1 package com.irtimaled.bbor;
3 import com.irtimaled.bbor.messages.*;
4 import net.minecraft.entity.player.EntityPlayer;
5 import net.minecraft.entity.player.EntityPlayerMP;
6 import net.minecraft.server.MinecraftServer;
7 import net.minecraft.world.chunk.IChunkProvider;
8 import net.minecraft.world.gen.ChunkProviderServer;
9 import net.minecraftforge.event.world.ChunkEvent;
10 import net.minecraftforge.event.world.WorldEvent;
11 import net.minecraftforge.fml.common.FMLLog;
12 import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
13 import net.minecraftforge.fml.common.gameevent.PlayerEvent;
14 import net.minecraftforge.fml.common.gameevent.TickEvent;
15 import net.minecraftforge.fml.common.network.NetworkRegistry;
16 import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper;
17 import net.minecraftforge.fml.relauncher.Side;
19 import java.util.HashMap;
20 import java.util.HashSet;
23 import java.util.concurrent.ConcurrentHashMap;
25 public class CommonProxy {
27 public Map<Integer, BoundingBoxCache> boundingBoxCacheMap = new ConcurrentHashMap<Integer, BoundingBoxCache>();
28 public Map<EntityPlayerMP, Integer> playerDimensions = new ConcurrentHashMap<EntityPlayerMP, Integer>();
29 private Map<EntityPlayerMP, Set<BoundingBox>> playerBoundingBoxesCache = new HashMap<EntityPlayerMP, Set<BoundingBox>>();
31 public ConfigManager configManager;
32 protected SimpleNetworkWrapper network;
36 protected boolean initialized;
39 network = NetworkRegistry.INSTANCE.newSimpleChannel("bbor");
40 network.registerMessage(AddBoundingBoxMessageHandler.class, AddBoundingBoxMessage.class, 0, Side.CLIENT);
41 network.registerMessage(RemoveBoundingBoxMessageHandler.class, RemoveBoundingBoxMessage.class, 1, Side.CLIENT);
42 network.registerMessage(InitializeClientMessageHandler.class, InitializeClientMessage.class, 2, Side.CLIENT);
46 public void worldEvent(WorldEvent.Load event) {
47 IChunkProvider chunkProvider = event.world.getChunkProvider();
48 if (chunkProvider instanceof ChunkProviderServer) {
49 chunkProvider = ((ChunkProviderServer) chunkProvider).serverChunkGenerator;
50 setWorldData(event.world.getSeed(), event.world.getWorldInfo().getSpawnX(), event.world.getWorldInfo().getSpawnZ());
51 int dimensionId = event.world.provider.getDimensionId();
52 FMLLog.info("create world dimension: %d, %s (chunkprovider: %s) (seed: %d)", dimensionId, event.world.getClass().toString(), chunkProvider.getClass().toString(), seed);
53 boundingBoxCacheMap.put(dimensionId, new DimensionProcessor(configManager, event.world, dimensionId, chunkProvider));
58 public void chunkEvent(ChunkEvent.Load event) {
59 int dimensionId = event.world.provider.getDimensionId();
60 if (boundingBoxCacheMap.containsKey(dimensionId)) {
61 boundingBoxCacheMap.get(dimensionId).refresh();
66 public void playerChangedDimensionEvent(PlayerEvent.PlayerChangedDimensionEvent evt) {
67 if (playerDimensions.containsKey(evt.player)) {
68 EntityPlayerMP player = (EntityPlayerMP) evt.player;
69 int dimension = player.dimension;
70 playerDimensions.put(player, dimension);
72 sendToPlayer(player, boundingBoxCacheMap.get(dimension));
76 protected boolean isRemotePlayer(EntityPlayer player) {
81 public void playerLoggedInEvent(PlayerEvent.PlayerLoggedInEvent evt) {
82 if (evt.player instanceof EntityPlayerMP &&
83 isRemotePlayer(evt.player)) {
84 EntityPlayerMP player = (EntityPlayerMP) evt.player;
85 initializeClient(player);
86 int dimension = player.dimension;
87 playerDimensions.put(player, dimension);
88 sendToPlayer(player, boundingBoxCacheMap.get(dimension));
93 public void playerLoggedOutEvent(PlayerEvent.PlayerLoggedOutEvent evt) {
94 if (playerDimensions.containsKey(evt.player)) {
95 playerDimensions.remove(evt.player);
96 playerBoundingBoxesCache.remove(evt.player);
101 public void tickEvent(TickEvent event) {
102 for (EntityPlayerMP player : playerDimensions.keySet()) {
104 MinecraftServer mc = MinecraftServer.getServer();
105 if (!mc.getConfigurationManager().playerEntityList.contains(player)) {
106 playerDimensions.remove(player);
108 int dimension = playerDimensions.get(player);
109 if (boundingBoxCacheMap.containsKey(dimension)) {
110 sendToPlayer(player, boundingBoxCacheMap.get(dimension));
116 private void initializeClient(EntityPlayerMP player) {
117 network.sendTo(InitializeClientMessage.from(seed, spawnX, spawnZ), player);
120 private void sendToPlayer(EntityPlayerMP player, BoundingBoxCache boundingBoxCache) {
121 Map<BoundingBox, Set<BoundingBox>> cacheSubset = getBoundingBoxMap(player, boundingBoxCache.getBoundingBoxes());
123 int dimension = player.dimension;
124 if (cacheSubset.keySet().size() > 0) {
125 FMLLog.info("send %d entries to %s (%d)", cacheSubset.keySet().size(), player.getDisplayNameString(), dimension);
128 for (BoundingBox key : cacheSubset.keySet()) {
129 Set<BoundingBox> boundingBoxes = cacheSubset.get(key);
130 network.sendTo(AddBoundingBoxMessage.from(dimension, key, boundingBoxes), player);
132 if (!playerBoundingBoxesCache.containsKey(player)) {
133 playerBoundingBoxesCache.put(player, new HashSet<BoundingBox>());
135 playerBoundingBoxesCache.get(player).add(key);
139 private Map<BoundingBox, Set<BoundingBox>> getBoundingBoxMap(EntityPlayerMP player, Map<BoundingBox, Set<BoundingBox>> boundingBoxMap) {
140 Map<BoundingBox, Set<BoundingBox>> cacheSubset = new HashMap<BoundingBox, Set<BoundingBox>>();
141 for (BoundingBox key : boundingBoxMap.keySet()) {
142 if (!playerBoundingBoxesCache.containsKey(player) || !playerBoundingBoxesCache.get(player).contains(key)) {
143 cacheSubset.put(key, boundingBoxMap.get(key));
149 public void boundingBoxRemoved(BoundingBox bb) {
150 // the only bounding boxes that can change are spawn or villages - both of these are in overworld so I guess
151 // hard coding dimension 0 is okay.
152 RemoveBoundingBoxMessage message = RemoveBoundingBoxMessage.from(0, bb);
153 for (EntityPlayerMP player : playerDimensions.keySet()) {
154 if (player.dimension == 0) {
155 FMLLog.info("remove 1 entry from %s (0)", player.getDisplayNameString());
156 network.sendTo(message, player);
158 if (playerBoundingBoxesCache.containsKey(player) &&
159 playerBoundingBoxesCache.get(player).contains(bb)) {
160 playerBoundingBoxesCache.get(player).remove(bb);
166 public void setWorldData(long seed, int spawnX, int spawnZ) {
168 this.spawnX = spawnX;
169 this.spawnZ = spawnZ;
170 this.initialized = true;
173 public void setWorldData(IWorldData worldData) {
174 setWorldData(worldData.getSeed(), worldData.getSpawnX(), worldData.getSpawnZ());