Skip to content

Commit b672e76

Browse files
committed
Add proper server support that works
1 parent 81766c6 commit b672e76

18 files changed

Lines changed: 290 additions & 160 deletions

build.gradle

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,10 @@ minecraft {
4343
makeObfSourceJar = false
4444

4545
replace "@VERSION@", project.version
46-
replaceIn "com/irtimaled/bbor/install/Main.java"
46+
replaceIn "com/irtimaled/bbor/Main.java"
4747

4848
replace "@MC_VERSION@", project.mcVersion
49-
replaceIn "com/irtimaled/bbor/install/Main.java"
49+
replaceIn "com/irtimaled/bbor/Main.java"
5050
}
5151

5252
mixin {
@@ -78,7 +78,7 @@ processResources {
7878
jar {
7979
finalizedBy reobfJar
8080
manifest.attributes(
81-
'Main-Class': 'com.irtimaled.bbor.install.Main'
81+
'Main-Class': 'com.irtimaled.bbor.Main'
8282
)
8383

8484
classifier = 'vanilla'
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.irtimaled.bbor;
2+
3+
import com.irtimaled.bbor.install.Installer;
4+
import com.irtimaled.bbor.server.ServerRunner;
5+
6+
import java.io.IOException;
7+
import java.util.Arrays;
8+
9+
public class Main {
10+
public static void main(String... args) throws IOException {
11+
if (args.length > 0 && args[0].equals("--server")) {
12+
ServerRunner.run("@MC_VERSION@", Arrays.asList(args).subList(1, args.length));
13+
} else {
14+
Installer.install("@VERSION@", "@MC_VERSION@");
15+
16+
}
17+
}
18+
}

src/main/java/com/irtimaled/bbor/client/ClientProxy.java

Lines changed: 1 addition & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -88,38 +88,8 @@ private void disconnectedFromServer() {
8888
@Override
8989
protected void setWorldData(long seed, int spawnX, int spawnZ) {
9090
super.setWorldData(seed, spawnX, spawnZ);
91-
addSpawnChunkBoundingBoxes(spawnX, spawnZ);
91+
renderer.setWorldData(seed, spawnX, spawnZ);
9292
}
9393

94-
private void addSpawnChunkBoundingBoxes(int spawnX, int spawnZ) {
95-
BoundingBox worldSpawnBoundingBox = getWorldSpawnBoundingBox(spawnX, spawnZ);
96-
BoundingBox spawnChunksBoundingBox = buildSpawnChunksBoundingBox(spawnX, spawnZ, 12, BoundingBoxType.SpawnChunks);
97-
BoundingBox lazySpawnChunksBoundingBox = buildSpawnChunksBoundingBox(spawnX, spawnZ, 16, BoundingBoxType.LazySpawnChunks);
9894

99-
runOnCache(DimensionType.OVERWORLD, cache -> {
100-
cache.addBoundingBox(worldSpawnBoundingBox);
101-
cache.addBoundingBox(spawnChunksBoundingBox);
102-
cache.addBoundingBox(lazySpawnChunksBoundingBox);
103-
});
104-
}
105-
106-
private BoundingBox getWorldSpawnBoundingBox(int spawnX, int spawnZ) {
107-
BlockPos minBlockPos = new BlockPos(spawnX - 10, 0, spawnZ - 10);
108-
BlockPos maxBlockPos = new BlockPos(spawnX + 10, 0, spawnZ + 10);
109-
110-
return BoundingBoxWorldSpawn.from(minBlockPos, maxBlockPos, BoundingBoxType.WorldSpawn);
111-
}
112-
113-
private BoundingBox buildSpawnChunksBoundingBox(int spawnX, int spawnZ, int size, BoundingBoxType type) {
114-
double midOffset = CHUNK_SIZE * (size / 2.0);
115-
double midX = Math.round((float) (spawnX / (double) CHUNK_SIZE)) * (double) CHUNK_SIZE;
116-
double midZ = Math.round((float) (spawnZ / (double) CHUNK_SIZE)) * (double) CHUNK_SIZE;
117-
BlockPos minBlockPos = new BlockPos(midX - midOffset, 0, midZ - midOffset);
118-
if (spawnX / (double) CHUNK_SIZE % 0.5D == 0.0D && spawnZ / (double) CHUNK_SIZE % 0.5D == 0.0D) {
119-
midX += (double) CHUNK_SIZE;
120-
midZ += (double) CHUNK_SIZE;
121-
}
122-
BlockPos maxBlockPos = new BlockPos(midX + midOffset, 0, midZ + midOffset);
123-
return BoundingBoxWorldSpawn.from(minBlockPos, maxBlockPos, type);
124-
}
12595
}

src/main/java/com/irtimaled/bbor/client/ClientRenderer.java

Lines changed: 100 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,25 @@
22

33
import com.irtimaled.bbor.client.renderers.*;
44
import com.irtimaled.bbor.common.BoundingBoxCache;
5+
import com.irtimaled.bbor.common.BoundingBoxType;
56
import com.irtimaled.bbor.common.models.*;
67
import com.irtimaled.bbor.config.ConfigManager;
78
import net.minecraft.client.Minecraft;
89
import net.minecraft.util.math.BlockPos;
10+
import net.minecraft.util.math.ChunkPos;
911
import net.minecraft.util.math.MathHelper;
1012
import net.minecraft.world.dimension.DimensionType;
1113
import org.lwjgl.opengl.GL11;
1214

13-
import java.util.HashMap;
14-
import java.util.Map;
15-
import java.util.Set;
15+
import java.util.*;
1616

1717
import static com.irtimaled.bbor.client.Constants.CHUNK_SIZE;
1818

1919
public class ClientRenderer {
2020
private final GetCache getCache;
2121
private static final Map<Class<? extends BoundingBox>, Renderer> boundingBoxRendererMap = new HashMap<>();
22+
private long seed;
23+
private Set<BoundingBox> spawnChunkBoundingBoxes = new HashSet<>();
2224

2325
ClientRenderer(GetCache getCache) {
2426
this.getCache = getCache;
@@ -42,9 +44,12 @@ private boolean isWithinRenderDistance(BlockPos minBlockPos, BlockPos maxBlockPo
4244
minBlockPos.getZ() <= maxZ;
4345
}
4446

47+
private boolean isWithinRenderDistance(BoundingBox boundingBox) {
48+
return isWithinRenderDistance(boundingBox.getMinBlockPos(), boundingBox.getMaxBlockPos());
49+
}
50+
4551
public void render(DimensionType dimensionType, Boolean outerBoxesOnly) {
46-
BoundingBoxCache cache = getCache.apply(dimensionType);
47-
if (cache == null) return;
52+
Map<BoundingBox, Set<BoundingBox>> boundingBoxes = getBoundingBoxes(dimensionType);
4853

4954
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
5055
GL11.glLineWidth(2.0f);
@@ -54,17 +59,17 @@ public void render(DimensionType dimensionType, Boolean outerBoxesOnly) {
5459
if (ConfigManager.alwaysVisible.get()) {
5560
GL11.glClear(GL11.GL_DEPTH_BUFFER_BIT);
5661
}
57-
for (Map.Entry<BoundingBox, Set<BoundingBox>> entry : cache.getBoundingBoxes().entrySet()) {
62+
for (Map.Entry<BoundingBox, Set<BoundingBox>> entry : boundingBoxes.entrySet()) {
5863
BoundingBox key = entry.getKey();
59-
if (!key.shouldRender() || !isWithinRenderDistance(key.getMinBlockPos(), key.getMaxBlockPos())) continue;
64+
if (!key.shouldRender()) continue;
6065

6166
Renderer renderer = boundingBoxRendererMap.get(key.getClass());
6267
if (renderer == null) continue;
6368

6469
if (!outerBoxesOnly) {
65-
Set<BoundingBox> boundingBoxes = entry.getValue();
66-
if (boundingBoxes != null) {
67-
boundingBoxes.forEach(renderer::render);
70+
Set<BoundingBox> children = entry.getValue();
71+
if (children != null) {
72+
children.forEach(renderer::render);
6873
continue;
6974
}
7075
}
@@ -75,4 +80,89 @@ public void render(DimensionType dimensionType, Boolean outerBoxesOnly) {
7580
GL11.glEnable(GL11.GL_CULL_FACE);
7681
GL11.glEnable(GL11.GL_TEXTURE_2D);
7782
}
83+
84+
private Map<BoundingBox, Set<BoundingBox>> getBoundingBoxes(DimensionType dimensionType) {
85+
Map<BoundingBox, Set<BoundingBox>> boundingBoxes = new HashMap<>();
86+
if (dimensionType == DimensionType.OVERWORLD) {
87+
if (BoundingBoxType.SlimeChunks.shouldRender()) {
88+
addSlimeChunks(boundingBoxes);
89+
}
90+
91+
for (BoundingBox boundingBox : spawnChunkBoundingBoxes) {
92+
if (boundingBox.shouldRender() && isWithinRenderDistance(boundingBox)) {
93+
boundingBoxes.put(boundingBox, null);
94+
}
95+
}
96+
}
97+
98+
BoundingBoxCache cache = getCache.apply(dimensionType);
99+
if (cache != null) {
100+
for (Map.Entry<BoundingBox, Set<BoundingBox>> entry : cache.getBoundingBoxes().entrySet()) {
101+
BoundingBox key = entry.getKey();
102+
if (key.shouldRender() && isWithinRenderDistance(key)) {
103+
boundingBoxes.put(key, entry.getValue());
104+
}
105+
}
106+
}
107+
return boundingBoxes;
108+
}
109+
110+
private void addSlimeChunks(Map<BoundingBox, Set<BoundingBox>> boundingBoxes) {
111+
Minecraft minecraft = Minecraft.getInstance();
112+
int renderDistanceChunks = minecraft.gameSettings.renderDistanceChunks;
113+
int playerChunkX = MathHelper.floor(PlayerData.getX() / 16.0D);
114+
int playerChunkZ = MathHelper.floor(PlayerData.getZ() / 16.0D);
115+
for (int chunkX = playerChunkX - renderDistanceChunks; chunkX <= playerChunkX + renderDistanceChunks; ++chunkX) {
116+
for (int chunkZ = playerChunkZ - renderDistanceChunks; chunkZ <= playerChunkZ + renderDistanceChunks; ++chunkZ) {
117+
if (isSlimeChunk(chunkX, chunkZ)) {
118+
ChunkPos chunk = new ChunkPos(chunkX, chunkZ);
119+
BlockPos minBlockPos = new BlockPos(chunk.getXStart(), 1, chunk.getZStart());
120+
BlockPos maxBlockPos = new BlockPos(chunk.getXEnd(), 38, chunk.getZEnd());
121+
boundingBoxes.put(BoundingBoxSlimeChunk.from(minBlockPos, maxBlockPos), null);
122+
}
123+
}
124+
}
125+
}
126+
127+
private boolean isSlimeChunk(int chunkX, int chunkZ) {
128+
Random r = new Random(seed +
129+
(long) (chunkX * chunkX * 4987142) +
130+
(long) (chunkX * 5947611) +
131+
(long) (chunkZ * chunkZ) * 4392871L +
132+
(long) (chunkZ * 389711) ^ 987234911L);
133+
return r.nextInt(10) == 0;
134+
}
135+
136+
void setWorldData(long seed, int spawnX, int spawnZ) {
137+
this.seed = seed;
138+
spawnChunkBoundingBoxes = getSpawnChunkBoundingBoxes(spawnX, spawnZ);
139+
}
140+
141+
private Set<BoundingBox> getSpawnChunkBoundingBoxes(int spawnX, int spawnZ) {
142+
Set<BoundingBox> boundingBoxes = new HashSet<>();
143+
boundingBoxes.add(getWorldSpawnBoundingBox(spawnX, spawnZ));
144+
boundingBoxes.add(buildSpawnChunksBoundingBox(spawnX, spawnZ, 12, BoundingBoxType.SpawnChunks));
145+
boundingBoxes.add(buildSpawnChunksBoundingBox(spawnX, spawnZ, 16, BoundingBoxType.LazySpawnChunks));
146+
return boundingBoxes;
147+
}
148+
149+
private BoundingBox getWorldSpawnBoundingBox(int spawnX, int spawnZ) {
150+
BlockPos minBlockPos = new BlockPos(spawnX - 10, 0, spawnZ - 10);
151+
BlockPos maxBlockPos = new BlockPos(spawnX + 10, 0, spawnZ + 10);
152+
153+
return BoundingBoxWorldSpawn.from(minBlockPos, maxBlockPos, BoundingBoxType.WorldSpawn);
154+
}
155+
156+
private BoundingBox buildSpawnChunksBoundingBox(int spawnX, int spawnZ, int size, BoundingBoxType type) {
157+
double midOffset = CHUNK_SIZE * (size / 2.0);
158+
double midX = Math.round((float) (spawnX / (double) CHUNK_SIZE)) * (double) CHUNK_SIZE;
159+
double midZ = Math.round((float) (spawnZ / (double) CHUNK_SIZE)) * (double) CHUNK_SIZE;
160+
BlockPos minBlockPos = new BlockPos(midX - midOffset, 0, midZ - midOffset);
161+
if (spawnX / (double) CHUNK_SIZE % 0.5D == 0.0D && spawnZ / (double) CHUNK_SIZE % 0.5D == 0.0D) {
162+
midX += (double) CHUNK_SIZE;
163+
midZ += (double) CHUNK_SIZE;
164+
}
165+
BlockPos maxBlockPos = new BlockPos(midX + midOffset, 0, midZ + midOffset);
166+
return BoundingBoxWorldSpawn.from(minBlockPos, maxBlockPos, type);
167+
}
78168
}

src/main/java/com/irtimaled/bbor/common/CommonProxy.java

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import com.irtimaled.bbor.common.models.BoundingBoxVillage;
1515
import com.irtimaled.bbor.common.models.WorldData;
1616
import com.irtimaled.bbor.config.ConfigManager;
17+
import io.netty.channel.local.LocalAddress;
1718
import net.minecraft.entity.player.EntityPlayerMP;
1819
import net.minecraft.network.play.server.SPacketCustomPayload;
1920
import net.minecraft.util.math.BlockPos;
@@ -32,7 +33,7 @@
3233
import java.util.function.Consumer;
3334

3435
public class CommonProxy {
35-
private Map<EntityPlayerMP, DimensionType> playerDimensions = new ConcurrentHashMap<>();
36+
private Set<EntityPlayerMP> players = new HashSet<>();
3637
private Map<EntityPlayerMP, Set<BoundingBox>> playerBoundingBoxesCache = new HashMap<>();
3738
private Map<Integer, BoundingBoxVillage> villageCache = new HashMap<>();
3839
private Map<DimensionType, ChunkProcessor> chunkProcessors = new HashMap<>();
@@ -43,7 +44,6 @@ public void init() {
4344
EventBus.subscribe(WorldLoaded.class, e -> worldLoaded(e.getWorld()));
4445
EventBus.subscribe(ChunkLoaded.class, e -> chunkLoaded(e.getChunk()));
4546
EventBus.subscribe(MobSpawnerBroken.class, e -> mobSpawnerBroken(e.getDimensionType(), e.getPos()));
46-
EventBus.subscribe(PlayerChangedDimension.class, e -> playerChangedDimension(e.getPlayer()));
4747
EventBus.subscribe(PlayerLoggedIn.class, e -> playerLoggedIn(e.getPlayer()));
4848
EventBus.subscribe(PlayerLoggedOut.class, e -> playerLoggedOut(e.getPlayer()));
4949
EventBus.subscribe(PlayerSubscribed.class, e -> sendBoundingBoxes(e.getPlayer()));
@@ -65,7 +65,7 @@ private void worldLoaded(World world) {
6565
ChunkProcessor chunkProcessor = null;
6666
if (dimensionType == DimensionType.OVERWORLD) {
6767
setWorldData(world.getSeed(), world.getWorldInfo().getSpawnX(), world.getWorldInfo().getSpawnZ());
68-
chunkProcessor = new OverworldChunkProcessor(boundingBoxCache, world.getSeed());
68+
chunkProcessor = new OverworldChunkProcessor(boundingBoxCache);
6969
}
7070
if (dimensionType == DimensionType.NETHER) {
7171
chunkProcessor = new NetherChunkProcessor(boundingBoxCache);
@@ -86,26 +86,22 @@ private void chunkLoaded(Chunk chunk) {
8686
}
8787
}
8888

89-
private void playerChangedDimension(EntityPlayerMP player) {
90-
if (playerDimensions.containsKey(player)) {
91-
sendBoundingBoxes(player);
92-
}
93-
}
94-
9589
private void playerLoggedIn(EntityPlayerMP player) {
90+
if (player.connection.netManager.getRemoteAddress() instanceof LocalAddress) return;
9691
player.connection.sendPacket(InitializeClient.getPayload(worldData));
9792
}
9893

9994
private void playerLoggedOut(EntityPlayerMP player) {
100-
playerDimensions.remove(player);
95+
players.remove(player);
10196
playerBoundingBoxesCache.remove(player);
10297
}
10398

10499
private void sendRemoveBoundingBox(DimensionType dimensionType, BoundingBox boundingBox) {
105100
SPacketCustomPayload payload = RemoveBoundingBox.getPayload(dimensionType, boundingBox);
106-
for (EntityPlayerMP player : playerDimensions.keySet()) {
101+
if (payload == null) return;
102+
103+
for (EntityPlayerMP player : players) {
107104
if (DimensionType.getById(player.dimension) == dimensionType) {
108-
Logger.info("remove 1 entry from %s (%s)", player.getScoreboardName(), dimensionType);
109105
player.connection.sendPacket(payload);
110106

111107
if (playerBoundingBoxesCache.containsKey(player)) {
@@ -117,7 +113,7 @@ private void sendRemoveBoundingBox(DimensionType dimensionType, BoundingBox boun
117113

118114
private void sendBoundingBoxes(EntityPlayerMP player) {
119115
DimensionType dimensionType = DimensionType.getById(player.dimension);
120-
playerDimensions.put(player, dimensionType);
116+
players.add(player);
121117
sendToPlayer(player, getCache(dimensionType));
122118
}
123119

@@ -127,13 +123,12 @@ private void sendToPlayer(EntityPlayerMP player, BoundingBoxCache boundingBoxCac
127123
Map<BoundingBox, Set<BoundingBox>> cacheSubset = getBoundingBoxMap(player, boundingBoxCache.getBoundingBoxes());
128124

129125
DimensionType dimensionType = DimensionType.getById(player.dimension);
130-
if (cacheSubset.keySet().size() > 0) {
131-
Logger.info("send %d entries to %s (%s)", cacheSubset.keySet().size(), player.getScoreboardName(), dimensionType);
132-
}
133126

134127
for (BoundingBox key : cacheSubset.keySet()) {
135128
Set<BoundingBox> boundingBoxes = cacheSubset.get(key);
136-
player.connection.sendPacket(AddBoundingBox.getPayload(dimensionType, key, boundingBoxes));
129+
SPacketCustomPayload payload = AddBoundingBox.getPayload(dimensionType, key, boundingBoxes);
130+
if (payload != null)
131+
player.connection.sendPacket(payload);
137132

138133
if (!playerBoundingBoxesCache.containsKey(player)) {
139134
playerBoundingBoxesCache.put(player, new HashSet<>());
@@ -166,8 +161,8 @@ private void mobSpawnerBroken(DimensionType dimensionType, BlockPos pos) {
166161
}
167162

168163
private void tick() {
169-
for (EntityPlayerMP player : playerDimensions.keySet()) {
170-
DimensionType dimensionType = playerDimensions.get(player);
164+
for (EntityPlayerMP player : players) {
165+
DimensionType dimensionType = DimensionType.getById(player.dimension);
171166
sendToPlayer(player, getCache(dimensionType));
172167
}
173168
}
@@ -196,8 +191,7 @@ protected BoundingBoxCache getCache(DimensionType dimensionType) {
196191
return dimensionCache.get(dimensionType);
197192
}
198193

199-
protected BoundingBoxCache getOrCreateCache(DimensionType dimensionType)
200-
{
194+
protected BoundingBoxCache getOrCreateCache(DimensionType dimensionType) {
201195
return dimensionCache.computeIfAbsent(dimensionType, dt -> new BoundingBoxCache());
202196
}
203197

src/main/java/com/irtimaled/bbor/common/EventBus.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ public class EventBus {
88
private static Map<Class<?>, Consumer<?>> handlers = new HashMap<>();
99

1010
public static <evt> void publish(evt event) {
11+
if (event == null) return;
12+
1113
Class clazz = event.getClass();
1214
Consumer<?> handler = handlers.get(clazz);
1315
if (handler == null) return;

0 commit comments

Comments
 (0)