Compare commits

..

18 Commits

Author SHA1 Message Date
d764c3ff8c Merge pull request 'Merge Latest Changes' (#2) from update into main
Some checks failed
Build Paper / build (21) (push) Has been cancelled
Build Paper / Event File (push) Has been cancelled
Reviewed-on: https://steamwar.de/devlabs/SteamWar/Paper/pulls/2
2025-01-01 12:39:18 +01:00
53747c723b Merge remote-tracking branch 'upstream/main' into update 2024-12-31 17:12:20 +01:00
9298f593b7 Update paperweight to 2.0.0-beta.10 2024-12-30 12:35:18 -08:00
1e4669e8be [ci skip] Clarify loot table behavior when set to null. (#11861)
Updated documentation to specify that setting a null loot table resets it to its default behavior.
2024-12-30 11:07:40 +01:00
a81990e0e8 Update mache, fixes dev bundle use with Java 23 2024-12-30 11:04:58 +01:00
60edd611f2 [ci skip] Fix spelling of ignition's word into javadoc (#11864) 2024-12-29 22:30:51 +01:00
d00344af65 update jb annotations to 26.0.1 (#11860) 2024-12-29 06:53:38 -08:00
887f3f74d1 [ci skip] Replace FQN with import in EventExecutor 2024-12-29 00:34:45 +01:00
287eb52fa4 Use hidden classes for event executors (#11848)
Static final MethodHandles perform similar to direct calls. Additionally,
hidden classes simplify logic around ClassLoaders as they can be defined
weakly coupled to their defining class loader. All variants of methods
(static, private, non-void) can be covered by this mechanism.
2024-12-29 00:11:09 +01:00
93a3df085c Extend HumanEntity#dropItem API (#11810) 2024-12-28 23:47:21 +01:00
a6bd638bab Compile pls? 2024-12-26 18:50:36 +01:00
04924c1385 Revert "Fix Compile?"
This reverts commit 44cf7ff229.
2024-12-26 11:00:01 +01:00
44cf7ff229 Fix Compile? 2024-12-26 10:58:07 +01:00
c06d6c6ae2 Merge pull request 'Paper 1.21.4 & Hardfork' (#1) from init into main
Reviewed-on: https://steamwar.de/devlabs/SteamWar/Paper/pulls/1
2024-12-26 10:49:10 +01:00
eb48d457d9 Change maven name to prevent automatic compilation failures 2024-12-26 10:48:44 +01:00
1f3cbc08da SW Remove Debug Message 2024-12-25 12:37:36 +01:00
94b0d30c7f SW Disable Commands 2024-12-25 12:37:24 +01:00
2833e4c0a5 SW Remove Worldlock and Symlink Check 2024-12-25 12:37:14 +01:00
29 changed files with 593 additions and 359 deletions

View File

@ -1,4 +1,4 @@
tiny 2 0 spigot mojang+yarn
tiny 2 0 spigot mojang
# Originally DistanceManager, which also implements DistanceManager, so clashes since the implemented class
# is imported and not fully qualified. Easiest fix is to just change the name

View File

@ -10,7 +10,7 @@
# a significant amount of time for us to track down every possible issue, so this file will likely be around and in
# use - at least in some capacity - for a long time.
tiny 2 0 mojang+yarn spigot
tiny 2 0 mojang spigot
# CraftBukkit changes type
c net/minecraft/server/level/ServerLevel net/minecraft/server/level/WorldServer

View File

@ -12,7 +12,7 @@ import java.nio.file.Path
import kotlin.random.Random
plugins {
id("io.papermc.paperweight.core") version "2.0.0-beta.8" apply false
id("io.papermc.paperweight.core") version "2.0.0-beta.10" apply false
}
subprojects {

View File

@ -16,7 +16,7 @@ dependencies {
implementation("com.squareup:javapoet:1.13.0")
implementation(project(":paper-api"))
implementation("io.github.classgraph:classgraph:4.8.47")
implementation("org.jetbrains:annotations:24.1.0")
implementation("org.jetbrains:annotations:26.0.1")
testImplementation("org.junit.jupiter:junit-jupiter:5.10.2")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}

View File

@ -9,7 +9,7 @@ java {
withJavadocJar()
}
val annotationsVersion = "24.1.0"
val annotationsVersion = "26.0.1"
val bungeeCordChatVersion = "1.20-R0.2"
val adventureVersion = "4.18.0"
val slf4jVersion = "2.0.9"
@ -68,9 +68,6 @@ dependencies {
apiAndDocs("net.kyori:adventure-text-serializer-plain")
apiAndDocs("net.kyori:adventure-text-logger-slf4j")
implementation("org.ow2.asm:asm:9.7.1")
implementation("org.ow2.asm:asm-commons:9.7.1")
api("org.apache.maven:maven-resolver-provider:3.9.6") // make API dependency for Paper Plugins
compileOnly("org.apache.maven.resolver:maven-resolver-connector-basic:1.9.18")
compileOnly("org.apache.maven.resolver:maven-resolver-transport-http:1.9.18")

View File

@ -1,54 +0,0 @@
package com.destroystokyo.paper.event.executor;
import com.destroystokyo.paper.util.SneakyThrow;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;
import org.bukkit.event.Event;
import org.bukkit.event.EventException;
import org.bukkit.event.Listener;
import org.bukkit.plugin.EventExecutor;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
@ApiStatus.Internal
@NullMarked
public class MethodHandleEventExecutor implements EventExecutor {
private final Class<? extends Event> eventClass;
private final MethodHandle handle;
private final @Nullable Method method;
public MethodHandleEventExecutor(final Class<? extends Event> eventClass, final MethodHandle handle) {
this.eventClass = eventClass;
this.handle = handle;
this.method = null;
}
public MethodHandleEventExecutor(final Class<? extends Event> eventClass, final Method m) {
this.eventClass = eventClass;
try {
m.setAccessible(true);
this.handle = MethodHandles.lookup().unreflect(m);
} catch (final IllegalAccessException e) {
throw new AssertionError("Unable to set accessible", e);
}
this.method = m;
}
@Override
public void execute(final Listener listener, final Event event) throws EventException {
if (!this.eventClass.isInstance(event)) return;
try {
this.handle.invoke(listener, event);
} catch (final Throwable t) {
SneakyThrow.sneaky(t);
}
}
@Override
public String toString() {
return "MethodHandleEventExecutor['" + this.method + "']";
}
}

View File

@ -1,51 +0,0 @@
package com.destroystokyo.paper.event.executor;
import com.destroystokyo.paper.util.SneakyThrow;
import com.google.common.base.Preconditions;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import org.bukkit.event.Event;
import org.bukkit.event.EventException;
import org.bukkit.event.Listener;
import org.bukkit.plugin.EventExecutor;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
@ApiStatus.Internal
@NullMarked
public class StaticMethodHandleEventExecutor implements EventExecutor {
private final Class<? extends Event> eventClass;
private final MethodHandle handle;
private final Method method;
public StaticMethodHandleEventExecutor(final Class<? extends Event> eventClass, final Method m) {
Preconditions.checkArgument(Modifier.isStatic(m.getModifiers()), "Not a static method: %s", m);
Preconditions.checkArgument(eventClass != null, "eventClass is null");
this.eventClass = eventClass;
try {
m.setAccessible(true);
this.handle = MethodHandles.lookup().unreflect(m);
} catch (final IllegalAccessException e) {
throw new AssertionError("Unable to set accessible", e);
}
this.method = m;
}
@Override
public void execute(final Listener listener, final Event event) throws EventException {
if (!this.eventClass.isInstance(event)) return;
try {
this.handle.invoke(event);
} catch (final Throwable throwable) {
SneakyThrow.sneaky(throwable);
}
}
@Override
public String toString() {
return "StaticMethodHandleEventExecutor['" + this.method + "']";
}
}

View File

@ -1,59 +0,0 @@
package com.destroystokyo.paper.event.executor.asm;
import java.lang.reflect.Method;
import java.util.concurrent.atomic.AtomicInteger;
import org.bukkit.plugin.EventExecutor;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.GeneratorAdapter;
import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
import static org.objectweb.asm.Opcodes.INVOKEINTERFACE;
import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
import static org.objectweb.asm.Opcodes.V1_8;
@ApiStatus.Internal
@NullMarked
public final class ASMEventExecutorGenerator {
private static final String EXECUTE_DESCRIPTOR = "(Lorg/bukkit/event/Listener;Lorg/bukkit/event/Event;)V";
public static byte[] generateEventExecutor(final Method m, final String name) {
final ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
writer.visit(V1_8, ACC_PUBLIC, name.replace('.', '/'), null, Type.getInternalName(Object.class), new String[]{Type.getInternalName(EventExecutor.class)});
// Generate constructor
GeneratorAdapter methodGenerator = new GeneratorAdapter(writer.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null), ACC_PUBLIC, "<init>", "()V");
methodGenerator.loadThis();
methodGenerator.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(Object.class), "<init>", "()V", false); // Invoke the super class (Object) constructor
methodGenerator.returnValue();
methodGenerator.endMethod();
// Generate the execute method
methodGenerator = new GeneratorAdapter(writer.visitMethod(ACC_PUBLIC, "execute", EXECUTE_DESCRIPTOR, null, null), ACC_PUBLIC, "execute", EXECUTE_DESCRIPTOR);
methodGenerator.loadArg(0);
methodGenerator.checkCast(Type.getType(m.getDeclaringClass()));
methodGenerator.loadArg(1);
methodGenerator.checkCast(Type.getType(m.getParameterTypes()[0]));
methodGenerator.visitMethodInsn(m.getDeclaringClass().isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL, Type.getInternalName(m.getDeclaringClass()), m.getName(), Type.getMethodDescriptor(m), m.getDeclaringClass().isInterface());
// The only purpose of this switch statement is to generate the correct pop instruction, should the event handler method return something other than void.
// Non-void event handlers will be unsupported in a future release.
switch (Type.getType(m.getReturnType()).getSize()) {
// case 0 is omitted because the only type that has size 0 is void - no pop instruction needed.
case 1 -> methodGenerator.pop(); // handles reference types and most primitives
case 2 -> methodGenerator.pop2(); // handles long and double
}
methodGenerator.returnValue();
methodGenerator.endMethod();
writer.visitEnd();
return writer.toByteArray();
}
public static AtomicInteger NEXT_ID = new AtomicInteger(1);
public static String generateName() {
final int id = NEXT_ID.getAndIncrement();
return "com.destroystokyo.paper.event.executor.asm.generated.GeneratedEventExecutor" + id;
}
}

View File

@ -1,35 +0,0 @@
package com.destroystokyo.paper.event.executor.asm;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
@ApiStatus.Internal
@NullMarked
public interface ClassDefiner {
/**
* Returns if the defined classes can bypass access checks
*
* @return if classes bypass access checks
*/
default boolean isBypassAccessChecks() {
return false;
}
/**
* Define a class
*
* @param parentLoader the parent classloader
* @param name the name of the class
* @param data the class data to load
* @return the defined class
* @throws ClassFormatError if the class data is invalid
* @throws NullPointerException if any of the arguments are null
*/
Class<?> defineClass(ClassLoader parentLoader, String name, byte[] data);
static ClassDefiner getInstance() {
return SafeClassDefiner.INSTANCE;
}
}

View File

@ -1,66 +0,0 @@
package com.destroystokyo.paper.event.executor.asm;
import com.google.common.base.Preconditions;
import com.google.common.collect.MapMaker;
import java.util.concurrent.ConcurrentMap;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
@ApiStatus.Internal
@NullMarked
public class SafeClassDefiner implements ClassDefiner {
/* default */ static final SafeClassDefiner INSTANCE = new SafeClassDefiner();
private SafeClassDefiner() {
}
private final ConcurrentMap<ClassLoader, GeneratedClassLoader> loaders = new MapMaker().weakKeys().makeMap();
@Override
public Class<?> defineClass(final ClassLoader parentLoader, final String name, final byte[] data) {
final GeneratedClassLoader loader = this.loaders.computeIfAbsent(parentLoader, GeneratedClassLoader::new);
synchronized (loader.getClassLoadingLock(name)) {
Preconditions.checkState(!loader.hasClass(name), "%s already defined", name);
final Class<?> c = loader.define(name, data);
assert c.getName().equals(name);
return c;
}
}
private static class GeneratedClassLoader extends ClassLoader {
static {
ClassLoader.registerAsParallelCapable();
}
protected GeneratedClassLoader(final ClassLoader parent) {
super(parent);
}
private Class<?> define(final String name, final byte[] data) {
synchronized (this.getClassLoadingLock(name)) {
assert !this.hasClass(name);
final Class<?> c = this.defineClass(name, data, 0, data.length);
this.resolveClass(c);
return c;
}
}
@Override
public Object getClassLoadingLock(final String name) {
return super.getClassLoadingLock(name);
}
public boolean hasClass(final String name) {
synchronized (this.getClassLoadingLock(name)) {
try {
Class.forName(name);
return true;
} catch (final ClassNotFoundException e) {
return false;
}
}
}
}
}

View File

@ -0,0 +1,74 @@
package io.papermc.paper.event.executor;
import org.bukkit.event.Event;
import org.bukkit.event.Listener;
import org.bukkit.plugin.EventExecutor;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
import java.io.IOException;
import java.io.InputStream;
import java.lang.constant.ConstantDescs;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.List;
import java.util.Objects;
@ApiStatus.Internal
@NullMarked
public final class EventExecutorFactory {
private static final byte[] TEMPLATE_CLASS_BYTES;
static {
try (final InputStream is = EventExecutorFactory.class.getResourceAsStream("MethodHandleEventExecutorTemplate.class")) {
TEMPLATE_CLASS_BYTES = Objects.requireNonNull(is, "template class is missing").readAllBytes();
} catch (IOException e) {
throw new AssertionError(e);
}
}
private EventExecutorFactory() {
}
/**
* {@return an {@link EventExecutor} implemented by a hidden class calling a method handle}
*
* @param method the method to be invoked by the created event executor
* @param eventClass the class of the event to handle
*/
public static EventExecutor create(final Method method, final Class<? extends Event> eventClass) {
final List<?> classData = List.of(method, eventClass);
try {
final MethodHandles.Lookup newClass = MethodHandles.lookup().defineHiddenClassWithClassData(TEMPLATE_CLASS_BYTES, classData, true);
return newClass.lookupClass().asSubclass(EventExecutor.class).getDeclaredConstructor().newInstance();
} catch (ReflectiveOperationException e) {
throw new AssertionError(e);
}
}
record ClassData(Method method, MethodHandle methodHandle, Class<? extends Event> eventClass) {
}
/**
* Extracts the class data and creates an adjusted MethodHandle directly usable by the lookup class.
* The logic is kept here to minimize memory usage per created class.
*/
static ClassData classData(final MethodHandles.Lookup lookup) {
try {
final Method method = MethodHandles.classDataAt(lookup, ConstantDescs.DEFAULT_NAME, Method.class, 0);
MethodHandle mh = lookup.unreflect(method);
if (Modifier.isStatic(method.getModifiers())) {
mh = MethodHandles.dropArguments(mh, 0, Listener.class);
}
mh = mh.asType(MethodType.methodType(void.class, Listener.class, Event.class));
final Class<?> eventClass = MethodHandles.classDataAt(lookup, ConstantDescs.DEFAULT_NAME, Class.class, 1);
return new ClassData(method, mh, eventClass.asSubclass(Event.class));
} catch (ReflectiveOperationException e) {
throw new AssertionError(e);
}
}
}

View File

@ -0,0 +1,56 @@
package io.papermc.paper.event.executor;
import com.destroystokyo.paper.util.SneakyThrow;
import org.bukkit.event.Event;
import org.bukkit.event.EventException;
import org.bukkit.event.Listener;
import org.bukkit.plugin.EventExecutor;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;
/**
* This class is designed to be used as hidden class template.
* Initializing the class directly will fail due to missing {@code classData}.
* Instead, {@link java.lang.invoke.MethodHandles.Lookup#defineHiddenClassWithClassData(byte[], Object, boolean, MethodHandles.Lookup.ClassOption...)}
* must be used, with the {@code classData} object being a list consisting of two elements:
* <ol>
* <li>A {@link Method} representing the event handler method</li>
* <li>A {@link Class} representing the event type</li>
* </ol>
* The method must take {@link Event} or a subtype of it as its single parameter.
* If the method is non-static, it also needs to reside in a class implementing {@link Listener}.
*/
@SuppressWarnings("unused")
@ApiStatus.Internal
@NullMarked
class MethodHandleEventExecutorTemplate implements EventExecutor {
private static final Method METHOD;
private static final MethodHandle HANDLE;
private static final Class<? extends Event> EVENT_CLASS;
static {
final MethodHandles.Lookup lookup = MethodHandles.lookup();
final EventExecutorFactory.ClassData classData = EventExecutorFactory.classData(lookup);
METHOD = classData.method();
HANDLE = classData.methodHandle();
EVENT_CLASS = classData.eventClass();
}
@Override
public void execute(final Listener listener, final Event event) throws EventException {
if (!EVENT_CLASS.isInstance(event)) return;
try {
HANDLE.invokeExact(listener, event);
} catch (Throwable t) {
SneakyThrow.sneaky(t);
}
}
@Override
public String toString() {
return "MethodHandleEventExecutorTemplate['" + METHOD + "']";
}
}

View File

@ -89,7 +89,7 @@ public interface Attribute extends OldEnum<Attribute>, Keyed, Translatable, net.
*/
Attribute JUMP_STRENGTH = getAttribute("jump_strength");
/**
* How long an entity remains burning after ingition.
* How long an entity remains burning after ignition.
*/
Attribute BURNING_TIME = getAttribute("burning_time");
/**

View File

@ -2,10 +2,12 @@ package org.bukkit.entity;
import java.util.Collection;
import java.util.Set;
import java.util.function.Consumer;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.InventoryView;
@ -14,6 +16,7 @@ import org.bukkit.inventory.MainHand;
import org.bukkit.inventory.Merchant;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.inventory.meta.FireworkMeta;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -703,8 +706,115 @@ public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder
*
* @param dropAll True to drop entire stack, false to drop 1 of the stack
* @return True if item was dropped successfully
* @apiNote You should instead use {@link #dropItem(EquipmentSlot, int)} or {@link #dropItem(EquipmentSlot)} with a {@link EquipmentSlot#HAND} parameter.
*/
public boolean dropItem(boolean dropAll);
@ApiStatus.Obsolete(since = "1.21.4")
boolean dropItem(boolean dropAll);
/**
* Makes the player drop all items from their inventory based on the inventory slot.
*
* @param slot the equipment slot to drop
* @return the dropped item entity, or null if the action was unsuccessful
*/
@Nullable
default Item dropItem(final int slot) {
return this.dropItem(slot, Integer.MAX_VALUE);
}
/**
* Makes the player drop an item from their inventory based on the inventory slot.
*
* @param slot the slot to drop
* @param amount the number of items to drop from this slot. Values below one always return null
* @return the dropped item entity, or null if the action was unsuccessful
* @throws IllegalArgumentException if the slot is negative or bigger than the player's inventory
*/
@Nullable
default Item dropItem(final int slot, final int amount) {
return this.dropItem(slot, amount, false, null);
}
/**
* Makes the player drop an item from their inventory based on the inventory slot.
*
* @param slot the slot to drop
* @param amount the number of items to drop from this slot. Values below one always return null
* @param throwRandomly controls the randomness of the dropped items velocity, where {@code true} mimics dropped
* items during a player's death, while {@code false} acts like a normal item drop.
* @param entityOperation the function to be run before adding the entity into the world
* @return the dropped item entity, or null if the action was unsuccessful
* @throws IllegalArgumentException if the slot is negative or bigger than the player's inventory
*/
@Nullable
Item dropItem(int slot, int amount, boolean throwRandomly, @Nullable Consumer<Item> entityOperation);
/**
* Makes the player drop all items from their inventory based on the equipment slot.
*
* @param slot the equipment slot to drop
* @return the dropped item entity, or null if the action was unsuccessful
*/
@Nullable
default Item dropItem(final @NotNull EquipmentSlot slot) {
return this.dropItem(slot, Integer.MAX_VALUE);
}
/**
* Makes the player drop an item from their inventory based on the equipment slot.
*
* @param slot the equipment slot to drop
* @param amount the amount of items to drop from this equipment slot. Values below one always return null
* @return the dropped item entity, or null if the action was unsuccessful
*/
@Nullable
default Item dropItem(final @NotNull EquipmentSlot slot, final int amount) {
return this.dropItem(slot, amount, false, null);
}
/**
* Makes the player drop an item from their inventory based on the equipment slot.
*
* @param slot the equipment slot to drop
* @param amount The amount of items to drop from this equipment slot. Values below one always return null
* @param throwRandomly controls the randomness of the dropped items velocity, where {@code true} mimics dropped
* items during a player's death, while {@code false} acts like a normal item drop.
* @param entityOperation the function to be run before adding the entity into the world
* @return the dropped item entity, or null if the action was unsuccessful
*/
@Nullable
Item dropItem(@NotNull EquipmentSlot slot, int amount, boolean throwRandomly, @Nullable Consumer<Item> entityOperation);
/**
* Makes the player drop any arbitrary {@link ItemStack}, independently of whether the player actually
* has that item in their inventory.
* <p>
* This method modifies neither the item nor the player's inventory.
* Item removal has to be handled by the method caller.
*
* @param itemStack the itemstack to drop
* @return the dropped item entity, or null if the action was unsuccessful
*/
@Nullable
default Item dropItem(final @NotNull ItemStack itemStack) {
return this.dropItem(itemStack, false, null);
}
/**
* Makes the player drop any arbitrary {@link ItemStack}, independently of whether the player actually
* has that item in their inventory.
* <p>
* This method modifies neither the item nor the player's inventory.
* Item removal has to be handled by the method caller.
*
* @param itemStack the itemstack to drop
* @param throwRandomly controls the randomness of the dropped items velocity, where {@code true} mimics dropped
* items during a player's death, while {@code false} acts like a normal item drop.
* @param entityOperation the function to be run before adding the entity into the world
* @return the dropped item entity, or null if the action was unsuccessful
*/
@Nullable
Item dropItem(final @NotNull ItemStack itemStack, boolean throwRandomly, @Nullable Consumer<Item> entityOperation);
/**
* Gets the players current exhaustion level.

View File

@ -16,7 +16,7 @@ public interface Lootable {
/**
* Set the loot table for a container or entity.
* <br>
* To remove a loot table use null.
* If the provided loot table is null, the loot table will be reset to its default behavior.
*
* @param table the Loot Table this {@link org.bukkit.block.Container} or
* {@link org.bukkit.entity.Mob} will have.
@ -38,6 +38,8 @@ public interface Lootable {
// Paper start
/**
* Set the loot table and seed for a container or entity at the same time.
* <br>
* If the provided loot table is null, the loot table will be reset to its default behavior.
*
* @param table the Loot Table this {@link org.bukkit.block.Container} or {@link org.bukkit.entity.Mob} will have.
* @param seed the seed to used to generate loot. Default is 0.
@ -53,7 +55,8 @@ public interface Lootable {
}
/**
* Clears the associated Loot Table to this object
* Clears the associated Loot Table to this object, essentially resetting it to default
* @see #setLootTable(LootTable)
*/
default void clearLootTable() {
this.setLootTable(null);

View File

@ -1,24 +1,15 @@
package org.bukkit.plugin;
import com.google.common.base.Preconditions;
import io.papermc.paper.event.executor.EventExecutorFactory;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import org.bukkit.event.Event;
import org.bukkit.event.EventException;
import org.bukkit.event.Listener;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
// Paper start
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Function;
import com.destroystokyo.paper.event.executor.MethodHandleEventExecutor;
import com.destroystokyo.paper.event.executor.StaticMethodHandleEventExecutor;
import com.destroystokyo.paper.event.executor.asm.ASMEventExecutorGenerator;
import com.destroystokyo.paper.event.executor.asm.ClassDefiner;
import com.google.common.base.Preconditions;
// Paper end
/**
* Interface which defines the class for event call backs to plugins
*/
@ -26,69 +17,25 @@ public interface EventExecutor {
public void execute(@NotNull Listener listener, @NotNull Event event) throws EventException;
// Paper start
ConcurrentMap<Method, Class<? extends EventExecutor>> eventExecutorMap = new ConcurrentHashMap<Method, Class<? extends EventExecutor>>() {
@NotNull
@Override
public Class<? extends EventExecutor> computeIfAbsent(@NotNull Method key, @NotNull Function<? super Method, ? extends Class<? extends EventExecutor>> mappingFunction) {
Class<? extends EventExecutor> executorClass = get(key);
if (executorClass != null)
return executorClass;
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (key) {
executorClass = get(key);
if (executorClass != null)
return executorClass;
return super.computeIfAbsent(key, mappingFunction);
}
}
};
@NotNull
public static EventExecutor create(@NotNull Method m, @NotNull Class<? extends Event> eventClass) {
static EventExecutor create(@NotNull Method m, @NotNull Class<? extends Event> eventClass) {
Preconditions.checkNotNull(m, "Null method");
Preconditions.checkArgument(m.getParameterCount() != 0, "Incorrect number of arguments %s", m.getParameterCount());
Preconditions.checkArgument(m.getParameterTypes()[0] == eventClass, "First parameter %s doesn't match event class %s", m.getParameterTypes()[0], eventClass);
ClassDefiner definer = ClassDefiner.getInstance();
if (m.getReturnType() != Void.TYPE) {
final org.bukkit.plugin.java.JavaPlugin plugin = org.bukkit.plugin.java.JavaPlugin.getProvidingPlugin(m.getDeclaringClass());
final JavaPlugin plugin = JavaPlugin.getProvidingPlugin(m.getDeclaringClass());
org.bukkit.Bukkit.getLogger().warning("@EventHandler method " + m.getDeclaringClass().getName() + (Modifier.isStatic(m.getModifiers()) ? '.' : '#') + m.getName()
+ " returns non-void type " + m.getReturnType().getName() + ". This is unsupported behavior and will no longer work in a future version of Paper."
+ " This should be reported to the developers of " + plugin.getPluginMeta().getDisplayName() + " (" + String.join(",", plugin.getPluginMeta().getAuthors()) + ')');
}
if (Modifier.isStatic(m.getModifiers())) {
return new StaticMethodHandleEventExecutor(eventClass, m);
} else if (definer.isBypassAccessChecks() || Modifier.isPublic(m.getDeclaringClass().getModifiers()) && Modifier.isPublic(m.getModifiers())) {
// get the existing generated EventExecutor class for the Method or generate one
Class<? extends EventExecutor> executorClass = eventExecutorMap.computeIfAbsent(m, (__) -> {
String name = ASMEventExecutorGenerator.generateName();
byte[] classData = ASMEventExecutorGenerator.generateEventExecutor(m, name);
return definer.defineClass(m.getDeclaringClass().getClassLoader(), name, classData).asSubclass(EventExecutor.class);
});
try {
EventExecutor asmExecutor = executorClass.newInstance();
// Define a wrapper to conform to bukkit stupidity (passing in events that don't match and wrapper exception)
return new EventExecutor() {
@Override
public void execute(@NotNull Listener listener, @NotNull Event event) throws EventException {
if (!eventClass.isInstance(event)) return;
asmExecutor.execute(listener, event);
}
@Override
@NotNull
public String toString() {
return "ASMEventExecutor['" + m + "']";
}
};
} catch (InstantiationException | IllegalAccessException e) {
throw new AssertionError("Unable to initialize generated event executor", e);
}
} else {
return new MethodHandleEventExecutor(eventClass, m);
if (!m.trySetAccessible()) {
final JavaPlugin plugin = JavaPlugin.getProvidingPlugin(m.getDeclaringClass());
throw new AssertionError(
"@EventHandler method " + m.getDeclaringClass().getName() + (Modifier.isStatic(m.getModifiers()) ? '.' : '#') + m.getName() + " is not accessible."
+ " This should be reported to the developers of " + plugin.getDescription().getName() + " (" + String.join(",", plugin.getDescription().getAuthors()) + ')'
);
}
return EventExecutorFactory.create(m, eventClass);
}
// Paper end
}

View File

@ -11,7 +11,7 @@ plugins {
val paperMavenPublicUrl = "https://repo.papermc.io/repository/maven-public/"
dependencies {
mache("io.papermc:mache:1.21.4+build.6")
mache("io.papermc:mache:1.21.4+build.7")
paperclip("io.papermc:paperclip:3.0.3")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}

View File

@ -0,0 +1,72 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Chaoscaot <chaos@chaoscaot.de>
Date: Wed, 25 Dec 2024 12:18:00 +0100
Subject: [PATCH] SW Remove Worldlock and Symlink Check
diff --git a/net/minecraft/world/level/storage/LevelStorageSource.java b/net/minecraft/world/level/storage/LevelStorageSource.java
index de43e54698125ce9f319d4889dd49f7029fe95e0..e21d744040bcf58b391f002f2dd1129e532ff1b6 100644
--- a/net/minecraft/world/level/storage/LevelStorageSource.java
+++ b/net/minecraft/world/level/storage/LevelStorageSource.java
@@ -343,7 +343,7 @@ public class LevelStorageSource {
public LevelStorageSource.LevelStorageAccess validateAndCreateAccess(String saveName, ResourceKey<LevelStem> dimensionType) throws IOException, ContentValidationException { // CraftBukkit
Path levelPath = this.getLevelPath(saveName);
- List<ForbiddenSymlinkInfo> list = Boolean.getBoolean("paper.disableWorldSymlinkValidation") ? List.of() : this.worldDirValidator.validateDirectory(levelPath, true); // Paper - add skipping of symlinks scan
+ List<ForbiddenSymlinkInfo> list = List.of(); // Paper - add skipping of symlinks scan
if (!list.isEmpty()) {
throw new ContentValidationException(levelPath, list);
} else {
@@ -420,7 +420,6 @@ public class LevelStorageSource {
}
public class LevelStorageAccess implements AutoCloseable {
- final DirectoryLock lock;
public final LevelStorageSource.LevelDirectory levelDirectory;
private final String levelId;
private final Map<LevelResource, Path> resources = Maps.newHashMap();
@@ -432,7 +431,6 @@ public class LevelStorageSource {
// CraftBukkit end
this.levelId = levelId;
this.levelDirectory = new LevelStorageSource.LevelDirectory(levelDir);
- this.lock = DirectoryLock.create(levelDir);
}
public long estimateDiskSpace() {
@@ -476,9 +474,7 @@ public class LevelStorageSource {
}
private void checkLock() {
- if (!this.lock.isValid()) {
- throw new IllegalStateException("Lock is no longer valid");
- }
+ //nope
}
public PlayerDataStorage createPlayerStorage() {
@@ -532,7 +528,7 @@ public class LevelStorageSource {
}
public Optional<Path> getIconFile() {
- return !this.lock.isValid() ? Optional.empty() : Optional.of(this.levelDirectory.iconFile());
+ return Optional.of(this.levelDirectory.iconFile());
}
public void deleteLevel() throws IOException {
@@ -561,7 +557,6 @@ public class LevelStorageSource {
throw exception;
} else {
if (dir.equals(LevelStorageAccess.this.levelDirectory.path())) {
- LevelStorageAccess.this.lock.close();
Files.deleteIfExists(path);
}
@@ -645,7 +640,7 @@ public class LevelStorageSource {
@Override
public void close() throws IOException {
- this.lock.close();
+ //ignored
}
public boolean restoreLevelDataFromOld() {

View File

@ -0,0 +1,152 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Chaoscaot <chaos@chaoscaot.de>
Date: Wed, 25 Dec 2024 12:31:02 +0100
Subject: [PATCH] SW Disable Commands
diff --git a/net/minecraft/commands/Commands.java b/net/minecraft/commands/Commands.java
index 19ccf3abf14c67f72a1ca065e4a304f50e645ef4..86d2a9b1cbe6e03066ea4a2034e2dd611bff67cb 100644
--- a/net/minecraft/commands/Commands.java
+++ b/net/minecraft/commands/Commands.java
@@ -150,66 +150,66 @@ public class Commands {
private final CommandDispatcher<CommandSourceStack> dispatcher = new CommandDispatcher<>();
public Commands(Commands.CommandSelection selection, CommandBuildContext context) {
- AdvancementCommands.register(this.dispatcher);
- AttributeCommand.register(this.dispatcher, context);
- ExecuteCommand.register(this.dispatcher, context);
- BossBarCommands.register(this.dispatcher, context);
+ //AdvancementCommands.register(this.dispatcher);
+ //AttributeCommand.register(this.dispatcher, context);
+ //ExecuteCommand.register(this.dispatcher, context);
+ //BossBarCommands.register(this.dispatcher, context);
ClearInventoryCommands.register(this.dispatcher, context);
- CloneCommands.register(this.dispatcher, context);
- DamageCommand.register(this.dispatcher, context);
- DataCommands.register(this.dispatcher);
- DataPackCommand.register(this.dispatcher);
- DebugCommand.register(this.dispatcher);
- DefaultGameModeCommands.register(this.dispatcher);
- DifficultyCommand.register(this.dispatcher);
+ //CloneCommands.register(this.dispatcher, context);
+ //DamageCommand.register(this.dispatcher, context);
+ //DataCommands.register(this.dispatcher);
+ //DataPackCommand.register(this.dispatcher);
+ //DebugCommand.register(this.dispatcher);
+ //DefaultGameModeCommands.register(this.dispatcher);
+ //DifficultyCommand.register(this.dispatcher);
EffectCommands.register(this.dispatcher, context);
- EmoteCommands.register(this.dispatcher);
+ //EmoteCommands.register(this.dispatcher);
EnchantCommand.register(this.dispatcher, context);
- ExperienceCommand.register(this.dispatcher);
- FillCommand.register(this.dispatcher, context);
+ //ExperienceCommand.register(this.dispatcher);
+ //FillCommand.register(this.dispatcher, context);
FillBiomeCommand.register(this.dispatcher, context);
- ForceLoadCommand.register(this.dispatcher);
- FunctionCommand.register(this.dispatcher);
+ //ForceLoadCommand.register(this.dispatcher);
+ //FunctionCommand.register(this.dispatcher);
GameModeCommand.register(this.dispatcher);
GameRuleCommand.register(this.dispatcher, context);
GiveCommand.register(this.dispatcher, context);
- HelpCommand.register(this.dispatcher);
- ItemCommands.register(this.dispatcher, context);
+ //HelpCommand.register(this.dispatcher);
+ //ItemCommands.register(this.dispatcher, context);
KickCommand.register(this.dispatcher);
KillCommand.register(this.dispatcher);
- ListPlayersCommand.register(this.dispatcher);
- LocateCommand.register(this.dispatcher, context);
- LootCommand.register(this.dispatcher, context);
- MsgCommand.register(this.dispatcher);
- ParticleCommand.register(this.dispatcher, context);
- PlaceCommand.register(this.dispatcher);
- PlaySoundCommand.register(this.dispatcher);
- RandomCommand.register(this.dispatcher);
- ReloadCommand.register(this.dispatcher);
- RecipeCommand.register(this.dispatcher);
- ReturnCommand.register(this.dispatcher);
- RideCommand.register(this.dispatcher);
+ //ListPlayersCommand.register(this.dispatcher);
+ //LocateCommand.register(this.dispatcher, context);
+ //LootCommand.register(this.dispatcher, context);
+ //MsgCommand.register(this.dispatcher);
+ //ParticleCommand.register(this.dispatcher, context);
+ //PlaceCommand.register(this.dispatcher);
+ //PlaySoundCommand.register(this.dispatcher);
+ //RandomCommand.register(this.dispatcher);
+ //ReloadCommand.register(this.dispatcher);
+ //RecipeCommand.register(this.dispatcher);
+ //ReturnCommand.register(this.dispatcher);
+ //RideCommand.register(this.dispatcher);
RotateCommand.register(this.dispatcher);
- SayCommand.register(this.dispatcher);
- ScheduleCommand.register(this.dispatcher);
- ScoreboardCommand.register(this.dispatcher, context);
- SeedCommand.register(this.dispatcher, selection != Commands.CommandSelection.INTEGRATED);
- SetBlockCommand.register(this.dispatcher, context);
- SetSpawnCommand.register(this.dispatcher);
+ //SayCommand.register(this.dispatcher);
+ //ScheduleCommand.register(this.dispatcher);
+ //ScoreboardCommand.register(this.dispatcher, context);
+ //SeedCommand.register(this.dispatcher, selection != Commands.CommandSelection.INTEGRATED);
+ //SetBlockCommand.register(this.dispatcher, context);
+ //SetSpawnCommand.register(this.dispatcher);
SetWorldSpawnCommand.register(this.dispatcher);
SpectateCommand.register(this.dispatcher);
- SpreadPlayersCommand.register(this.dispatcher);
- StopSoundCommand.register(this.dispatcher);
+ //SpreadPlayersCommand.register(this.dispatcher);
+ //StopSoundCommand.register(this.dispatcher);
SummonCommand.register(this.dispatcher, context);
- TagCommand.register(this.dispatcher);
- TeamCommand.register(this.dispatcher, context);
- TeamMsgCommand.register(this.dispatcher);
+ //TagCommand.register(this.dispatcher);
+ //TeamCommand.register(this.dispatcher, context);
+ //TeamMsgCommand.register(this.dispatcher);
TeleportCommand.register(this.dispatcher);
- TellRawCommand.register(this.dispatcher, context);
+ //TellRawCommand.register(this.dispatcher, context);
TickCommand.register(this.dispatcher);
TimeCommand.register(this.dispatcher);
- TitleCommand.register(this.dispatcher, context);
- TriggerCommand.register(this.dispatcher);
+ //TitleCommand.register(this.dispatcher, context);
+ //TriggerCommand.register(this.dispatcher);
WeatherCommand.register(this.dispatcher);
WorldBorderCommand.register(this.dispatcher);
if (JvmProfiler.INSTANCE.isAvailable()) {
@@ -230,20 +230,20 @@ public class Commands {
}
if (selection.includeDedicated) {
- BanIpCommands.register(this.dispatcher);
- BanListCommands.register(this.dispatcher);
- BanPlayerCommands.register(this.dispatcher);
- DeOpCommands.register(this.dispatcher);
- OpCommand.register(this.dispatcher);
- PardonCommand.register(this.dispatcher);
- PardonIpCommand.register(this.dispatcher);
- PerfCommand.register(this.dispatcher);
+ //BanIpCommands.register(this.dispatcher);
+ //BanListCommands.register(this.dispatcher);
+ //BanPlayerCommands.register(this.dispatcher);
+ //DeOpCommands.register(this.dispatcher);
+ //OpCommand.register(this.dispatcher);
+ //PardonCommand.register(this.dispatcher);
+ //PardonIpCommand.register(this.dispatcher);
+ //PerfCommand.register(this.dispatcher);
SaveAllCommand.register(this.dispatcher);
SaveOffCommand.register(this.dispatcher);
SaveOnCommand.register(this.dispatcher);
- SetPlayerIdleTimeoutCommand.register(this.dispatcher);
+ //SetPlayerIdleTimeoutCommand.register(this.dispatcher);
StopCommand.register(this.dispatcher);
- TransferCommand.register(this.dispatcher);
+ //TransferCommand.register(this.dispatcher);
WhitelistCommand.register(this.dispatcher);
}

View File

@ -0,0 +1,27 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Chaoscaot <chaos@chaoscaot.de>
Date: Wed, 25 Dec 2024 12:36:40 +0100
Subject: [PATCH] SW Remove Debug Message
diff --git a/net/minecraft/server/players/StoredUserList.java b/net/minecraft/server/players/StoredUserList.java
index d445e8f126f077d8419c52fa5436ea963a1a42a4..dfb0d766b5244646d18ddec5d8b91eddb69d9e97 100644
--- a/net/minecraft/server/players/StoredUserList.java
+++ b/net/minecraft/server/players/StoredUserList.java
@@ -12,6 +12,7 @@ import com.mojang.logging.LogUtils;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
@@ -103,6 +104,8 @@ public abstract class StoredUserList<K, V extends StoredUserEntry<K>> {
try (BufferedWriter writer = Files.newWriter(this.file, StandardCharsets.UTF_8)) {
GSON.toJson(jsonArray, GSON.newJsonWriter(writer));
+ } catch (FileNotFoundException e) {
+ return;
}
}

View File

@ -1342,17 +1342,18 @@
}
public SectionPos getLastSectionPos() {
@@ -1930,21 +_,54 @@
@@ -1930,21 +_,55 @@
}
@Override
- public ItemEntity drop(ItemStack droppedItem, boolean dropAround, boolean traceItem) {
+ public ItemEntity drop(ItemStack droppedItem, boolean dropAround, boolean traceItem, boolean callEvent) { // CraftBukkit - SPIGOT-2942: Add boolean to call event
+ public ItemEntity drop(ItemStack droppedItem, boolean dropAround, boolean traceItem, boolean callEvent, @Nullable java.util.function.Consumer<org.bukkit.entity.Item> entityOperation) { // Paper start - Extend HumanEntity#dropItem API
ItemEntity itemEntity = this.createItemStackToDrop(droppedItem, dropAround, traceItem);
if (itemEntity == null) {
return null;
} else {
+ // CraftBukkit start - fire PlayerDropItemEvent
+ if (entityOperation != null) entityOperation.accept((org.bukkit.entity.Item) itemEntity.getBukkitEntity());
+ if (callEvent) {
+ org.bukkit.entity.Player player = this.getBukkitEntity();
+ org.bukkit.entity.Item drop = (org.bukkit.entity.Item) itemEntity.getBukkitEntity();

View File

@ -112,16 +112,21 @@
this.removeEntitiesOnShoulder();
}
}
@@ -717,6 +_,13 @@
@@ -717,6 +_,18 @@
@Nullable
public ItemEntity drop(ItemStack droppedItem, boolean dropAround, boolean includeThrowerName) {
+ // CraftBukkit start - SPIGOT-2942: Add boolean to call event
+ return this.drop(droppedItem, dropAround, includeThrowerName, true);
+ return this.drop(droppedItem, dropAround, includeThrowerName, true, null);
+ }
+
+ @Nullable
+ public ItemEntity drop(ItemStack droppedItem, boolean dropAround, boolean includeThrowerName, boolean callEvent) {
+ return this.drop(droppedItem, dropAround, includeThrowerName, callEvent, null);
+ }
+
+ @Nullable
+ public ItemEntity drop(ItemStack droppedItem, boolean dropAround, boolean includeThrowerName, boolean callEvent, @Nullable java.util.function.Consumer<org.bukkit.entity.Item> entityOperation) {
+ // CraftBukkit end
if (!droppedItem.isEmpty() && this.level().isClientSide) {
this.swing(InteractionHand.MAIN_HAND);

View File

@ -92,7 +92,7 @@ public enum VersionHistoryManager {
)) {
gson.toJson(currentData, writer);
} catch (final IOException e) {
logger.log(Level.SEVERE, "Failed to write to version history file", e);
// logger.log(Level.SEVERE, "Failed to write to version history file", e);
}
}

View File

@ -112,7 +112,7 @@ public abstract class Configurations<G, W> {
loader.save(node);
} catch (ConfigurateException ex) {
if (ex.getCause() instanceof AccessDeniedException) {
LOGGER.warn("Could not save {}: Paper could not persist the full set of configuration settings in the configuration file. Any setting missing from the configuration file will be set with its default value in memory. Admins should make sure to review the configuration documentation at https://docs.papermc.io/paper/configuration for more details.", filename, ex);
//LOGGER.warn("Could not save {}: Paper could not persist the full set of configuration settings in the configuration file. Any setting missing from the configuration file will be set with its default value in memory. Admins should make sure to review the configuration documentation at https://docs.papermc.io/paper/configuration for more details.", filename, ex);
} else throw ex;
}
}

View File

@ -463,8 +463,6 @@ public class PaperConfigurations extends Configurations<GlobalConfiguration, Wor
// Symlinks are not correctly checked in createDirectories
static void createDirectoriesSymlinkAware(Path path) throws IOException {
if (!Files.isDirectory(path)) {
Files.createDirectories(path);
}
// do nothing
}
}

View File

@ -517,7 +517,7 @@ public final class CraftServer implements Server {
try {
this.configuration.save(this.getConfigFile());
} catch (IOException ex) {
Logger.getLogger(CraftServer.class.getName()).log(Level.SEVERE, "Could not save " + this.getConfigFile(), ex);
//Logger.getLogger(CraftServer.class.getName()).log(Level.SEVERE, "Could not save " + this.getConfigFile(), ex);
}
}
@ -525,7 +525,7 @@ public final class CraftServer implements Server {
try {
this.commandsConfiguration.save(this.getCommandsConfigFile());
} catch (IOException ex) {
Logger.getLogger(CraftServer.class.getName()).log(Level.SEVERE, "Could not save " + this.getCommandsConfigFile(), ex);
//Logger.getLogger(CraftServer.class.getName()).log(Level.SEVERE, "Could not save " + this.getCommandsConfigFile(), ex);
}
}
@ -615,7 +615,7 @@ public final class CraftServer implements Server {
DefaultPermissions.registerCorePermissions();
CraftDefaultPermissions.registerCorePermissions();
if (!io.papermc.paper.configuration.GlobalConfiguration.get().misc.loadPermissionsYmlBeforePlugins) this.loadCustomPermissions(); // Paper
this.helpMap.initializeCommands();
//this.helpMap.initializeCommands();
this.syncCommands();
}
}

View File

@ -7,6 +7,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
@ -19,6 +20,7 @@ import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntitySpawnReason;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.HumanoidArm;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.projectile.FireworkRocketEntity;
import net.minecraft.world.inventory.AbstractContainerMenu;
@ -48,13 +50,14 @@ import org.bukkit.craftbukkit.inventory.CraftInventoryView;
import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.craftbukkit.inventory.CraftMerchantCustom;
import org.bukkit.craftbukkit.inventory.CraftRecipe;
import org.bukkit.craftbukkit.util.CraftChatMessage;
import org.bukkit.craftbukkit.util.CraftLocation;
import org.bukkit.entity.Firework;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Item;
import org.bukkit.entity.Villager;
import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
import org.bukkit.inventory.EntityEquipment;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryView;
import org.bukkit.inventory.ItemStack;
@ -66,6 +69,8 @@ import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionAttachment;
import org.bukkit.permissions.PermissionAttachmentInfo;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity {
private CraftInventoryPlayer inventory;
@ -801,6 +806,47 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity {
// Paper end - Fix HumanEntity#drop not updating the client inv
}
@Override
@Nullable
public Item dropItem(final int slot, final int amount, final boolean throwRandomly, final @Nullable Consumer<Item> entityOperation) {
Preconditions.checkArgument(slot >= 0 && slot < this.inventory.getSize(), "Slot %s is not a valid inventory slot.", slot);
return internalDropItemFromInventory(this.inventory.getItem(slot), amount, throwRandomly, entityOperation);
}
@Override
@Nullable
public Item dropItem(final @NotNull EquipmentSlot slot, final int amount, final boolean throwRandomly, final @Nullable Consumer<Item> entityOperation) {
return internalDropItemFromInventory(this.inventory.getItem(slot), amount, throwRandomly, entityOperation);
}
@Nullable
private Item internalDropItemFromInventory(final ItemStack originalItemStack, final int amount, final boolean throwRandomly, final @Nullable Consumer<Item> entityOperation) {
if (originalItemStack == null || originalItemStack.isEmpty() || amount <= 0) return null;
final net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.unwrap(originalItemStack);
final net.minecraft.world.item.ItemStack dropContent = nmsItemStack.split(amount);
// This will return the itemstack back to its original amount in case events fail
final ItemEntity droppedEntity = this.getHandle().drop(dropContent, throwRandomly, true, true, entityOperation);
return droppedEntity == null ? null : (Item) droppedEntity.getBukkitEntity();
}
@Override
@Nullable
public Item dropItem(final ItemStack itemStack, final boolean throwRandomly, final @Nullable Consumer<Item> entityOperation) {
// This method implementation differs from the previous dropItem implementations, as it does not source
// its itemstack from the players inventory. As such, we cannot reuse #internalDropItemFromInventory.
Preconditions.checkArgument(itemStack != null, "Cannot drop a null itemstack");
if (itemStack.isEmpty()) return null;
final net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.asNMSCopy(itemStack);
// Do *not* call the event here, the item is not in the player inventory, they are not dropping it / do not need recovering logic (which would be a dupe).
final ItemEntity droppedEntity = this.getHandle().drop(nmsItemStack, throwRandomly, true, false, entityOperation);
return droppedEntity == null ? null : (Item) droppedEntity.getBukkitEntity();
}
@Override
public float getExhaustion() {
return this.getHandle().getFoodData().exhaustionLevel;

View File

@ -97,7 +97,7 @@ public class SpigotConfig {
try {
SpigotConfig.config.save(SpigotConfig.CONFIG_FILE);
} catch (IOException ex) {
Bukkit.getLogger().log(Level.SEVERE, "Could not save " + SpigotConfig.CONFIG_FILE, ex);
//Bukkit.getLogger().log(Level.SEVERE, "Could not save " + SpigotConfig.CONFIG_FILE, ex);
}
}

11
steamwarci.yml Normal file
View File

@ -0,0 +1,11 @@
build:
- "JAVA_HOME=/usr/lib/jvm/java-21.0.5-openjdk-amd64 ./gradlew applyPatches"
- "JAVA_HOME=/usr/lib/jvm/java-21.0.5-openjdk-amd64 ./gradlew createMojmapBundlerJar"
- "JAVA_HOME=/usr/lib/jvm/java-21.0.5-openjdk-amd64 ./gradlew --stop"
artifacts:
"/binarys/paper-1.21.4.jar": "paper-server/build/libs/paper-bundler-1.21.4-R0.1-SNAPSHOT-mojmap.jar"
"/binarys/spigot-1.21.4-inner.jar": "paper-server/build/libs/paper-server-1.21.4-R0.1-SNAPSHOT.jar"
release:
- "mvn deploy:deploy-file -DgroupId=de.steamwar -DartifactId=spigot -Dversion=1.21.4 -Dpackaging=jar -Dfile=paper-server/build/libs/paper-server-1.21.4-R0.1-SNAPSHOT.jar -Durl=file:///var/www/html/maven/"