diff --git a/patches/api/0040-LootTable-API.patch b/patches/api/0040-LootTable-API.patch index 8be71089d4..244d7995a3 100644 --- a/patches/api/0040-LootTable-API.patch +++ b/patches/api/0040-LootTable-API.patch @@ -58,10 +58,10 @@ index 0000000000000000000000000000000000000000..b387894fe8001edb41ad2ad2b70ebabe +} diff --git a/src/main/java/com/destroystokyo/paper/loottable/LootableInventory.java b/src/main/java/com/destroystokyo/paper/loottable/LootableInventory.java new file mode 100644 -index 0000000000000000000000000000000000000000..97815eeb231cf0706b34fa47a4f7d1bb786305b4 +index 0000000000000000000000000000000000000000..2b01a50b6e18856f4c9e28340a7a111cae646a0a --- /dev/null +++ b/src/main/java/com/destroystokyo/paper/loottable/LootableInventory.java -@@ -0,0 +1,116 @@ +@@ -0,0 +1,125 @@ +package com.destroystokyo.paper.loottable; + +import org.bukkit.entity.Player; @@ -106,6 +106,15 @@ index 0000000000000000000000000000000000000000..97815eeb231cf0706b34fa47a4f7d1bb + } + + /** ++ * Checks if this player can loot this block. Takes into account the "restrict player reloot" settings ++ * ++ * @param player the player to check ++ * ++ * @return Whether this player can loot this block ++ */ ++ boolean canPlayerLoot(@NotNull UUID player); ++ ++ /** + * Has this player ever looted this block + * @param player The player to check + * @return Whether or not this player has looted this block diff --git a/patches/server/0005-Paper-config-files.patch b/patches/server/0005-Paper-config-files.patch index 9f8f81fe06..3338a3e409 100644 --- a/patches/server/0005-Paper-config-files.patch +++ b/patches/server/0005-Paper-config-files.patch @@ -948,10 +948,10 @@ index 0000000000000000000000000000000000000000..69add4a7f1147015806bc9b63a8340d1 +} diff --git a/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java b/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java new file mode 100644 -index 0000000000000000000000000000000000000000..ad2177cdbc61a6f41c7e2ed81af262d4ffe7d861 +index 0000000000000000000000000000000000000000..e471960e0443392f6f54732b052a4debf2a8fd97 --- /dev/null +++ b/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java -@@ -0,0 +1,440 @@ +@@ -0,0 +1,442 @@ +package io.papermc.paper.configuration; + +import com.google.common.base.Suppliers; @@ -978,6 +978,7 @@ index 0000000000000000000000000000000000000000..ad2177cdbc61a6f41c7e2ed81af262d4 +import io.papermc.paper.configuration.type.BooleanOrDefault; +import io.papermc.paper.configuration.type.DoubleOrDefault; +import io.papermc.paper.configuration.type.Duration; ++import io.papermc.paper.configuration.type.DurationOrDisabled; +import io.papermc.paper.configuration.type.EngineMode; +import io.papermc.paper.configuration.type.IntOr; +import io.papermc.paper.configuration.type.fallback.FallbackValueSerializer; @@ -1166,6 +1167,7 @@ index 0000000000000000000000000000000000000000..ad2177cdbc61a6f41c7e2ed81af262d4 + .register(DoubleOrDefault.SERIALIZER) + .register(BooleanOrDefault.SERIALIZER) + .register(Duration.SERIALIZER) ++ .register(DurationOrDisabled.SERIALIZER) + .register(EngineMode.SERIALIZER) + .register(NbtPathSerializer.SERIALIZER) + .register(FallbackValueSerializer.create(contextMap.require(SPIGOT_WORLD_CONFIG_CONTEXT_KEY).get(), MinecraftServer::getServer)) @@ -1477,10 +1479,10 @@ index 0000000000000000000000000000000000000000..f0d4ec73bc8872a85e34f5c6b4d342e7 +} diff --git a/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java b/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java new file mode 100644 -index 0000000000000000000000000000000000000000..a33de97340f14219291c4175e9194914cdf441db +index 0000000000000000000000000000000000000000..d47c57afafc01e25b965f1844938b2516a7bd031 --- /dev/null +++ b/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java -@@ -0,0 +1,482 @@ +@@ -0,0 +1,484 @@ +package io.papermc.paper.configuration; + +import com.google.common.collect.HashBasedTable; @@ -1496,6 +1498,7 @@ index 0000000000000000000000000000000000000000..a33de97340f14219291c4175e9194914 +import io.papermc.paper.configuration.type.BooleanOrDefault; +import io.papermc.paper.configuration.type.DoubleOrDefault; +import io.papermc.paper.configuration.type.Duration; ++import io.papermc.paper.configuration.type.DurationOrDisabled; +import io.papermc.paper.configuration.type.EngineMode; +import io.papermc.paper.configuration.type.IntOr; +import io.papermc.paper.configuration.type.fallback.ArrowDespawnRate; @@ -1775,6 +1778,7 @@ index 0000000000000000000000000000000000000000..a33de97340f14219291c4175e9194914 + public class Lootables extends ConfigurationPart { + public boolean autoReplenish = false; + public boolean restrictPlayerReloot = true; ++ public DurationOrDisabled restrictPlayerRelootTime = DurationOrDisabled.USE_DISABLED; + public boolean resetSeedOnFill = true; + public int maxRefills = -1; + public Duration refreshMin = Duration.of("12h"); @@ -3936,7 +3940,7 @@ index 0000000000000000000000000000000000000000..193709f1d08e489fc51cbe11d4325297 +} diff --git a/src/main/java/io/papermc/paper/configuration/type/Duration.java b/src/main/java/io/papermc/paper/configuration/type/Duration.java new file mode 100644 -index 0000000000000000000000000000000000000000..fdc906b106a5c6fff2675d5399650f5b793deb70 +index 0000000000000000000000000000000000000000..422ccb0b332b3e94be228b9b94f379467d6461a5 --- /dev/null +++ b/src/main/java/io/papermc/paper/configuration/type/Duration.java @@ -0,0 +1,97 @@ @@ -4021,7 +4025,7 @@ index 0000000000000000000000000000000000000000..fdc906b106a5c6fff2675d5399650f5b + return (int) num; + } + -+ private static final class Serializer extends ScalarSerializer { ++ static final class Serializer extends ScalarSerializer { + private Serializer() { + super(Duration.class); + } @@ -4037,6 +4041,66 @@ index 0000000000000000000000000000000000000000..fdc906b106a5c6fff2675d5399650f5b + } + } +} +diff --git a/src/main/java/io/papermc/paper/configuration/type/DurationOrDisabled.java b/src/main/java/io/papermc/paper/configuration/type/DurationOrDisabled.java +new file mode 100644 +index 0000000000000000000000000000000000000000..3f17e75e08e1cb4359b96a78c5b8d5284c484e43 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/configuration/type/DurationOrDisabled.java +@@ -0,0 +1,54 @@ ++package io.papermc.paper.configuration.type; ++ ++import java.lang.reflect.Type; ++import java.util.Optional; ++import java.util.function.Predicate; ++import org.spongepowered.configurate.serialize.ScalarSerializer; ++import org.spongepowered.configurate.serialize.SerializationException; ++ ++@SuppressWarnings("OptionalUsedAsFieldOrParameterType") ++public final class DurationOrDisabled { ++ private static final String DISABLE_VALUE = "disabled"; ++ public static final DurationOrDisabled USE_DISABLED = new DurationOrDisabled(Optional.empty()); ++ public static final ScalarSerializer SERIALIZER = new Serializer(); ++ ++ private Optional value; ++ ++ public DurationOrDisabled(final Optional value) { ++ this.value = value; ++ } ++ ++ public Optional value() { ++ return this.value; ++ } ++ ++ public void value(final Optional value) { ++ this.value = value; ++ } ++ ++ public Duration or(final Duration fallback) { ++ return this.value.orElse(fallback); ++ } ++ ++ private static final class Serializer extends ScalarSerializer { ++ Serializer() { ++ super(DurationOrDisabled.class); ++ } ++ ++ @Override ++ public DurationOrDisabled deserialize(final Type type, final Object obj) throws SerializationException { ++ if (obj instanceof final String string) { ++ if (DISABLE_VALUE.equalsIgnoreCase(string)) { ++ return USE_DISABLED; ++ } ++ return new DurationOrDisabled(Optional.of(Duration.SERIALIZER.deserialize(string))); ++ } ++ throw new SerializationException(obj + "(" + type + ") is not a duration or '" + DISABLE_VALUE + "'"); ++ } ++ ++ @Override ++ protected Object serialize(final DurationOrDisabled item, final Predicate> typeSupported) { ++ return item.value.map(Duration::value).orElse(DISABLE_VALUE); ++ } ++ } ++} diff --git a/src/main/java/io/papermc/paper/configuration/type/EngineMode.java b/src/main/java/io/papermc/paper/configuration/type/EngineMode.java new file mode 100644 index 0000000000000000000000000000000000000000..7f8b685762f59049fde88e8d1bc10e1504916010 @@ -4474,7 +4538,7 @@ index e7240acad17dc9c0d93f2792cc0d90c1855ac436..35e7f8e7b19c217fa5f3f55abb0f8b9c String s = (String) Optional.ofNullable((String) optionset.valueOf("world")).orElse(dedicatedserversettings.getProperties().levelName); LevelStorageSource convertable = LevelStorageSource.createDefault(file.toPath()); diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 49eaa50c5e83e47022a1d126c62f6984f2d16f46..8eb949b43e8b403f3d98e36066cabd7cb9ab0e63 100644 +index c7d90803c302fc3cb06f44abf12d86c7e02944cd..a6e12acf65068a2eaea75a7df877f6145a229195 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -295,6 +295,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop(); + } + if (looted) { -+ if (!this.lootedPlayers.containsKey(player)) { -+ this.lootedPlayers.put(player, System.currentTimeMillis()); -+ } ++ this.lootedPlayers.put(player, System.currentTimeMillis()); + } else if (this.lootedPlayers != null) { + this.lootedPlayers.remove(player); + } + } + ++ boolean canPlayerLoot(final UUID player, final WorldConfiguration worldConfiguration) { ++ final Long lastLooted = getLastLooted(player); ++ if (!worldConfiguration.lootables.restrictPlayerReloot || lastLooted == null) return true; ++ ++ final DurationOrDisabled restrictPlayerRelootTime = worldConfiguration.lootables.restrictPlayerRelootTime; ++ if (restrictPlayerRelootTime.value().isEmpty()) return true; ++ ++ return TimeUnit.SECONDS.toMillis(restrictPlayerRelootTime.value().get().seconds()) + lastLooted < System.currentTimeMillis(); ++ } ++ + boolean hasPlayerLooted(UUID player) { + return this.lootedPlayers != null && this.lootedPlayers.containsKey(player); + } @@ -490,7 +504,7 @@ index 0000000000000000000000000000000000000000..9cfa5d36a6991067a3866e0d437749fa + } +} diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 9fadfb41a41b575aa1ca1c28e34118708eded498..fbd28a3f571766e6ed4ba73f337b2e835ef50453 100644 +index 2f15c9df59ebfbe7619e190b8d6ef1fe122809f8..069fe5df02806103c9bbef396c2e39ca3be90101 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -235,6 +235,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {