From c1a405b7557d80f27ba414885564faf8eb7e05de Mon Sep 17 00:00:00 2001 From: s809 <43530948+s809@users.noreply.github.com> Date: Sat, 5 Oct 2024 14:03:02 +0500 Subject: [PATCH 1/5] Decouple beacon beam data handling from render handling, send beacon beams to clients --- .../distanthorizons/coreapi/ModInfo.java | 2 +- .../file/beacon/BeaconBeamDataHandler.java | 166 ++++++++++++++++++ .../generation/RemoteWorldRetrievalQueue.java | 4 +- .../core/level/AbstractDhLevel.java | 29 +-- .../core/level/AbstractDhServerLevel.java | 10 +- .../core/level/DhClientLevel.java | 5 +- .../AbstractFullDataNetworkRequestQueue.java | 8 +- .../client/SyncOnLoginRequestQueue.java | 4 +- .../core/network/INetworkObject.java | 33 ++-- .../messages/fullData/FullDataPayload.java | 14 +- .../core/pos/DhSectionPos.java | 16 ++ .../core/pos/blockPos/DhBlockPos.java | 26 ++- .../renderer/generic/BeaconRenderHandler.java | 111 +----------- .../core/sql/dto/BeaconBeamDTO.java | 24 ++- 14 files changed, 297 insertions(+), 155 deletions(-) create mode 100644 core/src/main/java/com/seibel/distanthorizons/core/file/beacon/BeaconBeamDataHandler.java diff --git a/api/src/main/java/com/seibel/distanthorizons/coreapi/ModInfo.java b/api/src/main/java/com/seibel/distanthorizons/coreapi/ModInfo.java index 21c802c7b..4a4d6f6a0 100644 --- a/api/src/main/java/com/seibel/distanthorizons/coreapi/ModInfo.java +++ b/api/src/main/java/com/seibel/distanthorizons/coreapi/ModInfo.java @@ -31,7 +31,7 @@ public final class ModInfo public static final String DEDICATED_SERVER_INITIAL_PATH = "dedicated_server_initial"; /** Incremented every time any packets are added, changed or removed, with a few exceptions. */ - public static final int PROTOCOL_VERSION = 4; + public static final int PROTOCOL_VERSION = 5; public static final String WRAPPER_PACKET_PATH = "message"; /** The internal mod name */ diff --git a/core/src/main/java/com/seibel/distanthorizons/core/file/beacon/BeaconBeamDataHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/file/beacon/BeaconBeamDataHandler.java new file mode 100644 index 000000000..04dd9bf89 --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/file/beacon/BeaconBeamDataHandler.java @@ -0,0 +1,166 @@ +package com.seibel.distanthorizons.core.file.beacon; + +import com.seibel.distanthorizons.core.pos.DhChunkPos; +import com.seibel.distanthorizons.core.pos.DhSectionPos; +import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos; +import com.seibel.distanthorizons.core.render.renderer.generic.BeaconRenderHandler; +import com.seibel.distanthorizons.core.render.renderer.generic.GenericObjectRenderer; +import com.seibel.distanthorizons.core.sql.dto.BeaconBeamDTO; +import com.seibel.distanthorizons.core.sql.repo.BeaconBeamRepo; +import com.seibel.distanthorizons.core.util.LodUtil; +import org.jetbrains.annotations.NotNull; + +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; + +public class BeaconBeamDataHandler +{ + private final BeaconBeamRepo beaconBeamRepo; + + @Nullable + private BeaconRenderHandler beaconRenderHandler; + + + + //=============// + // constructor // + //=============// + + public BeaconBeamDataHandler(@NotNull BeaconBeamRepo beaconBeamRepo, @Nullable GenericObjectRenderer renderer) + { + this.beaconBeamRepo = beaconBeamRepo; + + if (renderer != null) + { + this.beaconRenderHandler = new BeaconRenderHandler(renderer); + } + } + + + + //==========// + // updating // + //==========// + + public void setBeaconBeamsForChunk(DhChunkPos chunkPos, List activeBeamList) + { + long sectionPos = DhSectionPos.encode(LodUtil.CHUNK_DETAIL_LEVEL, chunkPos.getX(), chunkPos.getZ()); + this.setBeaconBeamsForPos(sectionPos, activeBeamList); + } + + public void setBeaconBeamsForPos(long sectionPos, List activeBeamList) + { + // synchronized to prevent two threads from updating the same chunk at the same time + synchronized (this) + { + HashSet allPosSet = new HashSet<>(); + + // sort new beams + HashMap activeBeamByPos = new HashMap<>(activeBeamList.size()); + for (BeaconBeamDTO beam : activeBeamList) + { + activeBeamByPos.put(beam.blockPos, beam); + allPosSet.add(beam.blockPos); + } + + // get existing beams + List existingBeamList = this.beaconBeamRepo.getAllBeamsForPos(sectionPos); + HashMap existingBeamByPos = new HashMap<>(existingBeamList.size()); + for (BeaconBeamDTO beam : existingBeamList) + { + existingBeamByPos.put(beam.blockPos, beam); + allPosSet.add(beam.blockPos); + } + + + + for (DhBlockPos beaconPos : allPosSet) + { + if (!DhSectionPos.contains(sectionPos, beaconPos)) + { + // don't update beacons outside the updated chunk + continue; + } + + BeaconBeamDTO existingBeam = existingBeamByPos.get(beaconPos); + BeaconBeamDTO activeBeam = activeBeamByPos.get(beaconPos); + + + if (activeBeam != null) + { + if (existingBeam == null) + { + // new beam found, add to DB + this.beaconBeamRepo.save(activeBeam); + if (this.beaconRenderHandler != null) + { + this.beaconRenderHandler.startRenderingBeacon(activeBeam); + } + } + else + { + // beam still exists in chunk + if (!existingBeam.color.equals(activeBeam.color)) + { + // beam colors were changed + this.beaconBeamRepo.save(activeBeam); + if (this.beaconRenderHandler != null) + { + this.beaconRenderHandler.updateBeaconColor(activeBeam); + } + } + } + } + else if (existingBeam != null) + { + // beam no longer exists at position, remove from DB + this.beaconBeamRepo.deleteWithKey(beaconPos); + if (this.beaconRenderHandler != null) + { + this.beaconRenderHandler.stopRenderingBeaconAtPos(beaconPos); + } + } + + } + } + } + + + + //===================// + // loading/unloading // + //===================// + + public void loadBeaconBeamsInPos(long pos) + { + if (this.beaconRenderHandler == null) + { + return; + } + + // get all beams in pos + List existingBeamList = this.beaconBeamRepo.getAllBeamsForPos(pos); + for (BeaconBeamDTO newBeam : existingBeamList) + { + this.beaconRenderHandler.startRenderingBeacon(newBeam); + } + } + + public void unloadBeaconBeamsInPos(long pos) + { + if (this.beaconRenderHandler == null) + { + return; + } + + // get all beams in pos + List existingBeamList = this.beaconBeamRepo.getAllBeamsForPos(pos); + for (BeaconBeamDTO beam : existingBeamList) + { + this.beaconRenderHandler.stopRenderingBeaconAtPos(beam.blockPos); + } + } + +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/generation/RemoteWorldRetrievalQueue.java b/core/src/main/java/com/seibel/distanthorizons/core/generation/RemoteWorldRetrievalQueue.java index 48a7ef395..56b23490f 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/generation/RemoteWorldRetrievalQueue.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/generation/RemoteWorldRetrievalQueue.java @@ -3,7 +3,7 @@ package com.seibel.distanthorizons.core.generation; import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.generation.tasks.IWorldGenTaskTracker; import com.seibel.distanthorizons.core.generation.tasks.WorldGenResult; -import com.seibel.distanthorizons.core.level.IDhClientLevel; +import com.seibel.distanthorizons.core.level.DhClientLevel; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.multiplayer.client.AbstractFullDataNetworkRequestQueue; import com.seibel.distanthorizons.core.multiplayer.client.ClientNetworkState; @@ -26,7 +26,7 @@ public class RemoteWorldRetrievalQueue extends AbstractFullDataNetworkRequestQue // constructor // //=============// - public RemoteWorldRetrievalQueue(ClientNetworkState networkState, IDhClientLevel level) + public RemoteWorldRetrievalQueue(ClientNetworkState networkState, DhClientLevel level) { super(networkState, level, false, Config.Client.Advanced.Debugging.DebugWireframe.showWorldGenQueue); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/AbstractDhLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/AbstractDhLevel.java index 7afcaceb6..78356d5fe 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/AbstractDhLevel.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/AbstractDhLevel.java @@ -21,6 +21,7 @@ package com.seibel.distanthorizons.core.level; import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiChunkModifiedEvent; import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2; +import com.seibel.distanthorizons.core.file.beacon.BeaconBeamDataHandler; import com.seibel.distanthorizons.core.file.fullDatafile.DelayedFullDataSourceSaveCache; import com.seibel.distanthorizons.core.generation.DhLightingEngine; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; @@ -66,7 +67,7 @@ public abstract class AbstractDhLevel implements IDhLevel /** Will be null if clouds shouldn't be rendered for this level. */ @Nullable protected CloudRenderHandler cloudRenderHandler; - protected BeaconRenderHandler beaconRenderHandler; + protected BeaconBeamDataHandler beaconBeamDataHandler; @@ -124,13 +125,13 @@ public abstract class AbstractDhLevel implements IDhLevel this.cloudRenderHandler = new CloudRenderHandler((IDhClientLevel)this, genericRenderer); } } - - - // shouldn't happen, but just in case - if (this.beaconBeamRepo != null) - { - this.beaconRenderHandler = new BeaconRenderHandler(this.beaconBeamRepo, genericRenderer); - } + } + + + // shouldn't happen, but just in case + if (this.beaconBeamRepo != null) + { + this.beaconBeamDataHandler = new BeaconBeamDataHandler(this.beaconBeamRepo, genericRenderer); } } @@ -228,27 +229,27 @@ public abstract class AbstractDhLevel implements IDhLevel @Override public void updateBeaconBeamsForChunk(IChunkWrapper chunkToUpdate, ArrayList nearbyChunkList) { - if (this.beaconRenderHandler != null) + if (this.beaconBeamDataHandler != null) { List activeBeamList = chunkToUpdate.getAllActiveBeacons(nearbyChunkList); - this.beaconRenderHandler.setBeaconBeamsForChunk(chunkToUpdate.getChunkPos(), activeBeamList); + this.beaconBeamDataHandler.setBeaconBeamsForChunk(chunkToUpdate.getChunkPos(), activeBeamList); } } @Override public void loadBeaconBeamsInPos(long pos) { - if (this.beaconRenderHandler != null) + if (this.beaconBeamDataHandler != null) { - this.beaconRenderHandler.loadBeaconBeamsInPos(pos); + this.beaconBeamDataHandler.loadBeaconBeamsInPos(pos); } } @Override public void unloadBeaconBeamsInPos(long pos) { - if (this.beaconRenderHandler != null) + if (this.beaconBeamDataHandler != null) { - this.beaconRenderHandler.unloadBeaconBeamsInPos(pos); + this.beaconBeamDataHandler.unloadBeaconBeamsInPos(pos); } } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/AbstractDhServerLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/AbstractDhServerLevel.java index b321761f8..84fd62dec 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/AbstractDhServerLevel.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/AbstractDhServerLevel.java @@ -32,6 +32,7 @@ import org.apache.logging.log4j.Logger; import javax.annotation.CheckForNull; import javax.annotation.Nullable; import java.util.Map; +import java.util.Objects; import java.util.concurrent.*; public abstract class AbstractDhServerLevel extends AbstractDhLevel implements IDhServerLevel @@ -126,7 +127,8 @@ public abstract class AbstractDhServerLevel extends AbstractDhLevel implements I } CompletableFuture.runAsync(() -> { - FullDataPayload payload = new FullDataPayload(requestGroup.fullDataSource); + Objects.requireNonNull(this.beaconBeamRepo); + FullDataPayload payload = new FullDataPayload(requestGroup.fullDataSource, this.beaconBeamRepo.getAllBeamsForPos(entry.getKey())); for (FullDataSourceRequestMessage msg : requestGroup.requestMessages.values()) { this.requestGroupByFutureId.remove(msg.futureId); @@ -273,7 +275,8 @@ public abstract class AbstractDhServerLevel extends AbstractDhLevel implements I { rateLimiterSet.syncOnLoginRateLimiter.release(); - FullDataPayload payload = new FullDataPayload(fullDataSource); + Objects.requireNonNull(this.beaconBeamRepo); + FullDataPayload payload = new FullDataPayload(fullDataSource, this.beaconBeamRepo.getAllBeamsForPos(message.sectionPos)); payload.splitAndSend(FULL_DATA_SPLIT_SIZE_IN_BYTES, message.getSession()::sendMessage); message.sendResponse(new FullDataSourceResponseMessage(payload)); }, executor); @@ -412,7 +415,8 @@ public abstract class AbstractDhServerLevel extends AbstractDhLevel implements I } CompletableFuture.runAsync(() -> { - FullDataPayload payload = new FullDataPayload(data); + Objects.requireNonNull(this.beaconBeamRepo); + FullDataPayload payload = new FullDataPayload(data, this.beaconBeamRepo.getAllBeamsForPos(data.getPos())); for (ServerPlayerState serverPlayerState : this.serverPlayerStateManager.getReadyPlayers()) { if (serverPlayerState.getServerPlayer().getLevel() != this.serverLevelWrapper) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java index 6d0f28092..290ef1083 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java @@ -24,6 +24,7 @@ import com.seibel.distanthorizons.core.config.AppliedConfigState; import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; +import com.seibel.distanthorizons.core.file.beacon.BeaconBeamDataHandler; import com.seibel.distanthorizons.core.file.fullDatafile.FullDataSourceProviderV2; import com.seibel.distanthorizons.core.file.fullDatafile.RemoteFullDataSourceProvider; import com.seibel.distanthorizons.core.file.structure.ISaveStructure; @@ -138,6 +139,7 @@ public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel return; } + this.beaconBeamDataHandler.setBeaconBeamsForPos(dataSourceDto.pos, message.payload.beaconBeams); this.updateDataSourcesAsync(dataSourceDto.createPooledDataSource(this.levelWrapper)); } catch (Exception e) @@ -276,6 +278,7 @@ public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel ClientLevelModule.ClientRenderState renderState = this.clientside.ClientRenderStateRef.get(); return (renderState != null) ? renderState.renderBufferHandler : null; } + public BeaconBeamDataHandler getBeaconBeamDataHandler() { return this.beaconBeamDataHandler; } @@ -360,7 +363,7 @@ public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel private static class WorldGenState extends WorldGenModule.AbstractWorldGenState { - WorldGenState(IDhClientLevel level, ClientNetworkState networkState) + WorldGenState(DhClientLevel level, ClientNetworkState networkState) { this.worldGenerationQueue = new RemoteWorldRetrievalQueue(networkState, level); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/client/AbstractFullDataNetworkRequestQueue.java b/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/client/AbstractFullDataNetworkRequestQueue.java index feb720750..085147ef1 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/client/AbstractFullDataNetworkRequestQueue.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/client/AbstractFullDataNetworkRequestQueue.java @@ -5,8 +5,7 @@ import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.config.types.ConfigEntry; import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; -import com.seibel.distanthorizons.core.level.DhServerLevel; -import com.seibel.distanthorizons.core.level.IDhClientLevel; +import com.seibel.distanthorizons.core.level.DhClientLevel; import com.seibel.distanthorizons.core.logging.ConfigBasedSpamLogger; import com.seibel.distanthorizons.core.network.exceptions.InvalidLevelException; import com.seibel.distanthorizons.core.network.exceptions.RateLimitedException; @@ -56,7 +55,7 @@ public abstract class AbstractFullDataNetworkRequestQueue implements IDebugRende public final ClientNetworkState networkState; - protected final IDhClientLevel level; + protected final DhClientLevel level; private final boolean changedOnly; private volatile CompletableFuture closingFuture = null; @@ -84,7 +83,7 @@ public abstract class AbstractFullDataNetworkRequestQueue implements IDebugRende //=============// public AbstractFullDataNetworkRequestQueue( - ClientNetworkState networkState, IDhClientLevel level, + ClientNetworkState networkState, DhClientLevel level, boolean changedOnly, ConfigEntry showDebugWireframeConfig) { this.networkState = networkState; @@ -206,6 +205,7 @@ public abstract class AbstractFullDataNetworkRequestQueue implements IDebugRende { try { + this.level.getBeaconBeamDataHandler().setBeaconBeamsForPos(dataSourceDto.pos, response.payload.beaconBeams); FullDataSourceV2 fullDataSource = dataSourceDto.createPooledDataSource(this.level.getLevelWrapper()); entry.dataSourceConsumer.accept(fullDataSource); FullDataSourceV2.DATA_SOURCE_POOL.returnPooledDataSource(fullDataSource); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/client/SyncOnLoginRequestQueue.java b/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/client/SyncOnLoginRequestQueue.java index efc68baba..355835841 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/client/SyncOnLoginRequestQueue.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/client/SyncOnLoginRequestQueue.java @@ -2,7 +2,7 @@ package com.seibel.distanthorizons.core.multiplayer.client; import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.generation.RemoteWorldRetrievalQueue; -import com.seibel.distanthorizons.core.level.IDhClientLevel; +import com.seibel.distanthorizons.core.level.DhClientLevel; import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos2D; /** @@ -20,7 +20,7 @@ public class SyncOnLoginRequestQueue extends AbstractFullDataNetworkRequestQueue // constructor // //=============// - public SyncOnLoginRequestQueue(IDhClientLevel level, ClientNetworkState networkState) + public SyncOnLoginRequestQueue(DhClientLevel level, ClientNetworkState networkState) { super(networkState, level, true, Config.Client.Advanced.Debugging.DebugWireframe.showWorldGenQueue); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/network/INetworkObject.java b/core/src/main/java/com/seibel/distanthorizons/core/network/INetworkObject.java index 16dc9610b..580e80cdd 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/network/INetworkObject.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/network/INetworkObject.java @@ -98,21 +98,21 @@ public interface INetworkObject // collections // - default void writeCollection(ByteBuf outputByteBuf, Collection collection) + default void writeCollection(ByteBuf outputByteBuf, Collection collection) { outputByteBuf.writeInt(collection.size()); this.writeFixedLengthCollection(outputByteBuf, collection); } - default void writeFixedLengthCollection(ByteBuf outputByteBuf, Collection collection) + default void writeFixedLengthCollection(ByteBuf outputByteBuf, Collection collection) { - for (T item : collection) + for (Object item : collection) { Codec codec = Codec.getCodec(item.getClass()); codec.encode.accept(item, outputByteBuf); } } - default void readCollection(ByteBuf inputByteBuf, Collection collection, Supplier innerValueConstructor) + default , T> TCollection readCollection(ByteBuf inputByteBuf, TCollection collection, Supplier innerValueConstructor) { int size = inputByteBuf.readInt(); @@ -130,9 +130,11 @@ public interface INetworkObject collection.add(item); } + + return collection; } - default void readMap(ByteBuf inputByteBuf, Map map, Supplier keySupplier, Supplier valueSupplier) + default , K, V> TMap readMap(ByteBuf inputByteBuf, TMap map, Supplier keySupplier, Supplier valueSupplier) { ArrayList> entryList = new ArrayList<>(); @@ -141,6 +143,8 @@ public interface INetworkObject { map.put(entry.getKey(), entry.getValue()); } + + return map; } @@ -150,11 +154,10 @@ public interface INetworkObject //================// /** - * Defines (de)serialization for different classes, - * specifically for base classes like {@link Integer}, {@link Boolean}, and {@link String}.

- * - * Should only be used for non-editable classes; - * otherwise, you may want to implement {@link INetworkObject} and use its methods where applicable. + * Defines (de)serialization for classes that cannot be directly edited, + * specifically for primitives, Java and third-party library classes and other types. + *

+ * If you're able to edit the target class yourself, implement {@link INetworkObject} and use its methods where applicable instead. */ class Codec { @@ -209,18 +212,18 @@ public interface INetworkObject public static Codec getCodec(Class clazz) { - return CODEC_MAP.computeIfAbsent(clazz, ignored -> - { - // TODO when would this ever return true? + return CODEC_MAP.computeIfAbsent(clazz, classToAdd -> { + // Check if the class is a subclass of any existing key in the map. + // If it is, return the existing codec and bind it to this class for faster future searches. for (Map.Entry, Codec> entry : CODEC_MAP.entrySet()) { - if (entry.getKey().isAssignableFrom(clazz)) + if (entry.getKey().isAssignableFrom(classToAdd)) { return entry.getValue(); } } - throw new AssertionError("Class has no compatible codec: " + clazz.getSimpleName()); + throw new AssertionError("Class has no compatible codec: " + classToAdd.getSimpleName()); }); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/network/messages/fullData/FullDataPayload.java b/core/src/main/java/com/seibel/distanthorizons/core/network/messages/fullData/FullDataPayload.java index 1a8a2ad39..71a8bd6ea 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/network/messages/fullData/FullDataPayload.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/network/messages/fullData/FullDataPayload.java @@ -5,6 +5,7 @@ import com.seibel.distanthorizons.api.enums.config.EDhApiDataCompressionMode; import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2; import com.seibel.distanthorizons.core.network.INetworkObject; +import com.seibel.distanthorizons.core.sql.dto.BeaconBeamDTO; import com.seibel.distanthorizons.core.sql.dto.FullDataSourceV2DTO; import com.seibel.distanthorizons.core.util.TimerUtil; import io.netty.buffer.ByteBuf; @@ -12,9 +13,7 @@ import io.netty.buffer.ByteBufAllocator; import org.jetbrains.annotations.NotNull; import java.io.IOException; -import java.util.Objects; -import java.util.Timer; -import java.util.TimerTask; +import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; @@ -31,6 +30,8 @@ public class FullDataPayload implements INetworkObject public int dtoBufferId; public ByteBuf dtoBuffer; + public List beaconBeams; + //==============// @@ -38,7 +39,7 @@ public class FullDataPayload implements INetworkObject //==============// public FullDataPayload() { } - public FullDataPayload(@NotNull FullDataSourceV2 fullDataSource) + public FullDataPayload(@NotNull FullDataSourceV2 fullDataSource, List beaconBeams) { Objects.requireNonNull(fullDataSource); @@ -65,6 +66,8 @@ public class FullDataPayload implements INetworkObject { throw new RuntimeException(e); } + + this.beaconBeams = beaconBeams; } @@ -77,12 +80,14 @@ public class FullDataPayload implements INetworkObject public void encode(ByteBuf out) { out.writeInt(this.dtoBufferId); + this.writeCollection(out, this.beaconBeams); } @Override public void decode(ByteBuf in) { this.dtoBufferId = in.readInt(); + this.beaconBeams = this.readCollection(in, new ArrayList<>(), () -> new BeaconBeamDTO(null, null)); } /** @@ -121,6 +126,7 @@ public class FullDataPayload implements INetworkObject return MoreObjects.toStringHelper(this) .add("dtoBufferId", this.dtoBufferId) .add("dtoBuffer", this.dtoBuffer) + .add("beaconBeams", this.beaconBeams) .toString(); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java index d02071b4b..3fb1252af 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java @@ -348,6 +348,22 @@ public class DhSectionPos return aMinX <= bMinX && bMinX <= aMaxX && aMinZ <= bMinZ && bMinZ <= aMaxZ; } + + public static boolean contains(long aPos, DhBlockPos blockPos) + { + int sectionMinX = getMinCornerBlockX(aPos); + int sectionMinZ = getMinCornerBlockZ(aPos); + + int blockX = blockPos.getX(); + int blockZ = blockPos.getZ(); + + int sectionBlockWidth = getBlockWidth(aPos) - 1; // minus 1 to account for zero based positional indexing + int sectionMaxX = sectionMinX + sectionBlockWidth; + int sectionMaxZ = sectionMinZ + sectionBlockWidth; + + return sectionMinX <= blockX && blockX <= sectionMaxX && + sectionMinZ <= blockZ && blockZ <= sectionMaxZ; + } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/pos/blockPos/DhBlockPos.java b/core/src/main/java/com/seibel/distanthorizons/core/pos/blockPos/DhBlockPos.java index 0f0943e2f..1b5926ffe 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/pos/blockPos/DhBlockPos.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/pos/blockPos/DhBlockPos.java @@ -20,8 +20,10 @@ package com.seibel.distanthorizons.core.pos.blockPos; import com.seibel.distanthorizons.core.enums.EDhDirection; +import com.seibel.distanthorizons.core.network.INetworkObject; import com.seibel.distanthorizons.core.util.LodUtil; +import io.netty.buffer.ByteBuf; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Objects; @@ -34,7 +36,7 @@ import java.util.Objects; * * @see DhBlockPosMutable */ -public class DhBlockPos +public class DhBlockPos implements INetworkObject { /** Useful for methods that need a position passed in but won't actually be used */ public static final DhBlockPos ZERO = new DhBlockPos(0, 0, 0); @@ -191,4 +193,26 @@ public class DhBlockPos @Override public String toString() { return "DHBlockPos["+ this.x +", "+ this.y +", "+ this.z +"]"; } + + + //=========// + // network // + //=========// + + @Override + public void encode(ByteBuf out) + { + out.writeInt(this.x); + out.writeInt(this.y); + out.writeInt(this.z); + } + + @Override + public void decode(ByteBuf in) + { + this.x = in.readInt(); + this.y = in.readInt(); + this.z = in.readInt(); + } + } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/generic/BeaconRenderHandler.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/generic/BeaconRenderHandler.java index a4ed56804..7e7b04ae4 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/generic/BeaconRenderHandler.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/generic/BeaconRenderHandler.java @@ -29,9 +29,7 @@ import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos; -import com.seibel.distanthorizons.core.pos.DhChunkPos; import com.seibel.distanthorizons.core.sql.dto.BeaconBeamDTO; -import com.seibel.distanthorizons.core.sql.repo.BeaconBeamRepo; import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.util.math.Vec3d; import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil; @@ -41,9 +39,7 @@ import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; -import java.util.HashMap; import java.util.HashSet; -import java.util.List; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.locks.ReentrantLock; @@ -61,9 +57,6 @@ public class BeaconRenderHandler - /** if this is null then the other handler is probably null too, but just in case */ - private final BeaconBeamRepo beaconBeamRepo; - private final ReentrantLock updateLock = new ReentrantLock(); private final IDhApiRenderableBoxGroup beaconBoxGroup; @@ -79,10 +72,8 @@ public class BeaconRenderHandler // constructor // //=============// - public BeaconRenderHandler(@NotNull BeaconBeamRepo beaconBeamRepo, @NotNull GenericObjectRenderer renderer) + public BeaconRenderHandler(@NotNull GenericObjectRenderer renderer) { - this.beaconBeamRepo = beaconBeamRepo; - this.beaconBoxGroup = GenericRenderObjectFactory.INSTANCE.createAbsolutePositionedGroup(ModInfo.NAME+":Beacons", new ArrayList<>(0)); this.beaconBoxGroup.setBlockLight(LodUtil.MAX_MC_LIGHT); this.beaconBoxGroup.setSkyLight(LodUtil.MAX_MC_LIGHT); @@ -95,105 +86,11 @@ public class BeaconRenderHandler - //=========================// - // level loading/unloading // - //=========================// - - public void setBeaconBeamsForChunk(DhChunkPos chunkPos, List activeBeamList) - { - // synchronized to prevent two threads from updating the same chunk at the same time - synchronized (this) - { - HashSet allPosSet = new HashSet<>(); - - // sort new beams - HashMap activeBeamByPos = new HashMap<>(activeBeamList.size()); - for (int i = 0; i < activeBeamList.size(); i++) - { - BeaconBeamDTO beam = activeBeamList.get(i); - activeBeamByPos.put(beam.blockPos, beam); - allPosSet.add(beam.blockPos); - } - - // get existing beams - List existingBeamList = this.beaconBeamRepo.getAllBeamsForPos(chunkPos); - HashMap existingBeamByPos = new HashMap<>(existingBeamList.size()); - for (int i = 0; i < existingBeamList.size(); i++) - { - BeaconBeamDTO beam = existingBeamList.get(i); - existingBeamByPos.put(beam.blockPos, beam); - allPosSet.add(beam.blockPos); - } - - - - for (DhBlockPos beaconPos : allPosSet) - { - if (!chunkPos.contains(beaconPos)) - { - // don't update beacons outside the updated chunk - continue; - } - - BeaconBeamDTO existingBeam = existingBeamByPos.get(beaconPos); - BeaconBeamDTO activeBeam = activeBeamByPos.get(beaconPos); - - if (existingBeam != null && activeBeam != null) - { - // beam still exists in chunk - if (!existingBeam.color.equals(activeBeam.color)) - { - // beam colors were changed - this.beaconBeamRepo.save(activeBeam); - this.updateBeaconColor(activeBeam); - } - } - else if (existingBeam == null && activeBeam != null) - { - // new beam found, add to DB - this.beaconBeamRepo.save(activeBeam); - this.startRenderingBeacon(activeBeam); - } - else if (existingBeam != null && activeBeam == null) - { - // beam no longer exists at position, remove from DB - this.beaconBeamRepo.deleteWithKey(beaconPos); - this.stopRenderingBeaconAtPos(beaconPos); - } - - } - } - } - - public void loadBeaconBeamsInPos(long pos) - { - // get all beams in pos - List existingBeamList = this.beaconBeamRepo.getAllBeamsForPos(pos); - for (int i = 0; i < existingBeamList.size(); i++) - { - BeaconBeamDTO newBeam = existingBeamList.get(i); - this.startRenderingBeacon(newBeam); - } - } - - public void unloadBeaconBeamsInPos(long pos) - { - // get all beams in pos - List existingBeamList = this.beaconBeamRepo.getAllBeamsForPos(pos); - for (int i = 0; i < existingBeamList.size(); i++) - { - BeaconBeamDTO beam = existingBeamList.get(i); - this.stopRenderingBeaconAtPos(beam.blockPos); - } - } - - - //=================// // render handling // //=================// - private void startRenderingBeacon(BeaconBeamDTO beacon) + public void startRenderingBeacon(BeaconBeamDTO beacon) { try { @@ -219,7 +116,7 @@ public class BeaconRenderHandler } } - private void stopRenderingBeaconAtPos(DhBlockPos beaconPos) + public void stopRenderingBeaconAtPos(DhBlockPos beaconPos) { try { @@ -245,7 +142,7 @@ public class BeaconRenderHandler } } - private void updateBeaconColor(BeaconBeamDTO newBeam) + public void updateBeaconColor(BeaconBeamDTO newBeam) { try { diff --git a/core/src/main/java/com/seibel/distanthorizons/core/sql/dto/BeaconBeamDTO.java b/core/src/main/java/com/seibel/distanthorizons/core/sql/dto/BeaconBeamDTO.java index 89b5bc992..0671a78dd 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/sql/dto/BeaconBeamDTO.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/sql/dto/BeaconBeamDTO.java @@ -20,12 +20,14 @@ package com.seibel.distanthorizons.core.sql.dto; import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2; +import com.seibel.distanthorizons.core.network.INetworkObject; import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos; +import io.netty.buffer.ByteBuf; import java.awt.*; /** handles storing {@link FullDataSourceV2}'s in the database. */ -public class BeaconBeamDTO implements IBaseDTO +public class BeaconBeamDTO implements IBaseDTO, INetworkObject { public DhBlockPos blockPos; public Color color; @@ -51,4 +53,24 @@ public class BeaconBeamDTO implements IBaseDTO @Override public DhBlockPos getKey() { return this.blockPos; } + + + //=========// + // network // + //=========// + + @Override + public void encode(ByteBuf out) + { + this.blockPos.encode(out); + out.writeInt(this.color.getRGB()); + } + + @Override + public void decode(ByteBuf in) + { + this.blockPos = INetworkObject.decodeToInstance(new DhBlockPos(), in); + this.color = new Color(in.readInt()); + } + } From 38d7ca4becc9ff920f3beea40c5c596b16fc8b06 Mon Sep 17 00:00:00 2001 From: s809 <43530948+s809@users.noreply.github.com> Date: Sat, 5 Oct 2024 21:29:58 +0500 Subject: [PATCH 2/5] Prevent server crash on shutdown --- .../distanthorizons/core/api/internal/SharedApi.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/SharedApi.java b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/SharedApi.java index d68ed239b..9267303f4 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/SharedApi.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/SharedApi.java @@ -99,7 +99,12 @@ public class SharedApi { ThreadPoolUtil.shutdownThreadPools(); DebugRenderer.clearRenderables(); - MC_RENDER.clearTargetFrameBuffer(); + + if (MC_RENDER != null) + { + MC_RENDER.clearTargetFrameBuffer(); + } + // shouldn't be necessary, but if we missed closing one of the connections this should make sure they're all closed AbstractDhRepo.closeAllConnections(); // needs to be closed on world shutdown to clear out un-processed chunks From 2aca8acaf6a980f0ff82585db8c26407a2e74d44 Mon Sep 17 00:00:00 2001 From: s809 <43530948+s809@users.noreply.github.com> Date: Sat, 5 Oct 2024 21:58:30 +0500 Subject: [PATCH 3/5] Change level key prefix comment --- .../com/seibel/distanthorizons/core/config/Config.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java b/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java index 8a517a8fb..063579181 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java @@ -1041,8 +1041,8 @@ public class Config .set(getDefaultLevelKeyPrefix()) .comment("" + "Prefix of the level keys sent to the clients.\n" - + "Should be set to a unique value for each backend server behind a proxy,\n" - + "or empty if you don't use a proxy.\n" + + "If the mod is running behind a proxy, each backend should use a unique value (an empty string is allowed for one of the servers).\n" + + "This value may be auto-generated if the mod is installed before the first start of the server.\n" + "") .setSide(EConfigEntryRelevantSide.BOTH) .build(); @@ -1756,13 +1756,13 @@ public class Config private static String getDefaultLevelKeyPrefix() { IMinecraftSharedWrapper mcWrapper = SingletonInjector.INSTANCE.get(IMinecraftSharedWrapper.class); - if (!mcWrapper.isDedicatedServer() || mcWrapper.isWorldNew()) + if (mcWrapper.isDedicatedServer() && mcWrapper.isWorldNew()) { - return ""; + return "server" + ThreadLocalRandom.current().nextInt(1, 1000); } else { - return "server" + ThreadLocalRandom.current().nextInt(1, 1000); + return ""; } } From cc8a2a70e87cb98374f3adc8151f16d53c6628ec Mon Sep 17 00:00:00 2001 From: s809 <43530948+s809@users.noreply.github.com> Date: Sun, 6 Oct 2024 00:19:42 +0500 Subject: [PATCH 4/5] Use level key prefixes to in LAN multiplayer --- .editorconfig | 2 +- .../api/internal/ClientPluginChannelApi.java | 4 +-- .../distanthorizons/core/config/Config.java | 30 +++++-------------- .../messages/base/CurrentLevelKeyMessage.java | 9 ++++++ .../minecraft/IMinecraftClientWrapper.java | 2 ++ .../world/IServerLevelWrapper.java | 20 ++++++++++++- .../assets/distanthorizons/lang/en_us.json | 3 +- 7 files changed, 40 insertions(+), 30 deletions(-) diff --git a/.editorconfig b/.editorconfig index 2228be96c..4661e28bb 100644 --- a/.editorconfig +++ b/.editorconfig @@ -537,7 +537,7 @@ ij_groovy_wrap_chain_calls_after_dot = false ij_groovy_wrap_long_lines = false [{*.har,*.json,*.png.mcmeta,mcmod.info,pack.mcmeta}] -indent_size = 4 +indent_size = 2 ij_json_array_wrapping = split_into_lines ij_json_keep_blank_lines_in_code = 0 ij_json_keep_indents_on_empty_lines = false diff --git a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ClientPluginChannelApi.java b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ClientPluginChannelApi.java index cc45ea3dc..4035ab5ee 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ClientPluginChannelApi.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/api/internal/ClientPluginChannelApi.java @@ -75,9 +75,7 @@ public class ClientPluginChannelApi private void onCurrentLevelKeyMessage(CurrentLevelKeyMessage msg) { - // prefix@namespace:path - // 1-50 characters in total, all parts except namespace can be omitted - if (!msg.levelKey.matches("^(?=.{1,50}$)([a-zA-Z0-9-_]+@)?[a-zA-Z0-9-_]+(:[a-zA-Z0-9-_]+)?$")) + if (!msg.levelKey.matches(CurrentLevelKeyMessage.VALIDATION_REGEX)) { throw new IllegalArgumentException("Server sent invalid level key."); } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java b/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java index 063579181..0933b0c53 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/config/Config.java @@ -34,6 +34,7 @@ import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.pos.DhSectionPos; import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper; import com.seibel.distanthorizons.coreapi.ModInfo; import com.seibel.distanthorizons.coreapi.util.StringUtil; @@ -64,7 +65,7 @@ public class Config public static ConfigCategory client = new ConfigCategory.Builder().set(Client.class).build(); - + @SuppressWarnings("ConcatenationWithEmptyString") public static class Client { public static ConfigEntry quickEnableRendering = new ConfigEntry.Builder() @@ -1007,24 +1008,6 @@ public class Config public static class ServerNetworking { public static ConfigUIComment generalSectionNote = new ConfigUIComment(); - public static ConfigEntry enableServerNetworking = new ConfigEntry.Builder() - .setServersideShortName("enableServerNetworking") - .set(true) - .comment("" - + "WARNING!\n" - + "Server-client networking is not yet fully implemented!\n" - + "Both the server and client must be running the server-side fork with this option enabled\n" - + "for Distant Horizons data to be transceived.\n" - + "\n" - + "If true, the server and client will attempt to communicate to transceive Distant Horizons data.\n" - + "This allows for further distant generation and LOD updates on all clients.\n" - + "\n" - + "This should only be used on trusted servers with trusted players!\n" - + "") - .setSide(EConfigEntryRelevantSide.BOTH) - .build(); - - public static ConfigEntry sendLevelKeys = new ConfigEntry.Builder() .setServersideShortName("sendLevelKeys") .setAppearance(EConfigEntryAppearance.ONLY_IN_FILE) @@ -1037,7 +1020,6 @@ public class Config .build(); public static ConfigEntry levelKeyPrefix = new ConfigEntry.Builder() .setServersideShortName("levelKeyPrefix") - .setAppearance(EConfigEntryAppearance.ONLY_IN_FILE) .set(getDefaultLevelKeyPrefix()) .comment("" + "Prefix of the level keys sent to the clients.\n" @@ -1756,13 +1738,15 @@ public class Config private static String getDefaultLevelKeyPrefix() { IMinecraftSharedWrapper mcWrapper = SingletonInjector.INSTANCE.get(IMinecraftSharedWrapper.class); - if (mcWrapper.isDedicatedServer() && mcWrapper.isWorldNew()) + if (mcWrapper.isDedicatedServer()) { - return "server" + ThreadLocalRandom.current().nextInt(1, 1000); + return mcWrapper.isWorldNew() + ? "server" + ThreadLocalRandom.current().nextInt(1, 1000) + : ""; } else { - return ""; + return SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class).getUsername(); } } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/network/messages/base/CurrentLevelKeyMessage.java b/core/src/main/java/com/seibel/distanthorizons/core/network/messages/base/CurrentLevelKeyMessage.java index 50d05fd3c..68539bfc9 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/network/messages/base/CurrentLevelKeyMessage.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/network/messages/base/CurrentLevelKeyMessage.java @@ -6,6 +6,15 @@ import io.netty.buffer.ByteBuf; public class CurrentLevelKeyMessage extends AbstractNetworkMessage { + public static final int MAX_LENGTH = 150; + + public static final String PART_ALLOWED_CHARS_REGEX = "a-zA-Z0-9-_"; + + // prefix@namespace:path + // 1-150 characters in total, all parts except namespace can be omitted + public static final String VALIDATION_REGEX = "^(?=.{1,$MAX_LENGTH}$)([$PART_ALLOWED_CHARS_REGEX]+@)?[$PART_ALLOWED_CHARS_REGEX]+(:[$PART_ALLOWED_CHARS_REGEX]+)?$"; + + public String levelKey; diff --git a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/minecraft/IMinecraftClientWrapper.java b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/minecraft/IMinecraftClientWrapper.java index 52dd7e0d8..bec5ddcff 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/minecraft/IMinecraftClientWrapper.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/minecraft/IMinecraftClientWrapper.java @@ -76,6 +76,8 @@ public interface IMinecraftClientWrapper extends IBindable UUID getPlayerUUID(); + String getUsername(); + DhBlockPos getPlayerBlockPos(); DhChunkPos getPlayerChunkPos(); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/world/IServerLevelWrapper.java b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/world/IServerLevelWrapper.java index 64577497d..2d9527eb4 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/world/IServerLevelWrapper.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/wrapperInterfaces/world/IServerLevelWrapper.java @@ -19,7 +19,11 @@ package com.seibel.distanthorizons.core.wrapperInterfaces.world; +import com.seibel.distanthorizons.core.api.internal.SharedApi; import com.seibel.distanthorizons.core.config.Config; +import com.seibel.distanthorizons.core.network.messages.base.CurrentLevelKeyMessage; +import com.seibel.distanthorizons.core.world.EWorldEnvironment; + import java.io.File; public interface IServerLevelWrapper extends ILevelWrapper @@ -33,9 +37,23 @@ public interface IServerLevelWrapper extends ILevelWrapper if (Config.Client.Advanced.Multiplayer.ServerNetworking.sendLevelKeys.get()) { String levelKeyPrefix = Config.Client.Advanced.Multiplayer.ServerNetworking.levelKeyPrefix.get(); + + if (SharedApi.getEnvironment() == EWorldEnvironment.CLIENT_SERVER) + { + String cleanWorldFolderName = this.getMcSaveFolder().getParentFile().getName() + .replaceAll("[^" + CurrentLevelKeyMessage.PART_ALLOWED_CHARS_REGEX + " ]", "") + .replaceAll(" ", "_"); + levelKeyPrefix += (!levelKeyPrefix.isEmpty() ? "_" : "") + cleanWorldFolderName; + } + if (!levelKeyPrefix.isEmpty()) { - return levelKeyPrefix + "@" + dimensionName; + String mainPart = "@" + dimensionName; + + return levelKeyPrefix.substring(0, Math.min( + CurrentLevelKeyMessage.MAX_LENGTH - mainPart.length(), + levelKeyPrefix.length() + )) + mainPart; } } diff --git a/core/src/main/resources/assets/distanthorizons/lang/en_us.json b/core/src/main/resources/assets/distanthorizons/lang/en_us.json index 7e5f9bede..3dab8e8bd 100644 --- a/core/src/main/resources/assets/distanthorizons/lang/en_us.json +++ b/core/src/main/resources/assets/distanthorizons/lang/en_us.json @@ -413,8 +413,7 @@ "distanthorizons.config.client.advanced.multiplayer.serverNetworking": "Server Networking", "distanthorizons.config.client.advanced.multiplayer.serverNetworking.generalSectionNote": " \u25cf General", - "distanthorizons.config.client.advanced.multiplayer.serverNetworking.enableServerNetworking": "Enable Server Networking", - "distanthorizons.config.client.advanced.multiplayer.serverNetworking.enableServerNetworking.@tooltip": "§6Attention:§r this feature is not fully implemented. \n\nIf true Distant Horizons will attempt to communicate with the connected \nserver in order to load LODs outside your vanilla render distance. \n\nNote: This requires DH to be installed on the server in order to function.", + "distanthorizons.config.client.advanced.multiplayer.serverNetworking.levelKeyPrefix": "Level Key Prefix", "distanthorizons.config.client.advanced.multiplayer.serverNetworking.generationSectionNote": " \u25cf Generation", "distanthorizons.config.client.advanced.multiplayer.serverNetworking.generationRequestRateLimit": "Rate Limit for Generation Requests", "distanthorizons.config.client.advanced.multiplayer.serverNetworking.generationRequestRateLimit.@tooltip": "How many LOD generation requests per second should a client send? \nAlso limits the amount of player's requests allowed to stay in the server's queue.", From 31fdf9fa436f8e20262e6f8105ab4e19930caeaf Mon Sep 17 00:00:00 2001 From: s809 <43530948+s809@users.noreply.github.com> Date: Sun, 6 Oct 2024 01:44:56 +0500 Subject: [PATCH 5/5] Fix unhandled message spam in replay mod --- .../core/level/DhClientLevel.java | 5 ++ .../core/logging/ConfigBasedLogger.java | 4 +- .../client/ClientNetworkState.java | 69 ++++++++++++------- 3 files changed, 51 insertions(+), 27 deletions(-) diff --git a/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java b/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java index 290ef1083..6319b4bfd 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/level/DhClientLevel.java @@ -130,6 +130,11 @@ public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel this.networkEventSource.registerHandler(FullDataPartialUpdateMessage.class, message -> { + if (MC_CLIENT.connectedToReplay()) + { + return; + } + try { FullDataSourceV2DTO dataSourceDto = this.networkState.decodeDataSourceAndReleaseBuffer(message.payload); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/logging/ConfigBasedLogger.java b/core/src/main/java/com/seibel/distanthorizons/core/logging/ConfigBasedLogger.java index ab59d0eab..7954d3ebf 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/logging/ConfigBasedLogger.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/logging/ConfigBasedLogger.java @@ -90,8 +90,10 @@ public class ConfigBasedLogger public void log(Level level, String str, Object... param) { + Message msg = param.length > 0 + ? this.logger.getMessageFactory().newMessage(str, param) + : this.logger.getMessageFactory().newMessage("{}", str); - Message msg = logger.getMessageFactory().newMessage(str, param); String msgStr = msg.getFormattedMessage(); if (mode.levelForFile.isLessSpecificThan(level)) { diff --git a/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/client/ClientNetworkState.java b/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/client/ClientNetworkState.java index cc5e646c5..c24bff051 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/client/ClientNetworkState.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/multiplayer/client/ClientNetworkState.java @@ -2,6 +2,7 @@ package com.seibel.distanthorizons.core.multiplayer.client; import com.google.common.cache.CacheBuilder; import com.seibel.distanthorizons.core.config.Config; +import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.logging.ConfigBasedLogger; import com.seibel.distanthorizons.core.multiplayer.config.SessionConfig; import com.seibel.distanthorizons.core.network.INetworkObject; @@ -10,12 +11,14 @@ import com.seibel.distanthorizons.core.network.event.internal.CloseInternalEvent import com.seibel.distanthorizons.core.network.event.internal.IncompatibleMessageInternalEvent; import com.seibel.distanthorizons.core.network.messages.base.CurrentLevelKeyMessage; import com.seibel.distanthorizons.core.network.messages.base.SessionConfigMessage; +import com.seibel.distanthorizons.core.network.messages.fullData.FullDataSourceResponseMessage; import com.seibel.distanthorizons.core.network.messages.fullData.FullDataSplitMessage; import com.seibel.distanthorizons.core.network.messages.fullData.FullDataPartialUpdateMessage; import com.seibel.distanthorizons.core.network.messages.fullData.FullDataPayload; import com.seibel.distanthorizons.core.network.session.NetworkSession; import com.seibel.distanthorizons.core.sql.dto.FullDataSourceV2DTO; import com.seibel.distanthorizons.core.util.LodUtil; +import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; import com.seibel.distanthorizons.coreapi.ModInfo; import io.netty.buffer.ByteBufAllocator; import io.netty.buffer.CompositeByteBuf; @@ -32,6 +35,8 @@ public class ClientNetworkState implements Closeable protected static final ConfigBasedLogger LOGGER = new ConfigBasedLogger(LogManager.getLogger(), () -> Config.Client.Advanced.Logging.logNetworkEvent.get()); + private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class); + private final ConcurrentMap fullDataBufferById = CacheBuilder.newBuilder() .expireAfterAccess(10, TimeUnit.SECONDS) @@ -85,41 +90,53 @@ public class ClientNetworkState implements Closeable } }); - this.networkSession.registerHandler(SessionConfigMessage.class, message -> - { - this.serverSupportStatus = EServerSupportStatus.FULL; - - LOGGER.info("Connection config has been changed: ["+message.config+"]."); - this.sessionConfig = message.config; - this.configReceived = true; - }); - this.networkSession.registerHandler(CloseInternalEvent.class, message -> { this.configReceived = false; }); - this.networkSession.registerHandler(FullDataSplitMessage.class, message -> - { - if (message.isFirst) - { - CompositeByteBuf composite = this.fullDataBufferById.remove(message.bufferId); - if (composite != null) - { - composite.release(); - LOGGER.debug("Released full data buffer ["+message.bufferId+"]: ["+composite+"]"); - } - } - - CompositeByteBuf byteBuffer = this.fullDataBufferById.computeIfAbsent(message.bufferId, bufferId -> ByteBufAllocator.DEFAULT.compositeBuffer()); - byteBuffer.addComponent(true, message.buffer); - LOGGER.debug("Full data buffer ["+message.bufferId+"]: ["+byteBuffer+"]."); - }); - this.networkSession.registerHandler(FullDataPartialUpdateMessage.class, msg -> { // Dummy handler to prevent unhandled message warnings }); + + if (MC_CLIENT.connectedToReplay()) + { + // Prevent handling specific messages because replay server is not interactive. + // Level keys are still good because they don't affect anything other than level loading. + + this.networkSession.registerHandler(SessionConfigMessage.class, message -> { }); + this.networkSession.registerHandler(FullDataSourceResponseMessage.class, message -> { }); + this.networkSession.registerHandler(FullDataSplitMessage.class, message -> { }); + } + else + { + this.networkSession.registerHandler(SessionConfigMessage.class, message -> + { + this.serverSupportStatus = EServerSupportStatus.FULL; + + LOGGER.info("Connection config has been changed: [" + message.config + "]."); + this.sessionConfig = message.config; + this.configReceived = true; + }); + + this.networkSession.registerHandler(FullDataSplitMessage.class, message -> + { + if (message.isFirst) + { + CompositeByteBuf composite = this.fullDataBufferById.remove(message.bufferId); + if (composite != null) + { + composite.release(); + LOGGER.debug("Released full data buffer [" + message.bufferId + "]: [" + composite + "]"); + } + } + + CompositeByteBuf byteBuffer = this.fullDataBufferById.computeIfAbsent(message.bufferId, bufferId -> ByteBufAllocator.DEFAULT.compositeBuffer()); + byteBuffer.addComponent(true, message.buffer); + LOGGER.debug("Full data buffer [" + message.bufferId + "]: [" + byteBuffer + "]."); + }); + } }