9
0
mirror of https://github.com/BX-Team/DivineMC.git synced 2025-12-19 14:59:25 +00:00

upstream leaves protocols

This commit is contained in:
NONPLAYT
2025-08-10 00:10:45 +03:00
parent 40638b2063
commit 3a0f5fa625
29 changed files with 243 additions and 172 deletions

View File

@@ -34,25 +34,6 @@ index fb263fa1f30a7dfcb7ec2656abfb38e5fe88eac9..c3be4c2fd4a544967322a45d3b8c0fe7
}
};
}
diff --git a/net/minecraft/network/protocol/common/custom/DiscardedPayload.java b/net/minecraft/network/protocol/common/custom/DiscardedPayload.java
index 62b9d9486c15a1ec6527f786df4e9fc483390bcb..36d8b93182cc44e3bea245800ea9e2719333ac65 100644
--- a/net/minecraft/network/protocol/common/custom/DiscardedPayload.java
+++ b/net/minecraft/network/protocol/common/custom/DiscardedPayload.java
@@ -4,12 +4,12 @@ import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.resources.ResourceLocation;
-public record DiscardedPayload(ResourceLocation id, byte[] data) implements CustomPacketPayload { // Paper - store data
+public record DiscardedPayload(ResourceLocation id, byte @org.jetbrains.annotations.Nullable [] data) implements CustomPacketPayload { // Paper - store data // DivineMC - Leaves Protocol Core
public static <T extends FriendlyByteBuf> StreamCodec<T, DiscardedPayload> codec(ResourceLocation id, int maxSize) {
return CustomPacketPayload.codec((value, output) -> {
// Paper start
// Always write data
- output.writeBytes(value.data);
+ if (value.data != null) output.writeBytes(value.data); // DivineMC - Leaves Protocol Core
}, buffer -> {
int i = buffer.readableBytes();
if (i >= 0 && i <= maxSize) {
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 89c1fa23b7ce507f86c69c8dcc8f0de38bfa8e99..ce422e12d985a274816abf2841bb3a939568b13b 100644
--- a/net/minecraft/server/MinecraftServer.java
@@ -66,69 +47,67 @@ index 89c1fa23b7ce507f86c69c8dcc8f0de38bfa8e99..ce422e12d985a274816abf2841bb3a93
for (int i = 0; i < this.tickables.size(); i++) {
this.tickables.get(i).run();
}
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index 963aaef7493e1e281882a9eeca72b1a08fe9cbe8..7f6996e03d7c7d3ecd9a71f9b261a1c0b60ab59c 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -432,6 +432,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
private boolean ramBar = false; // Purpur - Implement rambar commands
public boolean smoothWorldTeleport; // DivineMC - Smooth teleport API
public boolean hasTickedAtLeastOnceInNewWorld = false; // DivineMC - Parallel world ticking
+ public net.minecraft.network.Connection internalConnection; // DivineMC - Leaves Protocol Core
// Paper start - rewrite chunk system
private ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader.PlayerChunkLoaderData chunkLoader;
diff --git a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
index a7c4fad2b1cb0cbac742a18d37d688bb2663944e..b94243d293e805743453adf7b4fc8d852184f460 100644
index 2853d8a34038dd521df2a9e5dfe33d50a72cff82..e6e320100fe1609c58215ea8c9e7914cf02ce9a3 100644
--- a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
@@ -230,6 +230,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
final String channel = new String(data, from, length, java.nio.charset.StandardCharsets.US_ASCII);
if (register) {
bridge.addChannel(channel);
+ org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handleMinecraftRegister(channel, bridge); // DivineMC - Leaves Protocol Core
} else {
bridge.removeChannel(channel);
}
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 4d37b16adc5491db24fce1ce656f6cde575e10f4..799bb99c4b9403f72eaf30119fd423dd3d80183a 100644
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -3680,6 +3680,17 @@ public class ServerGamePacketListenerImpl
@@ -61,6 +61,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
public @Nullable String playerBrand;
public final java.util.Set<String> pluginMessagerChannels;
// Paper end - retain certain values
+ public final GameProfile profile; // DivineMC - Leaves Protocol Core
public ServerCommonPacketListenerImpl(MinecraftServer server, Connection connection, CommonListenerCookie cookie) {
this.server = server;
@@ -74,6 +75,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
this.pluginMessagerChannels = cookie.channels();
this.keepAlive = cookie.keepAlive();
// Paper end
+ this.profile = cookie.gameProfile(); // DivineMC - Leaves Protocol Core
}
// Paper start - configuration phase API
@@ -165,6 +167,18 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
@Override
public void handleCustomPayload(ServerboundCustomPayloadPacket packet) {
+ // DivineMC start - Leaves Protocol Core
+ if (packet.payload() instanceof org.leavesmc.leaves.protocol.core.LeavesCustomPayload leavesPayload) {
+ org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handlePayload(player, leavesPayload);
+ org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handlePayload(org.leavesmc.leaves.protocol.core.ProtocolUtils.createSelector(this), leavesPayload);
+ return;
+ }
+ if (packet.payload() instanceof net.minecraft.network.protocol.common.custom.DiscardedPayload(net.minecraft.resources.ResourceLocation id, byte[] data)) {
+ if (org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handleBytebuf(player, id, io.netty.buffer.Unpooled.wrappedBuffer(data))) {
+ if (org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handleBytebuf(org.leavesmc.leaves.protocol.core.ProtocolUtils.createSelector(this), id, io.netty.buffer.Unpooled.wrappedBuffer(data))) {
+ return;
+ }
+ }
+ // DivineMC end - Leaves Protocol Core
super.handleCustomPayload(packet); // Paper
}
+
// Paper start
if (!(packet.payload() instanceof final net.minecraft.network.protocol.common.custom.DiscardedPayload discardedPayload)) {
return;
@@ -230,6 +244,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
final String channel = new String(data, from, length, java.nio.charset.StandardCharsets.US_ASCII);
if (register) {
bridge.addChannel(channel);
+ org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handleMinecraftRegister(channel, org.leavesmc.leaves.protocol.core.ProtocolUtils.createSelector(this)); // DivineMC - Leaves Protocol Core
} else {
bridge.removeChannel(channel);
}
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
index e4513af9b89222cec9f9573a053504ec87fc30b8..2b4a87643e4f2d2564597b923a025b432bcf5d23 100644
index e4513af9b89222cec9f9573a053504ec87fc30b8..0888ba7853f07909e9915d35f706d39a1c6cf307 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -343,6 +343,11 @@ public abstract class PlayerList {
@@ -343,6 +343,8 @@ public abstract class PlayerList {
return;
}
+ // DivineMC start - Leaves Protocol Core
+ if (player.internalConnection == null) player.internalConnection = connection;
+ org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handlePlayerJoin(player);
+ // DivineMC end - Leaves Protocol Core
+ org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handlePlayerJoin(player); // DivineMC - Leaves Protocol Core
+
final net.kyori.adventure.text.Component jm = playerJoinEvent.joinMessage();
if (jm != null && !jm.equals(net.kyori.adventure.text.Component.empty())) { // Paper - Adventure
@@ -516,6 +521,7 @@ public abstract class PlayerList {
@@ -516,6 +518,7 @@ public abstract class PlayerList {
return this.remove(player, net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? player.getBukkitEntity().displayName() : io.papermc.paper.adventure.PaperAdventure.asAdventure(player.getDisplayName())));
}
public @Nullable net.kyori.adventure.text.Component remove(ServerPlayer player, net.kyori.adventure.text.Component leaveMessage) {
@@ -136,7 +115,7 @@ index e4513af9b89222cec9f9573a053504ec87fc30b8..2b4a87643e4f2d2564597b923a025b43
// Paper end - Fix kick event leave message not being sent
org.purpurmc.purpur.task.BossBarTask.removeFromAll(player.getBukkitEntity()); // Purpur - Implement TPSBar
ServerLevel serverLevel = player.level();
@@ -1459,6 +1465,7 @@ public abstract class PlayerList {
@@ -1459,6 +1462,7 @@ public abstract class PlayerList {
serverPlayer.connection.send(clientboundUpdateRecipesPacket);
serverPlayer.getRecipeBook().sendInitialRecipeBook(serverPlayer);
}

View File

@@ -39,10 +39,10 @@ index 02c02314a4a6a7a6da427f0d064dbc61ce92301d..56efd53d22f6d7338ef7d7cc36d612d4
+ // DivineMC end - Do not send spectator change packet
}
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
index 2b4a87643e4f2d2564597b923a025b432bcf5d23..a0b7d7046b762e6a3142408051ee327cafe80f45 100644
index 0888ba7853f07909e9915d35f706d39a1c6cf307..48a02a25c4fa6f3bacefaccd122694156da1a331 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -359,6 +359,8 @@ public abstract class PlayerList {
@@ -356,6 +356,8 @@ public abstract class PlayerList {
// CraftBukkit start - sendAll above replaced with this loop
ClientboundPlayerInfoUpdatePacket packet = ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(player)); // Paper - Add Listing API for Player
@@ -51,7 +51,7 @@ index 2b4a87643e4f2d2564597b923a025b432bcf5d23..a0b7d7046b762e6a3142408051ee327c
final List<ServerPlayer> onlinePlayers = Lists.newArrayListWithExpectedSize(this.players.size() - 1); // Paper - Use single player info update packet on join
for (int i = 0; i < this.players.size(); ++i) {
ServerPlayer entityplayer1 = (ServerPlayer) this.players.get(i);
@@ -367,7 +369,7 @@ public abstract class PlayerList {
@@ -364,7 +366,7 @@ public abstract class PlayerList {
// Paper start - Add Listing API for Player
if (entityplayer1.getBukkitEntity().isListed(bukkitPlayer)) {
// Paper end - Add Listing API for Player
@@ -60,7 +60,7 @@ index 2b4a87643e4f2d2564597b923a025b432bcf5d23..a0b7d7046b762e6a3142408051ee327c
// Paper start - Add Listing API for Player
} else {
entityplayer1.connection.send(ClientboundPlayerInfoUpdatePacket.createSinglePlayerInitializing(player, false));
@@ -383,7 +385,10 @@ public abstract class PlayerList {
@@ -380,7 +382,10 @@ public abstract class PlayerList {
}
// Paper start - Use single player info update packet on join
if (!onlinePlayers.isEmpty()) {
@@ -72,7 +72,7 @@ index 2b4a87643e4f2d2564597b923a025b432bcf5d23..a0b7d7046b762e6a3142408051ee327c
}
// Paper end - Use single player info update packet on join
player.sentListPacket = true;
@@ -1471,4 +1476,69 @@ public abstract class PlayerList {
@@ -1468,4 +1473,69 @@ public abstract class PlayerList {
public boolean isAllowCommandsForAllPlayers() {
return this.allowCommandsForAllPlayers;
}

View File

@@ -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" -> {

View File

@@ -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";

View File

@@ -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) {
}

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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();
}
}
}

View File

@@ -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 {
}
}
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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();

View File

@@ -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();

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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");

View File

@@ -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;

View File

@@ -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());
}

View File

@@ -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;

View File

@@ -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));
}

View File

@@ -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")

View File

@@ -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) {