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