1 package com.irtimaled.bbor.common;
3 import com.irtimaled.bbor.Logger;
4 import com.irtimaled.bbor.client.config.ConfigManager;
5 import com.irtimaled.bbor.common.events.PlayerLoggedIn;
6 import com.irtimaled.bbor.common.events.PlayerLoggedOut;
7 import com.irtimaled.bbor.common.events.PlayerSubscribed;
8 import com.irtimaled.bbor.common.events.ServerTick;
9 import com.irtimaled.bbor.common.events.StructuresLoaded;
10 import com.irtimaled.bbor.common.events.WorldLoaded;
11 import com.irtimaled.bbor.common.messages.AddBoundingBox;
12 import com.irtimaled.bbor.common.messages.InitializeClient;
13 import com.irtimaled.bbor.common.messages.PayloadBuilder;
14 import com.irtimaled.bbor.common.models.AbstractBoundingBox;
15 import com.irtimaled.bbor.common.models.DimensionId;
16 import com.irtimaled.bbor.common.models.ServerPlayer;
18 import java.util.HashMap;
19 import java.util.HashSet;
22 import java.util.concurrent.ConcurrentHashMap;
24 public class CommonProxy {
25 private final Map<Integer, ServerPlayer> players = new ConcurrentHashMap<>();
26 private final Map<Integer, Set<AbstractBoundingBox>> playerBoundingBoxesCache = new HashMap<>();
27 private final Map<DimensionId, StructureProcessor> structureProcessors = new HashMap<>();
28 private final Map<DimensionId, BoundingBoxCache> dimensionCache = new ConcurrentHashMap<>();
29 private Long seed = null;
30 private Integer spawnX = null;
31 private Integer spawnZ = null;
34 ConfigManager.loadConfig();
38 BoundingBoxType.registerTypes();
39 EventBus.subscribe(WorldLoaded.class, this::worldLoaded);
40 EventBus.subscribe(StructuresLoaded.class, this::structuresLoaded);
41 EventBus.subscribe(PlayerLoggedIn.class, this::playerLoggedIn);
42 EventBus.subscribe(PlayerLoggedOut.class, this::playerLoggedOut);
43 EventBus.subscribe(PlayerSubscribed.class, this::onPlayerSubscribed);
44 EventBus.subscribe(ServerTick.class, e -> serverTick());
47 protected void setSeed(long seed) {
51 protected void setWorldSpawn(int spawnX, int spawnZ) {
56 private void worldLoaded(WorldLoaded event) {
57 DimensionId dimensionId = event.getDimensionId();
58 long seed = event.getSeed();
59 if (dimensionId == DimensionId.OVERWORLD) {
61 setWorldSpawn(event.getSpawnX(), event.getSpawnZ());
63 Logger.info("create world dimension: %s (seed: %d)", dimensionId, seed);
66 private void structuresLoaded(StructuresLoaded event) {
67 DimensionId dimensionId = event.getDimensionId();
68 StructureProcessor structureProcessor = getStructureProcessor(dimensionId);
69 structureProcessor.process(event.getStructures());
72 private StructureProcessor getStructureProcessor(DimensionId dimensionId) {
73 StructureProcessor structureProcessor = structureProcessors.get(dimensionId);
74 if (structureProcessor == null) {
75 structureProcessor = new StructureProcessor(getOrCreateCache(dimensionId));
76 structureProcessors.put(dimensionId, structureProcessor);
78 return structureProcessor;
81 private void playerLoggedIn(PlayerLoggedIn event) {
82 if (seed == null || spawnX == null || spawnZ == null) {
85 ServerPlayer player = event.getPlayer();
86 player.sendPacket(InitializeClient.getPayload(seed, spawnX, spawnZ));
89 private void playerLoggedOut(PlayerLoggedOut event) {
90 int playerId = event.getPlayerId();
91 players.remove(playerId);
92 playerBoundingBoxesCache.remove(playerId);
95 private void onPlayerSubscribed(PlayerSubscribed event) {
96 int playerId = event.getPlayerId();
97 ServerPlayer player = event.getPlayer();
98 players.put(playerId, player);
99 sendToPlayer(playerId, player);
102 private void sendToPlayer(int playerId, ServerPlayer player) {
103 for (Map.Entry<DimensionId, BoundingBoxCache> entry : dimensionCache.entrySet()) {
104 DimensionId dimensionId = entry.getKey();
105 BoundingBoxCache boundingBoxCache = entry.getValue();
106 if (boundingBoxCache == null) return;
108 Set<AbstractBoundingBox> playerBoundingBoxes = playerBoundingBoxesCache.computeIfAbsent(playerId, k -> new HashSet<>());
110 Map<AbstractBoundingBox, Set<AbstractBoundingBox>> boundingBoxMap = boundingBoxCache.getBoundingBoxes();
111 for (AbstractBoundingBox key : boundingBoxMap.keySet()) {
112 if (playerBoundingBoxes.contains(key)) {
116 Set<AbstractBoundingBox> boundingBoxes = boundingBoxMap.get(key);
117 PayloadBuilder payload = AddBoundingBox.getPayload(dimensionId, key, boundingBoxes);
119 player.sendPacket(payload);
121 playerBoundingBoxes.add(key);
126 private void serverTick() {
127 for (Map.Entry<Integer, ServerPlayer> playerEntry : players.entrySet()) {
128 int playerId = playerEntry.getKey();
129 ServerPlayer player = playerEntry.getValue();
131 sendToPlayer(playerId, player);
135 protected BoundingBoxCache getCache(DimensionId dimensionId) {
136 return dimensionCache.get(dimensionId);
139 protected BoundingBoxCache getOrCreateCache(DimensionId dimensionId) {
140 return dimensionCache.computeIfAbsent(dimensionId, dt -> new BoundingBoxCache());
143 protected void clearCaches() {
144 structureProcessors.clear();
145 for (BoundingBoxCache cache : dimensionCache.values()) {
148 dimensionCache.clear();