]> git.lizzy.rs Git - BoundingBoxOutlineReloaded.git/commitdiff
Add initial server support
authorIrtimaled <irtimaled@gmail.com>
Wed, 27 Feb 2019 00:10:53 +0000 (16:10 -0800)
committerIrtimaled <irtimaled@gmail.com>
Tue, 5 Mar 2019 08:09:23 +0000 (00:09 -0800)
25 files changed:
src/main/java/com/irtimaled/bbor/client/ClientProxy.java
src/main/java/com/irtimaled/bbor/client/events/AddBoundingBoxReceived.java [new file with mode: 0644]
src/main/java/com/irtimaled/bbor/client/events/InitializeClientReceived.java [new file with mode: 0644]
src/main/java/com/irtimaled/bbor/client/events/RemoveBoundingBoxReceived.java [new file with mode: 0644]
src/main/java/com/irtimaled/bbor/common/CommonProxy.java
src/main/java/com/irtimaled/bbor/common/VillageProcessor.java
src/main/java/com/irtimaled/bbor/common/events/PlayerChangedDimension.java [new file with mode: 0644]
src/main/java/com/irtimaled/bbor/common/events/PlayerLoggedIn.java [new file with mode: 0644]
src/main/java/com/irtimaled/bbor/common/events/PlayerLoggedOut.java [new file with mode: 0644]
src/main/java/com/irtimaled/bbor/common/events/PlayerSubscribed.java [new file with mode: 0644]
src/main/java/com/irtimaled/bbor/common/events/Tick.java [new file with mode: 0644]
src/main/java/com/irtimaled/bbor/common/events/VillageRemoved.java [new file with mode: 0644]
src/main/java/com/irtimaled/bbor/common/messages/AddBoundingBox.java [new file with mode: 0644]
src/main/java/com/irtimaled/bbor/common/messages/BoundingBoxDeserializer.java [new file with mode: 0644]
src/main/java/com/irtimaled/bbor/common/messages/BoundingBoxSerializer.java [new file with mode: 0644]
src/main/java/com/irtimaled/bbor/common/messages/InitializeClient.java [new file with mode: 0644]
src/main/java/com/irtimaled/bbor/common/messages/RemoveBoundingBox.java [new file with mode: 0644]
src/main/java/com/irtimaled/bbor/common/messages/SubscribeToServer.java [new file with mode: 0644]
src/main/java/com/irtimaled/bbor/mixin/entity/player/MixinEntityPlayerMP.java [new file with mode: 0644]
src/main/java/com/irtimaled/bbor/mixin/network/play/client/MixinCPacketCustomPayload.java [new file with mode: 0644]
src/main/java/com/irtimaled/bbor/mixin/network/play/server/MixinSPacketCustomPayload.java [new file with mode: 0644]
src/main/java/com/irtimaled/bbor/mixin/server/MixinMinecraftServer.java
src/main/java/com/irtimaled/bbor/mixin/server/dedicated/MixinDedicatedServer.java [new file with mode: 0644]
src/main/java/com/irtimaled/bbor/mixin/server/management/MixinPlayerList.java [new file with mode: 0644]
src/main/resources/mixins.bbor.json

index 525b049e6df39a547b59daf2eec6298a65cb45d6..0042136ccbcc151c5d7aa69dfd25b1874f7d6347 100644 (file)
@@ -1,13 +1,9 @@
 package com.irtimaled.bbor.client;
 
-import com.irtimaled.bbor.client.events.ConnectedToRemoteServer;
-import com.irtimaled.bbor.client.events.DisconnectedFromRemoteServer;
-import com.irtimaled.bbor.client.events.KeyPressed;
-import com.irtimaled.bbor.client.events.RenderEvent;
-import com.irtimaled.bbor.common.CommonProxy;
-import com.irtimaled.bbor.common.EventBus;
-import com.irtimaled.bbor.common.VillageColorCache;
-import com.irtimaled.bbor.common.VillageProcessor;
+import com.irtimaled.bbor.client.events.*;
+import com.irtimaled.bbor.common.*;
+import com.irtimaled.bbor.common.events.Tick;
+import com.irtimaled.bbor.common.models.BoundingBox;
 import com.irtimaled.bbor.config.ConfigManager;
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.settings.KeyBinding;
@@ -17,6 +13,7 @@ import net.minecraft.world.dimension.DimensionType;
 
 import java.net.InetSocketAddress;
 import java.net.SocketAddress;
+import java.util.Set;
 
 public class ClientProxy extends CommonProxy {
     public static final String KeyCategory = "Bounding Box Outline Reloaded";
@@ -42,6 +39,10 @@ public class ClientProxy extends CommonProxy {
         EventBus.subscribe(KeyPressed.class, e -> keyPressed());
         EventBus.subscribe(ConnectedToRemoteServer.class, e -> connectedToServer(e.getNetworkManager()));
         EventBus.subscribe(DisconnectedFromRemoteServer.class, e -> disconnectedFromServer());
+        EventBus.subscribe(InitializeClientReceived.class, e -> dimensionCache.setWorldData(e.getSeed(), e.getSpawnX(), e.getSpawnZ()));
+        EventBus.subscribe(AddBoundingBoxReceived.class, e -> addBoundingBox(e.getDimensionType(), e.getKey(), e.getBoundingBoxes()));
+        EventBus.subscribe(RemoveBoundingBoxReceived.class, e -> removeBoundingBox(e.getDimensionType(), e.getKey()));
+        EventBus.subscribe(Tick.class, e -> tick());
     }
 
     private void render(float partialTicks) {
@@ -49,11 +50,17 @@ public class ClientProxy extends CommonProxy {
         PlayerData.setPlayerPosition(partialTicks, entityPlayer);
 
         if (this.active) {
-            tick();
             renderer.render(DimensionType.getById(entityPlayer.dimension), outerBoxOnly);
         }
     }
 
+    @Override
+    protected void tick() {
+        if (this.active || hasRemoteUsers()) {
+            super.tick();
+        }
+    }
+
     private void keyPressed() {
         if (ActiveHotKey.isPressed()) {
             active = !active;
@@ -81,4 +88,13 @@ public class ClientProxy extends CommonProxy {
         VillageColorCache.clear();
         dimensionCache.clear();
     }
+
+    private void addBoundingBox(DimensionType dimensionType, BoundingBox key, Set<BoundingBox> boundingBoxes) {
+        BoundingBoxCache cache = dimensionCache.get(dimensionType);
+        if (cache == null) {
+            dimensionCache.put(dimensionType, cache = new BoundingBoxCache());
+        }
+
+        cache.addBoundingBoxes(key, boundingBoxes);
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/com/irtimaled/bbor/client/events/AddBoundingBoxReceived.java b/src/main/java/com/irtimaled/bbor/client/events/AddBoundingBoxReceived.java
new file mode 100644 (file)
index 0000000..7957028
--- /dev/null
@@ -0,0 +1,30 @@
+package com.irtimaled.bbor.client.events;
+
+import com.irtimaled.bbor.common.models.BoundingBox;
+import net.minecraft.world.dimension.DimensionType;
+
+import java.util.Set;
+
+public class AddBoundingBoxReceived {
+    private final DimensionType dimensionType;
+    private final BoundingBox key;
+    private final Set<BoundingBox> boundingBoxes;
+
+    public AddBoundingBoxReceived(DimensionType dimensionType, BoundingBox key, Set<BoundingBox> boundingBoxes) {
+        this.dimensionType = dimensionType;
+        this.key = key;
+        this.boundingBoxes = boundingBoxes;
+    }
+
+    public DimensionType getDimensionType() {
+        return dimensionType;
+    }
+
+    public BoundingBox getKey() {
+        return key;
+    }
+
+    public Set<BoundingBox> getBoundingBoxes() {
+        return boundingBoxes;
+    }
+}
diff --git a/src/main/java/com/irtimaled/bbor/client/events/InitializeClientReceived.java b/src/main/java/com/irtimaled/bbor/client/events/InitializeClientReceived.java
new file mode 100644 (file)
index 0000000..1369a56
--- /dev/null
@@ -0,0 +1,25 @@
+package com.irtimaled.bbor.client.events;
+
+public class InitializeClientReceived {
+    private final long seed;
+    private final int spawnX;
+    private final int spawnZ;
+
+    public InitializeClientReceived(long seed, int spawnX, int spawnZ) {
+        this.seed = seed;
+        this.spawnX = spawnX;
+        this.spawnZ = spawnZ;
+    }
+
+    public long getSeed() {
+        return seed;
+    }
+
+    public int getSpawnX() {
+        return spawnX;
+    }
+
+    public int getSpawnZ() {
+        return spawnZ;
+    }
+}
diff --git a/src/main/java/com/irtimaled/bbor/client/events/RemoveBoundingBoxReceived.java b/src/main/java/com/irtimaled/bbor/client/events/RemoveBoundingBoxReceived.java
new file mode 100644 (file)
index 0000000..bc66bda
--- /dev/null
@@ -0,0 +1,22 @@
+package com.irtimaled.bbor.client.events;
+
+import com.irtimaled.bbor.common.models.BoundingBox;
+import net.minecraft.world.dimension.DimensionType;
+
+public class RemoveBoundingBoxReceived {
+    private final DimensionType dimensionType;
+    private final BoundingBox key;
+
+    public RemoveBoundingBoxReceived(DimensionType dimensionType, BoundingBox key) {
+        this.dimensionType = dimensionType;
+        this.key = key;
+    }
+
+    public DimensionType getDimensionType() {
+        return dimensionType;
+    }
+
+    public BoundingBox getKey() {
+        return key;
+    }
+}
index de9baff5bff457182373aa7570d78bf7e523589e..f5454aa16610c8784b12c146631eedc68db54198 100644 (file)
@@ -1,12 +1,15 @@
 package com.irtimaled.bbor.common;
 
 import com.irtimaled.bbor.Logger;
-import com.irtimaled.bbor.common.events.ChunkLoaded;
-import com.irtimaled.bbor.common.events.MobSpawnerBroken;
-import com.irtimaled.bbor.common.events.WorldLoaded;
+import com.irtimaled.bbor.common.events.*;
+import com.irtimaled.bbor.common.messages.AddBoundingBox;
+import com.irtimaled.bbor.common.messages.InitializeClient;
+import com.irtimaled.bbor.common.messages.RemoveBoundingBox;
 import com.irtimaled.bbor.common.models.BoundingBox;
 import com.irtimaled.bbor.common.models.BoundingBoxMobSpawner;
 import com.irtimaled.bbor.config.ConfigManager;
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.network.play.server.SPacketCustomPayload;
 import net.minecraft.util.math.BlockPos;
 import net.minecraft.world.World;
 import net.minecraft.world.chunk.Chunk;
@@ -14,10 +17,16 @@ import net.minecraft.world.chunk.IChunkProvider;
 import net.minecraft.world.dimension.DimensionType;
 import net.minecraft.world.gen.ChunkProviderServer;
 
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 
 public class CommonProxy {
+    private Map<EntityPlayerMP, DimensionType> playerDimensions = new ConcurrentHashMap<>();
+    private Map<EntityPlayerMP, Set<BoundingBox>> playerBoundingBoxesCache = new HashMap<>();
+
     protected DimensionCache dimensionCache;
     protected Set<VillageProcessor> villageProcessors = new HashSet<>();
 
@@ -30,6 +39,16 @@ public class CommonProxy {
         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(VillageRemoved.class, e -> sendRemoveBoundingBox(e.getDimensionType(), e.getBoundingBox()));
+        EventBus.subscribe(PlayerSubscribed.class, e -> sendBoundingBoxes(e.getPlayer()));
+        EventBus.subscribe(Tick.class, e -> tick());
+    }
+
+    protected boolean hasRemoteUsers() {
+        return playerDimensions.size() > 0;
     }
 
     private void worldLoaded(World world) {
@@ -41,7 +60,7 @@ public class CommonProxy {
             DimensionProcessor boundingBoxCache = new DimensionProcessor(dimensionType);
             dimensionCache.put(dimensionType, boundingBoxCache);
             if (ConfigManager.drawVillages.getBoolean()) {
-                villageProcessors.add(new VillageProcessor(world, boundingBoxCache));
+                villageProcessors.add(new VillageProcessor(world, dimensionType, boundingBoxCache));
             }
         }
     }
@@ -54,15 +73,90 @@ public class CommonProxy {
         }
     }
 
-    protected void tick() {
-        villageProcessors.forEach(VillageProcessor::process);
+    private void playerChangedDimension(EntityPlayerMP player) {
+        if (playerDimensions.containsKey(player)) {
+            sendBoundingBoxes(player);
+        }
     }
 
-    private void mobSpawnerBroken(DimensionType dimensionType, BlockPos pos) {
-        BoundingBox boundingBox = BoundingBoxMobSpawner.from(pos);
+    private void playerLoggedIn(EntityPlayerMP player) {
+        player.connection.sendPacket(InitializeClient.getPayload(dimensionCache.getWorldData()));
+    }
+
+    private void playerLoggedOut(EntityPlayerMP player) {
+        playerDimensions.remove(player);
+        playerBoundingBoxesCache.remove(player);
+    }
+
+    private void sendRemoveBoundingBox(DimensionType dimensionType, BoundingBox boundingBox) {
+        SPacketCustomPayload payload = RemoveBoundingBox.getPayload(dimensionType, boundingBox);
+        for (EntityPlayerMP player : playerDimensions.keySet()) {
+            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)) {
+                    playerBoundingBoxesCache.get(player).remove(boundingBox);
+                }
+            }
+        }
+    }
+
+    private void sendBoundingBoxes(EntityPlayerMP player) {
+        DimensionType dimensionType = DimensionType.getById(player.dimension);
+        playerDimensions.put(player, dimensionType);
+        sendToPlayer(player, dimensionCache.getBoundingBoxes(dimensionType));
+    }
+
+    private void sendToPlayer(EntityPlayerMP player, BoundingBoxCache boundingBoxCache) {
+        if (boundingBoxCache == null)
+            return;
+        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));
+
+            if (!playerBoundingBoxesCache.containsKey(player)) {
+                playerBoundingBoxesCache.put(player, new HashSet<>());
+            }
+            playerBoundingBoxesCache.get(player).add(key);
+        }
+    }
+
+    private Map<BoundingBox, Set<BoundingBox>> getBoundingBoxMap(EntityPlayerMP player, Map<BoundingBox, Set<BoundingBox>> boundingBoxMap) {
+        Map<BoundingBox, Set<BoundingBox>> cacheSubset = new HashMap<>();
+        for (BoundingBox key : boundingBoxMap.keySet()) {
+            if (!playerBoundingBoxesCache.containsKey(player) || !playerBoundingBoxesCache.get(player).contains(key)) {
+                cacheSubset.put(key, boundingBoxMap.get(key));
+            }
+        }
+        return cacheSubset;
+    }
+
+    protected void removeBoundingBox(DimensionType dimensionType, BoundingBox key) {
         BoundingBoxCache cache = dimensionCache.getBoundingBoxes(dimensionType);
         if (cache != null) {
-            cache.removeBoundingBox(boundingBox);
+            cache.removeBoundingBox(key);
+        }
+    }
+
+    private void mobSpawnerBroken(DimensionType dimensionType, BlockPos pos) {
+        BoundingBox boundingBox = BoundingBoxMobSpawner.from(pos);
+        removeBoundingBox(dimensionType, boundingBox);
+        sendRemoveBoundingBox(dimensionType, boundingBox);
+    }
+
+    protected void tick() {
+        villageProcessors.forEach(VillageProcessor::process);
+        for (EntityPlayerMP player : playerDimensions.keySet()) {
+            DimensionType dimensionType = playerDimensions.get(player);
+            sendToPlayer(player, dimensionCache.getBoundingBoxes(dimensionType));
         }
     }
 }
index 26c37118b9081b174fa2589bda7d4ad6bad8d4ed..0487d33058a6eee11f7d478a048ee12239cf38f2 100644 (file)
@@ -1,9 +1,11 @@
 package com.irtimaled.bbor.common;
 
+import com.irtimaled.bbor.common.events.VillageRemoved;
 import com.irtimaled.bbor.common.models.BoundingBoxVillage;
 import net.minecraft.village.Village;
 import net.minecraft.village.VillageCollection;
 import net.minecraft.world.World;
+import net.minecraft.world.dimension.DimensionType;
 
 import java.util.HashMap;
 import java.util.List;
@@ -11,12 +13,14 @@ import java.util.Map;
 
 public class VillageProcessor {
     private World world;
+    private DimensionType dimensionType;
     private BoundingBoxCache boundingBoxCache;
     private Map<Integer, BoundingBoxVillage> villageCache = new HashMap<>();
     private boolean closed = false;
 
-    VillageProcessor(World world, BoundingBoxCache boundingBoxCache) {
+    VillageProcessor(World world, DimensionType dimensionType, BoundingBoxCache boundingBoxCache) {
         this.world = world;
+        this.dimensionType = dimensionType;
         this.boundingBoxCache = boundingBoxCache;
     }
 
@@ -42,6 +46,7 @@ public class VillageProcessor {
         }
         for (BoundingBoxVillage village : oldVillages.values()) {
             boundingBoxCache.removeBoundingBox(village);
+            EventBus.publish(new VillageRemoved(dimensionType, village));
         }
         for (BoundingBoxVillage village : newVillages.values()) {
             boundingBoxCache.addBoundingBox(village);
diff --git a/src/main/java/com/irtimaled/bbor/common/events/PlayerChangedDimension.java b/src/main/java/com/irtimaled/bbor/common/events/PlayerChangedDimension.java
new file mode 100644 (file)
index 0000000..7ba767f
--- /dev/null
@@ -0,0 +1,15 @@
+package com.irtimaled.bbor.common.events;
+
+import net.minecraft.entity.player.EntityPlayerMP;
+
+public class PlayerChangedDimension {
+    private final EntityPlayerMP player;
+
+    public PlayerChangedDimension(EntityPlayerMP player) {
+        this.player = player;
+    }
+
+    public EntityPlayerMP getPlayer() {
+        return player;
+    }
+}
diff --git a/src/main/java/com/irtimaled/bbor/common/events/PlayerLoggedIn.java b/src/main/java/com/irtimaled/bbor/common/events/PlayerLoggedIn.java
new file mode 100644 (file)
index 0000000..6de9141
--- /dev/null
@@ -0,0 +1,15 @@
+package com.irtimaled.bbor.common.events;
+
+import net.minecraft.entity.player.EntityPlayerMP;
+
+public class PlayerLoggedIn {
+    private final EntityPlayerMP player;
+
+    public PlayerLoggedIn(EntityPlayerMP player) {
+        this.player = player;
+    }
+
+    public EntityPlayerMP getPlayer() {
+        return player;
+    }
+}
diff --git a/src/main/java/com/irtimaled/bbor/common/events/PlayerLoggedOut.java b/src/main/java/com/irtimaled/bbor/common/events/PlayerLoggedOut.java
new file mode 100644 (file)
index 0000000..b0f0e9f
--- /dev/null
@@ -0,0 +1,15 @@
+package com.irtimaled.bbor.common.events;
+
+import net.minecraft.entity.player.EntityPlayerMP;
+
+public class PlayerLoggedOut {
+    private final EntityPlayerMP player;
+
+    public PlayerLoggedOut(EntityPlayerMP player) {
+        this.player = player;
+    }
+
+    public EntityPlayerMP getPlayer() {
+        return player;
+    }
+}
diff --git a/src/main/java/com/irtimaled/bbor/common/events/PlayerSubscribed.java b/src/main/java/com/irtimaled/bbor/common/events/PlayerSubscribed.java
new file mode 100644 (file)
index 0000000..5657fae
--- /dev/null
@@ -0,0 +1,15 @@
+package com.irtimaled.bbor.common.events;
+
+import net.minecraft.entity.player.EntityPlayerMP;
+
+public class PlayerSubscribed {
+    private final EntityPlayerMP player;
+
+    public PlayerSubscribed(EntityPlayerMP player) {
+        this.player = player;
+    }
+
+    public EntityPlayerMP getPlayer() {
+        return player;
+    }
+}
diff --git a/src/main/java/com/irtimaled/bbor/common/events/Tick.java b/src/main/java/com/irtimaled/bbor/common/events/Tick.java
new file mode 100644 (file)
index 0000000..51232bf
--- /dev/null
@@ -0,0 +1,4 @@
+package com.irtimaled.bbor.common.events;
+
+public class Tick {
+}
diff --git a/src/main/java/com/irtimaled/bbor/common/events/VillageRemoved.java b/src/main/java/com/irtimaled/bbor/common/events/VillageRemoved.java
new file mode 100644 (file)
index 0000000..a067178
--- /dev/null
@@ -0,0 +1,22 @@
+package com.irtimaled.bbor.common.events;
+
+import com.irtimaled.bbor.common.models.BoundingBox;
+import net.minecraft.world.dimension.DimensionType;
+
+public class VillageRemoved {
+    private final DimensionType dimensionType;
+    private final BoundingBox boundingBox;
+
+    public VillageRemoved(DimensionType dimensionType, BoundingBox boundingBox) {
+        this.dimensionType = dimensionType;
+        this.boundingBox = boundingBox;
+    }
+
+    public DimensionType getDimensionType() {
+        return dimensionType;
+    }
+
+    public BoundingBox getBoundingBox() {
+        return boundingBox;
+    }
+}
diff --git a/src/main/java/com/irtimaled/bbor/common/messages/AddBoundingBox.java b/src/main/java/com/irtimaled/bbor/common/messages/AddBoundingBox.java
new file mode 100644 (file)
index 0000000..4501d2f
--- /dev/null
@@ -0,0 +1,41 @@
+package com.irtimaled.bbor.common.messages;
+
+import com.irtimaled.bbor.client.events.AddBoundingBoxReceived;
+import com.irtimaled.bbor.common.models.BoundingBox;
+import io.netty.buffer.Unpooled;
+import net.minecraft.network.PacketBuffer;
+import net.minecraft.network.play.server.SPacketCustomPayload;
+import net.minecraft.util.ResourceLocation;
+import net.minecraft.world.dimension.DimensionType;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class AddBoundingBox {
+    public static final ResourceLocation NAME = new ResourceLocation("bbor:add_bounding_box");
+
+    public static SPacketCustomPayload getPayload(DimensionType dimensionType, BoundingBox key, Set<BoundingBox> boundingBoxes) {
+        PacketBuffer buf = new PacketBuffer(Unpooled.buffer());
+        buf.writeVarInt(dimensionType.getId());
+        BoundingBoxSerializer.serialize(key, buf);
+        if (boundingBoxes != null && boundingBoxes.size() > 1) {
+            for (BoundingBox boundingBox : boundingBoxes) {
+                BoundingBoxSerializer.serialize(boundingBox, buf);
+            }
+        }
+        return new SPacketCustomPayload(NAME, buf);
+    }
+
+    public static AddBoundingBoxReceived getEvent(PacketBuffer buf) {
+        DimensionType dimensionType = DimensionType.getById(buf.readVarInt());
+        BoundingBox key = BoundingBoxDeserializer.deserialize(buf);
+        Set<BoundingBox> boundingBoxes = new HashSet<>();
+        while (buf.isReadable()) {
+            BoundingBox boundingBox = BoundingBoxDeserializer.deserialize(buf);
+            boundingBoxes.add(boundingBox);
+        }
+        if (boundingBoxes.size() == 0)
+            boundingBoxes.add(key);
+        return new AddBoundingBoxReceived(dimensionType, key, boundingBoxes);
+    }
+}
diff --git a/src/main/java/com/irtimaled/bbor/common/messages/BoundingBoxDeserializer.java b/src/main/java/com/irtimaled/bbor/common/messages/BoundingBoxDeserializer.java
new file mode 100644 (file)
index 0000000..6ceff3e
--- /dev/null
@@ -0,0 +1,59 @@
+package com.irtimaled.bbor.common.messages;
+
+import com.irtimaled.bbor.common.models.BoundingBox;
+import com.irtimaled.bbor.common.models.BoundingBoxMobSpawner;
+import com.irtimaled.bbor.common.models.BoundingBoxStructure;
+import com.irtimaled.bbor.common.models.BoundingBoxVillage;
+import net.minecraft.network.PacketBuffer;
+import net.minecraft.util.math.BlockPos;
+
+import java.awt.*;
+import java.util.HashSet;
+import java.util.Set;
+
+public class BoundingBoxDeserializer {
+    static BoundingBox deserialize(PacketBuffer buf) {
+        char type = buf.readChar();
+        switch (type) {
+            case 'V':
+                return deserializeVillage(buf);
+            case 'S':
+                return deserializeStructure(buf);
+            case 'M':
+                return deserializeMobSpawner(buf);
+        }
+        return null;
+    }
+
+    private static BoundingBox deserializeStructure(PacketBuffer buf) {
+        BlockPos minBlockPos = deserializeBlockPos(buf);
+        BlockPos maxBlockPos = deserializeBlockPos(buf);
+        Color color = new Color(buf.readVarInt());
+        return BoundingBoxStructure.from(minBlockPos, maxBlockPos, color);
+    }
+
+    private static BoundingBox deserializeVillage(PacketBuffer buf) {
+        BlockPos center = deserializeBlockPos(buf);
+        int radius = buf.readVarInt();
+        boolean spawnsIronGolems = buf.readBoolean();
+        Color color = new Color(buf.readVarInt());
+        Set<BlockPos> doors = new HashSet<>();
+        while (buf.isReadable()) {
+            BlockPos door = deserializeBlockPos(buf);
+            doors.add(door);
+        }
+        return BoundingBoxVillage.from(center, radius, color, spawnsIronGolems, doors);
+    }
+
+    private static BoundingBox deserializeMobSpawner(PacketBuffer buf) {
+        BlockPos center = deserializeBlockPos(buf);
+        return BoundingBoxMobSpawner.from(center);
+    }
+
+    private static BlockPos deserializeBlockPos(PacketBuffer buf) {
+        int x = buf.readVarInt();
+        int y = buf.readVarInt();
+        int z = buf.readVarInt();
+        return new BlockPos(x, y, z);
+    }
+}
diff --git a/src/main/java/com/irtimaled/bbor/common/messages/BoundingBoxSerializer.java b/src/main/java/com/irtimaled/bbor/common/messages/BoundingBoxSerializer.java
new file mode 100644 (file)
index 0000000..321af78
--- /dev/null
@@ -0,0 +1,61 @@
+package com.irtimaled.bbor.common.messages;
+
+import com.irtimaled.bbor.common.models.BoundingBox;
+import com.irtimaled.bbor.common.models.BoundingBoxMobSpawner;
+import com.irtimaled.bbor.common.models.BoundingBoxStructure;
+import com.irtimaled.bbor.common.models.BoundingBoxVillage;
+import net.minecraft.network.PacketBuffer;
+import net.minecraft.util.math.BlockPos;
+
+import java.awt.*;
+
+public class BoundingBoxSerializer {
+    static void serialize(BoundingBox boundingBox, PacketBuffer buf) {
+        if (boundingBox instanceof BoundingBoxVillage) {
+            serializeVillage((BoundingBoxVillage) boundingBox, buf);
+        }
+        if (boundingBox instanceof BoundingBoxStructure) {
+            serializeStructure((BoundingBoxStructure) boundingBox, buf);
+        }
+        if (boundingBox instanceof BoundingBoxMobSpawner) {
+            serializeMobSpawner((BoundingBoxMobSpawner) boundingBox, buf);
+        }
+    }
+
+    private static void serializeVillage(BoundingBoxVillage boundingBox, PacketBuffer buf) {
+        buf.writeChar('V');
+        serializeBlockPos(boundingBox.getCenter(), buf);
+        buf.writeVarInt(boundingBox.getRadius());
+        buf.writeBoolean(boundingBox.getSpawnsIronGolems());
+        serializeColor(boundingBox.getColor(), buf);
+        for (BlockPos door : boundingBox.getDoors()) {
+            serializeBlockPos(door, buf);
+        }
+    }
+
+    private static void serializeStructure(BoundingBoxStructure boundingBox, PacketBuffer buf) {
+        buf.writeChar('S');
+        serializeCuboid(boundingBox, buf);
+        serializeColor(boundingBox.getColor(), buf);
+    }
+
+    private static void serializeMobSpawner(BoundingBoxMobSpawner boundingBox, PacketBuffer buf) {
+        buf.writeChar('M');
+        serializeBlockPos(boundingBox.getCenter(), buf);
+    }
+
+    private static void serializeColor(Color color, PacketBuffer buf) {
+        buf.writeVarInt(color.getRGB());
+    }
+
+    private static void serializeCuboid(BoundingBox boundingBox, PacketBuffer buf) {
+        serializeBlockPos(boundingBox.getMinBlockPos(), buf);
+        serializeBlockPos(boundingBox.getMaxBlockPos(), buf);
+    }
+
+    private static void serializeBlockPos(BlockPos blockPos, PacketBuffer buf) {
+        buf.writeVarInt(blockPos.getX());
+        buf.writeVarInt(blockPos.getY());
+        buf.writeVarInt(blockPos.getZ());
+    }
+}
diff --git a/src/main/java/com/irtimaled/bbor/common/messages/InitializeClient.java b/src/main/java/com/irtimaled/bbor/common/messages/InitializeClient.java
new file mode 100644 (file)
index 0000000..d580029
--- /dev/null
@@ -0,0 +1,28 @@
+package com.irtimaled.bbor.common.messages;
+
+import com.irtimaled.bbor.client.events.InitializeClientReceived;
+import com.irtimaled.bbor.common.models.WorldData;
+import io.netty.buffer.Unpooled;
+import net.minecraft.network.PacketBuffer;
+import net.minecraft.network.play.server.SPacketCustomPayload;
+import net.minecraft.util.ResourceLocation;
+
+public class InitializeClient {
+    public static final ResourceLocation NAME = new ResourceLocation("bbor:initialize");
+
+    public static SPacketCustomPayload getPayload(WorldData worldData) {
+        PacketBuffer buf = new PacketBuffer(Unpooled.buffer());
+        buf.writeLong(worldData.getSeed());
+        buf.writeInt(worldData.getSpawnX());
+        buf.writeInt(worldData.getSpawnZ());
+
+        return new SPacketCustomPayload(NAME, buf);
+    }
+
+    public static InitializeClientReceived getEvent(PacketBuffer buf) {
+        long seed = buf.readLong();
+        int spawnX = buf.readInt();
+        int spawnZ = buf.readInt();
+        return new InitializeClientReceived(seed, spawnX, spawnZ);
+    }
+}
diff --git a/src/main/java/com/irtimaled/bbor/common/messages/RemoveBoundingBox.java b/src/main/java/com/irtimaled/bbor/common/messages/RemoveBoundingBox.java
new file mode 100644 (file)
index 0000000..1d002fe
--- /dev/null
@@ -0,0 +1,27 @@
+package com.irtimaled.bbor.common.messages;
+
+import com.irtimaled.bbor.client.events.RemoveBoundingBoxReceived;
+import com.irtimaled.bbor.common.models.BoundingBox;
+import io.netty.buffer.Unpooled;
+import net.minecraft.network.PacketBuffer;
+import net.minecraft.network.play.server.SPacketCustomPayload;
+import net.minecraft.util.ResourceLocation;
+import net.minecraft.world.dimension.DimensionType;
+
+public class RemoveBoundingBox {
+    public static final ResourceLocation NAME = new ResourceLocation("bbor:remove_bounding_box");
+
+    public static SPacketCustomPayload getPayload(DimensionType dimensionType, BoundingBox key) {
+        PacketBuffer buf = new PacketBuffer(Unpooled.buffer());
+        buf.writeVarInt(dimensionType.getId());
+        BoundingBoxSerializer.serialize(key, buf);
+
+        return new SPacketCustomPayload(NAME, buf);
+    }
+
+    public static RemoveBoundingBoxReceived getEvent(PacketBuffer buf) {
+        DimensionType dimensionType = DimensionType.getById(buf.readVarInt());
+        BoundingBox key = BoundingBoxDeserializer.deserialize(buf);
+        return new RemoveBoundingBoxReceived(dimensionType, key);
+    }
+}
diff --git a/src/main/java/com/irtimaled/bbor/common/messages/SubscribeToServer.java b/src/main/java/com/irtimaled/bbor/common/messages/SubscribeToServer.java
new file mode 100644 (file)
index 0000000..09a4dfd
--- /dev/null
@@ -0,0 +1,14 @@
+package com.irtimaled.bbor.common.messages;
+
+import io.netty.buffer.Unpooled;
+import net.minecraft.network.PacketBuffer;
+import net.minecraft.network.play.client.CPacketCustomPayload;
+import net.minecraft.util.ResourceLocation;
+
+public class SubscribeToServer {
+    public static final ResourceLocation NAME = new ResourceLocation("bbor:subscribe");
+
+    public static CPacketCustomPayload getPayload() {
+        return new CPacketCustomPayload(NAME, new PacketBuffer(Unpooled.buffer()));
+    }
+}
diff --git a/src/main/java/com/irtimaled/bbor/mixin/entity/player/MixinEntityPlayerMP.java b/src/main/java/com/irtimaled/bbor/mixin/entity/player/MixinEntityPlayerMP.java
new file mode 100644 (file)
index 0000000..abe6ff2
--- /dev/null
@@ -0,0 +1,18 @@
+package com.irtimaled.bbor.mixin.entity.player;
+
+import com.irtimaled.bbor.common.EventBus;
+import com.irtimaled.bbor.common.events.PlayerChangedDimension;
+import net.minecraft.entity.Entity;
+import net.minecraft.entity.player.EntityPlayerMP;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+
+@Mixin(EntityPlayerMP.class)
+public class MixinEntityPlayerMP {
+    @Inject(method = "changeDimension", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/management/PlayerList;changePlayerDimension(Lnet/minecraft/entity/player/EntityPlayerMP;I)V"))
+    private void changeDimension(int dimensionId, CallbackInfoReturnable<Entity> cir) {
+        EventBus.publish(new PlayerChangedDimension((EntityPlayerMP) (Object) this));
+    }
+}
diff --git a/src/main/java/com/irtimaled/bbor/mixin/network/play/client/MixinCPacketCustomPayload.java b/src/main/java/com/irtimaled/bbor/mixin/network/play/client/MixinCPacketCustomPayload.java
new file mode 100644 (file)
index 0000000..c95369f
--- /dev/null
@@ -0,0 +1,30 @@
+package com.irtimaled.bbor.mixin.network.play.client;
+
+import com.irtimaled.bbor.common.EventBus;
+import com.irtimaled.bbor.common.events.PlayerSubscribed;
+import com.irtimaled.bbor.common.messages.SubscribeToServer;
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.network.NetHandlerPlayServer;
+import net.minecraft.network.play.INetHandlerPlayServer;
+import net.minecraft.network.play.client.CPacketCustomPayload;
+import net.minecraft.util.ResourceLocation;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Redirect;
+
+@Mixin(CPacketCustomPayload.class)
+public class MixinCPacketCustomPayload {
+    @Shadow
+    private ResourceLocation channel;
+
+    @Redirect(method = "processPacket", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/play/INetHandlerPlayServer;processCustomPayload(Lnet/minecraft/network/play/client/CPacketCustomPayload;)V"))
+    private void processPacket(INetHandlerPlayServer netHandlerPlayServer, CPacketCustomPayload packet) {
+        if (this.channel.equals(SubscribeToServer.NAME)) {
+            EntityPlayerMP player = ((NetHandlerPlayServer) netHandlerPlayServer).player;
+            EventBus.publish(new PlayerSubscribed(player));
+        } else {
+            netHandlerPlayServer.processCustomPayload(packet);
+        }
+    }
+}
diff --git a/src/main/java/com/irtimaled/bbor/mixin/network/play/server/MixinSPacketCustomPayload.java b/src/main/java/com/irtimaled/bbor/mixin/network/play/server/MixinSPacketCustomPayload.java
new file mode 100644 (file)
index 0000000..360f2b5
--- /dev/null
@@ -0,0 +1,43 @@
+package com.irtimaled.bbor.mixin.network.play.server;
+
+import com.irtimaled.bbor.common.EventBus;
+import com.irtimaled.bbor.common.messages.AddBoundingBox;
+import com.irtimaled.bbor.common.messages.InitializeClient;
+import com.irtimaled.bbor.common.messages.RemoveBoundingBox;
+import com.irtimaled.bbor.common.messages.SubscribeToServer;
+import net.minecraft.client.network.NetHandlerPlayClient;
+import net.minecraft.network.PacketBuffer;
+import net.minecraft.network.play.INetHandlerPlayClient;
+import net.minecraft.network.play.server.SPacketCustomPayload;
+import net.minecraft.util.ResourceLocation;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Redirect;
+
+@Mixin(SPacketCustomPayload.class)
+public abstract class MixinSPacketCustomPayload {
+    @Shadow
+    private ResourceLocation channel;
+
+    @Redirect(method = "processPacket", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/play/INetHandlerPlayClient;handleCustomPayload(Lnet/minecraft/network/play/server/SPacketCustomPayload;)V"))
+    private void processPacket(INetHandlerPlayClient netHandlerPlayClient, SPacketCustomPayload packet) {
+        PacketBuffer data = null;
+        try {
+            data = packet.getBufferData();
+            if (InitializeClient.NAME.equals(channel)) {
+                EventBus.publish(InitializeClient.getEvent(data));
+                ((NetHandlerPlayClient) netHandlerPlayClient).sendPacket(SubscribeToServer.getPayload());
+            } else if (AddBoundingBox.NAME.equals(channel)) {
+                EventBus.publish(AddBoundingBox.getEvent(data));
+            } else if (RemoveBoundingBox.NAME.equals(channel)) {
+                EventBus.publish(RemoveBoundingBox.getEvent(data));
+            } else {
+                netHandlerPlayClient.handleCustomPayload(packet);
+            }
+        } finally {
+            if (data != null)
+                data.release();
+        }
+    }
+}
index c325468d45978124a9abeb362edeaec193fdfd1d..0e78d2159b32c98f4f346218b263bcb77d82473a 100644 (file)
@@ -1,6 +1,7 @@
 package com.irtimaled.bbor.mixin.server;
 
 import com.irtimaled.bbor.common.EventBus;
+import com.irtimaled.bbor.common.events.Tick;
 import com.irtimaled.bbor.common.events.WorldLoaded;
 import net.minecraft.server.MinecraftServer;
 import net.minecraft.world.World;
@@ -22,4 +23,9 @@ public class MixinMinecraftServer {
             EventBus.publish(new WorldLoaded(world));
         }
     }
+
+    @Inject(method = "tick", at = @At("RETURN"))
+    private void tick(CallbackInfo ci) {
+        EventBus.publish(new Tick());
+    }
 }
diff --git a/src/main/java/com/irtimaled/bbor/mixin/server/dedicated/MixinDedicatedServer.java b/src/main/java/com/irtimaled/bbor/mixin/server/dedicated/MixinDedicatedServer.java
new file mode 100644 (file)
index 0000000..4216033
--- /dev/null
@@ -0,0 +1,21 @@
+package com.irtimaled.bbor.mixin.server.dedicated;
+
+import com.irtimaled.bbor.common.CommonProxy;
+import com.irtimaled.bbor.config.ConfigManager;
+import net.minecraft.server.dedicated.DedicatedServer;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+
+import java.io.File;
+
+@Mixin(DedicatedServer.class)
+public class MixinDedicatedServer {
+    @Inject(method = "init", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/dedicated/DedicatedServer;loadAllWorlds(Ljava/lang/String;Ljava/lang/String;JLnet/minecraft/world/WorldType;Lcom/google/gson/JsonElement;)V"))
+    private void init(CallbackInfoReturnable<Boolean> cir) {
+        File gameDir = ((DedicatedServer) (Object) this).getDataDirectory();
+        ConfigManager.loadConfig(gameDir);
+        new CommonProxy().init();
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/irtimaled/bbor/mixin/server/management/MixinPlayerList.java b/src/main/java/com/irtimaled/bbor/mixin/server/management/MixinPlayerList.java
new file mode 100644 (file)
index 0000000..26f7f0c
--- /dev/null
@@ -0,0 +1,28 @@
+package com.irtimaled.bbor.mixin.server.management;
+
+import com.irtimaled.bbor.common.EventBus;
+import com.irtimaled.bbor.common.events.PlayerLoggedIn;
+import com.irtimaled.bbor.common.events.PlayerLoggedOut;
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.server.management.PlayerList;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+@Mixin(PlayerList.class)
+public class MixinPlayerList {
+    @Inject(method = "playerLoggedIn", at = @At("RETURN"))
+    private void playerLoggedIn(EntityPlayerMP player, CallbackInfo ci) {
+        if (player.world.isRemote) {
+            EventBus.publish(new PlayerLoggedIn(player));
+        }
+    }
+
+    @Inject(method = "playerLoggedOut", at = @At("HEAD"))
+    private void playerLoggedOut(EntityPlayerMP player, CallbackInfo ci) {
+        if (player.world.isRemote) {
+            EventBus.publish(new PlayerLoggedOut(player));
+        }
+    }
+}
index 6b2b68ae98257239228e85dee631051275a4b4cb..301fda97aa318c7e8d921fa4eec1c93e52d3c5b2 100644 (file)
@@ -7,6 +7,10 @@
   "refmap": "mixins.bbor.refmap.json",
   "mixins": [
     "world.chunk.MixinChunk",
+    "network.play.client.MixinCPacketCustomPayload",
+    "network.play.server.MixinSPacketCustomPayload",
+    "entity.player.MixinEntityPlayerMP",
+    "server.management.MixinPlayerList",
     "server.management.MixinPlayerInteractionManager",
     "server.MixinMinecraftServer"
   ],
@@ -17,5 +21,8 @@
     "client.network.MixinNetHandlerLoginClient",
     "client.settings.MixinKeyBinding",
     "client.settings.MixinGameSettings"
+  ],
+  "server": [
+    "server.dedicated.MixinDedicatedServer"
   ]
 }