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