mirror of
https://github.com/BX-Team/DivineMC.git
synced 2025-12-22 16:29:23 +00:00
upstream leaves protocols
This commit is contained in:
@@ -8,6 +8,7 @@ import net.minecraft.world.level.GameRules;
|
||||
import org.bxteam.divinemc.config.DivineConfig;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.leavesmc.leaves.protocol.core.Context;
|
||||
import org.leavesmc.leaves.protocol.core.LeavesProtocol;
|
||||
import org.leavesmc.leaves.protocol.core.ProtocolHandler;
|
||||
import org.leavesmc.leaves.protocol.core.ProtocolUtils;
|
||||
@@ -16,9 +17,11 @@ import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
@LeavesProtocol.Register(namespace = "appleskin")
|
||||
public class AppleSkinProtocol implements LeavesProtocol {
|
||||
|
||||
public static final String PROTOCOL_ID = "appleskin";
|
||||
|
||||
private static final ResourceLocation SATURATION_KEY = id("saturation");
|
||||
@@ -31,7 +34,7 @@ public class AppleSkinProtocol implements LeavesProtocol {
|
||||
private static final Map<ServerPlayer, Float> previousExhaustionLevels = new HashMap<>();
|
||||
private static final Map<ServerPlayer, Boolean> previousNaturalRegeneration = new HashMap<>();
|
||||
|
||||
private static final Map<ServerPlayer, Set<String>> subscribedChannels = new HashMap<>();
|
||||
private static final Map<UUID, Set<String>> subscribedChannels = new HashMap<>();
|
||||
|
||||
@Contract("_ -> new")
|
||||
public static ResourceLocation id(String path) {
|
||||
@@ -45,21 +48,24 @@ public class AppleSkinProtocol implements LeavesProtocol {
|
||||
|
||||
@ProtocolHandler.PlayerLeave
|
||||
public static void onPlayerLoggedOut(@NotNull ServerPlayer player) {
|
||||
subscribedChannels.remove(player);
|
||||
subscribedChannels.remove(player.getUUID());
|
||||
resetPlayerData(player);
|
||||
}
|
||||
|
||||
@ProtocolHandler.MinecraftRegister(onlyNamespace = true)
|
||||
public static void onPlayerSubscribed(@NotNull ServerPlayer player, ResourceLocation id) {
|
||||
subscribedChannels.computeIfAbsent(player, k -> new HashSet<>()).add(id.getPath());
|
||||
public static void onPlayerSubscribed(@NotNull Context context, ResourceLocation id) {
|
||||
subscribedChannels.computeIfAbsent(context.profile().getId(), k -> new HashSet<>()).add(id.getPath());
|
||||
}
|
||||
|
||||
@ProtocolHandler.Ticker
|
||||
public static void tick() {
|
||||
for (Map.Entry<ServerPlayer, Set<String>> entry : subscribedChannels.entrySet()) {
|
||||
ServerPlayer player = entry.getKey();
|
||||
FoodData data = player.getFoodData();
|
||||
for (Map.Entry<UUID, Set<String>> entry : subscribedChannels.entrySet()) {
|
||||
ServerPlayer player = MinecraftServer.getServer().getPlayerList().getPlayer(entry.getKey());
|
||||
if (player == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
FoodData data = player.getFoodData();
|
||||
for (String channel : entry.getValue()) {
|
||||
switch (channel) {
|
||||
case "saturation" -> {
|
||||
|
||||
@@ -10,6 +10,7 @@ import org.leavesmc.leaves.protocol.core.ProtocolUtils;
|
||||
|
||||
@LeavesProtocol.Register(namespace = "xaerominimap_or_xaeroworldmap_i_dont_care")
|
||||
public class XaeroMapProtocol implements LeavesProtocol {
|
||||
|
||||
public static final String PROTOCOL_ID_MINI = "xaerominimap";
|
||||
public static final String PROTOCOL_ID_WORLD = "xaeroworldmap";
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.leavesmc.leaves.protocol.core;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import net.minecraft.network.Connection;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public record Context(@NotNull GameProfile profile, Connection connection) {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package org.leavesmc.leaves.protocol.core;
|
||||
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public record IdentifierSelector(@Nullable Context context, @Nullable ServerPlayer player) {
|
||||
|
||||
public Object select(ProtocolHandler.Stage stage) {
|
||||
return stage == ProtocolHandler.Stage.CONFIGURATION ? context : player;
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
public interface LeavesCustomPayload extends CustomPacketPayload {
|
||||
|
||||
Type<? extends CustomPacketPayload> LEAVES_TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath("leaves", "custom_payload"));
|
||||
|
||||
@Override
|
||||
|
||||
@@ -6,6 +6,7 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
public interface LeavesProtocol {
|
||||
|
||||
boolean isActive();
|
||||
|
||||
default int tickerInterval(String tickerID) {
|
||||
@@ -17,4 +18,4 @@ public interface LeavesProtocol {
|
||||
@interface Register {
|
||||
String namespace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package org.leavesmc.leaves.protocol.core;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.papermc.paper.connection.PluginMessageBridgeImpl;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
@@ -15,9 +14,6 @@ import org.leavesmc.leaves.protocol.core.invoker.MinecraftRegisterInvokerHolder;
|
||||
import org.leavesmc.leaves.protocol.core.invoker.PayloadReceiverInvokerHolder;
|
||||
import org.leavesmc.leaves.protocol.core.invoker.PlayerInvokerHolder;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.craftbukkit.entity.CraftPlayer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
@@ -40,6 +36,7 @@ import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
public class LeavesProtocolManager {
|
||||
|
||||
private static final LeavesLogger LOGGER = LeavesLogger.LOGGER;
|
||||
|
||||
private static final Map<Class<? extends LeavesCustomPayload>, PayloadReceiverInvokerHolder> PAYLOAD_RECEIVERS = new HashMap<>();
|
||||
@@ -101,16 +98,6 @@ public class LeavesProtocolManager {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean active = true;
|
||||
try {
|
||||
Method isActiveMethod = clazz.getDeclaredMethod("isActive");
|
||||
isActiveMethod.setAccessible(true);
|
||||
active = (Boolean) isActiveMethod.invoke(protocol);
|
||||
} catch (Throwable e) {
|
||||
LOGGER.warning("Failed to check isActive for " + clazz.getName() + ": " + e);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (final Method method : clazz.getDeclaredMethods()) {
|
||||
if (method.isBridge() || method.isSynthetic()) {
|
||||
continue;
|
||||
@@ -128,20 +115,6 @@ public class LeavesProtocolManager {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!active) continue;
|
||||
|
||||
final ProtocolHandler.ReloadServer reloadServer = method.getAnnotation(ProtocolHandler.ReloadServer.class);
|
||||
if (reloadServer != null) {
|
||||
RELOAD_SERVER.add(new EmptyInvokerHolder<>(protocol, method, reloadServer));
|
||||
continue;
|
||||
}
|
||||
|
||||
final ProtocolHandler.ReloadDataPack reloadDataPack = method.getAnnotation(ProtocolHandler.ReloadDataPack.class);
|
||||
if (reloadDataPack != null) {
|
||||
RELOAD_DATAPACK.add(new EmptyInvokerHolder<>(protocol, method, reloadDataPack));
|
||||
continue;
|
||||
}
|
||||
|
||||
final ProtocolHandler.PayloadReceiver payloadReceiver = method.getAnnotation(ProtocolHandler.PayloadReceiver.class);
|
||||
if (payloadReceiver != null) {
|
||||
PAYLOAD_RECEIVERS.put(payloadReceiver.payload(), new PayloadReceiverInvokerHolder(protocol, method, payloadReceiver));
|
||||
@@ -186,6 +159,18 @@ public class LeavesProtocolManager {
|
||||
continue;
|
||||
}
|
||||
|
||||
final ProtocolHandler.ReloadServer reloadServer = method.getAnnotation(ProtocolHandler.ReloadServer.class);
|
||||
if (reloadServer != null) {
|
||||
RELOAD_SERVER.add(new EmptyInvokerHolder<>(protocol, method, reloadServer));
|
||||
continue;
|
||||
}
|
||||
|
||||
final ProtocolHandler.ReloadDataPack reloadDataPack = method.getAnnotation(ProtocolHandler.ReloadDataPack.class);
|
||||
if (reloadDataPack != null) {
|
||||
RELOAD_DATAPACK.add(new EmptyInvokerHolder<>(protocol, method, reloadDataPack));
|
||||
continue;
|
||||
}
|
||||
|
||||
final ProtocolHandler.MinecraftRegister minecraftRegister = method.getAnnotation(ProtocolHandler.MinecraftRegister.class);
|
||||
if (minecraftRegister != null) {
|
||||
String key = minecraftRegister.key();
|
||||
@@ -233,27 +218,27 @@ public class LeavesProtocolManager {
|
||||
codec.encode(ProtocolUtils.decorate(buf), payload);
|
||||
}
|
||||
|
||||
public static void handlePayload(ServerPlayer player, LeavesCustomPayload payload) {
|
||||
public static void handlePayload(IdentifierSelector selector, LeavesCustomPayload payload) {
|
||||
PayloadReceiverInvokerHolder holder;
|
||||
if ((holder = PAYLOAD_RECEIVERS.get(payload.getClass())) != null) {
|
||||
holder.invoke(player, payload);
|
||||
holder.invoke(selector, payload);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean handleBytebuf(ServerPlayer player, ResourceLocation location, ByteBuf buf) {
|
||||
public static boolean handleBytebuf(IdentifierSelector selector, ResourceLocation location, ByteBuf buf) {
|
||||
RegistryFriendlyByteBuf buf1 = ProtocolUtils.decorate(buf);
|
||||
BytebufReceiverInvokerHolder holder;
|
||||
if ((holder = STRICT_BYTEBUF_RECEIVERS.get(location.toString())) != null) {
|
||||
holder.invoke(player, buf1);
|
||||
holder.invoke(selector, buf1);
|
||||
return true;
|
||||
}
|
||||
if ((holder = NAMESPACED_BYTEBUF_RECEIVERS.get(location.getNamespace())) != null) {
|
||||
if (holder.invoke(player, buf1)) {
|
||||
if (holder.invoke(selector, buf1)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (var holder1 : GENERIC_BYTEBUF_RECEIVERS) {
|
||||
if (holder1.invoke(player, buf1)) {
|
||||
if (holder1.invoke(selector, buf1)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -293,39 +278,37 @@ public class LeavesProtocolManager {
|
||||
}
|
||||
}
|
||||
|
||||
public static void handleMinecraftRegister(String channelId, PluginMessageBridgeImpl bridge) {
|
||||
ServerPlayer player = null;
|
||||
if (bridge instanceof CraftPlayer craftPlayer) {
|
||||
player = craftPlayer.getHandle();
|
||||
}
|
||||
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
public static void handleMinecraftRegister(String channelId, IdentifierSelector selector) {
|
||||
ResourceLocation location = ResourceLocation.tryParse(channelId);
|
||||
if (location == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (var wildHolder : WILD_MINECRAFT_REGISTER) {
|
||||
wildHolder.invoke(player, location);
|
||||
wildHolder.invoke(selector, location);
|
||||
}
|
||||
|
||||
MinecraftRegisterInvokerHolder holder;
|
||||
if ((holder = STRICT_MINECRAFT_REGISTER.get(location.toString())) != null) {
|
||||
holder.invoke(player, location);
|
||||
holder.invoke(selector, location);
|
||||
}
|
||||
if ((holder = NAMESPACED_MINECRAFT_REGISTER.get(location.getNamespace())) != null) {
|
||||
holder.invoke(player, location);
|
||||
holder.invoke(selector, location);
|
||||
}
|
||||
}
|
||||
|
||||
private static void sendKnownId(ServerPlayer player) {
|
||||
Set<String> set = new HashSet<>();
|
||||
PAYLOAD_RECEIVERS.forEach((clazz, holder) -> set.add(IDS.get(clazz).toString()));
|
||||
STRICT_BYTEBUF_RECEIVERS.forEach((key, holder) -> set.add(key));
|
||||
if (set.isEmpty()) return;
|
||||
PAYLOAD_RECEIVERS.forEach((clazz, holder) -> {
|
||||
if (holder.owner().isActive()) {
|
||||
set.add(IDS.get(clazz).toString());
|
||||
}
|
||||
});
|
||||
STRICT_BYTEBUF_RECEIVERS.forEach((key, holder) -> {
|
||||
if (holder.owner().isActive()) {
|
||||
set.add(key);
|
||||
}
|
||||
});
|
||||
ProtocolUtils.sendBytebufPacket(player, ResourceLocation.fromNamespaceAndPath("minecraft", "register"), buf -> {
|
||||
for (String channel : set) {
|
||||
buf.writeBytes(channel.getBytes(StandardCharsets.US_ASCII));
|
||||
@@ -409,4 +392,4 @@ public class LeavesProtocolManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,14 @@
|
||||
package org.leavesmc.leaves.protocol.core;
|
||||
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
public class ProtocolHandler {
|
||||
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Init {
|
||||
@@ -15,6 +18,8 @@ public class ProtocolHandler {
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface PayloadReceiver {
|
||||
Class<? extends LeavesCustomPayload> payload();
|
||||
|
||||
Stage stage() default Stage.GAME;
|
||||
}
|
||||
|
||||
@Target(ElementType.METHOD)
|
||||
@@ -23,6 +28,8 @@ public class ProtocolHandler {
|
||||
String key() default "";
|
||||
|
||||
boolean onlyNamespace() default false;
|
||||
|
||||
Stage stage() default Stage.GAME;
|
||||
}
|
||||
|
||||
@Target(ElementType.METHOD)
|
||||
@@ -52,10 +59,27 @@ public class ProtocolHandler {
|
||||
String key() default "";
|
||||
|
||||
boolean onlyNamespace() default false;
|
||||
|
||||
Stage stage() default Stage.CONFIGURATION;
|
||||
}
|
||||
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ReloadDataPack {
|
||||
}
|
||||
}
|
||||
|
||||
public enum Stage {
|
||||
CONFIGURATION(Context.class),
|
||||
GAME(ServerPlayer.class);
|
||||
|
||||
private final Class<?> identifier;
|
||||
|
||||
Stage(Class<?> identifier) {
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
public Class<?> identifier() {
|
||||
return identifier;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,33 +11,61 @@ import net.minecraft.network.protocol.common.custom.DiscardedPayload;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.server.network.ServerCommonPacketListenerImpl;
|
||||
import net.minecraft.server.network.ServerGamePacketListenerImpl;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class ProtocolUtils {
|
||||
|
||||
private static final Function<ByteBuf, RegistryFriendlyByteBuf> bufDecorator = buf -> buf instanceof RegistryFriendlyByteBuf registry ? registry : new RegistryFriendlyByteBuf(buf, MinecraftServer.getServer().registryAccess());
|
||||
private static final byte[] EMPTY = new byte[0];
|
||||
|
||||
public static String buildProtocolVersion(String protocol) {
|
||||
return protocol + "-leaves-" + ServerBuildInfo.buildInfo().asString(ServerBuildInfo.StringRepresentation.VERSION_SIMPLE);
|
||||
}
|
||||
|
||||
public static void sendEmptyPacket(ServerPlayer player, ResourceLocation id) {
|
||||
player.internalConnection.send(new ClientboundCustomPayloadPacket(new DiscardedPayload(id, null)));
|
||||
player.connection.send(new ClientboundCustomPayloadPacket(new DiscardedPayload(id, EMPTY)));
|
||||
}
|
||||
|
||||
public static void sendBytebufPacket(@NotNull ServerPlayer player, ResourceLocation id, Consumer<? super RegistryFriendlyByteBuf> consumer) {
|
||||
RegistryFriendlyByteBuf buf = decorate(Unpooled.buffer());
|
||||
consumer.accept(buf);
|
||||
player.internalConnection.send(new ClientboundCustomPayloadPacket(new DiscardedPayload(id, ByteBufUtil.getBytes(buf))));
|
||||
player.connection.send(new ClientboundCustomPayloadPacket(new DiscardedPayload(id, ByteBufUtil.getBytes(buf))));
|
||||
}
|
||||
|
||||
public static void sendPayloadPacket(ServerPlayer player, CustomPacketPayload payload) {
|
||||
player.internalConnection.send(new ClientboundCustomPayloadPacket(payload));
|
||||
player.connection.send(new ClientboundCustomPayloadPacket(payload));
|
||||
}
|
||||
|
||||
public static void sendEmptyPacket(Context context, ResourceLocation id) {
|
||||
context.connection().send(new ClientboundCustomPayloadPacket(new DiscardedPayload(id, EMPTY)));
|
||||
}
|
||||
|
||||
public static void sendBytebufPacket(@NotNull Context context, ResourceLocation id, Consumer<? super RegistryFriendlyByteBuf> consumer) {
|
||||
RegistryFriendlyByteBuf buf = decorate(Unpooled.buffer());
|
||||
consumer.accept(buf);
|
||||
context.connection().send(new ClientboundCustomPayloadPacket(new DiscardedPayload(id, ByteBufUtil.getBytes(buf))));
|
||||
}
|
||||
|
||||
public static void sendPayloadPacket(Context context, CustomPacketPayload payload) {
|
||||
context.connection().send(new ClientboundCustomPayloadPacket(payload));
|
||||
}
|
||||
|
||||
public static RegistryFriendlyByteBuf decorate(ByteBuf buf) {
|
||||
return bufDecorator.apply(buf);
|
||||
}
|
||||
|
||||
public static IdentifierSelector createSelector(ServerCommonPacketListenerImpl common) {
|
||||
ServerPlayer player = common instanceof ServerGamePacketListenerImpl game ? game.getPlayer() : null;
|
||||
return new IdentifierSelector(new Context(common.profile, common.connection), player);
|
||||
}
|
||||
|
||||
public static ByteBuf wrapNullable(byte @Nullable [] data) {
|
||||
return data == null ? Unpooled.wrappedBuffer(EMPTY) : Unpooled.wrappedBuffer(data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,15 +4,18 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.leavesmc.leaves.protocol.core.LeavesProtocol;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
public abstract class AbstractInvokerHolder<T> {
|
||||
|
||||
protected final LeavesProtocol owner;
|
||||
protected final Method invoker;
|
||||
protected final T handler;
|
||||
protected final Class<?> returnType;
|
||||
protected final Class<?>[] parameterTypes;
|
||||
protected final boolean isStatic;
|
||||
|
||||
protected AbstractInvokerHolder(LeavesProtocol owner, Method invoker, T handler, @Nullable Class<?> returnType, @NotNull Class<?>... parameterTypes) {
|
||||
this.owner = owner;
|
||||
@@ -20,6 +23,7 @@ public abstract class AbstractInvokerHolder<T> {
|
||||
this.handler = handler;
|
||||
this.returnType = returnType;
|
||||
this.parameterTypes = parameterTypes;
|
||||
this.isStatic = Modifier.isStatic(invoker.getModifiers());
|
||||
|
||||
validateMethodSignature();
|
||||
}
|
||||
@@ -57,11 +61,13 @@ public abstract class AbstractInvokerHolder<T> {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
if (Modifier.isStatic(invoker.getModifiers())) {
|
||||
if (isStatic) {
|
||||
return invoker.invoke(null, args);
|
||||
} else {
|
||||
return invoker.invoke(owner, args);
|
||||
}
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e.getCause());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package org.leavesmc.leaves.protocol.core.invoker;
|
||||
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.leavesmc.leaves.protocol.core.IdentifierSelector;
|
||||
import org.leavesmc.leaves.protocol.core.LeavesProtocol;
|
||||
import org.leavesmc.leaves.protocol.core.ProtocolHandler;
|
||||
|
||||
@@ -9,10 +9,10 @@ import java.lang.reflect.Method;
|
||||
|
||||
public class BytebufReceiverInvokerHolder extends AbstractInvokerHolder<ProtocolHandler.BytebufReceiver> {
|
||||
public BytebufReceiverInvokerHolder(LeavesProtocol owner, Method invoker, ProtocolHandler.BytebufReceiver handler) {
|
||||
super(owner, invoker, handler, null, ServerPlayer.class, FriendlyByteBuf.class);
|
||||
super(owner, invoker, handler, null, handler.stage().identifier(), FriendlyByteBuf.class);
|
||||
}
|
||||
|
||||
public boolean invoke(ServerPlayer player, FriendlyByteBuf buf) {
|
||||
return invoke0(false, player, buf) instanceof Boolean b && b;
|
||||
public boolean invoke(IdentifierSelector selector, FriendlyByteBuf buf) {
|
||||
return invoke0(false, selector.select(handler.stage()), buf) instanceof Boolean b && b;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package org.leavesmc.leaves.protocol.core.invoker;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.leavesmc.leaves.protocol.core.IdentifierSelector;
|
||||
import org.leavesmc.leaves.protocol.core.LeavesProtocol;
|
||||
import org.leavesmc.leaves.protocol.core.ProtocolHandler;
|
||||
|
||||
@@ -9,10 +9,10 @@ import java.lang.reflect.Method;
|
||||
|
||||
public class MinecraftRegisterInvokerHolder extends AbstractInvokerHolder<ProtocolHandler.MinecraftRegister> {
|
||||
public MinecraftRegisterInvokerHolder(LeavesProtocol owner, Method invoker, ProtocolHandler.MinecraftRegister handler) {
|
||||
super(owner, invoker, handler, null, ServerPlayer.class, ResourceLocation.class);
|
||||
super(owner, invoker, handler, null, handler.stage().identifier(), ResourceLocation.class);
|
||||
}
|
||||
|
||||
public void invoke(ServerPlayer player, ResourceLocation id) {
|
||||
invoke0(false, player, id);
|
||||
public void invoke(IdentifierSelector selector, ResourceLocation id) {
|
||||
invoke0(false, selector.select(handler.stage()), id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package org.leavesmc.leaves.protocol.core.invoker;
|
||||
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.leavesmc.leaves.protocol.core.IdentifierSelector;
|
||||
import org.leavesmc.leaves.protocol.core.LeavesCustomPayload;
|
||||
import org.leavesmc.leaves.protocol.core.LeavesProtocol;
|
||||
import org.leavesmc.leaves.protocol.core.ProtocolHandler;
|
||||
@@ -9,10 +9,10 @@ import java.lang.reflect.Method;
|
||||
|
||||
public class PayloadReceiverInvokerHolder extends AbstractInvokerHolder<ProtocolHandler.PayloadReceiver> {
|
||||
public PayloadReceiverInvokerHolder(LeavesProtocol owner, Method invoker, ProtocolHandler.PayloadReceiver handler) {
|
||||
super(owner, invoker, handler, null, ServerPlayer.class, handler.payload());
|
||||
super(owner, invoker, handler, null, handler.stage().identifier(), handler.payload());
|
||||
}
|
||||
|
||||
public void invoke(ServerPlayer player, LeavesCustomPayload payload) {
|
||||
invoke0(false, player, payload);
|
||||
public void invoke(IdentifierSelector selector, LeavesCustomPayload payload) {
|
||||
invoke0(false, selector.select(handler.stage()), payload);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,6 @@ import org.leavesmc.leaves.protocol.jade.util.PairHierarchyLookup;
|
||||
import org.leavesmc.leaves.protocol.jade.util.PriorityStore;
|
||||
import org.leavesmc.leaves.protocol.jade.util.WrappedHierarchyLookup;
|
||||
import org.leavesmc.leaves.util.NbtUtils;
|
||||
import org.purpurmc.purpur.util.MinecraftInternalPlugin;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
@@ -92,7 +91,7 @@ import java.util.Set;
|
||||
public class JadeProtocol implements LeavesProtocol {
|
||||
|
||||
public static final String PROTOCOL_ID = "jade";
|
||||
public static final String PROTOCOL_VERSION = "7";
|
||||
public static final String PROTOCOL_VERSION = "8";
|
||||
public static final HierarchyLookup<IServerDataProvider<EntityAccessor>> entityDataProviders = new HierarchyLookup<>(Entity.class);
|
||||
public static final PairHierarchyLookup<IServerDataProvider<BlockAccessor>> blockDataProviders = new PairHierarchyLookup<>(new HierarchyLookup<>(Block.class), new HierarchyLookup<>(BlockEntity.class));
|
||||
public static final WrappedHierarchyLookup<IServerExtensionProvider<ItemStack>> itemStorageProviders = WrappedHierarchyLookup.forAccessor();
|
||||
|
||||
@@ -3,13 +3,13 @@ package org.leavesmc.leaves.protocol.jade.accessor;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.codec.StreamEncoder;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface Accessor<T extends HitResult> {
|
||||
Level getLevel();
|
||||
ServerLevel getLevel();
|
||||
|
||||
Player getPlayer();
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@ import net.minecraft.nbt.ByteArrayTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.codec.StreamEncoder;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
|
||||
@@ -14,20 +14,20 @@ import java.util.function.Supplier;
|
||||
|
||||
public abstract class AccessorImpl<T extends HitResult> implements Accessor<T> {
|
||||
|
||||
private final Level level;
|
||||
private final ServerLevel level;
|
||||
private final Player player;
|
||||
private final Supplier<T> hit;
|
||||
protected boolean verify;
|
||||
private RegistryFriendlyByteBuf buffer;
|
||||
|
||||
public AccessorImpl(Level level, Player player, Supplier<T> hit) {
|
||||
public AccessorImpl(ServerLevel level, Player player, Supplier<T> hit) {
|
||||
this.level = level;
|
||||
this.player = player;
|
||||
this.hit = hit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Level getLevel() {
|
||||
public ServerLevel getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package org.leavesmc.leaves.protocol.jade.accessor;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
@@ -23,7 +23,7 @@ public interface BlockAccessor extends Accessor<BlockHitResult> {
|
||||
|
||||
@ApiStatus.NonExtendable
|
||||
interface Builder {
|
||||
Builder level(Level level);
|
||||
Builder level(ServerLevel level);
|
||||
|
||||
Builder player(Player player);
|
||||
|
||||
|
||||
@@ -6,10 +6,10 @@ import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.codec.ByteBufCodecs;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
@@ -61,14 +61,14 @@ public class BlockAccessorImpl extends AccessorImpl<BlockHitResult> implements B
|
||||
}
|
||||
|
||||
public static class Builder implements BlockAccessor.Builder {
|
||||
private Level level;
|
||||
private ServerLevel level;
|
||||
private Player player;
|
||||
private BlockHitResult hit;
|
||||
private BlockState blockState = Blocks.AIR.defaultBlockState();
|
||||
private Supplier<BlockEntity> blockEntity;
|
||||
|
||||
@Override
|
||||
public Builder level(Level level) {
|
||||
public Builder level(ServerLevel level) {
|
||||
this.level = level;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package org.leavesmc.leaves.protocol.jade.accessor;
|
||||
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.EntityHitResult;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
@@ -19,7 +19,7 @@ public interface EntityAccessor extends Accessor<EntityHitResult> {
|
||||
|
||||
@ApiStatus.NonExtendable
|
||||
interface Builder {
|
||||
Builder level(Level level);
|
||||
Builder level(ServerLevel level);
|
||||
|
||||
Builder player(Player player);
|
||||
|
||||
|
||||
@@ -4,10 +4,10 @@ import com.google.common.base.Suppliers;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.codec.ByteBufCodecs;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.EntityHitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -41,13 +41,13 @@ public class EntityAccessorImpl extends AccessorImpl<EntityHitResult> implements
|
||||
}
|
||||
|
||||
public static class Builder implements EntityAccessor.Builder {
|
||||
private Level level;
|
||||
private ServerLevel level;
|
||||
private Player player;
|
||||
private Supplier<EntityHitResult> hit;
|
||||
private Supplier<Entity> entity;
|
||||
|
||||
@Override
|
||||
public Builder level(Level level) {
|
||||
public Builder level(ServerLevel level) {
|
||||
this.level = level;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,12 @@ import java.util.Map;
|
||||
|
||||
import static org.leavesmc.leaves.protocol.jade.util.JadeCodec.PRIMITIVE_STREAM_CODEC;
|
||||
|
||||
public record ServerHandshakePayload(Map<ResourceLocation, Object> serverConfig, List<Block> shearableBlocks, List<ResourceLocation> blockProviderIds, List<ResourceLocation> entityProviderIds) implements LeavesCustomPayload {
|
||||
public record ServerHandshakePayload(
|
||||
Map<ResourceLocation, Object> serverConfig,
|
||||
List<Block> shearableBlocks,
|
||||
List<ResourceLocation> blockProviderIds,
|
||||
List<ResourceLocation> entityProviderIds
|
||||
) implements LeavesCustomPayload {
|
||||
|
||||
@ID
|
||||
private static final ResourceLocation PACKET_SERVER_HANDSHAKE = JadeProtocol.id("server_handshake");
|
||||
|
||||
@@ -13,7 +13,6 @@ import net.minecraft.world.entity.vehicle.ContainerEntity;
|
||||
import net.minecraft.world.inventory.PlayerEnderChestContainer;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.block.ChestBlock;
|
||||
import net.minecraft.world.level.block.EnderChestBlock;
|
||||
import net.minecraft.world.level.block.entity.BaseContainerBlockEntity;
|
||||
import net.minecraft.world.level.block.entity.ChestBlockEntity;
|
||||
import net.minecraft.world.level.block.entity.EnderChestBlockEntity;
|
||||
@@ -58,7 +57,11 @@ public enum ItemStorageExtensionProvider implements IServerExtensionProvider<Ite
|
||||
if (blockEntity.getBlockState().getBlock() instanceof ChestBlock chestBlock) {
|
||||
Container compound = null;
|
||||
if (blockEntity.getLevel() != null) {
|
||||
compound = ChestBlock.getContainer(chestBlock, blockEntity.getBlockState(), blockEntity.getLevel(), blockEntity.getBlockPos(), false);
|
||||
compound = ChestBlock.getContainer(
|
||||
chestBlock, blockEntity.getBlockState(),
|
||||
blockEntity.getLevel(), blockEntity.getBlockPos(),
|
||||
true // Bypass lock check
|
||||
);
|
||||
}
|
||||
if (compound != null) {
|
||||
return compound;
|
||||
|
||||
@@ -22,7 +22,7 @@ public enum MobSpawnerCooldownProvider implements StreamServerDataProvider<Block
|
||||
public @Nullable Integer streamData(@NotNull BlockAccessor accessor) {
|
||||
TrialSpawnerBlockEntity spawner = (TrialSpawnerBlockEntity) accessor.getBlockEntity();
|
||||
TrialSpawnerStateData spawnerData = spawner.getTrialSpawner().getStateData();
|
||||
ServerLevel level = ((ServerLevel) accessor.getLevel());
|
||||
ServerLevel level = accessor.getLevel();
|
||||
if (spawner.getTrialSpawner().canSpawnInLevel(level) && level.getGameTime() < spawnerData.cooldownEndsAt) {
|
||||
return (int) (spawnerData.cooldownEndsAt - level.getGameTime());
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ public class ItemCollector<T> {
|
||||
return null;
|
||||
}
|
||||
long currentVersion = iterator.getVersion(container);
|
||||
long gameTime = request.getLevel().getGameTime();
|
||||
long gameTime = request.getLevel().getServer().getTickCount();
|
||||
if (mergedResult != null && iterator.isFinished()) {
|
||||
if (version == currentVersion) {
|
||||
return mergedResult; // content not changed
|
||||
@@ -73,7 +73,7 @@ public class ItemCollector<T> {
|
||||
items.addTo(def, stack.getCount());
|
||||
}
|
||||
});
|
||||
iterator.afterPopulate(count.get());
|
||||
iterator.afterPopulate(container, count.get());
|
||||
if (mergedResult != null && !iterator.isFinished()) {
|
||||
updateCollectingProgress(mergedResult.getFirst());
|
||||
return mergedResult;
|
||||
|
||||
@@ -15,6 +15,7 @@ public abstract class ItemIterator<T> {
|
||||
protected final int fromIndex;
|
||||
protected boolean finished;
|
||||
protected int currentIndex;
|
||||
protected float progress;
|
||||
|
||||
protected ItemIterator(Function<Object, @Nullable T> containerFinder, int fromIndex) {
|
||||
this.containerFinder = containerFinder;
|
||||
@@ -35,16 +36,19 @@ public abstract class ItemIterator<T> {
|
||||
|
||||
public abstract Stream<ItemStack> populate(T container);
|
||||
|
||||
protected abstract int getSlotCount(T container);
|
||||
|
||||
public void reset() {
|
||||
currentIndex = fromIndex;
|
||||
finished = false;
|
||||
}
|
||||
|
||||
public void afterPopulate(int count) {
|
||||
public void afterPopulate(T container, int count) {
|
||||
currentIndex += count;
|
||||
if (count == 0 || currentIndex >= 10000) {
|
||||
finished = true;
|
||||
}
|
||||
progress = (float) (currentIndex - fromIndex) / (getSlotCount(container) - fromIndex);
|
||||
}
|
||||
|
||||
public float getCollectingProgress() {
|
||||
@@ -52,14 +56,11 @@ public abstract class ItemIterator<T> {
|
||||
}
|
||||
|
||||
public static abstract class SlottedItemIterator<T> extends ItemIterator<T> {
|
||||
protected float progress;
|
||||
|
||||
public SlottedItemIterator(Function<Object, @Nullable T> containerFinder, int fromIndex) {
|
||||
super(containerFinder, fromIndex);
|
||||
}
|
||||
|
||||
protected abstract int getSlotCount(T container);
|
||||
|
||||
protected abstract ItemStack getItemInSlot(T container, int slot);
|
||||
|
||||
@Override
|
||||
@@ -70,7 +71,6 @@ public abstract class ItemIterator<T> {
|
||||
toIndex = slotCount;
|
||||
finished = true;
|
||||
}
|
||||
progress = (float) (currentIndex - fromIndex) / (slotCount - fromIndex);
|
||||
return IntStream.range(currentIndex, toIndex).mapToObj(slot -> getItemInSlot(container, slot));
|
||||
}
|
||||
|
||||
|
||||
@@ -28,12 +28,20 @@ public class ServerPlacement {
|
||||
|
||||
public ServerPlacement(final UUID id, final String fileName, final UUID hashValue, final PlayerIdentifier owner) {
|
||||
this.id = id;
|
||||
this.fileName = fileName;
|
||||
this.fileName = removeExtension(fileName);
|
||||
this.hashValue = hashValue;
|
||||
this.owner = owner;
|
||||
lastModifiedBy = owner;
|
||||
}
|
||||
|
||||
private static String removeExtension(final String fileName) {
|
||||
final int pos = fileName.lastIndexOf(".");
|
||||
if (pos < 0) {
|
||||
return fileName;
|
||||
}
|
||||
return fileName.substring(0, pos);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ServerPlacement fromJson(final @NotNull JsonObject obj) {
|
||||
if (obj.has("id")
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.leavesmc.leaves.protocol.syncmatica;
|
||||
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.bxteam.divinemc.config.DivineConfig;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -14,6 +15,7 @@ import java.util.Arrays;
|
||||
import java.util.UUID;
|
||||
|
||||
public class SyncmaticaProtocol {
|
||||
|
||||
public static final String PROTOCOL_ID = "syncmatica";
|
||||
public static final String PROTOCOL_VERSION = "leaves-syncmatica-1.1.0";
|
||||
private static final File litematicFolder = new File("." + File.separator + "syncmatics");
|
||||
@@ -80,11 +82,16 @@ public class SyncmaticaProtocol {
|
||||
|
||||
@NotNull
|
||||
public static String sanitizeFileName(final @NotNull String badFileName) {
|
||||
String input = badFileName;
|
||||
try {
|
||||
input = FilenameUtils.getName(input);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
final StringBuilder sanitized = new StringBuilder();
|
||||
final int len = badFileName.codePointCount(0, badFileName.length());
|
||||
final int len = input.codePointCount(0, input.length());
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
final int c = badFileName.codePointAt(i);
|
||||
final int c = input.codePointAt(i);
|
||||
if (Arrays.binarySearch(ILLEGAL_CHARS, c) < 0) {
|
||||
sanitized.appendCodePoint(c);
|
||||
if (sanitized.length() == 255) {
|
||||
|
||||
Reference in New Issue
Block a user