Initial Network System implementation

This commit is contained in:
2022-09-24 21:21:01 +02:00
parent ab33e57245
commit 570321b274
25 changed files with 625 additions and 74 deletions

View File

@@ -0,0 +1,65 @@
package me.hypherionmc.craterlib.common;
import me.hypherionmc.craterlib.network.CraterNetworkHandler;
import me.hypherionmc.craterlib.network.CraterPacket;
import me.hypherionmc.craterlib.network.ForgeNetworkHandler;
import me.hypherionmc.craterlib.platform.services.LibCommonHelper;
import net.minecraft.client.Minecraft;
import net.minecraft.network.Connection;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraftforge.server.ServerLifecycleHooks;
import java.util.Objects;
import java.util.function.Function;
/**
* @author HypherionSA
* @date 24/09/2022
*/
public class ForgeCommonHelper implements LibCommonHelper {
@Override
public CraterNetworkHandler createPacketHandler(String modid) {
return ForgeNetworkHandler.of(modid, true, true);
}
@Override
public Minecraft getClientInstance() {
return Minecraft.getInstance();
}
@Override
public Player getClientPlayer() {
return Minecraft.getInstance().player;
}
@Override
public Level getClientLevel() {
return Minecraft.getInstance().level;
}
@Override
public Connection getClientConnection() {
Objects.requireNonNull(Minecraft.getInstance().getConnection(), "Cannot send packets when not in game!");
return Minecraft.getInstance().getConnection().getConnection();
}
@Override
public MinecraftServer getMCServer() {
return ServerLifecycleHooks.getCurrentServer();
}
@Override
public void registerClientReceiver(ResourceLocation channelName, Function<FriendlyByteBuf, CraterPacket<?>> factory) {
// UNUSED
}
@Override
public void registerServerReceiver(ResourceLocation channelName, Function<FriendlyByteBuf, CraterPacket<?>> factory) {
// UNUSED
}
}

View File

@@ -0,0 +1,72 @@
package me.hypherionmc.craterlib.common;
import me.hypherionmc.craterlib.platform.services.Environment;
import me.hypherionmc.craterlib.platform.services.ILoaderHelper;
import net.minecraft.SharedConstants;
import net.minecraft.client.Minecraft;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.loading.FMLLoader;
import net.minecraftforge.fml.loading.FMLPaths;
import java.io.File;
/**
* @author HypherionSA
* @date 07/08/2022
*/
public class ForgeLoaderHelper implements ILoaderHelper {
@Override
public boolean isFabric() {
return false;
}
@Override
public boolean isForge() {
return true;
}
@Override
public String getGameVersion() {
return SharedConstants.VERSION_STRING;
}
@Override
public File getGameFolder() {
return Minecraft.getInstance().gameDirectory;
}
@Override
public File getConfigFolder() {
return FMLPaths.CONFIGDIR.get().toFile();
}
@Override
public File getModsFolder() {
return FMLPaths.MODSDIR.get().toFile();
}
@Override
public Environment getEnvironment() {
switch (FMLLoader.getDist()) {
case CLIENT -> {
return Environment.CLIENT;
}
case DEDICATED_SERVER -> {
return Environment.SERVER;
}
}
return Environment.UNKNOWN;
}
@Override
public boolean isModLoaded(String modid) {
return ModList.get().isLoaded(modid);
}
@Override
public boolean isDevEnv() {
return !FMLLoader.isProduction();
}
}

View File

@@ -1,27 +0,0 @@
package me.hypherionmc.craterlib.common;
import me.hypherionmc.craterlib.platform.services.IPlatformHelper;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.loading.FMLLoader;
/**
* @author HypherionSA
* @date 07/08/2022
*/
public class ForgePlatformHelper implements IPlatformHelper {
@Override
public String getPlatformName() {
return "Forge";
}
@Override
public boolean isModLoaded(String modId) {
return ModList.get().isLoaded(modId);
}
@Override
public boolean isDevelopmentEnvironment() {
return !FMLLoader.isProduction();
}
}

View File

@@ -0,0 +1,112 @@
package me.hypherionmc.craterlib.network;
import com.google.common.collect.Maps;
import me.hypherionmc.craterlib.platform.Platform;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.protocol.Packet;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.player.Player;
import net.minecraftforge.common.util.LogicalSidedProvider;
import net.minecraftforge.fml.LogicalSide;
import net.minecraftforge.network.NetworkDirection;
import net.minecraftforge.network.NetworkEvent;
import net.minecraftforge.network.NetworkRegistry;
import net.minecraftforge.network.simple.SimpleChannel;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* @author HypherionSA
* @date 24/09/2022
* Partly inspired by and based on https://github.com/Fuzss/puzzleslib/blob/1.19/Forge/src/main/java/fuzs/puzzleslib/network/ForgeNetworkHandler.java
*/
public class ForgeNetworkHandler implements CraterNetworkHandler {
private static final Map<String, ForgeNetworkHandler> NETWORK_HANDLERS = Maps.newConcurrentMap();
private static final String PROTOCOL = Integer.toString(1);
private final SimpleChannel channel;
private final boolean clientRequired;
private final boolean serverRequired;
private final AtomicInteger packetID = new AtomicInteger();
private ForgeNetworkHandler(SimpleChannel channel, boolean clientRequired, boolean serverRequired) {
this.channel = channel;
this.clientRequired = clientRequired;
this.serverRequired = serverRequired;
}
@Override
public <T extends CraterPacket<T>> void registerPacket(Class<? extends T> clazz, Supplier<T> supplier, PacketDirection packetDirection) {
BiConsumer<T, FriendlyByteBuf> encoder = CraterPacket::write;
Function<FriendlyByteBuf, T> decoder = buf -> {
T packet = supplier.get();
packet.read(buf);
return packet;
};
BiConsumer<T, Supplier<NetworkEvent.Context>> handler = (packet, sup) -> {
NetworkEvent.Context context = sup.get();
LogicalSide expectedSide = getSideFromDirection(packetDirection);
LogicalSide currentSide = context.getDirection().getReceptionSide();
if (expectedSide != currentSide) {
throw new IllegalStateException(String.format("Received message on wrong side, expected %s, was %s", expectedSide, currentSide));
}
context.enqueueWork(() -> {
Player player;
if (packetDirection == PacketDirection.TO_CLIENT) {
player = Platform.COMMON_HELPER.getClientPlayer();
} else {
player = context.getSender();
}
packet.handle(player, LogicalSidedProvider.WORKQUEUE.get(expectedSide));
});
context.setPacketHandled(true);
};
this.channel.registerMessage(this.packetID.getAndIncrement(), (Class<T>) clazz, encoder, decoder, handler);
}
@Override
public Packet<?> toServerBound(CraterPacket<?> packet) {
return this.channel.toVanillaPacket(packet, NetworkDirection.PLAY_TO_SERVER);
}
@Override
public Packet<?> toClientBound(CraterPacket<?> packet) {
return this.channel.toVanillaPacket(packet, NetworkDirection.PLAY_TO_CLIENT);
}
@Override
public void sendToServer(CraterPacket<?> packet) {
CraterNetworkHandler.super.sendToServer(packet);
}
public synchronized static CraterNetworkHandler of(String modId, boolean clientRequired, boolean serverRequired) {
ForgeNetworkHandler handler = NETWORK_HANDLERS.computeIfAbsent(modId, modId1 -> new ForgeNetworkHandler(buildSimpleChannel(modId1, clientRequired, serverRequired), clientRequired, serverRequired));
if (handler.clientRequired != clientRequired) throw new IllegalArgumentException("client channel settings mismatch, expected %s, but was %s".formatted(handler.clientRequired, clientRequired));
if (handler.serverRequired != serverRequired) throw new IllegalArgumentException("server channel settings mismatch, expected %s, but was %s".formatted(handler.serverRequired, serverRequired));
return handler;
}
private static SimpleChannel buildSimpleChannel(String modId, boolean clientAcceptsVanillaOrMissing, boolean serverAcceptsVanillaOrMissing) {
return NetworkRegistry.ChannelBuilder
.named(new ResourceLocation(modId, "crater_network"))
.networkProtocolVersion(() -> PROTOCOL)
.clientAcceptedVersions(clientAcceptsVanillaOrMissing ? NetworkRegistry.acceptMissingOr(PROTOCOL) : PROTOCOL::equals)
.serverAcceptedVersions(serverAcceptsVanillaOrMissing ? NetworkRegistry.acceptMissingOr(PROTOCOL) : PROTOCOL::equals)
.simpleChannel();
}
private LogicalSide getSideFromDirection(PacketDirection direction) {
return direction == PacketDirection.TO_CLIENT ? LogicalSide.CLIENT : LogicalSide.SERVER;
}
}

View File

@@ -0,0 +1 @@
me.hypherionmc.craterlib.common.ForgeLoaderHelper

View File

@@ -1 +0,0 @@
me.hypherionmc.craterlib.common.ForgePlatformHelper

View File

@@ -0,0 +1 @@
me.hypherionmc.craterlib.common.ForgeCommonHelper