mirror of
https://github.com/Winds-Studio/Leaf.git
synced 2025-12-19 15:09:25 +00:00
Update changes from ver/1.21.4 branch
This commit is contained in:
58
.github/workflows/build-1215.yml
vendored
58
.github/workflows/build-1215.yml
vendored
@@ -1,4 +1,5 @@
|
||||
name: Build Leaf 1.21.5
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "dev/1.21.5" ]
|
||||
@@ -10,8 +11,6 @@ jobs:
|
||||
env:
|
||||
BUILD_NUMBER: ${{ github.run_number }}
|
||||
GRADLE_MEMORY: "-Xmx4g -XX:MaxMetaspaceSize=2g"
|
||||
outputs:
|
||||
build_number: ${{ env.BUILD_NUMBER }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@main
|
||||
@@ -82,16 +81,6 @@ jobs:
|
||||
- name: Create MojmapPaperclipJar
|
||||
run: ./gradlew createMojmapPaperclipJar --stacktrace --parallel --no-daemon
|
||||
|
||||
- name: Rename Paperclip JARs
|
||||
run: |
|
||||
mv leaf-server/build/libs/leaf-paperclip-1.21.5-R0.1-SNAPSHOT-mojmap.jar ./leaf-1.21.5-${{ env.BUILD_NUMBER }}.jar
|
||||
|
||||
- name: Upload Leaf as build artifact
|
||||
uses: actions/upload-artifact@main
|
||||
with:
|
||||
name: Leaf 1.21.5
|
||||
path: ./leaf-1.21.5-*.jar
|
||||
|
||||
- name: Prepare release notes and artifacts
|
||||
run: |
|
||||
chmod +x ./scripts/prepareRelease.sh
|
||||
@@ -101,6 +90,12 @@ jobs:
|
||||
GITHUB_REPO: ${{ github.repository }}
|
||||
BUILD_NUMBER: ${{ env.BUILD_NUMBER }}
|
||||
|
||||
- name: Upload Leaf
|
||||
uses: actions/upload-artifact@main
|
||||
with:
|
||||
name: Leaf 1.21.5
|
||||
path: ./leaf-1.21.5-${{ env.BUILD_NUMBER }}.jar
|
||||
|
||||
- name: Release Leaf
|
||||
uses: softprops/action-gh-release@master
|
||||
with:
|
||||
@@ -112,3 +107,42 @@ jobs:
|
||||
target_commitish: "${{ github.sha }}"
|
||||
draft: false
|
||||
prerelease: true
|
||||
|
||||
- name: Calculate SHA-256
|
||||
id: hash
|
||||
run: |
|
||||
FILE_NAME="leaf-1.21.5-${{ env.BUILD_NUMBER }}.jar"
|
||||
HASH=$(sha256sum "$FILE_NAME" | awk '{ print $1 }')
|
||||
echo "sha256=$HASH" >> $GITHUB_OUTPUT
|
||||
- name: Upload JAR to download API
|
||||
uses: appleboy/scp-action@master
|
||||
with:
|
||||
host: ${{ secrets.API_HOST }}
|
||||
username: ${{ secrets.API_USER }}
|
||||
password: ${{ secrets.API_PASS }}
|
||||
source: "./leaf-1.21.5-${{ env.BUILD_NUMBER }}.jar"
|
||||
target: "~/api/uploads/"
|
||||
|
||||
- name: Insert build to download API
|
||||
uses: appleboy/ssh-action@master
|
||||
with:
|
||||
host: ${{ secrets.API_HOST }}
|
||||
username: ${{ secrets.API_USER }}
|
||||
password: ${{ secrets.API_PASS }}
|
||||
script: |
|
||||
BRANCH="${{ github.ref_name }}"
|
||||
REPO_DIR="/root/Leaf-${BRANCH//\//-}" # Replace slashes with dashes to avoid directory issues
|
||||
[ -d "$REPO_DIR/.git" ] && cd "$REPO_DIR" && git fetch origin && git checkout "$BRANCH" && git reset --hard "origin/$BRANCH" || git clone --branch "$BRANCH" --depth 1 https://github.com/Winds-Studio/Leaf "$REPO_DIR"
|
||||
# Proceed to insert the build into the API
|
||||
cd ~/api/cli
|
||||
node insertBuild.js \
|
||||
--projectName leaf \
|
||||
--projectFriendlyName "Leaf" \
|
||||
--version 1.21.5 \
|
||||
--versionGroupName 1.21.5 \
|
||||
--versionName 1.21.5 \
|
||||
--build-number ${{ env.BUILD_NUMBER }} \
|
||||
--repositoryPath "$REPO_DIR" \
|
||||
--storagePath /root/api/storage \
|
||||
--download "primary:/root/api/uploads/leaf-1.21.5-${{ env.BUILD_NUMBER }}.jar:${{ steps.hash.outputs.sha256 }}" \
|
||||
--buildChannel default
|
||||
|
||||
4
.github/workflows/publish-api.yml
vendored
4
.github/workflows/publish-api.yml
vendored
@@ -1,7 +1,7 @@
|
||||
name: Publish API
|
||||
on:
|
||||
push:
|
||||
branches: [ "ver/1.21.4" ]
|
||||
branches: [ "dev/1.21.5" ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -44,7 +44,7 @@ jobs:
|
||||
- name: Build
|
||||
run: ./gradlew build -x test
|
||||
|
||||
- name: Publish API
|
||||
- name: Publish Maven API
|
||||
continue-on-error: true
|
||||
run: |
|
||||
./gradlew :leaf-api:publish
|
||||
|
||||
@@ -4,6 +4,7 @@ protected net.minecraft.world.entity.Entity dimensions
|
||||
protected net.minecraft.world.entity.ai.goal.RemoveBlockGoal blockToRemove
|
||||
protected net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal getTargetConditions()Lnet/minecraft/world/entity/ai/targeting/TargetingConditions;
|
||||
protected-f net.minecraft.world.level.block.state.BlockBehaviour$BlockStateBase$Cache largeCollisionShape
|
||||
public net.minecraft.server.level.ServerEntity sendDirtyEntityData()V
|
||||
public net.minecraft.server.players.PlayerList SEND_PLAYER_INFO_INTERVAL
|
||||
public net.minecraft.util.Mth SIN
|
||||
public net.minecraft.world.entity.Entity blockPosition
|
||||
|
||||
@@ -1277,60 +1277,39 @@ index df142a89b8c43acb81eb383eac0ef048a1f49a6e..00000000000000000000000000000000
|
||||
- }
|
||||
-}
|
||||
diff --git a/src/main/java/co/aikar/timings/Timings.java b/src/main/java/co/aikar/timings/Timings.java
|
||||
deleted file mode 100644
|
||||
index 95b7cdf0677ef71e6885fa78aa5c75bb500f5f53..0000000000000000000000000000000000000000
|
||||
index 95b7cdf0677ef71e6885fa78aa5c75bb500f5f53..908b610bfdfe911675748211b74b809d9e0af3e5 100644
|
||||
--- a/src/main/java/co/aikar/timings/Timings.java
|
||||
+++ /dev/null
|
||||
@@ -1,325 +0,0 @@
|
||||
-/*
|
||||
- * This file is licensed under the MIT License (MIT).
|
||||
- *
|
||||
- * Copyright (c) 2014 Daniel Ennis <http://aikar.co>
|
||||
- *
|
||||
- * Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
- * of this software and associated documentation files (the "Software"), to deal
|
||||
- * in the Software without restriction, including without limitation the rights
|
||||
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
- * copies of the Software, and to permit persons to whom the Software is
|
||||
- * furnished to do so, subject to the following conditions:
|
||||
- *
|
||||
- * The above copyright notice and this permission notice shall be included in
|
||||
- * all copies or substantial portions of the Software.
|
||||
- *
|
||||
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
- * THE SOFTWARE.
|
||||
- */
|
||||
-package co.aikar.timings;
|
||||
-
|
||||
+++ b/src/main/java/co/aikar/timings/Timings.java
|
||||
@@ -23,303 +23,48 @@
|
||||
*/
|
||||
package co.aikar.timings;
|
||||
|
||||
-import com.google.common.base.Preconditions;
|
||||
-import com.google.common.collect.EvictingQueue;
|
||||
-import com.google.common.collect.Lists;
|
||||
-import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.Component;
|
||||
-import net.kyori.adventure.text.event.ClickEvent;
|
||||
-import net.kyori.adventure.text.format.TextColor;
|
||||
-import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||
-import org.bukkit.Bukkit;
|
||||
-import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.CommandSender;
|
||||
-import org.bukkit.plugin.Plugin;
|
||||
-
|
||||
|
||||
-import java.util.List;
|
||||
-import java.util.Queue;
|
||||
-import java.util.logging.Level;
|
||||
-import org.jetbrains.annotations.NotNull;
|
||||
-import org.jetbrains.annotations.Nullable;
|
||||
-
|
||||
-/**
|
||||
- * @deprecated Timings will be removed in the future
|
||||
- */
|
||||
-@Deprecated(forRemoval = true)
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
+// Leaf start - Remove Timings
|
||||
/**
|
||||
* @deprecated Timings will be removed in the future
|
||||
+ * Keep this class for plugin compatibility (detect usage)
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
-@SuppressWarnings({"UnusedDeclaration", "WeakerAccess", "SameParameterValue"})
|
||||
-public final class Timings {
|
||||
-
|
||||
public final class Timings {
|
||||
|
||||
- final static List<CommandSender> requestingReport = Lists.newArrayList();
|
||||
- private static final int MAX_HISTORY_FRAMES = 12;
|
||||
- public static final Timing NULL_HANDLER = new NullTimingHandler();
|
||||
@@ -1340,8 +1319,8 @@ index 95b7cdf0677ef71e6885fa78aa5c75bb500f5f53..00000000000000000000000000000000
|
||||
- private static int historyLength = -1;
|
||||
- private static boolean warnedAboutDeprecationOnEnable;
|
||||
-
|
||||
- private Timings() {}
|
||||
-
|
||||
private Timings() {}
|
||||
|
||||
- /**
|
||||
- * Returns a Timing for a plugin corresponding to a name.
|
||||
- *
|
||||
@@ -1417,9 +1396,10 @@ index 95b7cdf0677ef71e6885fa78aa5c75bb500f5f53..00000000000000000000000000000000
|
||||
- *
|
||||
- * @return Enabled or not
|
||||
- */
|
||||
- public static boolean isTimingsEnabled() {
|
||||
public static boolean isTimingsEnabled() {
|
||||
- return timingsEnabled;
|
||||
- }
|
||||
+ return false;
|
||||
}
|
||||
-
|
||||
- /**
|
||||
- * <p>Sets whether or not the Spigot Timings system should be enabled</p>
|
||||
@@ -1428,14 +1408,14 @@ index 95b7cdf0677ef71e6885fa78aa5c75bb500f5f53..00000000000000000000000000000000
|
||||
- *
|
||||
- * @param enabled Should timings be reported
|
||||
- */
|
||||
- public static void setTimingsEnabled(boolean enabled) {
|
||||
public static void setTimingsEnabled(boolean enabled) {
|
||||
- if (enabled && !warnedAboutDeprecationOnEnable) {
|
||||
- Bukkit.getLogger().severe(PlainTextComponentSerializer.plainText().serialize(deprecationMessage()));
|
||||
- warnedAboutDeprecationOnEnable = true;
|
||||
- }
|
||||
- }
|
||||
}
|
||||
-
|
||||
- public static Component deprecationMessage() {
|
||||
public static Component deprecationMessage() {
|
||||
- return Component.text()
|
||||
- .color(TextColor.color(0xffc93a))
|
||||
- .append(Component.text("[!] The timings profiler is in no-op mode and will be fully removed in a later update."))
|
||||
@@ -1450,7 +1430,8 @@ index 95b7cdf0677ef71e6885fa78aa5c75bb500f5f53..00000000000000000000000000000000
|
||||
- .clickEvent(ClickEvent.openUrl("https://github.com/PaperMC/Paper/discussions/10565")))
|
||||
- )
|
||||
- .build();
|
||||
- }
|
||||
+ return Component.empty();
|
||||
}
|
||||
-
|
||||
- /**
|
||||
- * <p>Sets whether or not the Timings should monitor at Verbose level.</p>
|
||||
@@ -1459,9 +1440,10 @@ index 95b7cdf0677ef71e6885fa78aa5c75bb500f5f53..00000000000000000000000000000000
|
||||
- *
|
||||
- * @return Enabled or not
|
||||
- */
|
||||
- public static boolean isVerboseTimingsEnabled() {
|
||||
public static boolean isVerboseTimingsEnabled() {
|
||||
- return verboseEnabled;
|
||||
- }
|
||||
+ return false;
|
||||
}
|
||||
-
|
||||
- /**
|
||||
- * <p>Sets whether or not the Timings should monitor at Verbose level.</p>
|
||||
@@ -1471,10 +1453,10 @@ index 95b7cdf0677ef71e6885fa78aa5c75bb500f5f53..00000000000000000000000000000000
|
||||
- *
|
||||
- * @param enabled Should high-frequency timings be reported
|
||||
- */
|
||||
- public static void setVerboseTimingsEnabled(boolean enabled) {
|
||||
public static void setVerboseTimingsEnabled(boolean enabled) {
|
||||
- verboseEnabled = enabled;
|
||||
- TimingsManager.needsRecheckEnabled = true;
|
||||
- }
|
||||
}
|
||||
-
|
||||
- /**
|
||||
- * <p>Gets the interval between Timing History report generation.</p>
|
||||
@@ -1483,9 +1465,10 @@ index 95b7cdf0677ef71e6885fa78aa5c75bb500f5f53..00000000000000000000000000000000
|
||||
- *
|
||||
- * @return Interval in ticks
|
||||
- */
|
||||
- public static int getHistoryInterval() {
|
||||
public static int getHistoryInterval() {
|
||||
- return historyInterval;
|
||||
- }
|
||||
+ return 0;
|
||||
}
|
||||
-
|
||||
- /**
|
||||
- * <p>Sets the interval between Timing History report generations.</p>
|
||||
@@ -1497,13 +1480,13 @@ index 95b7cdf0677ef71e6885fa78aa5c75bb500f5f53..00000000000000000000000000000000
|
||||
- *
|
||||
- * @param interval Interval in ticks
|
||||
- */
|
||||
- public static void setHistoryInterval(int interval) {
|
||||
public static void setHistoryInterval(int interval) {
|
||||
- historyInterval = Math.max(20*60, interval);
|
||||
- // Recheck the history length with the new Interval
|
||||
- if (historyLength != -1) {
|
||||
- setHistoryLength(historyLength);
|
||||
- }
|
||||
- }
|
||||
}
|
||||
-
|
||||
- /**
|
||||
- * Gets how long in ticks Timings history is kept for the server.
|
||||
@@ -1512,9 +1495,10 @@ index 95b7cdf0677ef71e6885fa78aa5c75bb500f5f53..00000000000000000000000000000000
|
||||
- *
|
||||
- * @return Duration in Ticks
|
||||
- */
|
||||
- public static int getHistoryLength() {
|
||||
public static int getHistoryLength() {
|
||||
- return historyLength;
|
||||
- }
|
||||
+ return 0;
|
||||
}
|
||||
-
|
||||
- /**
|
||||
- * Sets how long Timing History reports are kept for the server.
|
||||
@@ -1527,7 +1511,7 @@ index 95b7cdf0677ef71e6885fa78aa5c75bb500f5f53..00000000000000000000000000000000
|
||||
- *
|
||||
- * @param length Duration in ticks
|
||||
- */
|
||||
- public static void setHistoryLength(int length) {
|
||||
public static void setHistoryLength(int length) {
|
||||
- // Cap at 12 History Frames, 1 hour at 5 minute frames.
|
||||
- int maxLength = historyInterval * MAX_HISTORY_FRAMES;
|
||||
- // For special cases of servers with special permission to bypass the max.
|
||||
@@ -1544,14 +1528,14 @@ index 95b7cdf0677ef71e6885fa78aa5c75bb500f5f53..00000000000000000000000000000000
|
||||
- }
|
||||
- TimingsManager.HISTORY = EvictingQueue.create(frames);
|
||||
- TimingsManager.HISTORY.addAll(oldQueue);
|
||||
- }
|
||||
}
|
||||
-
|
||||
- /**
|
||||
- * Resets all Timing Data
|
||||
- */
|
||||
- public static void reset() {
|
||||
public static void reset() {
|
||||
- TimingsManager.reset();
|
||||
- }
|
||||
}
|
||||
-
|
||||
- /**
|
||||
- * Generates a report and sends it to the specified command sender.
|
||||
@@ -1559,7 +1543,7 @@ index 95b7cdf0677ef71e6885fa78aa5c75bb500f5f53..00000000000000000000000000000000
|
||||
- * If sender is null, ConsoleCommandSender will be used.
|
||||
- * @param sender The sender to send to, or null to use the ConsoleCommandSender
|
||||
- */
|
||||
- public static void generateReport(@Nullable CommandSender sender) {
|
||||
public static void generateReport(@Nullable CommandSender sender) {
|
||||
- if (sender == null) {
|
||||
- sender = Bukkit.getConsoleSender();
|
||||
- }
|
||||
@@ -1604,9 +1588,10 @@ index 95b7cdf0677ef71e6885fa78aa5c75bb500f5f53..00000000000000000000000000000000
|
||||
- @NotNull
|
||||
- static TimingHandler ofSafe(@Nullable String groupName, @NotNull String name, @Nullable Timing groupHandler) {
|
||||
- return TimingsManager.getHandler(groupName, name, groupHandler);
|
||||
- }
|
||||
-}
|
||||
-
|
||||
}
|
||||
+ // Leaf end - Remove Timings
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/co/aikar/timings/TimingsCommand.java b/src/main/java/co/aikar/timings/TimingsCommand.java
|
||||
deleted file mode 100644
|
||||
index b83e5ff7ada8771fdf27ba9807c77ba6a4ce12da..0000000000000000000000000000000000000000
|
||||
@@ -2831,37 +2816,6 @@ index 3e61a926620a67daec3af54b72a1b911eaef2ed4..00000000000000000000000000000000
|
||||
- return new MRUMapCache<K, V>(map);
|
||||
- }
|
||||
-}
|
||||
diff --git a/src/main/java/org/bukkit/command/BufferedCommandSender.java b/src/main/java/org/bukkit/command/BufferedCommandSender.java
|
||||
deleted file mode 100644
|
||||
index 45ed63797b13e114bf3795c80a6c3967d8eb2351..0000000000000000000000000000000000000000
|
||||
--- a/src/main/java/org/bukkit/command/BufferedCommandSender.java
|
||||
+++ /dev/null
|
||||
@@ -1,25 +0,0 @@
|
||||
-package org.bukkit.command;
|
||||
-
|
||||
-import org.jetbrains.annotations.NotNull;
|
||||
-
|
||||
-/**
|
||||
- * @deprecated Timings will be removed in the future
|
||||
- */
|
||||
-@Deprecated(forRemoval = true)
|
||||
-public class BufferedCommandSender implements MessageCommandSender {
|
||||
- private final StringBuffer buffer = new StringBuffer();
|
||||
- @Override
|
||||
- public void sendMessage(@NotNull String message) {
|
||||
- buffer.append(message);
|
||||
- buffer.append("\n");
|
||||
- }
|
||||
-
|
||||
- @NotNull
|
||||
- public String getBuffer() {
|
||||
- return buffer.toString();
|
||||
- }
|
||||
-
|
||||
- public void reset() {
|
||||
- this.buffer.setLength(0);
|
||||
- }
|
||||
-}
|
||||
diff --git a/src/main/java/org/bukkit/command/Command.java b/src/main/java/org/bukkit/command/Command.java
|
||||
index 27a7c69f23084e821d945d5e97e51a94ddd94e58..d645ee8470a2dd9f7b8eff2b7ff2211aba9c342f 100644
|
||||
--- a/src/main/java/org/bukkit/command/Command.java
|
||||
@@ -3017,38 +2971,15 @@ index ce45dbc7b02c405f1b3460563cf87e7888702ba9..c43ce5b7bed3297cd655a7f2ed4b4717
|
||||
}
|
||||
return ret;
|
||||
diff --git a/src/main/java/org/spigotmc/CustomTimingsHandler.java b/src/main/java/org/spigotmc/CustomTimingsHandler.java
|
||||
deleted file mode 100644
|
||||
index 5fbacfcf108432c5187aa9a4092d00d7d5b0fd53..0000000000000000000000000000000000000000
|
||||
index 5fbacfcf108432c5187aa9a4092d00d7d5b0fd53..68e2a332e512a4aea45b8fb33a6e34431548d3be 100644
|
||||
--- a/src/main/java/org/spigotmc/CustomTimingsHandler.java
|
||||
+++ /dev/null
|
||||
@@ -1,67 +0,0 @@
|
||||
-/*
|
||||
- * This file is licensed under the MIT License (MIT).
|
||||
- *
|
||||
- * Copyright (c) 2014 Daniel Ennis <http://aikar.co>
|
||||
- *
|
||||
- * Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
- * of this software and associated documentation files (the "Software"), to deal
|
||||
- * in the Software without restriction, including without limitation the rights
|
||||
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
- * copies of the Software, and to permit persons to whom the Software is
|
||||
- * furnished to do so, subject to the following conditions:
|
||||
- *
|
||||
- * The above copyright notice and this permission notice shall be included in
|
||||
- * all copies or substantial portions of the Software.
|
||||
- *
|
||||
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
- * THE SOFTWARE.
|
||||
- */
|
||||
-package org.spigotmc;
|
||||
-
|
||||
+++ b/src/main/java/org/spigotmc/CustomTimingsHandler.java
|
||||
@@ -23,45 +23,20 @@
|
||||
*/
|
||||
package org.spigotmc;
|
||||
|
||||
-import org.bukkit.Bukkit;
|
||||
-import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
-import org.bukkit.plugin.AuthorNagException;
|
||||
-import co.aikar.timings.Timing;
|
||||
-import co.aikar.timings.Timings;
|
||||
@@ -3056,20 +2987,23 @@ index 5fbacfcf108432c5187aa9a4092d00d7d5b0fd53..00000000000000000000000000000000
|
||||
-
|
||||
-import java.lang.reflect.Method;
|
||||
-import java.util.logging.Level;
|
||||
-
|
||||
-/**
|
||||
|
||||
+// Leaf start - Remove Timings
|
||||
/**
|
||||
- * This is here for legacy purposes incase any plugin used it.
|
||||
- *
|
||||
- * If you use this, migrate ASAP as this will be removed in the future!
|
||||
- *
|
||||
- * @deprecated
|
||||
- * @see co.aikar.timings.Timings#of
|
||||
- */
|
||||
-@Deprecated(forRemoval = true)
|
||||
-public final class CustomTimingsHandler {
|
||||
+ * @deprecated Timings will be removed in the future
|
||||
+ * Keep this class for plugin compatibility (detect usage)
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public final class CustomTimingsHandler {
|
||||
- private final Timing handler;
|
||||
-
|
||||
- public CustomTimingsHandler(@NotNull String name) {
|
||||
|
||||
public CustomTimingsHandler(@NotNull String name) {
|
||||
- Timing timing;
|
||||
-
|
||||
- new AuthorNagException("Deprecated use of CustomTimingsHandler. Timings has been removed.").printStackTrace();
|
||||
@@ -3083,12 +3017,15 @@ index 5fbacfcf108432c5187aa9a4092d00d7d5b0fd53..00000000000000000000000000000000
|
||||
- timing = Timings.NULL_HANDLER;
|
||||
- }
|
||||
- handler = timing;
|
||||
- }
|
||||
-
|
||||
}
|
||||
|
||||
- public void startTiming() { handler.startTiming(); }
|
||||
- public void stopTiming() { handler.stopTiming(); }
|
||||
-
|
||||
-}
|
||||
+ public void startTiming() {}
|
||||
+ public void stopTiming() {}
|
||||
+ // Leaf end - Remove Timings
|
||||
}
|
||||
diff --git a/src/test/java/org/bukkit/AnnotationTest.java b/src/test/java/org/bukkit/AnnotationTest.java
|
||||
index 37feafd626aaa17aba888d7ff13728b3c6f26d4d..e42619418c1a3e3dac22e7310bb9d64b42b9f6a7 100644
|
||||
--- a/src/test/java/org/bukkit/AnnotationTest.java
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Taiyou06 <kaandindar21@gmail.com>
|
||||
Date: Thu, 8 May 2025 00:05:01 +0200
|
||||
Subject: [PATCH] Save world async properly
|
||||
|
||||
Removed since Paper 1.21.4/5, added on Paper side
|
||||
|
||||
P.S from Tai: I've been using this fix for weeks in my own server but didn't had balls to push it as thought it may cause issues but, it's merged in paper 1.21.5 now.
|
||||
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index ba1dd51e7187a80e8438e46383257c22f5382130..6cb0c14cb7aa243bbee6ca9ba57da4cc6eafdfd8 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -1439,7 +1439,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
}
|
||||
|
||||
if (doFull) {
|
||||
- this.saveLevelData(true);
|
||||
+ this.saveLevelData(false); // Leaf - Save world async properly
|
||||
}
|
||||
// chunk autosave is already called by the ChunkSystem during unload processing (ChunkMap#processUnloads)
|
||||
// Copied from save()
|
||||
@@ -33,18 +33,18 @@ index c1130f596cf3443eeb62eb1b12587172fe0859ee..18590e0b1d94ee3266637c5f3ab65ead
|
||||
|
||||
@Override
|
||||
diff --git a/net/minecraft/world/inventory/AbstractContainerMenu.java b/net/minecraft/world/inventory/AbstractContainerMenu.java
|
||||
index e6419715fab462b12790ecb175ce1e1a1fceed8f..8a0d1aebad1f92c43112e279b9c5922fdd1fd432 100644
|
||||
index 3dcd8df0b395a8fed8bc0cbe0ff78f4ae0056fd3..cee7daa4908efde754442bf7ef0932b94cf5ebca 100644
|
||||
--- a/net/minecraft/world/inventory/AbstractContainerMenu.java
|
||||
+++ b/net/minecraft/world/inventory/AbstractContainerMenu.java
|
||||
@@ -306,7 +306,12 @@ public abstract class AbstractContainerMenu {
|
||||
|
||||
private void synchronizeCarriedToRemote() {
|
||||
if (!this.suppressRemoteUpdates) {
|
||||
- if (!this.matchesRemote(this.getCarried(), this.remoteCarried)) { // Paper - add flag to simplify remote matching logic
|
||||
- if (!ItemStack.matches(this.getCarried(), this.remoteCarried)) {
|
||||
+ // Leaf start - Hide specified item components - Avoid some frequent client animations
|
||||
+ final boolean matchResult = org.dreeam.leaf.config.modules.gameplay.HideItemComponent.enabled
|
||||
+ ? !org.dreeam.leaf.util.item.ItemStackStripper.matchesStripped(this.getCarried(), this.remoteCarried)
|
||||
+ : !this.matchesRemote(this.getCarried(), this.remoteCarried); // Paper - add flag to simplify remote matching logic
|
||||
+ : !ItemStack.matches(this.getCarried(), this.remoteCarried);
|
||||
+ if (matchResult) {
|
||||
+ // Leaf end - Hide specified item components - Avoid some frequent client animations
|
||||
this.remoteCarried = this.getCarried().copy();
|
||||
|
||||
@@ -568,7 +568,7 @@ index d4048661575ebfaf128ba25da365843774364e0e..33dd16a26edd2974f04d9a868d3e58e8
|
||||
|
||||
// Gale start - Pufferfish - SIMD support
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index ae5d3de44fb710b48fdabf04f5e706df1f9889b7..31abf2da10bc9b4b7825ed4b3d4e9da52feb2e39 100644
|
||||
index a66e5f6652d9633c856490de36d8d8fdf8a5298a..60e0296312030d25f917c568c17ce86d08e18122 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -182,7 +182,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
@@ -650,10 +650,10 @@ index ae5d3de44fb710b48fdabf04f5e706df1f9889b7..31abf2da10bc9b4b7825ed4b3d4e9da5
|
||||
// Paper start - extra debug info
|
||||
if (entity.valid) {
|
||||
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
|
||||
index fefaab58da149b082a4d1e3bed9ec84ae8488d45..9100da3fe4e478cea7198cb4e028fcefccb3eb3c 100644
|
||||
index 8362def0dc61496a087bd859052bd80ebba83185..09f517059aa47ca67329bc913243d4fdee09abe5 100644
|
||||
--- a/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -434,6 +434,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
@@ -427,6 +427,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
return this.viewDistanceHolder;
|
||||
}
|
||||
// Paper end - rewrite chunk system
|
||||
@@ -661,7 +661,7 @@ index fefaab58da149b082a4d1e3bed9ec84ae8488d45..9100da3fe4e478cea7198cb4e028fcef
|
||||
|
||||
public ServerPlayer(MinecraftServer server, ServerLevel level, GameProfile gameProfile, ClientInformation clientInformation) {
|
||||
super(level, level.getSharedSpawnPos(), level.getSharedSpawnAngle(), gameProfile);
|
||||
@@ -810,6 +811,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
@@ -803,6 +804,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
@@ -669,7 +669,7 @@ index fefaab58da149b082a4d1e3bed9ec84ae8488d45..9100da3fe4e478cea7198cb4e028fcef
|
||||
// CraftBukkit start
|
||||
if (this.joining) {
|
||||
this.joining = false;
|
||||
@@ -1455,6 +1457,8 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
@@ -1448,6 +1450,8 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
teleportTransition.postTeleportTransition().onTransition(this);
|
||||
return this;
|
||||
} else {
|
||||
@@ -678,7 +678,7 @@ index fefaab58da149b082a4d1e3bed9ec84ae8488d45..9100da3fe4e478cea7198cb4e028fcef
|
||||
// CraftBukkit start
|
||||
/*
|
||||
this.isChangingDimension = true;
|
||||
@@ -1826,6 +1830,12 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
@@ -1819,6 +1823,12 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
return OptionalInt.empty();
|
||||
} else {
|
||||
// CraftBukkit start
|
||||
@@ -691,7 +691,7 @@ index fefaab58da149b082a4d1e3bed9ec84ae8488d45..9100da3fe4e478cea7198cb4e028fcef
|
||||
this.containerMenu = abstractContainerMenu; // Moved up
|
||||
if (!this.isImmobile())
|
||||
this.connection
|
||||
@@ -1890,6 +1900,11 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
@@ -1883,6 +1893,11 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
}
|
||||
@Override
|
||||
public void closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason reason) {
|
||||
@@ -704,7 +704,7 @@ index fefaab58da149b082a4d1e3bed9ec84ae8488d45..9100da3fe4e478cea7198cb4e028fcef
|
||||
// Paper end - Inventory close reason
|
||||
this.connection.send(new ClientboundContainerClosePacket(this.containerMenu.containerId));
|
||||
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
|
||||
index b17c8a2f5294ac28cc05fb05c84a041b2c6c8721..0b8b4658dbbad1bacc13e97b4fc0cdcea7e36a06 100644
|
||||
index b17c8a2f5294ac28cc05fb05c84a041b2c6c8721..3591de34443069f3f163f8d17df6372c3068611d 100644
|
||||
--- a/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/net/minecraft/server/players/PlayerList.java
|
||||
@@ -252,6 +252,8 @@ public abstract class PlayerList {
|
||||
@@ -716,14 +716,12 @@ index b17c8a2f5294ac28cc05fb05c84a041b2c6c8721..0b8b4658dbbad1bacc13e97b4fc0cdce
|
||||
player.isRealPlayer = true; // Paper
|
||||
player.loginTime = System.currentTimeMillis(); // Paper - Replace OfflinePlayer#getLastPlayed
|
||||
GameProfile gameProfile = player.getGameProfile();
|
||||
@@ -891,6 +893,17 @@ public abstract class PlayerList {
|
||||
@@ -891,6 +893,15 @@ public abstract class PlayerList {
|
||||
return this.respawn(player, keepInventory, reason, eventReason, null);
|
||||
}
|
||||
public ServerPlayer respawn(ServerPlayer player, boolean keepInventory, Entity.RemovalReason reason, org.bukkit.event.player.PlayerRespawnEvent.RespawnReason eventReason, org.bukkit.Location location) {
|
||||
+ // Leaf start - SparklyPaper - parallel world ticking mod (make configurable)
|
||||
+ if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled) {
|
||||
+ // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||
+ System.out.println("respawning player - current player container is " + player.containerMenu + " but their inventory is " + player.inventoryMenu);
|
||||
+ if (location != null) // Leaf - THIS CAN BE NULL; see PlayerList::respawn(ServerPlayer, boolean, Entity.RemovalReason, PlayerRespawnEvent.RespawnReason)
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureOnlyTickThread("Cannot respawn player off-main, from world " + player.serverLevel().getWorld().getName() + " to world " + location.getWorld().getName());
|
||||
+ else
|
||||
@@ -734,7 +732,7 @@ index b17c8a2f5294ac28cc05fb05c84a041b2c6c8721..0b8b4658dbbad1bacc13e97b4fc0cdce
|
||||
player.stopRiding(); // CraftBukkit
|
||||
this.players.remove(player);
|
||||
this.playersByName.remove(player.getScoreboardName().toLowerCase(java.util.Locale.ROOT)); // Spigot
|
||||
@@ -902,6 +915,7 @@ public abstract class PlayerList {
|
||||
@@ -902,6 +913,7 @@ public abstract class PlayerList {
|
||||
ServerPlayer serverPlayer = player;
|
||||
Level fromWorld = player.level();
|
||||
player.wonGame = false;
|
||||
@@ -871,32 +869,48 @@ index 88b07fbb96b20124777889830afa480673629d43..f8bb32840129e57b7799f883cb4570d2
|
||||
+ // Leaf end - SparklyPaper - parallel world ticking mod (prevent clearing portal process)
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/ai/behavior/GoToPotentialJobSite.java b/net/minecraft/world/entity/ai/behavior/GoToPotentialJobSite.java
|
||||
index 3614551856c594f3c0cfee984fcf03fad672b007..1a41dd00a1ea4d0587d833c85545baf1b5f660d5 100644
|
||||
index 3614551856c594f3c0cfee984fcf03fad672b007..f4577f908ca9f279b72d89e5b0822d34b6fb7dd1 100644
|
||||
--- a/net/minecraft/world/entity/ai/behavior/GoToPotentialJobSite.java
|
||||
+++ b/net/minecraft/world/entity/ai/behavior/GoToPotentialJobSite.java
|
||||
@@ -46,12 +46,20 @@ public class GoToPotentialJobSite extends Behavior<Villager> {
|
||||
@@ -44,14 +44,34 @@ public class GoToPotentialJobSite extends Behavior<Villager> {
|
||||
Optional<GlobalPos> memory = entity.getBrain().getMemory(MemoryModuleType.POTENTIAL_JOB_SITE);
|
||||
memory.ifPresent(globalPos -> {
|
||||
BlockPos blockPos = globalPos.pos();
|
||||
ServerLevel level1 = level.getServer().getLevel(globalPos.dimension());
|
||||
if (level1 != null) {
|
||||
- ServerLevel level1 = level.getServer().getLevel(globalPos.dimension());
|
||||
- if (level1 != null) {
|
||||
- PoiManager poiManager = level1.getPoiManager();
|
||||
- if (poiManager.exists(blockPos, holder -> true)) {
|
||||
- poiManager.release(blockPos);
|
||||
- }
|
||||
+ // Leaf start - SparklyPaper - parallel world ticking mod (handling for navigating to potential job site cross-dimension)
|
||||
+ Runnable releasePoiTask = () -> {
|
||||
+ PoiManager poiManager = level1.getPoiManager();
|
||||
+ // Leaf start - SparklyPaper - parallel world ticking
|
||||
+ ServerLevel entityLevel = level; // Villager's current level
|
||||
+ ServerLevel poiLevel = entityLevel.getServer().getLevel(globalPos.dimension()); // POI's actual level
|
||||
+
|
||||
+ if (poiLevel != null) {
|
||||
+ Runnable poiOperationsTask = () -> {
|
||||
+ PoiManager poiManager = poiLevel.getPoiManager();
|
||||
+ if (poiManager.exists(blockPos, holder -> true)) {
|
||||
+ poiManager.release(blockPos);
|
||||
+ }
|
||||
+ };
|
||||
+
|
||||
+ // DebugPackets.sendPoiTicketCountPacket uses the entity's level for its PoiManager context.
|
||||
+ Runnable debugPacketTask = () -> {
|
||||
+ DebugPackets.sendPoiTicketCountPacket(entityLevel, blockPos);
|
||||
+ };
|
||||
|
||||
- DebugPackets.sendPoiTicketCountPacket(level, blockPos);
|
||||
+ DebugPackets.sendPoiTicketCountPacket(level, blockPos);
|
||||
+ };
|
||||
+ if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled)
|
||||
+ level.moonrise$getChunkTaskScheduler().scheduleChunkTask(0, 0, releasePoiTask, ca.spottedleaf.concurrentutil.util.Priority.BLOCKING);
|
||||
+ else
|
||||
+ releasePoiTask.run();
|
||||
+ // Leaf end - SparklyPaper - parallel world ticking mod (handling for navigating to potential job site cross-dimension)
|
||||
+ if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled) { // Added curly braces here
|
||||
+ // Schedule POI operations on the POI's level thread, using POI's chunk coordinates for locality
|
||||
+ poiLevel.moonrise$getChunkTaskScheduler().scheduleChunkTask(blockPos.getX() >> 4, blockPos.getZ() >> 4, poiOperationsTask, ca.spottedleaf.concurrentutil.util.Priority.BLOCKING);
|
||||
+ // Schedule debug packet on the entity's level thread, using entity's chunk coordinates for locality
|
||||
+ entityLevel.moonrise$getChunkTaskScheduler().scheduleChunkTask(entity.chunkPosition().x, entity.chunkPosition().z, debugPacketTask, ca.spottedleaf.concurrentutil.util.Priority.BLOCKING);
|
||||
+ }
|
||||
+ else { // PWT disabled, run inline on current (entity's) thread
|
||||
+ poiOperationsTask.run(); // This will use poiLevel's PoiManager but thread checks are permissive
|
||||
+ debugPacketTask.run(); // This will use entityLevel's PoiManager
|
||||
+ }
|
||||
+ // Leaf end - SparklyPaper - parallel world ticking
|
||||
}
|
||||
});
|
||||
entity.getBrain().eraseMemory(MemoryModuleType.POTENTIAL_JOB_SITE);
|
||||
@@ -1017,7 +1031,7 @@ index d212f57c8c0b2086f567fd30237b110203d9e8cb..ed4df82581b5411e54068ccc59ea85a7
|
||||
} else {
|
||||
Entity entity = owner.teleport(
|
||||
diff --git a/net/minecraft/world/inventory/AbstractContainerMenu.java b/net/minecraft/world/inventory/AbstractContainerMenu.java
|
||||
index 8a0d1aebad1f92c43112e279b9c5922fdd1fd432..d4fc9466d61a680b85859965a8f7dc795b8c7130 100644
|
||||
index cee7daa4908efde754442bf7ef0932b94cf5ebca..ff2ff95ec9d94e2e31e8174196b384c37d56f38a 100644
|
||||
--- a/net/minecraft/world/inventory/AbstractContainerMenu.java
|
||||
+++ b/net/minecraft/world/inventory/AbstractContainerMenu.java
|
||||
@@ -92,8 +92,14 @@ public abstract class AbstractContainerMenu {
|
||||
|
||||
@@ -27,7 +27,7 @@ index ac751d460ae0c8dbb858c4047c459a11b57ae175..24926aa7ed5c78b235659daf18b224b1
|
||||
CrashReport crashReport = CrashReport.forThrowable(levelTickingException, "Exception ticking world");
|
||||
serverLevel.fillReportDetails(crashReport);
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index 4ecb9a4125233f91379fd2792112aca6bbb3e33f..b5a61261083ddab70582c1a1d5cac0b9ced9b652 100644
|
||||
index 31abf2da10bc9b4b7825ed4b3d4e9da52feb2e39..9ba1c29b75ba0eb545097eef4fe568c53ebd885c 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -573,6 +573,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
@@ -0,0 +1,83 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Yive <6853318+Yive@users.noreply.github.com>
|
||||
Date: Tue, 11 Jul 2023 13:27:01 -0700
|
||||
Subject: [PATCH] Pluto: Check if the cactus can even survive being placed
|
||||
|
||||
Original license: GPLv3
|
||||
Original project: https://github.com/Yive/Pluto
|
||||
|
||||
Results at 3,000 randomTickSpeed and 24,448 cacti:
|
||||
|
||||
check-survival-before-growth - false & doTileDrop - true: 48mspt
|
||||
check-survival-before-growth - true & doTileDrop - true: 25mspt
|
||||
check-survival-before-growth - false & doTileDrop - false: 18mspt
|
||||
check-survival-before-growth - true & doTileDrop - false: 6mspt
|
||||
|
||||
Setting the gamerule "doTileDrop" to false was to simulate a server that has chunk collectors.
|
||||
|
||||
Note: This might increase the item output of a cacti farm, though in theory it should act the same as vanilla.
|
||||
|
||||
diff --git a/net/minecraft/world/level/block/CactusBlock.java b/net/minecraft/world/level/block/CactusBlock.java
|
||||
index 079b4c95cf81119ca99daeb159aefca389afed74..8fe29455d7ae44f43c663718d38ea2d8cf639797 100644
|
||||
--- a/net/minecraft/world/level/block/CactusBlock.java
|
||||
+++ b/net/minecraft/world/level/block/CactusBlock.java
|
||||
@@ -49,10 +49,15 @@ public class CactusBlock extends Block implements BonemealableBlock { // Purpur
|
||||
@Override
|
||||
protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
|
||||
BlockPos blockPos = pos.above();
|
||||
- if (level.isEmptyBlock(blockPos)) {
|
||||
+ // Pluto start - Decrease chunk/block lookups
|
||||
+ net.minecraft.world.level.chunk.LevelChunk chunk = level.getChunkIfLoaded(blockPos);
|
||||
+ if (chunk == null) return;
|
||||
+
|
||||
+ if (chunk.getBlockState(blockPos).isAir()) {
|
||||
+ // Pluto end - Decrease chunk/block lookups
|
||||
int i = 1;
|
||||
|
||||
- while (level.getBlockState(pos.below(i)).is(this)) {
|
||||
+ while (chunk.getBlockState(pos.below(i)).is(this)) { // Pluto - Decrease chunk/block lookups
|
||||
i++;
|
||||
}
|
||||
|
||||
@@ -61,11 +66,28 @@ public class CactusBlock extends Block implements BonemealableBlock { // Purpur
|
||||
|
||||
int modifier = level.spigotConfig.cactusModifier; // Spigot - SPIGOT-7159: Better modifier resolution
|
||||
if (ageValue >= 15 || (modifier != 100 && random.nextFloat() < (modifier / (100.0f * 16)))) { // Spigot - SPIGOT-7159: Better modifier
|
||||
+ // Pluto start - Check if the cactus can even survive being placed
|
||||
+ if (org.dreeam.leaf.config.modules.opt.CheckSurvivalBeforeGrowth.cactusCheckSurvivalBeforeGrowth && !canSurvive(level, blockPos)) {
|
||||
+ level.levelEvent(LevelEvent.PARTICLES_DESTROY_BLOCK, blockPos, Block.getId(state));
|
||||
+ // We're going to fake the block breaking to match vanilla standards.
|
||||
+ for (net.minecraft.world.item.ItemStack drop : Block.getDrops(state, level, pos, null)) { // Use base cactus since we don't place a block
|
||||
+ Block.popResource(level, blockPos, drop);
|
||||
+ }
|
||||
+ level.setBlock(pos, state.setValue(CactusBlock.AGE, 0), Block.UPDATE_CLIENTS | Block.UPDATE_KNOWN_SHAPE);
|
||||
+ return;
|
||||
+ }
|
||||
+ // Pluto end - Check if the cactus can even survive being placed
|
||||
org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, blockPos, this.defaultBlockState()); // CraftBukkit
|
||||
BlockState blockState = state.setValue(AGE, Integer.valueOf(0));
|
||||
level.setBlock(pos, blockState, 4);
|
||||
level.neighborChanged(blockState, blockPos, this, null, false);
|
||||
} else if (modifier == 100 || random.nextFloat() < (modifier / (100.0f * 16))) { // Spigot - SPIGOT-7159: Better modifier resolution
|
||||
+ // Pluto start - Check if the cactus can even survive being placed
|
||||
+ if (org.dreeam.leaf.config.modules.opt.CheckSurvivalBeforeGrowth.cactusCheckSurvivalBeforeGrowth) {
|
||||
+ level.setBlock(pos, state.setValue(CactusBlock.AGE, ageValue + 1), Block.UPDATE_CLIENTS | Block.UPDATE_KNOWN_SHAPE);
|
||||
+ return;
|
||||
+ }
|
||||
+ // Pluto end - Check if the cactus can even survive being placed
|
||||
level.setBlock(pos, state.setValue(AGE, Integer.valueOf(ageValue + 1)), 4);
|
||||
}
|
||||
}
|
||||
@@ -102,6 +124,12 @@ public class CactusBlock extends Block implements BonemealableBlock { // Purpur
|
||||
|
||||
@Override
|
||||
protected boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
|
||||
+ // Pluto start - Check if the cactus can even survive being placed
|
||||
+ return canSurvive(level, pos);
|
||||
+ }
|
||||
+
|
||||
+ protected boolean canSurvive(LevelReader level, BlockPos pos) {
|
||||
+ // Pluto end - Check if the cactus can even survive being placed
|
||||
for (Direction direction : Direction.Plane.HORIZONTAL) {
|
||||
BlockState blockState = level.getBlockState(pos.relative(direction));
|
||||
if ((level.getWorldBorder().world.purpurConfig.cactusBreaksFromSolidNeighbors && blockState.isSolid()) || level.getFluidState(pos.relative(direction)).is(FluidTags.LAVA)) { // Purpur - Cactus breaks from solid neighbors config
|
||||
@@ -22,6 +22,13 @@ public class ProtocolSupport extends ConfigModules {
|
||||
public static boolean syncmaticaQuota = false;
|
||||
public static int syncmaticaQuotaLimit = 40000000;
|
||||
|
||||
public static boolean doABarrelRollProtocol = false;
|
||||
public static boolean doABarrelRollAllowThrusting = false;
|
||||
public static boolean doABarrelRollForceEnabled = false;
|
||||
public static boolean doABarrelRollForceInstalled = false;
|
||||
public static int doABarrelRollInstalledTimeout = 40;
|
||||
public static DoABarrelRollPackets.KineticDamage doABarrelRollKineticDamage = DoABarrelRollPackets.KineticDamage.VANILLA;
|
||||
|
||||
@Override
|
||||
public void onLoaded() {
|
||||
jadeProtocol = config.getBoolean(getBasePath() + ".jade-protocol", jadeProtocol);
|
||||
@@ -38,5 +45,26 @@ public class ProtocolSupport extends ConfigModules {
|
||||
if (syncmaticaProtocol) {
|
||||
org.leavesmc.leaves.protocol.syncmatica.SyncmaticaProtocol.init();
|
||||
}
|
||||
|
||||
doABarrelRollProtocol = config.getBoolean(getBasePath() + ".do-a-barrel-roll-protocol", doABarrelRollProtocol);
|
||||
doABarrelRollAllowThrusting = config.getBoolean(getBasePath() + ".do-a-barrel-roll-allow-thrusting", doABarrelRollAllowThrusting);
|
||||
doABarrelRollForceEnabled = config.getBoolean(getBasePath() + ".do-a-barrel-roll-force-enabled", doABarrelRollForceEnabled);
|
||||
doABarrelRollForceInstalled = config.getBoolean(getBasePath() + ".do-a-barrel-roll-force-installed", doABarrelRollForceInstalled);
|
||||
doABarrelRollInstalledTimeout = config.getInt(getBasePath() + ".do-a-barrel-roll-installed-timeout", 0);
|
||||
doABarrelRollKineticDamage = DoABarrelRollPackets.KineticDamage.valueOf(config.getString(getBasePath() + ".do-a-barrel-roll-kinetic-damage", doABarrelRollKineticDamage.name()));
|
||||
if (doABarrelRollInstalledTimeout <= 0) {
|
||||
doABarrelRollInstalledTimeout = 40;
|
||||
}
|
||||
if (doABarrelRollProtocol) {
|
||||
DoABarrelRollProtocol.init(
|
||||
doABarrelRollAllowThrusting,
|
||||
doABarrelRollForceEnabled,
|
||||
doABarrelRollForceInstalled,
|
||||
doABarrelRollInstalledTimeout,
|
||||
doABarrelRollKineticDamage
|
||||
);
|
||||
} else {
|
||||
DoABarrelRollProtocol.deinit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ Subject: [PATCH] Cache player profileResult
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
index 9dce1d22c7de3a3dd0e0e8f117cfbb54d1b15042..50137b67b578b0f9f34bb11a6d572df99ee9fa37 100644
|
||||
index 9dce1d22c7de3a3dd0e0e8f117cfbb54d1b15042..405b62c082017024abae7ccc1db5f74caab1eabf 100644
|
||||
--- a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
@@ -70,6 +70,11 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
|
||||
@@ -29,7 +29,7 @@ index 9dce1d22c7de3a3dd0e0e8f117cfbb54d1b15042..50137b67b578b0f9f34bb11a6d572df9
|
||||
- .hasJoinedServer(string1, string, this.getAddress());
|
||||
+ // Leaf start - Cache player profileResult
|
||||
+ ProfileResult profileResult;
|
||||
+ if (org.dreeam.leaf.config.modules.misc.Cache.cachePlayerProfileResult) {
|
||||
+ if (false) { // TODO
|
||||
+ profileResult = playerProfileResultCache.getIfPresent(string1);
|
||||
+
|
||||
+ if (profileResult == null) {
|
||||
|
||||
@@ -5,7 +5,7 @@ Subject: [PATCH] Configurable unknown command message
|
||||
|
||||
|
||||
diff --git a/net/minecraft/commands/Commands.java b/net/minecraft/commands/Commands.java
|
||||
index aba02a7e3139030050c3c61aabf7708c6c088a68..a6d5ad7690f3acc7e80770e24c41d7dbf2b71861 100644
|
||||
index aba02a7e3139030050c3c61aabf7708c6c088a68..4bc1aa7a85596fa1bb275e88834b25f4fe2c6ea0 100644
|
||||
--- a/net/minecraft/commands/Commands.java
|
||||
+++ b/net/minecraft/commands/Commands.java
|
||||
@@ -403,31 +403,8 @@ public class Commands {
|
||||
@@ -41,17 +41,27 @@ index aba02a7e3139030050c3c61aabf7708c6c088a68..a6d5ad7690f3acc7e80770e24c41d7db
|
||||
org.bukkit.Bukkit.getServer().getPluginManager().callEvent(event);
|
||||
if (event.message() != null) {
|
||||
source.sendFailure(io.papermc.paper.adventure.PaperAdventure.asVanilla(event.message()), false);
|
||||
@@ -677,6 +654,86 @@ public class Commands {
|
||||
@@ -677,6 +654,92 @@ public class Commands {
|
||||
};
|
||||
}
|
||||
|
||||
+ // Leaf start - Configurable unknown command message
|
||||
+ private static net.kyori.adventure.text.TextComponent getUnknownCommandMessage(
|
||||
+ private static net.kyori.adventure.text.Component getUnknownCommandMessage(
|
||||
+ net.kyori.adventure.text.TextComponent.Builder builder, CommandSyntaxException commandSyntaxException, String label
|
||||
+ ) {
|
||||
+ String rawMessage = org.dreeam.leaf.config.modules.misc.UnknownCommandMessage.unknownCommandMessage;
|
||||
+
|
||||
+ if (!"default".equals(rawMessage)) {
|
||||
+ if ("default".equals(rawMessage)) {
|
||||
+ return getVanillaUnknownCommandMessage(builder, commandSyntaxException, label);
|
||||
+ }
|
||||
+
|
||||
+ net.kyori.adventure.text.Component messageComponent = null;
|
||||
+ net.kyori.adventure.text.Component detailComponent = null;
|
||||
+
|
||||
+ if (rawMessage.contains("<message>")) {
|
||||
+ messageComponent = io.papermc.paper.command.brigadier.MessageComponentSerializer.message().deserialize(commandSyntaxException.getRawMessage());
|
||||
+ }
|
||||
+
|
||||
+ final String input = commandSyntaxException.getInput();
|
||||
+ final int cursor = commandSyntaxException.getCursor();
|
||||
+
|
||||
@@ -81,19 +91,15 @@ index aba02a7e3139030050c3c61aabf7708c6c088a68..a6d5ad7690f3acc7e80770e24c41d7db
|
||||
+ detail.append(context);
|
||||
+ detail.clickEvent(event);
|
||||
+
|
||||
+ builder.append(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(rawMessage, net.kyori.adventure.text.minimessage.tag.resolver.Placeholder.component("detail", detail.build())));
|
||||
+ } else {
|
||||
+ rawMessage = rawMessage.replace("<detail>", "");
|
||||
+ builder.append(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(rawMessage));
|
||||
+ detailComponent = detail.build();
|
||||
+ }
|
||||
+
|
||||
+ return builder.build();
|
||||
+ return builder.append(net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(rawMessage)).build()
|
||||
+ .replaceText(net.kyori.adventure.text.TextReplacementConfig.builder().matchLiteral("<message>").replacement(messageComponent).build())
|
||||
+ .replaceText(net.kyori.adventure.text.TextReplacementConfig.builder().matchLiteral("<detail>").replacement(detailComponent).build());
|
||||
+ }
|
||||
+
|
||||
+ return getVanillaUnknownCommandMessage(builder, commandSyntaxException, label);
|
||||
+ }
|
||||
+
|
||||
+ private static net.kyori.adventure.text.TextComponent getVanillaUnknownCommandMessage(
|
||||
+ private static net.kyori.adventure.text.Component getVanillaUnknownCommandMessage(
|
||||
+ net.kyori.adventure.text.TextComponent.Builder builder, CommandSyntaxException var7, String label
|
||||
+ ) {
|
||||
+ builder.color(net.kyori.adventure.text.format.NamedTextColor.RED).append(io.papermc.paper.command.brigadier.MessageComponentSerializer.message().deserialize(var7.getRawMessage()));
|
||||
|
||||
@@ -37,7 +37,7 @@ index 02a9ef1694c796584c29430d27f0a09047368835..32608df3da169159c070f37cb55407f4
|
||||
private static final byte CHUNK_TICKET_STAGE_NONE = 0;
|
||||
private static final byte CHUNK_TICKET_STAGE_LOADING = 1;
|
||||
diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
|
||||
index c60b9e4076450de2157c1a3cf4f98cc2c19e4e6a..560a857f3b61679bbf2ee93ac6da393052a1f320 100644
|
||||
index c60b9e4076450de2157c1a3cf4f98cc2c19e4e6a..41da66fd77924a9a4bd9cc12f517e2e693645dfe 100644
|
||||
--- a/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -255,6 +255,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
@@ -62,7 +62,7 @@ index c60b9e4076450de2157c1a3cf4f98cc2c19e4e6a..560a857f3b61679bbf2ee93ac6da3930
|
||||
protected void tick() {
|
||||
+ // Leaf start - Multithreaded tracker
|
||||
+ if (org.dreeam.leaf.config.modules.async.MultithreadedTracker.enabled) {
|
||||
+ final ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel level = this.level;
|
||||
+ final ServerLevel level = this.level;
|
||||
+ org.dreeam.leaf.async.tracker.MultithreadedTracker.tick(level);
|
||||
+ return;
|
||||
+ }
|
||||
@@ -70,23 +70,83 @@ index c60b9e4076450de2157c1a3cf4f98cc2c19e4e6a..560a857f3b61679bbf2ee93ac6da3930
|
||||
// Paper start - optimise entity tracker
|
||||
if (true) {
|
||||
this.newTrackerTick();
|
||||
@@ -1135,7 +1151,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
@@ -1135,7 +1151,18 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
final Entity entity;
|
||||
private final int range;
|
||||
SectionPos lastSectionPos;
|
||||
- public final Set<ServerPlayerConnection> seenBy = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(); // Paper - Perf: optimise map impl
|
||||
+ public final Set<ServerPlayerConnection> seenBy = org.dreeam.leaf.config.modules.async.MultithreadedTracker.enabled ? com.google.common.collect.Sets.newConcurrentHashSet() : new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(); // Paper - Perf: optimise map impl // Leaf - petal - Multithreaded tracker
|
||||
+ // Leaf start - Multithreaded tracker
|
||||
+ public static final ServerPlayerConnection[] EMPTY_OBJECT_ARRAY = new ServerPlayerConnection[0];
|
||||
+ public final Object sync = new Object();
|
||||
+ public final Set<ServerPlayerConnection> seenBy = org.dreeam.leaf.config.modules.async.MultithreadedTracker.enabled ? it.unimi.dsi.fastutil.objects.ReferenceSets.synchronize(new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>()) : new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(); // Paper - Perf: optimise map impl
|
||||
+ private volatile ServerPlayerConnection[] seenByArray = EMPTY_OBJECT_ARRAY;
|
||||
+ public ServerPlayerConnection[] seenBy() {
|
||||
+ return seenByArray;
|
||||
+ }
|
||||
+ public void seenByUpdated() {
|
||||
+ this.seenByArray = this.seenBy.toArray(EMPTY_OBJECT_ARRAY);
|
||||
+ }
|
||||
+ // Leaf end - Multithreaded tracker
|
||||
|
||||
// Paper start - optimise entity tracker
|
||||
private long lastChunkUpdate = -1L;
|
||||
@@ -1162,7 +1178,39 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
@@ -1162,27 +1189,95 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
this.lastTrackedChunk = chunk;
|
||||
|
||||
final ServerPlayer[] playersRaw = players.getRawDataUnchecked();
|
||||
+ final int playersLen = players.size(); // Ensure length won't change in the future tasks
|
||||
-
|
||||
- for (int i = 0, len = players.size(); i < len; ++i) {
|
||||
+ final int playersLength = Math.min(playersRaw.length, players.size()); // Leaf - Multithreaded tracker
|
||||
+ for (int i = 0; i < playersLength; ++i) { // Leaf - Multithreaded tracker
|
||||
final ServerPlayer player = playersRaw[i];
|
||||
this.updatePlayer(player);
|
||||
}
|
||||
|
||||
if (lastChunkUpdate != currChunkUpdate || lastTrackedChunk != chunk) {
|
||||
// need to purge any players possible not in the chunk list
|
||||
- for (final ServerPlayerConnection conn : new java.util.ArrayList<>(this.seenBy)) {
|
||||
+ // Leaf start - Multithreaded tracker
|
||||
+ boolean removed = false;
|
||||
+ for (final ServerPlayerConnection conn : this.seenBy()) {
|
||||
final ServerPlayer player = conn.getPlayer();
|
||||
if (!players.contains(player)) {
|
||||
- this.removePlayer(player);
|
||||
+ removed |= this.removePlayerMulti(player);
|
||||
}
|
||||
}
|
||||
+ if (removed) {
|
||||
+ this.seenByUpdated();
|
||||
+ }
|
||||
}
|
||||
}
|
||||
+ // Leaf end - Multithreaded tracker
|
||||
+
|
||||
+ // Leaf start - Multithreaded tracker
|
||||
+ if (org.dreeam.leaf.config.modules.async.MultithreadedTracker.enabled && org.dreeam.leaf.config.modules.async.MultithreadedTracker.compatModeEnabled) {
|
||||
+ public final @Nullable Runnable leafTickCompact(final ca.spottedleaf.moonrise.common.misc.NearbyPlayers.TrackedChunk chunk) {
|
||||
+ if (chunk == null) {
|
||||
+ this.moonrise$clearPlayers();
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ final ca.spottedleaf.moonrise.common.list.ReferenceList<ServerPlayer> players = chunk.getPlayers(ca.spottedleaf.moonrise.common.misc.NearbyPlayers.NearbyMapType.VIEW_DISTANCE);
|
||||
+
|
||||
+ if (players == null) {
|
||||
+ this.moonrise$clearPlayers();
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ final long lastChunkUpdate = this.lastChunkUpdate;
|
||||
+ final long currChunkUpdate = chunk.getUpdateCount();
|
||||
+ final ca.spottedleaf.moonrise.common.misc.NearbyPlayers.TrackedChunk lastTrackedChunk = this.lastTrackedChunk;
|
||||
+ this.lastChunkUpdate = currChunkUpdate;
|
||||
+ this.lastTrackedChunk = chunk;
|
||||
+
|
||||
+ final ServerPlayer[] playersRaw = players.getRawDataUnchecked();
|
||||
+ final int playersLen = players.size(); // Ensure length won't change in the future tasks
|
||||
+
|
||||
+ if (!org.dreeam.leaf.config.modules.async.MultithreadedTracker.enabled || !org.dreeam.leaf.config.modules.async.MultithreadedTracker.compatModeEnabled) {
|
||||
+ throw new IllegalStateException();
|
||||
+ }
|
||||
+ final boolean isServerPlayer = this.entity instanceof ServerPlayer;
|
||||
+ final boolean isRealPlayer = isServerPlayer && ((ca.spottedleaf.moonrise.patches.chunk_system.player.ChunkSystemServerPlayer) this.entity).moonrise$isRealPlayer();
|
||||
+ Runnable updatePlayerTasks = () -> {
|
||||
@@ -94,15 +154,19 @@ index c60b9e4076450de2157c1a3cf4f98cc2c19e4e6a..560a857f3b61679bbf2ee93ac6da3930
|
||||
+ final ServerPlayer player = playersRaw[i];
|
||||
+ this.updatePlayer(player);
|
||||
+ }
|
||||
|
||||
+
|
||||
+ if (lastChunkUpdate != currChunkUpdate || lastTrackedChunk != chunk) {
|
||||
+ // need to purge any players possible not in the chunk list
|
||||
+ for (final ServerPlayerConnection conn : new java.util.ArrayList<>(this.seenBy)) {
|
||||
+ boolean removed = false;
|
||||
+ for (final ServerPlayerConnection conn : this.seenBy()) {
|
||||
+ final ServerPlayer player = conn.getPlayer();
|
||||
+ if (!players.contains(player)) {
|
||||
+ this.removePlayer(player);
|
||||
+ removed |= this.removePlayerMulti(player);
|
||||
+ }
|
||||
+ }
|
||||
+ if (removed) {
|
||||
+ this.seenByUpdated();
|
||||
+ }
|
||||
+ }
|
||||
+ };
|
||||
+
|
||||
@@ -111,48 +175,89 @@ index c60b9e4076450de2157c1a3cf4f98cc2c19e4e6a..560a857f3b61679bbf2ee93ac6da3930
|
||||
+ // To prevent visible issue with player type NPCs
|
||||
+ // btw, still recommend to use packet based NPC plugins, like ZNPC Plus, Adyeshach, Fancy NPC, etc.
|
||||
+ if (isRealPlayer || !isServerPlayer) {
|
||||
+ org.dreeam.leaf.async.tracker.MultithreadedTracker.getTrackerExecutor().execute(updatePlayerTasks);
|
||||
+ return updatePlayerTasks;
|
||||
+ } else {
|
||||
+ updatePlayerTasks.run();
|
||||
+ return null;
|
||||
+ }
|
||||
+ } else {
|
||||
for (int i = 0, len = players.size(); i < len; ++i) {
|
||||
final ServerPlayer player = playersRaw[i];
|
||||
this.updatePlayer(player);
|
||||
@@ -1177,6 +1225,8 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
}
|
||||
}
|
||||
}
|
||||
+ }
|
||||
+ // Leaf end - Multithreaded tracker
|
||||
|
||||
@Override
|
||||
public final void moonrise$removeNonTickThreadPlayers() {
|
||||
boolean foundToRemove = false;
|
||||
- for (final ServerPlayerConnection conn : this.seenBy) {
|
||||
+ for (final ServerPlayerConnection conn : this.seenBy()) { // Leaf - Multithreaded tracker
|
||||
if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(conn.getPlayer())) {
|
||||
foundToRemove = true;
|
||||
break;
|
||||
@@ -1193,12 +1288,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
return;
|
||||
}
|
||||
|
||||
- for (final ServerPlayerConnection conn : new java.util.ArrayList<>(this.seenBy)) {
|
||||
+ for (final ServerPlayerConnection conn : this.seenBy()) { // Leaf - Multithreaded tracker
|
||||
ServerPlayer player = conn.getPlayer();
|
||||
if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(player)) {
|
||||
- this.removePlayer(player);
|
||||
+ this.removePlayerMulti(player); // Leaf - Multithreaded tracker
|
||||
}
|
||||
}
|
||||
+ this.seenByUpdated(); // Leaf - Multithreaded tracker
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1238,7 +1288,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
@@ -1208,10 +1304,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
if (this.seenBy.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
- for (final ServerPlayerConnection conn : new java.util.ArrayList<>(this.seenBy)) {
|
||||
+ for (final ServerPlayerConnection conn : this.seenBy()) { // Leaf - Multithreaded tracker
|
||||
ServerPlayer player = conn.getPlayer();
|
||||
- this.removePlayer(player);
|
||||
+ this.removePlayerMulti(player); // Leaf - Multithreaded tracker
|
||||
}
|
||||
+ this.seenByUpdated(); // Leaf - Multithreaded tracker
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1238,7 +1335,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
}
|
||||
|
||||
public void broadcast(Packet<?> packet) {
|
||||
- for (ServerPlayerConnection serverPlayerConnection : this.seenBy) {
|
||||
+ for (ServerPlayerConnection serverPlayerConnection : this.seenBy.toArray(new ServerPlayerConnection[0])) {// Leaf - petal - Multithreaded tracker
|
||||
+ for (ServerPlayerConnection serverPlayerConnection : this.seenBy()) { // Leaf - petal - Multithreaded tracker
|
||||
serverPlayerConnection.send(packet);
|
||||
}
|
||||
}
|
||||
@@ -1259,21 +1309,22 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
@@ -1259,21 +1356,34 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
}
|
||||
|
||||
public void broadcastRemoved() {
|
||||
- for (ServerPlayerConnection serverPlayerConnection : this.seenBy) {
|
||||
+ for (ServerPlayerConnection serverPlayerConnection : this.seenBy.toArray(new ServerPlayerConnection[0])) {// Leaf - petal - Multithreaded tracker
|
||||
+ for (ServerPlayerConnection serverPlayerConnection : this.seenBy()) { // Leaf - petal - Multithreaded tracker
|
||||
this.serverEntity.removePairing(serverPlayerConnection.getPlayer());
|
||||
}
|
||||
}
|
||||
|
||||
+ // Leaf start - Multithreaded tracker
|
||||
+ public boolean removePlayerMulti(ServerPlayer player) {
|
||||
+ if (this.seenBy.remove(player.connection)) {
|
||||
+ this.serverEntity.removePairing(player);
|
||||
+ return true;
|
||||
+ } else {
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+ // Leaf end - Multithreaded tracker
|
||||
+
|
||||
public void removePlayer(ServerPlayer player) {
|
||||
- org.spigotmc.AsyncCatcher.catchOp("player tracker clear"); // Spigot
|
||||
+ //org.spigotmc.AsyncCatcher.catchOp("player tracker clear"); // Spigot // Leaf - petal - Multithreaded tracker - We can remove async too
|
||||
if (this.seenBy.remove(player.connection)) {
|
||||
this.serverEntity.removePairing(player);
|
||||
}
|
||||
+ this.seenByUpdated(); // Leaf - Multithreaded tracker
|
||||
}
|
||||
|
||||
public void updatePlayer(ServerPlayer player) {
|
||||
@@ -163,6 +268,22 @@ index c60b9e4076450de2157c1a3cf4f98cc2c19e4e6a..560a857f3b61679bbf2ee93ac6da3930
|
||||
// Paper start - remove allocation of Vec3D here
|
||||
// Vec3 vec3 = player.position().subtract(this.entity.position());
|
||||
double vec3_dx = player.getX() - this.entity.getX();
|
||||
@@ -1301,6 +1411,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
// CraftBukkit end
|
||||
if (flag) {
|
||||
if (this.seenBy.add(player.connection)) {
|
||||
+ this.seenByUpdated(); // Leaf - Multithreaded tracker
|
||||
// Paper start - entity tracking events
|
||||
if (io.papermc.paper.event.player.PlayerTrackEntityEvent.getHandlerList().getRegisteredListeners().length == 0 || new io.papermc.paper.event.player.PlayerTrackEntityEvent(player.getBukkitEntity(), this.entity.getBukkitEntity()).callEvent()) {
|
||||
this.serverEntity.addPairing(player);
|
||||
@@ -1309,6 +1420,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
this.serverEntity.onPlayerAdd(); // Paper - fix desync when a player is added to the tracker
|
||||
}
|
||||
} else if (this.seenBy.remove(player.connection)) {
|
||||
+ this.seenByUpdated(); // Leaf - Multithreaded tracker
|
||||
this.serverEntity.removePairing(player);
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/server/level/ServerBossEvent.java b/net/minecraft/server/level/ServerBossEvent.java
|
||||
index f106373ef3ac4a8685c2939c9e8361688a285913..51ae390c68e7a3aa193329cc3bc47ca675930ff2 100644
|
||||
--- a/net/minecraft/server/level/ServerBossEvent.java
|
||||
@@ -177,31 +298,39 @@ index f106373ef3ac4a8685c2939c9e8361688a285913..51ae390c68e7a3aa193329cc3bc47ca6
|
||||
public boolean visible = true;
|
||||
|
||||
diff --git a/net/minecraft/server/level/ServerEntity.java b/net/minecraft/server/level/ServerEntity.java
|
||||
index 44d87997e1ce9b846ebed541634a4478334c920c..87b032ad2ba3e3e0a2e5cfcf185533102247a946 100644
|
||||
index 1a9601aee097b6c10cf2ae1c52fddf45da85f60f..867936866d952c559b6ffa49fdf78acd70a9bab9 100644
|
||||
--- a/net/minecraft/server/level/ServerEntity.java
|
||||
+++ b/net/minecraft/server/level/ServerEntity.java
|
||||
@@ -460,15 +460,18 @@ public class ServerEntity {
|
||||
if (this.entity instanceof LivingEntity) {
|
||||
Set<AttributeInstance> attributesToSync = ((LivingEntity)this.entity).getAttributes().getAttributesToSync();
|
||||
if (!attributesToSync.isEmpty()) {
|
||||
+ // Leaf start - petal - Multithreaded tracker - send in main thread
|
||||
+ final Set<AttributeInstance> copy = new it.unimi.dsi.fastutil.objects.ObjectOpenHashSet<>(attributesToSync);
|
||||
// CraftBukkit start - Send scaled max health
|
||||
if (this.entity instanceof ServerPlayer serverPlayer) {
|
||||
- serverPlayer.getBukkitEntity().injectScaledMaxHealth(attributesToSync, false);
|
||||
+ serverPlayer.getBukkitEntity().injectScaledMaxHealth(copy, false);
|
||||
}
|
||||
// CraftBukkit end
|
||||
- this.broadcastAndSend(new ClientboundUpdateAttributesPacket(this.entity.getId(), attributesToSync));
|
||||
+ this.broadcastAndSend(new ClientboundUpdateAttributesPacket(this.entity.getId(), copy));
|
||||
+ // Leaf end - petal - Multithreaded tracker - send in main thread
|
||||
}
|
||||
|
||||
- attributesToSync.clear();
|
||||
+ ((LivingEntity)this.entity).getAttributes().getAttributesToSync().clear(); // Leaf - Multithreaded tracker
|
||||
}
|
||||
@@ -75,6 +75,7 @@ public class ServerEntity {
|
||||
@Nullable
|
||||
private List<SynchedEntityData.DataValue<?>> trackedDataValues;
|
||||
private final Set<net.minecraft.server.network.ServerPlayerConnection> trackedPlayers; // Paper
|
||||
+ public boolean wantSendDirtyEntityData = false; // Leaf - Multithreaded tracker
|
||||
|
||||
public ServerEntity(
|
||||
ServerLevel level,
|
||||
@@ -146,7 +147,7 @@ public class ServerEntity {
|
||||
MapId mapId = itemFrame.cachedMapId; // Paper - Perf: Cache map ids on item frames
|
||||
MapItemSavedData savedData = MapItem.getSavedData(mapId, this.level);
|
||||
if (savedData != null) {
|
||||
- for (final net.minecraft.server.network.ServerPlayerConnection connection : this.trackedPlayers) { // Paper
|
||||
+ for (final net.minecraft.server.network.ServerPlayerConnection connection : this.trackedPlayers.toArray(ChunkMap.TrackedEntity.EMPTY_OBJECT_ARRAY)) { // Paper // Leaf - Multithreaded tracker
|
||||
final ServerPlayer serverPlayer = connection.getPlayer(); // Paper
|
||||
savedData.tickCarriedBy(serverPlayer, item);
|
||||
Packet<?> updatePacket = savedData.getUpdatePacket(mapId, serverPlayer);
|
||||
@@ -450,6 +451,12 @@ public class ServerEntity {
|
||||
}
|
||||
|
||||
public void sendDirtyEntityData() {
|
||||
+ // Leaf start - Multithreaded tracker
|
||||
+ if (Thread.currentThread() instanceof org.dreeam.leaf.async.tracker.MultithreadedTracker.MultithreadedTrackerThread) {
|
||||
+ wantSendDirtyEntityData = true;
|
||||
+ return;
|
||||
+ }
|
||||
+ // Leaf end - Multithreaded tracker
|
||||
SynchedEntityData entityData = this.entity.getEntityData();
|
||||
List<SynchedEntityData.DataValue<?>> list = entityData.packDirty();
|
||||
if (list != null) {
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index 5943b18f172fb1d77ef1fe768daa8e8f43c3c8c1..7b85a9ebdbe3e8bee0a8fc100ede8a3f07eee5ce 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -237,98 +366,55 @@ index 729f595491c7a4edf24dff2e876dfb69ade87a17..a3069b29a1b78012314747d705e27c16
|
||||
// Paper start - Prevent teleporting dead entities
|
||||
if (this.player.isRemoved()) {
|
||||
LOGGER.info("Attempt to teleport removed player {} restricted", player.getScoreboardName());
|
||||
diff --git a/net/minecraft/world/entity/ai/attributes/AttributeInstance.java b/net/minecraft/world/entity/ai/attributes/AttributeInstance.java
|
||||
index 3ac9f36eae87369354e992a1d9b5c5b2d87d17cb..11520972f4fabde3be48edd296351113453b2869 100644
|
||||
--- a/net/minecraft/world/entity/ai/attributes/AttributeInstance.java
|
||||
+++ b/net/minecraft/world/entity/ai/attributes/AttributeInstance.java
|
||||
@@ -26,8 +26,11 @@ public class AttributeInstance {
|
||||
private final Map<AttributeModifier.Operation, Map<ResourceLocation, AttributeModifier>> modifiersByOperation = Maps.newEnumMap(
|
||||
AttributeModifier.Operation.class
|
||||
);
|
||||
- private final Map<ResourceLocation, AttributeModifier> modifierById = new Object2ObjectArrayMap<>();
|
||||
- private final Map<ResourceLocation, AttributeModifier> permanentModifiers = new Object2ObjectArrayMap<>();
|
||||
diff --git a/net/minecraft/world/entity/item/PrimedTnt.java b/net/minecraft/world/entity/item/PrimedTnt.java
|
||||
index 36e3937c9e09852937c94c268c877a15337835c5..8aedc3ca463745fe32cac977208b23dc0b8e73b6 100644
|
||||
--- a/net/minecraft/world/entity/item/PrimedTnt.java
|
||||
+++ b/net/minecraft/world/entity/item/PrimedTnt.java
|
||||
@@ -145,12 +145,14 @@ public class PrimedTnt extends Entity implements TraceableEntity {
|
||||
net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket velocityPacket = new net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket(this);
|
||||
net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket positionPacket = net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket.teleport(this.getId(), net.minecraft.world.entity.PositionMoveRotation.of(this), java.util.Set.of(), this.onGround);
|
||||
|
||||
- ete.seenBy.stream()
|
||||
- .filter(viewer -> (viewer.getPlayer().getX() - this.getX()) * (viewer.getPlayer().getY() - this.getY()) * (viewer.getPlayer().getZ() - this.getZ()) < 16 * 16)
|
||||
- .forEach(viewer -> {
|
||||
+ // Leaf start - Multithreaded tracker
|
||||
+ private final boolean multiThreadedTrackingEnabled = org.dreeam.leaf.config.modules.async.MultithreadedTracker.enabled;
|
||||
+ private final Map<ResourceLocation, AttributeModifier> modifierById = multiThreadedTrackingEnabled ? it.unimi.dsi.fastutil.objects.Object2ObjectMaps.synchronize(new Object2ObjectArrayMap<>(), this) : new Object2ObjectArrayMap<>();
|
||||
+ private final Map<ResourceLocation, AttributeModifier> permanentModifiers = multiThreadedTrackingEnabled ? it.unimi.dsi.fastutil.objects.Object2ObjectMaps.synchronize(new Object2ObjectArrayMap<>(), this) : new Object2ObjectArrayMap<>();
|
||||
+ for (var viewer : ete.seenBy()) {
|
||||
+ if ((viewer.getPlayer().getX() - this.getX()) * (viewer.getPlayer().getY() - this.getY()) * (viewer.getPlayer().getZ() - this.getZ()) < 16 * 16) {
|
||||
viewer.send(velocityPacket);
|
||||
viewer.send(positionPacket);
|
||||
- });
|
||||
+ }
|
||||
+ }
|
||||
+ // Leaf end - Multithreaded tracker
|
||||
private double baseValue;
|
||||
private boolean dirty = true;
|
||||
private double cachedValue;
|
||||
@@ -116,7 +119,15 @@ public class AttributeInstance {
|
||||
}
|
||||
|
||||
protected void setDirty() {
|
||||
- this.dirty = true;
|
||||
+ // Leaf start - Multithreaded tracker
|
||||
+ if (multiThreadedTrackingEnabled) {
|
||||
+ synchronized (this) {
|
||||
+ this.dirty = true;
|
||||
+ }
|
||||
+ } else {
|
||||
+ this.dirty = true;
|
||||
+ }
|
||||
+ // Leaf end - Multithreaded tracker
|
||||
this.onDirty.accept(this);
|
||||
}
|
||||
// Paper end - Option to prevent TNT from moving in water
|
||||
diff --git a/net/minecraft/world/entity/vehicle/NewMinecartBehavior.java b/net/minecraft/world/entity/vehicle/NewMinecartBehavior.java
|
||||
index 325ec57df2885f5e81b8a6b61e3a9fed9484b30f..abc5c097861d0decf49d0d3970ab48f1cf8b1cf1 100644
|
||||
--- a/net/minecraft/world/entity/vehicle/NewMinecartBehavior.java
|
||||
+++ b/net/minecraft/world/entity/vehicle/NewMinecartBehavior.java
|
||||
@@ -35,13 +35,20 @@ public class NewMinecartBehavior extends MinecartBehavior {
|
||||
private int cachedLerpDelay;
|
||||
private float cachedPartialTick;
|
||||
private int lerpDelay = 0;
|
||||
- public final List<NewMinecartBehavior.MinecartStep> lerpSteps = new LinkedList<>();
|
||||
+ public final List<NewMinecartBehavior.MinecartStep> lerpSteps; // Leaf - Multithreaded tracker
|
||||
public final List<NewMinecartBehavior.MinecartStep> currentLerpSteps = new LinkedList<>();
|
||||
public double currentLerpStepsTotalWeight = 0.0;
|
||||
public NewMinecartBehavior.MinecartStep oldLerp = NewMinecartBehavior.MinecartStep.ZERO;
|
||||
|
||||
@@ -143,6 +154,17 @@ public class AttributeInstance {
|
||||
}
|
||||
|
||||
public double getValue() {
|
||||
+ // Leaf start - Multithreaded tracker
|
||||
+ if (multiThreadedTrackingEnabled) {
|
||||
+ synchronized (this) {
|
||||
+ if (this.dirty) {
|
||||
+ this.cachedValue = this.calculateValue();
|
||||
+ this.dirty = false;
|
||||
+ }
|
||||
+ return this.cachedValue;
|
||||
+ }
|
||||
+ }
|
||||
+ // Leaf end - Multithreaded tracker
|
||||
if (this.dirty) {
|
||||
this.cachedValue = this.calculateValue();
|
||||
this.dirty = false;
|
||||
diff --git a/net/minecraft/world/entity/ai/attributes/AttributeMap.java b/net/minecraft/world/entity/ai/attributes/AttributeMap.java
|
||||
index 701025715e0aca3c1f920a66f9b3d03ec08eaf02..8a299c81799b3f0c353eecce56afd14b9150df5f 100644
|
||||
--- a/net/minecraft/world/entity/ai/attributes/AttributeMap.java
|
||||
+++ b/net/minecraft/world/entity/ai/attributes/AttributeMap.java
|
||||
@@ -14,11 +14,11 @@ import net.minecraft.nbt.ListTag;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class AttributeMap {
|
||||
- // Gale start - Lithium - replace AI attributes with optimized collections
|
||||
- private final Map<Holder<Attribute>, AttributeInstance> attributes = new it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap<>(0);
|
||||
- private final Set<AttributeInstance> attributesToSync = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(0);
|
||||
- private final Set<AttributeInstance> attributesToUpdate = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(0);
|
||||
- // Gale end - Lithium - replace AI attributes with optimized collections
|
||||
+ // Leaf start - Multithreaded tracker
|
||||
+ private final Map<Holder<Attribute>, AttributeInstance> attributes;
|
||||
+ private final Set<AttributeInstance> attributesToSync;
|
||||
+ private final Set<AttributeInstance> attributesToUpdate;
|
||||
+ // Leaf end - Multithreaded tracker
|
||||
private final AttributeSupplier supplier;
|
||||
private final java.util.function.Function<Holder<Attribute>, AttributeInstance> createInstance; // Gale - Airplane - reduce entity allocations
|
||||
private final net.minecraft.world.entity.LivingEntity entity; // Purpur - Ridables
|
||||
@@ -32,6 +32,17 @@ public class AttributeMap {
|
||||
// Purpur end - Ridables
|
||||
this.supplier = defaultAttributes;
|
||||
this.createInstance = holder -> this.supplier.createInstance(this::onAttributeModified, holder); // Gale - Airplane - reduce entity allocations
|
||||
public NewMinecartBehavior(AbstractMinecart minecart) {
|
||||
super(minecart);
|
||||
+ // Leaf start - Multithreaded tracker
|
||||
+ if (org.dreeam.leaf.config.modules.async.MultithreadedTracker.enabled) {
|
||||
+ this.attributes = it.unimi.dsi.fastutil.objects.Reference2ReferenceMaps.synchronize(new it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap<>(0));
|
||||
+ this.attributesToSync = it.unimi.dsi.fastutil.objects.ReferenceSets.synchronize(new it.unimi.dsi.fastutil.objects.ReferenceArraySet<>(0));
|
||||
+ this.attributesToUpdate = it.unimi.dsi.fastutil.objects.ReferenceSets.synchronize(new it.unimi.dsi.fastutil.objects.ReferenceArraySet<>(0));
|
||||
+ lerpSteps = it.unimi.dsi.fastutil.objects.ObjectLists.synchronize(new it.unimi.dsi.fastutil.objects.ObjectArrayList<>());
|
||||
+ } else {
|
||||
+ this.attributes = new it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap<>(0);
|
||||
+ this.attributesToSync = new it.unimi.dsi.fastutil.objects.ReferenceArraySet<>(0);
|
||||
+ this.attributesToUpdate = new it.unimi.dsi.fastutil.objects.ReferenceArraySet<>(0);
|
||||
+ lerpSteps = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>();
|
||||
+ }
|
||||
+ // Leaf end - Multithreaded tracker
|
||||
}
|
||||
|
||||
private void onAttributeModified(AttributeInstance instance) {
|
||||
@Override
|
||||
diff --git a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
|
||||
index 7bbeed6c998c91e68376d3f17a510d68e3cd0b27..d62ff9ebd4b55e1a9a0b51e84be868d844e5a954 100644
|
||||
--- a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
|
||||
|
||||
@@ -12,116 +12,40 @@ In non-strict test, this can give ~60-110% improvement (524ms on Paper, 204ms on
|
||||
under 625 villagers situation.
|
||||
|
||||
diff --git a/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java b/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java
|
||||
index b0c5e41fefc7c9adf1a61bd5b52861736657d37e..83af90c7a2e425b775abd7907895d211ced07955 100644
|
||||
index b0c5e41fefc7c9adf1a61bd5b52861736657d37e..ef87b95d53e5ea2555778e6020ea07a11c474961 100644
|
||||
--- a/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java
|
||||
+++ b/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java
|
||||
@@ -13,18 +13,102 @@ import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities;
|
||||
@@ -13,17 +13,27 @@ import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
|
||||
public class NearestLivingEntitySensor<T extends LivingEntity> extends Sensor<T> {
|
||||
+
|
||||
+ // Leaf start - Optimized entity sorting with buffer reuse
|
||||
+ private static final int SMALL_ARRAY_THRESHOLD = 2;
|
||||
+ private LivingEntity[] entityBuffer = new LivingEntity[0];
|
||||
+ private long[] bitsBuffer = new long[0];
|
||||
+ // Leaf start - Smart sort entities in NearestLivingEntitySensor
|
||||
+ private final org.dreeam.leaf.util.FastBitRadixSort sorter;
|
||||
+ public NearestLivingEntitySensor() {
|
||||
+ this.sorter = new org.dreeam.leaf.util.FastBitRadixSort();
|
||||
+ }
|
||||
+ // Leaf end - Smart sort entities in NearestLivingEntitySensor
|
||||
+
|
||||
@Override
|
||||
protected void doTick(ServerLevel level, T entity) {
|
||||
- double attributeValue = entity.getAttributeValue(Attributes.FOLLOW_RANGE);
|
||||
- AABB aabb = entity.getBoundingBox().inflate(attributeValue, attributeValue, attributeValue);
|
||||
double attributeValue = entity.getAttributeValue(Attributes.FOLLOW_RANGE);
|
||||
AABB aabb = entity.getBoundingBox().inflate(attributeValue, attributeValue, attributeValue);
|
||||
- List<LivingEntity> entitiesOfClass = level.getEntitiesOfClass(
|
||||
- LivingEntity.class, aabb, matchableEntity -> matchableEntity != entity && matchableEntity.isAlive()
|
||||
+ double range = entity.getAttributeValue(Attributes.FOLLOW_RANGE);
|
||||
+ double rangeSqr = range * range;
|
||||
+ AABB aabb = entity.getBoundingBox().inflate(range, range, range);
|
||||
+
|
||||
+ List<LivingEntity> entities = level.getEntitiesOfClass(
|
||||
+ LivingEntity.class, aabb, e -> e != entity && e.isAlive() && entity.distanceToSqr(e) <= rangeSqr
|
||||
);
|
||||
- );
|
||||
- entitiesOfClass.sort(Comparator.comparingDouble(entity::distanceToSqr));
|
||||
+
|
||||
+ LivingEntity[] sorted = smartSort(entities, entity);
|
||||
+ // Leaf start - Smart sort entities in NearestLivingEntitySensor
|
||||
+ double rangeSqr = attributeValue * attributeValue;
|
||||
+ List<LivingEntity> entities = level.getEntitiesOfClass(LivingEntity.class, aabb, e -> e != entity && e.isAlive() && entity.distanceToSqr(e) <= rangeSqr);
|
||||
+ LivingEntity[] sorted = this.sorter.sort(entities, entity, LivingEntity.class);
|
||||
+ List<LivingEntity> sortedList = java.util.Arrays.asList(sorted);
|
||||
+
|
||||
Brain<?> brain = entity.getBrain();
|
||||
- brain.setMemory(MemoryModuleType.NEAREST_LIVING_ENTITIES, entitiesOfClass);
|
||||
- brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, new NearestVisibleLivingEntities(level, entity, entitiesOfClass));
|
||||
+ brain.setMemory(MemoryModuleType.NEAREST_LIVING_ENTITIES, sortedList);
|
||||
+ brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES,
|
||||
+ new NearestVisibleLivingEntities(level, entity, sortedList));
|
||||
+ }
|
||||
+
|
||||
+ private LivingEntity[] smartSort(List<LivingEntity> entities, T reference) {
|
||||
+ int size = entities.size();
|
||||
+ if (size <= 1) return entities.toArray(new LivingEntity[0]);
|
||||
+
|
||||
+ if (entityBuffer.length < size) {
|
||||
+ entityBuffer = new LivingEntity[size];
|
||||
+ bitsBuffer = new long[size];
|
||||
+ }
|
||||
+
|
||||
+ for (int i = 0; i < size; i++) {
|
||||
+ LivingEntity e = entities.get(i);
|
||||
+ entityBuffer[i] = e;
|
||||
+ bitsBuffer[i] = Double.doubleToRawLongBits(reference.distanceToSqr(e));
|
||||
+ }
|
||||
+
|
||||
+ fastRadixSort(entityBuffer, bitsBuffer, 0, size - 1, 62);
|
||||
+
|
||||
+ return java.util.Arrays.copyOf(entityBuffer, size);
|
||||
+ }
|
||||
+
|
||||
+ private void fastRadixSort(LivingEntity[] ents, long[] bits, int low, int high, int bit) {
|
||||
+ if (bit < 0 || low >= high) return;
|
||||
+
|
||||
+ if (high - low <= SMALL_ARRAY_THRESHOLD) {
|
||||
+ insertionSort(ents, bits, low, high);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ int i = low, j = high;
|
||||
+ final long mask = 1L << bit;
|
||||
+
|
||||
+ while (i <= j) {
|
||||
+ while (i <= j && (bits[i] & mask) == 0) i++;
|
||||
+ while (i <= j && (bits[j] & mask) != 0) j--;
|
||||
+
|
||||
+ if (i < j) {
|
||||
+ swap(ents, bits, i++, j--);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (low < j) fastRadixSort(ents, bits, low, j, bit - 1);
|
||||
+ if (i < high) fastRadixSort(ents, bits, i, high, bit - 1);
|
||||
+ }
|
||||
+
|
||||
+ private void insertionSort(LivingEntity[] ents, long[] bits, int low, int high) {
|
||||
+ for (int i = low + 1; i <= high; i++) {
|
||||
+ int j = i;
|
||||
+ LivingEntity e = ents[j];
|
||||
+ long b = bits[j];
|
||||
+
|
||||
+ while (j > low && bits[j - 1] > b) {
|
||||
+ ents[j] = ents[j - 1];
|
||||
+ bits[j] = bits[j - 1];
|
||||
+ j--;
|
||||
+ }
|
||||
+
|
||||
+ ents[j] = e;
|
||||
+ bits[j] = b;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private void swap(LivingEntity[] ents, long[] bits, int a, int b) {
|
||||
+ LivingEntity te = ents[a];
|
||||
+ ents[a] = ents[b];
|
||||
+ ents[b] = te;
|
||||
+
|
||||
+ long tb = bits[a];
|
||||
+ bits[a] = bits[b];
|
||||
+ bits[b] = tb;
|
||||
+ brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, new NearestVisibleLivingEntities(level, entity, sortedList));
|
||||
+ // Leaf end - Smart sort entities in NearestLivingEntitySensor
|
||||
}
|
||||
+ // Leaf end - Optimized entity sorting with buffer reuse
|
||||
|
||||
@Override
|
||||
public Set<MemoryModuleType<?>> requires() {
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Taiyou06 <kaandindar21@gmail.com>
|
||||
Date: Sun, 2 Mar 2025 21:23:20 +0100
|
||||
Subject: [PATCH] Async chunk send
|
||||
|
||||
|
||||
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
|
||||
index 32608df3da169159c070f37cb55407f4f6187744..3a78e7512772fd3f7cf8f221e3a72474def14bea 100644
|
||||
--- a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
|
||||
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
|
||||
@@ -436,7 +436,15 @@ public final class RegionizedPlayerChunkLoader {
|
||||
// Note: drop isAlive() check so that chunks properly unload client-side when the player dies
|
||||
((ChunkSystemChunkHolder)((ChunkSystemServerLevel)this.world).moonrise$getChunkTaskScheduler().chunkHolderManager
|
||||
.getChunkHolder(chunkX, chunkZ).vanillaChunkHolder).moonrise$removeReceivedChunk(this.player);
|
||||
- this.player.connection.send(new ClientboundForgetLevelChunkPacket(new ChunkPos(chunkX, chunkZ)));
|
||||
+ // Leaf start - Async chunk send
|
||||
+ if (org.dreeam.leaf.config.modules.async.AsyncChunkSend.enabled) {
|
||||
+ org.dreeam.leaf.async.chunk.AsyncChunkSend.POOL.execute(
|
||||
+ () -> this.player.connection.send(new ClientboundForgetLevelChunkPacket(new ChunkPos(chunkX, chunkZ)))
|
||||
+ );
|
||||
+ } else {
|
||||
+ this.player.connection.send(new ClientboundForgetLevelChunkPacket(new ChunkPos(chunkX, chunkZ)));
|
||||
+ }
|
||||
+ // Leaf end - Async chunk send
|
||||
// Paper start - PlayerChunkUnloadEvent
|
||||
if (io.papermc.paper.event.packet.PlayerChunkUnloadEvent.getHandlerList().getRegisteredListeners().length > 0) {
|
||||
new io.papermc.paper.event.packet.PlayerChunkUnloadEvent(player.getBukkitEntity().getWorld().getChunkAt(new ChunkPos(chunkX, chunkZ).longKey), player.getBukkitEntity()).callEvent();
|
||||
diff --git a/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java b/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
||||
index 526c117e0d53ad527eb610c79cdc46ec16b18c0c..9151e580b4840fddab04e487d723130a5a769a1a 100644
|
||||
--- a/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
||||
+++ b/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
||||
@@ -75,6 +75,45 @@ public class ClientboundLevelChunkPacketData {
|
||||
}
|
||||
}
|
||||
|
||||
+ // Leaf start - Async chunk send
|
||||
+ public ClientboundLevelChunkPacketData(LevelChunk levelChunk, io.papermc.paper.antixray.ChunkPacketInfo<net.minecraft.world.level.block.state.BlockState> chunkPacketInfo, BlockEntity[] blockEntities, Map<Heightmap.Types, long[]> heightmaps) {
|
||||
+ this.heightmaps = heightmaps;
|
||||
+
|
||||
+ if (Thread.currentThread() instanceof org.dreeam.leaf.async.chunk.AsyncChunkSendThread) {
|
||||
+ var buffer = new io.netty.buffer.UnpooledByteBufAllocator(false).buffer(calculateChunkSize(levelChunk));
|
||||
+ extractChunkData(new FriendlyByteBuf(buffer), levelChunk, chunkPacketInfo);
|
||||
+ var array = it.unimi.dsi.fastutil.bytes.ByteArrays.trim(buffer.array(), buffer.writerIndex());
|
||||
+ if (chunkPacketInfo != null) {
|
||||
+ chunkPacketInfo.setBuffer(array);
|
||||
+ }
|
||||
+ this.buffer = array;
|
||||
+ } else {
|
||||
+ this.buffer = new byte[calculateChunkSize(levelChunk)];
|
||||
+ // Paper start - Anti-Xray - Add chunk packet info
|
||||
+ if (chunkPacketInfo != null) {
|
||||
+ chunkPacketInfo.setBuffer(this.buffer);
|
||||
+ }
|
||||
+ extractChunkData(new FriendlyByteBuf(this.getWriteBuffer()), levelChunk, chunkPacketInfo);
|
||||
+ }
|
||||
+
|
||||
+ this.blockEntitiesData = Lists.newArrayList();
|
||||
+ int totalTileEntities = 0; // Paper - Handle oversized block entities in chunks
|
||||
+
|
||||
+ for (BlockEntity blockEntity : blockEntities) {
|
||||
+ // Paper start - Handle oversized block entities in chunks
|
||||
+ if (++totalTileEntities > BLOCK_ENTITY_LIMIT) {
|
||||
+ net.minecraft.network.protocol.Packet<ClientGamePacketListener> packet = blockEntity.getUpdatePacket();
|
||||
+ if (packet != null) {
|
||||
+ this.extraPackets.add(packet);
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Handle oversized block entities in chunks
|
||||
+ this.blockEntitiesData.add(ClientboundLevelChunkPacketData.BlockEntityInfo.create(blockEntity));
|
||||
+ }
|
||||
+ }
|
||||
+ // Leaf end - Async chunk send
|
||||
+
|
||||
public ClientboundLevelChunkPacketData(RegistryFriendlyByteBuf buffer, int x, int z) {
|
||||
this.heightmaps = HEIGHTMAPS_STREAM_CODEC.decode(buffer);
|
||||
int varInt = buffer.readVarInt();
|
||||
diff --git a/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java b/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java
|
||||
index 8578d1f78ddd1bb75f3230f04bfaa35af9f5f822..4f54c4c8e49c1e0352ab2c5c23277b4103504c55 100644
|
||||
--- a/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java
|
||||
+++ b/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java
|
||||
@@ -44,6 +44,17 @@ public class ClientboundLevelChunkWithLightPacket implements Packet<ClientGamePa
|
||||
this.lightData = new ClientboundLightUpdatePacketData(pos, lightEngine, skyLight, blockLight);
|
||||
chunk.getLevel().chunkPacketBlockController.modifyBlocks(this, chunkPacketInfo); // Paper - Anti-Xray - Modify blocks
|
||||
}
|
||||
+ // Leaf start - Async chunk send
|
||||
+ public ClientboundLevelChunkWithLightPacket(LevelChunk chunk, LevelLightEngine lightEngine, @Nullable BitSet skyLight, @Nullable BitSet blockLight, boolean modifyBlocks, net.minecraft.world.level.block.entity.BlockEntity[] blockEntities, java.util.Map<net.minecraft.world.level.levelgen.Heightmap.Types, long[]> heightmaps) {
|
||||
+ ChunkPos pos = chunk.getPos();
|
||||
+ this.x = pos.x;
|
||||
+ this.z = pos.z;
|
||||
+ io.papermc.paper.antixray.ChunkPacketInfo<net.minecraft.world.level.block.state.BlockState> chunkPacketInfo = modifyBlocks ? chunk.getLevel().chunkPacketBlockController.getChunkPacketInfo(this, chunk) : null; // Paper - Ant-Xray
|
||||
+ this.chunkData = new ClientboundLevelChunkPacketData(chunk, chunkPacketInfo, blockEntities, heightmaps); // Paper - Anti-Xray
|
||||
+ this.lightData = new ClientboundLightUpdatePacketData(pos, lightEngine, skyLight, blockLight);
|
||||
+ chunk.getLevel().chunkPacketBlockController.modifyBlocks(this, chunkPacketInfo); // Paper - Anti-Xray - Modify blocks
|
||||
+ }
|
||||
+ // Leaf end - Async chunk send
|
||||
|
||||
private ClientboundLevelChunkWithLightPacket(RegistryFriendlyByteBuf buffer) {
|
||||
this.x = buffer.readInt();
|
||||
diff --git a/net/minecraft/server/network/PlayerChunkSender.java b/net/minecraft/server/network/PlayerChunkSender.java
|
||||
index 14878690a88fd4de3e2c127086607e6c819c636c..69581890ab34af20f9c608678f378ec9fe3ec775 100644
|
||||
--- a/net/minecraft/server/network/PlayerChunkSender.java
|
||||
+++ b/net/minecraft/server/network/PlayerChunkSender.java
|
||||
@@ -64,13 +64,29 @@ public class PlayerChunkSender {
|
||||
if (!list.isEmpty()) {
|
||||
ServerGamePacketListenerImpl serverGamePacketListenerImpl = player.connection;
|
||||
this.unacknowledgedBatches++;
|
||||
- serverGamePacketListenerImpl.send(ClientboundChunkBatchStartPacket.INSTANCE);
|
||||
+ // Leaf start - Async chunk send
|
||||
+ if (org.dreeam.leaf.config.modules.async.AsyncChunkSend.enabled) {
|
||||
+ org.dreeam.leaf.async.chunk.AsyncChunkSend.POOL.execute(
|
||||
+ () -> serverGamePacketListenerImpl.send(ClientboundChunkBatchStartPacket.INSTANCE)
|
||||
+ );
|
||||
+ } else {
|
||||
+ serverGamePacketListenerImpl.send(ClientboundChunkBatchStartPacket.INSTANCE);
|
||||
+ }
|
||||
+ // Leaf end - Async chunk send
|
||||
|
||||
for (LevelChunk levelChunk : list) {
|
||||
sendChunk(serverGamePacketListenerImpl, serverLevel, levelChunk);
|
||||
}
|
||||
|
||||
- serverGamePacketListenerImpl.send(new ClientboundChunkBatchFinishedPacket(list.size()));
|
||||
+ // Leaf start - Async chunk send
|
||||
+ if (org.dreeam.leaf.config.modules.async.AsyncChunkSend.enabled) {
|
||||
+ org.dreeam.leaf.async.chunk.AsyncChunkSend.POOL.execute(
|
||||
+ () -> serverGamePacketListenerImpl.send(new ClientboundChunkBatchFinishedPacket(list.size()))
|
||||
+ );
|
||||
+ } else {
|
||||
+ serverGamePacketListenerImpl.send(new ClientboundChunkBatchFinishedPacket(list.size()));
|
||||
+ }
|
||||
+ // Leaf end - Async chunk send
|
||||
this.batchQuota = this.batchQuota - list.size();
|
||||
}
|
||||
}
|
||||
@@ -81,7 +97,23 @@ public class PlayerChunkSender {
|
||||
// Paper start - Anti-Xray
|
||||
public static void sendChunk(ServerGamePacketListenerImpl packetListener, ServerLevel level, LevelChunk chunk) {
|
||||
final boolean shouldModify = level.chunkPacketBlockController.shouldModify(packetListener.player, chunk);
|
||||
- packetListener.send(new ClientboundLevelChunkWithLightPacket(chunk, level.getLightEngine(), null, null, shouldModify));
|
||||
+ // Leaf start - Async chunk send
|
||||
+ if (org.dreeam.leaf.config.modules.async.AsyncChunkSend.enabled) {
|
||||
+ var blockEntities = chunk.blockEntities.values().toArray(new net.minecraft.world.level.block.entity.BlockEntity[0]);
|
||||
+ java.util.Map<net.minecraft.world.level.levelgen.Heightmap.Types, long[]> heightmaps = new java.util.concurrent.ConcurrentHashMap<>();
|
||||
+
|
||||
+ for (var entry : chunk.getHeightmaps()) {
|
||||
+ if (entry.getKey().sendToClient()) {
|
||||
+ heightmaps.put(entry.getKey(), entry.getValue().getRawData());
|
||||
+ }
|
||||
+ }
|
||||
+ org.dreeam.leaf.async.chunk.AsyncChunkSend.POOL.execute(
|
||||
+ () -> packetListener.send(new ClientboundLevelChunkWithLightPacket(chunk, level.getLightEngine(), null, null, shouldModify, blockEntities, heightmaps))
|
||||
+ );
|
||||
+ } else {
|
||||
+ packetListener.send(new ClientboundLevelChunkWithLightPacket(chunk, level.getLightEngine(), null, null, shouldModify));
|
||||
+ }
|
||||
+ // Leaf end - Async chunk send
|
||||
// Paper end - Anti-Xray
|
||||
// Paper start - PlayerChunkLoadEvent
|
||||
if (io.papermc.paper.event.packet.PlayerChunkLoadEvent.getHandlerList().getRegisteredListeners().length > 0) {
|
||||
diff --git a/net/minecraft/world/level/chunk/LevelChunkSection.java b/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||||
index 36c033b0ee63dfc273d721fb4b614733e8fdef19..1cc33a038060aaf5258ee4f1deb19b4a1be59a29 100644
|
||||
--- a/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||||
+++ b/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||||
@@ -18,7 +18,7 @@ public class LevelChunkSection implements ca.spottedleaf.moonrise.patches.block_
|
||||
public static final int SECTION_HEIGHT = 16;
|
||||
public static final int SECTION_SIZE = 4096;
|
||||
public static final int BIOME_CONTAINER_BITS = 2;
|
||||
- short nonEmptyBlockCount; // Paper - package private
|
||||
+ volatile short nonEmptyBlockCount; // Paper - package private // Leaf - Async chunk send - volatile
|
||||
private short tickingBlockCount;
|
||||
private short tickingFluidCount;
|
||||
private boolean isRandomlyTickingBlocksStatus; // Leaf - Cache random tick block status
|
||||
@@ -1,108 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Taiyou06 <kaandindar21@gmail.com>
|
||||
Date: Sun, 2 Mar 2025 21:23:20 +0100
|
||||
Subject: [PATCH] Async chunk sending
|
||||
|
||||
|
||||
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
|
||||
index 32608df3da169159c070f37cb55407f4f6187744..67275e803e0287306b163f4eec17388b9c701a8c 100644
|
||||
--- a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
|
||||
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
|
||||
@@ -409,19 +409,91 @@ public final class RegionizedPlayerChunkLoader {
|
||||
this.delayedTicketOps.addLast(op);
|
||||
}
|
||||
|
||||
+ // Leaf start - Async chunk sending
|
||||
+ /**
|
||||
+ * Sends a chunk to the player.
|
||||
+ * If async chunk sending is enabled, this will prepare and send the chunk packet asynchronously.
|
||||
+ * Otherwise, it will use the synchronous chunk sending implementation.
|
||||
+ */
|
||||
private void sendChunk(final int chunkX, final int chunkZ) {
|
||||
- if (this.sentChunks.add(CoordinateUtils.getChunkKey(chunkX, chunkZ))) {
|
||||
- ((ChunkSystemChunkHolder)((ChunkSystemServerLevel)this.world).moonrise$getChunkTaskScheduler().chunkHolderManager
|
||||
- .getChunkHolder(chunkX, chunkZ).vanillaChunkHolder).moonrise$addReceivedChunk(this.player);
|
||||
+ final long chunkKey = CoordinateUtils.getChunkKey(chunkX, chunkZ);
|
||||
|
||||
- final LevelChunk chunk = ((ChunkSystemLevel)this.world).moonrise$getFullChunkIfLoaded(chunkX, chunkZ);
|
||||
+ if (!this.sentChunks.add(chunkKey)) {
|
||||
+ // Already in our sent list - silently return instead of throwing an exception
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ // Get the chunk now, as we need it for both sync and async paths
|
||||
+ final LevelChunk chunk = ((ChunkSystemLevel) this.world).moonrise$getFullChunkIfLoaded(chunkX, chunkZ);
|
||||
+ if (chunk == null) {
|
||||
+ // Handle case where chunk is no longer loaded
|
||||
+ this.sentChunks.remove(chunkKey);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ // Try to mark the chunk as received by this player
|
||||
+ try {
|
||||
+ // This part needs to remain on the main thread as it affects shared state
|
||||
+ ((ChunkSystemServerLevel) this.world).moonrise$getChunkTaskScheduler().chunkHolderManager
|
||||
+ .getChunkHolder(chunkX, chunkZ).vanillaChunkHolder.moonrise$addReceivedChunk(this.player);
|
||||
|
||||
+ // Call onChunkWatch on the main thread as it might affect server state
|
||||
PlatformHooks.get().onChunkWatch(this.world, chunk, this.player);
|
||||
- PlayerChunkSender.sendChunk(this.player.connection, this.world, chunk);
|
||||
+ } catch (IllegalStateException e) {
|
||||
+ // This happens if the chunk was already marked as received by this player
|
||||
+ // Just remove it from our sent list and return
|
||||
+ this.sentChunks.remove(chunkKey);
|
||||
return;
|
||||
}
|
||||
- throw new IllegalStateException();
|
||||
+
|
||||
+ // Check if async chunk sending is enabled
|
||||
+ if (org.dreeam.leaf.config.modules.async.AsyncChunkSend.enabled) {
|
||||
+ // Async implementation
|
||||
+ net.minecraft.Util.backgroundExecutor().execute(() -> {
|
||||
+ try {
|
||||
+ final net.minecraft.server.network.ServerGamePacketListenerImpl connection = this.player.connection;
|
||||
+ final ServerLevel serverLevel = this.world;
|
||||
+
|
||||
+ // Create the packet with anti-xray control flag
|
||||
+ final net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket packet = new net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket(
|
||||
+ chunk, serverLevel.getLightEngine(), null, null,
|
||||
+ serverLevel.chunkPacketBlockController.shouldModify(this.player, chunk)
|
||||
+ );
|
||||
+
|
||||
+ // Let the main thread handle the anti-xray processing
|
||||
+ serverLevel.getServer().execute(() -> {
|
||||
+ if (this.removed || !this.sentChunks.contains(chunkKey)) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ // This will trigger anti-xray processing and mark the packet as ready when done
|
||||
+ // The packet automatically handles readiness
|
||||
+ // Send the packet (which will be held until ready by the network layer)
|
||||
+ connection.send(packet);
|
||||
+
|
||||
+ // Fire events and send POI packets
|
||||
+ if (io.papermc.paper.event.packet.PlayerChunkLoadEvent.getHandlerList().getRegisteredListeners().length > 0) {
|
||||
+ new io.papermc.paper.event.packet.PlayerChunkLoadEvent(
|
||||
+ new org.bukkit.craftbukkit.CraftChunk(chunk),
|
||||
+ this.player.getBukkitEntity()
|
||||
+ ).callEvent();
|
||||
+ }
|
||||
+
|
||||
+ net.minecraft.network.protocol.game.DebugPackets.sendPoiPacketsForChunk(serverLevel, chunk.getPos());
|
||||
+ });
|
||||
+ } catch (Exception e) {
|
||||
+ org.dreeam.leaf.async.AsyncChunkSending.LOGGER.error("Failed to send chunk asynchronously!", e);
|
||||
+
|
||||
+ if (!this.removed) {
|
||||
+ this.sentChunks.remove(chunkKey);
|
||||
+ }
|
||||
+ }
|
||||
+ });
|
||||
+ } else {
|
||||
+ PlayerChunkSender.sendChunk(this.player.connection, this.world, chunk);
|
||||
+ }
|
||||
}
|
||||
+ // Leaf end - Async chunk sending
|
||||
|
||||
private void sendUnloadChunk(final int chunkX, final int chunkZ) {
|
||||
if (!this.sentChunks.remove(CoordinateUtils.getChunkKey(chunkX, chunkZ))) {
|
||||
@@ -5,7 +5,7 @@ Subject: [PATCH] Spawner Configurations
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/level/BaseSpawner.java b/net/minecraft/world/level/BaseSpawner.java
|
||||
index 9fa9d84033c28071120e8a1c796ace4f9a45d4c5..9914e347838f55b4658a0ab8998bc0eeade0f4f8 100644
|
||||
index 9fa9d84033c28071120e8a1c796ace4f9a45d4c5..dc1d0c8a5b26142eeb8b9c167cef8d3ddcc1ad55 100644
|
||||
--- a/net/minecraft/world/level/BaseSpawner.java
|
||||
+++ b/net/minecraft/world/level/BaseSpawner.java
|
||||
@@ -55,6 +55,12 @@ public abstract class BaseSpawner {
|
||||
@@ -58,7 +58,7 @@ index 9fa9d84033c28071120e8a1c796ace4f9a45d4c5..9914e347838f55b4658a0ab8998bc0ee
|
||||
if (this.isNearPlayer(serverLevel, pos)) {
|
||||
if (this.spawnDelay < -tickDelay) { // Paper - Configurable mob spawner tick rate
|
||||
this.delay(serverLevel, pos);
|
||||
@@ -112,18 +141,41 @@ public abstract class BaseSpawner {
|
||||
@@ -112,18 +141,48 @@ public abstract class BaseSpawner {
|
||||
pos.getZ() + (random.nextDouble() - random.nextDouble()) * this.spawnRange + 0.5
|
||||
)
|
||||
);
|
||||
@@ -68,7 +68,11 @@ index 9fa9d84033c28071120e8a1c796ace4f9a45d4c5..9914e347838f55b4658a0ab8998bc0ee
|
||||
+ boolean skipBlockChecks = org.dreeam.leaf.config.modules.gameplay.SpawnerSettings.enabled &&
|
||||
+ !org.dreeam.leaf.config.modules.gameplay.SpawnerSettings.spawnerBlockChecks;
|
||||
+ if (skipBlockChecks || serverLevel.noCollision(optional.get().getSpawnAABB(vec3.x, vec3.y, vec3.z))) {
|
||||
+ // 'skipBlockChecks' is true if SpawnerSettings.spawnerBlockChecks is false.
|
||||
+ // It means we skip physical block checks like collision and custom rule isValidPosition.
|
||||
+
|
||||
BlockPos blockPos = BlockPos.containing(vec3);
|
||||
+
|
||||
+ // Add light level check if enabled
|
||||
+ if (org.dreeam.leaf.config.modules.gameplay.SpawnerSettings.enabled &&
|
||||
+ org.dreeam.leaf.config.modules.gameplay.SpawnerSettings.lightLevelCheck) {
|
||||
@@ -85,8 +89,9 @@ index 9fa9d84033c28071120e8a1c796ace4f9a45d4c5..9914e347838f55b4658a0ab8998bc0ee
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ // Handle spawn rules checks
|
||||
+ boolean skipSpawnRules = false;
|
||||
+ // Determine if mob-specific spawn rules (like block types, biome requirements) should be skipped
|
||||
+ boolean skipMobSpecificRules = org.dreeam.leaf.config.modules.gameplay.SpawnerSettings.enabled &&
|
||||
+ org.dreeam.leaf.config.modules.gameplay.SpawnerSettings.ignoreSpawnRules;
|
||||
+ // Leaf end - Spawner Configurations
|
||||
if (nextSpawnData.getCustomSpawnRules().isPresent()) {
|
||||
if (!optional.get().getCategory().isFriendly() && serverLevel.getDifficulty() == Difficulty.PEACEFUL) {
|
||||
@@ -95,15 +100,17 @@ index 9fa9d84033c28071120e8a1c796ace4f9a45d4c5..9914e347838f55b4658a0ab8998bc0ee
|
||||
|
||||
SpawnData.CustomSpawnRules customSpawnRules = nextSpawnData.getCustomSpawnRules().get();
|
||||
- if (!customSpawnRules.isValidPosition(blockPos, serverLevel)) {
|
||||
+ // customSpawnRules.isValidPosition is controlled by spawnerBlockChecks (via !skipBlockChecks)
|
||||
+ if (!skipBlockChecks && !customSpawnRules.isValidPosition(blockPos, serverLevel)) { // Leaf - Spawner Configurations
|
||||
continue;
|
||||
}
|
||||
- } else if (!SpawnPlacements.checkSpawnRules(optional.get(), serverLevel, EntitySpawnReason.SPAWNER, blockPos, serverLevel.getRandom())) {
|
||||
+ } else if (!skipBlockChecks && !SpawnPlacements.checkSpawnRules(optional.get(), serverLevel, EntitySpawnReason.SPAWNER, blockPos, serverLevel.getRandom())) { // Leaf - Spawner Configurations
|
||||
+ } else if (!skipMobSpecificRules && !SpawnPlacements.checkSpawnRules(optional.get(), serverLevel, EntitySpawnReason.SPAWNER, blockPos, serverLevel.getRandom())) {
|
||||
+ // If not skipping mob-specific rules AND standard spawn rules fail, continue.
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -151,6 +203,7 @@ public abstract class BaseSpawner {
|
||||
@@ -151,6 +210,7 @@ public abstract class BaseSpawner {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -111,7 +118,7 @@ index 9fa9d84033c28071120e8a1c796ace4f9a45d4c5..9914e347838f55b4658a0ab8998bc0ee
|
||||
int size = serverLevel.getEntities(
|
||||
EntityTypeTest.forExactClass(entity.getClass()),
|
||||
new AABB(pos.getX(), pos.getY(), pos.getZ(), pos.getX() + 1, pos.getY() + 1, pos.getZ() + 1).inflate(this.spawnRange),
|
||||
@@ -161,12 +214,16 @@ public abstract class BaseSpawner {
|
||||
@@ -161,12 +221,29 @@ public abstract class BaseSpawner {
|
||||
this.delay(serverLevel, pos);
|
||||
return;
|
||||
}
|
||||
@@ -123,14 +130,27 @@ index 9fa9d84033c28071120e8a1c796ace4f9a45d4c5..9914e347838f55b4658a0ab8998bc0ee
|
||||
- if (nextSpawnData.getCustomSpawnRules().isEmpty() && !mob.checkSpawnRules(serverLevel, EntitySpawnReason.SPAWNER)
|
||||
- || !mob.checkSpawnObstruction(serverLevel)) {
|
||||
+ // Leaf start - Spawner Configurations
|
||||
+ // Skip spawn rule and obstruction checks if block checks are disabled
|
||||
+ if (!skipBlockChecks && (nextSpawnData.getCustomSpawnRules().isEmpty() && !mob.checkSpawnRules(serverLevel, EntitySpawnReason.SPAWNER)
|
||||
+ || !mob.checkSpawnObstruction(serverLevel))) {
|
||||
+ // mob.checkSpawnRules is controlled by ignoreSpawnRules (via !skipMobSpecificRules)
|
||||
+ // mob.checkSpawnObstruction is controlled by spawnerBlockChecks (via !skipBlockChecks)
|
||||
+
|
||||
+ boolean mobSpecificRulesFailed = false;
|
||||
+ if (nextSpawnData.getCustomSpawnRules().isEmpty() && !skipMobSpecificRules) {
|
||||
+ if (!mob.checkSpawnRules(serverLevel, EntitySpawnReason.SPAWNER)) {
|
||||
+ mobSpecificRulesFailed = true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ boolean obstructionFailed = false;
|
||||
+ if (!skipBlockChecks && !mob.checkSpawnObstruction(serverLevel)) { // If not skipping physical checks and obstruction fails
|
||||
+ obstructionFailed = true;
|
||||
+ }
|
||||
+
|
||||
+ if (mobSpecificRulesFailed || obstructionFailed) {
|
||||
+ // Leaf end - Spawner Configurations
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -231,10 +288,16 @@ public abstract class BaseSpawner {
|
||||
@@ -231,10 +308,16 @@ public abstract class BaseSpawner {
|
||||
tag.read("SpawnData", SpawnData.CODEC).ifPresent(spawnData -> this.setNextSpawnData(level, pos, spawnData));
|
||||
this.spawnPotentials = tag.read("SpawnPotentials", SpawnData.LIST_CODEC)
|
||||
.orElseGet(() -> WeightedList.of(this.nextSpawnData != null ? this.nextSpawnData : new SpawnData()));
|
||||
|
||||
@@ -5,10 +5,10 @@ Subject: [PATCH] Optimize addOrUpdateTransientModifier
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/entity/ai/attributes/AttributeInstance.java b/net/minecraft/world/entity/ai/attributes/AttributeInstance.java
|
||||
index 11520972f4fabde3be48edd296351113453b2869..5fe88b105efd3546c675b3397be46bf42e830fb3 100644
|
||||
index 3ac9f36eae87369354e992a1d9b5c5b2d87d17cb..c39654d3e1e5573646b3729502e4eae1a6dba7c9 100644
|
||||
--- a/net/minecraft/world/entity/ai/attributes/AttributeInstance.java
|
||||
+++ b/net/minecraft/world/entity/ai/attributes/AttributeInstance.java
|
||||
@@ -90,8 +90,13 @@ public class AttributeInstance {
|
||||
@@ -87,8 +87,13 @@ public class AttributeInstance {
|
||||
}
|
||||
|
||||
public void addOrUpdateTransientModifier(AttributeModifier modifier) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,110 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Taiyou06 <kaandindar21@gmail.com>
|
||||
Date: Sun, 13 Apr 2025 16:15:17 +0200
|
||||
Subject: [PATCH] Replace ConcurrentLong2ReferenceChainedHashTable with custom
|
||||
map
|
||||
|
||||
|
||||
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/queue/ChunkUnloadQueue.java b/ca/spottedleaf/moonrise/patches/chunk_system/queue/ChunkUnloadQueue.java
|
||||
index 7eafc5b7cba23d8dec92ecc1050afe3fd8c9e309..9b421f0681fe740520457951b1a1632ada59438a 100644
|
||||
--- a/ca/spottedleaf/moonrise/patches/chunk_system/queue/ChunkUnloadQueue.java
|
||||
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/queue/ChunkUnloadQueue.java
|
||||
@@ -16,7 +16,7 @@ public final class ChunkUnloadQueue {
|
||||
|
||||
public final int coordinateShift;
|
||||
private final AtomicLong orderGenerator = new AtomicLong();
|
||||
- private final ConcurrentLong2ReferenceChainedHashTable<UnloadSection> unloadSections = new ConcurrentLong2ReferenceChainedHashTable<>();
|
||||
+ private final org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable<UnloadSection> unloadSections = new org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable<>(); // Leaf - Replace ConcurrentLong2ReferenceChainedHashTable with custom map
|
||||
|
||||
/*
|
||||
* Note: write operations do not occur in parallel for any given section.
|
||||
@@ -32,8 +32,10 @@ public final class ChunkUnloadQueue {
|
||||
public List<SectionToUnload> retrieveForAllRegions() {
|
||||
final List<SectionToUnload> ret = new ArrayList<>();
|
||||
|
||||
- for (final Iterator<ConcurrentLong2ReferenceChainedHashTable.TableEntry<UnloadSection>> iterator = this.unloadSections.entryIterator(); iterator.hasNext();) {
|
||||
- final ConcurrentLong2ReferenceChainedHashTable.TableEntry<UnloadSection> entry = iterator.next();
|
||||
+ // Leaf start - Replace ConcurrentLong2ReferenceChainedHashTable with custom map
|
||||
+ for (final Iterator<org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable.TableEntry<UnloadSection>> iterator = this.unloadSections.entryIterator(); iterator.hasNext(); ) {
|
||||
+ final org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable.TableEntry<UnloadSection> entry = iterator.next();
|
||||
+ // Leaf end - Replace ConcurrentLong2ReferenceChainedHashTable with custom map
|
||||
final long key = entry.getKey();
|
||||
final UnloadSection section = entry.getValue();
|
||||
final int sectionX = CoordinateUtils.getChunkX(key);
|
||||
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java
|
||||
index ea4010df54dbd17cdae22d671ea1e4bd7b685b3e..9f771d78f5401ce8776de38d11e453e8e5857572 100644
|
||||
--- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java
|
||||
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java
|
||||
@@ -72,11 +72,13 @@ public final class ChunkHolderManager {
|
||||
private static final long NO_TIMEOUT_MARKER = Long.MIN_VALUE;
|
||||
public final ReentrantAreaLock ticketLockArea;
|
||||
|
||||
- private final ConcurrentLong2ReferenceChainedHashTable<SortedArraySet<Ticket>> tickets = new ConcurrentLong2ReferenceChainedHashTable<>();
|
||||
- private final ConcurrentLong2ReferenceChainedHashTable<Long2IntOpenHashMap> sectionToChunkToExpireCount = new ConcurrentLong2ReferenceChainedHashTable<>();
|
||||
+ // Leaf start - Replace ConcurrentLong2ReferenceChainedHashTable with custom map
|
||||
+ private final org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable<SortedArraySet<Ticket>> tickets = new org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable<>();
|
||||
+ private final org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable<Long2IntOpenHashMap> sectionToChunkToExpireCount = new org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable<>();
|
||||
+ // Leaf end - Replace ConcurrentLong2ReferenceChainedHashTable with custom map
|
||||
final ChunkUnloadQueue unloadQueue;
|
||||
|
||||
- private final ConcurrentLong2ReferenceChainedHashTable<NewChunkHolder> chunkHolders = ConcurrentLong2ReferenceChainedHashTable.createWithCapacity(16384, 0.25f);
|
||||
+ private final org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable<NewChunkHolder> chunkHolders = org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable.createWithCapacity(16384, 0.25f); // Leaf - Replace ConcurrentLong2ReferenceChainedHashTable with custom map
|
||||
private final ServerLevel world;
|
||||
private final ChunkTaskScheduler taskScheduler;
|
||||
private long currentTick;
|
||||
@@ -1502,9 +1504,9 @@ public final class ChunkHolderManager {
|
||||
final JsonArray allTicketsJson = new JsonArray();
|
||||
ret.add("tickets", allTicketsJson);
|
||||
|
||||
- for (final Iterator<ConcurrentLong2ReferenceChainedHashTable.TableEntry<SortedArraySet<Ticket>>> iterator = this.tickets.entryIterator();
|
||||
+ for (final Iterator<org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable.TableEntry<SortedArraySet<Ticket>>> iterator = this.tickets.entryIterator(); // Leaf - Replace ConcurrentLong2ReferenceChainedHashTable with custom map
|
||||
iterator.hasNext();) {
|
||||
- final ConcurrentLong2ReferenceChainedHashTable.TableEntry<SortedArraySet<Ticket>> coordinateTickets = iterator.next();
|
||||
+ final org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable.TableEntry<SortedArraySet<Ticket>> coordinateTickets = iterator.next(); // Leaf - Replace ConcurrentLong2ReferenceChainedHashTable with custom map
|
||||
final long coordinate = coordinateTickets.getKey();
|
||||
final SortedArraySet<Ticket> tickets = coordinateTickets.getValue();
|
||||
|
||||
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ThreadedTicketLevelPropagator.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ThreadedTicketLevelPropagator.java
|
||||
index 310a8f80debadd64c2d962ebf83b7d0505ce6e42..3a7fad46465cac8d2c1b0933b457f5b075586709 100644
|
||||
--- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ThreadedTicketLevelPropagator.java
|
||||
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ThreadedTicketLevelPropagator.java
|
||||
@@ -35,11 +35,11 @@ public abstract class ThreadedTicketLevelPropagator {
|
||||
}
|
||||
|
||||
private final UpdateQueue updateQueue;
|
||||
- private final ConcurrentLong2ReferenceChainedHashTable<Section> sections;
|
||||
+ private final org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable<Section> sections; // Leaf - Replace ConcurrentLong2ReferenceChainedHashTable with custom map
|
||||
|
||||
public ThreadedTicketLevelPropagator() {
|
||||
this.updateQueue = new UpdateQueue();
|
||||
- this.sections = new ConcurrentLong2ReferenceChainedHashTable<>();
|
||||
+ this.sections = new org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable<>(); // Leaf - Replace ConcurrentLong2ReferenceChainedHashTable with custom map
|
||||
}
|
||||
|
||||
// must hold ticket lock for:
|
||||
diff --git a/ca/spottedleaf/moonrise/patches/starlight/light/StarLightInterface.java b/ca/spottedleaf/moonrise/patches/starlight/light/StarLightInterface.java
|
||||
index e1812910d7c3941dec3d4f1c90f4cf966a631de3..87c229db79f6c6dc98811c7cbccbe5c549fd744f 100644
|
||||
--- a/ca/spottedleaf/moonrise/patches/starlight/light/StarLightInterface.java
|
||||
+++ b/ca/spottedleaf/moonrise/patches/starlight/light/StarLightInterface.java
|
||||
@@ -739,7 +739,7 @@ public final class StarLightInterface {
|
||||
|
||||
public static final class ServerLightQueue extends LightQueue {
|
||||
|
||||
- private final ConcurrentLong2ReferenceChainedHashTable<ServerChunkTasks> chunkTasks = new ConcurrentLong2ReferenceChainedHashTable<>();
|
||||
+ private final org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable<ServerChunkTasks> chunkTasks = new org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable<>(); // Leaf - Replace ConcurrentLong2ReferenceChainedHashTable with custom map
|
||||
|
||||
public ServerLightQueue(final StarLightInterface lightInterface) {
|
||||
super(lightInterface);
|
||||
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
|
||||
index 0f9d18dd29e210ad656da211a3cb1cb25cd4efb1..f89fb321e50338e7765476cb5d7bdf2f02a497b3 100644
|
||||
--- a/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -76,7 +76,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
@VisibleForDebug
|
||||
private NaturalSpawner.SpawnState lastSpawnState;
|
||||
// Paper start
|
||||
- private final ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable<net.minecraft.world.level.chunk.LevelChunk> fullChunks = new ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable<>();
|
||||
+ private final org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable<LevelChunk> fullChunks = new org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable<>(); // Leaf - Replace ConcurrentLong2ReferenceChainedHashTable with custom map
|
||||
public int getFullChunksCount() {
|
||||
return this.fullChunks.size();
|
||||
}
|
||||
@@ -5,7 +5,7 @@ Subject: [PATCH] Optimize ThreadedTicketLevelPropagator
|
||||
|
||||
|
||||
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ThreadedTicketLevelPropagator.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ThreadedTicketLevelPropagator.java
|
||||
index 3a7fad46465cac8d2c1b0933b457f5b075586709..a2d76e6fabf2749a1a9f21fe6bdf6524af8bb9b7 100644
|
||||
index 310a8f80debadd64c2d962ebf83b7d0505ce6e42..878f8beb769e87f1de70e7be963e88678a89dd0a 100644
|
||||
--- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ThreadedTicketLevelPropagator.java
|
||||
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ThreadedTicketLevelPropagator.java
|
||||
@@ -998,6 +998,7 @@ public abstract class ThreadedTicketLevelPropagator {
|
||||
@@ -159,7 +159,7 @@ index 4ca68a903e67606fc4ef0bfa9862a73797121c8b..bed3a64388bb43e47c2ba4e67f7dde5b
|
||||
|
||||
public static final class SaveState {
|
||||
diff --git a/net/minecraft/world/level/chunk/LevelChunkSection.java b/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||||
index 36c033b0ee63dfc273d721fb4b614733e8fdef19..dc9f1bc6dd8b1057da3416e24f15f2329658f996 100644
|
||||
index 1cc33a038060aaf5258ee4f1deb19b4a1be59a29..a14247b043715de50b253ab1f10a9244003f8797 100644
|
||||
--- a/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||||
+++ b/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||||
@@ -24,6 +24,7 @@ public class LevelChunkSection implements ca.spottedleaf.moonrise.patches.block_
|
||||
@@ -15,7 +15,7 @@ The delay is currently set to 2 seconds, however, we may want to adjust this bef
|
||||
fixes Paper#9581
|
||||
|
||||
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
|
||||
index 67275e803e0287306b163f4eec17388b9c701a8c..4344e5d9eda940849352e08734f95de2036bd87a 100644
|
||||
index 3a78e7512772fd3f7cf8f221e3a72474def14bea..ba52af914e9e231caa0ac50562e9a6925908c615 100644
|
||||
--- a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
|
||||
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
|
||||
@@ -48,6 +48,7 @@ public final class RegionizedPlayerChunkLoader {
|
||||
@@ -5,10 +5,10 @@ Subject: [PATCH] Sakura: copy-EntityList-implementation-to-BasicEntityList
|
||||
|
||||
|
||||
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
|
||||
index 7b686d834e4eb36be5758b0e0a846a70d1e2294b..37930d1b87378ac3e8c7f5ebd79148bb66771f48 100644
|
||||
index 956d48fb7146b9eb2a5b5b4e23a83f60d0e40b4c..5847cbe6229f217d0361eda0950668bd0e9573f4 100644
|
||||
--- a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
|
||||
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
|
||||
@@ -382,6 +382,13 @@ public final class ChunkEntitySlices {
|
||||
@@ -415,6 +415,13 @@ public final class ChunkEntitySlices {
|
||||
|
||||
private E[] storage;
|
||||
private int size;
|
||||
@@ -22,7 +22,7 @@ index 7b686d834e4eb36be5758b0e0a846a70d1e2294b..37930d1b87378ac3e8c7f5ebd79148bb
|
||||
|
||||
public BasicEntityList() {
|
||||
this(0);
|
||||
@@ -402,6 +409,7 @@ public final class ChunkEntitySlices {
|
||||
@@ -435,6 +442,7 @@ public final class ChunkEntitySlices {
|
||||
private void resize() {
|
||||
if (this.storage == me.titaniumtown.ArrayConstants.emptyEntityArray) { // Gale - JettPack - reduce array allocations
|
||||
this.storage = (E[])new Entity[DEFAULT_CAPACITY];
|
||||
@@ -30,7 +30,7 @@ index 7b686d834e4eb36be5758b0e0a846a70d1e2294b..37930d1b87378ac3e8c7f5ebd79148bb
|
||||
} else {
|
||||
this.storage = Arrays.copyOf(this.storage, this.storage.length * 2);
|
||||
}
|
||||
@@ -415,6 +423,7 @@ public final class ChunkEntitySlices {
|
||||
@@ -448,6 +456,7 @@ public final class ChunkEntitySlices {
|
||||
} else {
|
||||
this.storage[idx] = entity;
|
||||
}
|
||||
@@ -38,7 +38,7 @@ index 7b686d834e4eb36be5758b0e0a846a70d1e2294b..37930d1b87378ac3e8c7f5ebd79148bb
|
||||
}
|
||||
|
||||
public int indexOf(final E entity) {
|
||||
@@ -430,24 +439,32 @@ public final class ChunkEntitySlices {
|
||||
@@ -463,24 +472,32 @@ public final class ChunkEntitySlices {
|
||||
}
|
||||
|
||||
public boolean remove(final E entity) {
|
||||
@@ -0,0 +1,85 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: hayanesuru <hayanesuru@outlook.jp>
|
||||
Date: Tue, 6 May 2025 17:44:16 +0900
|
||||
Subject: [PATCH] Protocol Core
|
||||
|
||||
|
||||
diff --git a/net/minecraft/network/protocol/common/custom/CustomPacketPayload.java b/net/minecraft/network/protocol/common/custom/CustomPacketPayload.java
|
||||
index fb263fa1f30a7dfcb7ec2656abfb38e5fe88eac9..a5f4deff8ecde365b7fbec92760b1a7cc5b8c58e 100644
|
||||
--- a/net/minecraft/network/protocol/common/custom/CustomPacketPayload.java
|
||||
+++ b/net/minecraft/network/protocol/common/custom/CustomPacketPayload.java
|
||||
@@ -40,6 +40,12 @@ public interface CustomPacketPayload {
|
||||
|
||||
@Override
|
||||
public void encode(B buffer, CustomPacketPayload value) {
|
||||
+ // Leaf start - Protocol core
|
||||
+ if (value instanceof org.dreeam.leaf.protocol.LeafCustomPayload payload) {
|
||||
+ org.dreeam.leaf.protocol.Protocols.write(buffer, payload);
|
||||
+ return;
|
||||
+ }
|
||||
+ // Leaf end - Protocol core
|
||||
this.writeCap(buffer, value.type(), value);
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index 78aee57ad8224b0728411c699d2e3844847c9c79..8f5b400bdf5c1c194f75ee98e2f1e984e6137a50 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -1770,6 +1770,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
GameTestTicker.SINGLETON.tick();
|
||||
}
|
||||
|
||||
+ org.dreeam.leaf.protocol.Protocols.tickServer(this); // Leaf - Protocol core
|
||||
+
|
||||
for (int i = 0; i < this.tickables.size(); i++) {
|
||||
this.tickables.get(i).run();
|
||||
}
|
||||
diff --git a/net/minecraft/server/level/ServerEntity.java b/net/minecraft/server/level/ServerEntity.java
|
||||
index 867936866d952c559b6ffa49fdf78acd70a9bab9..b1953701583ba88c524368a52988fea6fb1ab8d2 100644
|
||||
--- a/net/minecraft/server/level/ServerEntity.java
|
||||
+++ b/net/minecraft/server/level/ServerEntity.java
|
||||
@@ -298,6 +298,7 @@ public class ServerEntity {
|
||||
this.entity.hurtMarked = false;
|
||||
this.broadcastAndSend(new ClientboundSetEntityMotionPacket(this.entity));
|
||||
}
|
||||
+ if (entity instanceof ServerPlayer serverPlayer) org.dreeam.leaf.protocol.Protocols.tickTracker(serverPlayer); // Leaf - Protocol core
|
||||
}
|
||||
|
||||
private Stream<Entity> mountedOrDismounted(List<Entity> entities) {
|
||||
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
|
||||
index ff4ca34dca8e0061977ea63707eb34c6e06dd66a..30783379baee569ec7ff51d34524ccdcba38d764 100644
|
||||
--- a/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -809,6 +809,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
}
|
||||
}
|
||||
// Purpur end - Ridables
|
||||
+ org.dreeam.leaf.protocol.Protocols.tickPlayer(this); // Leaf - Protocol core
|
||||
}
|
||||
|
||||
private void updatePlayerAttributes() {
|
||||
diff --git a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
|
||||
index 434be9d08d8e816e2dea1e9d23fa26d21b9f35f6..98f169c64b31ff523fe8b2d435f796a5156203a9 100644
|
||||
--- a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
|
||||
@@ -162,6 +162,8 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
|
||||
|
||||
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel());
|
||||
|
||||
+ org.dreeam.leaf.protocol.Protocols.handle(this.player, discardedPayload); // Leaf - Protocol core
|
||||
+
|
||||
final net.minecraft.resources.ResourceLocation identifier = packet.payload().type().id();
|
||||
final byte[] data = discardedPayload.data();
|
||||
try {
|
||||
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
|
||||
index 8173242d149709f092e6d609f6e1d831eca0a884..05bc165ecae4151355dd9329673f10cff6253ca4 100644
|
||||
--- a/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/net/minecraft/server/players/PlayerList.java
|
||||
@@ -536,6 +536,7 @@ public abstract class PlayerList {
|
||||
return this.remove(player, net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? player.getBukkitEntity().displayName() : io.papermc.paper.adventure.PaperAdventure.asAdventure(player.getDisplayName())));
|
||||
}
|
||||
public @Nullable net.kyori.adventure.text.Component remove(ServerPlayer player, net.kyori.adventure.text.Component leaveMessage) {
|
||||
+ org.dreeam.leaf.protocol.Protocols.disconnected(player); // Leaf - Protocol core
|
||||
// Paper end - Fix kick event leave message not being sent
|
||||
org.purpurmc.purpur.task.BossBarTask.removeFromAll(player.getBukkitEntity()); // Purpur - Implement TPSBar
|
||||
net.minecraft.server.network.ServerGamePacketListenerImpl.afkCooldown.remove(player.getBukkitEntity().getUniqueId()); // Leaf - Improve Purpur AFK system
|
||||
@@ -0,0 +1,28 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Taiyou06 <kaandindar21@gmail.com>
|
||||
Date: Thu, 8 May 2025 10:08:54 +0200
|
||||
Subject: [PATCH] Reduce PlayerChunk Updates
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index a3069b29a1b78012314747d705e27c167acd10b3..3b322c7d65a7f71b94cff660d8702abf646f52e6 100644
|
||||
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -1418,6 +1418,8 @@ public class ServerGamePacketListenerImpl
|
||||
this.resetPosition();
|
||||
}
|
||||
|
||||
+ final net.minecraft.world.level.ChunkPos playerStartChunkPosition = this.player.chunkPosition(); // Leaf - Reduce PlayerChunk Updates
|
||||
+
|
||||
if (this.player.hasClientLoaded()) {
|
||||
float f = Mth.wrapDegrees(packet.getYRot(this.player.getYRot())); final float toYaw = f; // Paper - OBFHELPER
|
||||
float f1 = Mth.wrapDegrees(packet.getXRot(this.player.getXRot())); final float toPitch = f1; // Paper - OBFHELPER
|
||||
@@ -1696,7 +1698,7 @@ public class ServerGamePacketListenerImpl
|
||||
&& !isFallFlying
|
||||
&& !isAutoSpinAttack
|
||||
&& this.noBlocksAround(this.player);
|
||||
- this.player.serverLevel().getChunkSource().move(this.player);
|
||||
+ if (!org.dreeam.leaf.config.modules.opt.ReduceChunkSourceUpdates.enabled || this.player.serverLevel() != serverLevel || this.player.chunkPosition() == playerStartChunkPosition) this.player.serverLevel().getChunkSource().move(this.player); // Leaf - Reduce PlayerChunk Updates
|
||||
Vec3 vec3 = new Vec3(this.player.getX() - x, this.player.getY() - y, this.player.getZ() - z);
|
||||
this.player.setOnGroundWithMovement(packet.isOnGround(), packet.horizontalCollision(), vec3);
|
||||
this.player.doCheckFallDamage(vec3.x, vec3.y, vec3.z, packet.isOnGround());
|
||||
@@ -0,0 +1,156 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: hayanesuru <hayanesuru@outlook.jp>
|
||||
Date: Fri, 9 May 2025 16:55:34 +0900
|
||||
Subject: [PATCH] Async switch connection state
|
||||
|
||||
|
||||
diff --git a/net/minecraft/network/Connection.java b/net/minecraft/network/Connection.java
|
||||
index f3e9de8716f5e1a72ec465ee897c8f0413f7b1c3..c83ee2137a57e62003b1d20c3ceea9f569350a53 100644
|
||||
--- a/net/minecraft/network/Connection.java
|
||||
+++ b/net/minecraft/network/Connection.java
|
||||
@@ -342,6 +342,11 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
if (protocolInfo.flow() != this.getReceiving()) {
|
||||
throw new IllegalStateException("Invalid inbound protocol: " + protocolInfo.id());
|
||||
} else {
|
||||
+ // Leaf start - Async switch connection state
|
||||
+ if (org.dreeam.leaf.config.modules.network.AlternativeJoin.enabled && ca.spottedleaf.moonrise.common.util.TickThread.isTickThread()) {
|
||||
+ this.channel.config().setAutoRead(false);
|
||||
+ }
|
||||
+ // Leaf end - Async switch connection state
|
||||
this.packetListener = packetInfo;
|
||||
this.disconnectListener = null;
|
||||
UnconfiguredPipelineHandler.InboundConfigurationTask inboundConfigurationTask = UnconfiguredPipelineHandler.setupInboundProtocol(protocolInfo);
|
||||
@@ -351,7 +356,14 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
inboundConfigurationTask = inboundConfigurationTask.andThen(context -> context.pipeline().addAfter("decoder", "bundler", packetBundlePacker));
|
||||
}
|
||||
|
||||
- syncAfterConfigurationChange(this.channel.writeAndFlush(inboundConfigurationTask));
|
||||
+ // Leaf start - Async switch connection state
|
||||
+ var cf = this.channel.writeAndFlush(inboundConfigurationTask);
|
||||
+ if (org.dreeam.leaf.config.modules.network.AlternativeJoin.enabled && ca.spottedleaf.moonrise.common.util.TickThread.isTickThread()) {
|
||||
+ cf.addListener((ChannelFutureListener) Connection::syncAfterConfigurationChange);
|
||||
+ return;
|
||||
+ }
|
||||
+ syncAfterConfigurationChange(cf);
|
||||
+ // Leaf end - Async switch connection state
|
||||
}
|
||||
}
|
||||
|
||||
@@ -369,7 +381,38 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
}
|
||||
|
||||
boolean flag = protocolInfo.id() == ConnectionProtocol.LOGIN;
|
||||
- syncAfterConfigurationChange(this.channel.writeAndFlush(outboundConfigurationTask.andThen(context -> this.sendLoginDisconnect = flag)));
|
||||
+ var cf = this.channel.writeAndFlush(outboundConfigurationTask.andThen(context -> this.sendLoginDisconnect = flag));
|
||||
+ // Leaf start - Async switch connection state
|
||||
+ if (org.dreeam.leaf.config.modules.network.AlternativeJoin.enabled) {
|
||||
+ if (ca.spottedleaf.moonrise.common.util.TickThread.isTickThread()) {
|
||||
+ throw new IllegalStateException("Thread failed netty thread check: Switching outbound protocol state use setupOutboundProtocolAsync instead");
|
||||
+ }
|
||||
+ }
|
||||
+ syncAfterConfigurationChange(cf);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public @Nullable ChannelFuture setupOutboundProtocolAsync(ProtocolInfo<?> protocolInfo) {
|
||||
+ if (protocolInfo.flow() != this.getSending()) {
|
||||
+ throw new IllegalStateException("Invalid outbound protocol: " + protocolInfo.id());
|
||||
+ } else {
|
||||
+ UnconfiguredPipelineHandler.OutboundConfigurationTask outboundConfigurationTask = UnconfiguredPipelineHandler.setupOutboundProtocol(protocolInfo);
|
||||
+ BundlerInfo bundlerInfo = protocolInfo.bundlerInfo();
|
||||
+ if (bundlerInfo != null) {
|
||||
+ PacketBundleUnpacker packetBundleUnpacker = new PacketBundleUnpacker(bundlerInfo);
|
||||
+ outboundConfigurationTask = outboundConfigurationTask.andThen(
|
||||
+ context -> context.pipeline().addAfter("encoder", "unbundler", packetBundleUnpacker)
|
||||
+ );
|
||||
+ }
|
||||
+
|
||||
+ boolean flag = protocolInfo.id() == ConnectionProtocol.LOGIN;
|
||||
+ var cf = this.channel.writeAndFlush(outboundConfigurationTask.andThen(context -> this.sendLoginDisconnect = flag));
|
||||
+ if (org.dreeam.leaf.config.modules.network.AlternativeJoin.enabled) {
|
||||
+ cf.addListener((ChannelFutureListener) Connection::syncAfterConfigurationChange);
|
||||
+ return cf;
|
||||
+ }
|
||||
+ return null;
|
||||
+ // Leaf end - Async switch connection state
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java b/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java
|
||||
index 2e9eb04c7c4342393c05339906c267bca9ff29b1..53b9daa909c2b89046d5af515e17afe09ea7015a 100644
|
||||
--- a/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java
|
||||
@@ -140,11 +140,34 @@ public class ServerConfigurationPacketListenerImpl extends ServerCommonPacketLis
|
||||
}
|
||||
}
|
||||
|
||||
+ private volatile boolean changingState = false; // Leaf - Async switch connection state
|
||||
@Override
|
||||
public void handleConfigurationFinished(ServerboundFinishConfigurationPacket packet) {
|
||||
+ // Leaf start - Async switch connection state
|
||||
+ if (org.dreeam.leaf.config.modules.network.AlternativeJoin.enabled && !changingState) {
|
||||
+ changingState = true;
|
||||
+ this.finishCurrentTask(JoinWorldTask.TYPE);
|
||||
+ this.connection.setupOutboundProtocolAsync(GameProtocols.CLIENTBOUND_TEMPLATE.bind(RegistryFriendlyByteBuf.decorator(this.server.registryAccess()))).addListener(l -> {
|
||||
+ try {
|
||||
+ PacketUtils.ensureRunningOnSameThread(packet, this, this.server);
|
||||
+ } catch (net.minecraft.server.RunningOnDifferentThreadException ignored) {
|
||||
+ } catch (
|
||||
+ io.papermc.paper.util.ServerStopRejectedExecutionException ignored) { // Paper - do not prematurely disconnect players on stop
|
||||
+ } catch (java.util.concurrent.RejectedExecutionException var6) {
|
||||
+ this.connection.disconnect(Component.translatable("multiplayer.disconnect.server_shutdown"));
|
||||
+ } catch (ClassCastException var7) {
|
||||
+ LOGGER.error("Received {} that couldn't be processed", packet.getClass(), var7);
|
||||
+ this.connection.disconnect(Component.translatable("multiplayer.disconnect.invalid_packet"));
|
||||
+ }
|
||||
+ });
|
||||
+ return;
|
||||
+ }
|
||||
PacketUtils.ensureRunningOnSameThread(packet, this, this.server);
|
||||
- this.finishCurrentTask(JoinWorldTask.TYPE);
|
||||
- this.connection.setupOutboundProtocol(GameProtocols.CLIENTBOUND_TEMPLATE.bind(RegistryFriendlyByteBuf.decorator(this.server.registryAccess())));
|
||||
+ if (!org.dreeam.leaf.config.modules.network.AlternativeJoin.enabled) {
|
||||
+ this.finishCurrentTask(JoinWorldTask.TYPE);
|
||||
+ this.connection.setupOutboundProtocol(GameProtocols.CLIENTBOUND_TEMPLATE.bind(RegistryFriendlyByteBuf.decorator(this.server.registryAccess())));
|
||||
+ }
|
||||
+ // Leaf end - Async switch connection state
|
||||
|
||||
try {
|
||||
PlayerList playerList = this.server.getPlayerList();
|
||||
diff --git a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
index 405b62c082017024abae7ccc1db5f74caab1eabf..1ad1fc46775a473e6f7fd97eac4b8c7110c7332b 100644
|
||||
--- a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
@@ -471,11 +471,31 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
|
||||
this.disconnect(ServerCommonPacketListenerImpl.DISCONNECT_UNEXPECTED_QUERY);
|
||||
}
|
||||
|
||||
+ private volatile boolean changingState = false; // Leaf - Async switch connection state
|
||||
@Override
|
||||
public void handleLoginAcknowledgement(ServerboundLoginAcknowledgedPacket packet) {
|
||||
+ // Leaf start - Async switch connection state
|
||||
+ if (org.dreeam.leaf.config.modules.network.AlternativeJoin.enabled && !changingState) {
|
||||
+ changingState = true;
|
||||
+ this.connection.setupOutboundProtocolAsync(ConfigurationProtocols.CLIENTBOUND).addListener(l -> {
|
||||
+ try {
|
||||
+ net.minecraft.network.protocol.PacketUtils.ensureRunningOnSameThread(packet, this, this.server);
|
||||
+ } catch (net.minecraft.server.RunningOnDifferentThreadException ignored) {
|
||||
+ } catch (
|
||||
+ io.papermc.paper.util.ServerStopRejectedExecutionException ignored) { // Paper - do not prematurely disconnect players on stop
|
||||
+ } catch (java.util.concurrent.RejectedExecutionException var6) {
|
||||
+ this.connection.disconnect(Component.translatable("multiplayer.disconnect.server_shutdown"));
|
||||
+ } catch (ClassCastException var7) {
|
||||
+ LOGGER.error("Received {} that couldn't be processed", packet.getClass(), var7);
|
||||
+ this.connection.disconnect(Component.translatable("multiplayer.disconnect.invalid_packet"));
|
||||
+ }
|
||||
+ });
|
||||
+ return;
|
||||
+ }
|
||||
+ // Leaf end - Async switch connection state
|
||||
net.minecraft.network.protocol.PacketUtils.ensureRunningOnSameThread(packet, this, this.server); // CraftBukkit
|
||||
Validate.validState(this.state == ServerLoginPacketListenerImpl.State.PROTOCOL_SWITCHING, "Unexpected login acknowledgement packet");
|
||||
- this.connection.setupOutboundProtocol(ConfigurationProtocols.CLIENTBOUND);
|
||||
+ if (!org.dreeam.leaf.config.modules.network.AlternativeJoin.enabled) this.connection.setupOutboundProtocol(ConfigurationProtocols.CLIENTBOUND); // Leaf - Async switch connection state
|
||||
CommonListenerCookie commonListenerCookie = CommonListenerCookie.createInitial(Objects.requireNonNull(this.authenticatedProfile), this.transferred);
|
||||
ServerConfigurationPacketListenerImpl serverConfigurationPacketListenerImpl = new ServerConfigurationPacketListenerImpl(
|
||||
this.server, this.connection, commonListenerCookie, this.player // CraftBukkit
|
||||
@@ -0,0 +1,19 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Taiyou06 <kaandindar21@gmail.com>
|
||||
Date: Thu, 8 May 2025 13:30:07 +0200
|
||||
Subject: [PATCH] Optimise BlockEntities tickersInLevel
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
index 5ca0aa1fdaae3ba03a464e2c5bc061adc076b649..3e00ef33413764df933c85bb836d2cd327248edd 100644
|
||||
--- a/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -73,7 +73,7 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p
|
||||
return "<null>";
|
||||
}
|
||||
};
|
||||
- private final Map<BlockPos, LevelChunk.RebindableTickingBlockEntityWrapper> tickersInLevel = Maps.newHashMap();
|
||||
+ private final Map<BlockPos, LevelChunk.RebindableTickingBlockEntityWrapper> tickersInLevel = org.dreeam.leaf.config.modules.opt.OptimiseBlockEntities.enabled ? new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>() : Maps.newHashMap(); // Leaf - Optimise BlockEntities tickersInLevel
|
||||
public boolean loaded;
|
||||
public final ServerLevel level; // CraftBukkit - type
|
||||
@Nullable
|
||||
@@ -0,0 +1,37 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Taiyou06 <kaandindar21@gmail.com>
|
||||
Date: Sun, 11 May 2025 19:45:58 +0200
|
||||
Subject: [PATCH] Flush location while knockback
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java
|
||||
index 4217131b5f7aa985d5af452554849847a36ce9ce..d1b7fffc20ccd00bcc82f830a1f53a85fd86658a 100644
|
||||
--- a/net/minecraft/world/entity/player/Player.java
|
||||
+++ b/net/minecraft/world/entity/player/Player.java
|
||||
@@ -1352,6 +1352,13 @@ public abstract class Player extends LivingEntity {
|
||||
}
|
||||
|
||||
if (!cancelled) {
|
||||
+ // Leaf start - Flush location while knockback
|
||||
+ if (org.dreeam.leaf.config.modules.gameplay.Knockback.flushKnockback && target instanceof ServerPlayer targetPlayer && this instanceof ServerPlayer player1) {
|
||||
+ targetPlayer.connection.send(net.minecraft.network.protocol.game.ClientboundEntityPositionSyncPacket.of(this));
|
||||
+ player1.connection.send(new net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket(targetPlayer));
|
||||
+ player1.connection.send(net.minecraft.network.protocol.game.ClientboundEntityPositionSyncPacket.of(targetPlayer));
|
||||
+ }
|
||||
+ // Leaf end - Flush location while knockback
|
||||
((ServerPlayer)target).connection.send(new ClientboundSetEntityMotionPacket(target));
|
||||
target.hurtMarked = false;
|
||||
target.setDeltaMovement(deltaMovement);
|
||||
@@ -1420,6 +1427,12 @@ public abstract class Player extends LivingEntity {
|
||||
}
|
||||
|
||||
this.causeFoodExhaustion(this.level().spigotConfig.combatExhaustion, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.ATTACK); // CraftBukkit - EntityExhaustionEvent // Spigot - Change to use configurable value
|
||||
+ // Leaf start - Flush location while knockback
|
||||
+ if (org.dreeam.leaf.config.modules.gameplay.Knockback.flushKnockback && this instanceof ServerPlayer player1 && target instanceof ServerPlayer target1) {
|
||||
+ target1.connection.connection.flushChannel();
|
||||
+ player1.connection.connection.flushChannel();
|
||||
+ }
|
||||
+ // Leaf end - Flush location while knockback
|
||||
} else {
|
||||
sendSoundEffect(this, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_NODAMAGE, this.getSoundSource(), 1.0F, 1.0F); // Paper - send while respecting visibility
|
||||
this.containerMenu.sendAllDataToRemote(); // CraftBukkit - resync on cancelled event
|
||||
@@ -0,0 +1,49 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Taiyou06 <kaandindar21@gmail.com>
|
||||
Date: Fri, 9 May 2025 23:50:55 +0200
|
||||
Subject: [PATCH] Only tick items at hand
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
|
||||
index 30783379baee569ec7ff51d34524ccdcba38d764..e2178e12a5c41ab525eea2cd13f14aadd8d66f49 100644
|
||||
--- a/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -838,12 +838,19 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
super.tick();
|
||||
}
|
||||
|
||||
+ // Leaf start - Only tick items at hand
|
||||
+ if (org.dreeam.leaf.config.modules.opt.OptimizeItemTicking.onlyTickItemsInHand) {
|
||||
+ this.synchronizeSpecialItemUpdates(this.getMainHandItem());
|
||||
+ this.synchronizeSpecialItemUpdates(this.getOffhandItem());
|
||||
+ } else {
|
||||
for (int i = 0; i < this.getInventory().getContainerSize(); i++) {
|
||||
ItemStack item = this.getInventory().getItem(i);
|
||||
if (!item.isEmpty()) {
|
||||
this.synchronizeSpecialItemUpdates(item);
|
||||
}
|
||||
}
|
||||
+ }
|
||||
+ // Leaf end - Only tick items at hand
|
||||
|
||||
if (this.getHealth() != this.lastSentHealth
|
||||
|| this.lastSentFood != this.foodData.getFoodLevel()
|
||||
diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java
|
||||
index d1b7fffc20ccd00bcc82f830a1f53a85fd86658a..688a63644a66c0cd3f08deb3786d756c310c079c 100644
|
||||
--- a/net/minecraft/world/entity/player/Player.java
|
||||
+++ b/net/minecraft/world/entity/player/Player.java
|
||||
@@ -639,7 +639,14 @@ public abstract class Player extends LivingEntity {
|
||||
}
|
||||
|
||||
this.tickRegeneration();
|
||||
+ // Leaf start - Only tick items at hand
|
||||
+ if (org.dreeam.leaf.config.modules.opt.OptimizeItemTicking.onlyTickItemsInHand) {
|
||||
+ this.getMainHandItem().inventoryTick(this.level(), this, EquipmentSlot.MAINHAND);
|
||||
+ this.getOffhandItem().inventoryTick(this.level(), this, EquipmentSlot.OFFHAND);
|
||||
+ } else {
|
||||
this.inventory.tick();
|
||||
+ }
|
||||
+ // Leaf end - Only tick items at hand
|
||||
this.oBob = this.bob;
|
||||
if (this.abilities.flying && !this.isPassenger()) {
|
||||
this.resetFallDistance();
|
||||
@@ -0,0 +1,36 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Taiyou06 <kaandindar21@gmail.com>
|
||||
Date: Sat, 10 May 2025 22:04:42 +0200
|
||||
Subject: [PATCH] Smart sort items in NearestItemSensor
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java b/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java
|
||||
index 09fd13e2d958da8326276c4dadf25bf488aff5ac..651797720f7fc6ff9dc614f4de56053c304b1170 100644
|
||||
--- a/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java
|
||||
+++ b/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java
|
||||
@@ -16,6 +16,12 @@ public class NearestItemSensor extends Sensor<Mob> {
|
||||
private static final long Y_RANGE = 16L;
|
||||
public static final int MAX_DISTANCE_TO_WANTED_ITEM = 32;
|
||||
|
||||
+ // Leaf start - Smart sort items in NearestItemSensor
|
||||
+ private final org.dreeam.leaf.util.FastBitRadixSort itemSorter;
|
||||
+ public NearestItemSensor() {
|
||||
+ this.itemSorter = new org.dreeam.leaf.util.FastBitRadixSort();
|
||||
+ }
|
||||
+ // Leaf end - Smart sort items in NearestItemSensor
|
||||
@Override
|
||||
public Set<MemoryModuleType<?>> requires() {
|
||||
return ImmutableSet.of(MemoryModuleType.NEAREST_VISIBLE_WANTED_ITEM);
|
||||
@@ -25,10 +31,10 @@ public class NearestItemSensor extends Sensor<Mob> {
|
||||
protected void doTick(ServerLevel level, Mob entity) {
|
||||
Brain<?> brain = entity.getBrain();
|
||||
List<ItemEntity> entitiesOfClass = level.getEntitiesOfClass(ItemEntity.class, entity.getBoundingBox().inflate(32.0, 16.0, 32.0), itemEntity -> itemEntity.closerThan(entity, MAX_DISTANCE_TO_WANTED_ITEM) && entity.wantsToPickUp(level, itemEntity.getItem())); // Paper - Perf: Move predicate into getEntities
|
||||
- entitiesOfClass.sort(Comparator.comparingDouble(entity::distanceToSqr));
|
||||
+ ItemEntity[] sortedItems = this.itemSorter.sort(entitiesOfClass, entity, ItemEntity.class); // Leaf - Smart sort items in NearestItemSensor
|
||||
// Paper start - Perf: remove streams from hot code
|
||||
ItemEntity nearest = null;
|
||||
- for (final ItemEntity itemEntity : entitiesOfClass) {
|
||||
+ for (final ItemEntity itemEntity : sortedItems) { // Leaf - Smart sort items in NearestItemSensor
|
||||
if (entity.hasLineOfSight(itemEntity)) { // Paper - Perf: Move predicate into getEntities
|
||||
nearest = itemEntity;
|
||||
break;
|
||||
@@ -0,0 +1,19 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Taiyou06 <kaandindar21@gmail.com>
|
||||
Date: Sat, 10 May 2025 23:18:17 +0200
|
||||
Subject: [PATCH] Optimise player movement checks
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
|
||||
index 658b8af9b1db252d5664956907a5c0db538018b0..6f3fd83c9f0bafe613c780ba56430084e91fdd2a 100644
|
||||
--- a/net/minecraft/world/entity/Entity.java
|
||||
+++ b/net/minecraft/world/entity/Entity.java
|
||||
@@ -1190,7 +1190,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
}
|
||||
// Paper end
|
||||
|
||||
- movement = this.maybeBackOffFromEdge(movement, type);
|
||||
+ if (!org.dreeam.leaf.config.modules.opt.OptimizePlayerMovementProcessing.enabled) movement = this.maybeBackOffFromEdge(movement, type); // Leaf - Optimise player movement checks
|
||||
Vec3 vec3 = this.collide(movement);
|
||||
double d = vec3.lengthSqr();
|
||||
if (d > 1.0E-7 || movement.lengthSqr() - d < 1.0E-7) {
|
||||
@@ -0,0 +1,29 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Taiyou06 <kaandindar21@gmail.com>
|
||||
Date: Mon, 12 May 2025 19:11:16 +0200
|
||||
Subject: [PATCH] Remove streams in MobSensor
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/entity/ai/sensing/MobSensor.java b/net/minecraft/world/entity/ai/sensing/MobSensor.java
|
||||
index bda210b4809a5aade7ab4d0f26fdda4d5f53f619..2271196768bfc90626e007a70602f818c832e348 100644
|
||||
--- a/net/minecraft/world/entity/ai/sensing/MobSensor.java
|
||||
+++ b/net/minecraft/world/entity/ai/sensing/MobSensor.java
|
||||
@@ -40,10 +40,15 @@ public class MobSensor<T extends LivingEntity> extends Sensor<T> {
|
||||
public void checkForMobsNearby(T sensingEntity) {
|
||||
Optional<List<LivingEntity>> memory = sensingEntity.getBrain().getMemory(MemoryModuleType.NEAREST_LIVING_ENTITIES);
|
||||
if (!memory.isEmpty()) {
|
||||
- boolean flag = memory.get().stream().anyMatch(livingEntity -> this.mobTest.test(sensingEntity, livingEntity));
|
||||
- if (flag) {
|
||||
- this.mobDetected(sensingEntity);
|
||||
+ // Leaf start - Remove streams in MobSensor
|
||||
+ List<LivingEntity> entities = memory.get();
|
||||
+ for (LivingEntity livingEntity : entities) {
|
||||
+ if (this.mobTest.test(sensingEntity, livingEntity)) {
|
||||
+ this.mobDetected(sensingEntity);
|
||||
+ break;
|
||||
+ }
|
||||
}
|
||||
+ // Leaf end - Remove streams in MobSensor
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Taiyou06 <kaandindar21@gmail.com>
|
||||
Date: Mon, 12 May 2025 19:39:03 +0200
|
||||
Subject: [PATCH] Remove streams in TemptingSensor
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/entity/ai/sensing/TemptingSensor.java b/net/minecraft/world/entity/ai/sensing/TemptingSensor.java
|
||||
index 6074c091d0df7843c9f9dc691703eba1a24a7253..5919192968d7272bbf119f248def7e96a1ea359b 100644
|
||||
--- a/net/minecraft/world/entity/ai/sensing/TemptingSensor.java
|
||||
+++ b/net/minecraft/world/entity/ai/sensing/TemptingSensor.java
|
||||
@@ -28,15 +28,21 @@ public class TemptingSensor extends Sensor<PathfinderMob> {
|
||||
protected void doTick(ServerLevel level, PathfinderMob entity) {
|
||||
Brain<?> brain = entity.getBrain();
|
||||
TargetingConditions targetingConditions = TEMPT_TARGETING.copy().range((float)entity.getAttributeValue(Attributes.TEMPT_RANGE));
|
||||
- List<Player> list = level.players()
|
||||
- .stream()
|
||||
- .filter(EntitySelector.NO_SPECTATORS)
|
||||
- .filter(serverPlayer -> targetingConditions.test(level, entity, serverPlayer))
|
||||
- .filter(this::playerHoldingTemptation)
|
||||
- .filter(serverPlayer -> !entity.hasPassenger(serverPlayer))
|
||||
- .sorted(Comparator.comparingDouble(entity::distanceToSqr))
|
||||
- .collect(Collectors.toList());
|
||||
+ // Leaf start - Remove streams in TemptingSensor
|
||||
+ List<net.minecraft.server.level.ServerPlayer> allPlayers = level.players();
|
||||
+ List<Player> list = new java.util.ArrayList<>();
|
||||
+ for (Player serverPlayer : allPlayers) {
|
||||
+ if (EntitySelector.NO_SPECTATORS.test(serverPlayer) &&
|
||||
+ targetingConditions.test(level, entity, serverPlayer) &&
|
||||
+ this.playerHoldingTemptation(serverPlayer) &&
|
||||
+ !entity.hasPassenger(serverPlayer)) {
|
||||
+ list.add(serverPlayer);
|
||||
+ }
|
||||
+ }
|
||||
+ // Leaf end - Remove streams in TemptingSensor
|
||||
+
|
||||
if (!list.isEmpty()) {
|
||||
+ list.sort(Comparator.comparingDouble(entity::distanceToSqr)); // Leaf - Remove streams in TemptingSensor
|
||||
Player player = list.get(0);
|
||||
// CraftBukkit start
|
||||
org.bukkit.event.entity.EntityTargetLivingEntityEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTargetLivingEvent(
|
||||
@@ -0,0 +1,35 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Taiyou06 <kaandindar21@gmail.com>
|
||||
Date: Tue, 13 May 2025 20:41:07 +0200
|
||||
Subject: [PATCH] Use HashedList on WeightedList
|
||||
|
||||
|
||||
diff --git a/net/minecraft/util/random/WeightedList.java b/net/minecraft/util/random/WeightedList.java
|
||||
index daab145028c59c07049a2cf75c4f159e4c5073dc..4bb07ffde3674dc8d09b858ec0bd1ebc8a83bff1 100644
|
||||
--- a/net/minecraft/util/random/WeightedList.java
|
||||
+++ b/net/minecraft/util/random/WeightedList.java
|
||||
@@ -19,6 +19,7 @@ public class WeightedList<E> { // Paper - non-final
|
||||
private final List<Weighted<E>> items;
|
||||
@Nullable
|
||||
private final WeightedList.Selector<E> selector;
|
||||
+ private List<Weighted<E>> entryHashList; // Leaf - Use HashedList on WeightedList
|
||||
|
||||
protected WeightedList(List<? extends Weighted<E>> items) { // Paper - protected
|
||||
this.items = List.copyOf(items);
|
||||
@@ -30,6 +31,7 @@ public class WeightedList<E> { // Paper - non-final
|
||||
} else {
|
||||
this.selector = new WeightedList.Compact<>(this.items);
|
||||
}
|
||||
+ this.entryHashList = this.items.size() > 4 ? this.items : java.util.Collections.unmodifiableList(new org.dreeam.leaf.util.list.HashedReferenceList<>(this.items)); // Leaf - Use HashedList on WeightedList
|
||||
}
|
||||
|
||||
public static <E> WeightedList<E> of() {
|
||||
@@ -80,7 +82,7 @@ public class WeightedList<E> { // Paper - non-final
|
||||
}
|
||||
|
||||
public List<Weighted<E>> unwrap() {
|
||||
- return this.items;
|
||||
+ return this.entryHashList; // Leaf - Use HashedList on WeightedList
|
||||
}
|
||||
|
||||
public static <E> Codec<WeightedList<E>> codec(Codec<E> elementCodec) {
|
||||
@@ -0,0 +1,35 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: adabugra <57899270+adabugra@users.noreply.github.com>
|
||||
Date: Thu, 15 May 2025 19:09:04 +0300
|
||||
Subject: [PATCH] Add configurable death item drop knockback settings
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
|
||||
index e2178e12a5c41ab525eea2cd13f14aadd8d66f49..8cc4ee6b62a7f7bd86dce0b5cd7c470156872fdc 100644
|
||||
--- a/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -1033,7 +1033,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
if (!keepInventory) {
|
||||
for (ItemStack item : this.getInventory().getContents()) {
|
||||
if (!item.isEmpty() && !EnchantmentHelper.has(item, net.minecraft.world.item.enchantment.EnchantmentEffectComponents.PREVENT_EQUIPMENT_DROP)) {
|
||||
- loot.add(new DefaultDrop(item, stack -> this.drop(stack, true, false, false, null))); // Paper - Restore vanilla drops behavior; drop function taken from Inventory#dropAll (don't fire drop event)
|
||||
+ loot.add(new DefaultDrop(item, stack -> this.drop(stack, org.dreeam.leaf.config.modules.gameplay.DeathItemDropKnockback.dropAround, false, false, null))); // Paper - Restore vanilla drops behavior; drop function taken from Inventory#dropAll (don't fire drop event) // Leaf - Add configurable death item drop knockback settings
|
||||
}
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
|
||||
index 8461be7c6723925d26f7f162564a18f4aa162089..27dffa0a104b27687fd7ec0add46657bcab4299a 100644
|
||||
--- a/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -4088,9 +4088,9 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
}
|
||||
|
||||
if (randomizeMotion) {
|
||||
- float f = this.random.nextFloat() * 0.5F;
|
||||
+ float f = this.random.nextFloat() * (float) org.dreeam.leaf.config.modules.gameplay.DeathItemDropKnockback.horizontalForce; // Leaf - Add configurable death item drop knockback settings
|
||||
float f1 = this.random.nextFloat() * (float) (Math.PI * 2);
|
||||
- itemEntity.setDeltaMovement(-Mth.sin(f1) * f, 0.2F, Mth.cos(f1) * f);
|
||||
+ itemEntity.setDeltaMovement(-Mth.sin(f1) * f, (float) org.dreeam.leaf.config.modules.gameplay.DeathItemDropKnockback.verticalForce, Mth.cos(f1) * f); // Leaf - Add configurable death item drop knockback settings
|
||||
} else {
|
||||
float f = 0.3F;
|
||||
float f1 = Mth.sin(this.getXRot() * (float) (Math.PI / 180.0));
|
||||
@@ -0,0 +1,86 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: hayanesuru <hayanesuru@outlook.jp>
|
||||
Date: Thu, 15 May 2025 21:11:18 +0900
|
||||
Subject: [PATCH] Optimize AttributeMap
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/entity/ai/attributes/Attribute.java b/net/minecraft/world/entity/ai/attributes/Attribute.java
|
||||
index f8419dde44ebc7324e783f8bee42132d5ec973c3..406767c60ec1a324faaf5d3658b161647497f99b 100644
|
||||
--- a/net/minecraft/world/entity/ai/attributes/Attribute.java
|
||||
+++ b/net/minecraft/world/entity/ai/attributes/Attribute.java
|
||||
@@ -16,10 +16,15 @@ public class Attribute {
|
||||
private boolean syncable;
|
||||
private final String descriptionId;
|
||||
private Attribute.Sentiment sentiment = Attribute.Sentiment.POSITIVE;
|
||||
+ // Leaf start - Optimize AttributeMap
|
||||
+ public final int uid;
|
||||
+ private static final java.util.concurrent.atomic.AtomicInteger SIZE = new java.util.concurrent.atomic.AtomicInteger();
|
||||
+ // Leaf end - Optimize AttributeMap
|
||||
|
||||
protected Attribute(String descriptionId, double defaultValue) {
|
||||
this.defaultValue = defaultValue;
|
||||
this.descriptionId = descriptionId;
|
||||
+ this.uid = SIZE.getAndAdd(1); // Leaf - Optimize AttributeMap
|
||||
}
|
||||
|
||||
public double getDefaultValue() {
|
||||
diff --git a/net/minecraft/world/entity/ai/attributes/AttributeMap.java b/net/minecraft/world/entity/ai/attributes/AttributeMap.java
|
||||
index 701025715e0aca3c1f920a66f9b3d03ec08eaf02..1ef934b02bd99c0fe997e9ec163457b39dba55f0 100644
|
||||
--- a/net/minecraft/world/entity/ai/attributes/AttributeMap.java
|
||||
+++ b/net/minecraft/world/entity/ai/attributes/AttributeMap.java
|
||||
@@ -15,12 +15,12 @@ import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class AttributeMap {
|
||||
// Gale start - Lithium - replace AI attributes with optimized collections
|
||||
- private final Map<Holder<Attribute>, AttributeInstance> attributes = new it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap<>(0);
|
||||
+ private final Map<Holder<Attribute>, AttributeInstance> attributes = new org.dreeam.leaf.util.map.AttributeInstanceArrayMap(); // Leaf - Optimize AttributeMap
|
||||
private final Set<AttributeInstance> attributesToSync = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(0);
|
||||
private final Set<AttributeInstance> attributesToUpdate = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(0);
|
||||
// Gale end - Lithium - replace AI attributes with optimized collections
|
||||
private final AttributeSupplier supplier;
|
||||
- private final java.util.function.Function<Holder<Attribute>, AttributeInstance> createInstance; // Gale - Airplane - reduce entity allocations
|
||||
+ //private final java.util.function.Function<Holder<Attribute>, AttributeInstance> createInstance; // Gale - Airplane - reduce entity allocations // Leaf - Optimize AttributeMap
|
||||
private final net.minecraft.world.entity.LivingEntity entity; // Purpur - Ridables
|
||||
|
||||
public AttributeMap(AttributeSupplier supplier) {
|
||||
@@ -31,7 +31,7 @@ public class AttributeMap {
|
||||
this.entity = entity;
|
||||
// Purpur end - Ridables
|
||||
this.supplier = defaultAttributes;
|
||||
- this.createInstance = holder -> this.supplier.createInstance(this::onAttributeModified, holder); // Gale - Airplane - reduce entity allocations
|
||||
+ //this.createInstance = holder -> this.supplier.createInstance(this::onAttributeModified, holder); // Gale - Airplane - reduce entity allocations // Leaf - Optimize AttributeMap
|
||||
}
|
||||
|
||||
private void onAttributeModified(AttributeInstance instance) {
|
||||
@@ -55,7 +55,17 @@ public class AttributeMap {
|
||||
|
||||
@Nullable
|
||||
public AttributeInstance getInstance(Holder<Attribute> attribute) {
|
||||
- return this.attributes.computeIfAbsent(attribute, this.createInstance); // Gale - Airplane - reduce entity allocations - cache lambda, as for some reason java allocates it anyways
|
||||
+ // Leaf start - Optimize AttributeMap
|
||||
+ AttributeInstance v;
|
||||
+ if ((v = this.attributes.get(attribute)) == null) {
|
||||
+ AttributeInstance newValue;
|
||||
+ if ((newValue = this.supplier.createInstance(this::onAttributeModified, attribute)) != null) {
|
||||
+ this.attributes.put(attribute, newValue);
|
||||
+ return newValue;
|
||||
+ }
|
||||
+ }
|
||||
+ return v;
|
||||
+ // Leaf end - Optimize AttributeMap
|
||||
}
|
||||
|
||||
public boolean hasAttribute(Holder<Attribute> attribute) {
|
||||
diff --git a/net/minecraft/world/entity/ai/attributes/AttributeSupplier.java b/net/minecraft/world/entity/ai/attributes/AttributeSupplier.java
|
||||
index 24710041ccbc70e5506d8d89ae34f0141977f209..09341ef6c651150aba223689badbead490162b2b 100644
|
||||
--- a/net/minecraft/world/entity/ai/attributes/AttributeSupplier.java
|
||||
+++ b/net/minecraft/world/entity/ai/attributes/AttributeSupplier.java
|
||||
@@ -11,7 +11,7 @@ public class AttributeSupplier {
|
||||
private final Map<Holder<Attribute>, AttributeInstance> instances;
|
||||
|
||||
AttributeSupplier(Map<Holder<Attribute>, AttributeInstance> instances) {
|
||||
- this.instances = instances;
|
||||
+ this.instances = new org.dreeam.leaf.util.map.AttributeInstanceArrayMap(instances); // Leaf - Optimize AttributeMap
|
||||
}
|
||||
|
||||
public AttributeInstance getAttributeInstance(Holder<Attribute> attribute) {
|
||||
@@ -0,0 +1,25 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: hayanesuru <hayanesuru@outlook.jp>
|
||||
Date: Sat, 17 May 2025 19:01:50 +0900
|
||||
Subject: [PATCH] Optimize getScaledTrackingDistance
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
index 747eb54f84650a9a507398e3d5352e001b042490..595284787053a5fb7385e8493953c73a19fe7aee 100644
|
||||
--- a/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -780,7 +780,13 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
|
||||
@Override
|
||||
public int getScaledTrackingDistance(int trackingDistance) {
|
||||
- return this.getProperties().entityBroadcastRangePercentage * trackingDistance / 100;
|
||||
+ // Leaf start - Optimize getScaledTrackingDistance
|
||||
+ int p = this.getProperties().entityBroadcastRangePercentage;
|
||||
+ if (p == 100) {
|
||||
+ return trackingDistance;
|
||||
+ }
|
||||
+ return p * trackingDistance / 100;
|
||||
+ // Leaf end - Optimize getScaledTrackingDistance
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -0,0 +1,27 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: hayanesuru <hayanesuru@outlook.jp>
|
||||
Date: Sat, 17 May 2025 19:03:31 +0900
|
||||
Subject: [PATCH] Optimize SynchedEntityData#packDirty
|
||||
|
||||
|
||||
diff --git a/net/minecraft/network/syncher/SynchedEntityData.java b/net/minecraft/network/syncher/SynchedEntityData.java
|
||||
index f1ab0e66e7d464f7f31a7a360528ed97cdda0aa0..7ca540c70cd40815c0d4c18c2cae28a4cfd88e86 100644
|
||||
--- a/net/minecraft/network/syncher/SynchedEntityData.java
|
||||
+++ b/net/minecraft/network/syncher/SynchedEntityData.java
|
||||
@@ -84,7 +84,15 @@ public class SynchedEntityData {
|
||||
return null;
|
||||
} else {
|
||||
this.isDirty = false;
|
||||
- List<SynchedEntityData.DataValue<?>> list = new ArrayList<>();
|
||||
+ // Leaf start - Optimize SynchedEntityData#packDirty
|
||||
+ int cap = 0;
|
||||
+ for (SynchedEntityData.DataItem<?> dataItem : this.itemsById) {
|
||||
+ if (dataItem.isDirty()) {
|
||||
+ cap += 1;
|
||||
+ }
|
||||
+ }
|
||||
+ ArrayList<SynchedEntityData.DataValue<?>> list = new ArrayList<>(cap);
|
||||
+ // Leaf end - Optimize SynchedEntityData#packDirty
|
||||
|
||||
for (SynchedEntityData.DataItem<?> dataItem : this.itemsById) {
|
||||
if (dataItem.isDirty()) {
|
||||
@@ -0,0 +1,77 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: wling-art <wlingzhenyu@163.com>
|
||||
Date: Sat, 17 May 2025 08:25:33 +0800
|
||||
Subject: [PATCH] Optimize isEyeInFluid
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
|
||||
index 6f3fd83c9f0bafe613c780ba56430084e91fdd2a..fbdc7e54df6cf28264b1dc0d395b9f91206cd50e 100644
|
||||
--- a/net/minecraft/world/entity/Entity.java
|
||||
+++ b/net/minecraft/world/entity/Entity.java
|
||||
@@ -269,6 +269,9 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
protected Object2DoubleMap<TagKey<Fluid>> fluidHeight = new Object2DoubleArrayMap<>(2);
|
||||
protected boolean wasEyeInWater;
|
||||
private final Set<TagKey<Fluid>> fluidOnEyes = new HashSet<>();
|
||||
+ private static final int FLUID_WATER = 1; // Leaf - Optimize isEyeInFluid
|
||||
+ private static final int FLUID_LAVA = 2; // Leaf - Optimize isEyeInFluid
|
||||
+ private int fluidCache = 0; // Leaf - Optimize isEyeInFluid
|
||||
public int invulnerableTime;
|
||||
protected boolean firstTick = true;
|
||||
protected final SynchedEntityData entityData;
|
||||
@@ -1997,7 +2000,8 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
|
||||
private void updateFluidOnEyes() {
|
||||
this.wasEyeInWater = this.isEyeInFluid(FluidTags.WATER);
|
||||
- this.fluidOnEyes.clear();
|
||||
+ if (org.dreeam.leaf.config.modules.opt.EyeFluidCache.enabled) fluidCache = 0; else this.fluidOnEyes.clear(); // Leaf - Optimize isEyeInFluid
|
||||
+
|
||||
double eyeY = this.getEyeY();
|
||||
if (!(
|
||||
this.getVehicle() instanceof AbstractBoat abstractBoat
|
||||
@@ -2009,7 +2013,18 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
FluidState fluidState = this.level().getFluidState(blockPos);
|
||||
double d = blockPos.getY() + fluidState.getHeight(this.level(), blockPos);
|
||||
if (d > eyeY) {
|
||||
- this.fluidOnEyes.addAll(fluidState.getTagsAsSet()); // Leaf - Remove stream in updateFluidOnEyes
|
||||
+ // Leaf start - Optimize isEyeInFluid
|
||||
+ if (org.dreeam.leaf.config.modules.opt.EyeFluidCache.enabled) {
|
||||
+ if (fluidState.is(FluidTags.WATER)) {
|
||||
+ setFluidStatus(FluidTags.WATER, true);
|
||||
+ }
|
||||
+ if (fluidState.is(FluidTags.LAVA)) {
|
||||
+ setFluidStatus(FluidTags.LAVA, true);
|
||||
+ }
|
||||
+ } else {
|
||||
+ this.fluidOnEyes.addAll(fluidState.getTagsAsSet()); // Leaf - Remove stream in updateFluidOnEyes
|
||||
+ }
|
||||
+ // Leaf end - Optimize isEyeInFluid
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2089,9 +2104,25 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
}
|
||||
}
|
||||
|
||||
+ // Leaf start - Optimize isEyeInFluid
|
||||
public boolean isEyeInFluid(TagKey<Fluid> fluidTag) {
|
||||
- return this.fluidOnEyes.contains(fluidTag);
|
||||
+ if (!org.dreeam.leaf.config.modules.opt.EyeFluidCache.enabled) {
|
||||
+ return this.fluidOnEyes.contains(fluidTag);
|
||||
+ }
|
||||
+ return fluidTag == FluidTags.WATER ? (fluidCache & FLUID_WATER) != 0
|
||||
+ : fluidTag == FluidTags.LAVA && (fluidCache & FLUID_LAVA) != 0;
|
||||
+ }
|
||||
+
|
||||
+ public void setFluidStatus(TagKey<Fluid> fluidTag, boolean isInFluid) {
|
||||
+ int bit = fluidTag == FluidTags.WATER ? FLUID_WATER
|
||||
+ : fluidTag == FluidTags.LAVA ? FLUID_LAVA
|
||||
+ : 0;
|
||||
+
|
||||
+ if (bit == 0) return;
|
||||
+
|
||||
+ fluidCache = isInFluid ? (fluidCache | bit) : (fluidCache & ~bit);
|
||||
}
|
||||
+ // Leaf end - Optimize isEyeInFluid
|
||||
|
||||
public boolean isInLava() {
|
||||
return !this.firstTick && this.fluidHeight.getDouble(FluidTags.LAVA) > 0.0;
|
||||
@@ -1,7 +1,7 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Dreeam <61569423+Dreeam-qwq@users.noreply.github.com>
|
||||
Date: Thu, 24 Apr 2025 16:36:16 -0400
|
||||
Subject: [PATCH] paw optimization
|
||||
Subject: [PATCH] Paw optimization
|
||||
|
||||
Some random optimizations
|
||||
|
||||
@@ -10,10 +10,10 @@ Some random optimizations
|
||||
- Secret patches (WIP)
|
||||
|
||||
diff --git a/net/minecraft/network/Connection.java b/net/minecraft/network/Connection.java
|
||||
index f3e9de8716f5e1a72ec465ee897c8f0413f7b1c3..f998cf8d70302a21289de4d84b46d322d0b8a8fe 100644
|
||||
index c83ee2137a57e62003b1d20c3ceea9f569350a53..de1f271d36c7daa10c398e146386b51e2622df9a 100644
|
||||
--- a/net/minecraft/network/Connection.java
|
||||
+++ b/net/minecraft/network/Connection.java
|
||||
@@ -617,13 +617,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
@@ -660,13 +660,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
if (!(this.packetListener instanceof net.minecraft.server.network.ServerLoginPacketListenerImpl loginPacketListener)
|
||||
|| loginPacketListener.state != net.minecraft.server.network.ServerLoginPacketListenerImpl.State.VERIFYING
|
||||
|| Connection.joinAttemptsThisTick++ < MAX_PER_TICK) {
|
||||
@@ -77,7 +77,7 @@ index 4535858701b2bb232b9d2feb2af6551526232ddc..e65c62dbe4c1560ae153e4c4344e9194
|
||||
- // Paper end - detailed watchdog information
|
||||
}
|
||||
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
|
||||
index f89fb321e50338e7765476cb5d7bdf2f02a497b3..83fcef85ed2a5410275e4419e4356994016f21d1 100644
|
||||
index 0f9d18dd29e210ad656da211a3cb1cb25cd4efb1..d1c36cd17c83e7e0167046093c4a2b8427c8bae0 100644
|
||||
--- a/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -622,8 +622,10 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
@@ -94,7 +94,7 @@ index f89fb321e50338e7765476cb5d7bdf2f02a497b3..83fcef85ed2a5410275e4419e4356994
|
||||
|
||||
for (LevelChunk levelChunk : list) {
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index 8ade900d016026cde482ccbca7a411993d9eadd9..414a70c352263a1cd2bfb938053990ea2be2b2c3 100644
|
||||
index 48e06770ee9789e0b64e7369e26f23eea72f691a..31599270e0827db49037d54b0bf5f7a78e3a5e5e 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -1367,13 +1367,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
@@ -126,10 +126,10 @@ index 8ade900d016026cde482ccbca7a411993d9eadd9..414a70c352263a1cd2bfb938053990ea
|
||||
|
||||
private void tickPassenger(Entity ridingEntity, Entity passengerEntity, final boolean isActive) { // Paper - EAR 2
|
||||
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
|
||||
index 960ae487a5a88a5fe9899c16b9553cea0fbfba37..1ff8522b81eb4bc6297b44a1f2a48c8021104185 100644
|
||||
index fbdc7e54df6cf28264b1dc0d395b9f91206cd50e..fa315f46e9b917ef2329d7071c0790d7a4b8ed53 100644
|
||||
--- a/net/minecraft/world/entity/Entity.java
|
||||
+++ b/net/minecraft/world/entity/Entity.java
|
||||
@@ -1138,16 +1138,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
@@ -1140,16 +1140,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
return this.onGround;
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ index 960ae487a5a88a5fe9899c16b9553cea0fbfba37..1ff8522b81eb4bc6297b44a1f2a48c80
|
||||
public void move(MoverType type, Vec3 movement) {
|
||||
// Gale start - VMP - skip entity move if movement is zero
|
||||
if (!this.boundingBoxChanged && movement.equals(Vec3.ZERO)) {
|
||||
@@ -1155,16 +1145,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
@@ -1157,16 +1147,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
}
|
||||
// Gale end - VMP - skip entity move if movement is zero
|
||||
final Vec3 originalMovement = movement; // Paper - Expose pre-collision velocity
|
||||
@@ -163,7 +163,7 @@ index 960ae487a5a88a5fe9899c16b9553cea0fbfba37..1ff8522b81eb4bc6297b44a1f2a48c80
|
||||
if (this.noPhysics) {
|
||||
this.setPos(this.getX() + movement.x, this.getY() + movement.y, this.getZ() + movement.z);
|
||||
} else {
|
||||
@@ -1298,13 +1279,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
@@ -1300,13 +1281,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
// Gale end - skip negligible planar movement multiplication
|
||||
}
|
||||
}
|
||||
@@ -177,7 +177,7 @@ index 960ae487a5a88a5fe9899c16b9553cea0fbfba37..1ff8522b81eb4bc6297b44a1f2a48c80
|
||||
}
|
||||
|
||||
private void applyMovementEmissionAndPlaySound(Entity.MovementEmission movementEmission, Vec3 movement, BlockPos pos, BlockState state) {
|
||||
@@ -4771,9 +4745,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
@@ -4801,9 +4775,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
}
|
||||
|
||||
public void setDeltaMovement(Vec3 deltaMovement) {
|
||||
@@ -187,7 +187,7 @@ index 960ae487a5a88a5fe9899c16b9553cea0fbfba37..1ff8522b81eb4bc6297b44a1f2a48c80
|
||||
}
|
||||
|
||||
public void addDeltaMovement(Vec3 addend) {
|
||||
@@ -4881,9 +4853,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
@@ -4911,9 +4883,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
}
|
||||
// Paper end - Fix MC-4
|
||||
if (this.position.x != x || this.position.y != y || this.position.z != z) {
|
||||
@@ -197,3 +197,16 @@ index 960ae487a5a88a5fe9899c16b9553cea0fbfba37..1ff8522b81eb4bc6297b44a1f2a48c80
|
||||
int floor = Mth.floor(x);
|
||||
int floor1 = Mth.floor(y);
|
||||
int floor2 = Mth.floor(z);
|
||||
diff --git a/net/minecraft/world/level/levelgen/structure/structures/DesertPyramidStructure.java b/net/minecraft/world/level/levelgen/structure/structures/DesertPyramidStructure.java
|
||||
index ef9c2c0a665a1acf490affd9cd4496ae9d677410..27e7c1bb585f30165bd501bb8f8aab0dd147ca5b 100644
|
||||
--- a/net/minecraft/world/level/levelgen/structure/structures/DesertPyramidStructure.java
|
||||
+++ b/net/minecraft/world/level/levelgen/structure/structures/DesertPyramidStructure.java
|
||||
@@ -48,7 +48,7 @@ public class DesertPyramidStructure extends SinglePieceStructure {
|
||||
}
|
||||
}
|
||||
|
||||
- ObjectArrayList<BlockPos> list = new ObjectArrayList<>(set.stream().toList());
|
||||
+ ObjectArrayList<BlockPos> list = new ObjectArrayList<>(set); // Leaf - paw optimization - TODO: use array
|
||||
RandomSource randomSource = RandomSource.create(level.getSeed()).forkPositional().at(pieces.calculateBoundingBox().getCenter());
|
||||
Util.shuffle(list, randomSource);
|
||||
int min = Math.min(set.size(), randomSource.nextInt(5, 8));
|
||||
@@ -0,0 +1,122 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: hayanesuru <hayanesuru@outlook.jp>
|
||||
Date: Fri, 23 May 2025 12:01:42 +0900
|
||||
Subject: [PATCH] Cache block path type
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/Bootstrap.java b/net/minecraft/server/Bootstrap.java
|
||||
index 83bc2f6b7774c8753a15dbeb00f0c9103713fd1b..20a720253092b4ec0b648edf06a048f92da201e0 100644
|
||||
--- a/net/minecraft/server/Bootstrap.java
|
||||
+++ b/net/minecraft/server/Bootstrap.java
|
||||
@@ -60,6 +60,7 @@ public class Bootstrap {
|
||||
io.papermc.paper.world.worldgen.OptionallyFlatBedrockConditionSource.bootstrap(); // Paper - Flat bedrock generator settings
|
||||
});
|
||||
// Paper end
|
||||
+ net.minecraft.world.level.block.Blocks.initPathType(); // Leaf - Cache path type
|
||||
CreativeModeTabs.validate();
|
||||
wrapStreams();
|
||||
bootstrapDuration.set(Duration.between(instant, Instant.now()).toMillis());
|
||||
diff --git a/net/minecraft/world/level/block/Blocks.java b/net/minecraft/world/level/block/Blocks.java
|
||||
index 303bd27d44e4acfee49334235a6704724e3fd616..d001d0859c9508eb06f05010ab1cb8069f9b87cf 100644
|
||||
--- a/net/minecraft/world/level/block/Blocks.java
|
||||
+++ b/net/minecraft/world/level/block/Blocks.java
|
||||
@@ -7078,4 +7078,14 @@ public class Blocks {
|
||||
}
|
||||
}
|
||||
}
|
||||
+
|
||||
+ // Leaf start - Cache path type
|
||||
+ public static void initPathType() {
|
||||
+ for (Block block : BuiltInRegistries.BLOCK) {
|
||||
+ for (BlockState blockState : block.getStateDefinition().getPossibleStates()) {
|
||||
+ blockState.initPathType();
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ // Leaf end - Cache path type
|
||||
}
|
||||
diff --git a/net/minecraft/world/level/block/state/BlockBehaviour.java b/net/minecraft/world/level/block/state/BlockBehaviour.java
|
||||
index 6d522e9485fadd6fc0f350cb30ba5224aa046d4f..611887f5f8f218f5ec1ad19580f3123a60b20d46 100644
|
||||
--- a/net/minecraft/world/level/block/state/BlockBehaviour.java
|
||||
+++ b/net/minecraft/world/level/block/state/BlockBehaviour.java
|
||||
@@ -473,6 +473,7 @@ public abstract class BlockBehaviour implements FeatureElement {
|
||||
private boolean emptyCollisionShape;
|
||||
private boolean emptyConstantCollisionShape;
|
||||
private VoxelShape constantCollisionShape;
|
||||
+ public net.minecraft.world.level.pathfinder.PathType pathType; // Leaf - Cache path type
|
||||
|
||||
private static void initCaches(final VoxelShape shape, final boolean neighbours) {
|
||||
((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)shape).moonrise$isFullBlock();
|
||||
@@ -642,6 +643,12 @@ public abstract class BlockBehaviour implements FeatureElement {
|
||||
// Paper end - optimise collisions
|
||||
}
|
||||
|
||||
+ // Leaf start - Cache path type
|
||||
+ public void initPathType() {
|
||||
+ pathType = net.minecraft.world.level.pathfinder.WalkNodeEvaluator.getPathTypeFromState(this.asState());
|
||||
+ }
|
||||
+ // Leaf end - Cache path type
|
||||
+
|
||||
public Block getBlock() {
|
||||
return this.owner;
|
||||
}
|
||||
diff --git a/net/minecraft/world/level/pathfinder/PathTypeCache.java b/net/minecraft/world/level/pathfinder/PathTypeCache.java
|
||||
index 3b190ba2a719cc45045d9be893884b50b9364b58..b44f6562a7f7651b2728ba49699031000b54b818 100644
|
||||
--- a/net/minecraft/world/level/pathfinder/PathTypeCache.java
|
||||
+++ b/net/minecraft/world/level/pathfinder/PathTypeCache.java
|
||||
@@ -24,7 +24,7 @@ public class PathTypeCache {
|
||||
}
|
||||
|
||||
private PathType compute(BlockGetter level, BlockPos pos, int index, long packedPos) {
|
||||
- PathType pathTypeFromState = WalkNodeEvaluator.getPathTypeFromState(level, pos);
|
||||
+ PathType pathTypeFromState = WalkNodeEvaluator.leafPathType(level, pos); // Leaf - Cache path type
|
||||
this.positions[index] = packedPos;
|
||||
this.pathTypes[index] = pathTypeFromState;
|
||||
return pathTypeFromState;
|
||||
diff --git a/net/minecraft/world/level/pathfinder/PathfindingContext.java b/net/minecraft/world/level/pathfinder/PathfindingContext.java
|
||||
index 4eca1dd0819c7ee7a77e45fc5fa03f4ee5cdceaf..ff68b19b5fe4c80872d483363611b843146de989 100644
|
||||
--- a/net/minecraft/world/level/pathfinder/PathfindingContext.java
|
||||
+++ b/net/minecraft/world/level/pathfinder/PathfindingContext.java
|
||||
@@ -27,7 +27,7 @@ public class PathfindingContext {
|
||||
|
||||
public PathType getPathTypeFromState(int x, int y, int z) {
|
||||
BlockPos blockPos = this.mutablePos.set(x, y, z);
|
||||
- return this.cache == null ? WalkNodeEvaluator.getPathTypeFromState(this.level, blockPos) : this.cache.getOrCompute(this.level, blockPos);
|
||||
+ return this.cache == null ? WalkNodeEvaluator.leafPathType(this.level, blockPos) : this.cache.getOrCompute(this.level, blockPos); // Leaf - Cache path type
|
||||
}
|
||||
|
||||
public BlockState getBlockState(BlockPos pos) {
|
||||
diff --git a/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java b/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java
|
||||
index db6baaa698fe93aba3fbd595158b568badd6cb8a..5bd1300ef82a1d431c098d9cf75a7fa9d5a43502 100644
|
||||
--- a/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java
|
||||
+++ b/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java
|
||||
@@ -479,6 +479,16 @@ public class WalkNodeEvaluator extends NodeEvaluator {
|
||||
return pathType;
|
||||
}
|
||||
|
||||
+ // Leaf start - Cache path type
|
||||
+ public static PathType leafPathType(BlockGetter level, BlockPos blockPos) {
|
||||
+ BlockState blockState = level.getBlockStateIfLoaded(blockPos);
|
||||
+ if (blockState == null) {
|
||||
+ return PathType.BLOCKED;
|
||||
+ }
|
||||
+ return blockState.pathType;
|
||||
+ }
|
||||
+ // Leaf end - Cache path type
|
||||
+
|
||||
protected static PathType getPathTypeFromState(BlockGetter level, BlockPos pos) {
|
||||
// Paper start - Do not load chunks during pathfinding
|
||||
BlockState blockState = level.getBlockStateIfLoaded(pos);
|
||||
@@ -486,6 +496,12 @@ public class WalkNodeEvaluator extends NodeEvaluator {
|
||||
return PathType.BLOCKED;
|
||||
}
|
||||
// Paper end
|
||||
+ // Leaf start - Cache path type
|
||||
+ return getPathTypeFromState(blockState);
|
||||
+ }
|
||||
+
|
||||
+ public static PathType getPathTypeFromState(BlockState blockState) {
|
||||
+ // Leaf end - Cache path type
|
||||
Block block = blockState.getBlock();
|
||||
if (blockState.isAir()) {
|
||||
return PathType.OPEN;
|
||||
@@ -0,0 +1,63 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: hayanesuru <hayanesuru@outlook.jp>
|
||||
Date: Fri, 23 May 2025 15:57:42 +0900
|
||||
Subject: [PATCH] optimize getEntityStatus
|
||||
|
||||
|
||||
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java
|
||||
index 7554c109c35397bc1a43dd80e87764fd78645bbf..151476fd036839a416c226599279d0d8bf79717b 100644
|
||||
--- a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java
|
||||
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java
|
||||
@@ -93,8 +93,14 @@ public abstract class EntityLookup implements LevelEntityGetter<Entity> {
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
- final Visibility visibility = EntityLookup.getEntityStatus(entity);
|
||||
- return visibility.isAccessible() ? entity : null;
|
||||
+ // Leaf start
|
||||
+ final FullChunkStatus entityStatus = ((ChunkSystemEntity) entity).moonrise$getChunkStatus();
|
||||
+ return switch (entityStatus) {
|
||||
+ case INACCESSIBLE -> null;
|
||||
+ case FULL, BLOCK_TICKING, ENTITY_TICKING -> entity;
|
||||
+ case null -> null;
|
||||
+ };
|
||||
+ // Leaf end
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -394,7 +400,14 @@ public abstract class EntityLookup implements LevelEntityGetter<Entity> {
|
||||
return Visibility.TICKING;
|
||||
}
|
||||
final FullChunkStatus entityStatus = ((ChunkSystemEntity)entity).moonrise$getChunkStatus();
|
||||
- return Visibility.fromFullChunkStatus(entityStatus == null ? FullChunkStatus.INACCESSIBLE : entityStatus);
|
||||
+ // Leaf start
|
||||
+ return switch (entityStatus) {
|
||||
+ case INACCESSIBLE -> Visibility.HIDDEN;
|
||||
+ case FULL, BLOCK_TICKING -> Visibility.TRACKED;
|
||||
+ case ENTITY_TICKING -> Visibility.TICKING;
|
||||
+ case null -> Visibility.HIDDEN;
|
||||
+ };
|
||||
+ // Leaf end
|
||||
}
|
||||
|
||||
protected boolean addEntity(final Entity entity, final boolean fromDisk, final boolean event) {
|
||||
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
|
||||
index fa315f46e9b917ef2329d7071c0790d7a4b8ed53..f130002b8bdfbf3ae9fa1a8166fd502924c5a42f 100644
|
||||
--- a/net/minecraft/world/entity/Entity.java
|
||||
+++ b/net/minecraft/world/entity/Entity.java
|
||||
@@ -370,6 +370,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
// Paper end
|
||||
// Paper start - rewrite chunk system
|
||||
private final boolean isHardColliding = this.moonrise$isHardCollidingUncached();
|
||||
+ @org.jetbrains.annotations.Nullable // Leaf
|
||||
private net.minecraft.server.level.FullChunkStatus chunkStatus;
|
||||
private ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkData chunkData;
|
||||
private int sectionX = Integer.MIN_VALUE;
|
||||
@@ -383,6 +384,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
}
|
||||
|
||||
@Override
|
||||
+ @org.jetbrains.annotations.Nullable // Leaf
|
||||
public final net.minecraft.server.level.FullChunkStatus moonrise$getChunkStatus() {
|
||||
return this.chunkStatus;
|
||||
}
|
||||
@@ -40,6 +40,37 @@ index db031298c2090eb36032de4b52335c62186e4cfb..84905d7802f8a5c3f68e15f1b17ef082
|
||||
throw new IllegalStateException(event.getEventName() + " may only be triggered synchronously.");
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
index d891595b25cf04980cc24a6e6b9bd95553527100..216a273d65fc7eda8f2e229e4257b2708294849c 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
@@ -738,7 +738,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
||||
ChunkMap.TrackedEntity entityTracker = world.getChunkSource().chunkMap.entityMap.get(this.getEntityId());
|
||||
|
||||
if (entityTracker != null) {
|
||||
- for (ServerPlayerConnection connection : entityTracker.seenBy) {
|
||||
+ for (ServerPlayerConnection connection : entityTracker.seenBy()) { // Leaf - Multithreaded tracker
|
||||
players.add(connection.getPlayer().getBukkitEntity());
|
||||
}
|
||||
}
|
||||
@@ -1054,7 +1054,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
||||
return;
|
||||
}
|
||||
|
||||
- for (final ServerPlayerConnection connection : entityTracker.seenBy) {
|
||||
+ for (final ServerPlayerConnection connection : entityTracker.seenBy()) { // Leaf - Multithreaded tracker
|
||||
this.getHandle().resendPossiblyDesyncedEntityData(connection.getPlayer());
|
||||
}
|
||||
}
|
||||
@@ -1201,7 +1201,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
||||
}
|
||||
|
||||
Set<org.bukkit.entity.Player> set = new java.util.HashSet<>(tracker.seenBy.size());
|
||||
- for (net.minecraft.server.network.ServerPlayerConnection connection : tracker.seenBy) {
|
||||
+ for (net.minecraft.server.network.ServerPlayerConnection connection : tracker.seenBy()) { // Leaf - Multithreaded tracker
|
||||
set.add(connection.getPlayer().getBukkitEntity().getPlayer());
|
||||
}
|
||||
return set;
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
index f32316b0357f1cb0501a052361a0221f8e9d1438..ebb07b9b9f6bef9195978c8ecdd5f4ef3ee198bc 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: hayanesuru <mc@jvavav.com>
|
||||
Date: Fri, 2 May 2025 18:22:24 -0700
|
||||
Subject: [PATCH] Async chunk send
|
||||
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/antixray/ChunkPacketBlockControllerAntiXray.java b/src/main/java/io/papermc/paper/antixray/ChunkPacketBlockControllerAntiXray.java
|
||||
index ca24f4cd7a50f0156d84e263c60f841cca95c669..7e15038e8fceab1e97c2245c2e9111deed6455fb 100644
|
||||
--- a/src/main/java/io/papermc/paper/antixray/ChunkPacketBlockControllerAntiXray.java
|
||||
+++ b/src/main/java/io/papermc/paper/antixray/ChunkPacketBlockControllerAntiXray.java
|
||||
@@ -185,7 +185,7 @@ public final class ChunkPacketBlockControllerAntiXray extends ChunkPacketBlockCo
|
||||
return;
|
||||
}
|
||||
|
||||
- if (!Bukkit.isPrimaryThread()) {
|
||||
+ if (!Bukkit.isPrimaryThread() && !(Thread.currentThread() instanceof org.dreeam.leaf.async.chunk.AsyncChunkSendThread)) { // Leaf - Async chunk send
|
||||
// Plugins?
|
||||
MinecraftServer.getServer().scheduleOnMain(() -> modifyBlocks(chunkPacket, chunkPacketInfo));
|
||||
return;
|
||||
@@ -0,0 +1,22 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Taiyou06 <kaandindar21@gmail.com>
|
||||
Date: Sun, 11 May 2025 00:37:44 +0200
|
||||
Subject: [PATCH] Optimise player movement checks
|
||||
|
||||
|
||||
diff --git a/src/main/java/ca/spottedleaf/moonrise/common/misc/SingleUserAreaMap.java b/src/main/java/ca/spottedleaf/moonrise/common/misc/SingleUserAreaMap.java
|
||||
index 7e85bb58b8a5de17fdab9ad3c574f2f80952e1ca..8e424b48c06e90893f0f2fde7c35410bd8271469 100644
|
||||
--- a/src/main/java/ca/spottedleaf/moonrise/common/misc/SingleUserAreaMap.java
|
||||
+++ b/src/main/java/ca/spottedleaf/moonrise/common/misc/SingleUserAreaMap.java
|
||||
@@ -86,6 +86,11 @@ public abstract class SingleUserAreaMap<T> {
|
||||
if (fromX == NOT_SET) {
|
||||
return false;
|
||||
}
|
||||
+ // Leaf start - Optimise player movement checks
|
||||
+ if (org.dreeam.leaf.config.modules.opt.OptimizePlayerMovementProcessing.enabled && fromX == toX && fromZ == toZ && oldViewDistance == newViewDistance) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ // Leaf end - Optimise player movement checks
|
||||
|
||||
this.lastChunkX = toX;
|
||||
this.lastChunkZ = toZ;
|
||||
@@ -1,9 +0,0 @@
|
||||
package org.dreeam.leaf.async;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
public class AsyncChunkSending {
|
||||
|
||||
public static final Logger LOGGER = LogManager.getLogger(AsyncChunkSending.class.getSimpleName());
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.dreeam.leaf.async;
|
||||
|
||||
import net.minecraft.Util;
|
||||
import org.dreeam.leaf.config.modules.async.AsyncPlayerDataSave;
|
||||
|
||||
import java.util.Optional;
|
||||
@@ -17,7 +18,7 @@ public class AsyncPlayerDataSaving {
|
||||
new com.google.common.util.concurrent.ThreadFactoryBuilder()
|
||||
.setPriority(Thread.NORM_PRIORITY - 2)
|
||||
.setNameFormat("Leaf IO Thread")
|
||||
.setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(net.minecraft.server.MinecraftServer.LOGGER))
|
||||
.setUncaughtExceptionHandler(Util::onThreadException)
|
||||
.build(),
|
||||
new ThreadPoolExecutor.DiscardPolicy()
|
||||
);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.dreeam.leaf.async.ai;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.Mob;
|
||||
@@ -8,80 +9,99 @@ import org.apache.logging.log4j.Logger;
|
||||
import org.dreeam.leaf.config.modules.async.AsyncTargetFinding;
|
||||
import org.dreeam.leaf.util.queue.SpscIntQueue;
|
||||
|
||||
import java.util.OptionalInt;
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
|
||||
public class AsyncGoalExecutor {
|
||||
|
||||
public static final Logger LOGGER = LogManager.getLogger("Leaf Async Goal");
|
||||
|
||||
protected static final Logger LOGGER = LogManager.getLogger("Leaf Async Goal");
|
||||
protected final SpscIntQueue queue;
|
||||
protected final SpscIntQueue wake;
|
||||
protected final IntArrayList submit;
|
||||
private final AsyncGoalThread thread;
|
||||
private final ServerLevel serverLevel;
|
||||
private boolean dirty = false;
|
||||
private long tickCount = 0L;
|
||||
private static final int SPIN_LIMIT = 100;
|
||||
private final ServerLevel world;
|
||||
private long midTickCount = 0L;
|
||||
|
||||
public AsyncGoalExecutor(AsyncGoalThread thread, ServerLevel serverLevel) {
|
||||
this.serverLevel = serverLevel;
|
||||
public AsyncGoalExecutor(AsyncGoalThread thread, ServerLevel world) {
|
||||
this.world = world;
|
||||
this.queue = new SpscIntQueue(AsyncTargetFinding.queueSize);
|
||||
this.wake = new SpscIntQueue(AsyncTargetFinding.queueSize);
|
||||
this.submit = new IntArrayList();
|
||||
this.thread = thread;
|
||||
}
|
||||
|
||||
boolean wake(int id) {
|
||||
Entity entity = this.serverLevel.getEntities().get(id);
|
||||
Entity entity = this.world.getEntities().get(id);
|
||||
if (entity == null || entity.isRemoved() || !(entity instanceof Mob mob)) {
|
||||
return false;
|
||||
}
|
||||
mob.goalSelector.wake();
|
||||
mob.targetSelector.wake();
|
||||
mob.goalSelector.ctx.wake();
|
||||
mob.targetSelector.ctx.wake();
|
||||
return true;
|
||||
}
|
||||
|
||||
public final void submit(int entityId) {
|
||||
if (!this.queue.send(entityId)) {
|
||||
int spinCount = 0;
|
||||
while (!this.queue.send(entityId)) {
|
||||
spinCount++;
|
||||
// Unpark the thread after some spinning to help clear the queue
|
||||
if (spinCount > SPIN_LIMIT) {
|
||||
unpark();
|
||||
spinCount = 0;
|
||||
}
|
||||
Thread.onSpinWait();
|
||||
}
|
||||
}
|
||||
dirty = true;
|
||||
this.submit.add(entityId);
|
||||
}
|
||||
|
||||
public final void unpark() {
|
||||
if (dirty) LockSupport.unpark(thread);
|
||||
dirty = false;
|
||||
public final void tick() {
|
||||
batchSubmit();
|
||||
LockSupport.unpark(thread);
|
||||
}
|
||||
|
||||
private void batchSubmit() {
|
||||
if (submit.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
int[] raw = submit.elements();
|
||||
int size = submit.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
int id = raw[i];
|
||||
if (poll(id) && !this.queue.send(id)) {
|
||||
do {
|
||||
wake(id);
|
||||
} while (poll(id));
|
||||
}
|
||||
}
|
||||
this.submit.clear();
|
||||
}
|
||||
|
||||
public final void midTick() {
|
||||
boolean didWork = false;
|
||||
while (true) {
|
||||
int id = this.wake.recv();
|
||||
if (id == Integer.MAX_VALUE) {
|
||||
OptionalInt result = this.wake.recv();
|
||||
if (result.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
didWork = true;
|
||||
Entity entity = this.serverLevel.getEntities().get(id);
|
||||
if (entity == null || !entity.isAlive() || !(entity instanceof Mob mob)) {
|
||||
continue;
|
||||
int id = result.getAsInt();
|
||||
if (poll(id) && !this.queue.send(id)) {
|
||||
do {
|
||||
wake(id);
|
||||
} while (poll(id));
|
||||
}
|
||||
}
|
||||
if (AsyncTargetFinding.threshold <= 0L || (midTickCount % AsyncTargetFinding.threshold) == 0L) {
|
||||
batchSubmit();
|
||||
}
|
||||
|
||||
midTickCount += 1;
|
||||
}
|
||||
|
||||
private boolean poll(int id) {
|
||||
Entity entity = this.world.getEntities().get(id);
|
||||
if (entity == null || entity.isRemoved() || !(entity instanceof Mob mob)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
mob.tickingTarget = true;
|
||||
boolean a = mob.targetSelector.poll();
|
||||
mob.tickingTarget = false;
|
||||
boolean b = mob.goalSelector.poll();
|
||||
if (a || b) {
|
||||
submit(id);
|
||||
return a || b;
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Exception while polling", e);
|
||||
// retry
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (didWork || (tickCount & 15L) == 0L) unpark();
|
||||
tickCount += 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,12 +4,11 @@ import net.minecraft.Util;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
|
||||
import java.util.OptionalInt;
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
|
||||
public class AsyncGoalThread extends Thread {
|
||||
|
||||
private static final int SPIN_TRIES = 1000;
|
||||
|
||||
public AsyncGoalThread(final MinecraftServer server) {
|
||||
super(() -> run(server), "Leaf Async Goal Thread");
|
||||
this.setDaemon(false);
|
||||
@@ -19,38 +18,29 @@ public class AsyncGoalThread extends Thread {
|
||||
}
|
||||
|
||||
private static void run(MinecraftServer server) {
|
||||
int emptySpins = 0;
|
||||
|
||||
while (server.isRunning()) {
|
||||
boolean didWork = false;
|
||||
boolean retry = false;
|
||||
for (ServerLevel level : server.getAllLevels()) {
|
||||
var exec = level.asyncGoalExecutor;
|
||||
boolean levelWork = false;
|
||||
while (true) {
|
||||
int id = exec.queue.recv();
|
||||
if (id == Integer.MAX_VALUE) {
|
||||
OptionalInt result = exec.queue.recv();
|
||||
if (result.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
levelWork = true;
|
||||
int id = result.getAsInt();
|
||||
retry = true;
|
||||
if (exec.wake(id)) {
|
||||
while (!exec.wake.send(id)) {
|
||||
Thread.onSpinWait();
|
||||
}
|
||||
}
|
||||
}
|
||||
didWork |= levelWork;
|
||||
}
|
||||
// Adaptive parking
|
||||
if (didWork) {
|
||||
emptySpins = 0; // Reset counter when work was done
|
||||
} else {
|
||||
emptySpins++;
|
||||
if (emptySpins > SPIN_TRIES) {
|
||||
LockSupport.park(); // Only park after several empty spins
|
||||
emptySpins = 0;
|
||||
} else {
|
||||
Thread.onSpinWait(); // Yield to other threads but don't park
|
||||
|
||||
Thread.yield();
|
||||
}
|
||||
|
||||
if (!retry) {
|
||||
LockSupport.parkNanos(10_000L);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package org.dreeam.leaf.async.ai;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface VWaker {
|
||||
@Nullable Object wake();
|
||||
}
|
||||
@@ -5,14 +5,26 @@ import org.jetbrains.annotations.Nullable;
|
||||
public class Waker {
|
||||
|
||||
@Nullable
|
||||
public volatile Runnable wake = null;
|
||||
public volatile VWaker wake = null;
|
||||
@Nullable
|
||||
public volatile Object result = null;
|
||||
public volatile boolean state = true;
|
||||
public boolean state = true;
|
||||
|
||||
public final @Nullable Object result() {
|
||||
Object result = this.result;
|
||||
this.result = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
final void wake() {
|
||||
final var wake = this.wake;
|
||||
if (wake != null) {
|
||||
try {
|
||||
this.result = wake.wake();
|
||||
} catch (Exception e) {
|
||||
AsyncGoalExecutor.LOGGER.error("Exception while wake", e);
|
||||
}
|
||||
this.wake = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package org.dreeam.leaf.async.chunk;
|
||||
|
||||
import net.minecraft.Util;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class AsyncChunkSend {
|
||||
|
||||
public static final ExecutorService POOL = new ThreadPoolExecutor(
|
||||
1, 1, 0L, TimeUnit.MILLISECONDS,
|
||||
new LinkedBlockingQueue<>(),
|
||||
new com.google.common.util.concurrent.ThreadFactoryBuilder()
|
||||
.setPriority(Thread.NORM_PRIORITY - 2)
|
||||
.setNameFormat("Leaf Async Chunk Send Thread")
|
||||
.setUncaughtExceptionHandler(Util::onThreadException)
|
||||
.setThreadFactory(AsyncChunkSendThread::new)
|
||||
.build(),
|
||||
new ThreadPoolExecutor.DiscardPolicy()
|
||||
);
|
||||
public static final Logger LOGGER = LogManager.getLogger("Leaf Async Chunk Send");
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package org.dreeam.leaf.async.chunk;
|
||||
|
||||
public class AsyncChunkSendThread extends Thread {
|
||||
|
||||
protected AsyncChunkSendThread(Runnable task) {
|
||||
super(task);
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,12 @@ import net.minecraft.tags.TagKey;
|
||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||
import net.minecraft.world.level.levelgen.structure.Structure;
|
||||
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package org.dreeam.leaf.async.path;
|
||||
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.world.level.pathfinder.Path;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -12,7 +10,13 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.RejectedExecutionHandler;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
@@ -97,4 +101,5 @@ public class AsyncPathProcessor {
|
||||
final int queueCapacity = org.dreeam.leaf.config.modules.async.AsyncPathfinding.asyncPathfindingQueueSize;
|
||||
|
||||
return new LinkedBlockingQueue<>(queueCapacity);
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package org.dreeam.leaf.async.path;
|
||||
|
||||
import ca.spottedleaf.concurrentutil.collection.MultiThreadedQueue;
|
||||
import net.minecraft.world.level.pathfinder.NodeEvaluator;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package org.dreeam.leaf.async.path;
|
||||
|
||||
import net.minecraft.world.level.pathfinder.*;
|
||||
import net.minecraft.world.level.pathfinder.AmphibiousNodeEvaluator;
|
||||
import net.minecraft.world.level.pathfinder.FlyNodeEvaluator;
|
||||
import net.minecraft.world.level.pathfinder.NodeEvaluator;
|
||||
import net.minecraft.world.level.pathfinder.SwimNodeEvaluator;
|
||||
|
||||
public enum NodeEvaluatorType {
|
||||
WALK,
|
||||
|
||||
@@ -2,12 +2,14 @@ package org.dreeam.leaf.async.tracker;
|
||||
|
||||
import ca.spottedleaf.moonrise.common.list.ReferenceList;
|
||||
import ca.spottedleaf.moonrise.common.misc.NearbyPlayers;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.server.ServerEntityLookup;
|
||||
import ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerEntity;
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import it.unimi.dsi.fastutil.objects.ReferenceArrayList;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.server.level.ChunkMap;
|
||||
import net.minecraft.server.level.FullChunkStatus;
|
||||
import net.minecraft.server.level.ServerEntity;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
@@ -16,14 +18,35 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.RejectedExecutionHandler;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class MultithreadedTracker {
|
||||
|
||||
private static final String THREAD_PREFIX = "Leaf Async Tracker";
|
||||
private static final Logger LOGGER = LogManager.getLogger(THREAD_PREFIX);
|
||||
private static long lastWarnMillis = System.currentTimeMillis();
|
||||
private static final ThreadPoolExecutor trackerExecutor = new ThreadPoolExecutor(
|
||||
private static ThreadPoolExecutor TRACKER_EXECUTOR = null;
|
||||
|
||||
private record SendChanges(Object[] entities, int size) implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
for (int i = 0; i < size; i++) {
|
||||
((ServerEntity) entities[i]).sendDirtyEntityData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private MultithreadedTracker() {
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
if (TRACKER_EXECUTOR == null) {
|
||||
TRACKER_EXECUTOR = new ThreadPoolExecutor(
|
||||
getCorePoolSize(),
|
||||
getMaxPoolSize(),
|
||||
getKeepAliveTime(), TimeUnit.SECONDS,
|
||||
@@ -31,15 +54,12 @@ public class MultithreadedTracker {
|
||||
getThreadFactory(),
|
||||
getRejectedPolicy()
|
||||
);
|
||||
|
||||
private MultithreadedTracker() {
|
||||
} else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
public static Executor getTrackerExecutor() {
|
||||
return trackerExecutor;
|
||||
}
|
||||
|
||||
public static void tick(ChunkSystemServerLevel level) {
|
||||
public static void tick(ServerLevel level) {
|
||||
try {
|
||||
if (!org.dreeam.leaf.config.modules.async.MultithreadedTracker.compatModeEnabled) {
|
||||
tickAsync(level);
|
||||
@@ -51,7 +71,7 @@ public class MultithreadedTracker {
|
||||
}
|
||||
}
|
||||
|
||||
private static void tickAsync(ChunkSystemServerLevel level) {
|
||||
private static void tickAsync(ServerLevel level) {
|
||||
final NearbyPlayers nearbyPlayers = level.moonrise$getNearbyPlayers();
|
||||
final ServerEntityLookup entityLookup = (ServerEntityLookup) level.moonrise$getEntityLookup();
|
||||
|
||||
@@ -59,7 +79,8 @@ public class MultithreadedTracker {
|
||||
final Entity[] trackerEntitiesRaw = trackerEntities.getRawDataUnchecked();
|
||||
|
||||
// Move tracking to off-main
|
||||
trackerExecutor.execute(() -> {
|
||||
TRACKER_EXECUTOR.execute(() -> {
|
||||
ReferenceArrayList<ServerEntity> sendDirty = new ReferenceArrayList<>();
|
||||
for (final Entity entity : trackerEntitiesRaw) {
|
||||
if (entity == null) continue;
|
||||
|
||||
@@ -67,19 +88,30 @@ public class MultithreadedTracker {
|
||||
|
||||
if (tracker == null) continue;
|
||||
|
||||
// Don't Parallel Tick Tracker of Entity
|
||||
synchronized (tracker.sync) {
|
||||
tracker.moonrise$tick(nearbyPlayers.getChunk(entity.chunkPosition()));
|
||||
tracker.serverEntity.sendChanges();
|
||||
if (tracker.serverEntity.wantSendDirtyEntityData) {
|
||||
tracker.serverEntity.wantSendDirtyEntityData = false;
|
||||
sendDirty.add(tracker.serverEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!sendDirty.isEmpty()) {
|
||||
level.getServer().execute(new SendChanges(sendDirty.elements(), sendDirty.size()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void tickAsyncWithCompatMode(ChunkSystemServerLevel level) {
|
||||
private static void tickAsyncWithCompatMode(ServerLevel level) {
|
||||
final NearbyPlayers nearbyPlayers = level.moonrise$getNearbyPlayers();
|
||||
final ServerEntityLookup entityLookup = (ServerEntityLookup) level.moonrise$getEntityLookup();
|
||||
|
||||
final ReferenceList<Entity> trackerEntities = entityLookup.trackerEntities;
|
||||
final Entity[] trackerEntitiesRaw = trackerEntities.getRawDataUnchecked();
|
||||
final Runnable[] sendChangesTasks = new Runnable[trackerEntitiesRaw.length];
|
||||
final Runnable[] tickTask = new Runnable[trackerEntitiesRaw.length];
|
||||
int index = 0;
|
||||
|
||||
for (final Entity entity : trackerEntitiesRaw) {
|
||||
@@ -89,30 +121,54 @@ public class MultithreadedTracker {
|
||||
|
||||
if (tracker == null) continue;
|
||||
|
||||
tracker.moonrise$tick(nearbyPlayers.getChunk(entity.chunkPosition()));
|
||||
sendChangesTasks[index++] = () -> tracker.serverEntity.sendChanges(); // Collect send changes to task array
|
||||
synchronized (tracker.sync) {
|
||||
tickTask[index] = tracker.leafTickCompact(nearbyPlayers.getChunk(entity.chunkPosition()));
|
||||
sendChangesTasks[index] = () -> tracker.serverEntity.sendChanges(); // Collect send changes to task array
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
// batch submit tasks
|
||||
trackerExecutor.execute(() -> {
|
||||
TRACKER_EXECUTOR.execute(() -> {
|
||||
for (final Runnable tick : tickTask) {
|
||||
if (tick == null) continue;
|
||||
|
||||
tick.run();
|
||||
}
|
||||
for (final Runnable sendChanges : sendChangesTasks) {
|
||||
if (sendChanges == null) continue;
|
||||
|
||||
sendChanges.run();
|
||||
}
|
||||
|
||||
ReferenceArrayList<ServerEntity> sendDirty = new ReferenceArrayList<>();
|
||||
for (final Entity entity : trackerEntitiesRaw) {
|
||||
if (entity == null) continue;
|
||||
|
||||
final ChunkMap.TrackedEntity tracker = ((EntityTrackerEntity) entity).moonrise$getTrackedEntity();
|
||||
|
||||
if (tracker == null) continue;
|
||||
if (tracker.serverEntity.wantSendDirtyEntityData) {
|
||||
tracker.serverEntity.wantSendDirtyEntityData = false;
|
||||
sendDirty.add(tracker.serverEntity);
|
||||
}
|
||||
}
|
||||
if (!sendDirty.isEmpty()) {
|
||||
level.getServer().execute(new SendChanges(sendDirty.elements(), sendDirty.size()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Original ChunkMap#newTrackerTick of Paper
|
||||
// Just for diff usage for future update
|
||||
private static void tickOriginal(ServerLevel level) {
|
||||
final ca.spottedleaf.moonrise.patches.chunk_system.level.entity.server.ServerEntityLookup entityLookup = (ca.spottedleaf.moonrise.patches.chunk_system.level.entity.server.ServerEntityLookup) ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel) level).moonrise$getEntityLookup();
|
||||
final ServerEntityLookup entityLookup = (ServerEntityLookup) ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel) level).moonrise$getEntityLookup();
|
||||
|
||||
final ca.spottedleaf.moonrise.common.list.ReferenceList<net.minecraft.world.entity.Entity> trackerEntities = entityLookup.trackerEntities;
|
||||
final ReferenceList<Entity> trackerEntities = entityLookup.trackerEntities;
|
||||
final Entity[] trackerEntitiesRaw = trackerEntities.getRawDataUnchecked();
|
||||
for (int i = 0, len = trackerEntities.size(); i < len; ++i) {
|
||||
final Entity entity = trackerEntitiesRaw[i];
|
||||
final ChunkMap.TrackedEntity tracker = ((ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerEntity) entity).moonrise$getTrackedEntity();
|
||||
final ChunkMap.TrackedEntity tracker = ((EntityTrackerEntity) entity).moonrise$getTrackedEntity();
|
||||
if (tracker == null) {
|
||||
continue;
|
||||
}
|
||||
@@ -147,6 +203,7 @@ public class MultithreadedTracker {
|
||||
.setThreadFactory(MultithreadedTrackerThread::new)
|
||||
.setNameFormat(THREAD_PREFIX + " Thread - %d")
|
||||
.setPriority(Thread.NORM_PRIORITY - 2)
|
||||
.setUncaughtExceptionHandler(Util::onThreadException)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -4,9 +4,15 @@ import io.papermc.paper.configuration.GlobalConfiguration;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.minecraft.Util;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dreeam.leaf.config.modules.misc.SentryDSN;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -30,13 +36,6 @@ import java.util.concurrent.CompletableFuture;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
/*
|
||||
* Yoinked from: https://github.com/xGinko/AnarchyExploitFixes/ & https://github.com/LuminolMC/Luminol
|
||||
* @author: @xGinko & @MrHua269
|
||||
@@ -223,6 +222,11 @@ public class LeafConfig {
|
||||
"config/gale-world-defaults.yml"
|
||||
));
|
||||
|
||||
@Nullable String existing = System.getProperty("spark.serverconfigs.extra");
|
||||
if (existing != null) {
|
||||
extraConfigs.addAll(Arrays.asList(existing.split(",")));
|
||||
}
|
||||
|
||||
for (World world : Bukkit.getWorlds()) {
|
||||
extraConfigs.add(world.getWorldFolder().getName() + "/gale-world.yml"); // Gale world config
|
||||
}
|
||||
@@ -230,10 +234,13 @@ public class LeafConfig {
|
||||
return extraConfigs;
|
||||
}
|
||||
|
||||
private static String[] buildSparkHiddenPaths() {
|
||||
return new String[]{
|
||||
SentryDSN.sentryDsnConfigPath // Hide Sentry DSN key
|
||||
};
|
||||
private static List<String> buildSparkHiddenPaths() {
|
||||
@Nullable String existing = System.getProperty("spark.serverconfigs.hiddenpaths");
|
||||
|
||||
List<String> extraHidden = existing != null ? new ArrayList<>(Arrays.asList(existing.split(","))) : new ArrayList<>();
|
||||
extraHidden.add(SentryDSN.sentryDsnConfigPath); // Hide Sentry DSN key
|
||||
|
||||
return extraHidden;
|
||||
}
|
||||
|
||||
public static void regSparkExtraConfig() {
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package org.dreeam.leaf.config.annotations;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Indicates that a feature is experimental and may be removed or changed in the future.
|
||||
|
||||
@@ -10,6 +10,7 @@ public class AsyncChunkSend extends ConfigModules {
|
||||
}
|
||||
|
||||
public static boolean enabled = false;
|
||||
private static boolean asyncChunkSendInitialized;
|
||||
|
||||
@Override
|
||||
public void onLoaded() {
|
||||
@@ -20,6 +21,12 @@ public class AsyncChunkSend extends ConfigModules {
|
||||
使区块数据包准备和发送异步化以提高服务器性能.
|
||||
当许多玩家同时加载区块时, 这可以显著减少主线程负载.""");
|
||||
|
||||
if (asyncChunkSendInitialized) {
|
||||
config.getConfigSection(getBasePath());
|
||||
return;
|
||||
}
|
||||
asyncChunkSendInitialized = true;
|
||||
|
||||
enabled = config.getBoolean(getBasePath() + ".enabled", enabled);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package org.dreeam.leaf.config.modules.async;
|
||||
|
||||
import org.dreeam.leaf.config.ConfigModules;
|
||||
import org.dreeam.leaf.config.EnumConfigCategory;
|
||||
import org.dreeam.leaf.config.annotations.Experimental;
|
||||
|
||||
public class AsyncPlayerDataSave extends ConfigModules {
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package org.dreeam.leaf.config.modules.async;
|
||||
|
||||
import org.dreeam.leaf.config.ConfigModules;
|
||||
import org.dreeam.leaf.config.EnumConfigCategory;
|
||||
import org.dreeam.leaf.config.annotations.Experimental;
|
||||
|
||||
public class AsyncTargetFinding extends ConfigModules {
|
||||
|
||||
@@ -16,6 +15,7 @@ public class AsyncTargetFinding extends ConfigModules {
|
||||
public static boolean searchBlock = true;
|
||||
public static boolean searchEntity = true;
|
||||
public static int queueSize = 4096;
|
||||
public static long threshold = 10L;
|
||||
private static boolean asyncTargetFindingInitialized;
|
||||
|
||||
@Override
|
||||
@@ -36,11 +36,15 @@ public class AsyncTargetFinding extends ConfigModules {
|
||||
alertOther = config.getBoolean(getBasePath() + ".async-alert-other", true);
|
||||
searchBlock = config.getBoolean(getBasePath() + ".async-search-block", true);
|
||||
searchEntity = config.getBoolean(getBasePath() + ".async-search-entity", true);
|
||||
queueSize = config.getInt(getBasePath() + ".queue-size", 4096);
|
||||
queueSize = config.getInt(getBasePath() + ".queue-size", 0);
|
||||
threshold = config.getLong(getBasePath() + ".threshold", 0);
|
||||
|
||||
if (queueSize <= 0) {
|
||||
queueSize = 4096;
|
||||
}
|
||||
if (threshold == 0L) {
|
||||
threshold = 10L;
|
||||
}
|
||||
if (!enabled) {
|
||||
alertOther = false;
|
||||
searchEntity = false;
|
||||
|
||||
@@ -57,5 +57,8 @@ public class MultithreadedTracker extends ConfigModules {
|
||||
|
||||
if (asyncEntityTrackerQueueSize <= 0)
|
||||
asyncEntityTrackerQueueSize = asyncEntityTrackerMaxThreads * 384;
|
||||
if (enabled) {
|
||||
org.dreeam.leaf.async.tracker.MultithreadedTracker.init();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package org.dreeam.leaf.config.modules.gameplay;
|
||||
|
||||
import org.dreeam.leaf.config.ConfigModules;
|
||||
import org.dreeam.leaf.config.EnumConfigCategory;
|
||||
|
||||
public class DeathItemDropKnockback extends ConfigModules {
|
||||
|
||||
public String getBasePath() {
|
||||
return EnumConfigCategory.GAMEPLAY.getBaseKeyName() + ".death-item-drop-knockback";
|
||||
}
|
||||
|
||||
public static boolean dropAround = true;
|
||||
public static double horizontalForce = 0.5;
|
||||
public static double verticalForce = 0.2;
|
||||
|
||||
@Override
|
||||
public void onLoaded() {
|
||||
dropAround = config.getBoolean(getBasePath() + ".drop-around", dropAround,
|
||||
config.pickStringRegionBased(
|
||||
"If true, items will drop randomly around the player on death.",
|
||||
"如果为 “true”,物品会在玩家死亡时随机掉落在其周围."
|
||||
));
|
||||
|
||||
horizontalForce = config.getDouble(getBasePath() + ".horizontal-force", horizontalForce,
|
||||
config.pickStringRegionBased(
|
||||
"Base speed for horizontal velocity when randomly dropping items.",
|
||||
"随机掉落物品时水平速度的基本速度."
|
||||
));
|
||||
|
||||
verticalForce = config.getDouble(getBasePath() + ".vertical-force", verticalForce,
|
||||
config.pickStringRegionBased(
|
||||
"Upward motion for randomly dropped items.",
|
||||
"随机掉落物品的向上运动."
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package org.dreeam.leaf.config.modules.gameplay;
|
||||
|
||||
import org.dreeam.leaf.config.ConfigModules;
|
||||
import org.dreeam.leaf.config.EnumConfigCategory;
|
||||
import org.dreeam.leaf.config.annotations.Experimental;
|
||||
|
||||
public class Knockback extends ConfigModules {
|
||||
|
||||
@@ -12,6 +13,8 @@ public class Knockback extends ConfigModules {
|
||||
public static boolean snowballCanKnockback = false;
|
||||
public static boolean eggCanKnockback = false;
|
||||
public static boolean canPlayerKnockbackZombie = true;
|
||||
@Experimental
|
||||
public static boolean flushKnockback = false;
|
||||
|
||||
@Override
|
||||
public void onLoaded() {
|
||||
@@ -30,5 +33,6 @@ public class Knockback extends ConfigModules {
|
||||
"Make players can knockback zombie.",
|
||||
"使玩家可以击退僵尸."
|
||||
));
|
||||
flushKnockback = config.getBoolean(getBasePath() + ".flush-location-while-knockback-player", flushKnockback);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ public class SpawnerSettings extends ConfigModules {
|
||||
public static boolean checkForNearbyPlayers = true;
|
||||
public static boolean spawnerBlockChecks = false;
|
||||
public static boolean waterPreventSpawnCheck = false;
|
||||
public static boolean ignoreSpawnRules = false;
|
||||
|
||||
public static int minSpawnDelay = 200;
|
||||
public static int maxSpawnDelay = 800;
|
||||
@@ -60,8 +61,8 @@ public class SpawnerSettings extends ConfigModules {
|
||||
|
||||
spawnerBlockChecks = config.getBoolean(getBasePath() + ".checks.spawner-block-checks", spawnerBlockChecks,
|
||||
config.pickStringRegionBased(
|
||||
"Check if there are blocks blocking the spawner to spawn the mob",
|
||||
"检查是否有方块阻挡刷怪笼生成怪物"
|
||||
"Check if there are physical blocks obstructing the spawn location, or if custom spawn rules (isValidPosition) fail due to block conditions.",
|
||||
"检查是否有物理方块阻挡生成位置, 或自定义生成规则(isValidPosition)因方块条件失败."
|
||||
));
|
||||
|
||||
waterPreventSpawnCheck = config.getBoolean(getBasePath() + ".checks.water-prevent-spawn-check", waterPreventSpawnCheck,
|
||||
@@ -69,6 +70,11 @@ public class SpawnerSettings extends ConfigModules {
|
||||
"Checks if there is water around that prevents spawning",
|
||||
"检查周围是否有水阻止生成"
|
||||
));
|
||||
ignoreSpawnRules = config.getBoolean(getBasePath() + ".checks.ignore-spawn-rules", ignoreSpawnRules,
|
||||
config.pickStringRegionBased(
|
||||
"Ignore mob-specific spawn rules, like animals needing grass or specific biomes/blocks (does not affect light level or physical obstruction checks).",
|
||||
"忽略特定于生物的生成规则, 例如动物需要草方块或特定的生物群系/方块 (不影响光照等级或物理障碍物检查)."
|
||||
));
|
||||
|
||||
// Delay settings
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ public class Cache extends ConfigModules {
|
||||
return EnumConfigCategory.MISC.getBaseKeyName() + ".cache";
|
||||
}
|
||||
|
||||
public static boolean cachePlayerProfileResult = true;
|
||||
public static boolean cachePlayerProfileResult = false;
|
||||
public static int cachePlayerProfileResultTimeout = 1440;
|
||||
|
||||
@Override
|
||||
|
||||
@@ -9,15 +9,19 @@ public class UnknownCommandMessage extends ConfigModules {
|
||||
return EnumConfigCategory.MISC.getBaseKeyName() + ".message";
|
||||
}
|
||||
|
||||
public static String unknownCommandMessage = "<red><lang:command.unknown.command><newline><detail>";
|
||||
public static String unknownCommandMessage = "default";
|
||||
|
||||
@Override
|
||||
public void onLoaded() {
|
||||
unknownCommandMessage = config.getString(getBasePath() + ".unknown-command", unknownCommandMessage, config.pickStringRegionBased("""
|
||||
Unknown command message, using MiniMessage format, set to "default" to use vanilla message,
|
||||
placeholder: <detail>, shows detail of the unknown command information.""",
|
||||
placeholder:
|
||||
<message>, show message of the command exception.
|
||||
<detail>, shows detail of the command exception.""",
|
||||
"""
|
||||
发送未知命令时的消息, 使用 MiniMessage 格式, 设置为 "default" 使用原版消息.
|
||||
变量: <detail>, 显示未知命令详细信息."""));
|
||||
变量:
|
||||
<message>, 显示命令错误所附提示消息.
|
||||
<detail>, 显示命令错误详细信息."""));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package org.dreeam.leaf.config.modules.network;
|
||||
|
||||
import org.dreeam.leaf.config.ConfigModules;
|
||||
import org.dreeam.leaf.config.EnumConfigCategory;
|
||||
|
||||
public class AlternativeJoin extends ConfigModules {
|
||||
|
||||
public String getBasePath() {
|
||||
return EnumConfigCategory.NETWORK.getBaseKeyName();
|
||||
}
|
||||
|
||||
public static boolean enabled = false;
|
||||
|
||||
@Override
|
||||
public void onLoaded() {
|
||||
enabled = config.getBoolean(getBasePath() + ".async-switch-state", enabled, config.pickStringRegionBased(
|
||||
"Async switch connection state.",
|
||||
"异步切换连接状态."));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.dreeam.leaf.config.modules.opt;
|
||||
|
||||
import org.dreeam.leaf.config.ConfigModules;
|
||||
import org.dreeam.leaf.config.EnumConfigCategory;
|
||||
|
||||
public class CheckSurvivalBeforeGrowth extends ConfigModules {
|
||||
|
||||
public String getBasePath() {
|
||||
return EnumConfigCategory.PERF.getBaseKeyName() + ".check-survival-before-growth";
|
||||
}
|
||||
|
||||
public static boolean cactusCheckSurvivalBeforeGrowth = false;
|
||||
|
||||
@Override
|
||||
public void onLoaded() {
|
||||
cactusCheckSurvivalBeforeGrowth = config.getBoolean(getBasePath() + ".cactus-check-survival", cactusCheckSurvivalBeforeGrowth,
|
||||
config.pickStringRegionBased("""
|
||||
Check if a cactus can survive before growing.""",
|
||||
"""
|
||||
在仙人掌生长前检查其是否能够存活。"""));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.dreeam.leaf.config.modules.opt;
|
||||
|
||||
import org.dreeam.leaf.config.ConfigModules;
|
||||
import org.dreeam.leaf.config.EnumConfigCategory;
|
||||
|
||||
public class EyeFluidCache extends ConfigModules {
|
||||
|
||||
public String getBasePath() {
|
||||
return EnumConfigCategory.PERF.getBaseKeyName();
|
||||
}
|
||||
|
||||
public static boolean enabled = false;
|
||||
|
||||
@Override
|
||||
public void onLoaded() {
|
||||
enabled = config.getBoolean(getBasePath() + ".cache-eye-fluid-status", enabled,
|
||||
config.pickStringRegionBased(
|
||||
"Whether to cache the isEyeInFluid method to improve performance and reduce memory usage.",
|
||||
"是否为 isEyeInFluid 方法启用缓存,以优化性能并减少内存使用."));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package org.dreeam.leaf.config.modules.opt;
|
||||
|
||||
import org.dreeam.leaf.config.ConfigModules;
|
||||
import org.dreeam.leaf.config.EnumConfigCategory;
|
||||
|
||||
public class OptimiseBlockEntities extends ConfigModules {
|
||||
|
||||
public String getBasePath() {
|
||||
return EnumConfigCategory.PERF.getBaseKeyName();
|
||||
}
|
||||
|
||||
public static boolean enabled = true;
|
||||
|
||||
@Override
|
||||
public void onLoaded() {
|
||||
enabled = config.getBoolean(getBasePath() + ".optimise-block-entities", enabled);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.dreeam.leaf.config.modules.opt;
|
||||
|
||||
import org.dreeam.leaf.config.ConfigModules;
|
||||
import org.dreeam.leaf.config.EnumConfigCategory;
|
||||
|
||||
public class OptimizeItemTicking extends ConfigModules {
|
||||
|
||||
public String getBasePath() {
|
||||
return EnumConfigCategory.PERF.getBaseKeyName();
|
||||
}
|
||||
|
||||
public static boolean onlyTickItemsInHand = false;
|
||||
|
||||
@Override
|
||||
public void onLoaded() {
|
||||
onlyTickItemsInHand = config.getBoolean(getBasePath() + ".only-tick-items-in-hand", onlyTickItemsInHand, config.pickStringRegionBased("""
|
||||
Whether to only tick / update items in main hand and offhand instead of the entire inventory.""",
|
||||
"""
|
||||
是否只对主手和副手中的物品进行 tick / 更新,而不是整个物品栏中的所有物品。"""));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.dreeam.leaf.config.modules.opt;
|
||||
|
||||
import org.dreeam.leaf.config.ConfigModules;
|
||||
import org.dreeam.leaf.config.EnumConfigCategory;
|
||||
|
||||
public class OptimizePlayerMovementProcessing extends ConfigModules {
|
||||
|
||||
public String getBasePath() {
|
||||
return EnumConfigCategory.PERF.getBaseKeyName();
|
||||
}
|
||||
|
||||
public static boolean enabled = true;
|
||||
|
||||
@Override
|
||||
public void onLoaded() {
|
||||
enabled = config.getBoolean(getBasePath() + ".optimize-player-movement", enabled, config.pickStringRegionBased("""
|
||||
Whether to optimize player movement processing by skipping unnecessary edge checks and avoiding redundant view distance updates.""",
|
||||
"""
|
||||
是否优化玩家移动处理,跳过不必要的边缘检查并避免冗余的视距更新。"""));
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package org.dreeam.leaf.config.modules.opt;
|
||||
|
||||
import org.dreeam.leaf.config.ConfigModules;
|
||||
import org.dreeam.leaf.config.EnumConfigCategory;
|
||||
|
||||
public class ReduceChunkSourceUpdates extends ConfigModules {
|
||||
|
||||
public String getBasePath() {
|
||||
return EnumConfigCategory.PERF.getBaseKeyName() + ".reduce-chunk-source-updates";
|
||||
}
|
||||
|
||||
public static boolean enabled = false;
|
||||
|
||||
@Override
|
||||
public void onLoaded() {
|
||||
enabled = config.getBoolean(getBasePath() + ".enabled", enabled,
|
||||
config.pickStringRegionBased(
|
||||
"Reduces chunk source updates on inter-chunk player moves. (Recommended to enable)",
|
||||
"减少玩家跨区块移动时的区块源更新。"
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
package org.dreeam.leaf.protocol;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.codec.ByteBufCodecs;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class DoABarrelRollPackets {
|
||||
|
||||
private static <T extends LeafCustomPayload> LeafCustomPayload.@NotNull Type<T> createType(String path) {
|
||||
return new LeafCustomPayload.Type<>(ResourceLocation.fromNamespaceAndPath(DoABarrelRollProtocol.NAMESPACE, path));
|
||||
}
|
||||
|
||||
public record ConfigResponseC2SPacket(int protocolVersion, boolean success) implements LeafCustomPayload {
|
||||
public static final Type<ConfigResponseC2SPacket> TYPE = createType("config_response");
|
||||
public static final StreamCodec<FriendlyByteBuf, ConfigResponseC2SPacket> STREAM_CODEC = StreamCodec.composite(
|
||||
ByteBufCodecs.INT, ConfigResponseC2SPacket::protocolVersion,
|
||||
ByteBufCodecs.BOOL, ConfigResponseC2SPacket::success,
|
||||
ConfigResponseC2SPacket::new
|
||||
);
|
||||
|
||||
@Override
|
||||
public @NotNull Type<ConfigResponseC2SPacket> type() {
|
||||
return TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
public record ConfigSyncS2CPacket(int protocolVersion,
|
||||
LimitedModConfigServer applicableConfig,
|
||||
boolean isLimited,
|
||||
ModConfigServer fullConfig
|
||||
) implements LeafCustomPayload {
|
||||
public static final Type<ConfigSyncS2CPacket> TYPE = createType("config_sync");
|
||||
public static final StreamCodec<FriendlyByteBuf, ConfigSyncS2CPacket> STREAM_CODEC = StreamCodec.composite(
|
||||
ByteBufCodecs.INT, ConfigSyncS2CPacket::protocolVersion,
|
||||
LimitedModConfigServer.getCodec(), ConfigSyncS2CPacket::applicableConfig,
|
||||
ByteBufCodecs.BOOL, ConfigSyncS2CPacket::isLimited,
|
||||
ModConfigServer.PACKET_CODEC, ConfigSyncS2CPacket::fullConfig,
|
||||
ConfigSyncS2CPacket::new
|
||||
);
|
||||
|
||||
@Override
|
||||
public @NotNull Type<ConfigSyncS2CPacket> type() {
|
||||
return TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
public record ConfigUpdateAckS2CPacket(int protocolVersion, boolean success) implements LeafCustomPayload {
|
||||
public static final Type<ConfigUpdateAckS2CPacket> TYPE = createType("config_update_ack");
|
||||
public static final StreamCodec<FriendlyByteBuf, ConfigUpdateAckS2CPacket> STREAM_CODEC = StreamCodec.composite(
|
||||
ByteBufCodecs.INT, ConfigUpdateAckS2CPacket::protocolVersion,
|
||||
ByteBufCodecs.BOOL, ConfigUpdateAckS2CPacket::success,
|
||||
ConfigUpdateAckS2CPacket::new
|
||||
);
|
||||
|
||||
@Override
|
||||
public @NotNull Type<ConfigUpdateAckS2CPacket> type() {
|
||||
return TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
public record ConfigUpdateC2SPacket(int protocolVersion, ModConfigServer config) implements LeafCustomPayload {
|
||||
public static final Type<ConfigUpdateC2SPacket> TYPE = createType("config_update");
|
||||
public static final StreamCodec<FriendlyByteBuf, ConfigUpdateC2SPacket> STREAM_CODEC = StreamCodec.composite(
|
||||
ByteBufCodecs.INT, ConfigUpdateC2SPacket::protocolVersion,
|
||||
ModConfigServer.PACKET_CODEC, ConfigUpdateC2SPacket::config,
|
||||
ConfigUpdateC2SPacket::new
|
||||
);
|
||||
|
||||
@Override
|
||||
public @NotNull Type<ConfigUpdateC2SPacket> type() {
|
||||
return TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
public record RollSyncC2SPacket(boolean rolling, float roll) implements LeafCustomPayload {
|
||||
public static final Type<RollSyncC2SPacket> TYPE = createType("roll_sync");
|
||||
public static final StreamCodec<FriendlyByteBuf, RollSyncC2SPacket> STREAM_CODEC = StreamCodec.composite(
|
||||
ByteBufCodecs.BOOL, RollSyncC2SPacket::rolling,
|
||||
ByteBufCodecs.FLOAT, RollSyncC2SPacket::roll,
|
||||
RollSyncC2SPacket::new
|
||||
);
|
||||
|
||||
@Override
|
||||
public @NotNull Type<RollSyncC2SPacket> type() {
|
||||
return TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
public record RollSyncS2CPacket(int entityId, boolean rolling, float roll) implements LeafCustomPayload {
|
||||
public static final Type<RollSyncS2CPacket> TYPE = createType("roll_sync");
|
||||
public static final StreamCodec<FriendlyByteBuf, RollSyncS2CPacket> STREAM_CODEC = StreamCodec.composite(
|
||||
ByteBufCodecs.INT, RollSyncS2CPacket::entityId,
|
||||
ByteBufCodecs.BOOL, RollSyncS2CPacket::rolling,
|
||||
ByteBufCodecs.FLOAT, RollSyncS2CPacket::roll,
|
||||
RollSyncS2CPacket::new
|
||||
);
|
||||
|
||||
@Override
|
||||
public @NotNull Type<RollSyncS2CPacket> type() {
|
||||
return TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
public interface LimitedModConfigServer {
|
||||
boolean allowThrusting();
|
||||
|
||||
boolean forceEnabled();
|
||||
|
||||
static StreamCodec<ByteBuf, LimitedModConfigServer> getCodec() {
|
||||
return StreamCodec.composite(
|
||||
ByteBufCodecs.BOOL, LimitedModConfigServer::allowThrusting,
|
||||
ByteBufCodecs.BOOL, LimitedModConfigServer::forceEnabled,
|
||||
Impl::new
|
||||
);
|
||||
}
|
||||
|
||||
record Impl(boolean allowThrusting, boolean forceEnabled) implements LimitedModConfigServer {
|
||||
}
|
||||
}
|
||||
|
||||
public record ModConfigServer(boolean allowThrusting,
|
||||
boolean forceEnabled,
|
||||
boolean forceInstalled,
|
||||
int installedTimeout,
|
||||
KineticDamage kineticDamage
|
||||
) implements LimitedModConfigServer {
|
||||
public static final StreamCodec<ByteBuf, ModConfigServer> PACKET_CODEC = StreamCodec.composite(
|
||||
ByteBufCodecs.BOOL, ModConfigServer::allowThrusting,
|
||||
ByteBufCodecs.BOOL, ModConfigServer::forceEnabled,
|
||||
ByteBufCodecs.BOOL, ModConfigServer::forceInstalled,
|
||||
ByteBufCodecs.INT, ModConfigServer::installedTimeout,
|
||||
KineticDamage.CODEC, ModConfigServer::kineticDamage,
|
||||
ModConfigServer::new
|
||||
);
|
||||
}
|
||||
|
||||
public enum KineticDamage {
|
||||
VANILLA,
|
||||
HIGH_SPEED,
|
||||
NONE,
|
||||
INSTANT_KILL;
|
||||
|
||||
public static final StreamCodec<ByteBuf, KineticDamage> CODEC =
|
||||
ByteBufCodecs.STRING_UTF8.map(KineticDamage::valueOf, KineticDamage::name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,313 @@
|
||||
package org.dreeam.leaf.protocol;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import it.unimi.dsi.fastutil.objects.Reference2BooleanMap;
|
||||
import it.unimi.dsi.fastutil.objects.Reference2BooleanMaps;
|
||||
import it.unimi.dsi.fastutil.objects.Reference2BooleanOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.Reference2FloatMap;
|
||||
import it.unimi.dsi.fastutil.objects.Reference2FloatMaps;
|
||||
import it.unimi.dsi.fastutil.objects.Reference2FloatOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.Reference2ReferenceMap;
|
||||
import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.server.network.ServerGamePacketListenerImpl;
|
||||
import net.minecraft.server.network.ServerPlayerConnection;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dreeam.leaf.protocol.DoABarrelRollPackets.ConfigResponseC2SPacket;
|
||||
import org.dreeam.leaf.protocol.DoABarrelRollPackets.ConfigSyncS2CPacket;
|
||||
import org.dreeam.leaf.protocol.DoABarrelRollPackets.ConfigUpdateAckS2CPacket;
|
||||
import org.dreeam.leaf.protocol.DoABarrelRollPackets.ConfigUpdateC2SPacket;
|
||||
import org.dreeam.leaf.protocol.DoABarrelRollPackets.KineticDamage;
|
||||
import org.dreeam.leaf.protocol.DoABarrelRollPackets.ModConfigServer;
|
||||
import org.dreeam.leaf.protocol.DoABarrelRollPackets.RollSyncC2SPacket;
|
||||
import org.dreeam.leaf.protocol.DoABarrelRollPackets.RollSyncS2CPacket;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.bukkit.event.player.PlayerKickEvent;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.OptionalInt;
|
||||
|
||||
public class DoABarrelRollProtocol implements Protocol {
|
||||
|
||||
protected static final String NAMESPACE = "do_a_barrel_roll";
|
||||
private static final Logger LOGGER = LogManager.getLogger(NAMESPACE);
|
||||
private static final int PROTOCOL_VERSION = 4;
|
||||
private static final ModConfigServer DEFAULT = new ModConfigServer(false, false, false, 40, KineticDamage.VANILLA);
|
||||
private static final Component SYNC_TIMEOUT_MESSAGE = Component.literal("Please install Do a Barrel Roll 2.4.0 or later to play on this server.");
|
||||
private static DoABarrelRollProtocol INSTANCE = null;
|
||||
|
||||
private final List<Protocols.TypeAndCodec<FriendlyByteBuf, ? extends LeafCustomPayload>> c2s = ImmutableList.of(
|
||||
new Protocols.TypeAndCodec<>(ConfigUpdateC2SPacket.TYPE, ConfigUpdateC2SPacket.STREAM_CODEC),
|
||||
new Protocols.TypeAndCodec<>(ConfigResponseC2SPacket.TYPE, ConfigResponseC2SPacket.STREAM_CODEC),
|
||||
new Protocols.TypeAndCodec<>(RollSyncC2SPacket.TYPE, RollSyncC2SPacket.STREAM_CODEC));
|
||||
|
||||
private final List<Protocols.TypeAndCodec<FriendlyByteBuf, ? extends LeafCustomPayload>> s2c = ImmutableList.of(
|
||||
new Protocols.TypeAndCodec<>(ConfigUpdateAckS2CPacket.TYPE, ConfigUpdateAckS2CPacket.STREAM_CODEC),
|
||||
new Protocols.TypeAndCodec<>(ConfigSyncS2CPacket.TYPE, ConfigSyncS2CPacket.STREAM_CODEC),
|
||||
new Protocols.TypeAndCodec<>(RollSyncS2CPacket.TYPE, RollSyncS2CPacket.STREAM_CODEC)
|
||||
);
|
||||
|
||||
private ModConfigServer config = DEFAULT;
|
||||
private boolean configUpdated = false;
|
||||
|
||||
private final Reference2ReferenceMap<ServerGamePacketListenerImpl, ClientInfo> syncStates = new Reference2ReferenceOpenHashMap<>();
|
||||
private final Reference2ReferenceMap<ServerGamePacketListenerImpl, DelayedRunnable> scheduledKicks = new Reference2ReferenceOpenHashMap<>();
|
||||
public final Reference2BooleanMap<ServerGamePacketListenerImpl> isRollingMap = Reference2BooleanMaps.synchronize(new Reference2BooleanOpenHashMap<>());
|
||||
public final Reference2FloatMap<ServerGamePacketListenerImpl> rollMap = Reference2FloatMaps.synchronize(new Reference2FloatOpenHashMap<>());
|
||||
public final Reference2BooleanMap<ServerGamePacketListenerImpl> lastIsRollingMap = Reference2BooleanMaps.synchronize(new Reference2BooleanOpenHashMap<>());
|
||||
public final Reference2FloatMap<ServerGamePacketListenerImpl> lastRollMap = Reference2FloatMaps.synchronize(new Reference2FloatOpenHashMap<>());
|
||||
|
||||
public static void deinit() {
|
||||
if (INSTANCE != null) {
|
||||
INSTANCE = null;
|
||||
Protocols.unregister(INSTANCE);
|
||||
}
|
||||
}
|
||||
|
||||
public static void init(
|
||||
boolean allowThrusting,
|
||||
boolean forceEnabled,
|
||||
boolean forceInstalled,
|
||||
int installedTimeout,
|
||||
KineticDamage kineticDamage
|
||||
) {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = new DoABarrelRollProtocol();
|
||||
Protocols.register(INSTANCE);
|
||||
}
|
||||
INSTANCE.config = new ModConfigServer(allowThrusting, forceEnabled, forceInstalled, installedTimeout, kineticDamage);
|
||||
INSTANCE.configUpdated = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String namespace() {
|
||||
return NAMESPACE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Protocols.TypeAndCodec<FriendlyByteBuf, ? extends LeafCustomPayload>> c2s() {
|
||||
return c2s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Protocols.TypeAndCodec<FriendlyByteBuf, ? extends LeafCustomPayload>> s2c() {
|
||||
return s2c;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(ServerPlayer player, @NotNull LeafCustomPayload payload) {
|
||||
switch (payload) {
|
||||
case ConfigUpdateC2SPacket ignored ->
|
||||
player.connection.send(Protocols.createPacket(new ConfigUpdateAckS2CPacket(PROTOCOL_VERSION, false)));
|
||||
case ConfigResponseC2SPacket configResponseC2SPacket -> {
|
||||
var reply = clientReplied(player.connection, configResponseC2SPacket);
|
||||
if (reply == HandshakeState.RESEND) {
|
||||
sendHandshake(player);
|
||||
}
|
||||
}
|
||||
case RollSyncC2SPacket rollSyncC2SPacket -> {
|
||||
var state = getHandshakeState(player.connection);
|
||||
if (state.state != HandshakeState.ACCEPTED) {
|
||||
return;
|
||||
}
|
||||
var rolling = rollSyncC2SPacket.rolling();
|
||||
var roll = rollSyncC2SPacket.roll();
|
||||
isRollingMap.put(player.connection, rolling);
|
||||
if (Float.isInfinite(roll)) {
|
||||
roll = 0.0F;
|
||||
}
|
||||
rollMap.put(player.connection, roll);
|
||||
}
|
||||
default -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnected(ServerPlayer player) {
|
||||
final var handler = player.connection;
|
||||
syncStates.remove(handler);
|
||||
isRollingMap.removeBoolean(handler);
|
||||
rollMap.removeFloat(handler);
|
||||
lastIsRollingMap.removeBoolean(handler);
|
||||
lastRollMap.removeFloat(handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tickTracker(ServerPlayer player) {
|
||||
if (!isRollingMap.containsKey(player.connection)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var isRolling = isRollingMap.getBoolean(player.connection);
|
||||
var roll = rollMap.getFloat(player.connection);
|
||||
var lastIsRolling = lastIsRollingMap.getBoolean(player.connection);
|
||||
var lastRoll = lastRollMap.getFloat(player.connection);
|
||||
if (isRolling == lastIsRolling && roll == lastRoll) {
|
||||
return;
|
||||
}
|
||||
var payload = new RollSyncS2CPacket(player.getId(), isRolling, roll);
|
||||
var packet = Protocols.createPacket(payload);
|
||||
for (ServerPlayerConnection seenBy : player.moonrise$getTrackedEntity().seenBy()) {
|
||||
if (seenBy instanceof ServerGamePacketListenerImpl conn
|
||||
&& getHandshakeState(conn).state == HandshakeState.ACCEPTED) {
|
||||
seenBy.send(packet);
|
||||
}
|
||||
}
|
||||
lastIsRollingMap.put(player.connection, isRolling);
|
||||
lastRollMap.put(player.connection, roll);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tickPlayer(ServerPlayer player) {
|
||||
if (getHandshakeState(player.connection).state == HandshakeState.NOT_SENT) {
|
||||
sendHandshake(player);
|
||||
}
|
||||
if (!isRollingMap.containsKey(player.connection)) {
|
||||
return;
|
||||
}
|
||||
if (!isRollingMap.getBoolean(player.connection)) {
|
||||
rollMap.put(player.connection, 0.0F);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tickServer(MinecraftServer server) {
|
||||
var it = scheduledKicks.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
var entry = it.next();
|
||||
if (entry.getValue().isDone()) {
|
||||
it.remove();
|
||||
} else {
|
||||
entry.getValue().tick();
|
||||
}
|
||||
}
|
||||
|
||||
if (configUpdated) {
|
||||
configUpdated = false;
|
||||
for (ServerPlayer player : server.getPlayerList().players) {
|
||||
sendHandshake(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private OptionalInt getSyncTimeout(ModConfigServer config) {
|
||||
return config.forceInstalled() ? OptionalInt.of(config.installedTimeout()) : OptionalInt.empty();
|
||||
}
|
||||
|
||||
private void sendHandshake(ServerPlayer player) {
|
||||
player.connection.send(Protocols.createPacket(initiateConfigSync(player.connection)));
|
||||
configSentToClient(player.connection);
|
||||
}
|
||||
|
||||
private void configSentToClient(ServerGamePacketListenerImpl handler) {
|
||||
getHandshakeState(handler).state = HandshakeState.SENT;
|
||||
|
||||
OptionalInt timeout = getSyncTimeout(config);
|
||||
if (timeout.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
scheduledKicks.put(handler, new DelayedRunnable(timeout.getAsInt(), () -> {
|
||||
if (getHandshakeState(handler).state != HandshakeState.ACCEPTED) {
|
||||
LOGGER.warn(
|
||||
"{} did not accept config syncing, config indicates we kick them.",
|
||||
handler.getPlayer().getName().getString()
|
||||
);
|
||||
handler.disconnect(SYNC_TIMEOUT_MESSAGE, PlayerKickEvent.Cause.PLUGIN);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private HandshakeState clientReplied(ServerGamePacketListenerImpl handler, ConfigResponseC2SPacket packet) {
|
||||
var info = getHandshakeState(handler);
|
||||
var player = handler.getPlayer();
|
||||
|
||||
if (info.state == HandshakeState.SENT) {
|
||||
var protocolVersion = packet.protocolVersion();
|
||||
if (protocolVersion < 1 || protocolVersion > PROTOCOL_VERSION) {
|
||||
LOGGER.warn(
|
||||
"{} sent unknown protocol version, expected range 1-{}, got {}. Will attempt to proceed anyway.",
|
||||
player.getName().getString(),
|
||||
PROTOCOL_VERSION,
|
||||
protocolVersion
|
||||
);
|
||||
}
|
||||
|
||||
if (protocolVersion == 2 && info.protocolVersion != 2) {
|
||||
LOGGER.info("{} is using an older protocol version, resending.", player.getName().getString());
|
||||
info.state = HandshakeState.RESEND;
|
||||
} else if (packet.success()) {
|
||||
LOGGER.info("{} accepted server config.", player.getName().getString());
|
||||
info.state = HandshakeState.ACCEPTED;
|
||||
} else {
|
||||
LOGGER.warn(
|
||||
"{} failed to process server config, check client logs find what went wrong.",
|
||||
player.getName().getString());
|
||||
info.state = HandshakeState.FAILED;
|
||||
}
|
||||
info.protocolVersion = protocolVersion;
|
||||
}
|
||||
|
||||
return info.state;
|
||||
}
|
||||
|
||||
private boolean isLimited(ServerGamePacketListenerImpl net) {
|
||||
return true;
|
||||
// return net.getPlayer().getBukkitEntity().hasPermission(DoABarrelRoll.MODID + ".configure");
|
||||
}
|
||||
|
||||
private ClientInfo getHandshakeState(ServerGamePacketListenerImpl handler) {
|
||||
return syncStates.computeIfAbsent(handler, key -> new ClientInfo(HandshakeState.NOT_SENT, PROTOCOL_VERSION, true));
|
||||
}
|
||||
|
||||
private ConfigSyncS2CPacket initiateConfigSync(ServerGamePacketListenerImpl handler) {
|
||||
var isLimited = isLimited(handler);
|
||||
getHandshakeState(handler).isLimited = isLimited;
|
||||
return new ConfigSyncS2CPacket(PROTOCOL_VERSION, config, isLimited, isLimited ? DEFAULT : config);
|
||||
}
|
||||
|
||||
private static class ClientInfo {
|
||||
private HandshakeState state;
|
||||
private int protocolVersion;
|
||||
private boolean isLimited;
|
||||
|
||||
private ClientInfo(HandshakeState state, int protocolVersion, boolean isLimited) {
|
||||
this.state = state;
|
||||
this.protocolVersion = protocolVersion;
|
||||
this.isLimited = isLimited;
|
||||
}
|
||||
}
|
||||
|
||||
private static class DelayedRunnable {
|
||||
private final Runnable runnable;
|
||||
private final int delay;
|
||||
private int ticks = 0;
|
||||
|
||||
private DelayedRunnable(int delay, Runnable runnable) {
|
||||
this.runnable = runnable;
|
||||
this.delay = delay;
|
||||
}
|
||||
|
||||
private void tick() {
|
||||
if (++ticks >= delay) {
|
||||
runnable.run();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isDone() {
|
||||
return ticks >= delay;
|
||||
}
|
||||
}
|
||||
|
||||
private enum HandshakeState {
|
||||
NOT_SENT,
|
||||
SENT,
|
||||
ACCEPTED,
|
||||
FAILED,
|
||||
RESEND
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package org.dreeam.leaf.protocol;
|
||||
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface LeafCustomPayload extends CustomPacketPayload {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
Type<? extends LeafCustomPayload> type();
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package org.dreeam.leaf.protocol;
|
||||
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
interface Protocol {
|
||||
|
||||
String namespace();
|
||||
|
||||
List<Protocols.TypeAndCodec<FriendlyByteBuf, ? extends LeafCustomPayload>> c2s();
|
||||
|
||||
List<Protocols.TypeAndCodec<FriendlyByteBuf, ? extends LeafCustomPayload>> s2c();
|
||||
|
||||
void tickServer(MinecraftServer server);
|
||||
|
||||
void tickPlayer(ServerPlayer player);
|
||||
|
||||
void tickTracker(ServerPlayer player);
|
||||
|
||||
void disconnected(ServerPlayer conn);
|
||||
|
||||
void handle(ServerPlayer player, @NotNull LeafCustomPayload payload);
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package org.dreeam.leaf.protocol;
|
||||
|
||||
import io.netty.buffer.Unpooled;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket;
|
||||
import net.minecraft.network.protocol.common.custom.DiscardedPayload;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class Protocols {
|
||||
|
||||
private static final ObjectArrayList<Protocol> PROTOCOLS = new ObjectArrayList<>();
|
||||
|
||||
static void register(Protocol protocol) {
|
||||
PROTOCOLS.add(protocol);
|
||||
}
|
||||
|
||||
static void unregister(Protocol protocol) {
|
||||
PROTOCOLS.remove(protocol);
|
||||
}
|
||||
|
||||
public record TypeAndCodec<B extends FriendlyByteBuf, T extends LeafCustomPayload>(LeafCustomPayload.Type<T> type,
|
||||
StreamCodec<B, T> codec) {
|
||||
}
|
||||
|
||||
public static <B extends FriendlyByteBuf> void write(B byteBuf, LeafCustomPayload payload) {
|
||||
for (Protocol protocol : PROTOCOLS) {
|
||||
if (protocol.namespace().equals(payload.type().id().getNamespace())) {
|
||||
encode(byteBuf, payload, protocol);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void handle(ServerPlayer player, @NotNull DiscardedPayload payload) {
|
||||
for (Protocol protocol : PROTOCOLS) {
|
||||
if (payload.type().id().getNamespace().equals(protocol.namespace())) {
|
||||
var leafCustomPayload = decode(protocol, payload);
|
||||
if (leafCustomPayload != null) {
|
||||
protocol.handle(player, leafCustomPayload);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void tickServer(MinecraftServer server) {
|
||||
for (Protocol protocol : PROTOCOLS) {
|
||||
protocol.tickServer(server);
|
||||
}
|
||||
}
|
||||
|
||||
public static void tickPlayer(ServerPlayer player) {
|
||||
for (Protocol protocol : PROTOCOLS) {
|
||||
protocol.tickPlayer(player);
|
||||
}
|
||||
}
|
||||
|
||||
public static void tickTracker(ServerPlayer player) {
|
||||
for (Protocol protocol : PROTOCOLS) {
|
||||
protocol.tickTracker(player);
|
||||
}
|
||||
}
|
||||
|
||||
public static void disconnected(ServerPlayer conn) {
|
||||
for (Protocol protocol : PROTOCOLS) {
|
||||
protocol.disconnected(conn);
|
||||
}
|
||||
}
|
||||
|
||||
@Contract("_ -> new")
|
||||
public static @NotNull ClientboundCustomPayloadPacket createPacket(LeafCustomPayload payload) {
|
||||
return new ClientboundCustomPayloadPacket(payload);
|
||||
}
|
||||
|
||||
private static <B extends FriendlyByteBuf> void encode(B byteBuf, LeafCustomPayload payload, Protocol protocol) {
|
||||
for (var codec : protocol.s2c()) {
|
||||
if (codec.type().id().equals(payload.type().id())) {
|
||||
byteBuf.writeResourceLocation(payload.type().id());
|
||||
//noinspection unchecked,rawtypes
|
||||
((StreamCodec) codec.codec()).encode(byteBuf, payload);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static @Nullable LeafCustomPayload decode(Protocol protocol, DiscardedPayload payload) {
|
||||
for (var packet : protocol.c2s()) {
|
||||
if (packet.type().id().equals(payload.type().id())) {
|
||||
return packet.codec().decode(new FriendlyByteBuf(Unpooled.wrappedBuffer(payload.data())));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package org.dreeam.leaf.util;
|
||||
|
||||
import net.minecraft.world.entity.Entity;
|
||||
|
||||
import java.lang.reflect.Array; // Required for Array.newInstance
|
||||
import java.util.List;
|
||||
|
||||
public class FastBitRadixSort {
|
||||
|
||||
private static final int SMALL_ARRAY_THRESHOLD = 2;
|
||||
private Entity[] entityBuffer = new Entity[0];
|
||||
private long[] bitsBuffer = new long[0];
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Entity, T_REF extends Entity> T[] sort(List<T> entities, T_REF referenceEntity, Class<T> entityClass) {
|
||||
int size = entities.size();
|
||||
if (size <= 1) {
|
||||
T[] resultArray = (T[]) Array.newInstance(entityClass, size);
|
||||
return entities.toArray(resultArray);
|
||||
}
|
||||
|
||||
if (this.entityBuffer.length < size) {
|
||||
this.entityBuffer = new Entity[size];
|
||||
this.bitsBuffer = new long[size];
|
||||
}
|
||||
for (int i = 0; i < size; i++) {
|
||||
this.entityBuffer[i] = entities.get(i);
|
||||
this.bitsBuffer[i] = Double.doubleToRawLongBits(
|
||||
referenceEntity.distanceToSqr(entities.get(i))
|
||||
);
|
||||
}
|
||||
|
||||
fastRadixSort(this.entityBuffer, this.bitsBuffer, 0, size - 1, 62);
|
||||
|
||||
T[] resultArray = (T[]) Array.newInstance(entityClass, size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
resultArray[i] = entityClass.cast(this.entityBuffer[i]);
|
||||
}
|
||||
return resultArray;
|
||||
}
|
||||
|
||||
private void fastRadixSort(
|
||||
Entity[] ents,
|
||||
long[] bits,
|
||||
int low,
|
||||
int high,
|
||||
int bit
|
||||
) {
|
||||
if (bit < 0 || low >= high) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (high - low <= SMALL_ARRAY_THRESHOLD) {
|
||||
insertionSort(ents, bits, low, high);
|
||||
return;
|
||||
}
|
||||
|
||||
int i = low;
|
||||
int j = high;
|
||||
final long mask = 1L << bit;
|
||||
|
||||
while (i <= j) {
|
||||
while (i <= j && (bits[i] & mask) == 0) {
|
||||
i++;
|
||||
}
|
||||
while (i <= j && (bits[j] & mask) != 0) {
|
||||
j--;
|
||||
}
|
||||
if (i < j) {
|
||||
swap(ents, bits, i++, j--);
|
||||
}
|
||||
}
|
||||
|
||||
if (low < j) {
|
||||
fastRadixSort(ents, bits, low, j, bit - 1);
|
||||
}
|
||||
if (i < high) {
|
||||
fastRadixSort(ents, bits, i, high, bit - 1);
|
||||
}
|
||||
}
|
||||
|
||||
private void insertionSort(
|
||||
Entity[] ents,
|
||||
long[] bits,
|
||||
int low,
|
||||
int high
|
||||
) {
|
||||
for (int i = low + 1; i <= high; i++) {
|
||||
int j = i;
|
||||
Entity currentEntity = ents[j];
|
||||
long currentBits = bits[j];
|
||||
|
||||
while (j > low && bits[j - 1] > currentBits) {
|
||||
ents[j] = ents[j - 1];
|
||||
bits[j] = bits[j - 1];
|
||||
j--;
|
||||
}
|
||||
ents[j] = currentEntity;
|
||||
bits[j] = currentBits;
|
||||
}
|
||||
}
|
||||
|
||||
private void swap(Entity[] ents, long[] bits, int a, int b) {
|
||||
Entity tempEntity = ents[a];
|
||||
ents[a] = ents[b];
|
||||
ents[b] = tempEntity;
|
||||
|
||||
long tempBits = bits[a];
|
||||
bits[a] = bits[b];
|
||||
bits[b] = tempBits;
|
||||
}
|
||||
}
|
||||
@@ -2,13 +2,12 @@ package org.dreeam.leaf.util.cache;
|
||||
|
||||
import it.unimi.dsi.fastutil.longs.LongArrayList;
|
||||
import it.unimi.dsi.fastutil.longs.LongList;
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
||||
/**
|
||||
* @author 2No2Name, original implemenation by SuperCoder7979 and Gegy1000
|
||||
*/
|
||||
|
||||
@@ -2,11 +2,10 @@ package org.dreeam.leaf.util.cache;
|
||||
|
||||
import it.unimi.dsi.fastutil.longs.LongIterator;
|
||||
import it.unimi.dsi.fastutil.longs.LongList;
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
||||
/**
|
||||
* @author 2No2Name
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,303 @@
|
||||
package org.dreeam.leaf.util.list;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ReferenceArrayList;
|
||||
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* A List implementation that maintains a hash-based counter for O(1) element lookup.
|
||||
* Combines an array-based list for order with a hash map for fast containment checks.
|
||||
*/
|
||||
public class HashedReferenceList<T> implements List<T> {
|
||||
|
||||
// The actual ordered storage of elements
|
||||
private final ReferenceArrayList<T> list = new ReferenceArrayList<>();
|
||||
// Tracks occurrence count of each element for O(1) contains checks
|
||||
private final Reference2IntOpenHashMap<T> counter;
|
||||
|
||||
/**
|
||||
* Creates a new HashedReferenceList containing all elements from the provided list
|
||||
* while building a counter map for fast lookups.
|
||||
*/
|
||||
public HashedReferenceList(List<T> list) {
|
||||
this.list.addAll(list);
|
||||
this.counter = new Reference2IntOpenHashMap<>();
|
||||
this.counter.defaultReturnValue(0);
|
||||
for (T obj : this.list) {
|
||||
this.counter.addTo(obj, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return this.list.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return this.list.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an element exists in the list in O(1) time using the counter map.
|
||||
*/
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return this.counter.containsKey(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return this.listIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
return this.list.toArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T1> T1[] toArray(T1 @NotNull [] a) {
|
||||
return this.list.toArray(a);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an element and updates the counter map.
|
||||
*/
|
||||
@Override
|
||||
public boolean add(T t) {
|
||||
this.trackReferenceAdded(t);
|
||||
return this.list.add(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an element and updates the counter map.
|
||||
*/
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
this.trackReferenceRemoved(o);
|
||||
return this.list.remove(o);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if all elements of the collection exist in this list.
|
||||
*/
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> c) {
|
||||
for (Object obj : c) {
|
||||
if (this.counter.containsKey(obj)) continue;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends T> c) {
|
||||
for (T obj : c) {
|
||||
this.trackReferenceAdded(obj);
|
||||
}
|
||||
return this.list.addAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(int index, Collection<? extends T> c) {
|
||||
for (T obj : c) {
|
||||
this.trackReferenceAdded(obj);
|
||||
}
|
||||
return this.list.addAll(index, c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimizes removal by converting to a hash set for large operations.
|
||||
*/
|
||||
@Override
|
||||
public boolean removeAll(@NotNull Collection<?> c) {
|
||||
if (this.size() >= 2 && c.size() > 4 && c instanceof List) {
|
||||
c = new ReferenceOpenHashSet<>(c);
|
||||
}
|
||||
this.counter.keySet().removeAll(c);
|
||||
return this.list.removeAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(@NotNull Collection<?> c) {
|
||||
this.counter.keySet().retainAll(c);
|
||||
return this.list.retainAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
this.counter.clear();
|
||||
this.list.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get(int index) {
|
||||
return this.list.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an element at specific index while maintaining accurate counts.
|
||||
*/
|
||||
@Override
|
||||
public T set(int index, T element) {
|
||||
T prev = this.list.set(index, element);
|
||||
if (prev != element) {
|
||||
if (prev != null) {
|
||||
this.trackReferenceRemoved(prev);
|
||||
}
|
||||
this.trackReferenceAdded(element);
|
||||
}
|
||||
return prev;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int index, T element) {
|
||||
this.trackReferenceAdded(element);
|
||||
this.list.add(index, element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T remove(int index) {
|
||||
T prev = this.list.remove(index);
|
||||
if (prev != null) {
|
||||
this.trackReferenceRemoved(prev);
|
||||
}
|
||||
return prev;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int indexOf(Object o) {
|
||||
return this.list.indexOf(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lastIndexOf(Object o) {
|
||||
return this.list.lastIndexOf(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListIterator<T> listIterator() {
|
||||
return this.listIterator(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom ListIterator implementation that maintains counter consistency.
|
||||
*/
|
||||
@Override
|
||||
public ListIterator<T> listIterator(final int index) {
|
||||
return new ListIterator<>() {
|
||||
private final ListIterator<T> inner;
|
||||
|
||||
{
|
||||
this.inner = HashedReferenceList.this.list.listIterator(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return this.inner.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
return this.inner.next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPrevious() {
|
||||
return this.inner.hasPrevious();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T previous() {
|
||||
return this.inner.previous();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int nextIndex() {
|
||||
return this.inner.nextIndex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int previousIndex() {
|
||||
return this.inner.previousIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the current element and updates counter.
|
||||
*/
|
||||
@Override
|
||||
public void remove() {
|
||||
int last = this.previousIndex();
|
||||
if (last == -1) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
Object prev = HashedReferenceList.this.get(last);
|
||||
if (prev != null) {
|
||||
HashedReferenceList.this.trackReferenceRemoved(prev);
|
||||
}
|
||||
this.inner.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current element and updates counter.
|
||||
*/
|
||||
@Override
|
||||
public void set(T t) {
|
||||
int last = this.previousIndex();
|
||||
if (last == -1) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
Object prev = HashedReferenceList.this.get(last);
|
||||
if (prev != t) {
|
||||
if (prev != null) {
|
||||
HashedReferenceList.this.trackReferenceRemoved(prev);
|
||||
}
|
||||
HashedReferenceList.this.trackReferenceAdded(t);
|
||||
}
|
||||
this.inner.remove();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(T t) {
|
||||
HashedReferenceList.this.trackReferenceAdded(t);
|
||||
this.inner.add(t);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> subList(int fromIndex, int toIndex) {
|
||||
return this.list.subList(fromIndex, toIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the reference counter for an added element.
|
||||
*/
|
||||
private void trackReferenceAdded(T t) {
|
||||
this.counter.addTo(t, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements the reference counter and removes if count reaches 0.
|
||||
*/
|
||||
private void trackReferenceRemoved(Object o) {
|
||||
if (this.counter.addTo((T) o, -1) <= 1) {
|
||||
this.counter.removeInt(o);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to create a HashedReferenceList from an existing list.
|
||||
*/
|
||||
public static <T> HashedReferenceList<T> wrapper(List<T> list) {
|
||||
return new HashedReferenceList<>(list);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,313 @@
|
||||
package org.dreeam.leaf.util.map;
|
||||
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.world.entity.ai.attributes.Attribute;
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeInstance;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.AbstractMap.SimpleEntry;
|
||||
|
||||
// fast array backend map with O(1) get & put & remove
|
||||
public class AttributeInstanceArrayMap implements Map<Holder<Attribute>, AttributeInstance>, Cloneable {
|
||||
|
||||
private int size = 0;
|
||||
private transient AttributeInstance[] a = new AttributeInstance[32];
|
||||
private transient KeySet keys;
|
||||
private transient Values values;
|
||||
private transient EntrySet entries;
|
||||
|
||||
public AttributeInstanceArrayMap() {
|
||||
if (BuiltInRegistries.ATTRIBUTE.size() != 32) {
|
||||
throw new IllegalStateException("Registered custom attribute");
|
||||
}
|
||||
}
|
||||
|
||||
public AttributeInstanceArrayMap(final @NotNull Map<Holder<Attribute>, AttributeInstance> m) {
|
||||
this();
|
||||
putAll(m);
|
||||
}
|
||||
|
||||
private void setByIndex(int index, @Nullable AttributeInstance instance) {
|
||||
boolean empty = a[index] == null;
|
||||
if (instance == null) {
|
||||
if (!empty) {
|
||||
size--;
|
||||
a[index] = null;
|
||||
}
|
||||
} else {
|
||||
if (empty) {
|
||||
size++;
|
||||
}
|
||||
a[index] = instance;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isEmpty() {
|
||||
return size == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean containsKey(Object key) {
|
||||
if (key instanceof Holder<?> holder && holder.value() instanceof Attribute attribute) {
|
||||
int uid = attribute.uid;
|
||||
return uid >= 0 && uid < a.length && a[uid] != null;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean containsValue(Object value) {
|
||||
for (final AttributeInstance instance : a) {
|
||||
if (Objects.equals(value, instance)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final AttributeInstance get(Object key) {
|
||||
return key instanceof Holder<?> holder && holder.value() instanceof Attribute attribute ? a[attribute.uid] : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final AttributeInstance put(@NotNull Holder<Attribute> key, AttributeInstance value) {
|
||||
int uid = key.value().uid;
|
||||
AttributeInstance prev = a[uid];
|
||||
setByIndex(uid, value);
|
||||
return prev;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final AttributeInstance remove(Object key) {
|
||||
if (!(key instanceof Holder<?> holder) || !(holder.value() instanceof Attribute attribute)) return null;
|
||||
int uid = attribute.uid;
|
||||
AttributeInstance prev = a[uid];
|
||||
setByIndex(uid, null);
|
||||
return prev;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void putAll(@NotNull Map<? extends Holder<Attribute>, ? extends AttributeInstance> m) {
|
||||
for (AttributeInstance e : m.values()) {
|
||||
if (e != null) {
|
||||
setByIndex(e.getAttribute().value().uid, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void clear() {
|
||||
Arrays.fill(a, null);
|
||||
size = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final @NotNull Set<Holder<Attribute>> keySet() {
|
||||
if (keys == null) {
|
||||
keys = new KeySet();
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final @NotNull Collection<AttributeInstance> values() {
|
||||
if (values == null) {
|
||||
values = new Values();
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final @NotNull Set<Entry<Holder<Attribute>, AttributeInstance>> entrySet() {
|
||||
if (entries == null) {
|
||||
entries = new EntrySet();
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean equals(Object o) {
|
||||
if (!(o instanceof AttributeInstanceArrayMap that)) return false;
|
||||
return size == that.size && Arrays.equals(a, that.a);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
return Arrays.hashCode(a);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttributeInstanceArrayMap clone() {
|
||||
AttributeInstanceArrayMap c;
|
||||
try {
|
||||
c = (AttributeInstanceArrayMap) super.clone();
|
||||
} catch (CloneNotSupportedException cantHappen) {
|
||||
throw new InternalError();
|
||||
}
|
||||
c.a = a.clone();
|
||||
c.entries = null;
|
||||
c.keys = null;
|
||||
c.values = null;
|
||||
return c;
|
||||
}
|
||||
|
||||
private final class KeySet extends AbstractSet<Holder<Attribute>> {
|
||||
@Override
|
||||
public @NotNull Iterator<Holder<Attribute>> iterator() {
|
||||
return new KeyIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return AttributeInstanceArrayMap.this.containsKey(o);
|
||||
}
|
||||
}
|
||||
|
||||
private final class KeyIterator implements Iterator<Holder<Attribute>> {
|
||||
private int currentIndex = -1;
|
||||
private int nextIndex = findNextOccupied(0);
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return nextIndex != -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Holder<Attribute> next() {
|
||||
if (!hasNext()) throw new NoSuchElementException();
|
||||
currentIndex = nextIndex;
|
||||
nextIndex = findNextOccupied(nextIndex + 1);
|
||||
return BuiltInRegistries.ATTRIBUTE.asHolderIdMap().byIdOrThrow(currentIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
if (currentIndex == -1) throw new IllegalStateException();
|
||||
setByIndex(currentIndex, null);
|
||||
currentIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
private final class Values extends AbstractCollection<AttributeInstance> {
|
||||
@Override
|
||||
public @NotNull Iterator<AttributeInstance> iterator() {
|
||||
return new ValueIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return containsValue(o);
|
||||
}
|
||||
}
|
||||
|
||||
private final class ValueIterator implements Iterator<AttributeInstance> {
|
||||
private int currentIndex = -1;
|
||||
private int nextIndex = findNextOccupied(0);
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return nextIndex != -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttributeInstance next() {
|
||||
if (!hasNext()) throw new NoSuchElementException();
|
||||
currentIndex = nextIndex;
|
||||
AttributeInstance value = a[nextIndex];
|
||||
nextIndex = findNextOccupied(nextIndex + 1);
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
if (currentIndex == -1) throw new IllegalStateException();
|
||||
setByIndex(currentIndex, null);
|
||||
currentIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
private final class EntrySet extends AbstractSet<Entry<Holder<Attribute>, AttributeInstance>> {
|
||||
@Override
|
||||
public @NotNull Iterator<Entry<Holder<Attribute>, AttributeInstance>> iterator() {
|
||||
return new EntryIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
if (!(o instanceof Entry<?, ?> e)) {
|
||||
return false;
|
||||
}
|
||||
return Objects.equals(get(e.getKey()), e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private final class EntryIterator implements Iterator<Entry<Holder<Attribute>, AttributeInstance>> {
|
||||
private int currentIndex = -1;
|
||||
private int nextIndex = findNextOccupied(0);
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return nextIndex != -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<Holder<Attribute>, AttributeInstance> next() {
|
||||
if (!hasNext()) throw new NoSuchElementException();
|
||||
currentIndex = nextIndex;
|
||||
Holder<Attribute> key = BuiltInRegistries.ATTRIBUTE.asHolderIdMap().byIdOrThrow(nextIndex);
|
||||
AttributeInstance value = a[nextIndex];
|
||||
nextIndex = findNextOccupied(nextIndex + 1);
|
||||
return new SimpleEntry<>(key, value) {
|
||||
@Override
|
||||
public AttributeInstance setValue(AttributeInstance newValue) {
|
||||
AttributeInstance old = put(key, newValue);
|
||||
super.setValue(newValue);
|
||||
return old;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
if (currentIndex == -1) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
setByIndex(currentIndex, null);
|
||||
currentIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
private int findNextOccupied(int start) {
|
||||
for (int i = start; i < a.length; i++) {
|
||||
if (a[i] != null) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,7 @@
|
||||
package org.dreeam.leaf.util.queue;
|
||||
|
||||
import java.util.OptionalInt;
|
||||
|
||||
/// Lock-free Single Producer Single Consumer Queue
|
||||
public class SpscIntQueue {
|
||||
|
||||
@@ -33,14 +35,14 @@ public class SpscIntQueue {
|
||||
}
|
||||
|
||||
|
||||
public final int recv() {
|
||||
public final OptionalInt recv() {
|
||||
final int idx = consumerIdx.getOpaque();
|
||||
int cachedIdx = producerCachedIdx.getPlain();
|
||||
if (idx == cachedIdx) {
|
||||
cachedIdx = producerIdx.getAcquire();
|
||||
producerCachedIdx.setPlain(cachedIdx);
|
||||
if (idx == cachedIdx) {
|
||||
return Integer.MAX_VALUE;
|
||||
return OptionalInt.empty();
|
||||
}
|
||||
}
|
||||
int e = data[idx];
|
||||
@@ -49,7 +51,7 @@ public class SpscIntQueue {
|
||||
nextIdx = 0;
|
||||
}
|
||||
consumerIdx.setRelease(nextIdx);
|
||||
return e;
|
||||
return OptionalInt.of(e);
|
||||
}
|
||||
|
||||
public final int size() {
|
||||
@@ -57,8 +59,28 @@ public class SpscIntQueue {
|
||||
}
|
||||
|
||||
static class PaddedAtomicInteger extends java.util.concurrent.atomic.AtomicInteger {
|
||||
// @formatter:off
|
||||
@SuppressWarnings("unused")
|
||||
private int i1, i2, i3, i4, i5, i6, i7, i8,
|
||||
i9, i10, i11, i12, i13, i14, i15;
|
||||
private byte
|
||||
i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15,
|
||||
j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15,
|
||||
k0, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13, k14, k15,
|
||||
l0, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15,
|
||||
|
||||
m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15,
|
||||
n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15,
|
||||
o0, o1, o2, o3, o4, o5, o6, o7, o8, o9, o10, o11, o12, o13, o14, o15,
|
||||
p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15,
|
||||
|
||||
q0, q1, q2, q3, q4, q5, q6, q7, q8, q9, q10, q11, q12, q13, q14, q15,
|
||||
r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15,
|
||||
s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15,
|
||||
t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15,
|
||||
|
||||
u0, u1, u2, u3, u4, u5, u6, u7, u8, u9, u10, u11, u12, u13, u14, u15,
|
||||
v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,
|
||||
w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15,
|
||||
x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11;
|
||||
// @formatter:on
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,9 @@ JAR_NAME="leaf-1.21.5"
|
||||
CURRENT_TAG="ver-1.21.5"
|
||||
RELEASE_NOTES="release_notes.md"
|
||||
|
||||
# Rename Leaf jar
|
||||
mv ./leaf-server/build/libs/leaf-paperclip-1.21.5-R0.1-SNAPSHOT-mojmap.jar ./$JAR_NAME-${BUILD_NUMBER}.jar
|
||||
|
||||
# Branch name
|
||||
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
||||
echo "✨Current branch: $CURRENT_BRANCH"
|
||||
|
||||
4
todos.md
4
todos.md
@@ -2,7 +2,6 @@
|
||||
- [ ] Do a benchmark for `Remove streams and iterators from range check`, getEffectiveRange in ChunkMap
|
||||
|
||||
# Leaf TODOs
|
||||
- [ ] refactor leaves protocol manager opt and pr it.
|
||||
- [ ] Transfer patch notes to file for Gale and Leaf
|
||||
- [ ] check Dont send useless entity packets
|
||||
- [ ] Use different state to separate different configs reload
|
||||
@@ -12,4 +11,5 @@
|
||||
- [ ] Update README.md
|
||||
- [ ] Remove stream in Inventory and check new changes
|
||||
- [ ] Check Purpur's Projectile offset config, in BowItem shoot
|
||||
- [ ] Update from Leaf 1.21.4 (curr commit: `1431eff510a3ac1725ec82d52f5c253b4b7932d9`)
|
||||
- [ ] Remove Gale's attribute patch
|
||||
- [ ] Update from Leaf 1.21.4 (curr commit: `a022d84c5b5b52f7e8a62f6bff774d0c23176ed5`)
|
||||
|
||||
Reference in New Issue
Block a user