Skip to content

Commit

Permalink
Add proper server support that works
Browse files Browse the repository at this point in the history
  • Loading branch information
irtimaled committed Mar 10, 2019
1 parent 81766c6 commit b672e76
Show file tree
Hide file tree
Showing 18 changed files with 290 additions and 160 deletions.
6 changes: 3 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ minecraft {
makeObfSourceJar = false

replace "@VERSION@", project.version
replaceIn "com/irtimaled/bbor/install/Main.java"
replaceIn "com/irtimaled/bbor/Main.java"

replace "@MC_VERSION@", project.mcVersion
replaceIn "com/irtimaled/bbor/install/Main.java"
replaceIn "com/irtimaled/bbor/Main.java"
}

mixin {
Expand Down Expand Up @@ -78,7 +78,7 @@ processResources {
jar {
finalizedBy reobfJar
manifest.attributes(
'Main-Class': 'com.irtimaled.bbor.install.Main'
'Main-Class': 'com.irtimaled.bbor.Main'
)

classifier = 'vanilla'
Expand Down
18 changes: 18 additions & 0 deletions src/main/java/com/irtimaled/bbor/Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.irtimaled.bbor;

import com.irtimaled.bbor.install.Installer;
import com.irtimaled.bbor.server.ServerRunner;

import java.io.IOException;
import java.util.Arrays;

public class Main {
public static void main(String... args) throws IOException {
if (args.length > 0 && args[0].equals("--server")) {
ServerRunner.run("@MC_VERSION@", Arrays.asList(args).subList(1, args.length));
} else {
Installer.install("@VERSION@", "@MC_VERSION@");

}
}
}
32 changes: 1 addition & 31 deletions src/main/java/com/irtimaled/bbor/client/ClientProxy.java
Original file line number Diff line number Diff line change
Expand Up @@ -88,38 +88,8 @@ private void disconnectedFromServer() {
@Override
protected void setWorldData(long seed, int spawnX, int spawnZ) {
super.setWorldData(seed, spawnX, spawnZ);
addSpawnChunkBoundingBoxes(spawnX, spawnZ);
renderer.setWorldData(seed, spawnX, spawnZ);
}

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

runOnCache(DimensionType.OVERWORLD, cache -> {
cache.addBoundingBox(worldSpawnBoundingBox);
cache.addBoundingBox(spawnChunksBoundingBox);
cache.addBoundingBox(lazySpawnChunksBoundingBox);
});
}

private BoundingBox getWorldSpawnBoundingBox(int spawnX, int spawnZ) {
BlockPos minBlockPos = new BlockPos(spawnX - 10, 0, spawnZ - 10);
BlockPos maxBlockPos = new BlockPos(spawnX + 10, 0, spawnZ + 10);

return BoundingBoxWorldSpawn.from(minBlockPos, maxBlockPos, BoundingBoxType.WorldSpawn);
}

private BoundingBox buildSpawnChunksBoundingBox(int spawnX, int spawnZ, int size, BoundingBoxType type) {
double midOffset = CHUNK_SIZE * (size / 2.0);
double midX = Math.round((float) (spawnX / (double) CHUNK_SIZE)) * (double) CHUNK_SIZE;
double midZ = Math.round((float) (spawnZ / (double) CHUNK_SIZE)) * (double) CHUNK_SIZE;
BlockPos minBlockPos = new BlockPos(midX - midOffset, 0, midZ - midOffset);
if (spawnX / (double) CHUNK_SIZE % 0.5D == 0.0D && spawnZ / (double) CHUNK_SIZE % 0.5D == 0.0D) {
midX += (double) CHUNK_SIZE;
midZ += (double) CHUNK_SIZE;
}
BlockPos maxBlockPos = new BlockPos(midX + midOffset, 0, midZ + midOffset);
return BoundingBoxWorldSpawn.from(minBlockPos, maxBlockPos, type);
}
}
110 changes: 100 additions & 10 deletions src/main/java/com/irtimaled/bbor/client/ClientRenderer.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,25 @@

import com.irtimaled.bbor.client.renderers.*;
import com.irtimaled.bbor.common.BoundingBoxCache;
import com.irtimaled.bbor.common.BoundingBoxType;
import com.irtimaled.bbor.common.models.*;
import com.irtimaled.bbor.config.ConfigManager;
import net.minecraft.client.Minecraft;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.dimension.DimensionType;
import org.lwjgl.opengl.GL11;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.*;

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

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

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

private boolean isWithinRenderDistance(BoundingBox boundingBox) {
return isWithinRenderDistance(boundingBox.getMinBlockPos(), boundingBox.getMaxBlockPos());
}

public void render(DimensionType dimensionType, Boolean outerBoxesOnly) {
BoundingBoxCache cache = getCache.apply(dimensionType);
if (cache == null) return;
Map<BoundingBox, Set<BoundingBox>> boundingBoxes = getBoundingBoxes(dimensionType);

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

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

if (!outerBoxesOnly) {
Set<BoundingBox> boundingBoxes = entry.getValue();
if (boundingBoxes != null) {
boundingBoxes.forEach(renderer::render);
Set<BoundingBox> children = entry.getValue();
if (children != null) {
children.forEach(renderer::render);
continue;
}
}
Expand All @@ -75,4 +80,89 @@ public void render(DimensionType dimensionType, Boolean outerBoxesOnly) {
GL11.glEnable(GL11.GL_CULL_FACE);
GL11.glEnable(GL11.GL_TEXTURE_2D);
}

private Map<BoundingBox, Set<BoundingBox>> getBoundingBoxes(DimensionType dimensionType) {
Map<BoundingBox, Set<BoundingBox>> boundingBoxes = new HashMap<>();
if (dimensionType == DimensionType.OVERWORLD) {
if (BoundingBoxType.SlimeChunks.shouldRender()) {
addSlimeChunks(boundingBoxes);
}

for (BoundingBox boundingBox : spawnChunkBoundingBoxes) {
if (boundingBox.shouldRender() && isWithinRenderDistance(boundingBox)) {
boundingBoxes.put(boundingBox, null);
}
}
}

BoundingBoxCache cache = getCache.apply(dimensionType);
if (cache != null) {
for (Map.Entry<BoundingBox, Set<BoundingBox>> entry : cache.getBoundingBoxes().entrySet()) {
BoundingBox key = entry.getKey();
if (key.shouldRender() && isWithinRenderDistance(key)) {
boundingBoxes.put(key, entry.getValue());
}
}
}
return boundingBoxes;
}

private void addSlimeChunks(Map<BoundingBox, Set<BoundingBox>> boundingBoxes) {
Minecraft minecraft = Minecraft.getInstance();
int renderDistanceChunks = minecraft.gameSettings.renderDistanceChunks;
int playerChunkX = MathHelper.floor(PlayerData.getX() / 16.0D);
int playerChunkZ = MathHelper.floor(PlayerData.getZ() / 16.0D);
for (int chunkX = playerChunkX - renderDistanceChunks; chunkX <= playerChunkX + renderDistanceChunks; ++chunkX) {
for (int chunkZ = playerChunkZ - renderDistanceChunks; chunkZ <= playerChunkZ + renderDistanceChunks; ++chunkZ) {
if (isSlimeChunk(chunkX, chunkZ)) {
ChunkPos chunk = new ChunkPos(chunkX, chunkZ);
BlockPos minBlockPos = new BlockPos(chunk.getXStart(), 1, chunk.getZStart());
BlockPos maxBlockPos = new BlockPos(chunk.getXEnd(), 38, chunk.getZEnd());
boundingBoxes.put(BoundingBoxSlimeChunk.from(minBlockPos, maxBlockPos), null);
}
}
}
}

private boolean isSlimeChunk(int chunkX, int chunkZ) {
Random r = new Random(seed +
(long) (chunkX * chunkX * 4987142) +
(long) (chunkX * 5947611) +
(long) (chunkZ * chunkZ) * 4392871L +
(long) (chunkZ * 389711) ^ 987234911L);
return r.nextInt(10) == 0;
}

void setWorldData(long seed, int spawnX, int spawnZ) {
this.seed = seed;
spawnChunkBoundingBoxes = getSpawnChunkBoundingBoxes(spawnX, spawnZ);
}

private Set<BoundingBox> getSpawnChunkBoundingBoxes(int spawnX, int spawnZ) {
Set<BoundingBox> boundingBoxes = new HashSet<>();
boundingBoxes.add(getWorldSpawnBoundingBox(spawnX, spawnZ));
boundingBoxes.add(buildSpawnChunksBoundingBox(spawnX, spawnZ, 12, BoundingBoxType.SpawnChunks));
boundingBoxes.add(buildSpawnChunksBoundingBox(spawnX, spawnZ, 16, BoundingBoxType.LazySpawnChunks));
return boundingBoxes;
}

private BoundingBox getWorldSpawnBoundingBox(int spawnX, int spawnZ) {
BlockPos minBlockPos = new BlockPos(spawnX - 10, 0, spawnZ - 10);
BlockPos maxBlockPos = new BlockPos(spawnX + 10, 0, spawnZ + 10);

return BoundingBoxWorldSpawn.from(minBlockPos, maxBlockPos, BoundingBoxType.WorldSpawn);
}

private BoundingBox buildSpawnChunksBoundingBox(int spawnX, int spawnZ, int size, BoundingBoxType type) {
double midOffset = CHUNK_SIZE * (size / 2.0);
double midX = Math.round((float) (spawnX / (double) CHUNK_SIZE)) * (double) CHUNK_SIZE;
double midZ = Math.round((float) (spawnZ / (double) CHUNK_SIZE)) * (double) CHUNK_SIZE;
BlockPos minBlockPos = new BlockPos(midX - midOffset, 0, midZ - midOffset);
if (spawnX / (double) CHUNK_SIZE % 0.5D == 0.0D && spawnZ / (double) CHUNK_SIZE % 0.5D == 0.0D) {
midX += (double) CHUNK_SIZE;
midZ += (double) CHUNK_SIZE;
}
BlockPos maxBlockPos = new BlockPos(midX + midOffset, 0, midZ + midOffset);
return BoundingBoxWorldSpawn.from(minBlockPos, maxBlockPos, type);
}
}
36 changes: 15 additions & 21 deletions src/main/java/com/irtimaled/bbor/common/CommonProxy.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import com.irtimaled.bbor.common.models.BoundingBoxVillage;
import com.irtimaled.bbor.common.models.WorldData;
import com.irtimaled.bbor.config.ConfigManager;
import io.netty.channel.local.LocalAddress;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.network.play.server.SPacketCustomPayload;
import net.minecraft.util.math.BlockPos;
Expand All @@ -32,7 +33,7 @@
import java.util.function.Consumer;

public class CommonProxy {
private Map<EntityPlayerMP, DimensionType> playerDimensions = new ConcurrentHashMap<>();
private Set<EntityPlayerMP> players = new HashSet<>();
private Map<EntityPlayerMP, Set<BoundingBox>> playerBoundingBoxesCache = new HashMap<>();
private Map<Integer, BoundingBoxVillage> villageCache = new HashMap<>();
private Map<DimensionType, ChunkProcessor> chunkProcessors = new HashMap<>();
Expand All @@ -43,7 +44,6 @@ public void init() {
EventBus.subscribe(WorldLoaded.class, e -> worldLoaded(e.getWorld()));
EventBus.subscribe(ChunkLoaded.class, e -> chunkLoaded(e.getChunk()));
EventBus.subscribe(MobSpawnerBroken.class, e -> mobSpawnerBroken(e.getDimensionType(), e.getPos()));
EventBus.subscribe(PlayerChangedDimension.class, e -> playerChangedDimension(e.getPlayer()));
EventBus.subscribe(PlayerLoggedIn.class, e -> playerLoggedIn(e.getPlayer()));
EventBus.subscribe(PlayerLoggedOut.class, e -> playerLoggedOut(e.getPlayer()));
EventBus.subscribe(PlayerSubscribed.class, e -> sendBoundingBoxes(e.getPlayer()));
Expand All @@ -65,7 +65,7 @@ private void worldLoaded(World world) {
ChunkProcessor chunkProcessor = null;
if (dimensionType == DimensionType.OVERWORLD) {
setWorldData(world.getSeed(), world.getWorldInfo().getSpawnX(), world.getWorldInfo().getSpawnZ());
chunkProcessor = new OverworldChunkProcessor(boundingBoxCache, world.getSeed());
chunkProcessor = new OverworldChunkProcessor(boundingBoxCache);
}
if (dimensionType == DimensionType.NETHER) {
chunkProcessor = new NetherChunkProcessor(boundingBoxCache);
Expand All @@ -86,26 +86,22 @@ private void chunkLoaded(Chunk chunk) {
}
}

private void playerChangedDimension(EntityPlayerMP player) {
if (playerDimensions.containsKey(player)) {
sendBoundingBoxes(player);
}
}

private void playerLoggedIn(EntityPlayerMP player) {
if (player.connection.netManager.getRemoteAddress() instanceof LocalAddress) return;
player.connection.sendPacket(InitializeClient.getPayload(worldData));
}

private void playerLoggedOut(EntityPlayerMP player) {
playerDimensions.remove(player);
players.remove(player);
playerBoundingBoxesCache.remove(player);
}

private void sendRemoveBoundingBox(DimensionType dimensionType, BoundingBox boundingBox) {
SPacketCustomPayload payload = RemoveBoundingBox.getPayload(dimensionType, boundingBox);
for (EntityPlayerMP player : playerDimensions.keySet()) {
if (payload == null) return;

for (EntityPlayerMP player : players) {
if (DimensionType.getById(player.dimension) == dimensionType) {
Logger.info("remove 1 entry from %s (%s)", player.getScoreboardName(), dimensionType);
player.connection.sendPacket(payload);

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

private void sendBoundingBoxes(EntityPlayerMP player) {
DimensionType dimensionType = DimensionType.getById(player.dimension);
playerDimensions.put(player, dimensionType);
players.add(player);
sendToPlayer(player, getCache(dimensionType));
}

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

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

for (BoundingBox key : cacheSubset.keySet()) {
Set<BoundingBox> boundingBoxes = cacheSubset.get(key);
player.connection.sendPacket(AddBoundingBox.getPayload(dimensionType, key, boundingBoxes));
SPacketCustomPayload payload = AddBoundingBox.getPayload(dimensionType, key, boundingBoxes);
if (payload != null)
player.connection.sendPacket(payload);

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

private void tick() {
for (EntityPlayerMP player : playerDimensions.keySet()) {
DimensionType dimensionType = playerDimensions.get(player);
for (EntityPlayerMP player : players) {
DimensionType dimensionType = DimensionType.getById(player.dimension);
sendToPlayer(player, getCache(dimensionType));
}
}
Expand Down Expand Up @@ -196,8 +191,7 @@ protected BoundingBoxCache getCache(DimensionType dimensionType) {
return dimensionCache.get(dimensionType);
}

protected BoundingBoxCache getOrCreateCache(DimensionType dimensionType)
{
protected BoundingBoxCache getOrCreateCache(DimensionType dimensionType) {
return dimensionCache.computeIfAbsent(dimensionType, dt -> new BoundingBoxCache());
}

Expand Down
2 changes: 2 additions & 0 deletions src/main/java/com/irtimaled/bbor/common/EventBus.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ public class EventBus {
private static Map<Class<?>, Consumer<?>> handlers = new HashMap<>();

public static <evt> void publish(evt event) {
if (event == null) return;

Class clazz = event.getClass();
Consumer<?> handler = handlers.get(clazz);
if (handler == null) return;
Expand Down
Loading

0 comments on commit b672e76

Please sign in to comment.