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