mirror of
https://github.com/Samsuik/Sakura.git
synced 2025-12-19 14:59:30 +00:00
start fresh with commit history
dw, they're kept up on a private repository
This commit is contained in:
6
.editorconfig
Normal file
6
.editorconfig
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
[*.java]
|
||||||
|
charset=utf-8
|
||||||
|
end_of_line=lf
|
||||||
|
insert_final_newline=true
|
||||||
|
indent_style=space
|
||||||
|
indent_size=4
|
||||||
7
.gitattributes
vendored
Normal file
7
.gitattributes
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
* text=auto
|
||||||
|
|
||||||
|
*.sh text eol=lf
|
||||||
|
gradlew text eol=lf
|
||||||
|
*.bat text eol=crlf
|
||||||
|
|
||||||
|
*.jar binary
|
||||||
52
.gitignore
vendored
Normal file
52
.gitignore
vendored
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
.gradle/
|
||||||
|
build/
|
||||||
|
|
||||||
|
# Eclipse stuff
|
||||||
|
.classpath
|
||||||
|
.project
|
||||||
|
.settings/
|
||||||
|
|
||||||
|
# VSCode stuff
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
# netbeans
|
||||||
|
nbproject/
|
||||||
|
nbactions.xml
|
||||||
|
|
||||||
|
# we use maven!
|
||||||
|
build.xml
|
||||||
|
|
||||||
|
# maven
|
||||||
|
target/
|
||||||
|
dependency-reduced-pom.xml
|
||||||
|
|
||||||
|
# vim
|
||||||
|
.*.sw[a-p]
|
||||||
|
|
||||||
|
# various other potential build files
|
||||||
|
build/
|
||||||
|
bin/
|
||||||
|
dist/
|
||||||
|
manifest.mf
|
||||||
|
|
||||||
|
# Mac filesystem dust
|
||||||
|
.DS_Store/
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# intellij
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
|
.idea/
|
||||||
|
out/
|
||||||
|
|
||||||
|
# Linux temp files
|
||||||
|
*~
|
||||||
|
|
||||||
|
# other stuff
|
||||||
|
run/
|
||||||
|
|
||||||
|
Sakura-Server
|
||||||
|
Sakura-API
|
||||||
|
|
||||||
|
!gradle/wrapper/gradle-wrapper.jar
|
||||||
9
README.md
Normal file
9
README.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
Sakura
|
||||||
|
===========
|
||||||
|
This is a fork of Paper to optimise cannoning intended for cannon and factions servers on modern versions.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Initially this repository will be publicised with just some cannon optimisations.
|
||||||
|
Later updates will bring feature parity with [Blossom](https://github.com/Samsuik/Blossom) and the private Sakura builds is planned.
|
||||||
|
|
||||||
12
build-data/dev-imports.txt
Normal file
12
build-data/dev-imports.txt
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# You can use this file to import files from minecraft libraries into the project
|
||||||
|
# format:
|
||||||
|
# <artifactId> <fileName>
|
||||||
|
# both fully qualified and a file based syntax are accepted for <fileName>:
|
||||||
|
# authlib com/mojang/authlib/yggdrasil/YggdrasilGameProfileRepository.java
|
||||||
|
# datafixerupper com.mojang.datafixers.DataFixerBuilder
|
||||||
|
# datafixerupper com/mojang/datafixers/util/Either.java
|
||||||
|
# To import classes from the vanilla Minecraft jar use `minecraft` as the artifactId:
|
||||||
|
# minecraft net.minecraft.world.level.entity.LevelEntityGetterAdapter
|
||||||
|
# minecraft net/minecraft/world/level/entity/LevelEntityGetter.java
|
||||||
|
minecraft net.minecraft.world.level.block.piston.PistonStructureResolver
|
||||||
|
minecraft net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket
|
||||||
61
build.gradle.kts
Normal file
61
build.gradle.kts
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
import io.papermc.paperweight.util.constants.PAPERCLIP_CONFIG
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
java
|
||||||
|
id("com.github.johnrengelman.shadow") version "8.1.1" apply false
|
||||||
|
id("io.papermc.paperweight.patcher") version "1.5.7"
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
maven("https://papermc.io/repo/repository/maven-public/") {
|
||||||
|
content { onlyForConfigurations(PAPERCLIP_CONFIG) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
remapper("net.fabricmc:tiny-remapper:0.8.6:fat")
|
||||||
|
decompiler("net.minecraftforge:forgeflower:2.0.627.2")
|
||||||
|
paperclip("io.papermc:paperclip:3.0.3")
|
||||||
|
}
|
||||||
|
|
||||||
|
subprojects {
|
||||||
|
apply(plugin = "java")
|
||||||
|
|
||||||
|
java {
|
||||||
|
toolchain { languageVersion.set(JavaLanguageVersion.of(17)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType<JavaCompile>().configureEach {
|
||||||
|
options.encoding = "UTF-8"
|
||||||
|
options.release.set(17)
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
maven("https://oss.sonatype.org/content/groups/public/")
|
||||||
|
maven("https://papermc.io/repo/repository/maven-public/")
|
||||||
|
maven("https://ci.emc.gs/nexus/content/groups/aikar/")
|
||||||
|
maven("https://repo.aikar.co/content/groups/aikar")
|
||||||
|
maven("https://repo.md-5.net/content/repositories/releases/")
|
||||||
|
maven("https://hub.spigotmc.org/nexus/content/groups/public/")
|
||||||
|
maven("https://jitpack.io")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
paperweight {
|
||||||
|
serverProject.set(project(":sakura-server"))
|
||||||
|
|
||||||
|
remapRepo.set("https://maven.fabricmc.net/")
|
||||||
|
decompileRepo.set("https://files.minecraftforge.net/maven/")
|
||||||
|
|
||||||
|
usePaperUpstream(providers.gradleProperty("paperRef")) {
|
||||||
|
withPaperPatcher {
|
||||||
|
apiPatchDir.set(layout.projectDirectory.dir("patches/api"))
|
||||||
|
apiOutputDir.set(layout.projectDirectory.dir("sakura-api"))
|
||||||
|
|
||||||
|
serverPatchDir.set(layout.projectDirectory.dir("patches/server"))
|
||||||
|
serverOutputDir.set(layout.projectDirectory.dir("sakura-server"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
12
gradle.properties
Normal file
12
gradle.properties
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
group=me.samsuik.sakura
|
||||||
|
version=1.20.2-R0.1-SNAPSHOT
|
||||||
|
|
||||||
|
mcVersion=1.20.2
|
||||||
|
paperRef=08c0b488b9f1e56a4465cfabe6212d0351b69e59
|
||||||
|
|
||||||
|
org.gradle.jvmargs=-Xmx2G
|
||||||
|
|
||||||
|
org.gradle.caching=true
|
||||||
|
org.gradle.parallel=true
|
||||||
|
org.gradle.daemon=true
|
||||||
|
# org.gradle.configureondemand=true
|
||||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
5
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
5
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
234
gradlew
vendored
Normal file
234
gradlew
vendored
Normal file
@@ -0,0 +1,234 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright © 2015-2021 the original authors.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Gradle start up script for POSIX generated by Gradle.
|
||||||
|
#
|
||||||
|
# Important for running:
|
||||||
|
#
|
||||||
|
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||||
|
# noncompliant, but you have some other compliant shell such as ksh or
|
||||||
|
# bash, then to run this script, type that shell name before the whole
|
||||||
|
# command line, like:
|
||||||
|
#
|
||||||
|
# ksh Gradle
|
||||||
|
#
|
||||||
|
# Busybox and similar reduced shells will NOT work, because this script
|
||||||
|
# requires all of these POSIX shell features:
|
||||||
|
# * functions;
|
||||||
|
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||||
|
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||||
|
# * compound commands having a testable exit status, especially «case»;
|
||||||
|
# * various built-in commands including «command», «set», and «ulimit».
|
||||||
|
#
|
||||||
|
# Important for patching:
|
||||||
|
#
|
||||||
|
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||||
|
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||||
|
#
|
||||||
|
# The "traditional" practice of packing multiple parameters into a
|
||||||
|
# space-separated string is a well documented source of bugs and security
|
||||||
|
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||||
|
# options in "$@", and eventually passing that to Java.
|
||||||
|
#
|
||||||
|
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||||
|
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||||
|
# see the in-line comments for details.
|
||||||
|
#
|
||||||
|
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||||
|
# Darwin, MinGW, and NonStop.
|
||||||
|
#
|
||||||
|
# (3) This script is generated from the Groovy template
|
||||||
|
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
|
# within the Gradle project.
|
||||||
|
#
|
||||||
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
# Attempt to set APP_HOME
|
||||||
|
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
app_path=$0
|
||||||
|
|
||||||
|
# Need this for daisy-chained symlinks.
|
||||||
|
while
|
||||||
|
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||||
|
[ -h "$app_path" ]
|
||||||
|
do
|
||||||
|
ls=$( ls -ld "$app_path" )
|
||||||
|
link=${ls#*' -> '}
|
||||||
|
case $link in #(
|
||||||
|
/*) app_path=$link ;; #(
|
||||||
|
*) app_path=$APP_HOME$link ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||||
|
|
||||||
|
APP_NAME="Gradle"
|
||||||
|
APP_BASE_NAME=${0##*/}
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
|
MAX_FD=maximum
|
||||||
|
|
||||||
|
warn () {
|
||||||
|
echo "$*"
|
||||||
|
} >&2
|
||||||
|
|
||||||
|
die () {
|
||||||
|
echo
|
||||||
|
echo "$*"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
} >&2
|
||||||
|
|
||||||
|
# OS specific support (must be 'true' or 'false').
|
||||||
|
cygwin=false
|
||||||
|
msys=false
|
||||||
|
darwin=false
|
||||||
|
nonstop=false
|
||||||
|
case "$( uname )" in #(
|
||||||
|
CYGWIN* ) cygwin=true ;; #(
|
||||||
|
Darwin* ) darwin=true ;; #(
|
||||||
|
MSYS* | MINGW* ) msys=true ;; #(
|
||||||
|
NONSTOP* ) nonstop=true ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
|
# Determine the Java command to use to start the JVM.
|
||||||
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||||
|
else
|
||||||
|
JAVACMD=$JAVA_HOME/bin/java
|
||||||
|
fi
|
||||||
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD=java
|
||||||
|
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Increase the maximum file descriptors if we can.
|
||||||
|
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||||
|
case $MAX_FD in #(
|
||||||
|
max*)
|
||||||
|
MAX_FD=$( ulimit -H -n ) ||
|
||||||
|
warn "Could not query maximum file descriptor limit"
|
||||||
|
esac
|
||||||
|
case $MAX_FD in #(
|
||||||
|
'' | soft) :;; #(
|
||||||
|
*)
|
||||||
|
ulimit -n "$MAX_FD" ||
|
||||||
|
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Collect all arguments for the java command, stacking in reverse order:
|
||||||
|
# * args from the command line
|
||||||
|
# * the main class name
|
||||||
|
# * -classpath
|
||||||
|
# * -D...appname settings
|
||||||
|
# * --module-path (only if needed)
|
||||||
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||||
|
|
||||||
|
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||||
|
if "$cygwin" || "$msys" ; then
|
||||||
|
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||||
|
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||||
|
|
||||||
|
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||||
|
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
for arg do
|
||||||
|
if
|
||||||
|
case $arg in #(
|
||||||
|
-*) false ;; # don't mess with options #(
|
||||||
|
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||||
|
[ -e "$t" ] ;; #(
|
||||||
|
*) false ;;
|
||||||
|
esac
|
||||||
|
then
|
||||||
|
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||||
|
fi
|
||||||
|
# Roll the args list around exactly as many times as the number of
|
||||||
|
# args, so each arg winds up back in the position where it started, but
|
||||||
|
# possibly modified.
|
||||||
|
#
|
||||||
|
# NB: a `for` loop captures its iteration list before it begins, so
|
||||||
|
# changing the positional parameters here affects neither the number of
|
||||||
|
# iterations, nor the values presented in `arg`.
|
||||||
|
shift # remove old arg
|
||||||
|
set -- "$@" "$arg" # push replacement arg
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Collect all arguments for the java command;
|
||||||
|
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||||
|
# shell script including quotes and variable substitutions, so put them in
|
||||||
|
# double quotes to make sure that they get re-expanded; and
|
||||||
|
# * put everything else in single quotes, so that it's not re-expanded.
|
||||||
|
|
||||||
|
set -- \
|
||||||
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
|
-classpath "$CLASSPATH" \
|
||||||
|
org.gradle.wrapper.GradleWrapperMain \
|
||||||
|
"$@"
|
||||||
|
|
||||||
|
# Use "xargs" to parse quoted args.
|
||||||
|
#
|
||||||
|
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||||
|
#
|
||||||
|
# In Bash we could simply go:
|
||||||
|
#
|
||||||
|
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||||
|
# set -- "${ARGS[@]}" "$@"
|
||||||
|
#
|
||||||
|
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||||
|
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||||
|
# character that might be a shell metacharacter, then use eval to reverse
|
||||||
|
# that process (while maintaining the separation between arguments), and wrap
|
||||||
|
# the whole thing up as a single "set" statement.
|
||||||
|
#
|
||||||
|
# This will of course break if any of these variables contains a newline or
|
||||||
|
# an unmatched quote.
|
||||||
|
#
|
||||||
|
|
||||||
|
eval "set -- $(
|
||||||
|
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||||
|
xargs -n1 |
|
||||||
|
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||||
|
tr '\n' ' '
|
||||||
|
)" '"$@"'
|
||||||
|
|
||||||
|
exec "$JAVACMD" "$@"
|
||||||
89
gradlew.bat
vendored
Normal file
89
gradlew.bat
vendored
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
@rem
|
||||||
|
@rem Copyright 2015 the original author or authors.
|
||||||
|
@rem
|
||||||
|
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@rem you may not use this file except in compliance with the License.
|
||||||
|
@rem You may obtain a copy of the License at
|
||||||
|
@rem
|
||||||
|
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
@rem
|
||||||
|
@rem Unless required by applicable law or agreed to in writing, software
|
||||||
|
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@rem See the License for the specific language governing permissions and
|
||||||
|
@rem limitations under the License.
|
||||||
|
@rem
|
||||||
|
|
||||||
|
@if "%DEBUG%" == "" @echo off
|
||||||
|
@rem ##########################################################################
|
||||||
|
@rem
|
||||||
|
@rem Gradle startup script for Windows
|
||||||
|
@rem
|
||||||
|
@rem ##########################################################################
|
||||||
|
|
||||||
|
@rem Set local scope for the variables with windows NT shell
|
||||||
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
|
set DIRNAME=%~dp0
|
||||||
|
if "%DIRNAME%" == "" set DIRNAME=.
|
||||||
|
set APP_BASE_NAME=%~n0
|
||||||
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||||
|
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||||
|
|
||||||
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||||
|
|
||||||
|
@rem Find java.exe
|
||||||
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
|
set JAVA_EXE=java.exe
|
||||||
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
|
if "%ERRORLEVEL%" == "0" goto execute
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:findJavaFromJavaHome
|
||||||
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:execute
|
||||||
|
@rem Setup the command line
|
||||||
|
|
||||||
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
|
@rem Execute Gradle
|
||||||
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||||
|
|
||||||
|
:end
|
||||||
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||||
|
|
||||||
|
:fail
|
||||||
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
|
rem the _cmd.exe /c_ return code!
|
||||||
|
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||||
|
exit /b 1
|
||||||
|
|
||||||
|
:mainEnd
|
||||||
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
|
:omega
|
||||||
85
patches/api/0001-Customise-Version-Command.patch
Normal file
85
patches/api/0001-Customise-Version-Command.patch
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
|
||||||
|
Date: Wed, 2 Aug 2023 18:00:04 +0100
|
||||||
|
Subject: [PATCH] Customise Version Command
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java
|
||||||
|
index f78b5fd3c3347d28da58777bff88903d2eb140f6..5999909827ede80c14becb058cde3189f10fb3ef 100644
|
||||||
|
--- a/src/main/java/org/bukkit/Bukkit.java
|
||||||
|
+++ b/src/main/java/org/bukkit/Bukkit.java
|
||||||
|
@@ -127,6 +127,20 @@ public final class Bukkit {
|
||||||
|
// Paper end
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Sakura start - expose git info
|
||||||
|
+ @NotNull
|
||||||
|
+ public static String getGitInformation() {
|
||||||
|
+ final var manifest = JarManifests.manifest(Bukkit.getServer().getClass());
|
||||||
|
+ final String gitBranch = manifest == null ? null : manifest.getMainAttributes().getValue("Git-Branch");
|
||||||
|
+ final String gitCommit = manifest == null ? null : manifest.getMainAttributes().getValue("Git-Commit");
|
||||||
|
+ String branchMsg = " on " + gitBranch;
|
||||||
|
+ if ("master".equals(gitBranch) || "main".equals(gitBranch)) {
|
||||||
|
+ branchMsg = ""; // Don't show branch on main/master
|
||||||
|
+ }
|
||||||
|
+ return "(Git: " + gitCommit + branchMsg + ")";
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
+
|
||||||
|
/**
|
||||||
|
* Gets the name of this server implementation.
|
||||||
|
*
|
||||||
|
diff --git a/src/main/java/org/bukkit/command/defaults/VersionCommand.java b/src/main/java/org/bukkit/command/defaults/VersionCommand.java
|
||||||
|
index fd5d9881abfd930bb883120f018f76dc78b62b14..0cf55a5a4afc8d2eccd781a613b407c857cfe13d 100644
|
||||||
|
--- a/src/main/java/org/bukkit/command/defaults/VersionCommand.java
|
||||||
|
+++ b/src/main/java/org/bukkit/command/defaults/VersionCommand.java
|
||||||
|
@@ -17,6 +17,15 @@ import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
+
|
||||||
|
+import io.papermc.paper.util.JarManifests;
|
||||||
|
+import net.kyori.adventure.text.Component;
|
||||||
|
+import net.kyori.adventure.text.event.ClickEvent;
|
||||||
|
+import net.kyori.adventure.text.event.HoverEvent;
|
||||||
|
+import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
+import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||||
|
+import net.kyori.adventure.text.minimessage.tag.Tag;
|
||||||
|
+import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
@@ -49,17 +58,29 @@ public class VersionCommand extends BukkitCommand {
|
||||||
|
this.description = "Gets the version of this server including any plugins in use";
|
||||||
|
this.usageMessage = "/version [plugin name]";
|
||||||
|
this.setPermission("bukkit.command.version");
|
||||||
|
- this.setAliases(Arrays.asList("ver", "about"));
|
||||||
|
+ this.setAliases(Arrays.asList("ver", "about", "sver")); // Sakura
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean execute(@NotNull CommandSender sender, @NotNull String currentAlias, @NotNull String[] args) {
|
||||||
|
- if (!testPermission(sender)) return true;
|
||||||
|
+ // Sakura - move down into else
|
||||||
|
|
||||||
|
if (args.length == 0) {
|
||||||
|
//sender.sendMessage("This server is running " + Bukkit.getName() + " version " + Bukkit.getVersion() + " (Implementing API version " + Bukkit.getBukkitVersion() + ")"); // Paper - moved to setVersionMessage
|
||||||
|
- sendVersion(sender);
|
||||||
|
- } else {
|
||||||
|
+ // Sakura start
|
||||||
|
+ sender.sendMessage(MiniMessage.miniMessage().deserialize("""
|
||||||
|
+ <dark_purple>.
|
||||||
|
+ | <white>This server is running <phase>Sakura</white>
|
||||||
|
+ | <white>Commit<dark_gray>: \\<<commit>> <gray>targeting </gray>(<yellow>MC</yellow>: <gray><version></gray>)</white>
|
||||||
|
+ | <white>Github<dark_gray>: \\<<yellow><click:open_url:'https://github.com/Samsuik/Sakura'>link</click></yellow>></white>
|
||||||
|
+ '""",
|
||||||
|
+ TagResolver.resolver("phase", Tag.preProcessParsed("<gradient:light_purple:red:0.5>")),
|
||||||
|
+ TagResolver.resolver("commit", Tag.selfClosingInserting(Component.text("hover", NamedTextColor.YELLOW)
|
||||||
|
+ .hoverEvent(HoverEvent.showText(Component.text(Bukkit.getGitInformation()))))),
|
||||||
|
+ TagResolver.resolver("version", Tag.preProcessParsed(Bukkit.getMinecraftVersion()))
|
||||||
|
+ ));
|
||||||
|
+ } else if (testPermission(sender)) {
|
||||||
|
+ // Sakura end
|
||||||
|
StringBuilder name = new StringBuilder();
|
||||||
|
|
||||||
|
for (String arg : args) {
|
||||||
135
patches/api/0002-Player-GUI-API.patch
Normal file
135
patches/api/0002-Player-GUI-API.patch
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Samsuik <kfian294ma4@gmail.com>
|
||||||
|
Date: Thu, 12 Jan 2023 22:59:28 +0000
|
||||||
|
Subject: [PATCH] Player GUI API
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/me/samsuik/sakura/player/gui/ItemIcon.java b/src/main/java/me/samsuik/sakura/player/gui/ItemIcon.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..cc0645aa27e6e96922f26242e71fef5d6c06fcfd
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/me/samsuik/sakura/player/gui/ItemIcon.java
|
||||||
|
@@ -0,0 +1,9 @@
|
||||||
|
+package me.samsuik.sakura.player.gui;
|
||||||
|
+
|
||||||
|
+import org.bukkit.entity.Player;
|
||||||
|
+import org.bukkit.inventory.ItemStack;
|
||||||
|
+
|
||||||
|
+import java.util.function.Consumer;
|
||||||
|
+import java.util.function.Function;
|
||||||
|
+
|
||||||
|
+public record ItemIcon(Function<Player, ItemStack> itemUpdate, Consumer<Player> onClick, int slot) {}
|
||||||
|
diff --git a/src/main/java/me/samsuik/sakura/player/gui/PlayerGUI.java b/src/main/java/me/samsuik/sakura/player/gui/PlayerGUI.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..55d914153ca3f6458ee52223665516d5735a7c34
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/me/samsuik/sakura/player/gui/PlayerGUI.java
|
||||||
|
@@ -0,0 +1,108 @@
|
||||||
|
+package me.samsuik.sakura.player.gui;
|
||||||
|
+
|
||||||
|
+import org.bukkit.entity.Player;
|
||||||
|
+import org.bukkit.event.EventPriority;
|
||||||
|
+import org.bukkit.event.inventory.InventoryClickEvent;
|
||||||
|
+import org.bukkit.inventory.Inventory;
|
||||||
|
+import org.bukkit.inventory.InventoryHolder;
|
||||||
|
+import org.bukkit.plugin.EventExecutor;
|
||||||
|
+import org.bukkit.plugin.RegisteredListener;
|
||||||
|
+import org.jetbrains.annotations.ApiStatus;
|
||||||
|
+import org.jetbrains.annotations.NotNull;
|
||||||
|
+
|
||||||
|
+import java.util.ArrayList;
|
||||||
|
+import java.util.HashMap;
|
||||||
|
+import java.util.List;
|
||||||
|
+import java.util.Map;
|
||||||
|
+import java.util.function.BiFunction;
|
||||||
|
+import java.util.function.Consumer;
|
||||||
|
+
|
||||||
|
+public abstract class PlayerGUI {
|
||||||
|
+
|
||||||
|
+ private static final List<PlayerGUI> REGISTERED_GUIS = new ArrayList<>();
|
||||||
|
+ protected static final Consumer<Player> NOTHING = (p) -> {};
|
||||||
|
+
|
||||||
|
+ private final Map<Integer, ItemIcon> iconMap = new HashMap<>();
|
||||||
|
+ private final Holder holder = new Holder();
|
||||||
|
+ private final BiFunction<Player, Holder, Inventory> base;
|
||||||
|
+ private boolean registered = false;
|
||||||
|
+
|
||||||
|
+ public PlayerGUI(BiFunction<Player, Holder, Inventory> base) {
|
||||||
|
+ this.base = base;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ protected void registerIcon(ItemIcon icon) {
|
||||||
|
+ iconMap.put(icon.slot(), icon);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ protected abstract void register();
|
||||||
|
+
|
||||||
|
+ public void unregister() {
|
||||||
|
+ REGISTERED_GUIS.remove(this);
|
||||||
|
+ registered = false;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @ApiStatus.Internal
|
||||||
|
+ public static void onWindowClick(InventoryClickEvent event) {
|
||||||
|
+ for (PlayerGUI ui : REGISTERED_GUIS) {
|
||||||
|
+ var inventory = event.getClickedInventory();
|
||||||
|
+
|
||||||
|
+ if (inventory != null && inventory.getHolder() == ui.holder) {
|
||||||
|
+ ui.handleSlotClick(event, inventory);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private void handleSlotClick(InventoryClickEvent event, Inventory inventory) {
|
||||||
|
+ event.setCancelled(true);
|
||||||
|
+
|
||||||
|
+ var player = (Player) event.getWhoClicked();
|
||||||
|
+ var slot = event.getSlot();
|
||||||
|
+ var icon = iconMap.get(slot);
|
||||||
|
+
|
||||||
|
+ if (icon != null) {
|
||||||
|
+ icon.onClick()
|
||||||
|
+ .andThen((p) -> updateIcon(player, icon, inventory))
|
||||||
|
+ .accept(player);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private void updateIcon(Player player, ItemIcon icon, Inventory inventory) {
|
||||||
|
+ var item = icon.itemUpdate().apply(player);
|
||||||
|
+ inventory.setItem(icon.slot(), item);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void showTo(Player player) {
|
||||||
|
+ player.openInventory(createInventory(player));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private Inventory createInventory(Player player) {
|
||||||
|
+ if (!registered) {
|
||||||
|
+ registerUI();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ var inventory = base.apply(player, holder);
|
||||||
|
+
|
||||||
|
+ for (var icon : iconMap.values()) {
|
||||||
|
+ updateIcon(player, icon, inventory);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return inventory;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private void registerUI() {
|
||||||
|
+ register();
|
||||||
|
+ REGISTERED_GUIS.add(this);
|
||||||
|
+ registered = true;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ protected static class Holder implements InventoryHolder {
|
||||||
|
+ private Holder() {}
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public @NotNull Inventory getInventory() {
|
||||||
|
+ return null;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+}
|
||||||
174
patches/api/0003-Visibility-API.patch
Normal file
174
patches/api/0003-Visibility-API.patch
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Samsuik <kfian294ma4@gmail.com>
|
||||||
|
Date: Tue, 21 Sep 2021 23:55:45 +0100
|
||||||
|
Subject: [PATCH] Visibility API
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/me/samsuik/sakura/player/visibility/Visibility.java b/src/main/java/me/samsuik/sakura/player/visibility/Visibility.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..8d9a5ffe7dfe00ff2d3deb6bc94b5dc53af15cd4
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/me/samsuik/sakura/player/visibility/Visibility.java
|
||||||
|
@@ -0,0 +1,142 @@
|
||||||
|
+package me.samsuik.sakura.player.visibility;
|
||||||
|
+
|
||||||
|
+import java.util.EnumSet;
|
||||||
|
+import java.util.Locale;
|
||||||
|
+
|
||||||
|
+public class Visibility {
|
||||||
|
+
|
||||||
|
+ private final EnumSet<Setting> settings = EnumSet.noneOf(Setting.class);
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Checks if the provided setting has been modified.
|
||||||
|
+ *
|
||||||
|
+ * @param setting provided
|
||||||
|
+ * @return the setting has been modified
|
||||||
|
+ */
|
||||||
|
+ public boolean isToggled(Setting setting) {
|
||||||
|
+ return settings.contains(setting);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Checks if the provided setting is enabled.
|
||||||
|
+ *
|
||||||
|
+ * @param setting provided
|
||||||
|
+ * @return the setting is enabled
|
||||||
|
+ */
|
||||||
|
+ public boolean isEnabled(Setting setting) {
|
||||||
|
+ return setting.defaultValue != isToggled(setting);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Checks if the provided setting is disabled.
|
||||||
|
+ *
|
||||||
|
+ * @param setting provided
|
||||||
|
+ * @return the setting is disabled
|
||||||
|
+ */
|
||||||
|
+ public boolean isDisabled(Setting setting) {
|
||||||
|
+ return !isEnabled(setting);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Toggles the provided settings state.
|
||||||
|
+ * [ true -> false, false -> true ]
|
||||||
|
+ * NOTE: the default value can vary.
|
||||||
|
+ *
|
||||||
|
+ * @param setting provided
|
||||||
|
+ */
|
||||||
|
+ public void toggle(Setting setting) {
|
||||||
|
+ if (settings.contains(setting)) {
|
||||||
|
+ settings.remove(setting);
|
||||||
|
+ } else {
|
||||||
|
+ settings.add(setting);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Toggles the provided settings state if it matches the modified state.
|
||||||
|
+ *
|
||||||
|
+ * @param setting provided
|
||||||
|
+ * @param modified fun
|
||||||
|
+ */
|
||||||
|
+ public void toggle(Setting setting, boolean modified) {
|
||||||
|
+ if (isToggled(setting) == modified) {
|
||||||
|
+ toggle(setting);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Sets the provided settings state.
|
||||||
|
+ *
|
||||||
|
+ * @param setting provided
|
||||||
|
+ * @param enable whether to enable this setting
|
||||||
|
+ */
|
||||||
|
+ public void set(Setting setting, boolean enable) {
|
||||||
|
+ if (isEnabled(setting) && !enable || isDisabled(setting) && enable) {
|
||||||
|
+ toggle(setting);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Toggles all settings based on the logic below.
|
||||||
|
+ * IF: settings are untouched or have been modified
|
||||||
|
+ * THEN: disable all settings
|
||||||
|
+ * IF: all settings are disabled
|
||||||
|
+ * THEN: enable all settings
|
||||||
|
+ */
|
||||||
|
+ public void toggleAll() {
|
||||||
|
+ var toggled = true; // true == all toggled
|
||||||
|
+
|
||||||
|
+ // If something is enabled set state to true
|
||||||
|
+ for (var setting : Setting.values()) {
|
||||||
|
+ toggled &= isToggled(setting);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // apply the opposite of the state so that it toggles
|
||||||
|
+ for (var setting : Setting.values()) {
|
||||||
|
+ toggle(setting, toggled);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Whether the settings have been modified.
|
||||||
|
+ * This is exposed to allow for quick return optimisations.
|
||||||
|
+ *
|
||||||
|
+ * @return settings have been modified
|
||||||
|
+ */
|
||||||
|
+ public boolean isModified() {
|
||||||
|
+ return !settings.isEmpty();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public enum Setting {
|
||||||
|
+ TNT_VISIBILITY("TNT Visibility", true),
|
||||||
|
+ SAND_VISIBILITY("Sand Visibility", true),
|
||||||
|
+ MINIMAL("Minimal TNT/Sand", false),
|
||||||
|
+ FLASHING_TNT("Flashing TNT", true),
|
||||||
|
+ EXPLOSIONS("Explosion Particles", true),
|
||||||
|
+ ENCHANTMENT_GLINT("Enchantment Glint", true),
|
||||||
|
+ SPAWNERS("Spawner Visibility", true),
|
||||||
|
+ REDSTONE("Redstone Animations", true),
|
||||||
|
+ PISTONS("Piston Animations", true);
|
||||||
|
+
|
||||||
|
+ private final String friendlyName;
|
||||||
|
+ private final boolean defaultValue;
|
||||||
|
+
|
||||||
|
+ Setting(String friendlyName, boolean defaultValue) {
|
||||||
|
+ this.friendlyName = friendlyName;
|
||||||
|
+ this.defaultValue = defaultValue;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public boolean getDefault() {
|
||||||
|
+ return defaultValue;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public String friendlyName() {
|
||||||
|
+ return friendlyName;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public String basicName() {
|
||||||
|
+ return name().replace("_", "").toLowerCase(Locale.ROOT);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java
|
||||||
|
index 20fa1024f9ad8f478a347be5c554b5e45b398a1c..b6d299b2fa9bb30d0a3b8735417dfa9be897d355 100644
|
||||||
|
--- a/src/main/java/org/bukkit/entity/Player.java
|
||||||
|
+++ b/src/main/java/org/bukkit/entity/Player.java
|
||||||
|
@@ -53,6 +53,15 @@ import org.jetbrains.annotations.Nullable;
|
||||||
|
*/
|
||||||
|
public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginMessageRecipient, net.kyori.adventure.identity.Identified, net.kyori.adventure.bossbar.BossBarViewer, com.destroystokyo.paper.network.NetworkClient { // Paper
|
||||||
|
|
||||||
|
+ // Sakura start
|
||||||
|
+ /**
|
||||||
|
+ * Visibility API for FPS settings.
|
||||||
|
+ *
|
||||||
|
+ * @return visibility api
|
||||||
|
+ */
|
||||||
|
+ me.samsuik.sakura.player.visibility.Visibility getVisibility();
|
||||||
|
+ // Sakura end
|
||||||
|
+
|
||||||
|
// Paper start
|
||||||
|
@Override
|
||||||
|
default net.kyori.adventure.identity.@NotNull Identity identity() {
|
||||||
122
patches/api/0004-Merge-Cannon-Entities.patch
Normal file
122
patches/api/0004-Merge-Cannon-Entities.patch
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
|
||||||
|
Date: Thu, 5 Oct 2023 14:34:30 +0100
|
||||||
|
Subject: [PATCH] Merge Cannon Entities
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/me/samsuik/sakura/entity/merge/MergeLevel.java b/src/main/java/me/samsuik/sakura/entity/merge/MergeLevel.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..16e68720eaf2eeedb2ba9bb906c21a16fc818e89
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/me/samsuik/sakura/entity/merge/MergeLevel.java
|
||||||
|
@@ -0,0 +1,65 @@
|
||||||
|
+package me.samsuik.sakura.entity.merge;
|
||||||
|
+
|
||||||
|
+import java.util.Locale;
|
||||||
|
+
|
||||||
|
+public enum MergeLevel {
|
||||||
|
+ /**
|
||||||
|
+ * Disabled.
|
||||||
|
+ */
|
||||||
|
+ NONE(-1),
|
||||||
|
+ /**
|
||||||
|
+ * Merge entities with the same OOE, properties and position.
|
||||||
|
+ * This is safe for all use cases and won't cause breakage.
|
||||||
|
+ */
|
||||||
|
+ STRICT(1),
|
||||||
|
+ /**
|
||||||
|
+ * Merge entities with the same properties and position.
|
||||||
|
+ * If the entities are known to have merged in the past
|
||||||
|
+ * this will be able to merge them together regardless of OOE.
|
||||||
|
+ */
|
||||||
|
+ NON_STRICT(2),
|
||||||
|
+ /**
|
||||||
|
+ * This will make sure of Non-Strict as a base, once the cannon
|
||||||
|
+ * has past the "on spawn" merge threshold it will be deemed safe
|
||||||
|
+ * for on spawn merging. This will merge all entities together on
|
||||||
|
+ * spawn that have merged together in the past.
|
||||||
|
+ */
|
||||||
|
+ SPAWN(3);
|
||||||
|
+
|
||||||
|
+ private final int level;
|
||||||
|
+
|
||||||
|
+ MergeLevel(int level) {
|
||||||
|
+ this.level = level;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public boolean atLeast(MergeLevel level) {
|
||||||
|
+ return getLevel() >= level.getLevel();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public int getLevel() {
|
||||||
|
+ return level;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public static MergeLevel from(int of) {
|
||||||
|
+ for (MergeLevel t : values()) {
|
||||||
|
+ if (t.getLevel() == of) {
|
||||||
|
+ return t;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return NONE;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public static MergeLevel from(String string) {
|
||||||
|
+ try {
|
||||||
|
+ return from(Integer.parseInt(string));
|
||||||
|
+ } catch (NumberFormatException ignored) {}
|
||||||
|
+
|
||||||
|
+ try {
|
||||||
|
+ var name = string.toUpperCase(Locale.ROOT);
|
||||||
|
+ return valueOf(name);
|
||||||
|
+ } catch (IllegalArgumentException ignored) {}
|
||||||
|
+
|
||||||
|
+ return NONE;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/me/samsuik/sakura/entity/merge/Mergeable.java b/src/main/java/me/samsuik/sakura/entity/merge/Mergeable.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..c241a3a359cad1d7c2cdb690649e0cacc491508b
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/me/samsuik/sakura/entity/merge/Mergeable.java
|
||||||
|
@@ -0,0 +1,13 @@
|
||||||
|
+package me.samsuik.sakura.entity.merge;
|
||||||
|
+
|
||||||
|
+import org.jetbrains.annotations.NotNull;
|
||||||
|
+
|
||||||
|
+public interface Mergeable {
|
||||||
|
+ @NotNull MergeLevel getMergeLevel();
|
||||||
|
+
|
||||||
|
+ void setMergeLevel(@NotNull MergeLevel level);
|
||||||
|
+
|
||||||
|
+ int getStacked();
|
||||||
|
+
|
||||||
|
+ void setStacked(int stacked);
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/org/bukkit/entity/FallingBlock.java b/src/main/java/org/bukkit/entity/FallingBlock.java
|
||||||
|
index 95e75f5a4ccdedd3b26f8639f37de9450ed63d6b..be52a64e73e7880c6a28d8a6912923973b7cb13b 100644
|
||||||
|
--- a/src/main/java/org/bukkit/entity/FallingBlock.java
|
||||||
|
+++ b/src/main/java/org/bukkit/entity/FallingBlock.java
|
||||||
|
@@ -7,7 +7,7 @@ import org.jetbrains.annotations.NotNull;
|
||||||
|
/**
|
||||||
|
* Represents a falling block
|
||||||
|
*/
|
||||||
|
-public interface FallingBlock extends Entity {
|
||||||
|
+public interface FallingBlock extends Entity, me.samsuik.sakura.entity.merge.Mergeable { // Sakura
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the Material of the falling block
|
||||||
|
diff --git a/src/main/java/org/bukkit/entity/TNTPrimed.java b/src/main/java/org/bukkit/entity/TNTPrimed.java
|
||||||
|
index 0813bd913c8fdb2001963ce3e82c07c2af105418..0bc227b6ba953c778ac950ec40f99276c77e880c 100644
|
||||||
|
--- a/src/main/java/org/bukkit/entity/TNTPrimed.java
|
||||||
|
+++ b/src/main/java/org/bukkit/entity/TNTPrimed.java
|
||||||
|
@@ -6,7 +6,7 @@ import org.jetbrains.annotations.Nullable;
|
||||||
|
/**
|
||||||
|
* Represents a Primed TNT.
|
||||||
|
*/
|
||||||
|
-public interface TNTPrimed extends Explosive {
|
||||||
|
+public interface TNTPrimed extends Explosive, me.samsuik.sakura.entity.merge.Mergeable { // Sakura
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the number of ticks until the TNT blows up after being primed.
|
||||||
34
patches/api/0005-isPushedByFluid-API.patch
Normal file
34
patches/api/0005-isPushedByFluid-API.patch
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
|
||||||
|
Date: Fri, 13 Oct 2023 20:01:48 +0100
|
||||||
|
Subject: [PATCH] isPushedByFluid API
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java
|
||||||
|
index d340ddcf6924cc834455de3acbbac91ab9c66e39..7170c875d81a5e234ee952062b6197dab088241f 100644
|
||||||
|
--- a/src/main/java/org/bukkit/entity/Entity.java
|
||||||
|
+++ b/src/main/java/org/bukkit/entity/Entity.java
|
||||||
|
@@ -108,6 +108,23 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent
|
||||||
|
*/
|
||||||
|
public boolean isInWater();
|
||||||
|
|
||||||
|
+ // Sakura start
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Gets if the entity will be pushed by fluid
|
||||||
|
+ *
|
||||||
|
+ * @return ahem
|
||||||
|
+ */
|
||||||
|
+ boolean isPushedByFluid();
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Sets if the entity will be pushed by fluid
|
||||||
|
+ *
|
||||||
|
+ * @param push pushed by fluid
|
||||||
|
+ */
|
||||||
|
+ void setPushedByFluid(boolean push);
|
||||||
|
+ // Sakura end
|
||||||
|
+
|
||||||
|
/**
|
||||||
|
* Gets the current world this entity resides in
|
||||||
|
*
|
||||||
30
patches/api/0006-Falling-Block-Parity-API.patch
Normal file
30
patches/api/0006-Falling-Block-Parity-API.patch
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
|
||||||
|
Date: Sun, 15 Oct 2023 22:53:38 +0100
|
||||||
|
Subject: [PATCH] Falling Block Parity API
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/org/bukkit/entity/FallingBlock.java b/src/main/java/org/bukkit/entity/FallingBlock.java
|
||||||
|
index be52a64e73e7880c6a28d8a6912923973b7cb13b..265a6029d65216fac7d309dda431a2b2ff1786b8 100644
|
||||||
|
--- a/src/main/java/org/bukkit/entity/FallingBlock.java
|
||||||
|
+++ b/src/main/java/org/bukkit/entity/FallingBlock.java
|
||||||
|
@@ -156,4 +156,19 @@ public interface FallingBlock extends Entity, me.samsuik.sakura.entity.merge.Mer
|
||||||
|
*/
|
||||||
|
void shouldAutoExpire(boolean autoExpires);
|
||||||
|
// Paper End - Auto expire setting
|
||||||
|
+ // Sakura start
|
||||||
|
+ /**
|
||||||
|
+ * Gets if falling block has height parity
|
||||||
|
+ *
|
||||||
|
+ * @return parity
|
||||||
|
+ */
|
||||||
|
+ boolean getHeightParity();
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Sets falling block height parity
|
||||||
|
+ *
|
||||||
|
+ * @param parity value
|
||||||
|
+ */
|
||||||
|
+ void setHeightParity(boolean parity);
|
||||||
|
+ // Sakura end
|
||||||
|
}
|
||||||
74
patches/server/0001-Branding-changes.patch
Normal file
74
patches/server/0001-Branding-changes.patch
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: MiniDigger <admin@minidigger.me>
|
||||||
|
Date: Sat, 12 Jun 2021 16:40:34 +0200
|
||||||
|
Subject: [PATCH] Branding changes
|
||||||
|
|
||||||
|
From ForkPaper.
|
||||||
|
|
||||||
|
diff --git a/build.gradle.kts b/build.gradle.kts
|
||||||
|
index c187641f0ec6444a10e0e1583e1697d07e8f0267..db5d5682a068518d9d5f0b232e2a582e3a8c4aee 100644
|
||||||
|
--- a/build.gradle.kts
|
||||||
|
+++ b/build.gradle.kts
|
||||||
|
@@ -13,8 +13,12 @@ configurations.named(log4jPlugins.compileClasspathConfigurationName) {
|
||||||
|
val alsoShade: Configuration by configurations.creating
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
- implementation(project(":paper-api"))
|
||||||
|
- implementation(project(":paper-mojangapi"))
|
||||||
|
+ // Sakura start
|
||||||
|
+ implementation(project(":sakura-api"))
|
||||||
|
+ implementation("io.papermc.paper:paper-mojangapi:1.20.1-R0.1-SNAPSHOT") {
|
||||||
|
+ exclude("io.papermc.paper", "paper-api")
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
// Paper start
|
||||||
|
implementation("org.jline:jline-terminal-jansi:3.21.0")
|
||||||
|
implementation("net.minecrell:terminalconsoleappender:1.3.0")
|
||||||
|
@@ -72,7 +76,7 @@ tasks.jar {
|
||||||
|
attributes(
|
||||||
|
"Main-Class" to "org.bukkit.craftbukkit.Main",
|
||||||
|
"Implementation-Title" to "CraftBukkit",
|
||||||
|
- "Implementation-Version" to "git-Paper-$implementationVersion",
|
||||||
|
+ "Implementation-Version" to "git-Sakura-$implementationVersion", // Sakura
|
||||||
|
"Implementation-Vendor" to date, // Paper
|
||||||
|
"Specification-Title" to "Bukkit",
|
||||||
|
"Specification-Version" to project.version,
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
index 97745f0bab8d82d397c6c2a5775aed92bca0a034..188da766381393afe643de28dccaa6aa7c9130a0 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
@@ -1697,7 +1697,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||||
|
|
||||||
|
@DontObfuscate
|
||||||
|
public String getServerModName() {
|
||||||
|
- return "Paper"; // Paper - Paper > // Spigot - Spigot > // CraftBukkit - cb > vanilla!
|
||||||
|
+ return "Sakura"; // Sakura - Sakura > // Paper - Paper > // Spigot - Spigot > // CraftBukkit - cb > vanilla!
|
||||||
|
}
|
||||||
|
|
||||||
|
public SystemReport fillSystemReport(SystemReport details) {
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
index b7e7e6ed60f55d2ab5e4fcefb3638ad1768c3b7f..28a1e39ed1b7fd10f4c01e076258cb8689b4e5bf 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
@@ -267,7 +267,7 @@ import javax.annotation.Nullable; // Paper
|
||||||
|
import javax.annotation.Nonnull; // Paper
|
||||||
|
|
||||||
|
public final class CraftServer implements Server {
|
||||||
|
- private final String serverName = "Paper"; // Paper
|
||||||
|
+ private final String serverName = "Sakura"; // Sakura // Paper
|
||||||
|
private final String serverVersion;
|
||||||
|
private final String bukkitVersion = Versioning.getBukkitVersion();
|
||||||
|
private final Logger logger = Logger.getLogger("Minecraft");
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java
|
||||||
|
index 774556a62eb240da42e84db4502e2ed43495be17..1941fd2dbdc7a10ddf17e2543a038dbd7fe8c88c 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java
|
||||||
|
@@ -11,7 +11,7 @@ public final class Versioning {
|
||||||
|
public static String getBukkitVersion() {
|
||||||
|
String result = "Unknown-Version";
|
||||||
|
|
||||||
|
- InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/io.papermc.paper/paper-api/pom.properties");
|
||||||
|
+ InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/me.samsuik.sakura/sakura-api/pom.properties"); // Sakura
|
||||||
|
Properties properties = new Properties();
|
||||||
|
|
||||||
|
if (stream != null) {
|
||||||
167
patches/server/0002-Sakura-Utils.patch
Normal file
167
patches/server/0002-Sakura-Utils.patch
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
|
||||||
|
Date: Tue, 23 May 2023 23:07:20 +0100
|
||||||
|
Subject: [PATCH] Sakura Utils
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/me/samsuik/sakura/utils/collections/OrderedComparatorList.java b/src/main/java/me/samsuik/sakura/utils/collections/OrderedComparatorList.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..ff4909a2ba8f451a7c6aa55ee98e33c88dd69e5e
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/me/samsuik/sakura/utils/collections/OrderedComparatorList.java
|
||||||
|
@@ -0,0 +1,51 @@
|
||||||
|
+package me.samsuik.sakura.utils.collections;
|
||||||
|
+
|
||||||
|
+import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||||
|
+
|
||||||
|
+import java.util.Arrays;
|
||||||
|
+import java.util.Comparator;
|
||||||
|
+
|
||||||
|
+public class OrderedComparatorList<T> extends ObjectArrayList<T> {
|
||||||
|
+
|
||||||
|
+ private final Comparator<T> comparator;
|
||||||
|
+ private boolean binarySearch = true;
|
||||||
|
+
|
||||||
|
+ public OrderedComparatorList(int capacity, Comparator<T> comparator) {
|
||||||
|
+ super(capacity);
|
||||||
|
+ this.comparator = Comparator.nullsLast(comparator);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public OrderedComparatorList(Comparator<T> comparator) {
|
||||||
|
+ this(DEFAULT_INITIAL_CAPACITY, comparator);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private void validateBounds(int index, T t, boolean up) {
|
||||||
|
+ if (index != 0 && comparator.compare(get(index - 1), t) > 0) {
|
||||||
|
+ binarySearch = false;
|
||||||
|
+ } else if (up && index < size() - 1 && comparator.compare(get(index + 1), t) < 0) {
|
||||||
|
+ binarySearch = false;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public boolean add(T t) {
|
||||||
|
+ validateBounds(size(), t, false);
|
||||||
|
+ return super.add(t);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void add(int index, T t) {
|
||||||
|
+ validateBounds(index, t, true);
|
||||||
|
+ super.add(index, t);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public int indexOf(final Object k) {
|
||||||
|
+ if (binarySearch) {
|
||||||
|
+ return Math.max(Arrays.binarySearch(a, (T) k, comparator), -1);
|
||||||
|
+ } else {
|
||||||
|
+ return super.indexOf(k);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/me/samsuik/sakura/utils/collections/TrackedEntityChunkMap.java b/src/main/java/me/samsuik/sakura/utils/collections/TrackedEntityChunkMap.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..8f4ac8acd2e0752e7a615d152b8047d790947b9f
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/me/samsuik/sakura/utils/collections/TrackedEntityChunkMap.java
|
||||||
|
@@ -0,0 +1,29 @@
|
||||||
|
+package me.samsuik.sakura.utils.collections;
|
||||||
|
+
|
||||||
|
+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
|
+import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||||
|
+import it.unimi.dsi.fastutil.objects.ObjectCollection;
|
||||||
|
+import net.minecraft.server.level.ChunkMap;
|
||||||
|
+
|
||||||
|
+public class TrackedEntityChunkMap extends Int2ObjectOpenHashMap<ChunkMap.TrackedEntity> {
|
||||||
|
+
|
||||||
|
+ private final ObjectArrayList<ChunkMap.TrackedEntity> entityList = new UnorderedIndexedList<>();
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public ChunkMap.TrackedEntity put(int k, ChunkMap.TrackedEntity trackedEntity) {
|
||||||
|
+ entityList.add(trackedEntity);
|
||||||
|
+ return super.put(k, trackedEntity);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public ChunkMap.TrackedEntity remove(int k) {
|
||||||
|
+ entityList.remove(k);
|
||||||
|
+ return super.remove(k);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public ObjectCollection<ChunkMap.TrackedEntity> values() {
|
||||||
|
+ return entityList;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/me/samsuik/sakura/utils/collections/UnorderedIndexedList.java b/src/main/java/me/samsuik/sakura/utils/collections/UnorderedIndexedList.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..7bdd93f1078dde97233a9096d0b7738dae061ae4
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/me/samsuik/sakura/utils/collections/UnorderedIndexedList.java
|
||||||
|
@@ -0,0 +1,63 @@
|
||||||
|
+package me.samsuik.sakura.utils.collections;
|
||||||
|
+
|
||||||
|
+import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||||
|
+import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||||
|
+
|
||||||
|
+public class UnorderedIndexedList<T> extends ObjectArrayList<T> {
|
||||||
|
+
|
||||||
|
+ private final Int2IntOpenHashMap elementToIndex = new Int2IntOpenHashMap();
|
||||||
|
+
|
||||||
|
+ {
|
||||||
|
+ elementToIndex.defaultReturnValue(-1);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public UnorderedIndexedList(int capacity) {
|
||||||
|
+ super(capacity);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public UnorderedIndexedList() {
|
||||||
|
+ super();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public boolean add(final T t) {
|
||||||
|
+ elementToIndex.put(t.hashCode(), size());
|
||||||
|
+ return super.add(t);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public T remove(final int index) {
|
||||||
|
+ final int tail = size() - 1;
|
||||||
|
+ final T at = a[index];
|
||||||
|
+
|
||||||
|
+ if (index != tail) {
|
||||||
|
+ final T tailObj = a[tail];
|
||||||
|
+ if (tailObj != null)
|
||||||
|
+ elementToIndex.put(tailObj.hashCode(), index);
|
||||||
|
+ a[index] = tailObj;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (at != null)
|
||||||
|
+ elementToIndex.remove(at.hashCode());
|
||||||
|
+ a[tail] = null;
|
||||||
|
+ size--;
|
||||||
|
+ return at;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void clear() {
|
||||||
|
+ elementToIndex.clear();
|
||||||
|
+ super.clear();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public int indexOf(final Object k) {
|
||||||
|
+ return elementToIndex.get(k.hashCode());
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void add(final int index, final T t) {
|
||||||
|
+ throw new UnsupportedOperationException();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+}
|
||||||
41
patches/server/0003-MC-Dev-Fixes.patch
Normal file
41
patches/server/0003-MC-Dev-Fixes.patch
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Samsuik <kfian294ma4@gmail.com>
|
||||||
|
Date: Fri, 15 Oct 2021 18:32:13 +0100
|
||||||
|
Subject: [PATCH] MC-Dev-Fixes
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/tags/TagKey.java b/src/main/java/net/minecraft/tags/TagKey.java
|
||||||
|
index 3899e39ef9c602cbe33c71e85af76e72d8938219..b385f7cf774a81d90319e7eb5838a52929c330fb 100644
|
||||||
|
--- a/src/main/java/net/minecraft/tags/TagKey.java
|
||||||
|
+++ b/src/main/java/net/minecraft/tags/TagKey.java
|
||||||
|
@@ -31,7 +31,7 @@ public record TagKey<T>(ResourceKey<? extends Registry<T>> registry, ResourceLoc
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> TagKey<T> create(ResourceKey<? extends Registry<T>> registry, ResourceLocation id) {
|
||||||
|
- return VALUES.intern(new TagKey<>(registry, id));
|
||||||
|
+ return (TagKey<T>) VALUES.intern(new TagKey<>(registry, id)); // Sakura - compile error
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFor(ResourceKey<? extends Registry<?>> registryRef) {
|
||||||
|
@@ -39,7 +39,7 @@ public record TagKey<T>(ResourceKey<? extends Registry<T>> registry, ResourceLoc
|
||||||
|
}
|
||||||
|
|
||||||
|
public <E> Optional<TagKey<E>> cast(ResourceKey<? extends Registry<E>> registryRef) {
|
||||||
|
- return this.isFor(registryRef) ? Optional.of(this) : Optional.empty();
|
||||||
|
+ return this.isFor(registryRef) ? Optional.of((TagKey<E>) this) : Optional.empty(); // Sakura - compile error
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
diff --git a/src/main/java/net/minecraft/util/ClassInstanceMultiMap.java b/src/main/java/net/minecraft/util/ClassInstanceMultiMap.java
|
||||||
|
index 50a9f33aa31e9273c7c52d4bb2b02f0f884f7ba5..5fb7573022c5af775b2e737dcd05c53cd9ae39ec 100644
|
||||||
|
--- a/src/main/java/net/minecraft/util/ClassInstanceMultiMap.java
|
||||||
|
+++ b/src/main/java/net/minecraft/util/ClassInstanceMultiMap.java
|
||||||
|
@@ -61,7 +61,7 @@ public class ClassInstanceMultiMap<T> extends AbstractCollection<T> {
|
||||||
|
List<? extends T> list = this.byClass.computeIfAbsent(type, (typeClass) -> {
|
||||||
|
return this.allInstances.stream().filter(typeClass::isInstance).collect(Collectors.toList());
|
||||||
|
});
|
||||||
|
- return Collections.unmodifiableCollection(list);
|
||||||
|
+ return (Collection<S>) Collections.unmodifiableCollection(list); // Sakura - decompile fix
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
909
patches/server/0004-Sakura-Configuration-Files.patch
Normal file
909
patches/server/0004-Sakura-Configuration-Files.patch
Normal file
@@ -0,0 +1,909 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: "kfian294ma4@gmail.com" <kfian294ma4@gmail.com>
|
||||||
|
Date: Sun, 5 Sep 2021 18:01:34 +0100
|
||||||
|
Subject: [PATCH] Sakura Configuration Files
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/io/papermc/paper/configuration/Configurations.java b/src/main/java/io/papermc/paper/configuration/Configurations.java
|
||||||
|
index 9ef6712c70fcd8912a79f3f61e351aac09572cf3..4cb0c8291833cd10d9704cdbe4f0332827c02ae2 100644
|
||||||
|
--- a/src/main/java/io/papermc/paper/configuration/Configurations.java
|
||||||
|
+++ b/src/main/java/io/papermc/paper/configuration/Configurations.java
|
||||||
|
@@ -88,7 +88,7 @@ public abstract class Configurations<G, W> {
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
- static <T> CheckedFunction<ConfigurationNode, T, SerializationException> reloader(Class<T> type, T instance) {
|
||||||
|
+ public static <T> CheckedFunction<ConfigurationNode, T, SerializationException> reloader(Class<T> type, T instance) { // Sakura - public
|
||||||
|
return node -> {
|
||||||
|
ObjectMapper.Factory factory = (ObjectMapper.Factory) Objects.requireNonNull(node.options().serializers().get(type));
|
||||||
|
ObjectMapper.Mutable<T> mutable = (ObjectMapper.Mutable<T>) factory.get(type);
|
||||||
|
@@ -206,7 +206,7 @@ public abstract class Configurations<G, W> {
|
||||||
|
.path(worldConfigFile)
|
||||||
|
.build();
|
||||||
|
final ConfigurationNode worldNode = worldLoader.load();
|
||||||
|
- if (newFile) { // set the version field if new file
|
||||||
|
+ if (newFile && this instanceof PaperConfigurations) { // Sakura - hack this into working // set the version field if new file
|
||||||
|
worldNode.node(Configuration.VERSION_FIELD).set(WorldConfiguration.CURRENT_VERSION);
|
||||||
|
}
|
||||||
|
this.applyWorldConfigTransformations(contextMap, worldNode);
|
||||||
|
diff --git a/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java b/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java
|
||||||
|
index 9e8b8de907654050c51400286af971caca87d6bd..8e173ad0adc71c295394e61bbabf11336bd10332 100644
|
||||||
|
--- a/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java
|
||||||
|
+++ b/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java
|
||||||
|
@@ -449,7 +449,7 @@ public class PaperConfigurations extends Configurations<GlobalConfiguration, Wor
|
||||||
|
}
|
||||||
|
|
||||||
|
// Symlinks are not correctly checked in createDirectories
|
||||||
|
- static void createDirectoriesSymlinkAware(Path path) throws IOException {
|
||||||
|
+ public static void createDirectoriesSymlinkAware(Path path) throws IOException { // Sakura - make public
|
||||||
|
if (!Files.isDirectory(path)) {
|
||||||
|
Files.createDirectories(path);
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/io/papermc/paper/configuration/mapping/InnerClassInstanceFactory.java b/src/main/java/io/papermc/paper/configuration/mapping/InnerClassInstanceFactory.java
|
||||||
|
index cec678ae24a7d99a46fa672be907f4c28fe4da96..9906ef363c72ade71c16d8141a0d6d79d72d4eff 100644
|
||||||
|
--- a/src/main/java/io/papermc/paper/configuration/mapping/InnerClassInstanceFactory.java
|
||||||
|
+++ b/src/main/java/io/papermc/paper/configuration/mapping/InnerClassInstanceFactory.java
|
||||||
|
@@ -11,13 +11,13 @@ import org.spongepowered.configurate.serialize.SerializationException;
|
||||||
|
|
||||||
|
import static io.leangen.geantyref.GenericTypeReflector.erase;
|
||||||
|
|
||||||
|
-final class InnerClassInstanceFactory implements FieldDiscoverer.MutableInstanceFactory<Map<Field, Object>> {
|
||||||
|
+public final class InnerClassInstanceFactory implements FieldDiscoverer.MutableInstanceFactory<Map<Field, Object>> { // Sakura
|
||||||
|
|
||||||
|
private final InnerClassInstanceSupplier instanceSupplier;
|
||||||
|
private final FieldDiscoverer.MutableInstanceFactory<Map<Field, Object>> fallback;
|
||||||
|
private final AnnotatedType targetType;
|
||||||
|
|
||||||
|
- InnerClassInstanceFactory(final InnerClassInstanceSupplier instanceSupplier, final FieldDiscoverer.MutableInstanceFactory<Map<Field, Object>> fallback, final AnnotatedType targetType) {
|
||||||
|
+ public InnerClassInstanceFactory(final InnerClassInstanceSupplier instanceSupplier, final FieldDiscoverer.MutableInstanceFactory<Map<Field, Object>> fallback, final AnnotatedType targetType) { // Sakura
|
||||||
|
this.instanceSupplier = instanceSupplier;
|
||||||
|
this.fallback = fallback;
|
||||||
|
this.targetType = targetType;
|
||||||
|
diff --git a/src/main/java/io/papermc/paper/configuration/mapping/InnerClassInstanceSupplier.java b/src/main/java/io/papermc/paper/configuration/mapping/InnerClassInstanceSupplier.java
|
||||||
|
index 8d8bc050441c02cf65dfcb6400978363d6b8ef10..5872095a811452037cc0772ba2a31bf9a795cc82 100644
|
||||||
|
--- a/src/main/java/io/papermc/paper/configuration/mapping/InnerClassInstanceSupplier.java
|
||||||
|
+++ b/src/main/java/io/papermc/paper/configuration/mapping/InnerClassInstanceSupplier.java
|
||||||
|
@@ -19,7 +19,7 @@ import static io.leangen.geantyref.GenericTypeReflector.erase;
|
||||||
|
* {@link ConfigurationPart}. Only 1 instance of each {@link ConfigurationPart} should be present for each instance
|
||||||
|
* of the field discoverer this is used in.
|
||||||
|
*/
|
||||||
|
-final class InnerClassInstanceSupplier implements CheckedFunction<AnnotatedType, @Nullable Supplier<Object>, SerializationException> {
|
||||||
|
+public final class InnerClassInstanceSupplier implements CheckedFunction<AnnotatedType, @Nullable Supplier<Object>, SerializationException> { // Sakua - :<
|
||||||
|
|
||||||
|
private final Map<Class<?>, Object> instanceMap = new HashMap<>();
|
||||||
|
private final Map<Class<?>, Object> initialOverrides;
|
||||||
|
@@ -27,7 +27,7 @@ final class InnerClassInstanceSupplier implements CheckedFunction<AnnotatedType,
|
||||||
|
/**
|
||||||
|
* @param initialOverrides map of types to objects to preload the config objects with.
|
||||||
|
*/
|
||||||
|
- InnerClassInstanceSupplier(final Map<Class<?>, Object> initialOverrides) {
|
||||||
|
+ public InnerClassInstanceSupplier(final Map<Class<?>, Object> initialOverrides) { // Sakura
|
||||||
|
this.initialOverrides = initialOverrides;
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/src/main/java/me/samsuik/sakura/command/BaseSubCommand.java b/src/main/java/me/samsuik/sakura/command/BaseSubCommand.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..9b5af05f7a4593eb44f36fff90d94e98d6999c7f
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/me/samsuik/sakura/command/BaseSubCommand.java
|
||||||
|
@@ -0,0 +1,47 @@
|
||||||
|
+package me.samsuik.sakura.command;
|
||||||
|
+
|
||||||
|
+import org.bukkit.command.Command;
|
||||||
|
+import org.bukkit.command.CommandSender;
|
||||||
|
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||||
|
+import org.jetbrains.annotations.NotNull;
|
||||||
|
+
|
||||||
|
+import java.util.ArrayList;
|
||||||
|
+import java.util.List;
|
||||||
|
+
|
||||||
|
+@DefaultQualifier(NonNull.class)
|
||||||
|
+public abstract class BaseSubCommand extends Command {
|
||||||
|
+
|
||||||
|
+ public BaseSubCommand(String name) {
|
||||||
|
+ super(name);
|
||||||
|
+ this.description = "Sakura Command " + name;
|
||||||
|
+ this.setPermission("bukkit.command." + name);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public abstract void execute(CommandSender sender, String[] args);
|
||||||
|
+
|
||||||
|
+ public void tabComplete(List<String> list, String[] args) throws IllegalArgumentException {}
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ @Deprecated
|
||||||
|
+ public final boolean execute(CommandSender sender, String label, String[] args) {
|
||||||
|
+ if (testPermission(sender)) {
|
||||||
|
+ execute(sender, args);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return true;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ @NotNull
|
||||||
|
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
|
||||||
|
+ var completions = new ArrayList<String>(0);
|
||||||
|
+
|
||||||
|
+ if (testPermissionSilent(sender)) {
|
||||||
|
+ tabComplete(completions, args);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return completions;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/me/samsuik/sakura/command/SakuraCommand.java b/src/main/java/me/samsuik/sakura/command/SakuraCommand.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..f4e75ba8f2c53a82cb40868f0e1ab77ffcc19e3e
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/me/samsuik/sakura/command/SakuraCommand.java
|
||||||
|
@@ -0,0 +1,93 @@
|
||||||
|
+package me.samsuik.sakura.command;
|
||||||
|
+
|
||||||
|
+import net.kyori.adventure.text.Component;
|
||||||
|
+import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
+import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||||
|
+import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
|
||||||
|
+import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
|
||||||
|
+import net.minecraft.server.MinecraftServer;
|
||||||
|
+import org.bukkit.command.Command;
|
||||||
|
+import org.bukkit.command.CommandSender;
|
||||||
|
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||||
|
+import org.jetbrains.annotations.NotNull;
|
||||||
|
+
|
||||||
|
+import javax.annotation.Nullable;
|
||||||
|
+import java.util.ArrayList;
|
||||||
|
+import java.util.Arrays;
|
||||||
|
+import java.util.Collections;
|
||||||
|
+import java.util.List;
|
||||||
|
+
|
||||||
|
+@DefaultQualifier(NonNull.class)
|
||||||
|
+public class SakuraCommand extends Command {
|
||||||
|
+
|
||||||
|
+ private static final Component INFORMATION_MESSAGE = MiniMessage.miniMessage().deserialize("""
|
||||||
|
+ <dark_purple>.</dark_purple>
|
||||||
|
+ <dark_purple>| <white>This is the main command for <gradient:red:light_purple:0.5>Sakura</gradient>.
|
||||||
|
+ <dark_purple>| <white>All exclusive commands are listed below."""
|
||||||
|
+ );
|
||||||
|
+
|
||||||
|
+ private static final String COMMAND_MSG = "<dark_purple>| <dark_gray>*</dark_gray> /<light_purple><command>";
|
||||||
|
+
|
||||||
|
+ public SakuraCommand(String name) {
|
||||||
|
+ super(name);
|
||||||
|
+
|
||||||
|
+ this.description = "";
|
||||||
|
+ this.usageMessage = "/sakura";
|
||||||
|
+ this.setPermission("bukkit.command.sakura");
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public boolean execute(CommandSender sender, String commandLabel, String[] args) {
|
||||||
|
+ if (args.length > 0) {
|
||||||
|
+ var commands = new ArrayList<>(SakuraCommands.COMMANDS.values());
|
||||||
|
+
|
||||||
|
+ // This part is copied from the VersionCommand SubCommand in paper
|
||||||
|
+ @Nullable
|
||||||
|
+ var internalVersion = MinecraftServer.getServer().server.getCommandMap().getCommand("version");
|
||||||
|
+ if (internalVersion != null) {
|
||||||
|
+ commands.add(internalVersion);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ for (var base : commands) {
|
||||||
|
+ if (base.getName().equalsIgnoreCase(args[0])) {
|
||||||
|
+ return base.execute(sender, commandLabel, Arrays.copyOfRange(args, 1, args.length));
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ sendHelpMessage(sender);
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private void sendHelpMessage(CommandSender sender) {
|
||||||
|
+ sender.sendMessage(INFORMATION_MESSAGE);
|
||||||
|
+
|
||||||
|
+ var uniqueCommands = SakuraCommands.COMMANDS.values()
|
||||||
|
+ .stream()
|
||||||
|
+ .filter(command -> command != this);
|
||||||
|
+
|
||||||
|
+ uniqueCommands.forEach((command) -> {
|
||||||
|
+ sender.sendMessage(MiniMessage.miniMessage().deserialize(COMMAND_MSG,
|
||||||
|
+ Placeholder.unparsed("command", command.getName()))
|
||||||
|
+ );
|
||||||
|
+ });
|
||||||
|
+
|
||||||
|
+ sender.sendMessage(Component.text("'", NamedTextColor.DARK_PURPLE));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @NotNull
|
||||||
|
+ @Override
|
||||||
|
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
|
||||||
|
+ if (!testPermissionSilent(sender)) {
|
||||||
|
+ return Collections.emptyList();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return SakuraCommands.COMMANDS.values().stream()
|
||||||
|
+ .filter(command -> command != this) // ahem
|
||||||
|
+ .map(Command::getName)
|
||||||
|
+ .filter(name -> args.length <= 1 || name.startsWith(args[args.length - 1]))
|
||||||
|
+ .toList();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/me/samsuik/sakura/command/SakuraCommands.java b/src/main/java/me/samsuik/sakura/command/SakuraCommands.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..c2651cac1dcf85fb67fe981b97efee4e56431de2
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/me/samsuik/sakura/command/SakuraCommands.java
|
||||||
|
@@ -0,0 +1,26 @@
|
||||||
|
+package me.samsuik.sakura.command;
|
||||||
|
+
|
||||||
|
+import io.papermc.paper.command.PaperPluginsCommand;
|
||||||
|
+import me.samsuik.sakura.command.subcommands.ConfigCommand;
|
||||||
|
+import net.minecraft.server.MinecraftServer;
|
||||||
|
+import org.bukkit.command.Command;
|
||||||
|
+
|
||||||
|
+import java.util.HashMap;
|
||||||
|
+import java.util.Map;
|
||||||
|
+
|
||||||
|
+public class SakuraCommands {
|
||||||
|
+
|
||||||
|
+ static final Map<String, Command> COMMANDS = new HashMap<>();
|
||||||
|
+ static {
|
||||||
|
+ COMMANDS.put("sakura", new SakuraCommand("sakura"));
|
||||||
|
+ COMMANDS.put("config", new ConfigCommand("config"));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public static void registerCommands(final MinecraftServer server) {
|
||||||
|
+ COMMANDS.forEach((s, command) -> {
|
||||||
|
+ server.server.getCommandMap().register(s, "sakura", command);
|
||||||
|
+ });
|
||||||
|
+ server.server.getCommandMap().register("bukkit", new PaperPluginsCommand());
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/me/samsuik/sakura/command/subcommands/ConfigCommand.java b/src/main/java/me/samsuik/sakura/command/subcommands/ConfigCommand.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..0b5f50c7447d1c1732a745bae54c4fcd4f45da46
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/me/samsuik/sakura/command/subcommands/ConfigCommand.java
|
||||||
|
@@ -0,0 +1,45 @@
|
||||||
|
+package me.samsuik.sakura.command.subcommands;
|
||||||
|
+
|
||||||
|
+import me.samsuik.sakura.command.BaseSubCommand;
|
||||||
|
+import net.minecraft.server.MinecraftServer;
|
||||||
|
+import org.bukkit.command.Command;
|
||||||
|
+import org.bukkit.command.CommandSender;
|
||||||
|
+import org.bukkit.craftbukkit.CraftServer;
|
||||||
|
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||||
|
+import org.jetbrains.annotations.NotNull;
|
||||||
|
+
|
||||||
|
+import java.util.Collections;
|
||||||
|
+import java.util.List;
|
||||||
|
+
|
||||||
|
+import static net.kyori.adventure.text.Component.text;
|
||||||
|
+import static net.kyori.adventure.text.format.NamedTextColor.GREEN;
|
||||||
|
+import static net.kyori.adventure.text.format.NamedTextColor.RED;
|
||||||
|
+
|
||||||
|
+@DefaultQualifier(NonNull.class)
|
||||||
|
+public class ConfigCommand extends BaseSubCommand {
|
||||||
|
+
|
||||||
|
+ public ConfigCommand(String name) {
|
||||||
|
+ super(name);
|
||||||
|
+ this.description = "Command for reloading the sakura configuration file";
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void execute(CommandSender sender, String[] args) {
|
||||||
|
+ Command.broadcastCommandMessage(sender, text("Please note that this command is not supported and may cause issues.", RED));
|
||||||
|
+ Command.broadcastCommandMessage(sender, text("If you encounter any issues please use the /stop command to restart your server.", RED));
|
||||||
|
+
|
||||||
|
+ MinecraftServer server = ((CraftServer) sender.getServer()).getServer();
|
||||||
|
+ server.sakuraConfigurations.reloadConfigs(server);
|
||||||
|
+ server.server.reloadCount++;
|
||||||
|
+
|
||||||
|
+ Command.broadcastCommandMessage(sender, text("Sakura config reload complete.", GREEN));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @NotNull
|
||||||
|
+ @Override
|
||||||
|
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
|
||||||
|
+ return Collections.emptyList();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/me/samsuik/sakura/configuration/GlobalConfiguration.java b/src/main/java/me/samsuik/sakura/configuration/GlobalConfiguration.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..bc6db446dca3024b8f6d3f24499242775dd02219
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/me/samsuik/sakura/configuration/GlobalConfiguration.java
|
||||||
|
@@ -0,0 +1,42 @@
|
||||||
|
+package me.samsuik.sakura.configuration;
|
||||||
|
+
|
||||||
|
+import com.mojang.logging.LogUtils;
|
||||||
|
+import io.papermc.paper.configuration.Configuration;
|
||||||
|
+import io.papermc.paper.configuration.ConfigurationPart;
|
||||||
|
+import org.slf4j.Logger;
|
||||||
|
+import org.spongepowered.configurate.objectmapping.meta.Setting;
|
||||||
|
+
|
||||||
|
+@SuppressWarnings({"CanBeFinal", "FieldCanBeLocal", "FieldMayBeFinal", "NotNullFieldNotInitialized", "InnerClassMayBeStatic", "RedundantSuppression"})
|
||||||
|
+public class GlobalConfiguration extends ConfigurationPart {
|
||||||
|
+
|
||||||
|
+ private static final Logger LOGGER = LogUtils.getClassLogger();
|
||||||
|
+ static final int CURRENT_VERSION = 1;// (when you change the version, change the comment, so it conflicts on rebases): rename filter bad nbt from spawn eggs
|
||||||
|
+
|
||||||
|
+ private static GlobalConfiguration instance;
|
||||||
|
+ public static GlobalConfiguration get() {
|
||||||
|
+ return instance;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ static void set(GlobalConfiguration instance) {
|
||||||
|
+ GlobalConfiguration.instance = instance;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Setting(Configuration.VERSION_FIELD)
|
||||||
|
+ public int version = CURRENT_VERSION;
|
||||||
|
+
|
||||||
|
+ public Fps fps;
|
||||||
|
+ public class Fps extends ConfigurationPart {
|
||||||
|
+ public String message = "<dark_gray>(<light_purple>S</light_purple>) <gray><state> <yellow><name>";
|
||||||
|
+ public String material = "pink_stained_glass_pane";
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public Cannons cannons;
|
||||||
|
+ public class Cannons extends ConfigurationPart {
|
||||||
|
+ public Explosion explosion = new Explosion();
|
||||||
|
+
|
||||||
|
+ public class Explosion extends ConfigurationPart {
|
||||||
|
+ public boolean reducedSearchRays;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/me/samsuik/sakura/configuration/SakuraConfigurations.java b/src/main/java/me/samsuik/sakura/configuration/SakuraConfigurations.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..37f41089a2fb7ad11ceda07cf5de0fc8b34b8db2
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/me/samsuik/sakura/configuration/SakuraConfigurations.java
|
||||||
|
@@ -0,0 +1,220 @@
|
||||||
|
+package me.samsuik.sakura.configuration;
|
||||||
|
+
|
||||||
|
+import com.google.common.collect.Table;
|
||||||
|
+import com.mojang.logging.LogUtils;
|
||||||
|
+import io.leangen.geantyref.TypeToken;
|
||||||
|
+import io.papermc.paper.configuration.ConfigurationPart;
|
||||||
|
+import io.papermc.paper.configuration.Configurations;
|
||||||
|
+import io.papermc.paper.configuration.NestedSetting;
|
||||||
|
+import io.papermc.paper.configuration.PaperConfigurations;
|
||||||
|
+import io.papermc.paper.configuration.serializer.*;
|
||||||
|
+import io.papermc.paper.configuration.serializer.collections.FastutilMapSerializer;
|
||||||
|
+import io.papermc.paper.configuration.serializer.collections.MapSerializer;
|
||||||
|
+import io.papermc.paper.configuration.serializer.collections.TableSerializer;
|
||||||
|
+import io.papermc.paper.configuration.serializer.registry.RegistryHolderSerializer;
|
||||||
|
+import io.papermc.paper.configuration.serializer.registry.RegistryValueSerializer;
|
||||||
|
+import io.papermc.paper.configuration.type.BooleanOrDefault;
|
||||||
|
+import io.papermc.paper.configuration.type.Duration;
|
||||||
|
+import io.papermc.paper.configuration.type.DurationOrDisabled;
|
||||||
|
+import io.papermc.paper.configuration.type.EngineMode;
|
||||||
|
+import io.papermc.paper.configuration.type.number.DoubleOr;
|
||||||
|
+import io.papermc.paper.configuration.type.number.IntOr;
|
||||||
|
+import it.unimi.dsi.fastutil.objects.Reference2IntMap;
|
||||||
|
+import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
|
||||||
|
+import it.unimi.dsi.fastutil.objects.Reference2LongMap;
|
||||||
|
+import it.unimi.dsi.fastutil.objects.Reference2LongOpenHashMap;
|
||||||
|
+import me.samsuik.sakura.configuration.mapping.InnerClassFieldDiscoverer;
|
||||||
|
+import net.minecraft.core.registries.Registries;
|
||||||
|
+import net.minecraft.resources.ResourceLocation;
|
||||||
|
+import net.minecraft.server.MinecraftServer;
|
||||||
|
+import net.minecraft.server.level.ServerLevel;
|
||||||
|
+import net.minecraft.world.entity.EntityType;
|
||||||
|
+import net.minecraft.world.item.Item;
|
||||||
|
+import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
|
||||||
|
+import org.slf4j.Logger;
|
||||||
|
+import org.spongepowered.configurate.ConfigurateException;
|
||||||
|
+import org.spongepowered.configurate.ConfigurationNode;
|
||||||
|
+import org.spongepowered.configurate.ConfigurationOptions;
|
||||||
|
+import org.spongepowered.configurate.objectmapping.ObjectMapper;
|
||||||
|
+import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
|
||||||
|
+
|
||||||
|
+import java.io.IOException;
|
||||||
|
+import java.lang.reflect.Type;
|
||||||
|
+import java.nio.file.Path;
|
||||||
|
+import java.util.function.Function;
|
||||||
|
+
|
||||||
|
+import static io.leangen.geantyref.GenericTypeReflector.erase;
|
||||||
|
+
|
||||||
|
+@SuppressWarnings("Convert2Diamond")
|
||||||
|
+public class SakuraConfigurations extends Configurations<GlobalConfiguration, WorldConfiguration> {
|
||||||
|
+
|
||||||
|
+ private static final Logger LOGGER = LogUtils.getClassLogger();
|
||||||
|
+ static final String GLOBAL_CONFIG_FILE_NAME = "sakura-global.yml";
|
||||||
|
+ static final String WORLD_DEFAULTS_CONFIG_FILE_NAME = "sakura-world-defaults.yml";
|
||||||
|
+ static final String WORLD_CONFIG_FILE_NAME = "sakura-world.yml";
|
||||||
|
+ public static final String CONFIG_DIR = "config";
|
||||||
|
+
|
||||||
|
+ private static final String GLOBAL_HEADER = String.format("""
|
||||||
|
+ This is the global configuration file for Sakura.
|
||||||
|
+ As you can see, there's a lot to configure. Some options may impact gameplay, so use
|
||||||
|
+ with caution, and make sure you know what each option does before configuring.
|
||||||
|
+
|
||||||
|
+ The world configuration options have been moved inside
|
||||||
|
+ their respective world folder. The files are named %s""", WORLD_CONFIG_FILE_NAME);
|
||||||
|
+
|
||||||
|
+ private static final String WORLD_DEFAULTS_HEADER = """
|
||||||
|
+ This is the world defaults configuration file for Sakura.
|
||||||
|
+ As you can see, there's a lot to configure. Some options may impact gameplay, so use
|
||||||
|
+ with caution, and make sure you know what each option does before configuring.
|
||||||
|
+
|
||||||
|
+ Configuration options here apply to all worlds, unless you specify overrides inside
|
||||||
|
+ the world-specific config file inside each world folder.""";
|
||||||
|
+
|
||||||
|
+ private static final Function<ContextMap, String> WORLD_HEADER = map -> String.format("""
|
||||||
|
+ This is a world configuration file for Sakura.
|
||||||
|
+ This file may start empty but can be filled with settings to override ones in the %s/%s
|
||||||
|
+
|
||||||
|
+ World: %s (%s)""",
|
||||||
|
+ SakuraConfigurations.CONFIG_DIR,
|
||||||
|
+ SakuraConfigurations.WORLD_DEFAULTS_CONFIG_FILE_NAME,
|
||||||
|
+ map.require(WORLD_NAME),
|
||||||
|
+ map.require(WORLD_KEY)
|
||||||
|
+ );
|
||||||
|
+
|
||||||
|
+ public SakuraConfigurations(final Path globalFolder) {
|
||||||
|
+ super(globalFolder, GlobalConfiguration.class, WorldConfiguration.class, GLOBAL_CONFIG_FILE_NAME, WORLD_DEFAULTS_CONFIG_FILE_NAME, WORLD_CONFIG_FILE_NAME);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ protected YamlConfigurationLoader.Builder createLoaderBuilder() {
|
||||||
|
+ return super.createLoaderBuilder()
|
||||||
|
+ .defaultOptions(SakuraConfigurations::defaultOptions);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private static ConfigurationOptions defaultOptions(ConfigurationOptions options) {
|
||||||
|
+ return options.serializers(builder -> builder
|
||||||
|
+ .register(MapSerializer.TYPE, new MapSerializer(false))
|
||||||
|
+ .register(new EnumValueSerializer())
|
||||||
|
+ .register(new ComponentSerializer())
|
||||||
|
+ );
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ protected ObjectMapper.Factory.Builder createGlobalObjectMapperFactoryBuilder() {
|
||||||
|
+ return defaultGlobalFactoryBuilder(super.createGlobalObjectMapperFactoryBuilder());
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private static ObjectMapper.Factory.Builder defaultGlobalFactoryBuilder(ObjectMapper.Factory.Builder builder) {
|
||||||
|
+ return builder.addDiscoverer(InnerClassFieldDiscoverer.globalConfig());
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ protected YamlConfigurationLoader.Builder createGlobalLoaderBuilder() {
|
||||||
|
+ return super.createGlobalLoaderBuilder()
|
||||||
|
+ .defaultOptions(SakuraConfigurations::defaultGlobalOptions);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private static ConfigurationOptions defaultGlobalOptions(ConfigurationOptions options) {
|
||||||
|
+ return options
|
||||||
|
+ .header(GLOBAL_HEADER)
|
||||||
|
+ .serializers(builder -> builder
|
||||||
|
+ .register(new PacketClassSerializer())
|
||||||
|
+ .register(IntOr.Default.SERIALIZER)
|
||||||
|
+ );
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public GlobalConfiguration initializeGlobalConfiguration() throws ConfigurateException {
|
||||||
|
+ GlobalConfiguration configuration = super.initializeGlobalConfiguration();
|
||||||
|
+ GlobalConfiguration.set(configuration);
|
||||||
|
+ return configuration;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ protected ObjectMapper.Factory.Builder createWorldObjectMapperFactoryBuilder(final ContextMap contextMap) {
|
||||||
|
+ return super.createWorldObjectMapperFactoryBuilder(contextMap)
|
||||||
|
+ .addNodeResolver(new NestedSetting.Factory())
|
||||||
|
+ .addDiscoverer(InnerClassFieldDiscoverer.worldConfig(createWorldConfigInstance(contextMap)));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private static WorldConfiguration createWorldConfigInstance(ContextMap contextMap) {
|
||||||
|
+ return new WorldConfiguration(
|
||||||
|
+ contextMap.require(Configurations.WORLD_KEY)
|
||||||
|
+ );
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ protected YamlConfigurationLoader.Builder createWorldConfigLoaderBuilder(final ContextMap contextMap) {
|
||||||
|
+ return super.createWorldConfigLoaderBuilder(contextMap)
|
||||||
|
+ .defaultOptions(options -> options
|
||||||
|
+ .header(contextMap.require(WORLD_NAME).equals(WORLD_DEFAULTS) ? WORLD_DEFAULTS_HEADER : WORLD_HEADER.apply(contextMap))
|
||||||
|
+ .serializers(serializers -> serializers
|
||||||
|
+ .register(new TypeToken<Reference2IntMap<?>>() {}, new FastutilMapSerializer.SomethingToPrimitive<Reference2IntMap<?>>(Reference2IntOpenHashMap::new, Integer.TYPE))
|
||||||
|
+ .register(new TypeToken<Reference2LongMap<?>>() {}, new FastutilMapSerializer.SomethingToPrimitive<Reference2LongMap<?>>(Reference2LongOpenHashMap::new, Long.TYPE))
|
||||||
|
+ .register(new TypeToken<Table<?, ?, ?>>() {}, new TableSerializer())
|
||||||
|
+ .register(StringRepresentableSerializer::isValidFor, new StringRepresentableSerializer())
|
||||||
|
+ .register(IntOr.Default.SERIALIZER)
|
||||||
|
+ .register(IntOr.Disabled.SERIALIZER)
|
||||||
|
+ .register(DoubleOr.Default.SERIALIZER)
|
||||||
|
+ .register(BooleanOrDefault.SERIALIZER)
|
||||||
|
+ .register(Duration.SERIALIZER)
|
||||||
|
+ .register(DurationOrDisabled.SERIALIZER)
|
||||||
|
+ .register(EngineMode.SERIALIZER)
|
||||||
|
+ .register(NbtPathSerializer.SERIALIZER)
|
||||||
|
+ .register(new RegistryValueSerializer<>(new TypeToken<EntityType<?>>() {}, Registries.ENTITY_TYPE, true))
|
||||||
|
+ .register(new RegistryValueSerializer<>(Item.class, Registries.ITEM, true))
|
||||||
|
+ .register(new RegistryHolderSerializer<>(new TypeToken<ConfiguredFeature<?, ?>>() {}, Registries.CONFIGURED_FEATURE, false))
|
||||||
|
+ .register(new RegistryHolderSerializer<>(Item.class, Registries.ITEM, true))
|
||||||
|
+ )
|
||||||
|
+ );
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public WorldConfiguration createWorldConfig(final ContextMap contextMap) {
|
||||||
|
+ final String levelName = contextMap.require(WORLD_NAME);
|
||||||
|
+ try {
|
||||||
|
+ return super.createWorldConfig(contextMap);
|
||||||
|
+ } catch (IOException exception) {
|
||||||
|
+ throw new RuntimeException("Could not create world config for " + levelName, exception);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ protected boolean isConfigType(final Type type) {
|
||||||
|
+ return ConfigurationPart.class.isAssignableFrom(erase(type));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void reloadConfigs(MinecraftServer server) {
|
||||||
|
+ try {
|
||||||
|
+ this.initializeGlobalConfiguration(reloader(this.globalConfigClass, GlobalConfiguration.get()));
|
||||||
|
+ this.initializeWorldDefaultsConfiguration();
|
||||||
|
+ for (ServerLevel level : server.getAllLevels()) {
|
||||||
|
+ this.createWorldConfig(createWorldContextMap(level), reloader(this.worldConfigClass, level.sakuraConfig()));
|
||||||
|
+ }
|
||||||
|
+ } catch (Exception ex) {
|
||||||
|
+ throw new RuntimeException("Could not reload paper configuration files", ex);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private static ContextMap createWorldContextMap(ServerLevel level) {
|
||||||
|
+ return createWorldContextMap(level.convertable.levelDirectory.path(), level.serverLevelData.getLevelName(), level.dimension().location());
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public static ContextMap createWorldContextMap(Path dir, String levelName, ResourceLocation worldKey) {
|
||||||
|
+ return ContextMap.builder()
|
||||||
|
+ .put(WORLD_DIRECTORY, dir)
|
||||||
|
+ .put(WORLD_NAME, levelName)
|
||||||
|
+ .put(WORLD_KEY, worldKey)
|
||||||
|
+ .build();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public static SakuraConfigurations setup(final Path configDir) {
|
||||||
|
+ try {
|
||||||
|
+ PaperConfigurations.createDirectoriesSymlinkAware(configDir);
|
||||||
|
+ return new SakuraConfigurations(configDir);
|
||||||
|
+ } catch (final IOException ex) {
|
||||||
|
+ throw new RuntimeException("Could not setup PaperConfigurations", ex);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/me/samsuik/sakura/configuration/WorldConfiguration.java b/src/main/java/me/samsuik/sakura/configuration/WorldConfiguration.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..c2617fb071a48f1b8b328b12041feda293e2824c
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/me/samsuik/sakura/configuration/WorldConfiguration.java
|
||||||
|
@@ -0,0 +1,63 @@
|
||||||
|
+package me.samsuik.sakura.configuration;
|
||||||
|
+
|
||||||
|
+import com.mojang.logging.LogUtils;
|
||||||
|
+import io.papermc.paper.configuration.Configuration;
|
||||||
|
+import io.papermc.paper.configuration.ConfigurationPart;
|
||||||
|
+import io.papermc.paper.configuration.PaperConfigurations;
|
||||||
|
+import me.samsuik.sakura.entity.merge.MergeLevel;
|
||||||
|
+import net.minecraft.resources.ResourceLocation;
|
||||||
|
+import org.slf4j.Logger;
|
||||||
|
+import org.spongepowered.configurate.objectmapping.meta.Setting;
|
||||||
|
+
|
||||||
|
+@SuppressWarnings({"FieldCanBeLocal", "FieldMayBeFinal", "NotNullFieldNotInitialized", "InnerClassMayBeStatic", "RedundantSuppression"})
|
||||||
|
+public class WorldConfiguration extends ConfigurationPart {
|
||||||
|
+
|
||||||
|
+ private static final Logger LOGGER = LogUtils.getClassLogger();
|
||||||
|
+ static final int CURRENT_VERSION = 1; // (when you change the version, change the comment, so it conflicts on rebases): rename filter bad nbt from spawn eggs
|
||||||
|
+
|
||||||
|
+ private transient final ResourceLocation worldKey;
|
||||||
|
+ WorldConfiguration(ResourceLocation worldKey) {
|
||||||
|
+ this.worldKey = worldKey;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public boolean isDefault() {
|
||||||
|
+ return this.worldKey.equals(PaperConfigurations.WORLD_DEFAULTS_KEY);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Setting(Configuration.VERSION_FIELD)
|
||||||
|
+ public int version = CURRENT_VERSION;
|
||||||
|
+
|
||||||
|
+ public Cannons cannons;
|
||||||
|
+ public class Cannons extends ConfigurationPart {
|
||||||
|
+ public MergeLevel mergeLevel = MergeLevel.STRICT;
|
||||||
|
+
|
||||||
|
+ public Tnt tnt = new Tnt();
|
||||||
|
+ public class Tnt extends ConfigurationPart {
|
||||||
|
+ public boolean loadsChunks;
|
||||||
|
+ public boolean forcePositionUpdates;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public Sand sand = new Sand();
|
||||||
|
+ public class Sand extends ConfigurationPart {
|
||||||
|
+ public boolean loadsChunks;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public Explosion explosion = new Explosion();
|
||||||
|
+ public class Explosion extends ConfigurationPart {
|
||||||
|
+ public boolean optimiseProtectedRegions = true;
|
||||||
|
+ public boolean avoidRedundantBlockSearches = true;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public Mechanics mechanics = new Mechanics();
|
||||||
|
+ public class Mechanics extends ConfigurationPart {
|
||||||
|
+ public TNTSpread tntSpread = TNTSpread.ALL;
|
||||||
|
+ public boolean tntFlowsInWater = true;
|
||||||
|
+ public boolean fallingBlockParity = false;
|
||||||
|
+
|
||||||
|
+ public enum TNTSpread {
|
||||||
|
+ ALL, Y, NONE;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/me/samsuik/sakura/configuration/mapping/InnerClassFieldDiscoverer.java b/src/main/java/me/samsuik/sakura/configuration/mapping/InnerClassFieldDiscoverer.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..96080117b5ac9dea6b9eeb7489dc0c87d2c5f8a1
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/me/samsuik/sakura/configuration/mapping/InnerClassFieldDiscoverer.java
|
||||||
|
@@ -0,0 +1,55 @@
|
||||||
|
+package me.samsuik.sakura.configuration.mapping;
|
||||||
|
+
|
||||||
|
+import io.papermc.paper.configuration.ConfigurationPart;
|
||||||
|
+import io.papermc.paper.configuration.mapping.InnerClassInstanceFactory;
|
||||||
|
+import io.papermc.paper.configuration.mapping.InnerClassInstanceSupplier;
|
||||||
|
+import me.samsuik.sakura.configuration.WorldConfiguration;
|
||||||
|
+import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
+import org.spongepowered.configurate.objectmapping.FieldDiscoverer;
|
||||||
|
+import org.spongepowered.configurate.serialize.SerializationException;
|
||||||
|
+
|
||||||
|
+import java.lang.reflect.AnnotatedType;
|
||||||
|
+import java.lang.reflect.Field;
|
||||||
|
+import java.util.Collections;
|
||||||
|
+import java.util.Map;
|
||||||
|
+
|
||||||
|
+import static io.leangen.geantyref.GenericTypeReflector.erase;
|
||||||
|
+
|
||||||
|
+public final class InnerClassFieldDiscoverer implements FieldDiscoverer<Map<Field, Object>> {
|
||||||
|
+
|
||||||
|
+ private final InnerClassInstanceSupplier instanceSupplier;
|
||||||
|
+ private final FieldDiscoverer<Map<Field, Object>> delegate;
|
||||||
|
+
|
||||||
|
+ @SuppressWarnings("unchecked")
|
||||||
|
+ public InnerClassFieldDiscoverer(final Map<Class<?>, Object> initialOverrides) {
|
||||||
|
+ this.instanceSupplier = new InnerClassInstanceSupplier(initialOverrides);
|
||||||
|
+ this.delegate = (FieldDiscoverer<Map<Field, Object>>) FieldDiscoverer.object(this.instanceSupplier);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public @Nullable <V> InstanceFactory<Map<Field, Object>> discover(final AnnotatedType target, final FieldCollector<Map<Field, Object>, V> collector) throws SerializationException {
|
||||||
|
+ final Class<?> clazz = erase(target.getType());
|
||||||
|
+ if (ConfigurationPart.class.isAssignableFrom(clazz)) {
|
||||||
|
+ final @Nullable InstanceFactory<Map<Field, Object>> instanceFactoryDelegate = this.delegate.<V>discover(target, (name, type, annotations, deserializer, serializer) -> {
|
||||||
|
+ if (!erase(type.getType()).equals(clazz.getEnclosingClass())) { // don't collect synth fields for inner classes
|
||||||
|
+ collector.accept(name, type, annotations, deserializer, serializer);
|
||||||
|
+ }
|
||||||
|
+ });
|
||||||
|
+ if (instanceFactoryDelegate instanceof MutableInstanceFactory<Map<Field, Object>> mutableInstanceFactoryDelegate) {
|
||||||
|
+ return new InnerClassInstanceFactory(this.instanceSupplier, mutableInstanceFactoryDelegate, target);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ return null;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public static FieldDiscoverer<?> worldConfig(WorldConfiguration worldConfiguration) {
|
||||||
|
+ final Map<Class<?>, Object> overrides = Map.of(
|
||||||
|
+ WorldConfiguration.class, worldConfiguration
|
||||||
|
+ );
|
||||||
|
+ return new InnerClassFieldDiscoverer(overrides);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public static FieldDiscoverer<?> globalConfig() {
|
||||||
|
+ return new InnerClassFieldDiscoverer(Collections.emptyMap());
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/me/samsuik/sakura/utils/VariousHelpers.java b/src/main/java/me/samsuik/sakura/utils/VariousHelpers.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..141b15887ca075fef5d36ff15125b3e071049917
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/me/samsuik/sakura/utils/VariousHelpers.java
|
||||||
|
@@ -0,0 +1,61 @@
|
||||||
|
+package me.samsuik.sakura.utils;
|
||||||
|
+
|
||||||
|
+import net.minecraft.core.Registry;
|
||||||
|
+import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
|
+import net.minecraft.world.entity.EntityType;
|
||||||
|
+
|
||||||
|
+import java.util.List;
|
||||||
|
+import java.util.regex.Pattern;
|
||||||
|
+import org.apache.commons.lang.StringUtils;
|
||||||
|
+
|
||||||
|
+public class VariousHelpers {
|
||||||
|
+
|
||||||
|
+ public static List<EntityType<?>> getEntityTypes(String from) {
|
||||||
|
+ Pattern pattern = VariousHelpers.wildcardPattern(from);
|
||||||
|
+
|
||||||
|
+ return BuiltInRegistries.ENTITY_TYPE.stream()
|
||||||
|
+ .filter((type) -> pattern.matcher(type.getDescriptionId()).find()
|
||||||
|
+ || pattern.matcher(type.getCategory().getName()).find())
|
||||||
|
+ .toList();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public static Pattern wildcardPattern(String string) {
|
||||||
|
+ String included = string.replaceAll("\\*{2}", ".*?");
|
||||||
|
+ return Pattern.compile("^(%s)$".formatted(included));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public static String capitalise(String string) {
|
||||||
|
+ StringBuilder builder = new StringBuilder(string.length());
|
||||||
|
+ boolean capitalise = true;
|
||||||
|
+
|
||||||
|
+ for (char character : string.toCharArray()) {
|
||||||
|
+ if (!Character.isAlphabetic(character)) {
|
||||||
|
+ capitalise = true;
|
||||||
|
+ } else if (capitalise) {
|
||||||
|
+ character = Character.toUpperCase(character);
|
||||||
|
+ capitalise = false;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ builder.append(character);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return builder.toString();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public static int sequential(String of, String provided) {
|
||||||
|
+ for (int i = 0; i < of.length() && i < provided.length(); ++i) {
|
||||||
|
+ if (provided.charAt(i) != of.charAt(i)) {
|
||||||
|
+ return i;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return Math.min(of.length(), provided.length());
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public static double similarity(String a, String b) {
|
||||||
|
+ double distance = StringUtils.getLevenshteinDistance(a, b);
|
||||||
|
+ int highest = Math.max(a.length(), b.length());
|
||||||
|
+ return 1 - (distance / highest);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
index 188da766381393afe643de28dccaa6aa7c9130a0..2a3af1a071766c30567cdf1681059cdce967afff 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
@@ -300,6 +300,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||||
|
public final double[] recentTps = new double[ 3 ];
|
||||||
|
// Spigot end
|
||||||
|
public final io.papermc.paper.configuration.PaperConfigurations paperConfigurations;
|
||||||
|
+ public final me.samsuik.sakura.configuration.SakuraConfigurations sakuraConfigurations; // Sakura - missing paper comment above D:
|
||||||
|
public static long currentTickLong = 0L; // Paper
|
||||||
|
|
||||||
|
public volatile Thread shutdownThread; // Paper
|
||||||
|
@@ -405,6 +406,10 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||||
|
Runtime.getRuntime().addShutdownHook(new org.bukkit.craftbukkit.util.ServerShutdownThread(this));
|
||||||
|
// CraftBukkit end
|
||||||
|
this.paperConfigurations = services.paperConfigurations(); // Paper
|
||||||
|
+ // Sakura start
|
||||||
|
+ final var sakuraConfigDirPath = ((File) options.valueOf("sakura-settings-directory")).toPath();
|
||||||
|
+ this.sakuraConfigurations = me.samsuik.sakura.configuration.SakuraConfigurations.setup(sakuraConfigDirPath);
|
||||||
|
+ // Sakura end
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readScoreboard(DimensionDataStorage persistentStateManager) {
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||||
|
index dbccbcb9b44e4efacdf53c2d161115cc20b36cff..8409735fd5d9f78a71d8741c45a58c9d5ed9ead3 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||||
|
@@ -221,6 +221,11 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||||
|
com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // load version history now
|
||||||
|
io.papermc.paper.brigadier.PaperBrigadierProviderImpl.INSTANCE.getClass(); // init PaperBrigadierProvider
|
||||||
|
// Paper end
|
||||||
|
+ // Sakura start
|
||||||
|
+ sakuraConfigurations.initializeGlobalConfiguration();
|
||||||
|
+ sakuraConfigurations.initializeWorldDefaultsConfiguration();
|
||||||
|
+ me.samsuik.sakura.command.SakuraCommands.registerCommands(this);
|
||||||
|
+ // Sakura end
|
||||||
|
|
||||||
|
this.setPvpAllowed(dedicatedserverproperties.pvp);
|
||||||
|
this.setFlightAllowed(dedicatedserverproperties.allowFlight);
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
index 51d282b524b5249438f7744f7f0b1cc27b76470e..80c571f73057cfeb39e550aeabd4647f323de9c1 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
@@ -691,7 +691,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||||
|
// Holder holder = worlddimension.type(); // CraftBukkit - decompile error
|
||||||
|
|
||||||
|
// Objects.requireNonNull(minecraftserver); // CraftBukkit - decompile error
|
||||||
|
- super(iworlddataserver, resourcekey, minecraftserver.registryAccess(), worlddimension.type(), minecraftserver::getProfiler, false, flag, i, minecraftserver.getMaxChainedNeighborUpdates(), gen, biomeProvider, env, spigotConfig -> minecraftserver.paperConfigurations.createWorldConfig(io.papermc.paper.configuration.PaperConfigurations.createWorldContextMap(convertable_conversionsession.levelDirectory.path(), iworlddataserver.getLevelName(), resourcekey.location(), spigotConfig)), executor); // Paper - Async-Anti-Xray - Pass executor
|
||||||
|
+ super(iworlddataserver, resourcekey, minecraftserver.registryAccess(), worlddimension.type(), minecraftserver::getProfiler, false, flag, i, minecraftserver.getMaxChainedNeighborUpdates(), gen, biomeProvider, env, spigotConfig -> minecraftserver.paperConfigurations.createWorldConfig(io.papermc.paper.configuration.PaperConfigurations.createWorldContextMap(convertable_conversionsession.levelDirectory.path(), iworlddataserver.getLevelName(), resourcekey.location(), spigotConfig)), () -> minecraftserver.sakuraConfigurations.createWorldConfig(me.samsuik.sakura.configuration.SakuraConfigurations.createWorldContextMap(convertable_conversionsession.levelDirectory.path(), iworlddataserver.getLevelName(), resourcekey.location())), executor); // Sakura // Paper - Async-Anti-Xray - Pass executor
|
||||||
|
this.pvpMode = minecraftserver.isPvpAllowed();
|
||||||
|
this.convertable = convertable_conversionsession;
|
||||||
|
this.uuid = WorldUUID.getUUID(convertable_conversionsession.levelDirectory.path().toFile());
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
index ea8a0961190e9aafda4fed6fecd85097c141040a..8006ec1eece1e1c5c0b18bc2b5190bbb43e9d4c3 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
@@ -174,6 +174,12 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||||
|
return this.paperConfig;
|
||||||
|
}
|
||||||
|
// Paper end
|
||||||
|
+ // Sakura start
|
||||||
|
+ private final me.samsuik.sakura.configuration.WorldConfiguration sakuraConfig;
|
||||||
|
+ public me.samsuik.sakura.configuration.WorldConfiguration sakuraConfig() {
|
||||||
|
+ return this.sakuraConfig;
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
|
||||||
|
public final com.destroystokyo.paper.antixray.ChunkPacketBlockController chunkPacketBlockController; // Paper - Anti-Xray
|
||||||
|
public final co.aikar.timings.WorldTimingsHandler timings; // Paper
|
||||||
|
@@ -210,9 +216,10 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||||
|
|
||||||
|
public abstract ResourceKey<LevelStem> getTypeKey();
|
||||||
|
|
||||||
|
- protected Level(WritableLevelData worlddatamutable, ResourceKey<Level> resourcekey, RegistryAccess iregistrycustom, Holder<DimensionType> holder, Supplier<ProfilerFiller> supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function<org.spigotmc.SpigotWorldConfig, io.papermc.paper.configuration.WorldConfiguration> paperWorldConfigCreator, java.util.concurrent.Executor executor) { // Paper - Async-Anti-Xray - Pass executor
|
||||||
|
+ protected Level(WritableLevelData worlddatamutable, ResourceKey<Level> resourcekey, RegistryAccess iregistrycustom, Holder<DimensionType> holder, Supplier<ProfilerFiller> supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function<org.spigotmc.SpigotWorldConfig, io.papermc.paper.configuration.WorldConfiguration> paperWorldConfigCreator, Supplier<me.samsuik.sakura.configuration.WorldConfiguration> sakuraWorldConfigCreator, java.util.concurrent.Executor executor) { // Sakura // Paper - Async-Anti-Xray - Pass executor
|
||||||
|
this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot
|
||||||
|
this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper
|
||||||
|
+ this.sakuraConfig = sakuraWorldConfigCreator.get(); // Sakura
|
||||||
|
this.generator = gen;
|
||||||
|
this.world = new CraftWorld((ServerLevel) this, gen, biomeProvider, env);
|
||||||
|
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
index 28a1e39ed1b7fd10f4c01e076258cb8689b4e5bf..feacca7ca9838a3811d09c617fa609fdef1e6da7 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
@@ -1039,6 +1039,7 @@ public final class CraftServer implements Server {
|
||||||
|
|
||||||
|
org.spigotmc.SpigotConfig.init((File) console.options.valueOf("spigot-settings")); // Spigot
|
||||||
|
this.console.paperConfigurations.reloadConfigs(this.console);
|
||||||
|
+ this.console.sakuraConfigurations.reloadConfigs(this.console); // Sakura - missing comment above
|
||||||
|
for (ServerLevel world : this.console.getAllLevels()) {
|
||||||
|
// world.serverLevelData.setDifficulty(config.difficulty); // Paper - per level difficulty
|
||||||
|
world.setSpawnSettings(world.serverLevelData.getDifficulty() != Difficulty.PEACEFUL && config.spawnMonsters, config.spawnAnimals); // Paper - per level difficulty (from MinecraftServer#setDifficulty(ServerLevel, Difficulty, boolean))
|
||||||
|
@@ -1069,6 +1070,7 @@ public final class CraftServer implements Server {
|
||||||
|
this.reloadData();
|
||||||
|
org.spigotmc.SpigotConfig.registerCommands(); // Spigot
|
||||||
|
io.papermc.paper.command.PaperCommands.registerCommands(this.console); // Paper
|
||||||
|
+ me.samsuik.sakura.command.SakuraCommands.registerCommands(this.console); // Sakura
|
||||||
|
this.overrideAllCommandBlockCommands = this.commandsConfiguration.getStringList("command-block-overrides").contains("*");
|
||||||
|
this.ignoreVanillaPermissions = this.commandsConfiguration.getBoolean("ignore-vanilla-permissions");
|
||||||
|
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||||
|
index e4cacb17f56c618bef19e1165c07aac86af61150..2c327be8efba101bb76482967a7171d01ecce4bc 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||||
|
@@ -173,6 +173,14 @@ public class Main {
|
||||||
|
.describedAs("Jar file");
|
||||||
|
// Paper end
|
||||||
|
|
||||||
|
+ // Sakura start
|
||||||
|
+ acceptsAll(asList("sakura-dir", "sakura-settings-directory"), "Directory for Sakura settings")
|
||||||
|
+ .withRequiredArg()
|
||||||
|
+ .ofType(File.class)
|
||||||
|
+ .defaultsTo(new File(me.samsuik.sakura.configuration.SakuraConfigurations.CONFIG_DIR))
|
||||||
|
+ .describedAs("Config directory");
|
||||||
|
+ // Sakura end
|
||||||
|
+
|
||||||
|
// Paper start
|
||||||
|
acceptsAll(asList("server-name"), "Name of the server")
|
||||||
|
.withRequiredArg()
|
||||||
619
patches/server/0005-Visibility-API-and-Command.patch
Normal file
619
patches/server/0005-Visibility-API-and-Command.patch
Normal file
@@ -0,0 +1,619 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Samsuik <kfian294ma4@gmail.com>
|
||||||
|
Date: Tue, 21 Sep 2021 23:54:25 +0100
|
||||||
|
Subject: [PATCH] Visibility API and Command
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/me/samsuik/sakura/command/SakuraCommands.java b/src/main/java/me/samsuik/sakura/command/SakuraCommands.java
|
||||||
|
index c2651cac1dcf85fb67fe981b97efee4e56431de2..d7d0c49cc5d576c594dee16ddba037cd147e11fa 100644
|
||||||
|
--- a/src/main/java/me/samsuik/sakura/command/SakuraCommands.java
|
||||||
|
+++ b/src/main/java/me/samsuik/sakura/command/SakuraCommands.java
|
||||||
|
@@ -2,6 +2,9 @@ package me.samsuik.sakura.command;
|
||||||
|
|
||||||
|
import io.papermc.paper.command.PaperPluginsCommand;
|
||||||
|
import me.samsuik.sakura.command.subcommands.ConfigCommand;
|
||||||
|
+import me.samsuik.sakura.command.subcommands.FPSCommand;
|
||||||
|
+import me.samsuik.sakura.command.subcommands.VisualCommand;
|
||||||
|
+import me.samsuik.sakura.player.visibility.Visibility;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
|
||||||
|
@@ -14,6 +17,10 @@ public class SakuraCommands {
|
||||||
|
static {
|
||||||
|
COMMANDS.put("sakura", new SakuraCommand("sakura"));
|
||||||
|
COMMANDS.put("config", new ConfigCommand("config"));
|
||||||
|
+ COMMANDS.put("fps", new FPSCommand("fps"));
|
||||||
|
+ COMMANDS.put("tntvisibility", new VisualCommand(Visibility.Setting.TNT_VISIBILITY, "tnttoggle"));
|
||||||
|
+ COMMANDS.put("sandvisibility", new VisualCommand(Visibility.Setting.SAND_VISIBILITY, "sandtoggle"));
|
||||||
|
+ COMMANDS.put("minimal", new VisualCommand(Visibility.Setting.MINIMAL, "minimaltnt", "tntlag"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void registerCommands(final MinecraftServer server) {
|
||||||
|
diff --git a/src/main/java/me/samsuik/sakura/command/subcommands/FPSCommand.java b/src/main/java/me/samsuik/sakura/command/subcommands/FPSCommand.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..23a12e9a8697a39951f9e8d841a119c14e06e02e
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/me/samsuik/sakura/command/subcommands/FPSCommand.java
|
||||||
|
@@ -0,0 +1,26 @@
|
||||||
|
+package me.samsuik.sakura.command.subcommands;
|
||||||
|
+
|
||||||
|
+import me.samsuik.sakura.command.BaseSubCommand;
|
||||||
|
+import me.samsuik.sakura.player.visibility.ui.VisibilityGUI;
|
||||||
|
+import org.bukkit.command.CommandSender;
|
||||||
|
+import org.bukkit.entity.Player;
|
||||||
|
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||||
|
+
|
||||||
|
+@DefaultQualifier(NonNull.class)
|
||||||
|
+public class FPSCommand extends BaseSubCommand {
|
||||||
|
+
|
||||||
|
+ private final VisibilityGUI VISIBILITY_GUI = new VisibilityGUI();
|
||||||
|
+
|
||||||
|
+ public FPSCommand(String name) {
|
||||||
|
+ super(name);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void execute(CommandSender sender, String[] args) {
|
||||||
|
+ if (sender instanceof Player player) {
|
||||||
|
+ VISIBILITY_GUI.showTo(player);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/me/samsuik/sakura/command/subcommands/VisualCommand.java b/src/main/java/me/samsuik/sakura/command/subcommands/VisualCommand.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..6027e4741e2de7c6d3bd7b094c196a212e34e2f5
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/me/samsuik/sakura/command/subcommands/VisualCommand.java
|
||||||
|
@@ -0,0 +1,45 @@
|
||||||
|
+package me.samsuik.sakura.command.subcommands;
|
||||||
|
+
|
||||||
|
+import me.samsuik.sakura.command.BaseSubCommand;
|
||||||
|
+import me.samsuik.sakura.configuration.GlobalConfiguration;
|
||||||
|
+import me.samsuik.sakura.player.visibility.Visibility;
|
||||||
|
+import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||||
|
+import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
|
||||||
|
+import org.bukkit.command.CommandSender;
|
||||||
|
+import org.bukkit.entity.Player;
|
||||||
|
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
+import org.checkerframework.framework.qual.DefaultQualifier;
|
||||||
|
+
|
||||||
|
+import java.util.Arrays;
|
||||||
|
+
|
||||||
|
+@DefaultQualifier(NonNull.class)
|
||||||
|
+public class VisualCommand extends BaseSubCommand {
|
||||||
|
+
|
||||||
|
+ private final Visibility.Setting type;
|
||||||
|
+
|
||||||
|
+ public VisualCommand(Visibility.Setting type, String... aliases) {
|
||||||
|
+ super(type.basicName());
|
||||||
|
+ this.setAliases(Arrays.asList(aliases));
|
||||||
|
+ this.type = type;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void execute(CommandSender sender, String[] args) {
|
||||||
|
+ if (!(sender instanceof Player player)) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ var visibility = player.getVisibility();
|
||||||
|
+
|
||||||
|
+ // Toggle clicked setting visibility
|
||||||
|
+ visibility.toggle(type);
|
||||||
|
+
|
||||||
|
+ // Send message to player
|
||||||
|
+ var state = visibility.isEnabled(type) ? "Enabled" : "Disabled";
|
||||||
|
+ player.sendMessage(MiniMessage.miniMessage().deserialize(GlobalConfiguration.get().fps.message,
|
||||||
|
+ Placeholder.unparsed("name", type.friendlyName()),
|
||||||
|
+ Placeholder.unparsed("state", state))
|
||||||
|
+ );
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/me/samsuik/sakura/player/visibility/ui/VisibilityGUI.java b/src/main/java/me/samsuik/sakura/player/visibility/ui/VisibilityGUI.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..725dd617641f7344d18d100dfa487430080e1d93
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/me/samsuik/sakura/player/visibility/ui/VisibilityGUI.java
|
||||||
|
@@ -0,0 +1,108 @@
|
||||||
|
+package me.samsuik.sakura.player.visibility.ui;
|
||||||
|
+
|
||||||
|
+import me.samsuik.sakura.configuration.GlobalConfiguration;
|
||||||
|
+import me.samsuik.sakura.player.gui.ItemIcon;
|
||||||
|
+import me.samsuik.sakura.player.gui.PlayerGUI;
|
||||||
|
+import me.samsuik.sakura.player.visibility.Visibility;
|
||||||
|
+import net.kyori.adventure.text.Component;
|
||||||
|
+import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
+import net.kyori.adventure.text.format.TextColor;
|
||||||
|
+import net.kyori.adventure.text.format.TextDecoration;
|
||||||
|
+import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||||
|
+import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
|
||||||
|
+import org.bukkit.Bukkit;
|
||||||
|
+import org.bukkit.Material;
|
||||||
|
+import org.bukkit.entity.Player;
|
||||||
|
+import org.bukkit.inventory.Inventory;
|
||||||
|
+import org.bukkit.inventory.ItemStack;
|
||||||
|
+
|
||||||
|
+import java.util.function.BiFunction;
|
||||||
|
+
|
||||||
|
+public class VisibilityGUI extends PlayerGUI {
|
||||||
|
+
|
||||||
|
+ private static final BiFunction<Player, Holder, Inventory> CREATE_INVENTORY = (player, holder) -> {
|
||||||
|
+ var inventory = Bukkit.createInventory(holder, 45, Component.text("FPS GUI"));
|
||||||
|
+
|
||||||
|
+ for (var i = 0; i < inventory.getSize(); ++i) {
|
||||||
|
+ var column = i % 9;
|
||||||
|
+ var row = (i + 1) / 9;
|
||||||
|
+
|
||||||
|
+ var background = column > 0 && column < 8 ? (row > 0 && row < 4 || column > 1 && column < 7)
|
||||||
|
+ ? Material.matchMaterial(GlobalConfiguration.get().fps.material)
|
||||||
|
+ : Material.WHITE_STAINED_GLASS_PANE
|
||||||
|
+ : Material.BLACK_STAINED_GLASS_PANE;
|
||||||
|
+
|
||||||
|
+ var itemstack = new ItemStack(background);
|
||||||
|
+ var meta = itemstack.getItemMeta();
|
||||||
|
+ meta.displayName(Component.space());
|
||||||
|
+ itemstack.setItemMeta(meta);
|
||||||
|
+
|
||||||
|
+ inventory.setItem(i, itemstack);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return inventory;
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
+ public VisibilityGUI() {
|
||||||
|
+ super(CREATE_INVENTORY);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ protected void register() {
|
||||||
|
+ registerFPSIcon(Visibility.Setting.TNT_VISIBILITY, Material.TNT, NamedTextColor.RED, 12);
|
||||||
|
+ registerFPSIcon(Visibility.Setting.SAND_VISIBILITY, Material.SAND, NamedTextColor.YELLOW, 14);
|
||||||
|
+ registerFPSIcon(Visibility.Setting.MINIMAL, Material.NETHER_BRICK_SLAB, NamedTextColor.GOLD, 13);
|
||||||
|
+ registerFPSIcon(Visibility.Setting.SPAWNERS, Material.SPAWNER, NamedTextColor.DARK_GRAY, 20);
|
||||||
|
+ registerFPSIcon(Visibility.Setting.FLASHING_TNT, Material.REDSTONE_LAMP, NamedTextColor.RED, 22);
|
||||||
|
+ registerFPSIcon(Visibility.Setting.EXPLOSIONS, Material.COBWEB, NamedTextColor.WHITE, 24);
|
||||||
|
+ registerFPSIcon(Visibility.Setting.PISTONS, Material.PISTON, NamedTextColor.GOLD, 30);
|
||||||
|
+ registerFPSIcon(Visibility.Setting.REDSTONE, Material.REDSTONE, NamedTextColor.DARK_RED, 31);
|
||||||
|
+ registerFPSIcon(Visibility.Setting.ENCHANTMENT_GLINT, Material.ENCHANTED_BOOK, NamedTextColor.DARK_PURPLE, 32);
|
||||||
|
+
|
||||||
|
+ registerIcon(new ItemIcon(
|
||||||
|
+ (player) -> new ItemStack(Material.EMERALD_BLOCK),
|
||||||
|
+ (player) -> player.getVisibility().toggleAll(),
|
||||||
|
+ 26
|
||||||
|
+ ));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private void registerFPSIcon(Visibility.Setting setting, Material material, TextColor colour, int slot) {
|
||||||
|
+ registerIcon(new ItemIcon((player) -> {
|
||||||
|
+ var visibility = player.getVisibility();
|
||||||
|
+
|
||||||
|
+ // Get the current state as a string
|
||||||
|
+ var state = visibility.isEnabled(setting)
|
||||||
|
+ ? "Enabled" : "Disabled";
|
||||||
|
+
|
||||||
|
+ // Friendly name as a component
|
||||||
|
+ var title = Component.text(setting.friendlyName()).color(colour);
|
||||||
|
+ var itemstack = new ItemStack(material);
|
||||||
|
+ var meta = itemstack.getItemMeta();
|
||||||
|
+
|
||||||
|
+ // Display names are italic by default
|
||||||
|
+ title = title.decoration(TextDecoration.ITALIC, false);
|
||||||
|
+
|
||||||
|
+ // Set the display name
|
||||||
|
+ meta.displayName(title.append(Component.space())
|
||||||
|
+ .append(Component.text(state).color(NamedTextColor.GRAY)));
|
||||||
|
+
|
||||||
|
+ itemstack.setItemMeta(meta);
|
||||||
|
+ return itemstack;
|
||||||
|
+ }, (player) -> {
|
||||||
|
+ var visibility = player.getVisibility();
|
||||||
|
+
|
||||||
|
+ // Toggle clicked setting visibility
|
||||||
|
+ visibility.toggle(setting);
|
||||||
|
+
|
||||||
|
+ // Send message to player
|
||||||
|
+ var state = visibility.isEnabled(setting) ? "Enabled" : "Disabled";
|
||||||
|
+ player.sendMessage(MiniMessage.miniMessage().deserialize(GlobalConfiguration.get().fps.message,
|
||||||
|
+ Placeholder.unparsed("name", setting.friendlyName()),
|
||||||
|
+ Placeholder.unparsed("state", state))
|
||||||
|
+ );
|
||||||
|
+ },
|
||||||
|
+ slot
|
||||||
|
+ ));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java
|
||||||
|
index e3f355c85eb7cc8c1683e3009502c10a5ed32daa..349e56d5caad3fc38e83eac6ffff83e2fb30eaa7 100644
|
||||||
|
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java
|
||||||
|
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java
|
||||||
|
@@ -16,7 +16,7 @@ public class ClientboundSectionBlocksUpdatePacket implements Packet<ClientGamePa
|
||||||
|
private static final int POS_IN_SECTION_BITS = 12;
|
||||||
|
private final SectionPos sectionPos;
|
||||||
|
private final short[] positions;
|
||||||
|
- private final BlockState[] states;
|
||||||
|
+ public final BlockState[] states; // Sakura - private -> public
|
||||||
|
|
||||||
|
public ClientboundSectionBlocksUpdatePacket(SectionPos sectionPos, ShortSet positions, LevelChunkSection section) {
|
||||||
|
this.sectionPos = sectionPos;
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
index 2a3af1a071766c30567cdf1681059cdce967afff..4535beab09310915b0239b01c1b807f1ca25d959 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
@@ -1575,6 +1575,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||||
|
this.profiler.pop();
|
||||||
|
this.profiler.pop();
|
||||||
|
worldserver.explosionDensityCache.clear(); // Paper - Optimize explosions
|
||||||
|
+ worldserver.minimalTNT.clear(); // Sakura - visibility api
|
||||||
|
}
|
||||||
|
this.isIteratingOverLevels = false; // Paper
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||||
|
index 0c2617574e21037d94ac56ad08b490f9bca5c5af..45f0e7ef92c32dc51b81c0cc9f1d1a2fbab02599 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||||
|
@@ -1301,6 +1301,22 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||||
|
}
|
||||||
|
// Paper end - check Y
|
||||||
|
|
||||||
|
+ // Sakura start - visibility api
|
||||||
|
+ if (this.entity.isPrimedTNT && player.visibility.isToggled(me.samsuik.sakura.player.visibility.Visibility.Setting.TNT_VISIBILITY)
|
||||||
|
+ || this.entity.isFallingBlock && player.visibility.isToggled(me.samsuik.sakura.player.visibility.Visibility.Setting.SAND_VISIBILITY)) {
|
||||||
|
+ flag = false;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (flag && (this.entity.isPrimedTNT || this.entity.isFallingBlock) && player.visibility.isToggled(me.samsuik.sakura.player.visibility.Visibility.Setting.MINIMAL)) {
|
||||||
|
+ long key = entity.blockPosition().asLong();
|
||||||
|
+
|
||||||
|
+ if (level.minimalTNT.containsKey(key)) {
|
||||||
|
+ flag = level.minimalTNT.get(key) == entity.getId();
|
||||||
|
+ } else {
|
||||||
|
+ level.minimalTNT.put(key, entity.getId());
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
// CraftBukkit start - respect vanish API
|
||||||
|
if (!player.getBukkitEntity().canSee(this.entity.getBukkitEntity())) {
|
||||||
|
flag = false;
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||||
|
index 35674f92a67f93382103c2766df4b678ba5c862f..83c4639c2bdca4dc4281d9f5eca104af3063bfa5 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||||
|
@@ -47,6 +47,13 @@ import net.minecraft.util.Mth;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.player.PlayerVelocityEvent;
|
||||||
|
// CraftBukkit end
|
||||||
|
+// Sakura start
|
||||||
|
+import me.samsuik.sakura.player.visibility.Visibility;
|
||||||
|
+import net.minecraft.network.protocol.game.ClientboundAddEntityPacket;
|
||||||
|
+import net.minecraft.world.entity.EntityType;
|
||||||
|
+import net.minecraft.world.level.block.Block;
|
||||||
|
+import net.minecraft.world.level.block.Blocks;
|
||||||
|
+// Sakura end
|
||||||
|
|
||||||
|
public class ServerEntity {
|
||||||
|
|
||||||
|
@@ -284,6 +291,18 @@ public class ServerEntity {
|
||||||
|
this.entity.startSeenByPlayer(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Sakura start - visibility api
|
||||||
|
+ protected Packet<ClientGamePacketListener> createEntityPacket(Entity entity, ServerPlayer entityplayer) {
|
||||||
|
+ if (entity.isPrimedTNT && entityplayer.visibility.isToggled(Visibility.Setting.FLASHING_TNT)) {
|
||||||
|
+ return new ClientboundAddEntityPacket(entity.getId(), entity.getUUID(),
|
||||||
|
+ entity.getX(), entity.getY(), entity.getZ(), 0, 0, EntityType.FALLING_BLOCK,
|
||||||
|
+ Block.getId(Blocks.TNT.defaultBlockState()), entity.getDeltaMovement(), entity.getYHeadRot());
|
||||||
|
+ } else {
|
||||||
|
+ return entity.getAddEntityPacket();
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
+
|
||||||
|
public void sendPairingData(ServerPlayer player, Consumer<Packet<ClientGamePacketListener>> sender) {
|
||||||
|
if (this.entity.isRemoved()) {
|
||||||
|
// CraftBukkit start - Remove useless error spam, just return
|
||||||
|
@@ -292,12 +311,19 @@ public class ServerEntity {
|
||||||
|
// CraftBukkit end
|
||||||
|
}
|
||||||
|
|
||||||
|
- Packet<ClientGamePacketListener> packet = this.entity.getAddEntityPacket();
|
||||||
|
+ Packet<ClientGamePacketListener> packet = this.createEntityPacket(this.entity, player); // Sakura - visibility api
|
||||||
|
|
||||||
|
this.yHeadRotp = Mth.floor(this.entity.getYHeadRot() * 256.0F / 360.0F);
|
||||||
|
sender.accept(packet);
|
||||||
|
if (this.trackedDataValues != null) {
|
||||||
|
- sender.accept(new ClientboundSetEntityDataPacket(this.entity.getId(), this.trackedDataValues));
|
||||||
|
+ // Sakura start - visibility api
|
||||||
|
+ if (this.entity.isPrimedTNT && player.visibility.isToggled(Visibility.Setting.FLASHING_TNT)) {
|
||||||
|
+ // Could modifying this break something elsewhere?
|
||||||
|
+ trackedDataValues.removeIf((data) -> data.id() == 8);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ sender.accept(new ClientboundSetEntityDataPacket(this.entity.getId(), trackedDataValues));
|
||||||
|
+ // Sakura end
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean flag = this.trackDelta;
|
||||||
|
@@ -367,6 +393,32 @@ public class ServerEntity {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ // Sakura start - visibility api
|
||||||
|
+ private void broadcastEntityData(List<SynchedEntityData.DataValue<?>> packedValues) {
|
||||||
|
+ Packet<?> packet0 = new ClientboundSetEntityDataPacket(this.entity.getId(), packedValues);
|
||||||
|
+ Packet<?> packet1 = null;
|
||||||
|
+
|
||||||
|
+ if (this.entity.isPrimedTNT) {
|
||||||
|
+ var copyOfDirtyItems = Lists.newArrayList(packedValues);
|
||||||
|
+ copyOfDirtyItems.removeIf((data) -> data.id() == 8);
|
||||||
|
+
|
||||||
|
+ if (!copyOfDirtyItems.isEmpty()) {
|
||||||
|
+ packet1 = new ClientboundSetEntityDataPacket(this.entity.getId(), copyOfDirtyItems);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ for (var connection : trackedPlayers) {
|
||||||
|
+ var player = connection.getPlayer();
|
||||||
|
+
|
||||||
|
+ if (!this.entity.isPrimedTNT || !player.visibility.isToggled(Visibility.Setting.FLASHING_TNT)) {
|
||||||
|
+ connection.send(packet0);
|
||||||
|
+ } else if (packet1 != null) {
|
||||||
|
+ connection.send(packet1);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
|
||||||
|
private void sendDirtyEntityData() {
|
||||||
|
SynchedEntityData datawatcher = this.entity.getEntityData();
|
||||||
|
@@ -374,7 +426,7 @@ public class ServerEntity {
|
||||||
|
|
||||||
|
if (list != null) {
|
||||||
|
this.trackedDataValues = datawatcher.getNonDefaultValues();
|
||||||
|
- this.broadcastAndSend(new ClientboundSetEntityDataPacket(this.entity.getId(), list));
|
||||||
|
+ this.broadcastEntityData(list); // Sakura - visibility api
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.entity instanceof LivingEntity) {
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
index 80c571f73057cfeb39e550aeabd4647f323de9c1..a9cd388c7ebb377511f59398b8f31a04d7abe493 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
@@ -1931,7 +1931,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
ServerPlayer entityplayer = (ServerPlayer) iterator.next();
|
||||||
|
|
||||||
|
- if (entityplayer.distanceToSqr(x, y, z) < 4096.0D) {
|
||||||
|
+ if (entityplayer.distanceToSqr(x, y, z) < 4096.0D && !entityplayer.visibility.isToggled(me.samsuik.sakura.player.visibility.Visibility.Setting.EXPLOSIONS)) { // Sakura - visibility api
|
||||||
|
entityplayer.connection.send(new ClientboundExplodePacket(x, y, z, power, explosion.getToBlow(), (Vec3) explosion.getHitPlayers().get(entityplayer)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||||
|
index d4aec99cac3f83d764e21946cc904c00e084704e..eef39746b355d72376651c3a6ba2f8101849141a 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||||
|
@@ -254,6 +254,7 @@ public class ServerPlayer extends Player {
|
||||||
|
public final int[] mobCounts = new int[MOBCATEGORY_TOTAL_ENUMS]; // Paper
|
||||||
|
// Paper end - mob spawning rework
|
||||||
|
public final int[] mobBackoffCounts = new int[MOBCATEGORY_TOTAL_ENUMS]; // Paper - per player mob count backoff
|
||||||
|
+ public final me.samsuik.sakura.player.visibility.Visibility visibility = new me.samsuik.sakura.player.visibility.Visibility(); // Sakura - visiblity api
|
||||||
|
|
||||||
|
// CraftBukkit start
|
||||||
|
public String displayName;
|
||||||
|
@@ -559,6 +560,15 @@ public class ServerPlayer extends Player {
|
||||||
|
this.respawnDimension = (ResourceKey) dataresult1.resultOrPartial(logger1::error).orElse(Level.OVERWORLD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+ // Sakura start - visibility api
|
||||||
|
+ CompoundTag tag = nbt.getCompound("Sakura.Visuals");
|
||||||
|
+
|
||||||
|
+ for (me.samsuik.sakura.player.visibility.Visibility.Setting setting : me.samsuik.sakura.player.visibility.Visibility.Setting.values()) {
|
||||||
|
+ if (tag.getBoolean(setting.name())) {
|
||||||
|
+ visibility.toggle(setting);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -625,6 +635,13 @@ public class ServerPlayer extends Player {
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.getBukkitEntity().setExtraData(nbt); // CraftBukkit
|
||||||
|
+ // Sakura start - visibility api
|
||||||
|
+ CompoundTag tag = new CompoundTag();
|
||||||
|
+ for (me.samsuik.sakura.player.visibility.Visibility.Setting setting : me.samsuik.sakura.player.visibility.Visibility.Setting.values()) {
|
||||||
|
+ tag.putBoolean(setting.name(), visibility.isToggled(setting));
|
||||||
|
+ }
|
||||||
|
+ nbt.put("Sakura.Visuals", tag);
|
||||||
|
+ // Sakura end
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
|
||||||
|
index 231150bac0ae61e9722c2cdfd70d6f7d254681e4..a091a2c7cb755607f7be30eec4844b0571e8b7f8 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
|
||||||
|
@@ -40,6 +40,23 @@ import org.bukkit.craftbukkit.util.Waitable;
|
||||||
|
import org.bukkit.event.player.PlayerKickEvent;
|
||||||
|
import org.bukkit.event.player.PlayerResourcePackStatusEvent;
|
||||||
|
// CraftBukkit end
|
||||||
|
+// Sakura start
|
||||||
|
+import com.mojang.datafixers.util.Pair;
|
||||||
|
+import me.samsuik.sakura.player.visibility.Visibility.Setting;
|
||||||
|
+import net.minecraft.world.level.block.Blocks;
|
||||||
|
+import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
|
||||||
|
+import net.minecraft.network.protocol.game.ClientboundBlockEventPacket;
|
||||||
|
+import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket;
|
||||||
|
+import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData;
|
||||||
|
+import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData.BlockEntityTagOutput;
|
||||||
|
+import net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket;
|
||||||
|
+import net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket;
|
||||||
|
+import net.minecraft.world.level.block.DiodeBlock;
|
||||||
|
+import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||||
|
+import net.minecraft.world.level.block.RedStoneWireBlock;
|
||||||
|
+import net.minecraft.world.level.block.piston.PistonBaseBlock;
|
||||||
|
+import net.minecraft.world.level.block.piston.PistonHeadBlock;
|
||||||
|
+// Sakura end
|
||||||
|
|
||||||
|
public abstract class ServerCommonPacketListenerImpl implements ServerCommonPacketListener {
|
||||||
|
|
||||||
|
@@ -242,6 +259,61 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
|
||||||
|
} else if (packet instanceof ClientboundSetDefaultSpawnPositionPacket) {
|
||||||
|
ClientboundSetDefaultSpawnPositionPacket packet6 = (ClientboundSetDefaultSpawnPositionPacket) packet;
|
||||||
|
this.player.compassTarget = CraftLocation.toBukkit(packet6.pos, this.getCraftPlayer().getWorld());
|
||||||
|
+ // Sakura start - visibility api
|
||||||
|
+ } else if (!player.visibility.isModified()) {
|
||||||
|
+ // Skip players that haven't modified their settings
|
||||||
|
+ } else if (packet instanceof ClientboundSetEquipmentPacket equipment
|
||||||
|
+ && player.visibility.isToggled(Setting.ENCHANTMENT_GLINT)) {
|
||||||
|
+ var slots = new java.util.ArrayList<Pair<net.minecraft.world.entity.EquipmentSlot, net.minecraft.world.item.ItemStack>>();
|
||||||
|
+
|
||||||
|
+ for (int i = 0; i < equipment.getSlots().size(); i++) {
|
||||||
|
+ var pair = equipment.getSlots().get(i);
|
||||||
|
+ var itemstack = pair.getSecond();
|
||||||
|
+
|
||||||
|
+ if (itemstack.isEnchanted()) {
|
||||||
|
+ var copy = itemstack.copy();
|
||||||
|
+ copy.getTag().remove("ench");
|
||||||
|
+ itemstack = copy;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ slots.add(new Pair<>(pair.getFirst(), itemstack));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ packet = new ClientboundSetEquipmentPacket(equipment.getEntity(), slots);
|
||||||
|
+ } else if (packet instanceof ClientboundBlockEntityDataPacket blockdata
|
||||||
|
+ && player.visibility.isToggled(Setting.SPAWNERS)
|
||||||
|
+ && player.level().getBlockIfLoaded(blockdata.getPos()) == Blocks.SPAWNER) {
|
||||||
|
+ packet = new ClientboundBlockUpdatePacket(blockdata.getPos(), Blocks.BLACK_STAINED_GLASS.defaultBlockState());
|
||||||
|
+ } else if (packet instanceof ClientboundBlockUpdatePacket updatePacket) {
|
||||||
|
+ if (player.visibility.isToggled(Setting.SPAWNERS) && updatePacket.blockState.getBlock() == Blocks.SPAWNER) {
|
||||||
|
+ packet = new ClientboundBlockUpdatePacket(updatePacket.getPos(), Blocks.BLACK_STAINED_GLASS.defaultBlockState());
|
||||||
|
+ } else if (player.visibility.isToggled(Setting.REDSTONE)
|
||||||
|
+ && (updatePacket.blockState.getBlock() instanceof DiodeBlock
|
||||||
|
+ || updatePacket.blockState.getBlock() instanceof RedStoneWireBlock)) {
|
||||||
|
+ return;
|
||||||
|
+ } else if (player.visibility.isToggled(Setting.PISTONS)
|
||||||
|
+ && (updatePacket.blockState.getBlock() instanceof PistonBaseBlock
|
||||||
|
+ || updatePacket.blockState.getBlock() instanceof PistonHeadBlock)) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ } else if (packet instanceof ClientboundSectionBlocksUpdatePacket sectionPacket) {
|
||||||
|
+ for (var state : sectionPacket.states) {
|
||||||
|
+ if (player.visibility.isToggled(Setting.REDSTONE)
|
||||||
|
+ && (state.getBlock() instanceof DiodeBlock
|
||||||
|
+ || state.getBlock() instanceof RedStoneWireBlock)) {
|
||||||
|
+ return;
|
||||||
|
+ } else if (player.visibility.isToggled(Setting.PISTONS)
|
||||||
|
+ && (state.getBlock() instanceof PistonBaseBlock
|
||||||
|
+ || state.getBlock() instanceof PistonHeadBlock)) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ } else if (packet instanceof ClientboundBlockEventPacket blockevent
|
||||||
|
+ && player.visibility.isToggled(Setting.PISTONS)
|
||||||
|
+ && (blockevent.getBlock() instanceof PistonBaseBlock
|
||||||
|
+ || blockevent.getBlock() instanceof PistonHeadBlock)) {
|
||||||
|
+ return;
|
||||||
|
+ // Sakura end
|
||||||
|
}
|
||||||
|
// CraftBukkit end
|
||||||
|
boolean flag = !this.suspendFlushingOnServerThread || !this.server.isSameThread();
|
||||||
|
@@ -252,8 +324,11 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
|
||||||
|
CrashReport crashreport = CrashReport.forThrowable(throwable, "Sending packet");
|
||||||
|
CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Packet being sent");
|
||||||
|
|
||||||
|
+ // Sakura start - this has to be effectively final as we're modifying the packet above
|
||||||
|
+ var packetFinal = packet;
|
||||||
|
crashreportsystemdetails.setDetail("Packet class", () -> {
|
||||||
|
- return packet.getClass().getCanonicalName();
|
||||||
|
+ return packetFinal.getClass().getCanonicalName();
|
||||||
|
+ // Sakura end
|
||||||
|
});
|
||||||
|
throw new ReportedException(crashreport);
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||||
|
index 8bd243a8d5a4be54f907af2b02e96ea833cee62f..946e01733d85b119abe99910efe30029a344185b 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||||
|
@@ -3098,6 +3098,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||||
|
|
||||||
|
event.setCancelled(cancelled);
|
||||||
|
AbstractContainerMenu oldContainer = this.player.containerMenu; // SPIGOT-1224
|
||||||
|
+ me.samsuik.sakura.player.gui.PlayerGUI.onWindowClick(event); // Sakura - visibility gui
|
||||||
|
cserver.getPluginManager().callEvent(event);
|
||||||
|
if (this.player.containerMenu != oldContainer) {
|
||||||
|
return;
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
index f20ae9153b7098980ce6c0e75fcbbb4da652661b..0ebeac99c589ca70c26fa7db55f0c8f9a0e5fcd1 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
@@ -528,6 +528,8 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||||
|
this.teleportTo(worldserver, null);
|
||||||
|
}
|
||||||
|
// Paper end - make end portalling safe
|
||||||
|
+ public boolean isPrimedTNT; // Sakura
|
||||||
|
+ public boolean isFallingBlock; // Sakura
|
||||||
|
|
||||||
|
public Entity(EntityType<?> type, Level world) {
|
||||||
|
this.id = Entity.ENTITY_COUNTER.incrementAndGet();
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||||
|
index 9105418b29c89f092378da11b14e3d324332a2ba..d5560231aa398d56d1de06b19946bfcfe003df00 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||||
|
@@ -73,6 +73,7 @@ public class FallingBlockEntity extends Entity {
|
||||||
|
this.blockState = Blocks.SAND.defaultBlockState();
|
||||||
|
this.dropItem = true;
|
||||||
|
this.fallDamageMax = 40;
|
||||||
|
+ this.isFallingBlock = true; // Sakura
|
||||||
|
}
|
||||||
|
|
||||||
|
public FallingBlockEntity(Level world, double x, double y, double z, BlockState block) {
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||||
|
index 4ce3e69970dd9eb251d0538a2d233ca30e9e5e47..d14a8e2cf748cb3784253d99d1bf3c8f9eb2089c 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||||
|
@@ -31,6 +31,7 @@ public class PrimedTnt extends Entity implements TraceableEntity {
|
||||||
|
public PrimedTnt(EntityType<? extends PrimedTnt> type, Level world) {
|
||||||
|
super(type, world);
|
||||||
|
this.blocksBuilding = true;
|
||||||
|
+ this.isPrimedTNT = true; // Sakura
|
||||||
|
}
|
||||||
|
|
||||||
|
public PrimedTnt(Level world, double x, double y, double z, @Nullable LivingEntity igniter) {
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
index 8006ec1eece1e1c5c0b18bc2b5190bbb43e9d4c3..9e49196f7038c710e850005b6ad96c4eafca0f2e 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
@@ -216,6 +216,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||||
|
|
||||||
|
public abstract ResourceKey<LevelStem> getTypeKey();
|
||||||
|
|
||||||
|
+ public final it.unimi.dsi.fastutil.longs.Long2IntMap minimalTNT = new it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap(); // Sakura - visibility api
|
||||||
|
+
|
||||||
|
protected Level(WritableLevelData worlddatamutable, ResourceKey<Level> resourcekey, RegistryAccess iregistrycustom, Holder<DimensionType> holder, Supplier<ProfilerFiller> supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function<org.spigotmc.SpigotWorldConfig, io.papermc.paper.configuration.WorldConfiguration> paperWorldConfigCreator, Supplier<me.samsuik.sakura.configuration.WorldConfiguration> sakuraWorldConfigCreator, java.util.concurrent.Executor executor) { // Sakura // Paper - Async-Anti-Xray - Pass executor
|
||||||
|
this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot
|
||||||
|
this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||||
|
index e188bb3ba5d2ec28421947c0b66b25eecb569bfe..9ac026a464f8b5db5fe7543b71cd5bcaa3f65f70 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||||
|
@@ -489,6 +489,13 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||||
|
this.getHandle().displayName = name == null ? getName() : name;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Sakura start - visiblity api
|
||||||
|
+ @Override
|
||||||
|
+ public me.samsuik.sakura.player.visibility.Visibility getVisibility() {
|
||||||
|
+ return getHandle().visibility;
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
+
|
||||||
|
// Paper start
|
||||||
|
@Override
|
||||||
|
public void playerListName(net.kyori.adventure.text.Component name) {
|
||||||
134
patches/server/0006-Optimise-rayTracing.patch
Normal file
134
patches/server/0006-Optimise-rayTracing.patch
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Samsuik <kfian294ma4@gmail.com>
|
||||||
|
Date: Tue, 1 Mar 2022 18:40:09 +0000
|
||||||
|
Subject: [PATCH] Optimise rayTracing
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java
|
||||||
|
index 45243249a561440512ef2a620c60b02e159c80e2..54a7678c807e4954e6b56e59e49bab53a88a4860 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/Explosion.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/Explosion.java
|
||||||
|
@@ -281,7 +281,7 @@ public class Explosion {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (!collision.isEmpty() && collision.clip(from, to, currPos) != null) {
|
||||||
|
+ if (!collision.isEmpty() && collision.clipDirect(from, to, currPos)) { // Sakura
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/phys/shapes/VoxelShape.java b/src/main/java/net/minecraft/world/phys/shapes/VoxelShape.java
|
||||||
|
index 6bd6385ad82481a099f3556ed2dbd3744888fc34..157dc1c815cb15818fd6fb103a9e806ca2f3d68c 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/phys/shapes/VoxelShape.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/phys/shapes/VoxelShape.java
|
||||||
|
@@ -695,6 +695,110 @@ public abstract class VoxelShape {
|
||||||
|
// Paper end - optimise collisions
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Sakura start
|
||||||
|
+ // As of 1.20.2 paper has their own version of the pufferfish patch that this patch expanded on.
|
||||||
|
+ // A bit this patch is now obsolete such as simple AABB clipping.
|
||||||
|
+ // We will still use our method when a detailed hit result isn't required.
|
||||||
|
+ public boolean clipDirect(Vec3 start, Vec3 end, BlockPos pos) {
|
||||||
|
+ if (this.isEmpty) {
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ double vec3_x = end.x - start.x;
|
||||||
|
+ double vec3_y = end.y - start.y;
|
||||||
|
+ double vec3_z = end.z - start.z;
|
||||||
|
+ double vec3_lengthSqr = (vec3_x * vec3_x) + (vec3_y * vec3_y) + (vec3_z * vec3_z);
|
||||||
|
+
|
||||||
|
+ if (vec3_lengthSqr < 1.0E-7D) {
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ AABB singleAABB = this.singleAABBRepresentation;
|
||||||
|
+ //noinspection ConstantValue
|
||||||
|
+ if (singleAABB != null) {
|
||||||
|
+ return clipWithBBDirect(singleAABB, vec3_x, vec3_y, vec3_z, start, pos);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return clipWithBBsDirect(vec3_x, vec3_y, vec3_z, start, pos);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ protected boolean clipWithBBDirect(AABB single, double deltaX, double deltaY, double deltaZ, Vec3 from, BlockPos pos) {
|
||||||
|
+ double posX = pos.getX();
|
||||||
|
+ double posY = pos.getY();
|
||||||
|
+ double posZ = pos.getZ();
|
||||||
|
+
|
||||||
|
+ return clipPointBB(single, from, posX, posY, posZ, deltaX, deltaY, deltaZ)
|
||||||
|
+ || clipInsideDirectBB(single, deltaX, deltaY, deltaZ, from, pos);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ protected boolean clipWithBBsDirect(double deltaX, double deltaY, double deltaZ, Vec3 from, BlockPos pos) {
|
||||||
|
+ double posX = pos.getX();
|
||||||
|
+ double posY = pos.getY();
|
||||||
|
+ double posZ = pos.getZ();
|
||||||
|
+
|
||||||
|
+ for (AABB bb : toAabbs()) { // err
|
||||||
|
+ if (clipPointBB(bb, from, posX, posY, posZ, deltaX, deltaY, deltaZ)) {
|
||||||
|
+ return true;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return clipInsideDirectBBs(deltaX, deltaY, deltaZ, from, pos);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @SuppressWarnings("SuspiciousNameCombination")
|
||||||
|
+ protected static boolean clipPointBB(AABB box, Vec3 p, double posX, double posY, double posZ, double deltaX, double deltaY, double deltaZ) {
|
||||||
|
+ double minX = box.minX + posX;
|
||||||
|
+ double minY = box.minY + posY;
|
||||||
|
+ double minZ = box.minZ + posZ;
|
||||||
|
+ double maxX = box.maxX + posX;
|
||||||
|
+ double maxY = box.maxY + posY;
|
||||||
|
+ double maxZ = box.maxZ + posZ;
|
||||||
|
+
|
||||||
|
+ // todo: this could be simplified by using the centre of the bb
|
||||||
|
+ // if the bb dimensions are not the same then either scale or subtract from the result.
|
||||||
|
+ double closestX = deltaX > 1.0E-7D ? minX : maxX;
|
||||||
|
+ double closestY = deltaY > 1.0E-7D ? minY : maxY;
|
||||||
|
+ double closestZ = deltaZ > 1.0E-7D ? minZ : maxZ;
|
||||||
|
+
|
||||||
|
+ return clipPoint(deltaX, deltaY, deltaZ, closestX, minY, maxY, minZ, maxZ, p.x, p.y, p.z)
|
||||||
|
+ || clipPoint(deltaY, deltaZ, deltaX, closestY, minZ, maxZ, minX, maxX, p.y, p.z, p.x)
|
||||||
|
+ || clipPoint(deltaZ, deltaX, deltaY, closestZ, minX, maxX, minY, maxY, p.z, p.x, p.y);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private static boolean clipPoint(double deltaX, double deltaY, double deltaZ, double begin, double minX, double maxX, double minZ, double maxZ, double startX, double startY, double startZ) {
|
||||||
|
+ double d = (begin - startX) / deltaX;
|
||||||
|
+ double e = startY + d * deltaY;
|
||||||
|
+ double f = startZ + d * deltaZ;
|
||||||
|
+ return (d > 0.0D && d < 1.0) && (minX - 1.0E-7D < e && maxX + 1.0E-7D > e) && (minZ - 1.0E-7D < f && maxZ + 1.0E-7D > f);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // Absolutely horrendous code that takes a toll on all clip misses.
|
||||||
|
+ // This cannot be removed to maintain edge cases caused by this code existing in vanilla.
|
||||||
|
+ protected boolean clipInsideDirectBB(AABB single, double vec3_x, double vec3_y, double vec3_z, Vec3 start, BlockPos pos) {
|
||||||
|
+ double fromBehindX = start.x + (vec3_x * 0.001D);
|
||||||
|
+ double fromBehindY = start.y + (vec3_y * 0.001D);
|
||||||
|
+ double fromBehindZ = start.z + (vec3_z * 0.001D);
|
||||||
|
+
|
||||||
|
+ double fromBehindOffsetX = fromBehindX - (double) pos.getX();
|
||||||
|
+ double fromBehindOffsetY = fromBehindY - (double) pos.getY();
|
||||||
|
+ double fromBehindOffsetZ = fromBehindZ - (double) pos.getZ();
|
||||||
|
+
|
||||||
|
+ return single.contains(fromBehindOffsetX, fromBehindOffsetY, fromBehindOffsetZ);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ protected boolean clipInsideDirectBBs(double vec3_x, double vec3_y, double vec3_z, Vec3 start, BlockPos pos) {
|
||||||
|
+ double fromBehindX = start.x + (vec3_x * 0.001D);
|
||||||
|
+ double fromBehindY = start.y + (vec3_y * 0.001D);
|
||||||
|
+ double fromBehindZ = start.z + (vec3_z * 0.001D);
|
||||||
|
+
|
||||||
|
+ int indexX = this.findIndex(Direction.Axis.X, fromBehindX - (double)pos.getX());
|
||||||
|
+ int indexY = this.findIndex(Direction.Axis.Y, fromBehindY - (double)pos.getY());
|
||||||
|
+ int indexZ = this.findIndex(Direction.Axis.Z, fromBehindZ - (double)pos.getZ());
|
||||||
|
+
|
||||||
|
+ return this.shape.isFullWide(indexX, indexY, indexZ);
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
+
|
||||||
|
public Optional<Vec3> closestPointTo(Vec3 target) {
|
||||||
|
// Paper start - optimise collisions
|
||||||
|
if (this.isEmpty) {
|
||||||
247
patches/server/0007-Reduce-deltaMovement-Allocations.patch
Normal file
247
patches/server/0007-Reduce-deltaMovement-Allocations.patch
Normal file
@@ -0,0 +1,247 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Samsuik <kfian294ma4@gmail.com>
|
||||||
|
Date: Fri, 24 Mar 2023 16:29:21 +0000
|
||||||
|
Subject: [PATCH] Reduce deltaMovement Allocations
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
index 0ebeac99c589ca70c26fa7db55f0c8f9a0e5fcd1..514c34e25b6e42fa591ccbcd134149e64235b899 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
@@ -1196,7 +1196,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||||
|
this.tryCheckInsideBlocks();
|
||||||
|
float f = this.getBlockSpeedFactor();
|
||||||
|
|
||||||
|
- this.setDeltaMovement(this.getDeltaMovement().multiply((double) f, 1.0D, (double) f));
|
||||||
|
+ this.multiplyDeltaMovement((double) f, 1.0D, (double) f); // Sakura - reduce movement allocations
|
||||||
|
// Paper start - remove expensive streams from here
|
||||||
|
boolean noneMatch = true;
|
||||||
|
AABB fireSearchBox = this.getBoundingBox().deflate(1.0E-6D);
|
||||||
|
@@ -2016,6 +2016,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||||
|
public void moveTo(double x, double y, double z, float yaw, float pitch) {
|
||||||
|
// Paper - cancel entity velocity if teleported
|
||||||
|
if (!preserveMotion) {
|
||||||
|
+ this.movementDirty = false; // Sakura
|
||||||
|
this.deltaMovement = Vec3.ZERO;
|
||||||
|
} else {
|
||||||
|
this.preserveMotion = false;
|
||||||
|
@@ -3389,29 +3390,33 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onAboveBubbleCol(boolean drag) {
|
||||||
|
- Vec3 vec3d = this.getDeltaMovement();
|
||||||
|
+ // Sakura start - reduce movement allocations
|
||||||
|
+ // Vec3 vec3d = this.getDeltaMovement();
|
||||||
|
+ this.syncDeltaMovement();
|
||||||
|
double d0;
|
||||||
|
|
||||||
|
if (drag) {
|
||||||
|
- d0 = Math.max(-0.9D, vec3d.y - 0.03D);
|
||||||
|
+ d0 = Math.max(-0.9D, movementY - 0.03D);
|
||||||
|
} else {
|
||||||
|
- d0 = Math.min(1.8D, vec3d.y + 0.1D);
|
||||||
|
+ d0 = Math.min(1.8D, movementY + 0.1D);
|
||||||
|
}
|
||||||
|
|
||||||
|
- this.setDeltaMovement(vec3d.x, d0, vec3d.z);
|
||||||
|
+ this.setDeltaMovement(movementX, d0, movementZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onInsideBubbleColumn(boolean drag) {
|
||||||
|
- Vec3 vec3d = this.getDeltaMovement();
|
||||||
|
+ // Vec3 vec3d = this.getDeltaMovement();
|
||||||
|
+ this.syncDeltaMovement();
|
||||||
|
double d0;
|
||||||
|
|
||||||
|
if (drag) {
|
||||||
|
- d0 = Math.max(-0.3D, vec3d.y - 0.03D);
|
||||||
|
+ d0 = Math.max(-0.3D, movementY - 0.03D);
|
||||||
|
} else {
|
||||||
|
- d0 = Math.min(0.7D, vec3d.y + 0.06D);
|
||||||
|
+ d0 = Math.min(0.7D, movementY + 0.06D);
|
||||||
|
}
|
||||||
|
|
||||||
|
- this.setDeltaMovement(vec3d.x, d0, vec3d.z);
|
||||||
|
+ this.setDeltaMovement(movementX, d0, movementZ);
|
||||||
|
+ // Sakura end
|
||||||
|
this.resetFallDistance();
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -4385,16 +4390,19 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||||
|
vec3d = vec3d.normalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
- Vec3 vec3d2 = this.getDeltaMovement();
|
||||||
|
+ // Sakura start - reduce movement allocations
|
||||||
|
+ // Vec3 vec3d2 = this.getDeltaMovement();
|
||||||
|
+ this.syncDeltaMovement();
|
||||||
|
|
||||||
|
vec3d = vec3d.scale(speed * 1.0D);
|
||||||
|
double d3 = 0.003D;
|
||||||
|
|
||||||
|
- if (Math.abs(vec3d2.x) < 0.003D && Math.abs(vec3d2.z) < 0.003D && vec3d.length() < 0.0045000000000000005D) {
|
||||||
|
+ if (Math.abs(movementX) < 0.003D && Math.abs(movementZ) < 0.003D && vec3d.length() < 0.0045000000000000005D) {
|
||||||
|
vec3d = vec3d.normalize().scale(0.0045000000000000005D);
|
||||||
|
}
|
||||||
|
|
||||||
|
- this.setDeltaMovement(this.getDeltaMovement().add(vec3d));
|
||||||
|
+ this.addDeltaMovement(vec3d.x, vec3d.y, vec3d.z);
|
||||||
|
+ // Sakura end
|
||||||
|
}
|
||||||
|
|
||||||
|
this.fluidHeight.put(tag, d1);
|
||||||
|
@@ -4465,11 +4473,53 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||||
|
return this.chunkPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Sakura start - reduce movement allocations
|
||||||
|
+ private double movementX;
|
||||||
|
+ private double movementY;
|
||||||
|
+ private double movementZ;
|
||||||
|
+ private boolean movementDirty;
|
||||||
|
+
|
||||||
|
+ public void addDeltaMovement(double x, double y, double z) {
|
||||||
|
+ syncDeltaMovement();
|
||||||
|
+ movementX += x;
|
||||||
|
+ movementY += y;
|
||||||
|
+ movementZ += z;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void scaleDeltaMovement(double n) {
|
||||||
|
+ syncDeltaMovement();
|
||||||
|
+ movementX *= n;
|
||||||
|
+ movementY *= n;
|
||||||
|
+ movementZ *= n;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void multiplyDeltaMovement(double x, double y, double z) {
|
||||||
|
+ syncDeltaMovement();
|
||||||
|
+ movementX *= x;
|
||||||
|
+ movementY *= y;
|
||||||
|
+ movementZ *= z;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private void updateDeltaMovement() {
|
||||||
|
+ if (movementDirty) {
|
||||||
|
+ deltaMovement = new Vec3(movementX, movementY, movementZ);
|
||||||
|
+ movementDirty = false;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private void syncDeltaMovement() {
|
||||||
|
+ if (!movementDirty) {
|
||||||
|
+ setDeltaMovement(deltaMovement.x, deltaMovement.y, deltaMovement.z);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
public Vec3 getDeltaMovement() {
|
||||||
|
+ updateDeltaMovement();
|
||||||
|
return this.deltaMovement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeltaMovement(Vec3 velocity) {
|
||||||
|
+ movementDirty = false;
|
||||||
|
synchronized (this.posLock) { // Paper
|
||||||
|
this.deltaMovement = velocity;
|
||||||
|
} // Paper
|
||||||
|
@@ -4480,7 +4530,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeltaMovement(double x, double y, double z) {
|
||||||
|
- this.setDeltaMovement(new Vec3(x, y, z));
|
||||||
|
+ movementX = x;
|
||||||
|
+ movementY = y;
|
||||||
|
+ movementZ = z;
|
||||||
|
+ movementDirty = true;
|
||||||
|
+ // Sakura end
|
||||||
|
}
|
||||||
|
|
||||||
|
public final int getBlockX() {
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||||
|
index d5560231aa398d56d1de06b19946bfcfe003df00..240a762b91a3c570583ee65bfe55b9677c4f63be 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||||
|
@@ -145,7 +145,7 @@ public class FallingBlockEntity extends Entity {
|
||||||
|
|
||||||
|
++this.time;
|
||||||
|
if (!this.isNoGravity()) {
|
||||||
|
- this.setDeltaMovement(this.getDeltaMovement().add(0.0D, -0.04D, 0.0D));
|
||||||
|
+ this.addDeltaMovement(0.0D, -0.04D, 0.0D); // Sakura - reduce movement allocations
|
||||||
|
}
|
||||||
|
|
||||||
|
this.move(MoverType.SELF, this.getDeltaMovement());
|
||||||
|
@@ -192,7 +192,7 @@ public class FallingBlockEntity extends Entity {
|
||||||
|
} else {
|
||||||
|
BlockState iblockdata = this.level().getBlockState(blockposition);
|
||||||
|
|
||||||
|
- this.setDeltaMovement(this.getDeltaMovement().multiply(0.7D, -0.5D, 0.7D));
|
||||||
|
+ this.multiplyDeltaMovement(0.7D, -0.5D, 0.7D); // Sakura - reduce movement allocations
|
||||||
|
if (!iblockdata.is(Blocks.MOVING_PISTON)) {
|
||||||
|
if (!this.cancelDrop) {
|
||||||
|
boolean flag2 = iblockdata.canBeReplaced((BlockPlaceContext) (new DirectionalPlaceContext(this.level(), blockposition, Direction.DOWN, ItemStack.EMPTY, Direction.UP)));
|
||||||
|
@@ -259,7 +259,7 @@ public class FallingBlockEntity extends Entity {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- this.setDeltaMovement(this.getDeltaMovement().scale(0.98D));
|
||||||
|
+ this.scaleDeltaMovement(0.98D); // Sakura - reduce movement allocations
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||||
|
index d14a8e2cf748cb3784253d99d1bf3c8f9eb2089c..369cfaeba980d1d98d0dcefffb584dcbbe144b1d 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||||
|
@@ -66,7 +66,7 @@ public class PrimedTnt extends Entity implements TraceableEntity {
|
||||||
|
public void tick() {
|
||||||
|
if (this.level().spigotConfig.maxTntTicksPerTick > 0 && ++this.level().spigotConfig.currentPrimedTnt > this.level().spigotConfig.maxTntTicksPerTick) { return; } // Spigot
|
||||||
|
if (!this.isNoGravity()) {
|
||||||
|
- this.setDeltaMovement(this.getDeltaMovement().add(0.0D, -0.04D, 0.0D));
|
||||||
|
+ this.addDeltaMovement(0.0D, -0.04D, 0.0D); // Sakura - reduce movement allocations
|
||||||
|
}
|
||||||
|
|
||||||
|
this.move(MoverType.SELF, this.getDeltaMovement());
|
||||||
|
@@ -76,9 +76,9 @@ public class PrimedTnt extends Entity implements TraceableEntity {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Paper end
|
||||||
|
- this.setDeltaMovement(this.getDeltaMovement().scale(0.98D));
|
||||||
|
+ this.scaleDeltaMovement(0.98D); // Sakura - reduce movement allocations
|
||||||
|
if (this.onGround()) {
|
||||||
|
- this.setDeltaMovement(this.getDeltaMovement().multiply(0.7D, -0.5D, 0.7D));
|
||||||
|
+ this.multiplyDeltaMovement(0.7D, -0.5D, 0.7D); // Sakura - reduce movement allocations
|
||||||
|
}
|
||||||
|
|
||||||
|
int i = this.getFuse() - 1;
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java
|
||||||
|
index 54a7678c807e4954e6b56e59e49bab53a88a4860..1b335111bd9eb90bbda87225b740768705f26193 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/Explosion.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/Explosion.java
|
||||||
|
@@ -600,10 +600,12 @@ public class Explosion {
|
||||||
|
d8 *= d14;
|
||||||
|
d9 *= d14;
|
||||||
|
d10 *= d14;
|
||||||
|
- Vec3 vec3d1 = new Vec3(d8, d9, d10);
|
||||||
|
|
||||||
|
- entity.setDeltaMovement(entity.getDeltaMovement().add(vec3d1));
|
||||||
|
+ // Sakura start - reduce deltamovement allocations
|
||||||
|
+ entity.addDeltaMovement(d8, d9, d10);
|
||||||
|
if (entity instanceof Player) {
|
||||||
|
+ Vec3 vec3d1 = new Vec3(d8, d9, d10);
|
||||||
|
+ // Sakura end
|
||||||
|
Player entityhuman = (Player) entity;
|
||||||
|
|
||||||
|
if (!entityhuman.isSpectator() && (!entityhuman.isCreative() || !entityhuman.getAbilities().flying) && !level.paperConfig().environment.disableExplosionKnockback) { // Paper - Disable explosion knockback
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java
|
||||||
|
index d4cbff18adb62073a1dceb189043789620af6877..26cc4c10d441a800623fd5b76a9c31a57291cdba 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/block/Block.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/block/Block.java
|
||||||
|
@@ -453,7 +453,7 @@ public class Block extends BlockBehaviour implements ItemLike {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateEntityAfterFallOn(BlockGetter world, Entity entity) {
|
||||||
|
- entity.setDeltaMovement(entity.getDeltaMovement().multiply(1.0D, 0.0D, 1.0D));
|
||||||
|
+ entity.multiplyDeltaMovement(1.0D, 0.0D, 1.0D); // Sakura
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemStack getCloneItemStack(BlockGetter world, BlockPos pos, BlockState state) {
|
||||||
25
patches/server/0008-Optional-Force-Position-Updates.patch
Normal file
25
patches/server/0008-Optional-Force-Position-Updates.patch
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Samsuik <kfian294ma4@gmail.com>
|
||||||
|
Date: Sat, 11 Sep 2021 22:23:39 +0100
|
||||||
|
Subject: [PATCH] Optional Force Position Updates
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||||
|
index 369cfaeba980d1d98d0dcefffb584dcbbe144b1d..5b4e1d56f63935c5b6506dc94d174e8efebd260f 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||||
|
@@ -99,6 +99,14 @@ public class PrimedTnt extends Entity implements TraceableEntity {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Sakura start - configurable force position updates
|
||||||
|
+ if (level().sakuraConfig().cannons.tnt.forcePositionUpdates) {
|
||||||
|
+ forcePositionUpdate();
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private void forcePositionUpdate() {
|
||||||
|
+ // Sakura end
|
||||||
|
// Paper start - Optional prevent TNT from moving in water
|
||||||
|
if (!this.isRemoved() && this.wasTouchingWater && this.level().paperConfig().fixes.preventTntFromMovingInWater) {
|
||||||
|
/*
|
||||||
60
patches/server/0009-Load-Chunks-on-Movement.patch
Normal file
60
patches/server/0009-Load-Chunks-on-Movement.patch
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Samsuik <kfian294ma4@gmail.com>
|
||||||
|
Date: Sat, 11 Sep 2021 19:19:41 +0100
|
||||||
|
Subject: [PATCH] Load Chunks on Movement
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
index 514c34e25b6e42fa591ccbcd134149e64235b899..c35ca0785ecc268fb7e20dee56d42bdadca41ee6 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
@@ -397,6 +397,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||||
|
public org.bukkit.projectiles.ProjectileSource projectileSource; // For projectiles only
|
||||||
|
public boolean lastDamageCancelled; // SPIGOT-5339, SPIGOT-6252, SPIGOT-6777: Keep track if the event was canceled
|
||||||
|
public boolean persistentInvisibility = false;
|
||||||
|
+ public boolean loadChunks = false; // Sakura - load chunks
|
||||||
|
public BlockPos lastLavaContact;
|
||||||
|
// Spigot start
|
||||||
|
public final org.spigotmc.ActivationRange.ActivationType activationType = org.spigotmc.ActivationRange.initializeEntityActivationType(this);
|
||||||
|
@@ -1457,7 +1458,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||||
|
|
||||||
|
io.papermc.paper.util.CollisionUtil.getCollisions(
|
||||||
|
world, this, collisionBox, potentialCollisionsVoxel, potentialCollisionsBB,
|
||||||
|
- (0),
|
||||||
|
+ (0) | (loadChunks ? io.papermc.paper.util.CollisionUtil.COLLISION_FLAG_LOAD_CHUNKS : 0), // Sakura
|
||||||
|
null, null
|
||||||
|
);
|
||||||
|
|
||||||
|
@@ -4800,7 +4801,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAlwaysTicking() {
|
||||||
|
- return false;
|
||||||
|
+ return loadChunks; // Sakura - always tick in chunks
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean mayInteract(Level world, BlockPos pos) {
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||||
|
index 240a762b91a3c570583ee65bfe55b9677c4f63be..2e0f38ffad09b6afbea74205b89beb774e779545 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||||
|
@@ -74,6 +74,7 @@ public class FallingBlockEntity extends Entity {
|
||||||
|
this.dropItem = true;
|
||||||
|
this.fallDamageMax = 40;
|
||||||
|
this.isFallingBlock = true; // Sakura
|
||||||
|
+ this.loadChunks = world.sakuraConfig().cannons.sand.loadsChunks; // Sakura - load chunks
|
||||||
|
}
|
||||||
|
|
||||||
|
public FallingBlockEntity(Level world, double x, double y, double z, BlockState block) {
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||||
|
index 5b4e1d56f63935c5b6506dc94d174e8efebd260f..4c328a511ff6c0e6b73ef9701c82373e02c12830 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||||
|
@@ -32,6 +32,7 @@ public class PrimedTnt extends Entity implements TraceableEntity {
|
||||||
|
super(type, world);
|
||||||
|
this.blocksBuilding = true;
|
||||||
|
this.isPrimedTNT = true; // Sakura
|
||||||
|
+ this.loadChunks = world.sakuraConfig().cannons.tnt.loadsChunks; // Sakura - load chunks
|
||||||
|
}
|
||||||
|
|
||||||
|
public PrimedTnt(Level world, double x, double y, double z, @Nullable LivingEntity igniter) {
|
||||||
509
patches/server/0010-TPS-Graph-Command.patch
Normal file
509
patches/server/0010-TPS-Graph-Command.patch
Normal file
@@ -0,0 +1,509 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Samsuik <kfian294ma4@gmail.com>
|
||||||
|
Date: Sun, 19 Sep 2021 01:10:02 +0100
|
||||||
|
Subject: [PATCH] TPS Graph Command
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/me/samsuik/sakura/command/SakuraCommands.java b/src/main/java/me/samsuik/sakura/command/SakuraCommands.java
|
||||||
|
index d7d0c49cc5d576c594dee16ddba037cd147e11fa..2ed50a4fc9cddc036adc5b4288bd5d83442b1572 100644
|
||||||
|
--- a/src/main/java/me/samsuik/sakura/command/SakuraCommands.java
|
||||||
|
+++ b/src/main/java/me/samsuik/sakura/command/SakuraCommands.java
|
||||||
|
@@ -4,6 +4,7 @@ import io.papermc.paper.command.PaperPluginsCommand;
|
||||||
|
import me.samsuik.sakura.command.subcommands.ConfigCommand;
|
||||||
|
import me.samsuik.sakura.command.subcommands.FPSCommand;
|
||||||
|
import me.samsuik.sakura.command.subcommands.VisualCommand;
|
||||||
|
+import me.samsuik.sakura.command.subcommands.TPSCommand;
|
||||||
|
import me.samsuik.sakura.player.visibility.Visibility;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
@@ -21,6 +22,7 @@ public class SakuraCommands {
|
||||||
|
COMMANDS.put("tntvisibility", new VisualCommand(Visibility.Setting.TNT_VISIBILITY, "tnttoggle"));
|
||||||
|
COMMANDS.put("sandvisibility", new VisualCommand(Visibility.Setting.SAND_VISIBILITY, "sandtoggle"));
|
||||||
|
COMMANDS.put("minimal", new VisualCommand(Visibility.Setting.MINIMAL, "minimaltnt", "tntlag"));
|
||||||
|
+ COMMANDS.put("tps", new TPSCommand("tps"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void registerCommands(final MinecraftServer server) {
|
||||||
|
diff --git a/src/main/java/me/samsuik/sakura/command/subcommands/TPSCommand.java b/src/main/java/me/samsuik/sakura/command/subcommands/TPSCommand.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..0b9e254f821145369dc9c382029e8585693fa29c
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/me/samsuik/sakura/command/subcommands/TPSCommand.java
|
||||||
|
@@ -0,0 +1,69 @@
|
||||||
|
+package me.samsuik.sakura.command.subcommands;
|
||||||
|
+
|
||||||
|
+import me.samsuik.sakura.command.BaseSubCommand;
|
||||||
|
+import me.samsuik.sakura.utils.tps.TPSGraph;
|
||||||
|
+import me.samsuik.sakura.utils.tps.TickTracking;
|
||||||
|
+import net.kyori.adventure.text.Component;
|
||||||
|
+import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
+import net.kyori.adventure.text.format.TextDecoration;
|
||||||
|
+import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||||
|
+import net.kyori.adventure.text.minimessage.tag.Tag;
|
||||||
|
+import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
|
||||||
|
+import net.minecraft.server.MinecraftServer;
|
||||||
|
+import net.minecraft.util.Mth;
|
||||||
|
+import org.bukkit.command.CommandSender;
|
||||||
|
+
|
||||||
|
+public class TPSCommand extends BaseSubCommand {
|
||||||
|
+
|
||||||
|
+ public TPSCommand(String name) {
|
||||||
|
+ super(name);
|
||||||
|
+ this.description = "Gets the current ticks per second for the server";
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void execute(CommandSender sender, String[] args) {
|
||||||
|
+ var tracking = MinecraftServer.tickTracking;
|
||||||
|
+
|
||||||
|
+ var average = tracking.averageTps(10) * 1.75;
|
||||||
|
+ int lines = 10;
|
||||||
|
+
|
||||||
|
+ try {
|
||||||
|
+ average = Double.parseDouble(args[0]);
|
||||||
|
+ lines = Mth.clamp(Integer.parseInt(args[1]), 1, 18);
|
||||||
|
+ } catch (NumberFormatException | ArrayIndexOutOfBoundsException ignored) {}
|
||||||
|
+
|
||||||
|
+ sender.sendMessage(Component.text(".", NamedTextColor.DARK_PURPLE));
|
||||||
|
+ sender.sendMessage(createInformationComponent(tracking));
|
||||||
|
+
|
||||||
|
+ // Create the graph
|
||||||
|
+ var graph = new TPSGraph(tracking, lines, 75, average);
|
||||||
|
+ graph.map();
|
||||||
|
+
|
||||||
|
+ // Send the graph to the user
|
||||||
|
+ for (var component : graph.components()) {
|
||||||
|
+ sender.sendMessage(Component.text("| ", NamedTextColor.DARK_PURPLE).append(component));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ sender.sendMessage(Component.text("| ", NamedTextColor.DARK_PURPLE).append(Component.text(" ".repeat(75), NamedTextColor.GRAY, TextDecoration.STRIKETHROUGH)));
|
||||||
|
+ sender.sendMessage(Component.text("'", NamedTextColor.DARK_PURPLE));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private Component createInformationComponent(TickTracking tracking) {
|
||||||
|
+ return MiniMessage.miniMessage().deserialize("<dark_purple>| <gray>-------------- <dark_gray>( <white>Now</white>: <tps>, <white>Mem</white>: <memory><gray>%</gray> ) </dark_gray>---------------",
|
||||||
|
+ TagResolver.resolver("tps", Tag.selfClosingInserting(
|
||||||
|
+ Component.text("%.1f".formatted(tracking.averageTps(1)), TPSGraph.colour(tracking.averageTps(1) / 20.0))
|
||||||
|
+ )),
|
||||||
|
+ TagResolver.resolver("memory", Tag.selfClosingInserting(
|
||||||
|
+ Component.text("%.1f".formatted(memoryUsage() * 100), TPSGraph.colour(1.0 - memoryUsage()))
|
||||||
|
+ )));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private double memoryUsage() {
|
||||||
|
+ Runtime runtime = Runtime.getRuntime();
|
||||||
|
+ double free = runtime.freeMemory();
|
||||||
|
+ double max = runtime.maxMemory();
|
||||||
|
+ double alloc = runtime.totalMemory();
|
||||||
|
+ return (alloc - free) / max;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/me/samsuik/sakura/utils/tps/TPSGraph.java b/src/main/java/me/samsuik/sakura/utils/tps/TPSGraph.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..efbf8360657c862dd522d0264aa1c5d8f73bd8b5
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/me/samsuik/sakura/utils/tps/TPSGraph.java
|
||||||
|
@@ -0,0 +1,255 @@
|
||||||
|
+package me.samsuik.sakura.utils.tps;
|
||||||
|
+
|
||||||
|
+import me.samsuik.sakura.utils.tps.TickTracking.Point;
|
||||||
|
+import net.kyori.adventure.text.Component;
|
||||||
|
+import net.kyori.adventure.text.TextComponent;
|
||||||
|
+import net.kyori.adventure.text.event.HoverEvent;
|
||||||
|
+import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
+import net.kyori.adventure.text.format.TextColor;
|
||||||
|
+import net.kyori.adventure.text.format.TextDecoration;
|
||||||
|
+import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||||
|
+import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
|
||||||
|
+import net.minecraft.util.Mth;
|
||||||
|
+
|
||||||
|
+public class TPSGraph {
|
||||||
|
+
|
||||||
|
+ private final Parts[][] parts;
|
||||||
|
+ private final TickTracking tracked;
|
||||||
|
+ private final int lines;
|
||||||
|
+ private final int length;
|
||||||
|
+ private final double ceiling;
|
||||||
|
+
|
||||||
|
+ public TPSGraph(TickTracking tracked, int lines, int length, double ceiling) {
|
||||||
|
+ this.parts = new Parts[lines][length];
|
||||||
|
+ this.tracked = tracked;
|
||||||
|
+ this.length = length;
|
||||||
|
+ this.lines = lines;
|
||||||
|
+ this.ceiling = ceiling;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void map() {
|
||||||
|
+ // Create the background
|
||||||
|
+ for (var line = 0; line < lines; ++line) {
|
||||||
|
+ for (var column = 0; column < length; ++column) {
|
||||||
|
+ parts[line][column] = Parts.BACKGROUND;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // Create normal points on the graph
|
||||||
|
+ for (var column = 0; column < length; ++column) {
|
||||||
|
+ var tps = tracked.point(column).tps();
|
||||||
|
+ // Likely the server has just started
|
||||||
|
+ if (tps == 0.0) break;
|
||||||
|
+ // Create normal point for column
|
||||||
|
+ var line = getLine(tps);
|
||||||
|
+ var lineParts = parts[line];
|
||||||
|
+ lineParts[column] = Parts.NORMAL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // Create spikes on the graph, what is a spike?
|
||||||
|
+ // By spike I am referring to a situation where
|
||||||
|
+ // the normal point would be "moving" more than
|
||||||
|
+ // 2 lines, which looks terrible.
|
||||||
|
+ for (var column = 0; column < length; ++column) {
|
||||||
|
+ var nextTps = tracked.point(column + 1).tps();
|
||||||
|
+ // Likely the server has just started
|
||||||
|
+ if (nextTps == 0.0) break;
|
||||||
|
+ var curr = getLine(tracked.point(column).tps());
|
||||||
|
+ var prev = getLine(tracked.point(Math.max(column - 1, 0)).tps());
|
||||||
|
+ var next = getLine(nextTps);
|
||||||
|
+ var min = Math.min(curr, next);
|
||||||
|
+ var max = Math.max(curr, next);
|
||||||
|
+
|
||||||
|
+ if (max - min < 2) {
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // Create vertical parts between the two points
|
||||||
|
+ for (var line = min; line < max; ++line) {
|
||||||
|
+ parts[line][column] = Parts.VERTICAL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ parts[min][column] = Parts.TOP;
|
||||||
|
+ parts[max][column] = Parts.BOTTOM;
|
||||||
|
+
|
||||||
|
+ if (column + 1 < length) {
|
||||||
|
+ // dodgy hack because the previous value can change +/- 1
|
||||||
|
+ // causing the spike to not correctly line up.
|
||||||
|
+ // this isn't a problem in the other direction
|
||||||
|
+ if (prev == curr + 1 && next < curr) {
|
||||||
|
+ parts[max][column] = Parts.SPIKE_TOP_RIGHT;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (min == next) {
|
||||||
|
+ parts[min][column] = Parts.SPIKE_BOTTOM_LEFT; // '!
|
||||||
|
+ } else if (prev <= min) { // has to be <= due to the issue I noted above
|
||||||
|
+ parts[min][column] = Parts.SPIKE_BOTTOM_RIGHT; // !'
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // cone on the top of a spike
|
||||||
|
+ if (max == curr && Math.abs(next - max) > 1 && Math.abs(prev - max) > 1 && prev < max) {
|
||||||
|
+ parts[max][column - 1] = Parts.SPIKE_TOP_LEFT;
|
||||||
|
+ parts[max][column] = Parts.SPIKE_TOP_RIGHT;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // cone on the bottom of a spike
|
||||||
|
+ if (min == curr && Math.abs(next - min) > 1 && Math.abs(prev - min) > 1 && prev > min) {
|
||||||
|
+ parts[min][column - 1] = Parts.SPIKE_BOTTOM_LEFT;
|
||||||
|
+ parts[min][column] = Parts.SPIKE_BOTTOM_RIGHT;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // Create special points on the graph, this
|
||||||
|
+ // is to handle slopes and slight differences
|
||||||
|
+ // that show up, anything else should be too
|
||||||
|
+ // extreme and get treated as a spike instead.
|
||||||
|
+ for (var column = 0; column < length; ++column) {
|
||||||
|
+ var tps = tracked.point(column).tps();
|
||||||
|
+ // Likely the server has just started
|
||||||
|
+ if (tps == 0.0) continue;
|
||||||
|
+ var curr = getLine(tps);
|
||||||
|
+ var prev = getLine(tracked.point(Math.max(column - 1, 0)).tps());
|
||||||
|
+ var next = getLine(tracked.point(column + 1).tps());
|
||||||
|
+
|
||||||
|
+ // Ignore spikes, it'd mess up and be a waste of time
|
||||||
|
+ if (Math.abs(curr - next) >= 2) {
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // SANITY: positive = rising, negative = declining
|
||||||
|
+ var direction = next - prev;
|
||||||
|
+ var change = Math.abs(direction);
|
||||||
|
+
|
||||||
|
+ if (change >= 2 && Math.max(next, prev) == curr + 1) {
|
||||||
|
+ // Create slopes, only requirement is that the highest point
|
||||||
|
+ // and the current are one line away from one another.
|
||||||
|
+ if (direction < 0) {
|
||||||
|
+ parts[curr][column] = Parts.DECLINING;
|
||||||
|
+ } else {
|
||||||
|
+ parts[curr][column] = Parts.RISING;
|
||||||
|
+ }
|
||||||
|
+ } else if (Math.abs(curr - next) == 1 || direction == 0) {
|
||||||
|
+ // if we have no direction always do this as a special case for slight dips and rises
|
||||||
|
+ if (curr < next) {
|
||||||
|
+ parts[curr][column] = Parts.TOP;
|
||||||
|
+ } else if (curr > next) {
|
||||||
|
+ parts[curr][column] = Parts.BOTTOM;
|
||||||
|
+ }
|
||||||
|
+ } else if (Math.abs(curr - prev) == 1) {
|
||||||
|
+ if (prev > curr) {
|
||||||
|
+ parts[curr][column] = Parts.TOP;
|
||||||
|
+ } else if (prev < curr) {
|
||||||
|
+ parts[curr][column] = Parts.BOTTOM;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private int getLine(double tps) {
|
||||||
|
+ var per = (ceiling / 10); // How many lines 1 tick should display
|
||||||
|
+ var line = (int) (tps / per);
|
||||||
|
+ return Mth.clamp(line, 0, lines - 1);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public Component[] components() {
|
||||||
|
+ // Create graph component array
|
||||||
|
+ var graph = new TextComponent.Builder[lines];
|
||||||
|
+
|
||||||
|
+ // Initialise graph components
|
||||||
|
+ for (var line = 0; line < graph.length; ++line) {
|
||||||
|
+ graph[line] = Component.text();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // Write the graph
|
||||||
|
+ for (var line = 0; line < parts.length; line++) {
|
||||||
|
+ writeLine(graph[line], parts[parts.length - line - 1]);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // Create built component array
|
||||||
|
+ var parts = new Component[graph.length];
|
||||||
|
+
|
||||||
|
+ // Store built components
|
||||||
|
+ for (var i = 0; i < graph.length; i++) {
|
||||||
|
+ parts[i] = graph[i].build();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return parts;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private void writeLine(TextComponent.Builder builder, Parts[] lineParts) {
|
||||||
|
+ for (var column = 0; column < lineParts.length; column++) {
|
||||||
|
+ var point = tracked.point(column);
|
||||||
|
+ var part = lineParts[column];
|
||||||
|
+
|
||||||
|
+ var colour = colour(point.tps() / 20.0);
|
||||||
|
+ var component = part.getPart();
|
||||||
|
+
|
||||||
|
+ if (part != Parts.BACKGROUND) {
|
||||||
|
+ component = component.color(colour);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // Display information from the current point
|
||||||
|
+ builder.append(appendHoverEvent(component, point, colour));
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private Component appendHoverEvent(Component in, Point point, TextColor colour) {
|
||||||
|
+ return in.hoverEvent(HoverEvent.showText(MiniMessage.miniMessage().deserialize("""
|
||||||
|
+ TPS: <tps>
|
||||||
|
+ MS: (<ms>, <highest>)
|
||||||
|
+ Chunks: <chunks>
|
||||||
|
+ Entities: <entities>""",
|
||||||
|
+ Placeholder.component("tps", Component.text("%.1f".formatted(point.tps()), colour)),
|
||||||
|
+ Placeholder.component("ms", Component.text("%.1f".formatted(point.mspt()), colour)),
|
||||||
|
+ Placeholder.component("highest", Component.text("%.1f".formatted(point.highest()), colour)),
|
||||||
|
+ Placeholder.unparsed("chunks", String.valueOf(point.chunks())),
|
||||||
|
+ Placeholder.unparsed("entities", String.valueOf(point.entities()))
|
||||||
|
+ )));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public static TextColor colour(double percentage) {
|
||||||
|
+ if (percentage > 0.75) return shift(percentage, 1.0, 0.75, NamedTextColor.GREEN, NamedTextColor.YELLOW);
|
||||||
|
+ if (percentage > 0.6) return shift(percentage, 0.75, 0.6, NamedTextColor.YELLOW, NamedTextColor.GOLD);
|
||||||
|
+ if (percentage > 0.4) return shift(percentage, 0.6, 0.4, NamedTextColor.GOLD, NamedTextColor.RED);
|
||||||
|
+ if (percentage > 0.2) return shift(percentage, 0.4, 0.2, NamedTextColor.RED, NamedTextColor.DARK_GRAY);
|
||||||
|
+ return shift(percentage, 0.2, 0.0, NamedTextColor.DARK_GRAY, NamedTextColor.BLACK);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private static TextColor shift(double percentage, double from, double to, TextColor fromColour, TextColor toColour) {
|
||||||
|
+ var f = (float) ((percentage - from) / (to - from));
|
||||||
|
+ return TextColor.lerp(Math.max(f, 0.0f), fromColour, toColour);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public static double format(double num, int decimals) {
|
||||||
|
+ var pow = Math.pow(10, decimals);
|
||||||
|
+ return Math.round(num * pow) / pow;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private enum Parts {
|
||||||
|
+ // Adventure doesn't have a Component.text(String, TextDecoration)
|
||||||
|
+ BACKGROUND(Component.text("::", NamedTextColor.BLACK)),
|
||||||
|
+ NORMAL(Component.text(" ").decorate(TextDecoration.STRIKETHROUGH)),
|
||||||
|
+ VERTICAL(Component.text("||")),
|
||||||
|
+ RISING(Component.text(".").decorate(TextDecoration.STRIKETHROUGH).append(Component.text("'").decoration(TextDecoration.STRIKETHROUGH, false))),
|
||||||
|
+ DECLINING(Component.text("'").append(Component.text(".").decorate(TextDecoration.STRIKETHROUGH))),
|
||||||
|
+ SPIKE_TOP_LEFT(Component.text(".!")),
|
||||||
|
+ SPIKE_TOP_RIGHT(Component.text("!.")),
|
||||||
|
+ SPIKE_BOTTOM_LEFT(Component.text("'!")),
|
||||||
|
+ SPIKE_BOTTOM_RIGHT(Component.text("!'")),
|
||||||
|
+ TOP(Component.text("''")),
|
||||||
|
+ BOTTOM(Component.text("..")),
|
||||||
|
+ ;
|
||||||
|
+
|
||||||
|
+ private final Component part;
|
||||||
|
+
|
||||||
|
+ Parts(Component component) {
|
||||||
|
+ part = component;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public Component getPart() {
|
||||||
|
+ return part;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/me/samsuik/sakura/utils/tps/TickTracking.java b/src/main/java/me/samsuik/sakura/utils/tps/TickTracking.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..8a94b1a2cb1ff57664c97a7b471c99ec391103ae
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/me/samsuik/sakura/utils/tps/TickTracking.java
|
||||||
|
@@ -0,0 +1,53 @@
|
||||||
|
+package me.samsuik.sakura.utils.tps;
|
||||||
|
+
|
||||||
|
+import net.minecraft.server.level.ServerLevel;
|
||||||
|
+
|
||||||
|
+import java.util.ArrayList;
|
||||||
|
+import java.util.Arrays;
|
||||||
|
+import java.util.Collection;
|
||||||
|
+import java.util.List;
|
||||||
|
+import java.util.stream.IntStream;
|
||||||
|
+
|
||||||
|
+public class TickTracking {
|
||||||
|
+
|
||||||
|
+ private final List<Point> history = new ArrayList<>();
|
||||||
|
+ private final double[] msptSamples = new double[20];
|
||||||
|
+
|
||||||
|
+ public TickTracking(int samples) {
|
||||||
|
+ for (int i = 0; i < samples; ++i) {
|
||||||
|
+ history.add(new Point(0.0, 0.0,0.0, 0, 0));
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ Point point(int at) {
|
||||||
|
+ return history.get(at);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public double averageTps(int samples) {
|
||||||
|
+ return IntStream.range(0, samples)
|
||||||
|
+ .mapToDouble(i -> history.get(i).tps)
|
||||||
|
+ .average()
|
||||||
|
+ .orElse(0.0);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void secondSample(Collection<ServerLevel> server, double tps) {
|
||||||
|
+ history.remove(history.size() - 1);
|
||||||
|
+
|
||||||
|
+ int entities = server.stream().mapToInt((world) -> world.entityTickList.entityCount()).sum();
|
||||||
|
+ int loaded = server.stream().mapToInt((world) -> world.chunkSource.actualLoadedChunkCount()).sum();
|
||||||
|
+
|
||||||
|
+ double mspt = Arrays.stream(msptSamples).average().orElse(0.0);
|
||||||
|
+ double max = Arrays.stream(msptSamples).max().orElse(0.0);
|
||||||
|
+
|
||||||
|
+ history.add(0, new Point(tps, mspt, max, entities, loaded));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void tickSample(long mspt) {
|
||||||
|
+ for (int i = msptSamples.length - 2; i >= 0; --i)
|
||||||
|
+ msptSamples[i + 1] = msptSamples[i];
|
||||||
|
+ msptSamples[0] = mspt;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public record Point(double tps, double mspt, double highest, int entities, int chunks) {}
|
||||||
|
+
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
index 4535beab09310915b0239b01c1b807f1ca25d959..eef411f838ecdeff0d4052fac22900e4ad87ceb5 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
@@ -1080,6 +1080,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private static final java.math.BigDecimal TPS_BASE = new java.math.BigDecimal(1E9).multiply(new java.math.BigDecimal(SAMPLE_INTERVAL));
|
||||||
|
+ public static final me.samsuik.sakura.utils.tps.TickTracking tickTracking = new me.samsuik.sakura.utils.tps.TickTracking(120); // Sakura - TPS Graph
|
||||||
|
// Paper End
|
||||||
|
// Spigot End
|
||||||
|
|
||||||
|
@@ -1136,6 +1137,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||||
|
{
|
||||||
|
final long diff = curTime - tickSection;
|
||||||
|
java.math.BigDecimal currentTps = TPS_BASE.divide(new java.math.BigDecimal(diff), 30, java.math.RoundingMode.HALF_UP);
|
||||||
|
+ tickTracking.secondSample(levels.values(), currentTps.doubleValue()); // Sakura
|
||||||
|
tps1.add(currentTps, diff);
|
||||||
|
tps5.add(currentTps, diff);
|
||||||
|
tps15.add(currentTps, diff);
|
||||||
|
@@ -1159,6 +1161,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||||
|
this.startMetricsRecordingTick();
|
||||||
|
this.profiler.push("tick");
|
||||||
|
this.tickServer(this::haveTime);
|
||||||
|
+ tickTracking.tickSample((System.nanoTime() - curTime) / 1_000_000L); // Sakura
|
||||||
|
this.profiler.popPush("nextTickWait");
|
||||||
|
this.mayHaveDelayedTasks = true;
|
||||||
|
this.delayedTasksMaxNextTickTime = Math.max(Util.getMillis() + 50L, this.nextTickTime);
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||||
|
index 17b6925b46f8386dcfc561483693de516465ec12..3a925f6bd215f14878bd397aa3f0d7b6eda92ce1 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||||
|
@@ -76,6 +76,12 @@ public class ServerChunkCache extends ChunkSource {
|
||||||
|
|
||||||
|
private final LevelChunk[] lastLoadedChunks = new LevelChunk[4 * 4];
|
||||||
|
|
||||||
|
+ // Sakura start - there's another method with the same name that returns how many chunks players have loaded
|
||||||
|
+ public int actualLoadedChunkCount() {
|
||||||
|
+ return loadedChunkMap.size();
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
+
|
||||||
|
private static int getChunkCacheKey(int x, int z) {
|
||||||
|
return x & 3 | ((z & 3) << 2);
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
index a9cd388c7ebb377511f59398b8f31a04d7abe493..bc73d8625ac296372640f540ade170aed8ae5353 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
@@ -192,7 +192,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||||
|
public final ServerChunkCache chunkSource;
|
||||||
|
private final MinecraftServer server;
|
||||||
|
public final PrimaryLevelData serverLevelData; // CraftBukkit - type
|
||||||
|
- final EntityTickList entityTickList;
|
||||||
|
+ public final EntityTickList entityTickList; // Sakura - public!
|
||||||
|
//public final PersistentEntitySectionManager<Entity> entityManager; // Paper - rewrite chunk system
|
||||||
|
private final GameEventDispatcher gameEventDispatcher;
|
||||||
|
public boolean noSave;
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/entity/EntityTickList.java b/src/main/java/net/minecraft/world/level/entity/EntityTickList.java
|
||||||
|
index 4cdfc433df67afcd455422e9baf56f167dd712ae..1fcce60790cab6e7b137464ccd87e6782a5ae98c 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/entity/EntityTickList.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/entity/EntityTickList.java
|
||||||
|
@@ -10,6 +10,12 @@ import net.minecraft.world.entity.Entity;
|
||||||
|
public class EntityTickList {
|
||||||
|
private final io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<Entity> entities = new io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<>(true); // Paper - rewrite this, always keep this updated - why would we EVER tick an entity that's not ticking?
|
||||||
|
|
||||||
|
+ // Sakura start
|
||||||
|
+ public int entityCount() {
|
||||||
|
+ return entities.size();
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
+
|
||||||
|
private void ensureActiveIsNotIterated() {
|
||||||
|
// Paper - replace with better logic, do not delay removals
|
||||||
|
|
||||||
|
diff --git a/src/main/java/org/spigotmc/SpigotConfig.java b/src/main/java/org/spigotmc/SpigotConfig.java
|
||||||
|
index 612c3169c3463d702b85975e1db79ae6e47d60d0..2063a6c6ab0786aee51be027950c2a936f593b55 100644
|
||||||
|
--- a/src/main/java/org/spigotmc/SpigotConfig.java
|
||||||
|
+++ b/src/main/java/org/spigotmc/SpigotConfig.java
|
||||||
|
@@ -283,7 +283,7 @@ public class SpigotConfig
|
||||||
|
|
||||||
|
private static void tpsCommand()
|
||||||
|
{
|
||||||
|
- SpigotConfig.commands.put( "tps", new TicksPerSecondCommand( "tps" ) );
|
||||||
|
+ // SpigotConfig.commands.put( "tps", new TicksPerSecondCommand( "tps" ) ); // Sakura - TPS Graph
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int playerSample;
|
||||||
66
patches/server/0011-Optimise-New-Liquid-Level.patch
Normal file
66
patches/server/0011-Optimise-New-Liquid-Level.patch
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Samsuik <kfian294ma4@gmail.com>
|
||||||
|
Date: Wed, 6 Oct 2021 17:25:27 +0100
|
||||||
|
Subject: [PATCH] Optimise New Liquid Level
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/material/FlowingFluid.java b/src/main/java/net/minecraft/world/level/material/FlowingFluid.java
|
||||||
|
index e21f4c5aff3a8e97101f6efc1349fbecf326b5ea..6d59f8b68d644cb43939bcdf5239fa1caf54ed47 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/material/FlowingFluid.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/material/FlowingFluid.java
|
||||||
|
@@ -137,7 +137,7 @@ public abstract class FlowingFluid extends Fluid {
|
||||||
|
BlockState iblockdata = world.getBlockState(fluidPos);
|
||||||
|
BlockPos blockposition1 = fluidPos.below();
|
||||||
|
BlockState iblockdata1 = world.getBlockState(blockposition1);
|
||||||
|
- FluidState fluid1 = this.getNewLiquid(world, blockposition1, iblockdata1);
|
||||||
|
+ FluidState fluid1 = this.getLiquid(world, blockposition1, iblockdata1, fluidPos, iblockdata); // Sakura - optimise liquid level
|
||||||
|
|
||||||
|
if (this.canSpreadTo(world, fluidPos, iblockdata, Direction.DOWN, blockposition1, iblockdata1, world.getFluidState(blockposition1), fluid1.getType())) {
|
||||||
|
// CraftBukkit start
|
||||||
|
@@ -197,6 +197,25 @@ public abstract class FlowingFluid extends Fluid {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected FluidState getNewLiquid(Level world, BlockPos pos, BlockState state) {
|
||||||
|
+ // Sakura start - optimise liquid level
|
||||||
|
+ BlockPos blockposition2 = pos.above();
|
||||||
|
+ BlockState iblockdata3 = world.getBlockState(blockposition2);
|
||||||
|
+
|
||||||
|
+ return getLiquid(world, pos, state, blockposition2, iblockdata3);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // SANITY: world, pos, state, above pos, above state
|
||||||
|
+ protected FluidState getLiquid(Level world, BlockPos pos, BlockState state, BlockPos blockposition2, BlockState iblockdata3) {
|
||||||
|
+ FluidState fluid2 = iblockdata3.getFluidState();
|
||||||
|
+
|
||||||
|
+ if (!fluid2.isEmpty() && fluid2.getType().isSame(this) && this.canPassThroughWall(Direction.UP, world, pos, state, blockposition2, iblockdata3)) {
|
||||||
|
+ return this.getFlowing(8, true);
|
||||||
|
+ } else {
|
||||||
|
+ return this.getLiquidFromSurroundings(world, pos, state);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ protected FluidState getLiquidFromSurroundings(Level world, BlockPos pos, BlockState state) {
|
||||||
|
int i = 0;
|
||||||
|
int j = 0;
|
||||||
|
Iterator iterator = Direction.Plane.HORIZONTAL.iterator();
|
||||||
|
@@ -227,17 +246,10 @@ public abstract class FlowingFluid extends Fluid {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- BlockPos blockposition2 = pos.above();
|
||||||
|
- BlockState iblockdata3 = world.getBlockState(blockposition2);
|
||||||
|
- FluidState fluid2 = iblockdata3.getFluidState();
|
||||||
|
+ int k = i - this.getDropOff(world);
|
||||||
|
|
||||||
|
- if (!fluid2.isEmpty() && fluid2.getType().isSame(this) && this.canPassThroughWall(Direction.UP, world, pos, state, blockposition2, iblockdata3)) {
|
||||||
|
- return this.getFlowing(8, true);
|
||||||
|
- } else {
|
||||||
|
- int k = i - this.getDropOff(world);
|
||||||
|
-
|
||||||
|
- return k <= 0 ? Fluids.EMPTY.defaultFluidState() : this.getFlowing(k, false);
|
||||||
|
- }
|
||||||
|
+ return k <= 0 ? Fluids.EMPTY.defaultFluidState() : this.getFlowing(k, false);
|
||||||
|
+ // Sakura end
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean canPassThroughWall(Direction face, BlockGetter world, BlockPos pos, BlockState state, BlockPos fromPos, BlockState fromState) {
|
||||||
291
patches/server/0012-Slice-Packet-obfuscation-and-reduction.patch
Normal file
291
patches/server/0012-Slice-Packet-obfuscation-and-reduction.patch
Normal file
@@ -0,0 +1,291 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Cryptite <cryptite@gmail.com>
|
||||||
|
Date: Wed, 6 Oct 2021 11:03:01 -0500
|
||||||
|
Subject: [PATCH] (Slice) Packet obfuscation and reduction
|
||||||
|
|
||||||
|
Minecraft is overzealous about packet updates for Entities. In Loka's case, we want to reduce as many unnecessary
|
||||||
|
packet updates as possible. This patch is likely to be updated over and over in terms of reducing packet sends.
|
||||||
|
|
||||||
|
In summary, this patch creates the concept of a "foreignValue" of a packet's data. We treat packets in two ways:
|
||||||
|
1) The packet sent to the player itself (the normal way). This always has all of the values as usual.
|
||||||
|
2) The packet data as seen by any other (foreign) players.
|
||||||
|
|
||||||
|
This patch adds the ability to set a "foreignValue" for an entity value so as to obfuscate data received by other players.
|
||||||
|
The current packets modified/obfuscated are the following:
|
||||||
|
|
||||||
|
# This reduces the amount of health packet updates as well which is great for players in combat.
|
||||||
|
|
||||||
|
# Air level packets are sent PER-TICK, and as such a player with any change in air level will only spam themselves
|
||||||
|
# with packets instead of every single player within tracking distance
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/network/syncher/SynchedEntityData.java b/src/main/java/net/minecraft/network/syncher/SynchedEntityData.java
|
||||||
|
index 5dfb35117c285e0b202dc9c088ad5848beb8d054..e24dd4c7108a014533e5731ad2dafc51a55ebf6d 100644
|
||||||
|
--- a/src/main/java/net/minecraft/network/syncher/SynchedEntityData.java
|
||||||
|
+++ b/src/main/java/net/minecraft/network/syncher/SynchedEntityData.java
|
||||||
|
@@ -39,6 +39,7 @@ public class SynchedEntityData {
|
||||||
|
private static final int GROW_FACTOR = 8;
|
||||||
|
private SynchedEntityData.DataItem<?>[] itemsArray = new SynchedEntityData.DataItem<?>[DEFAULT_ENTRY_COUNT];
|
||||||
|
// Paper end
|
||||||
|
+ private boolean isForeignDirty; // Slice
|
||||||
|
|
||||||
|
public SynchedEntityData(Entity trackedEntity) {
|
||||||
|
this.entity = trackedEntity;
|
||||||
|
@@ -165,6 +166,16 @@ public class SynchedEntityData {
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> void set(EntityDataAccessor<T> key, T value, boolean force) {
|
||||||
|
+ // Slice start
|
||||||
|
+ this.set(key, value, null, force);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public <T> void set(EntityDataAccessor<T> key, T value, T foreignValue) {
|
||||||
|
+ this.set(key, value, foreignValue, false);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public <T> void set(EntityDataAccessor<T> key, T value, T foreignValue, boolean force) {
|
||||||
|
+ // Slice end
|
||||||
|
SynchedEntityData.DataItem<T> datawatcher_item = this.getItem(key);
|
||||||
|
|
||||||
|
if (force || ObjectUtils.notEqual(value, datawatcher_item.getValue())) {
|
||||||
|
@@ -174,6 +185,12 @@ public class SynchedEntityData {
|
||||||
|
this.isDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Slice start
|
||||||
|
+ if (foreignValue != null && ObjectUtils.notEqual(foreignValue, datawatcher_item.getForeignValue())) {
|
||||||
|
+ datawatcher_item.setForeignValue(foreignValue);
|
||||||
|
+ this.isForeignDirty = true;
|
||||||
|
+ }
|
||||||
|
+ // Slice end
|
||||||
|
}
|
||||||
|
|
||||||
|
// CraftBukkit start - add method from above
|
||||||
|
@@ -183,6 +200,12 @@ public class SynchedEntityData {
|
||||||
|
}
|
||||||
|
// CraftBukkit end
|
||||||
|
|
||||||
|
+ // Slice start
|
||||||
|
+ public boolean isForeignDirty() {
|
||||||
|
+ return this.isForeignDirty;
|
||||||
|
+ }
|
||||||
|
+ // Slice end
|
||||||
|
+
|
||||||
|
public boolean isDirty() {
|
||||||
|
return this.isDirty;
|
||||||
|
}
|
||||||
|
@@ -215,6 +238,29 @@ public class SynchedEntityData {
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Slice start
|
||||||
|
+ @Nullable
|
||||||
|
+ public List<SynchedEntityData.DataValue<?>> packForeignDirty(List<DataValue<?>> unpackedData) {
|
||||||
|
+ List<SynchedEntityData.DataValue<?>> list = null;
|
||||||
|
+
|
||||||
|
+ for (DataValue<?> dataItem : unpackedData) {
|
||||||
|
+ DataItem<?> item = itemsById.get(dataItem.id());
|
||||||
|
+ if (item.isDirty(true)) {
|
||||||
|
+ item.setForeignDirty(false);
|
||||||
|
+
|
||||||
|
+ if (list == null) {
|
||||||
|
+ list = new ArrayList<>();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ list.add(item.copy(true));
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ this.isForeignDirty = false;
|
||||||
|
+ return list;
|
||||||
|
+ }
|
||||||
|
+ // Slice end
|
||||||
|
+
|
||||||
|
@Nullable
|
||||||
|
public List<SynchedEntityData.DataValue<?>> getNonDefaultValues() {
|
||||||
|
List<SynchedEntityData.DataValue<?>> list = null;
|
||||||
|
@@ -336,11 +382,14 @@ public class SynchedEntityData {
|
||||||
|
T value;
|
||||||
|
private final T initialValue;
|
||||||
|
private boolean dirty;
|
||||||
|
+ @Nullable T foreignValue = null; // Slice
|
||||||
|
+ private boolean foreignDirty; // Slice
|
||||||
|
|
||||||
|
public DataItem(EntityDataAccessor<T> data, T value) {
|
||||||
|
this.accessor = data;
|
||||||
|
this.initialValue = value;
|
||||||
|
this.value = value;
|
||||||
|
+ this.foreignDirty = true; // Slice
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntityDataAccessor<T> getAccessor() {
|
||||||
|
@@ -367,6 +416,35 @@ public class SynchedEntityData {
|
||||||
|
return this.initialValue.equals(this.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Slice start
|
||||||
|
+ public void setForeignValue(T foreignValue) {
|
||||||
|
+ this.foreignValue = foreignValue;
|
||||||
|
+ this.foreignDirty = true;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public @Nullable T getForeignValue() {
|
||||||
|
+ return foreignValue;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public boolean isDirty(boolean foreign) {
|
||||||
|
+ if (foreign) {
|
||||||
|
+ //There must be a foreign value in order for this to be dirty, otherwise we consider this a normal
|
||||||
|
+ //value and check the normal dirty flag.
|
||||||
|
+ return foreignValue == null || this.foreignDirty;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return this.dirty;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void setForeignDirty(boolean dirty) {
|
||||||
|
+ this.foreignDirty = dirty;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public SynchedEntityData.DataValue<T> copy(boolean foreign) {
|
||||||
|
+ return SynchedEntityData.DataValue.create(this.accessor, this.accessor.getSerializer().copy((foreign && this.foreignValue != null ? this.foreignValue : this.value)));
|
||||||
|
+ }
|
||||||
|
+ // Slice end
|
||||||
|
+
|
||||||
|
public SynchedEntityData.DataValue<T> value() {
|
||||||
|
return SynchedEntityData.DataValue.create(this.accessor, this.value);
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||||
|
index 83c4639c2bdca4dc4281d9f5eca104af3063bfa5..f7d8aaededd39ce52a9d0105f66fd759635b5288 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||||
|
@@ -148,7 +148,7 @@ public class ServerEntity {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (this.tickCount % this.updateInterval == 0 || this.entity.hasImpulse || this.entity.getEntityData().isDirty()) {
|
||||||
|
+ if (this.tickCount % this.updateInterval == 0 || this.entity.hasImpulse || this.entity.getEntityData().isForeignDirty()) { // Slice
|
||||||
|
int i;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
@@ -395,11 +395,23 @@ public class ServerEntity {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sakura start - visibility api
|
||||||
|
- private void broadcastEntityData(List<SynchedEntityData.DataValue<?>> packedValues) {
|
||||||
|
+ private void broadcastEntityData(SynchedEntityData datawatcher, List<SynchedEntityData.DataValue<?>> packedValues) {
|
||||||
|
Packet<?> packet0 = new ClientboundSetEntityDataPacket(this.entity.getId(), packedValues);
|
||||||
|
Packet<?> packet1 = null;
|
||||||
|
|
||||||
|
- if (this.entity.isPrimedTNT) {
|
||||||
|
+ // Slice start
|
||||||
|
+ if (this.entity instanceof ServerPlayer serverPlayer) {
|
||||||
|
+ serverPlayer.connection.send(packet0);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ packedValues = datawatcher.packForeignDirty(packedValues);
|
||||||
|
+
|
||||||
|
+ if (packedValues != null) {
|
||||||
|
+ packet0 = new ClientboundSetEntityDataPacket(this.entity.getId(), packedValues);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (packedValues != null && this.entity.isPrimedTNT) {
|
||||||
|
+ // Slice end
|
||||||
|
var copyOfDirtyItems = Lists.newArrayList(packedValues);
|
||||||
|
copyOfDirtyItems.removeIf((data) -> data.id() == 8);
|
||||||
|
|
||||||
|
@@ -426,7 +438,7 @@ public class ServerEntity {
|
||||||
|
|
||||||
|
if (list != null) {
|
||||||
|
this.trackedDataValues = datawatcher.getNonDefaultValues();
|
||||||
|
- this.broadcastEntityData(list); // Sakura - visibility api
|
||||||
|
+ this.broadcastEntityData(datawatcher, list); // Sakura - visibility api
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.entity instanceof LivingEntity) {
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
index c35ca0785ecc268fb7e20dee56d42bdadca41ee6..217eba9f4860cf1e67d307ba8cdb99430c7469f8 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
@@ -3321,7 +3321,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||||
|
this.entityData.markDirty(Entity.DATA_AIR_SUPPLY_ID);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
- this.entityData.set(Entity.DATA_AIR_SUPPLY_ID, event.getAmount());
|
||||||
|
+ this.entityData.set(Entity.DATA_AIR_SUPPLY_ID, event.getAmount(), getMaxAirSupply()); // Slice
|
||||||
|
// CraftBukkit end
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -3330,7 +3330,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTicksFrozen(int frozenTicks) {
|
||||||
|
- this.entityData.set(Entity.DATA_TICKS_FROZEN, frozenTicks);
|
||||||
|
+ this.entityData.set(Entity.DATA_TICKS_FROZEN, (frozenTicks / 10) * 10); // Slice
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getPercentFrozen() {
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/animal/Bee.java b/src/main/java/net/minecraft/world/entity/animal/Bee.java
|
||||||
|
index 9a7956befc346e1b58f064213800fd099a052fc6..6a794d672621d31f4fc7b3c44907fe3976420ca1 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/animal/Bee.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java
|
||||||
|
@@ -427,7 +427,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRemainingPersistentAngerTime(int angerTime) {
|
||||||
|
- this.entityData.set(Bee.DATA_REMAINING_ANGER_TIME, angerTime);
|
||||||
|
+ this.entityData.set(Bee.DATA_REMAINING_ANGER_TIME, angerTime, (angerTime / 20) * 20); // Slice
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||||
|
index 4c328a511ff6c0e6b73ef9701c82373e02c12830..fbeb52a49b791f992af19c7d69ba44b820541b09 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||||
|
@@ -172,7 +172,7 @@ public class PrimedTnt extends Entity implements TraceableEntity {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFuse(int fuse) {
|
||||||
|
- this.entityData.set(PrimedTnt.DATA_FUSE_ID, fuse);
|
||||||
|
+ this.entityData.set(PrimedTnt.DATA_FUSE_ID, fuse, (fuse / 10) * 10); // Slice
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFuse() {
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||||
|
index d58b4c0dbe651b5068212e5f14dce3164ee520f5..c69660c3c49e6d21e8d31dbe16906bd152b61d3f 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||||
|
@@ -649,7 +649,7 @@ public abstract class Player extends LivingEntity {
|
||||||
|
public void increaseScore(int score) {
|
||||||
|
int j = this.getScore();
|
||||||
|
|
||||||
|
- this.entityData.set(Player.DATA_SCORE_ID, j + score);
|
||||||
|
+ this.entityData.set(Player.DATA_SCORE_ID, j + score, 0); // Slice
|
||||||
|
}
|
||||||
|
|
||||||
|
public void startAutoSpinAttack(int riptideTicks) {
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/vehicle/Boat.java b/src/main/java/net/minecraft/world/entity/vehicle/Boat.java
|
||||||
|
index 5c07da62c82bc70138f6cb5007629d6974be69ac..974563607f6731e5c352fd03663d069ea888b7ef 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/vehicle/Boat.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/vehicle/Boat.java
|
||||||
|
@@ -973,7 +973,7 @@ public class Boat extends Entity implements VariantHolder<Boat.Type> {
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setBubbleTime(int wobbleTicks) {
|
||||||
|
- this.entityData.set(Boat.DATA_ID_BUBBLE_TIME, wobbleTicks);
|
||||||
|
+ this.entityData.set(Boat.DATA_ID_BUBBLE_TIME, wobbleTicks, (wobbleTicks / 5) * 5); // Slice
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getBubbleTime() {
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||||
|
index 9ac026a464f8b5db5fe7543b71cd5bcaa3f65f70..fab6b511319a9891277fd001cfa06a6c802c45bc 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||||
|
@@ -2606,7 +2606,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||||
|
this.sendHealthUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- this.getHandle().getEntityData().set(net.minecraft.world.entity.LivingEntity.DATA_HEALTH_ID, (float) this.getScaledHealth());
|
||||||
|
+ this.getHandle().getEntityData().set(net.minecraft.world.entity.LivingEntity.DATA_HEALTH_ID, (float) this.getScaledHealth(), isDead() ? 0f : 20f); // Slice
|
||||||
|
|
||||||
|
this.getHandle().maxHealthCache = getMaxHealth();
|
||||||
|
}
|
||||||
35
patches/server/0013-Use-Optimised-TrackedEntityMap.patch
Normal file
35
patches/server/0013-Use-Optimised-TrackedEntityMap.patch
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
|
||||||
|
Date: Thu, 3 Aug 2023 12:54:52 +0100
|
||||||
|
Subject: [PATCH] Use Optimised TrackedEntityMap
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/me/samsuik/sakura/utils/collections/TrackedEntityChunkMap.java b/src/main/java/me/samsuik/sakura/utils/collections/TrackedEntityChunkMap.java
|
||||||
|
index 8f4ac8acd2e0752e7a615d152b8047d790947b9f..1394adbe98a24f74fc7892e1b39ab1502fe082c1 100644
|
||||||
|
--- a/src/main/java/me/samsuik/sakura/utils/collections/TrackedEntityChunkMap.java
|
||||||
|
+++ b/src/main/java/me/samsuik/sakura/utils/collections/TrackedEntityChunkMap.java
|
||||||
|
@@ -17,8 +17,9 @@ public class TrackedEntityChunkMap extends Int2ObjectOpenHashMap<ChunkMap.Tracke
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChunkMap.TrackedEntity remove(int k) {
|
||||||
|
- entityList.remove(k);
|
||||||
|
- return super.remove(k);
|
||||||
|
+ var v = super.remove(k);
|
||||||
|
+ entityList.remove(v);
|
||||||
|
+ return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||||
|
index 45f0e7ef92c32dc51b81c0cc9f1d1a2fbab02599..e3ee8b66dfabb643c2b0d47bef20af4d8680e008 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||||
|
@@ -214,7 +214,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||||
|
// Paper - rewrite chunk system
|
||||||
|
this.tickingGenerated = new AtomicInteger();
|
||||||
|
this.playerMap = new PlayerMap();
|
||||||
|
- this.entityMap = new Int2ObjectOpenHashMap();
|
||||||
|
+ this.entityMap = new me.samsuik.sakura.utils.collections.TrackedEntityChunkMap(); // Sakura - optimised tracked entity map
|
||||||
|
this.chunkTypeCache = new Long2ByteOpenHashMap();
|
||||||
|
this.chunkSaveCooldowns = new Long2LongOpenHashMap();
|
||||||
|
this.unloadQueue = Queues.newConcurrentLinkedQueue();
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Samsuik <kfian294ma4@gmail.com>
|
||||||
|
Date: Thu, 14 Oct 2021 19:16:49 +0100
|
||||||
|
Subject: [PATCH] Copy EntityList methods to BasicEntityList
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java b/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java
|
||||||
|
index 7e8dc9e8f381abfdcce2746edc93122d623622d1..2d79633d86007c7d40eecf5f9271fa3f351b72b5 100644
|
||||||
|
--- a/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java
|
||||||
|
+++ b/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java
|
||||||
|
@@ -25,6 +25,8 @@ import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
+import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; // Sakura
|
||||||
|
+
|
||||||
|
public final class ChunkEntitySlices {
|
||||||
|
|
||||||
|
protected final int minSection;
|
||||||
|
@@ -303,6 +305,13 @@ public final class ChunkEntitySlices {
|
||||||
|
|
||||||
|
protected static final class BasicEntityList<E extends Entity> {
|
||||||
|
|
||||||
|
+ // Sakura start - copy entitylist methods across
|
||||||
|
+ protected final Int2IntOpenHashMap entityToIndex = new Int2IntOpenHashMap(2, 0.8f);
|
||||||
|
+ {
|
||||||
|
+ this.entityToIndex.defaultReturnValue(Integer.MIN_VALUE);
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
+
|
||||||
|
protected static final Entity[] EMPTY = new Entity[0];
|
||||||
|
protected static final int DEFAULT_CAPACITY = 4;
|
||||||
|
|
||||||
|
@@ -325,55 +334,52 @@ public final class ChunkEntitySlices {
|
||||||
|
return this.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
- private void resize() {
|
||||||
|
- if (this.storage == EMPTY) {
|
||||||
|
- this.storage = (E[])new Entity[DEFAULT_CAPACITY];
|
||||||
|
- } else {
|
||||||
|
- this.storage = Arrays.copyOf(this.storage, this.storage.length * 2);
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
+ // Sakura start - copy entitylist methods across
|
||||||
|
public void add(final E entity) {
|
||||||
|
- final int idx = this.size++;
|
||||||
|
- if (idx >= this.storage.length) {
|
||||||
|
- this.resize();
|
||||||
|
- this.storage[idx] = entity;
|
||||||
|
- } else {
|
||||||
|
- this.storage[idx] = entity;
|
||||||
|
+ final int count = this.size;
|
||||||
|
+ final int currIndex = this.entityToIndex.putIfAbsent(entity.getId(), count);
|
||||||
|
+
|
||||||
|
+ if (currIndex != Integer.MIN_VALUE) {
|
||||||
|
+ return; // already in this list
|
||||||
|
}
|
||||||
|
- }
|
||||||
|
|
||||||
|
- public int indexOf(final E entity) {
|
||||||
|
- final E[] storage = this.storage;
|
||||||
|
+ E[] list = this.storage;
|
||||||
|
|
||||||
|
- for (int i = 0, len = Math.min(this.storage.length, this.size); i < len; ++i) {
|
||||||
|
- if (storage[i] == entity) {
|
||||||
|
- return i;
|
||||||
|
- }
|
||||||
|
+ if (list.length == count) {
|
||||||
|
+ // resize required
|
||||||
|
+ list = this.storage = Arrays.copyOf(list, (int)Math.max(4L, count * 2L)); // overflow results in negative
|
||||||
|
}
|
||||||
|
|
||||||
|
- return -1;
|
||||||
|
+ list[count] = entity;
|
||||||
|
+ this.size = count + 1;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public int indexOf(final E entity) {
|
||||||
|
+ return this.entityToIndex.getOrDefault(entity.getId(), -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean remove(final E entity) {
|
||||||
|
- final int idx = this.indexOf(entity);
|
||||||
|
- if (idx == -1) {
|
||||||
|
+ final int index = this.entityToIndex.remove(entity.getId());
|
||||||
|
+ if (index == Integer.MIN_VALUE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
- final int size = --this.size;
|
||||||
|
- final E[] storage = this.storage;
|
||||||
|
- if (idx != size) {
|
||||||
|
- System.arraycopy(storage, idx + 1, storage, idx, size - idx);
|
||||||
|
+ // move the entity at the end to this index
|
||||||
|
+ final int endIndex = --this.size;
|
||||||
|
+ final E end = this.storage[endIndex];
|
||||||
|
+ if (index != endIndex) {
|
||||||
|
+ // not empty after this call
|
||||||
|
+ this.entityToIndex.put(end.getId(), index); // update index
|
||||||
|
}
|
||||||
|
-
|
||||||
|
- storage[size] = null;
|
||||||
|
+ this.storage[index] = end;
|
||||||
|
+ this.storage[endIndex] = null;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean has(final E entity) {
|
||||||
|
- return this.indexOf(entity) != -1;
|
||||||
|
+ return this.entityToIndex.containsKey(entity.getId());
|
||||||
|
+ // Sakura end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Samsuik <kfian294ma4@gmail.com>
|
||||||
|
Date: Fri, 15 Oct 2021 18:49:48 +0100
|
||||||
|
Subject: [PATCH] Optimise ClassInstanceMultiMap removals
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/util/ClassInstanceMultiMap.java b/src/main/java/net/minecraft/util/ClassInstanceMultiMap.java
|
||||||
|
index 5fb7573022c5af775b2e737dcd05c53cd9ae39ec..a3e5bf8355bbe8d4b8ee687abdb49a04fb39ae75 100644
|
||||||
|
--- a/src/main/java/net/minecraft/util/ClassInstanceMultiMap.java
|
||||||
|
+++ b/src/main/java/net/minecraft/util/ClassInstanceMultiMap.java
|
||||||
|
@@ -15,7 +15,7 @@ import java.util.stream.Collectors;
|
||||||
|
public class ClassInstanceMultiMap<T> extends AbstractCollection<T> {
|
||||||
|
private final Map<Class<?>, List<T>> byClass = Maps.newHashMap();
|
||||||
|
private final Class<T> baseClass;
|
||||||
|
- private final List<T> allInstances = Lists.newArrayList();
|
||||||
|
+ private final List<T> allInstances = new me.samsuik.sakura.utils.collections.UnorderedIndexedList<>(); // Sakura
|
||||||
|
|
||||||
|
public ClassInstanceMultiMap(Class<T> elementType) {
|
||||||
|
this.baseClass = elementType;
|
||||||
|
@@ -59,7 +59,15 @@ public class ClassInstanceMultiMap<T> extends AbstractCollection<T> {
|
||||||
|
throw new IllegalArgumentException("Don't know how to search for " + type);
|
||||||
|
} else {
|
||||||
|
List<? extends T> list = this.byClass.computeIfAbsent(type, (typeClass) -> {
|
||||||
|
- return this.allInstances.stream().filter(typeClass::isInstance).collect(Collectors.toList());
|
||||||
|
+ // Sakura start
|
||||||
|
+ List<T> result = new me.samsuik.sakura.utils.collections.UnorderedIndexedList<>();
|
||||||
|
+ for (T allInstance : this.allInstances) {
|
||||||
|
+ if (typeClass.isInstance(allInstance)) {
|
||||||
|
+ result.add(allInstance);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ return result;
|
||||||
|
+ // Sakura end
|
||||||
|
});
|
||||||
|
return (Collection<S>) Collections.unmodifiableCollection(list); // Sakura - decompile fix
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
|
||||||
|
Date: Thu, 3 Aug 2023 13:48:27 +0100
|
||||||
|
Subject: [PATCH] Add utility methods to EntitySlices
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java b/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java
|
||||||
|
index 2d79633d86007c7d40eecf5f9271fa3f351b72b5..d917a19c838ed3d74322abd85e1f737e852b5d7b 100644
|
||||||
|
--- a/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java
|
||||||
|
+++ b/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java
|
||||||
|
@@ -251,6 +251,12 @@ public final class ChunkEntitySlices {
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ // Sakura start
|
||||||
|
+ public Entity[] getSectionEntities(int sectionY) {
|
||||||
|
+ return this.allEntities.getSectionEntities(sectionY);
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
|
||||||
|
public void getHardCollidingEntities(final Entity except, final AABB box, final List<Entity> into, final Predicate<? super Entity> predicate) {
|
||||||
|
this.hardCollidingEntities.getEntities(except, box, into, predicate);
|
||||||
|
@@ -429,6 +435,18 @@ public final class ChunkEntitySlices {
|
||||||
|
this.nonEmptyBitset[sectionIndex >>> 6] ^= (1L << (sectionIndex & (Long.SIZE - 1)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ // Sakura start
|
||||||
|
+ public Entity[] getSectionEntities(int sectionY) {
|
||||||
|
+ var list = entitiesBySection[sectionY - this.manager.minSection];
|
||||||
|
+
|
||||||
|
+ if (list != null) {
|
||||||
|
+ return list.storage;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return new Entity[0];
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
|
||||||
|
public void getEntities(final Entity except, final AABB box, final List<Entity> into, final Predicate<? super Entity> predicate) {
|
||||||
|
if (this.count == 0) {
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
index 9e49196f7038c710e850005b6ad96c4eafca0f2e..a29d41bf162c923e3b3b15e7500e0c8693908866 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
@@ -218,6 +218,16 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||||
|
|
||||||
|
public final it.unimi.dsi.fastutil.longs.Long2IntMap minimalTNT = new it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap(); // Sakura - visibility api
|
||||||
|
|
||||||
|
+ // Sakura start
|
||||||
|
+ public Entity[] getSectionEntities(int chunkX, int chunkY, int chunkZ) {
|
||||||
|
+ var slices = ((ServerLevel)this).getEntityLookup().getChunk(chunkX, chunkZ);
|
||||||
|
+ if (slices == null) {
|
||||||
|
+ return new Entity[0];
|
||||||
|
+ }
|
||||||
|
+ return slices.getSectionEntities(chunkY);
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
+
|
||||||
|
protected Level(WritableLevelData worlddatamutable, ResourceKey<Level> resourcekey, RegistryAccess iregistrycustom, Holder<DimensionType> holder, Supplier<ProfilerFiller> supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function<org.spigotmc.SpigotWorldConfig, io.papermc.paper.configuration.WorldConfiguration> paperWorldConfigCreator, Supplier<me.samsuik.sakura.configuration.WorldConfiguration> sakuraWorldConfigCreator, java.util.concurrent.Executor executor) { // Sakura // Paper - Async-Anti-Xray - Pass executor
|
||||||
|
this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot
|
||||||
|
this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper
|
||||||
104
patches/server/0017-Store-Entity-Data-State.patch
Normal file
104
patches/server/0017-Store-Entity-Data-State.patch
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
|
||||||
|
Date: Wed, 16 Aug 2023 22:34:49 +0100
|
||||||
|
Subject: [PATCH] Store Entity Data/State
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/me/samsuik/sakura/entity/EntityState.java b/src/main/java/me/samsuik/sakura/entity/EntityState.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..c9f2c5ae57878283e8c8bc3847fe63b98f4e8d10
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/me/samsuik/sakura/entity/EntityState.java
|
||||||
|
@@ -0,0 +1,41 @@
|
||||||
|
+package me.samsuik.sakura.entity;
|
||||||
|
+
|
||||||
|
+import net.minecraft.core.BlockPos;
|
||||||
|
+import net.minecraft.world.entity.Entity;
|
||||||
|
+import net.minecraft.world.phys.AABB;
|
||||||
|
+import net.minecraft.world.phys.Vec3;
|
||||||
|
+
|
||||||
|
+import java.util.Optional;
|
||||||
|
+
|
||||||
|
+public record EntityState(Vec3 position, Vec3 momentum, AABB bb, Vec3 stuckSpeed, Optional<BlockPos> supportingPos, boolean onGround, float fallDistance) {
|
||||||
|
+
|
||||||
|
+ public static EntityState of(Entity entity) {
|
||||||
|
+ return new EntityState(entity.position(), entity.getDeltaMovement(), entity.getBoundingBox(), entity.stuckSpeedMultiplier(), entity.mainSupportingBlockPos, entity.onGround(), entity.fallDistance);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void apply(Entity entity) {
|
||||||
|
+ entity.setPos(position);
|
||||||
|
+ entity.setDeltaMovement(momentum);
|
||||||
|
+ entity.setBoundingBox(bb);
|
||||||
|
+ // null here is only safe for our use case (tnt and sand)
|
||||||
|
+ //noinspection DataFlowIssue
|
||||||
|
+ entity.makeStuckInBlock(null, stuckSpeed);
|
||||||
|
+ entity.onGround = onGround;
|
||||||
|
+ entity.mainSupportingBlockPos = supportingPos;
|
||||||
|
+ entity.fallDistance = fallDistance;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void position(Entity entity) {
|
||||||
|
+ entity.setPos(position);
|
||||||
|
+ entity.setBoundingBox(bb);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public boolean isCurrentState(Entity entity) {
|
||||||
|
+ return entity.position().equals(position)
|
||||||
|
+ && entity.getDeltaMovement().equals(momentum);
|
||||||
|
+ // 1.14+ versions seem to correct morphed bounding boxes after a gametick.
|
||||||
|
+ // If there are any related issues uncomment this line of code.
|
||||||
|
+ // && entity.getBoundingBox().equals(bb);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
index 217eba9f4860cf1e67d307ba8cdb99430c7469f8..7e906ad87ae48942445b6ad1fa22ab9442c8943e 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
@@ -531,6 +531,34 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||||
|
// Paper end - make end portalling safe
|
||||||
|
public boolean isPrimedTNT; // Sakura
|
||||||
|
public boolean isFallingBlock; // Sakura
|
||||||
|
+ // Sakura start - entity state (from start of tick)
|
||||||
|
+ private @Nullable me.samsuik.sakura.entity.EntityState entityState = null;
|
||||||
|
+
|
||||||
|
+ public Vec3 stuckSpeedMultiplier() {
|
||||||
|
+ return stuckSpeedMultiplier;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void storeEntityState() {
|
||||||
|
+ entityState = me.samsuik.sakura.entity.EntityState.of(this);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public @Nullable me.samsuik.sakura.entity.EntityState entityState() {
|
||||||
|
+ return entityState;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public boolean compareState(Entity to) {
|
||||||
|
+ return to.entityState() != null && to.entityState().isCurrentState(this);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public long getPackedOrigin() {
|
||||||
|
+ var v = getOriginVector();
|
||||||
|
+ if (v == null) return Long.MIN_VALUE;
|
||||||
|
+ // Note: vector#getBlockN may not be 100% exact
|
||||||
|
+ // If there's any future issues at let's say 0.999999...
|
||||||
|
+ // giving an incorrect position change it to Mth instead.
|
||||||
|
+ return BlockPos.asLong(v.getBlockX(), v.getBlockY(), v.getBlockZ());
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
|
||||||
|
public Entity(EntityType<?> type, Level world) {
|
||||||
|
this.id = Entity.ENTITY_COUNTER.incrementAndGet();
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
index a29d41bf162c923e3b3b15e7500e0c8693908866..6d9a15a1c1faff57103757b6ff71f38e4713ef71 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
@@ -1325,6 +1325,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||||
|
|
||||||
|
public <T extends Entity> void guardEntityTick(Consumer<T> tickConsumer, T entity) {
|
||||||
|
try {
|
||||||
|
+ entity.storeEntityState(); // Sakura - store entity state
|
||||||
|
tickConsumer.accept(entity);
|
||||||
|
MinecraftServer.getServer().executeMidTickTasks(); // Paper - execute chunk tasks mid tick
|
||||||
|
} catch (Throwable throwable) {
|
||||||
619
patches/server/0018-Merge-Cannon-Entities.patch
Normal file
619
patches/server/0018-Merge-Cannon-Entities.patch
Normal file
@@ -0,0 +1,619 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
|
||||||
|
Date: Sat, 9 Sep 2023 18:39:15 +0100
|
||||||
|
Subject: [PATCH] Merge Cannon Entities
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/me/samsuik/sakura/entity/merge/MergeHistory.java b/src/main/java/me/samsuik/sakura/entity/merge/MergeHistory.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..794547b36f0780b4dd300fc162cd9b7018c38edb
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/me/samsuik/sakura/entity/merge/MergeHistory.java
|
||||||
|
@@ -0,0 +1,155 @@
|
||||||
|
+package me.samsuik.sakura.entity.merge;
|
||||||
|
+
|
||||||
|
+import it.unimi.dsi.fastutil.HashCommon;
|
||||||
|
+import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||||
|
+import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||||
|
+import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||||
|
+import it.unimi.dsi.fastutil.longs.LongSet;
|
||||||
|
+import net.minecraft.server.MinecraftServer;
|
||||||
|
+import net.minecraft.world.entity.Entity;
|
||||||
|
+
|
||||||
|
+public class MergeHistory {
|
||||||
|
+
|
||||||
|
+ // packed position -> known merging information
|
||||||
|
+ private final Long2ObjectMap<MergeData> mergeDataMap = new Long2ObjectOpenHashMap<>();
|
||||||
|
+ private MergeData mergeData = null;
|
||||||
|
+
|
||||||
|
+ public MergeData retrievePositions(Entity entity) {
|
||||||
|
+ var origin = entity.getPackedOrigin();
|
||||||
|
+
|
||||||
|
+ if (mergeData != null && mergeData.knownPositions().contains(origin)) {
|
||||||
|
+ return mergeData;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return mergeData = mergeDataMap.get(origin);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void markPositions(Entity entity) {
|
||||||
|
+ var mergeList = entity.getMergeList();
|
||||||
|
+ var origin = entity.getPackedOrigin();
|
||||||
|
+
|
||||||
|
+ // I apologise for the lambda parameter name in advance
|
||||||
|
+ var data = mergeDataMap.computeIfAbsent(origin, (OwO) -> new MergeData(
|
||||||
|
+ // Known entity positions that have been able to merge
|
||||||
|
+ // This is used for non-strict merging.
|
||||||
|
+ new LongOpenHashSet(),
|
||||||
|
+ // First copy of the previous positions that is retained.
|
||||||
|
+ // This is used for on spawn (aot) merging.
|
||||||
|
+ // Retaining means if the collection you're comparing doesn't the same elements the rest gets yeeted.
|
||||||
|
+ // We also make use of a _reasonable_ threshold before on spawn merging to reduce abuse and breakage.
|
||||||
|
+ new LongOpenHashSet(),
|
||||||
|
+ new EntityTable(Math.min(mergeList.size() * 2, 512)),
|
||||||
|
+ // todo: allow configuring expiry and threshold
|
||||||
|
+ new Expiry(MinecraftServer.currentTickLong, 200),
|
||||||
|
+ new Threshold(MinecraftServer.currentTickLong, 12, 200)
|
||||||
|
+ ));
|
||||||
|
+
|
||||||
|
+ // Refresh expiry
|
||||||
|
+ data.expiry().refresh(MinecraftServer.currentTickLong);
|
||||||
|
+
|
||||||
|
+ var insert = data.knownPositions().isEmpty();
|
||||||
|
+ var positions = new LongOpenHashSet((mergeList.size() + 1) / 2);
|
||||||
|
+
|
||||||
|
+ positions.add(entity.getPackedOrigin());
|
||||||
|
+
|
||||||
|
+ for (var mergedEntity : mergeList) {
|
||||||
|
+ positions.add(mergedEntity.getPackedOrigin());
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // todo: if tnt spread is enabled double the threshold above then make the first half of the threshold inserting known positions.
|
||||||
|
+ // ^ This can allow better merging of randomised tnt for the compromise of it taking longer to merge on spawn.
|
||||||
|
+ // ^ There is an uncommon design that uses a single booster at the back and pushes all the tnt forward.
|
||||||
|
+ // ^ Using a chest as an offset means tnt alignment doesn't matter so people get away with spread but can make merging difficult.
|
||||||
|
+ if (insert) {
|
||||||
|
+ data.retainedPositions().addAll(positions);
|
||||||
|
+ } else {
|
||||||
|
+ data.retainedPositions().retainAll(positions);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ data.knownPositions().addAll(positions);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void expire(long tick) {
|
||||||
|
+ // clear this every tick
|
||||||
|
+ mergeData = null;
|
||||||
|
+
|
||||||
|
+ // only expire every 20 ticks
|
||||||
|
+ if (tick % 20 != 0) return;
|
||||||
|
+
|
||||||
|
+ // using a linked hashmap isn't applicable here as an optimisation
|
||||||
|
+ // because we allow the spawn positions to "refresh" this would create a memory leak
|
||||||
|
+ mergeDataMap.values().removeIf((data) -> data.expiry().isExpired(tick));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public record MergeData(LongSet knownPositions, LongSet retainedPositions, EntityTable table, Expiry expiry, Threshold threshold) {
|
||||||
|
+ public boolean hasPassed() {
|
||||||
|
+ return threshold.hasPassed(MinecraftServer.currentTickLong);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public Entity findFirstAtPosition(Entity entity) {
|
||||||
|
+ var found = table.locate(entity);
|
||||||
|
+
|
||||||
|
+ if (found != null && found.getId() < entity.getId() && knownPositions.contains(found.getPackedOrigin()) && !found.isRemoved() && entity.compareState(found)) {
|
||||||
|
+ return found;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return null;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private static class EntityTable {
|
||||||
|
+ private final Entity[] entities;
|
||||||
|
+ private final int mask;
|
||||||
|
+
|
||||||
|
+ EntityTable(int size) {
|
||||||
|
+ var n = HashCommon.nextPowerOfTwo(size - 1);
|
||||||
|
+ entities = new Entity[n];
|
||||||
|
+ mask = n - 1;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ Entity locate(Entity entity) {
|
||||||
|
+ var pos = entity.blockPosition().hashCode();
|
||||||
|
+ var key = pos & mask;
|
||||||
|
+ var found = entities[key];
|
||||||
|
+ entities[key] = entity;
|
||||||
|
+ return found;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private static class Threshold {
|
||||||
|
+ private final long existence; // tick when this was created
|
||||||
|
+ private final int thresholdAttempts;
|
||||||
|
+ private final long thresholdAge;
|
||||||
|
+ private int attempts;
|
||||||
|
+
|
||||||
|
+ Threshold(long tick, int attempts, long age) {
|
||||||
|
+ existence = tick;
|
||||||
|
+ thresholdAttempts = attempts;
|
||||||
|
+ thresholdAge = age;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ boolean hasPassed(long tick) {
|
||||||
|
+ return ++attempts >= thresholdAttempts
|
||||||
|
+ || tick - existence >= thresholdAge;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private static class Expiry {
|
||||||
|
+ private long expireAt;
|
||||||
|
+ private final int inc;
|
||||||
|
+
|
||||||
|
+ Expiry(long tick, int inc) {
|
||||||
|
+ expireAt = tick + inc;
|
||||||
|
+ this.inc = inc;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ void refresh(long tick) {
|
||||||
|
+ expireAt = tick + inc;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ boolean isExpired(long tick) {
|
||||||
|
+ return tick >= expireAt;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/me/samsuik/sakura/utils/collections/EntityTable.java b/src/main/java/me/samsuik/sakura/utils/collections/EntityTable.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..8f43264f436f5cea06b892e11b7f4864d321c49e
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/me/samsuik/sakura/utils/collections/EntityTable.java
|
||||||
|
@@ -0,0 +1,30 @@
|
||||||
|
+package me.samsuik.sakura.utils.collections;
|
||||||
|
+
|
||||||
|
+import it.unimi.dsi.fastutil.HashCommon;
|
||||||
|
+import net.minecraft.world.entity.Entity;
|
||||||
|
+
|
||||||
|
+import java.util.Arrays;
|
||||||
|
+
|
||||||
|
+public class EntityTable {
|
||||||
|
+
|
||||||
|
+ private final Entity[] entities;
|
||||||
|
+ private final int mask;
|
||||||
|
+
|
||||||
|
+ public EntityTable(int capacity) {
|
||||||
|
+ capacity = HashCommon.nextPowerOfTwo(capacity - 1);
|
||||||
|
+ entities = new Entity[capacity];
|
||||||
|
+ mask = capacity - 1;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public Entity put(Entity entity) {
|
||||||
|
+ var pos = entity.blockPosition().hashCode() & mask;
|
||||||
|
+ var found = entities[pos];
|
||||||
|
+ entities[pos] = entity;
|
||||||
|
+ return found;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void clear() {
|
||||||
|
+ Arrays.fill(entities, null);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
index eef411f838ecdeff0d4052fac22900e4ad87ceb5..4bc68b3145f42f5a432e1e897b3f41606735afd1 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
@@ -1579,6 +1579,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||||
|
this.profiler.pop();
|
||||||
|
worldserver.explosionDensityCache.clear(); // Paper - Optimize explosions
|
||||||
|
worldserver.minimalTNT.clear(); // Sakura - visibility api
|
||||||
|
+ worldserver.mergeHistory.expire(currentTickLong); // Sakura - merge cannoning entities
|
||||||
|
}
|
||||||
|
this.isIteratingOverLevels = false; // Paper
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
index bc73d8625ac296372640f540ade170aed8ae5353..04afadf047b84492dddd5ecc39e116ca74189545 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
@@ -877,6 +877,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||||
|
|
||||||
|
org.spigotmc.ActivationRange.activateEntities(this); // Spigot
|
||||||
|
timings.entityTick.startTiming(); // Spigot
|
||||||
|
+ var previousEntity = new Entity[1]; // Sakura
|
||||||
|
this.entityTickList.forEach((entity) -> {
|
||||||
|
if (!entity.isRemoved()) {
|
||||||
|
if (false && this.shouldDiscardEntity(entity)) { // CraftBukkit - We prevent spawning in general, so this butchering is not needed
|
||||||
|
@@ -896,6 +897,15 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||||
|
entity.stopRiding();
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Sakura start
|
||||||
|
+ var previous = previousEntity[0];
|
||||||
|
+ if (entity.isMergeableType(previous) && entity.tryMergeInto(previous)) {
|
||||||
|
+ return;
|
||||||
|
+ } else {
|
||||||
|
+ previousEntity[0] = entity;
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
+
|
||||||
|
gameprofilerfiller.push("tick");
|
||||||
|
this.guardEntityTick(this::tickNonPassenger, entity);
|
||||||
|
gameprofilerfiller.pop();
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
index 7e906ad87ae48942445b6ad1fa22ab9442c8943e..311891f079d2136a18f62478bd289c91ff515772 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
@@ -559,6 +559,105 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||||
|
return BlockPos.asLong(v.getBlockX(), v.getBlockY(), v.getBlockZ());
|
||||||
|
}
|
||||||
|
// Sakura end
|
||||||
|
+ // Sakura start - cannon entity merging
|
||||||
|
+ // List of merged entities, should be naturally sorted (oldest -> youngest)
|
||||||
|
+ private final List<Entity> mergeList = new java.util.ArrayList<>(1);
|
||||||
|
+ private @Nullable me.samsuik.sakura.entity.merge.MergeHistory.MergeData originData = null;
|
||||||
|
+ private me.samsuik.sakura.entity.merge.MergeLevel mergeLevel;
|
||||||
|
+ protected int stacked = 1; // default
|
||||||
|
+
|
||||||
|
+ public final me.samsuik.sakura.entity.merge.MergeLevel getMergeLevel() {
|
||||||
|
+ return mergeLevel;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public final void setMergeLevel(me.samsuik.sakura.entity.merge.MergeLevel level) {
|
||||||
|
+ mergeLevel = level;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public final int getStacked() {
|
||||||
|
+ return stacked;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public final void setStacked(int stack) {
|
||||||
|
+ stacked = stack;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public List<Entity> getMergeList() {
|
||||||
|
+ return mergeList;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private boolean isSafeToSpawnMerge(Entity entity) {
|
||||||
|
+ return tickCount == 1 && originData != null
|
||||||
|
+ && originData.hasPassed() // on spawn safety delay has passed
|
||||||
|
+ && originData == entity.originData // make sure it's the same group
|
||||||
|
+ && originData.retainedPositions().contains(entity.getPackedOrigin());
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public boolean isMergeableType(@Nullable Entity previous) {
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public final boolean tryMergeInto(@Nullable Entity entity) {
|
||||||
|
+ if (mergeLevel.atLeast(me.samsuik.sakura.entity.merge.MergeLevel.NON_STRICT) && tickCount == 0) {
|
||||||
|
+ originData = level.mergeHistory.retrievePositions(this);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ Entity mergeEntity = null;
|
||||||
|
+
|
||||||
|
+ if (entity == null || entity.getType() != getType()) {
|
||||||
|
+ // first entity in the tick loop, we have to let it into this method so that we can retrieve the originData
|
||||||
|
+ return false;
|
||||||
|
+ } else if (mergeLevel.atLeast(me.samsuik.sakura.entity.merge.MergeLevel.SPAWN) && entity.isSafeToSpawnMerge(this)) {
|
||||||
|
+ // On spawn merging, this merges entities immediately upon spawning after
|
||||||
|
+ // it is considered "safe". We try to make sure it is safe by only retaining
|
||||||
|
+ // positions that do not change when we're collecting information.
|
||||||
|
+ mergeEntity = entity;
|
||||||
|
+ } else {
|
||||||
|
+ // Strict, simple merging
|
||||||
|
+ // This merges entities that are in the exact same state and sequential.
|
||||||
|
+ // Sane for most use cases but as it is merging entities plugins may misbehave.
|
||||||
|
+ if (mergeLevel.atLeast(me.samsuik.sakura.entity.merge.MergeLevel.STRICT) && compareState(entity)) {
|
||||||
|
+ mergeEntity = entity;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // Non strict merging algorithm uses information collected after entities die
|
||||||
|
+ // to be able to perform more aggressive merging by already knowing the OOE.
|
||||||
|
+ if (mergeLevel.atLeast(me.samsuik.sakura.entity.merge.MergeLevel.NON_STRICT) && mergeEntity == null && originData != null) {
|
||||||
|
+ mergeEntity = originData.findFirstAtPosition(this);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (mergeEntity != null && isSafeToMergeInto(mergeEntity)) {
|
||||||
|
+ mergeInto(mergeEntity);
|
||||||
|
+ return true;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ protected void respawn() {}
|
||||||
|
+
|
||||||
|
+ protected boolean isSafeToMergeInto(Entity entity) {
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private void mergeInto(Entity entity) {
|
||||||
|
+ entity.mergeList.add(this);
|
||||||
|
+ entity.mergeList.addAll(mergeList);
|
||||||
|
+ entity.stacked += stacked;
|
||||||
|
+
|
||||||
|
+ mergeList.clear(); // clear the list to stop our tracking when merging
|
||||||
|
+ stacked = 0; // prevent any possible duplication
|
||||||
|
+
|
||||||
|
+ // update api handle, this is so cannondebug can function
|
||||||
|
+ //noinspection ConstantValue
|
||||||
|
+ if (bukkitEntity != null) {
|
||||||
|
+ bukkitEntity.setHandle(entity);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ discard();
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
|
||||||
|
public Entity(EntityType<?> type, Level world) {
|
||||||
|
this.id = Entity.ENTITY_COUNTER.incrementAndGet();
|
||||||
|
@@ -607,6 +706,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||||
|
this.getEntityData().registrationLocked = true; // Spigot
|
||||||
|
this.setPos(0.0D, 0.0D, 0.0D);
|
||||||
|
this.eyeHeight = this.getEyeHeight(net.minecraft.world.entity.Pose.STANDING, this.dimensions);
|
||||||
|
+ this.mergeLevel = level.sakuraConfig().cannons.mergeLevel; // Sakura
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isColliding(BlockPos pos, BlockState state) {
|
||||||
|
@@ -2454,6 +2554,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||||
|
nbt.putBoolean("Paper.FreezeLock", true);
|
||||||
|
}
|
||||||
|
// Paper end
|
||||||
|
+ // Sakura start
|
||||||
|
+ if (stacked > 0) {
|
||||||
|
+ nbt.putInt("Sakura.Stacked", stacked);
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
return nbt;
|
||||||
|
} catch (Throwable throwable) {
|
||||||
|
CrashReport crashreport = CrashReport.forThrowable(throwable, "Saving entity NBT");
|
||||||
|
@@ -2622,6 +2727,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||||
|
freezeLocked = nbt.getBoolean("Paper.FreezeLock");
|
||||||
|
}
|
||||||
|
// Paper end
|
||||||
|
+ // Sakura start
|
||||||
|
+ if (nbt.contains("Sakura.Stacked")) {
|
||||||
|
+ stacked = nbt.getInt("Sakura.Stacked");
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
|
||||||
|
} catch (Throwable throwable) {
|
||||||
|
CrashReport crashreport = CrashReport.forThrowable(throwable, "Loading entity NBT");
|
||||||
|
@@ -4784,6 +4894,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Paper end - rewrite chunk system
|
||||||
|
+ // Sakura start
|
||||||
|
+ if (reason == RemovalReason.DISCARDED && !mergeList.isEmpty()) {
|
||||||
|
+ level.mergeHistory.markPositions(this);
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
final boolean alreadyRemoved = this.removalReason != null;
|
||||||
|
if (this.removalReason == null) {
|
||||||
|
this.removalReason = reason;
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||||
|
index 2e0f38ffad09b6afbea74205b89beb774e779545..2afcb3ebdfba545d7c1d73fd0aed486c1f8bf6ae 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||||
|
@@ -132,6 +132,58 @@ public class FallingBlockEntity extends Entity {
|
||||||
|
return !this.isRemoved();
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Sakura start - cannon entity merging
|
||||||
|
+ @Override
|
||||||
|
+ public boolean isMergeableType(@Nullable Entity previous) {
|
||||||
|
+ return previous == null || !isRemoved() && !previous.isRemoved();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ protected boolean isSafeToMergeInto(Entity entity) {
|
||||||
|
+ return entity instanceof FallingBlockEntity fbe
|
||||||
|
+ && fbe.blockState.equals(blockState)
|
||||||
|
+ && fbe.time - 1 == time; // todo: special case in case on spawn isn't used
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ protected void respawn() {
|
||||||
|
+ while (stacked-- > 1) {
|
||||||
|
+ // create a temporary falling block entity
|
||||||
|
+ var fallingBlock = new FallingBlockEntity(EntityType.FALLING_BLOCK, level());
|
||||||
|
+
|
||||||
|
+ // use our the previous state
|
||||||
|
+ entityState().apply(fallingBlock);
|
||||||
|
+ fallingBlock.time = time - 1;
|
||||||
|
+
|
||||||
|
+ // and tick
|
||||||
|
+ fallingBlock.tick();
|
||||||
|
+
|
||||||
|
+ // Well, this can actually happen.
|
||||||
|
+ // If you horizontal or rectangle stack sand into a b36 this condition will be met.
|
||||||
|
+ // This could break some suspicious render queuing setups relying on horizontal stacking
|
||||||
|
+ // and keeping sand in b36 using pistons pushing back and forth.
|
||||||
|
+ if (!fallingBlock.isRemoved()) {
|
||||||
|
+ fallingBlock.stacked = stacked;
|
||||||
|
+ level().addFreshEntity(fallingBlock);
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Nullable
|
||||||
|
+ public ItemEntity spawnAtLocation(ItemLike item) {
|
||||||
|
+ // This is to prevent sand continuing to respawn incase it broke.
|
||||||
|
+ ItemEntity itemEntity = null;
|
||||||
|
+
|
||||||
|
+ for (int i = 0; i < stacked; ++i) {
|
||||||
|
+ itemEntity = super.spawnAtLocation(item);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ stacked = 1;
|
||||||
|
+ return itemEntity;
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
+
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
// Paper start - fix sand duping
|
||||||
|
@@ -214,6 +266,7 @@ public class FallingBlockEntity extends Entity {
|
||||||
|
if (this.level().setBlock(blockposition, this.blockState, 3)) {
|
||||||
|
((ServerLevel) this.level()).getChunkSource().chunkMap.broadcast(this, new ClientboundBlockUpdatePacket(blockposition, this.level().getBlockState(blockposition)));
|
||||||
|
this.discard();
|
||||||
|
+ this.respawn(); // Sakura
|
||||||
|
if (block instanceof Fallable) {
|
||||||
|
((Fallable) block).onLand(this.level(), blockposition, this.blockState, iblockdata, this);
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||||
|
index fbeb52a49b791f992af19c7d69ba44b820541b09..02ef6ca32f3de52e921fdcf3f0f572ce7afef318 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||||
|
@@ -63,6 +63,60 @@ public class PrimedTnt extends Entity implements TraceableEntity {
|
||||||
|
return !this.isRemoved();
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Sakura start - cannon entity merging
|
||||||
|
+ @Override
|
||||||
|
+ public boolean isMergeableType(@Nullable Entity previous) {
|
||||||
|
+ return previous == null || !isRemoved() && !previous.isRemoved();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ protected boolean isSafeToMergeInto(Entity entity) {
|
||||||
|
+ return entity instanceof PrimedTnt tnt
|
||||||
|
+ && tnt.getFuse() + 1 == getFuse()
|
||||||
|
+ // required to prevent issues with powdered snow
|
||||||
|
+ && (tnt.entityState().fallDistance() == 0.0f && fallDistance == 0.0f
|
||||||
|
+ || tnt.entityState().fallDistance() > 2.5f && fallDistance > 2.5f);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ protected void respawn() {
|
||||||
|
+ if (stacked <= 1) return;
|
||||||
|
+
|
||||||
|
+ // we create a temporary entity that will be affected by each explosion
|
||||||
|
+ // this allows us to only keep one entity in the world in an attempt to
|
||||||
|
+ // minimise complexity of stacked tnt explosions.
|
||||||
|
+ var tnt = new PrimedTnt(level(), 0, 0, 0, owner);
|
||||||
|
+
|
||||||
|
+ // Copy our pre-tick state to the temporary entity
|
||||||
|
+ entityState().apply(tnt);
|
||||||
|
+
|
||||||
|
+ // add the entity to the world and chunk
|
||||||
|
+ level().addFreshEntity(tnt);
|
||||||
|
+
|
||||||
|
+ // Some bad plugins may change tnt momentum while we are respawning
|
||||||
|
+ // ex: a plugin that sets tnt momentum to 0 upon spawning
|
||||||
|
+ tnt.setDeltaMovement(entityState().momentum());
|
||||||
|
+
|
||||||
|
+ for (int i = stacked - 1; i >= 1; --i) {
|
||||||
|
+ // make sure this entity cannot explode unexpectedly
|
||||||
|
+ setFuse(100);
|
||||||
|
+ stacked = 0;
|
||||||
|
+
|
||||||
|
+ // explode!
|
||||||
|
+ explode();
|
||||||
|
+
|
||||||
|
+ // clone state from temporary entity
|
||||||
|
+ tnt.storeEntityState();
|
||||||
|
+ tnt.entityState().apply(this);
|
||||||
|
+
|
||||||
|
+ // tick, this is only to move the entity and apply physics.
|
||||||
|
+ tick();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ tnt.discard();
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
+
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
if (this.level().spigotConfig.maxTntTicksPerTick > 0 && ++this.level().spigotConfig.currentPrimedTnt > this.level().spigotConfig.maxTntTicksPerTick) { return; } // Spigot
|
||||||
|
@@ -88,6 +142,7 @@ public class PrimedTnt extends Entity implements TraceableEntity {
|
||||||
|
if (i <= 0) {
|
||||||
|
// CraftBukkit start - Need to reverse the order of the explosion and the entity death so we have a location for the event
|
||||||
|
// this.discard();
|
||||||
|
+ this.respawn(); // Sakura
|
||||||
|
if (!this.level().isClientSide) {
|
||||||
|
this.explode();
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
index 6d9a15a1c1faff57103757b6ff71f38e4713ef71..2f72a059b051bb3d35e0844c6b7ae3b6e2655e36 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
@@ -227,6 +227,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||||
|
return slices.getSectionEntities(chunkY);
|
||||||
|
}
|
||||||
|
// Sakura end
|
||||||
|
+ public final me.samsuik.sakura.entity.merge.MergeHistory mergeHistory = new me.samsuik.sakura.entity.merge.MergeHistory(); // Sakura
|
||||||
|
|
||||||
|
protected Level(WritableLevelData worlddatamutable, ResourceKey<Level> resourcekey, RegistryAccess iregistrycustom, Holder<DimensionType> holder, Supplier<ProfilerFiller> supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function<org.spigotmc.SpigotWorldConfig, io.papermc.paper.configuration.WorldConfiguration> paperWorldConfigCreator, Supplier<me.samsuik.sakura.configuration.WorldConfiguration> sakuraWorldConfigCreator, java.util.concurrent.Executor executor) { // Sakura // Paper - Async-Anti-Xray - Pass executor
|
||||||
|
this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java
|
||||||
|
index a39694a27e362312eb42a29fd7c833f9c7437d46..55bfb0afc0e4e9f1ce2dd15f729bee61822c5afc 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java
|
||||||
|
@@ -14,6 +14,28 @@ public class CraftFallingBlock extends CraftEntity implements FallingBlock {
|
||||||
|
super(server, entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Sakura start
|
||||||
|
+ @Override
|
||||||
|
+ public @org.jetbrains.annotations.NotNull me.samsuik.sakura.entity.merge.MergeLevel getMergeLevel() {
|
||||||
|
+ return getHandle().getMergeLevel();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void setMergeLevel(@org.jetbrains.annotations.NotNull me.samsuik.sakura.entity.merge.MergeLevel level) {
|
||||||
|
+ getHandle().setMergeLevel(level);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public int getStacked() {
|
||||||
|
+ return getHandle().getStacked();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void setStacked(int stacked) {
|
||||||
|
+ getHandle().setStacked(stacked);
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
+
|
||||||
|
@Override
|
||||||
|
public FallingBlockEntity getHandle() {
|
||||||
|
return (FallingBlockEntity) entity;
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftTNTPrimed.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftTNTPrimed.java
|
||||||
|
index dc13deb1cea14f0650b292ddb6437fadefc0b8be..e9f8abb514654b87ec4f35b90fff04818a05780d 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftTNTPrimed.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftTNTPrimed.java
|
||||||
|
@@ -12,6 +12,28 @@ public class CraftTNTPrimed extends CraftEntity implements TNTPrimed {
|
||||||
|
super(server, entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Sakura start
|
||||||
|
+ @Override
|
||||||
|
+ public @org.jetbrains.annotations.NotNull me.samsuik.sakura.entity.merge.MergeLevel getMergeLevel() {
|
||||||
|
+ return getHandle().getMergeLevel();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void setMergeLevel(@org.jetbrains.annotations.NotNull me.samsuik.sakura.entity.merge.MergeLevel level) {
|
||||||
|
+ getHandle().setMergeLevel(level);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public int getStacked() {
|
||||||
|
+ return getHandle().getStacked();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void setStacked(int stacked) {
|
||||||
|
+ getHandle().setStacked(stacked);
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
+
|
||||||
|
@Override
|
||||||
|
public float getYield() {
|
||||||
|
return this.getHandle().yield;
|
||||||
979
patches/server/0019-Optimised-Explosions.patch
Normal file
979
patches/server/0019-Optimised-Explosions.patch
Normal file
@@ -0,0 +1,979 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
|
||||||
|
Date: Thu, 12 Oct 2023 16:23:31 +0100
|
||||||
|
Subject: [PATCH] Optimised Explosions
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/me/samsuik/sakura/explosion/DensityCache.java b/src/main/java/me/samsuik/sakura/explosion/DensityCache.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..3f6f34cc617efaad420485a7f613cfcad88e3783
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/me/samsuik/sakura/explosion/DensityCache.java
|
||||||
|
@@ -0,0 +1,130 @@
|
||||||
|
+package me.samsuik.sakura.explosion;
|
||||||
|
+
|
||||||
|
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
|
+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
|
+import net.minecraft.util.Mth;
|
||||||
|
+import net.minecraft.world.entity.Entity;
|
||||||
|
+import net.minecraft.world.phys.AABB;
|
||||||
|
+import net.minecraft.world.phys.Vec3;
|
||||||
|
+
|
||||||
|
+import javax.annotation.Nullable;
|
||||||
|
+
|
||||||
|
+public class DensityCache {
|
||||||
|
+
|
||||||
|
+ private final Int2ObjectMap<Density> densityMap = new Int2ObjectOpenHashMap<>();
|
||||||
|
+
|
||||||
|
+ public @Nullable Density retrieveCache(int key) {
|
||||||
|
+ return densityMap.get(key);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void createCache(int key, Entity entity, Vec3 vec3d, float density) {
|
||||||
|
+ densityMap.put(key, new Density(entity.getBoundingBox(), vec3d, density));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void clear() {
|
||||||
|
+ densityMap.clear();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public static int createKey(Entity entity, Vec3 vec3d) {
|
||||||
|
+ int hash = Mth.floor(vec3d.x);
|
||||||
|
+ hash = 31 * hash ^ Mth.floor(vec3d.y);
|
||||||
|
+ hash = 31 * hash ^ Mth.floor(vec3d.z);
|
||||||
|
+ hash = 31 * hash ^ Mth.floor(entity.getX());
|
||||||
|
+ hash = 31 * hash ^ Mth.floor(entity.getY());
|
||||||
|
+ hash = 31 * hash ^ Mth.floor(entity.getZ());
|
||||||
|
+ return hash;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public static final class Density {
|
||||||
|
+ private AABB source;
|
||||||
|
+ private AABB entity;
|
||||||
|
+ private AABB obstruction;
|
||||||
|
+ private final float density;
|
||||||
|
+ private final boolean expand;
|
||||||
|
+
|
||||||
|
+ Density(AABB bb, Vec3 p, float d) {
|
||||||
|
+ entity = bb;
|
||||||
|
+ source = new AABB(p, p);
|
||||||
|
+ density = d;
|
||||||
|
+ expand = density == 0.0f || density == 1.0f;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public boolean isExpandable() {
|
||||||
|
+ return expand;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public float density() {
|
||||||
|
+ return density;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void obscure(Vec3 p) {
|
||||||
|
+ if (obstruction == null) {
|
||||||
|
+ obstruction = new AABB(p, p);
|
||||||
|
+ } else {
|
||||||
|
+ obstruction = expandBBWithVec3(p, obstruction);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public boolean isObscured(Vec3 p) {
|
||||||
|
+ return obstruction != null
|
||||||
|
+ && obstruction.minX <= p.x && obstruction.maxX >= p.x
|
||||||
|
+ && obstruction.minY <= p.y && obstruction.maxY >= p.y
|
||||||
|
+ && obstruction.minZ <= p.z && obstruction.maxZ >= p.z;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void expand(AABB bb, Vec3 p) {
|
||||||
|
+ entity = entity.minmax(bb);
|
||||||
|
+ source = expandBBWithVec3(p, source);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public boolean has(AABB bb, Vec3 p) {
|
||||||
|
+ return isBBWithinBounds(bb) && isPointWithinBounds(p);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public boolean has(Vec3 p) {
|
||||||
|
+ return isPointWithinBounds(p);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private boolean isBBWithinBounds(AABB bb) {
|
||||||
|
+ return entity.minX <= bb.minX && entity.maxX >= bb.maxX
|
||||||
|
+ && entity.minY <= bb.minY && entity.maxY >= bb.maxY
|
||||||
|
+ && entity.minZ <= bb.minZ && entity.maxZ >= bb.maxZ;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private boolean isPointWithinBounds(Vec3 p) {
|
||||||
|
+ return source.minX <= p.x && source.maxX >= p.x
|
||||||
|
+ && source.minY <= p.y && source.maxY >= p.y
|
||||||
|
+ && source.minZ <= p.z && source.maxZ >= p.z;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private AABB expandBBWithVec3(Vec3 point, AABB what) {
|
||||||
|
+ double minX = what.minX;
|
||||||
|
+ double minY = what.minY;
|
||||||
|
+ double minZ = what.minZ;
|
||||||
|
+ double maxX = what.maxX;
|
||||||
|
+ double maxY = what.maxY;
|
||||||
|
+ double maxZ = what.maxZ;
|
||||||
|
+
|
||||||
|
+ if (point.x < minX) {
|
||||||
|
+ minX = point.x;
|
||||||
|
+ } else if (point.x > maxX) {
|
||||||
|
+ maxX = point.x;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (point.y < minY) {
|
||||||
|
+ minY = point.y;
|
||||||
|
+ } else if (point.y > maxY) {
|
||||||
|
+ maxY = point.y;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (point.z < minZ) {
|
||||||
|
+ minZ = point.z;
|
||||||
|
+ } else if (point.z > maxZ) {
|
||||||
|
+ maxZ = point.z;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return new AABB(minX, minY, minZ, maxX, maxY, maxZ);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/me/samsuik/sakura/explosion/SakuraExplosion.java b/src/main/java/me/samsuik/sakura/explosion/SakuraExplosion.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..34514f41cf20284b449e8ed6b5f96c2d07c62053
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/me/samsuik/sakura/explosion/SakuraExplosion.java
|
||||||
|
@@ -0,0 +1,383 @@
|
||||||
|
+package me.samsuik.sakura.explosion;
|
||||||
|
+
|
||||||
|
+import net.minecraft.core.BlockPos;
|
||||||
|
+import net.minecraft.server.level.ServerLevel;
|
||||||
|
+import net.minecraft.util.Mth;
|
||||||
|
+import net.minecraft.world.damagesource.DamageSource;
|
||||||
|
+import net.minecraft.world.entity.Entity;
|
||||||
|
+import net.minecraft.world.entity.LivingEntity;
|
||||||
|
+import net.minecraft.world.entity.boss.EnderDragonPart;
|
||||||
|
+import net.minecraft.world.entity.boss.enderdragon.EnderDragon;
|
||||||
|
+import net.minecraft.world.entity.item.PrimedTnt;
|
||||||
|
+import net.minecraft.world.entity.player.Player;
|
||||||
|
+import net.minecraft.world.item.enchantment.ProtectionEnchantment;
|
||||||
|
+import net.minecraft.world.level.Explosion;
|
||||||
|
+import net.minecraft.world.level.ExplosionDamageCalculator;
|
||||||
|
+import net.minecraft.world.level.Level;
|
||||||
|
+import net.minecraft.world.phys.AABB;
|
||||||
|
+import net.minecraft.world.phys.Vec3;
|
||||||
|
+import org.bukkit.craftbukkit.event.CraftEventFactory;
|
||||||
|
+import org.jetbrains.annotations.Nullable;
|
||||||
|
+
|
||||||
|
+import java.util.ArrayList;
|
||||||
|
+import java.util.List;
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * Special explosion implementation to take advantage of TNT merging.
|
||||||
|
+ *
|
||||||
|
+ * This allows us to introduce more optimisations
|
||||||
|
+ * * if we have been unable to find any blocks nearby stop searching for blocks
|
||||||
|
+ * * avoid trying to affect entities that are completely obscured
|
||||||
|
+ * * reduce range checks for out of range entities
|
||||||
|
+ * * take better advantage of the block cache in paper
|
||||||
|
+ * * special case for explosions in the same position
|
||||||
|
+ *
|
||||||
|
+ * Unfortunately, this requires duplicating the impact entity section from Explosion.
|
||||||
|
+ *
|
||||||
|
+ * This does hurt performance in a "rogue tnt" scenario, tnt that has been spawned
|
||||||
|
+ * by an explosion destroying a tnt block often in massive blocks of tnt. It is not
|
||||||
|
+ * realistic to explode a big block of tnt in survival or factions. They only cause
|
||||||
|
+ * harm to a server and extremely wasteful for resources with minimal impact to terrain.
|
||||||
|
+ */
|
||||||
|
+public class SakuraExplosion extends Explosion {
|
||||||
|
+
|
||||||
|
+ private final Level level;
|
||||||
|
+
|
||||||
|
+ public SakuraExplosion(Level world, @Nullable Entity entity, @Nullable DamageSource damageSource, @Nullable ExplosionDamageCalculator behavior, double x, double y, double z, float power, boolean createFire, BlockInteraction destructionType) {
|
||||||
|
+ super(world, entity, damageSource, behavior, x, y, z, power, createFire, destructionType);
|
||||||
|
+ this.level = world;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void explode() {
|
||||||
|
+ PrimedTnt origin = (PrimedTnt) source;
|
||||||
|
+ List<Vec3> positions = new ArrayList<>(origin.getStacked());
|
||||||
|
+
|
||||||
|
+ // This is a temporary entity that will be used for movement.
|
||||||
|
+ PrimedTnt tnt = new PrimedTnt(level, 0, 0, 0, null);
|
||||||
|
+ AABB bounds = new AABB(x, y, z, x, y, z);
|
||||||
|
+
|
||||||
|
+ origin.entityState().apply(tnt);
|
||||||
|
+
|
||||||
|
+ Vec3 lastMovement = tnt.getDeltaMovement();
|
||||||
|
+ ExplosionBlockCache[] blockCache = createBlockCache();
|
||||||
|
+ int wrapped = 0;
|
||||||
|
+
|
||||||
|
+ for (int i = 0; i < origin.getStacked() && !wasCanceled; ++i) {
|
||||||
|
+ if (i > 0) {
|
||||||
|
+ updatePosition(origin, tnt);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // block at explosion position
|
||||||
|
+ int blockX = Mth.floor(x);
|
||||||
|
+ int blockY = Mth.floor(y);
|
||||||
|
+ int blockZ = Mth.floor(z);
|
||||||
|
+ Vec3 position = new Vec3(x, y, z);
|
||||||
|
+
|
||||||
|
+ // search for blocks if necessary
|
||||||
|
+ if (wrapped < 7 + 12) {
|
||||||
|
+ getToBlow().clear();
|
||||||
|
+
|
||||||
|
+ long key = BlockPos.asLong(blockX, blockY, blockZ);
|
||||||
|
+ ExplosionBlockCache center = getOrCacheExplosionBlock(blockX, blockY, blockZ, key, true);
|
||||||
|
+
|
||||||
|
+ if (interactsWithBlocks() && isDestructibleBlock(center.blockState) && !isProtectedRegion()) {
|
||||||
|
+ searchForBlocks(blockCache);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // keep track of positions and bounds
|
||||||
|
+ positions.add(position);
|
||||||
|
+ bounds = bounds.minmax(new AABB(position, position));
|
||||||
|
+
|
||||||
|
+ Vec3 movement = tnt.getDeltaMovement();
|
||||||
|
+
|
||||||
|
+ if (wrapped < 7) {
|
||||||
|
+ // Check if the explosion has wrapped around with swinging on each axis
|
||||||
|
+ if (movement.x == lastMovement.x || movement.x * lastMovement.x < 0) wrapped |= 1;
|
||||||
|
+ if (movement.y == lastMovement.y || movement.y * lastMovement.y < 0) wrapped |= 1 << 1;
|
||||||
|
+ if (movement.z == lastMovement.z || movement.z * lastMovement.z < 0) wrapped |= 1 << 2;
|
||||||
|
+ } else if (getToBlow().isEmpty() && level.sakuraConfig().cannons.explosion.avoidRedundantBlockSearches) {
|
||||||
|
+ wrapped++;
|
||||||
|
+ } else {
|
||||||
|
+ wrapped = 7;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ lastMovement = tnt.getDeltaMovement();
|
||||||
|
+
|
||||||
|
+ if (i + 1 < origin.getStacked()) {
|
||||||
|
+ BlockPos.MutableBlockPos mbp = new BlockPos.MutableBlockPos();
|
||||||
|
+ impactEntityIdle(tnt, new Entity[0], position, 1, radius * 2.0f, mbp, blockCache);
|
||||||
|
+
|
||||||
|
+ // The purpose of this is to make sure papers blockCache doesn't become
|
||||||
|
+ // outdated by flushing the map and removing stale entries from the recent
|
||||||
|
+ // cache array. If there is any case where tnt can provide its self delta
|
||||||
|
+ // movement and then start moving without blocks this may break stuff to
|
||||||
|
+ // fix it see the note above or add a boolean to mark the cache as dirty
|
||||||
|
+ // outside this loop and then invalidate before the final impact entities.
|
||||||
|
+ if (!getToBlow().isEmpty() && tnt.getDeltaMovement().lengthSqr() <= 64.0) {
|
||||||
|
+ invalidateBlockCache(blockCache);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // could it be viable to have a configuration option to only
|
||||||
|
+ // call finalize explosion when blocks are found
|
||||||
|
+ // may affect plugins that need exact explosion positions
|
||||||
|
+ super.finalizeExplosion(false);
|
||||||
|
+ ((ServerLevel) level).notifyPlayersOfExplosion(x, y, z, radius, this);
|
||||||
|
+ } else {
|
||||||
|
+ locateAndImpactEntities(positions, bounds, blockCache);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ clearBlockCache();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private void updatePosition(PrimedTnt origin, PrimedTnt tnt) {
|
||||||
|
+ boolean originMoved = !origin.position().equals(tnt.position());
|
||||||
|
+
|
||||||
|
+ origin.setFuse(100);
|
||||||
|
+ tnt.storeEntityState();
|
||||||
|
+ tnt.entityState().apply(origin);
|
||||||
|
+
|
||||||
|
+ // We have to check delta movement otherwise this optimisation can break reversing tnt.
|
||||||
|
+ // If origin was shot upwards to a block then falls in the explosion tick it will swing
|
||||||
|
+ // and origin and tnt will be in the same position every other tnt while swinging.
|
||||||
|
+ if (!getToBlow().isEmpty() || tnt.getDeltaMovement().lengthSqr() <= 64.0 || originMoved) {
|
||||||
|
+ origin.tick();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // update explosion position
|
||||||
|
+ x = origin.getX();
|
||||||
|
+ y = origin.getY(0.0625);
|
||||||
|
+ z = origin.getZ();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private void locateAndImpactEntities(List<Vec3> positions, AABB bb, ExplosionBlockCache[] blockCache) {
|
||||||
|
+ double radius = this.radius * 2.0f;
|
||||||
|
+
|
||||||
|
+ int minSection = io.papermc.paper.util.WorldUtil.getMinSection(level);
|
||||||
|
+ int maxSection = io.papermc.paper.util.WorldUtil.getMaxSection(level);
|
||||||
|
+
|
||||||
|
+ int minChunkX = Mth.floor(bb.minX - radius) >> 4;
|
||||||
|
+ int minChunkY = Mth.clamp(Mth.floor(bb.minY - radius) >> 4, minSection, maxSection);
|
||||||
|
+ int minChunkZ = Mth.floor(bb.minZ - radius) >> 4;
|
||||||
|
+ int maxChunkX = Mth.floor(bb.maxX + radius) >> 4;
|
||||||
|
+ int maxChunkY = Mth.clamp(Mth.floor(bb.maxY + radius) >> 4, minSection, maxSection);
|
||||||
|
+ int maxChunkZ = Mth.floor(bb.maxZ + radius) >> 4;
|
||||||
|
+
|
||||||
|
+ Vec3 center = bb.getCenter();
|
||||||
|
+ double change = Math.max(bb.maxX - bb.minX, Math.max(bb.maxY - bb.minY, bb.maxZ - bb.minZ));
|
||||||
|
+ double maxDistanceSqr = Math.pow(radius + change, 2);
|
||||||
|
+
|
||||||
|
+ boolean moved = change != 0.0;
|
||||||
|
+
|
||||||
|
+ BlockPos.MutableBlockPos blockPos = new BlockPos.MutableBlockPos(); // Paper - optimise explosions
|
||||||
|
+
|
||||||
|
+ io.papermc.paper.chunk.system.entity.EntityLookup entityLookup = ((ServerLevel) level).getEntityLookup();
|
||||||
|
+
|
||||||
|
+ // impact entities already has a range check there is no reason to also
|
||||||
|
+ // do an intersection check when retrieving entities from the chunk.
|
||||||
|
+
|
||||||
|
+ for (int chunkX = minChunkX; chunkX <= maxChunkX; ++chunkX) {
|
||||||
|
+ for (int chunkZ = minChunkZ; chunkZ <= maxChunkZ; ++chunkZ) {
|
||||||
|
+ io.papermc.paper.world.ChunkEntitySlices chunk = entityLookup.getChunk(chunkX, chunkZ);
|
||||||
|
+
|
||||||
|
+ if (chunk == null) {
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ for (int chunkY = minChunkY; chunkY <= maxChunkY; ++chunkY) {
|
||||||
|
+ if (moved) {
|
||||||
|
+ impactEntities(chunk.getSectionEntities(chunkY), positions, center, blockPos, blockCache, radius, maxDistanceSqr);
|
||||||
|
+ } else {
|
||||||
|
+ impactEntitiesIdle(chunk.getSectionEntities(chunkY), positions.get(0), positions.size(), blockPos, blockCache, radius);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // swinging case: more than 1 position and actively changing positions.
|
||||||
|
+ private void impactEntities(Entity[] entities, List<Vec3> positions, Vec3 center, BlockPos.MutableBlockPos blockPos, ExplosionBlockCache[] blockCache, double radius, double maxDistanceSqr) {
|
||||||
|
+ for (int i = 0; i < entities.length; ++i) {
|
||||||
|
+ Entity entity = entities[i];
|
||||||
|
+ if (entity == null) break;
|
||||||
|
+
|
||||||
|
+ if (entity != source && !entity.ignoreExplosion()
|
||||||
|
+ && entity.distanceToSqr(center.x, center.y, center.z) <= maxDistanceSqr
|
||||||
|
+ ) {
|
||||||
|
+ int key = DensityCache.createKey(entity, center);
|
||||||
|
+ DensityCache.Density data = level.densityCache.retrieveCache(key);
|
||||||
|
+ Vec3 position = entity.position();
|
||||||
|
+
|
||||||
|
+ if (data != null && data.isObscured(position)) {
|
||||||
|
+ continue;
|
||||||
|
+ } else if (impactEntity(entity, entities, positions, radius, blockPos, blockCache) == 1 && data != null) {
|
||||||
|
+ data.obscure(position);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // chunk entities can change while we're affecting entities
|
||||||
|
+ if (entities[i] != entity) {
|
||||||
|
+ i--;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private int impactEntity(Entity entity, Entity[] section, List<Vec3> positions, double radius, BlockPos.MutableBlockPos blockPos, ExplosionBlockCache[] blockCache) {
|
||||||
|
+ int found = 0;
|
||||||
|
+
|
||||||
|
+ //noinspection ForLoopReplaceableByForEach
|
||||||
|
+ for (int i = 0; i < positions.size(); i++) {
|
||||||
|
+ Vec3 pos = positions.get(i);
|
||||||
|
+
|
||||||
|
+ double distanceFromBottom = Math.sqrt(entity.distanceToSqr(pos)) / radius;
|
||||||
|
+
|
||||||
|
+ if (distanceFromBottom > 1.0) continue;
|
||||||
|
+
|
||||||
|
+ double x = entity.getX() - pos.x;
|
||||||
|
+ double y = (entity instanceof PrimedTnt ? entity.getY() : entity.getEyeY()) - pos.y;
|
||||||
|
+ double z = entity.getZ() - pos.z;
|
||||||
|
+ double distance = Math.sqrt(x * x + y * y + z * z);
|
||||||
|
+
|
||||||
|
+ if (distance == 0.0D) continue;
|
||||||
|
+
|
||||||
|
+ x /= distance;
|
||||||
|
+ y /= distance;
|
||||||
|
+ z /= distance;
|
||||||
|
+ double density = this.getBlockDensity(pos, entity, blockCache, blockPos); // Paper - Optimize explosions // Paper - optimise explosions
|
||||||
|
+ double exposure = (1.0D - distanceFromBottom) * density;
|
||||||
|
+
|
||||||
|
+ int visible = density != 0.0 ? 1 : 0;
|
||||||
|
+ found |= (visible << 1) | 1;
|
||||||
|
+
|
||||||
|
+ if (entity.isPrimedTNT || entity.isFallingBlock) {
|
||||||
|
+ entity.addDeltaMovement(x * exposure, y * exposure, z * exposure);
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ impactNonLiving(entity, pos, section, x, y, z, exposure, blockPos, blockCache);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return found;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // stationary case: 1 position or stationary
|
||||||
|
+ private void impactEntitiesIdle(Entity[] entities, Vec3 position, int potential, BlockPos.MutableBlockPos blockPos, ExplosionBlockCache[] blockCache, double radius) {
|
||||||
|
+ for (int i = 0; i < entities.length; ++i) {
|
||||||
|
+ Entity entity = entities[i];
|
||||||
|
+ if (entity == null) break;
|
||||||
|
+
|
||||||
|
+ if (entity != source && !entity.ignoreExplosion()) {
|
||||||
|
+ impactEntityIdle(entity, entities, position, potential, radius, blockPos, blockCache);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // chunk entities can change while we're affecting entities
|
||||||
|
+ if (entities[i] != entity) {
|
||||||
|
+ i--;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private void impactEntityIdle(Entity entity, Entity[] section, Vec3 pos, int potential, double radius, BlockPos.MutableBlockPos blockPos, ExplosionBlockCache[] blockCache) {
|
||||||
|
+ double distanceFromBottom = Math.sqrt(entity.distanceToSqr(pos)) / radius;
|
||||||
|
+
|
||||||
|
+ if (distanceFromBottom <= 1.0) {
|
||||||
|
+ double x = entity.getX() - pos.x;
|
||||||
|
+ double y = (entity instanceof PrimedTnt ? entity.getY() : entity.getEyeY()) - pos.y;
|
||||||
|
+ double z = entity.getZ() - pos.z;
|
||||||
|
+ double distance = Math.sqrt(x * x + y * y + z * z);
|
||||||
|
+
|
||||||
|
+ if (distance != 0.0D) {
|
||||||
|
+ x /= distance;
|
||||||
|
+ y /= distance;
|
||||||
|
+ z /= distance;
|
||||||
|
+ double density = this.getBlockDensity(pos, entity, blockCache, blockPos); // Paper - Optimize explosions // Paper - optimise explosions
|
||||||
|
+ double exposure = (1.0D - distanceFromBottom) * density;
|
||||||
|
+
|
||||||
|
+ if (entity.isPrimedTNT || entity.isFallingBlock) {
|
||||||
|
+ x *= exposure;
|
||||||
|
+ y *= exposure;
|
||||||
|
+ z *= exposure;
|
||||||
|
+
|
||||||
|
+ if (exposure == 0.0) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ for (int i = 0; i < potential; ++i) {
|
||||||
|
+ entity.addDeltaMovement(x, y, z);
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
+ for (int i = 0; i < potential; ++i) {
|
||||||
|
+ impactNonLiving(entity, pos, section, x, y, z, exposure, blockPos, blockCache);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private void impactNonLiving(Entity entity, Vec3 pos, Entity[] section, double d8, double d9, double d10, double d13, BlockPos.MutableBlockPos blockPos, ExplosionBlockCache[] blockCache) {
|
||||||
|
+ // CraftBukkit start
|
||||||
|
+
|
||||||
|
+ // Special case ender dragon only give knockback if no damage is cancelled
|
||||||
|
+ // Thinks to note:
|
||||||
|
+ // - Setting a velocity to a ComplexEntityPart is ignored (and therefore not needed)
|
||||||
|
+ // - Damaging ComplexEntityPart while forward the damage to EntityEnderDragon
|
||||||
|
+ // - Damaging EntityEnderDragon does nothing
|
||||||
|
+ // - EntityEnderDragon hitbock always covers the other parts and is therefore always present
|
||||||
|
+ if (entity instanceof EnderDragonPart) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ CraftEventFactory.entityDamage = this.source;
|
||||||
|
+ entity.lastDamageCancelled = false;
|
||||||
|
+
|
||||||
|
+ if (entity instanceof EnderDragon) {
|
||||||
|
+ for (EnderDragonPart entityComplexPart : ((EnderDragon) entity).subEntities) {
|
||||||
|
+ for (Entity ent : section) {
|
||||||
|
+ if (ent == null) break;
|
||||||
|
+ // Calculate damage separately for each EntityComplexPart
|
||||||
|
+ double d7part;
|
||||||
|
+ if (ent == entityComplexPart && (d7part = Math.sqrt(entityComplexPart.distanceToSqr(pos)) / radius) <= 1.0D) {
|
||||||
|
+ double d13part = (1.0D - d7part) * this.getSeenFraction(pos, entityComplexPart, null, blockCache, blockPos); // Sakura // Paper - optimise explosions
|
||||||
|
+ entityComplexPart.hurt(this.getDamageSource(), (float) ((int) ((d13part * d13part + d13part) / 2.0D * 7.0D * (double) radius + 1.0D)));
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
+ entity.hurt(this.getDamageSource(), (float) ((int) ((d13 * d13 + d13) / 2.0D * 7.0D * radius + 1.0D)));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ CraftEventFactory.entityDamage = null;
|
||||||
|
+ if (entity.lastDamageCancelled) { // SPIGOT-5339, SPIGOT-6252, SPIGOT-6777: Skip entity if damage event was cancelled
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ // CraftBukkit end
|
||||||
|
+ double d14;
|
||||||
|
+
|
||||||
|
+ if (entity instanceof LivingEntity) {
|
||||||
|
+ LivingEntity entityliving = (LivingEntity) entity;
|
||||||
|
+
|
||||||
|
+ d14 = entity instanceof Player && level.paperConfig().environment.disableExplosionKnockback ? 0 : ProtectionEnchantment.getExplosionKnockbackAfterDampener(entityliving, d13); // Paper - disable explosion knockback
|
||||||
|
+ } else {
|
||||||
|
+ d14 = d13;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ d8 *= d14;
|
||||||
|
+ d9 *= d14;
|
||||||
|
+ d10 *= d14;
|
||||||
|
+
|
||||||
|
+ // Sakura start - reduce deltamovement allocations
|
||||||
|
+ entity.addDeltaMovement(d8, d9, d10);
|
||||||
|
+ if (entity instanceof Player) {
|
||||||
|
+ Vec3 vec3d1 = new Vec3(d8, d9, d10);
|
||||||
|
+ // Sakura end
|
||||||
|
+ Player entityhuman = (Player) entity;
|
||||||
|
+
|
||||||
|
+ if (!entityhuman.isSpectator() && (!entityhuman.isCreative() || !entityhuman.getAbilities().flying) && !level.paperConfig().environment.disableExplosionKnockback) { // Paper - Disable explosion knockback
|
||||||
|
+ this.getHitPlayers().put(entityhuman, vec3d1);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/me/samsuik/sakura/utils/ExplosionUtil.java b/src/main/java/me/samsuik/sakura/utils/ExplosionUtil.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..e0387f16ff49031fdcbc8990613417da88d84e87
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/me/samsuik/sakura/utils/ExplosionUtil.java
|
||||||
|
@@ -0,0 +1,64 @@
|
||||||
|
+package me.samsuik.sakura.utils;
|
||||||
|
+
|
||||||
|
+import it.unimi.dsi.fastutil.doubles.DoubleArrayList;
|
||||||
|
+
|
||||||
|
+import java.util.ArrayList;
|
||||||
|
+import java.util.List;
|
||||||
|
+
|
||||||
|
+public class ExplosionUtil {
|
||||||
|
+
|
||||||
|
+ private static final java.util.function.Function<double[], Double> highestOf = (vector) -> {
|
||||||
|
+ double highest = 0;
|
||||||
|
+
|
||||||
|
+ for (double v : vector) {
|
||||||
|
+ highest = Math.max(Math.abs(v), highest);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return highest;
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
+ public static void reduceRays(DoubleArrayList rayCoords) {
|
||||||
|
+ // temporarily transform rayCoords into a double[] list
|
||||||
|
+ List<double[]> vectors = new ArrayList<>();
|
||||||
|
+
|
||||||
|
+ for (int i = 0; i < rayCoords.size(); i += 3) {
|
||||||
|
+ vectors.add(new double[] {
|
||||||
|
+ rayCoords.getDouble(i),
|
||||||
|
+ rayCoords.getDouble(i + 1),
|
||||||
|
+ rayCoords.getDouble(i + 2)
|
||||||
|
+ });
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ vectors.sort((o1, o2) -> Double.compare(highestOf.apply(o2), highestOf.apply(o1)));
|
||||||
|
+
|
||||||
|
+ List<double[]> checked = new java.util.ArrayList<>();
|
||||||
|
+
|
||||||
|
+ for (double[] vector : vectors) {
|
||||||
|
+ boolean found = checked.stream().anyMatch((filtered) -> {
|
||||||
|
+ double x = (filtered[0] - vector[0]) / 0.3f;
|
||||||
|
+ double y = (filtered[1] - vector[1]) / 0.3f;
|
||||||
|
+ double z = (filtered[2] - vector[2]) / 0.3f;
|
||||||
|
+ double distanceSquared = x * x + y * y + z * z;
|
||||||
|
+
|
||||||
|
+ return (distanceSquared > 0.009 && distanceSquared < 0.01)
|
||||||
|
+ || (distanceSquared > 0.0075 && distanceSquared < 0.008)
|
||||||
|
+ || (distanceSquared > 0.006 && distanceSquared < 0.00675);
|
||||||
|
+ });
|
||||||
|
+
|
||||||
|
+ if (!found) {
|
||||||
|
+ checked.add(vector);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ rayCoords.clear();
|
||||||
|
+
|
||||||
|
+ for (double[] vector : vectors) {
|
||||||
|
+ for (double coord : vector) {
|
||||||
|
+ rayCoords.add(coord);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ rayCoords.trim();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
index 4bc68b3145f42f5a432e1e897b3f41606735afd1..dc02ae364afe4b1226d224d54e563cef1d784393 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||||
|
@@ -1580,6 +1580,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||||
|
worldserver.explosionDensityCache.clear(); // Paper - Optimize explosions
|
||||||
|
worldserver.minimalTNT.clear(); // Sakura - visibility api
|
||||||
|
worldserver.mergeHistory.expire(currentTickLong); // Sakura - merge cannoning entities
|
||||||
|
+ worldserver.densityCache.clear(); // Sakura
|
||||||
|
}
|
||||||
|
this.isIteratingOverLevels = false; // Paper
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
index 04afadf047b84492dddd5ecc39e116ca74189545..fdc2a130c22bb63fc2a84b4f1be0889f78fd40d4 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||||
|
@@ -1935,7 +1935,12 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||||
|
if (!explosion.interactsWithBlocks()) {
|
||||||
|
explosion.clearToBlow();
|
||||||
|
}
|
||||||
|
-
|
||||||
|
+ // Sakura start
|
||||||
|
+ notifyPlayersOfExplosion(x, y, z, power, explosion);
|
||||||
|
+ return explosion;
|
||||||
|
+ }
|
||||||
|
+ public void notifyPlayersOfExplosion(double x, double y, double z, float power, Explosion explosion) {
|
||||||
|
+ // Sakura end
|
||||||
|
Iterator iterator = this.players.iterator();
|
||||||
|
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
@@ -1946,7 +1951,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- return explosion;
|
||||||
|
+ // Sakura - move up
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||||
|
index 02ef6ca32f3de52e921fdcf3f0f572ce7afef318..919680a42a8362859cd87fb3d87e8ee80e9cd960 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||||
|
@@ -78,6 +78,7 @@ public class PrimedTnt extends Entity implements TraceableEntity {
|
||||||
|
|| tnt.entityState().fallDistance() > 2.5f && fallDistance > 2.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ /*
|
||||||
|
@Override
|
||||||
|
protected void respawn() {
|
||||||
|
if (stacked <= 1) return;
|
||||||
|
@@ -115,6 +116,7 @@ public class PrimedTnt extends Entity implements TraceableEntity {
|
||||||
|
|
||||||
|
tnt.discard();
|
||||||
|
}
|
||||||
|
+ */
|
||||||
|
// Sakura end
|
||||||
|
|
||||||
|
@Override
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java
|
||||||
|
index 1b335111bd9eb90bbda87225b740768705f26193..545b8dc248d3d57396f548e57898e009876cc150 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/Explosion.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/Explosion.java
|
||||||
|
@@ -56,12 +56,14 @@ public class Explosion {
|
||||||
|
private final Explosion.BlockInteraction blockInteraction;
|
||||||
|
private final RandomSource random;
|
||||||
|
private final Level level;
|
||||||
|
- private final double x;
|
||||||
|
- private final double y;
|
||||||
|
- private final double z;
|
||||||
|
+ // Sakura start - final private -> protected
|
||||||
|
+ protected double x;
|
||||||
|
+ protected double y;
|
||||||
|
+ protected double z;
|
||||||
|
+ // Sakura end
|
||||||
|
@Nullable
|
||||||
|
public final Entity source;
|
||||||
|
- private final float radius;
|
||||||
|
+ protected final float radius; // Sakura - private -> protected
|
||||||
|
private final DamageSource damageSource;
|
||||||
|
private final ExplosionDamageCalculator damageCalculator;
|
||||||
|
private final ObjectArrayList<BlockPos> toBlow;
|
||||||
|
@@ -122,6 +124,12 @@ public class Explosion {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Sakura start
|
||||||
|
+ if (me.samsuik.sakura.configuration.GlobalConfiguration.get().cannons.explosion.reducedSearchRays) {
|
||||||
|
+ me.samsuik.sakura.utils.ExplosionUtil.reduceRays(rayCoords);
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
+
|
||||||
|
CACHED_RAYS = rayCoords.toDoubleArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -129,14 +137,14 @@ public class Explosion {
|
||||||
|
private static final int CHUNK_CACHE_MASK = (1 << CHUNK_CACHE_SHIFT) - 1;
|
||||||
|
private static final int CHUNK_CACHE_WIDTH = 1 << CHUNK_CACHE_SHIFT;
|
||||||
|
|
||||||
|
- private static final int BLOCK_EXPLOSION_CACHE_SHIFT = 3;
|
||||||
|
- private static final int BLOCK_EXPLOSION_CACHE_MASK = (1 << BLOCK_EXPLOSION_CACHE_SHIFT) - 1;
|
||||||
|
+ protected static final int BLOCK_EXPLOSION_CACHE_SHIFT = 3; // Sakura - protected
|
||||||
|
+ protected static final int BLOCK_EXPLOSION_CACHE_MASK = (1 << BLOCK_EXPLOSION_CACHE_SHIFT) - 1; // Sakura - protected
|
||||||
|
private static final int BLOCK_EXPLOSION_CACHE_WIDTH = 1 << BLOCK_EXPLOSION_CACHE_SHIFT;
|
||||||
|
|
||||||
|
// resistance = (res + 0.3F) * 0.3F;
|
||||||
|
// so for resistance = 0, we need res = -0.3F
|
||||||
|
private static final Float ZERO_RESISTANCE = Float.valueOf(-0.3f);
|
||||||
|
- private it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<ExplosionBlockCache> blockCache = null;
|
||||||
|
+ protected it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<ExplosionBlockCache> blockCache = null; // Sakura - protected
|
||||||
|
|
||||||
|
public static final class ExplosionBlockCache {
|
||||||
|
|
||||||
|
@@ -163,7 +171,7 @@ public class Explosion {
|
||||||
|
private long[] chunkPosCache = null;
|
||||||
|
private net.minecraft.world.level.chunk.LevelChunk[] chunkCache = null;
|
||||||
|
|
||||||
|
- private ExplosionBlockCache getOrCacheExplosionBlock(final int x, final int y, final int z,
|
||||||
|
+ protected ExplosionBlockCache getOrCacheExplosionBlock(final int x, final int y, final int z, // Sakura - private -> protected
|
||||||
|
final long key, final boolean calculateResistance) {
|
||||||
|
ExplosionBlockCache ret = this.blockCache.get(key);
|
||||||
|
if (ret != null) {
|
||||||
|
@@ -281,7 +289,7 @@ public class Explosion {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (!collision.isEmpty() && collision.clipDirect(from, to, currPos)) { // Sakura
|
||||||
|
+ if (!collision.isEmpty() && collision.clip(from, to, currPos) != null) { // Sakura
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -313,7 +321,8 @@ public class Explosion {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- private float getSeenFraction(final Vec3 source, final Entity target,
|
||||||
|
+ protected float getSeenFraction(final Vec3 source, final Entity target, // Sakura - protected
|
||||||
|
+ final @Nullable me.samsuik.sakura.explosion.DensityCache.Density data, // Sakura
|
||||||
|
final ExplosionBlockCache[] blockCache,
|
||||||
|
final BlockPos.MutableBlockPos blockPos) {
|
||||||
|
final AABB boundingBox = target.getBoundingBox();
|
||||||
|
@@ -351,7 +360,11 @@ public class Explosion {
|
||||||
|
Math.fma(dz, diffZ, offZ)
|
||||||
|
);
|
||||||
|
|
||||||
|
- if (!this.clipsAnything(from, source, context, blockCache, blockPos)) {
|
||||||
|
+ // Sakura start
|
||||||
|
+ if (data != null && data.isExpandable() && data.has(from)) {
|
||||||
|
+ missedRays += (int) data.density();
|
||||||
|
+ } else if (!this.clipsAnything(from, source, context, blockCache, blockPos)) {
|
||||||
|
+ // Sakura end
|
||||||
|
++missedRays;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -361,6 +374,66 @@ public class Explosion {
|
||||||
|
return (float)missedRays / (float)totalRays;
|
||||||
|
}
|
||||||
|
// Paper end - optimise collisions
|
||||||
|
+ // Sakura start
|
||||||
|
+ protected ExplosionBlockCache[] createBlockCache() {
|
||||||
|
+ this.blockCache = new it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<>();
|
||||||
|
+
|
||||||
|
+ this.chunkPosCache = new long[CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH];
|
||||||
|
+ java.util.Arrays.fill(this.chunkPosCache, ChunkPos.INVALID_CHUNK_POS);
|
||||||
|
+
|
||||||
|
+ this.chunkCache = new net.minecraft.world.level.chunk.LevelChunk[CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH];
|
||||||
|
+
|
||||||
|
+ return new ExplosionBlockCache[BLOCK_EXPLOSION_CACHE_WIDTH * BLOCK_EXPLOSION_CACHE_WIDTH * BLOCK_EXPLOSION_CACHE_WIDTH];
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ protected void clearBlockCache() {
|
||||||
|
+ this.blockCache = null; // Paper - optimise explosions
|
||||||
|
+ this.chunkPosCache = null; // Paper - optimise explosions
|
||||||
|
+ this.chunkCache = null; // Paper - optimise explosions
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ protected void invalidateBlockCache(ExplosionBlockCache[] blockCaches) {
|
||||||
|
+ for (BlockPos blow : getToBlow()) {
|
||||||
|
+ final int cacheKey =
|
||||||
|
+ (blow.getX() & BLOCK_EXPLOSION_CACHE_MASK) |
|
||||||
|
+ (blow.getY() & BLOCK_EXPLOSION_CACHE_MASK) << (BLOCK_EXPLOSION_CACHE_SHIFT) |
|
||||||
|
+ (blow.getZ() & BLOCK_EXPLOSION_CACHE_MASK) << (BLOCK_EXPLOSION_CACHE_SHIFT + BLOCK_EXPLOSION_CACHE_SHIFT);
|
||||||
|
+
|
||||||
|
+ blockCaches[cacheKey] = null;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ blockCache.clear();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ protected boolean isDestructibleBlock(BlockState state) {
|
||||||
|
+ if (state == null) {
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ float power = radius * 1.3f;
|
||||||
|
+ float blockRes = state.getBlock().getExplosionResistance();
|
||||||
|
+ float fluidRes = state.getFluidState().getExplosionResistance();
|
||||||
|
+
|
||||||
|
+ // This should be better than just checking if we're within a fluid block.
|
||||||
|
+ return Math.max(blockRes, fluidRes) <= power;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ protected boolean isProtectedRegion() {
|
||||||
|
+ // check if there is a plugin cancelling or clearing the block list.
|
||||||
|
+ // for our use case on factions and cannon servers this is a relatively
|
||||||
|
+ // sane optimisation, this may not be the case for other servers.
|
||||||
|
+ if (source != null && level.sakuraConfig().cannons.explosion.optimiseProtectedRegions) {
|
||||||
|
+ Location location = new Location(level.getWorld(), x, y, z);
|
||||||
|
+ java.util.ArrayList<org.bukkit.block.Block> blocks = new java.util.ArrayList<>(1);
|
||||||
|
+ blocks.add(location.getBlock());
|
||||||
|
+ EntityExplodeEvent event = new EntityExplodeEvent(source.getBukkitEntity(), location, blocks, 0.0f);
|
||||||
|
+ event.callEvent();
|
||||||
|
+ return !event.isCancelled() && !event.blockList().isEmpty();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
|
||||||
|
private ExplosionDamageCalculator makeDamageCalculator(@Nullable Entity entity) {
|
||||||
|
return (ExplosionDamageCalculator) (entity == null ? Explosion.EXPLOSION_DAMAGE_CALCULATOR : new EntityBasedExplosionDamageCalculator(entity));
|
||||||
|
@@ -407,7 +480,29 @@ public class Explosion {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// CraftBukkit end
|
||||||
|
+ // Sakura start
|
||||||
|
+ final ExplosionBlockCache[] blockCache = createBlockCache();
|
||||||
|
+
|
||||||
|
+ // block at explosion position
|
||||||
|
+ int blockX = Mth.floor(x);
|
||||||
|
+ int blockY = Mth.floor(y);
|
||||||
|
+ int blockZ = Mth.floor(z);
|
||||||
|
+ long key = BlockPos.asLong(blockX, blockY, blockZ);
|
||||||
|
+ ExplosionBlockCache center = this.getOrCacheExplosionBlock(blockX, blockY, blockZ, key, true);
|
||||||
|
+
|
||||||
|
+ if (interactsWithBlocks() && isDestructibleBlock(center.blockState) && !isProtectedRegion()) {
|
||||||
|
+ searchForBlocks(blockCache);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // Checking if this explosion occurred inside a block is not a viable optimisation.
|
||||||
|
+ // If an entity is 1.0e-7 away from the position no matter it will be affected no matter what.
|
||||||
|
+ locateAndImpactEntities(blockCache);
|
||||||
|
+ clearBlockCache();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ protected void searchForBlocks(ExplosionBlockCache[] blockCache) {
|
||||||
|
this.level.gameEvent(this.source, GameEvent.EXPLODE, new Vec3(this.x, this.y, this.z));
|
||||||
|
+ // Sakura end
|
||||||
|
Set<BlockPos> set = Sets.newHashSet();
|
||||||
|
boolean flag = true;
|
||||||
|
|
||||||
|
@@ -415,14 +510,7 @@ public class Explosion {
|
||||||
|
int j;
|
||||||
|
|
||||||
|
// Paper start - optimise explosions
|
||||||
|
- this.blockCache = new it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<>();
|
||||||
|
-
|
||||||
|
- this.chunkPosCache = new long[CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH];
|
||||||
|
- java.util.Arrays.fill(this.chunkPosCache, ChunkPos.INVALID_CHUNK_POS);
|
||||||
|
-
|
||||||
|
- this.chunkCache = new net.minecraft.world.level.chunk.LevelChunk[CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH];
|
||||||
|
-
|
||||||
|
- final ExplosionBlockCache[] blockCache = new ExplosionBlockCache[BLOCK_EXPLOSION_CACHE_WIDTH * BLOCK_EXPLOSION_CACHE_WIDTH * BLOCK_EXPLOSION_CACHE_WIDTH];
|
||||||
|
+ // Sakura - move up
|
||||||
|
// use initial cache value that is most likely to be used: the source position
|
||||||
|
final ExplosionBlockCache initialCache;
|
||||||
|
{
|
||||||
|
@@ -521,10 +609,15 @@ public class Explosion {
|
||||||
|
}
|
||||||
|
|
||||||
|
this.toBlow.addAll(set);
|
||||||
|
+ // Sakura start
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ protected void locateAndImpactEntities(ExplosionBlockCache[] blockCache) {
|
||||||
|
float f2 = this.radius * 2.0F;
|
||||||
|
|
||||||
|
- i = Mth.floor(this.x - (double) f2 - 1.0D);
|
||||||
|
- j = Mth.floor(this.x + (double) f2 + 1.0D);
|
||||||
|
+ int i = Mth.floor(this.x - (double) f2 - 1.0D);
|
||||||
|
+ int j = Mth.floor(this.x + (double) f2 + 1.0D);
|
||||||
|
+ // Sakura end
|
||||||
|
int l = Mth.floor(this.y - (double) f2 - 1.0D);
|
||||||
|
int i1 = Mth.floor(this.y + (double) f2 + 1.0D);
|
||||||
|
int j1 = Mth.floor(this.z - (double) f2 - 1.0D);
|
||||||
|
@@ -574,7 +667,7 @@ public class Explosion {
|
||||||
|
// Calculate damage separately for each EntityComplexPart
|
||||||
|
double d7part;
|
||||||
|
if (list.contains(entityComplexPart) && (d7part = Math.sqrt(entityComplexPart.distanceToSqr(vec3d)) / f2) <= 1.0D) {
|
||||||
|
- double d13part = (1.0D - d7part) * this.getSeenFraction(vec3d, entityComplexPart, blockCache, blockPos); // Paper - optimise explosions
|
||||||
|
+ double d13part = (1.0D - d7part) * this.getSeenFraction(vec3d, entityComplexPart, null, blockCache, blockPos); // Sakura // Paper - optimise explosions
|
||||||
|
entityComplexPart.hurt(this.getDamageSource(), (float) ((int) ((d13part * d13part + d13part) / 2.0D * 7.0D * (double) f2 + 1.0D)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -617,9 +710,7 @@ public class Explosion {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- this.blockCache = null; // Paper - optimise explosions
|
||||||
|
- this.chunkPosCache = null; // Paper - optimise explosions
|
||||||
|
- this.chunkCache = null; // Paper - optimise explosions
|
||||||
|
+ // Sakura - move up
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -683,6 +774,12 @@ public class Explosion {
|
||||||
|
this.toBlow.add(coords);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Sakura start
|
||||||
|
+ if (!level.paperConfig().environment.optimizeExplosions) {
|
||||||
|
+ level.densityCache.clear();
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
+
|
||||||
|
if (cancelled) {
|
||||||
|
this.wasCanceled = true;
|
||||||
|
return;
|
||||||
|
@@ -850,15 +947,22 @@ public class Explosion {
|
||||||
|
private BlockInteraction() {}
|
||||||
|
}
|
||||||
|
// Paper start - Optimize explosions
|
||||||
|
- private float getBlockDensity(Vec3 vec3d, Entity entity, ExplosionBlockCache[] blockCache, BlockPos.MutableBlockPos blockPos) { // Paper - optimise explosions
|
||||||
|
- if (!this.level.paperConfig().environment.optimizeExplosions) {
|
||||||
|
- return this.getSeenFraction(vec3d, entity, blockCache, blockPos); // Paper - optimise explosions
|
||||||
|
+ // Sakura start
|
||||||
|
+ protected float getBlockDensity(Vec3 vec3d, Entity entity, ExplosionBlockCache[] blockCache, BlockPos.MutableBlockPos blockPos) { // Paper - optimise explosions
|
||||||
|
+ int key = me.samsuik.sakura.explosion.DensityCache.createKey(entity, vec3d);
|
||||||
|
+ me.samsuik.sakura.explosion.DensityCache.Density data = level.densityCache.retrieveCache(key);
|
||||||
|
+
|
||||||
|
+ if (data != null && data.has(entity.getBoundingBox(), vec3d)) {
|
||||||
|
+ return data.density();
|
||||||
|
}
|
||||||
|
- CacheKey key = new CacheKey(this, entity.getBoundingBox());
|
||||||
|
- Float blockDensity = this.level.explosionDensityCache.get(key);
|
||||||
|
- if (blockDensity == null) {
|
||||||
|
- blockDensity = this.getSeenFraction(vec3d, entity, blockCache, blockPos); // Paper - optimise explosions;
|
||||||
|
- this.level.explosionDensityCache.put(key, blockDensity);
|
||||||
|
+
|
||||||
|
+ float blockDensity = this.getSeenFraction(vec3d, entity, data, blockCache, blockPos); // Paper - optimise explosions;
|
||||||
|
+
|
||||||
|
+ if (data == null || !data.isExpandable() && (blockDensity == 0.0f || blockDensity == 1.0f)) {
|
||||||
|
+ level.densityCache.createCache(key, entity, vec3d, blockDensity);
|
||||||
|
+ } else if (data.isExpandable() && data.density() == blockDensity) {
|
||||||
|
+ data.expand(entity.getBoundingBox(), vec3d);
|
||||||
|
+ // Sakura end
|
||||||
|
}
|
||||||
|
|
||||||
|
return blockDensity;
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
index 2f72a059b051bb3d35e0844c6b7ae3b6e2655e36..1ed0e2f30944575c252603b7c45649bb745efd2a 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
@@ -228,6 +228,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||||
|
}
|
||||||
|
// Sakura end
|
||||||
|
public final me.samsuik.sakura.entity.merge.MergeHistory mergeHistory = new me.samsuik.sakura.entity.merge.MergeHistory(); // Sakura
|
||||||
|
+ public final me.samsuik.sakura.explosion.DensityCache densityCache = new me.samsuik.sakura.explosion.DensityCache();
|
||||||
|
|
||||||
|
protected Level(WritableLevelData worlddatamutable, ResourceKey<Level> resourcekey, RegistryAccess iregistrycustom, Holder<DimensionType> holder, Supplier<ProfilerFiller> supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function<org.spigotmc.SpigotWorldConfig, io.papermc.paper.configuration.WorldConfiguration> paperWorldConfigCreator, Supplier<me.samsuik.sakura.configuration.WorldConfiguration> sakuraWorldConfigCreator, java.util.concurrent.Executor executor) { // Sakura // Paper - Async-Anti-Xray - Pass executor
|
||||||
|
this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot
|
||||||
|
@@ -1406,7 +1407,15 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||||
|
}
|
||||||
|
|
||||||
|
Explosion.BlockInteraction explosion_effect1 = explosion_effect;
|
||||||
|
- Explosion explosion = new Explosion(this, entity, damageSource, behavior, x, y, z, power, createFire, explosion_effect1);
|
||||||
|
+ // Sakura start
|
||||||
|
+ Explosion explosion;
|
||||||
|
+
|
||||||
|
+ if (explosionSourceType == ExplosionInteraction.TNT) {
|
||||||
|
+ explosion = new me.samsuik.sakura.explosion.SakuraExplosion(this, entity, damageSource, behavior, x, y, z, power, createFire, explosion_effect1);
|
||||||
|
+ } else {
|
||||||
|
+ explosion = new Explosion(this, entity, damageSource, behavior, x, y, z, power, createFire, explosion_effect1);
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
|
||||||
|
explosion.explode();
|
||||||
|
explosion.finalizeExplosion(particles);
|
||||||
232
patches/server/0020-Optimise-Fast-Movement.patch
Normal file
232
patches/server/0020-Optimise-Fast-Movement.patch
Normal file
@@ -0,0 +1,232 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
|
||||||
|
Date: Fri, 13 Oct 2023 14:36:19 +0100
|
||||||
|
Subject: [PATCH] Optimise Fast Movement
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
index 311891f079d2136a18f62478bd289c91ff515772..01c5279084a8f84dcaf8d0d51a3305dc04476944 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
@@ -1165,6 +1165,95 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||||
|
}
|
||||||
|
// Paper end - detailed watchdog information
|
||||||
|
|
||||||
|
+ // Sakura start - stripped back movement method for basic entities
|
||||||
|
+ public void moveBasic(MoverType movementType, Vec3 movement) {
|
||||||
|
+ io.papermc.paper.util.TickThread.ensureTickThread("Cannot move an entity off-main");
|
||||||
|
+
|
||||||
|
+ if (this.noPhysics) {
|
||||||
|
+ this.setPos(this.getX() + movement.x, this.getY() + movement.y, this.getZ() + movement.z);
|
||||||
|
+ } else {
|
||||||
|
+ if (movementType == MoverType.PISTON) { // Paper
|
||||||
|
+ movement = this.limitPistonMovement(movement);
|
||||||
|
+ if (movement.equals(Vec3.ZERO)) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ this.level().getProfiler().push("move");
|
||||||
|
+ if (this.stuckSpeedMultiplier.lengthSqr() > 1.0E-7D) {
|
||||||
|
+ movement = movement.multiply(this.stuckSpeedMultiplier);
|
||||||
|
+ this.stuckSpeedMultiplier = Vec3.ZERO;
|
||||||
|
+ this.setDeltaMovement(Vec3.ZERO);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // collideScan for optimised large movements
|
||||||
|
+ Vec3 vec3d1 = this.collideScan(movement);
|
||||||
|
+ double d0 = vec3d1.lengthSqr();
|
||||||
|
+
|
||||||
|
+ if (d0 > 1.0E-7D) {
|
||||||
|
+ // We might be able to get away with the addition of the falling block special case here and the 2.5f limit.
|
||||||
|
+ // Falling blocks only use fall distance for damaging entities when they land such as anvils.
|
||||||
|
+ if (this.fallDistance != 0.0F && d0 >= 1.0D && !isFallingBlock) {
|
||||||
|
+ BlockHitResult movingobjectpositionblock = this.level().clip(new ClipContext(this.position(), this.position().add(vec3d1), ClipContext.Block.FALLDAMAGE_RESETTING, ClipContext.Fluid.WATER, this));
|
||||||
|
+
|
||||||
|
+ if (movingobjectpositionblock.getType() != HitResult.Type.MISS) {
|
||||||
|
+ this.resetFallDistance();
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ this.setPos(this.getX() + vec3d1.x, this.getY() + vec3d1.y, this.getZ() + vec3d1.z);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ this.level().getProfiler().pop();
|
||||||
|
+ this.level().getProfiler().push("rest");
|
||||||
|
+ boolean flag = !Mth.equal(movement.x, vec3d1.x);
|
||||||
|
+ boolean flag1 = !Mth.equal(movement.z, vec3d1.z);
|
||||||
|
+
|
||||||
|
+ this.horizontalCollision = flag || flag1;
|
||||||
|
+ this.verticalCollision = movement.y != vec3d1.y;
|
||||||
|
+ this.verticalCollisionBelow = this.verticalCollision && movement.y < 0.0D;
|
||||||
|
+ if (this.horizontalCollision) {
|
||||||
|
+ this.minorHorizontalCollision = this.isHorizontalCollisionMinor(vec3d1);
|
||||||
|
+ } else {
|
||||||
|
+ this.minorHorizontalCollision = false;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ this.setOnGroundWithKnownMovement(this.verticalCollisionBelow, vec3d1);
|
||||||
|
+ BlockPos blockposition = this.getOnPosLegacy();
|
||||||
|
+ BlockState iblockdata = this.level().getBlockState(blockposition);
|
||||||
|
+
|
||||||
|
+ this.checkFallDamage(vec3d1.y, this.onGround(), iblockdata, blockposition);
|
||||||
|
+ if (this.isRemoved()) {
|
||||||
|
+ this.level().getProfiler().pop();
|
||||||
|
+ } else {
|
||||||
|
+ if (this.horizontalCollision) {
|
||||||
|
+ Vec3 vec3d2 = this.getDeltaMovement();
|
||||||
|
+
|
||||||
|
+ this.setDeltaMovement(flag ? 0.0D : vec3d2.x, vec3d2.y, flag1 ? 0.0D : vec3d2.z);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ Block block = iblockdata.getBlock();
|
||||||
|
+
|
||||||
|
+ if (movement.y != vec3d1.y) {
|
||||||
|
+ block.updateEntityAfterFallOn(this.level(), this);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (this.onGround()) {
|
||||||
|
+ // used for slowing down entities on top of slime
|
||||||
|
+ block.stepOn(this.level(), blockposition, iblockdata, this);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ this.tryCheckInsideBlocks();
|
||||||
|
+
|
||||||
|
+ float f = this.getBlockSpeedFactor();
|
||||||
|
+
|
||||||
|
+ this.multiplyDeltaMovement((double) f, 1.0D, (double) f); // Sakura - reduce movement allocations
|
||||||
|
+ this.level().getProfiler().pop();
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
+
|
||||||
|
public void move(MoverType movementType, Vec3 movement) {
|
||||||
|
// Paper start - detailed watchdog information
|
||||||
|
io.papermc.paper.util.TickThread.ensureTickThread("Cannot move an entity off-main");
|
||||||
|
@@ -1542,6 +1631,99 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||||
|
return offsetFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Sakura start
|
||||||
|
+ private Vec3 collideScan(Vec3 movement) {
|
||||||
|
+ if (movement.x == 0.0 && movement.y == 0.0 && movement.z == 0.0) {
|
||||||
|
+ return movement;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ final boolean scan = movement.lengthSqr() >= 12.0;
|
||||||
|
+ final List<AABB> potentialCollisionsBB = new java.util.ArrayList<>(8);
|
||||||
|
+ final List<VoxelShape> potentialCollisionsVoxel = new java.util.ArrayList<>(2);
|
||||||
|
+ final AABB currBoundingBox = getBoundingBox();
|
||||||
|
+
|
||||||
|
+ if (scan) {
|
||||||
|
+ return scanAndCollide(movement, currBoundingBox, potentialCollisionsVoxel, potentialCollisionsBB);
|
||||||
|
+ } else {
|
||||||
|
+ final AABB bb = currBoundingBox.expandTowards(movement.x, movement.y, movement.z);
|
||||||
|
+ collectCollisions(bb, potentialCollisionsVoxel, potentialCollisionsBB);
|
||||||
|
+ return io.papermc.paper.util.CollisionUtil.performCollisions(movement, currBoundingBox, potentialCollisionsVoxel, potentialCollisionsBB);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private Vec3 scanAndCollide(Vec3 movement, AABB currBoundingBox, List<VoxelShape> voxelList, List<AABB> bbList) {
|
||||||
|
+ double x = movement.x;
|
||||||
|
+ double y = movement.y;
|
||||||
|
+ double z = movement.z;
|
||||||
|
+
|
||||||
|
+ final boolean xSmaller = Math.abs(x) < Math.abs(z);
|
||||||
|
+
|
||||||
|
+ if (y != 0.0) {
|
||||||
|
+ y = scanY(currBoundingBox, y, voxelList, bbList);
|
||||||
|
+
|
||||||
|
+ if (y != 0.0) {
|
||||||
|
+ currBoundingBox = io.papermc.paper.util.CollisionUtil.offsetY(currBoundingBox, y);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (xSmaller && z != 0.0) {
|
||||||
|
+ z = scanZ(currBoundingBox, z, voxelList, bbList);
|
||||||
|
+
|
||||||
|
+ if (z != 0.0) {
|
||||||
|
+ currBoundingBox = io.papermc.paper.util.CollisionUtil.offsetZ(currBoundingBox, z);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (x != 0.0) {
|
||||||
|
+ x = scanX(currBoundingBox, x, voxelList, bbList);
|
||||||
|
+
|
||||||
|
+ if (x != 0.0) {
|
||||||
|
+ currBoundingBox = io.papermc.paper.util.CollisionUtil.offsetX(currBoundingBox, x);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (!xSmaller && z != 0.0) {
|
||||||
|
+ z = scanZ(currBoundingBox, z, voxelList, bbList);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return new Vec3(x, y, z);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private void collectCollisions(AABB collisionBox, List<VoxelShape> voxelList, List<AABB> bbList) {
|
||||||
|
+ // Copied from the collide method below
|
||||||
|
+ io.papermc.paper.util.CollisionUtil.getCollisions(
|
||||||
|
+ level, this, collisionBox, voxelList, bbList,
|
||||||
|
+ (0) | (loadChunks ? io.papermc.paper.util.CollisionUtil.COLLISION_FLAG_LOAD_CHUNKS : 0), // Sakura
|
||||||
|
+ null, null
|
||||||
|
+ );
|
||||||
|
+
|
||||||
|
+ if (collidingWithWorldBorder = io.papermc.paper.util.CollisionUtil.isCollidingWithBorderEdge(level.getWorldBorder(), collisionBox)) { // Paper - this line *is* correct, ignore the IDE warning about assignments being used as a condition
|
||||||
|
+ voxelList.add(level.getWorldBorder().getCollisionShape());
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private double scanX(AABB currBoundingBox, double x, List<VoxelShape> voxelList, List<AABB> bbList) {
|
||||||
|
+ AABB scanBox = currBoundingBox.expandTowards(x, 0.0, 0.0);
|
||||||
|
+ collectCollisions(scanBox, voxelList, bbList);
|
||||||
|
+ x = io.papermc.paper.util.CollisionUtil.performAABBCollisionsX(currBoundingBox, x, bbList);
|
||||||
|
+ return io.papermc.paper.util.CollisionUtil.performVoxelCollisionsX(currBoundingBox, x, voxelList);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private double scanY(AABB currBoundingBox, double y, List<VoxelShape> voxelList, List<AABB> bbList) {
|
||||||
|
+ AABB scanBox = currBoundingBox.expandTowards(0.0, y, 0.0);
|
||||||
|
+ collectCollisions(scanBox, voxelList, bbList);
|
||||||
|
+ y = io.papermc.paper.util.CollisionUtil.performAABBCollisionsY(currBoundingBox, y, bbList);
|
||||||
|
+ return io.papermc.paper.util.CollisionUtil.performVoxelCollisionsY(currBoundingBox, y, voxelList);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private double scanZ(AABB currBoundingBox, double z, List<VoxelShape> voxelList, List<AABB> bbList) {
|
||||||
|
+ AABB scanBox = currBoundingBox.expandTowards(0.0, 0.0, z);
|
||||||
|
+ collectCollisions(scanBox, voxelList, bbList);
|
||||||
|
+ z = io.papermc.paper.util.CollisionUtil.performAABBCollisionsZ(currBoundingBox, z, bbList);
|
||||||
|
+ return io.papermc.paper.util.CollisionUtil.performVoxelCollisionsZ(currBoundingBox, z, voxelList);
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
+
|
||||||
|
private Vec3 collide(Vec3 movement) {
|
||||||
|
// Paper start - optimise collisions
|
||||||
|
final boolean xZero = movement.x == 0.0;
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||||
|
index 2afcb3ebdfba545d7c1d73fd0aed486c1f8bf6ae..b592416daef8233a08537267c79290c6758250b4 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||||
|
@@ -201,7 +201,7 @@ public class FallingBlockEntity extends Entity {
|
||||||
|
this.addDeltaMovement(0.0D, -0.04D, 0.0D); // Sakura - reduce movement allocations
|
||||||
|
}
|
||||||
|
|
||||||
|
- this.move(MoverType.SELF, this.getDeltaMovement());
|
||||||
|
+ this.moveBasic(MoverType.SELF, this.getDeltaMovement()); // Sakura
|
||||||
|
|
||||||
|
// Paper start - fix sand duping
|
||||||
|
if (this.isRemoved()) {
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||||
|
index 919680a42a8362859cd87fb3d87e8ee80e9cd960..f661c6225401dba8bb13edcc72fb919a2c76d675 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||||
|
@@ -126,7 +126,7 @@ public class PrimedTnt extends Entity implements TraceableEntity {
|
||||||
|
this.addDeltaMovement(0.0D, -0.04D, 0.0D); // Sakura - reduce movement allocations
|
||||||
|
}
|
||||||
|
|
||||||
|
- this.move(MoverType.SELF, this.getDeltaMovement());
|
||||||
|
+ this.moveBasic(MoverType.SELF, this.getDeltaMovement()); // Sakura
|
||||||
|
// Paper start - Configurable TNT entity height nerf
|
||||||
|
if (this.level().paperConfig().fixes.tntEntityHeightNerf.test(v -> this.getY() > v)) {
|
||||||
|
this.discard();
|
||||||
374
patches/server/0021-Limited-Get-Entities.patch
Normal file
374
patches/server/0021-Limited-Get-Entities.patch
Normal file
@@ -0,0 +1,374 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Samsuik <kfian294ma4@gmail.com>
|
||||||
|
Date: Thu, 23 Sep 2021 15:19:31 +0100
|
||||||
|
Subject: [PATCH] Limited Get Entities
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java b/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java
|
||||||
|
index c4d1dbbd39ba0cdc9176ffa6d350d2aa50380211..857d530ad68aacb23baf40128a3f8b843b472259 100644
|
||||||
|
--- a/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java
|
||||||
|
+++ b/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java
|
||||||
|
@@ -514,6 +514,128 @@ public final class EntityLookup implements LevelEntityGetter<Entity> {
|
||||||
|
return slices;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Sakura start - limited get entities
|
||||||
|
+ public void getLimitedEntities(final Entity except, final AABB box, final List<Entity> into,
|
||||||
|
+ final Predicate<? super Entity> predicate, final int limit, final int search) {
|
||||||
|
+ final int minChunkX = (Mth.floor(box.minX) - 2) >> 4;
|
||||||
|
+ final int minChunkZ = (Mth.floor(box.minZ) - 2) >> 4;
|
||||||
|
+ final int maxChunkX = (Mth.floor(box.maxX) + 2) >> 4;
|
||||||
|
+ final int maxChunkZ = (Mth.floor(box.maxZ) + 2) >> 4;
|
||||||
|
+
|
||||||
|
+ final int minRegionX = minChunkX >> REGION_SHIFT;
|
||||||
|
+ final int minRegionZ = minChunkZ >> REGION_SHIFT;
|
||||||
|
+ final int maxRegionX = maxChunkX >> REGION_SHIFT;
|
||||||
|
+ final int maxRegionZ = maxChunkZ >> REGION_SHIFT;
|
||||||
|
+
|
||||||
|
+ for (int currRegionZ = minRegionZ; currRegionZ <= maxRegionZ; ++currRegionZ) {
|
||||||
|
+ final int minZ = currRegionZ == minRegionZ ? minChunkZ & REGION_MASK : 0;
|
||||||
|
+ final int maxZ = currRegionZ == maxRegionZ ? maxChunkZ & REGION_MASK : REGION_MASK;
|
||||||
|
+
|
||||||
|
+ for (int currRegionX = minRegionX; currRegionX <= maxRegionX; ++currRegionX) {
|
||||||
|
+ final ChunkSlicesRegion region = this.getRegion(currRegionX, currRegionZ);
|
||||||
|
+
|
||||||
|
+ if (region == null) {
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ final int minX = currRegionX == minRegionX ? minChunkX & REGION_MASK : 0;
|
||||||
|
+ final int maxX = currRegionX == maxRegionX ? maxChunkX & REGION_MASK : REGION_MASK;
|
||||||
|
+
|
||||||
|
+ for (int currZ = minZ; currZ <= maxZ; ++currZ) {
|
||||||
|
+ for (int currX = minX; currX <= maxX; ++currX) {
|
||||||
|
+ final ChunkEntitySlices chunk = region.get(currX | (currZ << REGION_SHIFT));
|
||||||
|
+ if (chunk == null || !chunk.status.isOrAfter(FullChunkStatus.FULL)) {
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ chunk.getLimitedEntities(except, box, into, predicate, limit, search);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public <T extends Entity> void getLimitedEntities(final EntityType<?> type, final AABB box, final List<? super T> into,
|
||||||
|
+ final Predicate<? super T> predicate, final int limit, final int search) {
|
||||||
|
+ final int minChunkX = (Mth.floor(box.minX) - 2) >> 4;
|
||||||
|
+ final int minChunkZ = (Mth.floor(box.minZ) - 2) >> 4;
|
||||||
|
+ final int maxChunkX = (Mth.floor(box.maxX) + 2) >> 4;
|
||||||
|
+ final int maxChunkZ = (Mth.floor(box.maxZ) + 2) >> 4;
|
||||||
|
+
|
||||||
|
+ final int minRegionX = minChunkX >> REGION_SHIFT;
|
||||||
|
+ final int minRegionZ = minChunkZ >> REGION_SHIFT;
|
||||||
|
+ final int maxRegionX = maxChunkX >> REGION_SHIFT;
|
||||||
|
+ final int maxRegionZ = maxChunkZ >> REGION_SHIFT;
|
||||||
|
+
|
||||||
|
+ for (int currRegionZ = minRegionZ; currRegionZ <= maxRegionZ; ++currRegionZ) {
|
||||||
|
+ final int minZ = currRegionZ == minRegionZ ? minChunkZ & REGION_MASK : 0;
|
||||||
|
+ final int maxZ = currRegionZ == maxRegionZ ? maxChunkZ & REGION_MASK : REGION_MASK;
|
||||||
|
+
|
||||||
|
+ for (int currRegionX = minRegionX; currRegionX <= maxRegionX; ++currRegionX) {
|
||||||
|
+ final ChunkSlicesRegion region = this.getRegion(currRegionX, currRegionZ);
|
||||||
|
+
|
||||||
|
+ if (region == null) {
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ final int minX = currRegionX == minRegionX ? minChunkX & REGION_MASK : 0;
|
||||||
|
+ final int maxX = currRegionX == maxRegionX ? maxChunkX & REGION_MASK : REGION_MASK;
|
||||||
|
+
|
||||||
|
+ for (int currZ = minZ; currZ <= maxZ; ++currZ) {
|
||||||
|
+ for (int currX = minX; currX <= maxX; ++currX) {
|
||||||
|
+ final ChunkEntitySlices chunk = region.get(currX | (currZ << REGION_SHIFT));
|
||||||
|
+ if (chunk == null || !chunk.status.isOrAfter(FullChunkStatus.FULL)) {
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ chunk.getLimitedEntities(type, box, (List)into, (Predicate)predicate, limit, search);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public <T extends Entity> void getLimitedEntities(final Class<? extends T> clazz, final Entity except, final AABB box, final List<? super T> into,
|
||||||
|
+ final Predicate<? super T> predicate, final int limit, final int search) {
|
||||||
|
+ final int minChunkX = (Mth.floor(box.minX) - 2) >> 4;
|
||||||
|
+ final int minChunkZ = (Mth.floor(box.minZ) - 2) >> 4;
|
||||||
|
+ final int maxChunkX = (Mth.floor(box.maxX) + 2) >> 4;
|
||||||
|
+ final int maxChunkZ = (Mth.floor(box.maxZ) + 2) >> 4;
|
||||||
|
+
|
||||||
|
+ final int minRegionX = minChunkX >> REGION_SHIFT;
|
||||||
|
+ final int minRegionZ = minChunkZ >> REGION_SHIFT;
|
||||||
|
+ final int maxRegionX = maxChunkX >> REGION_SHIFT;
|
||||||
|
+ final int maxRegionZ = maxChunkZ >> REGION_SHIFT;
|
||||||
|
+
|
||||||
|
+ for (int currRegionZ = minRegionZ; currRegionZ <= maxRegionZ; ++currRegionZ) {
|
||||||
|
+ final int minZ = currRegionZ == minRegionZ ? minChunkZ & REGION_MASK : 0;
|
||||||
|
+ final int maxZ = currRegionZ == maxRegionZ ? maxChunkZ & REGION_MASK : REGION_MASK;
|
||||||
|
+
|
||||||
|
+ for (int currRegionX = minRegionX; currRegionX <= maxRegionX; ++currRegionX) {
|
||||||
|
+ final ChunkSlicesRegion region = this.getRegion(currRegionX, currRegionZ);
|
||||||
|
+
|
||||||
|
+ if (region == null) {
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ final int minX = currRegionX == minRegionX ? minChunkX & REGION_MASK : 0;
|
||||||
|
+ final int maxX = currRegionX == maxRegionX ? maxChunkX & REGION_MASK : REGION_MASK;
|
||||||
|
+
|
||||||
|
+ for (int currZ = minZ; currZ <= maxZ; ++currZ) {
|
||||||
|
+ for (int currX = minX; currX <= maxX; ++currX) {
|
||||||
|
+ final ChunkEntitySlices chunk = region.get(currX | (currZ << REGION_SHIFT));
|
||||||
|
+ if (chunk == null || !chunk.status.isOrAfter(FullChunkStatus.FULL)) {
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ chunk.getLimitedEntities(clazz, except, box, into, predicate, limit, search);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
+
|
||||||
|
public void getEntitiesWithoutDragonParts(final Entity except, final AABB box, final List<Entity> into, final Predicate<? super Entity> predicate) {
|
||||||
|
final int minChunkX = (Mth.floor(box.minX) - 2) >> 4;
|
||||||
|
final int minChunkZ = (Mth.floor(box.minZ) - 2) >> 4;
|
||||||
|
diff --git a/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java b/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java
|
||||||
|
index d917a19c838ed3d74322abd85e1f737e852b5d7b..1ba10713c85d6f19f075cc267602a04c7e048252 100644
|
||||||
|
--- a/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java
|
||||||
|
+++ b/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java
|
||||||
|
@@ -258,6 +258,30 @@ public final class ChunkEntitySlices {
|
||||||
|
}
|
||||||
|
// Sakura end
|
||||||
|
|
||||||
|
+ // Sakura start - limited get entities
|
||||||
|
+ public void getLimitedEntities(final Entity except, final AABB box, final List<Entity> into, final Predicate<? super Entity> predicate, final int limit, final int search) {
|
||||||
|
+ this.allEntities.getLimitedEntities(except, box, into, predicate, limit, search);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public <T extends Entity> void getLimitedEntities(final EntityType<?> type, final AABB box, final List<? super T> into,
|
||||||
|
+ final Predicate<? super T> predicate, final int limit, final int search) {
|
||||||
|
+ this.allEntities.getLimitedEntities(type, box, (List)into, (Predicate)predicate, limit, search);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public <T extends Entity> void getLimitedEntities(final Class<? extends T> clazz, final Entity except, final AABB box, final List<? super T> into,
|
||||||
|
+ final Predicate<? super T> predicate, final int limit, final int search) {
|
||||||
|
+ EntityCollectionBySection collection = this.entitiesByClass.get(clazz);
|
||||||
|
+ if (collection != null) {
|
||||||
|
+ collection.getLimitedEntities(except, clazz, box, (List)into, (Predicate)predicate, limit, search);
|
||||||
|
+ } else {
|
||||||
|
+ synchronized (this) {
|
||||||
|
+ this.entitiesByClass.putIfAbsent(clazz, collection = this.initClass(clazz));
|
||||||
|
+ }
|
||||||
|
+ collection.getLimitedEntities(except, clazz, box, (List)into, (Predicate)predicate, limit, search);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
+
|
||||||
|
public void getHardCollidingEntities(final Entity except, final AABB box, final List<Entity> into, final Predicate<? super Entity> predicate) {
|
||||||
|
this.hardCollidingEntities.getEntities(except, box, into, predicate);
|
||||||
|
}
|
||||||
|
@@ -448,6 +472,155 @@ public final class ChunkEntitySlices {
|
||||||
|
}
|
||||||
|
// Sakura end
|
||||||
|
|
||||||
|
+ // Sakura start - limited get entities
|
||||||
|
+ public void getLimitedEntities(final Entity except, final Class<?> clazz, final AABB box, final List<Entity> into,
|
||||||
|
+ final Predicate<? super Entity> predicate, final int limit, int search) {
|
||||||
|
+ if (this.count == 0) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ final int minSection = this.manager.minSection;
|
||||||
|
+ final int maxSection = this.manager.maxSection;
|
||||||
|
+
|
||||||
|
+ final int min = Mth.clamp(Mth.floor(box.minY - 2.0) >> 4, minSection, maxSection);
|
||||||
|
+ final int max = Mth.clamp(Mth.floor(box.maxY + 2.0) >> 4, minSection, maxSection);
|
||||||
|
+
|
||||||
|
+ // TODO use the bitset
|
||||||
|
+
|
||||||
|
+ final BasicEntityList<Entity>[] entitiesBySection = this.entitiesBySection;
|
||||||
|
+
|
||||||
|
+ for (int section = min; section <= max; ++section) {
|
||||||
|
+ final BasicEntityList<Entity> list = entitiesBySection[section - minSection];
|
||||||
|
+
|
||||||
|
+ if (list == null) {
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ final Entity[] storage = list.storage;
|
||||||
|
+
|
||||||
|
+ int len = Math.min(storage.length, list.size());
|
||||||
|
+ int index = manager.world.random.nextInt(len); // starting position
|
||||||
|
+
|
||||||
|
+ for (int i = 0; i < len; ++i) {
|
||||||
|
+ index = (index + 1) % len; // Update index
|
||||||
|
+ final Entity entity = storage[index];
|
||||||
|
+
|
||||||
|
+ if (into.size() >= limit || search-- <= 0) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (entity == null || entity == except || !clazz.isInstance(entity) || !entity.getBoundingBox().intersects(box)) {
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (predicate != null && !predicate.test(entity)) {
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ into.add(entity);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public <T extends Entity> void getLimitedEntities(final EntityType<?> type, final AABB box, final List<? super T> into,
|
||||||
|
+ final Predicate<? super T> predicate, final int limit, int search) {
|
||||||
|
+ if (this.count == 0) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ final int minSection = this.manager.minSection;
|
||||||
|
+ final int maxSection = this.manager.maxSection;
|
||||||
|
+
|
||||||
|
+ final int min = Mth.clamp(Mth.floor(box.minY - 2.0) >> 4, minSection, maxSection);
|
||||||
|
+ final int max = Mth.clamp(Mth.floor(box.maxY + 2.0) >> 4, minSection, maxSection);
|
||||||
|
+
|
||||||
|
+ // TODO use the bitset
|
||||||
|
+
|
||||||
|
+ final BasicEntityList<Entity>[] entitiesBySection = this.entitiesBySection;
|
||||||
|
+
|
||||||
|
+ for (int section = min; section <= max; ++section) {
|
||||||
|
+ final BasicEntityList<Entity> list = entitiesBySection[section - minSection];
|
||||||
|
+
|
||||||
|
+ if (list == null) {
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ final Entity[] storage = list.storage;
|
||||||
|
+
|
||||||
|
+ int len = Math.min(storage.length, list.size());
|
||||||
|
+ int index = manager.world.random.nextInt(len); // starting position
|
||||||
|
+
|
||||||
|
+ for (int i = 0; i < len; ++i) {
|
||||||
|
+ index = (index + 1) % len; // Update index
|
||||||
|
+ final Entity entity = storage[index];
|
||||||
|
+
|
||||||
|
+ if (into.size() >= limit || search-- <= 0) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (entity == null || (type != null && entity.getType() != type) || !entity.getBoundingBox().intersects(box)) {
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (predicate != null && !predicate.test((T)entity)) {
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ into.add((T)entity);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public void getLimitedEntities(final Entity except, final AABB box, final List<Entity> into,
|
||||||
|
+ final Predicate<? super Entity> predicate, final int limit, int search) {
|
||||||
|
+ if (this.count == 0) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ final int minSection = this.manager.minSection;
|
||||||
|
+ final int maxSection = this.manager.maxSection;
|
||||||
|
+
|
||||||
|
+ final int min = Mth.clamp(Mth.floor(box.minY - 2.0) >> 4, minSection, maxSection);
|
||||||
|
+ final int max = Mth.clamp(Mth.floor(box.maxY + 2.0) >> 4, minSection, maxSection);
|
||||||
|
+
|
||||||
|
+ // TODO use the bitset
|
||||||
|
+
|
||||||
|
+ final BasicEntityList<Entity>[] entitiesBySection = this.entitiesBySection;
|
||||||
|
+
|
||||||
|
+ for (int section = min; section <= max; ++section) {
|
||||||
|
+ final BasicEntityList<Entity> list = entitiesBySection[section - minSection];
|
||||||
|
+
|
||||||
|
+ if (list == null) {
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ final Entity[] storage = list.storage;
|
||||||
|
+
|
||||||
|
+ int len = Math.min(storage.length, list.size());
|
||||||
|
+ int index = manager.world.random.nextInt(len); // starting position
|
||||||
|
+
|
||||||
|
+ for (int i = 0; i < len; ++i) {
|
||||||
|
+ index = (index + 1) % len; // Update index
|
||||||
|
+ final Entity entity = storage[index];
|
||||||
|
+
|
||||||
|
+ if (into.size() >= limit || search-- <= 0) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (entity == null || entity == except || !entity.getBoundingBox().intersects(box)) {
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (predicate != null && !predicate.test(entity)) {
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ into.add(entity);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
+
|
||||||
|
public void getEntities(final Entity except, final AABB box, final List<Entity> into, final Predicate<? super Entity> predicate) {
|
||||||
|
if (this.count == 0) {
|
||||||
|
return;
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
index 1ed0e2f30944575c252603b7c45649bb745efd2a..7382075d369a1c154d8ca62028c6a887d85adb07 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||||
|
@@ -230,6 +230,39 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||||
|
public final me.samsuik.sakura.entity.merge.MergeHistory mergeHistory = new me.samsuik.sakura.entity.merge.MergeHistory(); // Sakura
|
||||||
|
public final me.samsuik.sakura.explosion.DensityCache densityCache = new me.samsuik.sakura.explosion.DensityCache();
|
||||||
|
|
||||||
|
+ // Sakura start - limited get entities
|
||||||
|
+ public void getLimitedEntities(Entity except, AABB box, Predicate<? super Entity> predicate, List<Entity> into, int limit, int search) {
|
||||||
|
+ ((ServerLevel)this).getEntityLookup().getLimitedEntities(except, box, into, predicate, limit, search);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public <T extends Entity> List<T> getLimitedEntities(net.minecraft.world.entity.EntityType<?> filter, AABB box, Predicate<? super T> predicate, int limit, int search) {
|
||||||
|
+ List<T> ret = new java.util.ArrayList<>();
|
||||||
|
+ ((ServerLevel)this).getEntityLookup().getLimitedEntities(filter, box, ret, predicate, limit, search);
|
||||||
|
+ return ret;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public <T> void getLimitedEntitiesByClass(Class<? extends T> clazz, Entity except, final AABB box, List<? super T> into,
|
||||||
|
+ Predicate<? super T> predicate, int limit, int search) {
|
||||||
|
+ ((ServerLevel)this).getEntityLookup().getLimitedEntities((Class)clazz, except, box, (List)into, (Predicate)predicate, limit, search);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public <T extends Entity> List<T> getLimitedEntitiesOfClass(Class<T> entityClass, AABB box, Predicate<? super T> predicate, int limit, int search) {
|
||||||
|
+ List<T> ret = new java.util.ArrayList<>();
|
||||||
|
+ ((ServerLevel)this).getEntityLookup().getLimitedEntities(entityClass, null, box, ret, predicate, limit, search);
|
||||||
|
+ return ret;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public List<Entity> getLimitedEntities(@Nullable Entity except, AABB box, Predicate<? super Entity> predicate, int limit, int search) {
|
||||||
|
+ List<Entity> list = Lists.newArrayList();
|
||||||
|
+ getLimitedEntities(except, box, predicate, list, limit, search);
|
||||||
|
+ return list;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public List<Entity> getLimitedEntities(@Nullable Entity except, AABB box, int limit, int search) {
|
||||||
|
+ return this.getLimitedEntities(except, box, net.minecraft.world.entity.EntitySelector.NO_SPECTATORS, limit, search);
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
+
|
||||||
|
protected Level(WritableLevelData worlddatamutable, ResourceKey<Level> resourcekey, RegistryAccess iregistrycustom, Holder<DimensionType> holder, Supplier<ProfilerFiller> supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function<org.spigotmc.SpigotWorldConfig, io.papermc.paper.configuration.WorldConfiguration> paperWorldConfigCreator, Supplier<me.samsuik.sakura.configuration.WorldConfiguration> sakuraWorldConfigCreator, java.util.concurrent.Executor executor) { // Sakura // Paper - Async-Anti-Xray - Pass executor
|
||||||
|
this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot
|
||||||
|
this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper
|
||||||
50
patches/server/0022-isPushedByFluid-API.patch
Normal file
50
patches/server/0022-isPushedByFluid-API.patch
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
|
||||||
|
Date: Fri, 13 Oct 2023 20:02:04 +0100
|
||||||
|
Subject: [PATCH] isPushedByFluid API
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
index 01c5279084a8f84dcaf8d0d51a3305dc04476944..f8faa10e12f5e67fc89ccac831895c70d6333536 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
@@ -658,6 +658,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||||
|
discard();
|
||||||
|
}
|
||||||
|
// Sakura end
|
||||||
|
+ public boolean pushedByFluid; // Sakura
|
||||||
|
|
||||||
|
public Entity(EntityType<?> type, Level world) {
|
||||||
|
this.id = Entity.ENTITY_COUNTER.incrementAndGet();
|
||||||
|
@@ -4154,7 +4155,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPushedByFluid() {
|
||||||
|
- return true;
|
||||||
|
+ return pushedByFluid; // Sakura
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double getViewScale() {
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||||
|
index 315d8260e196709ed9084272aa640f11e327c0a8..f8dc36e73389035995b67ac04ce14886526888fc 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||||
|
@@ -548,6 +548,18 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
||||||
|
return this.entity.isInWater();
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Sakura start
|
||||||
|
+ @Override
|
||||||
|
+ public boolean isPushedByFluid() {
|
||||||
|
+ return getHandle().isPushedByFluid();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void setPushedByFluid(boolean push) {
|
||||||
|
+ getHandle().pushedByFluid = push;
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
+
|
||||||
|
@Override
|
||||||
|
public World getWorld() {
|
||||||
|
return this.entity.level().getWorld();
|
||||||
86
patches/server/0023-Cannon-Mechanics.patch
Normal file
86
patches/server/0023-Cannon-Mechanics.patch
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
|
||||||
|
Date: Sun, 15 Oct 2023 22:48:35 +0100
|
||||||
|
Subject: [PATCH] Cannon Mechanics
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||||
|
index b592416daef8233a08537267c79290c6758250b4..0ebb06d3f8350dc4d4a931f339c872f9943b7631 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||||
|
@@ -67,6 +67,7 @@ public class FallingBlockEntity extends Entity {
|
||||||
|
public CompoundTag blockData;
|
||||||
|
protected static final EntityDataAccessor<BlockPos> DATA_START_POS = SynchedEntityData.defineId(FallingBlockEntity.class, EntityDataSerializers.BLOCK_POS);
|
||||||
|
public boolean autoExpire = true; // Paper - Auto expire setting
|
||||||
|
+ public boolean heightParity; // Sakura
|
||||||
|
|
||||||
|
public FallingBlockEntity(EntityType<? extends FallingBlockEntity> type, Level world) {
|
||||||
|
super(type, world);
|
||||||
|
@@ -75,6 +76,7 @@ public class FallingBlockEntity extends Entity {
|
||||||
|
this.fallDamageMax = 40;
|
||||||
|
this.isFallingBlock = true; // Sakura
|
||||||
|
this.loadChunks = world.sakuraConfig().cannons.sand.loadsChunks; // Sakura - load chunks
|
||||||
|
+ this.heightParity = world.sakuraConfig().cannons.mechanics.fallingBlockParity; // Sakura
|
||||||
|
}
|
||||||
|
|
||||||
|
public FallingBlockEntity(Level world, double x, double y, double z, BlockState block) {
|
||||||
|
@@ -183,6 +185,12 @@ public class FallingBlockEntity extends Entity {
|
||||||
|
return itemEntity;
|
||||||
|
}
|
||||||
|
// Sakura end
|
||||||
|
+ // Sakura start
|
||||||
|
+ @Override
|
||||||
|
+ public final double getEyeY() {
|
||||||
|
+ return heightParity ? getY() : super.getEyeY();
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||||
|
index f661c6225401dba8bb13edcc72fb919a2c76d675..3818d07261ce4f276968691ad32a22b88ffe6826 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||||
|
@@ -46,6 +46,12 @@ public class PrimedTnt extends Entity implements TraceableEntity {
|
||||||
|
this.yo = y;
|
||||||
|
this.zo = z;
|
||||||
|
this.owner = igniter;
|
||||||
|
+ // Sakura start
|
||||||
|
+ switch (world.sakuraConfig().cannons.mechanics.tntSpread) {
|
||||||
|
+ case NONE -> multiplyDeltaMovement(0, 0, 0);
|
||||||
|
+ case Y -> multiplyDeltaMovement(0, 1, 0);
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@@ -239,7 +245,7 @@ public class PrimedTnt extends Entity implements TraceableEntity {
|
||||||
|
// Paper start - Optional prevent TNT from moving in water
|
||||||
|
@Override
|
||||||
|
public boolean isPushedByFluid() {
|
||||||
|
- return !level().paperConfig().fixes.preventTntFromMovingInWater && super.isPushedByFluid();
|
||||||
|
+ return !level().paperConfig().fixes.preventTntFromMovingInWater && level().sakuraConfig().cannons.mechanics.tntFlowsInWater && super.isPushedByFluid(); // Sakura - convenience
|
||||||
|
}
|
||||||
|
// Paper end
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java
|
||||||
|
index 55bfb0afc0e4e9f1ce2dd15f729bee61822c5afc..69b3682783308d188929742f738ec71df973eb03 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java
|
||||||
|
@@ -34,6 +34,16 @@ public class CraftFallingBlock extends CraftEntity implements FallingBlock {
|
||||||
|
public void setStacked(int stacked) {
|
||||||
|
getHandle().setStacked(stacked);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void setHeightParity(boolean parity) {
|
||||||
|
+ getHandle().heightParity = parity;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public boolean getHeightParity() {
|
||||||
|
+ return getHandle().heightParity;
|
||||||
|
+ }
|
||||||
|
// Sakura end
|
||||||
|
|
||||||
|
@Override
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
|
||||||
|
Date: Mon, 16 Oct 2023 22:41:12 +0100
|
||||||
|
Subject: [PATCH] Cache MovingBlockEntity collision shape
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java b/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
|
||||||
|
index 1ef87580574919796dbba707f44a413ee5c5781b..a971bb30ef8620f016a5968a9da40187ee31a3ef 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
|
||||||
|
@@ -43,6 +43,11 @@ public class PistonMovingBlockEntity extends BlockEntity {
|
||||||
|
private float progressO;
|
||||||
|
private long lastTicked;
|
||||||
|
private int deathTicks;
|
||||||
|
+ // Sakura start
|
||||||
|
+ private VoxelShape collisionShape = Shapes.empty();
|
||||||
|
+ private Direction shapeDirection = null;
|
||||||
|
+ private float shapeProgress = Float.MIN_VALUE;
|
||||||
|
+ // Sakura end
|
||||||
|
|
||||||
|
public PistonMovingBlockEntity(BlockPos pos, BlockState state) {
|
||||||
|
super(BlockEntityType.PISTON, pos, state);
|
||||||
|
@@ -336,6 +341,18 @@ public class PistonMovingBlockEntity extends BlockEntity {
|
||||||
|
}
|
||||||
|
|
||||||
|
public VoxelShape getCollisionShape(BlockGetter world, BlockPos pos) {
|
||||||
|
+ // Sakura start
|
||||||
|
+ var direction = NOCLIP.get();
|
||||||
|
+ if (progress == shapeProgress && direction == shapeDirection) {
|
||||||
|
+ return collisionShape;
|
||||||
|
+ } else {
|
||||||
|
+ shapeProgress = progress;
|
||||||
|
+ shapeDirection = direction;
|
||||||
|
+ return collisionShape = createCollisionShape(world, pos);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ private VoxelShape createCollisionShape(BlockGetter world, BlockPos pos) {
|
||||||
|
+ // Sakura end
|
||||||
|
VoxelShape voxelShape;
|
||||||
|
if (!this.extending && this.isSourcePiston && this.movedState.getBlock() instanceof PistonBaseBlock) {
|
||||||
|
voxelShape = this.movedState.setValue(PistonBaseBlock.EXTENDED, Boolean.valueOf(true)).getCollisionShape(world, pos);
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Samsuik <40902469+Samsuik@users.noreply.github.com>
|
||||||
|
Date: Mon, 16 Oct 2023 22:57:55 +0100
|
||||||
|
Subject: [PATCH] Optimise TNT fluid state and pushing
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
index f8faa10e12f5e67fc89ccac831895c70d6333536..91c05521b50f0c97841a6356b369f855ad804df1 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||||
|
@@ -2135,7 +2135,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||||
|
return this.isInWater() || flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
- void updateInWaterStateAndDoWaterCurrentPushing() {
|
||||||
|
+ protected void updateInWaterStateAndDoWaterCurrentPushing() { // Sakura
|
||||||
|
Entity entity = this.getVehicle();
|
||||||
|
|
||||||
|
if (entity instanceof Boat) {
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||||
|
index 3818d07261ce4f276968691ad32a22b88ffe6826..923dd09399cd85cdb31e129a03affb9403feb181 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
|
||||||
|
@@ -124,6 +124,19 @@ public class PrimedTnt extends Entity implements TraceableEntity {
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
// Sakura end
|
||||||
|
+ // Sakura start
|
||||||
|
+ protected boolean updateInWaterStateAndDoFluidPushing() {
|
||||||
|
+ if (isPushedByFluid()) {
|
||||||
|
+ return this.updateInWaterStateAndDoFluidPushing();
|
||||||
|
+ } else {
|
||||||
|
+ // super method also handles lava fluid pushing
|
||||||
|
+ // we only need to search for water to negate fall distance
|
||||||
|
+ this.fluidHeight.clear();
|
||||||
|
+ this.updateInWaterStateAndDoWaterCurrentPushing();
|
||||||
|
+ return isInWater();
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Sakura end
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
23
patches/server/0026-Optimise-LivingEntity-pushEntities.patch
Normal file
23
patches/server/0026-Optimise-LivingEntity-pushEntities.patch
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Samsuik <kfian294ma4@gmail.com>
|
||||||
|
Date: Thu, 23 Sep 2021 18:50:13 +0100
|
||||||
|
Subject: [PATCH] Optimise LivingEntity#pushEntities
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||||
|
index 77a1c7dfbaccc2e74da5c78ce4dfcd1717a7ac65..68b5e7d5293557cd1d7c1c202c48ac8caa40e721 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||||
|
@@ -3543,7 +3543,11 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Paper end - don't run getEntities if we're not going to use its result
|
||||||
|
- List<Entity> list = this.level().getEntities((Entity) this, this.getBoundingBox(), EntitySelector.pushable(this, this.level().paperConfig().collisions.fixClimbingBypassingCrammingRule)); // Paper - fix climbing bypassing cramming rule
|
||||||
|
+ // Sakura start - optimise entity pushing
|
||||||
|
+ int limit = Math.max(i, this.level().paperConfig().collisions.maxEntityCollisions);
|
||||||
|
+ int search = limit * limit;
|
||||||
|
+ List<Entity> list = this.level().getLimitedEntities(this, this.getBoundingBox(), EntitySelector.pushable(this, level().paperConfig().collisions.fixClimbingBypassingCrammingRule), limit, search); // Paper - fix climbing bypassing cramming rule
|
||||||
|
+ // Sakura end
|
||||||
|
|
||||||
|
if (!list.isEmpty()) {
|
||||||
|
// Paper - moved up
|
||||||
75
scripts/apatch.sh
Normal file
75
scripts/apatch.sh
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
gitcmd="git -c commit.gpgsign=false"
|
||||||
|
|
||||||
|
noapply=1
|
||||||
|
isreject=0
|
||||||
|
if [[ $1 == "--noapplied" ]]; then
|
||||||
|
noapply=1
|
||||||
|
shift
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -z "$1" ]; then
|
||||||
|
file="$1"
|
||||||
|
elif [ -z "$1" ] && [ -f .git/rebase-apply/patch ]; then
|
||||||
|
file=".git/rebase-apply/patch"
|
||||||
|
noapply=1
|
||||||
|
isreject=1
|
||||||
|
else
|
||||||
|
echo "Please specify a file"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
applied=$(echo $file | sed 's/.patch$/-applied\.patch/g')
|
||||||
|
if [ "$1" == "--reset" ]; then
|
||||||
|
$gitcmd am --abort
|
||||||
|
$gitcmd reset --hard
|
||||||
|
$gitcmd clean -f
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
(test "$isreject" != "1" && $gitcmd am -3 $file) || (
|
||||||
|
echo "Failures - Wiggling"
|
||||||
|
$gitcmd reset --hard
|
||||||
|
$gitcmd clean -f
|
||||||
|
errors=$($gitcmd apply --rej $file 2>&1)
|
||||||
|
echo "$errors" >> ~/patch.log
|
||||||
|
export missingfiles=""
|
||||||
|
export summaryfail=""
|
||||||
|
export summarygood=""
|
||||||
|
for i in $(find . -name \*.rej); do
|
||||||
|
base=$(echo "$i" | sed 's/.rej//g')
|
||||||
|
if [ -f "$i" ]; then
|
||||||
|
sed -e 's/^diff a\/\(.*\) b\/\(.*\)[[:space:]].*rejected.*$/--- \1\n+++ \2/' -i $i && wiggle -v -l --replace "$base" "$i"
|
||||||
|
rm "$base.porig" "$i"
|
||||||
|
else
|
||||||
|
echo "No such file: $base"
|
||||||
|
missingfiles="$missingfiles\n$base"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
for i in $($gitcmd status --porcelain | awk '{print $2}'); do
|
||||||
|
filedata=$(cat "$i")
|
||||||
|
if [ -f "$file" ] && [[ "$filedata" == *"<<<<<"* ]]; then
|
||||||
|
export summaryfail="$summaryfail\nFAILED TO APPLY: $i"
|
||||||
|
else
|
||||||
|
$gitcmd add --force "$i"
|
||||||
|
export summarygood="$summarygood\nAPPLIED CLEAN: $i"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo -e "$summarygood"
|
||||||
|
echo -e "$summaryfail"
|
||||||
|
if [[ "$errors" == *"No such file"* ]]; then
|
||||||
|
echo "===========================";
|
||||||
|
echo " "
|
||||||
|
echo " MISSING FILES"
|
||||||
|
echo $(echo "$errors" | grep "No such file")
|
||||||
|
echo -e "$missingfiles"
|
||||||
|
echo " "
|
||||||
|
echo "===========================";
|
||||||
|
fi
|
||||||
|
$gitcmd status
|
||||||
|
$gitcmd diff
|
||||||
|
)
|
||||||
|
if [[ "$noapply" != "1" ]] && [[ "$file" != *-applied.patch ]]; then
|
||||||
|
mv "$file" "$applied"
|
||||||
|
fi
|
||||||
27
scripts/upstream.sh
Normal file
27
scripts/upstream.sh
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
exit_on_error() {
|
||||||
|
echo "$1"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
git reset HEAD --hard
|
||||||
|
|
||||||
|
oldHash=$(grep "paperRef=" gradle.properties | cut -d "=" -f2)
|
||||||
|
newHash=$(curl -s https://api.github.com/repos/PaperMC/paper/commits/master | jq -r .sha)
|
||||||
|
|
||||||
|
if [ "$oldHash" = "$newHash" ]; then
|
||||||
|
echo "Upstream has not updated!"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Updating paper: $oldHash -> $newHash"
|
||||||
|
|
||||||
|
sed -i "s/$oldHash/$newHash/g" gradle.properties
|
||||||
|
git add gradle.properties
|
||||||
|
|
||||||
|
./gradlew applyPatches || exit_on_error "An error occurred when merging patches!"
|
||||||
|
./gradlew rebuildPatches || exit_on_error "An error occurred when rebuilding patches!"
|
||||||
|
./gradlew createReobfPaperclipJar || exit_on_error "An error occurred when building!"
|
||||||
|
|
||||||
|
scripts/upstreamCommit.sh $oldHash $newHash
|
||||||
|
|
||||||
|
echo "Created new commit, please review before pushing."
|
||||||
27
scripts/upstreamCommit.sh
Normal file
27
scripts/upstreamCommit.sh
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# requires curl & jq
|
||||||
|
|
||||||
|
# upstreamCommit <baseHash> <newHash>
|
||||||
|
# param: bashHash - the commit hash to use for comparing commits (baseHash...newHash)
|
||||||
|
# param: newHash - the commit hash to use for comparing commits
|
||||||
|
|
||||||
|
(
|
||||||
|
set -e
|
||||||
|
PS1="$"
|
||||||
|
|
||||||
|
paper=$(curl -H "Accept: application/vnd.github.v3+json" https://api.github.com/repos/PaperMC/Paper/compare/$1...$2 | jq -r '.commits[] | "PaperMC/Paper@\(.sha[:7]) \(.commit.message | split("\r\n")[0] | split("\n")[0])"')
|
||||||
|
|
||||||
|
updated=""
|
||||||
|
logsuffix=""
|
||||||
|
if [ ! -z "paper" ]; then
|
||||||
|
logsuffix="$logsuffix\n\nPaper Changes:\n$paper"
|
||||||
|
updated="Paper"
|
||||||
|
fi
|
||||||
|
disclaimer="Upstream has released updates that appear to apply and compile correctly"
|
||||||
|
|
||||||
|
log="${UP_LOG_PREFIX}Updated Upstream ($updated)\n\n${disclaimer}${logsuffix}"
|
||||||
|
|
||||||
|
echo -e "$log" | git commit -F -
|
||||||
|
|
||||||
|
) || exit 1
|
||||||
10
settings.gradle.kts
Normal file
10
settings.gradle.kts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
pluginManagement {
|
||||||
|
repositories {
|
||||||
|
gradlePluginPortal()
|
||||||
|
maven("https://papermc.io/repo/repository/maven-public/")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rootProject.name = "sakura"
|
||||||
|
|
||||||
|
include("sakura-api", "sakura-server")
|
||||||
Reference in New Issue
Block a user