]> git.lizzy.rs Git - BoundingBoxOutlineReloaded.git/blob - src/main/java/com/irtimaled/bbor/common/CommonProxy.java
Rework config ready for gui
[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.BoundingBoxVillage;
15 import com.irtimaled.bbor.common.models.WorldData;
16 import com.irtimaled.bbor.config.ConfigManager;
17 import net.minecraft.entity.player.EntityPlayerMP;
18 import net.minecraft.network.play.server.SPacketCustomPayload;
19 import net.minecraft.util.math.BlockPos;
20 import net.minecraft.village.Village;
21 import net.minecraft.world.World;
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 Map<EntityPlayerMP, DimensionType> playerDimensions = new ConcurrentHashMap<>();
36     private Map<EntityPlayerMP, Set<BoundingBox>> playerBoundingBoxesCache = new HashMap<>();
37     private Map<Integer, BoundingBoxVillage> villageCache = 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(PlayerChangedDimension.class, e -> playerChangedDimension(e.getPlayer()));
47         EventBus.subscribe(PlayerLoggedIn.class, e -> playerLoggedIn(e.getPlayer()));
48         EventBus.subscribe(PlayerLoggedOut.class, e -> playerLoggedOut(e.getPlayer()));
49         EventBus.subscribe(PlayerSubscribed.class, e -> sendBoundingBoxes(e.getPlayer()));
50         EventBus.subscribe(Tick.class, e -> tick());
51         if (ConfigManager.drawVillages.get()) {
52             EventBus.subscribe(VillageUpdated.class, e -> villageUpdated(e.getDimensionType(), e.getVillage()));
53         }
54     }
55
56     protected void setWorldData(long seed, int spawnX, int spawnZ) {
57         worldData = new WorldData(seed, spawnX, spawnZ);
58     }
59
60     private void worldLoaded(World world) {
61         IChunkProvider chunkProvider = world.getChunkProvider();
62         if (chunkProvider instanceof ChunkProviderServer) {
63             DimensionType dimensionType = world.dimension.getType();
64             BoundingBoxCache boundingBoxCache = getOrCreateCache(dimensionType);
65             ChunkProcessor chunkProcessor = null;
66             if (dimensionType == DimensionType.OVERWORLD) {
67                 setWorldData(world.getSeed(), world.getWorldInfo().getSpawnX(), world.getWorldInfo().getSpawnZ());
68                 chunkProcessor = new OverworldChunkProcessor(boundingBoxCache, world.getSeed());
69             }
70             if (dimensionType == DimensionType.NETHER) {
71                 chunkProcessor = new NetherChunkProcessor(boundingBoxCache);
72             }
73             if (dimensionType == DimensionType.THE_END) {
74                 chunkProcessor = new EndChunkProcessor(boundingBoxCache);
75             }
76             Logger.info("create world dimension: %s, %s (seed: %d)", dimensionType, world.getClass().toString(), world.getSeed());
77             chunkProcessors.put(dimensionType, chunkProcessor);
78         }
79     }
80
81     private void chunkLoaded(Chunk chunk) {
82         DimensionType dimensionType = chunk.getWorld().dimension.getType();
83         ChunkProcessor chunkProcessor = chunkProcessors.get(dimensionType);
84         if (chunkProcessor != null) {
85             chunkProcessor.process(chunk);
86         }
87     }
88
89     private void playerChangedDimension(EntityPlayerMP player) {
90         if (playerDimensions.containsKey(player)) {
91             sendBoundingBoxes(player);
92         }
93     }
94
95     private void playerLoggedIn(EntityPlayerMP player) {
96         player.connection.sendPacket(InitializeClient.getPayload(worldData));
97     }
98
99     private void playerLoggedOut(EntityPlayerMP player) {
100         playerDimensions.remove(player);
101         playerBoundingBoxesCache.remove(player);
102     }
103
104     private void sendRemoveBoundingBox(DimensionType dimensionType, BoundingBox boundingBox) {
105         SPacketCustomPayload payload = RemoveBoundingBox.getPayload(dimensionType, boundingBox);
106         for (EntityPlayerMP player : playerDimensions.keySet()) {
107             if (DimensionType.getById(player.dimension) == dimensionType) {
108                 Logger.info("remove 1 entry from %s (%s)", player.getScoreboardName(), dimensionType);
109                 player.connection.sendPacket(payload);
110
111                 if (playerBoundingBoxesCache.containsKey(player)) {
112                     playerBoundingBoxesCache.get(player).remove(boundingBox);
113                 }
114             }
115         }
116     }
117
118     private void sendBoundingBoxes(EntityPlayerMP player) {
119         DimensionType dimensionType = DimensionType.getById(player.dimension);
120         playerDimensions.put(player, dimensionType);
121         sendToPlayer(player, getCache(dimensionType));
122     }
123
124     private void sendToPlayer(EntityPlayerMP player, BoundingBoxCache boundingBoxCache) {
125         if (boundingBoxCache == null) return;
126
127         Map<BoundingBox, Set<BoundingBox>> cacheSubset = getBoundingBoxMap(player, boundingBoxCache.getBoundingBoxes());
128
129         DimensionType dimensionType = DimensionType.getById(player.dimension);
130         if (cacheSubset.keySet().size() > 0) {
131             Logger.info("send %d entries to %s (%s)", cacheSubset.keySet().size(), player.getScoreboardName(), dimensionType);
132         }
133
134         for (BoundingBox key : cacheSubset.keySet()) {
135             Set<BoundingBox> boundingBoxes = cacheSubset.get(key);
136             player.connection.sendPacket(AddBoundingBox.getPayload(dimensionType, key, boundingBoxes));
137
138             if (!playerBoundingBoxesCache.containsKey(player)) {
139                 playerBoundingBoxesCache.put(player, new HashSet<>());
140             }
141             playerBoundingBoxesCache.get(player).add(key);
142         }
143     }
144
145     private Map<BoundingBox, Set<BoundingBox>> getBoundingBoxMap(EntityPlayerMP player, Map<BoundingBox, Set<BoundingBox>> boundingBoxMap) {
146         Map<BoundingBox, Set<BoundingBox>> cacheSubset = new HashMap<>();
147         for (BoundingBox key : boundingBoxMap.keySet()) {
148             if (!playerBoundingBoxesCache.containsKey(player) || !playerBoundingBoxesCache.get(player).contains(key)) {
149                 cacheSubset.put(key, boundingBoxMap.get(key));
150             }
151         }
152         return cacheSubset;
153     }
154
155     protected void removeBoundingBox(DimensionType dimensionType, BoundingBox key) {
156         BoundingBoxCache cache = getCache(dimensionType);
157         if (cache == null) return;
158
159         cache.removeBoundingBox(key);
160     }
161
162     private void mobSpawnerBroken(DimensionType dimensionType, BlockPos pos) {
163         BoundingBox boundingBox = BoundingBoxMobSpawner.from(pos);
164         removeBoundingBox(dimensionType, boundingBox);
165         sendRemoveBoundingBox(dimensionType, boundingBox);
166     }
167
168     private void tick() {
169         for (EntityPlayerMP player : playerDimensions.keySet()) {
170             DimensionType dimensionType = playerDimensions.get(player);
171             sendToPlayer(player, getCache(dimensionType));
172         }
173     }
174
175     private void villageUpdated(DimensionType dimensionType, Village village) {
176         BoundingBoxCache cache = getCache(dimensionType);
177         if (cache == null) return;
178
179         int villageId = village.hashCode();
180         BoundingBoxVillage oldVillage = villageCache.get(villageId);
181         if (oldVillage != null && !oldVillage.matches(village)) {
182             cache.removeBoundingBox(oldVillage);
183             sendRemoveBoundingBox(dimensionType, oldVillage);
184             oldVillage = null;
185         }
186         if (village.isAnnihilated()) {
187             villageCache.remove(villageId);
188         } else {
189             BoundingBoxVillage newVillage = oldVillage == null ? BoundingBoxVillage.from(village) : oldVillage;
190             cache.addBoundingBox(newVillage);
191             villageCache.put(villageId, newVillage);
192         }
193     }
194
195     protected BoundingBoxCache getCache(DimensionType dimensionType) {
196         return dimensionCache.get(dimensionType);
197     }
198
199     protected BoundingBoxCache getOrCreateCache(DimensionType dimensionType)
200     {
201         return dimensionCache.computeIfAbsent(dimensionType, dt -> new BoundingBoxCache());
202     }
203
204     protected void runOnCache(DimensionType dimensionType, Consumer<BoundingBoxCache> action) {
205         action.accept(getOrCreateCache(dimensionType));
206     }
207
208     protected void clearCaches() {
209         villageCache.clear();
210         for (BoundingBoxCache cache : dimensionCache.values()) {
211             cache.close();
212         }
213         dimensionCache.clear();
214     }
215 }