9
0
mirror of https://github.com/Samsuik/Sakura.git synced 2025-12-29 03:39:07 +00:00

Start on updating 1.21.4

This commit is contained in:
Samsuik
2025-01-14 23:02:38 +00:00
parent 6225f7d928
commit 24d7230079
101 changed files with 189 additions and 112 deletions

View File

@@ -0,0 +1,251 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
Date: Tue, 23 May 2023 23:07:20 +0100
Subject: [PATCH] Sakura Utils
diff --git a/src/main/java/me/samsuik/sakura/utils/collections/FixedSizeCustomObjectTable.java b/src/main/java/me/samsuik/sakura/utils/collections/FixedSizeCustomObjectTable.java
new file mode 100644
index 0000000000000000000000000000000000000000..e97f3cc00945f79026af894685d6104dfc920a35
--- /dev/null
+++ b/src/main/java/me/samsuik/sakura/utils/collections/FixedSizeCustomObjectTable.java
@@ -0,0 +1,54 @@
+package me.samsuik.sakura.utils.collections;
+
+import it.unimi.dsi.fastutil.HashCommon;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.function.ToIntFunction;
+
+public final class FixedSizeCustomObjectTable<T> {
+ private final ToIntFunction<T> keyFunction;
+ private final T[] contents;
+ private final int mask;
+
+ public FixedSizeCustomObjectTable(int size, @NotNull ToIntFunction<T> keyFunction) {
+ if (size < 0) {
+ throw new IllegalArgumentException("Table size cannot be negative");
+ } else {
+ int n = HashCommon.nextPowerOfTwo(size - 1);
+ this.keyFunction = keyFunction;
+ this.contents = (T[]) new Object[n];
+ this.mask = (n - 1);
+ }
+ }
+
+ private int key(T value) {
+ return this.keyFunction.applyAsInt(value);
+ }
+
+ public @Nullable T get(T value) {
+ return this.get(this.key(value));
+ }
+
+ public @Nullable T get(int key) {
+ return this.contents[key & this.mask];
+ }
+
+ public void write(int key, T value) {
+ this.contents[key & this.mask] = value;
+ }
+
+ public @Nullable T getAndWrite(T value) {
+ int key = this.key(value);
+ T found = this.get(key);
+ this.write(key, value);
+ return found;
+ }
+
+ public void clear() {
+ int size = this.contents.length;
+ for (int i = 0; i < size; ++i) {
+ this.contents[i] = null;
+ }
+ }
+}
diff --git a/src/main/java/me/samsuik/sakura/utils/collections/OrderedComparatorList.java b/src/main/java/me/samsuik/sakura/utils/collections/OrderedComparatorList.java
new file mode 100644
index 0000000000000000000000000000000000000000..edbbf9dea7c6659c2053407dc55b5a2a1cfcb0dd
--- /dev/null
+++ b/src/main/java/me/samsuik/sakura/utils/collections/OrderedComparatorList.java
@@ -0,0 +1,49 @@
+package me.samsuik.sakura.utils.collections;
+
+import it.unimi.dsi.fastutil.objects.ObjectArrayList;
+
+import java.util.Arrays;
+import java.util.Comparator;
+
+public final class OrderedComparatorList<T> extends ObjectArrayList<T> {
+ private final Comparator<T> comparator;
+ private boolean binarySearch = true;
+
+ public OrderedComparatorList(int capacity, Comparator<T> comparator) {
+ super(capacity);
+ this.comparator = Comparator.nullsLast(comparator);
+ }
+
+ public OrderedComparatorList(Comparator<T> comparator) {
+ this(DEFAULT_INITIAL_CAPACITY, comparator);
+ }
+
+ private void validateBounds(int index, T t, boolean up) {
+ if (index != 0 && this.comparator.compare(get(index - 1), t) > 0) {
+ this.binarySearch = false;
+ } else if (up && index < size() - 1 && this.comparator.compare(get(index + 1), t) < 0) {
+ this.binarySearch = false;
+ }
+ }
+
+ @Override
+ public boolean add(T t) {
+ this.validateBounds(size(), t, false);
+ return super.add(t);
+ }
+
+ @Override
+ public void add(int index, T t) {
+ this.validateBounds(index, t, true);
+ super.add(index, t);
+ }
+
+ @Override
+ public int indexOf(final Object k) {
+ if (this.binarySearch) {
+ return Math.max(Arrays.binarySearch(this.a, (T) k, this.comparator), -1);
+ } else {
+ return super.indexOf(k);
+ }
+ }
+}
diff --git a/src/main/java/me/samsuik/sakura/utils/collections/TrackedEntityChunkMap.java b/src/main/java/me/samsuik/sakura/utils/collections/TrackedEntityChunkMap.java
new file mode 100644
index 0000000000000000000000000000000000000000..d112b559eaff82c32e943edf34c616565cb1e189
--- /dev/null
+++ b/src/main/java/me/samsuik/sakura/utils/collections/TrackedEntityChunkMap.java
@@ -0,0 +1,32 @@
+package me.samsuik.sakura.utils.collections;
+
+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
+import it.unimi.dsi.fastutil.objects.ObjectArrayList;
+import it.unimi.dsi.fastutil.objects.ObjectCollection;
+import net.minecraft.server.level.ChunkMap;
+
+public final class TrackedEntityChunkMap extends Int2ObjectOpenHashMap<ChunkMap.TrackedEntity> {
+ private final ObjectArrayList<ChunkMap.TrackedEntity> entityList = new UnorderedIndexedList<>();
+
+ @Override
+ public ChunkMap.TrackedEntity put(int k, ChunkMap.TrackedEntity trackedEntity) {
+ ChunkMap.TrackedEntity tracked = super.put(k, trackedEntity);
+ // bad plugins may replace entries
+ if (tracked != null)
+ this.entityList.remove(trackedEntity);
+ this.entityList.add(trackedEntity);
+ return tracked;
+ }
+
+ @Override
+ public ChunkMap.TrackedEntity remove(int k) {
+ ChunkMap.TrackedEntity tracked = super.remove(k);
+ this.entityList.remove(tracked);
+ return tracked;
+ }
+
+ @Override
+ public ObjectCollection<ChunkMap.TrackedEntity> values() {
+ return this.entityList;
+ }
+}
diff --git a/src/main/java/me/samsuik/sakura/utils/collections/UnorderedIndexedList.java b/src/main/java/me/samsuik/sakura/utils/collections/UnorderedIndexedList.java
new file mode 100644
index 0000000000000000000000000000000000000000..131dc69cdd2c121975199324022f942194d345c8
--- /dev/null
+++ b/src/main/java/me/samsuik/sakura/utils/collections/UnorderedIndexedList.java
@@ -0,0 +1,61 @@
+package me.samsuik.sakura.utils.collections;
+
+import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
+import it.unimi.dsi.fastutil.objects.ObjectArrayList;
+
+public final class UnorderedIndexedList<T> extends ObjectArrayList<T> {
+ private final Int2IntOpenHashMap elementToIndex;
+
+ public UnorderedIndexedList() {
+ this(DEFAULT_INITIAL_CAPACITY);
+ }
+
+ public UnorderedIndexedList(int capacity) {
+ super(capacity);
+ this.elementToIndex = new Int2IntOpenHashMap();
+ this.elementToIndex.defaultReturnValue(-1);
+ }
+
+ @Override
+ public boolean add(final T t) {
+ this.elementToIndex.put(t.hashCode(), size());
+ return super.add(t);
+ }
+
+ @Override
+ public T remove(final int index) {
+ final int tail = size() - 1;
+ final T at = a[index];
+
+ if (index != tail) {
+ final T tailObj = a[tail];
+ if (tailObj != null)
+ this.elementToIndex.put(tailObj.hashCode(), index);
+ this.a[index] = tailObj;
+ }
+
+ if (at != null)
+ this.elementToIndex.remove(at.hashCode());
+ this.a[tail] = null;
+ this.size = tail;
+ return at;
+ }
+
+ @Override
+ public void clear() {
+ this.elementToIndex.clear();
+ super.clear();
+ }
+
+ @Override
+ public int indexOf(final Object k) {
+ if (k == null) return -1;
+ // entities uses their id as a hashcode
+ return this.elementToIndex.get(k.hashCode());
+ }
+
+ @Override
+ public void add(final int index, final T t) {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/src/main/java/me/samsuik/sakura/utils/objects/Expiry.java b/src/main/java/me/samsuik/sakura/utils/objects/Expiry.java
new file mode 100644
index 0000000000000000000000000000000000000000..97a54930416951645e35f7bd7ec11325d1ba4d53
--- /dev/null
+++ b/src/main/java/me/samsuik/sakura/utils/objects/Expiry.java
@@ -0,0 +1,19 @@
+package me.samsuik.sakura.utils.objects;
+
+public final class Expiry {
+ private int expireAt;
+ private final int inc;
+
+ public Expiry(int tick, int inc) {
+ this.expireAt = tick + inc;
+ this.inc = inc;
+ }
+
+ public void refresh(int tick) {
+ this.expireAt = tick + this.inc;
+ }
+
+ public boolean isExpired(int tick) {
+ return tick >= this.expireAt;
+ }
+}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,263 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
Date: Tue, 21 Nov 2023 23:24:24 +0000
Subject: [PATCH] Local Config and Value Storage API
diff --git a/src/main/java/me/samsuik/sakura/local/config/LocalConfigManager.java b/src/main/java/me/samsuik/sakura/local/config/LocalConfigManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..2b77b942b1733380c566683ba0516a74ee5c6389
--- /dev/null
+++ b/src/main/java/me/samsuik/sakura/local/config/LocalConfigManager.java
@@ -0,0 +1,141 @@
+package me.samsuik.sakura.local.config;
+
+import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
+import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
+import it.unimi.dsi.fastutil.longs.Long2ObjectRBTreeMap;
+import it.unimi.dsi.fastutil.longs.Long2ObjectSortedMap;
+import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
+import me.samsuik.sakura.local.LocalRegion;
+import me.samsuik.sakura.local.storage.LocalStorageHandler;
+import me.samsuik.sakura.local.storage.LocalValueStorage;
+import me.samsuik.sakura.utils.objects.Expiry;
+import net.minecraft.core.BlockPos;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.world.level.ChunkPos;
+import net.minecraft.world.level.Level;
+import org.bukkit.Location;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public final class LocalConfigManager implements LocalStorageHandler {
+ private final Map<LocalRegion, LocalValueStorage> storageMap = new Object2ObjectOpenHashMap<>();
+ // tree is a tree. it may not be correct but it works.
+ private final Long2ObjectRBTreeMap<LocalRegion> regionTree = new Long2ObjectRBTreeMap<>();
+ private final Long2ObjectMap<LocalValueConfig> chunkConfigs = new Long2ObjectOpenHashMap<>();
+ private final Level level;
+
+ public LocalConfigManager(Level level) {
+ this.level = level;
+ }
+
+ @Override
+ public LocalRegion locate(Location location, int searchDistance) {
+ return this.locate(location.getBlockX(), location.getBlockZ(), searchDistance);
+ }
+
+ @Override
+ public synchronized LocalRegion locate(int x, int z, int searchDistance) {
+ long search = (long) searchDistance << 32;
+ long coordinate = ChunkPos.asLong(x, z);
+
+ // all regions below the coordinate (they're stored with the minX, minZ)
+ Long2ObjectSortedMap<LocalRegion> head = this.regionTree.headMap(coordinate);
+
+ if (head.isEmpty()) return null;
+
+ for (Long2ObjectMap.Entry<LocalRegion> entry : head.long2ObjectEntrySet()) {
+ // this has no respect for the x coordinate, but it works
+ if (coordinate - entry.getLongKey() > search) {
+ break;
+ }
+
+ // check if the region we found contains the position
+ if (entry.getValue().contains(x, z)) {
+ return entry.getValue();
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public synchronized LocalValueStorage get(LocalRegion region) {
+ return this.storageMap.get(region);
+ }
+
+ @Override
+ public synchronized boolean has(LocalRegion region) {
+ return this.storageMap.containsKey(region);
+ }
+
+ @Override
+ public synchronized void put(LocalRegion region, LocalValueStorage storage) {
+ assert region != null : "region cannot be null";
+ assert storage != null : "storage cannot be null";
+
+ long base = ChunkPos.asLong(region.minX(), region.minZ());
+ this.ensureNotOverlapping(region);
+
+ this.storageMap.put(region, storage);
+ this.regionTree.put(base, region);
+ }
+
+ @Override
+ public synchronized void remove(LocalRegion region) {
+ assert region != null : "region cannot be null";
+
+ long base = ChunkPos.asLong(region.minX(), region.minZ());
+
+ this.storageMap.remove(region);
+ this.regionTree.remove(base);
+ }
+
+ @Override
+ public synchronized List<LocalRegion> regions() {
+ return new ArrayList<>(this.storageMap.keySet());
+ }
+
+ public synchronized LocalValueConfig config(BlockPos position) {
+ long chunkKey = ChunkPos.asLong(position.getX() >> 4, position.getZ() >> 4);
+
+ LocalValueConfig local = this.chunkConfigs.computeIfAbsent(chunkKey, key -> {
+ LocalValueConfig config = new LocalValueConfig(new Expiry(MinecraftServer.currentTick, 600));
+
+ // defaults from sakura config
+ config.loadDefaults(this.level);
+
+ // search the entire map if we have to for a region
+ LocalRegion region = this.locate(position.getX(), position.getZ(), Integer.MAX_VALUE);
+
+ if (region != null) {
+ // load local values
+ config.loadFromStorage(this.storageMap.get(region));
+ }
+
+ return config;
+ });
+
+ local.expiry().refresh(MinecraftServer.currentTick);
+ return local;
+ }
+
+ public synchronized void expire(int tick) {
+ if (tick % 200 != 0) return;
+
+ // remove expired
+ this.chunkConfigs.values().removeIf(obj -> obj.expiry().isExpired(tick));
+ }
+
+ private void ensureNotOverlapping(LocalRegion region) {
+ long top = ChunkPos.asLong(region.maxX(), region.maxZ());
+ Long2ObjectSortedMap<LocalRegion> head = this.regionTree.headMap(top);
+
+ for (LocalRegion present : head.values()) {
+ if (present != region && present.intersects(region)) {
+ throw new UnsupportedOperationException("overlapping regions");
+ }
+ }
+ }
+}
diff --git a/src/main/java/me/samsuik/sakura/local/config/LocalValueConfig.java b/src/main/java/me/samsuik/sakura/local/config/LocalValueConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..53d2c0f3d3c2d857a44c7a993cbd91ea5ce4b099
--- /dev/null
+++ b/src/main/java/me/samsuik/sakura/local/config/LocalValueConfig.java
@@ -0,0 +1,57 @@
+package me.samsuik.sakura.local.config;
+
+import io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation;
+import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap;
+import me.samsuik.sakura.explosion.durable.DurableMaterial;
+import me.samsuik.sakura.local.LocalValueKeys;
+import me.samsuik.sakura.local.storage.LocalValueStorage;
+import me.samsuik.sakura.physics.PhysicsVersion;
+import me.samsuik.sakura.utils.objects.Expiry;
+import net.minecraft.world.level.Level;
+import net.minecraft.world.level.block.Block;
+import org.bukkit.craftbukkit.util.CraftMagicNumbers;
+
+import java.util.Map;
+
+public final class LocalValueConfig {
+ private final Expiry expiry;
+ public Map<Block, DurableMaterial> durableMaterials;
+ public RedstoneImplementation redstoneImplementation;
+ public PhysicsVersion physicsVersion;
+ public boolean consistentRadius;
+ public boolean redstoneCache;
+ public int lavaFlowSpeed = -1;
+
+ LocalValueConfig(Expiry expiry) {
+ this.expiry = expiry;
+ }
+
+ void loadDefaults(Level level) {
+ this.durableMaterials = new Reference2ObjectOpenHashMap<>(level.sakuraConfig().cannons.explosion.durableMaterials);
+ this.redstoneImplementation = level.paperConfig().misc.redstoneImplementation;
+ this.physicsVersion = level.sakuraConfig().cannons.mechanics.physicsVersion;
+ this.consistentRadius = level.sakuraConfig().cannons.explosion.consistentRadius;
+ this.redstoneCache = level.sakuraConfig().technical.redstone.redstoneCache;
+ }
+
+ void loadFromStorage(LocalValueStorage storage) {
+ storage.get(LocalValueKeys.DURABLE_MATERIALS).ifPresent(materials -> {
+ materials.forEach((materialType, materialProperties) -> {
+ Block nmsBlock = CraftMagicNumbers.getBlock(materialType);
+ DurableMaterial durableMaterial = new DurableMaterial(materialProperties.getKey(), materialProperties.getValue());
+ this.durableMaterials.put(nmsBlock, durableMaterial);
+ });
+ });
+ storage.get(LocalValueKeys.REDSTONE_IMPLEMENTATION).ifPresent(implementation -> {
+ this.redstoneImplementation = RedstoneImplementation.values()[implementation.ordinal()];
+ });
+ this.physicsVersion = storage.getOrDefault(LocalValueKeys.PHYSICS_VERSION, this.physicsVersion);
+ this.consistentRadius = storage.getOrDefault(LocalValueKeys.CONSISTENT_EXPLOSION_RADIUS, this.consistentRadius);
+ this.redstoneCache = storage.getOrDefault(LocalValueKeys.REDSTONE_CACHE, this.redstoneCache);
+ this.lavaFlowSpeed = storage.getOrDefault(LocalValueKeys.LAVA_FLOW_SPEED, this.lavaFlowSpeed);
+ }
+
+ Expiry expiry() {
+ return this.expiry;
+ }
+}
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index a39b00ebb37a0bf041bc7b9861fb7f9ebd962c40..1f9f023a43c16cc472deea5285b01c19136e019f 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -1890,6 +1890,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
gameprofilerfiller.pop();
gameprofilerfiller.pop();
worldserver.explosionDensityCache.clear(); // Paper - Optimize explosions
+ worldserver.localConfig().expire(currentTick); // Sakura - add local config
}
this.isIteratingOverLevels = false; // Paper - Throw exception on world create while being ticked
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index 34e7ae8b36e375280f9515c1580c55c0832fc194..13e8ac95daa115720a2b1f52ad33d124351cbd6d 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -179,6 +179,12 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
return this.sakuraConfig;
}
// Sakura end - sakura configuration files
+ // Sakura start - add local config
+ private final me.samsuik.sakura.local.config.LocalConfigManager localConfig = new me.samsuik.sakura.local.config.LocalConfigManager(this);
+ public final me.samsuik.sakura.local.config.LocalConfigManager localConfig() {
+ return this.localConfig;
+ }
+ // Sakura end - add local config
public final com.destroystokyo.paper.antixray.ChunkPacketBlockController chunkPacketBlockController; // Paper - Anti-Xray
public static BlockPos lastPhysicsProblem; // Spigot
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
index 92d9f0ea8f7810ae20d3996f49aefa539b4bcb69..8fc4b65887351a4dc35eaa837dea4dc9513514a8 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
@@ -289,6 +289,13 @@ public class CraftWorld extends CraftRegionAccessor implements World {
}
// Paper end
+ // Sakura start - add local config
+ @Override
+ public final me.samsuik.sakura.local.storage.LocalStorageHandler getStorageHandler() {
+ return this.getHandle().localConfig();
+ }
+ // Sakura end - add local config
+
private static final Random rand = new Random();
public CraftWorld(ServerLevel world, ChunkGenerator gen, BiomeProvider biomeProvider, Environment env) {

View File

@@ -0,0 +1,25 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <kfian294ma4@gmail.com>
Date: Sat, 11 Sep 2021 22:23:39 +0100
Subject: [PATCH] Optional Force Position Updates
diff --git a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
index 5bd189fad703ac99d57258fa448dbcc103077297..eff8a8353b513da72e18f993fd41494291bdff3a 100644
--- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
+++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
@@ -136,6 +136,14 @@ public class PrimedTnt extends Entity implements TraceableEntity {
}
}
+ // Sakura start - configure force position updates
+ if (this.level().sakuraConfig().cannons.tnt.forcePositionUpdates) {
+ this.forcePositionUpdate();
+ }
+ }
+
+ private void forcePositionUpdate() {
+ // Sakura end - configure force position updates
// Paper start - Option to prevent TNT from moving in water
if (!this.isRemoved() && this.wasTouchingWater && this.level().paperConfig().fixes.preventTntFromMovingInWater) {
/*

View File

@@ -0,0 +1,656 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <kfian294ma4@gmail.com>
Date: Sun, 19 Sep 2021 01:10:02 +0100
Subject: [PATCH] Track Tick Information
Keeps track of useful information every tick such as the tick rate,
entities, chunks and displays them with the tps command.
diff --git a/src/main/java/me/samsuik/sakura/command/SakuraCommands.java b/src/main/java/me/samsuik/sakura/command/SakuraCommands.java
index cbb2e57f9ab3b48a6e5f792711c4c6fd2d34d445..8e93fc5d7e1bc200f79b0e54edb62dc4d0bf5e74 100644
--- a/src/main/java/me/samsuik/sakura/command/SakuraCommands.java
+++ b/src/main/java/me/samsuik/sakura/command/SakuraCommands.java
@@ -4,6 +4,7 @@ import me.samsuik.sakura.command.subcommands.ConfigCommand;
import me.samsuik.sakura.command.subcommands.FPSCommand;
import me.samsuik.sakura.command.subcommands.VisualCommand;
import me.samsuik.sakura.player.visibility.VisibilityTypes;
+import me.samsuik.sakura.command.subcommands.TPSCommand;
import net.minecraft.server.MinecraftServer;
import org.bukkit.command.Command;
@@ -18,6 +19,7 @@ public final class SakuraCommands {
COMMANDS.put("fps", new FPSCommand("fps"));
COMMANDS.put("tntvisibility", new VisualCommand(VisibilityTypes.TNT, "tnttoggle"));
COMMANDS.put("sandvisibility", new VisualCommand(VisibilityTypes.SAND, "sandtoggle"));
+ COMMANDS.put("tps", new TPSCommand("tps"));
}
public static void registerCommands(MinecraftServer server) {
diff --git a/src/main/java/me/samsuik/sakura/command/subcommands/TPSCommand.java b/src/main/java/me/samsuik/sakura/command/subcommands/TPSCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..db6d03c1ed1c1d0390826dd3f96e774e2bea8a1a
--- /dev/null
+++ b/src/main/java/me/samsuik/sakura/command/subcommands/TPSCommand.java
@@ -0,0 +1,92 @@
+package me.samsuik.sakura.command.subcommands;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+import me.samsuik.sakura.command.BaseSubCommand;
+import me.samsuik.sakura.tps.ServerTickInformation;
+import me.samsuik.sakura.tps.graph.BuiltComponentCanvas;
+import me.samsuik.sakura.tps.graph.DetailedTPSGraph;
+import me.samsuik.sakura.tps.graph.GraphComponents;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.TextComponent;
+import net.kyori.adventure.text.event.ClickEvent;
+import net.kyori.adventure.text.format.NamedTextColor;
+import net.kyori.adventure.text.format.Style;
+import net.kyori.adventure.text.format.TextDecoration;
+import net.minecraft.server.MinecraftServer;
+import org.bukkit.command.CommandSender;
+import org.jspecify.annotations.NullMarked;
+
+@NullMarked
+public final class TPSCommand extends BaseSubCommand {
+ private static final int GRAPH_WIDTH = 71;
+ private static final int GRAPH_HEIGHT = 10;
+ private static final Style GRAY_WITH_STRIKETHROUGH = Style.style(NamedTextColor.GRAY, TextDecoration.STRIKETHROUGH);
+
+ public TPSCommand(String name) {
+ super(name);
+ this.description = "Displays the current ticks per second";
+ }
+
+ @Override
+ public void execute(CommandSender sender, String[] args) {
+ ServerTickInformation tickInformation = MinecraftServer.getServer().latestTickInformation();
+ long identifier = this.parseLong(args, 1).orElse(tickInformation.identifier());
+ double scale = this.parseDouble(args, 0).orElse(-1.0);
+ if (scale < 0.0) {
+ scale = this.dynamicScale(identifier);
+ }
+
+ ImmutableList<ServerTickInformation> tickHistory = MinecraftServer.getServer().tickHistory(identifier - GRAPH_WIDTH, identifier);
+ DetailedTPSGraph graph = new DetailedTPSGraph(GRAPH_WIDTH, GRAPH_HEIGHT, scale, tickHistory);
+ BuiltComponentCanvas canvas = graph.plot();
+ canvas.appendLeft(Component.text(":", NamedTextColor.BLACK));
+ canvas.appendRight(Component.text(":", NamedTextColor.BLACK));
+ canvas.header(this.createHeaderComponent(tickInformation, identifier));
+ canvas.footer(Component.text("*", NamedTextColor.DARK_GRAY)
+ .append(Component.text(Strings.repeat(" ", GRAPH_WIDTH - 1), GRAY_WITH_STRIKETHROUGH))
+ .append(Component.text("*")));
+
+ for (Component component : canvas.components()) {
+ sender.sendMessage(component);
+ }
+ }
+
+ private double dynamicScale(long identifier) {
+ ImmutableList<ServerTickInformation> tickHistory = MinecraftServer.getServer().tickHistory(identifier - 5, identifier);
+ double averageTps = tickHistory.stream()
+ .mapToDouble(ServerTickInformation::tps)
+ .average()
+ .orElse(0.0);
+ return 20 / averageTps;
+ }
+
+ private Component createHeaderComponent(ServerTickInformation tickInformation, long identifier) {
+ int scrollAmount = GRAPH_WIDTH / 3 * 2;
+ double memoryUsage = memoryUsage();
+ TextComponent.Builder builder = Component.text();
+ builder.color(NamedTextColor.DARK_GRAY);
+ builder.append(Component.text("< ")
+ .clickEvent(ClickEvent.runCommand("/tps -1 " + (identifier + scrollAmount))));
+ builder.append(Component.text(Strings.repeat(" ", 19), GRAY_WITH_STRIKETHROUGH));
+ builder.append(Component.text(" ( "));
+ builder.append(Component.text("Now: ", NamedTextColor.WHITE)
+ .append(Component.text("%.1f".formatted(tickInformation.tps()), tickInformation.colour())));
+ builder.appendSpace();
+ builder.append(Component.text("Mem: ", NamedTextColor.WHITE)
+ .append(Component.text("%.1f".formatted(memoryUsage * 100), GraphComponents.colour(1 - (float) memoryUsage))));
+ builder.append(Component.text("% ) "));
+ builder.append(Component.text(Strings.repeat(" ", 18), GRAY_WITH_STRIKETHROUGH));
+ builder.append(Component.text(" >")
+ .clickEvent(ClickEvent.runCommand("/tps -1 " + (identifier - scrollAmount))));
+ return builder.build();
+ }
+
+ private static double memoryUsage() {
+ Runtime runtime = Runtime.getRuntime();
+ double free = runtime.freeMemory();
+ double max = runtime.maxMemory();
+ double alloc = runtime.totalMemory();
+ return (alloc - free) / max;
+ }
+}
diff --git a/src/main/java/me/samsuik/sakura/tps/ServerTickInformation.java b/src/main/java/me/samsuik/sakura/tps/ServerTickInformation.java
new file mode 100644
index 0000000000000000000000000000000000000000..9a65a3dac75834a2fe10d2c6d6ae594ceb208fef
--- /dev/null
+++ b/src/main/java/me/samsuik/sakura/tps/ServerTickInformation.java
@@ -0,0 +1,37 @@
+package me.samsuik.sakura.tps;
+
+import me.samsuik.sakura.configuration.GlobalConfiguration;
+import me.samsuik.sakura.tps.graph.GraphComponents;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.TextComponent;
+import net.kyori.adventure.text.format.TextColor;
+import net.minecraft.server.MinecraftServer;
+import org.jspecify.annotations.NullMarked;
+
+@NullMarked
+public record ServerTickInformation(long identifier, double tps, double averageTick, long longestTick, float targetTickRate, int chunks, int entities) {
+ public static final ServerTickInformation FILLER = new ServerTickInformation(0, 0.0, 0.0, 0, 0.0f, 0, 0);
+
+ public TextColor colour() {
+ float lag = (float) this.tps / this.targetTickRate;
+ return GraphComponents.colour(lag);
+ }
+
+ public Component hoverComponent(TextColor colour) {
+ TextComponent.Builder builder = Component.text();
+ builder.append(Component.text("TPS: ")
+ .append(Component.text("%.1f".formatted(this.tps), colour)));
+ builder.appendNewline();
+ builder.append(Component.text("MSPT: ")
+ .append(Component.text("%.1f".formatted(this.averageTick), colour))
+ .append(Component.text("/"))
+ .append(Component.text(this.longestTick, colour)));
+ if (GlobalConfiguration.get().messages.tpsShowEntityAndChunkCount) {
+ builder.appendNewline();
+ builder.append(Component.text("Entities: " + this.entities));
+ builder.appendNewline();
+ builder.append(Component.text("Chunks: " + this.chunks));
+ }
+ return builder.build();
+ }
+}
diff --git a/src/main/java/me/samsuik/sakura/tps/TickInformationCollector.java b/src/main/java/me/samsuik/sakura/tps/TickInformationCollector.java
new file mode 100644
index 0000000000000000000000000000000000000000..5f88e17db0cf8eca161d98cc8cdac8383903e694
--- /dev/null
+++ b/src/main/java/me/samsuik/sakura/tps/TickInformationCollector.java
@@ -0,0 +1,71 @@
+package me.samsuik.sakura.tps;
+
+import com.google.common.collect.ImmutableList;
+import it.unimi.dsi.fastutil.longs.LongArrayList;
+import it.unimi.dsi.fastutil.objects.ObjectArrayList;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.level.ServerLevel;
+import org.jspecify.annotations.NullMarked;
+
+import java.util.Collection;
+import java.util.List;
+
+@NullMarked
+public final class TickInformationCollector {
+ private static final int TEN_MINUTES = 10 * 60;
+ private final ObjectArrayList<ServerTickInformation> collectedInformation = new ObjectArrayList<>();
+ private final LongArrayList tickSamples = new LongArrayList();
+ private long identifier = 0;
+
+ public ServerTickInformation latestTickInformation() {
+ return this.collectedInformation.getLast();
+ }
+
+ public void levelData(Collection<ServerLevel> levels, double tps) {
+ int chunks = 0;
+ int entities = 0;
+ for (ServerLevel level : levels) {
+ chunks += level.chunkSource.getFullChunksCount();
+ entities += level.entityTickList.entities.size();
+ }
+
+ double averageTick = this.tickSamples.longStream()
+ .average()
+ .orElse(0.0);
+ long longestTick = this.tickSamples.longStream()
+ .max()
+ .orElse(0);
+ float targetTickRate = MinecraftServer.getServer().tickRateManager().tickrate();
+
+ ServerTickInformation tickInformation = new ServerTickInformation(
+ this.identifier++, tps, averageTick, longestTick, targetTickRate, chunks, entities
+ );
+
+ this.collectedInformation.add(tickInformation);
+ this.tickSamples.clear();
+
+ if (this.collectedInformation.size() > TEN_MINUTES) {
+ this.collectedInformation.subList(0, 60).clear();
+ }
+ }
+
+ public void tickDuration(long timeTaken) {
+ this.tickSamples.add(timeTaken);
+ }
+
+ public ImmutableList<ServerTickInformation> collect(long from, long to) {
+ List<ServerTickInformation> collected = new ObjectArrayList<>();
+ for (ServerTickInformation tickInformation : this.collectedInformation.reversed()) {
+ if (tickInformation.identifier() >= from && tickInformation.identifier() < to) {
+ collected.add(tickInformation);
+ }
+ }
+ long ahead = to - this.identifier;
+ long missing = to - from - collected.size();
+ for (int i = 0; i < missing; ++i) {
+ int ind = (i < ahead) ? 0 : collected.size();
+ collected.add(ind, ServerTickInformation.FILLER);
+ }
+ return ImmutableList.copyOf(collected);
+ }
+}
diff --git a/src/main/java/me/samsuik/sakura/tps/graph/BuiltComponentCanvas.java b/src/main/java/me/samsuik/sakura/tps/graph/BuiltComponentCanvas.java
new file mode 100644
index 0000000000000000000000000000000000000000..bf3e953c99825274b800d19c74019c904620ec74
--- /dev/null
+++ b/src/main/java/me/samsuik/sakura/tps/graph/BuiltComponentCanvas.java
@@ -0,0 +1,36 @@
+package me.samsuik.sakura.tps.graph;
+
+import com.google.common.collect.ImmutableList;
+import net.kyori.adventure.text.Component;
+import org.jspecify.annotations.NullMarked;
+
+import java.util.List;
+
+@NullMarked
+public final class BuiltComponentCanvas {
+ private final List<Component> components;
+
+ BuiltComponentCanvas(List<Component> components) {
+ this.components = components;
+ }
+
+ public void appendLeft(Component component) {
+ this.components.replaceAll(component::append);
+ }
+
+ public void appendRight(Component component) {
+ this.components.replaceAll(row -> row.append(component));
+ }
+
+ public void header(Component component) {
+ this.components.addFirst(component);
+ }
+
+ public void footer(Component component) {
+ this.components.add(component);
+ }
+
+ public ImmutableList<Component> components() {
+ return ImmutableList.copyOf(this.components);
+ }
+}
diff --git a/src/main/java/me/samsuik/sakura/tps/graph/ComponentCanvas.java b/src/main/java/me/samsuik/sakura/tps/graph/ComponentCanvas.java
new file mode 100644
index 0000000000000000000000000000000000000000..42024655f1b1cad12ba1db66086bb978c5ee8f02
--- /dev/null
+++ b/src/main/java/me/samsuik/sakura/tps/graph/ComponentCanvas.java
@@ -0,0 +1,63 @@
+package me.samsuik.sakura.tps.graph;
+
+import com.google.common.base.Preconditions;
+import it.unimi.dsi.fastutil.objects.ObjectArrayList;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.JoinConfiguration;
+import org.jspecify.annotations.NullMarked;
+
+import java.util.List;
+
+@NullMarked
+public final class ComponentCanvas {
+ private final int width;
+ private final int height;
+ private final Component[][] components;
+
+ public ComponentCanvas(int width, int height) {
+ this.width = width;
+ this.height = height;
+ // [x, y] is flipped as it makes converting the components into a list easier
+ this.components = new Component[height][width];
+ }
+
+ public void flip() {
+ for (int y = 0; y < this.height; ++y) {
+ if (y >= this.height / 2) {
+ Component[] row = this.components[y];
+ int relocatingRow = this.height - 1 - y;
+ this.components[y] = this.components[relocatingRow];
+ this.components[relocatingRow] = row;
+ }
+ }
+ }
+
+ public void fill(Component component) {
+ for (int x = 0; x < this.width; ++x) {
+ for (int y = 0; y < this.height; ++y) {
+ this.set(x, y, component);
+ }
+ }
+ }
+
+ public Component get(int x, int y) {
+ Component component = this.components[y][x];
+ return Preconditions.checkNotNull(component, "missing component at x:{} y:{}", x, y);
+ }
+
+ public void set(int x, int y, Component component) {
+ this.components[y][x] = component;
+ }
+
+ public BuiltComponentCanvas build() {
+ return new BuiltComponentCanvas(this.joinComponents());
+ }
+
+ private List<Component> joinComponents() {
+ List<Component> componentList = new ObjectArrayList<>(this.height);
+ for (Component[] row : this.components) {
+ componentList.add(Component.join(JoinConfiguration.noSeparators(), row));
+ }
+ return componentList;
+ }
+}
diff --git a/src/main/java/me/samsuik/sakura/tps/graph/DetailedTPSGraph.java b/src/main/java/me/samsuik/sakura/tps/graph/DetailedTPSGraph.java
new file mode 100644
index 0000000000000000000000000000000000000000..bebc61d33a5cbb6a46c7f5ac0a9b453e0ab48655
--- /dev/null
+++ b/src/main/java/me/samsuik/sakura/tps/graph/DetailedTPSGraph.java
@@ -0,0 +1,102 @@
+package me.samsuik.sakura.tps.graph;
+
+import me.samsuik.sakura.tps.ServerTickInformation;
+import org.jspecify.annotations.NullMarked;
+
+import java.util.List;
+
+@NullMarked
+public final class DetailedTPSGraph extends TPSGraph {
+ public DetailedTPSGraph(int width, int height, double scale, List<ServerTickInformation> tickInformation) {
+ super(width, height, scale, tickInformation);
+ }
+
+ @Override
+ public BuiltComponentCanvas plot() {
+ ComponentCanvas canvas = new ComponentCanvas(this.width, this.height);
+ canvas.fill(GraphComponents.BACKGROUND);
+
+ this.basicOutline(canvas);
+ this.prettifyOutline(canvas);
+ this.addColourAndHoverInformation(canvas);
+
+ canvas.flip();
+ return canvas.build();
+ }
+
+ private void basicOutline(ComponentCanvas canvas) {
+ for (int x = 0; x < this.width; ++x) {
+ int row = this.rowFromColumn(x);
+ int nextRow = this.rowFromColumn(x + 1);
+ int minRow = Math.min(row, nextRow);
+ int maxRow = Math.max(row, nextRow);
+
+ if (maxRow - minRow >= 2) {
+ canvas.set(x, minRow, GraphComponents.TOP_DOTTED_LINE);
+ canvas.set(x, maxRow, GraphComponents.BOTTOM_DOTTED_LINE);
+
+ for (int y = minRow + 1; y < maxRow; ++y) {
+ canvas.set(x, y, GraphComponents.VERTICAL_LINE);
+ }
+ } else {
+ canvas.set(x, row, GraphComponents.HORIZONTAL_LINE);
+ }
+ }
+ }
+
+ private void prettifyOutline(ComponentCanvas canvas) {
+ for (int x = 0; x < this.width; ++x) {
+ int row = this.rowFromColumn(x);
+ int nextRow = this.rowFromColumn(x + 1);
+ int prevRow = this.rowFromColumn(x - 1);
+ int minRow = Math.min(row, nextRow);
+ int maxRow = Math.max(row, nextRow);
+
+ if (maxRow - minRow >= 2) {
+ this.prettifyVerticalOutline(canvas, x, row, nextRow, prevRow, minRow, maxRow);
+ } else {
+ this.prettifySlopes(canvas, x, row, nextRow, prevRow);
+ }
+ }
+ }
+
+ private void prettifyVerticalOutline(ComponentCanvas canvas, int x, int row, int nextRow, int prevRow, int minRow, int maxRow) {
+ if (minRow == nextRow) {
+ canvas.set(x, minRow, GraphComponents.CONE_BOTTOM_LEFT);
+ } else if (prevRow <= minRow) {
+ canvas.set(x, minRow, GraphComponents.CONE_BOTTOM_RIGHT);
+ }
+ if (prevRow == row + 1 && nextRow < row) {
+ canvas.set(x, maxRow, GraphComponents.CONE_TOP_RIGHT);
+ }
+ if (maxRow == row && Math.abs(nextRow - maxRow) > 1 && Math.abs(prevRow - maxRow) > 1 && prevRow < maxRow) {
+ canvas.set(x - 1, maxRow, GraphComponents.CONE_TOP_LEFT);
+ canvas.set(x, maxRow, GraphComponents.CONE_TOP_RIGHT);
+ }
+ if (minRow == row && Math.abs(nextRow - minRow) > 1 && Math.abs(prevRow - minRow) > 1 && prevRow > minRow) {
+ canvas.set(x - 1, minRow, GraphComponents.CONE_BOTTOM_LEFT);
+ canvas.set(x, minRow, GraphComponents.CONE_BOTTOM_RIGHT);
+ }
+ }
+
+ private void prettifySlopes(ComponentCanvas canvas, int x, int row, int nextRow, int prevRow) {
+ int slopeDirection = nextRow - prevRow;
+ int slopeChange = Math.abs(slopeDirection);
+
+ if (slopeChange >= 2 && Math.max(nextRow, prevRow) == row + 1) {
+ canvas.set(x, row, slopeDirection < 0 ? GraphComponents.TL_TO_BR : GraphComponents.BL_TO_TR);
+ } else if (Math.abs(row - nextRow) == 1 || slopeDirection == 0) {
+ if (row < nextRow) {
+ canvas.set(x, row, GraphComponents.TOP_DOTTED_LINE);
+ } else if (row > nextRow) {
+ canvas.set(x, row, GraphComponents.BOTTOM_DOTTED_LINE);
+ }
+ } else if (Math.abs(row - prevRow) == 1) {
+ if (prevRow > row) {
+ canvas.set(x, row, GraphComponents.TOP_DOTTED_LINE);
+ } else if (prevRow < row) {
+ canvas.set(x, row, GraphComponents.BOTTOM_DOTTED_LINE);
+ }
+ }
+ }
+}
diff --git a/src/main/java/me/samsuik/sakura/tps/graph/GraphComponents.java b/src/main/java/me/samsuik/sakura/tps/graph/GraphComponents.java
new file mode 100644
index 0000000000000000000000000000000000000000..95d3c8031e4708d2d0a0a12213060acd9ab65522
--- /dev/null
+++ b/src/main/java/me/samsuik/sakura/tps/graph/GraphComponents.java
@@ -0,0 +1,42 @@
+package me.samsuik.sakura.tps.graph;
+
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.format.NamedTextColor;
+import net.kyori.adventure.text.format.Style;
+import net.kyori.adventure.text.format.TextColor;
+import net.kyori.adventure.text.format.TextDecoration;
+
+import java.util.List;
+
+public final class GraphComponents {
+ private static final Style STRIKE_THROUGH_STYLE = Style.style(TextDecoration.STRIKETHROUGH);
+ private static final Style REMOVE_STRIKE_THROUGH_STYLE = Style.style(TextDecoration.STRIKETHROUGH.withState(false));
+
+ public static final Component BACKGROUND = Component.text("::");
+ public static final Component HORIZONTAL_LINE = Component.text(" ", STRIKE_THROUGH_STYLE);
+ public static final Component VERTICAL_LINE = Component.text("||");
+ public static final Component TOP_DOTTED_LINE = Component.text("''");
+ public static final Component BOTTOM_DOTTED_LINE = Component.text("..");
+ public static final Component BL_TO_TR = Component.text(".", STRIKE_THROUGH_STYLE).append(Component.text("'", REMOVE_STRIKE_THROUGH_STYLE));
+ public static final Component TL_TO_BR = Component.text("'").append(Component.text(".", STRIKE_THROUGH_STYLE));
+ public static final Component CONE_TOP_LEFT = Component.text(".!");
+ public static final Component CONE_TOP_RIGHT = Component.text("!.");
+ public static final Component CONE_BOTTOM_LEFT = Component.text("'!");
+ public static final Component CONE_BOTTOM_RIGHT = Component.text("!'");
+
+ private static final List<TextColor> COLOURS = List.of(
+ NamedTextColor.GREEN, NamedTextColor.YELLOW, NamedTextColor.GOLD,
+ NamedTextColor.RED, NamedTextColor.DARK_GRAY, TextColor.color(40, 40, 40)
+ );
+
+ public static TextColor colour(float num) {
+ float segment = 1.0f / COLOURS.size();
+ float a = (1.0f - num) / segment;
+ float t = a % 1.0f;
+ int startIndex = Math.clamp((int) a, 0, COLOURS.size() - 2);
+ int endIndex = startIndex + 1;
+ TextColor startColour = COLOURS.get(startIndex);
+ TextColor endColour = COLOURS.get(endIndex);
+ return TextColor.lerp(t, startColour, endColour);
+ }
+}
diff --git a/src/main/java/me/samsuik/sakura/tps/graph/TPSGraph.java b/src/main/java/me/samsuik/sakura/tps/graph/TPSGraph.java
new file mode 100644
index 0000000000000000000000000000000000000000..27b6b071ad38589d37e35ea7fdf1d45924079f49
--- /dev/null
+++ b/src/main/java/me/samsuik/sakura/tps/graph/TPSGraph.java
@@ -0,0 +1,60 @@
+package me.samsuik.sakura.tps.graph;
+
+import com.google.common.base.Preconditions;
+import me.samsuik.sakura.tps.ServerTickInformation;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.event.HoverEvent;
+import net.kyori.adventure.text.format.NamedTextColor;
+import net.kyori.adventure.text.format.TextColor;
+import net.minecraft.util.Mth;
+import org.jspecify.annotations.NullMarked;
+
+import java.util.List;
+
+@NullMarked
+public abstract class TPSGraph {
+ protected final List<ServerTickInformation> tickInformation;
+ protected final int width;
+ protected final int height;
+ protected final double scale;
+
+ public TPSGraph(int width, int height, double scale, List<ServerTickInformation> tickInformation) {
+ Preconditions.checkArgument(tickInformation.size() == width);
+ this.width = width;
+ this.height = height;
+ this.scale = scale;
+ this.tickInformation = tickInformation;
+ }
+
+ public abstract BuiltComponentCanvas plot();
+
+ protected final int rowFromColumn(int x) {
+ int clamped = Math.clamp(x, 0, this.width - 1);
+ ServerTickInformation tickInformation = this.tickInformation.get(clamped);
+ return this.rowFromTPS(tickInformation.tps());
+ }
+
+ protected final int rowFromTPS(double tps) {
+ int row = Mth.floor((tps / 3) * this.scale);
+ return Mth.clamp(row, 0, this.height - 1);
+ }
+
+ protected final void addColourAndHoverInformation(ComponentCanvas canvas) {
+ for (int x = 0; x < this.width; ++x) {
+ ServerTickInformation tickInformation = this.tickInformation.get(x);
+ TextColor colourFromTPS = tickInformation.colour();
+ Component hoverComponent = tickInformation.hoverComponent(colourFromTPS);
+ HoverEvent<Component> hoverEvent = HoverEvent.showText(hoverComponent);
+
+ for (int y = 0; y < this.height; ++y) {
+ Component component = canvas.get(x, y);
+ if (component == GraphComponents.BACKGROUND) {
+ component = component.color(NamedTextColor.BLACK);
+ } else {
+ component = component.color(colourFromTPS);
+ }
+ canvas.set(x, y, component.hoverEvent(hoverEvent));
+ }
+ }
+ }
+}
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 1d0462b970304f543ff949f7aa32c67a1860ba4f..733541e91b0064d50de6c5c0985e9c472685c20c 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -427,6 +427,17 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
}
}
// Paper end - rewrite chunk system
+ // Sakura start - track tick information
+ private final me.samsuik.sakura.tps.TickInformationCollector tickInformationCollector = new me.samsuik.sakura.tps.TickInformationCollector();
+
+ public final me.samsuik.sakura.tps.ServerTickInformation latestTickInformation() {
+ return this.tickInformationCollector.latestTickInformation();
+ }
+
+ public final ImmutableList<me.samsuik.sakura.tps.ServerTickInformation> tickHistory(long from, long to) {
+ return this.tickInformationCollector.collect(from, to);
+ }
+ // Sakura end - track tick information
public MinecraftServer(OptionSet options, WorldLoader.DataLoadContext worldLoader, Thread thread, LevelStorageSource.LevelStorageAccess convertable_conversionsession, PackRepository resourcepackrepository, WorldStem worldstem, Proxy proxy, DataFixer datafixer, Services services, ChunkProgressListenerFactory worldloadlistenerfactory) {
super("Server");
@@ -1301,6 +1312,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
if (++MinecraftServer.currentTick % MinecraftServer.SAMPLE_INTERVAL == 0) {
final long diff = currentTime - tickSection;
final java.math.BigDecimal currentTps = TPS_BASE.divide(new java.math.BigDecimal(diff), 30, java.math.RoundingMode.HALF_UP);
+ this.tickInformationCollector.levelData(this.levels.values(), currentTps.doubleValue()); // Sakura - track tick information
tps1.add(currentTps, diff);
tps5.add(currentTps, diff);
tps15.add(currentTps, diff);
@@ -1343,6 +1355,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
throw new RuntimeException("Chunk system crash propagated to tick()", crash);
}
// Paper end - rewrite chunk system
+ this.tickInformationCollector.tickDuration((System.nanoTime() - currentTime) / 1_000_000L); // Sakura - track tick information
this.tickFrame.end();
gameprofilerfiller.popPush("nextTickWait");
this.mayHaveDelayedTasks = true;
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 0c1587b8ccf05e7a0a5df5a64c483cee434e1c0f..e1f0da0b20ec310470160718338920bbd5b088de 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -201,7 +201,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
private final MinecraftServer server;
public final PrimaryLevelData serverLevelData; // CraftBukkit - type
private int lastSpawnChunkRadius;
- final EntityTickList entityTickList = new EntityTickList();
+ public final EntityTickList entityTickList = new EntityTickList(); // Sakura - package-private -> public
// Paper - rewrite chunk system
private final GameEventDispatcher gameEventDispatcher;
public boolean noSave;
diff --git a/src/main/java/net/minecraft/world/level/entity/EntityTickList.java b/src/main/java/net/minecraft/world/level/entity/EntityTickList.java
index d8b4196adf955f8d414688dc451caac2d9c609d9..0859aecb141261638b8547fb8854768fb6b6f5c7 100644
--- a/src/main/java/net/minecraft/world/level/entity/EntityTickList.java
+++ b/src/main/java/net/minecraft/world/level/entity/EntityTickList.java
@@ -9,7 +9,7 @@ import javax.annotation.Nullable;
import net.minecraft.world.entity.Entity;
public class EntityTickList {
- private final ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet<net.minecraft.world.entity.Entity> entities = new ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet<>(); // Paper - rewrite chunk system
+ public final ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet<net.minecraft.world.entity.Entity> entities = new ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet<>(); // Sakura - track tick information; expose entity list // Paper - rewrite chunk system
private void ensureActiveIsNotIterated() {
// Paper - rewrite chunk system
diff --git a/src/main/java/org/spigotmc/SpigotConfig.java b/src/main/java/org/spigotmc/SpigotConfig.java
index 4dbb109d0526afee99b9190fc256585121aac9b5..019ae7104a644f23495e42510a80573a7ac06a37 100644
--- a/src/main/java/org/spigotmc/SpigotConfig.java
+++ b/src/main/java/org/spigotmc/SpigotConfig.java
@@ -279,7 +279,7 @@ public class SpigotConfig
private static void tpsCommand()
{
- SpigotConfig.commands.put( "tps", new TicksPerSecondCommand( "tps" ) );
+ // SpigotConfig.commands.put( "tps", new TicksPerSecondCommand( "tps" ) ); // Sakura - TPS Graph
}
public static int playerSample;

View File

@@ -0,0 +1,58 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <kfian294ma4@gmail.com>
Date: Wed, 6 Oct 2021 17:25:27 +0100
Subject: [PATCH] Optimise New Liquid Level
diff --git a/src/main/java/net/minecraft/world/level/material/FlowingFluid.java b/src/main/java/net/minecraft/world/level/material/FlowingFluid.java
index f4fbcbb8ff6d2677af1a02a0801a323c06dce9b1..4613162b6e716e33a838c59171c486b9c4d4b097 100644
--- a/src/main/java/net/minecraft/world/level/material/FlowingFluid.java
+++ b/src/main/java/net/minecraft/world/level/material/FlowingFluid.java
@@ -181,7 +181,7 @@ public abstract class FlowingFluid extends Fluid {
FluidState fluid1 = iblockdata1.getFluidState();
if (this.canMaybePassThrough(world, fluidPos, blockState, Direction.DOWN, blockposition1, iblockdata1, fluid1)) {
- FluidState fluid2 = this.getNewLiquid(world, blockposition1, iblockdata1);
+ FluidState fluid2 = this.getLiquid(world, blockposition1, iblockdata1, fluidPos, blockState); // Sakura - optimise new liquid level
Fluid fluidtype = fluid2.getType();
if (fluid1.canBeReplacedWith(world, blockposition1, fluidtype, Direction.DOWN) && FlowingFluid.canHoldSpecificFluid(world, blockposition1, iblockdata1, fluidtype)) {
@@ -245,6 +245,23 @@ public abstract class FlowingFluid extends Fluid {
}
protected FluidState getNewLiquid(ServerLevel world, BlockPos pos, BlockState state) {
+ // Sakura start - optimise new liquid level
+ final BlockPos abovePos = pos.above();
+ final BlockState aboveState = world.getBlockState(abovePos);
+ return this.getLiquid(world, pos, state, abovePos, aboveState);
+ }
+
+ private FluidState getLiquid(final ServerLevel world, final BlockPos flowToPos, final BlockState flowToState, final BlockPos abovePos, final BlockState aboveState) {
+ final FluidState aboveFluid = aboveState.getFluidState();
+ if (!aboveFluid.isEmpty() && aboveFluid.getType().isSame(this) && FlowingFluid.canPassThroughWall(Direction.UP, world, flowToPos, flowToState, abovePos, aboveState)) {
+ return this.getFlowing(8, true);
+ } else {
+ return this.getLiquidFromSurroundings(world, flowToPos, flowToState);
+ }
+ }
+
+ private FluidState getLiquidFromSurroundings(final ServerLevel world, final BlockPos pos, final BlockState state) {
+ // Sakura start - optimise new liquid level
int i = 0;
int j = 0;
BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos();
@@ -275,13 +292,7 @@ public abstract class FlowingFluid extends Fluid {
}
}
- BlockPos.MutableBlockPos blockposition_mutableblockposition2 = blockposition_mutableblockposition.setWithOffset(pos, Direction.UP);
- BlockState iblockdata3 = world.getBlockState(blockposition_mutableblockposition2);
- FluidState fluid2 = iblockdata3.getFluidState();
-
- if (!fluid2.isEmpty() && fluid2.getType().isSame(this) && FlowingFluid.canPassThroughWall(Direction.UP, world, pos, state, blockposition_mutableblockposition2, iblockdata3)) {
- return this.getFlowing(8, true);
- } else {
+ { // Sakura - optimise new liquid level
int k = i - this.getDropOff(world);
return k <= 0 ? Fluids.EMPTY.defaultFluidState() : this.getFlowing(k, false);

View File

@@ -0,0 +1,238 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Cryptite <cryptite@gmail.com>
Date: Wed, 6 Oct 2021 11:03:01 -0500
Subject: [PATCH] (Slice) Packet obfuscation and reduction
Minecraft is overzealous about packet updates for Entities. In Loka's case, we want to reduce as many unnecessary
packet updates as possible. This patch is likely to be updated over and over in terms of reducing packet sends.
In summary, this patch creates the concept of a "foreignValue" of a packet's data. We treat packets in two ways:
1) The packet sent to the player itself (the normal way). This always has all of the values as usual.
2) The packet data as seen by any other (foreign) players.
This patch adds the ability to set a "foreignValue" for an entity value so as to obfuscate data received by other players.
The current packets modified/obfuscated are the following:
# This reduces the amount of health packet updates as well which is great for players in combat.
# Air level packets are sent PER-TICK, and as such a player with any change in air level will only spam themselves
# with packets instead of every single player within tracking distance
diff --git a/src/main/java/net/minecraft/network/syncher/SynchedEntityData.java b/src/main/java/net/minecraft/network/syncher/SynchedEntityData.java
index 0f99733660f91280e4c6262cf75b3c9cae86f65a..ba9f8fe6fafc54bbdfb104de28af4b392feb4483 100644
--- a/src/main/java/net/minecraft/network/syncher/SynchedEntityData.java
+++ b/src/main/java/net/minecraft/network/syncher/SynchedEntityData.java
@@ -22,6 +22,7 @@ public class SynchedEntityData {
private final SyncedDataHolder entity;
private final SynchedEntityData.DataItem<?>[] itemsById;
private boolean isDirty;
+ private boolean isForeignDirty; // Slice
SynchedEntityData(SyncedDataHolder trackedEntity, SynchedEntityData.DataItem<?>[] entries) {
this.entity = trackedEntity;
@@ -63,6 +64,16 @@ public class SynchedEntityData {
}
public <T> void set(EntityDataAccessor<T> key, T value, boolean force) {
+ // Slice start
+ this.set(key, value, null, force);
+ }
+
+ public <T> void set(EntityDataAccessor<T> key, T value, T foreignValue) {
+ this.set(key, value, foreignValue, false);
+ }
+
+ public <T> void set(EntityDataAccessor<T> key, T value, T foreignValue, boolean force) {
+ // Slice end
SynchedEntityData.DataItem<T> datawatcher_item = this.getItem(key);
if (force || ObjectUtils.notEqual(value, datawatcher_item.getValue())) {
@@ -72,6 +83,12 @@ public class SynchedEntityData {
this.isDirty = true;
}
+ // Slice start
+ if (foreignValue != null && ObjectUtils.notEqual(foreignValue, datawatcher_item.getForeignValue())) {
+ datawatcher_item.setForeignValue(foreignValue);
+ this.isForeignDirty = true;
+ }
+ // Slice end
}
// CraftBukkit start - add method from above
@@ -81,6 +98,12 @@ public class SynchedEntityData {
}
// CraftBukkit end
+ // Slice start
+ public boolean isForeignDirty() {
+ return this.isForeignDirty;
+ }
+ // Slice end
+
public boolean isDirty() {
return this.isDirty;
}
@@ -108,6 +131,29 @@ public class SynchedEntityData {
}
}
+ // Slice start
+ @Nullable
+ public List<SynchedEntityData.DataValue<?>> packForeignDirty(List<DataValue<?>> unpackedData) {
+ List<SynchedEntityData.DataValue<?>> list = null;
+
+ for (DataValue<?> dataItem : unpackedData) {
+ DataItem<?> item = this.itemsById[dataItem.id()];
+ if (item.isDirty(true)) {
+ item.setForeignDirty(false);
+
+ if (list == null) {
+ list = new ArrayList<>();
+ }
+
+ list.add(item.copy(true));
+ }
+ }
+
+ this.isForeignDirty = false;
+ return list;
+ }
+ // Slice end
+
@Nullable
public List<SynchedEntityData.DataValue<?>> getNonDefaultValues() {
List<SynchedEntityData.DataValue<?>> list = null;
@@ -171,11 +217,14 @@ public class SynchedEntityData {
T value;
private final T initialValue;
private boolean dirty;
+ @Nullable T foreignValue = null; // Slice
+ private boolean foreignDirty; // Slice
public DataItem(EntityDataAccessor<T> data, T value) {
this.accessor = data;
this.initialValue = value;
this.value = value;
+ this.foreignDirty = true; // Slice
}
public EntityDataAccessor<T> getAccessor() {
@@ -202,6 +251,35 @@ public class SynchedEntityData {
return this.initialValue.equals(this.value);
}
+ // Slice start
+ public void setForeignValue(T foreignValue) {
+ this.foreignValue = foreignValue;
+ this.foreignDirty = true;
+ }
+
+ public @Nullable T getForeignValue() {
+ return this.foreignValue;
+ }
+
+ public boolean isDirty(boolean foreign) {
+ if (foreign) {
+ //There must be a foreign value in order for this to be dirty, otherwise we consider this a normal
+ //value and check the normal dirty flag.
+ return this.foreignValue == null || this.foreignDirty;
+ }
+
+ return this.dirty;
+ }
+
+ public void setForeignDirty(boolean dirty) {
+ this.foreignDirty = dirty;
+ }
+
+ public SynchedEntityData.DataValue<T> copy(boolean foreign) {
+ return SynchedEntityData.DataValue.create(this.accessor, this.accessor.serializer().copy((foreign && this.foreignValue != null ? this.foreignValue : this.value)));
+ }
+ // Slice end
+
public SynchedEntityData.DataValue<T> value() {
return SynchedEntityData.DataValue.create(this.accessor, this.value);
}
diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java
index 103e2c414780be66324bcb9cd4ea539bbdfe12ad..8004c920f9709723c9f4fe1a430247b5ee1520f1 100644
--- a/src/main/java/net/minecraft/server/level/ServerEntity.java
+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java
@@ -156,7 +156,7 @@ public class ServerEntity {
}
}
- if (this.forceStateResync || this.tickCount % this.updateInterval == 0 || this.entity.hasImpulse || this.entity.getEntityData().isDirty()) { // Paper - fix desync when a player is added to the tracker
+ if (this.forceStateResync || this.tickCount % this.updateInterval == 0 || this.entity.hasImpulse || this.entity.getEntityData().isForeignDirty()) { // Slice // Paper - fix desync when a player is added to the tracker
byte b0 = Mth.packDegrees(this.entity.getYRot());
byte b1 = Mth.packDegrees(this.entity.getXRot());
boolean flag = Math.abs(b0 - this.lastSentYRot) >= 1 || Math.abs(b1 - this.lastSentXRot) >= 1;
@@ -449,7 +449,15 @@ public class ServerEntity {
if (list != null) {
this.trackedDataValues = datawatcher.getNonDefaultValues();
- this.broadcastAndSend(new ClientboundSetEntityDataPacket(this.entity.getId(), list));
+ // Slice start
+ if (!(this.entity instanceof ServerPlayer)) {
+ list = datawatcher.packForeignDirty(list);
+ }
+
+ if (list != null) {
+ this.broadcastAndSend(new ClientboundSetEntityDataPacket(this.entity.getId(), list));
+ }
+ // Slice end
}
if (this.entity instanceof LivingEntity) {
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 20980e5a180e0e7951d5c9a97b8b8f792c619b9a..384b64cfbc2fef49fa22baf1f640ea8f440093cd 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -3703,7 +3703,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
this.entityData.markDirty(Entity.DATA_AIR_SUPPLY_ID);
return;
}
- this.entityData.set(Entity.DATA_AIR_SUPPLY_ID, event.getAmount());
+ this.entityData.set(Entity.DATA_AIR_SUPPLY_ID, event.getAmount(), getMaxAirSupply()); // Slice
// CraftBukkit end
}
diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
index 20fa9a70f2d51aaa7f9ea01150d65c1f73caa374..81d02da6afd4b77c0ca60e9c8c5100ce6988753c 100644
--- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
+++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
@@ -124,7 +124,7 @@ public class FallingBlockEntity extends Entity {
}
public void setStartPos(BlockPos pos) {
- this.entityData.set(FallingBlockEntity.DATA_START_POS, pos);
+ this.entityData.set(FallingBlockEntity.DATA_START_POS, pos, BlockPos.ZERO); // Slice
}
public BlockPos getStartPos() {
diff --git a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
index 539219a4117c67278461ee483a457c005e6edcfc..46b729ecf0c58bdbe7a4717e73b098dcffd910f1 100644
--- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
+++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
@@ -217,7 +217,7 @@ public class PrimedTnt extends Entity implements TraceableEntity {
}
public void setFuse(int fuse) {
- this.entityData.set(PrimedTnt.DATA_FUSE_ID, fuse);
+ this.entityData.set(PrimedTnt.DATA_FUSE_ID, fuse, (fuse / 10) * 10); // Slice
}
public int getFuse() {
diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java
index 5b8b85a295a08ae495f729c595b3a78778965342..99133ad27aac31f68101aff4a4c4965c7ff1fd6b 100644
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
@@ -679,7 +679,7 @@ public abstract class Player extends LivingEntity {
public void increaseScore(int score) {
int j = this.getScore();
- this.entityData.set(Player.DATA_SCORE_ID, j + score);
+ this.entityData.set(Player.DATA_SCORE_ID, j + score, 0); // Slice
}
public void startAutoSpinAttack(int riptideTicks, float riptideAttackDamage, ItemStack stack) {

View File

@@ -0,0 +1,19 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
Date: Thu, 3 Aug 2023 12:54:52 +0100
Subject: [PATCH] Use Optimised TrackedEntityMap
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index 464fc90376075ecc46f7b7731ba5e2c705324e7d..dff0b8a1f2afcef21ca7e7aea3ee635826a2e9ef 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -187,7 +187,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
this.toDrop = new LongOpenHashSet();
this.tickingGenerated = new AtomicInteger();
this.playerMap = new PlayerMap();
- this.entityMap = new Int2ObjectOpenHashMap();
+ this.entityMap = new me.samsuik.sakura.utils.collections.TrackedEntityChunkMap(); // Sakura - optimised tracked entity map
this.chunkTypeCache = new Long2ByteOpenHashMap();
// Paper - rewrite chunk system
Path path = session.getDimensionPath(world.dimension());

View File

@@ -0,0 +1,81 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <kfian294ma4@gmail.com>
Date: Thu, 14 Oct 2021 19:16:49 +0100
Subject: [PATCH] Copy EntityList methods to BasicEntityList
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
index d21ce54ebb5724c04eadf56a2cde701d5eeb5db2..1fad004f07270e8a27a85557de6fcf5e693751db 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
@@ -383,6 +383,13 @@ public final class ChunkEntitySlices {
private E[] storage;
private int size;
+ // Sakura start - use methods from EntityList
+ private it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap entityToIndex = null;
+ private void setupIndexMap() {
+ this.entityToIndex = new it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap(2, 0.8f);
+ this.entityToIndex.defaultReturnValue(Integer.MIN_VALUE);
+ }
+ // Sakura end - use methods from EntityList
public BasicEntityList() {
this(0);
@@ -403,6 +410,7 @@ public final class ChunkEntitySlices {
private void resize() {
if (this.storage == EMPTY) {
this.storage = (E[])new Entity[DEFAULT_CAPACITY];
+ this.setupIndexMap(); // Sakura - use methods from EntityList
} else {
this.storage = Arrays.copyOf(this.storage, this.storage.length * 2);
}
@@ -416,6 +424,7 @@ public final class ChunkEntitySlices {
} else {
this.storage[idx] = entity;
}
+ this.entityToIndex.put(entity.getId(), idx); // Sakura - use methods from EntityList
}
public int indexOf(final E entity) {
@@ -431,24 +440,32 @@ public final class ChunkEntitySlices {
}
public boolean remove(final E entity) {
- final int idx = this.indexOf(entity);
- if (idx == -1) {
+ // Sakura start - use methods from EntityList
+ if (this.entityToIndex == null) {
return false;
}
- final int size = --this.size;
- final E[] storage = this.storage;
- if (idx != size) {
- System.arraycopy(storage, idx + 1, storage, idx, size - idx);
+ final int index = this.entityToIndex.remove(entity.getId());
+ if (index == Integer.MIN_VALUE) {
+ return false;
}
- storage[size] = null;
+ // move the entity at the end to this index
+ final int endIndex = --this.size;
+ final E end = this.storage[endIndex];
+ if (index != endIndex) {
+ // not empty after this call
+ this.entityToIndex.put(end.getId(), index); // update index
+ }
+ this.storage[index] = end;
+ this.storage[endIndex] = null;
+ // Sakura end - use methods from EntityList
return true;
}
public boolean has(final E entity) {
- return this.indexOf(entity) != -1;
+ return this.entityToIndex != null && this.entityToIndex.containsKey(entity.getId()); // Sakura - use methods from EntityList
}
}

View File

@@ -0,0 +1,42 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
Date: Thu, 3 Aug 2023 13:48:27 +0100
Subject: [PATCH] Add utility methods to EntitySlices
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
index 1fad004f07270e8a27a85557de6fcf5e693751db..39148fe540d616cdd4d63c4d1a02b422cab0f6eb 100644
--- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
@@ -297,6 +297,12 @@ public final class ChunkEntitySlices {
return true;
}
+ // Sakura start - add utility methods to entity slices
+ public Entity[] getSectionEntities(int sectionY) {
+ return this.allEntities.getSectionEntities(sectionY);
+ }
+ // Sakura end - add utility methods to entity slices
+
public void getHardCollidingEntities(final Entity except, final AABB box, final List<Entity> into, final Predicate<? super Entity> predicate) {
this.hardCollidingEntities.getEntities(except, box, into, predicate);
}
@@ -512,6 +518,18 @@ public final class ChunkEntitySlices {
}
}
+ // Sakura start - add utility methods to entity slices
+ public Entity[] getSectionEntities(int sectionY) {
+ BasicEntityList<Entity> list = this.entitiesBySection[sectionY - this.slices.minSection];
+
+ if (list != null) {
+ return list.storage;
+ }
+
+ return new Entity[0];
+ }
+ // Sakura end - add utility methods to entity slices
+
public void getEntities(final Entity except, final AABB box, final List<Entity> into, final Predicate<? super Entity> predicate) {
if (this.count == 0) {
return;

View File

@@ -0,0 +1,50 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
Date: Fri, 13 Oct 2023 20:02:04 +0100
Subject: [PATCH] Entity pushed by fluid API
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 953aa1b3d292dd8e8ed29926c269e6d6e79a83c0..b1ae26d08f12aadea37e44221c44db6430a3a99c 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -622,6 +622,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
}
}
// Sakura end - merge cannon entities
+ public boolean pushedByFluid = true; // Sakura - entity pushed by fluid api
public Entity(EntityType<?> type, Level world) {
this.id = Entity.ENTITY_COUNTER.incrementAndGet();
@@ -4480,7 +4481,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
}
public boolean isPushedByFluid() {
- return true;
+ return this.pushedByFluid; // Sakura - entity pushed by fluid api
}
public static double getViewScale() {
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
index b25b10c24a379097233e61bcc10add841b6a7115..4f4c708361160461bb472dcc79751fa29c5274b9 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
@@ -204,6 +204,18 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
return this.entity.isInWater();
}
+ // Sakura start - entity pushed by fluid api
+ @Override
+ public boolean isPushedByFluid() {
+ return this.getHandle().isPushedByFluid();
+ }
+
+ @Override
+ public void setPushedByFluid(boolean push) {
+ this.getHandle().pushedByFluid = push;
+ }
+ // Sakura end - entity pushed by fluid api
+
@Override
public World getWorld() {
return this.entity.level().getWorld();

View File

@@ -0,0 +1,88 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
Date: Sun, 15 Oct 2023 22:48:35 +0100
Subject: [PATCH] Cannon Mechanics
diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
index 32811e9d925911864e0c0fa5a2e25031098f423e..e6e38c5f2922989c8616d0cf0bd7bd32403ea863 100644
--- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
+++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
@@ -72,6 +72,7 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti
public boolean forceTickAfterTeleportToDuplicate;
protected static final EntityDataAccessor<BlockPos> DATA_START_POS = SynchedEntityData.defineId(FallingBlockEntity.class, EntityDataSerializers.BLOCK_POS);
public boolean autoExpire = true; // Paper - Expand FallingBlock API
+ public boolean heightParity; // Sakura - configure cannon mechanics
// Sakura start - merge cannon entities
private final me.samsuik.sakura.entity.merge.MergeEntityData mergeData = new me.samsuik.sakura.entity.merge.MergeEntityData(this);
@@ -133,6 +134,7 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti
this.isFallingBlock = true; // Sakura
this.loadChunks = world.sakuraConfig().cannons.loadChunks; // Sakura - load chunks on movement
this.mergeData.setMergeLevel(world.sakuraConfig().cannons.mergeLevel); // Sakura - merge cannon entities
+ this.heightParity = world.sakuraConfig().cannons.mechanics.fallingBlockParity; // Sakura - configure cannon mechanics
}
public FallingBlockEntity(Level world, double x, double y, double z, BlockState block) {
@@ -199,6 +201,13 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti
return !this.isRemoved();
}
+ // Sakura start - configure cannon mechanics
+ @Override
+ public final double getEyeY() {
+ return this.heightParity ? this.getY() : super.getEyeY();
+ }
+ // Sakura end - configure cannon mechanics
+
@Override
protected double getDefaultGravity() {
return 0.04D;
diff --git a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
index 7bb55565208b99db095c5842a7e21fd21700173e..93cf290b25d569820dd1bf9b4b5fb255abdbd8cd 100644
--- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
+++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
@@ -102,6 +102,12 @@ public class PrimedTnt extends Entity implements TraceableEntity, me.samsuik.sak
this.yo = y;
this.zo = z;
this.owner = igniter;
+ // Sakura start - configure cannon mechanics
+ switch (world.sakuraConfig().cannons.mechanics.tntSpread) {
+ case NONE -> this.setDeltaMovement(0.0, 0.0, 0.0);
+ case Y -> this.setDeltaMovement(this.getDeltaMovement().multiply(0.0, 1.0, 0.0));
+ }
+ // Sakura end - configure cannon mechanics
}
@Override
@@ -286,7 +292,7 @@ public class PrimedTnt extends Entity implements TraceableEntity, me.samsuik.sak
// Paper start - Option to prevent TNT from moving in water
@Override
public boolean isPushedByFluid() {
- return !level().paperConfig().fixes.preventTntFromMovingInWater && super.isPushedByFluid();
+ return !level().paperConfig().fixes.preventTntFromMovingInWater && level().sakuraConfig().cannons.mechanics.tntFlowsInWater && super.isPushedByFluid(); // Sakura - configure cannon mechanics
}
// Paper end - Option to prevent TNT from moving in water
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java
index 55f67c2ca07eca0d3e1522eebbb4ce37704bdd04..2de0befc3948a23910cfc609fc25c57bbd0cb030 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java
@@ -35,6 +35,17 @@ public class CraftFallingBlock extends CraftEntity implements FallingBlock {
this.getHandle().getMergeEntityData().setCount(stacked);
}
// Sakura end - merge cannon entities
+ // Sakura start - cannon mechanics
+ @Override
+ public void setHeightParity(boolean parity) {
+ this.getHandle().heightParity = parity;
+ }
+
+ @Override
+ public boolean getHeightParity() {
+ return this.getHandle().heightParity;
+ }
+ // Sakura end - cannon mechanics
@Override
public FallingBlockEntity getHandle() {

View File

@@ -0,0 +1,41 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
Date: Mon, 16 Oct 2023 22:41:12 +0100
Subject: [PATCH] Cache MovingBlockEntity collision shape
diff --git a/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java b/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
index e1c9a961064887070b29207efd7af47884f8dc29..f873061666cf7ba30b2b5dfe3b3a1ea85d2cdd4f 100644
--- a/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
@@ -43,6 +43,11 @@ public class PistonMovingBlockEntity extends BlockEntity {
private float progressO;
private long lastTicked;
private int deathTicks;
+ // Sakura start
+ private VoxelShape collisionShape = Shapes.empty();
+ private Direction shapeDirection = null;
+ private float shapeProgress = Float.MIN_VALUE;
+ // Sakura end
public PistonMovingBlockEntity(BlockPos pos, BlockState state) {
super(BlockEntityType.PISTON, pos, state);
@@ -358,6 +363,18 @@ public class PistonMovingBlockEntity extends BlockEntity {
}
public VoxelShape getCollisionShape(BlockGetter world, BlockPos pos) {
+ // Sakura start
+ var direction = NOCLIP.get();
+ if (progress == shapeProgress && direction == shapeDirection) {
+ return collisionShape;
+ } else {
+ shapeProgress = progress;
+ shapeDirection = direction;
+ return collisionShape = createCollisionShape(world, pos);
+ }
+ }
+ private VoxelShape createCollisionShape(BlockGetter world, BlockPos pos) {
+ // Sakura end
VoxelShape voxelShape;
if (!this.extending && this.isSourcePiston && this.movedState.getBlock() instanceof PistonBaseBlock) {
voxelShape = this.movedState.setValue(PistonBaseBlock.EXTENDED, Boolean.valueOf(true)).getCollisionShape(world, pos);

View File

@@ -0,0 +1,45 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
Date: Mon, 16 Oct 2023 22:57:55 +0100
Subject: [PATCH] Optimise TNT fluid state
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index b1ae26d08f12aadea37e44221c44db6430a3a99c..a56517cb6628939e6eed4b26e5e7f8bf6fc1c7af 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -2256,7 +2256,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
return this.isInWater() || flag;
}
- void updateInWaterStateAndDoWaterCurrentPushing() {
+ protected void updateInWaterStateAndDoWaterCurrentPushing() { // Sakura
Entity entity = this.getVehicle();
if (entity instanceof AbstractBoat abstractboat) {
diff --git a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
index 712ac847cf5fbb01133da2630f942afc69c79672..00801a9396e3c128730fe75c287d7b29ad0a00df 100644
--- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
+++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
@@ -126,6 +126,21 @@ public class PrimedTnt extends Entity implements TraceableEntity, me.samsuik.sak
return !this.isRemoved();
}
+ // Sakura start - optimise tnt fluid state
+ @Override
+ protected boolean updateInWaterStateAndDoFluidPushing() {
+ if (this.isPushedByFluid()) {
+ return super.updateInWaterStateAndDoFluidPushing();
+ } else {
+ // super method also handles lava fluid pushing
+ // we only need to search for water to negate fall distance
+ this.fluidHeight.clear();
+ this.updateInWaterStateAndDoWaterCurrentPushing();
+ return this.isInWater();
+ }
+ }
+ // Sakura end - optimise tnt fluid state
+
@Override
protected double getDefaultGravity() {
return 0.04D;

View File

@@ -0,0 +1,19 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
Date: Wed, 15 Nov 2023 13:04:16 +0000
Subject: [PATCH] Despawn falling blocks inside moving pistons
diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
index e6e38c5f2922989c8616d0cf0bd7bd32403ea863..2f719d88d292fdf8e9fe51e3445b49e2ecc71e29 100644
--- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
+++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
@@ -255,7 +255,7 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti
}
}
- if (!this.onGround() && !flag1) {
+ if (!this.onGround() && !flag1 || this.level().sakuraConfig().cannons.sand.despawnInsideMovingPistons && autoExpire && this.time > 600) { // Sakura - allow falling blocks to despawn inside moving pistons
if ((this.time > 100 && autoExpire) && (blockposition.getY() <= this.level().getMinY() || blockposition.getY() > this.level().getMaxY()) || (this.time > 600 && autoExpire)) { // Paper - Expand FallingBlock API
if (this.dropItem && worldserver.getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS)) {
this.spawnAtLocation(worldserver, (ItemLike) block);

View File

@@ -0,0 +1,130 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
Date: Wed, 15 Nov 2023 20:52:56 +0000
Subject: [PATCH] Configure Entity Knockback
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 01179c4b01aa4898d08b392bd682587e3858b822..f1560f5139b3090057950b41c4374ded4c50b3e2 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -1572,7 +1572,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
}
// Paper end - Check distance in entity interactions
- this.knockback(0.4000000059604645D, d0, d1, entity1, entity1 == null ? io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.DAMAGE : io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK); // CraftBukkit // Paper - knockback events
+ this.knockback((float) this.level().sakuraConfig().players.knockback.baseKnockback, d0, d1, entity1, entity1 == null ? io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.DAMAGE : io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK); // CraftBukkit // Paper - knockback events // Sakura - configure entity knockback
if (!flag) {
this.indicateDamage(d0, d1);
}
@@ -1685,7 +1685,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
}
protected void blockedByShield(LivingEntity target) {
- target.knockback(0.5D, target.getX() - this.getX(), target.getZ() - this.getZ(), this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.SHIELD_BLOCK); // CraftBukkit // Paper - fix attacker & knockback events
+ target.knockback((float) this.level().sakuraConfig().players.knockback.shieldHitKnockback, target.getX() - this.getX(), target.getZ() - this.getZ(), this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.SHIELD_BLOCK); // CraftBukkit // Paper - fix attacker & knockback events // Sakura - configure entity knockback
}
private boolean checkTotemDeathProtection(DamageSource source) {
@@ -2035,7 +2035,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
}
public void knockback(double d0, double d1, double d2, @Nullable Entity attacker, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause cause) { // Paper - knockback events
- d0 *= 1.0D - this.getAttributeValue(Attributes.KNOCKBACK_RESISTANCE);
+ d0 *= 1.0D - this.getAttributeValue(Attributes.KNOCKBACK_RESISTANCE) * this.level().sakuraConfig().players.knockback.knockbackResistanceModifier; // Sakura - configure entity knockback
if (true || d0 > 0.0D) { // CraftBukkit - Call event even when force is 0
//this.hasImpulse = true; // CraftBukkit - Move down
@@ -2046,9 +2046,21 @@ public abstract class LivingEntity extends Entity implements Attackable {
}
Vec3 vec3d1 = (new Vec3(d1, 0.0D, d2)).normalize().scale(d0);
+ // Sakura start - configure entity knockback
+ double velocityX = vec3d.x / 2.0D - vec3d1.x;
+ double velocityY = vec3d.y / 2.0D + this.level().sakuraConfig().players.knockback.knockbackVertical.or(d0);
+ double velocityZ = vec3d.z / 2.0D - vec3d1.z;
+
+ // this.onGround() ? Math.min(0.4D, vec3d.y / 2.0D + d0) : vec3d.y
+ if (!this.level().sakuraConfig().players.knockback.verticalKnockbackRequireGround || this.onGround()) {
+ velocityY = Math.min(this.level().sakuraConfig().players.knockback.knockbackVerticalLimit, velocityY);
+ } else {
+ velocityY = vec3d.y;
+ }
+ // Sakura end - configure entity knockback
// Paper start - knockback events
- Vec3 finalVelocity = new Vec3(vec3d.x / 2.0D - vec3d1.x, this.onGround() ? Math.min(0.4D, vec3d.y / 2.0D + d0) : vec3d.y, vec3d.z / 2.0D - vec3d1.z);
+ Vec3 finalVelocity = new Vec3(velocityX, velocityY, velocityZ); // Sakura - configure entity knockback
Vec3 diff = finalVelocity.subtract(vec3d);
io.papermc.paper.event.entity.EntityKnockbackEvent event = CraftEventFactory.callEntityKnockbackEvent((org.bukkit.craftbukkit.entity.CraftLivingEntity) this.getBukkitEntity(), attacker, attacker, cause, d0, diff);
// Paper end - knockback events
diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java
index 99133ad27aac31f68101aff4a4c4965c7ff1fd6b..d11f67157c1bf8c14776c56748de3588273c7d45 100644
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
@@ -200,6 +200,7 @@ public abstract class Player extends LivingEntity {
private int currentImpulseContextResetGraceTime;
public boolean affectsSpawning = true; // Paper - Affects Spawning API
public net.kyori.adventure.util.TriState flyingFallDamage = net.kyori.adventure.util.TriState.NOT_SET; // Paper - flying fall damage
+ private long lastSprintKnockback = -1; // Sakura - configure entity knockback
// CraftBukkit start
public boolean fauxSleeping;
@@ -1264,7 +1265,7 @@ public abstract class Player extends LivingEntity {
boolean flag = f2 > 0.9F;
boolean flag1;
- if (this.isSprinting() && flag) {
+ if (this.isSprinting() && (!this.level().sakuraConfig().players.knockback.sprinting.requireFullAttack || flag)) { // Sakura - configure entity knockback
sendSoundEffect(this, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_KNOCKBACK, this.getSoundSource(), 1.0F, 1.0F); // Paper - send while respecting visibility
flag1 = true;
} else {
@@ -1307,7 +1308,21 @@ public abstract class Player extends LivingEntity {
float f5 = this.getKnockback(target, damagesource) + (flag1 ? 1.0F : 0.0F);
if (f5 > 0.0F) {
- if (target instanceof LivingEntity) {
+ // Sakura start - configure entity knockback; extra sprinting knockback
+ long millis = System.currentTimeMillis();
+ long sinceLastKnockback = millis - this.lastSprintKnockback;
+ if (flag1) { // attackHasExtraKnockback
+ double knockbackToApply = 0.0;
+ if (sinceLastKnockback >= this.level().sakuraConfig().players.knockback.sprinting.knockbackDelay.value().orElse(0)) {
+ knockbackToApply = this.level().sakuraConfig().players.knockback.sprinting.extraKnockback;
+ this.lastSprintKnockback = millis;
+ }
+ f5 = (f5 - 1.0f) + ((float) knockbackToApply * 2.0f);
+ }
+ if (f5 == 0.0f) {
+ // required
+ } else if (target instanceof LivingEntity) {
+ // Sakura end - configure entity knockback; extra sprinting knockback
LivingEntity entityliving1 = (LivingEntity) target;
entityliving1.knockback((double) (f5 * 0.5F), (double) Mth.sin(this.getYRot() * 0.017453292F), (double) (-Mth.cos(this.getYRot() * 0.017453292F)), this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK); // Paper - knockback events
@@ -1340,7 +1355,7 @@ public abstract class Player extends LivingEntity {
continue;
}
// CraftBukkit end
- entityliving2.knockback(0.4000000059604645D, (double) Mth.sin(this.getYRot() * 0.017453292F), (double) (-Mth.cos(this.getYRot() * 0.017453292F)), this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.SWEEP_ATTACK); // CraftBukkit // Paper - knockback events
+ entityliving2.knockback((float) this.level().sakuraConfig().players.knockback.sweepingEdgeKnockback, (double) Mth.sin(this.getYRot() * 0.017453292F), (double) (-Mth.cos(this.getYRot() * 0.017453292F)), this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.SWEEP_ATTACK); // Sakura - configure entity knockback // CraftBukkit // Paper - knockback events
// entityliving2.hurt(damagesource, f7); // CraftBukkit - moved up
Level world = this.level();
diff --git a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java
index 5e6ceb3c3728c0c08a516566c70a5c0d72d59196..1cc44f6626dfff7724e2ea1b41917ae4715b8d4d 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java
@@ -304,6 +304,12 @@ public class FishingHook extends Projectile {
this.setHookedEntity(entityHitResult.getEntity());
}
+ // Sakura start - configure entity knockback
+ if (this.level().sakuraConfig().players.knockback.fishingHooksApplyKnockback) {
+ Entity entity = entityHitResult.getEntity();
+ entity.hurt(this.damageSources().thrown(this, this.getOwner()), 0.0f);
+ }
+ // Sakura end - configure entity knockback
}
@Override

View File

@@ -0,0 +1,19 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
Date: Thu, 16 Nov 2023 20:53:51 +0000
Subject: [PATCH] Falling Block Stacking Restrictions
diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
index 2f719d88d292fdf8e9fe51e3445b49e2ecc71e29..890f1d6f8ad740afb0b30208f7cd42594e4c9d20 100644
--- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
+++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
@@ -273,7 +273,7 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti
boolean flag3 = FallingBlock.isFree(this.level().getBlockState(blockposition.below())) && (!flag || !flag1);
boolean flag4 = this.blockState.canSurvive(this.level(), blockposition) && !flag3;
- if (flag2 && flag4) {
+ if (flag2 && flag4 && level().sakuraConfig().cannons.sand.isFallingBlockInBounds(this)) { // Sakura
if (this.blockState.hasProperty(BlockStateProperties.WATERLOGGED) && this.level().getFluidState(blockposition).getType() == Fluids.WATER) {
this.blockState = (BlockState) this.blockState.setValue(BlockStateProperties.WATERLOGGED, true);
}

View File

@@ -0,0 +1,22 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Hermelijn15 <j.s.dekker-1@student.utwente.nl>
Date: Fri, 17 Nov 2023 20:09:03 +0100
Subject: [PATCH] Added list of ItemEntity's that ignore explosions
diff --git a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
index 0f086af57a5ff08c264dcbf89a8c3931ec73a609..d9a6324eeb0cfaef3d0bbff884ddfadc6e4132f7 100644
--- a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
+++ b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
@@ -410,6 +410,11 @@ public class ItemEntity extends Entity implements TraceableEntity {
@Override
public boolean ignoreExplosion(Explosion explosion) {
+ // Sakura start - add list of items that ignore explosions
+ if (this.level().sakuraConfig().entity.items.explosionResistantItems.contains(this.getItem().getItem())) {
+ return true;
+ }
+ // Sakura end - add list of items that ignore explosions
return explosion.shouldAffectBlocklikeEntities() ? super.ignoreExplosion(explosion) : true;
}

View File

@@ -0,0 +1,19 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
Date: Sat, 18 Nov 2023 15:12:14 +0000
Subject: [PATCH] Add option to disable entity ai
diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java
index 5a0b51342f4a646101f4588697bcae7d1ca8a010..700a690321fb08e0ce594505e6cc6f3b81d86995 100644
--- a/src/main/java/net/minecraft/world/entity/Mob.java
+++ b/src/main/java/net/minecraft/world/entity/Mob.java
@@ -910,7 +910,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
protected final void serverAiStep() {
++this.noActionTime;
// Paper start - Allow nerfed mobs to jump and float
- if (!this.aware) {
+ if (!this.aware || this.level().sakuraConfig().entity.disableMobAi) { // Sakura - add option to disable entity ai
if (goalFloat != null) {
if (goalFloat.canUse()) goalFloat.tick();
this.getJumpControl().tick();

View File

@@ -0,0 +1,35 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
Date: Mon, 20 Nov 2023 19:32:31 +0000
Subject: [PATCH] Consistent Explosion Radius
diff --git a/src/main/java/net/minecraft/world/level/ServerExplosion.java b/src/main/java/net/minecraft/world/level/ServerExplosion.java
index cc97e3a88ea99362ec043edf13c1f54c2c75daaa..1a912813ab7fa112379876ea1d4c903afe45c069 100644
--- a/src/main/java/net/minecraft/world/level/ServerExplosion.java
+++ b/src/main/java/net/minecraft/world/level/ServerExplosion.java
@@ -412,6 +412,7 @@ public class ServerExplosion implements Explosion {
return this.damageCalculator.getBlockExplosionResistance(this, this.level, pos, blockState, fluidState);
}
// Sakura end - explosion durable blocks
+ private final boolean consistentRadius; // Sakura - consistent explosion radius
public ServerExplosion(ServerLevel world, @Nullable Entity entity, @Nullable DamageSource damageSource, @Nullable ExplosionDamageCalculator behavior, Vec3 pos, float power, boolean createFire, Explosion.BlockInteraction destructionType) {
this.level = world;
@@ -423,6 +424,7 @@ public class ServerExplosion implements Explosion {
this.damageSource = damageSource == null ? world.damageSources().explosion(this) : damageSource;
this.damageCalculator = behavior == null ? this.makeDamageCalculator(entity) : behavior;
this.yield = this.blockInteraction == Explosion.BlockInteraction.DESTROY_WITH_DECAY ? 1.0F / this.radius : 1.0F; // CraftBukkit
+ this.consistentRadius = world.localConfig().config(BlockPos.containing(this.center)).consistentRadius; // Sakura - consistent explosion radius
}
private ExplosionDamageCalculator makeDamageCalculator(@Nullable Entity entity) {
@@ -533,7 +535,7 @@ public class ServerExplosion implements Explosion {
ray += 3;
- float power = this.radius * (0.7F + this.level.random.nextFloat() * 0.6F);
+ float power = this.radius * (0.7F + (this.consistentRadius ? 0.7F : this.level.random.nextFloat()) * 0.6F); // Sakura - consistent explosion radius
do {
final int blockX = Mth.floor(currX);

View File

@@ -0,0 +1,19 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
Date: Tue, 21 Nov 2023 10:56:30 +0000
Subject: [PATCH] Remove spigot max tnt per tick
diff --git a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
index f2206e57c04d29ed470ae2083b25ab502144ccb1..3e4935f4a07fa14152d1f55f069c49fdd2f3bc02 100644
--- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
+++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
@@ -148,7 +148,7 @@ public class PrimedTnt extends Entity implements TraceableEntity, me.samsuik.sak
@Override
public void tick() {
- if (this.level().spigotConfig.maxTntTicksPerTick > 0 && ++this.level().spigotConfig.currentPrimedTnt > this.level().spigotConfig.maxTntTicksPerTick) { return; } // Spigot
+ // Sakura - remove max tnt per tick
this.handlePortal();
this.applyGravity();
this.moveStripped(MoverType.SELF, this.getDeltaMovement()); // Sakura - optimise cannon entity movement

View File

@@ -0,0 +1,19 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
Date: Tue, 21 Nov 2023 11:21:37 +0000
Subject: [PATCH] Option to configure entity water sensitivity
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index f1560f5139b3090057950b41c4374ded4c50b3e2..e7603a67c985ff105a8a4e16179fe33fe26f5b22 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -3730,7 +3730,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
// Paper end - Add EntityMoveEvent
world = this.level();
if (world instanceof ServerLevel worldserver) {
- if (this.isSensitiveToWater() && this.isInWaterRainOrBubble()) {
+ if (this.level().sakuraConfig().entity.waterSensitivity && this.isSensitiveToWater() && this.isInWaterRainOrBubble()) { // Sakura - configure entity water sensitivity
this.hurtServer(worldserver, this.damageSources().drown(), 1.0F);
}
}

View File

@@ -0,0 +1,58 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
Date: Wed, 29 Nov 2023 22:32:44 +0000
Subject: [PATCH] Add redstone implementation API
diff --git a/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java b/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java
index 5d847016f6ee2d6340d8b2234ed35c3b9228632b..5fae13db49b60ea32e046aff64059a08ce626e3f 100644
--- a/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java
@@ -300,7 +300,7 @@ public class RedStoneWireBlock extends Block {
* Note: Added 'source' argument so as to help determine direction of information flow
*/
private void updateSurroundingRedstone(Level worldIn, BlockPos pos, BlockState state, @Nullable Orientation orientation, boolean blockAdded) {
- if (worldIn.paperConfig().misc.redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.EIGENCRAFT) {
+ if (worldIn.localConfig().config(pos).redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.EIGENCRAFT) { // Sakura - redstone implementation api
// since 24w33a the source pos is no longer given, but instead an Orientation parameter
// when this is not null, it can be used to find the source pos, which the turbo uses
// to find the direction of information flow
@@ -373,7 +373,7 @@ public class RedStoneWireBlock extends Block {
protected void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean notify) {
if (!oldState.is(state.getBlock()) && !world.isClientSide) {
// Paper start - optimize redstone - replace call to updatePowerStrength
- if (world.paperConfig().misc.redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT) {
+ if (world.localConfig().config(pos).redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT) { // Sakura - redstone implementation api
world.getWireHandler().onWireAdded(pos, state); // Alternate Current
} else {
this.updateSurroundingRedstone(world, pos, state, null, true); // Vanilla/Eigencraft
@@ -398,7 +398,7 @@ public class RedStoneWireBlock extends Block {
}
// Paper start - optimize redstone - replace call to updatePowerStrength
- if (world.paperConfig().misc.redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT) {
+ if (world.localConfig().config(pos).redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT) { // Sakura - redstone implementation api
world.getWireHandler().onWireRemoved(pos, state); // Alternate Current
} else {
this.updateSurroundingRedstone(world, pos, state, null, false); // Vanilla/Eigencraft
@@ -428,7 +428,7 @@ public class RedStoneWireBlock extends Block {
if (!world.isClientSide) {
// Paper start - optimize redstone (Alternate Current)
// Alternate Current handles breaking of redstone wires in the WireHandler.
- if (world.paperConfig().misc.redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT) {
+ if (world.localConfig().config(pos).redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT) { // Sakura - redstone implementation api
world.getWireHandler().onWireUpdated(pos, state, wireOrientation);
} else
// Paper end - optimize redstone (Alternate Current)
diff --git a/src/main/java/net/minecraft/world/level/redstone/ExperimentalRedstoneUtils.java b/src/main/java/net/minecraft/world/level/redstone/ExperimentalRedstoneUtils.java
index 8342dd636531729a187aff1bd69878d7aef9d3eb..2272b081152fc70f5034186b36172b4a19e2680b 100644
--- a/src/main/java/net/minecraft/world/level/redstone/ExperimentalRedstoneUtils.java
+++ b/src/main/java/net/minecraft/world/level/redstone/ExperimentalRedstoneUtils.java
@@ -18,6 +18,7 @@ public class ExperimentalRedstoneUtils {
orientation = orientation.withFront(up);
}
// Paper start - Optimize redstone (Alternate Current) - use default front instead of random
+ // Sakura - redstone implementation api; conflict on change
else if (world.paperConfig().misc.redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT) {
orientation = orientation.withFront(Direction.WEST);
}

View File

@@ -0,0 +1,41 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
Date: Fri, 24 Nov 2023 18:52:51 +0000
Subject: [PATCH] Allow water in the nether
diff --git a/src/main/java/net/minecraft/world/item/BucketItem.java b/src/main/java/net/minecraft/world/item/BucketItem.java
index 3bddfb6f7412ab86e0c090d0cbc6cf254b3f891c..4cb809976b42af933401e8fc34ee43e181761558 100644
--- a/src/main/java/net/minecraft/world/item/BucketItem.java
+++ b/src/main/java/net/minecraft/world/item/BucketItem.java
@@ -196,7 +196,7 @@ public class BucketItem extends Item implements DispensibleContainerItem {
// CraftBukkit end
if (!flag2) {
return movingobjectpositionblock != null && this.emptyContents(entityhuman, world, movingobjectpositionblock.getBlockPos().relative(movingobjectpositionblock.getDirection()), (BlockHitResult) null, enumdirection, clicked, itemstack, enumhand); // CraftBukkit
- } else if (world.dimensionType().ultraWarm() && this.content.is(FluidTags.WATER)) {
+ } else if (!world.sakuraConfig().environment.allowWaterInTheNether && world.dimensionType().ultraWarm() && this.content.is(FluidTags.WATER)) { // Sakura
int i = blockposition.getX();
int j = blockposition.getY();
int k = blockposition.getZ();
diff --git a/src/main/java/net/minecraft/world/level/block/IceBlock.java b/src/main/java/net/minecraft/world/level/block/IceBlock.java
index a94762e65853ccad38cf90b0049ca256106c0c9f..fac57b911966855c31dccc26cae7d7113da437dd 100644
--- a/src/main/java/net/minecraft/world/level/block/IceBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/IceBlock.java
@@ -42,7 +42,7 @@ public class IceBlock extends HalfTransparentBlock {
public void afterDestroy(Level world, BlockPos pos, ItemStack tool) {
// Paper end - Improve Block#breakNaturally API
if (!EnchantmentHelper.hasTag(tool, EnchantmentTags.PREVENTS_ICE_MELTING)) {
- if (world.dimensionType().ultraWarm()) {
+ if (!world.sakuraConfig().environment.allowWaterInTheNether && world.dimensionType().ultraWarm()) { // Sakura
world.removeBlock(pos, false);
return;
}
@@ -70,7 +70,7 @@ public class IceBlock extends HalfTransparentBlock {
return;
}
// CraftBukkit end
- if (world.dimensionType().ultraWarm()) {
+ if (!world.sakuraConfig().environment.allowWaterInTheNether && world.dimensionType().ultraWarm()) { // Sakura
world.removeBlock(pos, false);
} else {
world.setBlockAndUpdate(pos, IceBlock.meltsInto());

View File

@@ -0,0 +1,19 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
Date: Sat, 25 Nov 2023 20:36:05 +0000
Subject: [PATCH] Configure concrete solidifying in water
diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
index 7ec7cfde4ce47a7f4a64e83fa49ed7287684d6a0..a41fef64424ae5419713e54af41f3d9622b64e89 100644
--- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
+++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
@@ -297,7 +297,7 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti
// However, it makes sense for legacy versions pre-1.17 before the world height change.
BlockPos blockposition = this.physics.before(1_17_0) ? this.patchedBlockPosition() : this.blockPosition();
// Sakura end - physics version api
- boolean flag = this.blockState.getBlock() instanceof ConcretePowderBlock;
+ boolean flag = this.level().sakuraConfig().cannons.sand.concreteSolidifyInWater && this.blockState.getBlock() instanceof ConcretePowderBlock; // Sakura
boolean flag1 = flag && this.level().getFluidState(blockposition).is(FluidTags.WATER);
double d0 = this.getDeltaMovement().lengthSqr();

View File

@@ -0,0 +1,19 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
Date: Sat, 25 Nov 2023 20:59:07 +0000
Subject: [PATCH] Option for fast nether dimension lava
diff --git a/src/main/java/net/minecraft/world/level/material/LavaFluid.java b/src/main/java/net/minecraft/world/level/material/LavaFluid.java
index e6ed1e46a4880743b7eeb73857b4b501971d6e29..cc5ed4e2cc0ef8acf3768539103d2cdeab30362f 100644
--- a/src/main/java/net/minecraft/world/level/material/LavaFluid.java
+++ b/src/main/java/net/minecraft/world/level/material/LavaFluid.java
@@ -184,7 +184,7 @@ public abstract class LavaFluid extends FlowingFluid {
@Override
public int getTickDelay(LevelReader world) {
- return world.dimensionType().ultraWarm() ? 10 : 30;
+ return world.dimensionType().ultraWarm() && !(world instanceof Level level && level.sakuraConfig().environment.disableFastNetherLava) ? 10 : 30; // Sakura - add option for fast nether lava
}
@Override

View File

@@ -0,0 +1,18 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
Date: Sun, 26 Nov 2023 17:41:00 +0000
Subject: [PATCH] Disable bubble columns affecting cannon entities
diff --git a/src/main/java/net/minecraft/world/level/block/BubbleColumnBlock.java b/src/main/java/net/minecraft/world/level/block/BubbleColumnBlock.java
index 385da0585f409ee453f10d45f5837cdc09adc21b..da5b41ba5e5fea8e7bc0d40a880ce0f0778d5785 100644
--- a/src/main/java/net/minecraft/world/level/block/BubbleColumnBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/BubbleColumnBlock.java
@@ -49,6 +49,7 @@ public class BubbleColumnBlock extends Block implements BucketPickup {
@Override
protected void entityInside(BlockState state, Level world, BlockPos pos, Entity entity) {
if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(world, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent
+ if (!world.sakuraConfig().cannons.tntAndSandAffectedByBubbleColumns && (entity.isPrimedTNT || entity.isFallingBlock)) return; // Sakura - configure bubble columns affecting cannon entities
BlockState blockState = world.getBlockState(pos.above());
if (blockState.isAir()) {
entity.onAboveBubbleCol(state.getValue(DRAG_DOWN));

View File

@@ -0,0 +1,28 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
Date: Thu, 7 Dec 2023 16:30:24 +0000
Subject: [PATCH] Configure mob spawner defaults
diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java
index 7de66aa435dd36899b80f4ecc64480680e474d94..90c87fabab274f6202a92150c4f1d5bfe9f5dad8 100644
--- a/src/main/java/net/minecraft/world/level/BaseSpawner.java
+++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java
@@ -51,7 +51,16 @@ public abstract class BaseSpawner {
public int spawnRange = 4;
private int tickDelay = 0; // Paper - Configurable mob spawner tick rate
- public BaseSpawner() {}
+ // Sakura start - configure spawner defaults
+ public BaseSpawner() {
+ this.minSpawnDelay = me.samsuik.sakura.configuration.GlobalConfiguration.get().environment.mobSpawnerDefaults.minSpawnDelay;
+ this.maxSpawnDelay = me.samsuik.sakura.configuration.GlobalConfiguration.get().environment.mobSpawnerDefaults.maxSpawnDelay;
+ this.spawnCount = me.samsuik.sakura.configuration.GlobalConfiguration.get().environment.mobSpawnerDefaults.spawnCount;
+ this.maxNearbyEntities = me.samsuik.sakura.configuration.GlobalConfiguration.get().environment.mobSpawnerDefaults.maxNearbyEntities;
+ this.requiredPlayerRange = me.samsuik.sakura.configuration.GlobalConfiguration.get().environment.mobSpawnerDefaults.requiredPlayerRange;
+ this.spawnRange = me.samsuik.sakura.configuration.GlobalConfiguration.get().environment.mobSpawnerDefaults.spawnRange;
+ // Sakura end
+ }
public void setEntityId(EntityType<?> type, @Nullable Level world, RandomSource random, BlockPos pos) {
this.getOrCreateNextSpawnData(world, random, pos).getEntityToSpawn().putString("id", BuiltInRegistries.ENTITY_TYPE.getKey(type).toString());

View File

@@ -0,0 +1,27 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
Date: Fri, 8 Dec 2023 18:12:20 +0000
Subject: [PATCH] Allow disabling random dispenser item selection
diff --git a/src/main/java/net/minecraft/world/level/block/entity/DispenserBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/DispenserBlockEntity.java
index c7f1937b0f171eee967388ab4699703dcdcfbd2b..77d2c11d5a01a1f209336c62ac5153b5efadbfd3 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/DispenserBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/DispenserBlockEntity.java
@@ -74,8 +74,15 @@ public class DispenserBlockEntity extends RandomizableContainerBlockEntity {
int j = 1;
for (int k = 0; k < this.items.size(); ++k) {
- if (!((ItemStack) this.items.get(k)).isEmpty() && random.nextInt(j++) == 0) {
+ // Sakura start - allow disabling dispenser random item selection
+ if (this.level.sakuraConfig().technical.dispenserRandomItemSelection || this instanceof DropperBlockEntity) {
+ if (!((ItemStack) this.items.get(k)).isEmpty() && random.nextInt(j++) == 0) {
+ i = k;
+ }
+ } else if (!this.items.get(k).isEmpty()) {
i = k;
+ break;
+ // Sakura end
}
}

View File

@@ -0,0 +1,23 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
Date: Fri, 8 Dec 2023 18:21:56 +0000
Subject: [PATCH] Add instant mob death animation
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index e7603a67c985ff105a8a4e16179fe33fe26f5b22..1bd9f31da1ec66259dc6391448e2b8ce69ddb817 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -1869,6 +1869,12 @@ public abstract class LivingEntity extends Entity implements Attackable {
// Paper start
if (this.dead) { // Paper
+ // Sakura start
+ if (level().sakuraConfig().entity.instantDeathAnimation && !(this instanceof Player)) {
+ this.deathTime = 20;
+ return;
+ }
+ // Sakura end
this.level().broadcastEntityEvent(this, (byte) 3);
this.setPose(Pose.DYING);

View File

@@ -0,0 +1,21 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
Date: Sat, 9 Dec 2023 00:11:48 +0000
Subject: [PATCH] Configure fluids breaking redstone
diff --git a/src/main/java/net/minecraft/world/level/material/FlowingFluid.java b/src/main/java/net/minecraft/world/level/material/FlowingFluid.java
index 45127421ccbd4375c5408c27963ef2fa6e29de2a..b45ef9f57bf52d8b05fb0f4f9e97d1f9af0c1716 100644
--- a/src/main/java/net/minecraft/world/level/material/FlowingFluid.java
+++ b/src/main/java/net/minecraft/world/level/material/FlowingFluid.java
@@ -514,6 +514,10 @@ public abstract class FlowingFluid extends Fluid {
if (block instanceof LiquidBlockContainer ifluidcontainer) {
return ifluidcontainer.canPlaceLiquid((Player) null, world, pos, state, fluid);
+ // Sakura start
+ } else if (world instanceof Level level && !level.sakuraConfig().technical.redstone.fluidsBreakRedstone && (state.isSignalSource() || state.getBlock() instanceof net.minecraft.world.level.block.CarpetBlock)) {
+ return false;
+ // Sakura end
} else {
return true;
}

View File

@@ -0,0 +1,22 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
Date: Sat, 9 Dec 2023 00:25:11 +0000
Subject: [PATCH] Option to disable explosions hurting players
diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java
index d11f67157c1bf8c14776c56748de3588273c7d45..b439c196db1af082d5ebcd6df59c436396dc144e 100644
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
@@ -928,6 +928,11 @@ public abstract class Player extends LivingEntity {
@Override
public boolean isInvulnerableTo(ServerLevel world, DamageSource source) {
+ // Sakura start - allow disabling explosions hurting players
+ if (!this.level().sakuraConfig().cannons.explosion.explosionsHurtPlayers && source.is(DamageTypeTags.IS_EXPLOSION)) {
+ return true;
+ }
+ // Sakura end - allow disabling explosions hurting players
return super.isInvulnerableTo(world, source) ? true : (source.is(DamageTypeTags.IS_DROWNING) ? !world.getGameRules().getBoolean(GameRules.RULE_DROWNING_DAMAGE) : (source.is(DamageTypeTags.IS_FALL) ? !world.getGameRules().getBoolean(GameRules.RULE_FALL_DAMAGE) : (source.is(DamageTypeTags.IS_FIRE) ? !world.getGameRules().getBoolean(GameRules.RULE_FIRE_DAMAGE) : (source.is(DamageTypeTags.IS_FREEZING) ? !world.getGameRules().getBoolean(GameRules.RULE_FREEZE_DAMAGE) : false))));
}

View File

@@ -0,0 +1,31 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <kfian294ma4@gmail.com>
Date: Sat, 9 Dec 2023 16:10:29 +0000
Subject: [PATCH] Iron golems take fall damage
diff --git a/src/main/java/net/minecraft/world/entity/animal/IronGolem.java b/src/main/java/net/minecraft/world/entity/animal/IronGolem.java
index e07b79ef172095c1800c88342b3ac8dc7703aea2..35dab3806fab4d1fe0ba4246c2e8566d2952b8d6 100644
--- a/src/main/java/net/minecraft/world/entity/animal/IronGolem.java
+++ b/src/main/java/net/minecraft/world/entity/animal/IronGolem.java
@@ -237,6 +237,20 @@ public class IronGolem extends AbstractGolem implements NeutralMob {
}
+ // Sakura start
+ @Override
+ protected int calculateFallDamage(float fallDistance, float damageMultiplier) {
+ if (!this.level().sakuraConfig().entity.ironGolemsTakeFalldamage) {
+ return super.calculateFallDamage(fallDistance, damageMultiplier);
+ } else {
+ net.minecraft.world.effect.MobEffectInstance mobeffect = this.getEffect(net.minecraft.world.effect.MobEffects.JUMP);
+ float f2 = mobeffect == null ? 0.0F : (float) (mobeffect.getAmplifier() + 1);
+
+ return net.minecraft.util.Mth.ceil((fallDistance - 3.0F - f2) * damageMultiplier);
+ }
+ }
+ // Sakura end
+
public int getAttackAnimationTick() {
return this.attackAnimationTick;
}

View File

@@ -0,0 +1,23 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <kfian294ma4@gmail.com>
Date: Sun, 24 Dec 2023 11:20:10 +0000
Subject: [PATCH] Add explosions dropping items config
diff --git a/src/main/java/net/minecraft/world/level/ServerExplosion.java b/src/main/java/net/minecraft/world/level/ServerExplosion.java
index e857fd02a5e341a1a701da71874dbd850e3c5a5d..0dae16d140666cae7633bbfef6d1c5b979d7dc9e 100644
--- a/src/main/java/net/minecraft/world/level/ServerExplosion.java
+++ b/src/main/java/net/minecraft/world/level/ServerExplosion.java
@@ -845,6 +845,12 @@ public class ServerExplosion implements Explosion {
});
}
+ // Sakura start - config for explosions dropping items
+ if (!this.level.sakuraConfig().cannons.explosion.explosionsDropItems) {
+ list1.clear();
+ }
+ // Sakura end - config for explosions dropping items
+
iterator = list1.iterator();
while (iterator.hasNext()) {

View File

@@ -0,0 +1,20 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <kfian294ma4@gmail.com>
Date: Mon, 22 Jan 2024 15:24:51 +0000
Subject: [PATCH] Avoid searching for lava if throttled water flow speed is
default
diff --git a/src/main/java/net/minecraft/world/level/block/LiquidBlock.java b/src/main/java/net/minecraft/world/level/block/LiquidBlock.java
index 0ea609556d906df3eadd3df83bd4a7f85857a14e..6cc129afdb19e121e1abe8dc07f5cc2216c7b084 100644
--- a/src/main/java/net/minecraft/world/level/block/LiquidBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/LiquidBlock.java
@@ -148,7 +148,7 @@ public class LiquidBlock extends Block implements BucketPickup {
// Paper start - Configurable speed for water flowing over lava
public int getFlowSpeed(Level world, BlockPos blockposition) {
- if (net.minecraft.core.registries.BuiltInRegistries.FLUID.wrapAsHolder(this.fluid).is(FluidTags.WATER)) {
+ if (net.minecraft.core.registries.BuiltInRegistries.FLUID.wrapAsHolder(this.fluid).is(FluidTags.WATER) && this.fluid.getTickDelay(world) != world.paperConfig().environment.waterOverLavaFlowSpeed) { // Sakura
if (
isLava(world, blockposition.north(1)) ||
isLava(world, blockposition.south(1)) ||

View File

@@ -0,0 +1,30 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <kfian294ma4@gmail.com>
Date: Mon, 22 Jan 2024 15:52:33 +0000
Subject: [PATCH] Calculate biome noise once per chunk section
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
index e4ae25c83ab9dd1aaa530a5456275ef63cdb8511..ee296175dba6f05f88e8dd585e72b83bd31defcd 100644
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
@@ -310,12 +310,18 @@ public class LevelChunkSection implements ca.spottedleaf.moonrise.patches.block_
public void fillBiomesFromNoise(BiomeResolver biomeSupplier, Climate.Sampler sampler, int x, int y, int z) {
PalettedContainer<Holder<Biome>> datapaletteblock = this.biomes.recreate();
+ Holder<Biome> biome = null; // Sakura
boolean flag = true;
for (int l = 0; l < 4; ++l) {
for (int i1 = 0; i1 < 4; ++i1) {
for (int j1 = 0; j1 < 4; ++j1) {
- datapaletteblock.getAndSetUnchecked(l, i1, j1, biomeSupplier.getNoiseBiome(x + l, y + i1, z + j1, sampler));
+ // Sakura start - calculate biome noise once per chunk section
+ if (biome == null || !me.samsuik.sakura.configuration.GlobalConfiguration.get().environment.calculateBiomeNoiseOncePerChunkSection) {
+ biome = biomeSupplier.getNoiseBiome(x + l, y + i1, z + j1, sampler);
+ }
+ datapaletteblock.getAndSetUnchecked(l, i1, j1, biome);
+ // Sakura end
}
}
}

View File

@@ -0,0 +1,22 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <kfian294ma4@gmail.com>
Date: Sun, 28 Jan 2024 20:30:09 +0000
Subject: [PATCH] Fix doEntityDrops gamerule preventing falling blocks from
breaking
diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
index a41fef64424ae5419713e54af41f3d9622b64e89..2d9e42465d4a8adf2095d3d23b29df29af3df00d 100644
--- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
+++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
@@ -376,6 +376,10 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti
this.discard(EntityRemoveEvent.Cause.DROP); // CraftBukkit - add Bukkit remove cause
this.callOnBrokenAfterFall(block, blockposition);
this.spawnAtLocation(worldserver, (ItemLike) block);
+ // Sakura start - fix the do entity drops gamerule
+ } else {
+ this.discard(EntityRemoveEvent.Cause.DROP); // CraftBukkit - add Bukkit remove cause
+ // Sakura end - fix the do entity drops gamerule
}
} else {
this.discard(EntityRemoveEvent.Cause.DROP); // CraftBukkit - add Bukkit remove cause

View File

@@ -0,0 +1,69 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <kfian294ma4@gmail.com>
Date: Fri, 23 Feb 2024 16:18:51 +0000
Subject: [PATCH] Configure potion speed and breaking inside entities
diff --git a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java
index 6c2d4d6f3a36ab452dfd3c33f66e54f152906639..d0ebc66072b50e977a1cd2cca01bcfaf16495c7b 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java
@@ -173,7 +173,7 @@ public abstract class Projectile extends Entity implements TraceableEntity {
super.tick();
}
- private boolean checkLeftOwner() {
+ protected boolean checkLeftOwner() { // Sakura - configure potion mechanics
Entity entity = this.getOwner();
if (entity != null) {
diff --git a/src/main/java/net/minecraft/world/entity/projectile/ProjectileUtil.java b/src/main/java/net/minecraft/world/entity/projectile/ProjectileUtil.java
index e09ffb062022263681148d93d7897feb4cc7e41b..1c6ad2e033b311c8c85c4cac37341f81a745c12c 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/ProjectileUtil.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/ProjectileUtil.java
@@ -51,7 +51,14 @@ public final class ProjectileUtil {
vec3 = hitResult.getLocation();
}
- HitResult hitResult2 = getEntityHitResult(world, entity, pos, vec3, entity.getBoundingBox().expandTowards(velocity).inflate(1.0), predicate, margin);
+ // Sakura start - configure potion mechanics
+ final HitResult hitResult2;
+ if (world.sakuraConfig().entity.thrownPotion.allowBreakingInsideEntities && entity instanceof ThrownPotion) {
+ hitResult2 = getEntityHitResult(entity, pos, vec3, entity.getBoundingBox().expandTowards(velocity).inflate(1.0), predicate, margin);
+ } else {
+ hitResult2 = getEntityHitResult(world, entity, pos, vec3, entity.getBoundingBox().expandTowards(velocity).inflate(1.0), predicate, margin);
+ }
+ // Sakura end - configure potion mechanics
if (hitResult2 != null) {
hitResult = hitResult2;
}
diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java b/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java
index 9d79b193fe2a737a20d1709548b2cd6c454ff27b..df3f8d8fcdd23cc155d3bb156a8e6290497cb060 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java
@@ -64,6 +64,25 @@ public class ThrownPotion extends ThrowableItemProjectile {
public ThrownPotion(Level world, double x, double y, double z, ItemStack stack) {
super(EntityType.POTION, x, y, z, world, stack);
}
+
+ // Sakura start - configure potion mechanics
+ @Override
+ public void shoot(double x, double y, double z, float speed, float divergence) {
+ super.shoot(x, y, z, speed, divergence);
+
+ net.minecraft.world.phys.Vec3 movement = this.getDeltaMovement();
+ double moveX = movement.x * this.level().sakuraConfig().entity.thrownPotion.horizontalSpeed;
+ double moveY = movement.y * this.level().sakuraConfig().entity.thrownPotion.verticalSpeed;
+ double moveZ = movement.z * this.level().sakuraConfig().entity.thrownPotion.horizontalSpeed;
+
+ this.setDeltaMovement(moveX, moveY, moveZ);
+ }
+
+ @Override
+ protected boolean checkLeftOwner() {
+ return super.checkLeftOwner() || this.level().sakuraConfig().entity.thrownPotion.allowBreakingInsideEntities && this.tickCount >= 5;
+ }
+ // Sakura end - configure potion mechanics
@Override
protected Item getDefaultItem() {

View File

@@ -0,0 +1,48 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <kfian294ma4@gmail.com>
Date: Thu, 14 Mar 2024 18:13:24 +0000
Subject: [PATCH] Add outline colliison to enderpearls
diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrowableProjectile.java b/src/main/java/net/minecraft/world/entity/projectile/ThrowableProjectile.java
index c309198d092fdae6bdcc5d773b7b707bab2738bd..b0e15d97514da292a97d0bbfd0c522fa8b57ab0f 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/ThrowableProjectile.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/ThrowableProjectile.java
@@ -44,12 +44,18 @@ public abstract class ThrowableProjectile extends Projectile {
return true;
}
+ // Sakura start - enderpearls use outline for collision
+ protected net.minecraft.world.level.ClipContext.Block getClipType() {
+ return net.minecraft.world.level.ClipContext.Block.COLLIDER;
+ }
+ // Sakura end - enderpearls use outline for collision
+
@Override
public void tick() {
this.handleFirstTickBubbleColumn();
this.applyGravity();
this.applyInertia();
- HitResult movingobjectposition = ProjectileUtil.getHitResultOnMoveVector(this, this::canHitEntity);
+ HitResult movingobjectposition = ProjectileUtil.getHitResultOnMoveVector(this, this::canHitEntity, this.getClipType()); // Sakura - enderpearls use outline for collision
Vec3 vec3d;
if (movingobjectposition.getType() != HitResult.Type.MISS) {
diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java b/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java
index bd2684528157f928460f2143dd71a48e11983123..59e55f1cd9a1bcfee657ec355007b1894301348c 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java
@@ -210,6 +210,13 @@ public class ThrownEnderpearl extends ThrowableItemProjectile {
}
}
+ // Sakura start - enderpearls use outline for collision
+ @Override
+ protected net.minecraft.world.level.ClipContext.Block getClipType() {
+ return this.level().sakuraConfig().entity.enderPearl.useOutlineForCollision ? net.minecraft.world.level.ClipContext.Block.OUTLINE : super.getClipType();
+ }
+ // Sakura end - enderpearls use outline for collision
+
@Override
public void tick() {
int i;

View File

@@ -0,0 +1,25 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <kfian294ma4@gmail.com>
Date: Thu, 14 Mar 2024 19:51:20 +0000
Subject: [PATCH] Disable player poses shrinking collision box
diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java
index b439c196db1af082d5ebcd6df59c436396dc144e..f14759c18f760165dfad670049c880c01adb96d4 100644
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
@@ -2249,7 +2249,13 @@ public abstract class Player extends LivingEntity {
@Override
public EntityDimensions getDefaultDimensions(Pose pose) {
- return (EntityDimensions) Player.POSES.getOrDefault(pose, Player.STANDING_DIMENSIONS);
+ // Sakura start - player poses shrink collision box
+ EntityDimensions dimensions = (EntityDimensions) Player.POSES.getOrDefault(pose, Player.STANDING_DIMENSIONS);
+ if (!level().sakuraConfig().players.posesShrinkCollisionBox && dimensions.height() == 0.6f) {
+ dimensions = Player.STANDING_DIMENSIONS;
+ }
+ return dimensions;
+ // Sakura end - player poses shrink collision box
}
@Override

View File

@@ -0,0 +1,46 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <kfian294ma4@gmail.com>
Date: Thu, 28 Mar 2024 15:44:33 +0000
Subject: [PATCH] Mob spawner behaviour
diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java
index 90c87fabab274f6202a92150c4f1d5bfe9f5dad8..4bc3a51116f95e924ccc5187a1ad7674ac3a97fc 100644
--- a/src/main/java/net/minecraft/world/level/BaseSpawner.java
+++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java
@@ -68,7 +68,7 @@ public abstract class BaseSpawner {
}
public boolean isNearPlayer(Level world, BlockPos pos) {
- return world.hasNearbyAlivePlayerThatAffectsSpawning((double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, (double) this.requiredPlayerRange); // Paper - Affects Spawning API
+ return !world.sakuraConfig().environment.mobSpawner.requireNearbyPlayer || world.hasNearbyAlivePlayerThatAffectsSpawning((double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, (double) this.requiredPlayerRange); // Sakura - mob spawner behaviour // Paper - Affects Spawning API
}
public void clientTick(Level world, BlockPos pos) {
@@ -139,7 +139,7 @@ public abstract class BaseSpawner {
if (!mobspawnerdata_a.isValidPosition(blockposition1, world)) {
continue;
}
- } else if (!SpawnPlacements.checkSpawnRules((EntityType) optional.get(), world, EntitySpawnReason.SPAWNER, blockposition1, world.getRandom())) {
+ } else if (world.sakuraConfig().environment.mobSpawner.checkSpawnConditions && !SpawnPlacements.checkSpawnRules((EntityType) optional.get(), world, EntitySpawnReason.SPAWNER, blockposition1, world.getRandom())) { // Sakura - mob spawner behaviour
continue;
}
// Paper start - PreCreatureSpawnEvent
@@ -167,7 +167,7 @@ public abstract class BaseSpawner {
return;
}
- int k = world.getEntities(EntityTypeTest.forExactClass(entity.getClass()), (new AABB((double) pos.getX(), (double) pos.getY(), (double) pos.getZ(), (double) (pos.getX() + 1), (double) (pos.getY() + 1), (double) (pos.getZ() + 1))).inflate((double) this.spawnRange), EntitySelector.NO_SPECTATORS).size();
+ int k = world.sakuraConfig().environment.mobSpawner.ignoreEntityLimit ? 0 : world.getEntities(EntityTypeTest.forExactClass(entity.getClass()), (new AABB((double) pos.getX(), (double) pos.getY(), (double) pos.getZ(), (double) (pos.getX() + 1), (double) (pos.getY() + 1), (double) (pos.getZ() + 1))).inflate((double) this.spawnRange), EntitySelector.NO_SPECTATORS).size(); // Sakura - mob spawner behaviour
if (k >= this.maxNearbyEntities) {
this.delay(world, pos);
@@ -179,7 +179,7 @@ public abstract class BaseSpawner {
if (entity instanceof Mob) {
Mob entityinsentient = (Mob) entity;
- if (mobspawnerdata.getCustomSpawnRules().isEmpty() && !entityinsentient.checkSpawnRules(world, EntitySpawnReason.SPAWNER) || !entityinsentient.checkSpawnObstruction(world)) {
+ if (world.sakuraConfig().environment.mobSpawner.checkSpawnConditions && (mobspawnerdata.getCustomSpawnRules().isEmpty() && !entityinsentient.checkSpawnRules(world, EntitySpawnReason.SPAWNER) || !entityinsentient.checkSpawnObstruction(world))) { // Sakura - mob spawner behaviour
continue;
}

View File

@@ -0,0 +1,75 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <kfian294ma4@gmail.com>
Date: Thu, 16 May 2024 21:20:52 +0100
Subject: [PATCH] Use random chance for crop growth instead of age
diff --git a/src/main/java/net/minecraft/world/level/block/CactusBlock.java b/src/main/java/net/minecraft/world/level/block/CactusBlock.java
index c045b1cccf0047dbef8c04d5a28d31d53389054f..02da342fa002af134a75a9d2046e43808b76fbcc 100644
--- a/src/main/java/net/minecraft/world/level/block/CactusBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/CactusBlock.java
@@ -53,6 +53,19 @@ public class CactusBlock extends Block {
@Override
protected void randomTick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
+ // Sakura start - use random chance for crop growth
+ if (world.sakuraConfig().environment.crops.useRandomChanceToGrow) {
+ int modifier = world.spigotConfig.cactusModifier;
+ if (random.nextFloat() >= modifier / (100.0f * 16)) {
+ return;
+ }
+ // set crop age to max so it grows right away
+ state = state.setValue(CactusBlock.AGE, AGE.max);
+ }
+ this.ageAndGrow(state, world, pos, random);
+ }
+ private void ageAndGrow(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
+ // Sakura end - use random chance for crop growth
BlockPos blockposition1 = pos.above();
if (world.isEmptyBlock(blockposition1)) {
@@ -69,7 +82,11 @@ public class CactusBlock extends Block {
if (j >= 15 || (modifier != 100 && random.nextFloat() < (modifier / (100.0f * 16)))) { // Spigot - SPIGOT-7159: Better modifier resolution
CraftEventFactory.handleBlockGrowEvent(world, blockposition1, this.defaultBlockState()); // CraftBukkit
BlockState iblockdata1 = (BlockState) state.setValue(CactusBlock.AGE, 0);
-
+ // Sakura start - use random chance for crop growth
+ if (world.sakuraConfig().environment.crops.useRandomChanceToGrow) {
+ world.neighborShapeChanged(Direction.UP, blockposition1, pos, state, 4, 1);
+ }
+ // Sakura end - use random chance for crop growth
world.setBlock(pos, iblockdata1, 4);
world.neighborChanged(iblockdata1, blockposition1, this, (Orientation) null, false);
} else if (modifier == 100 || random.nextFloat() < (modifier / (100.0f * 16))) { // Spigot - SPIGOT-7159: Better modifier resolution
diff --git a/src/main/java/net/minecraft/world/level/block/SugarCaneBlock.java b/src/main/java/net/minecraft/world/level/block/SugarCaneBlock.java
index 547ea09ed84595286c97c128b3b96f6d387ae25f..3db03582e710f87c176ec47d9cab901d27db2e5e 100644
--- a/src/main/java/net/minecraft/world/level/block/SugarCaneBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/SugarCaneBlock.java
@@ -52,6 +52,19 @@ public class SugarCaneBlock extends Block {
@Override
protected void randomTick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
+ // Sakura start - use random chance for crop growth
+ if (world.sakuraConfig().environment.crops.useRandomChanceToGrow) {
+ int modifier = world.spigotConfig.caneModifier;
+ if (random.nextFloat() >= modifier / (100.0f * 16)) {
+ return;
+ }
+ // set crop age to max so it grows right away
+ state = state.setValue(SugarCaneBlock.AGE, AGE.max);
+ }
+ this.ageAndGrow(state, world, pos, random);
+ }
+ private void ageAndGrow(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
+ // Sakura end - use random chance for crop growth
if (world.isEmptyBlock(pos.above())) {
int i;
@@ -66,6 +79,7 @@ public class SugarCaneBlock extends Block {
if (j >= 15 || (modifier != 100 && random.nextFloat() < (modifier / (100.0f * 16)))) { // Spigot - SPIGOT-7159: Better modifier resolution
org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(world, pos.above(), this.defaultBlockState()); // CraftBukkit
world.setBlock(pos, (BlockState) state.setValue(SugarCaneBlock.AGE, 0), 4);
+ // Sakura - conflict on change
} else if (modifier == 100 || random.nextFloat() < (modifier / (100.0f * 16))) { // Spigot - SPIGOT-7159: Better modifier resolution
world.setBlock(pos, (BlockState) state.setValue(SugarCaneBlock.AGE, j + 1), 4);
}

View File

@@ -0,0 +1,83 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <kfian294ma4@gmail.com>
Date: Wed, 22 May 2024 23:40:02 +0100
Subject: [PATCH] Protect block shapes against plugins
diff --git a/src/main/java/net/minecraft/world/level/block/CarpetBlock.java b/src/main/java/net/minecraft/world/level/block/CarpetBlock.java
index fe2d445a62fbd25d8dbbfad781bbf5a30e30175b..6b8e5ab4cf96865d608483e573d7bb809ac0b18a 100644
--- a/src/main/java/net/minecraft/world/level/block/CarpetBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/CarpetBlock.java
@@ -15,6 +15,7 @@ import net.minecraft.world.phys.shapes.VoxelShape;
public class CarpetBlock extends Block {
public static final MapCodec<CarpetBlock> CODEC = simpleCodec(CarpetBlock::new);
protected static final VoxelShape SHAPE = Block.box(0.0, 0.0, 0.0, 16.0, 1.0, 16.0);
+ private static final VoxelShape SHAPE_COPY = SHAPE.copy(); // Sakura - protect block shapes against plugins
@Override
public MapCodec<? extends CarpetBlock> codec() {
@@ -27,7 +28,7 @@ public class CarpetBlock extends Block {
@Override
protected VoxelShape getShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext context) {
- return SHAPE;
+ return SHAPE_COPY; // Sakura - protect block shapes against plugins
}
@Override
diff --git a/src/main/java/net/minecraft/world/level/block/LadderBlock.java b/src/main/java/net/minecraft/world/level/block/LadderBlock.java
index f702c88e96f1f692074dc56f2212230d49db41fb..f022aa201e25da7c5a3c7195662c202cc1b57695 100644
--- a/src/main/java/net/minecraft/world/level/block/LadderBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/LadderBlock.java
@@ -29,6 +29,12 @@ public class LadderBlock extends Block implements SimpleWaterloggedBlock {
protected static final VoxelShape WEST_AABB = Block.box(13.0, 0.0, 0.0, 16.0, 16.0, 16.0);
protected static final VoxelShape SOUTH_AABB = Block.box(0.0, 0.0, 0.0, 16.0, 16.0, 3.0);
protected static final VoxelShape NORTH_AABB = Block.box(0.0, 0.0, 13.0, 16.0, 16.0, 16.0);
+ // Sakura start - protect block shapes against plugins
+ private static final VoxelShape EAST_AABB_COPY = EAST_AABB.copy();
+ private static final VoxelShape WEST_AABB_COPY = WEST_AABB.copy();
+ private static final VoxelShape SOUTH_AABB_COPY = SOUTH_AABB.copy();
+ private static final VoxelShape NORTH_AABB_COPY = NORTH_AABB.copy();
+ // Sakura end - protect block shapes against plugins
// Sakura start - physics version api
protected static final VoxelShape LEGACY_EAST_AABB = Block.box(0.0, 0.0, 0.0, 2.0, 16.0, 16.0);
protected static final VoxelShape LEGACY_WEST_AABB = Block.box(14.0, 0.0, 0.0, 16.0, 16.0, 16.0);
@@ -69,14 +75,16 @@ public class LadderBlock extends Block implements SimpleWaterloggedBlock {
// Sakura end - physics version api
switch ((Direction)state.getValue(FACING)) {
case NORTH:
- return NORTH_AABB;
+ // Sakura start - protect block shapes against plugins
+ return NORTH_AABB_COPY;
case SOUTH:
- return SOUTH_AABB;
+ return SOUTH_AABB_COPY;
case WEST:
- return WEST_AABB;
+ return WEST_AABB_COPY;
case EAST:
default:
- return EAST_AABB;
+ return EAST_AABB_COPY;
+ // Sakura end - protect block shapes against plugins
}
}
diff --git a/src/main/java/net/minecraft/world/phys/shapes/VoxelShape.java b/src/main/java/net/minecraft/world/phys/shapes/VoxelShape.java
index 3f8e7e29c3e52211a29e6f0a32890f6b53bfd9a8..21210877f903323fbff961e9dd7f6eafb6f0a746 100644
--- a/src/main/java/net/minecraft/world/phys/shapes/VoxelShape.java
+++ b/src/main/java/net/minecraft/world/phys/shapes/VoxelShape.java
@@ -557,6 +557,13 @@ public abstract class VoxelShape implements ca.spottedleaf.moonrise.patches.coll
return this.isEmpty; // Paper - optimise collisions
}
+ // Sakura start - protect block shapes against plugins
+ public final VoxelShape copy() {
+ this.cachedToAABBs = null;
+ return this.move(Vec3.ZERO);
+ }
+ // Sakura end - protect block shapes against plugins
+
public VoxelShape move(Vec3 vec3d) {
return this.move(vec3d.x, vec3d.y, vec3d.z);
}

View File

@@ -0,0 +1,258 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <kfian294ma4@gmail.com>
Date: Fri, 23 Feb 2024 01:48:08 +0000
Subject: [PATCH] Legacy player combat mechanics
diff --git a/src/main/java/me/samsuik/sakura/player/combat/CombatUtil.java b/src/main/java/me/samsuik/sakura/player/combat/CombatUtil.java
new file mode 100644
index 0000000000000000000000000000000000000000..e0aa768656081fac2c87ff573b61584dc4c1a9a3
--- /dev/null
+++ b/src/main/java/me/samsuik/sakura/player/combat/CombatUtil.java
@@ -0,0 +1,64 @@
+package me.samsuik.sakura.player.combat;
+
+import net.minecraft.core.Holder;
+import net.minecraft.core.HolderLookup;
+import net.minecraft.core.RegistryAccess;
+import net.minecraft.core.component.DataComponents;
+import net.minecraft.core.registries.Registries;
+import net.minecraft.resources.ResourceKey;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.world.damagesource.DamageSource;
+import net.minecraft.world.entity.EquipmentSlot;
+import net.minecraft.world.entity.LivingEntity;
+import net.minecraft.world.entity.ai.attributes.AttributeModifier;
+import net.minecraft.world.entity.ai.attributes.Attributes;
+import net.minecraft.world.item.*;
+import net.minecraft.world.item.component.ItemAttributeModifiers;
+import net.minecraft.world.item.enchantment.Enchantment;
+import net.minecraft.world.item.enchantment.Enchantments;
+import net.minecraft.world.item.enchantment.ItemEnchantments;
+import org.apache.commons.lang3.mutable.MutableFloat;
+
+import java.util.OptionalDouble;
+
+public final class CombatUtil {
+ public static double getLegacyAttackDifference(ItemStack itemstack) {
+ ItemAttributeModifiers defaultModifiers = itemstack.getItem().components().get(DataComponents.ATTRIBUTE_MODIFIERS);
+ if (defaultModifiers != null && !defaultModifiers.modifiers().isEmpty()) { // exists
+ double baseAttack = 0.0;
+ for (ItemAttributeModifiers.Entry entry : defaultModifiers.modifiers()) {
+ if (!entry.slot().test(EquipmentSlot.MAINHAND) || !entry.attribute().is(Attributes.ATTACK_DAMAGE))
+ continue;
+ if (entry.modifier().operation() != AttributeModifier.Operation.ADD_VALUE)
+ return 0;
+ baseAttack += entry.modifier().amount();
+ }
+
+ OptionalDouble legacyAttack = LegacyDamageMapping.itemAttackDamage(itemstack.getItem());
+ if (baseAttack != 0.0 && legacyAttack.isPresent()) {
+ return legacyAttack.getAsDouble() - baseAttack;
+ }
+ }
+ return 0;
+ }
+
+ public static float calculateLegacySharpnessDamage(LivingEntity entity, ItemStack itemstack, DamageSource damageSource) {
+ Holder<Enchantment> enchantment = getEnchantmentHolder(Enchantments.SHARPNESS);
+ ItemEnchantments itemEnchantments = itemstack.getEnchantments();
+ int enchantmentLevel = itemEnchantments.getLevel(enchantment);
+ MutableFloat damage = new MutableFloat();
+
+ if (entity.level() instanceof ServerLevel level) {
+ enchantment.value().modifyDamage(level, enchantmentLevel, itemstack, entity, damageSource, damage);
+ }
+ // legacy - modern
+ return enchantmentLevel * 1.25F - damage.getValue();
+ }
+
+ private static Holder<Enchantment> getEnchantmentHolder(ResourceKey<Enchantment> enchantmentKey) {
+ RegistryAccess registryAccess = MinecraftServer.getServer().registryAccess();
+ HolderLookup.RegistryLookup<Enchantment> enchantments = registryAccess.lookupOrThrow(Registries.ENCHANTMENT);
+ return enchantments.getOrThrow(enchantmentKey);
+ }
+}
diff --git a/src/main/java/me/samsuik/sakura/player/combat/LegacyDamageMapping.java b/src/main/java/me/samsuik/sakura/player/combat/LegacyDamageMapping.java
new file mode 100644
index 0000000000000000000000000000000000000000..b4ab8f172d713204bb9c1ebf575dcc28bd7dd73e
--- /dev/null
+++ b/src/main/java/me/samsuik/sakura/player/combat/LegacyDamageMapping.java
@@ -0,0 +1,64 @@
+package me.samsuik.sakura.player.combat;
+
+import it.unimi.dsi.fastutil.objects.Reference2DoubleMap;
+import it.unimi.dsi.fastutil.objects.Reference2DoubleOpenHashMap;
+import net.minecraft.core.component.DataComponents;
+import net.minecraft.core.registries.BuiltInRegistries;
+import net.minecraft.world.entity.ai.attributes.Attributes;
+import net.minecraft.world.item.*;
+import net.minecraft.world.item.component.ItemAttributeModifiers;
+
+import java.util.OptionalDouble;
+
+public final class LegacyDamageMapping {
+ private static final Reference2DoubleMap<Item> LEGACY_ITEM_DAMAGE_MAP = new Reference2DoubleOpenHashMap<>();
+
+ public static OptionalDouble itemAttackDamage(Item item) {
+ double result = LEGACY_ITEM_DAMAGE_MAP.getDouble(item);
+ return result == Double.MIN_VALUE ? OptionalDouble.empty() : OptionalDouble.of(result);
+ }
+
+ private static double adjustDamageForItem(Item item, double attackDamage) {
+ return switch (item) {
+ case SwordItem i -> 1.0;
+ case PickaxeItem i -> 1.0;
+ case ShovelItem i -> -0.5;
+ case HoeItem i -> -attackDamage;
+ case null, default -> 0.0;
+ };
+ }
+
+ static {
+ LEGACY_ITEM_DAMAGE_MAP.defaultReturnValue(Double.MIN_VALUE);
+
+ // tool material is no longer exposed
+ LEGACY_ITEM_DAMAGE_MAP.put(Items.WOODEN_AXE, 3.0);
+ LEGACY_ITEM_DAMAGE_MAP.put(Items.GOLDEN_AXE, 3.0);
+ LEGACY_ITEM_DAMAGE_MAP.put(Items.STONE_AXE, 4.0);
+ LEGACY_ITEM_DAMAGE_MAP.put(Items.IRON_AXE, 5.0);
+ LEGACY_ITEM_DAMAGE_MAP.put(Items.DIAMOND_AXE, 6.0);
+ LEGACY_ITEM_DAMAGE_MAP.put(Items.NETHERITE_AXE, 7.0);
+
+ for (Item item : BuiltInRegistries.ITEM) {
+ ItemAttributeModifiers modifiers = item.components().get(DataComponents.ATTRIBUTE_MODIFIERS);
+
+ if (modifiers == null || LEGACY_ITEM_DAMAGE_MAP.containsKey(item)) {
+ continue;
+ }
+
+ assert item instanceof AxeItem : "missing axe mapping";
+
+ double attackDamage = modifiers.modifiers().stream()
+ .filter(e -> e.attribute().is(Attributes.ATTACK_DAMAGE))
+ .mapToDouble(e -> e.modifier().amount())
+ .sum();
+
+ if (attackDamage > 0.0) {
+ double adjustment = adjustDamageForItem(item, attackDamage);
+ LEGACY_ITEM_DAMAGE_MAP.put(item, attackDamage + adjustment);
+ }
+ }
+ }
+
+ private LegacyDamageMapping() {}
+}
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 1bd9f31da1ec66259dc6391448e2b8ce69ddb817..16e6bd46e54cba9e0ef39a488cefcc5e49476403 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -308,6 +308,43 @@ public abstract class LivingEntity extends Entity implements Attackable {
++this.noActionTime; // Above all the floats
}
// Spigot end
+ // Sakura start - legacy combat mechanics
+ private static final ResourceLocation LEGACY_COMBAT_MODIFIER_ID = ResourceLocation.fromNamespaceAndPath("sakura", "legacy_combat");
+ private static final AttributeModifier LEGACY_ATTACK_SPEED_MODIFIER = new AttributeModifier(LEGACY_COMBAT_MODIFIER_ID, 100.0, AttributeModifier.Operation.ADD_VALUE);
+
+ private void updateAttackSpeedModifier() {
+ AttributeInstance attackSpeed = this.getAttribute(Attributes.ATTACK_SPEED);
+ if (attackSpeed != null) {
+ attackSpeed.removeModifier(LEGACY_ATTACK_SPEED_MODIFIER);
+
+ if (this.level().sakuraConfig().players.combat.legacyCombatMechanics) {
+ attackSpeed.addTransientModifier(LEGACY_ATTACK_SPEED_MODIFIER);
+ }
+ }
+ }
+
+ protected final float getAttackDamageFromAttributes() {
+ AttributeInstance attackDamage = this.getAttribute(Attributes.ATTACK_DAMAGE);
+ AttributeModifier legacyModifier = null;
+
+ if (this.level().sakuraConfig().players.combat.legacyCombatMechanics) {
+ ItemStack heldItem = this.getLastHandItem(EquipmentSlot.MAINHAND);
+ double attackDifference = me.samsuik.sakura.player.combat.CombatUtil.getLegacyAttackDifference(heldItem);
+ legacyModifier = new AttributeModifier(LEGACY_COMBAT_MODIFIER_ID, attackDifference, AttributeModifier.Operation.ADD_VALUE);
+ }
+
+ final double damage;
+ if (attackDamage == null || legacyModifier == null) {
+ damage = this.getAttributeValue(Attributes.ATTACK_DAMAGE);
+ } else {
+ attackDamage.addTransientModifier(legacyModifier);
+ damage = this.getAttributeValue(Attributes.ATTACK_DAMAGE);
+ attackDamage.removeModifier(legacyModifier);
+ }
+
+ return (float) damage;
+ }
+ // Sakura end - legacy combat mechanics
protected LivingEntity(EntityType<? extends LivingEntity> type, Level world) {
super(type, world);
@@ -2302,7 +2339,16 @@ public abstract class LivingEntity extends Entity implements Attackable {
protected float getDamageAfterArmorAbsorb(DamageSource source, float amount) {
if (!source.is(DamageTypeTags.BYPASSES_ARMOR)) {
// this.hurtArmor(damagesource, f); // CraftBukkit - actuallyHurt(DamageSource, float, EntityDamageEvent) for handle damage
+ // Sakura start - legacy combat mechanics
+ if (!this.level().sakuraConfig().players.combat.legacyCombatMechanics) {
amount = CombatRules.getDamageAfterAbsorb(this, amount, source, (float) this.getArmorValue(), (float) this.getAttributeValue(Attributes.ARMOR_TOUGHNESS));
+ } else {
+ // See: applyArmorModifier(DamageSource, float)
+ int i = 25 - this.getArmorValue();
+ float f1 = amount * (float) i;
+ amount = f1 / 25.0F;
+ }
+ // Sakura end - legacy combat mechanics
}
return amount;
@@ -3492,6 +3538,11 @@ public abstract class LivingEntity extends Entity implements Attackable {
EnchantmentHelper.runLocationChangedEffects(worldserver, itemstack, this, enumitemslot1);
}
+ // Sakura start - legacy combat mechanics
+ if (this instanceof ServerPlayer && enumitemslot1 == EquipmentSlot.MAINHAND) {
+ this.updateAttackSpeedModifier();
+ }
+ // Sakura end - legacy combat mechanics
}
}
}
diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java
index f14759c18f760165dfad670049c880c01adb96d4..c6e728aec98c1abb55abc7bb31ae3604bd187374 100644
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
@@ -1243,14 +1243,20 @@ public abstract class Player extends LivingEntity {
if (playerAttackEntityEvent.callEvent() && willAttack) { // Logic moved to willAttack local variable.
{
// Paper end - PlayerAttackEntityEvent
- float f = this.isAutoSpinAttack() ? this.autoSpinAttackDmg : (float) this.getAttributeValue(Attributes.ATTACK_DAMAGE);
+ float f = this.isAutoSpinAttack() ? this.autoSpinAttackDmg : this.getAttackDamageFromAttributes(); // Sakura - legacy combat mechanics
ItemStack itemstack = this.getWeaponItem();
DamageSource damagesource = (DamageSource) Optional.ofNullable(itemstack.getItem().getDamageSource(this)).orElse(this.damageSources().playerAttack(this));
float f1 = this.getEnchantedDamage(target, f, damagesource) - f;
float f2 = this.getAttackStrengthScale(0.5F);
+ // Sakura start - legacy combat mechanics
+ if (!this.level().sakuraConfig().players.combat.legacyCombatMechanics) {
f *= 0.2F + f2 * f2 * 0.8F;
f1 *= f2;
+ } else if (f1 != 0.0) {
+ f1 += me.samsuik.sakura.player.combat.CombatUtil.calculateLegacySharpnessDamage(this, itemstack, damagesource);
+ }
+ // Sakura end - legacy combat mechanics
// this.resetAttackStrengthTicker(); // CraftBukkit - Moved to EntityLiving to reset the cooldown after the damage is dealt
if (target.getType().is(EntityTypeTags.REDIRECTABLE_PROJECTILE) && target instanceof Projectile) {
Projectile iprojectile = (Projectile) target;
@@ -1278,7 +1284,7 @@ public abstract class Player extends LivingEntity {
}
f += itemstack.getItem().getAttackDamageBonus(target, f, damagesource);
- boolean flag2 = flag && this.fallDistance > 0.0F && !this.onGround() && !this.onClimbable() && !this.isInWater() && !this.hasEffect(MobEffects.BLINDNESS) && !this.isPassenger() && target instanceof LivingEntity && !this.isSprinting();
+ boolean flag2 = flag && this.fallDistance > 0.0F && !this.onGround() && !this.onClimbable() && !this.isInWater() && !this.hasEffect(MobEffects.BLINDNESS) && !this.isPassenger() && target instanceof LivingEntity && (this.level().sakuraConfig().players.combat.legacyCombatMechanics || !this.isSprinting()); // Sakura - legacy combat mechanics
flag2 = flag2 && !this.level().paperConfig().entities.behavior.disablePlayerCrits; // Paper - Toggleable player crits
if (flag2) {

View File

@@ -0,0 +1,19 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <kfian294ma4@gmail.com>
Date: Fri, 23 Feb 2024 01:49:20 +0000
Subject: [PATCH] Allow disabling sweep attacks
diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java
index c6e728aec98c1abb55abc7bb31ae3604bd187374..23c66dc1bba4f4242c848121f70879bb94f0fb4b 100644
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
@@ -1351,7 +1351,7 @@ public abstract class Player extends LivingEntity {
LivingEntity entityliving2;
- if (flag3) {
+ if (flag3 && this.level().sakuraConfig().players.combat.allowSweepAttacks) { // Sakura - allow disabling sweep attacks
float f6 = 1.0F + (float) this.getAttributeValue(Attributes.SWEEPING_DAMAGE_RATIO) * f;
List<LivingEntity> list = this.level().getEntitiesOfClass(LivingEntity.class, target.getBoundingBox().inflate(1.0D, 0.25D, 1.0D));
Iterator iterator = list.iterator();

View File

@@ -0,0 +1,24 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <kfian294ma4@gmail.com>
Date: Fri, 23 Feb 2024 02:07:03 +0000
Subject: [PATCH] Change shields to reduce damage
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 16e6bd46e54cba9e0ef39a488cefcc5e49476403..8dab67d53a058b62d73e009e378d6376dae70075 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -2444,7 +2444,13 @@ public abstract class LivingEntity extends Entity implements Attackable {
com.google.common.base.Function<Double, Double> blocking = new com.google.common.base.Function<Double, Double>() {
@Override
public Double apply(Double f) {
+ // Sakura start - shield damage reduction
+ if (!level().sakuraConfig().players.combat.shieldDamageReduction || damagesource.getDirectEntity() instanceof AbstractArrow) {
return -((LivingEntity.this.isDamageSourceBlocked(damagesource)) ? f : 0.0);
+ } else {
+ return -(LivingEntity.this.isBlocking() ? f * 0.5 : 0.0);
+ }
+ // Sakura end - shield damage reduction
}
};
float blockingModifier = blocking.apply((double) f).floatValue();

View File

@@ -0,0 +1,88 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <kfian294ma4@gmail.com>
Date: Fri, 23 Feb 2024 14:40:32 +0000
Subject: [PATCH] Old enchanted golden apples
diff --git a/src/main/java/me/samsuik/sakura/player/combat/CustomGoldenApple.java b/src/main/java/me/samsuik/sakura/player/combat/CustomGoldenApple.java
new file mode 100644
index 0000000000000000000000000000000000000000..18cb28a9bdfcb9a421bc001f057b4be54c1550be
--- /dev/null
+++ b/src/main/java/me/samsuik/sakura/player/combat/CustomGoldenApple.java
@@ -0,0 +1,64 @@
+package me.samsuik.sakura.player.combat;
+
+import net.minecraft.core.component.DataComponents;
+import net.minecraft.world.InteractionHand;
+import net.minecraft.world.InteractionResult;
+import net.minecraft.world.effect.MobEffectInstance;
+import net.minecraft.world.effect.MobEffects;
+import net.minecraft.world.entity.LivingEntity;
+import net.minecraft.world.entity.player.Player;
+import net.minecraft.world.item.Item;
+import net.minecraft.world.item.ItemStack;
+import net.minecraft.world.item.component.Consumable;
+import net.minecraft.world.item.component.Consumables;
+import net.minecraft.world.item.consume_effects.ApplyStatusEffectsConsumeEffect;
+import net.minecraft.world.level.Level;
+import org.jspecify.annotations.NullMarked;
+
+import java.util.List;
+import java.util.Optional;
+
+@NullMarked
+@SuppressWarnings("OptionalAssignedToNull")
+public final class CustomGoldenApple extends Item {
+ private static final Consumable LEGACY_ENCHANTED_GOLDEN_APPLE = Consumables.defaultFood()
+ .onConsume(
+ new ApplyStatusEffectsConsumeEffect(
+ List.of(
+ new MobEffectInstance(MobEffects.REGENERATION, 600, 4),
+ new MobEffectInstance(MobEffects.DAMAGE_RESISTANCE, 6000, 0),
+ new MobEffectInstance(MobEffects.FIRE_RESISTANCE, 6000, 0),
+ new MobEffectInstance(MobEffects.ABSORPTION, 2400, 0)
+ )
+ )
+ )
+ .build();
+
+ public CustomGoldenApple(Properties settings) {
+ super(settings);
+ }
+
+ @Override
+ public InteractionResult use(Level level, Player player, InteractionHand hand) {
+ ItemStack stack = player.getItemInHand(hand);
+ if (this.itemHasConsumableComponent(stack, level)) {
+ return super.use(level, player, hand);
+ } else {
+ return LEGACY_ENCHANTED_GOLDEN_APPLE.startConsuming(player, stack, hand);
+ }
+ }
+
+ @Override
+ public ItemStack finishUsingItem(ItemStack stack, Level level, LivingEntity entity) {
+ if (this.itemHasConsumableComponent(stack, level)) {
+ return super.finishUsingItem(stack, level, entity);
+ } else {
+ return LEGACY_ENCHANTED_GOLDEN_APPLE.onConsume(level, entity, stack);
+ }
+ }
+
+ private boolean itemHasConsumableComponent(ItemStack stack, Level level) {
+ Optional<?> consumable = stack.getComponentsPatch().get(DataComponents.CONSUMABLE);
+ return consumable != null || !level.sakuraConfig().players.combat.oldEnchantedGoldenApple;
+ }
+}
diff --git a/src/main/java/net/minecraft/world/item/Items.java b/src/main/java/net/minecraft/world/item/Items.java
index 6d16b4433e79eca0ff8008941f0b9b807b1db9db..5aeb780535d6ab8010e544cade33fa2b20f9068c 100644
--- a/src/main/java/net/minecraft/world/item/Items.java
+++ b/src/main/java/net/minecraft/world/item/Items.java
@@ -1183,6 +1183,7 @@ public class Items {
public static final Item GOLDEN_APPLE = registerItem("golden_apple", new Item.Properties().food(Foods.GOLDEN_APPLE, Consumables.GOLDEN_APPLE));
public static final Item ENCHANTED_GOLDEN_APPLE = registerItem(
"enchanted_golden_apple",
+ me.samsuik.sakura.player.combat.CustomGoldenApple::new, // Sakura - old enchanted golden apples
new Item.Properties()
.rarity(Rarity.RARE)
.food(Foods.ENCHANTED_GOLDEN_APPLE, Consumables.ENCHANTED_GOLDEN_APPLE)

View File

@@ -0,0 +1,19 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <kfian294ma4@gmail.com>
Date: Thu, 6 Jun 2024 18:18:28 +0100
Subject: [PATCH] Configure fast health regen
diff --git a/src/main/java/net/minecraft/world/food/FoodData.java b/src/main/java/net/minecraft/world/food/FoodData.java
index 6a686be6a69ae890d519a54ca099d4ba14e5b9e1..bb8dcd7e307c033806de392fecf41a235c7d7765 100644
--- a/src/main/java/net/minecraft/world/food/FoodData.java
+++ b/src/main/java/net/minecraft/world/food/FoodData.java
@@ -74,7 +74,7 @@ public class FoodData {
boolean flag = worldserver.getGameRules().getBoolean(GameRules.RULE_NATURAL_REGENERATION);
- if (flag && this.saturationLevel > 0.0F && player.isHurt() && this.foodLevel >= 20) {
+ if (flag && this.saturationLevel > 0.0F && player.isHurt() && this.foodLevel >= 20 && player.level().sakuraConfig().players.combat.fastHealthRegen) { // Sakura - configure fast health regen
++this.tickTimer;
if (this.tickTimer >= this.saturatedRegenRate) { // CraftBukkit
float f = Math.min(this.saturationLevel, 6.0F);

View File

@@ -0,0 +1,19 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <kfian294ma4@gmail.com>
Date: Thu, 6 Jun 2024 20:34:29 +0100
Subject: [PATCH] Add option for fishing hooks pulling entities
diff --git a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java
index c563f71fb79990771d032b8044b8f676d8d21058..651a1d6313df92258d9af00ceb57142ebc40fee5 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java
@@ -621,7 +621,7 @@ public class FishingHook extends Projectile {
public void pullEntity(Entity entity) {
Entity entity1 = this.getOwner();
- if (entity1 != null) {
+ if (entity1 != null && (this.level().sakuraConfig().players.fishingHooksPullEntities || entity instanceof ItemEntity)) { // Sakura - Add option for fishing hooks pulling entities
Vec3 vec3d = (new Vec3(entity1.getX() - this.getX(), entity1.getY() - this.getY(), entity1.getZ() - this.getZ())).scale(0.1D);
entity.setDeltaMovement(entity.getDeltaMovement().add(vec3d));

View File

@@ -0,0 +1,27 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <kfian294ma4@gmail.com>
Date: Tue, 11 Jun 2024 13:37:51 +0100
Subject: [PATCH] Old combat sounds and particle effects
diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java
index 23c66dc1bba4f4242c848121f70879bb94f0fb4b..e0cb3a9d0cd27a98e302816bc736db291a32cf4f 100644
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
@@ -1461,7 +1461,7 @@ public abstract class Player extends LivingEntity {
float f8 = f4 - ((LivingEntity) target).getHealth();
this.awardStat(Stats.DAMAGE_DEALT, Math.round(f8 * 10.0F));
- if (this.level() instanceof ServerLevel && f8 > 2.0F) {
+ if (this.level() instanceof ServerLevel && f8 > 2.0F && !this.level().sakuraConfig().players.combat.oldSoundsAndParticleEffects) { // Sakura - old combat sounds and particles
int i = (int) ((double) f8 * 0.5D);
((ServerLevel) this.level()).sendParticles(ParticleTypes.DAMAGE_INDICATOR, target.getX(), target.getY(0.5D), target.getZ(), i, 0.1D, 0.0D, 0.1D, 0.2D);
@@ -1869,6 +1869,7 @@ public abstract class Player extends LivingEntity {
}
// Paper start - send while respecting visibility
private static void sendSoundEffect(Player fromEntity, double x, double y, double z, SoundEvent soundEffect, SoundSource soundCategory, float volume, float pitch) {
+ if (fromEntity.level().sakuraConfig().players.combat.oldSoundsAndParticleEffects) return; // Sakura - old combat sounds and particles
fromEntity.level().playSound(fromEntity, x, y, z, soundEffect, soundCategory, volume, pitch); // This will not send the effect to the entity itself
if (fromEntity instanceof ServerPlayer serverPlayer) {
serverPlayer.connection.send(new net.minecraft.network.protocol.game.ClientboundSoundPacket(net.minecraft.core.registries.BuiltInRegistries.SOUND_EVENT.wrapAsHolder(soundEffect), soundCategory, x, y, z, volume, pitch, fromEntity.random.nextLong()));

View File

@@ -0,0 +1,57 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <kfian294ma4@gmail.com>
Date: Tue, 18 Jun 2024 13:34:55 +0100
Subject: [PATCH] Entity tracking range modifier
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index 274b3a5e1d4606ed47ba7e3e4ee369d607cea8a1..49f8afdaa91e89b899b9fcce1ef9a972ec141b8b 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -1326,7 +1326,10 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
double vec3d_dz = player.getZ() - this.entity.getZ();
// Paper end - remove allocation of Vec3D here
int i = ChunkMap.this.getPlayerViewDistance(player);
- double d0 = (double) Math.min(this.getEffectiveRange(), i * 16);
+ // Sakura start - entity tracking range modifier
+ double visibleRange = (double) this.getEffectiveRange() * player.trackingRangeModifier;
+ double d0 = (double) Math.min(visibleRange, i * 16);
+ // Sakura end - entity tracking range modifier
double d1 = vec3d_dx * vec3d_dx + vec3d_dz * vec3d_dz; // Paper
double d2 = d0 * d0;
// Paper start - Configurable entity tracking range by Y
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index 2a9659158d39d4d5505328afd7a2d8dc9ecf456f..5f7945c852ef9eb0d1183cc0ce33db5a82edee56 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -358,6 +358,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player imple
}
// Paper end - rewrite chunk system
public final me.samsuik.sakura.player.visibility.PlayerVisibilitySettings visibilitySettings = new me.samsuik.sakura.player.visibility.PlayerVisibilitySettings(); // Sakura - client visibility settings
+ public double trackingRangeModifier = 1.0; // Sakura - entity tracking range modifier
public ServerPlayer(MinecraftServer server, ServerLevel world, GameProfile profile, ClientInformation clientOptions) {
super(world, world.getSharedSpawnPos(), world.getSharedSpawnAngle(), profile);
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 5455f78d4417f3f8b2e4820619ad24d91054d986..c01abfb8746c1280b9c48d22a5c7a33d5ba1cd61 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -3033,6 +3033,18 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
return (this.getHandle().requestedViewDistance() == 0) ? Bukkit.getViewDistance() : this.getHandle().requestedViewDistance();
}
+ // Sakura start - entity tracking range modifier
+ @Override
+ public double getTrackingRangeModifier() {
+ return this.getHandle().trackingRangeModifier * 100.0;
+ }
+
+ @Override
+ public void setTrackingRangeModifier(double mod) {
+ this.getHandle().trackingRangeModifier = mod / 100.0;
+ }
+ // Sakura end - entity tracking range modifier
+
// Paper start
@Override
public java.util.Locale locale() {

View File

@@ -0,0 +1,36 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <kfian294ma4@gmail.com>
Date: Mon, 29 Jul 2024 00:18:58 +0100
Subject: [PATCH] Set entity impulse on explosion
diff --git a/src/main/java/me/samsuik/sakura/explosion/special/SpecialisedExplosion.java b/src/main/java/me/samsuik/sakura/explosion/special/SpecialisedExplosion.java
index c916d3037bd5920ec06213a9162223a124428d6b..fd98f36ca2fd7e0b5961fd89aa976dbfc7df93b8 100644
--- a/src/main/java/me/samsuik/sakura/explosion/special/SpecialisedExplosion.java
+++ b/src/main/java/me/samsuik/sakura/explosion/special/SpecialisedExplosion.java
@@ -204,6 +204,7 @@ public abstract class SpecialisedExplosion<T extends Entity> extends ServerExplo
moveZ += z;
}
+ entity.hasImpulse = true; // Sakura - set entity impulse on explosion
entity.setDeltaMovement(moveX, moveY, moveZ);
}
}
diff --git a/src/main/java/net/minecraft/world/level/ServerExplosion.java b/src/main/java/net/minecraft/world/level/ServerExplosion.java
index 8ddcbb5f5ea867d3bce207ba25f93a940f78a93b..06cbe3ac6adf0d91a185e365a056b29ee54380e6 100644
--- a/src/main/java/net/minecraft/world/level/ServerExplosion.java
+++ b/src/main/java/net/minecraft/world/level/ServerExplosion.java
@@ -748,7 +748,12 @@ public class ServerExplosion implements Explosion {
// Paper end - knockback events
}
// CraftBukkit end
- entity.push(vec3d);
+ // Sakura start - set entity impulse on explosion
+ // Wait for upstream to change the push method to be more sane.
+ // entity.push(vec3d);
+ entity.hasImpulse = true;
+ entity.setDeltaMovement(entity.getDeltaMovement().add(vec3d));
+ // Sakura end - set entity impulse on explosion
if (entity instanceof Player) {
Player entityhuman = (Player) entity;

View File

@@ -0,0 +1,23 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <kfian294ma4@gmail.com>
Date: Wed, 2 Oct 2024 18:45:22 +0100
Subject: [PATCH] Add max armour durability damage
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 8dab67d53a058b62d73e009e378d6376dae70075..a32c4dac9c2a25f52ca39c8dcf7d72acc7ad7f8f 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -2546,6 +2546,12 @@ public abstract class LivingEntity extends Entity implements Attackable {
// Apply damage to armor
if (!damagesource.is(DamageTypeTags.BYPASSES_ARMOR)) {
float armorDamage = (float) (event.getDamage() + event.getDamage(DamageModifier.BLOCKING) + event.getDamage(DamageModifier.HARD_HAT));
+ // Sakura start - add max armour durability damage
+ int maxArmourDamage = this.level().sakuraConfig().players.combat.maxArmourDamage.or(-1);
+ if (maxArmourDamage >= 0) {
+ armorDamage = Math.min(armorDamage, maxArmourDamage);
+ }
+ // Sakura end - add max armour durability damage
this.hurtArmor(damagesource, armorDamage);
}

View File

@@ -0,0 +1,29 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <kfian294ma4@gmail.com>
Date: Sat, 14 Sep 2024 12:04:43 +0100
Subject: [PATCH] Modify bucket stack size
When a player interacts with a bucket this patch adds a data component to change the max stack size.
diff --git a/src/main/java/net/minecraft/world/item/BucketItem.java b/src/main/java/net/minecraft/world/item/BucketItem.java
index 4cb809976b42af933401e8fc34ee43e181761558..ed417a2f5a2105a25d1c2bd57e37785595738144 100644
--- a/src/main/java/net/minecraft/world/item/BucketItem.java
+++ b/src/main/java/net/minecraft/world/item/BucketItem.java
@@ -49,6 +49,17 @@ public class BucketItem extends Item implements DispensibleContainerItem {
this.content = fluid;
}
+ // Sakura start - modify bucket stack size
+ @Override
+ public void verifyComponentsAfterLoad(ItemStack stack) {
+ me.samsuik.sakura.configuration.GlobalConfiguration config = me.samsuik.sakura.configuration.GlobalConfiguration.get();
+ int customItemSize = config == null || !config.players.bucketStackSize.isDefined() ? -1 : config.players.bucketStackSize.intValue();
+ if (customItemSize > 0 && customItemSize < 100) {
+ stack.set(net.minecraft.core.component.DataComponents.MAX_STACK_SIZE, customItemSize);
+ }
+ }
+ // Sakura end - modify bucket stack size
+
@Override
public InteractionResult use(Level world, Player user, InteractionHand hand) {
ItemStack itemstack = user.getItemInHand(hand);

View File

@@ -0,0 +1,23 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <kfian294ma4@gmail.com>
Date: Mon, 11 Nov 2024 19:20:44 +0000
Subject: [PATCH] Configure TNT duplication
Adds a configuration option to enable TNT duplication.
diff --git a/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java b/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java
index 6146c786730b2cd5e5883acbe19d1eecff68e7e3..53065b89ffcbfbf00fd1f16800e4421e24f93d32 100644
--- a/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java
@@ -453,6 +453,11 @@ public class PistonBaseBlock extends DirectionalBlock {
for (j = list.size() - 1; j >= 0; --j) {
// Paper start - fix a variety of piston desync dupes
boolean allowDesync = io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPistonDuplication;
+ // Sakura start - configure tnt duplication
+ if (world.sakuraConfig().technical.allowTNTDuplication && list1.get(j).is(Blocks.TNT)) {
+ allowDesync = true;
+ }
+ // Sakura end - configure tnt duplication
BlockPos oldPos = blockposition3 = (BlockPos) list.get(j);
iblockdata1 = allowDesync ? world.getBlockState(oldPos) : null;
// Paper end - fix a variety of piston desync dupes

View File

@@ -0,0 +1,64 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <kfian294ma4@gmail.com>
Date: Thu, 5 Dec 2024 22:21:39 +0000
Subject: [PATCH] Add lava flow speed api
diff --git a/src/main/java/net/minecraft/world/level/block/LiquidBlock.java b/src/main/java/net/minecraft/world/level/block/LiquidBlock.java
index 6cc129afdb19e121e1abe8dc07f5cc2216c7b084..b4a775c486d6de994591dd6b34055e3a80d9a4d3 100644
--- a/src/main/java/net/minecraft/world/level/block/LiquidBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/LiquidBlock.java
@@ -158,7 +158,7 @@ public class LiquidBlock extends Block implements BucketPickup {
return world.paperConfig().environment.waterOverLavaFlowSpeed;
}
}
- return this.fluid.getTickDelay(world);
+ return this.fluid.getTickDelay(world, blockposition); // Sakura - lava flow speed api
}
private static boolean isLava(Level world, BlockPos blockPos) {
final FluidState fluidState = world.getFluidIfLoaded(blockPos);
diff --git a/src/main/java/net/minecraft/world/level/material/Fluid.java b/src/main/java/net/minecraft/world/level/material/Fluid.java
index 69586077f0d9b0eed1a7de7ef1d743048de0c9d5..86afcda1f14aec7ee9c459e935782037cb0c6634 100644
--- a/src/main/java/net/minecraft/world/level/material/Fluid.java
+++ b/src/main/java/net/minecraft/world/level/material/Fluid.java
@@ -69,6 +69,12 @@ public abstract class Fluid {
protected abstract Vec3 getFlow(BlockGetter world, BlockPos pos, FluidState state);
+ // Sakura start - lava flow speed api
+ public int getTickDelay(final Level world, final BlockPos pos) {
+ return this.getTickDelay(world);
+ }
+ // Sakura end - lava flow speed api
+
public abstract int getTickDelay(LevelReader world);
protected boolean isRandomlyTicking() {
diff --git a/src/main/java/net/minecraft/world/level/material/LavaFluid.java b/src/main/java/net/minecraft/world/level/material/LavaFluid.java
index 5fb8ad171e132174af12d63e45dd623ecac7480a..62d1487ee5820a38f033d60f197b476079ea3e51 100644
--- a/src/main/java/net/minecraft/world/level/material/LavaFluid.java
+++ b/src/main/java/net/minecraft/world/level/material/LavaFluid.java
@@ -182,6 +182,14 @@ public abstract class LavaFluid extends FlowingFluid {
// Sakura end - physics version api
}
+ // Sakura start - lava flow speed api
+ @Override
+ public final int getTickDelay(Level world, BlockPos pos) {
+ final int flowSpeed = world.localConfig().config(pos).lavaFlowSpeed;
+ return flowSpeed >= 0 ? flowSpeed : this.getTickDelay(world);
+ }
+ // Sakura end - lava flow speed api
+
@Override
public int getTickDelay(LevelReader world) {
return world.dimensionType().ultraWarm() && !(world instanceof Level level && level.sakuraConfig().environment.disableFastNetherLava) ? 10 : 30; // Sakura - add option for fast nether lava
@@ -189,7 +197,7 @@ public abstract class LavaFluid extends FlowingFluid {
@Override
public int getSpreadDelay(Level world, BlockPos pos, FluidState oldState, FluidState newState) {
- int i = this.getTickDelay(world);
+ int i = this.getTickDelay(world, pos); // Sakura - lava flow speed api
if (!oldState.isEmpty() && !newState.isEmpty() && !(Boolean) oldState.getValue(LavaFluid.FALLING) && !(Boolean) newState.getValue(LavaFluid.FALLING) && newState.getHeight(world, pos) > oldState.getHeight(world, pos) && world.getRandom().nextInt(4) != 0) {
i *= 4;

View File

@@ -0,0 +1,65 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: MiniDigger <admin@minidigger.me>
Date: Sat, 12 Jun 2021 16:40:34 +0200
Subject: [PATCH] Branding changes
From ForkPaper.
diff --git a/build.gradle.kts b/build.gradle.kts
index 2da91ed6363c0851e4c459188f5e8ef5475e0c97..478101cf841aebfce6d1e2422b96a080a3e56848 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -25,7 +25,7 @@ abstract class MockitoAgentProvider : CommandLineArgumentProvider {
// Paper end - configure mockito agent that is needed in newer java versions
dependencies {
- implementation(project(":paper-api"))
+ implementation(project(":sakura-api")) // Sakura
implementation("ca.spottedleaf:concurrentutil:0.0.2") // Paper - Add ConcurrentUtil dependency
// Paper start
implementation("org.jline:jline-terminal-ffm:3.27.1") // use ffm on java 22+
@@ -100,14 +100,14 @@ tasks.jar {
val gitBranch = git("rev-parse", "--abbrev-ref", "HEAD").getText().trim() // Paper
attributes(
"Main-Class" to "org.bukkit.craftbukkit.Main",
- "Implementation-Title" to "Paper",
+ "Implementation-Title" to "Sakura", // Sakura
"Implementation-Version" to implementationVersion,
"Implementation-Vendor" to date, // Paper
- "Specification-Title" to "Paper",
+ "Specification-Title" to "Sakura", // Sakura
"Specification-Version" to project.version,
"Specification-Vendor" to "Paper Team",
- "Brand-Id" to "papermc:paper",
- "Brand-Name" to "Paper",
+ "Brand-Id" to "samsuik:sakura", // Sakura
+ "Brand-Name" to "Sakura", // Sakura
"Build-Number" to (build ?: ""),
"Build-Time" to Instant.now().toString(),
"Git-Branch" to gitBranch, // Paper
diff --git a/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java b/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java
index 790bad0494454ca12ee152e3de6da3da634d9b20..57f9545e7d94365a1db175ef463fd71dcf508bfd 100644
--- a/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java
+++ b/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java
@@ -61,7 +61,7 @@ public record ServerBuildInfoImpl(
@Override
public boolean isBrandCompatible(final @NotNull Key brandId) {
- return brandId.equals(this.brandId);
+ return brandId.equals(this.brandId) || brandId.equals(BRAND_PAPER_ID); // Sakura
}
@Override
diff --git a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java
index 774556a62eb240da42e84db4502e2ed43495be17..1941fd2dbdc7a10ddf17e2543a038dbd7fe8c88c 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java
@@ -11,7 +11,7 @@ public final class Versioning {
public static String getBukkitVersion() {
String result = "Unknown-Version";
- InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/io.papermc.paper/paper-api/pom.properties");
+ InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/me.samsuik.sakura/sakura-api/pom.properties"); // Sakura
Properties properties = new Properties();
if (stream != null) {