9
0
mirror of https://github.com/Winds-Studio/Leaf.git synced 2025-12-25 18:09:17 +00:00

Updated Upstream (Paper/Purpur/Leaves)

Upstream has released updates that appear to apply and compile correctly

Paper Changes:
PaperMC/Paper@a5f2f614 Fix offhand item desync on cancelling interact events (#12828)
PaperMC/Paper@10318775 [ci/skip] Update mache for codebook 1.0.15 (#12887)

Purpur Changes:
PurpurMC/Purpur@c4e5604c Updated Upstream (Paper)
PurpurMC/Purpur@c130b18e Updated Upstream (Paper)
PurpurMC/Purpur@60bdf1c7 Final Paper Upstream
PurpurMC/Purpur@a39c4cb0 Updated Upstream (Paper)
PurpurMC/Purpur@ea7b18ab Updated Upstream (Paper)
PurpurMC/Purpur@0f82c210 Updated Upstream (Paper)
PurpurMC/Purpur@8de15d66 this is important for the build to not fail..
PurpurMC/Purpur@5053eb0c use a different method for dropping lapis, closes #1692

Leaves Changes:
LeavesMC/Leaves@df8397c7 Fix bot invulnerable
LeavesMC/Leaves@e1c21d3f Movable Budding Amethyst bind carpet rule (#561)
LeavesMC/Leaves@550dba49 Configurable item damage check and good shear behavior (#559)
LeavesMC/Leaves@cb64df44 Old Throwable Projectile tick order (#520)
LeavesMC/Leaves@b5793e80 Fix bot infinity desync (#584)
LeavesMC/Leaves@c5ecbe85 1.21.7/8 (#587)
LeavesMC/Leaves@5497dfb4 Fix CI
LeavesMC/Leaves@2f8255bd Fix LitematicaEasyPlaceProtocol
LeavesMC/Leaves@a416f476 Fix bot use actions (#606) (#605)
LeavesMC/Leaves@bfde470a fix: revert Configurable-collision-behavior patch (#607)
LeavesMC/Leaves@aaa2323d Fix Syncmatica file name
This commit is contained in:
Dreeam
2025-07-24 20:18:23 +08:00
parent e3edba1bdc
commit 3b9d8feb03
62 changed files with 518 additions and 277 deletions

View File

@@ -1,4 +1,4 @@
package org.leavesmc.leaves.entity;
package org.leavesmc.leaves.entity.photographer;
import net.minecraft.server.level.ServerPlayer;
import org.bukkit.craftbukkit.CraftServer;

View File

@@ -1,4 +1,4 @@
package org.leavesmc.leaves.entity;
package org.leavesmc.leaves.entity.photographer;
import com.google.common.collect.Lists;
import org.bukkit.Location;

View File

@@ -8,6 +8,7 @@ import net.minecraft.world.level.GameRules;
import org.dreeam.leaf.config.modules.network.ProtocolSupport;
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,6 +17,7 @@ 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 {
@@ -32,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) {
@@ -46,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

@@ -1,16 +0,0 @@
package org.leavesmc.leaves.protocol.chatimage;
public class ChatImageIndex {
public int index;
public int total;
public String url;
public String bytes;
public ChatImageIndex(int index, int total, String url, String bytes) {
this.index = index;
this.total = total;
this.url = url;
this.bytes = bytes;
}
}

View File

@@ -0,0 +1,72 @@
package org.leavesmc.leaves.protocol.chatimage;
import com.google.gson.Gson;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerPlayer;
import org.dreeam.leaf.config.modules.network.ProtocolSupport;
import org.jetbrains.annotations.Contract;
import org.leavesmc.leaves.protocol.core.LeavesProtocol;
import org.leavesmc.leaves.protocol.core.ProtocolHandler;
import org.leavesmc.leaves.protocol.core.ProtocolUtils;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import static org.leavesmc.leaves.protocol.chatimage.ServerBlockCache.SERVER_BLOCK_CACHE;
@LeavesProtocol.Register(namespace = "chatimage")
public class ChatImageProtocol implements LeavesProtocol {
public static final String PROTOCOL_ID = "chatimage";
public static final Gson gson = new Gson();
@Contract("_ -> new")
public static ResourceLocation id(String path) {
return ResourceLocation.tryBuild(PROTOCOL_ID, path);
}
@ProtocolHandler.PayloadReceiver(payload = FileChannelPayload.class)
public void serverFileChannelReceived(ServerPlayer player, FileChannelPayload payload) {
MinecraftServer server = MinecraftServer.getServer();
String res = payload.message();
ChatImageIndex title = gson.fromJson(res, ChatImageIndex.class);
Map<Integer, String> blocks = SERVER_BLOCK_CACHE.createBlock(title, res);
if (title.total != blocks.size()) {
return;
}
List<UUID> names = SERVER_BLOCK_CACHE.getUsers(title.url);
if (names == null || player == null) {
return;
}
for (UUID uuid : names) {
ServerPlayer serverPlayer = server.getPlayerList().getPlayer(uuid);
if (serverPlayer != null) {
ProtocolUtils.sendPayloadPacket(serverPlayer, new FileInfoChannelPayload("true->" + title.url));
}
}
}
@ProtocolHandler.PayloadReceiver(payload = FileInfoChannelPayload.class)
public void serverGetFileChannelReceived(ServerPlayer player, FileInfoChannelPayload packet) {
String url = packet.message();
Map<Integer, String> list = SERVER_BLOCK_CACHE.getBlock(url);
if (list == null) {
ProtocolUtils.sendPayloadPacket(player, new FileInfoChannelPayload("null->" + url));
SERVER_BLOCK_CACHE.tryAddUser(url, player.getUUID());
return;
}
for (Map.Entry<Integer, String> entry : list.entrySet()) {
ProtocolUtils.sendPayloadPacket(player, new DownloadFileChannelPayload(entry.getValue()));
}
}
@Override
public boolean isActive() {
return ProtocolSupport.chatImageProtocol;
}
public record ChatImageIndex(int index, int total, String url, String bytes) {
}
}

View File

@@ -0,0 +1,18 @@
package org.leavesmc.leaves.protocol.chatimage;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.resources.ResourceLocation;
import org.leavesmc.leaves.protocol.core.LeavesCustomPayload;
public record DownloadFileChannelPayload(String message) implements LeavesCustomPayload {
@ID
private static final ResourceLocation ID = ChatImageProtocol.id("download_file_channel");
@Codec
private static final StreamCodec<RegistryFriendlyByteBuf, DownloadFileChannelPayload> CODEC = StreamCodec.composite(
ByteBufCodecs.STRING_UTF8, DownloadFileChannelPayload::message, DownloadFileChannelPayload::new
);
}

View File

@@ -0,0 +1,18 @@
package org.leavesmc.leaves.protocol.chatimage;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.resources.ResourceLocation;
import org.leavesmc.leaves.protocol.core.LeavesCustomPayload;
public record FileChannelPayload(String message) implements LeavesCustomPayload {
@ID
private static final ResourceLocation ID = ChatImageProtocol.id("get_file_channel");
@Codec
private static final StreamCodec<RegistryFriendlyByteBuf, FileChannelPayload> CODEC = StreamCodec.composite(
ByteBufCodecs.STRING_UTF8, FileChannelPayload::message, FileChannelPayload::new
);
}

View File

@@ -0,0 +1,18 @@
package org.leavesmc.leaves.protocol.chatimage;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.resources.ResourceLocation;
import org.leavesmc.leaves.protocol.core.LeavesCustomPayload;
public record FileInfoChannelPayload(String message) implements LeavesCustomPayload {
@ID
private static final ResourceLocation ID = ChatImageProtocol.id("file_info");
@Codec
private static final StreamCodec<RegistryFriendlyByteBuf, FileInfoChannelPayload> CODEC = StreamCodec.composite(
ByteBufCodecs.STRING_UTF8, FileInfoChannelPayload::message, FileInfoChannelPayload::new
);
}

View File

@@ -0,0 +1,65 @@
package org.leavesmc.leaves.protocol.chatimage;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Lists;
import org.leavesmc.leaves.LeavesLogger;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
public class ServerBlockCache {
public static final ServerBlockCache SERVER_BLOCK_CACHE = new ServerBlockCache();
public Cache<String, List<UUID>> userCache = CacheBuilder.newBuilder().expireAfterAccess(60, TimeUnit.SECONDS).build();
public Cache<String, Map<Integer, String>> blockCache = CacheBuilder.newBuilder().expireAfterAccess(60, TimeUnit.SECONDS).build();
public Cache<String, Integer> fileCount = CacheBuilder.newBuilder().expireAfterAccess(60, TimeUnit.SECONDS).build();
public Map<Integer, String> createBlock(ChatImageProtocol.ChatImageIndex title, String imgBytes) {
try {
Map<Integer, String> blocks = this.blockCache.get(title.url(), HashMap::new);
blocks.put(title.index(), imgBytes);
this.blockCache.put(title.url(), blocks);
this.fileCount.put(title.url(), title.total());
return blocks;
} catch (Exception e) {
LeavesLogger.LOGGER.warning("Failed to create block for title " + title.url() + ": " + e);
return null;
}
}
public Map<Integer, String> getBlock(String url) {
Map<Integer, String> list;
Integer total;
if ((list = this.blockCache.getIfPresent(url)) != null && (total = this.fileCount.getIfPresent(url)) != null) {
if (total == list.size()) {
return list;
}
}
return null;
}
public void tryAddUser(String url, UUID uuid) {
try {
List<UUID> names = this.userCache.get(url, Lists::newArrayList);
names.add(uuid);
this.userCache.put(url, names);
} catch (Exception e) {
LeavesLogger.LOGGER.warning("Failed to add user " + uuid + ": " + e);
}
}
public List<UUID> getUsers(String url) {
List<UUID> names;
if ((names = this.userCache.getIfPresent(url)) != null) {
this.userCache.put(url, Lists.newArrayList());
return names;
} else {
return null;
}
}
}

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

@@ -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;
@@ -238,27 +234,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;
}
}
@@ -298,31 +294,22 @@ 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);
}
}

View File

@@ -1,5 +1,7 @@
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;
@@ -16,6 +18,8 @@ public class ProtocolHandler {
@Retention(RetentionPolicy.RUNTIME)
public @interface PayloadReceiver {
Class<? extends LeavesCustomPayload> payload();
Stage stage() default Stage.GAME;
}
@Target(ElementType.METHOD)
@@ -24,6 +28,8 @@ public class ProtocolHandler {
String key() default "";
boolean onlyNamespace() default false;
Stage stage() default Stage.GAME;
}
@Target(ElementType.METHOD)
@@ -53,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,7 +11,10 @@ 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;
@@ -19,26 +22,50 @@ 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

@@ -14,6 +14,7 @@ public abstract class AbstractInvokerHolder<T> {
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;
@@ -21,6 +22,7 @@ public abstract class AbstractInvokerHolder<T> {
this.handler = handler;
this.returnType = returnType;
this.parameterTypes = parameterTypes;
this.isStatic = Modifier.isStatic(invoker.getModifiers());
validateMethodSignature();
}
@@ -58,7 +60,7 @@ 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);

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

@@ -92,7 +92,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.dreeam.leaf.config.modules.network.ProtocolSupport;
import org.jetbrains.annotations.NotNull;
@@ -81,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) {

View File

@@ -14,8 +14,8 @@ import org.bukkit.craftbukkit.CraftWorld;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.LeavesLogger;
import org.leavesmc.leaves.bot.BotStatsCounter;
import org.leavesmc.leaves.entity.CraftPhotographer;
import org.leavesmc.leaves.entity.Photographer;
import org.leavesmc.leaves.entity.photographer.CraftPhotographer;
import org.leavesmc.leaves.entity.photographer.Photographer;
import java.io.File;
import java.io.IOException;
@@ -77,7 +77,7 @@ public class ServerPhotographer extends ServerPlayer {
super.tick();
super.doTick();
if (this.server.getTickCount() % 10 == 0) {
if (this.getServer().getTickCount() % 10 == 0) {
connection.resetPosition();
this.level().chunkSource.move(this);
}
@@ -129,7 +129,7 @@ public class ServerPhotographer extends ServerPlayer {
super.remove(RemovalReason.KILLED);
photographers.remove(this);
this.recorder.stop();
this.server.getPlayerList().removePhotographer(this);
this.getServer().getPlayerList().removePhotographer(this);
LeavesLogger.LOGGER.info("Photographer " + createState.id + " removed");