mirror of
https://github.com/Samsuik/Sakura.git
synced 2025-12-30 12:19:08 +00:00
Start on updating 1.21.4
This commit is contained in:
941
migrate/server/feature/0005-Client-Visibility-Settings.patch
Normal file
941
migrate/server/feature/0005-Client-Visibility-Settings.patch
Normal file
@@ -0,0 +1,941 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samsuik <kfian294ma4@gmail.com>
|
||||
Date: Tue, 21 Sep 2021 23:54:25 +0100
|
||||
Subject: [PATCH] Client Visibility Settings
|
||||
|
||||
|
||||
diff --git a/src/main/java/me/samsuik/sakura/command/SakuraCommands.java b/src/main/java/me/samsuik/sakura/command/SakuraCommands.java
|
||||
index 3e85c19db0655034c203eaab8d2e6b5504da5da8..cbb2e57f9ab3b48a6e5f792711c4c6fd2d34d445 100644
|
||||
--- a/src/main/java/me/samsuik/sakura/command/SakuraCommands.java
|
||||
+++ b/src/main/java/me/samsuik/sakura/command/SakuraCommands.java
|
||||
@@ -1,6 +1,9 @@
|
||||
package me.samsuik.sakura.command;
|
||||
|
||||
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 net.minecraft.server.MinecraftServer;
|
||||
import org.bukkit.command.Command;
|
||||
|
||||
@@ -12,6 +15,9 @@ public final class SakuraCommands {
|
||||
static {
|
||||
COMMANDS.put("sakura", new SakuraCommand("sakura"));
|
||||
COMMANDS.put("config", new ConfigCommand("config"));
|
||||
+ COMMANDS.put("fps", new FPSCommand("fps"));
|
||||
+ COMMANDS.put("tntvisibility", new VisualCommand(VisibilityTypes.TNT, "tnttoggle"));
|
||||
+ COMMANDS.put("sandvisibility", new VisualCommand(VisibilityTypes.SAND, "sandtoggle"));
|
||||
}
|
||||
|
||||
public static void registerCommands(MinecraftServer server) {
|
||||
diff --git a/src/main/java/me/samsuik/sakura/command/subcommands/FPSCommand.java b/src/main/java/me/samsuik/sakura/command/subcommands/FPSCommand.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..a85f84ebfef4ed3f3dc2a337a057d541f64c9d0e
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/me/samsuik/sakura/command/subcommands/FPSCommand.java
|
||||
@@ -0,0 +1,24 @@
|
||||
+package me.samsuik.sakura.command.subcommands;
|
||||
+
|
||||
+import me.samsuik.sakura.command.BaseSubCommand;
|
||||
+import me.samsuik.sakura.player.visibility.VisibilityGui;
|
||||
+import org.bukkit.command.CommandSender;
|
||||
+import org.bukkit.entity.Player;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public final class FPSCommand extends BaseSubCommand {
|
||||
+ private final VisibilityGui visibilityGui = new VisibilityGui();
|
||||
+
|
||||
+ public FPSCommand(String name) {
|
||||
+ super(name);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void execute(CommandSender sender, String[] args) {
|
||||
+ if (sender instanceof Player player) {
|
||||
+ this.visibilityGui.showTo(player);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/me/samsuik/sakura/command/subcommands/VisualCommand.java b/src/main/java/me/samsuik/sakura/command/subcommands/VisualCommand.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..cd9ebbb7bbb90c87faf75fcc4b487e93573f1387
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/me/samsuik/sakura/command/subcommands/VisualCommand.java
|
||||
@@ -0,0 +1,41 @@
|
||||
+package me.samsuik.sakura.command.subcommands;
|
||||
+
|
||||
+import me.samsuik.sakura.command.BaseSubCommand;
|
||||
+import me.samsuik.sakura.configuration.GlobalConfiguration;
|
||||
+import me.samsuik.sakura.player.visibility.VisibilitySettings;
|
||||
+import me.samsuik.sakura.player.visibility.VisibilityState;
|
||||
+import me.samsuik.sakura.player.visibility.VisibilityType;
|
||||
+import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
|
||||
+import org.bukkit.command.CommandSender;
|
||||
+import org.bukkit.entity.Player;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
+
|
||||
+import java.util.Arrays;
|
||||
+
|
||||
+@DefaultQualifier(NonNull.class)
|
||||
+public final class VisualCommand extends BaseSubCommand {
|
||||
+ private final VisibilityType type;
|
||||
+
|
||||
+ public VisualCommand(VisibilityType type, String... aliases) {
|
||||
+ super(type.key() + "visibility");
|
||||
+ this.setAliases(Arrays.asList(aliases));
|
||||
+ this.type = type;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void execute(CommandSender sender, String[] args) {
|
||||
+ if (!(sender instanceof Player player)) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ VisibilitySettings settings = player.getVisibility();
|
||||
+ VisibilityState state = settings.toggle(type);
|
||||
+
|
||||
+ String stateName = (state == VisibilityState.ON) ? "Enabled" : "Disabled";
|
||||
+ player.sendRichMessage(GlobalConfiguration.get().messages.fpsSettingChange,
|
||||
+ Placeholder.unparsed("name", this.type.key()),
|
||||
+ Placeholder.unparsed("state", stateName)
|
||||
+ );
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/me/samsuik/sakura/player/gui/FeatureGui.java b/src/main/java/me/samsuik/sakura/player/gui/FeatureGui.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..49f53c01d61cbe551aa68a91f53782e8f01d9c67
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/me/samsuik/sakura/player/gui/FeatureGui.java
|
||||
@@ -0,0 +1,44 @@
|
||||
+package me.samsuik.sakura.player.gui;
|
||||
+
|
||||
+import me.samsuik.sakura.player.gui.components.GuiComponent;
|
||||
+import net.kyori.adventure.text.Component;
|
||||
+import org.bukkit.entity.Player;
|
||||
+import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
+import org.bukkit.inventory.Inventory;
|
||||
+import org.jetbrains.annotations.ApiStatus;
|
||||
+import org.jspecify.annotations.NullMarked;
|
||||
+
|
||||
+@NullMarked
|
||||
+public abstract class FeatureGui {
|
||||
+ private final int size;
|
||||
+ private final Component title;
|
||||
+
|
||||
+ public FeatureGui(int size, Component title) {
|
||||
+ this.size = size;
|
||||
+ this.title = title;
|
||||
+ }
|
||||
+
|
||||
+ protected abstract void fillInventory(Inventory inventory);
|
||||
+
|
||||
+ protected abstract void afterFill(Player player, FeatureGuiInventory inventory);
|
||||
+
|
||||
+ public final void showTo(Player bukkitPlayer) {
|
||||
+ FeatureGuiInventory featureInventory = new FeatureGuiInventory(this, this.size, this.title);
|
||||
+ this.fillInventory(featureInventory.getInventory());
|
||||
+ this.afterFill(bukkitPlayer, featureInventory);
|
||||
+ bukkitPlayer.openInventory(featureInventory.getInventory());
|
||||
+ }
|
||||
+
|
||||
+ @ApiStatus.Internal
|
||||
+ public static void clickEvent(InventoryClickEvent event) {
|
||||
+ Inventory clicked = event.getClickedInventory();
|
||||
+ if (clicked != null && clicked.getHolder(false) instanceof FeatureGuiInventory featureInventory) {
|
||||
+ event.setCancelled(true);
|
||||
+ for (GuiComponent component : featureInventory.getComponents().reversed()) {
|
||||
+ if (component.interaction(event, featureInventory)) {
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/me/samsuik/sakura/player/gui/FeatureGuiInventory.java b/src/main/java/me/samsuik/sakura/player/gui/FeatureGuiInventory.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..6c86501b8a392ed04c46646bfac0cad9b2ca33bc
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/me/samsuik/sakura/player/gui/FeatureGuiInventory.java
|
||||
@@ -0,0 +1,90 @@
|
||||
+package me.samsuik.sakura.player.gui;
|
||||
+
|
||||
+import com.google.common.base.Preconditions;
|
||||
+import com.google.common.collect.HashMultimap;
|
||||
+import com.google.common.collect.ImmutableList;
|
||||
+import com.google.common.collect.Multimap;
|
||||
+import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap;
|
||||
+import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
|
||||
+import me.samsuik.sakura.player.gui.components.GuiComponent;
|
||||
+import net.kyori.adventure.text.Component;
|
||||
+import org.bukkit.Bukkit;
|
||||
+import org.bukkit.NamespacedKey;
|
||||
+import org.bukkit.inventory.Inventory;
|
||||
+import org.bukkit.inventory.InventoryHolder;
|
||||
+import org.jspecify.annotations.NullMarked;
|
||||
+
|
||||
+import java.util.Collection;
|
||||
+import java.util.Optional;
|
||||
+
|
||||
+@NullMarked
|
||||
+public final class FeatureGuiInventory implements InventoryHolder {
|
||||
+ private final Inventory inventory;
|
||||
+ private final FeatureGui gui;
|
||||
+ private final Multimap<NamespacedKey, GuiComponent> componentsUnderKey = HashMultimap.create();
|
||||
+ private final Object2ObjectMap<GuiComponent, NamespacedKey> componentKeys = new Object2ObjectLinkedOpenHashMap<>();
|
||||
+
|
||||
+ public FeatureGuiInventory(FeatureGui gui, int size, Component component) {
|
||||
+ this.inventory = Bukkit.createInventory(this, size, component);
|
||||
+ this.gui = gui;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Inventory getInventory() {
|
||||
+ return this.inventory;
|
||||
+ }
|
||||
+
|
||||
+ public FeatureGui getGui() {
|
||||
+ return this.gui;
|
||||
+ }
|
||||
+
|
||||
+ public ImmutableList<GuiComponent> getComponents() {
|
||||
+ return ImmutableList.copyOf(this.componentKeys.keySet());
|
||||
+ }
|
||||
+
|
||||
+ public ImmutableList<GuiComponent> findComponents(NamespacedKey key) {
|
||||
+ return ImmutableList.copyOf(this.componentsUnderKey.get(key));
|
||||
+ }
|
||||
+
|
||||
+ public Optional<GuiComponent> findFirst(NamespacedKey key) {
|
||||
+ Collection<GuiComponent> components = this.componentsUnderKey.get(key);
|
||||
+ return components.stream().findFirst();
|
||||
+ }
|
||||
+
|
||||
+ public void removeComponents(NamespacedKey key) {
|
||||
+ Collection<GuiComponent> removed = this.componentsUnderKey.removeAll(key);
|
||||
+ for (GuiComponent component : removed) {
|
||||
+ this.componentKeys.remove(component);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public void addComponent(GuiComponent component, NamespacedKey key) {
|
||||
+ Preconditions.checkArgument(!this.componentKeys.containsKey(component), "component has already been added");
|
||||
+ this.componentKeys.put(component, key);
|
||||
+ this.componentsUnderKey.put(key, component);
|
||||
+ this.inventoryUpdate(component);
|
||||
+ }
|
||||
+
|
||||
+ public void removeComponent(GuiComponent component) {
|
||||
+ NamespacedKey key = this.componentKeys.remove(component);
|
||||
+ this.componentsUnderKey.remove(key, component);
|
||||
+ }
|
||||
+
|
||||
+ public void replaceComponent(GuiComponent component, GuiComponent replacement) {
|
||||
+ NamespacedKey key = this.componentKeys.remove(component);
|
||||
+ Preconditions.checkNotNull(key, "component does not exist");
|
||||
+ this.componentKeys.put(replacement, key);
|
||||
+ this.componentsUnderKey.remove(key, component);
|
||||
+ this.componentsUnderKey.put(key, replacement);
|
||||
+ this.inventoryUpdate(replacement);
|
||||
+ }
|
||||
+
|
||||
+ public void removeAllComponents() {
|
||||
+ this.componentKeys.clear();
|
||||
+ this.componentsUnderKey.clear();
|
||||
+ }
|
||||
+
|
||||
+ private void inventoryUpdate(GuiComponent component) {
|
||||
+ component.creation(this.inventory);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/me/samsuik/sakura/player/gui/ItemStackUtil.java b/src/main/java/me/samsuik/sakura/player/gui/ItemStackUtil.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..eddf7632f194142c48f4012734128a10e422eea6
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/me/samsuik/sakura/player/gui/ItemStackUtil.java
|
||||
@@ -0,0 +1,19 @@
|
||||
+package me.samsuik.sakura.player.gui;
|
||||
+
|
||||
+import net.kyori.adventure.text.Component;
|
||||
+import org.bukkit.Material;
|
||||
+import org.bukkit.inventory.ItemStack;
|
||||
+import org.jspecify.annotations.NullMarked;
|
||||
+
|
||||
+@NullMarked
|
||||
+public class ItemStackUtil {
|
||||
+ public static ItemStack itemWithBlankName(Material material) {
|
||||
+ return itemWithName(material, Component.empty());
|
||||
+ }
|
||||
+
|
||||
+ public static ItemStack itemWithName(Material material, Component component) {
|
||||
+ ItemStack item = new ItemStack(material);
|
||||
+ item.editMeta(m -> m.itemName(component));
|
||||
+ return item;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/me/samsuik/sakura/player/gui/components/GuiClickEvent.java b/src/main/java/me/samsuik/sakura/player/gui/components/GuiClickEvent.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..39065d5003bfa60e7453079eb3202bea1b605d4a
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/me/samsuik/sakura/player/gui/components/GuiClickEvent.java
|
||||
@@ -0,0 +1,10 @@
|
||||
+package me.samsuik.sakura.player.gui.components;
|
||||
+
|
||||
+import me.samsuik.sakura.player.gui.FeatureGuiInventory;
|
||||
+import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
+import org.jspecify.annotations.NullMarked;
|
||||
+
|
||||
+@NullMarked
|
||||
+public interface GuiClickEvent {
|
||||
+ void doSomething(InventoryClickEvent event, FeatureGuiInventory inventory);
|
||||
+}
|
||||
diff --git a/src/main/java/me/samsuik/sakura/player/gui/components/GuiComponent.java b/src/main/java/me/samsuik/sakura/player/gui/components/GuiComponent.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..5a2ff0ca3462254bc4e01192b48c321c6f34e909
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/me/samsuik/sakura/player/gui/components/GuiComponent.java
|
||||
@@ -0,0 +1,13 @@
|
||||
+package me.samsuik.sakura.player.gui.components;
|
||||
+
|
||||
+import me.samsuik.sakura.player.gui.FeatureGuiInventory;
|
||||
+import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
+import org.bukkit.inventory.Inventory;
|
||||
+import org.jspecify.annotations.NullMarked;
|
||||
+
|
||||
+@NullMarked
|
||||
+public interface GuiComponent {
|
||||
+ boolean interaction(InventoryClickEvent event, FeatureGuiInventory featureInventory);
|
||||
+
|
||||
+ void creation(Inventory inventory);
|
||||
+}
|
||||
diff --git a/src/main/java/me/samsuik/sakura/player/gui/components/ItemButton.java b/src/main/java/me/samsuik/sakura/player/gui/components/ItemButton.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..6d49d3390b2e01fcffd638abdde569d1788f3256
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/me/samsuik/sakura/player/gui/components/ItemButton.java
|
||||
@@ -0,0 +1,34 @@
|
||||
+package me.samsuik.sakura.player.gui.components;
|
||||
+
|
||||
+import me.samsuik.sakura.player.gui.FeatureGuiInventory;
|
||||
+import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
+import org.bukkit.inventory.Inventory;
|
||||
+import org.bukkit.inventory.ItemStack;
|
||||
+import org.jspecify.annotations.NullMarked;
|
||||
+
|
||||
+@NullMarked
|
||||
+public final class ItemButton implements GuiComponent {
|
||||
+ private final ItemStack bukkitItem;
|
||||
+ private final int slot;
|
||||
+ private final GuiClickEvent whenClicked;
|
||||
+
|
||||
+ public ItemButton(ItemStack bukkitItem, int slot, GuiClickEvent whenClicked) {
|
||||
+ this.bukkitItem = bukkitItem;
|
||||
+ this.slot = slot;
|
||||
+ this.whenClicked = whenClicked;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean interaction(InventoryClickEvent event, FeatureGuiInventory featureInventory) {
|
||||
+ if (event.getSlot() == this.slot) {
|
||||
+ this.whenClicked.doSomething(event, featureInventory);
|
||||
+ return true;
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void creation(Inventory inventory) {
|
||||
+ inventory.setItem(this.slot, this.bukkitItem);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/me/samsuik/sakura/player/gui/components/ItemSwitch.java b/src/main/java/me/samsuik/sakura/player/gui/components/ItemSwitch.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..243f1cbabf7054d7d5092f21e923e4dea5085123
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/me/samsuik/sakura/player/gui/components/ItemSwitch.java
|
||||
@@ -0,0 +1,44 @@
|
||||
+package me.samsuik.sakura.player.gui.components;
|
||||
+
|
||||
+import com.google.common.base.Preconditions;
|
||||
+import me.samsuik.sakura.player.gui.FeatureGuiInventory;
|
||||
+import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
+import org.bukkit.inventory.Inventory;
|
||||
+import org.bukkit.inventory.ItemStack;
|
||||
+import org.jspecify.annotations.NullMarked;
|
||||
+
|
||||
+import java.util.Collections;
|
||||
+import java.util.List;
|
||||
+
|
||||
+@NullMarked
|
||||
+public final class ItemSwitch implements GuiComponent {
|
||||
+ private final List<ItemStack> items;
|
||||
+ private final int slot;
|
||||
+ private final int selected;
|
||||
+ private final GuiClickEvent whenClicked;
|
||||
+
|
||||
+ public ItemSwitch(List<ItemStack> items, int slot, int selected, GuiClickEvent whenClicked) {
|
||||
+ Preconditions.checkArgument(!items.isEmpty());
|
||||
+ this.items = Collections.unmodifiableList(items);
|
||||
+ this.slot = slot;
|
||||
+ this.selected = selected;
|
||||
+ this.whenClicked = whenClicked;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean interaction(InventoryClickEvent event, FeatureGuiInventory featureInventory) {
|
||||
+ if (this.slot == event.getSlot()) {
|
||||
+ int next = (this.selected + 1) % this.items.size();
|
||||
+ ItemSwitch itemSwitch = new ItemSwitch(this.items, this.slot, next, this.whenClicked);
|
||||
+ featureInventory.replaceComponent(this, itemSwitch);
|
||||
+ this.whenClicked.doSomething(event, featureInventory);
|
||||
+ return true;
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void creation(Inventory inventory) {
|
||||
+ inventory.setItem(this.slot, this.items.get(this.selected));
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/me/samsuik/sakura/player/visibility/PlayerVisibilitySettings.java b/src/main/java/me/samsuik/sakura/player/visibility/PlayerVisibilitySettings.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..938fe2143d0db2a0760022433c951155b5e088c3
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/me/samsuik/sakura/player/visibility/PlayerVisibilitySettings.java
|
||||
@@ -0,0 +1,65 @@
|
||||
+package me.samsuik.sakura.player.visibility;
|
||||
+
|
||||
+import it.unimi.dsi.fastutil.objects.Reference2ObjectMap;
|
||||
+import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap;
|
||||
+import net.minecraft.nbt.CompoundTag;
|
||||
+import org.jetbrains.annotations.NotNull;
|
||||
+import org.jspecify.annotations.NonNull;
|
||||
+
|
||||
+public final class PlayerVisibilitySettings implements VisibilitySettings {
|
||||
+ private static final String SETTINGS_COMPOUND_TAG = "clientVisibilitySettings";
|
||||
+ private final Reference2ObjectMap<VisibilityType, VisibilityState> visibilityStates = new Reference2ObjectOpenHashMap<>();
|
||||
+
|
||||
+ @Override
|
||||
+ public @NonNull VisibilityState get(@NonNull VisibilityType type) {
|
||||
+ VisibilityState state = this.visibilityStates.get(type);
|
||||
+ return state != null ? state : type.getDefault();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public @NotNull VisibilityState set(@NonNull VisibilityType type, @NonNull VisibilityState state) {
|
||||
+ if (type.isDefault(state)) {
|
||||
+ this.visibilityStates.remove(type);
|
||||
+ } else {
|
||||
+ this.visibilityStates.put(type, state);
|
||||
+ }
|
||||
+ return state;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public @NonNull VisibilityState currentState() {
|
||||
+ int modifiedCount = this.visibilityStates.size();
|
||||
+ if (modifiedCount == 0) {
|
||||
+ return VisibilityState.ON;
|
||||
+ } else if (modifiedCount != VisibilityTypes.types().size()) {
|
||||
+ return VisibilityState.MODIFIED;
|
||||
+ } else {
|
||||
+ return VisibilityState.OFF;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean playerModified() {
|
||||
+ return !this.visibilityStates.isEmpty();
|
||||
+ }
|
||||
+
|
||||
+ public void loadData(@NonNull CompoundTag tag) {
|
||||
+ if (!tag.contains(SETTINGS_COMPOUND_TAG, CompoundTag.TAG_COMPOUND)) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ CompoundTag settingsTag = tag.getCompound(SETTINGS_COMPOUND_TAG);
|
||||
+ for (VisibilityType type : VisibilityTypes.types()) {
|
||||
+ if (settingsTag.contains(type.key(), CompoundTag.TAG_STRING)) {
|
||||
+ VisibilityState state = VisibilityState.valueOf(settingsTag.getString(type.key()));
|
||||
+ this.visibilityStates.put(type, state);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public void saveData(@NonNull CompoundTag tag) {
|
||||
+ CompoundTag settingsTag = new CompoundTag();
|
||||
+ this.visibilityStates.forEach((t, s) -> settingsTag.putString(t.key(), s.name()));
|
||||
+ tag.put(SETTINGS_COMPOUND_TAG, settingsTag);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/me/samsuik/sakura/player/visibility/VisibilityGui.java b/src/main/java/me/samsuik/sakura/player/visibility/VisibilityGui.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..67b821b7a614704cb736afe286e967e1c955a289
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/me/samsuik/sakura/player/visibility/VisibilityGui.java
|
||||
@@ -0,0 +1,96 @@
|
||||
+package me.samsuik.sakura.player.visibility;
|
||||
+
|
||||
+import it.unimi.dsi.fastutil.ints.IntArrayFIFOQueue;
|
||||
+import me.samsuik.sakura.configuration.GlobalConfiguration;
|
||||
+import me.samsuik.sakura.player.gui.FeatureGui;
|
||||
+import me.samsuik.sakura.player.gui.FeatureGuiInventory;
|
||||
+import me.samsuik.sakura.player.gui.components.ItemButton;
|
||||
+import me.samsuik.sakura.player.gui.components.ItemSwitch;
|
||||
+import net.kyori.adventure.text.Component;
|
||||
+import org.bukkit.Material;
|
||||
+import org.bukkit.NamespacedKey;
|
||||
+import org.bukkit.entity.Player;
|
||||
+import org.bukkit.inventory.Inventory;
|
||||
+import org.jspecify.annotations.NullMarked;
|
||||
+
|
||||
+import static me.samsuik.sakura.player.gui.ItemStackUtil.itemWithBlankName;
|
||||
+
|
||||
+@NullMarked
|
||||
+public final class VisibilityGui extends FeatureGui {
|
||||
+ private static final NamespacedKey TOGGLE_BUTTON_KEY = new NamespacedKey("sakura", "toggle_button");
|
||||
+ private static final NamespacedKey MENU_ITEMS_KEY = new NamespacedKey("sakura", "menu_items");
|
||||
+
|
||||
+ public VisibilityGui() {
|
||||
+ super(45, Component.text("FPS Settings"));
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected void fillInventory(Inventory inventory) {
|
||||
+ for (int slot = 0; slot < inventory.getSize(); ++slot) {
|
||||
+ // x, y from top left of the inventory
|
||||
+ int x = slot % 9;
|
||||
+ int y = slot / 9;
|
||||
+ // from center
|
||||
+ int rx = x - 4;
|
||||
+ int ry = y - 2;
|
||||
+ double d = Math.sqrt(rx * rx + ry * ry);
|
||||
+ if (d <= 3.25) {
|
||||
+ inventory.setItem(slot, itemWithBlankName(GlobalConfiguration.get().fps.material));
|
||||
+ } else if (x % 8 == 0) {
|
||||
+ inventory.setItem(slot, itemWithBlankName(Material.BLACK_STAINED_GLASS_PANE));
|
||||
+ } else {
|
||||
+ inventory.setItem(slot, itemWithBlankName(Material.WHITE_STAINED_GLASS_PANE));
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected void afterFill(Player player, FeatureGuiInventory inventory) {
|
||||
+ VisibilitySettings settings = player.getVisibility();
|
||||
+ IntArrayFIFOQueue slots = this.availableSlots();
|
||||
+ this.updateToggleButton(settings, player, inventory);
|
||||
+ for (VisibilityType type : VisibilityTypes.types()) {
|
||||
+ VisibilityState state = settings.get(type);
|
||||
+ int index = type.states().indexOf(state);
|
||||
+ int slot = slots.dequeueInt();
|
||||
+
|
||||
+ ItemSwitch itemSwitch = new ItemSwitch(
|
||||
+ VisibilityGuiItems.GUI_ITEMS.get(type),
|
||||
+ slot, index,
|
||||
+ (e, inv) -> {
|
||||
+ settings.cycle(type);
|
||||
+ this.updateToggleButton(settings, player, inv);
|
||||
+ }
|
||||
+ );
|
||||
+
|
||||
+ inventory.addComponent(itemSwitch, MENU_ITEMS_KEY);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private void updateToggleButton(VisibilitySettings settings, Player player, FeatureGuiInventory inventory) {
|
||||
+ inventory.removeComponents(TOGGLE_BUTTON_KEY);
|
||||
+ VisibilityState settingsState = settings.currentState();
|
||||
+ ItemButton button = new ItemButton(
|
||||
+ VisibilityGuiItems.TOGGLE_BUTTON_ITEMS.get(settingsState),
|
||||
+ (2 * 9) + 8,
|
||||
+ (e, inv) -> {
|
||||
+ settings.toggleAll();
|
||||
+ inventory.removeAllComponents();
|
||||
+ this.afterFill(player, inv);
|
||||
+ }
|
||||
+ );
|
||||
+ inventory.addComponent(button, TOGGLE_BUTTON_KEY);
|
||||
+ }
|
||||
+
|
||||
+ private IntArrayFIFOQueue availableSlots() {
|
||||
+ IntArrayFIFOQueue slots = new IntArrayFIFOQueue();
|
||||
+ for (int row = 1; row < 4; ++row) {
|
||||
+ for (int column = 3; column < 6; ++column) {
|
||||
+ if ((column + row) % 2 == 0) {
|
||||
+ slots.enqueue((row * 9) + column);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return slots;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/me/samsuik/sakura/player/visibility/VisibilityGuiItems.java b/src/main/java/me/samsuik/sakura/player/visibility/VisibilityGuiItems.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..ca26410b394602f3aa0e50efc8109ad9c6ec0611
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/me/samsuik/sakura/player/visibility/VisibilityGuiItems.java
|
||||
@@ -0,0 +1,55 @@
|
||||
+package me.samsuik.sakura.player.visibility;
|
||||
+
|
||||
+import com.google.common.collect.ImmutableList;
|
||||
+import it.unimi.dsi.fastutil.objects.Reference2ObjectMap;
|
||||
+import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap;
|
||||
+import me.samsuik.sakura.player.gui.ItemStackUtil;
|
||||
+import net.kyori.adventure.text.Component;
|
||||
+import net.kyori.adventure.text.format.NamedTextColor;
|
||||
+import org.apache.commons.lang.StringUtils;
|
||||
+import org.bukkit.Material;
|
||||
+import org.bukkit.inventory.ItemStack;
|
||||
+
|
||||
+import java.util.Locale;
|
||||
+
|
||||
+public final class VisibilityGuiItems {
|
||||
+ static final Reference2ObjectMap<VisibilityType, ImmutableList<ItemStack>> GUI_ITEMS = new Reference2ObjectOpenHashMap<>();
|
||||
+ static final Reference2ObjectMap<VisibilityState, ItemStack> TOGGLE_BUTTON_ITEMS = new Reference2ObjectOpenHashMap<>();
|
||||
+
|
||||
+ static {
|
||||
+ Reference2ObjectMap<VisibilityType, ItemStack> items = new Reference2ObjectOpenHashMap<>();
|
||||
+
|
||||
+ items.put(VisibilityTypes.TNT, ItemStackUtil.itemWithName(Material.TNT, Component.text("Tnt", NamedTextColor.RED)));
|
||||
+ items.put(VisibilityTypes.SAND, ItemStackUtil.itemWithName(Material.SAND, Component.text("Sand", NamedTextColor.YELLOW)));
|
||||
+ items.put(VisibilityTypes.EXPLOSIONS, ItemStackUtil.itemWithName(Material.COBWEB, Component.text("Explosions", NamedTextColor.WHITE)));
|
||||
+ items.put(VisibilityTypes.SPAWNERS, ItemStackUtil.itemWithName(Material.SPAWNER, Component.text("Spawners", NamedTextColor.DARK_GRAY)));
|
||||
+ items.put(VisibilityTypes.PISTONS, ItemStackUtil.itemWithName(Material.PISTON, Component.text("Pistons", NamedTextColor.GOLD)));
|
||||
+
|
||||
+ for (VisibilityType type : VisibilityTypes.types()) {
|
||||
+ ItemStack item = items.get(type);
|
||||
+
|
||||
+ ImmutableList<ItemStack> stateItems = type.states().stream()
|
||||
+ .map(s -> createItemForState(item, s))
|
||||
+ .collect(ImmutableList.toImmutableList());
|
||||
+
|
||||
+ GUI_ITEMS.put(type, stateItems);
|
||||
+ }
|
||||
+
|
||||
+ TOGGLE_BUTTON_ITEMS.put(VisibilityState.ON, ItemStackUtil.itemWithName(Material.GREEN_STAINED_GLASS_PANE, Component.text("Enabled", NamedTextColor.GREEN)));
|
||||
+ TOGGLE_BUTTON_ITEMS.put(VisibilityState.MODIFIED, ItemStackUtil.itemWithName(Material.MAGENTA_STAINED_GLASS_PANE, Component.text("Modified", NamedTextColor.LIGHT_PURPLE)));
|
||||
+ TOGGLE_BUTTON_ITEMS.put(VisibilityState.OFF, ItemStackUtil.itemWithName(Material.RED_STAINED_GLASS_PANE, Component.text("Disabled", NamedTextColor.RED)));
|
||||
+ }
|
||||
+
|
||||
+ private static String lowercaseThenCapitalise(String name) {
|
||||
+ String lowercaseName = name.toLowerCase(Locale.ENGLISH);
|
||||
+ return StringUtils.capitalize(lowercaseName);
|
||||
+ }
|
||||
+
|
||||
+ private static ItemStack createItemForState(ItemStack in, VisibilityState state) {
|
||||
+ String capitalisedName = lowercaseThenCapitalise(state.name());
|
||||
+ Component component = Component.text(" | " + capitalisedName, NamedTextColor.GRAY);
|
||||
+ ItemStack itemCopy = in.clone();
|
||||
+ itemCopy.editMeta(m -> m.itemName(m.itemName().append(component)));
|
||||
+ return itemCopy;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java
|
||||
index 1a37654aff9a9c86c9f7af10a1cf721371f0c5ec..82644b34a77dc5e5af38260b7b07b3ec9aceae33 100644
|
||||
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java
|
||||
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java
|
||||
@@ -19,7 +19,7 @@ public class ClientboundSectionBlocksUpdatePacket implements Packet<ClientGamePa
|
||||
private static final int POS_IN_SECTION_BITS = 12;
|
||||
private final SectionPos sectionPos;
|
||||
private final short[] positions;
|
||||
- private final BlockState[] states;
|
||||
+ public final BlockState[] states; // Sakura - private -> public
|
||||
|
||||
public ClientboundSectionBlocksUpdatePacket(SectionPos sectionPos, ShortSet positions, LevelChunkSection section) {
|
||||
this.sectionPos = sectionPos;
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 1f9f023a43c16cc472deea5285b01c19136e019f..cf1e4cb1cdbda7dd1668ca40a788173942572a9e 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -1891,6 +1891,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
gameprofilerfiller.pop();
|
||||
worldserver.explosionDensityCache.clear(); // Paper - Optimize explosions
|
||||
worldserver.localConfig().expire(currentTick); // Sakura - add local config
|
||||
+ worldserver.explosionPositions.clear(); // Sakura - client visibility settings
|
||||
}
|
||||
this.isIteratingOverLevels = false; // Paper - Throw exception on world create while being ticked
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index cfeeddf2cb4ff50dbc29c6913e78ca1dee076790..d6c3f39cc9359f5d0fc5082949a7c860c38881cc 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -179,6 +179,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
this.handleLegacyStructureIndex(pos);
|
||||
}
|
||||
// Paper end - rewrite chunk system
|
||||
+ private final it.unimi.dsi.fastutil.longs.Long2IntMap minimalEntities; // Sakura - client visibility settings; minimal tnt/sand
|
||||
|
||||
public ChunkMap(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureTemplateManager structureTemplateManager, Executor executor, BlockableEventLoop<Runnable> mainThreadExecutor, LightChunkGetter chunkProvider, ChunkGenerator chunkGenerator, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier<DimensionDataStorage> persistentStateManagerFactory, int viewDistance, boolean dsync) {
|
||||
super(new RegionStorageInfo(session.getLevelId(), world.dimension(), "chunk"), session.getDimensionPath(world.dimension()).resolve("region"), dataFixer, dsync);
|
||||
@@ -222,6 +223,10 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
this.poiManager = new PoiManager(new RegionStorageInfo(session.getLevelId(), world.dimension(), "poi"), path.resolve("poi"), dataFixer, dsync, iregistrycustom, world.getServer(), world);
|
||||
this.setServerViewDistance(viewDistance);
|
||||
this.worldGenContext = new WorldGenContext(world, chunkGenerator, structureTemplateManager, this.lightEngine, null, this::setChunkUnsaved); // Paper - rewrite chunk system
|
||||
+ // Sakura start - client visibility settings; minimal tnt/sand
|
||||
+ this.minimalEntities = new it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap();
|
||||
+ this.minimalEntities.defaultReturnValue(Integer.MIN_VALUE);
|
||||
+ // Sakura end - client visibility settings; minimal tnt/sand
|
||||
}
|
||||
|
||||
private void setChunkUnsaved(ChunkPos pos) {
|
||||
@@ -973,6 +978,8 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
tracker.serverEntity.sendChanges();
|
||||
}
|
||||
}
|
||||
+
|
||||
+ this.minimalEntities.clear(); // Sakura - client visibility settings; minimal tnt/sand
|
||||
}
|
||||
// Paper end - optimise entity tracker
|
||||
|
||||
@@ -1210,6 +1217,32 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
return !this.seenBy.isEmpty();
|
||||
}
|
||||
// Paper end - optimise entity tracker
|
||||
+ // Sakura start - client visibility settings; entity visibility
|
||||
+ private boolean checkEntityVisibility(final ServerPlayer player) {
|
||||
+ final Entity entity = this.entity;
|
||||
+ final me.samsuik.sakura.player.visibility.VisibilitySettings settings = player.visibilitySettings;
|
||||
+ if (!settings.playerModified() || !(entity.isPrimedTNT || entity.isFallingBlock)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ final me.samsuik.sakura.player.visibility.VisibilityType type;
|
||||
+ if (entity.isPrimedTNT) {
|
||||
+ type = me.samsuik.sakura.player.visibility.VisibilityTypes.TNT;
|
||||
+ } else {
|
||||
+ type = me.samsuik.sakura.player.visibility.VisibilityTypes.SAND;
|
||||
+ }
|
||||
+ final me.samsuik.sakura.player.visibility.VisibilityState state = settings.get(type);
|
||||
+ if (state == me.samsuik.sakura.player.visibility.VisibilityState.MINIMAL) {
|
||||
+ final long key = entity.blockPosition().asLong() ^ entity.getType().hashCode();
|
||||
+ final long visibleEntity = ChunkMap.this.minimalEntities.get(key);
|
||||
+ if (visibleEntity != Integer.MIN_VALUE) {
|
||||
+ return entity.getId() == visibleEntity;
|
||||
+ } else {
|
||||
+ ChunkMap.this.minimalEntities.put(key, entity.getId());
|
||||
+ }
|
||||
+ }
|
||||
+ return state != me.samsuik.sakura.player.visibility.VisibilityState.OFF;
|
||||
+ }
|
||||
+ // Sakura end - client visibility settings; entity visibility
|
||||
|
||||
public TrackedEntity(final Entity entity, final int i, final int j, final boolean flag) {
|
||||
this.serverEntity = new ServerEntity(ChunkMap.this.level, entity, j, flag, this::broadcast, this.seenBy); // CraftBukkit
|
||||
@@ -1287,6 +1320,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
}
|
||||
flag = flag && this.entity.broadcastToPlayer(player) && ChunkMap.this.isChunkTracked(player, this.entity.chunkPosition().x, this.entity.chunkPosition().z);
|
||||
// Paper end - Configurable entity tracking range by Y
|
||||
+ flag = flag && this.checkEntityVisibility(player); // Sakura start - client visibility settings; entity visibility
|
||||
|
||||
// CraftBukkit start - respect vanish API
|
||||
if (flag && !player.getBukkitEntity().canSee(this.entity.getBukkitEntity())) { // Paper - only consider hits
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 876dc65f91bf09865563c8d583b78e4fdafd82b7..9ff9f5a5d9d156b3a2a939e67c412470b2631d8d 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -595,6 +595,21 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
this.lagCompensationTick = (System.nanoTime() - net.minecraft.server.MinecraftServer.SERVER_INIT) / (java.util.concurrent.TimeUnit.MILLISECONDS.toNanos(50L));
|
||||
}
|
||||
// Paper end - lag compensation
|
||||
+ // Sakura start - client visibility settings
|
||||
+ public final LongSet explosionPositions = new it.unimi.dsi.fastutil.longs.LongOpenHashSet();
|
||||
+
|
||||
+ public final boolean checkExplosionVisibility(final Vec3 position, final ServerPlayer player) {
|
||||
+ final me.samsuik.sakura.player.visibility.VisibilitySettings settings = player.visibilitySettings;
|
||||
+ if (settings.isDisabled(me.samsuik.sakura.player.visibility.VisibilityTypes.EXPLOSIONS)) {
|
||||
+ return false;
|
||||
+ } else if (settings.isToggled(me.samsuik.sakura.player.visibility.VisibilityTypes.EXPLOSIONS)) {
|
||||
+ final BlockPos blockPosition = BlockPos.containing(position);
|
||||
+ final long encodedPosition = blockPosition.asLong();
|
||||
+ return this.explosionPositions.add(encodedPosition);
|
||||
+ }
|
||||
+ return true;
|
||||
+ }
|
||||
+ // Sakura end - client visibility settings
|
||||
|
||||
// Add env and gen to constructor, IWorldDataServer -> WorldDataServer
|
||||
public ServerLevel(MinecraftServer minecraftserver, Executor executor, LevelStorageSource.LevelStorageAccess convertable_conversionsession, PrimaryLevelData iworlddataserver, ResourceKey<Level> resourcekey, LevelStem worlddimension, ChunkProgressListener worldloadlistener, boolean flag, long i, List<CustomSpawner> list, boolean flag1, @Nullable RandomSequences randomsequences, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider) {
|
||||
@@ -1906,7 +1921,18 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
if (entityplayer.distanceToSqr(vec3d) < 4096.0D) {
|
||||
Optional<Vec3> optional = Optional.ofNullable((Vec3) serverexplosion.getHitPlayers().get(entityplayer));
|
||||
|
||||
- entityplayer.connection.send(new ClientboundExplodePacket(vec3d, optional, particleparam2, holder));
|
||||
+ // Sakura start - client visibility settings; let players toggle explosion particles
|
||||
+ ParticleOptions particle = particleparam2;
|
||||
+ Vec3 position = vec3d;
|
||||
+ // In 1.22 and later this should be replaced with sending the motion through a PlayerPositionPacket.
|
||||
+ // The problem here is SetEntityMotion is capped to 3.9 b/pt and the only other alternate mean was
|
||||
+ // implemented in 1.21.3. I believe it's best to just wait on this issue and deal with this hack.
|
||||
+ if (!this.checkExplosionVisibility(vec3d, entityplayer)) {
|
||||
+ position = new Vec3(0.0, -1024.0, 0.0);
|
||||
+ particle = net.minecraft.core.particles.ParticleTypes.SMOKE;
|
||||
+ }
|
||||
+ entityplayer.connection.send(new ClientboundExplodePacket(position, optional, particle, holder));
|
||||
+ // Sakura end - client visibility settings; let players toggle explosion particles
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index fc7f7a34babd095a51b5321f600aef65a2a9d123..2a9659158d39d4d5505328afd7a2d8dc9ecf456f 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -357,6 +357,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player imple
|
||||
return this.viewDistanceHolder;
|
||||
}
|
||||
// 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 ServerPlayer(MinecraftServer server, ServerLevel world, GameProfile profile, ClientInformation clientOptions) {
|
||||
super(world, world.getSharedSpawnPos(), world.getSharedSpawnAngle(), profile);
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
|
||||
index b0bc66dc7248aae691dcab68b925b52a1695e63f..2f9413b9442cc7f95e1974a772812fe397d4c4bd 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
|
||||
@@ -101,6 +101,22 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
|
||||
protected final org.bukkit.craftbukkit.CraftServer cserver;
|
||||
public boolean processedDisconnect;
|
||||
|
||||
+ // Sakura start - client visibility settings
|
||||
+ private @Nullable Packet<?> recreatePacket(final Packet<?> packet) {
|
||||
+ final me.samsuik.sakura.player.visibility.VisibilitySettings settings = this.player.visibilitySettings;
|
||||
+ if (packet instanceof net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket bedPacket) {
|
||||
+ if (settings.isToggled(me.samsuik.sakura.player.visibility.VisibilityTypes.SPAWNERS) && bedPacket.getType() == net.minecraft.world.level.block.entity.BlockEntityType.MOB_SPAWNER) {
|
||||
+ return null;
|
||||
+ }
|
||||
+ } else if (packet instanceof net.minecraft.network.protocol.game.ClientboundBlockEventPacket bePacket) {
|
||||
+ if (settings.isToggled(me.samsuik.sakura.player.visibility.VisibilityTypes.PISTONS) && bePacket.getBlock() instanceof net.minecraft.world.level.block.piston.PistonBaseBlock) {
|
||||
+ return null;
|
||||
+ }
|
||||
+ }
|
||||
+ return packet;
|
||||
+ }
|
||||
+ // Sakura end - client visibility settings
|
||||
+
|
||||
public CraftPlayer getCraftPlayer() {
|
||||
return (this.player == null) ? null : (CraftPlayer) this.player.getBukkitEntity();
|
||||
// CraftBukkit end
|
||||
@@ -309,6 +325,12 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
|
||||
ClientboundSetDefaultSpawnPositionPacket packet6 = (ClientboundSetDefaultSpawnPositionPacket) packet;
|
||||
this.player.compassTarget = CraftLocation.toBukkit(packet6.pos, this.getCraftPlayer().getWorld());
|
||||
}
|
||||
+ // Sakura start - client visibility settings
|
||||
+ if (this.player.visibilitySettings.playerModified()) {
|
||||
+ packet = this.recreatePacket(packet);
|
||||
+ if (packet == null) return;
|
||||
+ }
|
||||
+ // Sakura end - client visibility settings
|
||||
// CraftBukkit end
|
||||
if (packet.isTerminal()) {
|
||||
this.close();
|
||||
@@ -322,8 +344,11 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
|
||||
CrashReport crashreport = CrashReport.forThrowable(throwable, "Sending packet");
|
||||
CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Packet being sent");
|
||||
|
||||
+ // Sakura start - this has to be effectively final as we're modifying the packet above
|
||||
+ var packetFinal = packet;
|
||||
crashreportsystemdetails.setDetail("Packet class", () -> {
|
||||
- return packet.getClass().getCanonicalName();
|
||||
+ return packetFinal.getClass().getCanonicalName();
|
||||
+ // Sakura end
|
||||
});
|
||||
throw new ReportedException(crashreport);
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 84fa24880d02dc7ba1ec8bda3575be38447fd4b2..52f79a8d1b7890ffba3495ca9390f0edc27e6f99 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -3314,6 +3314,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
|
||||
event.setCancelled(cancelled);
|
||||
AbstractContainerMenu oldContainer = this.player.containerMenu; // SPIGOT-1224
|
||||
+ me.samsuik.sakura.player.gui.FeatureGui.clickEvent(event); // Sakura - client visibility settings
|
||||
this.cserver.getPluginManager().callEvent(event);
|
||||
if (this.player.containerMenu != oldContainer) {
|
||||
return;
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index 7ac7d0729705cb02f22277be3c467aed4f69ec0e..34a8c152a4570802d1e96430a6de9d937375fedd 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -568,6 +568,10 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
}
|
||||
}
|
||||
// Paper end - optimise entity tracker
|
||||
+ // Sakura start - visibility api and command
|
||||
+ public boolean isPrimedTNT;
|
||||
+ public boolean isFallingBlock;
|
||||
+ // Sakura end - visibility api and command
|
||||
|
||||
public Entity(EntityType<?> type, Level world) {
|
||||
this.id = Entity.ENTITY_COUNTER.incrementAndGet();
|
||||
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 410c4e4a42640ebe8a9c233eb2064aad76e45a27..e270eaec13afb16ed80e7c3fd8ea35ee58291263 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||
@@ -78,6 +78,7 @@ public class FallingBlockEntity extends Entity {
|
||||
this.blockState = Blocks.SAND.defaultBlockState();
|
||||
this.dropItem = true;
|
||||
this.fallDamageMax = 40;
|
||||
+ this.isFallingBlock = true; // Sakura
|
||||
}
|
||||
|
||||
public FallingBlockEntity(Level world, double x, double y, double z, BlockState block) {
|
||||
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 809f5e847e2f5bb594c130cebd2cb897ea768d82..eebd53ac889da265cb259ba3cb8c1ce4ef34d931 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||
@@ -63,6 +63,7 @@ public class PrimedTnt extends Entity implements TraceableEntity {
|
||||
super(type, world);
|
||||
this.explosionPower = 4.0F;
|
||||
this.blocksBuilding = true;
|
||||
+ this.isPrimedTNT = true; // Sakura
|
||||
}
|
||||
|
||||
public PrimedTnt(Level world, double x, double y, double z, @Nullable LivingEntity igniter) {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
index 6a647cab8b2e476987931486e290703b8726f2c7..5455f78d4417f3f8b2e4820619ad24d91054d986 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -2403,6 +2403,13 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
handle.keepLevel = data.getBoolean("keepLevel");
|
||||
}
|
||||
}
|
||||
+
|
||||
+ // Sakura start - client visibility settings; load from nbt
|
||||
+ if (nbttagcompound.contains("sakura", 10)) {
|
||||
+ CompoundTag sakuraTag = nbttagcompound.getCompound("sakura");
|
||||
+ this.getHandle().visibilitySettings.loadData(sakuraTag);
|
||||
+ }
|
||||
+ // Sakura end - client visibility settings; load from nbt
|
||||
}
|
||||
|
||||
public void setExtraData(CompoundTag nbttagcompound) {
|
||||
@@ -2432,6 +2439,11 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
paper.putLong("LastLogin", handle.loginTime);
|
||||
paper.putLong("LastSeen", System.currentTimeMillis());
|
||||
// Paper end
|
||||
+ // Sakura start - client visibility settings; save to nbt
|
||||
+ CompoundTag sakuraTag = nbttagcompound.getCompound("sakura");
|
||||
+ this.getHandle().visibilitySettings.saveData(sakuraTag);
|
||||
+ nbttagcompound.put("sakura", sakuraTag);
|
||||
+ // Sakura end - client visibility settings; save to nbt
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -3091,6 +3103,13 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
return this.getHandle().allowsListing();
|
||||
}
|
||||
|
||||
+ // Sakura start - client visibility settings; api
|
||||
+ @Override
|
||||
+ public final me.samsuik.sakura.player.visibility.VisibilitySettings getVisibility() {
|
||||
+ return this.getHandle().visibilitySettings;
|
||||
+ }
|
||||
+ // Sakura end - client visibility settings; api
|
||||
+
|
||||
// Paper start
|
||||
@Override
|
||||
public net.kyori.adventure.text.Component displayName() {
|
||||
147
migrate/server/feature/0007-Load-Chunks-on-Movement.patch
Normal file
147
migrate/server/feature/0007-Load-Chunks-on-Movement.patch
Normal file
@@ -0,0 +1,147 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samsuik <kfian294ma4@gmail.com>
|
||||
Date: Sat, 11 Sep 2021 19:19:41 +0100
|
||||
Subject: [PATCH] Load Chunks on Movement
|
||||
|
||||
|
||||
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java b/src/main/java/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java
|
||||
index e04bd54744335fb5398c6e4f7ce8b981f35bfb7d..651a45b795818bd7b1364b95c52570fd99dd35e4 100644
|
||||
--- a/src/main/java/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java
|
||||
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java
|
||||
@@ -1885,6 +1885,7 @@ public final class CollisionUtil {
|
||||
public static final int COLLISION_FLAG_COLLIDE_WITH_UNLOADED_CHUNKS = 1 << 1;
|
||||
public static final int COLLISION_FLAG_CHECK_BORDER = 1 << 2;
|
||||
public static final int COLLISION_FLAG_CHECK_ONLY = 1 << 3;
|
||||
+ public static final int COLLISION_FLAG_ADD_TICKET = 1 << 4; // Sakura - load chunks on movement
|
||||
|
||||
public static boolean getCollisionsForBlocksOrWorldBorder(final Level world, final Entity entity, final AABB aabb,
|
||||
final List<VoxelShape> intoVoxel, final List<AABB> intoAABB,
|
||||
@@ -1936,6 +1937,7 @@ public final class CollisionUtil {
|
||||
final int maxChunkZ = maxBlockZ >> 4;
|
||||
|
||||
final boolean loadChunks = (collisionFlags & COLLISION_FLAG_LOAD_CHUNKS) != 0;
|
||||
+ final boolean addTicket = (collisionFlags & COLLISION_FLAG_ADD_TICKET) != 0; // Sakura - load chunks on movement
|
||||
final ChunkSource chunkSource = world.getChunkSource();
|
||||
|
||||
for (int currChunkZ = minChunkZ; currChunkZ <= maxChunkZ; ++currChunkZ) {
|
||||
@@ -1954,6 +1956,13 @@ public final class CollisionUtil {
|
||||
continue;
|
||||
}
|
||||
|
||||
+ // Sakura start - load chunks on movement
|
||||
+ if (addTicket && chunk.movementTicketNeedsUpdate() && chunkSource instanceof net.minecraft.server.level.ServerChunkCache chunkCache) {
|
||||
+ final long chunkKey = ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(currChunkX, currChunkZ);
|
||||
+ chunkCache.chunkMap.getDistanceManager().moonrise$getChunkHolderManager().addTicketAtLevel(net.minecraft.server.level.TicketType.ENTITY_MOVEMENT, currChunkX, currChunkZ, 31, chunkKey);
|
||||
+ chunk.updatedMovementTicket();
|
||||
+ }
|
||||
+ // Sakura end - load chunks on movement
|
||||
final LevelChunkSection[] sections = chunk.getSections();
|
||||
|
||||
// bound y
|
||||
diff --git a/src/main/java/net/minecraft/server/level/TicketType.java b/src/main/java/net/minecraft/server/level/TicketType.java
|
||||
index 4d3f7d4a8e05a8d84aa5202134eda1ce9621712e..db159b9b4ffc032f5abe68bf294e58cce04e1baa 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/TicketType.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/TicketType.java
|
||||
@@ -26,6 +26,7 @@ public class TicketType<T> {
|
||||
public static final TicketType<Unit> PLUGIN = TicketType.create("plugin", (a, b) -> 0); // CraftBukkit
|
||||
public static final TicketType<org.bukkit.plugin.Plugin> PLUGIN_TICKET = TicketType.create("plugin_ticket", (plugin1, plugin2) -> plugin1.getClass().getName().compareTo(plugin2.getClass().getName())); // CraftBukkit
|
||||
public static final TicketType<Integer> POST_TELEPORT = TicketType.create("post_teleport", Integer::compare, 5); // Paper - post teleport ticket type
|
||||
+ public static final TicketType<Long> ENTITY_MOVEMENT = TicketType.create("entity_movement", Long::compareTo, 10*20); // Sakura - load chunks on movement
|
||||
|
||||
public static <T> TicketType<T> create(String name, Comparator<T> argumentComparator) {
|
||||
return new TicketType<>(name, argumentComparator, 0L);
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index 29045a4857aadbc7f9ae0c612555743ad404682d..031d3fde74a08165dc6b8106246249583c2300c0 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -572,6 +572,20 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
public boolean isPrimedTNT;
|
||||
public boolean isFallingBlock;
|
||||
// Sakura end - visibility api and command
|
||||
+ // Sakura start - load chunks on movement
|
||||
+ protected boolean loadChunks = false;
|
||||
+
|
||||
+ private int getExtraCollisionFlags() {
|
||||
+ int flags = 0;
|
||||
+
|
||||
+ if (this.loadChunks) {
|
||||
+ flags |= ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_FLAG_LOAD_CHUNKS;
|
||||
+ flags |= ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_FLAG_ADD_TICKET;
|
||||
+ }
|
||||
+
|
||||
+ return flags;
|
||||
+ }
|
||||
+ // Sakura end - load chunks on movement
|
||||
|
||||
public Entity(EntityType<?> type, Level world) {
|
||||
this.id = Entity.ENTITY_COUNTER.incrementAndGet();
|
||||
@@ -1569,7 +1583,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
|
||||
ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.getCollisionsForBlocksOrWorldBorder(
|
||||
this.level, (Entity)(Object)this, initialCollisionBox, potentialCollisionsVoxel, potentialCollisionsBB,
|
||||
- ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_FLAG_CHECK_BORDER, null
|
||||
+ ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_FLAG_CHECK_BORDER | this.getExtraCollisionFlags(), null // Sakura - load chunks on movement
|
||||
);
|
||||
potentialCollisionsBB.addAll(entityAABBs);
|
||||
final Vec3 collided = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.performCollisions(movement, currentBox, potentialCollisionsVoxel, potentialCollisionsBB);
|
||||
@@ -5229,12 +5243,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
|
||||
@Override
|
||||
public boolean shouldBeSaved() {
|
||||
- return this.removalReason != null && !this.removalReason.shouldSave() ? false : (this.isPassenger() ? false : !this.isVehicle() || !((ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity)this).moonrise$hasAnyPlayerPassengers()); // Paper - rewrite chunk system
|
||||
+ return this.removalReason != null && !this.removalReason.shouldSave() ? false : (this.loadChunks || this.isPassenger() ? false : !this.isVehicle() || !((ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity)this).moonrise$hasAnyPlayerPassengers()); // Sakura - load chunks on movement; used to determine whether a chunk should unload // Paper - rewrite chunk system
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAlwaysTicking() {
|
||||
- return false;
|
||||
+ return this.loadChunks; // Sakura - load chunks on movement; always tick in unloaded & lazy chunks
|
||||
}
|
||||
|
||||
public boolean mayInteract(ServerLevel world, BlockPos pos) {
|
||||
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 e270eaec13afb16ed80e7c3fd8ea35ee58291263..20fa9a70f2d51aaa7f9ea01150d65c1f73caa374 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||
@@ -79,6 +79,7 @@ public class FallingBlockEntity extends Entity {
|
||||
this.dropItem = true;
|
||||
this.fallDamageMax = 40;
|
||||
this.isFallingBlock = true; // Sakura
|
||||
+ this.loadChunks = world.sakuraConfig().cannons.loadChunks; // Sakura - load chunks on movement
|
||||
}
|
||||
|
||||
public FallingBlockEntity(Level world, double x, double y, double z, BlockState block) {
|
||||
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 a7bcf197f062361c764d4e951ed88678994eca17..539219a4117c67278461ee483a457c005e6edcfc 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||
@@ -64,6 +64,7 @@ public class PrimedTnt extends Entity implements TraceableEntity {
|
||||
this.explosionPower = 4.0F;
|
||||
this.blocksBuilding = true;
|
||||
this.isPrimedTNT = true; // Sakura
|
||||
+ this.loadChunks = world.sakuraConfig().cannons.loadChunks; // Sakura - load chunks on movement
|
||||
}
|
||||
|
||||
public PrimedTnt(Level world, double x, double y, double z, @Nullable LivingEntity igniter) {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java b/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java
|
||||
index f87abb22dd161b2b74401086de80dc95c9ac2dbb..af1624aeda1ca72973b2b63ef05cd7367f678414 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java
|
||||
@@ -140,6 +140,17 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh
|
||||
private final int minSection;
|
||||
private final int maxSection;
|
||||
// Paper end - get block chunk optimisation
|
||||
+ // Sakura start - load chunks on movement
|
||||
+ private long lastMovementLoadTicket = 0;
|
||||
+
|
||||
+ public final boolean movementTicketNeedsUpdate() {
|
||||
+ return net.minecraft.server.MinecraftServer.currentTick - this.lastMovementLoadTicket >= 100;
|
||||
+ }
|
||||
+
|
||||
+ public final void updatedMovementTicket() {
|
||||
+ this.lastMovementLoadTicket = net.minecraft.server.MinecraftServer.currentTick;
|
||||
+ }
|
||||
+ // Sakura end - load chunks on movement
|
||||
|
||||
public ChunkAccess(ChunkPos pos, UpgradeData upgradeData, LevelHeightAccessor heightLimitView, Registry<Biome> biomeRegistry, long inhabitedTime, @Nullable LevelChunkSection[] sectionArray, @Nullable BlendingData blendingData) {
|
||||
this.locX = pos.x; this.locZ = pos.z; // Paper - reduce need for field lookups
|
||||
162
migrate/server/feature/0014-Optimise-paper-explosions.patch
Normal file
162
migrate/server/feature/0014-Optimise-paper-explosions.patch
Normal file
@@ -0,0 +1,162 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samsuik <kfian294ma4@gmail.com>
|
||||
Date: Fri, 19 Apr 2024 22:20:03 +0100
|
||||
Subject: [PATCH] Optimise paper explosions
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/ServerExplosion.java b/src/main/java/net/minecraft/world/level/ServerExplosion.java
|
||||
index bbbd451ff184be8fa13bd93d53c89a9502f9951a..a92be80081178cc302a7f0b646bad7daa28f7c66 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/ServerExplosion.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/ServerExplosion.java
|
||||
@@ -89,7 +89,7 @@ public class ServerExplosion implements Explosion {
|
||||
}
|
||||
}
|
||||
|
||||
- CACHED_RAYS = rayCoords.toDoubleArray();
|
||||
+ CACHED_RAYS = sortExplosionRays(rayCoords); // Sakura - optimise paper explosions
|
||||
}
|
||||
|
||||
private static final int CHUNK_CACHE_SHIFT = 2;
|
||||
@@ -307,6 +307,39 @@ public class ServerExplosion implements Explosion {
|
||||
return (float)missedRays / (float)totalRays;
|
||||
}
|
||||
// Paper end - collisions optimisations
|
||||
+ // Sakura start - optimise paper explosions
|
||||
+ /*
|
||||
+ * Sort the explosion rays to better utilise the chunk and block cache.
|
||||
+ * x + Vanilla Sorted
|
||||
+ * z @ z 8 5
|
||||
+ * - x 6 7 6 4
|
||||
+ * 4 @ 5 7 @ 3
|
||||
+ * 2 3 8 2
|
||||
+ * 1 1
|
||||
+ */
|
||||
+ private static double[] sortExplosionRays(it.unimi.dsi.fastutil.doubles.DoubleArrayList rayCoords) {
|
||||
+ List<double[]> explosionRays = new ArrayList<>();
|
||||
+
|
||||
+ for (int i = 0; i < rayCoords.size(); i += 3) {
|
||||
+ double[] ray = new double[3];
|
||||
+ rayCoords.getElements(i, ray, 0, 3);
|
||||
+ explosionRays.add(ray);
|
||||
+ }
|
||||
+
|
||||
+ rayCoords.clear();
|
||||
+ explosionRays.sort(java.util.Comparator.comparingDouble(vec -> {
|
||||
+ double sign = Math.signum(vec[0]);
|
||||
+ double dir = (sign - 1) / 2;
|
||||
+ return sign + 8 + vec[2] * dir;
|
||||
+ }));
|
||||
+
|
||||
+ double[] rays = new double[explosionRays.size() * 3];
|
||||
+ for (int i = 0; i < explosionRays.size() * 3; i++) {
|
||||
+ rays[i] = explosionRays.get(i / 3)[i % 3];
|
||||
+ }
|
||||
+ return rays;
|
||||
+ }
|
||||
+ // Sakura end - optimise paper explosions
|
||||
|
||||
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;
|
||||
@@ -389,6 +422,12 @@ public class ServerExplosion implements Explosion {
|
||||
initialCache = this.getOrCacheExplosionBlock(blockX, blockY, blockZ, key, true);
|
||||
}
|
||||
|
||||
+ // Sakura start - optimise paper explosions
|
||||
+ if (!this.interactsWithBlocks() || initialCache.resistance > (this.radius * 1.3f)) {
|
||||
+ return ret;
|
||||
+ }
|
||||
+ // Sakura end - optimise paper explosions
|
||||
+
|
||||
// only ~1/3rd of the loop iterations in vanilla will result in a ray, as it is iterating the perimeter of
|
||||
// a 16x16x16 cube
|
||||
// we can cache the rays and their normals as well, so that we eliminate the excess iterations / checks and
|
||||
@@ -467,19 +506,55 @@ public class ServerExplosion implements Explosion {
|
||||
// Paper end - collision optimisations
|
||||
}
|
||||
|
||||
- private void hurtEntities() {
|
||||
- float f = this.radius * 2.0F;
|
||||
+ // Sakura start - optimise paper explosions
|
||||
+ protected final AABB getExplosionBounds(float f) {
|
||||
int i = Mth.floor(this.center.x - (double) f - 1.0D);
|
||||
int j = Mth.floor(this.center.x + (double) f + 1.0D);
|
||||
int k = Mth.floor(this.center.y - (double) f - 1.0D);
|
||||
int l = Mth.floor(this.center.y + (double) f + 1.0D);
|
||||
int i1 = Mth.floor(this.center.z - (double) f - 1.0D);
|
||||
int j1 = Mth.floor(this.center.z + (double) f + 1.0D);
|
||||
- List<Entity> list = this.level.getEntities(excludeSourceFromDamage ? this.source : null, new AABB((double) i, (double) k, (double) i1, (double) j, (double) l, (double) j1), (com.google.common.base.Predicate<Entity>) entity -> entity.isAlive() && !entity.isSpectator()); // Paper - Fix lag from explosions processing dead entities, Allow explosions to damage source
|
||||
- Iterator iterator = list.iterator();
|
||||
+ return new AABB((double) i, (double) k, (double) i1, (double) j, (double) l, (double) j1);
|
||||
+ }
|
||||
|
||||
- while (iterator.hasNext()) {
|
||||
- Entity entity = (Entity) iterator.next();
|
||||
+ private void hurtEntities() {
|
||||
+ float f = this.radius * 2.0F;
|
||||
+
|
||||
+ int minSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMinSection(this.level);
|
||||
+ int maxSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMaxSection(this.level);
|
||||
+
|
||||
+ int minChunkX = Mth.floor(this.center.x - f) >> 4;
|
||||
+ int maxChunkX = Mth.floor(this.center.x + f) >> 4;
|
||||
+ int minChunkY = Mth.clamp(Mth.floor(this.center.y - f) >> 4, minSection, maxSection);
|
||||
+ int maxChunkY = Mth.clamp(Mth.floor(this.center.y + f) >> 4, minSection, maxSection);
|
||||
+ int minChunkZ = Mth.floor(this.center.z - f) >> 4;
|
||||
+ int maxChunkZ = Mth.floor(this.center.z + f) >> 4;
|
||||
+
|
||||
+ ca.spottedleaf.moonrise.patches.chunk_system.level.entity.EntityLookup entityLookup = this.level.moonrise$getEntityLookup();
|
||||
+ for (int chunkX = minChunkX; chunkX <= maxChunkX; ++chunkX) {
|
||||
+ for (int chunkZ = minChunkZ; chunkZ <= maxChunkZ; ++chunkZ) {
|
||||
+ ca.spottedleaf.moonrise.patches.chunk_system.level.entity.ChunkEntitySlices chunk = entityLookup.getChunk(chunkX, chunkZ);
|
||||
+ if (chunk == null) continue; // empty slice
|
||||
+
|
||||
+ for (int chunkY = minChunkY; chunkY <= maxChunkY; ++chunkY) {
|
||||
+ this.impactEntities(f, chunk.getSectionEntities(chunkY));
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ protected final void impactEntities(float f, Entity[] entities) {
|
||||
+ for (int i = 0; i < entities.length; i++) {
|
||||
+ Entity entity = entities[i];
|
||||
+ if (entity == null) break; // end of entity section
|
||||
+ this.impactEntity(f, entity);
|
||||
+ if (entity != entities[i]) i--; // entities can be removed mid-explosion
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ protected final void impactEntity(float f, Entity entity) {
|
||||
+ if (entity.isAlive() && !entity.isSpectator() && (!this.excludeSourceFromDamage || entity != this.source)) { // Paper - Fix lag from explosions processing dead entities, Allow explosions to damage source
|
||||
+ // Sakura end - optimise paper explosions
|
||||
|
||||
if (!entity.ignoreExplosion(this)) {
|
||||
double d0 = Math.sqrt(entity.distanceToSqr(this.center)) / (double) f;
|
||||
@@ -508,15 +583,16 @@ public class ServerExplosion implements Explosion {
|
||||
// - Damaging EntityEnderDragon does nothing
|
||||
// - EntityEnderDragon hitbock always covers the other parts and is therefore always present
|
||||
if (entity instanceof EnderDragonPart) {
|
||||
- continue;
|
||||
+ return; // Sakura - optimise paper explosions
|
||||
}
|
||||
|
||||
entity.lastDamageCancelled = false;
|
||||
|
||||
if (entity instanceof EnderDragon) {
|
||||
+ AABB bounds = this.getExplosionBounds(f); // Sakura - optimise paper explosions
|
||||
for (EnderDragonPart entityComplexPart : ((EnderDragon) entity).subEntities) {
|
||||
// Calculate damage separately for each EntityComplexPart
|
||||
- if (list.contains(entityComplexPart)) {
|
||||
+ if (entityComplexPart.getBoundingBox().intersects(bounds)) { // Sakura - optimise paper explosions
|
||||
entityComplexPart.hurtServer(this.level, this.damageSource, this.damageCalculator.getEntityDamageAmount(this, entity, f2));
|
||||
}
|
||||
}
|
||||
@@ -525,7 +601,7 @@ public class ServerExplosion implements Explosion {
|
||||
}
|
||||
|
||||
if (entity.lastDamageCancelled) { // SPIGOT-5339, SPIGOT-6252, SPIGOT-6777: Skip entity if damage event was cancelled
|
||||
- continue;
|
||||
+ return; // Sakura - optimise paper explosions
|
||||
}
|
||||
// CraftBukkit end
|
||||
}
|
||||
95
migrate/server/feature/0015-Store-Entity-Data-State.patch
Normal file
95
migrate/server/feature/0015-Store-Entity-Data-State.patch
Normal file
@@ -0,0 +1,95 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
|
||||
Date: Wed, 16 Aug 2023 22:34:49 +0100
|
||||
Subject: [PATCH] Store Entity Data/State
|
||||
|
||||
|
||||
diff --git a/src/main/java/me/samsuik/sakura/entity/EntityState.java b/src/main/java/me/samsuik/sakura/entity/EntityState.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..aeb5f128b369753cb20b7310fa382ddf2b6e8f0f
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/me/samsuik/sakura/entity/EntityState.java
|
||||
@@ -0,0 +1,41 @@
|
||||
+package me.samsuik.sakura.entity;
|
||||
+
|
||||
+import net.minecraft.core.BlockPos;
|
||||
+import net.minecraft.world.entity.Entity;
|
||||
+import net.minecraft.world.level.block.Blocks;
|
||||
+import net.minecraft.world.phys.AABB;
|
||||
+import net.minecraft.world.phys.Vec3;
|
||||
+import org.jspecify.annotations.NullMarked;
|
||||
+
|
||||
+import java.util.Optional;
|
||||
+
|
||||
+@NullMarked
|
||||
+public record EntityState(Vec3 position, Vec3 momentum, AABB bb, Vec3 stuckSpeed, Optional<BlockPos> supportingPos, boolean onGround, float fallDistance) {
|
||||
+ public static EntityState of(Entity entity) {
|
||||
+ return new EntityState(
|
||||
+ entity.position(), entity.getDeltaMovement(), entity.getBoundingBox(),
|
||||
+ entity.stuckSpeedMultiplier(), entity.mainSupportingBlockPos,
|
||||
+ entity.onGround(), entity.fallDistance
|
||||
+ );
|
||||
+ }
|
||||
+
|
||||
+ public void apply(Entity entity) {
|
||||
+ entity.setPos(this.position);
|
||||
+ entity.setDeltaMovement(this.momentum);
|
||||
+ entity.setBoundingBox(this.bb);
|
||||
+ entity.makeStuckInBlock(Blocks.AIR.defaultBlockState(), this.stuckSpeed);
|
||||
+ entity.onGround = this.onGround;
|
||||
+ entity.mainSupportingBlockPos = this.supportingPos;
|
||||
+ entity.fallDistance = this.fallDistance;
|
||||
+ }
|
||||
+
|
||||
+ public void applyEntityPosition(Entity entity) {
|
||||
+ entity.setPos(this.position);
|
||||
+ entity.setBoundingBox(this.bb);
|
||||
+ }
|
||||
+
|
||||
+ public boolean comparePositionAndMotion(Entity entity) {
|
||||
+ return entity.position().equals(this.position)
|
||||
+ && entity.getDeltaMovement().equals(this.momentum);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index 384b64cfbc2fef49fa22baf1f640ea8f440093cd..316ab62995a7804cf85a2cb986b22e15cd22b01c 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -586,6 +586,25 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
return flags;
|
||||
}
|
||||
// Sakura end - load chunks on movement
|
||||
+ // Sakura start - store entity data/state
|
||||
+ private me.samsuik.sakura.entity.EntityState entityState = null;
|
||||
+
|
||||
+ public final Vec3 stuckSpeedMultiplier() {
|
||||
+ return this.stuckSpeedMultiplier;
|
||||
+ }
|
||||
+
|
||||
+ public final void storeEntityState() {
|
||||
+ this.entityState = me.samsuik.sakura.entity.EntityState.of(this);
|
||||
+ }
|
||||
+
|
||||
+ public final me.samsuik.sakura.entity.EntityState entityState() {
|
||||
+ return this.entityState;
|
||||
+ }
|
||||
+
|
||||
+ public final boolean compareState(Entity to) {
|
||||
+ return to.entityState() != null && to.entityState().comparePositionAndMotion(this);
|
||||
+ }
|
||||
+ // Sakura end - store entity data/state
|
||||
|
||||
public Entity(EntityType<?> type, Level world) {
|
||||
this.id = Entity.ENTITY_COUNTER.incrementAndGet();
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index 13e8ac95daa115720a2b1f52ad33d124351cbd6d..c69c04451c61bcc32e539baae160f05e3418841f 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -1500,6 +1500,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
|
||||
public <T extends Entity> void guardEntityTick(Consumer<T> tickConsumer, T entity) {
|
||||
try {
|
||||
+ entity.storeEntityState(); // Sakura - store entity data/state
|
||||
tickConsumer.accept(entity);
|
||||
} catch (Throwable throwable) {
|
||||
if (throwable instanceof ThreadDeath) throw throwable; // Paper
|
||||
818
migrate/server/feature/0016-Merge-Cannon-Entities.patch
Normal file
818
migrate/server/feature/0016-Merge-Cannon-Entities.patch
Normal file
@@ -0,0 +1,818 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
|
||||
Date: Sat, 9 Sep 2023 18:39:15 +0100
|
||||
Subject: [PATCH] Merge Cannon Entities
|
||||
|
||||
|
||||
diff --git a/src/main/java/me/samsuik/sakura/entity/merge/EntityMergeHandler.java b/src/main/java/me/samsuik/sakura/entity/merge/EntityMergeHandler.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..917c2d4be95098a091ad19fb3e99f074188f00f9
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/me/samsuik/sakura/entity/merge/EntityMergeHandler.java
|
||||
@@ -0,0 +1,76 @@
|
||||
+package me.samsuik.sakura.entity.merge;
|
||||
+
|
||||
+import net.minecraft.world.entity.Entity;
|
||||
+import org.jetbrains.annotations.NotNull;
|
||||
+import org.jetbrains.annotations.Nullable;
|
||||
+
|
||||
+public final class EntityMergeHandler {
|
||||
+ private final TrackedMergeHistory trackedHistory = new TrackedMergeHistory();
|
||||
+
|
||||
+ /**
|
||||
+ * Tries to merge the provided entities using the {@link MergeStrategy}.
|
||||
+ *
|
||||
+ * @param previous the last entity to tick
|
||||
+ * @param entity the entity being merged
|
||||
+ * @return success
|
||||
+ */
|
||||
+ public boolean tryMerge(@Nullable Entity entity, @Nullable Entity previous) {
|
||||
+ if (entity instanceof MergeableEntity mergeEntity && previous instanceof MergeableEntity) {
|
||||
+ MergeEntityData mergeEntityData = mergeEntity.getMergeEntityData();
|
||||
+ MergeStrategy strategy = MergeStrategy.from(mergeEntityData.getMergeLevel());
|
||||
+ Entity into = strategy.mergeEntity(entity, previous, this.trackedHistory);
|
||||
+ if (into instanceof MergeableEntity intoEntity && !into.isRemoved() && mergeEntity.isSafeToMergeInto(intoEntity, strategy.trackHistory())) {
|
||||
+ return this.mergeEntity(mergeEntity, intoEntity);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * Stores the merged data of the provided entities if the {@link MergeStrategy} requires it.
|
||||
+ *
|
||||
+ * @param entity provided entity
|
||||
+ */
|
||||
+ public void removeEntity(@Nullable Entity entity) {
|
||||
+ if (entity instanceof MergeableEntity mergeEntity) {
|
||||
+ MergeEntityData mergeEntityData = mergeEntity.getMergeEntityData();
|
||||
+ MergeStrategy strategy = MergeStrategy.from(mergeEntityData.getMergeLevel());
|
||||
+ if (mergeEntityData.hasMerged() && strategy.trackHistory()) {
|
||||
+ this.trackedHistory.trackHistory(entity, mergeEntityData);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * Called every tick and provided the current server tick to remove any unneeded merge history.
|
||||
+ *
|
||||
+ * @param tick server tick
|
||||
+ */
|
||||
+ public void expire(int tick) {
|
||||
+ if (tick % 200 == 0) {
|
||||
+ this.trackedHistory.expire(tick);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * Merges the first entity into the second. The entity merge count can be retrieved through the {@link MergeEntityData}.
|
||||
+ * <p>
|
||||
+ * This method also updates the bukkit handle so that plugins reference the first entity after the second entity has been removed.
|
||||
+ *
|
||||
+ * @param mergeEntity the first entity
|
||||
+ * @param into the entity to merge into
|
||||
+ * @return if successful
|
||||
+ */
|
||||
+ public boolean mergeEntity(@NotNull MergeableEntity mergeEntity, @NotNull MergeableEntity into) {
|
||||
+ MergeEntityData entities = mergeEntity.getMergeEntityData();
|
||||
+ MergeEntityData mergeInto = into.getMergeEntityData();
|
||||
+ mergeInto.mergeWith(entities); // merge entities together
|
||||
+
|
||||
+ // discard the entity and update the bukkit handle
|
||||
+ Entity nmsEntity = (Entity) mergeEntity;
|
||||
+ nmsEntity.discard();
|
||||
+ nmsEntity.updateBukkitHandle((Entity) into);
|
||||
+ return true;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/me/samsuik/sakura/entity/merge/MergeCondition.java b/src/main/java/me/samsuik/sakura/entity/merge/MergeCondition.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..6c0c224bc30c9c75d4b82508661117ce16197680
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/me/samsuik/sakura/entity/merge/MergeCondition.java
|
||||
@@ -0,0 +1,16 @@
|
||||
+package me.samsuik.sakura.entity.merge;
|
||||
+
|
||||
+import net.minecraft.world.entity.Entity;
|
||||
+import org.jetbrains.annotations.NotNull;
|
||||
+
|
||||
+public interface MergeCondition {
|
||||
+ default MergeCondition and(@NotNull MergeCondition condition) {
|
||||
+ return (e,c,t) -> this.accept(e,c,t) && condition.accept(e,c,t);
|
||||
+ }
|
||||
+
|
||||
+ default MergeCondition or(@NotNull MergeCondition condition) {
|
||||
+ return (e,c,t) -> this.accept(e,c,t) || condition.accept(e,c,t);
|
||||
+ }
|
||||
+
|
||||
+ boolean accept(@NotNull Entity entity, int attempts, long sinceCreation);
|
||||
+}
|
||||
diff --git a/src/main/java/me/samsuik/sakura/entity/merge/MergeEntityData.java b/src/main/java/me/samsuik/sakura/entity/merge/MergeEntityData.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..b13e3dcc333bcb53b4493e7087765fcca0a88604
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/me/samsuik/sakura/entity/merge/MergeEntityData.java
|
||||
@@ -0,0 +1,52 @@
|
||||
+package me.samsuik.sakura.entity.merge;
|
||||
+
|
||||
+import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||
+import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
+import net.minecraft.world.entity.Entity;
|
||||
+import org.jetbrains.annotations.NotNull;
|
||||
+
|
||||
+import java.util.List;
|
||||
+
|
||||
+public final class MergeEntityData {
|
||||
+ private final Entity entity;
|
||||
+ private List<MergeEntityData> connected = new ObjectArrayList<>();
|
||||
+ private int count = 1;
|
||||
+ private MergeLevel mergeLevel = MergeLevel.NONE;
|
||||
+
|
||||
+ public MergeEntityData(Entity entity) {
|
||||
+ this.entity = entity;
|
||||
+ }
|
||||
+
|
||||
+ public void mergeWith(@NotNull MergeEntityData mergeEntityData) {
|
||||
+ this.connected.add(mergeEntityData);
|
||||
+ this.connected.addAll(mergeEntityData.connected);
|
||||
+ this.count += mergeEntityData.getCount();
|
||||
+ mergeEntityData.setCount(0);
|
||||
+ }
|
||||
+
|
||||
+ public LongOpenHashSet getOriginPositions() {
|
||||
+ LongOpenHashSet positions = new LongOpenHashSet();
|
||||
+ this.connected.forEach(entityData -> positions.add(entityData.entity.getPackedOriginPosition()));
|
||||
+ return positions;
|
||||
+ }
|
||||
+
|
||||
+ public boolean hasMerged() {
|
||||
+ return !this.connected.isEmpty() && this.count != 0;
|
||||
+ }
|
||||
+
|
||||
+ public void setMergeLevel(MergeLevel mergeLevel) {
|
||||
+ this.mergeLevel = mergeLevel;
|
||||
+ }
|
||||
+
|
||||
+ public MergeLevel getMergeLevel() {
|
||||
+ return mergeLevel;
|
||||
+ }
|
||||
+
|
||||
+ public void setCount(int count) {
|
||||
+ this.count = count;
|
||||
+ }
|
||||
+
|
||||
+ public int getCount() {
|
||||
+ return this.count;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/me/samsuik/sakura/entity/merge/MergeStrategy.java b/src/main/java/me/samsuik/sakura/entity/merge/MergeStrategy.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..3b490ddd7b98a41b14f67d0d754d89b5ef645d66
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/me/samsuik/sakura/entity/merge/MergeStrategy.java
|
||||
@@ -0,0 +1,118 @@
|
||||
+package me.samsuik.sakura.entity.merge;
|
||||
+
|
||||
+import me.samsuik.sakura.utils.collections.FixedSizeCustomObjectTable;
|
||||
+import net.minecraft.world.entity.Entity;
|
||||
+import net.minecraft.world.level.entity.EntityTickList;
|
||||
+import org.jetbrains.annotations.NotNull;
|
||||
+
|
||||
+public interface MergeStrategy {
|
||||
+ /**
|
||||
+ * If this merge strategy requires the merge history to be tracked.
|
||||
+ *
|
||||
+ * @return should track history
|
||||
+ */
|
||||
+ boolean trackHistory();
|
||||
+
|
||||
+ /**
|
||||
+ * Tries to merge the first entity into another entity.
|
||||
+ * <p>
|
||||
+ * The first entity should always be positioned right after the second entity in the
|
||||
+ * {@link EntityTickList}. This method should only
|
||||
+ * be called before the first entity and after the second entity has ticked.
|
||||
+ *
|
||||
+ * @param entity current entity
|
||||
+ * @param previous last entity to tick
|
||||
+ * @return success
|
||||
+ */
|
||||
+ Entity mergeEntity(@NotNull Entity entity, @NotNull Entity previous, @NotNull TrackedMergeHistory mergeHistory);
|
||||
+
|
||||
+ /**
|
||||
+ * Gets the {@link MergeStrategy} for the {@link MergeLevel}.
|
||||
+ *
|
||||
+ * @param level provided level
|
||||
+ * @return strategy
|
||||
+ */
|
||||
+ static MergeStrategy from(MergeLevel level) {
|
||||
+ return switch (level) {
|
||||
+ case NONE -> None.INSTANCE;
|
||||
+ case STRICT -> Strict.INSTANCE;
|
||||
+ case LENIENT -> Lenient.INSTANCE;
|
||||
+ case SPAWN -> Spawn.INSTANCE;
|
||||
+ };
|
||||
+ }
|
||||
+
|
||||
+ final class None implements MergeStrategy {
|
||||
+ private static final None INSTANCE = new None();
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean trackHistory() {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Entity mergeEntity(@NotNull Entity entity, @NotNull Entity previous, @NotNull TrackedMergeHistory mergeHistory) {
|
||||
+ return null;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ final class Strict implements MergeStrategy {
|
||||
+ private static final Strict INSTANCE = new Strict();
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean trackHistory() {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Entity mergeEntity(@NotNull Entity entity, @NotNull Entity previous, @NotNull TrackedMergeHistory mergeHistory) {
|
||||
+ return entity.compareState(previous) ? previous : null;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ final class Lenient implements MergeStrategy {
|
||||
+ private static final Lenient INSTANCE = new Lenient();
|
||||
+ private final FixedSizeCustomObjectTable<Entity> entityTable = new FixedSizeCustomObjectTable<>(512, entity -> {
|
||||
+ return entity.blockPosition().hashCode();
|
||||
+ });
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean trackHistory() {
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Entity mergeEntity(@NotNull Entity entity, @NotNull Entity previous, @NotNull TrackedMergeHistory mergeHistory) {
|
||||
+ if (entity.compareState(previous)) {
|
||||
+ return previous;
|
||||
+ }
|
||||
+
|
||||
+ Entity nextEntity = this.entityTable.getAndWrite(entity);
|
||||
+ if (nextEntity == null || !nextEntity.level().equals(entity.level())) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ return mergeHistory.hasPreviousMerged(entity, nextEntity) && entity.compareState(nextEntity) ? nextEntity : null;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ final class Spawn implements MergeStrategy {
|
||||
+ private static final Spawn INSTANCE = new Spawn();
|
||||
+ private static final MergeCondition CONDITION = (e, shots, time) -> (shots > 16 || time >= 200);
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean trackHistory() {
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Entity mergeEntity(@NotNull Entity entity, @NotNull Entity previous, @NotNull TrackedMergeHistory mergeHistory) {
|
||||
+ final Entity mergeInto;
|
||||
+ if (entity.tickCount == 1 && mergeHistory.hasPreviousMerged(entity, previous) && mergeHistory.hasMetCondition(previous, CONDITION)) {
|
||||
+ mergeInto = previous;
|
||||
+ } else {
|
||||
+ mergeInto = entity.compareState(previous) ? previous : null;
|
||||
+ }
|
||||
+ return mergeInto;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/me/samsuik/sakura/entity/merge/MergeableEntity.java b/src/main/java/me/samsuik/sakura/entity/merge/MergeableEntity.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..3061c3a48f7c68f64a3348b9583f4b41c16429a9
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/me/samsuik/sakura/entity/merge/MergeableEntity.java
|
||||
@@ -0,0 +1,22 @@
|
||||
+package me.samsuik.sakura.entity.merge;
|
||||
+
|
||||
+import org.jetbrains.annotations.NotNull;
|
||||
+
|
||||
+public interface MergeableEntity {
|
||||
+ @NotNull MergeEntityData getMergeEntityData();
|
||||
+
|
||||
+ boolean isSafeToMergeInto(@NotNull MergeableEntity entity, boolean ticksLived);
|
||||
+
|
||||
+ default boolean respawnEntity() {
|
||||
+ MergeEntityData mergeData = this.getMergeEntityData();
|
||||
+ int count = mergeData.getCount();
|
||||
+ if (count > 1) {
|
||||
+ mergeData.setCount(0);
|
||||
+ this.respawnEntity(count);
|
||||
+ return true;
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ void respawnEntity(int count);
|
||||
+}
|
||||
diff --git a/src/main/java/me/samsuik/sakura/entity/merge/TrackedMergeHistory.java b/src/main/java/me/samsuik/sakura/entity/merge/TrackedMergeHistory.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..fc68bccf135bdcc7b3db7976e452ccae01e03b89
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/me/samsuik/sakura/entity/merge/TrackedMergeHistory.java
|
||||
@@ -0,0 +1,83 @@
|
||||
+package me.samsuik.sakura.entity.merge;
|
||||
+
|
||||
+import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||
+import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
+import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||
+import me.samsuik.sakura.configuration.WorldConfiguration.Cannons.Mechanics.TNTSpread;
|
||||
+import me.samsuik.sakura.utils.objects.Expiry;
|
||||
+import net.minecraft.server.MinecraftServer;
|
||||
+import net.minecraft.world.entity.Entity;
|
||||
+import net.minecraft.world.entity.item.FallingBlockEntity;
|
||||
+import org.jetbrains.annotations.NotNull;
|
||||
+
|
||||
+public final class TrackedMergeHistory {
|
||||
+ private final Long2ObjectMap<PositionHistory> historyMap = new Long2ObjectOpenHashMap<>();
|
||||
+
|
||||
+ public boolean hasPreviousMerged(@NotNull Entity entity, @NotNull Entity into) {
|
||||
+ PositionHistory positions = this.getHistory(into);
|
||||
+ return positions != null && positions.has(entity.getPackedOriginPosition());
|
||||
+ }
|
||||
+
|
||||
+ public void trackHistory(@NotNull Entity entity, @NotNull MergeEntityData mergeEntityData) {
|
||||
+ long originPosition = entity.getPackedOriginPosition();
|
||||
+ PositionHistory positions = this.historyMap.computeIfAbsent(originPosition, p -> new PositionHistory());
|
||||
+ LongOpenHashSet originPositions = mergeEntityData.getOriginPositions();
|
||||
+ boolean createHistory = positions.hasTimePassed(160);
|
||||
+ if (createHistory && (entity instanceof FallingBlockEntity || entity.level().sakuraConfig().cannons.mechanics.tntSpread == TNTSpread.ALL)) {
|
||||
+ originPositions.forEach(pos -> this.historyMap.put(pos, positions));
|
||||
+ }
|
||||
+ positions.trackPositions(originPositions, !createHistory);
|
||||
+ }
|
||||
+
|
||||
+ public boolean hasMetCondition(@NotNull Entity entity, MergeCondition condition) {
|
||||
+ PositionHistory positions = this.getHistory(entity);
|
||||
+ return positions != null && positions.hasMetConditions(entity, condition);
|
||||
+ }
|
||||
+
|
||||
+ private PositionHistory getHistory(Entity entity) {
|
||||
+ long originPosition = entity.getPackedOriginPosition();
|
||||
+ return this.historyMap.get(originPosition);
|
||||
+ }
|
||||
+
|
||||
+ public void expire(int tick) {
|
||||
+ this.historyMap.values().removeIf(p -> p.expiry().isExpired(tick));
|
||||
+ }
|
||||
+
|
||||
+ private static final class PositionHistory {
|
||||
+ private final LongOpenHashSet positions = new LongOpenHashSet();
|
||||
+ private final Expiry expiry = new Expiry(MinecraftServer.currentTick, 200);
|
||||
+ private final long created = MinecraftServer.currentTick;
|
||||
+ private int cycles = 0;
|
||||
+
|
||||
+ public Expiry expiry() {
|
||||
+ return this.expiry;
|
||||
+ }
|
||||
+
|
||||
+ public boolean has(long position) {
|
||||
+ this.expiry.refresh(MinecraftServer.currentTick);
|
||||
+ return this.positions.contains(position);
|
||||
+ }
|
||||
+
|
||||
+ public void trackPositions(LongOpenHashSet positions, boolean retain) {
|
||||
+ if (retain) {
|
||||
+ this.positions.retainAll(positions);
|
||||
+ } else {
|
||||
+ this.positions.addAll(positions);
|
||||
+ }
|
||||
+ this.cycles++;
|
||||
+ }
|
||||
+
|
||||
+ public boolean hasMetConditions(@NotNull Entity entity, @NotNull MergeCondition condition) {
|
||||
+ this.expiry.refresh(MinecraftServer.currentTick);
|
||||
+ return condition.accept(entity, this.cycles, this.timeSinceCreation());
|
||||
+ }
|
||||
+
|
||||
+ public boolean hasTimePassed(int ticks) {
|
||||
+ return this.timeSinceCreation() > ticks;
|
||||
+ }
|
||||
+
|
||||
+ private long timeSinceCreation() {
|
||||
+ return MinecraftServer.currentTick - this.created;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 733541e91b0064d50de6c5c0985e9c472685c20c..c73aa5fd7da18219d1da63a0973f397316ba4210 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -1905,6 +1905,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
worldserver.explosionDensityCache.clear(); // Paper - Optimize explosions
|
||||
worldserver.localConfig().expire(currentTick); // Sakura - add local config
|
||||
worldserver.explosionPositions.clear(); // Sakura - client visibility settings
|
||||
+ worldserver.mergeHandler.expire(currentTick); // Sakura - merge cannon entities
|
||||
}
|
||||
this.isIteratingOverLevels = false; // Paper - Throw exception on world create while being ticked
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index e1f0da0b20ec310470160718338920bbd5b088de..1e940c5b9ce60dd1dd7ec03e83766e26d1112d73 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -807,6 +807,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
}
|
||||
|
||||
org.spigotmc.ActivationRange.activateEntities(this); // Spigot
|
||||
+ Entity[] previousEntity = new Entity[1]; // Sakura - merge cannon entities
|
||||
this.entityTickList.forEach((entity) -> {
|
||||
if (!entity.isRemoved()) {
|
||||
if (!tickratemanager.isEntityFrozen(entity)) {
|
||||
@@ -824,6 +825,15 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
entity.stopRiding();
|
||||
}
|
||||
|
||||
+ // Sakura start - merge cannon entities
|
||||
+ Entity previous = previousEntity[0];
|
||||
+ if (this.mergeHandler.tryMerge(entity, previous)) {
|
||||
+ return;
|
||||
+ } else {
|
||||
+ previousEntity[0] = entity;
|
||||
+ }
|
||||
+ // Sakura end - merge cannon entities
|
||||
+
|
||||
gameprofilerfiller.push("tick");
|
||||
this.guardEntityTick(this::tickNonPassenger, entity);
|
||||
gameprofilerfiller.pop();
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index 316ab62995a7804cf85a2cb986b22e15cd22b01c..fd1d02604a1e46545c7f2c8ad89968279e2fe1bf 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -605,6 +605,23 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
return to.entityState() != null && to.entityState().comparePositionAndMotion(this);
|
||||
}
|
||||
// Sakura end - store entity data/state
|
||||
+ // Sakura start - merge cannon entities
|
||||
+ public final void updateBukkitHandle(Entity entity) {
|
||||
+ if (this.bukkitEntity != null) {
|
||||
+ this.bukkitEntity.setHandle(entity);
|
||||
+ }
|
||||
+ this.bukkitEntity = entity.getBukkitEntity();
|
||||
+ }
|
||||
+
|
||||
+ public final long getPackedOriginPosition() {
|
||||
+ org.bukkit.util.Vector origin = this.getOriginVector();
|
||||
+ if (origin != null) {
|
||||
+ return BlockPos.asLong(origin.getBlockX(), origin.getBlockY(), origin.getBlockZ());
|
||||
+ } else {
|
||||
+ return Long.MIN_VALUE;
|
||||
+ }
|
||||
+ }
|
||||
+ // Sakura end - merge cannon entities
|
||||
|
||||
public Entity(EntityType<?> type, Level world) {
|
||||
this.id = Entity.ENTITY_COUNTER.incrementAndGet();
|
||||
@@ -5233,6 +5250,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
if (this.removalReason != Entity.RemovalReason.UNLOADED_TO_CHUNK) { this.getPassengers().forEach(Entity::stopRiding); } // Paper - rewrite chunk system
|
||||
this.levelCallback.onRemove(entity_removalreason);
|
||||
this.onRemoval(entity_removalreason);
|
||||
+ // Sakura start - merge cannon entities
|
||||
+ if (entity_removalreason == RemovalReason.DISCARDED) {
|
||||
+ this.level.mergeHandler.removeEntity(this);
|
||||
+ }
|
||||
+ // Sakura end - merge cannon entities
|
||||
// Paper start - Folia schedulers
|
||||
if (!(this instanceof ServerPlayer) && entity_removalreason != RemovalReason.CHANGED_DIMENSION && !alreadyRemoved) {
|
||||
// Players need to be special cased, because they are regularly removed from the world
|
||||
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 81d02da6afd4b77c0ca60e9c8c5100ce6988753c..7dc5e5d91bb91c86ddca52a462903e8452396090 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||
@@ -57,7 +57,7 @@ import org.bukkit.craftbukkit.event.CraftEventFactory;
|
||||
import org.bukkit.event.entity.EntityRemoveEvent;
|
||||
// CraftBukkit end
|
||||
|
||||
-public class FallingBlockEntity extends Entity {
|
||||
+public class FallingBlockEntity extends Entity implements me.samsuik.sakura.entity.merge.MergeableEntity { // Sakura - merge cannon entities
|
||||
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
public BlockState blockState;
|
||||
@@ -73,6 +73,58 @@ public class FallingBlockEntity extends Entity {
|
||||
protected static final EntityDataAccessor<BlockPos> DATA_START_POS = SynchedEntityData.defineId(FallingBlockEntity.class, EntityDataSerializers.BLOCK_POS);
|
||||
public boolean autoExpire = true; // Paper - Expand FallingBlock API
|
||||
|
||||
+ // Sakura start - merge cannon entities
|
||||
+ private final me.samsuik.sakura.entity.merge.MergeEntityData mergeData = new me.samsuik.sakura.entity.merge.MergeEntityData(this);
|
||||
+
|
||||
+ @Override
|
||||
+ public final me.samsuik.sakura.entity.merge.MergeEntityData getMergeEntityData() {
|
||||
+ return this.mergeData;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public final boolean isSafeToMergeInto(me.samsuik.sakura.entity.merge.MergeableEntity entity, boolean ticksLived) {
|
||||
+ return entity instanceof FallingBlockEntity fbe
|
||||
+ && fbe.blockState.equals(this.blockState)
|
||||
+ && (!ticksLived || fbe.time - 1 == this.time);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public final void respawnEntity(int count) {
|
||||
+ while (count-- >= 1) {
|
||||
+ // Unlike PrimedTnt we have to try respawn each stacked entity
|
||||
+ FallingBlockEntity fallingBlock = new FallingBlockEntity(EntityType.FALLING_BLOCK, this.level());
|
||||
+
|
||||
+ // Try to stack the falling block
|
||||
+ this.entityState().apply(fallingBlock);
|
||||
+ fallingBlock.blockState = this.blockState;
|
||||
+ fallingBlock.spawnReason = this.spawnReason;
|
||||
+ fallingBlock.time = this.time - 1;
|
||||
+ fallingBlock.tick();
|
||||
+
|
||||
+ // If you horizontal stack into a moving piston block this condition will be met.
|
||||
+ if (!fallingBlock.isRemoved()) {
|
||||
+ this.mergeData.setCount(count + 1);
|
||||
+ fallingBlock.storeEntityState();
|
||||
+ fallingBlock.entityState().apply(this);
|
||||
+ break;
|
||||
+ } else if (count == 0) {
|
||||
+ this.discard(EntityRemoveEvent.Cause.DESPAWN);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Nullable
|
||||
+ public ItemEntity spawnAtLocation(ServerLevel level, ItemLike item) { // may be overridden by plugins
|
||||
+ ItemEntity itemEntity = null;
|
||||
+
|
||||
+ for (int i = 0; i < this.mergeData.getCount(); ++i) {
|
||||
+ itemEntity = super.spawnAtLocation(level, item);
|
||||
+ }
|
||||
+
|
||||
+ return itemEntity;
|
||||
+ }
|
||||
+ // Sakura end - merge cannon entities
|
||||
+
|
||||
public FallingBlockEntity(EntityType<? extends FallingBlockEntity> type, Level world) {
|
||||
super(type, world);
|
||||
this.blockState = Blocks.SAND.defaultBlockState();
|
||||
@@ -80,6 +132,7 @@ public class FallingBlockEntity extends Entity {
|
||||
this.fallDamageMax = 40;
|
||||
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
|
||||
}
|
||||
|
||||
public FallingBlockEntity(Level world, double x, double y, double z, BlockState block) {
|
||||
@@ -222,6 +275,7 @@ public class FallingBlockEntity extends Entity {
|
||||
return;
|
||||
}
|
||||
// CraftBukkit end
|
||||
+ if (this.respawnEntity()) return; // Sakura - merge cannon entities
|
||||
if (this.level().setBlock(blockposition, this.blockState, 3)) {
|
||||
((ServerLevel) this.level()).getChunkSource().chunkMap.broadcast(this, new ClientboundBlockUpdatePacket(blockposition, this.level().getBlockState(blockposition)));
|
||||
this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause
|
||||
@@ -342,6 +396,7 @@ public class FallingBlockEntity extends Entity {
|
||||
|
||||
nbt.putBoolean("CancelDrop", this.cancelDrop);
|
||||
if (!autoExpire) {nbt.putBoolean("Paper.AutoExpire", false);} // Paper - Expand FallingBlock API
|
||||
+ nbt.putInt("merge_count", this.mergeData.getCount()); // Sakura - merge cannon entities
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -374,6 +429,11 @@ public class FallingBlockEntity extends Entity {
|
||||
this.autoExpire = nbt.getBoolean("Paper.AutoExpire");
|
||||
}
|
||||
// Paper end - Expand FallingBlock API
|
||||
+ // Sakura start - merge cannon entities
|
||||
+ if (nbt.contains("merge_count", 3)) {
|
||||
+ this.mergeData.setCount(nbt.getInt("merge_count"));
|
||||
+ }
|
||||
+ // Sakura end - merge cannon entities
|
||||
}
|
||||
|
||||
public void setHurtsEntities(float fallHurtAmount, int fallHurtMax) {
|
||||
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 46b729ecf0c58bdbe7a4717e73b098dcffd910f1..f7d8e2ba0ee9b8dd27f20a3e75992b107d07fbf0 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||
@@ -33,7 +33,7 @@ import org.bukkit.event.entity.EntityRemoveEvent;
|
||||
import org.bukkit.event.entity.ExplosionPrimeEvent;
|
||||
// CraftBukkit end
|
||||
|
||||
-public class PrimedTnt extends Entity implements TraceableEntity {
|
||||
+public class PrimedTnt extends Entity implements TraceableEntity, me.samsuik.sakura.entity.merge.MergeableEntity { // Sakura - merge cannon entities
|
||||
|
||||
private static final EntityDataAccessor<Integer> DATA_FUSE_ID = SynchedEntityData.defineId(PrimedTnt.class, EntityDataSerializers.INT);
|
||||
private static final EntityDataAccessor<BlockState> DATA_BLOCK_STATE_ID = SynchedEntityData.defineId(PrimedTnt.class, EntityDataSerializers.BLOCK_STATE);
|
||||
@@ -59,12 +59,49 @@ public class PrimedTnt extends Entity implements TraceableEntity {
|
||||
public float explosionPower;
|
||||
public boolean isIncendiary = false; // CraftBukkit - add field
|
||||
|
||||
+ // Sakura start - merge cannon entities
|
||||
+ private final me.samsuik.sakura.entity.merge.MergeEntityData mergeData = new me.samsuik.sakura.entity.merge.MergeEntityData(this);
|
||||
+
|
||||
+ @Override
|
||||
+ public final me.samsuik.sakura.entity.merge.MergeEntityData getMergeEntityData() {
|
||||
+ return this.mergeData;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public final boolean isSafeToMergeInto(me.samsuik.sakura.entity.merge.MergeableEntity entity, boolean ticksLived) {
|
||||
+ return entity instanceof PrimedTnt tnt
|
||||
+ && tnt.getFuse() + 1 == this.getFuse()
|
||||
+ // required to prevent issues with powdered snow
|
||||
+ && (tnt.entityState().fallDistance() == this.fallDistance
|
||||
+ || tnt.entityState().fallDistance() > 2.5f && this.fallDistance > 2.5f);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public final void respawnEntity(int count) {
|
||||
+ PrimedTnt tnt = new PrimedTnt(EntityType.TNT, this.level());
|
||||
+ tnt.updateBukkitHandle(this); // update handle for plugins
|
||||
+ while (count-- > 1) {
|
||||
+ this.setFuse(100); // Prevent unwanted explosions while ticking
|
||||
+
|
||||
+ // Cause an explosion to affect this entity
|
||||
+ tnt.setPos(this.position());
|
||||
+ tnt.setDeltaMovement(this.getDeltaMovement());
|
||||
+ this.entityState().apply(this);
|
||||
+ tnt.explode();
|
||||
+ this.storeEntityState();
|
||||
+
|
||||
+ this.tick();
|
||||
+ }
|
||||
+ }
|
||||
+ // Sakura end - merge cannon entities
|
||||
+
|
||||
public PrimedTnt(EntityType<? extends PrimedTnt> type, Level world) {
|
||||
super(type, world);
|
||||
this.explosionPower = 4.0F;
|
||||
this.blocksBuilding = true;
|
||||
this.isPrimedTNT = true; // Sakura
|
||||
this.loadChunks = world.sakuraConfig().cannons.loadChunks; // Sakura - load chunks on movement
|
||||
+ this.mergeData.setMergeLevel(world.sakuraConfig().cannons.mergeLevel); // Sakura - merge cannon entities
|
||||
}
|
||||
|
||||
public PrimedTnt(Level world, double x, double y, double z, @Nullable LivingEntity igniter) {
|
||||
@@ -125,6 +162,7 @@ public class PrimedTnt extends Entity implements TraceableEntity {
|
||||
if (i <= 0) {
|
||||
// CraftBukkit start - Need to reverse the order of the explosion and the entity death so we have a location for the event
|
||||
// this.discard();
|
||||
+ this.respawnEntity(); // Sakura - merge cannon entities
|
||||
if (!this.level().isClientSide) {
|
||||
this.explode();
|
||||
}
|
||||
@@ -185,7 +223,7 @@ public class PrimedTnt extends Entity implements TraceableEntity {
|
||||
if (this.explosionPower != 4.0F) {
|
||||
nbt.putFloat("explosion_power", this.explosionPower);
|
||||
}
|
||||
-
|
||||
+ nbt.putInt("merge_count", this.mergeData.getCount()); // Sakura - merge cannon entities
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -194,6 +232,11 @@ public class PrimedTnt extends Entity implements TraceableEntity {
|
||||
if (nbt.contains("block_state", 10)) {
|
||||
this.setBlockState(NbtUtils.readBlockState(this.level().holderLookup(Registries.BLOCK), nbt.getCompound("block_state")));
|
||||
}
|
||||
+ // Sakura start - merge cannon entities
|
||||
+ if (nbt.contains("merge_count", 3)) {
|
||||
+ this.mergeData.setCount(nbt.getInt("merge_count"));
|
||||
+ }
|
||||
+ // Sakura end - merge cannon entities
|
||||
|
||||
if (nbt.contains("explosion_power", 99)) {
|
||||
this.explosionPower = Mth.clamp(nbt.getFloat("explosion_power"), 0.0F, 128.0F);
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index c69c04451c61bcc32e539baae160f05e3418841f..8f4a0912a5b5f17c22d2b4c0ef39e1c5566fa5f7 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -842,6 +842,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
return chunk != null ? chunk.getNoiseBiome(x, y, z) : this.getUncachedNoiseBiome(x, y, z);
|
||||
}
|
||||
// Paper end - optimise random ticking
|
||||
+ public final me.samsuik.sakura.entity.merge.EntityMergeHandler mergeHandler = new me.samsuik.sakura.entity.merge.EntityMergeHandler(); // Sakura - merge cannon entities
|
||||
|
||||
protected Level(WritableLevelData worlddatamutable, ResourceKey<Level> resourcekey, RegistryAccess iregistrycustom, Holder<DimensionType> holder, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function<org.spigotmc.SpigotWorldConfig, io.papermc.paper.configuration.WorldConfiguration> paperWorldConfigCreator, java.util.function.Supplier<me.samsuik.sakura.configuration.WorldConfiguration> sakuraWorldConfigCreator, java.util.concurrent.Executor executor) { // Sakura - sakura configuration files // Paper - create paper world config & Anti-Xray
|
||||
// Paper start - getblock optimisations - cache world height/sections
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/BasePressurePlateBlock.java b/src/main/java/net/minecraft/world/level/block/BasePressurePlateBlock.java
|
||||
index 9afa811579ac2e556b5c5c23b3b49587439dfadc..c2eb63de04fc48bd2cc1aad8d9cba272c0829c80 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/BasePressurePlateBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/BasePressurePlateBlock.java
|
||||
@@ -89,7 +89,7 @@ public abstract class BasePressurePlateBlock extends Block {
|
||||
}
|
||||
|
||||
private void checkPressed(@Nullable Entity entity, Level world, BlockPos pos, BlockState state, int output) {
|
||||
- int j = this.getSignalStrength(world, pos);
|
||||
+ int j = this.getSignalStrength(world, pos, output == 0); // Sakura - merge cannon entities
|
||||
boolean flag = output > 0;
|
||||
boolean flag1 = j > 0;
|
||||
|
||||
@@ -171,6 +171,12 @@ public abstract class BasePressurePlateBlock extends Block {
|
||||
})); // CraftBukkit
|
||||
}
|
||||
|
||||
+ // Sakura start - merge cannon entities
|
||||
+ protected int getSignalStrength(Level world, BlockPos pos, boolean entityInside) {
|
||||
+ return this.getSignalStrength(world, pos);
|
||||
+ }
|
||||
+ // Sakura end - merge cannon entities
|
||||
+
|
||||
protected abstract int getSignalStrength(Level world, BlockPos pos);
|
||||
|
||||
protected abstract int getSignalForState(BlockState state);
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/WeightedPressurePlateBlock.java b/src/main/java/net/minecraft/world/level/block/WeightedPressurePlateBlock.java
|
||||
index 05bf23bd9ec951840ffceb68638458de02ad0063..f9c800e912ce966dba4f1026f2d5b702ae6549cd 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/WeightedPressurePlateBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/WeightedPressurePlateBlock.java
|
||||
@@ -42,6 +42,11 @@ public class WeightedPressurePlateBlock extends BasePressurePlateBlock {
|
||||
|
||||
@Override
|
||||
protected int getSignalStrength(Level world, BlockPos pos) {
|
||||
+ // Sakura start - merge cannon entities
|
||||
+ return this.getSignalStrength(world, pos, false);
|
||||
+ }
|
||||
+ protected final int getSignalStrength(Level world, BlockPos pos, boolean entityInside) {
|
||||
+ // Sakura end - merge cannon entities
|
||||
// CraftBukkit start
|
||||
// int i = Math.min(getEntityCount(world, BlockPressurePlateWeighted.TOUCH_AABB.move(blockposition), Entity.class), this.maxWeight);
|
||||
int i = 0;
|
||||
@@ -57,7 +62,7 @@ public class WeightedPressurePlateBlock extends BasePressurePlateBlock {
|
||||
|
||||
// We only want to block turning the plate on if all events are cancelled
|
||||
if (!cancellable.isCancelled()) {
|
||||
- i++;
|
||||
+ i += !entityInside && entity instanceof me.samsuik.sakura.entity.merge.MergeableEntity mergeEntity ? mergeEntity.getMergeEntityData().getCount() : 1; // Sakura - merge cannon entities
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java
|
||||
index 1359d25a32b4a5d5e8e68ce737bd19f7b5afaf69..55f67c2ca07eca0d3e1522eebbb4ce37704bdd04 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java
|
||||
@@ -14,6 +14,28 @@ public class CraftFallingBlock extends CraftEntity implements FallingBlock {
|
||||
super(server, entity);
|
||||
}
|
||||
|
||||
+ // Sakura start - merge cannon entities
|
||||
+ @Override
|
||||
+ public @org.jetbrains.annotations.NotNull me.samsuik.sakura.entity.merge.MergeLevel getMergeLevel() {
|
||||
+ return this.getHandle().getMergeEntityData().getMergeLevel();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setMergeLevel(@org.jetbrains.annotations.NotNull me.samsuik.sakura.entity.merge.MergeLevel level) {
|
||||
+ this.getHandle().getMergeEntityData().setMergeLevel(level);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getStacked() {
|
||||
+ return this.getHandle().getMergeEntityData().getCount();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setStacked(int stacked) {
|
||||
+ this.getHandle().getMergeEntityData().setCount(stacked);
|
||||
+ }
|
||||
+ // Sakura end - merge cannon entities
|
||||
+
|
||||
@Override
|
||||
public FallingBlockEntity getHandle() {
|
||||
return (FallingBlockEntity) this.entity;
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftTNTPrimed.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftTNTPrimed.java
|
||||
index a61aec087fa7cec27a803668bdc1b9e6eb336755..c6f36ab2368d0e2e4555d5f8edc0132dcb61a53c 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftTNTPrimed.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftTNTPrimed.java
|
||||
@@ -12,6 +12,28 @@ public class CraftTNTPrimed extends CraftEntity implements TNTPrimed {
|
||||
super(server, entity);
|
||||
}
|
||||
|
||||
+ // Sakura start - merge cannon entities
|
||||
+ @Override
|
||||
+ public @org.jetbrains.annotations.NotNull me.samsuik.sakura.entity.merge.MergeLevel getMergeLevel() {
|
||||
+ return this.getHandle().getMergeEntityData().getMergeLevel();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setMergeLevel(@org.jetbrains.annotations.NotNull me.samsuik.sakura.entity.merge.MergeLevel level) {
|
||||
+ this.getHandle().getMergeEntityData().setMergeLevel(level);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getStacked() {
|
||||
+ return this.getHandle().getMergeEntityData().getCount();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setStacked(int stacked) {
|
||||
+ this.getHandle().getMergeEntityData().setCount(stacked);
|
||||
+ }
|
||||
+ // Sakura end - merge cannon entities
|
||||
+
|
||||
@Override
|
||||
public float getYield() {
|
||||
return this.getHandle().explosionPower;
|
||||
@@ -0,0 +1,285 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samsuik <kfian294ma4@gmail.com>
|
||||
Date: Mon, 22 Apr 2024 23:01:26 +0100
|
||||
Subject: [PATCH] Replace explosion density cache
|
||||
|
||||
|
||||
diff --git a/src/main/java/me/samsuik/sakura/explosion/density/BlockDensityCache.java b/src/main/java/me/samsuik/sakura/explosion/density/BlockDensityCache.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..35454e122e87892099226ba8fd8d444664be9037
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/me/samsuik/sakura/explosion/density/BlockDensityCache.java
|
||||
@@ -0,0 +1,62 @@
|
||||
+package me.samsuik.sakura.explosion.density;
|
||||
+
|
||||
+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
+import net.minecraft.util.Mth;
|
||||
+import net.minecraft.world.entity.Entity;
|
||||
+import net.minecraft.world.phys.Vec3;
|
||||
+
|
||||
+/**
|
||||
+ * This is a replacement for papers explosion density cache to be more lenient and efficient.
|
||||
+ */
|
||||
+public final class BlockDensityCache {
|
||||
+ public static final float UNKNOWN_DENSITY = -1.0f;
|
||||
+
|
||||
+ private final Int2ObjectOpenHashMap<DensityData> densityDataMap = new Int2ObjectOpenHashMap<>();
|
||||
+ private DensityData data;
|
||||
+ private int key;
|
||||
+ private boolean knownSource;
|
||||
+
|
||||
+ public float getDensity(Vec3 explosion, Entity entity) {
|
||||
+ int key = getKey(explosion, entity);
|
||||
+ DensityData data = this.densityDataMap.get(key);
|
||||
+
|
||||
+ if (data != null && data.hasPosition(explosion, entity.getBoundingBox())) {
|
||||
+ return data.density();
|
||||
+ } else {
|
||||
+ this.knownSource = data != null && data.complete() && data.isExplosionPosition(explosion);
|
||||
+ this.data = data;
|
||||
+ this.key = key;
|
||||
+ return UNKNOWN_DENSITY;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public float getKnownDensity(Vec3 point) {
|
||||
+ if (this.knownSource && this.data.isKnownPosition(point)) {
|
||||
+ return this.data.density();
|
||||
+ } else {
|
||||
+ return UNKNOWN_DENSITY;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public void putDensity(Vec3 explosion, Entity entity, float density) {
|
||||
+ if (this.data == null || !this.data.complete()) {
|
||||
+ this.densityDataMap.put(this.key, new DensityData(explosion, entity, density));
|
||||
+ } else if (this.data.density() == density) {
|
||||
+ this.data.expand(explosion, entity);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public void invalidate() {
|
||||
+ this.densityDataMap.clear();
|
||||
+ }
|
||||
+
|
||||
+ private static int getKey(Vec3 explosion, Entity entity) {
|
||||
+ int key = Mth.floor(explosion.x());
|
||||
+ key = 31 * key + Mth.floor(explosion.y());
|
||||
+ key = 31 * key + Mth.floor(explosion.z());
|
||||
+ key = 31 * key + entity.getBlockX();
|
||||
+ key = 31 * key + entity.getBlockY();
|
||||
+ key = 31 * key + entity.getBlockZ();
|
||||
+ return key;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/me/samsuik/sakura/explosion/density/DensityData.java b/src/main/java/me/samsuik/sakura/explosion/density/DensityData.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..d7e24638f07f243502004970ab4ce646cbe1e436
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/me/samsuik/sakura/explosion/density/DensityData.java
|
||||
@@ -0,0 +1,47 @@
|
||||
+package me.samsuik.sakura.explosion.density;
|
||||
+
|
||||
+import net.minecraft.world.entity.Entity;
|
||||
+import net.minecraft.world.phys.AABB;
|
||||
+import net.minecraft.world.phys.Vec3;
|
||||
+
|
||||
+public final class DensityData {
|
||||
+ private AABB source;
|
||||
+ private AABB known;
|
||||
+ private AABB entity;
|
||||
+ private final float density;
|
||||
+ private final boolean complete;
|
||||
+
|
||||
+ public DensityData(Vec3 explosion, Entity entity, float density) {
|
||||
+ this.source = new AABB(explosion, explosion);
|
||||
+ this.known = new AABB(entity.position(), entity.position());
|
||||
+ this.entity = entity.getBoundingBox();
|
||||
+ this.density = density;
|
||||
+ this.complete = Math.abs(density - 0.5f) == 0.5f;
|
||||
+ }
|
||||
+
|
||||
+ public float density() {
|
||||
+ return this.density;
|
||||
+ }
|
||||
+
|
||||
+ public boolean complete() {
|
||||
+ return this.complete;
|
||||
+ }
|
||||
+
|
||||
+ public boolean hasPosition(Vec3 explosion, AABB entity) {
|
||||
+ return this.isExplosionPosition(explosion) && this.entity.isAABBInBounds(entity);
|
||||
+ }
|
||||
+
|
||||
+ public boolean isKnownPosition(Vec3 point) {
|
||||
+ return this.entity.isVec3InBounds(point);
|
||||
+ }
|
||||
+
|
||||
+ public boolean isExplosionPosition(Vec3 explosion) {
|
||||
+ return this.source.isVec3InBounds(explosion);
|
||||
+ }
|
||||
+
|
||||
+ public void expand(Vec3 explosion, Entity entity) {
|
||||
+ this.source = this.source.expand(explosion);
|
||||
+ this.known = this.known.expand(entity.position());
|
||||
+ this.entity = this.entity.minmax(entity.getBoundingBox());
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index c73aa5fd7da18219d1da63a0973f397316ba4210..56357e253247d19c108a7f753058fa3eba0302ee 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -1906,6 +1906,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
worldserver.localConfig().expire(currentTick); // Sakura - add local config
|
||||
worldserver.explosionPositions.clear(); // Sakura - client visibility settings
|
||||
worldserver.mergeHandler.expire(currentTick); // Sakura - merge cannon entities
|
||||
+ worldserver.densityCache.invalidate(); // Sakura - explosion density cache
|
||||
}
|
||||
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 8f4a0912a5b5f17c22d2b4c0ef39e1c5566fa5f7..addab159f6fb73fe063f8a057c281d0594a99122 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -843,6 +843,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
}
|
||||
// Paper end - optimise random ticking
|
||||
public final me.samsuik.sakura.entity.merge.EntityMergeHandler mergeHandler = new me.samsuik.sakura.entity.merge.EntityMergeHandler(); // Sakura - merge cannon entities
|
||||
+ public final me.samsuik.sakura.explosion.density.BlockDensityCache densityCache = new me.samsuik.sakura.explosion.density.BlockDensityCache(); // Sakura - explosion density cache
|
||||
|
||||
protected Level(WritableLevelData worlddatamutable, ResourceKey<Level> resourcekey, RegistryAccess iregistrycustom, Holder<DimensionType> holder, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function<org.spigotmc.SpigotWorldConfig, io.papermc.paper.configuration.WorldConfiguration> paperWorldConfigCreator, java.util.function.Supplier<me.samsuik.sakura.configuration.WorldConfiguration> sakuraWorldConfigCreator, java.util.concurrent.Executor executor) { // Sakura - sakura configuration files // Paper - create paper world config & Anti-Xray
|
||||
// Paper start - getblock optimisations - cache world height/sections
|
||||
diff --git a/src/main/java/net/minecraft/world/level/ServerExplosion.java b/src/main/java/net/minecraft/world/level/ServerExplosion.java
|
||||
index 076ef180360c54517b9acb3ef9e803be41b66f9d..4f9401f654630b5c219681efdda935006629eca7 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/ServerExplosion.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/ServerExplosion.java
|
||||
@@ -297,7 +297,12 @@ public class ServerExplosion implements Explosion {
|
||||
Math.fma(dz, diffZ, offZ)
|
||||
);
|
||||
|
||||
- if (!this.clipsAnything(from, source, context, blockCache, blockPos)) {
|
||||
+ // Sakura start - replace density cache
|
||||
+ final float density = this.level.densityCache.getKnownDensity(from);
|
||||
+ if (density != me.samsuik.sakura.explosion.density.BlockDensityCache.UNKNOWN_DENSITY) {
|
||||
+ missedRays += (int) density;
|
||||
+ } else if (!this.clipsAnything(from, source, context, blockCache, blockPos)) {
|
||||
+ // Sakura end - replace density cache
|
||||
++missedRays;
|
||||
}
|
||||
}
|
||||
@@ -377,7 +382,16 @@ public class ServerExplosion implements Explosion {
|
||||
double d10 = Mth.lerp(d7, axisalignedbb.minZ, axisalignedbb.maxZ);
|
||||
Vec3 vec3d1 = new Vec3(d8 + d3, d9, d10 + d4);
|
||||
|
||||
- if (entity.level().clip(new ClipContext(vec3d1, pos, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, entity)).getType() == HitResult.Type.MISS) {
|
||||
+ // Sakura start - replace density cache
|
||||
+ final net.minecraft.world.phys.HitResult.Type hitResult;
|
||||
+ final float density = entity.level().densityCache.getKnownDensity(vec3d1);
|
||||
+ if (density != me.samsuik.sakura.explosion.density.BlockDensityCache.UNKNOWN_DENSITY) {
|
||||
+ hitResult = density != 0.0f ? net.minecraft.world.phys.HitResult.Type.MISS : net.minecraft.world.phys.HitResult.Type.BLOCK;
|
||||
+ } else {
|
||||
+ hitResult = entity.level().clip(new ClipContext(vec3d1, pos, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, entity)).getType();
|
||||
+ }
|
||||
+ if (hitResult == HitResult.Type.MISS) {
|
||||
+ // Sakura end - replace density cache
|
||||
++i;
|
||||
}
|
||||
|
||||
@@ -691,6 +705,12 @@ public class ServerExplosion implements Explosion {
|
||||
return;
|
||||
}
|
||||
// CraftBukkit end
|
||||
+ // Sakura start - explosion density cache
|
||||
+ if (!positions.isEmpty() && !this.level.paperConfig().environment.optimizeExplosions) {
|
||||
+ this.level.densityCache.invalidate();
|
||||
+ }
|
||||
+ // Sakura end - explosion density cache
|
||||
+
|
||||
Iterator iterator = positions.iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
@@ -868,14 +888,12 @@ public class ServerExplosion implements Explosion {
|
||||
|
||||
// Paper start - Optimize explosions
|
||||
private float getBlockDensity(Vec3 vec3d, Entity entity) {
|
||||
- if (!this.level.paperConfig().environment.optimizeExplosions) {
|
||||
- return this.getSeenFraction(vec3d, entity, this.directMappedBlockCache, this.mutablePos); // Paper - collision optimisations
|
||||
- }
|
||||
- CacheKey key = new CacheKey(this, entity.getBoundingBox());
|
||||
- Float blockDensity = this.level.explosionDensityCache.get(key);
|
||||
- if (blockDensity == null) {
|
||||
+ // Sakura start - replace density cache
|
||||
+ float blockDensity = this.level.densityCache.getDensity(vec3d, entity);
|
||||
+ if (blockDensity == me.samsuik.sakura.explosion.density.BlockDensityCache.UNKNOWN_DENSITY) {
|
||||
blockDensity = this.getSeenFraction(vec3d, entity, this.directMappedBlockCache, this.mutablePos); // Paper - collision optimisations
|
||||
- this.level.explosionDensityCache.put(key, blockDensity);
|
||||
+ this.level.densityCache.putDensity(vec3d, entity, blockDensity);
|
||||
+ // Sakura end - replace density cache
|
||||
}
|
||||
|
||||
return blockDensity;
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/BasePressurePlateBlock.java b/src/main/java/net/minecraft/world/level/block/BasePressurePlateBlock.java
|
||||
index c2eb63de04fc48bd2cc1aad8d9cba272c0829c80..0d9f944a3777ac3a0f569832468c5c97b0fdf488 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/BasePressurePlateBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/BasePressurePlateBlock.java
|
||||
@@ -109,6 +109,11 @@ public abstract class BasePressurePlateBlock extends Block {
|
||||
if (output != j) {
|
||||
BlockState iblockdata1 = this.setSignalForState(state, j);
|
||||
|
||||
+ // Sakura start - explosion density cache
|
||||
+ if (!world.paperConfig().environment.optimizeExplosions) {
|
||||
+ world.densityCache.invalidate();
|
||||
+ }
|
||||
+ // Sakura end - explosion density cache
|
||||
world.setBlock(pos, iblockdata1, 2);
|
||||
this.updateNeighbours(world, pos);
|
||||
world.setBlocksDirty(pos, state, iblockdata1);
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java b/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java
|
||||
index c2589f42c467ca672417c24076313da51bb2dcbb..5ae5ef6edf3a6e2b8be9ce11ca46c7714accc4f3 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java
|
||||
@@ -175,6 +175,11 @@ public class TripWireHookBlock extends Block {
|
||||
blockposition1 = pos.relative(enumdirection, j);
|
||||
Direction enumdirection1 = enumdirection.getOpposite();
|
||||
|
||||
+ // Sakura start - explosion density cache
|
||||
+ if (!world.paperConfig().environment.optimizeExplosions) {
|
||||
+ world.densityCache.invalidate();
|
||||
+ }
|
||||
+ // Sakura end - explosion density cache
|
||||
world.setBlock(blockposition1, (BlockState) iblockdata3.setValue(TripWireHookBlock.FACING, enumdirection1), 3);
|
||||
TripWireHookBlock.notifyNeighbors(block, world, blockposition1, enumdirection1);
|
||||
TripWireHookBlock.emitState(world, blockposition1, flag4, flag5, flag2, flag3);
|
||||
diff --git a/src/main/java/net/minecraft/world/phys/AABB.java b/src/main/java/net/minecraft/world/phys/AABB.java
|
||||
index 6cf6d4ec7b9e43c7b2b4c0e2fb080964ff588130..a867ec0347038c7246af3f3377eceda17e695ec3 100644
|
||||
--- a/src/main/java/net/minecraft/world/phys/AABB.java
|
||||
+++ b/src/main/java/net/minecraft/world/phys/AABB.java
|
||||
@@ -551,4 +551,28 @@ public class AABB {
|
||||
public static AABB ofSize(Vec3 center, double dx, double dy, double dz) {
|
||||
return new AABB(center.x - dx / 2.0, center.y - dy / 2.0, center.z - dz / 2.0, center.x + dx / 2.0, center.y + dy / 2.0, center.z + dz / 2.0);
|
||||
}
|
||||
+
|
||||
+ // Sakura start - explosion density cache
|
||||
+ public final boolean isAABBInBounds(AABB bb) {
|
||||
+ return this.minX <= bb.minX && this.maxX >= bb.maxX
|
||||
+ && this.minY <= bb.minY && this.maxY >= bb.maxY
|
||||
+ && this.minZ <= bb.minZ && this.maxZ >= bb.maxZ;
|
||||
+ }
|
||||
+
|
||||
+ public final boolean isVec3InBounds(Vec3 p) {
|
||||
+ return this.minX <= p.x && this.maxX >= p.x
|
||||
+ && this.minY <= p.y && this.maxY >= p.y
|
||||
+ && this.minZ <= p.z && this.maxZ >= p.z;
|
||||
+ }
|
||||
+
|
||||
+ public final AABB expand(Vec3 pos) {
|
||||
+ double minX = Math.min(this.minX, pos.x);
|
||||
+ double minY = Math.min(this.minY, pos.y);
|
||||
+ double minZ = Math.min(this.minZ, pos.z);
|
||||
+ double maxX = Math.max(this.maxX, pos.x);
|
||||
+ double maxY = Math.max(this.maxY, pos.y);
|
||||
+ double maxZ = Math.max(this.maxZ, pos.z);
|
||||
+ return new AABB(minX, minY, minZ, maxX, maxY, maxZ);
|
||||
+ }
|
||||
+ // Sakura end - explosion density cache
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samsuik <kfian294ma4@gmail.com>
|
||||
Date: Fri, 3 May 2024 15:18:58 +0100
|
||||
Subject: [PATCH] Optimise explosions in protected regions
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/ServerExplosion.java b/src/main/java/net/minecraft/world/level/ServerExplosion.java
|
||||
index 10432b31acd047ac2aa8581f2ee863254ec8d1eb..b07c2eb8cc3cc54e8ab72c5ed3d6d7623416e7fb 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/ServerExplosion.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/ServerExplosion.java
|
||||
@@ -345,6 +345,22 @@ public class ServerExplosion implements Explosion {
|
||||
return rays;
|
||||
}
|
||||
// Sakura end - optimise paper explosions
|
||||
+ // Sakura start - optimise explosion protected regions
|
||||
+ protected final boolean isRegionUnprotected() {
|
||||
+ // optimisation: We check if a plugin has cancelled the event or cleared the blockList.
|
||||
+ // It tells us if the result was thrown away, so we can avoid the block searching logic.
|
||||
+ // As a side effect the event is called twice which may interfere with some plugins.
|
||||
+ if (this.source != null && this.level.sakuraConfig().cannons.explosion.optimiseProtectedRegions) {
|
||||
+ Location location = new Location(this.level.getWorld(), this.center.x, this.center.y, this.center.z);
|
||||
+ List<org.bukkit.block.Block> blocks = new ObjectArrayList<>(1);
|
||||
+ blocks.add(location.getBlock());
|
||||
+ EntityExplodeEvent event = CraftEventFactory.callEntityExplodeEvent(this.source, blocks, 0.0f, this.blockInteraction);
|
||||
+ return !event.isCancelled() && !event.blockList().isEmpty();
|
||||
+ }
|
||||
+
|
||||
+ return true;
|
||||
+ }
|
||||
+ // Sakura end - optimise explosion protected regions
|
||||
|
||||
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;
|
||||
@@ -441,6 +457,11 @@ public class ServerExplosion implements Explosion {
|
||||
return ret;
|
||||
}
|
||||
// Sakura end - optimise paper explosions
|
||||
+ // Sakura start - optimise protected explosions
|
||||
+ if (!this.isRegionUnprotected()) {
|
||||
+ return ret;
|
||||
+ }
|
||||
+ // Sakura end - optimise protected explosions
|
||||
|
||||
// only ~1/3rd of the loop iterations in vanilla will result in a ray, as it is iterating the perimeter of
|
||||
// a 16x16x16 cube
|
||||
661
migrate/server/feature/0019-Specialised-Explosions.patch
Normal file
661
migrate/server/feature/0019-Specialised-Explosions.patch
Normal file
@@ -0,0 +1,661 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samsuik <kfian294ma4@gmail.com>
|
||||
Date: Fri, 3 May 2024 15:04:31 +0100
|
||||
Subject: [PATCH] Specialised Explosions
|
||||
|
||||
|
||||
diff --git a/src/main/java/ca/spottedleaf/moonrise/common/list/IteratorSafeOrderedReferenceSet.java b/src/main/java/ca/spottedleaf/moonrise/common/list/IteratorSafeOrderedReferenceSet.java
|
||||
index c21e00812f1aaa1279834a0562d360d6b89e146c..1e1329adde1457898a3002279b53b1bbb91c36d2 100644
|
||||
--- a/src/main/java/ca/spottedleaf/moonrise/common/list/IteratorSafeOrderedReferenceSet.java
|
||||
+++ b/src/main/java/ca/spottedleaf/moonrise/common/list/IteratorSafeOrderedReferenceSet.java
|
||||
@@ -107,6 +107,12 @@ public final class IteratorSafeOrderedReferenceSet<E> {
|
||||
}
|
||||
}
|
||||
|
||||
+ // Sakura start - specialised explosions; add indexOf method
|
||||
+ public int indexOf(final E element) {
|
||||
+ return this.indexMap.getInt(element);
|
||||
+ }
|
||||
+ // Sakura end - specialised explosions; add indexOf method
|
||||
+
|
||||
public boolean remove(final E element) {
|
||||
final int index = this.indexMap.removeInt(element);
|
||||
if (index >= 0) {
|
||||
diff --git a/src/main/java/me/samsuik/sakura/explosion/special/SpecialisedExplosion.java b/src/main/java/me/samsuik/sakura/explosion/special/SpecialisedExplosion.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..ce04a5d9aaef3ca8ba8d7b988bdf0497285f90c1
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/me/samsuik/sakura/explosion/special/SpecialisedExplosion.java
|
||||
@@ -0,0 +1,203 @@
|
||||
+package me.samsuik.sakura.explosion.special;
|
||||
+
|
||||
+import ca.spottedleaf.moonrise.common.util.WorldUtil;
|
||||
+import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.ChunkEntitySlices;
|
||||
+import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.EntityLookup;
|
||||
+import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
+import net.minecraft.core.BlockPos;
|
||||
+import net.minecraft.server.level.ServerLevel;
|
||||
+import net.minecraft.util.Mth;
|
||||
+import net.minecraft.world.damagesource.DamageSource;
|
||||
+import net.minecraft.world.entity.Entity;
|
||||
+import net.minecraft.world.level.ExplosionDamageCalculator;
|
||||
+import net.minecraft.world.level.ServerExplosion;
|
||||
+import net.minecraft.world.phys.AABB;
|
||||
+import net.minecraft.world.phys.Vec3;
|
||||
+import org.jetbrains.annotations.Nullable;
|
||||
+
|
||||
+import java.util.List;
|
||||
+import java.util.function.Consumer;
|
||||
+
|
||||
+public abstract class SpecialisedExplosion<T extends Entity> extends ServerExplosion {
|
||||
+ private static final double ENTITY_DISPATCH_DISTANCE = Math.pow(32.0, 2.0);
|
||||
+
|
||||
+ protected final T cause; // preferred over source
|
||||
+ private Vec3 impactPosition;
|
||||
+ protected final BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos();
|
||||
+ private final Consumer<SpecialisedExplosion<T>> applyEffects;
|
||||
+
|
||||
+ public SpecialisedExplosion(ServerLevel level, T entity, @Nullable DamageSource damageSource, @Nullable ExplosionDamageCalculator behavior, Vec3 center, float power, boolean createFire, BlockInteraction destructionType, Consumer<SpecialisedExplosion<T>> applyEffects) {
|
||||
+ super(level, entity, damageSource, behavior, center, power, createFire, destructionType);
|
||||
+ this.cause = entity;
|
||||
+ this.impactPosition = center;
|
||||
+ this.applyEffects = applyEffects;
|
||||
+ }
|
||||
+
|
||||
+ protected double getExplosionOffset() {
|
||||
+ return (double) this.cause.getBbHeight() * 0.0625D;
|
||||
+ }
|
||||
+
|
||||
+ protected abstract int getExplosionCount();
|
||||
+
|
||||
+ protected abstract void startExplosion();
|
||||
+
|
||||
+ @Override
|
||||
+ public final void explode() {
|
||||
+ if (this.radius() < 0.1F) {
|
||||
+ // (radius < 0.1F) in bukkit is assumed to not be able to find any blocks or entities.
|
||||
+ for (int i = this.getExplosionCount() - 1; i >= 0; --i) {
|
||||
+ this.finalizeExplosionAndParticles(List.of());
|
||||
+ }
|
||||
+ } else {
|
||||
+ this.createBlockCache();
|
||||
+ this.startExplosion(); // search for blocks, impact entities, finalise if necessary
|
||||
+ this.clearBlockCache();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ protected final boolean requiresImpactEntities(List<BlockPos> blocks, Vec3 center) {
|
||||
+ if (this.impactPosition.distanceToSqr(center) > ENTITY_DISPATCH_DISTANCE) {
|
||||
+ this.impactPosition = center;
|
||||
+ return true;
|
||||
+ }
|
||||
+ return !blocks.isEmpty();
|
||||
+ }
|
||||
+
|
||||
+ protected final boolean finalizeExplosionAndParticles(List<BlockPos> blocks) {
|
||||
+ this.wasCanceled = false;
|
||||
+ List<BlockPos> explodedPositions = new ObjectArrayList<>(blocks);
|
||||
+ this.interactWithBlocks(explodedPositions);
|
||||
+
|
||||
+ if (!this.wasCanceled) {
|
||||
+ this.applyEffects.accept(this);
|
||||
+ this.getHitPlayers().clear();
|
||||
+ }
|
||||
+
|
||||
+ return !explodedPositions.isEmpty();
|
||||
+ }
|
||||
+
|
||||
+ protected void postExplosion(List<BlockPos> foundBlocks, boolean destroyedBlocks) {
|
||||
+ // optimisation: Keep the block cache across explosions and invalidate any found blocks.
|
||||
+ // This can help reduce block retrievals while block searching when there's a durable block,
|
||||
+ // and when ray tracing for obstructions. This is disabled by default because plugins can
|
||||
+ // change blocks in the explosion event.
|
||||
+ if (this.level().sakuraConfig().cannons.explosion.useBlockCacheAcrossExplosions && !foundBlocks.isEmpty() && !destroyedBlocks) {
|
||||
+ this.markBlocksInCacheAsExplodable(foundBlocks);
|
||||
+ } else {
|
||||
+ super.blockCache.clear();
|
||||
+ }
|
||||
+
|
||||
+ java.util.Arrays.fill(this.directMappedBlockCache, null);
|
||||
+ }
|
||||
+
|
||||
+ protected final void recalculateExplosionPosition() {
|
||||
+ this.recalculateExplosionPosition(this.cause);
|
||||
+ }
|
||||
+
|
||||
+ protected final void recalculateExplosionPosition(T entity) {
|
||||
+ double x = entity.getX();
|
||||
+ double y = entity.getY() + this.getExplosionOffset();
|
||||
+ double z = entity.getZ();
|
||||
+ this.center = new Vec3(x, y, z);
|
||||
+ }
|
||||
+
|
||||
+ protected final void forEachEntitySliceInBounds(AABB bb, Consumer<Entity[]> sliceConsumer) {
|
||||
+ int minSection = WorldUtil.getMinSection(this.level());
|
||||
+ int maxSection = WorldUtil.getMaxSection(this.level());
|
||||
+
|
||||
+ int minChunkX = Mth.floor(bb.minX) >> 4;
|
||||
+ int minChunkY = Mth.clamp(Mth.floor(bb.minY) >> 4, minSection, maxSection);
|
||||
+ int minChunkZ = Mth.floor(bb.minZ) >> 4;
|
||||
+ int maxChunkX = Mth.floor(bb.maxX) >> 4;
|
||||
+ int maxChunkY = Mth.clamp(Mth.floor(bb.maxY) >> 4, minSection, maxSection);
|
||||
+ int maxChunkZ = Mth.floor(bb.maxZ) >> 4;
|
||||
+
|
||||
+ EntityLookup entityLookup = this.level().moonrise$getEntityLookup();
|
||||
+ for (int chunkX = minChunkX; chunkX <= maxChunkX; ++chunkX) {
|
||||
+ for (int chunkZ = minChunkZ; chunkZ <= maxChunkZ; ++chunkZ) {
|
||||
+ ChunkEntitySlices chunk = entityLookup.getChunk(chunkX, chunkZ);
|
||||
+
|
||||
+ if (chunk == null) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ for (int chunkY = minChunkY; chunkY <= maxChunkY; ++chunkY) {
|
||||
+ sliceConsumer.accept(chunk.getSectionEntities(chunkY));
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ protected final void impactEntitiesFromPosition(Entity[] entities, Vec3 position, int potential, double radius) {
|
||||
+ for (int i = 0; i < entities.length; ++i) {
|
||||
+ Entity entity = entities[i];
|
||||
+ if (entity == null) break;
|
||||
+
|
||||
+ if (entity != this.source && !entity.ignoreExplosion(this)) {
|
||||
+ this.impactEntity(entity, position, potential, radius);
|
||||
+ }
|
||||
+
|
||||
+ if (entities[i] != entity) {
|
||||
+ i--;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ protected final void impactEntity(Entity entity, Vec3 pos, int potential, double radius) {
|
||||
+ if (this.excludeSourceFromDamage && entity == this.source) {
|
||||
+ return; // for paper api
|
||||
+ }
|
||||
+ if (entity.isPrimedTNT || entity.isFallingBlock) {
|
||||
+ this.impactCannonEntity(entity, pos, potential, radius);
|
||||
+ } else {
|
||||
+ for (int i = 0; i < potential; ++i) {
|
||||
+ super.impactEntity((float) radius, entity);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ protected final void impactCannonEntity(Entity entity, Vec3 pos, int potential, double radius) {
|
||||
+ double distanceFromBottom = Math.sqrt(entity.distanceToSqr(pos)) / radius;
|
||||
+
|
||||
+ if (distanceFromBottom <= 1.0) {
|
||||
+ double x = entity.getX() - pos.x;
|
||||
+ double y = (entity instanceof PrimedTnt ? entity.getY() : entity.getEyeY()) - pos.y;
|
||||
+ double z = entity.getZ() - pos.z;
|
||||
+ double distance = Math.sqrt(x * x + y * y + z * z);
|
||||
+
|
||||
+ if (distance != 0.0D) {
|
||||
+ x /= distance;
|
||||
+ y /= distance;
|
||||
+ z /= distance;
|
||||
+ double density = this.getBlockDensity(pos, entity); // Paper - Optimize explosions
|
||||
+ double exposure = (1.0D - distanceFromBottom) * density;
|
||||
+
|
||||
+ if (exposure == 0.0) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ x *= exposure;
|
||||
+ y *= exposure;
|
||||
+ z *= exposure;
|
||||
+
|
||||
+ this.applyEntityVelocity(entity, x, y, z, potential);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ protected final void applyEntityVelocity(Entity entity, double x, double y, double z, int potential) {
|
||||
+ Vec3 movement = entity.getDeltaMovement();
|
||||
+
|
||||
+ double moveX = movement.x();
|
||||
+ double moveY = movement.y();
|
||||
+ double moveZ = movement.z();
|
||||
+
|
||||
+ for (int i = 0; i < potential; ++i) {
|
||||
+ moveX += x;
|
||||
+ moveY += y;
|
||||
+ moveZ += z;
|
||||
+ }
|
||||
+
|
||||
+ entity.setDeltaMovement(moveX, moveY, moveZ);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/me/samsuik/sakura/explosion/special/TntExplosion.java b/src/main/java/me/samsuik/sakura/explosion/special/TntExplosion.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..ebe5f0c8c2f09920b5f5ef734e63f5e7cd8bd3a1
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/me/samsuik/sakura/explosion/special/TntExplosion.java
|
||||
@@ -0,0 +1,201 @@
|
||||
+package me.samsuik.sakura.explosion.special;
|
||||
+
|
||||
+import ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet;
|
||||
+import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
+import me.samsuik.sakura.entity.EntityState;
|
||||
+import me.samsuik.sakura.entity.merge.MergeLevel;
|
||||
+import me.samsuik.sakura.entity.merge.MergeableEntity;
|
||||
+import net.minecraft.core.BlockPos;
|
||||
+import net.minecraft.core.Direction;
|
||||
+import net.minecraft.server.level.ServerLevel;
|
||||
+import net.minecraft.world.damagesource.DamageSource;
|
||||
+import net.minecraft.world.entity.Entity;
|
||||
+import net.minecraft.world.entity.item.PrimedTnt;
|
||||
+import net.minecraft.world.level.ExplosionDamageCalculator;
|
||||
+import net.minecraft.world.phys.AABB;
|
||||
+import net.minecraft.world.phys.Vec3;
|
||||
+import org.bukkit.craftbukkit.util.CraftVector;
|
||||
+import org.bukkit.util.Vector;
|
||||
+import org.jetbrains.annotations.Nullable;
|
||||
+
|
||||
+import java.util.List;
|
||||
+import java.util.function.Consumer;
|
||||
+
|
||||
+public final class TntExplosion extends SpecialisedExplosion<PrimedTnt> {
|
||||
+ private static final int ALL_DIRECTIONS = 0b111;
|
||||
+ private static final int FOUND_ALL_BLOCKS = ALL_DIRECTIONS + 12;
|
||||
+
|
||||
+ private final Vec3 originalPosition;
|
||||
+ private final List<Vec3> explosions = new ObjectArrayList<>();
|
||||
+ private AABB bounds;
|
||||
+ private int wrapped = 0;
|
||||
+ private boolean moved = false;
|
||||
+
|
||||
+ public TntExplosion(ServerLevel level, PrimedTnt tnt, @Nullable DamageSource damageSource, @Nullable ExplosionDamageCalculator behavior, Vec3 center, float power, boolean createFire, BlockInteraction destructionType, Consumer<SpecialisedExplosion<PrimedTnt>> applyEffects) {
|
||||
+ super(level, tnt, damageSource, behavior, center, power, createFire, destructionType, applyEffects);
|
||||
+ this.originalPosition = center;
|
||||
+ this.bounds = new AABB(center, center);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected int getExplosionCount() {
|
||||
+ if (this.cause.getMergeEntityData().getMergeLevel() == MergeLevel.NONE) {
|
||||
+ this.mergeEntitiesBeforeExplosion();
|
||||
+ }
|
||||
+ return this.cause.getMergeEntityData().getCount();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected void startExplosion() {
|
||||
+ for (int i = this.getExplosionCount() - 1; i >= 0; --i) {
|
||||
+ Vec3 previousMomentum = this.cause.entityState().momentum();
|
||||
+ boolean lastCycle = i == 0;
|
||||
+ List<BlockPos> toBlow = this.midExplosion(previousMomentum, lastCycle); // search for blocks and impact entities
|
||||
+ boolean destroyedBlocks = this.finalizeExplosionAndParticles(toBlow);
|
||||
+
|
||||
+ if (!lastCycle) {
|
||||
+ EntityState entityState = this.nextSourceVelocity();
|
||||
+ this.postExplosion(toBlow, destroyedBlocks); // update wrapped, clear recent block cache
|
||||
+ this.updateExplosionPosition(entityState, destroyedBlocks);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private List<BlockPos> midExplosion(Vec3 previousMomentum, boolean lastCycle) {
|
||||
+ final List<BlockPos> explodedPositions;
|
||||
+ if (this.wrapped < FOUND_ALL_BLOCKS) {
|
||||
+ explodedPositions = this.calculateExplodedPositions();
|
||||
+ } else {
|
||||
+ explodedPositions = List.of();
|
||||
+ }
|
||||
+
|
||||
+ if (this.wrapped < ALL_DIRECTIONS) {
|
||||
+ Vec3 momentum = this.cause.entityState().momentum();
|
||||
+ for (Direction.Axis axis : Direction.Axis.VALUES) {
|
||||
+ double current = momentum.get(axis);
|
||||
+ double previous = previousMomentum.get(axis);
|
||||
+ if (current == previous || current * previous < 0) {
|
||||
+ this.wrapped |= 1 << axis.ordinal();
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ this.bounds = this.bounds.expand(this.center);
|
||||
+ this.explosions.add(this.center);
|
||||
+
|
||||
+ if (lastCycle || this.requiresImpactEntities(explodedPositions, this.center)) {
|
||||
+ this.locateAndImpactEntitiesInBounds();
|
||||
+ this.bounds = new AABB(this.center, this.center);
|
||||
+ this.explosions.clear();
|
||||
+ }
|
||||
+
|
||||
+ return explodedPositions;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected void postExplosion(List<BlockPos> foundBlocks, boolean destroyedBlocks) {
|
||||
+ super.postExplosion(foundBlocks, destroyedBlocks);
|
||||
+ // Update wrapped, this is for tracking swinging and if blocks are found
|
||||
+ if (this.wrapped >= ALL_DIRECTIONS) {
|
||||
+ if (!destroyedBlocks && this.level().sakuraConfig().cannons.explosion.avoidRedundantBlockSearches) {
|
||||
+ this.wrapped++;
|
||||
+ } else {
|
||||
+ this.wrapped = ALL_DIRECTIONS;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private Vector getCauseOrigin() {
|
||||
+ Vector origin = this.cause.getOriginVector();
|
||||
+ return origin == null ? CraftVector.toBukkit(this.center) : origin;
|
||||
+ }
|
||||
+
|
||||
+ private EntityState nextSourceVelocity() {
|
||||
+ Vector origin = this.getCauseOrigin(); // valid position to use while creating a temporary entity
|
||||
+ PrimedTnt tnt = new PrimedTnt(this.level(), origin.getX(), origin.getY(), origin.getZ(), null);
|
||||
+ this.cause.entityState().apply(tnt);
|
||||
+ this.impactCannonEntity(tnt, this.center, 1, this.radius() * 2.0f);
|
||||
+ return EntityState.of(tnt);
|
||||
+ }
|
||||
+
|
||||
+ private void updateExplosionPosition(EntityState entityState, boolean destroyedBlocks) {
|
||||
+ // Before setting entity state, otherwise we might cause issues.
|
||||
+ final boolean hasMoved;
|
||||
+ if (this.moved) {
|
||||
+ hasMoved = true;
|
||||
+ } else if (this.center.equals(this.cause.position())) {
|
||||
+ hasMoved = false;
|
||||
+ } else {
|
||||
+ double newMomentum = entityState.momentum().lengthSqr();
|
||||
+ double oldMomentum = this.cause.entityState().momentum().lengthSqr();
|
||||
+ hasMoved = oldMomentum <= Math.pow(this.radius() * 2.0 + 1.0, 2.0) || newMomentum <= oldMomentum;
|
||||
+ }
|
||||
+
|
||||
+ // Keep track of entity state
|
||||
+ entityState.apply(this.cause);
|
||||
+ this.cause.storeEntityState();
|
||||
+
|
||||
+ // Ticking is always required after destroying a block.
|
||||
+ if (destroyedBlocks || hasMoved) {
|
||||
+ this.cause.setFuse(100);
|
||||
+ this.cause.tick();
|
||||
+ this.moved |= !this.center.equals(this.originalPosition);
|
||||
+ this.recalculateExplosionPosition();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private void mergeEntitiesBeforeExplosion() {
|
||||
+ IteratorSafeOrderedReferenceSet<Entity> entities = this.level().entityTickList.entities;
|
||||
+ int index = entities.indexOf(this.cause);
|
||||
+
|
||||
+ entities.createRawIterator();
|
||||
+ // iterate over the entityTickList to find entities that are exploding in the same position.
|
||||
+ while ((index = entities.advanceRawIterator(index)) != -1) {
|
||||
+ Entity foundEntity = entities.rawGet(index);
|
||||
+ if (!(foundEntity instanceof MergeableEntity mergeEntity) || foundEntity.isRemoved() || !foundEntity.compareState(this.cause) || !mergeEntity.isSafeToMergeInto(this.cause, true))
|
||||
+ break;
|
||||
+ this.level().mergeHandler.mergeEntity(mergeEntity, this.cause);
|
||||
+ }
|
||||
+ entities.finishRawIterator();
|
||||
+ }
|
||||
+
|
||||
+ private void locateAndImpactEntitiesInBounds() {
|
||||
+ double radius = this.radius() * 2.0f;
|
||||
+ AABB bb = this.bounds;
|
||||
+
|
||||
+ Vec3 center = bb.getCenter();
|
||||
+ double change = Math.max(bb.getXsize(), Math.max(bb.getYsize(), bb.getZsize()));
|
||||
+ double maxDistanceSqr = Math.pow(radius + change, 2.0);
|
||||
+ boolean moved = (change != 0.0);
|
||||
+
|
||||
+ this.forEachEntitySliceInBounds(bb.inflate(radius), entities -> {
|
||||
+ if (moved) {
|
||||
+ this.impactEntitiesSwinging(entities, center, radius, maxDistanceSqr);
|
||||
+ } else {
|
||||
+ this.impactEntitiesFromPosition(entities, this.explosions.getFirst(), this.explosions.size(), radius);
|
||||
+ }
|
||||
+ });
|
||||
+ }
|
||||
+
|
||||
+ private void impactEntitiesSwinging(Entity[] entities, Vec3 center, double radius, double maxDistanceSqr) {
|
||||
+ for (int i = 0; i < entities.length; ++i) {
|
||||
+ Entity entity = entities[i];
|
||||
+ if (entity == null) break;
|
||||
+
|
||||
+ if (entity != this.source && !entity.ignoreExplosion(this) && entity.distanceToSqr(center.x, center.y, center.z) <= maxDistanceSqr) {
|
||||
+ this.impactEntity(entity, radius);
|
||||
+ }
|
||||
+
|
||||
+ if (entities[i] != entity) {
|
||||
+ i--;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private void impactEntity(Entity entity, double radius) {
|
||||
+ //noinspection ForLoopReplaceableByForEach
|
||||
+ for (int i = 0; i < this.explosions.size(); i++) {
|
||||
+ this.impactEntity(entity, this.explosions.get(i), 1, radius);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 1e940c5b9ce60dd1dd7ec03e83766e26d1112d73..1973da88ac7c3a36cc2db48aeb7d4eab788be500 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -1913,7 +1913,16 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
|
||||
Explosion.BlockInteraction explosion_effect1 = explosion_effect;
|
||||
Vec3 vec3d = new Vec3(d0, d1, d2);
|
||||
- ServerExplosion serverexplosion = new ServerExplosion(this, entity, damagesource, explosiondamagecalculator, vec3d, f, flag, explosion_effect1);
|
||||
+ // Sakura start - specialised explosions
|
||||
+ final ServerExplosion serverexplosion;
|
||||
+ if (entity instanceof net.minecraft.world.entity.item.PrimedTnt tnt) {
|
||||
+ serverexplosion = new me.samsuik.sakura.explosion.special.TntExplosion(this, tnt, damagesource, explosiondamagecalculator, vec3d, f, flag, explosion_effect1, self -> {
|
||||
+ this.notifyPlayersOfExplosion(self, self.center(), particleparam, particleparam1, holder);
|
||||
+ });
|
||||
+ } else {
|
||||
+ serverexplosion = new ServerExplosion(this, entity, damagesource, explosiondamagecalculator, vec3d, f, flag, explosion_effect1);
|
||||
+ }
|
||||
+ // Sakura end - specialised explosions
|
||||
if (configurator != null) configurator.accept(serverexplosion);// Paper - Allow explosions to damage source
|
||||
|
||||
serverexplosion.explode();
|
||||
@@ -1922,6 +1931,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
return serverexplosion;
|
||||
}
|
||||
// CraftBukkit end
|
||||
+ // Sakura start - specialised explosions
|
||||
+ this.notifyPlayersOfExplosion(serverexplosion, vec3d, particleparam, particleparam1, holder);
|
||||
+ return serverexplosion;
|
||||
+ }
|
||||
+
|
||||
+ private void notifyPlayersOfExplosion(ServerExplosion serverexplosion, Vec3 vec3d, ParticleOptions particleparam, ParticleOptions particleparam1, Holder<SoundEvent> holder) {
|
||||
+ // Sakura end - specialised explosions
|
||||
ParticleOptions particleparam2 = serverexplosion.isSmall() ? particleparam : particleparam1;
|
||||
Iterator iterator = this.players.iterator();
|
||||
|
||||
@@ -1946,7 +1962,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
}
|
||||
}
|
||||
|
||||
- return serverexplosion; // CraftBukkit
|
||||
+ // Sakura - specialised explosions; return moved up into explode
|
||||
}
|
||||
|
||||
private Explosion.BlockInteraction getDestroyType(GameRules.Key<GameRules.BooleanValue> decayRule) {
|
||||
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 f7d8e2ba0ee9b8dd27f20a3e75992b107d07fbf0..187cb36e139ce66497e4e20ce75c0a5c4309632e 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||
@@ -78,20 +78,7 @@ public class PrimedTnt extends Entity implements TraceableEntity, me.samsuik.sak
|
||||
|
||||
@Override
|
||||
public final void respawnEntity(int count) {
|
||||
- PrimedTnt tnt = new PrimedTnt(EntityType.TNT, this.level());
|
||||
- tnt.updateBukkitHandle(this); // update handle for plugins
|
||||
- while (count-- > 1) {
|
||||
- this.setFuse(100); // Prevent unwanted explosions while ticking
|
||||
-
|
||||
- // Cause an explosion to affect this entity
|
||||
- tnt.setPos(this.position());
|
||||
- tnt.setDeltaMovement(this.getDeltaMovement());
|
||||
- this.entityState().apply(this);
|
||||
- tnt.explode();
|
||||
- this.storeEntityState();
|
||||
-
|
||||
- this.tick();
|
||||
- }
|
||||
+ this.mergeData.setCount(count); // Sakura - specialised explosions
|
||||
}
|
||||
// Sakura end - merge cannon entities
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/ServerExplosion.java b/src/main/java/net/minecraft/world/level/ServerExplosion.java
|
||||
index 190eca0e25a8761f88d15a5eac02d9a67b5635de..74abe5fe92b3f1fe0139f4879fe5efa10d0623e0 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/ServerExplosion.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/ServerExplosion.java
|
||||
@@ -52,9 +52,9 @@ public class ServerExplosion implements Explosion {
|
||||
private final boolean fire;
|
||||
private final Explosion.BlockInteraction blockInteraction;
|
||||
private final ServerLevel level;
|
||||
- private final Vec3 center;
|
||||
+ protected Vec3 center; // Sakura - specialised explosions; private final -> protected
|
||||
@Nullable
|
||||
- private final Entity source;
|
||||
+ protected final Entity source; // Sakura - specialised explosions; private -> protected
|
||||
private final float radius;
|
||||
private final DamageSource damageSource;
|
||||
private final ExplosionDamageCalculator damageCalculator;
|
||||
@@ -103,13 +103,13 @@ public class ServerExplosion implements Explosion {
|
||||
// resistance = (res + 0.3F) * 0.3F;
|
||||
// so for resistance = 0, we need res = -0.3F
|
||||
private static final Float ZERO_RESISTANCE = Float.valueOf(-0.3f);
|
||||
- private it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache> blockCache = null;
|
||||
+ protected it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache> blockCache = null; // Sakura - specialised explosions; private -> protected
|
||||
private long[] chunkPosCache = null;
|
||||
private net.minecraft.world.level.chunk.LevelChunk[] chunkCache = null;
|
||||
- private ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache[] directMappedBlockCache;
|
||||
+ protected ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache[] directMappedBlockCache; // Sakura - specialised explosions; private -> protected
|
||||
private BlockPos.MutableBlockPos mutablePos;
|
||||
|
||||
- private ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache getOrCacheExplosionBlock(final int x, final int y, final int z,
|
||||
+ protected final ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache getOrCacheExplosionBlock(final int x, final int y, final int z, // Sakura - specialised explosions; private -> protected
|
||||
final long key, final boolean calculateResistance) {
|
||||
ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache ret = this.blockCache.get(key);
|
||||
if (ret != null) {
|
||||
@@ -361,6 +361,38 @@ public class ServerExplosion implements Explosion {
|
||||
return true;
|
||||
}
|
||||
// Sakura end - optimise explosion protected regions
|
||||
+ // Sakura start - specialised explosions
|
||||
+ protected final void createBlockCache() {
|
||||
+ // Paper start - collision optimisations
|
||||
+ this.blockCache = new it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<>();
|
||||
+ this.chunkPosCache = new long[CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH];
|
||||
+ java.util.Arrays.fill(this.chunkPosCache, ChunkPos.INVALID_CHUNK_POS);
|
||||
+ this.chunkCache = new net.minecraft.world.level.chunk.LevelChunk[CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH];
|
||||
+ this.directMappedBlockCache = new ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache[BLOCK_EXPLOSION_CACHE_WIDTH * BLOCK_EXPLOSION_CACHE_WIDTH * BLOCK_EXPLOSION_CACHE_WIDTH];
|
||||
+ this.mutablePos = new BlockPos.MutableBlockPos();
|
||||
+ // Paper end - collision optimisations
|
||||
+ }
|
||||
+
|
||||
+ protected final void markBlocksInCacheAsExplodable(List<BlockPos> explodedPositions) {
|
||||
+ for (BlockPos blow : explodedPositions) {
|
||||
+ ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache cache = this.blockCache.get(blow.asLong());
|
||||
+ // May be null if the blockCache is cleared then retrieved from the recent block cache
|
||||
+ if (cache != null) {
|
||||
+ cache.shouldExplode = null;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ protected final void clearBlockCache() {
|
||||
+ // Paper start - collision optimisations
|
||||
+ this.blockCache = null;
|
||||
+ this.chunkPosCache = null;
|
||||
+ this.chunkCache = null;
|
||||
+ this.directMappedBlockCache = null;
|
||||
+ this.mutablePos = null;
|
||||
+ // Paper end - collision optimisations
|
||||
+ }
|
||||
+ // Sakura end - specialised explosions
|
||||
|
||||
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;
|
||||
@@ -432,7 +464,7 @@ public class ServerExplosion implements Explosion {
|
||||
return this.center;
|
||||
}
|
||||
|
||||
- private List<BlockPos> calculateExplodedPositions() {
|
||||
+ protected final List<BlockPos> calculateExplodedPositions() { // Sakura - specialised explosions; private -> protected
|
||||
// Paper start - collision optimisations
|
||||
final ObjectArrayList<BlockPos> ret = new ObjectArrayList<>();
|
||||
|
||||
@@ -670,7 +702,10 @@ public class ServerExplosion implements Explosion {
|
||||
Player entityhuman = (Player) entity;
|
||||
|
||||
if (!entityhuman.isSpectator() && (!entityhuman.isCreative() || !entityhuman.getAbilities().flying) && !level.paperConfig().environment.disableExplosionKnockback) { // Paper - Option to disable explosion knockback
|
||||
- this.hitPlayers.put(entityhuman, vec3d);
|
||||
+ // Sakura start - specialised explosions; tally player velocity
|
||||
+ final Vec3 explosionImpact = vec3d;
|
||||
+ this.hitPlayers.compute(entityhuman, (p, v) -> v != null ? v.add(explosionImpact) : explosionImpact);
|
||||
+ // Sakura end - specialised explosions; tally player velocity
|
||||
}
|
||||
}
|
||||
|
||||
@@ -682,7 +717,7 @@ public class ServerExplosion implements Explosion {
|
||||
|
||||
}
|
||||
|
||||
- private void interactWithBlocks(List<BlockPos> positions) {
|
||||
+ protected final void interactWithBlocks(List<BlockPos> positions) { // Sakura - specialised explosions; private -> protected
|
||||
List<ServerExplosion.StackCollector> list1 = new ArrayList();
|
||||
|
||||
Util.shuffle(positions, this.level.random);
|
||||
@@ -787,14 +822,7 @@ public class ServerExplosion implements Explosion {
|
||||
return;
|
||||
}
|
||||
// CraftBukkit end
|
||||
- // Paper start - collision optimisations
|
||||
- this.blockCache = new it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<>();
|
||||
- this.chunkPosCache = new long[CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH];
|
||||
- java.util.Arrays.fill(this.chunkPosCache, ChunkPos.INVALID_CHUNK_POS);
|
||||
- this.chunkCache = new net.minecraft.world.level.chunk.LevelChunk[CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH];
|
||||
- this.directMappedBlockCache = new ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache[BLOCK_EXPLOSION_CACHE_WIDTH * BLOCK_EXPLOSION_CACHE_WIDTH * BLOCK_EXPLOSION_CACHE_WIDTH];
|
||||
- this.mutablePos = new BlockPos.MutableBlockPos();
|
||||
- // Paper end - collision optimisations
|
||||
+ this.createBlockCache(); // Sakura - specialised explosions
|
||||
this.level.gameEvent(this.source, (Holder) GameEvent.EXPLODE, this.center);
|
||||
List<BlockPos> list = this.calculateExplodedPositions();
|
||||
|
||||
@@ -810,13 +838,7 @@ public class ServerExplosion implements Explosion {
|
||||
if (this.fire) {
|
||||
this.createFire(list);
|
||||
}
|
||||
- // Paper start - collision optimisations
|
||||
- this.blockCache = null;
|
||||
- this.chunkPosCache = null;
|
||||
- this.chunkCache = null;
|
||||
- this.directMappedBlockCache = null;
|
||||
- this.mutablePos = null;
|
||||
- // Paper end - collision optimisations
|
||||
+ this.clearBlockCache(); // Sakura - specialised explosions
|
||||
|
||||
}
|
||||
|
||||
@@ -837,7 +859,7 @@ public class ServerExplosion implements Explosion {
|
||||
|
||||
}
|
||||
|
||||
- private boolean interactsWithBlocks() {
|
||||
+ protected final boolean interactsWithBlocks() { // Sakura - specialised explosions; private -> protected
|
||||
return this.blockInteraction != Explosion.BlockInteraction.KEEP;
|
||||
}
|
||||
|
||||
@@ -908,7 +930,7 @@ public class ServerExplosion implements Explosion {
|
||||
}
|
||||
|
||||
// Paper start - Optimize explosions
|
||||
- private float getBlockDensity(Vec3 vec3d, Entity entity) {
|
||||
+ protected final float getBlockDensity(Vec3 vec3d, Entity entity) { // Sakura - specialised explosions; private -> protected
|
||||
// Sakura start - replace density cache
|
||||
float blockDensity = this.level.densityCache.getDensity(vec3d, entity);
|
||||
if (blockDensity == me.samsuik.sakura.explosion.density.BlockDensityCache.UNKNOWN_DENSITY) {
|
||||
@@ -0,0 +1,220 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
|
||||
Date: Fri, 13 Oct 2023 14:36:19 +0100
|
||||
Subject: [PATCH] Optimise cannon entity movement
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index fd1d02604a1e46545c7f2c8ad89968279e2fe1bf..953aa1b3d292dd8e8ed29926c269e6d6e79a83c0 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -1222,6 +1222,75 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
return this.moveStartZ;
|
||||
}
|
||||
// Paper end - detailed watchdog information
|
||||
+ // Sakura start - optimise cannon entity movement; stripped back movement method
|
||||
+ public final void moveStripped(MoverType movementType, Vec3 movement) {
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread("Cannot move an entity off-main");
|
||||
+ if (this.noPhysics) {
|
||||
+ this.setPos(this.getX() + movement.x, this.getY() + movement.y, this.getZ() + movement.z);
|
||||
+ } else {
|
||||
+ if (movementType == MoverType.PISTON) {
|
||||
+ movement = this.limitPistonMovement(movement);
|
||||
+ if (movement.equals(Vec3.ZERO)) {
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ ProfilerFiller gameprofilerfiller = Profiler.get();
|
||||
+ gameprofilerfiller.push("move");
|
||||
+ if (this.stuckSpeedMultiplier.lengthSqr() > 1.0E-7D) {
|
||||
+ movement = movement.multiply(this.stuckSpeedMultiplier);
|
||||
+ this.stuckSpeedMultiplier = Vec3.ZERO;
|
||||
+ this.setDeltaMovement(Vec3.ZERO);
|
||||
+ }
|
||||
+
|
||||
+ Vec3 vec3d1 = this.sakura_collide(movement);
|
||||
+ double d0 = vec3d1.lengthSqr();
|
||||
+
|
||||
+ if (d0 > 1.0E-7D || movement.lengthSqr() - d0 < 1.0E-7D) {
|
||||
+ if (this.fallDistance != 0.0F && d0 >= 1.0D && !this.isFallingBlock) {
|
||||
+ BlockHitResult clipResult = this.level().clip(new ClipContext(this.position(), this.position().add(vec3d1), ClipContext.Block.FALLDAMAGE_RESETTING, ClipContext.Fluid.WATER, this));
|
||||
+ if (clipResult.getType() != HitResult.Type.MISS) {
|
||||
+ this.resetFallDistance();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ this.setPos(this.getX() + vec3d1.x, this.getY() + vec3d1.y, this.getZ() + vec3d1.z);
|
||||
+ }
|
||||
+
|
||||
+ gameprofilerfiller.pop();
|
||||
+ gameprofilerfiller.push("rest");
|
||||
+ boolean movedX = !Mth.equal(movement.x, vec3d1.x);
|
||||
+ boolean movedZ = !Mth.equal(movement.z, vec3d1.z);
|
||||
+
|
||||
+ this.horizontalCollision = movedX || movedZ;
|
||||
+ this.verticalCollision = movement.y != vec3d1.y;
|
||||
+ this.verticalCollisionBelow = this.verticalCollision && movement.y < 0.0D;
|
||||
+
|
||||
+ this.setOnGroundWithMovement(this.verticalCollisionBelow, this.horizontalCollision, vec3d1);
|
||||
+ BlockPos blockPosBelow = this.getOnPosLegacy();
|
||||
+ BlockState blockstate = this.level().getBlockState(blockPosBelow);
|
||||
+
|
||||
+ this.checkFallDamage(vec3d1.y, this.onGround(), blockstate, blockPosBelow);
|
||||
+ if (this.isRemoved()) {
|
||||
+ gameprofilerfiller.pop();
|
||||
+ } else {
|
||||
+ if (this.horizontalCollision) {
|
||||
+ Vec3 vec3d2 = this.getDeltaMovement();
|
||||
+ this.setDeltaMovement(movedX ? 0.0D : vec3d2.x, vec3d2.y, movedZ ? 0.0D : vec3d2.z);
|
||||
+ }
|
||||
+
|
||||
+ Block block = blockstate.getBlock();
|
||||
+ if (movement.y != vec3d1.y) { // remove y momentum
|
||||
+ block.updateEntityMovementAfterFallOn(this.level(), this);
|
||||
+ }
|
||||
+
|
||||
+ float f = this.getBlockSpeedFactor();
|
||||
+ this.setDeltaMovement(this.getDeltaMovement().multiply((double) f, 1.0D, (double) f));
|
||||
+ gameprofilerfiller.pop();
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ // Sakura end - optimise cannon entity movement; stripped back movement method
|
||||
|
||||
public void move(MoverType type, Vec3 movement) {
|
||||
final Vec3 originalMovement = movement; // Paper - Expose pre-collision velocity
|
||||
@@ -1588,6 +1657,107 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
return offsetFactor;
|
||||
}
|
||||
|
||||
+ // Sakura start - optimise cannon entity movement
|
||||
+ private Vec3 sakura_collide(Vec3 movement) {
|
||||
+ if (movement.x == 0.0 && movement.y == 0.0 && movement.z == 0.0) {
|
||||
+ return movement;
|
||||
+ }
|
||||
+
|
||||
+ List<VoxelShape> potentialCollisionsVoxel = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(0);
|
||||
+ List<AABB> potentialCollisionsBB = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(4);
|
||||
+ AABB currBoundingBox = this.getBoundingBox();
|
||||
+
|
||||
+ if (movement.lengthSqr() >= 12.0) { // axis scan on large movement
|
||||
+ return this.collideAxisScan(movement, currBoundingBox, potentialCollisionsVoxel, potentialCollisionsBB);
|
||||
+ } else {
|
||||
+ return this.collideCube(movement, currBoundingBox, potentialCollisionsVoxel, potentialCollisionsBB);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private Vec3 collideCube(Vec3 movement, AABB currBoundingBox, List<VoxelShape> voxelList, List<AABB> bbList) {
|
||||
+ final AABB bb;
|
||||
+ if (movement.x() == 0.0 && movement.z() == 0.0) {
|
||||
+ if (movement.y > 0.0) {
|
||||
+ bb = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.cutUpwards(currBoundingBox, movement.y);
|
||||
+ } else {
|
||||
+ bb = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.cutDownwards(currBoundingBox, movement.y);
|
||||
+ }
|
||||
+ } else {
|
||||
+ bb = currBoundingBox.expandTowards(movement.x, movement.y, movement.z);
|
||||
+ }
|
||||
+ this.collectCollisions(bb, voxelList, bbList);
|
||||
+ return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.performCollisions(movement, currBoundingBox, voxelList, bbList);
|
||||
+ }
|
||||
+
|
||||
+ private Vec3 collideAxisScan(Vec3 movement, AABB currBoundingBox, List<VoxelShape> voxelList, List<AABB> bbList) {
|
||||
+ double x = movement.x;
|
||||
+ double y = movement.y;
|
||||
+ double z = movement.z;
|
||||
+
|
||||
+ boolean xSmaller = Math.abs(x) < Math.abs(z);
|
||||
+
|
||||
+ if (y != 0.0) {
|
||||
+ y = this.scanY(currBoundingBox, y, voxelList, bbList);
|
||||
+ if (y != 0.0) {
|
||||
+ currBoundingBox = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.offsetY(currBoundingBox, y);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (xSmaller && z != 0.0) {
|
||||
+ z = this.scanZ(currBoundingBox, z, voxelList, bbList);
|
||||
+ if (z != 0.0) {
|
||||
+ currBoundingBox = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.offsetZ(currBoundingBox, z);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (x != 0.0) {
|
||||
+ x = this.scanX(currBoundingBox, x, voxelList, bbList);
|
||||
+ if (x != 0.0) {
|
||||
+ currBoundingBox = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.offsetX(currBoundingBox, x);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (!xSmaller && z != 0.0) {
|
||||
+ z = this.scanZ(currBoundingBox, z, voxelList, bbList);
|
||||
+ }
|
||||
+
|
||||
+ return new Vec3(x, y, z);
|
||||
+ }
|
||||
+
|
||||
+ private void collectCollisions(AABB collisionBox, List<VoxelShape> voxelList, List<AABB> bbList) {
|
||||
+ // Copied from the collide method below
|
||||
+ ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.getCollisionsForBlocksOrWorldBorder(
|
||||
+ this.level, this, collisionBox, voxelList, bbList,
|
||||
+ ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_FLAG_CHECK_BORDER | this.getExtraCollisionFlags(), null // Sakura - load chunks on movement
|
||||
+ );
|
||||
+
|
||||
+ ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.getEntityHardCollisions(
|
||||
+ this.level, this, collisionBox, bbList, 0, null
|
||||
+ );
|
||||
+ }
|
||||
+
|
||||
+ private double scanX(AABB currBoundingBox, double x, List<VoxelShape> voxelList, List<AABB> bbList) {
|
||||
+ AABB scanBox = currBoundingBox.expandTowards(x, 0.0, 0.0);
|
||||
+ this.collectCollisions(scanBox, voxelList, bbList);
|
||||
+ x = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.performAABBCollisionsX(currBoundingBox, x, bbList);
|
||||
+ return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.performVoxelCollisionsX(currBoundingBox, x, voxelList);
|
||||
+ }
|
||||
+
|
||||
+ private double scanY(AABB currBoundingBox, double y, List<VoxelShape> voxelList, List<AABB> bbList) {
|
||||
+ AABB scanBox = currBoundingBox.expandTowards(0.0, y, 0.0);
|
||||
+ this.collectCollisions(scanBox, voxelList, bbList);
|
||||
+ y = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.performAABBCollisionsY(currBoundingBox, y, bbList);
|
||||
+ return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.performVoxelCollisionsY(currBoundingBox, y, voxelList);
|
||||
+ }
|
||||
+
|
||||
+ private double scanZ(AABB currBoundingBox, double z, List<VoxelShape> voxelList, List<AABB> bbList) {
|
||||
+ AABB scanBox = currBoundingBox.expandTowards(0.0, 0.0, z);
|
||||
+ this.collectCollisions(scanBox, voxelList, bbList);
|
||||
+ z = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.performAABBCollisionsZ(currBoundingBox, z, bbList);
|
||||
+ return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.performVoxelCollisionsZ(currBoundingBox, z, voxelList);
|
||||
+ }
|
||||
+ // Sakura end - optimise cannon entity movement
|
||||
+
|
||||
private Vec3 collide(Vec3 movement) {
|
||||
// Paper start - optimise collisions
|
||||
final boolean xZero = movement.x == 0.0;
|
||||
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 7dc5e5d91bb91c86ddca52a462903e8452396090..a2683e26fc252f0ce933e3ea71fde9c84bcee0fd 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||
@@ -213,7 +213,7 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti
|
||||
|
||||
++this.time;
|
||||
this.applyGravity();
|
||||
- this.move(MoverType.SELF, this.getDeltaMovement());
|
||||
+ this.moveStripped(MoverType.SELF, this.getDeltaMovement()); // Sakura - optimise cannon entity movement
|
||||
this.applyEffectsFromBlocks();
|
||||
// Paper start - Configurable falling blocks height nerf
|
||||
if (this.level().paperConfig().fixes.fallingBlockHeightNerf.test(v -> this.getY() > v)) {
|
||||
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 187cb36e139ce66497e4e20ce75c0a5c4309632e..d60d25c0d731738c647fee6e618d3e4942949dc7 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||
@@ -130,7 +130,7 @@ public class PrimedTnt extends Entity implements TraceableEntity, me.samsuik.sak
|
||||
if (this.level().spigotConfig.maxTntTicksPerTick > 0 && ++this.level().spigotConfig.currentPrimedTnt > this.level().spigotConfig.maxTntTicksPerTick) { return; } // Spigot
|
||||
this.handlePortal();
|
||||
this.applyGravity();
|
||||
- this.move(MoverType.SELF, this.getDeltaMovement());
|
||||
+ this.moveStripped(MoverType.SELF, this.getDeltaMovement()); // Sakura - optimise cannon entity movement
|
||||
this.applyEffectsFromBlocks();
|
||||
// Paper start - Configurable TNT height nerf
|
||||
if (this.level().paperConfig().fixes.tntEntityHeightNerf.test(v -> this.getY() > v)) {
|
||||
117
migrate/server/feature/0025-Add-maxSearch-to-getEntities.patch
Normal file
117
migrate/server/feature/0025-Add-maxSearch-to-getEntities.patch
Normal file
@@ -0,0 +1,117 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samsuik <kfian294ma4@gmail.com>
|
||||
Date: Thu, 27 Jun 2024 17:02:32 +0100
|
||||
Subject: [PATCH] Add maxSearch to getEntities
|
||||
|
||||
|
||||
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 39148fe540d616cdd4d63c4d1a02b422cab0f6eb..50a551d5bcac9b2b6644d7b43e625185090657a6 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
|
||||
@@ -314,7 +314,14 @@ public final class ChunkEntitySlices {
|
||||
|
||||
public boolean getEntities(final Entity except, final AABB box, final List<Entity> into, final Predicate<? super Entity> predicate,
|
||||
final int maxCount) {
|
||||
- return this.allEntities.getEntitiesLimited(except, box, into, predicate, maxCount);
|
||||
+ // Sakura start - add maxSearch to getEntities
|
||||
+ return this.getEntities(except, box, into, predicate, maxCount, Integer.MAX_VALUE);
|
||||
+ }
|
||||
+
|
||||
+ public boolean getEntities(final Entity except, final AABB box, final List<Entity> into, final Predicate<? super Entity> predicate,
|
||||
+ final int maxCount, final int maxSearch) {
|
||||
+ return this.allEntities.getEntitiesLimited(except, box, into, predicate, maxCount, maxSearch);
|
||||
+ // Sakura end - add maxSearch to getEntities
|
||||
}
|
||||
|
||||
public <T extends Entity> void getEntities(final EntityType<?> type, final AABB box, final List<? super T> into,
|
||||
@@ -570,6 +577,13 @@ public final class ChunkEntitySlices {
|
||||
|
||||
public boolean getEntitiesLimited(final Entity except, final AABB box, final List<Entity> into, final Predicate<? super Entity> predicate,
|
||||
final int maxCount) {
|
||||
+ // Sakura start - add maxSearch to getEntities
|
||||
+ return this.getEntitiesLimited(except, box, into, predicate, maxCount, Integer.MAX_VALUE);
|
||||
+ }
|
||||
+
|
||||
+ public boolean getEntitiesLimited(final Entity except, final AABB box, final List<Entity> into, final Predicate<? super Entity> predicate,
|
||||
+ final int maxCount, final int maxSearch) {
|
||||
+ // Sakura end - add maxSearch to getEntities
|
||||
if (this.count == 0) {
|
||||
return false;
|
||||
}
|
||||
@@ -591,8 +605,14 @@ public final class ChunkEntitySlices {
|
||||
|
||||
final Entity[] storage = list.storage;
|
||||
|
||||
- for (int i = 0, len = Math.min(storage.length, list.size()); i < len; ++i) {
|
||||
- final Entity entity = storage[i];
|
||||
+ // Sakura start - add maxSearch to getEntities
|
||||
+ final int len = Math.min(storage.length, list.size());
|
||||
+ final int offset = this.slices.world.random.nextInt(len);
|
||||
+ for (int i = 0; i < len; ++i) {
|
||||
+ final int pos = (i + offset) % len;
|
||||
+ final Entity entity = storage[pos];
|
||||
+ if (i > maxSearch) break;
|
||||
+ // Sakura end - add maxSearch to getEntities
|
||||
|
||||
if (entity == null || entity == except || !entity.getBoundingBox().intersects(box)) {
|
||||
continue;
|
||||
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java
|
||||
index 7554c109c35397bc1a43dd80e87764fd78645bbf..d60f30f7afb15cc90c1bd4b816136d00b23a53e4 100644
|
||||
--- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java
|
||||
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java
|
||||
@@ -722,6 +722,13 @@ public abstract class EntityLookup implements LevelEntityGetter<Entity> {
|
||||
|
||||
public void getEntities(final Entity except, final AABB box, final List<Entity> into, final Predicate<? super Entity> predicate,
|
||||
final int maxCount) {
|
||||
+ // Sakura start - add maxSearch to getEntities
|
||||
+ this.getEntities(except, box, into, predicate, maxCount, Integer.MAX_VALUE);
|
||||
+ }
|
||||
+
|
||||
+ public void getEntities(final Entity except, final AABB box, final List<Entity> into, final Predicate<? super Entity> predicate,
|
||||
+ final int maxCount, final int maxSearch) {
|
||||
+ // Sakura end - add maxSearch to getEntities
|
||||
final int minChunkX = (Mth.floor(box.minX) - 2) >> 4;
|
||||
final int minChunkZ = (Mth.floor(box.minZ) - 2) >> 4;
|
||||
final int maxChunkX = (Mth.floor(box.maxX) + 2) >> 4;
|
||||
@@ -753,7 +760,7 @@ public abstract class EntityLookup implements LevelEntityGetter<Entity> {
|
||||
continue;
|
||||
}
|
||||
|
||||
- if (chunk.getEntities(except, box, into, predicate, maxCount)) {
|
||||
+ if (chunk.getEntities(except, box, into, predicate, maxCount, maxSearch)) { // Sakura - add maxSearch to getEntities
|
||||
return;
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index addab159f6fb73fe063f8a057c281d0594a99122..0301e304bb67d3a52de551442e425b83152fbabf 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -1693,10 +1693,18 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
this.getEntities(filter, box, predicate, result, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
- // Paper start - rewrite chunk system
|
||||
+ // Sakura start - add maxSearch to getEntities
|
||||
public <T extends Entity> void getEntities(final EntityTypeTest<Entity, T> entityTypeTest,
|
||||
final AABB boundingBox, final Predicate<? super T> predicate,
|
||||
final List<? super T> into, final int maxCount) {
|
||||
+ this.getEntities(entityTypeTest, boundingBox, predicate, into, maxCount, Integer.MAX_VALUE);
|
||||
+ }
|
||||
+
|
||||
+ // Paper start - rewrite chunk system
|
||||
+ public <T extends Entity> void getEntities(final EntityTypeTest<Entity, T> entityTypeTest,
|
||||
+ final AABB boundingBox, final Predicate<? super T> predicate,
|
||||
+ final List<? super T> into, final int maxCount, final int maxSearch) {
|
||||
+ // Sakura end - add maxSearch to getEntities
|
||||
Profiler.get().incrementCounter("getEntities");
|
||||
|
||||
if (entityTypeTest instanceof net.minecraft.world.entity.EntityType<T> byType) {
|
||||
@@ -1713,7 +1721,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
|
||||
if (entityTypeTest == null) {
|
||||
if (maxCount != Integer.MAX_VALUE) {
|
||||
- ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel)this).moonrise$getEntityLookup().getEntities((Entity)null, boundingBox, (List)into, (Predicate)predicate, maxCount);
|
||||
+ ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel)this).moonrise$getEntityLookup().getEntities((Entity)null, boundingBox, (List)into, (Predicate)predicate, maxCount, maxSearch); // Sakura - add maxSearch to getEntities
|
||||
ca.spottedleaf.moonrise.common.PlatformHooks.get().addToGetEntities((Level)(Object)this, entityTypeTest, boundingBox, predicate, into, maxCount);
|
||||
return;
|
||||
} else {
|
||||
@@ -0,0 +1,24 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samsuik <kfian294ma4@gmail.com>
|
||||
Date: Thu, 23 Sep 2021 18:50:13 +0100
|
||||
Subject: [PATCH] Optimise LivingEntity#pushEntities
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index 96b4fbe4a4655777ff10b32e3257e2fac2aba12a..01179c4b01aa4898d08b392bd682587e3858b822 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -3800,7 +3800,12 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
return;
|
||||
}
|
||||
// Paper end - don't run getEntities if we're not going to use its result
|
||||
- List list = this.level().getEntities((Entity) this, this.getBoundingBox(), EntitySelector.pushable(this, this.level().paperConfig().collisions.fixClimbingBypassingCrammingRule)); // Paper - Climbing should not bypass cramming gamerule
|
||||
+ // Sakura start - use maxEntityCollision limit for entity retrieval
|
||||
+ int limit = Math.max(i, this.level().paperConfig().collisions.maxEntityCollisions);
|
||||
+ int search = limit * limit;
|
||||
+ List<Entity> list = new ArrayList<>();
|
||||
+ this.level().getEntities(null, this.getBoundingBox(), EntitySelector.pushable(this, this.level().paperConfig().collisions.fixClimbingBypassingCrammingRule), list, limit, search); // Paper - Climbing should not bypass cramming gamerule
|
||||
+ // Sakura end - use maxEntityCollision limit for entity retrieval
|
||||
|
||||
if (!list.isEmpty()) {
|
||||
// Paper - don't run getEntities if we're not going to use its result; moved up
|
||||
155
migrate/server/feature/0029-Explosion-Durable-Blocks.patch
Normal file
155
migrate/server/feature/0029-Explosion-Durable-Blocks.patch
Normal file
@@ -0,0 +1,155 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
|
||||
Date: Wed, 15 Nov 2023 23:18:38 +0000
|
||||
Subject: [PATCH] Explosion Durable Blocks
|
||||
|
||||
|
||||
diff --git a/src/main/java/me/samsuik/sakura/explosion/durable/DurableBlockManager.java b/src/main/java/me/samsuik/sakura/explosion/durable/DurableBlockManager.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..e52cae27c2bbf4fa02d49d1c69d8e1240fddfb81
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/me/samsuik/sakura/explosion/durable/DurableBlockManager.java
|
||||
@@ -0,0 +1,43 @@
|
||||
+package me.samsuik.sakura.explosion.durable;
|
||||
+
|
||||
+import com.google.common.cache.Cache;
|
||||
+import com.google.common.cache.CacheBuilder;
|
||||
+import net.minecraft.core.BlockPos;
|
||||
+
|
||||
+import java.util.concurrent.TimeUnit;
|
||||
+
|
||||
+public final class DurableBlockManager {
|
||||
+ private final Cache<BlockPos, DurableBlock> durableBlocks = CacheBuilder.newBuilder()
|
||||
+ .expireAfterAccess(1, TimeUnit.MINUTES)
|
||||
+ .maximumSize(65534)
|
||||
+ .build();
|
||||
+
|
||||
+ public boolean damage(BlockPos pos, DurableMaterial material) {
|
||||
+ DurableBlock block = this.durableBlocks.getIfPresent(pos);
|
||||
+ if (block == null) {
|
||||
+ this.durableBlocks.put(pos, block = new DurableBlock(material.durability()));
|
||||
+ }
|
||||
+ return block.damage();
|
||||
+ }
|
||||
+
|
||||
+ public int durability(BlockPos pos, DurableMaterial material) {
|
||||
+ final DurableBlock block = this.durableBlocks.getIfPresent(pos);
|
||||
+ return block != null ? block.durability() : material.durability();
|
||||
+ }
|
||||
+
|
||||
+ private static final class DurableBlock {
|
||||
+ private int durability;
|
||||
+
|
||||
+ public DurableBlock(int durability) {
|
||||
+ this.durability = durability;
|
||||
+ }
|
||||
+
|
||||
+ public int durability() {
|
||||
+ return this.durability;
|
||||
+ }
|
||||
+
|
||||
+ public boolean damage() {
|
||||
+ return --this.durability <= 0;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/world/item/BlockItem.java b/src/main/java/net/minecraft/world/item/BlockItem.java
|
||||
index 4377fa2400c4320e0023ece230090a2a3b4b2ab6..9b66ac859619d3e79d5ab33939006b178699d474 100644
|
||||
--- a/src/main/java/net/minecraft/world/item/BlockItem.java
|
||||
+++ b/src/main/java/net/minecraft/world/item/BlockItem.java
|
||||
@@ -47,8 +47,32 @@ public class BlockItem extends Item {
|
||||
this.block = block;
|
||||
}
|
||||
|
||||
+ // Sakura start - explosion durable blocks
|
||||
+ private void sendBlockDurabilityToPlayer(UseOnContext context) {
|
||||
+ Player player = context.getPlayer();
|
||||
+ BlockState state = context.getLevel().getBlockState(context.getClickedPos());
|
||||
+ Block block = state.getBlock();
|
||||
+ me.samsuik.sakura.explosion.durable.DurableMaterial material = context.getLevel().localConfig().config(context.getClickedPos()).durableMaterials.get(block);
|
||||
+
|
||||
+ if (material != null) {
|
||||
+ int remaining = context.getLevel().durabilityManager.durability(context.getClickedPos(), material);
|
||||
+ int durability = material.durability();
|
||||
+
|
||||
+ player.getBukkitEntity().sendRichMessage(
|
||||
+ me.samsuik.sakura.configuration.GlobalConfiguration.get().messages.durableBlockInteraction,
|
||||
+ net.kyori.adventure.text.minimessage.tag.resolver.Placeholder.unparsed("remaining", String.valueOf(remaining)),
|
||||
+ net.kyori.adventure.text.minimessage.tag.resolver.Placeholder.unparsed("durability", String.valueOf(durability))
|
||||
+ );
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
@Override
|
||||
public InteractionResult useOn(UseOnContext context) {
|
||||
+ if (this.getBlock() == net.minecraft.world.level.block.Blocks.POTATOES && context.getPlayer() != null) {
|
||||
+ this.sendBlockDurabilityToPlayer(context);
|
||||
+ }
|
||||
+ // Sakura end - explosion durable blocks
|
||||
+
|
||||
InteractionResult enuminteractionresult = this.place(new BlockPlaceContext(context));
|
||||
|
||||
return !enuminteractionresult.consumesAction() && context.getItemInHand().has(DataComponents.CONSUMABLE) ? super.use(context.getLevel(), context.getPlayer(), context.getHand()) : enuminteractionresult;
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index 0301e304bb67d3a52de551442e425b83152fbabf..9fb78a9bd08521dff83b1f28be2421aa37af5898 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -844,6 +844,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
// Paper end - optimise random ticking
|
||||
public final me.samsuik.sakura.entity.merge.EntityMergeHandler mergeHandler = new me.samsuik.sakura.entity.merge.EntityMergeHandler(); // Sakura - merge cannon entities
|
||||
public final me.samsuik.sakura.explosion.density.BlockDensityCache densityCache = new me.samsuik.sakura.explosion.density.BlockDensityCache(); // Sakura - explosion density cache
|
||||
+ public final me.samsuik.sakura.explosion.durable.DurableBlockManager durabilityManager = new me.samsuik.sakura.explosion.durable.DurableBlockManager(); // Sakura - explosion durable blocks
|
||||
|
||||
protected Level(WritableLevelData worlddatamutable, ResourceKey<Level> resourcekey, RegistryAccess iregistrycustom, Holder<DimensionType> holder, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function<org.spigotmc.SpigotWorldConfig, io.papermc.paper.configuration.WorldConfiguration> paperWorldConfigCreator, java.util.function.Supplier<me.samsuik.sakura.configuration.WorldConfiguration> sakuraWorldConfigCreator, java.util.concurrent.Executor executor) { // Sakura - sakura configuration files // Paper - create paper world config & Anti-Xray
|
||||
// Paper start - getblock optimisations - cache world height/sections
|
||||
diff --git a/src/main/java/net/minecraft/world/level/ServerExplosion.java b/src/main/java/net/minecraft/world/level/ServerExplosion.java
|
||||
index 74abe5fe92b3f1fe0139f4879fe5efa10d0623e0..278ca240491096514f4c48be56bcfe2d2356520e 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/ServerExplosion.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/ServerExplosion.java
|
||||
@@ -134,7 +134,7 @@ public class ServerExplosion implements Explosion {
|
||||
BlockState blockState = ((ca.spottedleaf.moonrise.patches.getblock.GetBlockChunk)chunk).moonrise$getBlock(x, y, z);
|
||||
FluidState fluidState = blockState.getFluidState();
|
||||
|
||||
- Optional<Float> resistance = !calculateResistance ? Optional.empty() : this.damageCalculator.getBlockExplosionResistance((Explosion)(Object)this, this.level, pos, blockState, fluidState);
|
||||
+ Optional<Float> resistance = !calculateResistance ? Optional.empty() : this.calculateBlockResistance(blockState, fluidState, pos); // Sakura - explosion durable blocks
|
||||
|
||||
ret = new ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache(
|
||||
key, pos, blockState, fluidState,
|
||||
@@ -393,6 +393,20 @@ public class ServerExplosion implements Explosion {
|
||||
// Paper end - collision optimisations
|
||||
}
|
||||
// Sakura end - specialised explosions
|
||||
+ // Sakura start - explosion durable blocks
|
||||
+ private Optional<Float> calculateBlockResistance(BlockState blockState, FluidState fluidState, BlockPos pos) {
|
||||
+ if (!blockState.isAir()) {
|
||||
+ Block block = blockState.getBlock();
|
||||
+ me.samsuik.sakura.explosion.durable.DurableMaterial material = this.level.localConfig().config(pos).durableMaterials.get(block);
|
||||
+
|
||||
+ if (material != null && material.resistance() >= 0.0f && (this.level.sakuraConfig().cannons.explosion.allowNonTntBreakingDurableBlocks || this.source instanceof net.minecraft.world.entity.item.PrimedTnt)) {
|
||||
+ return Optional.of(material.resistance());
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return this.damageCalculator.getBlockExplosionResistance(this, this.level, pos, blockState, fluidState);
|
||||
+ }
|
||||
+ // Sakura end - explosion durable blocks
|
||||
|
||||
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;
|
||||
@@ -783,6 +797,16 @@ public class ServerExplosion implements Explosion {
|
||||
}
|
||||
}
|
||||
// CraftBukkit end
|
||||
+ // Sakura start - explosion durable blocks
|
||||
+ if (this.level.sakuraConfig().cannons.explosion.allowNonTntBreakingDurableBlocks || this.source instanceof net.minecraft.world.entity.item.PrimedTnt) {
|
||||
+ me.samsuik.sakura.explosion.durable.DurableMaterial material = this.level.localConfig().config(blockposition).durableMaterials.get(block);
|
||||
+
|
||||
+ if (material != null && material.durability() >= 0 && !this.level.durabilityManager.damage(blockposition, material)) {
|
||||
+ iterator.remove();
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+ // Sakura end - explosion durable blocks
|
||||
|
||||
this.level.getBlockState(blockposition).onExplosionHit(this.level, blockposition, this, (itemstack, blockposition1) -> {
|
||||
ServerExplosion.addOrAppendStack(list1, itemstack, blockposition1);
|
||||
22
migrate/server/feature/0030-Destroy-Waterlogged-Blocks.patch
Normal file
22
migrate/server/feature/0030-Destroy-Waterlogged-Blocks.patch
Normal file
@@ -0,0 +1,22 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
|
||||
Date: Thu, 16 Nov 2023 00:59:04 +0000
|
||||
Subject: [PATCH] Destroy Waterlogged Blocks
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/ServerExplosion.java b/src/main/java/net/minecraft/world/level/ServerExplosion.java
|
||||
index 8268f8df624a73eaf0b8baad9aa16bab2ed0f0bc..cc97e3a88ea99362ec043edf13c1f54c2c75daaa 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/ServerExplosion.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/ServerExplosion.java
|
||||
@@ -402,6 +402,11 @@ public class ServerExplosion implements Explosion {
|
||||
if (material != null && material.resistance() >= 0.0f && (this.level.sakuraConfig().cannons.explosion.allowNonTntBreakingDurableBlocks || this.source instanceof net.minecraft.world.entity.item.PrimedTnt)) {
|
||||
return Optional.of(material.resistance());
|
||||
}
|
||||
+ // Sakura start - destroy water logged blocks
|
||||
+ if (!fluidState.isEmpty() && !blockState.liquid() && this.level.sakuraConfig().cannons.explosion.destroyWaterloggedBlocks) {
|
||||
+ return Optional.of(ZERO_RESISTANCE);
|
||||
+ }
|
||||
+ // Sakura end - destroy water logged blocks
|
||||
}
|
||||
|
||||
return this.damageCalculator.getBlockExplosionResistance(this, this.level, pos, blockState, fluidState);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,35 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
|
||||
Date: Sat, 25 Nov 2023 21:14:45 +0000
|
||||
Subject: [PATCH] Allow explosions to destroy lava
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/ServerExplosion.java b/src/main/java/net/minecraft/world/level/ServerExplosion.java
|
||||
index bdc3ff8cbe4e5eaa9d9a34f38fdd150f7368e33b..e857fd02a5e341a1a701da71874dbd850e3c5a5d 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/ServerExplosion.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/ServerExplosion.java
|
||||
@@ -407,6 +407,11 @@ public class ServerExplosion implements Explosion {
|
||||
return Optional.of(ZERO_RESISTANCE);
|
||||
}
|
||||
// Sakura end - destroy water logged blocks
|
||||
+ // Sakura start - allow explosions to destroy lava
|
||||
+ if (blockState.is(Blocks.LAVA) && this.level.sakuraConfig().cannons.explosion.explodeLava) {
|
||||
+ return Optional.of(ZERO_RESISTANCE);
|
||||
+ }
|
||||
+ // Sakura end - allow explosions to destroy lava
|
||||
}
|
||||
|
||||
return this.damageCalculator.getBlockExplosionResistance(this, this.level, pos, blockState, fluidState);
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
|
||||
index 99fd67a78539133adf78d65e2c520ff3dd260301..37ea7f464d6ea691fb0ec08319d03f89bb41cfee 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
|
||||
@@ -198,7 +198,7 @@ public abstract class BlockBehaviour implements FeatureElement {
|
||||
});
|
||||
}
|
||||
|
||||
- world.setBlock(pos, Blocks.AIR.defaultBlockState(), 3);
|
||||
+ world.setBlock(pos, Blocks.AIR.defaultBlockState(), world.sakuraConfig().cannons.explosion.explodeLava && state.is(Blocks.LAVA) ? 2 : 3); // Sakura - allow explosions to destroy lava
|
||||
block.wasExploded(world, pos, explosion);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
|
||||
Date: Sun, 26 Nov 2023 17:57:50 +0000
|
||||
Subject: [PATCH] Treat solid blocks as full when moving fast
|
||||
|
||||
|
||||
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java b/src/main/java/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java
|
||||
index 079aa846fa9b5650675ae855ba0bb61ca42a6b52..7953ddb67530396c35b42496594a80e1b3f1b349 100644
|
||||
--- a/src/main/java/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java
|
||||
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java
|
||||
@@ -1908,6 +1908,7 @@ public final class CollisionUtil {
|
||||
public static final int COLLISION_FLAG_CHECK_BORDER = 1 << 2;
|
||||
public static final int COLLISION_FLAG_CHECK_ONLY = 1 << 3;
|
||||
public static final int COLLISION_FLAG_ADD_TICKET = 1 << 4; // Sakura - load chunks on movement
|
||||
+ public static final int COLLISION_FLAG_FULL_BLOCKS = 1 << 5; // Sakura - treat solid blocks as full when moving fast
|
||||
|
||||
public static boolean getCollisionsForBlocksOrWorldBorder(final Level world, final Entity entity, final AABB aabb,
|
||||
final List<VoxelShape> intoVoxel, final List<AABB> intoAABB,
|
||||
@@ -1960,6 +1961,7 @@ public final class CollisionUtil {
|
||||
|
||||
final boolean loadChunks = (collisionFlags & COLLISION_FLAG_LOAD_CHUNKS) != 0;
|
||||
final boolean addTicket = (collisionFlags & COLLISION_FLAG_ADD_TICKET) != 0; // Sakura - load chunks on movement
|
||||
+ final boolean fullBlocks = (collisionFlags & COLLISION_FLAG_FULL_BLOCKS) != 0; // Sakura - treat solid blocks as full when moving fast
|
||||
final ChunkSource chunkSource = world.getChunkSource();
|
||||
|
||||
for (int currChunkZ = minChunkZ; currChunkZ <= maxChunkZ; ++currChunkZ) {
|
||||
@@ -1999,7 +2001,7 @@ public final class CollisionUtil {
|
||||
continue;
|
||||
}
|
||||
|
||||
- final boolean hasSpecial = ((BlockCountingChunkSection)section).moonrise$hasSpecialCollidingBlocks();
|
||||
+ final boolean hasSpecial = !fullBlocks && ((BlockCountingChunkSection)section).moonrise$hasSpecialCollidingBlocks(); // Sakura - treat solid blocks as full when moving fast
|
||||
final int sectionAdjust = !hasSpecial ? 1 : 0;
|
||||
|
||||
final PalettedContainer<BlockState> blocks = section.states;
|
||||
@@ -2038,6 +2040,11 @@ public final class CollisionUtil {
|
||||
if (useEntityCollisionShape) {
|
||||
mutablePos.set(blockX, blockY, blockZ);
|
||||
blockCollision = collisionShape.getCollisionShape(blockData, world, mutablePos);
|
||||
+ // Sakura start - treat solid blocks as full when moving fast
|
||||
+ // todo: move this logic above emptyCollisionShape and consider all blocks as a solid except scaffolding and liquids
|
||||
+ } else if (fullBlocks && blockData.moonrise$getConstantContextCollisionShape() != null) {
|
||||
+ blockCollision = net.minecraft.world.phys.shapes.Shapes.block();
|
||||
+ // Sakura end - treat solid blocks as full when moving fast
|
||||
} else if (blockCollision == null) {
|
||||
mutablePos.set(blockX, blockY, blockZ);
|
||||
blockCollision = blockData.getCollisionShape(world, mutablePos, collisionShape);
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index 6ab4c1db02846123e72a805a2e8070c398d726e3..21ef61cc82df99aae6be1e6c3f603058cbeb548f 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -583,6 +583,14 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
flags |= ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_FLAG_ADD_TICKET;
|
||||
}
|
||||
|
||||
+ // Sakura start - treat solid blocks as full when moving fast
|
||||
+ if (this.level().sakuraConfig().cannons.treatAllBlocksAsFullWhenMoving && (this.isPrimedTNT || this.isFallingBlock)) {
|
||||
+ double horizontalMovementSqr = this.getDeltaMovement().horizontalDistanceSqr();
|
||||
+ if (horizontalMovementSqr > Math.pow(this.level().sakuraConfig().cannons.treatAllBlocksAsFullWhenMovingFasterThan, 2.0)) {
|
||||
+ flags |= ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_FLAG_FULL_BLOCKS;
|
||||
+ }
|
||||
+ }
|
||||
+ // Sakura end - treat solid blocks as full when moving fast
|
||||
return flags;
|
||||
}
|
||||
// Sakura end - load chunks on movement
|
||||
@@ -0,0 +1,52 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
|
||||
Date: Thu, 30 Nov 2023 15:54:49 +0000
|
||||
Subject: [PATCH] Reduce entity tracker player updates
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index ed7ae4617c992b4e5f5ce14f998b9c763ee1b7e2..54bfe3dfda0e023cc3d25ddcf1fe366a6cf50c90 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -972,7 +972,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
if (tracker == null) {
|
||||
continue;
|
||||
}
|
||||
- ((ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerTrackedEntity)tracker).moonrise$tick(((ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity)entity).moonrise$getChunkData().nearbyPlayers);
|
||||
+ // Sakura start - reduce entity tracker player updates
|
||||
+ if (tracker.shouldUpdatePlayers()) {
|
||||
+ ((ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerTrackedEntity)tracker).moonrise$tick(((ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity)entity).moonrise$getChunkData().nearbyPlayers);
|
||||
+ }
|
||||
+ // Sakura end - reduce entity tracker player updates
|
||||
if (((ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerTrackedEntity)tracker).moonrise$hasPlayers()
|
||||
|| ((ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity)entity).moonrise$getChunkStatus().isOrAfter(FullChunkStatus.ENTITY_TICKING)) {
|
||||
tracker.serverEntity.sendChanges();
|
||||
@@ -1243,12 +1247,28 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
return state != me.samsuik.sakura.player.visibility.VisibilityState.OFF;
|
||||
}
|
||||
// Sakura end - client visibility settings; entity visibility
|
||||
+ // Sakura start - reduce entity tracker player updates
|
||||
+ private final int playerUpdateInterval;
|
||||
+ private Vec3 entityPosition;
|
||||
+
|
||||
+ public final boolean shouldUpdatePlayers() {
|
||||
+ // We have to always update players otherwise they can turn invisible on teleports (why?)
|
||||
+ if (this.entity instanceof net.minecraft.world.entity.player.Player || this.entity.tickCount % this.playerUpdateInterval == 0) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ Vec3 lastPosition = this.entityPosition;
|
||||
+ this.entityPosition = this.entity.position();
|
||||
+ return this.entity.position().distanceToSqr(lastPosition) >= (double) this.range / 2.0;
|
||||
+ }
|
||||
+ // Sakura start - reduce entity tracker player updates
|
||||
|
||||
public TrackedEntity(final Entity entity, final int i, final int j, final boolean flag) {
|
||||
this.serverEntity = new ServerEntity(ChunkMap.this.level, entity, j, flag, this::broadcast, this.seenBy); // CraftBukkit
|
||||
this.entity = entity;
|
||||
this.range = i;
|
||||
this.lastSectionPos = SectionPos.of((EntityAccess) entity);
|
||||
+ this.playerUpdateInterval = Math.min(j, 20); // Sakura - reduce entity tracker player updates
|
||||
+ this.entityPosition = entity.position(); // Sakura - reduce entity tracker player updates
|
||||
}
|
||||
|
||||
public boolean equals(Object object) {
|
||||
@@ -0,0 +1,53 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
|
||||
Date: Sat, 2 Dec 2023 15:14:15 +0000
|
||||
Subject: [PATCH] Add option for legacy lava block formation
|
||||
|
||||
|
||||
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 9e0f4517069ee3fd16a60ccc214da68d518c7f85..0ea609556d906df3eadd3df83bd4a7f85857a14e 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/LiquidBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/LiquidBlock.java
|
||||
@@ -200,7 +200,15 @@ public class LiquidBlock extends Block implements BucketPickup {
|
||||
if (fluidState.isSource()) {
|
||||
block = Blocks.OBSIDIAN;
|
||||
} else {
|
||||
- final me.samsuik.sakura.physics.PhysicsVersion physics = world.localConfig().config(pos).physicsVersion;
|
||||
+ // Sakura start - legacy lava block formation
|
||||
+ final me.samsuik.sakura.physics.PhysicsVersion physics;
|
||||
+
|
||||
+ if (world.sakuraConfig().environment.blockGeneration.legacyBlockFormation) {
|
||||
+ physics = me.samsuik.sakura.physics.PhysicsVersion.v1_12;
|
||||
+ } else {
|
||||
+ physics = world.localConfig().config(pos).physicsVersion;
|
||||
+ }
|
||||
+ // Sakura end - legacy lava block formation
|
||||
|
||||
// SANITY: In legacy a patch by paper removes the fluid level condition from vanilla.
|
||||
if (physics.afterOrEqual(1_16_0) || physics.isLegacy()
|
||||
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 4132e26332e6e8e061f43867426291ec0aefe0a2..ce34bbe57c524964300b6086358fa456f9e6d3ca 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/material/LavaFluid.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/material/LavaFluid.java
|
||||
@@ -178,7 +178,7 @@ public abstract class LavaFluid extends FlowingFluid {
|
||||
public boolean canBeReplacedWith(FluidState state, BlockGetter world, BlockPos pos, Fluid fluid, Direction direction) {
|
||||
// Sakura start - physics version api
|
||||
return state.getHeight(world, pos) >= 0.44444445F && fluid.is(FluidTags.WATER)
|
||||
- && world instanceof Level level && level.localConfig().config(pos).physicsVersion.afterOrEqual(1_13_0);
|
||||
+ && world instanceof Level level && !level.sakuraConfig().environment.blockGeneration.legacyBlockFormation && level.localConfig().config(pos).physicsVersion.afterOrEqual(1_13_0); // Sakura - legacy lava block formation
|
||||
// Sakura end - physics version api
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/material/WaterFluid.java b/src/main/java/net/minecraft/world/level/material/WaterFluid.java
|
||||
index 66b9a574eb57c6fb2964825ecca7110d079fb7cc..3fa9e6baab6b8a4f4b02ea5cbbb68d57a7f6888d 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/material/WaterFluid.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/material/WaterFluid.java
|
||||
@@ -123,7 +123,7 @@ public abstract class WaterFluid extends FlowingFluid {
|
||||
public boolean canBeReplacedWith(FluidState state, BlockGetter world, BlockPos pos, Fluid fluid, Direction direction) {
|
||||
// Sakura start - physics version api
|
||||
return direction == Direction.DOWN && !fluid.is(FluidTags.WATER)
|
||||
- || fluid.is(FluidTags.LAVA) && world instanceof Level level && level.localConfig().config(pos).physicsVersion.before(1_13_0);
|
||||
+ || fluid.is(FluidTags.LAVA) && world instanceof Level level && (level.sakuraConfig().environment.blockGeneration.legacyBlockFormation || level.localConfig().config(pos).physicsVersion.before(1_13_0)); // Sakura - legacy lava block formation
|
||||
// Sakura end - physics version api
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samsuik <kfian294ma4@gmail.com>
|
||||
Date: Tue, 20 Feb 2024 19:16:16 +0000
|
||||
Subject: [PATCH] Add entity travel distance limits
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 1973da88ac7c3a36cc2db48aeb7d4eab788be500..88432d15be0167450afe5e5c130b8be233c78437 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -1329,6 +1329,11 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
final boolean isActive = org.spigotmc.ActivationRange.checkIfActive(entity); // Paper - EAR 2
|
||||
if (isActive) { // Paper - EAR 2
|
||||
entity.tick();
|
||||
+ // Sakura start - entity travel distance limits
|
||||
+ if (entity.isPastTravelDistanceLimit()) {
|
||||
+ entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN);
|
||||
+ }
|
||||
+ // Sakura end - entity travel distance limits
|
||||
entity.postTick(); // CraftBukkit
|
||||
} else { entity.inactiveTick(); } // Paper - EAR 2
|
||||
gameprofilerfiller.pop();
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index 1aa5803061861016a1bb790ac19b769170a76a79..a2b0fe7122c11da561ab6ceb91bc37385df16c0d 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -638,6 +638,19 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
return this.physics;
|
||||
}
|
||||
// Sakura end - physics version api
|
||||
+ // Sakura start - entity travel distance limits
|
||||
+ private final double travelDistanceLimit;
|
||||
+
|
||||
+ public final boolean isPastTravelDistanceLimit() {
|
||||
+ if (this.origin == null) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ double x = Math.pow(this.origin.getX() - this.position.x(), 2);
|
||||
+ double z = Math.pow(this.origin.getZ() - this.position.z(), 2);
|
||||
+ return Math.max(x, z) >= this.travelDistanceLimit;
|
||||
+ }
|
||||
+ // Sakura end - entity travel distance limits
|
||||
|
||||
public Entity(EntityType<?> type, Level world) {
|
||||
this.id = Entity.ENTITY_COUNTER.incrementAndGet();
|
||||
@@ -691,6 +704,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
this.entityData = datawatcher_a.build();
|
||||
this.setPos(0.0D, 0.0D, 0.0D);
|
||||
this.eyeHeight = this.dimensions.eyeHeight();
|
||||
+ this.travelDistanceLimit = Math.pow(this.level.sakuraConfig().entity.chunkTravelLimit.getOrDefault(type, Integer.MAX_VALUE) * 16.0, 2); // Sakura - entity travel distance limits
|
||||
}
|
||||
|
||||
public boolean isColliding(BlockPos pos, BlockState state) {
|
||||
@@ -0,0 +1,22 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samsuik <kfian294ma4@gmail.com>
|
||||
Date: Mon, 17 Jun 2024 14:04:12 +0100
|
||||
Subject: [PATCH] Protect scaffolding from creepers
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/ServerExplosion.java b/src/main/java/net/minecraft/world/level/ServerExplosion.java
|
||||
index 0dae16d140666cae7633bbfef6d1c5b979d7dc9e..a9a63fa9d2c45298ebd4146e0dfeea54b6431797 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/ServerExplosion.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/ServerExplosion.java
|
||||
@@ -412,6 +412,11 @@ public class ServerExplosion implements Explosion {
|
||||
return Optional.of(ZERO_RESISTANCE);
|
||||
}
|
||||
// Sakura end - allow explosions to destroy lava
|
||||
+ // Sakura start - protect scaffolding from creepers
|
||||
+ if (this.level.sakuraConfig().cannons.explosion.protectScaffoldingFromCreepers && blockState.is(Blocks.SCAFFOLDING) && this.source instanceof net.minecraft.world.entity.monster.Creeper) {
|
||||
+ return Optional.of(Blocks.BARRIER.getExplosionResistance());
|
||||
+ }
|
||||
+ // Sakura end - protect scaffolding from creepers
|
||||
}
|
||||
|
||||
return this.damageCalculator.getBlockExplosionResistance(this, this.level, pos, blockState, fluidState);
|
||||
@@ -0,0 +1,89 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samsuik <kfian294ma4@gmail.com>
|
||||
Date: Fri, 9 Aug 2024 20:43:53 +0100
|
||||
Subject: [PATCH] Configurable left shooting and adjusting limits
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index a2b0fe7122c11da561ab6ceb91bc37385df16c0d..95f4854ca21a6b34ad1ab95a1cb38f7d2dfd24c3 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -651,6 +651,46 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
return Math.max(x, z) >= this.travelDistanceLimit;
|
||||
}
|
||||
// Sakura end - entity travel distance limits
|
||||
+ // Sakura start - configurable left shooting and adjusting limits
|
||||
+ public final void limitLeftShooting() {
|
||||
+ Vec3 movement = this.getDeltaMovement();
|
||||
+ int threshold = this.level.sakuraConfig().cannons.restrictions.leftShootingThreshold.or(-1);
|
||||
+ if (threshold > 0 && (movement.x != 0.0 || movement.z != 0.0) && this.origin != null) {
|
||||
+ double travelledX = Math.abs(this.getX() - this.origin.getX());
|
||||
+ double travelledZ = Math.abs(this.getZ() - this.origin.getZ());
|
||||
+ boolean xSmaller = travelledX < travelledZ; // intended
|
||||
+
|
||||
+ // Once entities have travelled past the threshold changing direction is restricted.
|
||||
+ if (xSmaller && travelledX > threshold) {
|
||||
+ this.setDeltaMovement(movement.multiply(1.0, 1.0, 0.0)); // limit z
|
||||
+ } else if (!xSmaller && travelledZ > threshold) {
|
||||
+ this.setDeltaMovement(movement.multiply(0.0, 1.0, 1.0)); // limit x
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public final void limitAdjustMovement(AABB currBoundingBox, double dir, boolean xAdjust, List<VoxelShape> shapes) {
|
||||
+ int adjustDistance = this.level.sakuraConfig().cannons.restrictions.maxAdjustDistance.or(-1);
|
||||
+ if (adjustDistance > 0 && Math.abs(dir) > adjustDistance) {
|
||||
+ double minX = Double.NEGATIVE_INFINITY;
|
||||
+ double minZ = Double.NEGATIVE_INFINITY;
|
||||
+ double maxX = Double.POSITIVE_INFINITY;
|
||||
+ double maxZ = Double.POSITIVE_INFINITY;
|
||||
+ if (xAdjust) { // limit x adjust
|
||||
+ minX = Math.floor(currBoundingBox.minX) - adjustDistance;
|
||||
+ maxX = Math.floor(currBoundingBox.maxX) + adjustDistance + 1;
|
||||
+ } else { // limit z adjust
|
||||
+ minZ = Math.floor(currBoundingBox.minZ) - adjustDistance;
|
||||
+ maxZ = Math.floor(currBoundingBox.maxZ) + adjustDistance + 1;
|
||||
+ }
|
||||
+ VoxelShape safeSpace = Shapes.box(
|
||||
+ minX, Double.NEGATIVE_INFINITY, minZ,
|
||||
+ maxX, Double.POSITIVE_INFINITY, maxZ
|
||||
+ );
|
||||
+ shapes.add(Shapes.join(Shapes.INFINITY, safeSpace, BooleanOp.ONLY_FIRST));
|
||||
+ }
|
||||
+ }
|
||||
+ // Sakura end - configurable left shooting and adjusting limits
|
||||
|
||||
public Entity(EntityType<?> type, Level world) {
|
||||
this.id = Entity.ENTITY_COUNTER.incrementAndGet();
|
||||
@@ -1742,6 +1782,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
}
|
||||
|
||||
if (xSmaller && z != 0.0) {
|
||||
+ this.limitAdjustMovement(currBoundingBox, z, false, voxelList); // Sakura - configurable left shooting and adjusting limits
|
||||
z = this.scanZ(currBoundingBox, z, voxelList, bbList);
|
||||
if (z != 0.0) {
|
||||
currBoundingBox = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.offsetZ(currBoundingBox, z);
|
||||
@@ -1749,6 +1790,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
}
|
||||
|
||||
if (x != 0.0) {
|
||||
+ // Sakura start - configurable left shooting and adjusting limits
|
||||
+ if (!xSmaller) {
|
||||
+ this.limitAdjustMovement(currBoundingBox, x, true, voxelList);
|
||||
+ }
|
||||
+ // Sakura end - configurable left shooting and adjusting limits
|
||||
x = this.scanX(currBoundingBox, x, voxelList, bbList);
|
||||
if (x != 0.0) {
|
||||
currBoundingBox = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.offsetX(currBoundingBox, x);
|
||||
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 6a3d0d407dc25715c1408818cd7aba1d962ed382..1a90e7bb8209e20c288afd8c78e681c1fab317cb 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||
@@ -270,6 +270,7 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti
|
||||
// Sakura end - physics version api
|
||||
++this.time;
|
||||
this.applyGravity();
|
||||
+ this.limitLeftShooting(); // Sakura - configurable left shooting and adjusting limits
|
||||
this.moveStripped(MoverType.SELF, this.getDeltaMovement()); // Sakura - optimise cannon entity movement
|
||||
this.applyEffectsFromBlocks();
|
||||
// Paper start - Configurable falling blocks height nerf
|
||||
316
migrate/server/feature/0075-Optimise-hopper-ticking.patch
Normal file
316
migrate/server/feature/0075-Optimise-hopper-ticking.patch
Normal file
@@ -0,0 +1,316 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samsuik <kfian294ma4@gmail.com>
|
||||
Date: Mon, 12 Aug 2024 15:35:57 +0100
|
||||
Subject: [PATCH] Optimise hopper ticking
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/CompoundContainer.java b/src/main/java/net/minecraft/world/CompoundContainer.java
|
||||
index 241fec02e6869c638d3a160819b32173a081467b..dc15a12687ce9e8e354bea9825d9cd1882d00782 100644
|
||||
--- a/src/main/java/net/minecraft/world/CompoundContainer.java
|
||||
+++ b/src/main/java/net/minecraft/world/CompoundContainer.java
|
||||
@@ -58,6 +58,15 @@ public class CompoundContainer implements Container {
|
||||
return this.container1.getLocation(); // TODO: right?
|
||||
}
|
||||
// CraftBukkit end
|
||||
+ // Sakura start - optimise hopper ticking
|
||||
+ @Override
|
||||
+ public final boolean addListener(net.minecraft.world.level.block.entity.BlockEntity.BlockEntityChangeListener listener) {
|
||||
+ boolean result = false;
|
||||
+ result |= this.container1.addListener(listener);
|
||||
+ result |= this.container2.addListener(listener);
|
||||
+ return result;
|
||||
+ }
|
||||
+ // Sakura end - optimise hopper ticking
|
||||
|
||||
public CompoundContainer(Container first, Container second) {
|
||||
this.container1 = first;
|
||||
diff --git a/src/main/java/net/minecraft/world/Container.java b/src/main/java/net/minecraft/world/Container.java
|
||||
index 5db5ba026462ca642dcee718af732f80fadabef5..51e26395b53628b34b1f7f68935a9ba44a1e3feb 100644
|
||||
--- a/src/main/java/net/minecraft/world/Container.java
|
||||
+++ b/src/main/java/net/minecraft/world/Container.java
|
||||
@@ -17,6 +17,12 @@ public interface Container extends Clearable {
|
||||
|
||||
float DEFAULT_DISTANCE_BUFFER = 4.0F;
|
||||
|
||||
+ // Sakura start - optimise hopper ticking
|
||||
+ default boolean addListener(BlockEntity.BlockEntityChangeListener container) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Sakura end - optimise hopper ticking
|
||||
+
|
||||
int getContainerSize();
|
||||
|
||||
boolean isEmpty();
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index f99497c7b10716c1804d29e1e51e608c3a542127..290f3fc3c05892c4de8015fe38cec0c5e5d9fb61 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -1649,7 +1649,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
tilesThisCycle--;
|
||||
toRemove.add(tickingblockentity); // Paper - Fix MC-117075; use removeAll
|
||||
// Spigot end
|
||||
- } else if (flag && this.shouldTickBlocksAt(tickingblockentity.getPos())) {
|
||||
+ } else if (flag && tickingblockentity.isBlockEntityActive() && this.shouldTickBlocksAt(tickingblockentity.getPos())) { // Sakura - optimise hopper ticking
|
||||
tickingblockentity.tick();
|
||||
// Paper start - rewrite chunk system
|
||||
if ((++tickedEntities & 7) == 0) {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/HopperBlock.java b/src/main/java/net/minecraft/world/level/block/HopperBlock.java
|
||||
index 8ba23af2fa6c5174aa3ec34e78f9c21ce786c4fc..45070d4506b79890f3cd806789a2fa7ab9d37d27 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/HopperBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/HopperBlock.java
|
||||
@@ -140,6 +140,12 @@ public class HopperBlock extends BaseEntityBlock {
|
||||
private void checkPoweredState(Level world, BlockPos pos, BlockState state) {
|
||||
boolean bl = !world.hasNeighborSignal(pos);
|
||||
if (bl != state.getValue(ENABLED)) {
|
||||
+ // Sakura start - optimise hopper ticking
|
||||
+ BlockEntity blockEntity = world.getBlockEntity(pos);
|
||||
+ if (blockEntity instanceof HopperBlockEntity hbe && world.sakuraConfig().technical.optimiseIdleHopperTicking) {
|
||||
+ hbe.setBlockEntityTicking(bl);
|
||||
+ }
|
||||
+ // Sakura end - optimise hopper ticking
|
||||
world.setBlock(pos, state.setValue(ENABLED, Boolean.valueOf(bl)), 2);
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
|
||||
index 1f664c10138a6e19bdc0051fa80575516d5602e7..1d3b7bf7b06b340f15671db4b910ca8d830f268d 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
|
||||
@@ -48,6 +48,55 @@ public abstract class BlockEntity {
|
||||
private BlockState blockState;
|
||||
private DataComponentMap components;
|
||||
|
||||
+ // Sakura start - optimise hopper ticking
|
||||
+ private final Set<BlockEntityChangeListener> listeners = new it.unimi.dsi.fastutil.objects.ReferenceArraySet<>(0);
|
||||
+ private final java.util.List<BlockEntity> listeningBlocks = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(0);
|
||||
+ private boolean blockEntityTicking = true;
|
||||
+ private int tickCount = 0;
|
||||
+
|
||||
+ public final int getIdleTickCount() {
|
||||
+ return this.tickCount;
|
||||
+ }
|
||||
+
|
||||
+ public final boolean isBlockEntityActive() {
|
||||
+ this.tickCount++;
|
||||
+ return this.blockEntityTicking;
|
||||
+ }
|
||||
+
|
||||
+ public final void setBlockEntityTicking(boolean blockEntityTicking) {
|
||||
+ this.tickCount = 0;
|
||||
+ this.blockEntityTicking = blockEntityTicking;
|
||||
+ }
|
||||
+
|
||||
+ public final boolean addListener(BlockEntityChangeListener listener) {
|
||||
+ if (this.listeners.add(listener)) {
|
||||
+ ((BlockEntity) listener).listeningBlocks.add(this);
|
||||
+ }
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ public final void updateListeners(boolean onRemove) {
|
||||
+ for (BlockEntityChangeListener listener : this.listeners) {
|
||||
+ if (onRemove) {
|
||||
+ listener.neighborRemoved();
|
||||
+ } else {
|
||||
+ listener.neighborChange();
|
||||
+ }
|
||||
+ }
|
||||
+ if (onRemove) {
|
||||
+ this.listeningBlocks.forEach(blockEntity -> blockEntity.listeners.clear());
|
||||
+ this.listeningBlocks.clear();
|
||||
+ this.listeners.clear();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public interface BlockEntityChangeListener {
|
||||
+ void neighborChange();
|
||||
+
|
||||
+ void neighborRemoved();
|
||||
+ }
|
||||
+ // Sakura end - optimise hopper ticking
|
||||
+
|
||||
public BlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
|
||||
this.components = DataComponentMap.EMPTY;
|
||||
this.type = type;
|
||||
@@ -217,12 +266,23 @@ public abstract class BlockEntity {
|
||||
public void setChanged() {
|
||||
if (this.level != null) {
|
||||
if (ignoreTileUpdates) return; // Paper - Perf: Optimize Hoppers
|
||||
- BlockEntity.setChanged(this.level, this.worldPosition, this.blockState);
|
||||
+ BlockEntity.setChanged(this.level, this.worldPosition, this.blockState, this); // Sakura - optimise hopper ticking
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected static void setChanged(Level world, BlockPos pos, BlockState state) {
|
||||
+ // Sakura start - optimise hopper ticking
|
||||
+ net.minecraft.world.level.chunk.LevelChunk chunk = world.getChunkIfLoaded(pos);
|
||||
+ BlockEntity blockEntity = chunk != null ? chunk.getBlockEntity(pos) : null;
|
||||
+ setChanged(world, pos, state, blockEntity);
|
||||
+ }
|
||||
+
|
||||
+ protected static void setChanged(Level world, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity) {
|
||||
+ if (blockEntity != null) {
|
||||
+ blockEntity.updateListeners(false);
|
||||
+ }
|
||||
+ // Sakura end - optimise hopper ticking
|
||||
world.blockEntityChanged(pos);
|
||||
if (!state.isAir()) {
|
||||
world.updateNeighbourForOutputSignal(pos, state.getBlock());
|
||||
@@ -253,6 +313,7 @@ public abstract class BlockEntity {
|
||||
|
||||
public void setRemoved() {
|
||||
this.remove = true;
|
||||
+ this.updateListeners(true); // Sakura - optimise hopper ticking
|
||||
}
|
||||
|
||||
public void clearRemoved() {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java
|
||||
index 5ebbdb94d9b91c442ff60eb6872f740ebd790fa0..ab82d62cc119cbeb981fcccded3dca8fc36eea66 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java
|
||||
@@ -42,7 +42,7 @@ import org.bukkit.event.inventory.InventoryPickupItemEvent;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
// CraftBukkit end
|
||||
|
||||
-public class HopperBlockEntity extends RandomizableContainerBlockEntity implements Hopper {
|
||||
+public class HopperBlockEntity extends RandomizableContainerBlockEntity implements Hopper, BlockEntity.BlockEntityChangeListener { // Sakura - optimise hopper ticking
|
||||
|
||||
public static final int MOVE_ITEM_SPEED = 8;
|
||||
public static final int HOPPER_CONTAINER_SIZE = 5;
|
||||
@@ -81,6 +81,58 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
this.maxStack = size;
|
||||
}
|
||||
// CraftBukkit end
|
||||
+ // Sakura start - optimise hopper ticking
|
||||
+ private static final int SOURCE_CONTAINER = 1 << 0;
|
||||
+ private static final int ATTACHED_CONTAINER = 1 << 1;
|
||||
+ private int connectedContainers = 0;
|
||||
+
|
||||
+ @Override
|
||||
+ public final void neighborChange() {
|
||||
+ this.startTicking();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public final void neighborRemoved() {
|
||||
+ this.connectedContainers = 0;
|
||||
+ this.startTicking();
|
||||
+ }
|
||||
+
|
||||
+ private void startTicking() {
|
||||
+ this.cooldownTime -= this.getIdleTickCount();
|
||||
+ this.setBlockEntityTicking(true);
|
||||
+ }
|
||||
+
|
||||
+ private void waitForChange(int fullState) {
|
||||
+ if ((fullState == HOPPER_IS_FULL || (this.connectedContainers & SOURCE_CONTAINER) != 0) && (this.connectedContainers & ATTACHED_CONTAINER) != 0) {
|
||||
+ this.addListener(this);
|
||||
+ this.setBlockEntityTicking(false);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private static @Nullable Container sakura_getSourceContainer(Level level, Hopper hopper, BlockPos pos, BlockState state) {
|
||||
+ Container container = getSourceContainer(level, hopper, pos, state);
|
||||
+ if (hopper instanceof HopperBlockEntity hbe && HopperInventorySearchEvent.getHandlerList().getRegisteredListeners().length == 0) {
|
||||
+ hbe.listenForContainerChanges(container, SOURCE_CONTAINER);
|
||||
+ }
|
||||
+ return container;
|
||||
+ }
|
||||
+
|
||||
+ private static @Nullable Container sakura_getAttachedContainer(Level level, BlockPos pos, HopperBlockEntity hbe) {
|
||||
+ Container container = getAttachedContainer(level, pos, hbe);
|
||||
+ if (HopperInventorySearchEvent.getHandlerList().getRegisteredListeners().length == 0) {
|
||||
+ hbe.listenForContainerChanges(container, ATTACHED_CONTAINER);
|
||||
+ }
|
||||
+ return container;
|
||||
+ }
|
||||
+
|
||||
+ private void listenForContainerChanges(@Nullable Container container, int type) {
|
||||
+ if (container != null && container.addListener(this)) {
|
||||
+ this.connectedContainers |= type; // set
|
||||
+ } else if ((this.connectedContainers & type) != 0) {
|
||||
+ this.connectedContainers ^= type; // unset
|
||||
+ }
|
||||
+ }
|
||||
+ // Sakura end - optimise hopper ticking
|
||||
|
||||
public HopperBlockEntity(BlockPos pos, BlockState state) {
|
||||
super(BlockEntityType.HOPPER, pos, state);
|
||||
@@ -214,6 +266,12 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
setChanged(world, pos, state);
|
||||
return true;
|
||||
}
|
||||
+
|
||||
+ // Sakura start - optimise hopper ticking
|
||||
+ if (world.sakuraConfig().technical.optimiseIdleHopperTicking) {
|
||||
+ blockEntity.waitForChange(fullState);
|
||||
+ }
|
||||
+ // Sakura end - optimise hopper ticking
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -433,7 +491,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
// Paper end - Perf: Optimize Hoppers
|
||||
|
||||
private static boolean ejectItems(Level world, BlockPos pos, HopperBlockEntity blockEntity) {
|
||||
- Container iinventory = HopperBlockEntity.getAttachedContainer(world, pos, blockEntity);
|
||||
+ Container iinventory = HopperBlockEntity.sakura_getAttachedContainer(world, pos, blockEntity); // Sakura
|
||||
|
||||
if (iinventory == null) {
|
||||
return false;
|
||||
@@ -548,7 +606,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
public static boolean suckInItems(Level world, Hopper hopper) {
|
||||
BlockPos blockposition = BlockPos.containing(hopper.getLevelX(), hopper.getLevelY() + 1.0D, hopper.getLevelZ());
|
||||
BlockState iblockdata = world.getBlockState(blockposition);
|
||||
- Container iinventory = HopperBlockEntity.getSourceContainer(world, hopper, blockposition, iblockdata);
|
||||
+ Container iinventory = HopperBlockEntity.sakura_getSourceContainer(world, hopper, blockposition, iblockdata); // Sakura - optimise hopper ticking
|
||||
|
||||
if (iinventory != null) {
|
||||
Direction enumdirection = Direction.DOWN;
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/entity/TickingBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/TickingBlockEntity.java
|
||||
index 28e3b73507b988f7234cbf29c4024c88180d0aef..a0d247aa883553708c4b92158232425593d50534 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/entity/TickingBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/entity/TickingBlockEntity.java
|
||||
@@ -10,4 +10,10 @@ public interface TickingBlockEntity {
|
||||
BlockPos getPos();
|
||||
|
||||
String getType();
|
||||
+
|
||||
+ // Sakura start - optimise hopper ticking
|
||||
+ default boolean isBlockEntityActive() {
|
||||
+ return true;
|
||||
+ }
|
||||
+ // Sakura end - optimise hopper ticking
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
index 97937e3bd211997f0a0a3e9e671a1c59712d0003..ce92f8f2d2f96ec77ae7128b741689ec2b77aad9 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -1040,6 +1040,13 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p
|
||||
return this.ticker.getType();
|
||||
}
|
||||
|
||||
+ // Sakura start - optimise hopper ticking
|
||||
+ @Override
|
||||
+ public boolean isBlockEntityActive() {
|
||||
+ return this.ticker.isBlockEntityActive();
|
||||
+ }
|
||||
+ // Sakura end - optimise hopper ticking
|
||||
+
|
||||
public String toString() {
|
||||
return String.valueOf(this.ticker) + " <wrapped>";
|
||||
}
|
||||
@@ -1112,6 +1119,13 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p
|
||||
return BlockEntityType.getKey(this.blockEntity.getType()).toString();
|
||||
}
|
||||
|
||||
+ // Sakura start - optimise hopper ticking
|
||||
+ @Override
|
||||
+ public boolean isBlockEntityActive() {
|
||||
+ return this.blockEntity.isBlockEntityActive();
|
||||
+ }
|
||||
+ // Sakura end - optimise hopper ticking
|
||||
+
|
||||
public String toString() {
|
||||
String s = this.getType();
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samsuik <kfian294ma4@gmail.com>
|
||||
Date: Fri, 13 Sep 2024 17:22:51 +0100
|
||||
Subject: [PATCH] Tick entity schedulers only when necessary
|
||||
|
||||
|
||||
diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/server/ServerEntityLookup.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/server/ServerEntityLookup.java
|
||||
index 58d9187adc188b693b6becc400f766e069bf1bf5..8b7860390717c3d2a3c0f3d2b081799bcd3d65c1 100644
|
||||
--- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/server/ServerEntityLookup.java
|
||||
+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/server/ServerEntityLookup.java
|
||||
@@ -19,6 +19,22 @@ public final class ServerEntityLookup extends EntityLookup {
|
||||
|
||||
private final ServerLevel serverWorld;
|
||||
public final ReferenceList<Entity> trackerEntities = new ReferenceList<>(EMPTY_ENTITY_ARRAY); // Moonrise - entity tracker
|
||||
+ // Sakura start - tick entity schedulers only when necessary
|
||||
+ public final ReferenceList<org.bukkit.craftbukkit.entity.CraftEntity> scheduledEntities = new ReferenceList<>();
|
||||
+
|
||||
+ public void entityStartScheduled(final Entity entity) {
|
||||
+ org.bukkit.craftbukkit.entity.CraftEntity bukkitEntity = entity.getBukkitEntityRaw();
|
||||
+ if (bukkitEntity != null && bukkitEntity.taskScheduler.hasTask()) {
|
||||
+ this.scheduledEntities.add(bukkitEntity);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public void entityEndScheduled(final Entity entity) {
|
||||
+ if (entity.getBukkitEntityRaw() != null) {
|
||||
+ this.scheduledEntities.remove(entity.getBukkitEntityRaw());
|
||||
+ }
|
||||
+ }
|
||||
+ // Sakura end - tick entity schedulers only when necessary
|
||||
|
||||
public ServerEntityLookup(final ServerLevel world, final LevelCallback<Entity> worldCallback) {
|
||||
super(world, worldCallback);
|
||||
@@ -90,6 +106,7 @@ public final class ServerEntityLookup extends EntityLookup {
|
||||
// Moonrise start - entity tracker
|
||||
this.trackerEntities.add(entity);
|
||||
// Moonrise end - entity tracker
|
||||
+ this.entityStartScheduled(entity); // Sakura - tick entity schedulers only when necessary
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -97,6 +114,7 @@ public final class ServerEntityLookup extends EntityLookup {
|
||||
// Moonrise start - entity tracker
|
||||
this.trackerEntities.remove(entity);
|
||||
// Moonrise end - entity tracker
|
||||
+ this.entityEndScheduled(entity); // Sakura - tick entity schedulers only when necessary
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/io/papermc/paper/threadedregions/EntityScheduler.java b/src/main/java/io/papermc/paper/threadedregions/EntityScheduler.java
|
||||
index c03608fec96b51e1867f43d8f42e5aefb1520e46..32ac34e6ca4a7443e894369fee349911ebc1cf52 100644
|
||||
--- a/src/main/java/io/papermc/paper/threadedregions/EntityScheduler.java
|
||||
+++ b/src/main/java/io/papermc/paper/threadedregions/EntityScheduler.java
|
||||
@@ -50,6 +50,22 @@ public final class EntityScheduler {
|
||||
this.entity = Validate.notNull(entity);
|
||||
}
|
||||
|
||||
+ // Sakura start - tick entity schedulers only when necessary
|
||||
+ public boolean hasTask() {
|
||||
+ return !this.currentlyExecuting.isEmpty() || !this.oneTimeDelayed.isEmpty();
|
||||
+ }
|
||||
+
|
||||
+ private void newScheduledTask() {
|
||||
+ net.minecraft.server.MinecraftServer.getServer().scheduleOnMain(() -> {
|
||||
+ Entity handle = this.entity.getHandleRaw();
|
||||
+ net.minecraft.server.level.ServerLevel level = (net.minecraft.server.level.ServerLevel) handle.level();
|
||||
+ ca.spottedleaf.moonrise.patches.chunk_system.level.entity.server.ServerEntityLookup entityLookup = (ca.spottedleaf.moonrise.patches.chunk_system.level.entity.server.ServerEntityLookup) level.moonrise$getEntityLookup();
|
||||
+
|
||||
+ entityLookup.entityStartScheduled(handle);
|
||||
+ });
|
||||
+ }
|
||||
+ // Sakura end - tick entity schedulers only when necessary
|
||||
+
|
||||
/**
|
||||
* Retires the scheduler, preventing new tasks from being scheduled and invoking the retired callback
|
||||
* on all currently scheduled tasks.
|
||||
@@ -128,6 +144,7 @@ public final class EntityScheduler {
|
||||
return new ArrayList<>();
|
||||
}).add(task);
|
||||
}
|
||||
+ this.newScheduledTask(); // Sakura - tick entity schedulers only when necessary
|
||||
|
||||
return true;
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 56357e253247d19c108a7f753058fa3eba0302ee..c2c0cd8ae1afd90d9b08adec3cb127b13ce60331 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -1824,7 +1824,17 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
// Paper start - Folia scheduler API
|
||||
((io.papermc.paper.threadedregions.scheduler.FoliaGlobalRegionScheduler) Bukkit.getGlobalRegionScheduler()).tick();
|
||||
getAllLevels().forEach(level -> {
|
||||
- for (final Entity entity : level.getEntities().getAll()) {
|
||||
+ // Sakura start - tick entity schedulers only when necessary
|
||||
+ final ca.spottedleaf.moonrise.patches.chunk_system.level.entity.server.ServerEntityLookup entityLookup = (ca.spottedleaf.moonrise.patches.chunk_system.level.entity.server.ServerEntityLookup) level.moonrise$getEntityLookup();
|
||||
+ final Iterator<org.bukkit.craftbukkit.entity.CraftEntity> entityIterator = entityLookup.scheduledEntities.iterator();
|
||||
+ while (entityIterator.hasNext()) {
|
||||
+ final org.bukkit.craftbukkit.entity.CraftEntity scheduledEntity = entityIterator.next();
|
||||
+ final Entity entity = scheduledEntity.getHandle();
|
||||
+ if (!scheduledEntity.taskScheduler.hasTask()) {
|
||||
+ entityIterator.remove();
|
||||
+ continue;
|
||||
+ }
|
||||
+ // Sakura end - tick entity schedulers only when necessary
|
||||
if (entity.isRemoved()) {
|
||||
continue;
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samsuik <kfian294ma4@gmail.com>
|
||||
Date: Fri, 8 Nov 2024 19:35:49 +0000
|
||||
Subject: [PATCH] Optimise check inside blocks and traverse blocks
|
||||
|
||||
|
||||
diff --git a/src/main/java/me/samsuik/sakura/utils/BlockPosIterator.java b/src/main/java/me/samsuik/sakura/utils/BlockPosIterator.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..e00c07c614e007c007076e3dbe8bd8ccf6c6572d
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/me/samsuik/sakura/utils/BlockPosIterator.java
|
||||
@@ -0,0 +1,60 @@
|
||||
+package me.samsuik.sakura.utils;
|
||||
+
|
||||
+import com.google.common.collect.AbstractIterator;
|
||||
+import net.minecraft.core.BlockPos;
|
||||
+import net.minecraft.core.BlockPos.MutableBlockPos;
|
||||
+import net.minecraft.util.Mth;
|
||||
+import net.minecraft.world.phys.AABB;
|
||||
+import org.jspecify.annotations.NullMarked;
|
||||
+import org.jspecify.annotations.Nullable;
|
||||
+
|
||||
+@NullMarked
|
||||
+public final class BlockPosIterator extends AbstractIterator<BlockPos> {
|
||||
+ private final int startX;
|
||||
+ private final int startY;
|
||||
+ private final int startZ;
|
||||
+ private final int endX;
|
||||
+ private final int endY;
|
||||
+ private final int endZ;
|
||||
+ private @Nullable MutableBlockPos pos = null;
|
||||
+
|
||||
+ public static Iterable<BlockPos> iterable(AABB bb) {
|
||||
+ return () -> new BlockPosIterator(bb);
|
||||
+ }
|
||||
+
|
||||
+ public BlockPosIterator(AABB bb) {
|
||||
+ this.startX = Mth.floor(bb.minX);
|
||||
+ this.startY = Mth.floor(bb.minY);
|
||||
+ this.startZ = Mth.floor(bb.minZ);
|
||||
+ this.endX = Mth.floor(bb.maxX);
|
||||
+ this.endY = Mth.floor(bb.maxY);
|
||||
+ this.endZ = Mth.floor(bb.maxZ);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected BlockPos computeNext() {
|
||||
+ MutableBlockPos pos = this.pos;
|
||||
+ if (pos == null) {
|
||||
+ return this.pos = new MutableBlockPos(this.startX, this.startY, this.startZ);
|
||||
+ } else {
|
||||
+ int x = pos.getX();
|
||||
+ int y = pos.getY();
|
||||
+ int z = pos.getZ();
|
||||
+
|
||||
+ if (y < this.endY) {
|
||||
+ y += 1;
|
||||
+ } else if (x < this.endX) {
|
||||
+ x += 1;
|
||||
+ y = this.startY;
|
||||
+ } else if (z < this.endZ) {
|
||||
+ z += 1;
|
||||
+ x = this.startX;
|
||||
+ } else {
|
||||
+ return this.endOfData();
|
||||
+ }
|
||||
+
|
||||
+ pos.set(x, y, z);
|
||||
+ return pos;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index 95f4854ca21a6b34ad1ab95a1cb38f7d2dfd24c3..7d35952cdf48150f43b103b765358b7760411c9d 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -2061,6 +2061,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
}
|
||||
final Iterator iterator1 = positions.iterator();
|
||||
// Sakura end - physics version api
|
||||
+ // Sakura start - optimise check inside blocks
|
||||
+ int lastChunkX = Integer.MIN_VALUE;
|
||||
+ int lastChunkZ = Integer.MIN_VALUE;
|
||||
+ net.minecraft.world.level.chunk.ChunkAccess chunk = null;
|
||||
+ // Sakura end - optimise check inside blocks
|
||||
|
||||
while (iterator1.hasNext()) {
|
||||
BlockPos blockposition = (BlockPos) iterator1.next();
|
||||
@@ -2069,7 +2074,19 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
return;
|
||||
}
|
||||
|
||||
- BlockState iblockdata = this.level().getBlockState(blockposition);
|
||||
+ // Sakura start - optimise check inside blocks
|
||||
+ int chunkX = blockposition.getX() >> 4;
|
||||
+ int chunkZ = blockposition.getZ() >> 4;
|
||||
+ if (chunk == null || chunkX != lastChunkX || chunkZ != lastChunkZ) {
|
||||
+ chunk = this.level.getChunkIfLoadedImmediately(chunkX, chunkZ);
|
||||
+ if (chunk == null) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ lastChunkX = chunkX;
|
||||
+ lastChunkZ = chunkZ;
|
||||
+ }
|
||||
+ BlockState iblockdata = chunk.getBlockState(blockposition);
|
||||
+ // Sakura end - optimise check inside blocks
|
||||
|
||||
if (!iblockdata.isAir() && longset.add(blockposition.asLong())) {
|
||||
try {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/BlockGetter.java b/src/main/java/net/minecraft/world/level/BlockGetter.java
|
||||
index 62719778c62d6632a8eb6f2bc670956c15a247de..ecdb8769c1a388827bf5c4565c82f8e32672c5d7 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/BlockGetter.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/BlockGetter.java
|
||||
@@ -215,11 +215,18 @@ public interface BlockGetter extends LevelHeightAccessor {
|
||||
|
||||
static Iterable<BlockPos> boxTraverseBlocks(Vec3 oldPos, Vec3 newPos, AABB boundingBox) {
|
||||
Vec3 vec3d2 = newPos.subtract(oldPos);
|
||||
- Iterable<BlockPos> iterable = BlockPos.betweenClosed(boundingBox);
|
||||
-
|
||||
+ // Sakura start - optimise check inside blocks
|
||||
if (vec3d2.lengthSqr() < (double) Mth.square(0.99999F)) {
|
||||
- return iterable;
|
||||
+ return me.samsuik.sakura.utils.BlockPosIterator.iterable(boundingBox);
|
||||
} else {
|
||||
+ boolean xZero = vec3d2.x() == 0.0;
|
||||
+ boolean yZero = vec3d2.y() == 0.0;
|
||||
+ boolean zZero = vec3d2.z() == 0.0;
|
||||
+ if (xZero && yZero || yZero && zZero || xZero && zZero) {
|
||||
+ return traverseAreaFast(vec3d2, boundingBox);
|
||||
+ }
|
||||
+ Iterable<BlockPos> iterable = BlockPos.betweenClosed(boundingBox);
|
||||
+ // Sakura end - optimise check inside blocks
|
||||
Set<BlockPos> set = new ObjectLinkedOpenHashSet();
|
||||
Vec3 vec3d3 = boundingBox.getMinPosition();
|
||||
Vec3 vec3d4 = vec3d3.subtract(vec3d2);
|
||||
@@ -237,6 +244,16 @@ public interface BlockGetter extends LevelHeightAccessor {
|
||||
}
|
||||
}
|
||||
|
||||
+ // Sakura start - optimise check inside blocks
|
||||
+ private static Iterable<BlockPos> traverseAreaFast(Vec3 vec, AABB boundingBox) {
|
||||
+ double toTravel = Math.min(16.0 / vec.length(), 1.0);
|
||||
+ Vec3 movement = vec.scale(toTravel);
|
||||
+ AABB fromBB = boundingBox.move(-vec.x, -vec.y, -vec.z);
|
||||
+ AABB searchArea = fromBB.expandTowards(movement);
|
||||
+ return me.samsuik.sakura.utils.BlockPosIterator.iterable(searchArea);
|
||||
+ }
|
||||
+ // Sakura end - optimise check inside blocks
|
||||
+
|
||||
private static void addCollisionsAlongTravel(Set<BlockPos> result, Vec3 oldPos, Vec3 newPos, AABB boundingBox) {
|
||||
Vec3 vec3d2 = newPos.subtract(oldPos);
|
||||
int i = Mth.floor(oldPos.x);
|
||||
0
migrate/server/feature/applied/.ignore
Normal file
0
migrate/server/feature/applied/.ignore
Normal file
251
migrate/server/source/0002-Sakura-Utils.patch
Normal file
251
migrate/server/source/0002-Sakura-Utils.patch
Normal 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;
|
||||
+ }
|
||||
+}
|
||||
1309
migrate/server/source/0003-Sakura-Configuration-Files.patch
Normal file
1309
migrate/server/source/0003-Sakura-Configuration-Files.patch
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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) {
|
||||
@@ -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) {
|
||||
/*
|
||||
656
migrate/server/source/0008-Track-Tick-Information.patch
Normal file
656
migrate/server/source/0008-Track-Tick-Information.patch
Normal 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;
|
||||
58
migrate/server/source/0009-Optimise-New-Liquid-Level.patch
Normal file
58
migrate/server/source/0009-Optimise-New-Liquid-Level.patch
Normal 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);
|
||||
@@ -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) {
|
||||
@@ -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());
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
50
migrate/server/source/0021-Entity-pushed-by-fluid-API.patch
Normal file
50
migrate/server/source/0021-Entity-pushed-by-fluid-API.patch
Normal 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();
|
||||
88
migrate/server/source/0022-Cannon-Mechanics.patch
Normal file
88
migrate/server/source/0022-Cannon-Mechanics.patch
Normal 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() {
|
||||
@@ -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);
|
||||
45
migrate/server/source/0024-Optimise-TNT-fluid-state.patch
Normal file
45
migrate/server/source/0024-Optimise-TNT-fluid-state.patch
Normal 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;
|
||||
@@ -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);
|
||||
130
migrate/server/source/0028-Configure-Entity-Knockback.patch
Normal file
130
migrate/server/source/0028-Configure-Entity-Knockback.patch
Normal 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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
35
migrate/server/source/0034-Consistent-Explosion-Radius.patch
Normal file
35
migrate/server/source/0034-Consistent-Explosion-Radius.patch
Normal 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);
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
41
migrate/server/source/0039-Allow-water-in-the-nether.patch
Normal file
41
migrate/server/source/0039-Allow-water-in-the-nether.patch
Normal 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());
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
@@ -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));
|
||||
@@ -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());
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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))));
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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()) {
|
||||
@@ -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)) ||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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() {
|
||||
@@ -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;
|
||||
@@ -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
|
||||
46
migrate/server/source/0061-Mob-spawner-behaviour.patch
Normal file
46
migrate/server/source/0061-Mob-spawner-behaviour.patch
Normal 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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
258
migrate/server/source/0064-Legacy-player-combat-mechanics.patch
Normal file
258
migrate/server/source/0064-Legacy-player-combat-mechanics.patch
Normal 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) {
|
||||
@@ -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();
|
||||
@@ -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();
|
||||
88
migrate/server/source/0067-Old-enchanted-golden-apples.patch
Normal file
88
migrate/server/source/0067-Old-enchanted-golden-apples.patch
Normal 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)
|
||||
19
migrate/server/source/0068-Configure-fast-health-regen.patch
Normal file
19
migrate/server/source/0068-Configure-fast-health-regen.patch
Normal 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);
|
||||
@@ -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));
|
||||
@@ -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()));
|
||||
@@ -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() {
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
29
migrate/server/source/0078-Modify-bucket-stack-size.patch
Normal file
29
migrate/server/source/0078-Modify-bucket-stack-size.patch
Normal 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);
|
||||
23
migrate/server/source/0080-Configure-TNT-duplication.patch
Normal file
23
migrate/server/source/0080-Configure-TNT-duplication.patch
Normal 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
|
||||
64
migrate/server/source/0081-Add-lava-flow-speed-api.patch
Normal file
64
migrate/server/source/0081-Add-lava-flow-speed-api.patch
Normal 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;
|
||||
65
migrate/server/source/applied/0001-Branding-changes.patch
Normal file
65
migrate/server/source/applied/0001-Branding-changes.patch
Normal 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) {
|
||||
@@ -0,0 +1,427 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
|
||||
Date: Thu, 16 Nov 2023 13:38:06 +0000
|
||||
Subject: [PATCH] Cache Vanillia and Eigen Redstone
|
||||
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/util/RedstoneWireTurbo.java b/src/main/java/com/destroystokyo/paper/util/RedstoneWireTurbo.java
|
||||
index 9f17170179cc99d84ad25a1e838aff3d8cc66f93..a1fb1e286d66dde55682d899ded0e5d24715b642 100644
|
||||
--- a/src/main/java/com/destroystokyo/paper/util/RedstoneWireTurbo.java
|
||||
+++ b/src/main/java/com/destroystokyo/paper/util/RedstoneWireTurbo.java
|
||||
@@ -662,6 +662,7 @@ public class RedstoneWireTurbo {
|
||||
// restores old behavior, at the cost of bypassing the
|
||||
// max-chained-neighbor-updates server property.
|
||||
worldIn.getBlockState(upd.self).handleNeighborChanged(worldIn, upd.self, wire, upd.parent, false);
|
||||
+ worldIn.redstoneTracker.trackUpdate(upd.self, upd.currentState, upd.parent); // Sakura
|
||||
}
|
||||
}
|
||||
|
||||
@@ -777,6 +778,17 @@ public class RedstoneWireTurbo {
|
||||
// already on-going graph walk being performed by breadthFirstWalk.
|
||||
return scheduleReentrantNeighborChanged(worldIn, pos, newState, source);
|
||||
}
|
||||
+
|
||||
+ // Sakura start
|
||||
+ int oldPower = state.getValue(RedStoneWireBlock.POWER);
|
||||
+ int newPower = newState.getValue(RedStoneWireBlock.POWER);
|
||||
+ if (worldIn.redstoneTracker.applyFromCache(pos, oldPower, newPower)) {
|
||||
+ return newState;
|
||||
+ } else {
|
||||
+ worldIn.redstoneTracker.beginTracking(pos, oldPower, newPower);
|
||||
+ }
|
||||
+ // Sakura end
|
||||
+
|
||||
// If there are no on-going walks through redstone wire, then start a new walk.
|
||||
|
||||
// If the source of the block update to the redstone wire at 'pos' is known, we can use
|
||||
@@ -806,6 +818,8 @@ public class RedstoneWireTurbo {
|
||||
// updates in a breadth first order out from the initial update received for the block at 'pos'.
|
||||
breadthFirstWalk(worldIn);
|
||||
|
||||
+ worldIn.redstoneTracker.endTracking(); // Sakura - we're done with the breadth walk
|
||||
+
|
||||
// With the whole search completed, clear the list of all known blocks.
|
||||
// We do not want to keep around state information that may be changed by other code.
|
||||
// In theory, we could cache the neighbor block positions, but that is a separate
|
||||
@@ -913,6 +927,7 @@ public class RedstoneWireTurbo {
|
||||
// bypass the new neighbor update stack.
|
||||
if (worldIn.setBlock(upd.self, state, Block.UPDATE_KNOWN_SHAPE | Block.UPDATE_CLIENTS))
|
||||
updateNeighborShapes(worldIn, upd.self, state);
|
||||
+ worldIn.redstoneTracker.trackState(upd.self, state); // Sakura
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/me/samsuik/sakura/redstone/RedstoneTracker.java b/src/main/java/me/samsuik/sakura/redstone/RedstoneTracker.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..2e322ac7c8751ab4586fcce7974c26dacad18e4a
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/me/samsuik/sakura/redstone/RedstoneTracker.java
|
||||
@@ -0,0 +1,285 @@
|
||||
+package me.samsuik.sakura.redstone;
|
||||
+
|
||||
+import it.unimi.dsi.fastutil.HashCommon;
|
||||
+import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
|
||||
+import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||
+import it.unimi.dsi.fastutil.longs.Long2ObjectMaps;
|
||||
+import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
+import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
|
||||
+import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
+import me.samsuik.sakura.utils.objects.Expiry;
|
||||
+import net.minecraft.core.BlockPos;
|
||||
+import net.minecraft.core.Direction;
|
||||
+import net.minecraft.server.MinecraftServer;
|
||||
+import net.minecraft.world.level.Level;
|
||||
+import net.minecraft.world.level.block.*;
|
||||
+import net.minecraft.world.level.block.state.BlockState;
|
||||
+import net.minecraft.world.level.redstone.InstantNeighborUpdater;
|
||||
+import net.minecraft.world.level.redstone.NeighborUpdater;
|
||||
+
|
||||
+import java.util.ArrayList;
|
||||
+import java.util.List;
|
||||
+import java.util.function.Predicate;
|
||||
+
|
||||
+public final class RedstoneTracker {
|
||||
+
|
||||
+ private static final int DEPTH_LIMIT = 512;
|
||||
+
|
||||
+ // this is a fucking horrible hack, you could make a method in block
|
||||
+ // then override it but that is far more work than I am willing right now.
|
||||
+ private static final Predicate<Block> TECHNICAL_BLOCK = (block) -> {
|
||||
+ return block instanceof BaseEntityBlock
|
||||
+ || block instanceof DirectionalBlock
|
||||
+ || block instanceof HorizontalDirectionalBlock
|
||||
+ || block instanceof GameMasterBlock
|
||||
+ || block instanceof BaseRailBlock // rails themselves don't require it but it's variants do
|
||||
+ || block instanceof NoteBlock
|
||||
+ || block instanceof DoorBlock
|
||||
+ || block instanceof RedstoneLampBlock
|
||||
+ || block instanceof RedstoneTorchBlock
|
||||
+ || block instanceof RedStoneWireBlock; // required to update any nearby redstone that isn't the line currently being tested
|
||||
+ };
|
||||
+
|
||||
+ private final Level level;
|
||||
+ private final InstantNeighborUpdater updater;
|
||||
+ private final Long2ObjectOpenHashMap<RedstoneCache> wireCaches = new Long2ObjectOpenHashMap<>();
|
||||
+ // important locations, wires and adjacent
|
||||
+ private final Long2ObjectMap<List<RedstoneCache>> adjacent = new Long2ObjectOpenHashMap<>();
|
||||
+ // last block of physics
|
||||
+ private final Long2ObjectMap<List<RedstoneCache>> updates = new Long2ObjectOpenHashMap<>();
|
||||
+
|
||||
+ private ConnectedWires tracking;
|
||||
+ private int depth = 0;
|
||||
+
|
||||
+ public RedstoneTracker(Level level) {
|
||||
+ this.level = level;
|
||||
+ this.updater = new InstantNeighborUpdater(level);
|
||||
+ }
|
||||
+
|
||||
+ private static long cacheKey(BlockPos position, int previous, int next) {
|
||||
+ int powerState = 1 + previous + (next * 31); // previous and next only go up to 15
|
||||
+ long powerHash = HashCommon.murmurHash3((long) powerState); // long for a better hash
|
||||
+ return position.asLong() ^ powerHash;
|
||||
+ }
|
||||
+
|
||||
+ private boolean stillValid(BlockPos position, BlockState previous, BlockState next) {
|
||||
+ return previous.getBlock() == next.getBlock() || previous.isSignalSource() == next.isSignalSource()
|
||||
+ && previous.isRedstoneConductor(this.level, position) == next.isRedstoneConductor(this.level, position);
|
||||
+ }
|
||||
+
|
||||
+ public void updateNeighbors(BlockPos position, Block self) {
|
||||
+ this.updater.updateNeighborsAtExceptFromFacing(position, self, null);
|
||||
+ }
|
||||
+
|
||||
+ public boolean applyFromCache(BlockPos position, int previous, int next) {
|
||||
+ if (this.level.localConfig().config(position).redstoneCache && this.depth == 0) {
|
||||
+ long key = cacheKey(position, previous, next);
|
||||
+ RedstoneCache cache = this.wireCaches.get(key);
|
||||
+
|
||||
+ if (cache != null && !cache.expiry().isExpired(MinecraftServer.currentTick)) {
|
||||
+ cache.apply(this.level);
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ public void invalidate(BlockPos position, BlockState previous, BlockState next) {
|
||||
+ if (!this.stillValid(position, previous, next)) {
|
||||
+ long packed = position.asLong();
|
||||
+ this.invalidate(this.adjacent.get(packed));
|
||||
+
|
||||
+ if (TECHNICAL_BLOCK.test(next.getBlock())) {
|
||||
+ this.invalidate(this.updates.get(packed));
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private void invalidate(List<RedstoneCache> caches) {
|
||||
+ if (caches != null) {
|
||||
+ caches.forEach(cache -> cache.expiry().refresh(-200));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public void trackState(BlockPos position, BlockState state) {
|
||||
+ if (this.tracking != null) {
|
||||
+ this.tracking.wireUpdate(position, state);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public void trackUpdates(BlockPos position, Block block) {
|
||||
+ if (this.tracking != null) {
|
||||
+ this.tracking.updateNeighbors(position, block);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public void trackUpdate(BlockPos position, BlockState state, BlockPos parent) {
|
||||
+ if (this.tracking != null) {
|
||||
+ this.tracking.updates().put(position.asLong(), new UpdateState(state.getBlock(), parent));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public boolean isTracked(BlockPos position) {
|
||||
+ List<RedstoneCache> wires = this.adjacent.get(position.asLong());
|
||||
+ return wires != null && wires.stream().anyMatch(cache -> !cache.expiry().isExpired(MinecraftServer.currentTick));
|
||||
+ }
|
||||
+
|
||||
+ public boolean isTracking() {
|
||||
+ return this.tracking != null && this.depth != 0 && this.depth < DEPTH_LIMIT;
|
||||
+ }
|
||||
+
|
||||
+ public void beginTracking(BlockPos position, int previous, int next) {
|
||||
+ if (this.level.localConfig().config(position).redstoneCache && ++this.depth == 1) {
|
||||
+ long key = cacheKey(position, previous, next);
|
||||
+
|
||||
+ if (this.wireCaches.containsKey(key)) {
|
||||
+ return; // cache already exists
|
||||
+ }
|
||||
+
|
||||
+ this.tracking = new ConnectedWires(
|
||||
+ position, key,
|
||||
+ new Object2ObjectOpenHashMap<>(),
|
||||
+ new Long2ObjectLinkedOpenHashMap<>()
|
||||
+ );
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public void endTracking() {
|
||||
+ if (this.depth > 0 && --this.depth == 0 && this.tracking != null) {
|
||||
+ this.createRedstoneCache();
|
||||
+ this.tracking = null;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private void createRedstoneCache() {
|
||||
+ ConnectedWires connected = this.tracking;
|
||||
+ List<RedstoneUpdate> updates = new ArrayList<>(connected.updates().size() / 2);
|
||||
+
|
||||
+ Long2ObjectMaps.fastForEach(connected.updates(), entry -> {
|
||||
+ BlockPos position = BlockPos.of(entry.getLongKey());
|
||||
+ UpdateState update = entry.getValue();
|
||||
+
|
||||
+ // do not update wires that are connected
|
||||
+ if (connected.wires().containsKey(position)) return;
|
||||
+
|
||||
+ // filter out blocks that do not need updates
|
||||
+ BlockState state = this.level.getBlockState(position);
|
||||
+ if (TECHNICAL_BLOCK.test(state.getBlock())) {
|
||||
+ updates.add(new RedstoneUpdate(position, state, update));
|
||||
+ }
|
||||
+ });
|
||||
+
|
||||
+ List<RedstoneWire> wires = new ArrayList<>(connected.wires().size());
|
||||
+
|
||||
+ connected.wires().forEach((pos, state) -> {
|
||||
+ // is it even worth taking the hit here
|
||||
+ boolean shapeUpdate = updates.stream()
|
||||
+ .filter(update -> update.state().is(Blocks.OBSERVER))
|
||||
+ .anyMatch(update -> pos.distManhattan(update.position()) == 1);
|
||||
+
|
||||
+ wires.add(new RedstoneWire(pos, state, shapeUpdate));
|
||||
+ });
|
||||
+
|
||||
+ RedstoneCache redstoneCache = new RedstoneCache(
|
||||
+ wires, updates, connected,
|
||||
+ new Expiry(MinecraftServer.currentTick, 200)
|
||||
+ );
|
||||
+
|
||||
+ // put the newly created redstone cache into use
|
||||
+ this.wireCaches.put(connected.key(), redstoneCache);
|
||||
+
|
||||
+ // used for cache invalidation
|
||||
+ connected.updates().keySet().forEach(update -> {
|
||||
+ BlockPos position = BlockPos.of(update);
|
||||
+
|
||||
+ if (wires.stream().anyMatch(wire -> wire.position().distManhattan(position) == 1)) {
|
||||
+ this.adjacent.computeIfAbsent(update, key -> new ArrayList<>(1))
|
||||
+ .add(redstoneCache);
|
||||
+ } else {
|
||||
+ this.updates.computeIfAbsent(update, key -> new ArrayList<>(1))
|
||||
+ .add(redstoneCache);
|
||||
+ }
|
||||
+ });
|
||||
+
|
||||
+ wires.forEach(wire -> {
|
||||
+ this.adjacent.computeIfAbsent(wire.position().asLong(), key -> new ArrayList<>(1))
|
||||
+ .add(redstoneCache);
|
||||
+ });
|
||||
+ }
|
||||
+
|
||||
+ public void expire(int tick) {
|
||||
+ if (tick % 100 != 0) return;
|
||||
+
|
||||
+ this.wireCaches.values().removeIf(cache -> {
|
||||
+ if (cache.expiry().isExpired(tick)) {
|
||||
+ removeExpiredCache(cache);
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ return false;
|
||||
+ });
|
||||
+ }
|
||||
+
|
||||
+ private void removeExpiredCache(RedstoneCache cache) {
|
||||
+ cache.connected().updates().keySet().forEach(update -> {
|
||||
+ this.removeFromCaches(update, cache);
|
||||
+ });
|
||||
+
|
||||
+ cache.connected().wires().keySet().forEach(wire -> {
|
||||
+ this.removeFromCaches(wire.asLong(), cache);
|
||||
+ });
|
||||
+ }
|
||||
+
|
||||
+ private void removeFromCaches(long packed, RedstoneCache cache) {
|
||||
+ this.removeCache(this.adjacent, packed, cache);
|
||||
+ this.removeCache(this.updates, packed, cache);
|
||||
+ }
|
||||
+
|
||||
+ private void removeCache(Long2ObjectMap<List<RedstoneCache>> locationMap, long packed, RedstoneCache cache) {
|
||||
+ List<RedstoneCache> caches = locationMap.get(packed);
|
||||
+
|
||||
+ // in case something goes wrong
|
||||
+ if (caches == null) return;
|
||||
+
|
||||
+ caches.remove(cache);
|
||||
+
|
||||
+ if (caches.isEmpty()) {
|
||||
+ locationMap.remove(packed);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private record UpdateState(Block block, BlockPos position) {}
|
||||
+ private record RedstoneWire(BlockPos position, BlockState state, boolean shapeUpdate) {}
|
||||
+ private record RedstoneUpdate(BlockPos position, BlockState state, UpdateState parent) {}
|
||||
+
|
||||
+ private record RedstoneCache(List<RedstoneWire> wires, List<RedstoneUpdate> updates, ConnectedWires connected, Expiry expiry) {
|
||||
+ public void apply(Level level) {
|
||||
+ // Apply cached wire changes
|
||||
+ wires.forEach(wire -> level.setBlock(wire.position(), wire.state(), wire.shapeUpdate() ? 2 : 18));
|
||||
+
|
||||
+ // Now update the neighbors. We have to do this after applying wire changes
|
||||
+ // in case the block we're affecting here, checks the surrounding power level.
|
||||
+ updates.forEach(update -> {
|
||||
+ level.neighborChanged(update.position(), update.parent().block(), update.parent().position());
|
||||
+ });
|
||||
+
|
||||
+ // Refresh so the cache won't expire
|
||||
+ expiry.refresh(MinecraftServer.currentTick);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private record ConnectedWires(BlockPos source, long key, Object2ObjectMap<BlockPos, BlockState> wires, Long2ObjectMap<UpdateState> updates) {
|
||||
+ public void updateNeighbors(BlockPos position, Block block) {
|
||||
+ for (Direction direction : NeighborUpdater.UPDATE_ORDER) {
|
||||
+ BlockPos neighbor = position.relative(direction);
|
||||
+ this.updates.put(neighbor.asLong(), new UpdateState(block, position));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public void wireUpdate(BlockPos position, BlockState state) {
|
||||
+ this.wires.put(position, state);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index 88aa465a4bc6ae79dbad8dc8ecc21345f70abf0b..d82d64c98fc7624dfcc86fcbf49cde108bb34ede 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -698,6 +698,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
public final me.samsuik.sakura.entity.merge.EntityMergeHandler mergeHandler = new me.samsuik.sakura.entity.merge.EntityMergeHandler(); // Sakura - merge cannon entities
|
||||
public final me.samsuik.sakura.explosion.density.BlockDensityCache densityCache = new me.samsuik.sakura.explosion.density.BlockDensityCache(); // Sakura - explosion density cache
|
||||
public final me.samsuik.sakura.explosion.durable.DurableBlockManager durabilityManager = new me.samsuik.sakura.explosion.durable.DurableBlockManager(); // Sakura - explosion durable blocks
|
||||
+ public final me.samsuik.sakura.redstone.RedstoneTracker redstoneTracker = new me.samsuik.sakura.redstone.RedstoneTracker(this); // Sakura - cache vanilla and eigen redstone
|
||||
|
||||
protected Level(WritableLevelData worlddatamutable, ResourceKey<Level> resourcekey, RegistryAccess iregistrycustom, Holder<DimensionType> holder, Supplier<ProfilerFiller> supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function<org.spigotmc.SpigotWorldConfig, io.papermc.paper.configuration.WorldConfiguration> paperWorldConfigCreator, Supplier<me.samsuik.sakura.configuration.WorldConfiguration> sakuraWorldConfigCreator, java.util.concurrent.Executor executor) { // Sakura - sakura configuration files// Paper - create paper world config & Anti-Xray
|
||||
this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot
|
||||
@@ -1077,6 +1078,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
} else {
|
||||
BlockState iblockdata2 = this.getBlockState(pos);
|
||||
|
||||
+ this.redstoneTracker.invalidate(pos, iblockdata1, state); // Sakura
|
||||
/*
|
||||
if (iblockdata2 == iblockdata) {
|
||||
if (iblockdata1 != iblockdata2) {
|
||||
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 c131734cad123a35456d18f8a161f77a4ac9ac99..88ddd1747d9786210e8faf412b3b0363df4bab43 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java
|
||||
@@ -381,7 +381,15 @@ public class RedStoneWireBlock extends Block {
|
||||
}
|
||||
if (oldPower != i) {
|
||||
// CraftBukkit end
|
||||
+ // Sakura start
|
||||
+ if (world.redstoneTracker.applyFromCache(pos, oldPower, i)) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ world.redstoneTracker.beginTracking(pos, oldPower, i);
|
||||
if (world.getBlockState(pos) == state) {
|
||||
+ world.redstoneTracker.trackState(pos, state.setValue(RedStoneWireBlock.POWER, i));
|
||||
+ // Sakura end
|
||||
world.setBlock(pos, (BlockState) state.setValue(RedStoneWireBlock.POWER, i), 2);
|
||||
}
|
||||
|
||||
@@ -402,8 +410,17 @@ public class RedStoneWireBlock extends Block {
|
||||
while (iterator.hasNext()) {
|
||||
BlockPos blockposition1 = (BlockPos) iterator.next();
|
||||
|
||||
- world.updateNeighborsAt(blockposition1, this);
|
||||
+ // Sakura start
|
||||
+ world.redstoneTracker.trackUpdates(blockposition1, this);
|
||||
+ if (world.redstoneTracker.isTracking()) {
|
||||
+ world.redstoneTracker.updateNeighbors(blockposition1, this);
|
||||
+ } else {
|
||||
+ world.updateNeighborsAt(blockposition1, this);
|
||||
+ }
|
||||
+ // Sakura end
|
||||
}
|
||||
+
|
||||
+ world.redstoneTracker.endTracking(); // Sakura
|
||||
}
|
||||
|
||||
}
|
||||
@@ -559,7 +576,22 @@ public class RedStoneWireBlock extends Block {
|
||||
if (this.shouldSignal && direction != Direction.DOWN) {
|
||||
int i = (Integer) state.getValue(RedStoneWireBlock.POWER);
|
||||
|
||||
- return i == 0 ? 0 : (direction != Direction.UP && !((RedstoneSide) this.getConnectionState(world, state, pos).getValue((Property) RedStoneWireBlock.PROPERTY_BY_DIRECTION.get(direction.getOpposite()))).isConnected() ? 0 : i);
|
||||
+ // Sakura start - use redstone cache to avoid recalculating wires
|
||||
+ if (i == 0) {
|
||||
+ return 0;
|
||||
+ } else if (direction == Direction.UP) {
|
||||
+ return i;
|
||||
+ } else {
|
||||
+ final BlockState wireState;
|
||||
+ if (world instanceof Level level && level.redstoneTracker.isTracked(pos)) {
|
||||
+ wireState = state; // cached wire
|
||||
+ } else {
|
||||
+ wireState = this.getConnectionState(world, state, pos);
|
||||
+ }
|
||||
+ return !((RedstoneSide) wireState.getValue((Property) RedStoneWireBlock.PROPERTY_BY_DIRECTION.get(direction.getOpposite()))).isConnected() ? 0 : i;
|
||||
+ }
|
||||
+ //return i == 0 ? 0 : (direction != Direction.UP && !((RedstoneSide) this.getConnectionState(world, state, pos).getValue((Property) RedStoneWireBlock.PROPERTY_BY_DIRECTION.get(direction.getOpposite()))).isConnected() ? 0 : i);
|
||||
+ // Sakura end - use redstone cache to avoid recalculating wires
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user