]> git.lizzy.rs Git - BoundingBoxOutlineReloaded.git/blob - src/main/java/com/irtimaled/bbor/common/CommonProxy.java
Switch back to old village processors
[BoundingBoxOutlineReloaded.git] / src / main / java / com / irtimaled / bbor / common / CommonProxy.java
1 package com.irtimaled.bbor.common;
2
3 import com.irtimaled.bbor.Logger;
4 import com.irtimaled.bbor.common.chunkProcessors.ChunkProcessor;
5 import com.irtimaled.bbor.common.chunkProcessors.EndChunkProcessor;
6 import com.irtimaled.bbor.common.chunkProcessors.NetherChunkProcessor;
7 import com.irtimaled.bbor.common.chunkProcessors.OverworldChunkProcessor;
8 import com.irtimaled.bbor.common.events.*;
9 import com.irtimaled.bbor.common.messages.AddBoundingBox;
10 import com.irtimaled.bbor.common.messages.InitializeClient;
11 import com.irtimaled.bbor.common.messages.RemoveBoundingBox;
12 import com.irtimaled.bbor.common.models.BoundingBox;
13 import com.irtimaled.bbor.common.models.BoundingBoxMobSpawner;
14 import com.irtimaled.bbor.common.models.WorldData;
15 import io.netty.channel.local.LocalAddress;
16 import net.minecraft.entity.player.EntityPlayerMP;
17 import net.minecraft.network.play.server.SPacketCustomPayload;
18 import net.minecraft.util.math.BlockPos;
19 import net.minecraft.village.VillageCollection;
20 import net.minecraft.world.World;
21 import net.minecraft.world.WorldServer;
22 import net.minecraft.world.chunk.Chunk;
23 import net.minecraft.world.chunk.IChunkProvider;
24 import net.minecraft.world.dimension.DimensionType;
25 import net.minecraft.world.gen.ChunkProviderServer;
26
27 import java.util.HashMap;
28 import java.util.HashSet;
29 import java.util.Map;
30 import java.util.Set;
31 import java.util.concurrent.ConcurrentHashMap;
32 import java.util.function.Consumer;
33
34 public class CommonProxy {
35     private Set<EntityPlayerMP> players = new HashSet<>();
36     private Map<EntityPlayerMP, Set<BoundingBox>> playerBoundingBoxesCache = new HashMap<>();
37     private Map<DimensionType, VillageProcessor> villageProcessors = new HashMap<>();
38     private Map<DimensionType, ChunkProcessor> chunkProcessors = new HashMap<>();
39     private WorldData worldData = null;
40     private final Map<DimensionType, BoundingBoxCache> dimensionCache = new ConcurrentHashMap<>();
41
42     public void init() {
43         EventBus.subscribe(WorldLoaded.class, e -> worldLoaded(e.getWorld()));
44         EventBus.subscribe(ChunkLoaded.class, e -> chunkLoaded(e.getChunk()));
45         EventBus.subscribe(MobSpawnerBroken.class, e -> mobSpawnerBroken(e.getDimensionType(), e.getPos()));
46         EventBus.subscribe(PlayerLoggedIn.class, e -> playerLoggedIn(e.getPlayer()));
47         EventBus.subscribe(PlayerLoggedOut.class, e -> playerLoggedOut(e.getPlayer()));
48         EventBus.subscribe(PlayerSubscribed.class, e -> sendBoundingBoxes(e.getPlayer()));
49         EventBus.subscribe(ServerWorldTick.class, e -> serverWorldTick(e.getWorld()));
50         EventBus.subscribe(ServerTick.class, e -> serverTick());
51         EventBus.subscribe(VillageRemoved.class, e -> sendRemoveBoundingBox(e.getDimensionType(), e.getVillage()));
52     }
53
54     protected void setWorldData(long seed, int spawnX, int spawnZ) {
55         worldData = new WorldData(seed, spawnX, spawnZ);
56     }
57
58     private void worldLoaded(World world) {
59         IChunkProvider chunkProvider = world.getChunkProvider();
60         if (chunkProvider instanceof ChunkProviderServer) {
61             DimensionType dimensionType = world.dimension.getType();
62             BoundingBoxCache boundingBoxCache = getOrCreateCache(dimensionType);
63             ChunkProcessor chunkProcessor = null;
64             if (dimensionType == DimensionType.OVERWORLD) {
65                 setWorldData(world.getSeed(), world.getWorldInfo().getSpawnX(), world.getWorldInfo().getSpawnZ());
66                 chunkProcessor = new OverworldChunkProcessor(boundingBoxCache);
67             }
68             if (dimensionType == DimensionType.NETHER) {
69                 chunkProcessor = new NetherChunkProcessor(boundingBoxCache);
70             }
71             if (dimensionType == DimensionType.THE_END) {
72                 chunkProcessor = new EndChunkProcessor(boundingBoxCache);
73             }
74             Logger.info("create world dimension: %s, %s (seed: %d)", dimensionType, world.getClass().toString(), world.getSeed());
75             chunkProcessors.put(dimensionType, chunkProcessor);
76             villageProcessors.put(dimensionType, new VillageProcessor(dimensionType, boundingBoxCache));
77         }
78     }
79
80     private void chunkLoaded(Chunk chunk) {
81         DimensionType dimensionType = chunk.getWorld().dimension.getType();
82         ChunkProcessor chunkProcessor = chunkProcessors.get(dimensionType);
83         if (chunkProcessor != null) {
84             chunkProcessor.process(chunk);
85         }
86     }
87
88     private void playerLoggedIn(EntityPlayerMP player) {
89         if (player.connection.netManager.getRemoteAddress() instanceof LocalAddress) return;
90         player.connection.sendPacket(InitializeClient.getPayload(worldData));
91     }
92
93     private void playerLoggedOut(EntityPlayerMP player) {
94         players.remove(player);
95         playerBoundingBoxesCache.remove(player);
96     }
97
98     private void sendRemoveBoundingBox(DimensionType dimensionType, BoundingBox boundingBox) {
99         SPacketCustomPayload payload = RemoveBoundingBox.getPayload(dimensionType, boundingBox);
100         if (payload == null) return;
101
102         for (EntityPlayerMP player : players) {
103             if (DimensionType.getById(player.dimension) == dimensionType) {
104                 player.connection.sendPacket(payload);
105
106                 if (playerBoundingBoxesCache.containsKey(player)) {
107                     playerBoundingBoxesCache.get(player).remove(boundingBox);
108                 }
109             }
110         }
111     }
112
113     private void sendBoundingBoxes(EntityPlayerMP player) {
114         DimensionType dimensionType = DimensionType.getById(player.dimension);
115         players.add(player);
116         sendToPlayer(player, getCache(dimensionType));
117     }
118
119     private void sendToPlayer(EntityPlayerMP player, BoundingBoxCache boundingBoxCache) {
120         if (boundingBoxCache == null) return;
121
122         Map<BoundingBox, Set<BoundingBox>> cacheSubset = getBoundingBoxMap(player, boundingBoxCache.getBoundingBoxes());
123
124         DimensionType dimensionType = DimensionType.getById(player.dimension);
125
126         for (BoundingBox key : cacheSubset.keySet()) {
127             Set<BoundingBox> boundingBoxes = cacheSubset.get(key);
128             SPacketCustomPayload payload = AddBoundingBox.getPayload(dimensionType, key, boundingBoxes);
129             if (payload != null)
130                 player.connection.sendPacket(payload);
131
132             if (!playerBoundingBoxesCache.containsKey(player)) {
133                 playerBoundingBoxesCache.put(player, new HashSet<>());
134             }
135             playerBoundingBoxesCache.get(player).add(key);
136         }
137     }
138
139     private Map<BoundingBox, Set<BoundingBox>> getBoundingBoxMap(EntityPlayerMP player, Map<BoundingBox, Set<BoundingBox>> boundingBoxMap) {
140         Map<BoundingBox, Set<BoundingBox>> cacheSubset = new HashMap<>();
141         for (BoundingBox key : boundingBoxMap.keySet()) {
142             if (!playerBoundingBoxesCache.containsKey(player) || !playerBoundingBoxesCache.get(player).contains(key)) {
143                 cacheSubset.put(key, boundingBoxMap.get(key));
144             }
145         }
146         return cacheSubset;
147     }
148
149     protected void removeBoundingBox(DimensionType dimensionType, BoundingBox key) {
150         BoundingBoxCache cache = getCache(dimensionType);
151         if (cache == null) return;
152
153         cache.removeBoundingBox(key);
154     }
155
156     private void mobSpawnerBroken(DimensionType dimensionType, BlockPos pos) {
157         BoundingBox boundingBox = BoundingBoxMobSpawner.from(pos);
158         removeBoundingBox(dimensionType, boundingBox);
159         sendRemoveBoundingBox(dimensionType, boundingBox);
160     }
161
162     private void serverTick() {
163         for (EntityPlayerMP player : players) {
164             DimensionType dimensionType = DimensionType.getById(player.dimension);
165             sendToPlayer(player, getCache(dimensionType));
166         }
167     }
168
169     private void serverWorldTick(WorldServer world) {
170         DimensionType dimensionType = world.dimension.getType();
171         VillageProcessor villageProcessor = villageProcessors.get(dimensionType);
172         if(villageProcessor == null) return;
173
174         villageProcessor.process(world.getVillageCollection());
175     }
176
177     protected BoundingBoxCache getCache(DimensionType dimensionType) {
178         return dimensionCache.get(dimensionType);
179     }
180
181     protected BoundingBoxCache getOrCreateCache(DimensionType dimensionType) {
182         return dimensionCache.computeIfAbsent(dimensionType, dt -> new BoundingBoxCache());
183     }
184
185     protected void runOnCache(DimensionType dimensionType, Consumer<BoundingBoxCache> action) {
186         action.accept(getOrCreateCache(dimensionType));
187     }
188
189     protected void clearCaches() {
190         for(VillageProcessor villageProcessor : villageProcessors.values()) {
191             villageProcessor.clear();
192         }
193         villageProcessors.clear();
194         for (BoundingBoxCache cache : dimensionCache.values()) {
195             cache.clear();
196         }
197         dimensionCache.clear();
198     }
199 }