From 23ac6ec957f34d10ded63a3089769673666ea98d Mon Sep 17 00:00:00 2001 From: James Seibel Date: Sun, 15 Sep 2024 21:15:40 -0500 Subject: [PATCH] merge server side and minor refactoring --- buildAll | 18 +- buildAll.bat | 7 +- common/build.gradle | 8 + .../common/AbstractModInitializer.java | 163 +++++++++++++++++- .../common/AbstractPluginPacketSender.java | 114 ++++++++++++ .../common/CommonPacketPayload.java | 36 ++++ .../common/wrappers/WrapperFactory.java | 18 +- .../wrappers/block/BlockStateWrapper.java | 6 +- .../level/KeyedClientLevelManager.java | 30 ++-- .../level/ServerKeyedClientLevel.java | 3 + .../minecraft/MinecraftClientWrapper.java | 20 ++- .../minecraft/MinecraftServerWrapper.java | 2 +- .../wrappers/misc/IMixinServerPlayer.java | 11 ++ .../wrappers/misc/ServerPlayerWrapper.java | 112 +++++++++--- .../wrappers/world/ClientLevelWrapper.java | 30 ++-- .../wrappers/world/DimensionTypeWrapper.java | 14 +- .../wrappers/world/ServerLevelWrapper.java | 16 +- .../mimicObject/ChunkLoader.java | 2 +- .../1_16.distanthorizons.accesswidener | 3 + coreSubProjects | 2 +- .../fabric/FabricClientProxy.java | 43 +++-- .../distanthorizons/fabric/FabricMain.java | 29 +++- .../fabric/FabricPluginPacketSender.java | 46 +++++ .../fabric/FabricServerProxy.java | 88 ++++++++-- .../client/MixinClientPacketListener.java | 28 --- .../fabric/mixins/client/MixinMinecraft.java | 28 ++- .../mixins/server/MixinServerPlayer.java | 69 ++++++++ .../DistantHorizons.fabric.mixins.json | 3 +- .../forge/ForgeClientProxy.java | 70 +------- .../distanthorizons/forge/ForgeMain.java | 17 +- .../forge/ForgePluginPacketSender.java | 130 ++++++++++++++ .../forge/ForgeServerProxy.java | 54 +++++- .../mixins/server/MixinServerPlayer.java | 61 +++++++ .../DistantHorizons.forge.mixins.json | 3 +- .../neoforge/NeoforgeClientProxy.java | 70 +------- .../neoforge/NeoforgeMain.java | 35 +++- .../neoforge/NeoforgePluginPacketSender.java | 50 ++++++ .../neoforge/NeoforgeServerProxy.java | 26 +++ .../client/MixinClientPacketListener.java | 11 +- .../mixins/server/MixinServerPlayer.java | 73 ++++++++ .../DistantHorizons.neoforge.mixins.json | 3 +- 41 files changed, 1237 insertions(+), 315 deletions(-) create mode 100644 common/src/main/java/com/seibel/distanthorizons/common/AbstractPluginPacketSender.java create mode 100644 common/src/main/java/com/seibel/distanthorizons/common/CommonPacketPayload.java create mode 100644 common/src/main/java/com/seibel/distanthorizons/common/wrappers/misc/IMixinServerPlayer.java create mode 100644 fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricPluginPacketSender.java create mode 100644 fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinServerPlayer.java create mode 100644 forge/src/main/java/com/seibel/distanthorizons/forge/ForgePluginPacketSender.java create mode 100644 forge/src/main/java/com/seibel/distanthorizons/forge/mixins/server/MixinServerPlayer.java create mode 100644 neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgePluginPacketSender.java create mode 100644 neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinServerPlayer.java diff --git a/buildAll b/buildAll index c34616428..5f826736c 100755 --- a/buildAll +++ b/buildAll @@ -1,7 +1,8 @@ #!/bin/sh echo "==================== Note: All build jars will be in the folder called 'buildAllJars' ====================" -mkdir -p buildAllJars | true +mkdir -p buildAllJars +rm -rf buildAllJars/* # Loop trough everything in the version properties folder for d in versionProperties/*; do @@ -11,12 +12,17 @@ for d in versionProperties/*; do # Clean out the folders, build it, and merge it # (We could use "./" to run gradlew, but as it is a shell script im going to be running it with the "sh" command) echo "==================== Cleaning workspace to build $version ====================" - sh gradlew clean -PmcVer=$version --no-daemon || true + sh gradlew clean -PmcVer=$version + if [ $? != 0 ]; then continue; fi + echo "====================Building $version ====================" - sh gradlew build -PmcVer=$version --no-daemon || true + sh gradlew build -PmcVer=$version + if [ $? != 0 ]; then continue; fi + echo "==================== Merging $version ====================" - sh gradlew mergeJars -PmcVer=$version --no-daemon || true + sh gradlew mergeJars -PmcVer=$version + if [ $? != 0 ]; then continue; fi + echo "==================== Moving jar ====================" - mv Merged/*.jar buildAllJars/ || true - # The "| true" at the end of those are just to make sure the script continues even if a build fails + mv Merged/*.jar buildAllJars/ done diff --git a/buildAll.bat b/buildAll.bat index eb69d5c31..0197cc4fd 100644 --- a/buildAll.bat +++ b/buildAll.bat @@ -5,6 +5,7 @@ echo ==================== Note: All build jars will be in the folder called 'buildAllJars' ==================== mkdir buildAllJars +del buildAllJars/* @rem Loop trough everything in the version properties folder for %%f in (versionProperties\*) do ( @@ -13,11 +14,11 @@ for %%f in (versionProperties\*) do ( @rem Clean out the folders, build it, and merge it echo ==================== Cleaning workspace to build !version! ==================== - call .\gradlew.bat clean -PmcVer="!version!" --no-daemon + call .\gradlew.bat clean -PmcVer="!version!" echo ==================== Building !version! ==================== - call .\gradlew.bat build -PmcVer="!version!" --no-daemon + call .\gradlew.bat build -PmcVer="!version!" echo ==================== Merging !version! ==================== - call .\gradlew.bat mergeJars -PmcVer="!version!" --no-daemon + call .\gradlew.bat mergeJars -PmcVer="!version!" echo ==================== Moving jar ==================== move Merged\*.jar buildAllJars\ ) diff --git a/common/build.gradle b/common/build.gradle index 72e64e14d..13164c193 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -1,3 +1,11 @@ +// TODO can this be removed? +//buildscript { +// configurations.configureEach { +// resolutionStrategy { +// force 'org.spongepowered:vanillagradle:0.2.1-20240507.024226-82' +// } +// } +//} // temporary fix for broken spongepowered version buildscript { diff --git a/common/src/main/java/com/seibel/distanthorizons/common/AbstractModInitializer.java b/common/src/main/java/com/seibel/distanthorizons/common/AbstractModInitializer.java index 08f1509cf..029ee46b7 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/AbstractModInitializer.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/AbstractModInitializer.java @@ -1,18 +1,28 @@ package com.seibel.distanthorizons.common; +import com.mojang.brigadier.Command; import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.*; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiAfterDhInitEvent; import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeDhInitEvent; import com.seibel.distanthorizons.common.wrappers.DependencySetup; -import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftDedicatedServerWrapper; +import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftServerWrapper; +import com.seibel.distanthorizons.common.wrappers.misc.ServerPlayerWrapper; import com.seibel.distanthorizons.core.api.internal.SharedApi; import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.config.ConfigBase; import com.seibel.distanthorizons.core.config.eventHandlers.presets.ThreadPresetConfigEventHandler; +import com.seibel.distanthorizons.core.config.types.AbstractConfigType; +import com.seibel.distanthorizons.core.config.types.ConfigEntry; import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.jar.ModJarInfo; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; +import com.seibel.distanthorizons.core.network.messages.base.CodecCrashMessage; +import com.seibel.distanthorizons.core.util.objects.Pair; +import com.seibel.distanthorizons.core.world.DhServerWorld; import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModAccessor; import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker; import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector; @@ -23,9 +33,25 @@ import net.minecraft.server.dedicated.DedicatedServer; import org.apache.logging.log4j.Logger; import java.lang.invoke.MethodHandles; +import java.util.HashMap; +import java.util.Objects; +import java.util.function.BiFunction; import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.Supplier; +import static com.mojang.brigadier.arguments.DoubleArgumentType.doubleArg; +import static com.mojang.brigadier.arguments.IntegerArgumentType.integer; +import static com.seibel.distanthorizons.core.network.messages.MessageRegistry.DEBUG_CODEC_CRASH_MESSAGE; +import static net.minecraft.commands.Commands.argument; +import static net.minecraft.commands.Commands.literal; + +#if MC_VER >= MC_1_19_2 +import net.minecraft.network.chat.Component; +#else // < 1.19.2 +import net.minecraft.network.chat.TranslatableComponent; +#endif + /** * Base for all mod loader initializers * and handles most setup. @@ -100,6 +126,8 @@ public abstract class AbstractModInitializer this.createServerProxy(true).registerEvents(); + this.initializeModCompat(); + LOGGER.info(ModInfo.READABLE_NAME + " Initialized"); ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterDhInitEvent.class, null); @@ -107,7 +135,7 @@ public abstract class AbstractModInitializer this.subscribeServerStartingEvent(server -> { - MinecraftDedicatedServerWrapper.INSTANCE.dedicatedServer = (DedicatedServer)server; + MinecraftServerWrapper.INSTANCE.dedicatedServer = (DedicatedServer)server; this.initConfig(); this.postInit(); @@ -166,7 +194,136 @@ public abstract class AbstractModInitializer LOGGER.info("Mod Post-Initialized"); } - private void initCommands() { /* currently unimplemented */ } + @SuppressWarnings({"rawtypes", "unchecked"}) + private void initCommands() + { + LiteralArgumentBuilder builder = literal("dhconfig") + .requires(source -> source.hasPermission(4)); + + for (AbstractConfigType type : ConfigBase.INSTANCE.entries) + { + if (!(type instanceof ConfigEntry)) + { + continue; + } + //noinspection PatternVariableCanBeUsed + ConfigEntry configEntry = (ConfigEntry) type; + if (configEntry.getServersideShortName() == null) + { + continue; + } + + Function< + Function, Object>, + Command + > makeConfigUpdater = (getter) -> (commandContext) -> { + Object value = getter.apply(commandContext); + + commandContext.getSource().sendSuccess( + #if MC_VER >= MC_1_20_1 + () -> Component.literal("Changed the value of "+configEntry.getServersideShortName()+" to "+value), + #elif MC_VER >= MC_1_19_2 + Component.literal("Changed the value of "+configEntry.getServersideShortName()+" to "+value), + #else + new TranslatableComponent("Changed the value of "+configEntry.getServersideShortName()+" to "+value), + #endif + true); + configEntry.set(value); + return 1; + }; + + LiteralArgumentBuilder subcommand = literal(configEntry.getServersideShortName()) + .executes((commandContext) -> { + #if MC_VER >= MC_1_20_1 + commandContext.getSource().sendSuccess(() -> Component.literal("Current value of "+configEntry.getServersideShortName()+" is "+configEntry.get()), true); + #elif MC_VER >= MC_1_19_2 + commandContext.getSource().sendSuccess(Component.literal("Current value of "+configEntry.getServersideShortName()+" is "+configEntry.get()), true); + #else // < 1.19.2 + commandContext.getSource().sendSuccess(new TranslatableComponent("Current value of "+configEntry.getServersideShortName()+" is "+configEntry.get()), true); + #endif + return 1; + }); + + if (Enum.class.isAssignableFrom(configEntry.getType())) + { + for (Object choice : configEntry.getType().getEnumConstants()) + { + subcommand.then( + literal(choice.toString()) + .executes(makeConfigUpdater.apply(c -> choice)) + ); + } + } + else + { + boolean setterAdded = false; + + for (java.util.Map.Entry, Pair>, BiFunction, String, ?>>> pair : new HashMap< + Class, + Pair< + Supplier>, + BiFunction, String, ?>> + >() {{ + this.put(Integer.class, new Pair<>(() -> integer((int) configEntry.getMin(), (int) configEntry.getMax()), IntegerArgumentType::getInteger)); + this.put(Double.class, new Pair<>(() -> doubleArg((double) configEntry.getMin(), (double) configEntry.getMax()), DoubleArgumentType::getDouble)); + this.put(Boolean.class, new Pair<>(BoolArgumentType::bool, BoolArgumentType::getBool)); + this.put(String.class, new Pair<>(StringArgumentType::string, StringArgumentType::getString)); + }}.entrySet()) + { + if (!pair.getKey().isAssignableFrom(configEntry.getType())) + { + continue; + } + + subcommand.then(argument("value", pair.getValue().first.get()) + .executes(makeConfigUpdater.apply(c -> pair.getValue().second.apply(c, "value")))); + + setterAdded = true; + break; + } + + if (!setterAdded) + { + throw new RuntimeException("Config type of "+type.getName()+" is not supported: "+configEntry.getType().getSimpleName()); + } + } + + builder.then(subcommand); + } + + this.commandDispatcher.register(builder); + + if (DEBUG_CODEC_CRASH_MESSAGE) + { + LiteralArgumentBuilder dhcrash = literal("dhcrash") + .requires(source -> source.hasPermission(4)) + .then(literal("encode") + .executes(c -> { + assert SharedApi.getIDhServerWorld() != null; + ((DhServerWorld) SharedApi.getIDhServerWorld()).remotePlayerConnectionHandler + #if MC_VER >= MC_1_19_2 + .getConnectedPlayer(ServerPlayerWrapper.getWrapper(Objects.requireNonNull(c.getSource().getPlayer()))) + #else + .getConnectedPlayer(ServerPlayerWrapper.getWrapper(Objects.requireNonNull(c.getSource().getPlayerOrException()))) + #endif + .networkSession.sendMessage(new CodecCrashMessage(CodecCrashMessage.ECrashPhase.ENCODE)); + return 1; + })) + .then(literal("decode") + .executes(c -> { + assert SharedApi.getIDhServerWorld() != null; + ((DhServerWorld) SharedApi.getIDhServerWorld()).remotePlayerConnectionHandler + #if MC_VER >= MC_1_19_2 + .getConnectedPlayer(ServerPlayerWrapper.getWrapper(Objects.requireNonNull(c.getSource().getPlayer()))) + #else + .getConnectedPlayer(ServerPlayerWrapper.getWrapper(Objects.requireNonNull(c.getSource().getPlayerOrException()))) + #endif + .networkSession.sendMessage(new CodecCrashMessage(CodecCrashMessage.ECrashPhase.DECODE)); + return 1; + })); + this.commandDispatcher.register(dhcrash); + } + } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/AbstractPluginPacketSender.java b/common/src/main/java/com/seibel/distanthorizons/common/AbstractPluginPacketSender.java new file mode 100644 index 000000000..85b4141a0 --- /dev/null +++ b/common/src/main/java/com/seibel/distanthorizons/common/AbstractPluginPacketSender.java @@ -0,0 +1,114 @@ +package com.seibel.distanthorizons.common; + +import com.seibel.distanthorizons.core.config.Config; +import com.seibel.distanthorizons.core.logging.ConfigBasedLogger; +import com.seibel.distanthorizons.core.network.event.internal.IncompatibleMessageInternalEvent; +import com.seibel.distanthorizons.core.network.event.internal.ProtocolErrorInternalEvent; +import com.seibel.distanthorizons.core.network.messages.MessageRegistry; +import com.seibel.distanthorizons.core.network.messages.AbstractNetworkMessage; +import com.seibel.distanthorizons.core.network.messages.base.CloseReasonMessage; +import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender; +import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper; +import com.seibel.distanthorizons.coreapi.ModInfo; +import io.netty.buffer.ByteBufUtil; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; +import org.apache.logging.log4j.LogManager; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.util.Objects; + +public abstract class AbstractPluginPacketSender implements IPluginPacketSender +{ + private static final ConfigBasedLogger LOGGER = new ConfigBasedLogger(LogManager.getLogger(), + () -> Config.Client.Advanced.Logging.logNetworkEvent.get()); + + #if MC_VER >= MC_1_21_1 + public static final ResourceLocation WRAPPER_PACKET_RESOURCE = ResourceLocation.fromNamespaceAndPath(ModInfo.RESOURCE_NAMESPACE, ModInfo.WRAPPER_PACKET_PATH); + #else + public static final ResourceLocation WRAPPER_PACKET_RESOURCE = new ResourceLocation(ModInfo.RESOURCE_NAMESPACE, ModInfo.WRAPPER_PACKET_PATH); + #endif + + + @Override + public final void sendPluginServerPacket(IServerPlayerWrapper serverPlayer, AbstractNetworkMessage message) + { + this.sendPluginPacketServer((ServerPlayer) serverPlayer.getWrappedMcObject(), message); + } + + @Override + public abstract void sendPluginClientPacket(AbstractNetworkMessage message); + public abstract void sendPluginPacketServer(ServerPlayer serverPlayer, AbstractNetworkMessage message); + + @Nullable + public static AbstractNetworkMessage decodeMessage(FriendlyByteBuf in) + { + AbstractNetworkMessage message = null; + + try + { + in.markReaderIndex(); + + int protocolVersion = in.readShort(); + if (protocolVersion != ModInfo.PROTOCOL_VERSION) + { + return new IncompatibleMessageInternalEvent(protocolVersion); + } + + message = MessageRegistry.INSTANCE.createMessage(in.readUnsignedShort()); + message.decode(in); + + if (in.isReadable()) + { + throw new IOException("Buffer has not been fully read"); + } + + return message; + } + catch (Exception e) + { + in.resetReaderIndex(); + + LOGGER.error("Failed to decode message", e); + LOGGER.error("Buffer: ["+in+"]"); + LOGGER.error("Buffer contents: ["+ByteBufUtil.hexDump(in)+"]"); + + return new ProtocolErrorInternalEvent(e, message, true); + } + finally + { + // Prevent connection crashing if not entire buffer has been read + in.readerIndex(in.writerIndex()); + } + } + + public static void encodeMessage(FriendlyByteBuf out, AbstractNetworkMessage message) + { + // This is intentionally unhandled, because errors related to this are unlikely to appear in wild + Objects.requireNonNull(message); + out.writeShort(ModInfo.PROTOCOL_VERSION); + + try + { + out.markWriterIndex(); + out.writeShort(MessageRegistry.INSTANCE.getMessageId(message)); + message.encode(out); + } + catch (Exception e) + { + LOGGER.error("Failed to encode message", e); + LOGGER.error("Message: ["+message+"]"); + + message.getSession().tryHandleMessage(new ProtocolErrorInternalEvent(e, message, false)); + + // Encode close reason message instead + out.resetWriterIndex(); + message = new CloseReasonMessage("Internal error on other side"); + out.writeShort(MessageRegistry.INSTANCE.getMessageId(message)); + message.encode(out); + } + } + +} \ No newline at end of file diff --git a/common/src/main/java/com/seibel/distanthorizons/common/CommonPacketPayload.java b/common/src/main/java/com/seibel/distanthorizons/common/CommonPacketPayload.java new file mode 100644 index 000000000..07fa39e61 --- /dev/null +++ b/common/src/main/java/com/seibel/distanthorizons/common/CommonPacketPayload.java @@ -0,0 +1,36 @@ +package com.seibel.distanthorizons.common; + +#if MC_VER >= MC_1_20_6 + +import com.seibel.distanthorizons.core.network.messages.AbstractNetworkMessage; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public record CommonPacketPayload(@Nullable AbstractNetworkMessage message) implements CustomPacketPayload +{ + public static final Type TYPE = new Type<>(AbstractPluginPacketSender.WRAPPER_PACKET_RESOURCE); + + @NotNull + @Override + public Type type() { return TYPE; } + + + public static class Codec implements StreamCodec + { + @NotNull + @Override + public CommonPacketPayload decode(@NotNull FriendlyByteBuf in) + { return new CommonPacketPayload(AbstractPluginPacketSender.decodeMessage(in)); } + + @Override + public void encode(@NotNull FriendlyByteBuf out, CommonPacketPayload payload) + { AbstractPluginPacketSender.encodeMessage(out, payload.message()); } + + } + +} + +#endif \ No newline at end of file diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/WrapperFactory.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/WrapperFactory.java index f1916a214..9dde4a9e4 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/WrapperFactory.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/WrapperFactory.java @@ -179,19 +179,9 @@ public class WrapperFactory implements IWrapperFactory // level wrapper - ILevelWrapper levelWrapper; - if (level instanceof ServerLevel) - { - levelWrapper = ServerLevelWrapper.getWrapper((ServerLevel)level); - } - else if (level instanceof ClientLevel) - { - levelWrapper = ClientLevelWrapper.getWrapper((ClientLevel)level); - } - else - { - throw new ClassCastException(createChunkWrapperErrorMessage(objectArray)); - } + ILevelWrapper levelWrapper = level.isClientSide() + ? ClientLevelWrapper.getWrapper((ClientLevel)level) + : ServerLevelWrapper.getWrapper((ServerLevel)level); return new ChunkWrapper(chunk, lightSource, levelWrapper); @@ -215,7 +205,7 @@ public class WrapperFactory implements IWrapperFactory expectedClassNames = new String[] { ChunkAccess.class.getName(), - ServerLevel.class.getName() + "] or [" + ClientLevel.class.getName() + "[ServerLevel] or [ClientLevel]" // Classes are not referenced by names to avoid exception when one of them is missing }; //#endif diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BlockStateWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BlockStateWrapper.java index 7bed7f5d7..1711abaec 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BlockStateWrapper.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/block/BlockStateWrapper.java @@ -54,7 +54,6 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Registry; import net.minecraft.world.level.EmptyBlockGetter; #else -import net.minecraft.client.Minecraft; import net.minecraft.world.level.Level; import net.minecraft.core.BlockPos; import net.minecraft.core.registries.Registries; @@ -562,9 +561,8 @@ public class BlockStateWrapper implements IBlockStateWrapper { #if MC_VER > MC_1_17_1 - // use the given level if possible, otherwise try using the currently loaded one - Level level = (levelWrapper != null ? (Level) levelWrapper.getWrappedMcObject() : null); - level = (level == null ? Minecraft.getInstance().level : level); + LodUtil.assertTrue(levelWrapper != null && levelWrapper.getWrappedMcObject() != null); + Level level = (Level)levelWrapper.getWrappedMcObject(); #endif Block block; diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/level/KeyedClientLevelManager.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/level/KeyedClientLevelManager.java index b0de02033..daa28bf05 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/level/KeyedClientLevelManager.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/level/KeyedClientLevelManager.java @@ -1,21 +1,19 @@ package com.seibel.distanthorizons.common.wrappers.level; -import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper; import com.seibel.distanthorizons.core.level.IServerKeyedClientLevel; import com.seibel.distanthorizons.core.level.IKeyedClientLevelManager; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; -import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; import net.minecraft.client.multiplayer.ClientLevel; - -import java.util.Objects; +import org.jetbrains.annotations.Nullable; public class KeyedClientLevelManager implements IKeyedClientLevelManager { public static final KeyedClientLevelManager INSTANCE = new KeyedClientLevelManager(); /** This is set and managed by the ClientApi for servers with support for DH. */ - private IServerKeyedClientLevel overrideWrapper = null; - private boolean useOverrideWrapper = false; + @Nullable + private IServerKeyedClientLevel serverKeyedLevel = null; + //=============// @@ -31,24 +29,20 @@ public class KeyedClientLevelManager implements IKeyedClientLevelManager //======================// @Override - public void setServerKeyedLevel(IServerKeyedClientLevel clientLevel) { this.overrideWrapper = clientLevel; } - @Override - public IServerKeyedClientLevel getOverrideWrapper() { return this.overrideWrapper; } + @Nullable + public IServerKeyedClientLevel getServerKeyedLevel() { return this.serverKeyedLevel; } @Override - public IServerKeyedClientLevel getServerKeyedLevel(ILevelWrapper level, String serverLevelKey) + public IServerKeyedClientLevel setServerKeyedLevel(IClientLevelWrapper clientLevel, String levelKey) { - Objects.requireNonNull(level); - Objects.requireNonNull(serverLevelKey); - return new ServerKeyedClientLevel((ClientLevel) level.getWrappedMcObject(), serverLevelKey); + IServerKeyedClientLevel keyedLevel = new ServerKeyedClientLevel((ClientLevel) clientLevel.getWrappedMcObject(), levelKey); + this.serverKeyedLevel = keyedLevel; + return keyedLevel; } - @Override - public void setUseOverrideWrapper(boolean useOverrideWrapper) { this.useOverrideWrapper = useOverrideWrapper; } + public void clearKeyedLevel() { this.serverKeyedLevel = null; } @Override - public boolean getUseOverrideWrapper() { return this.useOverrideWrapper; } - - + public boolean hasLevelSet() { return this.serverKeyedLevel != null; } } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/level/ServerKeyedClientLevel.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/level/ServerKeyedClientLevel.java index 86048c145..3e07eba12 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/level/ServerKeyedClientLevel.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/level/ServerKeyedClientLevel.java @@ -18,4 +18,7 @@ public class ServerKeyedClientLevel extends ClientLevelWrapper implements IServe @Override public String getServerLevelKey() { return this.serverLevelKey; } + @Override + public String getDimensionName() { return this.getServerLevelKey(); } + } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/minecraft/MinecraftClientWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/minecraft/MinecraftClientWrapper.java index dcf6ccf41..ce85f8e27 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/minecraft/MinecraftClientWrapper.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/minecraft/MinecraftClientWrapper.java @@ -44,6 +44,7 @@ import com.seibel.distanthorizons.core.pos.DhChunkPos; import net.minecraft.CrashReport; import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.multiplayer.ServerData; import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.BlockPos; @@ -220,14 +221,19 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra @Nullable @Override - public IClientLevelWrapper getWrappedClientLevel() + public IClientLevelWrapper getWrappedClientLevel() { return this.getWrappedClientLevel(false); } + + @Override + @Nullable + public IClientLevelWrapper getWrappedClientLevel(boolean bypassLevelKeyManager) { - if (MINECRAFT.level == null) + ClientLevel level = MINECRAFT.level; + if (level == null) { return null; } - return ClientLevelWrapper.getWrapperIgnoringOverride(MINECRAFT.level); + return ClientLevelWrapper.getWrapper(level, bypassLevelKeyManager); } @Override @@ -266,7 +272,10 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra public void sendChatMessage(String string) { LocalPlayer player = this.getPlayer(); - if (player == null) return; + if (player == null) + { + return; + } #if MC_VER < MC_1_19_2 player.sendMessage(new TextComponent(string), getPlayer().getUUID()); #else @@ -306,4 +315,7 @@ public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecra @Override public void executeOnRenderThread(Runnable runnable) { MINECRAFT.execute(runnable); } + @Override + public boolean isWorldNew() { throw new UnsupportedOperationException("Not Implemented"); } + } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/minecraft/MinecraftServerWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/minecraft/MinecraftServerWrapper.java index 39fc3ad67..1410e785a 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/minecraft/MinecraftServerWrapper.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/minecraft/MinecraftServerWrapper.java @@ -44,7 +44,7 @@ public class MinecraftServerWrapper implements IMinecraftSharedWrapper } @Override - public boolean isWorldInitialized() + public boolean isWorldNew() { return this.dedicatedServer.getWorldData().overworldData().isInitialized(); } } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/misc/IMixinServerPlayer.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/misc/IMixinServerPlayer.java new file mode 100644 index 000000000..54e5a4dac --- /dev/null +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/misc/IMixinServerPlayer.java @@ -0,0 +1,11 @@ +package com.seibel.distanthorizons.common.wrappers.misc; + +import net.minecraft.server.level.ServerLevel; +import org.jetbrains.annotations.Nullable; + +public interface IMixinServerPlayer +{ + @Nullable + ServerLevel distantHorizons$getDimensionChangeDestination(); + +} diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/misc/ServerPlayerWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/misc/ServerPlayerWrapper.java index 63e54c45b..8fd6d97b5 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/misc/ServerPlayerWrapper.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/misc/ServerPlayerWrapper.java @@ -1,55 +1,115 @@ package com.seibel.distanthorizons.common.wrappers.misc; +import com.google.common.base.Objects; import com.google.common.collect.MapMaker; import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper; +import com.seibel.distanthorizons.core.util.math.Vec3d; +import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.ServerGamePacketListenerImpl; +import net.minecraft.world.phys.Vec3; -import java.util.UUID; +import java.net.SocketAddress; import java.util.concurrent.ConcurrentMap; +/** + * This wrapper transparently ensures that the underlying {@link ServerPlayer} is always valid, + * unless the player has disconnected. + */ public class ServerPlayerWrapper implements IServerPlayerWrapper { - private static final ConcurrentMap - serverPlayerWrapperMap = new MapMaker().weakKeys().makeMap(); + private static final ConcurrentMap serverPlayerWrapperMap = new MapMaker().weakKeys().weakValues().makeMap(); - private final ServerPlayer serverPlayer; + private final ServerGamePacketListenerImpl connection; - public static ServerPlayerWrapper getWrapper(ServerPlayer serverPlayer) - { - return serverPlayerWrapperMap.computeIfAbsent(serverPlayer, ServerPlayerWrapper::new); - } - private ServerPlayerWrapper(ServerPlayer serverPlayer) - { - this.serverPlayer = serverPlayer; - } - public UUID getUUID() - { - return serverPlayer.getUUID(); - } + //=============// + // constructor // + //=============// + public static ServerPlayerWrapper getWrapper(ServerPlayer serverPlayer) + { return serverPlayerWrapperMap.computeIfAbsent(serverPlayer.connection, ignored -> new ServerPlayerWrapper(serverPlayer.connection)); } + + private ServerPlayerWrapper(ServerGamePacketListenerImpl connection) { this.connection = connection; } + + + + //=========// + // getters // + //=========// + + private ServerPlayer getServerPlayer() { return this.connection.player; } + + @Override + public String getName() { return this.getServerPlayer().getName().getString(); } + + @Override public IServerLevelWrapper getLevel() { - #if MC_VER < MC_1_20_1 - return ServerLevelWrapper.getWrapper(this.serverPlayer.getLevel()); - #else - return ServerLevelWrapper.getWrapper(this.serverPlayer.serverLevel()); + ServerLevel level = ((IMixinServerPlayer) this.getServerPlayer()).distantHorizons$getDimensionChangeDestination(); + if (level == null) + { + #if MC_VER < MC_1_20_1 + level = this.serverPlayer().getLevel(); + #else + level = this.getServerPlayer().serverLevel(); + #endif + } + + return ServerLevelWrapper.getWrapper(level); + } + + @Override + public Vec3d getPosition() + { + Vec3 position = this.getServerPlayer().position(); + return new Vec3d(position.x, position.y, position.z); + } + + @Override + public int getViewDistance() { return this.getServerPlayer().server.getPlayerList().getViewDistance(); } + + @Override + public SocketAddress getRemoteAddress() + { + #if MC_VER >= MC_1_19_4 + return this.getServerPlayer().connection.getRemoteAddress(); + #else // < 1.19.4 + return this.serverPlayer().connection.connection.getRemoteAddress(); #endif } + + + //================// + // base overrides // + //================// + @Override - public Object getWrappedMcObject() + public Object getWrappedMcObject() { return this.getServerPlayer(); } + + @Override + public String toString() { return "Wrapped{" + this.getServerPlayer() + "}"; } + + @Override + public boolean equals(Object obj) { - return this.serverPlayer(); + if (this == obj) + { + return true; + } + if (!(obj instanceof ServerPlayerWrapper)) + { + return false; + } + ServerPlayerWrapper that = (ServerPlayerWrapper) obj; + return Objects.equal(this.connection, that.connection); } @Override - public String toString() - { - return "Wrapped{" + serverPlayer.toString() + "}"; - } + public int hashCode() { return Objects.hashCode(this.connection); } } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ClientLevelWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ClientLevelWrapper.java index f38d99cb6..883388b1b 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ClientLevelWrapper.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ClientLevelWrapper.java @@ -9,6 +9,7 @@ import com.seibel.distanthorizons.common.wrappers.block.ClientBlockStateColorCac import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.level.*; +import com.seibel.distanthorizons.core.level.IServerKeyedClientLevel; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos; import com.seibel.distanthorizons.core.pos.DhChunkPos; @@ -69,23 +70,28 @@ public class ClientLevelWrapper implements IClientLevelWrapper // wrapper logic // //===============// + public static IClientLevelWrapper getWrapper(@NotNull ClientLevel level) { return getWrapper(level, false); } + @Nullable - public static IClientLevelWrapper getWrapper(@Nullable ClientLevel level) + public static IClientLevelWrapper getWrapper(@Nullable ClientLevel level, boolean bypassLevelKeyManager) { - if (level == null) + if (!bypassLevelKeyManager) { - return null; + if (level == null) + { + return null; + } + + // used if the client is connected to a server that defines the currently loaded level + IServerKeyedClientLevel overrideLevel = KEYED_CLIENT_LEVEL_MANAGER.getServerKeyedLevel(); + if (overrideLevel != null) + { + return overrideLevel; + } } - // used if the client is connected to a server that defines the currently loaded level - if (KEYED_CLIENT_LEVEL_MANAGER.getUseOverrideWrapper()) - { - return KEYED_CLIENT_LEVEL_MANAGER.getOverrideWrapper(); - } - - return getWrapperIgnoringOverride(level); + return LEVEL_WRAPPER_BY_CLIENT_LEVEL.computeIfAbsent(level, ClientLevelWrapper::new); } - public static IClientLevelWrapper getWrapperIgnoringOverride(@NotNull ClientLevel level) { return LEVEL_WRAPPER_BY_CLIENT_LEVEL.computeIfAbsent(level, ClientLevelWrapper::new); } @Nullable @Override @@ -118,8 +124,6 @@ public class ClientLevelWrapper implements IClientLevelWrapper } } - - //====================// // base level methods // //====================// diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/DimensionTypeWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/DimensionTypeWrapper.java index 7264e7488..be5175eb6 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/DimensionTypeWrapper.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/DimensionTypeWrapper.java @@ -63,10 +63,14 @@ public class DimensionTypeWrapper implements IDimensionTypeWrapper } - @Override - public String getDimensionName() + private String getDimensionName() { - return dimensionType.effectsLocation().getPath(); + #if MC_VER <= MC_1_16_5 + // effectsLocation() is marked as client only, so using the backing field directly + return dimensionType.effectsLocation.getPath(); + #else + return this.dimensionType.effectsLocation().getPath(); + #endif } @Override @@ -87,7 +91,9 @@ public class DimensionTypeWrapper implements IDimensionTypeWrapper return this.dimensionType; } - + // there's definitely a better way of doing this, but it should work well enough for now + @Override + public boolean isTheEnd() { return this.getDimensionName().equalsIgnoreCase("the_end"); } @Override public boolean equals(Object obj) diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ServerLevelWrapper.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ServerLevelWrapper.java index 2cb04eb5c..ca2ac0ca1 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ServerLevelWrapper.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/world/ServerLevelWrapper.java @@ -116,10 +116,18 @@ public class ServerLevelWrapper implements IServerLevelWrapper @Override public IChunkWrapper tryGetChunk(DhChunkPos pos) { - if (!level.hasChunk(pos.getX(), pos.getZ())) return null; - ChunkAccess chunk = level.getChunk(pos.getX(), pos.getZ(), ChunkStatus.FULL, false); - if (chunk == null) return null; - return new ChunkWrapper(chunk, level, this); + if (!this.level.hasChunk(pos.getX(), pos.getZ())) + { + return null; + } + + ChunkAccess chunk = this.level.getChunk(pos.getX(), pos.getZ(), ChunkStatus.FULL, false); + if (chunk == null) + { + return null; + } + + return new ChunkWrapper(chunk, this.level, this); } @Override diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/ChunkLoader.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/ChunkLoader.java index 1a3f77e3f..1a23cc903 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/ChunkLoader.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/ChunkLoader.java @@ -128,7 +128,7 @@ public class ChunkLoader ChunkPos actualPos = new ChunkPos(tagLevel.getInt("xPos"), tagLevel.getInt("zPos")); if (!Objects.equals(chunkPos, actualPos)) { - #if MC_VER > MC_1_17_1 + #if MC_VER >= MC_1_18_2 if (actualPos.equals(ChunkPos.ZERO)) #else if (actualPos.equals(ChunkPos.INVALID_CHUNK_POS)) diff --git a/common/src/main/resources/1_16.distanthorizons.accesswidener b/common/src/main/resources/1_16.distanthorizons.accesswidener index 969ac463d..efb1e6a1f 100644 --- a/common/src/main/resources/1_16.distanthorizons.accesswidener +++ b/common/src/main/resources/1_16.distanthorizons.accesswidener @@ -47,4 +47,7 @@ accessible field net/minecraft/client/renderer/texture/TextureAtlasSprite frames accessible field net/minecraft/client/renderer/texture/TextureAtlasSprite framesY [I accessible field net/minecraft/client/renderer/texture/TextureAtlasSprite mainImage [Lcom/mojang/blaze3d/platform/NativeImage; +# DimensionTypeWrapper workaround +accessible field net/minecraft/world/level/dimension/DimensionType effectsLocation Lnet/minecraft/resources/ResourceLocation; + extendable class com/mojang/math/Matrix4f diff --git a/coreSubProjects b/coreSubProjects index 6d6cbd8a4..11e58eecd 160000 --- a/coreSubProjects +++ b/coreSubProjects @@ -1 +1 @@ -Subproject commit 6d6cbd8a44ecc27e18d3227c7ab6edb921cf1068 +Subproject commit 11e58eecdaa6b64d990f9d62d9e7886f6bcda6fe diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricClientProxy.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricClientProxy.java index 3a98a2f40..6d3ff981b 100644 --- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricClientProxy.java +++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricClientProxy.java @@ -20,6 +20,7 @@ package com.seibel.distanthorizons.fabric; import com.seibel.distanthorizons.common.AbstractModInitializer; +import com.seibel.distanthorizons.common.AbstractPluginPacketSender; import com.seibel.distanthorizons.common.wrappers.McObjectConverter; import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper; import com.seibel.distanthorizons.core.api.internal.ClientApi; @@ -40,12 +41,20 @@ import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientChunkEvents; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; +import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; import net.fabricmc.fabric.api.event.player.AttackBlockCallback; import net.fabricmc.fabric.api.event.player.UseBlockCallback; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.TitleScreen; +#if MC_VER >= MC_1_20_6 +import com.seibel.distanthorizons.common.CommonPacketPayload; +import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; +#else +import com.seibel.distanthorizons.core.network.messages.NetworkMessage; +#endif + #if MC_VER < MC_1_19_4 import java.nio.FloatBuffer; #endif @@ -243,17 +252,29 @@ public class FabricClientProxy implements AbstractModInitializer.IEventProxy // networking event // //==================// -// ClientPlayNetworking.registerGlobalReceiver(new ResourceLocation(ModInfo.NETWORKING_RESOURCE_NAMESPACE, ModInfo.MULTIVERSE_PLUGIN_NAMESPACE), -// (Minecraft client, ClientPacketListener handler, FriendlyByteBuf friendlyByteBuf, PacketSender responseSender) -> -// { -// // converting to a ByteBuf is necessary otherwise Fabric will complain when the game boots -// ByteBuf nettyByteBuf = friendlyByteBuf.asByteBuf(); -// -// // remove the Bukkit/Forge packet ID byte -// nettyByteBuf.readByte(); -// -// ClientApi.INSTANCE.serverMessageReceived(nettyByteBuf); -// }); + #if MC_VER >= MC_1_20_6 + PayloadTypeRegistry.playC2S().register(CommonPacketPayload.TYPE, new CommonPacketPayload.Codec()); + PayloadTypeRegistry.playS2C().register(CommonPacketPayload.TYPE, new CommonPacketPayload.Codec()); + ClientPlayNetworking.registerGlobalReceiver(CommonPacketPayload.TYPE, (payload, context) -> + { + if (payload.message() == null) + { + return; + } + ClientApi.INSTANCE.pluginMessageReceived(payload.message()); + }); + #else + ClientPlayNetworking.registerGlobalReceiver(AbstractPluginPacketSender.WRAPPER_PACKET_RESOURCE, (client, handler, buffer, packetSender) -> + { + // Forge packet ID + buffer.readByte(); + NetworkMessage message = AbstractPluginPacketSender.decodeMessage(buffer); + if (message != null) + { + ClientApi.INSTANCE.pluginMessageReceived(message); + } + }); + #endif } public void onKeyInput() diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricMain.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricMain.java index c5c60a66c..95597dabd 100644 --- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricMain.java +++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricMain.java @@ -27,6 +27,7 @@ import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; +import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender; import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.*; import com.seibel.distanthorizons.coreapi.ModInfo; import com.seibel.distanthorizons.fabric.wrappers.modAccessor.*; @@ -40,6 +41,12 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import org.apache.logging.log4j.Logger; +#if MC_VER >= MC_1_19_2 +import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; +#else // < 1.19.2 +import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback; +#endif + import javax.swing.*; import java.awt.*; import java.util.function.Consumer; @@ -51,14 +58,22 @@ import java.util.function.Consumer; */ public class FabricMain extends AbstractModInitializer implements ClientModInitializer, DedicatedServerModInitializer { - private static final ResourceLocation INITIAL_PHASE = ResourceLocation.tryParse("distanthorizons:dedicated_server_initial"); + #if MC_VER >= MC_1_21_1 + private static final ResourceLocation INITIAL_PHASE = ResourceLocation.fromNamespaceAndPath(ModInfo.RESOURCE_NAMESPACE, ModInfo.DEDICATED_SERVER_INITIAL_PATH); + #else + private static final ResourceLocation INITIAL_PHASE = new ResourceLocation(ModInfo.RESOURCE_NAMESPACE, ModInfo.DEDICATED_SERVER_INITIAL_PATH); + #endif private static final Logger LOGGER = DhLoggerBuilder.getLogger(); @Override - protected void createInitialBindings() { SingletonInjector.INSTANCE.bind(IModChecker.class, ModChecker.INSTANCE); } + protected void createInitialBindings() + { + SingletonInjector.INSTANCE.bind(IModChecker.class, ModChecker.INSTANCE); + SingletonInjector.INSTANCE.bind(IPluginPacketSender.class, new FabricPluginPacketSender()); + } @Override protected IEventProxy createClientProxy() { return new FabricClientProxy(); } @@ -102,7 +117,15 @@ public class FabricMain extends AbstractModInitializer implements ClientModIniti } @Override - protected void subscribeRegisterCommandsEvent(Consumer> eventHandler) { } + protected void subscribeRegisterCommandsEvent(Consumer> eventHandler) + { + CommandRegistrationCallback.EVENT.register( + (dispatcher, registryAccess #if MC_VER >= MC_1_19_2 , environment #endif ) -> + { + eventHandler.accept(dispatcher); + } + ); + } @Override protected void subscribeClientStartedEvent(Runnable eventHandler) { ClientLifecycleEvents.CLIENT_STARTED.register((mc) -> eventHandler.run()); } diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricPluginPacketSender.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricPluginPacketSender.java new file mode 100644 index 000000000..9a48e31c0 --- /dev/null +++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricPluginPacketSender.java @@ -0,0 +1,46 @@ +package com.seibel.distanthorizons.fabric; + +import com.seibel.distanthorizons.common.AbstractPluginPacketSender; +import com.seibel.distanthorizons.core.network.messages.AbstractNetworkMessage; +import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; +import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; +import net.minecraft.server.level.ServerPlayer; + +#if MC_VER >= MC_1_20_6 +import com.seibel.distanthorizons.common.CommonPacketPayload; +#else // < 1.20.6 +import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; +import net.minecraft.network.FriendlyByteBuf; +#endif + +public class FabricPluginPacketSender extends AbstractPluginPacketSender +{ + @Override + public void sendPluginClientPacket(AbstractNetworkMessage message) + { + #if MC_VER >= MC_1_20_6 + ClientPlayNetworking.send(new CommonPacketPayload(message)); + #else // < 1.20.6 + FriendlyByteBuf buffer = PacketByteBufs.create(); + // Forge packet ID + buffer.writeByte(0); + AbstractPluginPacketSender.encodeMessage(buffer, message); + ClientPlayNetworking.send(WRAPPER_PACKET_RESOURCE, buffer); + #endif + } + + @Override + public void sendPluginPacketServer(ServerPlayer serverPlayer, AbstractNetworkMessage message) + { + #if MC_VER >= MC_1_20_6 + ServerPlayNetworking.send(serverPlayer, new CommonPacketPayload(message)); + #else // < 1.20.6 + FriendlyByteBuf buffer = PacketByteBufs.create(); + // Forge packet ID + buffer.writeByte(0); + AbstractPluginPacketSender.encodeMessage(buffer, message); + ServerPlayNetworking.send(serverPlayer, WRAPPER_PACKET_RESOURCE, buffer); + #endif + } + +} \ No newline at end of file diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricServerProxy.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricServerProxy.java index 65db48284..8410f40ef 100644 --- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricServerProxy.java +++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/FabricServerProxy.java @@ -13,11 +13,13 @@ import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; import com.seibel.distanthorizons.fabric.testing.TestWorldGenBindingEvent; +import net.fabricmc.fabric.api.entity.event.v1.ServerEntityWorldChangeEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerChunkEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerWorldEvents; import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; +import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.TitleScreen; import net.minecraft.client.multiplayer.ClientLevel; @@ -25,6 +27,14 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import org.apache.logging.log4j.Logger; +#if MC_VER >= MC_1_20_6 +import com.seibel.distanthorizons.common.CommonPacketPayload; +import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; +#else +import com.seibel.distanthorizons.core.network.messages.NetworkMessage; +import com.seibel.distanthorizons.common.AbstractPluginPacketSender; +#endif + import java.util.function.Supplier; /** @@ -40,21 +50,26 @@ public class FabricServerProxy implements AbstractModInitializer.IEventProxy private static final ServerApi SERVER_API = ServerApi.INSTANCE; private static final Logger LOGGER = DhLoggerBuilder.getLogger(); - private final boolean isDedicated; + private final boolean isDedicatedServer; public static Supplier isGenerationThreadChecker = null; - public FabricServerProxy(boolean isDedicated) + //=============// + // constructor // + //=============// + + public FabricServerProxy(boolean isDedicatedServer) { - this.isDedicated = isDedicated; + this.isDedicatedServer = isDedicatedServer; } + // TODO rename private boolean isValidTime() { - if (isDedicated) + if (this.isDedicatedServer) { return true; } @@ -68,6 +83,7 @@ public class FabricServerProxy implements AbstractModInitializer.IEventProxy private ServerPlayerWrapper getServerPlayerWrapper(ServerPlayer player) { return ServerPlayerWrapper.getWrapper(player); } /** Registers Fabric Events */ + @Override public void registerEvents() { LOGGER.info("Registering Fabric Server Events"); @@ -90,15 +106,15 @@ public class FabricServerProxy implements AbstractModInitializer.IEventProxy //TODO: Check if both of these use the correct timed events. (i.e. is it 'ed' or 'ing' one?) ServerLifecycleEvents.SERVER_STARTING.register((server) -> { - if (isValidTime()) + if (this.isValidTime()) { - ServerApi.INSTANCE.serverLoadEvent(isDedicated); + ServerApi.INSTANCE.serverLoadEvent(this.isDedicatedServer); } }); // ServerWorldUnloadEvent ServerLifecycleEvents.SERVER_STOPPED.register((server) -> { - if (isValidTime()) + if (this.isValidTime()) { ServerApi.INSTANCE.serverUnloadEvent(); } @@ -107,25 +123,25 @@ public class FabricServerProxy implements AbstractModInitializer.IEventProxy // ServerLevelLoadEvent ServerWorldEvents.LOAD.register((server, level) -> { - if (isValidTime()) + if (this.isValidTime()) { - ServerApi.INSTANCE.serverLevelLoadEvent(getServerLevelWrapper(level)); + ServerApi.INSTANCE.serverLevelLoadEvent(this.getServerLevelWrapper(level)); } }); // ServerLevelUnloadEvent ServerWorldEvents.UNLOAD.register((server, level) -> { - if (isValidTime()) + if (this.isValidTime()) { - ServerApi.INSTANCE.serverLevelUnloadEvent(getServerLevelWrapper(level)); + ServerApi.INSTANCE.serverLevelUnloadEvent(this.getServerLevelWrapper(level)); } }); // ServerChunkLoadEvent ServerChunkEvents.CHUNK_LOAD.register((server, chunk) -> { - ILevelWrapper level = getServerLevelWrapper((ServerLevel) chunk.getLevel()); - if (isValidTime()) + ILevelWrapper level = this.getServerLevelWrapper((ServerLevel) chunk.getLevel()); + if (this.isValidTime()) { ServerApi.INSTANCE.serverChunkLoadEvent( new ChunkWrapper(chunk, chunk.getLevel(), level), @@ -136,18 +152,56 @@ public class FabricServerProxy implements AbstractModInitializer.IEventProxy ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> { - if (isValidTime()) + if (this.isValidTime()) { - ServerApi.INSTANCE.serverPlayerJoinEvent(getServerPlayerWrapper(handler.player)); + ServerApi.INSTANCE.serverPlayerJoinEvent(this.getServerPlayerWrapper(handler.player)); } }); ServerPlayConnectionEvents.DISCONNECT.register((handler, server) -> { - if (isValidTime()) + if (this.isValidTime()) { - ServerApi.INSTANCE.serverPlayerDisconnectEvent(getServerPlayerWrapper(handler.player)); + ServerApi.INSTANCE.serverPlayerDisconnectEvent(this.getServerPlayerWrapper(handler.player)); } }); + ServerEntityWorldChangeEvents.AFTER_PLAYER_CHANGE_WORLD.register((player, originLevel, destinationLevel) -> + { + if (this.isValidTime()) + { + ServerApi.INSTANCE.serverPlayerLevelChangeEvent( + this.getServerPlayerWrapper(player), + this.getServerLevelWrapper(originLevel), + this.getServerLevelWrapper(destinationLevel) + ); + } + }); + + if (this.isDedicatedServer) + { + #if MC_VER >= MC_1_20_6 + PayloadTypeRegistry.playC2S().register(CommonPacketPayload.TYPE, new CommonPacketPayload.Codec()); + PayloadTypeRegistry.playS2C().register(CommonPacketPayload.TYPE, new CommonPacketPayload.Codec()); + ServerPlayNetworking.registerGlobalReceiver(CommonPacketPayload.TYPE, (payload, context) -> + { + if (payload.message() == null) + { + return; + } + ServerApi.INSTANCE.pluginMessageReceived(ServerPlayerWrapper.getWrapper(context.player()), payload.message()); + }); + #else + ServerPlayNetworking.registerGlobalReceiver(AbstractPluginPacketSender.WRAPPER_PACKET_RESOURCE, (server, serverPlayer, handler, buffer, packetSender) -> + { + // Forge packet ID + buffer.readByte(); + NetworkMessage message = AbstractPluginPacketSender.decodeMessage(buffer); + if (message != null) + { + ServerApi.INSTANCE.pluginMessageReceived(ServerPlayerWrapper.getWrapper(serverPlayer), message); + } + }); + #endif + } } } diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinClientPacketListener.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinClientPacketListener.java index 2430745bb..bc86e2a37 100644 --- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinClientPacketListener.java +++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinClientPacketListener.java @@ -21,33 +21,9 @@ import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; @Mixin(ClientPacketListener.class) public class MixinClientPacketListener { - @Shadow - private ClientLevel level; - - @Unique - private ClientLevel previousLevel; - - @Inject(method = "handleLogin", at = @At("RETURN")) void onHandleLoginEnd(CallbackInfo ci) { ClientApi.INSTANCE.onClientOnlyConnected(); } - @Inject(method = "handleRespawn", at = @At("HEAD")) - void onHandleRespawnStart(CallbackInfo ci) { this.previousLevel = this.level; } - @Inject(method = "handleRespawn", at = @At("RETURN")) - void onHandleRespawnEnd(CallbackInfo ci) - { - // If the player changes dimensions the "this.level" will be changed halfway through the respawn method. - // By checking if the object references are the same, we can see if the previous level should be unloaded - // or if the player just respawned in the same level. - if (this.previousLevel != this.level) - { - ClientApi.INSTANCE.clientLevelUnloadEvent(ClientLevelWrapper.getWrapper(this.previousLevel)); - ClientApi.INSTANCE.clientLevelLoadEvent(ClientLevelWrapper.getWrapper(this.level)); - } - - this.previousLevel = null; - } - #if MC_VER < MC_1_19_4 @Inject(method = "cleanup", at = @At("HEAD")) #else @@ -55,10 +31,6 @@ public class MixinClientPacketListener #endif void onCleanupStart(CallbackInfo ci) { - if (this.level != null) - { - ClientApi.INSTANCE.clientLevelUnloadEvent(ClientLevelWrapper.getWrapper(this.level)); - } ClientApi.INSTANCE.onClientOnlyDisconnected(); } diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinMinecraft.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinMinecraft.java index f6b4b112a..f3d725865 100644 --- a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinMinecraft.java +++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/client/MixinMinecraft.java @@ -2,6 +2,8 @@ package com.seibel.distanthorizons.fabric.mixins.client; import com.seibel.distanthorizons.api.enums.config.EDhApiUpdateBranch; import com.seibel.distanthorizons.common.wrappers.gui.updater.UpdateModScreen; +import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper; +import com.seibel.distanthorizons.core.api.internal.ClientApi; import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; import com.seibel.distanthorizons.core.jar.installer.GitlabGetter; @@ -12,7 +14,9 @@ import com.seibel.distanthorizons.coreapi.ModInfo; import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.TitleScreen; +import net.minecraft.client.multiplayer.ClientLevel; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -25,8 +29,14 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; * @author coolGi */ @Mixin(Minecraft.class) -public class MixinMinecraft +public abstract class MixinMinecraft { + @Shadow + public abstract boolean isLocalServer(); + + @Unique + private ClientLevel lastLevel; + /** * Can be enabled for testing the auto updater UI.
* will always show the auto updater if set to true. @@ -113,6 +123,22 @@ public class MixinMinecraft } #endif + @Inject(at = @At("HEAD"), method = "updateLevelInEngines") + public void updateLevelInEngines(ClientLevel level, CallbackInfo ci) + { + if (this.lastLevel != null && level != this.lastLevel) + { + ClientApi.INSTANCE.clientLevelUnloadEvent(ClientLevelWrapper.getWrapper(this.lastLevel)); + } + + if (level != null) + { + ClientApi.INSTANCE.clientLevelLoadEvent(ClientLevelWrapper.getWrapper(level, true)); + } + + this.lastLevel = level; + } + @Inject(at = @At("HEAD"), method = "close()V") public void close(CallbackInfo ci) { SelfUpdater.onClose(); } diff --git a/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinServerPlayer.java b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinServerPlayer.java new file mode 100644 index 000000000..0578772df --- /dev/null +++ b/fabric/src/main/java/com/seibel/distanthorizons/fabric/mixins/server/MixinServerPlayer.java @@ -0,0 +1,69 @@ +/* + * This file is part of the Distant Horizons mod + * licensed under the GNU LGPL v3 License. + * + * Copyright (C) 2020-2023 James Seibel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.seibel.distanthorizons.fabric.mixins.server; + +import com.seibel.distanthorizons.common.wrappers.misc.IMixinServerPlayer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +#if MC_VER >= MC_1_21_1 +import net.minecraft.world.level.portal.DimensionTransition; +#endif + + +@Mixin(ServerPlayer.class) +public class MixinServerPlayer implements IMixinServerPlayer +{ + @Unique + @Nullable + private ServerLevel dimensionChangeDestination; + + @Override + @Nullable + public ServerLevel distantHorizons$getDimensionChangeDestination() + { return this.dimensionChangeDestination; } + + @Inject(at = @At("HEAD"), method = "changeDimension") + #if MC_VER >= MC_1_21_1 + public void changeDimension(DimensionTransition dimensionTransition, CallbackInfoReturnable cir) + { this.dimensionChangeDestination = dimensionTransition.newLevel(); } + #else + public void changeDimension(ServerLevel destination, CallbackInfoReturnable cir) + { this.dimensionChangeDestination = destination; } + #endif + + #if MC_VER >= MC_1_20_1 + @Inject(at = @At("RETURN"), method = "setServerLevel") + public void setServerLevel(ServerLevel level, CallbackInfo ci) + #else + @Inject(at = @At("RETURN"), method = "setLevel") + public void setLevel(ServerLevel level, CallbackInfo ci) + #endif + { this.dimensionChangeDestination = null; } + +} \ No newline at end of file diff --git a/fabric/src/main/resources/DistantHorizons.fabric.mixins.json b/fabric/src/main/resources/DistantHorizons.fabric.mixins.json index 38fab22fe..ee57216f0 100644 --- a/fabric/src/main/resources/DistantHorizons.fabric.mixins.json +++ b/fabric/src/main/resources/DistantHorizons.fabric.mixins.json @@ -5,7 +5,8 @@ "mixins": [ "server.MixinChunkGenerator", "server.MixinChunkMap", - "server.MixinUtilBackgroundThread" + "server.MixinUtilBackgroundThread", + "server.MixinServerPlayer" ], "client": [ "client.MixinClientLevel", diff --git a/forge/src/main/java/com/seibel/distanthorizons/forge/ForgeClientProxy.java b/forge/src/main/java/com/seibel/distanthorizons/forge/ForgeClientProxy.java index 252d1fbdf..c6eefb542 100644 --- a/forge/src/main/java/com/seibel/distanthorizons/forge/ForgeClientProxy.java +++ b/forge/src/main/java/com/seibel/distanthorizons/forge/ForgeClientProxy.java @@ -33,8 +33,6 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; -import com.seibel.distanthorizons.coreapi.ModInfo; -//import io.netty.buffer.ByteBuf; import net.minecraft.world.level.LevelAccessor; import net.minecraft.client.multiplayer.ClientLevel; @@ -53,8 +51,6 @@ import net.minecraftforge.event.entity.player.PlayerInteractEvent; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraftforge.common.MinecraftForge; -//import net.minecraftforge.network.NetworkRegistry; -//import net.minecraftforge.network.simple.SimpleChannel; import org.apache.logging.log4j.Logger; import org.lwjgl.glfw.GLFW; @@ -79,8 +75,6 @@ public class ForgeClientProxy implements AbstractModInitializer.IEventProxy { private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class); private static final Logger LOGGER = DhLoggerBuilder.getLogger(); - -// private static SimpleChannel multiversePluginChannel; #if MC_VER < MC_1_19_2 @@ -95,7 +89,7 @@ public class ForgeClientProxy implements AbstractModInitializer.IEventProxy public void registerEvents() { MinecraftForge.EVENT_BUS.register(this); - this.setupNetworkingListeners(); + ForgePluginPacketSender.setPacketHandler(ClientApi.INSTANCE::pluginMessageReceived); } @@ -139,7 +133,7 @@ public class ForgeClientProxy implements AbstractModInitializer.IEventProxy } ClientLevel clientLevel = (ClientLevel) level; - IClientLevelWrapper clientLevelWrapper = ClientLevelWrapper.getWrapper(clientLevel); + IClientLevelWrapper clientLevelWrapper = ClientLevelWrapper.getWrapper(clientLevel, true); // TODO this causes a crash due to level being set to null somewhere ClientApi.INSTANCE.clientLevelLoadEvent(clientLevelWrapper); } @@ -270,66 +264,6 @@ public class ForgeClientProxy implements AbstractModInitializer.IEventProxy } - - //============// - // networking // - //============// - - public void setupNetworkingListeners() - { -// multiversePluginChannel = NetworkRegistry.newSimpleChannel( -// new ResourceLocation(ModInfo.NETWORKING_RESOURCE_NAMESPACE, ModInfo.MULTIVERSE_PLUGIN_NAMESPACE), -// // network protocol version -// () -> ModInfo.MULTIVERSE_PLUGIN_PROTOCOL_VERSION +"", -// // client accepted versions -// ForgeClientProxy::isReceivedProtocolVersionAcceptable, -// // server accepted versions -// ForgeClientProxy::isReceivedProtocolVersionAcceptable -// ); -// -// multiversePluginChannel.registerMessage(0/*should be incremented for each simple channel we listen to*/, ByteBuf.class, -// // encoder -// (pack, friendlyByteBuf) -> { }, -// // decoder -// (friendlyByteBuf) -> friendlyByteBuf.asByteBuf(), -// // message consumer -// (nettyByteBuf, contextRef) -> -// { -// ClientApi.INSTANCE.serverMessageReceived(nettyByteBuf); -// contextRef.get().setPacketHandled(true); -// } -// ); - } - - public static boolean isReceivedProtocolVersionAcceptable(String versionString) - { - if (versionString.toLowerCase().contains("allowvanilla")) - { - // allow using networking on vanilla servers - return true; - } - else if (versionString.toLowerCase().contains("absent")) - { - // allow using networking even if DH isn't installed on the server - return true; - } - else - { - // DH is installed on the server, check if the version is valid to use - try - { - int version = Integer.parseInt(versionString); - return ModInfo.MULTIVERSE_PLUGIN_PROTOCOL_VERSION == version; - } - catch (NumberFormatException ignored) - { - return false; - } - } - } - - - //===========// // rendering // //===========// diff --git a/forge/src/main/java/com/seibel/distanthorizons/forge/ForgeMain.java b/forge/src/main/java/com/seibel/distanthorizons/forge/ForgeMain.java index edd257828..64f8a7348 100644 --- a/forge/src/main/java/com/seibel/distanthorizons/forge/ForgeMain.java +++ b/forge/src/main/java/com/seibel/distanthorizons/forge/ForgeMain.java @@ -25,6 +25,8 @@ import com.seibel.distanthorizons.common.wrappers.gui.GetConfigScreen; import com.seibel.distanthorizons.core.api.internal.ClientApi; import com.seibel.distanthorizons.core.config.Config; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; +import com.seibel.distanthorizons.common.wrappers.gui.GetConfigScreen; +import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender; import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker; import com.seibel.distanthorizons.coreapi.ModInfo; import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IOptifineAccessor; @@ -36,15 +38,16 @@ import net.minecraft.commands.CommandSourceStack; import net.minecraft.server.MinecraftServer; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.RegisterCommandsEvent; +import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.fml.ModLoadingContext; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.*; #if MC_VER == MC_1_16_5 -import net.minecraftforge.fml.event.server.FMLServerStartingEvent; +import net.minecraftforge.fml.event.server.FMLServerAboutToStartEvent; #elif MC_VER == MC_1_17_1 -import net.minecraftforge.fmlserverevents.FMLServerStartingEvent; +import net.minecraftforge.fmlserverevents.FMLServerAboutToStartEvent; #else -import net.minecraftforge.event.server.ServerStartingEvent; +import net.minecraftforge.event.server.ServerAboutToStartEvent; #endif import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; #if MC_VER < MC_1_17_1 @@ -83,7 +86,11 @@ public class ForgeMain extends AbstractModInitializer } @Override - protected void createInitialBindings() { SingletonInjector.INSTANCE.bind(IModChecker.class, ModChecker.INSTANCE); } + protected void createInitialBindings() + { + SingletonInjector.INSTANCE.bind(IModChecker.class, ModChecker.INSTANCE); + SingletonInjector.INSTANCE.bind(IPluginPacketSender.class, new ForgePluginPacketSender()); + } @Override protected IEventProxy createClientProxy() { return new ForgeClientProxy(); } @@ -137,7 +144,7 @@ public class ForgeMain extends AbstractModInitializer @Override protected void subscribeServerStartingEvent(Consumer eventHandler) { - MinecraftForge.EVENT_BUS.addListener((#if MC_VER >= MC_1_18_2 ServerStartingEvent #else FMLServerStartingEvent #endif e) -> + MinecraftForge.EVENT_BUS.addListener(EventPriority.HIGH, (#if MC_VER >= MC_1_18_2 ServerAboutToStartEvent #else FMLServerAboutToStartEvent #endif e) -> { eventHandler.accept(e.getServer()); }); diff --git a/forge/src/main/java/com/seibel/distanthorizons/forge/ForgePluginPacketSender.java b/forge/src/main/java/com/seibel/distanthorizons/forge/ForgePluginPacketSender.java new file mode 100644 index 000000000..733c19c05 --- /dev/null +++ b/forge/src/main/java/com/seibel/distanthorizons/forge/ForgePluginPacketSender.java @@ -0,0 +1,130 @@ +package com.seibel.distanthorizons.forge; + +import com.seibel.distanthorizons.common.AbstractPluginPacketSender; +import com.seibel.distanthorizons.common.wrappers.misc.ServerPlayerWrapper; +import com.seibel.distanthorizons.core.network.messages.NetworkMessage; +import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper; +import net.minecraft.server.level.ServerPlayer; + +#if MC_VER >= MC_1_20_2 +import net.minecraftforge.network.PacketDistributor; +import net.minecraftforge.network.ChannelBuilder; +import net.minecraftforge.network.SimpleChannel; +#elif MC_VER >= MC_1_18_2 +import net.minecraftforge.network.PacketDistributor; +import net.minecraftforge.network.NetworkRegistry; +import net.minecraftforge.network.simple.SimpleChannel; +#elif MC_VER >= MC_1_17_1 +import net.minecraftforge.fmllegacy.network.NetworkRegistry; +import net.minecraftforge.fmllegacy.network.PacketDistributor; +import net.minecraftforge.fmllegacy.network.simple.SimpleChannel; +#else // < 1.17.1 +import net.minecraftforge.fml.network.NetworkRegistry; +import net.minecraftforge.fml.network.simple.SimpleChannel; +import net.minecraftforge.fml.network.PacketDistributor; +#endif + +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +public class ForgePluginPacketSender extends AbstractPluginPacketSender +{ + public static final SimpleChannel PLUGIN_CHANNEL = + #if MC_VER >= MC_1_20_2 + ChannelBuilder.named(AbstractPluginPacketSender.WRAPPER_PACKET_RESOURCE) + .networkProtocolVersion(1) + .serverAcceptedVersions((status, version) -> true) + .clientAcceptedVersions((status, version) -> true) + .simpleChannel(); + #else // < 1.20.2 + NetworkRegistry.newSimpleChannel( + AbstractPluginPacketSender.WRAPPER_PACKET_RESOURCE, + () -> "1", + ignored -> true, + ignored -> true + ); + #endif + + public static void setPacketHandler(Consumer consumer) + { + setPacketHandler((player, message) -> consumer.accept(message)); + } + public static void setPacketHandler(BiConsumer consumer) + { + #if MC_VER >= MC_1_20_2 + PLUGIN_CHANNEL.messageBuilder(MessageWrapper.class, 0) + .encoder((wrapper, out) -> AbstractPluginPacketSender.encodeMessage(out, wrapper.message)) + .decoder(in -> new MessageWrapper(AbstractPluginPacketSender.decodeMessage(in))) + .consumerNetworkThread((wrapper, context) -> + { + if (wrapper.message != null) + { + if (context.getSender() != null) + { + consumer.accept(ServerPlayerWrapper.getWrapper(context.getSender()), wrapper.message); + } + else + { + consumer.accept(null, wrapper.message); + } + } + context.setPacketHandled(true); + }) + .add(); + #else // < 1.20.2 + PLUGIN_CHANNEL.registerMessage(0, MessageWrapper.class, + (wrapper, out) -> AbstractPluginPacketSender.encodeMessage(out, wrapper.message), + in -> new MessageWrapper(AbstractPluginPacketSender.decodeMessage(in)), + (wrapper, context) -> + { + if (wrapper.message != null) + { + if (context.get().getSender() != null) + { + consumer.accept(ServerPlayerWrapper.getWrapper(context.get().getSender()), wrapper.message); + } + else + { + consumer.accept(null, wrapper.message); + } + } + context.get().setPacketHandled(true); + } + ); + #endif + } + + @Override + public void sendPluginPacketClient(NetworkMessage message) + { + #if MC_VER >= MC_1_20_2 + PLUGIN_CHANNEL.send(new MessageWrapper(message), PacketDistributor.SERVER.noArg()); + #else // < 1.20.2 + PLUGIN_CHANNEL.send(PacketDistributor.SERVER.noArg(), new MessageWrapper(message)); + #endif + } + + @Override + public void sendPluginPacketServer(ServerPlayer serverPlayer, NetworkMessage message) + { + #if MC_VER >= MC_1_20_2 + PLUGIN_CHANNEL.send(new MessageWrapper(message), PacketDistributor.PLAYER.with(serverPlayer)); + #else // < 1.20.2 + PLUGIN_CHANNEL.send(PacketDistributor.PLAYER.with(() -> serverPlayer), new MessageWrapper(message)); + #endif + } + + // Forge doesn't support using abstract classes + @SuppressWarnings({"ClassCanBeRecord", "RedundantSuppression"}) + public static class MessageWrapper + { + public final NetworkMessage message; + + public MessageWrapper(NetworkMessage message) + { + this.message = message; + } + + } + +} \ No newline at end of file diff --git a/forge/src/main/java/com/seibel/distanthorizons/forge/ForgeServerProxy.java b/forge/src/main/java/com/seibel/distanthorizons/forge/ForgeServerProxy.java index 1be3b415b..c949b43d0 100644 --- a/forge/src/main/java/com/seibel/distanthorizons/forge/ForgeServerProxy.java +++ b/forge/src/main/java/com/seibel/distanthorizons/forge/ForgeServerProxy.java @@ -3,16 +3,20 @@ package com.seibel.distanthorizons.forge; import com.seibel.distanthorizons.common.AbstractModInitializer; import com.seibel.distanthorizons.common.util.ProxyUtil; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; +import com.seibel.distanthorizons.common.wrappers.misc.ServerPlayerWrapper; import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper; import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment; import com.seibel.distanthorizons.core.api.internal.ServerApi; -import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; +import net.minecraft.resources.ResourceKey; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.TickEvent; +import net.minecraftforge.event.entity.player.PlayerEvent; #if MC_VER < MC_1_19_2 import net.minecraftforge.event.world.ChunkEvent; import net.minecraftforge.event.world.WorldEvent; @@ -22,6 +26,13 @@ import net.minecraftforge.event.level.LevelEvent; #endif import net.minecraftforge.eventbus.api.SubscribeEvent; +#if MC_VER >= MC_1_19_4 +import net.minecraft.core.registries.Registries; +#else // < 1.19.4 +import net.minecraft.core.Registry; +import net.minecraft.core.RegistryAccess; +#endif + #if MC_VER == MC_1_16_5 import net.minecraftforge.fml.event.server.FMLServerAboutToStartEvent; import net.minecraftforge.fml.event.server.FMLServerStoppingEvent; @@ -47,7 +58,6 @@ public class ForgeServerProxy implements AbstractModInitializer.IEventProxy #endif private final ServerApi serverApi = ServerApi.INSTANCE; - private static final Logger LOGGER = DhLoggerBuilder.getLogger(); private final boolean isDedicated; public static Supplier isGenerationThreadChecker = null; @@ -57,6 +67,10 @@ public class ForgeServerProxy implements AbstractModInitializer.IEventProxy public void registerEvents() { MinecraftForge.EVENT_BUS.register(this); + if (this.isDedicated) + { + ForgePluginPacketSender.setPacketHandler(ServerApi.INSTANCE::pluginMessageReceived); + } } @@ -111,7 +125,7 @@ public class ForgeServerProxy implements AbstractModInitializer.IEventProxy { if (GetEventLevel(event) instanceof ServerLevel) { - this.serverApi.serverLevelLoadEvent(this.getServerLevelWrapper((ServerLevel) GetEventLevel(event))); + this.serverApi.serverLevelLoadEvent(getServerLevelWrapper((ServerLevel) GetEventLevel(event))); } } @@ -125,7 +139,7 @@ public class ForgeServerProxy implements AbstractModInitializer.IEventProxy { if (GetEventLevel(event) instanceof ServerLevel) { - this.serverApi.serverLevelUnloadEvent(this.getServerLevelWrapper((ServerLevel) GetEventLevel(event))); + this.serverApi.serverLevelUnloadEvent(getServerLevelWrapper((ServerLevel) GetEventLevel(event))); } } @@ -138,6 +152,22 @@ public class ForgeServerProxy implements AbstractModInitializer.IEventProxy this.serverApi.serverChunkLoadEvent(chunk, levelWrapper); } + @SubscribeEvent + public void playerLoggedInEvent(PlayerEvent.PlayerLoggedInEvent event) + { this.serverApi.serverPlayerJoinEvent(getServerPlayerWrapper(event)); } + @SubscribeEvent + public void playerLoggedOutEvent(PlayerEvent.PlayerLoggedOutEvent event) + { this.serverApi.serverPlayerDisconnectEvent(getServerPlayerWrapper(event)); } + @SubscribeEvent + public void playerChangedDimensionEvent(PlayerEvent.PlayerChangedDimensionEvent event) + { + this.serverApi.serverPlayerLevelChangeEvent( + getServerPlayerWrapper(event), + getServerLevelWrapper(event.getFrom(), event), + getServerLevelWrapper(event.getTo(), event) + ); + } + //================// @@ -147,4 +177,20 @@ public class ForgeServerProxy implements AbstractModInitializer.IEventProxy private static ServerLevelWrapper getServerLevelWrapper(ServerLevel level) { return ServerLevelWrapper.getWrapper(level); } + private static ServerLevelWrapper getServerLevelWrapper(ResourceKey resourceKey, PlayerEvent event) + { + //noinspection DataFlowIssue (possible NPE after getServer()) + return getServerLevelWrapper(event.getEntity().getServer().getLevel(resourceKey)); + } + + private static ServerPlayerWrapper getServerPlayerWrapper(PlayerEvent event) { + return ServerPlayerWrapper.getWrapper( + #if MC_VER >= MC_1_19_2 + (ServerPlayer) event.getEntity() + #else + (ServerPlayer) event.getPlayer() + #endif + ); + } + } diff --git a/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/server/MixinServerPlayer.java b/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/server/MixinServerPlayer.java new file mode 100644 index 000000000..8cdd2da16 --- /dev/null +++ b/forge/src/main/java/com/seibel/distanthorizons/forge/mixins/server/MixinServerPlayer.java @@ -0,0 +1,61 @@ +/* + * This file is part of the Distant Horizons mod + * licensed under the GNU LGPL v3 License. + * + * Copyright (C) 2020-2023 James Seibel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.seibel.distanthorizons.forge.mixins.server; + +import com.seibel.distanthorizons.common.wrappers.misc.IMixinServerPlayer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraftforge.common.util.ITeleporter; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + + +@Mixin(ServerPlayer.class) +public class MixinServerPlayer implements IMixinServerPlayer +{ + @Unique + @Nullable + private volatile ServerLevel distantHorizons$dimensionChangeDestination; + + @Override + @Nullable + public ServerLevel distantHorizons$getDimensionChangeDestination() + { return this.distantHorizons$dimensionChangeDestination; } + + @Inject(at = @At("HEAD"), method = "changeDimension", remap = false) + public void changeDimension(ServerLevel destination, ITeleporter teleporter, CallbackInfoReturnable cir) + { this.distantHorizons$dimensionChangeDestination = destination; } + + #if MC_VER >= MC_1_20_1 + @Inject(at = @At("RETURN"), method = "setServerLevel") + public void setServerLevel(ServerLevel level, CallbackInfo ci) + #else + @Inject(at = @At("RETURN"), method = "setLevel") + public void setLevel(ServerLevel level, CallbackInfo ci) + #endif + { this.distantHorizons$dimensionChangeDestination = null; } + +} \ No newline at end of file diff --git a/forge/src/main/resources/DistantHorizons.forge.mixins.json b/forge/src/main/resources/DistantHorizons.forge.mixins.json index 439d030d5..3824c154c 100644 --- a/forge/src/main/resources/DistantHorizons.forge.mixins.json +++ b/forge/src/main/resources/DistantHorizons.forge.mixins.json @@ -6,7 +6,8 @@ "server.MixinUtilBackgroundThread", "server.MixinChunkGenerator", "server.MixinTFChunkGenerator", - "server.MixinChunkMap" + "server.MixinChunkMap", + "server.MixinServerPlayer" ], "client": [ "client.MixinClientPacketListener", diff --git a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgeClientProxy.java b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgeClientProxy.java index 88cec2806..8de440e2e 100644 --- a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgeClientProxy.java +++ b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgeClientProxy.java @@ -35,7 +35,6 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; -import com.seibel.distanthorizons.coreapi.ModInfo; import net.minecraft.world.level.LevelAccessor; import net.minecraft.client.multiplayer.ClientLevel; @@ -47,8 +46,6 @@ import net.neoforged.neoforge.event.level.LevelEvent; import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent; import net.minecraft.world.level.chunk.ChunkAccess; -//import net.neoforged.network.NetworkRegistry; -//import net.neoforged.network.simple.SimpleChannel; import org.apache.logging.log4j.Logger; import org.lwjgl.glfw.GLFW; @@ -90,11 +87,7 @@ public class NeoforgeClientProxy implements AbstractModInitializer.IEventProxy @Override - public void registerEvents() - { - NeoForge.EVENT_BUS.register(this); - setupNetworkingListeners(); - } + public void registerEvents() { NeoForge.EVENT_BUS.register(this); } @@ -137,7 +130,7 @@ public class NeoforgeClientProxy implements AbstractModInitializer.IEventProxy } ClientLevel clientLevel = (ClientLevel) level; - IClientLevelWrapper clientLevelWrapper = ClientLevelWrapper.getWrapper(clientLevel); + IClientLevelWrapper clientLevelWrapper = ClientLevelWrapper.getWrapper(clientLevel, true); // TODO this causes a crash due to level being set to null somewhere ClientApi.INSTANCE.clientLevelLoadEvent(clientLevelWrapper); } @@ -246,65 +239,6 @@ public class NeoforgeClientProxy implements AbstractModInitializer.IEventProxy - //============// - // networking // - //============// - - public static void setupNetworkingListeners() - { -// multiversePluginChannel = NetworkRegistry.newSimpleChannel( -// new ResourceLocation(ModInfo.NETWORKING_RESOURCE_NAMESPACE, ModInfo.MULTIVERSE_PLUGIN_NAMESPACE), -// // network protocol version -// () -> ModInfo.MULTIVERSE_PLUGIN_PROTOCOL_VERSION +"", -// // client accepted versions -// ForgeClientProxy::isReceivedProtocolVersionAcceptable, -// // server accepted versions -// ForgeClientProxy::isReceivedProtocolVersionAcceptable -// ); -// -// multiversePluginChannel.registerMessage(0/*should be incremented for each simple channel we listen to*/, ByteBuf.class, -// // encoder -// (pack, friendlyByteBuf) -> { }, -// // decoder -// (friendlyByteBuf) -> friendlyByteBuf.asByteBuf(), -// // message consumer -// (nettyByteBuf, contextRef) -> -// { -// ClientApi.INSTANCE.serverMessageReceived(nettyByteBuf); -// contextRef.get().setPacketHandled(true); -// } -// ); - } - - public static boolean isReceivedProtocolVersionAcceptable(String versionString) - { - if (versionString.toLowerCase().contains("allowvanilla")) - { - // allow using networking on vanilla servers - return true; - } - else if (versionString.toLowerCase().contains("absent")) - { - // allow using networking even if DH isn't installed on the server - return true; - } - else - { - // DH is installed on the server, check if the version is valid to use - try - { - int version = Integer.parseInt(versionString); - return ModInfo.MULTIVERSE_PLUGIN_PROTOCOL_VERSION == version; - } - catch (NumberFormatException ignored) - { - return false; - } - } - } - - - //===========// // rendering // //===========// diff --git a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgeMain.java b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgeMain.java index f2369520c..272e63cc7 100644 --- a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgeMain.java +++ b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgeMain.java @@ -24,7 +24,9 @@ import com.seibel.distanthorizons.common.AbstractModInitializer; import com.seibel.distanthorizons.common.wrappers.gui.GetConfigScreen; import com.seibel.distanthorizons.core.api.internal.ClientApi; import com.seibel.distanthorizons.core.config.Config; +import com.seibel.distanthorizons.core.api.internal.ServerApi; import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector; +import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender; import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker; import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IOptifineAccessor; import com.seibel.distanthorizons.coreapi.ModInfo; @@ -32,6 +34,7 @@ import com.seibel.distanthorizons.neoforge.wrappers.modAccessor.ModChecker; import com.seibel.distanthorizons.neoforge.wrappers.modAccessor.OptifineAccessor; import net.minecraft.commands.CommandSourceStack; import net.minecraft.server.MinecraftServer; +import net.neoforged.bus.api.EventPriority; import net.neoforged.bus.api.IEventBus; import net.neoforged.fml.ModLoadingContext; import net.neoforged.fml.common.Mod; @@ -40,6 +43,7 @@ import net.neoforged.fml.event.lifecycle.FMLDedicatedServerSetupEvent; import net.neoforged.neoforge.common.NeoForge; import net.neoforged.neoforge.event.RegisterCommandsEvent; import net.neoforged.neoforge.event.server.ServerStartingEvent; +import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent; import java.util.function.Consumer; @@ -55,19 +59,42 @@ import net.neoforged.neoforge.client.gui.IConfigScreenFactory; * check out the ClientProxy. */ @Mod(ModInfo.ID) +@SuppressWarnings("unused") public class NeoforgeMain extends AbstractModInitializer { public NeoforgeMain(IEventBus eventBus) { - eventBus.addListener((FMLClientSetupEvent e) -> this.onInitializeClient()); - eventBus.addListener((FMLDedicatedServerSetupEvent e) -> this.onInitializeServer()); + eventBus.addListener((FMLClientSetupEvent e) -> { + this.onInitializeClient(); + eventBus.addListener(this::registerNetworkingClient); + }); + eventBus.addListener((FMLDedicatedServerSetupEvent e) -> { + this.onInitializeServer(); + eventBus.addListener(this::registerNetworkingServer); + }); } + + + //============// + // networking // + //============// + public void registerNetworkingClient(RegisterPayloadHandlersEvent event) + { NeoforgePluginPacketSender.setPacketHandler(event, ClientApi.INSTANCE::pluginMessageReceived); } + public void registerNetworkingServer(RegisterPayloadHandlersEvent event) + { NeoforgePluginPacketSender.setPacketHandler(event, ServerApi.INSTANCE::pluginMessageReceived); } + + + @Override protected IEventProxy createServerProxy(boolean isDedicated) { return new NeoforgeServerProxy(isDedicated); } @Override - protected void createInitialBindings() { SingletonInjector.INSTANCE.bind(IModChecker.class, ModChecker.INSTANCE); } + protected void createInitialBindings() + { + SingletonInjector.INSTANCE.bind(IModChecker.class, ModChecker.INSTANCE); + SingletonInjector.INSTANCE.bind(IPluginPacketSender.class, new NeoforgePluginPacketSender()); + } @Override protected IEventProxy createClientProxy() { return new NeoforgeClientProxy(); } @@ -116,7 +143,7 @@ public class NeoforgeMain extends AbstractModInitializer @Override protected void subscribeServerStartingEvent(Consumer eventHandler) { - NeoForge.EVENT_BUS.addListener((ServerStartingEvent e) -> { eventHandler.accept(e.getServer()); }); + NeoForge.EVENT_BUS.addListener(EventPriority.HIGH, (ServerStartingEvent e) -> { eventHandler.accept(e.getServer()); }); } @Override diff --git a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgePluginPacketSender.java b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgePluginPacketSender.java new file mode 100644 index 000000000..44d85c370 --- /dev/null +++ b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgePluginPacketSender.java @@ -0,0 +1,50 @@ +package com.seibel.distanthorizons.neoforge; + +import com.seibel.distanthorizons.common.CommonPacketPayload; +import com.seibel.distanthorizons.common.wrappers.misc.ServerPlayerWrapper; +import com.seibel.distanthorizons.common.AbstractPluginPacketSender; +import com.seibel.distanthorizons.core.network.messages.AbstractNetworkMessage; +import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper; +import net.minecraft.server.level.ServerPlayer; +import net.neoforged.neoforge.network.PacketDistributor; +import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent; +import net.neoforged.neoforge.network.registration.PayloadRegistrar; + +import java.util.Optional; +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +public class NeoforgePluginPacketSender extends AbstractPluginPacketSender +{ + private static BiConsumer packetConsumer; + + public static void setPacketHandler(RegisterPayloadHandlersEvent event, Consumer consumer) + { setPacketHandler(event, (player, buffer) -> consumer.accept(buffer)); } + public static void setPacketHandler(RegisterPayloadHandlersEvent event, BiConsumer consumer) + { + packetConsumer = consumer; + + PayloadRegistrar registrar = event.registrar("1").optional(); + registrar.playBidirectional(CommonPacketPayload.TYPE, new CommonPacketPayload.Codec(), (payload, context) -> + { + ServerPlayerWrapper serverPlayer = Optional.of(context.player()) + .map(player -> player instanceof ServerPlayer ? (ServerPlayer) player : null) + .map(ServerPlayerWrapper::getWrapper) + .orElse(null); + + if (payload.message() != null) + { + packetConsumer.accept(serverPlayer, payload.message()); + } + }); + } + + @Override + public void sendPluginClientPacket(AbstractNetworkMessage message) + { PacketDistributor.sendToServer(new CommonPacketPayload(message)); } + + @Override + public void sendPluginPacketServer(ServerPlayer serverPlayer, AbstractNetworkMessage message) + { PacketDistributor.sendToPlayer(serverPlayer, new CommonPacketPayload(message)); } + +} \ No newline at end of file diff --git a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgeServerProxy.java b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgeServerProxy.java index 8b02e1779..0afbec7a2 100644 --- a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgeServerProxy.java +++ b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/NeoforgeServerProxy.java @@ -3,15 +3,20 @@ package com.seibel.distanthorizons.neoforge; import com.seibel.distanthorizons.common.AbstractModInitializer; import com.seibel.distanthorizons.common.util.ProxyUtil; import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper; +import com.seibel.distanthorizons.common.wrappers.misc.ServerPlayerWrapper; import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper; import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment; import com.seibel.distanthorizons.core.api.internal.ServerApi; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; +import net.minecraft.resources.ResourceKey; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; import net.neoforged.neoforge.common.NeoForge; +import net.neoforged.neoforge.event.entity.player.PlayerEvent; import net.neoforged.neoforge.event.level.ChunkEvent; import net.neoforged.neoforge.event.level.LevelEvent; import net.neoforged.bus.api.SubscribeEvent; @@ -123,6 +128,21 @@ public class NeoforgeServerProxy implements AbstractModInitializer.IEventProxy this.serverApi.serverChunkLoadEvent(chunk, levelWrapper); } + @SubscribeEvent + public void playerLoggedInEvent(PlayerEvent.PlayerLoggedInEvent event) { this.serverApi.serverPlayerJoinEvent(getServerPlayerWrapper(event)); } + @SubscribeEvent + public void playerLoggedOutEvent(PlayerEvent.PlayerLoggedOutEvent event) + { this.serverApi.serverPlayerDisconnectEvent(getServerPlayerWrapper(event)); } + @SubscribeEvent + public void playerChangedDimensionEvent(PlayerEvent.PlayerChangedDimensionEvent event) + { + this.serverApi.serverPlayerLevelChangeEvent( + getServerPlayerWrapper(event), + getServerLevelWrapper(event.getFrom(), event), + getServerLevelWrapper(event.getTo(), event) + ); + } + //================// @@ -130,6 +150,12 @@ public class NeoforgeServerProxy implements AbstractModInitializer.IEventProxy //================// private static ServerLevelWrapper getServerLevelWrapper(ServerLevel level) { return ServerLevelWrapper.getWrapper(level); } + private static ServerLevelWrapper getServerLevelWrapper(ResourceKey resourceKey, PlayerEvent event) + { + //noinspection DataFlowIssue (possible NPE after getServer()) + return getServerLevelWrapper(event.getEntity().getServer().getLevel(resourceKey)); + } + private static ServerPlayerWrapper getServerPlayerWrapper(PlayerEvent event) { return ServerPlayerWrapper.getWrapper((ServerPlayer) event.getEntity()); } } diff --git a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/client/MixinClientPacketListener.java b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/client/MixinClientPacketListener.java index 2439e0233..808a8ed15 100644 --- a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/client/MixinClientPacketListener.java +++ b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/client/MixinClientPacketListener.java @@ -1,8 +1,11 @@ package com.seibel.distanthorizons.neoforge.mixins.client; +import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper; import com.seibel.distanthorizons.core.api.internal.ClientApi; +import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.multiplayer.ClientPacketListener; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -10,10 +13,16 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(ClientPacketListener.class) public class MixinClientPacketListener { + @Shadow + private ClientLevel level; // TODO update fabric version as well @Inject(method = "handleLogin", at = @At("RETURN")) - void onHandleLoginEnd(CallbackInfo ci) { ClientApi.INSTANCE.onClientOnlyConnected(); } + void onHandleLoginEnd(CallbackInfo ci) + { + ClientApi.INSTANCE.onClientOnlyConnected(); + ClientApi.INSTANCE.clientLevelLoadEvent(ClientLevelWrapper.getWrapper(this.level, true)); + } #if MC_VER < MC_1_19_4 @Inject(method = "cleanup", at = @At("HEAD")) diff --git a/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinServerPlayer.java b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinServerPlayer.java new file mode 100644 index 000000000..52166866d --- /dev/null +++ b/neoforge/src/main/java/com/seibel/distanthorizons/neoforge/mixins/server/MixinServerPlayer.java @@ -0,0 +1,73 @@ +/* + * This file is part of the Distant Horizons mod + * licensed under the GNU LGPL v3 License. + * + * Copyright (C) 2020-2023 James Seibel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.seibel.distanthorizons.neoforge.mixins.server; + +import com.seibel.distanthorizons.common.wrappers.misc.IMixinServerPlayer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +#if MC_VER >= MC_1_21_1 +import net.minecraft.world.level.portal.DimensionTransition; +#endif + + +@Mixin(ServerPlayer.class) +public class MixinServerPlayer implements IMixinServerPlayer +{ + @Unique + @Nullable + private ServerLevel distantHorizons$dimensionChangeDestination; + + + @Unique + @Override + @Nullable + public ServerLevel distantHorizons$getDimensionChangeDestination() + { return this.distantHorizons$dimensionChangeDestination; } + + @Inject(at = @At("HEAD"), method = "changeDimension") + #if MC_VER >= MC_1_21_1 + public void changeDimension(DimensionTransition dimensionTransition, CallbackInfoReturnable cir) + { this.distantHorizons$dimensionChangeDestination = dimensionTransition.newLevel(); } + #else + public void changeDimension(ServerLevel destination, CallbackInfoReturnable cir) + { this.distantHorizons$dimensionChangeDestination = destination; } + #endif + + #if MC_VER >= MC_1_20_1 + @Inject(at = @At("RETURN"), method = "setServerLevel") + public void setServerLevel(ServerLevel level, CallbackInfo ci) + #else + @Inject(at = @At("RETURN"), method = "setLevel") + public void setLevel(ServerLevel level, CallbackInfo ci) + #endif + { + this.distantHorizons$dimensionChangeDestination = null; + } + +} \ No newline at end of file diff --git a/neoforge/src/main/resources/DistantHorizons.neoforge.mixins.json b/neoforge/src/main/resources/DistantHorizons.neoforge.mixins.json index eb99ea742..63d563684 100644 --- a/neoforge/src/main/resources/DistantHorizons.neoforge.mixins.json +++ b/neoforge/src/main/resources/DistantHorizons.neoforge.mixins.json @@ -6,7 +6,8 @@ "server.MixinUtilBackgroundThread", "server.MixinChunkGenerator", "server.MixinTFChunkGenerator", - "server.MixinChunkMap" + "server.MixinChunkMap", + "server.MixinServerPlayer" ], "client": [ "client.MixinClientPacketListener",