]> git.lizzy.rs Git - BoundingBoxOutlineReloaded.git/blob - src/main/java/com/irtimaled/bbor/common/CommonProxy.java
683bc77647c9b8acaad45d2592717117f9dd9c91
[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.PlayerLoggedIn;
5 import com.irtimaled.bbor.common.events.PlayerLoggedOut;
6 import com.irtimaled.bbor.common.events.PlayerSubscribed;
7 import com.irtimaled.bbor.common.events.ServerTick;
8 import com.irtimaled.bbor.common.events.StructuresLoaded;
9 import com.irtimaled.bbor.common.events.WorldLoaded;
10 import com.irtimaled.bbor.common.messages.AddBoundingBox;
11 import com.irtimaled.bbor.common.messages.InitializeClient;
12 import com.irtimaled.bbor.common.messages.PayloadBuilder;
13 import com.irtimaled.bbor.common.models.AbstractBoundingBox;
14 import com.irtimaled.bbor.common.models.DimensionId;
15 import com.irtimaled.bbor.common.models.ServerPlayer;
16
17 import java.util.HashMap;
18 import java.util.HashSet;
19 import java.util.Map;
20 import java.util.Set;
21 import java.util.concurrent.ConcurrentHashMap;
22
23 public class CommonProxy {
24     private final Map<Integer, ServerPlayer> players = new ConcurrentHashMap<>();
25     private final Map<Integer, Set<AbstractBoundingBox>> playerBoundingBoxesCache = new HashMap<>();
26     private final Map<DimensionId, StructureProcessor> structureProcessors = new HashMap<>();
27     private final Map<DimensionId, BoundingBoxCache> dimensionCache = new ConcurrentHashMap<>();
28     private Long seed = null;
29     private Integer spawnX = null;
30     private Integer spawnZ = null;
31
32     public void init() {
33         BoundingBoxType.registerTypes();
34         EventBus.subscribe(WorldLoaded.class, this::worldLoaded);
35         EventBus.subscribe(StructuresLoaded.class, this::structuresLoaded);
36         EventBus.subscribe(PlayerLoggedIn.class, this::playerLoggedIn);
37         EventBus.subscribe(PlayerLoggedOut.class, this::playerLoggedOut);
38         EventBus.subscribe(PlayerSubscribed.class, this::onPlayerSubscribed);
39         EventBus.subscribe(ServerTick.class, e -> serverTick());
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         DimensionId dimensionId = event.getDimensionId();
53         long seed = event.getSeed();
54         if (dimensionId == DimensionId.OVERWORLD) {
55             setSeed(seed);
56             setWorldSpawn(event.getSpawnX(), event.getSpawnZ());
57         }
58         Logger.info("create world dimension: %s (seed: %d)", dimensionId, seed);
59     }
60
61     private void structuresLoaded(StructuresLoaded event) {
62         DimensionId dimensionId = event.getDimensionId();
63         StructureProcessor structureProcessor = getStructureProcessor(dimensionId);
64         structureProcessor.process(event.getStructures());
65     }
66
67     private StructureProcessor getStructureProcessor(DimensionId dimensionId) {
68         StructureProcessor structureProcessor = structureProcessors.get(dimensionId);
69         if (structureProcessor == null) {
70             structureProcessor = new StructureProcessor(getOrCreateCache(dimensionId));
71             structureProcessors.put(dimensionId, structureProcessor);
72         }
73         return structureProcessor;
74     }
75
76     private void playerLoggedIn(PlayerLoggedIn event) {
77         if (seed == null || spawnX == null || spawnZ == null) {
78             return;
79         }
80         ServerPlayer player = event.getPlayer();
81         player.sendPacket(InitializeClient.getPayload(seed, spawnX, spawnZ));
82     }
83
84     private void playerLoggedOut(PlayerLoggedOut event) {
85         int playerId = event.getPlayerId();
86         players.remove(playerId);
87         playerBoundingBoxesCache.remove(playerId);
88     }
89
90     private void onPlayerSubscribed(PlayerSubscribed event) {
91         int playerId = event.getPlayerId();
92         ServerPlayer player = event.getPlayer();
93         players.put(playerId, player);
94         sendToPlayer(playerId, player);
95     }
96
97     private void sendToPlayer(int playerId, ServerPlayer player) {
98         for (Map.Entry<DimensionId, BoundingBoxCache> entry : dimensionCache.entrySet()) {
99             DimensionId dimensionId = entry.getKey();
100             BoundingBoxCache boundingBoxCache = entry.getValue();
101             if (boundingBoxCache == null) return;
102
103             Set<AbstractBoundingBox> playerBoundingBoxes = playerBoundingBoxesCache.computeIfAbsent(playerId, k -> new HashSet<>());
104
105             Map<AbstractBoundingBox, Set<AbstractBoundingBox>> boundingBoxMap = boundingBoxCache.getBoundingBoxes();
106             for (AbstractBoundingBox key : boundingBoxMap.keySet()) {
107                 if (playerBoundingBoxes.contains(key)) {
108                     continue;
109                 }
110
111                 Set<AbstractBoundingBox> boundingBoxes = boundingBoxMap.get(key);
112                 PayloadBuilder payload = AddBoundingBox.getPayload(dimensionId, key, boundingBoxes);
113                 if (payload != null)
114                     player.sendPacket(payload);
115
116                 playerBoundingBoxes.add(key);
117             }
118         }
119     }
120
121     private void serverTick() {
122         for (Map.Entry<Integer, ServerPlayer> playerEntry : players.entrySet()) {
123             int playerId = playerEntry.getKey();
124             ServerPlayer player = playerEntry.getValue();
125
126             sendToPlayer(playerId, player);
127         }
128     }
129
130     protected BoundingBoxCache getCache(DimensionId dimensionId) {
131         return dimensionCache.get(dimensionId);
132     }
133
134     protected BoundingBoxCache getOrCreateCache(DimensionId dimensionId) {
135         return dimensionCache.computeIfAbsent(dimensionId, dt -> new BoundingBoxCache());
136     }
137
138     protected void clearCaches() {
139         structureProcessors.clear();
140         for (BoundingBoxCache cache : dimensionCache.values()) {
141             cache.clear();
142         }
143         dimensionCache.clear();
144     }
145 }