mirror of
https://github.com/SparklyPower/SparklyPaper.git
synced 2025-12-21 16:09:30 +00:00
Update to Paper 1.21.4 (post hard fork™️ edition)
This commit is contained in:
94
sparklypaper-server/build.gradle.kts.patch
Normal file
94
sparklypaper-server/build.gradle.kts.patch
Normal file
@@ -0,0 +1,94 @@
|
||||
--- a/paper-server/build.gradle.kts
|
||||
+++ b/paper-server/build.gradle.kts
|
||||
@@ -4,6 +_,8 @@
|
||||
|
||||
plugins {
|
||||
`java-library`
|
||||
+ kotlin("jvm") version "2.0.0"
|
||||
+ kotlin("plugin.serialization") version "2.0.0"
|
||||
`maven-publish`
|
||||
id("io.papermc.paperweight.core")
|
||||
}
|
||||
@@ -21,6 +_,21 @@
|
||||
// macheOldPath = file("F:\\Projects\\PaperTooling\\mache\\versions\\1.21.4\\src\\main\\java")
|
||||
// gitFilePatches = true
|
||||
|
||||
+ val fork = forks.register("sparklypaper") {
|
||||
+ upstream.patchDir("paperServer") {
|
||||
+ upstreamPath = "paper-server"
|
||||
+ excludes = setOf("src/minecraft", "patches", "build.gradle.kts")
|
||||
+ patchesDir = rootDirectory.dir("sparklypaper-server/paper-patches")
|
||||
+ outputDir = rootDirectory.dir("paper-server")
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ activeFork = fork
|
||||
+
|
||||
+ paper {
|
||||
+ paperServerDir = upstreamsDirectory().map { it.dir("paper/paper-server") }
|
||||
+ }
|
||||
+
|
||||
spigot {
|
||||
buildDataRef = "3edaf46ec1eed4115ce1b18d2846cded42577e42"
|
||||
packageVersion = "v1_21_R3" // also needs to be updated in MappingEnvironment
|
||||
@@ -101,7 +_,20 @@
|
||||
}
|
||||
}
|
||||
|
||||
-val log4jPlugins = sourceSets.create("log4jPlugins")
|
||||
+sourceSets {
|
||||
+ main {
|
||||
+ java { srcDir("../paper-server/src/main/java") }
|
||||
+ resources { srcDir("../paper-server/src/main/resources") }
|
||||
+ }
|
||||
+ test {
|
||||
+ java { srcDir("../paper-server/src/test/java") }
|
||||
+ resources { srcDir("../paper-server/src/test/resources") }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+val log4jPlugins = sourceSets.create("log4jPlugins") {
|
||||
+ java { srcDir("../paper-server/src/log4jPlugins/java") }
|
||||
+}
|
||||
configurations.named(log4jPlugins.compileClasspathConfigurationName) {
|
||||
extendsFrom(configurations.compileClasspath.get())
|
||||
}
|
||||
@@ -119,7 +_,12 @@
|
||||
}
|
||||
|
||||
dependencies {
|
||||
- implementation(project(":paper-api"))
|
||||
+ // SparklyPaper start
|
||||
+ implementation(project(":sparklypaper-api"))
|
||||
+ implementation(kotlin("reflect"))
|
||||
+ implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
|
||||
+ implementation("com.charleskorn.kaml:kaml:0.55.0")
|
||||
+ // SparklyPaper end
|
||||
implementation("ca.spottedleaf:concurrentutil:0.0.3")
|
||||
implementation("org.jline:jline-terminal-ffm:3.27.1") // use ffm on java 22+
|
||||
implementation("org.jline:jline-terminal-jni:3.27.1") // fall back to jni on java 21
|
||||
@@ -183,7 +_,12 @@
|
||||
val build = System.getenv("BUILD_NUMBER") ?: null
|
||||
val buildTime = if (build != null) Instant.now() else Instant.EPOCH
|
||||
val gitHash = git.exec(providers, "rev-parse", "--short=7", "HEAD").get().trim()
|
||||
- val implementationVersion = "$mcVersion-${build ?: "DEV"}-$gitHash"
|
||||
+ // SparklyPaper start
|
||||
+ var implementationVersion = "$mcVersion-${build ?: "DEV"}-$gitHash"
|
||||
+ if (project.hasProperty("sparklypaperImplementationVersionSuffix")) {
|
||||
+ implementationVersion += "/${project.property("sparklypaperImplementationVersionSuffix")}"
|
||||
+ }
|
||||
+ // SparklyPaper end
|
||||
val date = git.exec(providers, "show", "-s", "--format=%ci", gitHash).get().trim()
|
||||
val gitBranch = git.exec(providers, "rev-parse", "--abbrev-ref", "HEAD").get().trim()
|
||||
attributes(
|
||||
@@ -194,8 +_,8 @@
|
||||
"Specification-Title" to "Paper",
|
||||
"Specification-Version" to project.version,
|
||||
"Specification-Vendor" to "Paper Team",
|
||||
- "Brand-Id" to "papermc:paper",
|
||||
- "Brand-Name" to "Paper",
|
||||
+ "Brand-Id" to "sparklypower:sparklypaper", // SparklyPaper
|
||||
+ "Brand-Name" to "SparklyPaper", // SparklyPaper
|
||||
"Build-Number" to (build ?: ""),
|
||||
"Build-Time" to buildTime.toString(),
|
||||
"Git-Branch" to gitBranch,
|
||||
@@ -0,0 +1,46 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||
Date: Mon, 13 Jan 2025 13:20:31 -0300
|
||||
Subject: [PATCH] SparklyPaper config files
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
index 97a294d2f5c1ddf0af7ffec3e1425eb329c5751b..4c420e17d936132bb4569776911757fd959e93d6 100644
|
||||
--- a/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -224,6 +224,15 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
io.papermc.paper.command.PaperCommands.registerCommands(this); // Paper - setup /paper command
|
||||
this.server.spark.registerCommandBeforePlugins(this.server); // Paper - spark
|
||||
com.destroystokyo.paper.Metrics.PaperMetrics.startMetrics(); // Paper - start metrics
|
||||
+ // SparklyPaper start
|
||||
+ try {
|
||||
+ net.sparklypower.sparklypaper.configs.SparklyPaperConfigUtils.INSTANCE.init((java.io.File) options.valueOf("sparklypaper-settings"));
|
||||
+ } catch (Exception e) {
|
||||
+ DedicatedServer.LOGGER.error("Unable to load server configuration", e);
|
||||
+ return false;
|
||||
+ }
|
||||
+ net.sparklypower.sparklypaper.SparklyPaperCommands.INSTANCE.registerCommands(this);
|
||||
+ // SparklyPaper end
|
||||
com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now
|
||||
|
||||
this.setPvpAllowed(properties.pvp);
|
||||
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
|
||||
index 2bbebb4335d927f240abcac67a5b423e38dc33d7..27c2ea4a387ee5f7d078a42cb57f146cb748501d 100644
|
||||
--- a/net/minecraft/world/level/Level.java
|
||||
+++ b/net/minecraft/world/level/Level.java
|
||||
@@ -170,6 +170,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
// Paper end - add paper world config
|
||||
|
||||
public final io.papermc.paper.antixray.ChunkPacketBlockController chunkPacketBlockController; // Paper - Anti-Xray
|
||||
+ public net.sparklypower.sparklypaper.configs.SparklyPaperConfig.SparklyPaperWorldConfig sparklyPaperConfig; // SparklyPaper
|
||||
public static BlockPos lastPhysicsProblem; // Spigot
|
||||
private org.spigotmc.TickLimiter entityLimiter;
|
||||
private org.spigotmc.TickLimiter tileLimiter;
|
||||
@@ -853,6 +854,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
// Paper end - getblock optimisations - cache world height/sections
|
||||
this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) levelData).getLevelName()); // Spigot
|
||||
this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper - create paper world config
|
||||
+ this.sparklyPaperConfig = net.sparklypower.sparklypaper.configs.SparklyPaperConfigUtils.INSTANCE.getWorldSettings(((net.minecraft.world.level.storage.PrimaryLevelData) levelData).getLevelName()); // SparklyPaper
|
||||
this.generator = gen;
|
||||
this.world = new CraftWorld((ServerLevel) this, gen, biomeProvider, env);
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||
Date: Mon, 13 Jan 2025 14:19:31 -0300
|
||||
Subject: [PATCH] Skip "distanceToSqr" call in "ServerEntity#sendChanges" if
|
||||
the delta movement hasn't changed
|
||||
|
||||
The "distanceToSqr" call is a bit expensive, so avoiding it is pretty nice, around ~15% calls are skipped with this check
|
||||
|
||||
We could also check if the x,y,z coordinates are equal, but for now, let's just keep the identity check, which also helps us since Minecraft's code does reuse the original delta movement Vec3 object
|
||||
|
||||
diff --git a/net/minecraft/server/level/ServerEntity.java b/net/minecraft/server/level/ServerEntity.java
|
||||
index 0fb253aa55a24b56b17f524b3261c5b75c7d7e59..8d0c259efc31de7de0ca5b900376677552e81f81 100644
|
||||
--- a/net/minecraft/server/level/ServerEntity.java
|
||||
+++ b/net/minecraft/server/level/ServerEntity.java
|
||||
@@ -195,6 +195,7 @@ public class ServerEntity {
|
||||
|
||||
if (this.entity.hasImpulse || this.trackDelta || this.entity instanceof LivingEntity && ((LivingEntity)this.entity).isFallFlying()) {
|
||||
Vec3 deltaMovement = this.entity.getDeltaMovement();
|
||||
+ if (deltaMovement != this.lastSentMovement) { // SparklyPaper start - skip distanceToSqr call in ServerEntity#sendChanges if the delta movement hasn't changed
|
||||
double d = deltaMovement.distanceToSqr(this.lastSentMovement);
|
||||
if (d > 1.0E-7 || d > 0.0 && deltaMovement.lengthSqr() == 0.0) {
|
||||
this.lastSentMovement = deltaMovement;
|
||||
@@ -212,6 +213,7 @@ public class ServerEntity {
|
||||
this.broadcast.accept(new ClientboundSetEntityMotionPacket(this.entity.getId(), this.lastSentMovement));
|
||||
}
|
||||
}
|
||||
+ } // SparklyPaper end
|
||||
}
|
||||
|
||||
if (packet != null) {
|
||||
@@ -0,0 +1,23 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||
Date: Fri, 17 Nov 2023 14:22:41 -0300
|
||||
Subject: [PATCH] Skip "MapItem#update()" if the map does not have the
|
||||
CraftMapRenderer present
|
||||
|
||||
Optimizes "image in map" maps, without requiring the map to be locked, which some old map plugins may not do
|
||||
|
||||
This has the disadvantage that the vanilla map data will never be updated while the CraftMapRenderer is not present, but that's not a huuuge problem for us
|
||||
|
||||
diff --git a/net/minecraft/world/item/MapItem.java b/net/minecraft/world/item/MapItem.java
|
||||
index 8795d54cff569c911e0a535f38a0ec4130f7b4d5..31960e54bf5ed4aa31cd12b60ab0fa263902ce2c 100644
|
||||
--- a/net/minecraft/world/item/MapItem.java
|
||||
+++ b/net/minecraft/world/item/MapItem.java
|
||||
@@ -277,7 +277,7 @@ public class MapItem extends Item {
|
||||
savedData.tickCarriedBy(player, stack);
|
||||
}
|
||||
|
||||
- if (!savedData.locked && (isSelected || entity instanceof Player && ((Player)entity).getOffhandItem() == stack)) {
|
||||
+ if (!savedData.locked && (!level.sparklyPaperConfig.getSkipMapItemDataUpdatesIfMapDoesNotHaveCraftMapRenderer() || savedData.mapView.getRenderers().stream().anyMatch(mapRenderer -> mapRenderer.getClass() == org.bukkit.craftbukkit.map.CraftMapRenderer.class)) && (isSelected || entity instanceof Player && ((Player)entity).getOffhandItem() == stack)) { // SparklyPaper - don't update maps if they don't have the CraftMapRenderer in the render list
|
||||
this.update(level, entity, savedData);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||
Date: Mon, 13 Jan 2025 14:32:08 -0300
|
||||
Subject: [PATCH] Skip dirty stats copy when requesting player stats
|
||||
|
||||
|
||||
diff --git a/net/minecraft/stats/ServerStatsCounter.java b/net/minecraft/stats/ServerStatsCounter.java
|
||||
index 6c5205fe1dc6387a77b1edbdcab748d39e775d7f..c6e4a7668ed923d93bd7f67d19af82d5d84a0dc0 100644
|
||||
--- a/net/minecraft/stats/ServerStatsCounter.java
|
||||
+++ b/net/minecraft/stats/ServerStatsCounter.java
|
||||
@@ -81,11 +81,15 @@ public class ServerStatsCounter extends StatsCounter {
|
||||
this.dirty.add(stat);
|
||||
}
|
||||
|
||||
+ // SparklyPaper start - Skip dirty stats copy when requesting player stats
|
||||
+ /*
|
||||
private Set<Stat<?>> getDirty() {
|
||||
Set<Stat<?>> set = Sets.newHashSet(this.dirty);
|
||||
this.dirty.clear();
|
||||
return set;
|
||||
}
|
||||
+ */
|
||||
+ // SparklyPaper end
|
||||
|
||||
public void parseLocal(DataFixer fixerUpper, String json) {
|
||||
try {
|
||||
@@ -190,10 +194,12 @@ public class ServerStatsCounter extends StatsCounter {
|
||||
public void sendStats(ServerPlayer player) {
|
||||
Object2IntMap<Stat<?>> map = new Object2IntOpenHashMap<>();
|
||||
|
||||
- for (Stat<?> stat : this.getDirty()) {
|
||||
+ for (Stat<?> stat : this.dirty) { // SparklyPaper - Skip dirty stats copy when requesting player stats
|
||||
map.put(stat, this.getValue(stat));
|
||||
}
|
||||
|
||||
+ this.dirty.clear(); // SparklyPaper - Skip dirty stats copy when requesting player stats
|
||||
+
|
||||
player.connection.send(new ClientboundAwardStatsPacket(map));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||
Date: Sun, 19 Nov 2023 12:35:16 -0300
|
||||
Subject: [PATCH] Skip EntityScheduler's executeTick checks if there isn't any
|
||||
tasks to be run
|
||||
|
||||
On each tick, Paper runs EntityScheduler's executeTick of each entity. This is a bit expensive, due to ArrayDeque's size() call because it ain't a simple "get the current queue size" function, due to the thread checks, and because it needs to iterate all entities in all worlds.
|
||||
|
||||
To avoid the hefty ArrayDeque's size() call, we check if we *really* need to execute the executeTick, by adding all entities with scheduled tasks to a global set.
|
||||
|
||||
Most entities won't have any scheduled tasks, so this is a nice performance bonus. These optimizations, however, wouldn't work in a Folia environment, but because in SparklyPaper executeTick is always executed on the main thread, it ain't an issue for us (yay).
|
||||
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index ae220a732c78ab076261f20b5a54c71d7fceb407..6ad6bfe60026be304aa2178d5f04a79531cc66a6 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -303,6 +303,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
public boolean isIteratingOverLevels = false; // Paper - Throw exception on world create while being ticked
|
||||
private final Set<String> pluginsBlockingSleep = new java.util.HashSet<>(); // Paper - API to allow/disallow tick sleeping
|
||||
public static final long SERVER_INIT = System.nanoTime(); // Paper - Lag compensation
|
||||
+ public final Set<net.minecraft.world.entity.Entity> entitiesWithScheduledTasks = java.util.concurrent.ConcurrentHashMap.newKeySet(); // SparklyPaper - skip EntityScheduler's executeTick checks if there isn't any tasks to be run (concurrent because plugins may schedule tasks async)
|
||||
|
||||
public static <S extends MinecraftServer> S spin(Function<Thread, S> threadFunction) {
|
||||
ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.init(); // Paper - rewrite data converter system
|
||||
@@ -1659,6 +1660,18 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
this.server.getScheduler().mainThreadHeartbeat(); // CraftBukkit
|
||||
// Paper start - Folia scheduler API
|
||||
((io.papermc.paper.threadedregions.scheduler.FoliaGlobalRegionScheduler) org.bukkit.Bukkit.getGlobalRegionScheduler()).tick();
|
||||
+ // SparklyPaper - skip EntityScheduler's executeTick checks if there isn't any tasks to be run
|
||||
+ for (final net.minecraft.world.entity.Entity entity : entitiesWithScheduledTasks) {
|
||||
+ if (entity.isRemoved()) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ final org.bukkit.craftbukkit.entity.CraftEntity bukkit = entity.getBukkitEntityRaw();
|
||||
+ if (bukkit != null) {
|
||||
+ bukkit.taskScheduler.executeTick();
|
||||
+ }
|
||||
+ }
|
||||
+ /*
|
||||
getAllLevels().forEach(level -> {
|
||||
for (final net.minecraft.world.entity.Entity entity : level.getEntities().getAll()) {
|
||||
if (entity.isRemoved()) {
|
||||
@@ -1670,6 +1683,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
}
|
||||
}
|
||||
});
|
||||
+ */
|
||||
+ // SparklyPaper end
|
||||
// Paper end - Folia scheduler API
|
||||
io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.CALLBACK_MANAGER.handleQueue(this.tickCount); // Paper
|
||||
profilerFiller.push("commandFunctions");
|
||||
@@ -0,0 +1,180 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||
Date: Mon, 13 Jan 2025 14:50:47 -0300
|
||||
Subject: [PATCH] Blazingly Simple Farm Checks
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/level/block/CropBlock.java b/net/minecraft/world/level/block/CropBlock.java
|
||||
index bc0969f40814094e42a860a72314fccd1a66fabe..c14de811ae7cead820a00a87b9d2ce8cfb241d92 100644
|
||||
--- a/net/minecraft/world/level/block/CropBlock.java
|
||||
+++ b/net/minecraft/world/level/block/CropBlock.java
|
||||
@@ -87,6 +87,57 @@ public class CropBlock extends BushBlock implements BonemealableBlock {
|
||||
if (level.getRawBrightness(pos, 0) >= 9) {
|
||||
int age = this.getAge(state);
|
||||
if (age < this.getMaxAge()) {
|
||||
+ // SparklyPaper start - Blazingly simple farm checks
|
||||
+ if (level.sparklyPaperConfig.getBlazinglySimpleFarmChecks().getEnabled()) {
|
||||
+ // These checks are similar to getGrowthSpeed, but we have "inlined" them because we want to access stuff like the farm block data later on
|
||||
+ // Is the block below us moisturised?
|
||||
+ BlockPos farmlandBelowTheCurrentBlock = pos.below();
|
||||
+ BlockState farmlandBelowTheCurrentBlockData = level.getBlockState(farmlandBelowTheCurrentBlock);
|
||||
+ float f = level.sparklyPaperConfig.getBlazinglySimpleFarmChecks().getDefaultGrowthSpeed();
|
||||
+ boolean isCurrentFarmlandStateMoist = false;
|
||||
+ if (farmlandBelowTheCurrentBlockData.is(Blocks.FARMLAND)) {
|
||||
+ if ((Integer) farmlandBelowTheCurrentBlockData.getValue(FarmBlock.MOISTURE) > 0) {
|
||||
+ // If we are currently moist, increase the speed!
|
||||
+ f = level.sparklyPaperConfig.getBlazinglySimpleFarmChecks().getMoistGrowthSpeed();
|
||||
+ isCurrentFarmlandStateMoist = true;
|
||||
+ }
|
||||
+ }
|
||||
+ // If we are skipping the middle aging stages, we need to change the growth speed and the next stage accordingly
|
||||
+ if (level.sparklyPaperConfig.getBlazinglySimpleFarmChecks().getSkipMiddleAgingStagesForCrops()) {
|
||||
+ f = f / getMaxAge();
|
||||
+ age = getMaxAge() - 1;
|
||||
+ }
|
||||
+
|
||||
+ // Spigot start
|
||||
+ int modifier;
|
||||
+ if (this == Blocks.BEETROOTS) {
|
||||
+ modifier = level.spigotConfig.beetrootModifier;
|
||||
+ } else if (this == Blocks.CARROTS) {
|
||||
+ modifier = level.spigotConfig.carrotModifier;
|
||||
+ } else if (this == Blocks.POTATOES) {
|
||||
+ modifier = level.spigotConfig.potatoModifier;
|
||||
+ // Paper start
|
||||
+ } else if (this == Blocks.TORCHFLOWER_CROP) {
|
||||
+ modifier = level.spigotConfig.torchFlowerModifier;
|
||||
+ // Paper end
|
||||
+ } else {
|
||||
+ modifier = level.spigotConfig.wheatModifier;
|
||||
+ }
|
||||
+
|
||||
+ if (random.nextFloat() < (modifier / (100.0f * (Math.floor((25.0F / f) + 1))))) { // Spigot - SPIGOT-7159: Better modifier resolution
|
||||
+ // Spigot end
|
||||
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, pos, this.getStateForAge(age + 1), 2)) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ // Now that we know that the crop will grow... is the next stage the crop's max age? If yes, we are going to check if the farm land is moist!
|
||||
+ if (age + 1 == getMaxAge() && isCurrentFarmlandStateMoist && !FarmBlock.isNearWater(level, farmlandBelowTheCurrentBlock)) {
|
||||
+ // Whoops, farm land ain't moist!
|
||||
+ // From FarmBlock, set the moisture to 0
|
||||
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleMoistureChangeEvent(level, farmlandBelowTheCurrentBlock, (BlockState) farmlandBelowTheCurrentBlockData.setValue(FarmBlock.MOISTURE, 0), 2); // CraftBukkit
|
||||
+ }
|
||||
+ }
|
||||
+ } else {
|
||||
float growthSpeed = getGrowthSpeed(this, level, pos);
|
||||
// Spigot start
|
||||
int modifier = 100;
|
||||
@@ -108,6 +159,8 @@ public class CropBlock extends BushBlock implements BonemealableBlock {
|
||||
// Spigot end
|
||||
org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, pos, this.getStateForAge(age + 1), 2); // CraftBukkit
|
||||
}
|
||||
+ }
|
||||
+ // SparklyPaper end
|
||||
}
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/world/level/block/FarmBlock.java b/net/minecraft/world/level/block/FarmBlock.java
|
||||
index 47c9b32c89e7e6f84a279c2f6098ada77dc58b6b..06a33e6f6118c2f2dce567efc2e23cbf877b7a9c 100644
|
||||
--- a/net/minecraft/world/level/block/FarmBlock.java
|
||||
+++ b/net/minecraft/world/level/block/FarmBlock.java
|
||||
@@ -95,6 +95,19 @@ public class FarmBlock extends Block {
|
||||
@Override
|
||||
protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
|
||||
int moistureValue = state.getValue(MOISTURE);
|
||||
+ // SparklyPaper start - Blazingly simple farm checks
|
||||
+ if (level.sparklyPaperConfig.getBlazinglySimpleFarmChecks().getEnabled()) {
|
||||
+ if (moistureValue == 0) { // We only care about non-moisturised farm blocks
|
||||
+ if (FarmBlock.isNearWater(level, pos)) {
|
||||
+ // Make it MOIST!
|
||||
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleMoistureChangeEvent(level, pos, (BlockState) state.setValue(FarmBlock.MOISTURE, 7), 2); // CraftBukkit
|
||||
+ } else if (!FarmBlock.shouldMaintainFarmland(level, pos)) {
|
||||
+ FarmBlock.turnToDirt((Entity) null, state, level, pos);
|
||||
+ }
|
||||
+ }
|
||||
+ return;
|
||||
+ }
|
||||
+ // SparklyPaper end
|
||||
if (moistureValue > 0 && level.paperConfig().tickRates.wetFarmland != 1 && (level.paperConfig().tickRates.wetFarmland < 1 || (net.minecraft.server.MinecraftServer.currentTick + pos.hashCode()) % level.paperConfig().tickRates.wetFarmland != 0)) { return; } // Paper - Configurable random tick rates for blocks
|
||||
if (moistureValue == 0 && level.paperConfig().tickRates.dryFarmland != 1 && (level.paperConfig().tickRates.dryFarmland < 1 || (net.minecraft.server.MinecraftServer.currentTick + pos.hashCode()) % level.paperConfig().tickRates.dryFarmland != 0)) { return; } // Paper - Configurable random tick rates for blocks
|
||||
if (!isNearWater(level, pos) && !level.isRainingAt(pos.above())) {
|
||||
@@ -154,7 +167,7 @@ public class FarmBlock extends Block {
|
||||
return level.getBlockState(pos.above()).is(BlockTags.MAINTAINS_FARMLAND);
|
||||
}
|
||||
|
||||
- private static boolean isNearWater(LevelReader level, BlockPos pos) {
|
||||
+ public static boolean isNearWater(LevelReader level, BlockPos pos) { // SparklyPaper - make public for the Blazingly simple farm checks
|
||||
// Paper start - Perf: remove abstract block iteration
|
||||
int xOff = pos.getX();
|
||||
int yOff = pos.getY();
|
||||
diff --git a/net/minecraft/world/level/block/StemBlock.java b/net/minecraft/world/level/block/StemBlock.java
|
||||
index 3dca57dd0c00dc64724cbc7f5a71963da9d12fd5..9839821365484bac93023b1aa542619dae4c88cf 100644
|
||||
--- a/net/minecraft/world/level/block/StemBlock.java
|
||||
+++ b/net/minecraft/world/level/block/StemBlock.java
|
||||
@@ -79,6 +79,56 @@ public class StemBlock extends BushBlock implements BonemealableBlock {
|
||||
@Override
|
||||
protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
|
||||
if (level.getRawBrightness(pos, 0) >= 9) {
|
||||
+ // SparklyPaper start - Blazingly simple farm checks
|
||||
+ if (level.sparklyPaperConfig.getBlazinglySimpleFarmChecks().getEnabled()) {
|
||||
+ // These checks are similar to getGrowthSpeed, but we have "inlined" them because we want to access stuff like the farm block data later on
|
||||
+ // Is the block below us moisturised?
|
||||
+ BlockPos farmlandBelowTheCurrentBlock = pos.below();
|
||||
+ BlockState farmlandBelowTheCurrentBlockData = level.getBlockState(farmlandBelowTheCurrentBlock);
|
||||
+ float f = level.sparklyPaperConfig.getBlazinglySimpleFarmChecks().getDefaultGrowthSpeed();
|
||||
+ boolean isCurrentFarmlandStateMoist = false;
|
||||
+ if (farmlandBelowTheCurrentBlockData.is(Blocks.FARMLAND)) {
|
||||
+ if ((Integer) farmlandBelowTheCurrentBlockData.getValue(FarmBlock.MOISTURE) > 0) {
|
||||
+ // If we are currently moist, increase the speed!
|
||||
+ f = level.sparklyPaperConfig.getBlazinglySimpleFarmChecks().getMoistGrowthSpeed();
|
||||
+ isCurrentFarmlandStateMoist = true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (random.nextFloat() < ((this == Blocks.PUMPKIN_STEM ? level.spigotConfig.pumpkinModifier : level.spigotConfig.melonModifier) / (100.0f * (Math.floor((25.0F / f) + 1))))) { // Spigot - SPIGOT-7159: Better modifier resolution
|
||||
+ int i = (Integer) state.getValue(StemBlock.AGE);
|
||||
+
|
||||
+ if (i < 7) {
|
||||
+ state = (BlockState) state.setValue(StemBlock.AGE, i + 1);
|
||||
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, pos, state, 2); // CraftBukkit
|
||||
+ } else {
|
||||
+ Direction enumdirection = Direction.Plane.HORIZONTAL.getRandomDirection(random);
|
||||
+ BlockPos blockposition1 = pos.relative(enumdirection);
|
||||
+ BlockState iblockdata1 = level.getBlockState(blockposition1.below());
|
||||
+
|
||||
+ if (level.getBlockState(blockposition1).isAir() && (iblockdata1.is(Blocks.FARMLAND) || iblockdata1.is(BlockTags.DIRT))) {
|
||||
+ Registry<Block> iregistry = net.minecraft.core.registries.BuiltInRegistries.BLOCK;
|
||||
+ Optional<Block> optional = iregistry.getOptional(this.fruit);
|
||||
+ Optional<Block> optional1 = iregistry.getOptional(this.attachedStem);
|
||||
+
|
||||
+ if (optional.isPresent() && optional1.isPresent()) {
|
||||
+ // CraftBukkit start
|
||||
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, blockposition1, ((Block) optional.get()).defaultBlockState())) {
|
||||
+ return;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+ // Now that we know that the crop will grow... is the next stage the crop's max age? If yes, we are going to check if the farm land is moist!
|
||||
+ if (isCurrentFarmlandStateMoist && !FarmBlock.isNearWater(level, farmlandBelowTheCurrentBlock)) {
|
||||
+ // Whoops, farm land ain't moist!
|
||||
+ // From FarmBlock, set the moisture to 0
|
||||
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleMoistureChangeEvent(level, farmlandBelowTheCurrentBlock, (BlockState) farmlandBelowTheCurrentBlockData.setValue(FarmBlock.MOISTURE, 0), 2); // CraftBukkit
|
||||
+ }
|
||||
+ level.setBlockAndUpdate(pos, (BlockState) ((Block) optional1.get()).defaultBlockState().setValue(HorizontalDirectionalBlock.FACING, enumdirection));
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ } else {
|
||||
float growthSpeed = CropBlock.getGrowthSpeed(this, level, pos);
|
||||
if (random.nextFloat() < ((this == Blocks.PUMPKIN_STEM ? level.spigotConfig.pumpkinModifier : level.spigotConfig.melonModifier) / (100.0f * (Math.floor((25.0F / growthSpeed) + 1))))) { // Spigot - SPIGOT-7159: Better modifier resolution
|
||||
int ageValue = state.getValue(AGE);
|
||||
@@ -105,6 +155,8 @@ public class StemBlock extends BushBlock implements BonemealableBlock {
|
||||
}
|
||||
}
|
||||
}
|
||||
+ }
|
||||
+ // SparklyPaper end
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -0,0 +1,109 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||
Date: Tue, 21 Nov 2023 16:50:04 -0300
|
||||
Subject: [PATCH] Spooky month optimizations
|
||||
|
||||
The quintessential patch that other performance forks also have for... some reason??? I thought that this optimization was too funny to not do it in SparklyPaper.
|
||||
|
||||
Caches when Bat's spooky season starts and ends, and when Skeleton and Zombies halloween starts and ends. The epoch is updated every 90 days. If your server is running for 90+ days straight without restarts, congratulations!
|
||||
|
||||
Avoids unnecessary date checks, even tho that this shouldn't really improve performance that much... unless you have a lot of bats/zombies/skeletons spawning.
|
||||
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index 6ad6bfe60026be304aa2178d5f04a79531cc66a6..4dbf2d9aa52029122f4816ca3504fa330b28a29b 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -304,6 +304,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
private final Set<String> pluginsBlockingSleep = new java.util.HashSet<>(); // Paper - API to allow/disallow tick sleeping
|
||||
public static final long SERVER_INIT = System.nanoTime(); // Paper - Lag compensation
|
||||
public final Set<net.minecraft.world.entity.Entity> entitiesWithScheduledTasks = java.util.concurrent.ConcurrentHashMap.newKeySet(); // SparklyPaper - skip EntityScheduler's executeTick checks if there isn't any tasks to be run (concurrent because plugins may schedule tasks async)
|
||||
+ public net.sparklypower.sparklypaper.HalloweenManager halloweenManager = new net.sparklypower.sparklypaper.HalloweenManager(); // SparklyPaper - Spooky month optimizations
|
||||
|
||||
public static <S extends MinecraftServer> S spin(Function<Thread, S> threadFunction) {
|
||||
ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.init(); // Paper - rewrite data converter system
|
||||
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
index 4c420e17d936132bb4569776911757fd959e93d6..6ac73610f6039290c4ef3dde2206b6863d2b5067 100644
|
||||
--- a/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -233,6 +233,10 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
}
|
||||
net.sparklypower.sparklypaper.SparklyPaperCommands.INSTANCE.registerCommands(this);
|
||||
// SparklyPaper end
|
||||
+ // SparklyPaper start - Spooky month optimizations
|
||||
+ halloweenManager.startHalloweenEpochTask();
|
||||
+ halloweenManager.waitUntilEpochHasBeenUpdated();
|
||||
+ // SparklyPaper end
|
||||
com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now
|
||||
|
||||
this.setPvpAllowed(properties.pvp);
|
||||
diff --git a/net/minecraft/world/entity/ambient/Bat.java b/net/minecraft/world/entity/ambient/Bat.java
|
||||
index 5ebe7b1dce367d5c5e1136b97b2b9f6737595201..b003fa86fab9a6106c9875205d73e49e46904498 100644
|
||||
--- a/net/minecraft/world/entity/ambient/Bat.java
|
||||
+++ b/net/minecraft/world/entity/ambient/Bat.java
|
||||
@@ -231,7 +231,7 @@ public class Bat extends AmbientCreature {
|
||||
} else {
|
||||
int maxLocalRawBrightness = level.getMaxLocalRawBrightness(pos);
|
||||
int i = 4;
|
||||
- if (isHalloween()) {
|
||||
+ if (level.getServer().halloweenManager.isSpookySeason()) {
|
||||
i = 7;
|
||||
} else if (randomSource.nextBoolean()) {
|
||||
return false;
|
||||
@@ -243,12 +243,15 @@ public class Bat extends AmbientCreature {
|
||||
}
|
||||
}
|
||||
|
||||
+ // SparklyPaper - Spooky month optimizations
|
||||
+ /*
|
||||
private static boolean isHalloween() {
|
||||
LocalDate localDate = LocalDate.now();
|
||||
int i = localDate.get(ChronoField.DAY_OF_MONTH);
|
||||
int i1 = localDate.get(ChronoField.MONTH_OF_YEAR);
|
||||
return i1 == 10 && i >= 20 || i1 == 11 && i <= 3;
|
||||
}
|
||||
+ */
|
||||
|
||||
private void setupAnimationStates() {
|
||||
if (this.isResting()) {
|
||||
diff --git a/net/minecraft/world/entity/monster/AbstractSkeleton.java b/net/minecraft/world/entity/monster/AbstractSkeleton.java
|
||||
index 37abc7769573e3cdda380166dd086551d5e7bd88..be623fd09ca573922297d3af3cd114160ec05061 100644
|
||||
--- a/net/minecraft/world/entity/monster/AbstractSkeleton.java
|
||||
+++ b/net/minecraft/world/entity/monster/AbstractSkeleton.java
|
||||
@@ -158,10 +158,12 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo
|
||||
this.reassessWeaponGoal();
|
||||
this.setCanPickUpLoot(this.level().paperConfig().entities.behavior.mobsCanAlwaysPickUpLoot.skeletons || random.nextFloat() < 0.55F * difficulty.getSpecialMultiplier()); // Paper - Add world settings for mobs picking up loot
|
||||
if (this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) {
|
||||
- LocalDate localDate = LocalDate.now();
|
||||
- int i = localDate.get(ChronoField.DAY_OF_MONTH);
|
||||
- int i1 = localDate.get(ChronoField.MONTH_OF_YEAR);
|
||||
- if (i1 == 10 && i == 31 && random.nextFloat() < 0.25F) {
|
||||
+ // SparklyPaper start - Spooky month optimizations
|
||||
+ // LocalDate localDate = LocalDate.now();
|
||||
+ // int i = localDate.get(ChronoField.DAY_OF_MONTH);
|
||||
+ // int i1 = localDate.get(ChronoField.MONTH_OF_YEAR);
|
||||
+ if (this.getServer().halloweenManager.isHalloween() /* i1 == 10 && i == 31 */&& random.nextFloat() < 0.25F) {
|
||||
+ // SparklyPaper end
|
||||
this.setItemSlot(EquipmentSlot.HEAD, new ItemStack(random.nextFloat() < 0.1F ? Blocks.JACK_O_LANTERN : Blocks.CARVED_PUMPKIN));
|
||||
this.armorDropChances[EquipmentSlot.HEAD.getIndex()] = 0.0F;
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/monster/Zombie.java b/net/minecraft/world/entity/monster/Zombie.java
|
||||
index 637790ff833abaa0c52fdee204abba7077d12ccc..600b96d4b2645e26fd690ac70d3901d567b7bc24 100644
|
||||
--- a/net/minecraft/world/entity/monster/Zombie.java
|
||||
+++ b/net/minecraft/world/entity/monster/Zombie.java
|
||||
@@ -550,10 +550,12 @@ public class Zombie extends Monster {
|
||||
}
|
||||
|
||||
if (this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) {
|
||||
- LocalDate localDate = LocalDate.now();
|
||||
- int i = localDate.get(ChronoField.DAY_OF_MONTH);
|
||||
- int i1 = localDate.get(ChronoField.MONTH_OF_YEAR);
|
||||
- if (i1 == 10 && i == 31 && random.nextFloat() < 0.25F) {
|
||||
+ // SparklyPaper start - Spooky month optimizations
|
||||
+ // LocalDate localDate = LocalDate.now();
|
||||
+ // int i = localDate.get(ChronoField.DAY_OF_MONTH);
|
||||
+ // int i1 = localDate.get(ChronoField.MONTH_OF_YEAR);
|
||||
+ if (this.getServer().halloweenManager.isHalloween() /* i1 == 10 && i == 31 */&& random.nextFloat() < 0.25F) {
|
||||
+ // SparklyPaper end
|
||||
this.setItemSlot(EquipmentSlot.HEAD, new ItemStack(random.nextFloat() < 0.1F ? Blocks.JACK_O_LANTERN : Blocks.CARVED_PUMPKIN));
|
||||
this.armorDropChances[EquipmentSlot.HEAD.getIndex()] = 0.0F;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||
Date: Mon, 13 Jan 2025 15:03:52 -0300
|
||||
Subject: [PATCH] Optimize canSee checks
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
|
||||
index b3f498558614243cf633dcd71e3c49c2c55e6e0f..ad9ab7fe6df3880c730388a50741b7938b037ff2 100644
|
||||
--- a/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -1232,7 +1232,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
flag = flag && this.entity.broadcastToPlayer(player) && ChunkMap.this.isChunkTracked(player, this.entity.chunkPosition().x, this.entity.chunkPosition().z);
|
||||
// Paper end - Configurable entity tracking range by Y
|
||||
// CraftBukkit start - respect vanish API
|
||||
- if (flag && !player.getBukkitEntity().canSee(this.entity.getBukkitEntity())) { // Paper - only consider hits
|
||||
+ if (flag && !player.getBukkitEntity().canSeeChunkMapUpdatePlayer(this.entity.getBukkitEntity())) { // Paper - only consider hits // SparklyPaper - optimize canSee checks
|
||||
flag = false;
|
||||
}
|
||||
// CraftBukkit end
|
||||
@@ -0,0 +1,39 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||
Date: Mon, 13 Jan 2025 16:41:37 -0300
|
||||
Subject: [PATCH] Fix MC-117075: TE Unload Lag Spike
|
||||
|
||||
We replaced the `blockEntityTickers` list with a custom list based on fastutil's `ObjectArrayList` with a small yet huge change for us: A method that allows us to remove a list of indexes from the list.
|
||||
|
||||
This is WAY FASTER than using `removeAll` with a list of entries to be removed, because we don't need to calculate the identity of each block entity to be removed, and we can jump directly to where the search should begin, giving a performance boost for small removals (because we don't need to loop thru the entire list to find what element should be removed) and a performance boost for big removals (no need to calculate the identity of each block entity).
|
||||
|
||||
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
|
||||
index 27c2ea4a387ee5f7d078a42cb57f146cb748501d..644ab8b2c797f0675530a3efe23a878899689d66 100644
|
||||
--- a/net/minecraft/world/level/Level.java
|
||||
+++ b/net/minecraft/world/level/Level.java
|
||||
@@ -115,7 +115,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
public static final int TICKS_PER_DAY = 24000;
|
||||
public static final int MAX_ENTITY_SPAWN_Y = 20000000;
|
||||
public static final int MIN_ENTITY_SPAWN_Y = -20000000;
|
||||
- public final List<TickingBlockEntity> blockEntityTickers = Lists.newArrayList(); // Paper - public
|
||||
+ public final net.sparklypower.sparklypaper.BlockEntityTickersList blockEntityTickers = new net.sparklypower.sparklypaper.BlockEntityTickersList(); // Paper - public // SparklyPaper - optimize block entity removals
|
||||
protected final NeighborUpdater neighborUpdater;
|
||||
private final List<TickingBlockEntity> pendingBlockEntityTickers = Lists.newArrayList();
|
||||
private boolean tickingBlockEntities;
|
||||
@@ -1479,7 +1479,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
TickingBlockEntity tickingBlockEntity = this.blockEntityTickers.get(this.tileTickPosition);
|
||||
// Spigot end
|
||||
if (tickingBlockEntity.isRemoved()) {
|
||||
- toRemove.add(tickingBlockEntity); // Paper - Fix MC-117075; use removeAll
|
||||
+ this.blockEntityTickers.markAsRemoved(this.tileTickPosition); // toRemove.add(tickingBlockEntity); // SparklyPaper - optimize block entity removals // Paper - Fix MC-117075; use removeAll
|
||||
} else if (runsNormally && this.shouldTickBlocksAt(tickingBlockEntity.getPos())) {
|
||||
tickingBlockEntity.tick();
|
||||
// Paper start - rewrite chunk system
|
||||
@@ -1491,6 +1491,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
}
|
||||
this.blockEntityTickers.removeAll(toRemove); // Paper - Fix MC-117075
|
||||
|
||||
+ this.blockEntityTickers.removeMarkedEntries(); // SparklyPaper - optimize block entity removals
|
||||
this.tickingBlockEntities = false;
|
||||
profilerFiller.pop();
|
||||
this.spigotConfig.currentPrimedTnt = 0; // Spigot
|
||||
@@ -0,0 +1,44 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||
Date: Mon, 6 Nov 2023 21:54:33 -0300
|
||||
Subject: [PATCH] Track how much MSPT each world used
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index 4dbf2d9aa52029122f4816ca3504fa330b28a29b..c15c11ab3feaca918ac0185383cd1653200cd186 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -1737,7 +1737,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
profilerFiller.push("tick");
|
||||
|
||||
try {
|
||||
+ long i = Util.getNanos(); // SparklyPaper - track world's MSPT
|
||||
serverLevel.tick(hasTimeLeft);
|
||||
+ // SparklyPaper start - track world's MSPT
|
||||
+ long j = Util.getNanos() - i;
|
||||
+
|
||||
+ // These are from the "tickServer" function
|
||||
+ serverLevel.tickTimes5s.add(this.tickCount, j);
|
||||
+ serverLevel.tickTimes10s.add(this.tickCount, j);
|
||||
+ serverLevel.tickTimes60s.add(this.tickCount, j);
|
||||
+ // SparklyPaper end
|
||||
} catch (Throwable var7) {
|
||||
CrashReport crashReport = CrashReport.forThrowable(var7, "Exception ticking world");
|
||||
serverLevel.fillReportDetails(crashReport);
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index ebeeb63c3dca505a3ce8b88feaa5d2ca20ec24a2..59465ab6d7723d27b1597cc7094b5044a3f24250 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -570,6 +570,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
}
|
||||
// Paper end - chunk tick iteration
|
||||
|
||||
+ // SparklyPaper start - track world's MSPT
|
||||
+ public final MinecraftServer.TickTimes tickTimes5s = new MinecraftServer.TickTimes(100);
|
||||
+ public final MinecraftServer.TickTimes tickTimes10s = new MinecraftServer.TickTimes(200);
|
||||
+ public final MinecraftServer.TickTimes tickTimes60s = new MinecraftServer.TickTimes(1200);
|
||||
+ // SparklyPaper end
|
||||
+
|
||||
public ServerLevel(
|
||||
MinecraftServer server,
|
||||
Executor dispatcher,
|
||||
@@ -0,0 +1,21 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||
Date: Wed, 5 Jun 2024 15:20:00 -0300
|
||||
Subject: [PATCH] Reset dirty flag when loading maps from the disk
|
||||
|
||||
By default, the server will start rewriting all map datas to the disk after loading it, even if the map didn't have any changes
|
||||
|
||||
This also slows down world saving a lot if you have a lot of maps
|
||||
|
||||
diff --git a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
|
||||
index f5a131e870a4f1ad06ebfb1f360720cf19656fb5..2aed9d55ea1a93b323865141a69c9947759eae29 100644
|
||||
--- a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
|
||||
+++ b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
|
||||
@@ -197,6 +197,7 @@ public class MapItemSavedData extends SavedData {
|
||||
}
|
||||
}
|
||||
|
||||
+ mapItemSavedData.setDirty(false); // SparklyPaper - reset dirty flag when loading maps from the disk (context for updates: this modification is at the end of the map "load" function)
|
||||
return mapItemSavedData;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||
Date: Mon, 10 Jun 2024 13:06:30 -0300
|
||||
Subject: [PATCH] Helpful NMS packet changes
|
||||
|
||||
Some nice changes to the packet internals to make packet sending and manipulation easier for us to avoid Reflection and JVM internals (ooo theUnsafe spooky) usage
|
||||
|
||||
diff --git a/net/minecraft/network/protocol/game/ClientboundAddEntityPacket.java b/net/minecraft/network/protocol/game/ClientboundAddEntityPacket.java
|
||||
index 1373977b339405ef59bb3ea03d195285c96dd3fe..20a782d1bb7355bbdc0822a02204e1e05dc44145 100644
|
||||
--- a/net/minecraft/network/protocol/game/ClientboundAddEntityPacket.java
|
||||
+++ b/net/minecraft/network/protocol/game/ClientboundAddEntityPacket.java
|
||||
@@ -22,7 +22,7 @@ public class ClientboundAddEntityPacket implements Packet<ClientGamePacketListen
|
||||
private static final double LIMIT = 3.9;
|
||||
private final int id;
|
||||
private final UUID uuid;
|
||||
- private final EntityType<?> type;
|
||||
+ public EntityType<?> type; // SparklyPaper - Helpful NMS packet changes: remove final and make public
|
||||
private final double x;
|
||||
private final double y;
|
||||
private final double z;
|
||||
@@ -180,6 +180,32 @@ public class ClientboundAddEntityPacket implements Packet<ClientGamePacketListen
|
||||
return Mth.unpackDegrees(this.yHeadRot);
|
||||
}
|
||||
|
||||
+ // SparklyPaper - Helpful NMS packet changes: expose raw rotational fields
|
||||
+ public int getXaRaw() {
|
||||
+ return this.xa;
|
||||
+ }
|
||||
+
|
||||
+ public int getYaRaw() {
|
||||
+ return this.ya;
|
||||
+ }
|
||||
+
|
||||
+ public int getZaRaw() {
|
||||
+ return this.za;
|
||||
+ }
|
||||
+
|
||||
+ public byte getXRotRaw() {
|
||||
+ return this.xRot;
|
||||
+ }
|
||||
+
|
||||
+ public byte getYRotRaw() {
|
||||
+ return this.yRot;
|
||||
+ }
|
||||
+
|
||||
+ public byte getYHeadRotRaw() {
|
||||
+ return this.yHeadRot;
|
||||
+ }
|
||||
+ // SparklyPaper end
|
||||
+
|
||||
public int getData() {
|
||||
return this.data;
|
||||
}
|
||||
diff --git a/net/minecraft/network/protocol/game/ClientboundBlockUpdatePacket.java b/net/minecraft/network/protocol/game/ClientboundBlockUpdatePacket.java
|
||||
index 8fca836e63731c5cef95bbc07e6e1414c9f02bea..c412dcab882abe11ecae34700df3e62ece464b82 100644
|
||||
--- a/net/minecraft/network/protocol/game/ClientboundBlockUpdatePacket.java
|
||||
+++ b/net/minecraft/network/protocol/game/ClientboundBlockUpdatePacket.java
|
||||
@@ -19,7 +19,7 @@ public class ClientboundBlockUpdatePacket implements Packet<ClientGamePacketList
|
||||
ClientboundBlockUpdatePacket::new
|
||||
);
|
||||
private final BlockPos pos;
|
||||
- public final BlockState blockState;
|
||||
+ public BlockState blockState; // SparklyPaper - Helpful NMS packet changes: remove final
|
||||
|
||||
public ClientboundBlockUpdatePacket(BlockPos pos, BlockState blockState) {
|
||||
this.pos = pos;
|
||||
diff --git a/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java b/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
||||
index 9e321ef1c3d5803519b243685f4ee598dc0cf640..851931062c4401817aad14721ac7fb0362c3b418 100644
|
||||
--- a/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
||||
+++ b/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
||||
@@ -25,7 +25,7 @@ import net.minecraft.world.level.levelgen.Heightmap;
|
||||
public class ClientboundLevelChunkPacketData {
|
||||
private static final int TWO_MEGABYTES = 2097152;
|
||||
private final CompoundTag heightmaps;
|
||||
- private final byte[] buffer;
|
||||
+ public byte[] buffer; // SparklyPaper - Helpful NMS packet changes: remove final and make public
|
||||
private final List<ClientboundLevelChunkPacketData.BlockEntityInfo> blockEntitiesData;
|
||||
// Paper start - Handle oversized block entities in chunks
|
||||
private final java.util.List<net.minecraft.network.protocol.Packet<?>> extraPackets = new java.util.ArrayList<>();
|
||||
diff --git a/net/minecraft/network/protocol/game/ClientboundRotateHeadPacket.java b/net/minecraft/network/protocol/game/ClientboundRotateHeadPacket.java
|
||||
index 4bcbf4bff67d4d4958d56764a273cf4a66b9dd0c..fd621a5d02170f6aa297dbd6a08ba1fef60e54c9 100644
|
||||
--- a/net/minecraft/network/protocol/game/ClientboundRotateHeadPacket.java
|
||||
+++ b/net/minecraft/network/protocol/game/ClientboundRotateHeadPacket.java
|
||||
@@ -20,6 +20,13 @@ public class ClientboundRotateHeadPacket implements Packet<ClientGamePacketListe
|
||||
this.yHeadRot = yHeadRot;
|
||||
}
|
||||
|
||||
+ // SparklyPaper start - Helpful NMS packet changes: add entity ID constructor
|
||||
+ public ClientboundRotateHeadPacket(int entityId, byte headYaw) {
|
||||
+ this.entityId = entityId;
|
||||
+ this.yHeadRot = headYaw;
|
||||
+ }
|
||||
+ // SparklyPaper end
|
||||
+
|
||||
private ClientboundRotateHeadPacket(FriendlyByteBuf buffer) {
|
||||
this.entityId = buffer.readVarInt();
|
||||
this.yHeadRot = buffer.readByte();
|
||||
diff --git a/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java b/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java
|
||||
index 10b46c59d83d1274cf491f217df2355d13b594c1..de8767eb8a01e1fed06fbb9d8d5904a83fd19bf5 100644
|
||||
--- a/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java
|
||||
+++ b/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java
|
||||
@@ -17,9 +17,9 @@ public class ClientboundSectionBlocksUpdatePacket implements Packet<ClientGamePa
|
||||
ClientboundSectionBlocksUpdatePacket::write, ClientboundSectionBlocksUpdatePacket::new
|
||||
);
|
||||
private static final int POS_IN_SECTION_BITS = 12;
|
||||
- private final SectionPos sectionPos;
|
||||
- private final short[] positions;
|
||||
- private final BlockState[] states;
|
||||
+ public SectionPos sectionPos; // SparklyPaper - Helpful NMS packet changes: remove final and make public
|
||||
+ public short[] positions; // SparklyPaper - Helpful NMS packet changes: remove final and make public
|
||||
+ public BlockState[] states; // SparklyPaper - Helpful NMS packet changes: remove final and make public
|
||||
|
||||
public ClientboundSectionBlocksUpdatePacket(SectionPos sectionPos, ShortSet positions, LevelChunkSection section) {
|
||||
this.sectionPos = sectionPos;
|
||||
diff --git a/net/minecraft/network/protocol/game/ClientboundSetCameraPacket.java b/net/minecraft/network/protocol/game/ClientboundSetCameraPacket.java
|
||||
index 2545057c7f1f355f59f1e7da06ce08fd2d997b43..9920fe2d2f2f74f372731f1be5abaa4953344632 100644
|
||||
--- a/net/minecraft/network/protocol/game/ClientboundSetCameraPacket.java
|
||||
+++ b/net/minecraft/network/protocol/game/ClientboundSetCameraPacket.java
|
||||
@@ -22,6 +22,12 @@ public class ClientboundSetCameraPacket implements Packet<ClientGamePacketListen
|
||||
this.cameraId = buffer.readVarInt();
|
||||
}
|
||||
|
||||
+ // SparklyPaper - Helpful NMS packet changes: add direct entityId constructor
|
||||
+ public ClientboundSetCameraPacket(int entityId) {
|
||||
+ this.cameraId = entityId;
|
||||
+ }
|
||||
+ // SparklyPaper end
|
||||
+
|
||||
private void write(FriendlyByteBuf buffer) {
|
||||
buffer.writeVarInt(this.cameraId);
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/Display.java b/net/minecraft/world/entity/Display.java
|
||||
index ff49fdcddb43ee479a377aa219eb18fcaefeffca..33a47487f79fdc5164ff6a6d639dfe5834deed0d 100644
|
||||
--- a/net/minecraft/world/entity/Display.java
|
||||
+++ b/net/minecraft/world/entity/Display.java
|
||||
@@ -800,7 +800,7 @@ public abstract class Display extends Entity {
|
||||
public static final byte FLAG_ALIGN_RIGHT = 16;
|
||||
private static final byte INITIAL_TEXT_OPACITY = -1;
|
||||
public static final int INITIAL_BACKGROUND = 1073741824;
|
||||
- private static final EntityDataAccessor<Component> DATA_TEXT_ID = SynchedEntityData.defineId(Display.TextDisplay.class, EntityDataSerializers.COMPONENT);
|
||||
+ public static final EntityDataAccessor<Component> DATA_TEXT_ID = SynchedEntityData.defineId(Display.TextDisplay.class, EntityDataSerializers.COMPONENT); // SparklyPaper - Helpful NMS packet changes: make public
|
||||
public static final EntityDataAccessor<Integer> DATA_LINE_WIDTH_ID = SynchedEntityData.defineId(Display.TextDisplay.class, EntityDataSerializers.INT);
|
||||
public static final EntityDataAccessor<Integer> DATA_BACKGROUND_COLOR_ID = SynchedEntityData.defineId(
|
||||
Display.TextDisplay.class, EntityDataSerializers.INT
|
||||
@@ -0,0 +1,51 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||
Date: Tue, 25 Jun 2024 02:52:32 -0300
|
||||
Subject: [PATCH] Add CraftItemRecipeEvent
|
||||
|
||||
Used when a player OR a crafter block crafts an item, as an alternative to PrepareItemCraftEvent and CraftItemEvent, because both events are not triggered when a item is crafted from a crafter
|
||||
|
||||
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 27ef385a85b13ceb58e8d149849983107c539b31..7f9ed94576c94161070fd1be1544aaed9aac0c6b 100644
|
||||
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -3156,6 +3156,21 @@ public class ServerGamePacketListenerImpl
|
||||
} else {
|
||||
event = new CraftItemEvent(recipe, inventory, type, slotNum, click, action);
|
||||
}
|
||||
+ // SparklyPaper start - add CraftItemRecipeEvent
|
||||
+ // We will pigback a bit on the current implementation
|
||||
+ net.sparklypower.sparklypaper.event.inventory.CraftItemRecipeEvent craftItemRecipeEvent = new net.sparklypower.sparklypaper.event.inventory.CraftItemRecipeEvent(
|
||||
+ ((CraftingInventory) top).getMatrix(), // We cannot use the top inventory directly because (it seems) that the first slot is the "result" slot
|
||||
+ recipe,
|
||||
+ event.getCurrentItem()
|
||||
+ );
|
||||
+ if (craftItemRecipeEvent.callEvent()) {
|
||||
+ event.setCurrentItem(craftItemRecipeEvent.getResult());
|
||||
+ } else {
|
||||
+ event.setCancelled(true);
|
||||
+ cancelled = true;
|
||||
+ event.setCurrentItem(craftItemRecipeEvent.getResult());
|
||||
+ }
|
||||
+ // SparklyPaper end
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/world/level/block/CrafterBlock.java b/net/minecraft/world/level/block/CrafterBlock.java
|
||||
index 5f5966278faf86ed9b28955c80ba845c0cb75595..751969d28951f59f381aa6bf7ad42d55d3e84d57 100644
|
||||
--- a/net/minecraft/world/level/block/CrafterBlock.java
|
||||
+++ b/net/minecraft/world/level/block/CrafterBlock.java
|
||||
@@ -167,6 +167,13 @@ public class CrafterBlock extends BaseEntityBlock {
|
||||
}
|
||||
itemStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getResult());
|
||||
// CraftBukkit end
|
||||
+ // SparklyPaper - add CraftItemRecipeEvent
|
||||
+ net.sparklypower.sparklypaper.event.inventory.CraftItemRecipeEvent sparklyEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callCraftItemRecipeEvent(crafterBlockEntity, recipeHolder.toBukkitRecipe(), itemStack);
|
||||
+ if (sparklyEvent.isCancelled()) {
|
||||
+ return;
|
||||
+ }
|
||||
+ itemStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(sparklyEvent.getResult());
|
||||
+ // SparklyPaper end
|
||||
if (itemStack.isEmpty()) {
|
||||
level.levelEvent(1050, pos, 0);
|
||||
} else {
|
||||
@@ -0,0 +1,19 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||
Date: Fri, 23 Aug 2024 16:20:45 -0300
|
||||
Subject: [PATCH] Allow throttling hopper checks if the target container is
|
||||
full
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
|
||||
index 5cd1326ad5d046c88b2b3449d610a78fa880b4cd..d512f44dcfc480b5608555aa319c93342ae5b208 100644
|
||||
--- a/net/minecraft/world/level/block/entity/HopperBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
|
||||
@@ -419,6 +419,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
} else {
|
||||
Direction opposite = blockEntity.facing.getOpposite();
|
||||
if (isFullContainer(attachedContainer, opposite)) {
|
||||
+ if (level.sparklyPaperConfig.getTicksPer().getHopperCooldownWhenTargetContainerIsFull() != 0) blockEntity.setCooldown(level.sparklyPaperConfig.getTicksPer().getHopperCooldownWhenTargetContainerIsFull()); // SparklyPaper - Allow throttling hopper checks if the target container is full
|
||||
return false;
|
||||
} else {
|
||||
// Paper start - Perf: Optimize Hoppers
|
||||
@@ -0,0 +1,42 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||
Date: Sat, 4 Jan 2025 23:58:55 -0300
|
||||
Subject: [PATCH] Add PlayerMoveControllableVehicleEvent
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 7f9ed94576c94161070fd1be1544aaed9aac0c6b..da190c2ab2080344dc11903aec51598af18d7556 100644
|
||||
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -587,6 +587,31 @@ public class ServerGamePacketListenerImpl
|
||||
LOGGER.warn("{} (vehicle of {}) moved wrongly! {}", rootVehicle.getName().getString(), this.player.getName().getString(), Math.sqrt(d7));
|
||||
}
|
||||
|
||||
+ // SparklyPaper start - Add PlayerMoveControllableVehicleEvent
|
||||
+ org.bukkit.entity.Player craftPlayer = this.getCraftPlayer();
|
||||
+ org.bukkit.entity.Entity bukkitVehicle = rootVehicle.getBukkitEntity();
|
||||
+ if (bukkitVehicle instanceof org.bukkit.entity.Vehicle) {
|
||||
+ net.sparklypower.sparklypaper.event.player.PlayerMoveControllableVehicleEvent playerMoveControllableVehicleEvent = new net.sparklypower.sparklypaper.event.player.PlayerMoveControllableVehicleEvent(
|
||||
+ craftPlayer,
|
||||
+ (org.bukkit.entity.Vehicle) bukkitVehicle,
|
||||
+ new org.bukkit.Location(craftPlayer.getWorld(), x, y, z, f, f1),
|
||||
+ new org.bukkit.Location(craftPlayer.getWorld(), d, d1, d2, f, f1)
|
||||
+ );
|
||||
+ if (!playerMoveControllableVehicleEvent.callEvent()) {
|
||||
+ // Cancelled, move back!
|
||||
+ rootVehicle.absMoveTo(x, y, z, f, f1);
|
||||
+ this.player.absMoveTo(x, y, z, this.player.getYRot(), this.player.getXRot()); // CraftBukkit
|
||||
+ this.send(ClientboundMoveVehiclePacket.fromEntity(rootVehicle));
|
||||
+ return;
|
||||
+ }
|
||||
+ d = playerMoveControllableVehicleEvent.getTo().x();
|
||||
+ d1 = playerMoveControllableVehicleEvent.getTo().y();
|
||||
+ d2 = playerMoveControllableVehicleEvent.getTo().z();
|
||||
+ f = playerMoveControllableVehicleEvent.getTo().getYaw();
|
||||
+ f1 = playerMoveControllableVehicleEvent.getTo().getPitch();
|
||||
+ }
|
||||
+ // SparklyPaper end
|
||||
+
|
||||
rootVehicle.absMoveTo(d, d1, d2, f, f1);
|
||||
this.player.absMoveTo(d, d1, d2, this.player.getYRot(), this.player.getXRot()); // CraftBukkit
|
||||
// Paper start - optimise out extra getCubes
|
||||
@@ -0,0 +1,86 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||
Date: Wed, 8 Jan 2025 22:48:04 -0300
|
||||
Subject: [PATCH] Add PlayerPreMoveEvent
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index da190c2ab2080344dc11903aec51598af18d7556..f637d2be3d67a928ed7f78eaa7aa80cbea85a3e6 100644
|
||||
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -1422,7 +1422,7 @@ public class ServerGamePacketListenerImpl
|
||||
d3 = d - this.lastGoodX; // Paper - diff on change, used for checking large move vectors above
|
||||
d4 = d1 - this.lastGoodY; // Paper - diff on change, used for checking large move vectors above
|
||||
d5 = d2 - this.lastGoodZ; // Paper - diff on change, used for checking large move vectors above
|
||||
- boolean flag = d4 > 0.0;
|
||||
+ boolean flag = d4 > 0.0; // SparklyPaper - diff on change, used to reset the fall distance, checks if d7 is > 0.0D (player is moving upwards)
|
||||
if (this.player.onGround() && !packet.isOnGround() && flag) {
|
||||
// Paper start - Add PlayerJumpEvent
|
||||
org.bukkit.entity.Player player = this.getCraftPlayer();
|
||||
@@ -1456,7 +1456,37 @@ public class ServerGamePacketListenerImpl
|
||||
|
||||
boolean flag1 = this.player.verticalCollisionBelow;
|
||||
this.player.move(MoverType.PLAYER, new Vec3(d3, d4, d5));
|
||||
- this.player.onGround = packet.isOnGround(); // CraftBukkit - SPIGOT-5810, SPIGOT-5835, SPIGOT-6828: reset by this.player.move
|
||||
+ // SparklyPaper start - Add PlayerPreMoveEvent event
|
||||
+ boolean isOnGround = packet.isOnGround();
|
||||
+ boolean horizontalCollision = packet.horizontalCollision();
|
||||
+ if (net.sparklypower.sparklypaper.event.player.PlayerPreMoveEvent.getHandlerList().getRegisteredListeners().length != 0) {
|
||||
+ org.bukkit.entity.Player player = this.getCraftPlayer();
|
||||
+ Location from = new Location(player.getWorld(), lastPosX, lastPosY, lastPosZ, lastYaw, lastPitch); // Get the Players previous Event location.
|
||||
+ Location to = player.getLocation().clone(); // Start off the To location as the Players current location.
|
||||
+
|
||||
+ // If the packet contains movement information then we update the To location with the correct XYZ.
|
||||
+ if (packet.hasPos) {
|
||||
+ to.setX(packet.x);
|
||||
+ to.setY(packet.y);
|
||||
+ to.setZ(packet.z);
|
||||
+ }
|
||||
+
|
||||
+ // If the packet contains look information then we update the To location with the correct Yaw & Pitch.
|
||||
+ if (packet.hasRot) {
|
||||
+ to.setYaw(packet.yRot);
|
||||
+ to.setPitch(packet.xRot);
|
||||
+ }
|
||||
+
|
||||
+ net.sparklypower.sparklypaper.event.player.PlayerPreMoveEvent event = new net.sparklypower.sparklypaper.event.player.PlayerPreMoveEvent(player, from, to, packet.isOnGround(), packet.horizontalCollision(), flag);
|
||||
+
|
||||
+ if (event.callEvent()) {
|
||||
+ isOnGround = event.isOnGround();
|
||||
+ horizontalCollision = event.isHorizontalCollision();
|
||||
+ flag = event.isResetFallDistance();
|
||||
+ }
|
||||
+ }
|
||||
+ // SparklyPaper end
|
||||
+ this.player.onGround = isOnGround; // CraftBukkit - SPIGOT-5810, SPIGOT-5835, SPIGOT-6828: reset by this.player.move // SparklyPaper - Add PlayerPreMoveEvent
|
||||
boolean didCollide = toX != this.player.getX() || toY != this.player.getY() || toZ != this.player.getZ(); // Paper - needed here as the difference in Y can be reset - also note: this is only a guess at whether collisions took place, floating point errors can make this true when it shouldn't be...
|
||||
// Paper start - prevent position desync
|
||||
if (this.awaitingPositionFromClient != null) {
|
||||
@@ -1590,15 +1620,15 @@ public class ServerGamePacketListenerImpl
|
||||
&& this.noBlocksAround(this.player);
|
||||
this.player.serverLevel().getChunkSource().move(this.player);
|
||||
Vec3 vec3 = new Vec3(this.player.getX() - x, this.player.getY() - y, this.player.getZ() - z);
|
||||
- this.player.setOnGroundWithMovement(packet.isOnGround(), packet.horizontalCollision(), vec3);
|
||||
- this.player.doCheckFallDamage(vec3.x, vec3.y, vec3.z, packet.isOnGround());
|
||||
+ this.player.setOnGroundWithMovement(isOnGround, horizontalCollision, vec3); // SparklyPaper - Add PlayerPreMoveEvent
|
||||
+ this.player.doCheckFallDamage(vec3.x, vec3.y, vec3.z, isOnGround); // SparklyPaper - Add PlayerPreMoveEvent
|
||||
this.player.recordMovementThroughBlocks(new Vec3(x, y, z), this.player.position());
|
||||
this.handlePlayerKnownMovement(vec3);
|
||||
if (flag) {
|
||||
this.player.resetFallDistance();
|
||||
}
|
||||
|
||||
- if (packet.isOnGround()
|
||||
+ if (isOnGround // SparklyPaper - Add PlayerPreMoveEvent
|
||||
|| this.player.hasLandedInLiquid()
|
||||
|| this.player.onClimbable()
|
||||
|| this.player.isSpectator()
|
||||
@@ -1613,7 +1643,7 @@ public class ServerGamePacketListenerImpl
|
||||
this.lastGoodZ = this.player.getZ();
|
||||
} else {
|
||||
this.internalTeleport(x, y, z, f, f1); // CraftBukkit - SPIGOT-1807: Don't call teleport event, when the client thinks the player is falling, because the chunks are not loaded on the client yet.
|
||||
- this.player.doCheckFallDamage(this.player.getX() - x, this.player.getY() - y, this.player.getZ() - z, packet.isOnGround());
|
||||
+ this.player.doCheckFallDamage(this.player.getX() - x, this.player.getY() - y, this.player.getZ() - z, isOnGround); // SparklyPaper - Add PlayerPreMoveEvent
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||
Date: Sun, 12 Jan 2025 23:26:44 -0300
|
||||
Subject: [PATCH] Add PreEntityShootBowEvent
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/item/BowItem.java b/net/minecraft/world/item/BowItem.java
|
||||
index 57c933af200551162774f1d473437521e5a85833..9d8a6763efcdd2a57507e208c34faa3f180d5421 100644
|
||||
--- a/net/minecraft/world/item/BowItem.java
|
||||
+++ b/net/minecraft/world/item/BowItem.java
|
||||
@@ -33,6 +33,11 @@ public class BowItem extends ProjectileWeaponItem {
|
||||
} else {
|
||||
int i = this.getUseDuration(stack, entity) - timeLeft;
|
||||
float powerForTime = getPowerForTime(i);
|
||||
+ // SparklyPaper start - Add PreEntityShootBowEvent
|
||||
+ net.sparklypower.sparklypaper.event.entity.PreEntityShootBowEvent event = new net.sparklypower.sparklypaper.event.entity.PreEntityShootBowEvent(player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack), player.getUsedItemHand() == InteractionHand.MAIN_HAND ? org.bukkit.inventory.EquipmentSlot.HAND : org.bukkit.inventory.EquipmentSlot.OFF_HAND, powerForTime);
|
||||
+ if (!event.callEvent())
|
||||
+ return false;
|
||||
+ // SparklyPaper end
|
||||
if (powerForTime < 0.1) {
|
||||
return false;
|
||||
} else {
|
||||
@@ -0,0 +1,967 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||
Date: Tue, 7 Nov 2023 01:34:14 -0300
|
||||
Subject: [PATCH] Parallel world ticking
|
||||
|
||||
"mom can we have folia?" "we already have folia at home" folia at home:
|
||||
|
||||
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java
|
||||
index b5817aa8f537593f6d9fc6b612c82ccccb250ac7..2dbbd33690265cbacd4c6516d24bc64890f50990 100644
|
||||
--- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java
|
||||
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java
|
||||
@@ -1031,7 +1031,7 @@ public final class ChunkHolderManager {
|
||||
if (changedFullStatus.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
- if (!TickThread.isTickThread()) {
|
||||
+ if (!TickThread.isTickThreadFor(world)) { // SparklyPaper - parallel world ticking
|
||||
this.taskScheduler.scheduleChunkTask(() -> {
|
||||
final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = ChunkHolderManager.this.pendingFullLoadUpdate;
|
||||
for (int i = 0, len = changedFullStatus.size(); i < len; ++i) {
|
||||
@@ -1057,7 +1057,7 @@ public final class ChunkHolderManager {
|
||||
|
||||
// note: never call while inside the chunk system, this will absolutely break everything
|
||||
public void processUnloads() {
|
||||
- TickThread.ensureTickThread("Cannot unload chunks off-main");
|
||||
+ TickThread.ensureTickThread(world, "Cannot unload chunks off-main"); // SparklyPaper - parallel world ticking
|
||||
|
||||
if (BLOCK_TICKET_UPDATES.get() == Boolean.TRUE) {
|
||||
throw new IllegalStateException("Cannot unload chunks recursively");
|
||||
@@ -1339,7 +1339,7 @@ public final class ChunkHolderManager {
|
||||
|
||||
List<NewChunkHolder> changedFullStatus = null;
|
||||
|
||||
- final boolean isTickThread = TickThread.isTickThread();
|
||||
+ final boolean isTickThread = TickThread.isTickThreadFor(world);
|
||||
|
||||
boolean ret = false;
|
||||
final boolean canProcessFullUpdates = processFullUpdates & isTickThread;
|
||||
diff --git a/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java b/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java
|
||||
index 4a881636ba21fae9e50950bbba2b4321b71d35ab..ef76ff3671d38b482ac9932560e574d0d8cd9318 100644
|
||||
--- a/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java
|
||||
+++ b/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java
|
||||
@@ -46,7 +46,7 @@ public class BoatDispenseItemBehavior extends DefaultDispenseItemBehavior {
|
||||
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleItemStack);
|
||||
|
||||
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(d1, d2 + d4, d3));
|
||||
- if (!DispenserBlock.eventFired) {
|
||||
+ if (!DispenserBlock.eventFired.get()) { // SparklyPaper - parallel world ticking
|
||||
serverLevel.getCraftServer().getPluginManager().callEvent(event);
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java b/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java
|
||||
index bd5bbc7e55c6bea77991fe5a3c0c2580313d16c5..a231e08edba33bd55bed9a34129615f5e6dddb4d 100644
|
||||
--- a/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java
|
||||
+++ b/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java
|
||||
@@ -78,7 +78,7 @@ public class DefaultDispenseItemBehavior implements DispenseItemBehavior {
|
||||
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack);
|
||||
|
||||
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), org.bukkit.craftbukkit.util.CraftVector.toBukkit(itemEntity.getDeltaMovement()));
|
||||
- if (!DispenserBlock.eventFired) {
|
||||
+ if (!DispenserBlock.eventFired.get()) { // SparklyPaper - parallel world ticking
|
||||
level.getCraftServer().getPluginManager().callEvent(event);
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/core/dispenser/DispenseItemBehavior.java b/net/minecraft/core/dispenser/DispenseItemBehavior.java
|
||||
index 717c84165d5e25cd384f56b7cb976abf6669b6f0..8771e808cdf90fa6590140654da4eab08e15e58f 100644
|
||||
--- a/net/minecraft/core/dispenser/DispenseItemBehavior.java
|
||||
+++ b/net/minecraft/core/dispenser/DispenseItemBehavior.java
|
||||
@@ -89,7 +89,7 @@ public interface DispenseItemBehavior {
|
||||
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleItemStack);
|
||||
|
||||
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0));
|
||||
- if (!DispenserBlock.eventFired) {
|
||||
+ if (!DispenserBlock.eventFired.get()) { // SparklyPaper - parallel world ticking
|
||||
serverLevel.getCraftServer().getPluginManager().callEvent(event);
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ public interface DispenseItemBehavior {
|
||||
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleItemStack);
|
||||
|
||||
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0));
|
||||
- if (!DispenserBlock.eventFired) {
|
||||
+ if (!DispenserBlock.eventFired.get()) { // SparklyPaper - parallel world ticking
|
||||
serverLevel.getCraftServer().getPluginManager().callEvent(event);
|
||||
}
|
||||
|
||||
@@ -201,7 +201,7 @@ public interface DispenseItemBehavior {
|
||||
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleItemStack);
|
||||
|
||||
org.bukkit.event.block.BlockDispenseArmorEvent event = new org.bukkit.event.block.BlockDispenseArmorEvent(block, craftItem.clone(), entitiesOfClass.get(0).getBukkitLivingEntity());
|
||||
- if (!DispenserBlock.eventFired) {
|
||||
+ if (!DispenserBlock.eventFired.get()) { // SparklyPaper - parallel world ticking
|
||||
world.getCraftServer().getPluginManager().callEvent(event);
|
||||
}
|
||||
|
||||
@@ -251,7 +251,7 @@ public interface DispenseItemBehavior {
|
||||
org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(world, blockSource.pos());
|
||||
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleCopy);
|
||||
org.bukkit.event.block.BlockDispenseArmorEvent event = new org.bukkit.event.block.BlockDispenseArmorEvent(block, craftItem.clone(), abstractChestedHorse.getBukkitLivingEntity());
|
||||
- if (!DispenserBlock.eventFired) {
|
||||
+ if (!DispenserBlock.eventFired.get()) { // SparklyPaper - parallel world ticking
|
||||
world.getCraftServer().getPluginManager().callEvent(event);
|
||||
}
|
||||
|
||||
@@ -329,7 +329,7 @@ public interface DispenseItemBehavior {
|
||||
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item.copyWithCount(1)); // Paper - single item in event
|
||||
|
||||
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(x, y, z));
|
||||
- if (!DispenserBlock.eventFired) {
|
||||
+ if (!DispenserBlock.eventFired.get()) { // SparklyPaper - parallel world ticking
|
||||
level.getCraftServer().getPluginManager().callEvent(event);
|
||||
}
|
||||
|
||||
@@ -389,7 +389,7 @@ public interface DispenseItemBehavior {
|
||||
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item.copyWithCount(1)); // Paper - single item in event
|
||||
|
||||
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), org.bukkit.craftbukkit.util.CraftVector.toBukkit(blockPos));
|
||||
- if (!DispenserBlock.eventFired) {
|
||||
+ if (!DispenserBlock.eventFired.get()) { // SparklyPaper - parallel world ticking
|
||||
levelAccessor.getMinecraftWorld().getCraftServer().getPluginManager().callEvent(event);
|
||||
}
|
||||
|
||||
@@ -425,7 +425,7 @@ public interface DispenseItemBehavior {
|
||||
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item); // Paper - ignore stack size on damageable items
|
||||
|
||||
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0));
|
||||
- if (!DispenserBlock.eventFired) {
|
||||
+ if (!DispenserBlock.eventFired.get()) { // SparklyPaper - parallel world ticking
|
||||
serverLevel.getCraftServer().getPluginManager().callEvent(event);
|
||||
}
|
||||
|
||||
@@ -482,7 +482,7 @@ public interface DispenseItemBehavior {
|
||||
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item.copyWithCount(1)); // Paper - single item in event
|
||||
|
||||
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0));
|
||||
- if (!DispenserBlock.eventFired) {
|
||||
+ if (!DispenserBlock.eventFired.get()) { // SparklyPaper - parallel world ticking
|
||||
level.getCraftServer().getPluginManager().callEvent(event);
|
||||
}
|
||||
|
||||
@@ -510,8 +510,8 @@ public interface DispenseItemBehavior {
|
||||
// CraftBukkit start
|
||||
level.captureTreeGeneration = false;
|
||||
if (level.capturedBlockStates.size() > 0) {
|
||||
- org.bukkit.TreeType treeType = net.minecraft.world.level.block.SaplingBlock.treeType;
|
||||
- net.minecraft.world.level.block.SaplingBlock.treeType = null;
|
||||
+ org.bukkit.TreeType treeType = net.minecraft.world.level.block.SaplingBlock.treeTypeRT.get(); // SparklyPaper - parallel world ticking
|
||||
+ net.minecraft.world.level.block.SaplingBlock.treeTypeRT.set(null); // SparklyPaper - parallel world ticking
|
||||
org.bukkit.Location location = org.bukkit.craftbukkit.util.CraftLocation.toBukkit(blockPos, level.getWorld());
|
||||
List<org.bukkit.block.BlockState> blocks = new java.util.ArrayList<>(level.capturedBlockStates.values());
|
||||
level.capturedBlockStates.clear();
|
||||
@@ -548,7 +548,7 @@ public interface DispenseItemBehavior {
|
||||
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleItemStack);
|
||||
|
||||
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector((double) blockPos.getX() + 0.5D, (double) blockPos.getY(), (double) blockPos.getZ() + 0.5D));
|
||||
- if (!DispenserBlock.eventFired) {
|
||||
+ if (!DispenserBlock.eventFired.get()) { // SparklyPaper - parallel world ticking
|
||||
level.getCraftServer().getPluginManager().callEvent(event);
|
||||
}
|
||||
|
||||
@@ -591,7 +591,7 @@ public interface DispenseItemBehavior {
|
||||
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item.copyWithCount(1)); // Paper - single item in event
|
||||
|
||||
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), org.bukkit.craftbukkit.util.CraftVector.toBukkit(blockPos));
|
||||
- if (!DispenserBlock.eventFired) {
|
||||
+ if (!DispenserBlock.eventFired.get()) { // SparklyPaper - parallel world ticking
|
||||
level.getCraftServer().getPluginManager().callEvent(event);
|
||||
}
|
||||
|
||||
@@ -644,7 +644,7 @@ public interface DispenseItemBehavior {
|
||||
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item.copyWithCount(1)); // Paper - single item in event
|
||||
|
||||
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), org.bukkit.craftbukkit.util.CraftVector.toBukkit(blockPos));
|
||||
- if (!DispenserBlock.eventFired) {
|
||||
+ if (!DispenserBlock.eventFired.get()) { // SparklyPaper - parallel world ticking
|
||||
level.getCraftServer().getPluginManager().callEvent(event);
|
||||
}
|
||||
|
||||
@@ -702,7 +702,7 @@ public interface DispenseItemBehavior {
|
||||
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item.copyWithCount(1)); // Paper - only single item in event
|
||||
|
||||
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), org.bukkit.craftbukkit.util.CraftVector.toBukkit(blockPos));
|
||||
- if (!DispenserBlock.eventFired) {
|
||||
+ if (!DispenserBlock.eventFired.get()) { // SparklyPaper - parallel world ticking
|
||||
serverLevel.getCraftServer().getPluginManager().callEvent(event);
|
||||
}
|
||||
|
||||
@@ -783,7 +783,7 @@ public interface DispenseItemBehavior {
|
||||
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item); // Paper - ignore stack size on damageable items
|
||||
|
||||
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseArmorEvent(block, craftItem.clone(), entitiesOfClass.get(0).getBukkitLivingEntity());
|
||||
- if (!DispenserBlock.eventFired) {
|
||||
+ if (!DispenserBlock.eventFired.get()) { // SparklyPaper - parallel world ticking
|
||||
serverLevel.getCraftServer().getPluginManager().callEvent(event);
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java b/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java
|
||||
index 3595bbd05fb3e8fe57e38d4e2df5c6237046b726..2b02d7cbc7fbb916c240f2d16bab365dbc1b8e56 100644
|
||||
--- a/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java
|
||||
+++ b/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java
|
||||
@@ -39,7 +39,7 @@ public class EquipmentDispenseItemBehavior extends DefaultDispenseItemBehavior {
|
||||
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack);
|
||||
|
||||
org.bukkit.event.block.BlockDispenseArmorEvent event = new org.bukkit.event.block.BlockDispenseArmorEvent(block, craftItem.clone(), (org.bukkit.craftbukkit.entity.CraftLivingEntity) livingEntity.getBukkitEntity());
|
||||
- if (!DispenserBlock.eventFired) {
|
||||
+ if (!DispenserBlock.eventFired.get()) { // SparklyPaper - parallel world ticking
|
||||
world.getCraftServer().getPluginManager().callEvent(event);
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java b/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java
|
||||
index 116395b6c00a0814922516707544a9ff26d68835..672ebd0cfc144d9b7315dcebf1e8007912ad7412 100644
|
||||
--- a/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java
|
||||
+++ b/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java
|
||||
@@ -62,7 +62,7 @@ public class MinecartDispenseItemBehavior extends DefaultDispenseItemBehavior {
|
||||
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack1);
|
||||
|
||||
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block2, craftItem.clone(), new org.bukkit.util.Vector(vec31.x, vec31.y, vec31.z));
|
||||
- if (!DispenserBlock.eventFired) {
|
||||
+ if (!DispenserBlock.eventFired.get()) { // SparklyPaper - parallel world ticking
|
||||
serverLevel.getCraftServer().getPluginManager().callEvent(event);
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java b/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java
|
||||
index 449d9b72ff4650961daa9d1bd25940f3914a6b12..df07b55924c1edca11eebd9debc75d9f184ede9d 100644
|
||||
--- a/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java
|
||||
+++ b/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java
|
||||
@@ -32,7 +32,7 @@ public class ProjectileDispenseBehavior extends DefaultDispenseItemBehavior {
|
||||
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack1);
|
||||
|
||||
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector((double) direction.getStepX(), (double) direction.getStepY(), (double) direction.getStepZ()));
|
||||
- if (!DispenserBlock.eventFired) {
|
||||
+ if (!DispenserBlock.eventFired.get()) { // SparklyPaper - parallel world ticking
|
||||
serverLevel.getCraftServer().getPluginManager().callEvent(event);
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java b/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java
|
||||
index 626e9feb6a6e7a2cbc7c63e30ba4fb6b923e85c7..6ac9a0fc92eb9801bed3bc296988ee224afffa14 100644
|
||||
--- a/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java
|
||||
+++ b/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java
|
||||
@@ -25,7 +25,7 @@ public class ShearsDispenseItemBehavior extends OptionalDispenseItemBehavior {
|
||||
org.bukkit.block.Block bukkitBlock = org.bukkit.craftbukkit.block.CraftBlock.at(serverLevel, blockSource.pos());
|
||||
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item); // Paper - ignore stack size on damageable items
|
||||
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0));
|
||||
- if (!DispenserBlock.eventFired) {
|
||||
+ if (!DispenserBlock.eventFired.get()) { // SparklyPaper - parallel world ticking
|
||||
serverLevel.getCraftServer().getPluginManager().callEvent(event);
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java b/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java
|
||||
index 5ab2c8333178335515e619b87ae420f948c83bd1..c98e3748ff467f75f0a0e5a429563feaf06105f3 100644
|
||||
--- a/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java
|
||||
+++ b/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java
|
||||
@@ -27,7 +27,7 @@ public class ShulkerBoxDispenseBehavior extends OptionalDispenseItemBehavior {
|
||||
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item.copyWithCount(1)); // Paper - single item in event
|
||||
|
||||
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(blockPos.getX(), blockPos.getY(), blockPos.getZ()));
|
||||
- if (!DispenserBlock.eventFired) {
|
||||
+ if (!DispenserBlock.eventFired.get()) { // SparklyPaper - parallel world ticking
|
||||
blockSource.level().getCraftServer().getPluginManager().callEvent(event);
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index c15c11ab3feaca918ac0185383cd1653200cd186..1bc0e3397a1299bdbe37a69097ece7d7395421f7 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -305,6 +305,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
public static final long SERVER_INIT = System.nanoTime(); // Paper - Lag compensation
|
||||
public final Set<net.minecraft.world.entity.Entity> entitiesWithScheduledTasks = java.util.concurrent.ConcurrentHashMap.newKeySet(); // SparklyPaper - skip EntityScheduler's executeTick checks if there isn't any tasks to be run (concurrent because plugins may schedule tasks async)
|
||||
public net.sparklypower.sparklypaper.HalloweenManager halloweenManager = new net.sparklypower.sparklypaper.HalloweenManager(); // SparklyPaper - Spooky month optimizations
|
||||
+ public java.util.concurrent.Semaphore serverLevelTickingSemaphore = null; // SparklyPaper - parallel world ticking
|
||||
|
||||
public static <S extends MinecraftServer> S spin(Function<Thread, S> threadFunction) {
|
||||
ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.init(); // Paper - rewrite data converter system
|
||||
@@ -1720,6 +1721,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
}
|
||||
|
||||
this.isIteratingOverLevels = true; // Paper - Throw exception on world create while being ticked
|
||||
+ // SparklyPaper start - parallel world ticking
|
||||
+ java.util.ArrayDeque<java.util.concurrent.Future<ServerLevel>> tasks = new java.util.ArrayDeque<>();
|
||||
+ try {
|
||||
for (ServerLevel serverLevel : this.getAllLevels()) {
|
||||
serverLevel.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - BlockPhysicsEvent
|
||||
serverLevel.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - Add EntityMoveEvent
|
||||
@@ -1736,27 +1740,46 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
profilerFiller.push("tick");
|
||||
|
||||
- try {
|
||||
- long i = Util.getNanos(); // SparklyPaper - track world's MSPT
|
||||
- serverLevel.tick(hasTimeLeft);
|
||||
- // SparklyPaper start - track world's MSPT
|
||||
- long j = Util.getNanos() - i;
|
||||
-
|
||||
- // These are from the "tickServer" function
|
||||
- serverLevel.tickTimes5s.add(this.tickCount, j);
|
||||
- serverLevel.tickTimes10s.add(this.tickCount, j);
|
||||
- serverLevel.tickTimes60s.add(this.tickCount, j);
|
||||
- // SparklyPaper end
|
||||
- } catch (Throwable var7) {
|
||||
- CrashReport crashReport = CrashReport.forThrowable(var7, "Exception ticking world");
|
||||
- serverLevel.fillReportDetails(crashReport);
|
||||
- throw new ReportedException(crashReport);
|
||||
- }
|
||||
+ serverLevelTickingSemaphore.acquire();
|
||||
+ tasks.add(
|
||||
+ serverLevel.tickExecutor.submit(() -> {
|
||||
+ try {
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ServerLevelTickThread currentThread = (ca.spottedleaf.moonrise.common.util.TickThread.ServerLevelTickThread) Thread.currentThread();
|
||||
+ currentThread.currentlyTickingServerLevel = serverLevel;
|
||||
+
|
||||
+ long i = Util.getNanos(); // SparklyPaper - track world's MSPT
|
||||
+ serverLevel.tick(hasTimeLeft);
|
||||
+ // SparklyPaper start - track world's MSPT
|
||||
+ long j = Util.getNanos() - i;
|
||||
+
|
||||
+ // These are from the "tickServer" function
|
||||
+ serverLevel.tickTimes5s.add(this.tickCount, j);
|
||||
+ serverLevel.tickTimes10s.add(this.tickCount, j);
|
||||
+ serverLevel.tickTimes60s.add(this.tickCount, j);
|
||||
+ // SparklyPaper end
|
||||
+ } catch (Throwable throwable) {
|
||||
+ CrashReport crashreport = CrashReport.forThrowable(throwable, "Exception ticking world");
|
||||
+
|
||||
+ serverLevel.fillReportDetails(crashreport);
|
||||
+ throw new ReportedException(crashreport);
|
||||
+ } finally {
|
||||
+ serverLevelTickingSemaphore.release();
|
||||
+ }
|
||||
+ }, serverLevel)
|
||||
+ );
|
||||
|
||||
profilerFiller.pop();
|
||||
profilerFiller.pop();
|
||||
serverLevel.explosionDensityCache.clear(); // Paper - Optimize explosions
|
||||
}
|
||||
+
|
||||
+ while (!tasks.isEmpty()) {
|
||||
+ tasks.pop().get();
|
||||
+ }
|
||||
+ } catch (java.lang.InterruptedException | java.util.concurrent.ExecutionException e) {
|
||||
+ throw new RuntimeException(e); // Propagate exception
|
||||
+ }
|
||||
+ // SparklyPaper end
|
||||
this.isIteratingOverLevels = false; // Paper - Throw exception on world create while being ticked
|
||||
|
||||
profilerFiller.popPush("connection");
|
||||
@@ -1847,6 +1870,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
Map<ResourceKey<Level>, ServerLevel> oldLevels = this.levels;
|
||||
Map<ResourceKey<Level>, ServerLevel> newLevels = Maps.newLinkedHashMap(oldLevels);
|
||||
newLevels.remove(level.dimension());
|
||||
+ level.tickExecutor.shutdown(); // SparklyPaper - parallel world ticking (We remove it in here instead of ServerLevel.close() because ServerLevel.close() is never called!)
|
||||
this.levels = Collections.unmodifiableMap(newLevels);
|
||||
}
|
||||
// CraftBukkit end
|
||||
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
index 6ac73610f6039290c4ef3dde2206b6863d2b5067..0c5dbfe1d7e17796c1a60bcb1f97673ddff4d94e 100644
|
||||
--- a/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -233,6 +233,8 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
}
|
||||
net.sparklypower.sparklypaper.SparklyPaperCommands.INSTANCE.registerCommands(this);
|
||||
// SparklyPaper end
|
||||
+ serverLevelTickingSemaphore = new java.util.concurrent.Semaphore(net.sparklypower.sparklypaper.configs.SparklyPaperConfigUtils.INSTANCE.getConfig().getParallelWorldTicking().getThreads()); // SparklyPaper - parallel world ticking
|
||||
+ DedicatedServer.LOGGER.info("Using " + serverLevelTickingSemaphore.availablePermits() + " permits for parallel world ticking"); // SparklyPaper - parallel world ticking
|
||||
// SparklyPaper start - Spooky month optimizations
|
||||
halloweenManager.startHalloweenEpochTask();
|
||||
halloweenManager.waitUntilEpochHasBeenUpdated();
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index 59465ab6d7723d27b1597cc7094b5044a3f24250..7d0e5184289b37c6c9acc34341b8d84399ba653f 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -184,7 +184,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
private final MinecraftServer server;
|
||||
public final net.minecraft.world.level.storage.PrimaryLevelData serverLevelData; // CraftBukkit - type
|
||||
private int lastSpawnChunkRadius;
|
||||
- final EntityTickList entityTickList = new EntityTickList();
|
||||
+ final EntityTickList entityTickList = new EntityTickList(this); // SparklyPaper - parallel world ticking
|
||||
// Paper - rewrite chunk system
|
||||
private final GameEventDispatcher gameEventDispatcher;
|
||||
public boolean noSave;
|
||||
@@ -208,6 +208,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
private final StructureCheck structureCheck;
|
||||
private final boolean tickTime;
|
||||
private final RandomSequences randomSequences;
|
||||
+ public java.util.concurrent.ExecutorService tickExecutor; // SparklyPaper - parallel world ticking
|
||||
|
||||
// CraftBukkit start
|
||||
public final LevelStorageSource.LevelStorageAccess levelStorageAccess;
|
||||
@@ -687,6 +688,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
this.chunkDataController = new ca.spottedleaf.moonrise.patches.chunk_system.io.datacontroller.ChunkDataController((ServerLevel)(Object)this, this.chunkTaskScheduler);
|
||||
// Paper end - rewrite chunk system
|
||||
this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit
|
||||
+ this.tickExecutor = java.util.concurrent.Executors.newSingleThreadExecutor(new net.sparklypower.sparklypaper.ServerLevelTickExecutorThreadFactory(getWorld().getName())); // SparklyPaper - parallel world ticking
|
||||
}
|
||||
|
||||
// Paper start
|
||||
@@ -1226,7 +1228,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
}
|
||||
// Paper start - rewrite chunk system
|
||||
if ((++this.tickedBlocksOrFluids & 7L) != 0L) {
|
||||
- ((ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer)this.server).moonrise$executeMidTickTasks();
|
||||
+ // ((ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer)this.server).moonrise$executeMidTickTasks(); // SparklyPaper - parallel world ticking (only run mid-tick at the end of each tick / fixes concurrency bugs related to executeMidTickTasks)
|
||||
}
|
||||
// Paper end - rewrite chunk system
|
||||
|
||||
@@ -1239,7 +1241,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
}
|
||||
// Paper start - rewrite chunk system
|
||||
if ((++this.tickedBlocksOrFluids & 7L) != 0L) {
|
||||
- ((ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer)this.server).moonrise$executeMidTickTasks();
|
||||
+ // ((ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer)this.server).moonrise$executeMidTickTasks(); // SparklyPaper - parallel world ticking (only run mid-tick at the end of each tick / fixes concurrency bugs related to executeMidTickTasks)
|
||||
}
|
||||
// Paper end - rewrite chunk system
|
||||
|
||||
@@ -1497,6 +1499,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
}
|
||||
|
||||
private void addPlayer(ServerPlayer player) {
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this, "Cannot add player off-main"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||
Entity entity = this.getEntities().get(player.getUUID());
|
||||
if (entity != null) {
|
||||
LOGGER.warn("Force-added player with duplicate UUID {}", player.getUUID());
|
||||
@@ -1509,7 +1512,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
|
||||
// CraftBukkit start
|
||||
private boolean addEntity(Entity entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason) {
|
||||
- org.spigotmc.AsyncCatcher.catchOp("entity add"); // Spigot
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this, "Cannot add entity off-main"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||
entity.generation = false; // Paper - Don't fire sync event during generation; Reset flag if it was added during a ServerLevel generation process
|
||||
// Paper start - extra debug info
|
||||
if (entity.valid) {
|
||||
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
|
||||
index f347ff8d863f4bcef46604c757de112cb3fe445c..532df406e9fb41ab2ccfd59bcc7a614d6ada6548 100644
|
||||
--- a/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -423,6 +423,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
return this.viewDistanceHolder;
|
||||
}
|
||||
// Paper end - rewrite chunk system
|
||||
+ public boolean hasTickedAtLeastOnceInNewWorld = false; // SparklyPaper - parallel world ticking (fixes bug in DreamResourceReset where the inventory is opened AFTER the player has changed worlds, if you click with the quick tp torch in a chest, because the inventory is opened AFTER the player has teleported)
|
||||
|
||||
public ServerPlayer(MinecraftServer server, ServerLevel level, GameProfile gameProfile, ClientInformation clientInformation) {
|
||||
super(level, level.getSharedSpawnPos(), level.getSharedSpawnAngle(), gameProfile);
|
||||
@@ -792,6 +793,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
+ hasTickedAtLeastOnceInNewWorld = true; // SparklyPaper - parallel world ticking (see: PARALLEL_NOTES.md - Opening an inventory after a world switch)
|
||||
// CraftBukkit start
|
||||
if (this.joining) {
|
||||
this.joining = false;
|
||||
@@ -1415,6 +1417,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
return this;
|
||||
} else {
|
||||
// CraftBukkit start
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureOnlyTickThread("Cannot change dimension of a player off-main, from world " + serverLevel().getWorld().getName() + " to world " + level.getWorld().getName()); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||
/*
|
||||
this.isChangingDimension = true;
|
||||
LevelData levelData = level.getLevelData();
|
||||
@@ -1768,6 +1771,12 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
return OptionalInt.empty();
|
||||
} else {
|
||||
// CraftBukkit start
|
||||
+ // SparklyPaper start - parallel world ticking (see: PARALLEL_NOTES.md - Opening an inventory after a world switch)
|
||||
+ if (!hasTickedAtLeastOnceInNewWorld) {
|
||||
+ MinecraftServer.LOGGER.warn("Ignoring request to open container " + abstractContainerMenu + " because we haven't ticked in the current world yet!", new Throwable());
|
||||
+ return OptionalInt.empty();
|
||||
+ }
|
||||
+ // SparklyPaper end
|
||||
this.containerMenu = abstractContainerMenu; // Moved up
|
||||
if (!this.isImmobile())
|
||||
this.connection
|
||||
@@ -1832,6 +1841,11 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
}
|
||||
@Override
|
||||
public void closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason reason) {
|
||||
+ // SparklyPaper start - parallel world ticking (debugging)
|
||||
+ if (net.sparklypower.sparklypaper.configs.SparklyPaperConfigUtils.INSTANCE.getLogContainerCreationStacktraces()) {
|
||||
+ MinecraftServer.LOGGER.warn("Closing " + this.getBukkitEntity().getName() + " inventory that was created at", this.containerMenu.containerCreationStacktrace);
|
||||
+ }
|
||||
+ // SparklyPaper end
|
||||
org.bukkit.craftbukkit.event.CraftEventFactory.handleInventoryCloseEvent(this, reason); // CraftBukkit
|
||||
// Paper end - Inventory close reason
|
||||
this.connection.send(new ClientboundContainerClosePacket(this.containerMenu.containerId));
|
||||
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
|
||||
index 03feaf0adb8ee87e33744a4615dc2507a02f92d7..d6e13845fce443ae9b8f2c9a4ee5b00c4c5cc831 100644
|
||||
--- a/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/net/minecraft/server/players/PlayerList.java
|
||||
@@ -113,7 +113,7 @@ public abstract class PlayerList {
|
||||
private static final SimpleDateFormat BAN_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd 'at' HH:mm:ss z");
|
||||
private final MinecraftServer server;
|
||||
public final List<ServerPlayer> players = new java.util.concurrent.CopyOnWriteArrayList(); // CraftBukkit - ArrayList -> CopyOnWriteArrayList: Iterator safety
|
||||
- private final Map<UUID, ServerPlayer> playersByUUID = Maps.newHashMap();
|
||||
+ private final Map<UUID, ServerPlayer> playersByUUID = Maps.newHashMap(); // SparklyPaper - parallel world ticking (we don't need to replace the original map because we never iterate on top of this map)
|
||||
private final UserBanList bans = new UserBanList(USERBANLIST_FILE);
|
||||
private final IpBanList ipBans = new IpBanList(IPBANLIST_FILE);
|
||||
private final ServerOpList ops = new ServerOpList(OPLIST_FILE);
|
||||
@@ -134,7 +134,7 @@ public abstract class PlayerList {
|
||||
|
||||
// CraftBukkit start
|
||||
private org.bukkit.craftbukkit.CraftServer cserver;
|
||||
- private final Map<String,ServerPlayer> playersByName = new java.util.HashMap<>();
|
||||
+ private final Map<String,ServerPlayer> playersByName = new java.util.HashMap<>(); // SparklyPaper - parallel world ticking (we don't need to replace the original map because we never iterate on top of this map)
|
||||
public @Nullable String collideRuleTeamName; // Paper - Configurable player collision
|
||||
|
||||
public PlayerList(MinecraftServer server, LayeredRegistryAccess<RegistryLayer> registries, PlayerDataStorage playerIo, int maxPlayers) {
|
||||
@@ -150,6 +150,7 @@ public abstract class PlayerList {
|
||||
abstract public void loadAndSaveFiles(); // Paper - fix converting txt to json file; moved from DedicatedPlayerList constructor
|
||||
|
||||
public void placeNewPlayer(Connection connection, ServerPlayer player, CommonListenerCookie cookie) {
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureOnlyTickThread("Cannot place new player off-main"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||
player.isRealPlayer = true; // Paper
|
||||
player.loginTime = System.currentTimeMillis(); // Paper - Replace OfflinePlayer#getLastPlayed
|
||||
GameProfile gameProfile = player.getGameProfile();
|
||||
@@ -714,6 +715,13 @@ public abstract class PlayerList {
|
||||
return this.respawn(player, keepInventory, reason, eventReason, null);
|
||||
}
|
||||
public ServerPlayer respawn(ServerPlayer player, boolean keepInventory, Entity.RemovalReason reason, org.bukkit.event.player.PlayerRespawnEvent.RespawnReason eventReason, org.bukkit.Location location) {
|
||||
+ System.out.println("respawning player - current player container is " + player.containerMenu + " but their inventory is " + player.inventoryMenu);
|
||||
+ // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||
+ if (location != null) // TODO: Is this really never null, or is IntelliJ IDEA tripping? Because I'm pretty sure that this can be null and there isn't any @NotNull annotations
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureOnlyTickThread("Cannot respawn player off-main, from world " + player.serverLevel().getWorld().getName() + " to world " + location.getWorld().getName());
|
||||
+ else
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureOnlyTickThread("Cannot respawn player off-main, respawning in world " + player.serverLevel().getWorld().getName());
|
||||
+ // SparklyPaper end
|
||||
player.stopRiding(); // CraftBukkit
|
||||
this.players.remove(player);
|
||||
this.playersByName.remove(player.getScoreboardName().toLowerCase(java.util.Locale.ROOT)); // Spigot
|
||||
@@ -724,6 +732,7 @@ public abstract class PlayerList {
|
||||
ServerPlayer serverPlayer = player;
|
||||
Level fromWorld = player.level();
|
||||
player.wonGame = false;
|
||||
+ serverPlayer.hasTickedAtLeastOnceInNewWorld = false; // SparklyPaper - parallel world ticking (see: PARALLEL_NOTES.md - Opening an inventory after a world switch)
|
||||
// CraftBukkit end
|
||||
serverPlayer.connection = player.connection;
|
||||
serverPlayer.restoreFrom(player, keepInventory);
|
||||
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
|
||||
index 1d0151a042ed5de4e235ef0bdac1a0e8240e85e7..731aecb84f87b6de41029b88e0c5c7ce2bab20cb 100644
|
||||
--- a/net/minecraft/world/entity/Entity.java
|
||||
+++ b/net/minecraft/world/entity/Entity.java
|
||||
@@ -822,7 +822,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
// CraftBukkit start
|
||||
public void postTick() {
|
||||
// No clean way to break out of ticking once the entity has been copied to a new world, so instead we move the portalling later in the tick cycle
|
||||
- if (!(this instanceof ServerPlayer) && this.isAlive()) { // Paper - don't attempt to teleport dead entities
|
||||
+ if (false && !(this instanceof ServerPlayer) && this.isAlive()) { // Paper - don't attempt to teleport dead entities // SparklyPaper - parallel world ticking (see issue #9, this is executed in the server level tick for non-player entities)
|
||||
this.handlePortal();
|
||||
}
|
||||
}
|
||||
@@ -3808,6 +3808,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
}
|
||||
|
||||
private Entity teleportCrossDimension(ServerLevel level, TeleportTransition teleportTransition) {
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(level, "Cannot teleport entity to another world off-main, from world " + this.level.getWorld().getName() + " to world " + level.getWorld().getName()); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||
List<Entity> passengers = this.getPassengers();
|
||||
List<Entity> list = new ArrayList<>(passengers.size());
|
||||
this.ejectPassengers();
|
||||
diff --git a/net/minecraft/world/inventory/AbstractContainerMenu.java b/net/minecraft/world/inventory/AbstractContainerMenu.java
|
||||
index 50af953a4698a3c6e16b840fab764dd733b3fbc9..27b6fcb12f1f6a36529fbf19f10ca6330280525a 100644
|
||||
--- a/net/minecraft/world/inventory/AbstractContainerMenu.java
|
||||
+++ b/net/minecraft/world/inventory/AbstractContainerMenu.java
|
||||
@@ -91,8 +91,14 @@ public abstract class AbstractContainerMenu {
|
||||
}
|
||||
public void startOpen() {}
|
||||
// CraftBukkit end
|
||||
+ public Throwable containerCreationStacktrace; // SparklyPaper - parallel world ticking (debugging)
|
||||
|
||||
protected AbstractContainerMenu(@Nullable MenuType<?> menuType, int containerId) {
|
||||
+ // SparklyPaper - parallel world ticking (debugging)
|
||||
+ if (net.sparklypower.sparklypaper.configs.SparklyPaperConfigUtils.INSTANCE.getLogContainerCreationStacktraces()) {
|
||||
+ this.containerCreationStacktrace = new Throwable();
|
||||
+ }
|
||||
+ // SparklyPaper end
|
||||
this.menuType = menuType;
|
||||
this.containerId = containerId;
|
||||
}
|
||||
diff --git a/net/minecraft/world/item/ItemStack.java b/net/minecraft/world/item/ItemStack.java
|
||||
index 76f50437396f8f856381d0fbef52953ef7c263f6..199fec37b2c2b2ea6a55700cb8f4ec98aeb6504a 100644
|
||||
--- a/net/minecraft/world/item/ItemStack.java
|
||||
+++ b/net/minecraft/world/item/ItemStack.java
|
||||
@@ -407,8 +407,8 @@ public final class ItemStack implements DataComponentHolder {
|
||||
if (interactionResult.consumesAction() && serverLevel.captureTreeGeneration && !serverLevel.capturedBlockStates.isEmpty()) {
|
||||
serverLevel.captureTreeGeneration = false;
|
||||
org.bukkit.Location location = org.bukkit.craftbukkit.util.CraftLocation.toBukkit(clickedPos, serverLevel.getWorld());
|
||||
- org.bukkit.TreeType treeType = net.minecraft.world.level.block.SaplingBlock.treeType;
|
||||
- net.minecraft.world.level.block.SaplingBlock.treeType = null;
|
||||
+ org.bukkit.TreeType treeType = net.minecraft.world.level.block.SaplingBlock.treeTypeRT.get(); // SparklyPaper - parallel world ticking
|
||||
+ net.minecraft.world.level.block.SaplingBlock.treeTypeRT.set(null);
|
||||
List<org.bukkit.craftbukkit.block.CraftBlockState> blocks = new java.util.ArrayList<>(serverLevel.capturedBlockStates.values());
|
||||
serverLevel.capturedBlockStates.clear();
|
||||
org.bukkit.event.world.StructureGrowEvent structureEvent = null;
|
||||
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
|
||||
index 644ab8b2c797f0675530a3efe23a878899689d66..b43cc51c23da0228aafd99d56e2a6e5cc05496ed 100644
|
||||
--- a/net/minecraft/world/level/Level.java
|
||||
+++ b/net/minecraft/world/level/Level.java
|
||||
@@ -171,6 +171,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
|
||||
public final io.papermc.paper.antixray.ChunkPacketBlockController chunkPacketBlockController; // Paper - Anti-Xray
|
||||
public net.sparklypower.sparklypaper.configs.SparklyPaperConfig.SparklyPaperWorldConfig sparklyPaperConfig; // SparklyPaper
|
||||
+ public io.papermc.paper.redstone.RedstoneWireTurbo turbo = new io.papermc.paper.redstone.RedstoneWireTurbo((net.minecraft.world.level.block.RedStoneWireBlock) net.minecraft.world.level.block.Blocks.REDSTONE_WIRE); // SparklyPaper - parallel world ticking (moved to world)
|
||||
public static BlockPos lastPhysicsProblem; // Spigot
|
||||
private org.spigotmc.TickLimiter entityLimiter;
|
||||
private org.spigotmc.TickLimiter tileLimiter;
|
||||
@@ -1100,6 +1101,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
|
||||
@Override
|
||||
public boolean setBlock(BlockPos pos, BlockState state, int flags, int recursionLeft) {
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread((ServerLevel)this, pos, "Updating block asynchronously"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||
// CraftBukkit start - tree generation
|
||||
if (this.captureTreeGeneration) {
|
||||
// Paper start - Protect Bedrock and End Portal/Frames from being destroyed
|
||||
@@ -1484,7 +1486,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
tickingBlockEntity.tick();
|
||||
// Paper start - rewrite chunk system
|
||||
if ((++tickedEntities & 7) == 0) {
|
||||
- ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel)(Level)(Object)this).moonrise$midTickTasks();
|
||||
+ // ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel)(Level)(Object)this).moonrise$midTickTasks(); // SparklyPaper - parallel world ticking (only run mid-tick at the end of each tick / fixes concurrency bugs related to executeMidTickTasks)
|
||||
}
|
||||
// Paper end - rewrite chunk system
|
||||
}
|
||||
@@ -1508,7 +1510,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD);
|
||||
// Paper end - Prevent block entity and entity crashes
|
||||
}
|
||||
- this.moonrise$midTickTasks(); // Paper - rewrite chunk system
|
||||
+ // this.moonrise$midTickTasks(); // Paper - rewrite chunk system // SparklyPaper - parallel world ticking (only run mid-tick at the end of each tick / fixes concurrency bugs related to executeMidTickTasks)
|
||||
}
|
||||
|
||||
// Paper start - Option to prevent armor stands from doing entity lookups
|
||||
@@ -1651,6 +1653,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
|
||||
@Nullable
|
||||
public BlockEntity getBlockEntity(BlockPos pos, boolean validate) {
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThreadOrAsyncThread((ServerLevel) this, "Cannot read world asynchronously"); // SparklyPaper - parallel world ticking
|
||||
// Paper start - Perf: Optimize capturedTileEntities lookup
|
||||
net.minecraft.world.level.block.entity.BlockEntity blockEntity;
|
||||
if (!this.capturedTileEntities.isEmpty() && (blockEntity = this.capturedTileEntities.get(pos)) != null) {
|
||||
@@ -1668,6 +1671,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
}
|
||||
|
||||
public void setBlockEntity(BlockEntity blockEntity) {
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread((ServerLevel) this, "Cannot modify world asynchronously"); // SparklyPaper - parallel world ticking
|
||||
BlockPos blockPos = blockEntity.getBlockPos();
|
||||
if (!this.isOutsideBuildHeight(blockPos)) {
|
||||
// CraftBukkit start
|
||||
@@ -1752,6 +1756,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
|
||||
@Override
|
||||
public List<Entity> getEntities(@Nullable Entity entity, AABB boundingBox, Predicate<? super Entity> predicate) {
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread((ServerLevel)this, boundingBox, "Cannot getEntities asynchronously"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||
Profiler.get().incrementCounter("getEntities");
|
||||
List<Entity> list = Lists.newArrayList();
|
||||
|
||||
@@ -2064,8 +2069,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
public abstract RecipeAccess recipeAccess();
|
||||
|
||||
public BlockPos getBlockRandomPos(int x, int y, int z, int yMask) {
|
||||
- this.randValue = this.randValue * 3 + 1013904223;
|
||||
- int i = this.randValue >> 2;
|
||||
+ int i = this.random.nextInt() >> 2; // SparklyPaper - parallel world ticking
|
||||
return new BlockPos(x + (i & 15), y + (i >> 16 & yMask), z + (i >> 8 & 15));
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/world/level/block/DispenserBlock.java b/net/minecraft/world/level/block/DispenserBlock.java
|
||||
index e0a4d41e5bcf144ea4c10d6f633c3a95ed2c5aec..ff99bff5b1986798ac8170def2809cc0c553e500 100644
|
||||
--- a/net/minecraft/world/level/block/DispenserBlock.java
|
||||
+++ b/net/minecraft/world/level/block/DispenserBlock.java
|
||||
@@ -50,7 +50,8 @@ public class DispenserBlock extends BaseEntityBlock {
|
||||
private static final DefaultDispenseItemBehavior DEFAULT_BEHAVIOR = new DefaultDispenseItemBehavior();
|
||||
public static final Map<Item, DispenseItemBehavior> DISPENSER_REGISTRY = new IdentityHashMap<>();
|
||||
private static final int TRIGGER_DURATION = 4;
|
||||
- public static boolean eventFired = false; // CraftBukkit
|
||||
+ // public static boolean eventFired = false; // CraftBukkit // SparklyPaper - parallel world ticking
|
||||
+ public static ThreadLocal<Boolean> eventFired = ThreadLocal.withInitial(() -> Boolean.FALSE); // SparklyPaper - parallel world ticking
|
||||
|
||||
@Override
|
||||
public MapCodec<? extends DispenserBlock> codec() {
|
||||
@@ -96,7 +97,7 @@ public class DispenserBlock extends BaseEntityBlock {
|
||||
DispenseItemBehavior dispenseMethod = this.getDispenseMethod(level, item);
|
||||
if (dispenseMethod != DispenseItemBehavior.NOOP) {
|
||||
if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockPreDispenseEvent(level, pos, item, randomSlot)) return; // Paper - Add BlockPreDispenseEvent
|
||||
- DispenserBlock.eventFired = false; // CraftBukkit - reset event status
|
||||
+ DispenserBlock.eventFired.set(Boolean.FALSE); // CraftBukkit - reset event status // SparklyPaper - parallel world ticking
|
||||
dispenserBlockEntity.setItem(randomSlot, dispenseMethod.dispense(blockSource, item));
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/world/level/block/FungusBlock.java b/net/minecraft/world/level/block/FungusBlock.java
|
||||
index 85f0eac75784565c658c5178c544f969db3d6f54..bfa0b1f72497cefecc112d9f484896edc9ec6f36 100644
|
||||
--- a/net/minecraft/world/level/block/FungusBlock.java
|
||||
+++ b/net/minecraft/world/level/block/FungusBlock.java
|
||||
@@ -76,9 +76,9 @@ public class FungusBlock extends BushBlock implements BonemealableBlock {
|
||||
// CraftBukkit start
|
||||
.map((value) -> {
|
||||
if (this == Blocks.WARPED_FUNGUS) {
|
||||
- SaplingBlock.treeType = org.bukkit.TreeType.WARPED_FUNGUS;
|
||||
+ SaplingBlock.treeTypeRT.set(org.bukkit.TreeType.WARPED_FUNGUS); // SparklyPaper - parallel world ticking
|
||||
} else if (this == Blocks.CRIMSON_FUNGUS) {
|
||||
- SaplingBlock.treeType = org.bukkit.TreeType.CRIMSON_FUNGUS;
|
||||
+ SaplingBlock.treeTypeRT.set(org.bukkit.TreeType.CRIMSON_FUNGUS); // SparklyPaper - parallel world ticking
|
||||
}
|
||||
return value;
|
||||
})
|
||||
diff --git a/net/minecraft/world/level/block/MushroomBlock.java b/net/minecraft/world/level/block/MushroomBlock.java
|
||||
index 904369f4d7db41026183f2de7c96c2f0f4dc204d..1ef0cf368fe9de49c7ba0ba3b647108b5bbe3e48 100644
|
||||
--- a/net/minecraft/world/level/block/MushroomBlock.java
|
||||
+++ b/net/minecraft/world/level/block/MushroomBlock.java
|
||||
@@ -94,7 +94,7 @@ public class MushroomBlock extends BushBlock implements BonemealableBlock {
|
||||
return false;
|
||||
} else {
|
||||
level.removeBlock(pos, false);
|
||||
- SaplingBlock.treeType = (this == Blocks.BROWN_MUSHROOM) ? org.bukkit.TreeType.BROWN_MUSHROOM : org.bukkit.TreeType.RED_MUSHROOM; // CraftBukkit
|
||||
+ SaplingBlock.treeTypeRT.set((this == Blocks.BROWN_MUSHROOM) ? org.bukkit.TreeType.BROWN_MUSHROOM : org.bukkit.TreeType.RED_MUSHROOM); // CraftBukkit // SparklyPaper - parallel world ticking
|
||||
if (optional.get().value().place(level, level.getChunkSource().getGenerator(), random, pos)) {
|
||||
return true;
|
||||
} else {
|
||||
diff --git a/net/minecraft/world/level/block/RedStoneWireBlock.java b/net/minecraft/world/level/block/RedStoneWireBlock.java
|
||||
index 12c9d60314c99fb65e640d255a2d0c6b7790ad4d..833b180741cd361562d86794b16e3cd6a25410d5 100644
|
||||
--- a/net/minecraft/world/level/block/RedStoneWireBlock.java
|
||||
+++ b/net/minecraft/world/level/block/RedStoneWireBlock.java
|
||||
@@ -292,7 +292,7 @@ public class RedStoneWireBlock extends Block {
|
||||
|
||||
// Paper start - Optimize redstone (Eigencraft)
|
||||
// The bulk of the new functionality is found in RedstoneWireTurbo.java
|
||||
- io.papermc.paper.redstone.RedstoneWireTurbo turbo = new io.papermc.paper.redstone.RedstoneWireTurbo(this);
|
||||
+ // io.papermc.paper.redstone.RedstoneWireTurbo turbo = new io.papermc.paper.redstone.RedstoneWireTurbo(this); // SparklyPaper - parallel world ticking (moved to world)
|
||||
|
||||
/*
|
||||
* Modified version of pre-existing updateSurroundingRedstone, which is called from
|
||||
@@ -308,7 +308,7 @@ public class RedStoneWireBlock extends Block {
|
||||
if (orientation != null) {
|
||||
source = pos.relative(orientation.getFront().getOpposite());
|
||||
}
|
||||
- turbo.updateSurroundingRedstone(worldIn, pos, state, source);
|
||||
+ worldIn.turbo.updateSurroundingRedstone(worldIn, pos, state, source); // SparklyPaper - parallel world ticking
|
||||
return;
|
||||
}
|
||||
updatePowerStrength(worldIn, pos, state, orientation, blockAdded);
|
||||
@@ -336,7 +336,7 @@ public class RedStoneWireBlock extends Block {
|
||||
// [Space Walker] suppress shape updates and emit those manually to
|
||||
// bypass the new neighbor update stack.
|
||||
if (level.setBlock(pos, state, Block.UPDATE_KNOWN_SHAPE | Block.UPDATE_CLIENTS)) {
|
||||
- turbo.updateNeighborShapes(level, pos, state);
|
||||
+ level.turbo.updateNeighborShapes(level, pos, state); // SparklyPaper - parallel world ticking
|
||||
}
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/world/level/block/SaplingBlock.java b/net/minecraft/world/level/block/SaplingBlock.java
|
||||
index e014f052e9b0f5ca6b28044e2389782b7d0e0cb8..c9091b66f5ddf7bd7145becdfc5e252163b03300 100644
|
||||
--- a/net/minecraft/world/level/block/SaplingBlock.java
|
||||
+++ b/net/minecraft/world/level/block/SaplingBlock.java
|
||||
@@ -26,7 +26,7 @@ public class SaplingBlock extends BushBlock implements BonemealableBlock {
|
||||
protected static final float AABB_OFFSET = 6.0F;
|
||||
protected static final VoxelShape SHAPE = Block.box(2.0, 0.0, 2.0, 14.0, 12.0, 14.0);
|
||||
protected final TreeGrower treeGrower;
|
||||
- public static org.bukkit.TreeType treeType; // CraftBukkit
|
||||
+ public static final ThreadLocal<org.bukkit.TreeType> treeTypeRT = new ThreadLocal<>(); // CraftBukkit // SparklyPaper - parallel world ticking (from Folia)
|
||||
|
||||
@Override
|
||||
public MapCodec<? extends SaplingBlock> codec() {
|
||||
@@ -63,8 +63,8 @@ public class SaplingBlock extends BushBlock implements BonemealableBlock {
|
||||
this.treeGrower.growTree(level, level.getChunkSource().getGenerator(), pos, state, random);
|
||||
level.captureTreeGeneration = false;
|
||||
if (!level.capturedBlockStates.isEmpty()) {
|
||||
- org.bukkit.TreeType treeType = SaplingBlock.treeType;
|
||||
- SaplingBlock.treeType = null;
|
||||
+ org.bukkit.TreeType treeType = SaplingBlock.treeTypeRT.get(); // SparklyPaper - parallel world ticking
|
||||
+ SaplingBlock.treeTypeRT.set(null); // SparklyPaper - parallel world ticking
|
||||
org.bukkit.Location location = org.bukkit.craftbukkit.util.CraftLocation.toBukkit(pos, level.getWorld());
|
||||
java.util.List<org.bukkit.block.BlockState> blocks = new java.util.ArrayList<>(level.capturedBlockStates.values());
|
||||
level.capturedBlockStates.clear();
|
||||
diff --git a/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java b/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java
|
||||
index 26db603ed681a6c302596627d4dd5bf8a9bafc4e..a2df3546922ea27b948ed89450428a27f65d93ed 100644
|
||||
--- a/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java
|
||||
@@ -77,6 +77,12 @@ public abstract class BaseContainerBlockEntity extends BlockEntity implements Co
|
||||
return canUnlock(player, code, displayName, null);
|
||||
}
|
||||
public static boolean canUnlock(Player player, LockCode code, Component displayName, @Nullable BlockEntity blockEntity) {
|
||||
+ // SparklyPaper - parallel world ticking (see: PARALLEL_NOTES.md - Opening an inventory after a world switch)
|
||||
+ if (player instanceof net.minecraft.server.level.ServerPlayer serverPlayer && blockEntity != null && blockEntity.getLevel() != serverPlayer.serverLevel()) {
|
||||
+ net.minecraft.server.MinecraftServer.LOGGER.warn("Player " + serverPlayer.getScoreboardName() + " (" + serverPlayer.getStringUUID() + ") attempted to open a BlockEntity @ " + blockEntity.getLevel().getWorld().getName() + " " + blockEntity.getBlockPos().getX() + ", " + blockEntity.getBlockPos().getY() + ", " + blockEntity.getBlockPos().getZ() + " while they were in a different world " + serverPlayer.level().getWorld().getName() + " than the block themselves!");
|
||||
+ return false;
|
||||
+ }
|
||||
+ // SparklyPaper end
|
||||
if (player instanceof net.minecraft.server.level.ServerPlayer serverPlayer && blockEntity != null && blockEntity.getLevel() != null && blockEntity.getLevel().getBlockEntity(blockEntity.getBlockPos()) == blockEntity) {
|
||||
final org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(blockEntity.getLevel(), blockEntity.getBlockPos());
|
||||
net.kyori.adventure.text.Component lockedMessage = net.kyori.adventure.text.Component.translatable("container.isLocked", io.papermc.paper.adventure.PaperAdventure.asAdventure(displayName));
|
||||
diff --git a/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java b/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java
|
||||
index 1638eccef431fb68775af624110f1968f0c6dabd..a1096b17ddd4f02cdbe5615030803df88d200ed7 100644
|
||||
--- a/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java
|
||||
@@ -43,9 +43,9 @@ public class SculkCatalystBlockEntity extends BlockEntity implements GameEventLi
|
||||
// Paper end - Fix NPE in SculkBloomEvent world access
|
||||
|
||||
public static void serverTick(Level level, BlockPos pos, BlockState state, SculkCatalystBlockEntity sculkCatalyst) {
|
||||
- org.bukkit.craftbukkit.event.CraftEventFactory.sourceBlockOverride = sculkCatalyst.getBlockPos(); // CraftBukkit - SPIGOT-7068: Add source block override, not the most elegant way but better than passing down a BlockPosition up to five methods deep.
|
||||
+ org.bukkit.craftbukkit.event.CraftEventFactory.sourceBlockOverrideRT.set(pos); // SparklyPaper - parallel world ticking // CraftBukkit - SPIGOT-7068: Add source block override, not the most elegant way but better than passing down a BlockPosition up to five methods deep.
|
||||
sculkCatalyst.catalystListener.getSculkSpreader().updateCursors(level, pos, level.getRandom(), true);
|
||||
- org.bukkit.craftbukkit.event.CraftEventFactory.sourceBlockOverride = null; // CraftBukkit
|
||||
+ org.bukkit.craftbukkit.event.CraftEventFactory.sourceBlockOverrideRT.set(null); // SparklyPaper - parallel world ticking // CraftBukkit
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/net/minecraft/world/level/block/grower/TreeGrower.java b/net/minecraft/world/level/block/grower/TreeGrower.java
|
||||
index cf7311c507de09a8f89934e430b2201e8bdffe51..2ad658fa8e42f26a37fed9faff421827cb72607b 100644
|
||||
--- a/net/minecraft/world/level/block/grower/TreeGrower.java
|
||||
+++ b/net/minecraft/world/level/block/grower/TreeGrower.java
|
||||
@@ -204,55 +204,59 @@ public final class TreeGrower {
|
||||
// CraftBukkit start
|
||||
private void setTreeType(Holder<ConfiguredFeature<?, ?>> holder) {
|
||||
ResourceKey<ConfiguredFeature<?, ?>> treeFeature = holder.unwrapKey().get();
|
||||
+ // SparklyPaper start - parallel world ticking
|
||||
+ org.bukkit.TreeType treeType;
|
||||
if (treeFeature == TreeFeatures.OAK || treeFeature == TreeFeatures.OAK_BEES_005) {
|
||||
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.TREE;
|
||||
+ treeType = org.bukkit.TreeType.TREE;
|
||||
} else if (treeFeature == TreeFeatures.HUGE_RED_MUSHROOM) {
|
||||
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.RED_MUSHROOM;
|
||||
+ treeType = org.bukkit.TreeType.RED_MUSHROOM;
|
||||
} else if (treeFeature == TreeFeatures.HUGE_BROWN_MUSHROOM) {
|
||||
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.BROWN_MUSHROOM;
|
||||
+ treeType = org.bukkit.TreeType.BROWN_MUSHROOM;
|
||||
} else if (treeFeature == TreeFeatures.JUNGLE_TREE) {
|
||||
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.COCOA_TREE;
|
||||
+ treeType = org.bukkit.TreeType.COCOA_TREE;
|
||||
} else if (treeFeature == TreeFeatures.JUNGLE_TREE_NO_VINE) {
|
||||
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.SMALL_JUNGLE;
|
||||
+ treeType = org.bukkit.TreeType.SMALL_JUNGLE;
|
||||
} else if (treeFeature == TreeFeatures.PINE) {
|
||||
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.TALL_REDWOOD;
|
||||
+ treeType = org.bukkit.TreeType.TALL_REDWOOD;
|
||||
} else if (treeFeature == TreeFeatures.SPRUCE) {
|
||||
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.REDWOOD;
|
||||
+ treeType = org.bukkit.TreeType.REDWOOD;
|
||||
} else if (treeFeature == TreeFeatures.ACACIA) {
|
||||
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.ACACIA;
|
||||
+ treeType = org.bukkit.TreeType.ACACIA;
|
||||
} else if (treeFeature == TreeFeatures.BIRCH || treeFeature == TreeFeatures.BIRCH_BEES_005) {
|
||||
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.BIRCH;
|
||||
+ treeType = org.bukkit.TreeType.BIRCH;
|
||||
} else if (treeFeature == TreeFeatures.SUPER_BIRCH_BEES_0002) {
|
||||
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.TALL_BIRCH;
|
||||
+ treeType = org.bukkit.TreeType.TALL_BIRCH;
|
||||
} else if (treeFeature == TreeFeatures.SWAMP_OAK) {
|
||||
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.SWAMP;
|
||||
+ treeType = org.bukkit.TreeType.SWAMP;
|
||||
} else if (treeFeature == TreeFeatures.FANCY_OAK || treeFeature == TreeFeatures.FANCY_OAK_BEES_005) {
|
||||
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.BIG_TREE;
|
||||
+ treeType = org.bukkit.TreeType.BIG_TREE;
|
||||
} else if (treeFeature == TreeFeatures.JUNGLE_BUSH) {
|
||||
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.JUNGLE_BUSH;
|
||||
+ treeType = org.bukkit.TreeType.JUNGLE_BUSH;
|
||||
} else if (treeFeature == TreeFeatures.DARK_OAK) {
|
||||
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.DARK_OAK;
|
||||
+ treeType = org.bukkit.TreeType.DARK_OAK;
|
||||
} else if (treeFeature == TreeFeatures.MEGA_SPRUCE) {
|
||||
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.MEGA_REDWOOD;
|
||||
+ treeType = org.bukkit.TreeType.MEGA_REDWOOD;
|
||||
} else if (treeFeature == TreeFeatures.MEGA_PINE) {
|
||||
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.MEGA_PINE;
|
||||
+ treeType = org.bukkit.TreeType.MEGA_PINE;
|
||||
} else if (treeFeature == TreeFeatures.MEGA_JUNGLE_TREE) {
|
||||
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.JUNGLE;
|
||||
+ treeType = org.bukkit.TreeType.JUNGLE;
|
||||
} else if (treeFeature == TreeFeatures.AZALEA_TREE) {
|
||||
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.AZALEA;
|
||||
+ treeType = org.bukkit.TreeType.AZALEA;
|
||||
} else if (treeFeature == TreeFeatures.MANGROVE) {
|
||||
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.MANGROVE;
|
||||
+ treeType = org.bukkit.TreeType.MANGROVE;
|
||||
} else if (treeFeature == TreeFeatures.TALL_MANGROVE) {
|
||||
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.TALL_MANGROVE;
|
||||
+ treeType = org.bukkit.TreeType.TALL_MANGROVE;
|
||||
} else if (treeFeature == TreeFeatures.CHERRY || treeFeature == TreeFeatures.CHERRY_BEES_005) {
|
||||
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.CHERRY;
|
||||
+ treeType = org.bukkit.TreeType.CHERRY;
|
||||
} else if (treeFeature == TreeFeatures.PALE_OAK || treeFeature == TreeFeatures.PALE_OAK_BONEMEAL) {
|
||||
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.PALE_OAK;
|
||||
+ treeType = org.bukkit.TreeType.PALE_OAK;
|
||||
} else if (treeFeature == TreeFeatures.PALE_OAK_CREAKING) {
|
||||
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.PALE_OAK_CREAKING;
|
||||
+ treeType = org.bukkit.TreeType.PALE_OAK_CREAKING;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown tree generator " + treeFeature);
|
||||
}
|
||||
+ net.minecraft.world.level.block.SaplingBlock.treeTypeRT.set(treeType); // SparklyPaper - parallel world ticking
|
||||
+ // SparklyPaper end
|
||||
}
|
||||
// CraftBukkit end
|
||||
}
|
||||
diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
index 761fdcd4a4e18f45547afd8edff44f61c6eeacb4..17fb7161171cbe44d145cf0065826f49183880b0 100644
|
||||
--- a/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -360,6 +360,7 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p
|
||||
|
||||
@Nullable
|
||||
public BlockState setBlockState(BlockPos pos, BlockState state, boolean isMoving, boolean doPlace) {
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.level, pos, "Updating block asynchronously"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||
// CraftBukkit end
|
||||
int y = pos.getY();
|
||||
LevelChunkSection section = this.getSection(this.getSectionIndex(y));
|
||||
diff --git a/net/minecraft/world/level/entity/EntityTickList.java b/net/minecraft/world/level/entity/EntityTickList.java
|
||||
index 423779a2b690f387a4f0bd07b97b50e0baefda76..24f9632e73d73c2ad68ebf30eb0e4cca7befae2d 100644
|
||||
--- a/net/minecraft/world/level/entity/EntityTickList.java
|
||||
+++ b/net/minecraft/world/level/entity/EntityTickList.java
|
||||
@@ -10,17 +10,26 @@ import net.minecraft.world.entity.Entity;
|
||||
|
||||
public class EntityTickList {
|
||||
private final ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet<net.minecraft.world.entity.Entity> entities = new ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet<>(); // Paper - rewrite chunk system
|
||||
+ // SparklyPaper start - parallel world ticking
|
||||
+ // Used to track async entity additions/removals/loops
|
||||
+ private final net.minecraft.server.level.ServerLevel serverLevel;
|
||||
+ public EntityTickList(net.minecraft.server.level.ServerLevel serverLevel) {
|
||||
+ this.serverLevel = serverLevel;
|
||||
+ }
|
||||
+ // SparklyPaper end
|
||||
|
||||
private void ensureActiveIsNotIterated() {
|
||||
// Paper - rewrite chunk system
|
||||
}
|
||||
|
||||
public void add(Entity entity) {
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(entity, "Asynchronous entity ticklist addition"); // Paper // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||
this.ensureActiveIsNotIterated();
|
||||
this.entities.add(entity); // Paper - rewrite chunk system
|
||||
}
|
||||
|
||||
public void remove(Entity entity) {
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(entity, "Asynchronous entity ticklist removal"); // Paper // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||
this.ensureActiveIsNotIterated();
|
||||
this.entities.remove(entity); // Paper - rewrite chunk system
|
||||
}
|
||||
@@ -30,6 +39,7 @@ public class EntityTickList {
|
||||
}
|
||||
|
||||
public void forEach(Consumer<Entity> entity) {
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverLevel, "Asynchronous entity ticklist iteration"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||
// Paper start - rewrite chunk system
|
||||
// To ensure nothing weird happens with dimension travelling, do not iterate over new entries...
|
||||
// (by dfl iterator() is configured to not iterate over new entries)
|
||||
diff --git a/net/minecraft/world/level/saveddata/maps/MapIndex.java b/net/minecraft/world/level/saveddata/maps/MapIndex.java
|
||||
index ffe604f8397a002800e6ecc2f878d0f6f1c98703..ee022449c1e00a106687496a1dfb98fc0d86fb72 100644
|
||||
--- a/net/minecraft/world/level/saveddata/maps/MapIndex.java
|
||||
+++ b/net/minecraft/world/level/saveddata/maps/MapIndex.java
|
||||
@@ -34,17 +34,20 @@ public class MapIndex extends SavedData {
|
||||
|
||||
@Override
|
||||
public CompoundTag save(CompoundTag tag, HolderLookup.Provider registries) {
|
||||
+ synchronized (this.usedAuxIds) { // SparklyPaper start - make map data thread-safe
|
||||
for (Entry<String> entry : this.usedAuxIds.object2IntEntrySet()) {
|
||||
tag.putInt(entry.getKey(), entry.getIntValue());
|
||||
}
|
||||
-
|
||||
+ } // SparklyPaper end - make map data thread-safe
|
||||
return tag;
|
||||
}
|
||||
|
||||
public MapId getFreeAuxValueForMap() {
|
||||
+ synchronized (this.usedAuxIds) { // SparklyPaper start - make map data thread-safe
|
||||
int i = this.usedAuxIds.getInt("map") + 1;
|
||||
this.usedAuxIds.put("map", i);
|
||||
this.setDirty();
|
||||
return new MapId(i);
|
||||
+ } // SparklyPaper end - make map data thread-safe
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||
Date: Sat, 1 Jun 2024 01:22:41 -0300
|
||||
Subject: [PATCH] SPARKLYPOWER Remap SparklyPower hacky legacy NBT tags
|
||||
|
||||
This is only useful for us in SparklyPower, but yeah...
|
||||
|
||||
diff --git a/ca/spottedleaf/dataconverter/minecraft/converters/itemstack/ConverterItemStackToDataComponents.java b/ca/spottedleaf/dataconverter/minecraft/converters/itemstack/ConverterItemStackToDataComponents.java
|
||||
index 2d29d89cc45866822189a62bffbe1a8fe57c477b..688230454b42fd7da72833ca8fe631e6fba06eb9 100644
|
||||
--- a/ca/spottedleaf/dataconverter/minecraft/converters/itemstack/ConverterItemStackToDataComponents.java
|
||||
+++ b/ca/spottedleaf/dataconverter/minecraft/converters/itemstack/ConverterItemStackToDataComponents.java
|
||||
@@ -1221,6 +1221,7 @@ public final class ConverterItemStackToDataComponents {
|
||||
ret.setString("id", this.id);
|
||||
ret.setInt("count", this.count);
|
||||
if (!this.tag.isEmpty()) {
|
||||
+ net.sparklypower.sparklypaper.LegacyNBTRemapper.INSTANCE.remap(this.tag); // SparklyPaper - Remap SparklyPower hacky legacy NBT tags
|
||||
this.components.setMap("minecraft:custom_data", this.tag);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||
Date: Wed, 12 Jun 2024 11:53:09 -0300
|
||||
Subject: [PATCH] SPARKLYPOWER Add custom blocks
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/level/block/Blocks.java b/net/minecraft/world/level/block/Blocks.java
|
||||
index 0401a5e88fe7840ae667748409411ab73888799c..d83e8b92b77f6b8179b24f07eae528dda5f12ed2 100644
|
||||
--- a/net/minecraft/world/level/block/Blocks.java
|
||||
+++ b/net/minecraft/world/level/block/Blocks.java
|
||||
@@ -6775,6 +6775,52 @@ public class Blocks {
|
||||
public static final Block POTTED_CLOSED_EYEBLOSSOM = register(
|
||||
"potted_closed_eyeblossom", properties -> new FlowerPotBlock(CLOSED_EYEBLOSSOM, properties), flowerPotProperties().randomTicks()
|
||||
);
|
||||
+ // SparklyPaper start - SparklyPower Survival custom blocks
|
||||
+ // Blocks' strength should be synced with the replaced block on the client side!
|
||||
+ public static final Block SPARKLYPOWER_RAINBOW_WOOL = register(
|
||||
+ "sparklypower_rainbow_wool",
|
||||
+ Block::new,
|
||||
+ BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_RED).strength(0.5F).sound(SoundType.GRASS)
|
||||
+ );
|
||||
+ public static final Block SPARKLYPOWER_RAINBOW_CONCRETE = register(
|
||||
+ "sparklypower_rainbow_concrete",
|
||||
+ Block::new,
|
||||
+ BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_RED).strength(0.5F).sound(SoundType.GRASS)
|
||||
+ );
|
||||
+ public static final Block SPARKLYPOWER_RAINBOW_TERRACOTTA = register(
|
||||
+ "sparklypower_rainbow_terracotta",
|
||||
+ Block::new,
|
||||
+ BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_RED).strength(0.5F).sound(SoundType.GRASS)
|
||||
+ );
|
||||
+ public static final Block SPARKLYPOWER_ASPHALT_SERVER = register(
|
||||
+ "sparklypower_asphalt_server",
|
||||
+ Block::new,
|
||||
+ BlockBehaviour.Properties.of()
|
||||
+ .mapColor(MapColor.COLOR_BLACK)
|
||||
+ .instrument(NoteBlockInstrument.BASEDRUM)
|
||||
+ .requiresCorrectToolForDrops()
|
||||
+ .strength(1.5F, 6.0F)
|
||||
+ );
|
||||
+ public static final Block SPARKLYPOWER_ASPHALT_SERVER_SLAB = register(
|
||||
+ "sparklypower_asphalt_server_slab",
|
||||
+ SlabBlock::new,
|
||||
+ BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_BLACK).instrument(NoteBlockInstrument.BASEDRUM).requiresCorrectToolForDrops().strength(2.0F, 6.0F)
|
||||
+ );
|
||||
+ public static final Block SPARKLYPOWER_ASPHALT_PLAYER = register(
|
||||
+ "sparklypower_asphalt_player",
|
||||
+ Block::new,
|
||||
+ BlockBehaviour.Properties.of()
|
||||
+ .mapColor(MapColor.COLOR_BLACK)
|
||||
+ .instrument(NoteBlockInstrument.BASEDRUM)
|
||||
+ .requiresCorrectToolForDrops()
|
||||
+ .strength(1.5F, 6.0F)
|
||||
+ );
|
||||
+ public static final Block SPARKLYPOWER_ASPHALT_PLAYER_SLAB = register(
|
||||
+ "sparklypower_asphalt_player_slab",
|
||||
+ SlabBlock::new,
|
||||
+ BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_BLACK).instrument(NoteBlockInstrument.BASEDRUM).requiresCorrectToolForDrops().strength(2.0F, 6.0F)
|
||||
+ );
|
||||
+ // SparklyPaper end
|
||||
|
||||
private static ToIntFunction<BlockState> litBlockEmission(int lightValue) {
|
||||
return state -> state.getValue(BlockStateProperties.LIT) ? lightValue : 0;
|
||||
@@ -0,0 +1,50 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||
Date: Sat, 12 Jun 2021 16:40:34 +0200
|
||||
Subject: [PATCH] new fork who dis - Rebrand to SparklyPaper and Build Changes
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java
|
||||
index 774556a62eb240da42e84db4502e2ed43495be17..9bc7b99b5b39a8ffe4118b8d86f5b8065c4fe460 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/net.sparklypower.sparklypaper/sparklypaper-api/pom.properties"); // SparklyPaper
|
||||
Properties properties = new Properties();
|
||||
|
||||
if (stream != null) {
|
||||
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
index a9339f59f81dff307317ae4afdff0dc296febcc9..2ce97bee092dd7a6d898836376c442b114d54003 100644
|
||||
--- a/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
@@ -77,14 +77,14 @@ public class WatchdogThread extends Thread {
|
||||
if (isLongTimeout) {
|
||||
// Paper end
|
||||
logger.log(Level.SEVERE, "------------------------------");
|
||||
- logger.log(Level.SEVERE, "The server has stopped responding! This is (probably) not a Paper bug."); // Paper
|
||||
+ logger.log(Level.SEVERE, "The server has stopped responding! This is (probably) not a Paper bug. This could be a SparklyPaper bug and, in that case, MrPowerGamerBR probably made a fucky wucky!"); // SparklyPaper - branding changes // Paper
|
||||
logger.log(Level.SEVERE, "If you see a plugin in the Server thread dump below, then please report it to that author");
|
||||
logger.log(Level.SEVERE, "\t *Especially* if it looks like HTTP or MySQL operations are occurring");
|
||||
logger.log(Level.SEVERE, "If you see a world save or edit, then it means you did far more than your server can handle at once");
|
||||
logger.log(Level.SEVERE, "\t If this is the case, consider increasing timeout-time in spigot.yml but note that this will replace the crash with LARGE lag spikes");
|
||||
- logger.log(Level.SEVERE, "If you are unsure or still think this is a Paper bug, please report this to https://github.com/PaperMC/Paper/issues");
|
||||
+ logger.log(Level.SEVERE, "If you are unsure or still think this is a SparklyPaper bug, please report this to https://github.com/SparklyPower/SparklyPaper/issues - and if you think this is a Paper bug, please report this to https://github.com/PaperMC/Paper/issues\""); // SparklyPaper - branding changes
|
||||
logger.log(Level.SEVERE, "Be sure to include ALL relevant console errors and Minecraft crash reports");
|
||||
- logger.log(Level.SEVERE, "Paper version: " + Bukkit.getServer().getVersion());
|
||||
+ logger.log(Level.SEVERE, "SparklyPaper version: " + Bukkit.getServer().getVersion()); // SparklyPaper - branding changes
|
||||
|
||||
if (net.minecraft.world.level.Level.lastPhysicsProblem != null) {
|
||||
logger.log(Level.SEVERE, "------------------------------");
|
||||
@@ -109,7 +109,7 @@ public class WatchdogThread extends Thread {
|
||||
}
|
||||
// Paper end - Different message for short timeout
|
||||
logger.log(Level.SEVERE, "------------------------------");
|
||||
- logger.log(Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):"); // Paper
|
||||
+ logger.log(Level.SEVERE, "Server thread dump (Look for plugins here before reporting to SparklyPaper!):"); // SparklyPaper - branding changes // Paper
|
||||
FeatureHooks.dumpAllChunkLoadInfo(MinecraftServer.getServer(), isLongTimeout); // Paper - log detailed tick information
|
||||
WatchdogThread.dumpThread(ManagementFactory.getThreadMXBean().getThreadInfo(MinecraftServer.getServer().serverThread.getId(), Integer.MAX_VALUE), logger);
|
||||
logger.log(Level.SEVERE, "------------------------------");
|
||||
@@ -0,0 +1,61 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||
Date: Mon, 13 Jan 2025 13:20:49 -0300
|
||||
Subject: [PATCH] SparklyPaper config files
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index d2de789967f8f1942e91d9e4c547113a5e31382b..6f3add0ee20978d84fba844955eefe5fdad71af8 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -111,6 +111,7 @@ import net.minecraft.world.level.storage.PlayerDataStorage;
|
||||
import net.minecraft.world.level.storage.PrimaryLevelData;
|
||||
import net.minecraft.world.level.validation.ContentValidationException;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
+import net.sparklypower.sparklypaper.configs.SparklyPaperConfigUtils;
|
||||
import org.bukkit.BanList;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
@@ -1087,6 +1088,7 @@ public final class CraftServer implements Server {
|
||||
|
||||
org.spigotmc.SpigotConfig.init((File) this.console.options.valueOf("spigot-settings")); // Spigot
|
||||
this.console.paperConfigurations.reloadConfigs(this.console);
|
||||
+ net.sparklypower.sparklypaper.configs.SparklyPaperConfigUtils.INSTANCE.init((File) console.options.valueOf("sparklypaper-settings")); // SparklyPaper
|
||||
for (ServerLevel world : this.console.getAllLevels()) {
|
||||
// world.serverLevelData.setDifficulty(config.difficulty); // Paper - per level difficulty
|
||||
world.setSpawnSettings(world.serverLevelData.getDifficulty() != Difficulty.PEACEFUL && config.spawnMonsters); // Paper - per level difficulty (from MinecraftServer#setDifficulty(ServerLevel, Difficulty, boolean))
|
||||
@@ -1102,6 +1104,7 @@ public final class CraftServer implements Server {
|
||||
}
|
||||
}
|
||||
world.spigotConfig.init(); // Spigot
|
||||
+ world.sparklyPaperConfig = SparklyPaperConfigUtils.INSTANCE.getWorldSettings(world.serverLevelData.getLevelName()); // SparklyPaper
|
||||
}
|
||||
|
||||
Plugin[] pluginClone = pluginManager.getPlugins().clone(); // Paper
|
||||
@@ -1119,6 +1122,7 @@ public final class CraftServer implements Server {
|
||||
org.spigotmc.SpigotConfig.registerCommands(); // Spigot
|
||||
io.papermc.paper.command.PaperCommands.registerCommands(this.console); // Paper
|
||||
this.spark.registerCommandBeforePlugins(this); // Paper - spark
|
||||
+ net.sparklypower.sparklypaper.SparklyPaperCommands.INSTANCE.registerCommands(this.console); // SparklyPaper
|
||||
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 ecb0fcd1f3b3f3d7751eded3cdf0977c1889c9ed..10f84fb104adc6e8cf57f12e9388398e32711f4a 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
@@ -176,6 +176,14 @@ public class Main {
|
||||
.describedAs("Jar file");
|
||||
// Paper end
|
||||
|
||||
+ // SparklyPaper Start
|
||||
+ acceptsAll(asList("sparklypaper", "sparklypaper-settings"), "File for SparklyPaper settings")
|
||||
+ .withRequiredArg()
|
||||
+ .ofType(File.class)
|
||||
+ .defaultsTo(new File("sparklypaper.yml"))
|
||||
+ .describedAs("Yml file");
|
||||
+ // SparklyPaper end
|
||||
+
|
||||
// Paper start
|
||||
acceptsAll(asList("server-name"), "Name of the server")
|
||||
.withRequiredArg()
|
||||
@@ -0,0 +1,19 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||
Date: Mon, 13 Jan 2025 14:27:53 -0300
|
||||
Subject: [PATCH] Fix concurrency issues when using imageToBytes
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/map/CraftMapColorCache.java b/src/main/java/org/bukkit/craftbukkit/map/CraftMapColorCache.java
|
||||
index 8149b9c51b78eb5c689b7218a2ca3aab60e73bcf..c983d8d7e79d55c9757add8ac1093a0a9d98e5b3 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/map/CraftMapColorCache.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/map/CraftMapColorCache.java
|
||||
@@ -145,7 +145,7 @@ public class CraftMapColorCache implements MapPalette.MapColorCache {
|
||||
}
|
||||
|
||||
@Override
|
||||
- public boolean isCached() {
|
||||
+ public synchronized boolean isCached() { // SparklyPaper - fix concurrency issues when using "imageToBytes" in multiple threads
|
||||
return this.cached || (!this.running.get() && this.initCache().isDone());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||
Date: Sun, 19 Nov 2023 12:35:16 -0300
|
||||
Subject: [PATCH] Skip EntityScheduler's executeTick checks if there isn't any
|
||||
tasks to be run
|
||||
|
||||
On each tick, Paper runs EntityScheduler's executeTick of each entity. This is a bit expensive, due to ArrayDeque's size() call because it ain't a simple "get the current queue size" function, due to the thread checks, and because it needs to iterate all entities in all worlds.
|
||||
|
||||
To avoid the hefty ArrayDeque's size() call, we check if we *really* need to execute the executeTick, by adding all entities with scheduled tasks to a global set.
|
||||
|
||||
Most entities won't have any scheduled tasks, so this is a nice performance bonus. These optimizations, however, wouldn't work in a Folia environment, but because in SparklyPaper executeTick is always executed on the main thread, it ain't an issue for us (yay).
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/threadedregions/EntityScheduler.java b/src/main/java/io/papermc/paper/threadedregions/EntityScheduler.java
|
||||
index c03608fec96b51e1867f43d8f42e5aefb1520e46..15b21fa3907db1b77ed5b5d1050a37f42d27d5ab 100644
|
||||
--- a/src/main/java/io/papermc/paper/threadedregions/EntityScheduler.java
|
||||
+++ b/src/main/java/io/papermc/paper/threadedregions/EntityScheduler.java
|
||||
@@ -36,6 +36,7 @@ public final class EntityScheduler {
|
||||
* The Entity. Note that it is the CraftEntity, since only that class properly tracks world transfers.
|
||||
*/
|
||||
public final CraftEntity entity;
|
||||
+ public final net.minecraft.server.MinecraftServer server; // SparklyPaper - skip EntityScheduler's executeTick checks if there isn't any tasks to be run
|
||||
|
||||
private static final record ScheduledTask(Consumer<? extends Entity> run, Consumer<? extends Entity> retired) {}
|
||||
|
||||
@@ -46,7 +47,8 @@ public final class EntityScheduler {
|
||||
|
||||
private final ArrayDeque<ScheduledTask> currentlyExecuting = new ArrayDeque<>();
|
||||
|
||||
- public EntityScheduler(final CraftEntity entity) {
|
||||
+ public EntityScheduler(final net.minecraft.server.MinecraftServer server, final CraftEntity entity) { // SparklyPaper - skip EntityScheduler's executeTick checks if there isn't any tasks to be run
|
||||
+ this.server = Validate.notNull(server);
|
||||
this.entity = Validate.notNull(entity);
|
||||
}
|
||||
|
||||
@@ -61,14 +63,16 @@ public final class EntityScheduler {
|
||||
* @throws IllegalStateException If the scheduler is already retired.
|
||||
*/
|
||||
public void retire() {
|
||||
+ final Entity thisEntity = this.entity.getHandleRaw(); // SparklyPaper - skip EntityScheduler's executeTick checks if there isn't any tasks to be run
|
||||
synchronized (this.stateLock) {
|
||||
if (this.tickCount == RETIRED_TICK_COUNT) {
|
||||
throw new IllegalStateException("Already retired");
|
||||
}
|
||||
this.tickCount = RETIRED_TICK_COUNT;
|
||||
+ this.server.entitiesWithScheduledTasks.remove(thisEntity); // SparklyPaper - skip EntityScheduler's executeTick checks if there isn't any tasks to be run
|
||||
}
|
||||
|
||||
- final Entity thisEntity = this.entity.getHandleRaw();
|
||||
+ // final Entity thisEntity = this.entity.getHandleRaw(); // SparklyPaper - skip EntityScheduler's executeTick checks if there isn't any tasks to be run (moved up)
|
||||
|
||||
// correctly handle and order retiring while running executeTick
|
||||
for (int i = 0, len = this.currentlyExecuting.size(); i < len; ++i) {
|
||||
@@ -124,6 +128,7 @@ public final class EntityScheduler {
|
||||
if (this.tickCount == RETIRED_TICK_COUNT) {
|
||||
return false;
|
||||
}
|
||||
+ this.server.entitiesWithScheduledTasks.add(this.entity.getHandleRaw()); // SparklyPaper - skip EntityScheduler's executeTick checks if there isn't any tasks to be run
|
||||
this.oneTimeDelayed.computeIfAbsent(this.tickCount + Math.max(1L, delay), (final long keyInMap) -> {
|
||||
return new ArrayList<>();
|
||||
}).add(task);
|
||||
@@ -143,6 +148,13 @@ public final class EntityScheduler {
|
||||
TickThread.ensureTickThread(thisEntity, "May not tick entity scheduler asynchronously");
|
||||
final List<ScheduledTask> toRun;
|
||||
synchronized (this.stateLock) {
|
||||
+ // SparklyPaper start - skip EntityScheduler's executeTick checks if there isn't any tasks to be run
|
||||
+ // Do we *really* have scheduled tasks tho?
|
||||
+ if (this.currentlyExecuting.isEmpty() && this.oneTimeDelayed.isEmpty()) { // Check if we have any pending tasks and, if not, skip!
|
||||
+ this.server.entitiesWithScheduledTasks.remove(thisEntity); // We don't! Bye bye!!
|
||||
+ return;
|
||||
+ }
|
||||
+ // SparklyPaper end
|
||||
if (this.tickCount == RETIRED_TICK_COUNT) {
|
||||
throw new IllegalStateException("Ticking retired scheduler");
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
index 4562bee2e2795801862bae03d783799fc076b73e..7107acb0a4ad4c84f78185bb8da2db8506c352d1 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
@@ -74,7 +74,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
||||
private final CraftPersistentDataContainer persistentDataContainer = new CraftPersistentDataContainer(CraftEntity.DATA_TYPE_REGISTRY);
|
||||
protected net.kyori.adventure.pointer.Pointers adventure$pointers; // Paper - implement pointers
|
||||
// Paper start - Folia shedulers
|
||||
- public final io.papermc.paper.threadedregions.EntityScheduler taskScheduler = new io.papermc.paper.threadedregions.EntityScheduler(this);
|
||||
+ public final io.papermc.paper.threadedregions.EntityScheduler taskScheduler; // = new io.papermc.paper.threadedregions.EntityScheduler(this); // SparklyPaper - skip EntityScheduler's executeTick checks if there isn't any tasks to be run
|
||||
private final io.papermc.paper.threadedregions.scheduler.FoliaEntityScheduler apiScheduler = new io.papermc.paper.threadedregions.scheduler.FoliaEntityScheduler(this);
|
||||
|
||||
@Override
|
||||
@@ -87,6 +87,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
||||
this.server = server;
|
||||
this.entity = entity;
|
||||
this.entityType = CraftEntityType.minecraftToBukkit(entity.getType());
|
||||
+ this.taskScheduler = new io.papermc.paper.threadedregions.EntityScheduler(this.entity.getServer(), this); // SparklyPaper - skip EntityScheduler's executeTick checks if there isn't any tasks to be run
|
||||
}
|
||||
|
||||
public static <T extends Entity> CraftEntity getEntity(CraftServer server, T entity) {
|
||||
@@ -0,0 +1,37 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||
Date: Mon, 13 Jan 2025 15:04:15 -0300
|
||||
Subject: [PATCH] Optimize canSee checks
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
index 98fc89cc7a715d35b62e13f8ecbe56c05605ca64..330e68e79f2201a5107c007d96ebd845bfa3caed 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -207,7 +207,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
private boolean hasPlayedBefore = false;
|
||||
private final ConversationTracker conversationTracker = new ConversationTracker();
|
||||
private final Set<String> channels = new HashSet<String>();
|
||||
- private final Map<UUID, Set<WeakReference<Plugin>>> invertedVisibilityEntities = new HashMap<>();
|
||||
+ private final Map<UUID, Set<WeakReference<Plugin>>> invertedVisibilityEntities = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(); // SparklyPaper - optimize canSee checks
|
||||
private final Set<UUID> unlistedEntities = new HashSet<>(); // Paper - Add Listing API for Player
|
||||
private static final WeakHashMap<Plugin, WeakReference<Plugin>> pluginWeakReferences = new WeakHashMap<>();
|
||||
private int hash = 0;
|
||||
@@ -2255,9 +2255,16 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
|
||||
@Override
|
||||
public boolean canSee(org.bukkit.entity.Entity entity) {
|
||||
- return this.equals(entity) || entity.isVisibleByDefault() ^ this.invertedVisibilityEntities.containsKey(entity.getUniqueId()); // SPIGOT-7312: Can always see self
|
||||
+ return this.equals(entity) || entity.isVisibleByDefault() ^ (!invertedVisibilityEntities.isEmpty() && this.invertedVisibilityEntities.containsKey(entity.getUniqueId())); // SPIGOT-7312: Can always see self // SparklyPaper - optimize canSee checks
|
||||
}
|
||||
|
||||
+ // SparklyPaper - optimize canSee checks
|
||||
+ // The check in ChunkMap#updatePlayer already rejects if it is the same entity, so we don't need to check it twice, especially because CraftPlayer's equals check is a bit expensive
|
||||
+ public boolean canSeeChunkMapUpdatePlayer(org.bukkit.entity.Entity entity) {
|
||||
+ return entity.isVisibleByDefault() ^ (!invertedVisibilityEntities.isEmpty() && this.invertedVisibilityEntities.containsKey(entity.getUniqueId())); // SPIGOT-7312: Can always see self // SparklyPaper - optimize canSee checks
|
||||
+ }
|
||||
+ // SparklyPaper end
|
||||
+
|
||||
public boolean canSeePlayer(UUID uuid) {
|
||||
org.bukkit.entity.Entity entity = this.getServer().getPlayer(uuid);
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||
Date: Mon, 6 Nov 2023 21:54:33 -0300
|
||||
Subject: [PATCH] Track how much MSPT each world used
|
||||
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/command/MSPTCommand.java b/src/main/java/io/papermc/paper/command/MSPTCommand.java
|
||||
index 8b5293b0c696ef21d0101493ffa41b60bf0bc86b..601198a33adb29316b0617d5390d1620b7c1095c 100644
|
||||
--- a/src/main/java/io/papermc/paper/command/MSPTCommand.java
|
||||
+++ b/src/main/java/io/papermc/paper/command/MSPTCommand.java
|
||||
@@ -78,6 +78,46 @@ public final class MSPTCommand extends Command {
|
||||
)
|
||||
)
|
||||
);
|
||||
+
|
||||
+ // SparklyPaper start - track world's MSPT
|
||||
+ sender.sendMessage(text());
|
||||
+ sender.sendMessage(text().content("World tick times ").color(GOLD)
|
||||
+ .append(text().color(YELLOW)
|
||||
+ .append(
|
||||
+ text("("),
|
||||
+ text("avg", GRAY),
|
||||
+ text("/"),
|
||||
+ text("min", GRAY),
|
||||
+ text("/"),
|
||||
+ text("max", GRAY),
|
||||
+ text(")")
|
||||
+ )
|
||||
+ ).append(
|
||||
+ text(" from last 5s"),
|
||||
+ text(",", GRAY),
|
||||
+ text(" 10s"),
|
||||
+ text(",", GRAY),
|
||||
+ text(" 1m"),
|
||||
+ text(":", YELLOW)
|
||||
+ )
|
||||
+ );
|
||||
+ for (net.minecraft.server.level.ServerLevel serverLevel : server.getAllLevels()) {
|
||||
+ List<Component> worldTimes = new ArrayList<>();
|
||||
+ worldTimes.addAll(eval(serverLevel.tickTimes5s.getTimes()));
|
||||
+ worldTimes.addAll(eval(serverLevel.tickTimes10s.getTimes()));
|
||||
+ worldTimes.addAll(eval(serverLevel.tickTimes60s.getTimes()));
|
||||
+
|
||||
+ sender.sendMessage(text().content("◴ " + serverLevel.getWorld().getName() + ": ").color(GOLD)
|
||||
+ .append(text().color(GRAY)
|
||||
+ .append(
|
||||
+ worldTimes.get(0), SLASH, worldTimes.get(1), SLASH, worldTimes.get(2), text(", ", YELLOW),
|
||||
+ worldTimes.get(3), SLASH, worldTimes.get(4), SLASH, worldTimes.get(5), text(", ", YELLOW),
|
||||
+ worldTimes.get(6), SLASH, worldTimes.get(7), SLASH, worldTimes.get(8)
|
||||
+ )
|
||||
+ )
|
||||
+ );
|
||||
+ }
|
||||
+ // SparklyPaper end
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||
Date: Tue, 25 Jun 2024 02:52:32 -0300
|
||||
Subject: [PATCH] Add CraftItemRecipeEvent
|
||||
|
||||
Used when a player OR a crafter block crafts an item, as an alternative to PrepareItemCraftEvent and CraftItemEvent, because both events are not triggered when a item is crafted from a crafter
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
index d7a52220e9525502163f5ee6afbadf2baaae6190..bbd000e3a3e9112e10a09e5d3ef6851b28e900fa 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
@@ -1472,6 +1472,24 @@ public class CraftEventFactory {
|
||||
Bukkit.getPluginManager().callEvent(crafterCraftEvent);
|
||||
return crafterCraftEvent;
|
||||
}
|
||||
+
|
||||
+ // SparklyPaper start - add CraftItemRecipeEvent
|
||||
+ public static net.sparklypower.sparklypaper.event.inventory.CraftItemRecipeEvent callCraftItemRecipeEvent(net.minecraft.world.inventory.CraftingContainer container, Recipe recipe, ItemStack result) {
|
||||
+ org.bukkit.inventory.ItemStack[] matrix = new org.bukkit.inventory.ItemStack[container.getItems().size()];
|
||||
+ int i = 0;
|
||||
+ for (ItemStack item : container.getItems()) {
|
||||
+ matrix[i] = CraftItemStack.asCraftMirror(item);
|
||||
+ i++;
|
||||
+ }
|
||||
+ org.bukkit.inventory.ItemStack bukkitResult = CraftItemStack.asCraftMirror(result);
|
||||
+
|
||||
+ net.sparklypower.sparklypaper.event.inventory.CraftItemRecipeEvent event = new net.sparklypower.sparklypaper.event.inventory.CraftItemRecipeEvent(matrix, recipe, bukkitResult);
|
||||
+ Bukkit.getPluginManager().callEvent(event);
|
||||
+
|
||||
+ return event;
|
||||
+ }
|
||||
+ // SparklyPaper end
|
||||
+
|
||||
// Paper start
|
||||
@Deprecated
|
||||
public static com.destroystokyo.paper.event.entity.ProjectileCollideEvent callProjectileCollideEvent(Entity entity, EntityHitResult position) {
|
||||
@@ -0,0 +1,37 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||
Date: Fri, 21 Jun 2024 18:07:25 -0300
|
||||
Subject: [PATCH] Allow item version downgrades
|
||||
|
||||
The server WON'T convert the item data from a newer version to an older version, so proceed with caution
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
index bd8005cd3a52532f4cb2e123da473f1490b59dbb..2d23110b61024847c8ed554ac5652982a35dd74b 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
@@ -85,6 +85,7 @@ import org.bukkit.potion.PotionType;
|
||||
public final class CraftMagicNumbers implements UnsafeValues {
|
||||
public static final CraftMagicNumbers INSTANCE = new CraftMagicNumbers();
|
||||
public static final boolean DISABLE_OLD_API_SUPPORT = Boolean.getBoolean("paper.disableOldApiSupport"); // Paper
|
||||
+ private static final boolean JUST_CORRUPT_IT = Boolean.getBoolean("sparklypaper.ignoreItemDataVersion"); // SparklyPaper - allow item downgrades
|
||||
|
||||
private final Commodore commodore = new Commodore();
|
||||
|
||||
@@ -246,7 +247,7 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
||||
@Override
|
||||
public Material getMaterial(String material, int version) {
|
||||
Preconditions.checkArgument(material != null, "material == null");
|
||||
- Preconditions.checkArgument(version <= this.getDataVersion(), "Newer version! Server downgrades are not supported!");
|
||||
+ Preconditions.checkArgument(JUST_CORRUPT_IT || version <= this.getDataVersion(), "Newer version! Server downgrades are not supported!"); // SparklyPaper - allow item downgrades
|
||||
|
||||
// Fastpath up to date materials
|
||||
if (version == this.getDataVersion()) {
|
||||
@@ -676,7 +677,7 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
int dataVersion = compound.getInt("DataVersion");
|
||||
- Preconditions.checkArgument(dataVersion <= getDataVersion(), "Newer version! Server downgrades are not supported!");
|
||||
+ Preconditions.checkArgument(JUST_CORRUPT_IT || dataVersion <= getDataVersion(), "Newer version! Server downgrades are not supported!"); // SparklyPaper - allow item downgrades
|
||||
return compound;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,627 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||
Date: Tue, 7 Nov 2023 01:34:14 -0300
|
||||
Subject: [PATCH] Parallel world ticking
|
||||
|
||||
"mom can we have folia?" "we already have folia at home" folia at home:
|
||||
|
||||
diff --git a/src/main/java/ca/spottedleaf/moonrise/common/util/TickThread.java b/src/main/java/ca/spottedleaf/moonrise/common/util/TickThread.java
|
||||
index 157e5edb507d6d2a922833c70a1c27abc93c9c34..f47b49b02f664725d310887e65477deb07414bde 100644
|
||||
--- a/src/main/java/ca/spottedleaf/moonrise/common/util/TickThread.java
|
||||
+++ b/src/main/java/ca/spottedleaf/moonrise/common/util/TickThread.java
|
||||
@@ -14,6 +14,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
public class TickThread extends Thread {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(TickThread.class);
|
||||
+ public static final boolean HARD_THROW = !Boolean.getBoolean("sparklypaper.disableHardThrow"); // SparklyPaper - parallel world ticking - THIS SHOULD NOT BE DISABLED SINCE IT CAN CAUSE DATA CORRUPTION!!! Anyhow, for production servers, if you want to make a test run to see if the server could crash, you can test it with this disabled
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
@@ -22,14 +23,15 @@ public class TickThread extends Thread {
|
||||
public static void ensureTickThread(final String reason) {
|
||||
if (!isTickThread()) {
|
||||
LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread check: " + reason, new Throwable());
|
||||
- throw new IllegalStateException(reason);
|
||||
+ if (HARD_THROW)
|
||||
+ throw new IllegalStateException(reason);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ensureTickThread(final Level world, final BlockPos pos, final String reason) {
|
||||
if (!isTickThreadFor(world, pos)) {
|
||||
final String ex = "Thread " + Thread.currentThread().getName() + " failed main thread check: " +
|
||||
- reason + ", world=" + WorldUtil.getWorldName(world) + ", block_pos=" + pos;
|
||||
+ reason + ", world=" + WorldUtil.getWorldName(world) + ", block_pos=" + pos + " - " + getTickThreadInformation(world.getServer());
|
||||
LOGGER.error(ex, new Throwable());
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
@@ -38,7 +40,7 @@ public class TickThread extends Thread {
|
||||
public static void ensureTickThread(final Level world, final BlockPos pos, final int blockRadius, final String reason) {
|
||||
if (!isTickThreadFor(world, pos, blockRadius)) {
|
||||
final String ex = "Thread " + Thread.currentThread().getName() + " failed main thread check: " +
|
||||
- reason + ", world=" + WorldUtil.getWorldName(world) + ", block_pos=" + pos + ", block_radius=" + blockRadius;
|
||||
+ reason + ", world=" + WorldUtil.getWorldName(world) + ", block_pos=" + pos + ", block_radius=" + blockRadius + " - " + getTickThreadInformation(world.getServer());
|
||||
LOGGER.error(ex, new Throwable());
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
@@ -56,7 +58,7 @@ public class TickThread extends Thread {
|
||||
public static void ensureTickThread(final Level world, final int chunkX, final int chunkZ, final String reason) {
|
||||
if (!isTickThreadFor(world, chunkX, chunkZ)) {
|
||||
final String ex = "Thread " + Thread.currentThread().getName() + " failed main thread check: " +
|
||||
- reason + ", world=" + WorldUtil.getWorldName(world) + ", chunk_pos=" + new ChunkPos(chunkX, chunkZ);
|
||||
+ reason + ", world=" + WorldUtil.getWorldName(world) + ", chunk_pos=" + new ChunkPos(chunkX, chunkZ) + " - " + getTickThreadInformation(world.getServer());
|
||||
LOGGER.error(ex, new Throwable());
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
@@ -65,7 +67,7 @@ public class TickThread extends Thread {
|
||||
public static void ensureTickThread(final Entity entity, final String reason) {
|
||||
if (!isTickThreadFor(entity)) {
|
||||
final String ex = "Thread " + Thread.currentThread().getName() + " failed main thread check: " +
|
||||
- reason + ", entity=" + entity;
|
||||
+ reason + ", entity=" + entity + " - " + getTickThreadInformation(entity.getServer());
|
||||
LOGGER.error(ex, new Throwable());
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
@@ -74,7 +76,7 @@ public class TickThread extends Thread {
|
||||
public static void ensureTickThread(final Level world, final AABB aabb, final String reason) {
|
||||
if (!isTickThreadFor(world, aabb)) {
|
||||
final String ex = "Thread " + Thread.currentThread().getName() + " failed main thread check: " +
|
||||
- reason + ", world=" + WorldUtil.getWorldName(world) + ", aabb=" + aabb;
|
||||
+ reason + ", world=" + WorldUtil.getWorldName(world) + ", aabb=" + aabb + " - " + getTickThreadInformation(world.getServer());
|
||||
LOGGER.error(ex, new Throwable());
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
@@ -83,12 +85,74 @@ public class TickThread extends Thread {
|
||||
public static void ensureTickThread(final Level world, final double blockX, final double blockZ, final String reason) {
|
||||
if (!isTickThreadFor(world, blockX, blockZ)) {
|
||||
final String ex = "Thread " + Thread.currentThread().getName() + " failed main thread check: " +
|
||||
- reason + ", world=" + WorldUtil.getWorldName(world) + ", block_pos=" + new Vec3(blockX, 0.0, blockZ);
|
||||
+ reason + ", world=" + WorldUtil.getWorldName(world) + ", block_pos=" + new Vec3(blockX, 0.0, blockZ) + " - " + getTickThreadInformation(world.getServer());
|
||||
LOGGER.error(ex, new Throwable());
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
+ // SparklyPaper - parallel world ticking
|
||||
+ // This is an additional method to check if the tick thread is bound to a specific world because, by default, Paper's isTickThread methods do not provide this information
|
||||
+ // Because we only tick worlds in parallel (instead of regions), we can use this for our checks
|
||||
+ public static void ensureTickThread(final net.minecraft.server.level.ServerLevel world, final String reason) {
|
||||
+ if (!isTickThreadFor(world)) {
|
||||
+ LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread check: " + reason + " @ world " + world.getWorld().getName() + " - " + getTickThreadInformation(world.getServer()), new Throwable());
|
||||
+ if (HARD_THROW)
|
||||
+ throw new IllegalStateException(reason);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // SparklyPaper - parallel world ticking
|
||||
+ // This is an additional method to check if it is a tick thread but ONLY a tick thread
|
||||
+ public static void ensureOnlyTickThread(final String reason) {
|
||||
+ boolean isTickThread = isTickThread();
|
||||
+ boolean isServerLevelTickThread = isServerLevelTickThread();
|
||||
+ if (!isTickThread || isServerLevelTickThread) {
|
||||
+ LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread ONLY tick thread check: " + reason, new Throwable());
|
||||
+ if (HARD_THROW)
|
||||
+ throw new IllegalStateException(reason);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // SparklyPaper - parallel world ticking
|
||||
+ // This is an additional method to check if the tick thread is bound to a specific world or if it is an async thread.
|
||||
+ public static void ensureTickThreadOrAsyncThread(final net.minecraft.server.level.ServerLevel world, final String reason) {
|
||||
+ boolean isValidTickThread = isTickThreadFor(world);
|
||||
+ boolean isAsyncThread = !isTickThread();
|
||||
+ boolean isValid = isAsyncThread || isValidTickThread;
|
||||
+ if (!isValid) {
|
||||
+ LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread or async thread check: " + reason + " @ world " + world.getWorld().getName() + " - " + getTickThreadInformation(world.getServer()), new Throwable());
|
||||
+ if (HARD_THROW)
|
||||
+ throw new IllegalStateException(reason);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public static String getTickThreadInformation(net.minecraft.server.MinecraftServer minecraftServer) {
|
||||
+ StringBuilder sb = new StringBuilder();
|
||||
+ Thread currentThread = Thread.currentThread();
|
||||
+ sb.append("Is tick thread? ");
|
||||
+ sb.append(currentThread instanceof TickThread);
|
||||
+ sb.append("; Is server level tick thread? ");
|
||||
+ sb.append(currentThread instanceof ServerLevelTickThread);
|
||||
+ if (currentThread instanceof ServerLevelTickThread serverLevelTickThread) {
|
||||
+ sb.append("; Currently ticking level: ");
|
||||
+ if (serverLevelTickThread.currentlyTickingServerLevel != null) {
|
||||
+ sb.append(serverLevelTickThread.currentlyTickingServerLevel.getWorld().getName());
|
||||
+ } else {
|
||||
+ sb.append("null");
|
||||
+ }
|
||||
+ }
|
||||
+ sb.append("; Is iterating over levels? ");
|
||||
+ sb.append(minecraftServer.isIteratingOverLevels);
|
||||
+ sb.append("; Are we going to hard throw? ");
|
||||
+ sb.append(HARD_THROW);
|
||||
+ return sb.toString();
|
||||
+ }
|
||||
+
|
||||
+ public static boolean isServerLevelTickThread() {
|
||||
+ return Thread.currentThread() instanceof ServerLevelTickThread;
|
||||
+ }
|
||||
+
|
||||
public final int id; /* We don't override getId as the spec requires that it be unique (with respect to all other threads) */
|
||||
|
||||
private static final AtomicInteger ID_GENERATOR = new AtomicInteger();
|
||||
@@ -123,7 +187,11 @@ public class TickThread extends Thread {
|
||||
}
|
||||
|
||||
public static boolean isTickThreadFor(final Level world, final BlockPos pos) {
|
||||
- return isTickThread();
|
||||
+ Thread currentThread = Thread.currentThread();
|
||||
+
|
||||
+ if (currentThread instanceof ServerLevelTickThread serverLevelTickThread) {
|
||||
+ return serverLevelTickThread.currentlyTickingServerLevel == world;
|
||||
+ } else return currentThread instanceof TickThread;
|
||||
}
|
||||
|
||||
public static boolean isTickThreadFor(final Level world, final BlockPos pos, final int blockRadius) {
|
||||
@@ -131,38 +199,103 @@ public class TickThread extends Thread {
|
||||
}
|
||||
|
||||
public static boolean isTickThreadFor(final Level world, final ChunkPos pos) {
|
||||
- return isTickThread();
|
||||
+ Thread currentThread = Thread.currentThread();
|
||||
+
|
||||
+ if (currentThread instanceof ServerLevelTickThread serverLevelTickThread) {
|
||||
+ return serverLevelTickThread.currentlyTickingServerLevel == world;
|
||||
+ } else return currentThread instanceof TickThread;
|
||||
}
|
||||
|
||||
public static boolean isTickThreadFor(final Level world, final Vec3 pos) {
|
||||
- return isTickThread();
|
||||
+ Thread currentThread = Thread.currentThread();
|
||||
+
|
||||
+ if (currentThread instanceof ServerLevelTickThread serverLevelTickThread) {
|
||||
+ return serverLevelTickThread.currentlyTickingServerLevel == world;
|
||||
+ } else return currentThread instanceof TickThread;
|
||||
}
|
||||
|
||||
public static boolean isTickThreadFor(final Level world, final int chunkX, final int chunkZ) {
|
||||
- return isTickThread();
|
||||
+ Thread currentThread = Thread.currentThread();
|
||||
+
|
||||
+ if (currentThread instanceof ServerLevelTickThread serverLevelTickThread) {
|
||||
+ return serverLevelTickThread.currentlyTickingServerLevel == world;
|
||||
+ } else return currentThread instanceof TickThread;
|
||||
}
|
||||
|
||||
public static boolean isTickThreadFor(final Level world, final AABB aabb) {
|
||||
- return isTickThread();
|
||||
+ Thread currentThread = Thread.currentThread();
|
||||
+
|
||||
+ if (currentThread instanceof ServerLevelTickThread serverLevelTickThread) {
|
||||
+ return serverLevelTickThread.currentlyTickingServerLevel == world;
|
||||
+ } else return currentThread instanceof TickThread;
|
||||
}
|
||||
|
||||
public static boolean isTickThreadFor(final Level world, final double blockX, final double blockZ) {
|
||||
- return isTickThread();
|
||||
+ Thread currentThread = Thread.currentThread();
|
||||
+
|
||||
+ if (currentThread instanceof ServerLevelTickThread serverLevelTickThread) {
|
||||
+ return serverLevelTickThread.currentlyTickingServerLevel == world;
|
||||
+ } else return currentThread instanceof TickThread;
|
||||
}
|
||||
|
||||
public static boolean isTickThreadFor(final Level world, final Vec3 position, final Vec3 deltaMovement, final int buffer) {
|
||||
- return isTickThread();
|
||||
+ Thread currentThread = Thread.currentThread();
|
||||
+
|
||||
+ if (currentThread instanceof ServerLevelTickThread serverLevelTickThread) {
|
||||
+ return serverLevelTickThread.currentlyTickingServerLevel == world;
|
||||
+ } else return currentThread instanceof TickThread;
|
||||
}
|
||||
|
||||
public static boolean isTickThreadFor(final Level world, final int fromChunkX, final int fromChunkZ, final int toChunkX, final int toChunkZ) {
|
||||
- return isTickThread();
|
||||
+ Thread currentThread = Thread.currentThread();
|
||||
+
|
||||
+ if (currentThread instanceof ServerLevelTickThread serverLevelTickThread) {
|
||||
+ return serverLevelTickThread.currentlyTickingServerLevel == world;
|
||||
+ } else return currentThread instanceof TickThread;
|
||||
}
|
||||
|
||||
public static boolean isTickThreadFor(final Level world, final int chunkX, final int chunkZ, final int radius) {
|
||||
- return isTickThread();
|
||||
+ Thread currentThread = Thread.currentThread();
|
||||
+
|
||||
+ if (currentThread instanceof ServerLevelTickThread serverLevelTickThread) {
|
||||
+ return serverLevelTickThread.currentlyTickingServerLevel == world;
|
||||
+ } else return currentThread instanceof TickThread;
|
||||
+ }
|
||||
+
|
||||
+ // SparklyPaper - parallel world ticking
|
||||
+ // This is an additional method to check if the tick thread is bound to a specific world because, by default, Paper's isTickThread methods do not provide this information
|
||||
+ // Because we only tick worlds in parallel (instead of regions), we can use this for our checks
|
||||
+ public static boolean isTickThreadFor(final Level world) {
|
||||
+ Thread currentThread = Thread.currentThread();
|
||||
+
|
||||
+ if (currentThread instanceof ServerLevelTickThread serverLevelTickThread) {
|
||||
+ return serverLevelTickThread.currentlyTickingServerLevel == world;
|
||||
+ } else return currentThread instanceof TickThread;
|
||||
}
|
||||
|
||||
public static boolean isTickThreadFor(final Entity entity) {
|
||||
- return isTickThread();
|
||||
+ if (entity == null) {
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ Thread currentThread = Thread.currentThread();
|
||||
+
|
||||
+ if (currentThread instanceof ServerLevelTickThread serverLevelTickThread) {
|
||||
+ return serverLevelTickThread.currentlyTickingServerLevel == entity.level();
|
||||
+ } else return currentThread instanceof TickThread;
|
||||
+ }
|
||||
+
|
||||
+ // SparklyPaper start - parallel world ticking
|
||||
+ public static class ServerLevelTickThread extends TickThread {
|
||||
+ public ServerLevelTickThread(String name) {
|
||||
+ super(name);
|
||||
+ }
|
||||
+
|
||||
+ public ServerLevelTickThread(Runnable run, String name) {
|
||||
+ super(run, name);
|
||||
+ }
|
||||
+
|
||||
+ public net.minecraft.server.level.ServerLevel currentlyTickingServerLevel;
|
||||
}
|
||||
+ // SparklyPaper end
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
index ba32db69c95b325a781cb2dff4200e4464a11baf..219a87300838cb4d078553dda666b3207f8191b8 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
@@ -457,7 +457,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
}
|
||||
|
||||
private boolean unloadChunk0(int x, int z, boolean save) {
|
||||
- org.spigotmc.AsyncCatcher.catchOp("chunk unload"); // Spigot
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, x, z, "Cannot unload chunk asynchronously"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||
if (!this.isChunkLoaded(x, z)) {
|
||||
return true;
|
||||
}
|
||||
@@ -480,6 +480,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
if (!unloadChunk0(x, z, false)) {
|
||||
return false;
|
||||
}
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, x, z, "Cannot regenerate chunk asynchronously"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||
warnUnsafeChunk("regenerating a faraway chunk", x, z); // Paper
|
||||
|
||||
final long chunkKey = ChunkCoordIntPair.pair(x, z);
|
||||
@@ -501,6 +502,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
|
||||
@Override
|
||||
public boolean refreshChunk(int x, int z) {
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, x, z, "Cannot refresh chunk asynchronously"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||
ChunkHolder playerChunk = this.world.getChunkSource().chunkMap.getVisibleChunkIfPresent(ChunkPos.asLong(x, z));
|
||||
if (playerChunk == null) return false;
|
||||
|
||||
@@ -551,7 +553,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
|
||||
@Override
|
||||
public boolean loadChunk(int x, int z, boolean generate) {
|
||||
- org.spigotmc.AsyncCatcher.catchOp("chunk load"); // Spigot
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.getHandle(), x, z, "May not sync load chunks asynchronously"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||
warnUnsafeChunk("loading a faraway chunk", x, z); // Paper
|
||||
ChunkAccess chunk = this.world.getChunkSource().getChunk(x, z, generate || isChunkGenerated(x, z) ? ChunkStatus.FULL : ChunkStatus.EMPTY, true); // Paper
|
||||
|
||||
@@ -779,6 +781,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
|
||||
@Override
|
||||
public boolean generateTree(Location loc, TreeType type, BlockChangeDelegate delegate) {
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, loc.getX(), loc.getZ(), "Cannot generate tree asynchronously"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||
this.world.captureTreeGeneration = true;
|
||||
this.world.captureBlockStates = true;
|
||||
boolean grownTree = this.generateTree(loc, type);
|
||||
@@ -894,6 +897,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
}
|
||||
public boolean createExplosion(double x, double y, double z, float power, boolean setFire, boolean breakBlocks, Entity source, Consumer<net.minecraft.world.level.ServerExplosion> configurator) {
|
||||
// Paper end - expand explosion API
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, x, z, "Cannot create explosion asynchronously"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||
net.minecraft.world.level.Level.ExplosionInteraction explosionType;
|
||||
if (!breakBlocks) {
|
||||
explosionType = net.minecraft.world.level.Level.ExplosionInteraction.NONE; // Don't break blocks
|
||||
@@ -985,6 +989,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
|
||||
@Override
|
||||
public int getHighestBlockYAt(int x, int z, org.bukkit.HeightMap heightMap) {
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, x >> 4, z >> 4, "Cannot retrieve chunk asynchronously"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||
warnUnsafeChunk("getting a faraway chunk", x >> 4, z >> 4); // Paper
|
||||
// Transient load for this tick
|
||||
return this.world.getChunk(x >> 4, z >> 4).getHeight(CraftHeightMap.toNMS(heightMap), x, z);
|
||||
@@ -1015,6 +1020,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
@Override
|
||||
public void setBiome(int x, int y, int z, Holder<net.minecraft.world.level.biome.Biome> bb) {
|
||||
BlockPos pos = new BlockPos(x, 0, z);
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, pos, "Cannot retrieve chunk asynchronously"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||
if (this.world.hasChunkAt(pos)) {
|
||||
net.minecraft.world.level.chunk.LevelChunk chunk = this.world.getChunkAt(pos);
|
||||
|
||||
@@ -2292,6 +2298,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
|
||||
@Override
|
||||
public void sendGameEvent(Entity sourceEntity, org.bukkit.GameEvent gameEvent, Vector position) {
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, position.getX(), position.getZ(), "Cannot send game event asynchronously"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||
getHandle().gameEvent(sourceEntity != null ? ((CraftEntity) sourceEntity).getHandle(): null, net.minecraft.core.registries.BuiltInRegistries.GAME_EVENT.get(org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(gameEvent.getKey())).orElseThrow(), org.bukkit.craftbukkit.util.CraftVector.toBlockPos(position));
|
||||
}
|
||||
// Paper end
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
|
||||
index 5cb69d0b822e11a99a96aef4f59986d083b079f4..78f9c3f3b068f638570942961ad41969abc9c028 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
|
||||
@@ -75,6 +75,11 @@ public class CraftBlock implements Block {
|
||||
}
|
||||
|
||||
public net.minecraft.world.level.block.state.BlockState getNMS() {
|
||||
+ // Folia start - parallel world ticking
|
||||
+ if (world instanceof ServerLevel serverWorld) {
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously");
|
||||
+ }
|
||||
+ // Folia end - parallel world ticking
|
||||
return this.world.getBlockState(this.position);
|
||||
}
|
||||
|
||||
@@ -157,6 +162,11 @@ public class CraftBlock implements Block {
|
||||
}
|
||||
|
||||
private void setData(final byte data, int flag) {
|
||||
+ // SparklyPaper start - parallel world ticking
|
||||
+ if (world instanceof ServerLevel serverWorld) {
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously");
|
||||
+ }
|
||||
+ // SparklyPaper end - parallel world ticking
|
||||
this.world.setBlock(this.position, CraftMagicNumbers.getBlock(this.getType(), data), flag);
|
||||
}
|
||||
|
||||
@@ -198,6 +208,12 @@ public class CraftBlock implements Block {
|
||||
}
|
||||
|
||||
public static boolean setTypeAndData(LevelAccessor world, BlockPos position, net.minecraft.world.level.block.state.BlockState old, net.minecraft.world.level.block.state.BlockState blockData, boolean applyPhysics) {
|
||||
+ // SparklyPaper start - parallel world ticking
|
||||
+ if (world instanceof ServerLevel serverWorld) {
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously");
|
||||
+ }
|
||||
+ // SparklyPaper end - parallel world ticking
|
||||
+
|
||||
// SPIGOT-611: need to do this to prevent glitchiness. Easier to handle this here (like /setblock) than to fix weirdness in tile entity cleanup
|
||||
if (old.hasBlockEntity() && blockData.getBlock() != old.getBlock()) { // SPIGOT-3725 remove old tile entity if block changes
|
||||
// SPIGOT-4612: faster - just clear tile
|
||||
@@ -343,18 +359,33 @@ public class CraftBlock implements Block {
|
||||
|
||||
@Override
|
||||
public Biome getBiome() {
|
||||
+ // SparklyPaper start - parallel world ticking
|
||||
+ if (world instanceof ServerLevel serverWorld) {
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously");
|
||||
+ }
|
||||
+ // SparklyPaper end - parallel world ticking
|
||||
return this.getWorld().getBiome(this.getX(), this.getY(), this.getZ());
|
||||
}
|
||||
|
||||
// Paper start
|
||||
@Override
|
||||
public Biome getComputedBiome() {
|
||||
+ // SparklyPaper start - parallel world ticking
|
||||
+ if (world instanceof ServerLevel serverWorld) {
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously");
|
||||
+ }
|
||||
+ // SparklyPaper end - parallel world ticking
|
||||
return this.getWorld().getComputedBiome(this.getX(), this.getY(), this.getZ());
|
||||
}
|
||||
// Paper end
|
||||
|
||||
@Override
|
||||
public void setBiome(Biome bio) {
|
||||
+ // SparklyPaper start - parallel world ticking
|
||||
+ if (world instanceof ServerLevel serverWorld) {
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously");
|
||||
+ }
|
||||
+ // SparklyPaper end - parallel world ticking
|
||||
this.getWorld().setBiome(this.getX(), this.getY(), this.getZ(), bio);
|
||||
}
|
||||
|
||||
@@ -402,6 +433,11 @@ public class CraftBlock implements Block {
|
||||
|
||||
@Override
|
||||
public boolean isBlockFaceIndirectlyPowered(BlockFace face) {
|
||||
+ // SparklyPaper start - parallel world ticking
|
||||
+ if (world instanceof ServerLevel serverWorld) {
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously");
|
||||
+ }
|
||||
+ // SparklyPaper end - parallel world ticking
|
||||
int power = this.world.getMinecraftWorld().getSignal(this.position, CraftBlock.blockFaceToNotch(face));
|
||||
|
||||
Block relative = this.getRelative(face);
|
||||
@@ -414,6 +450,11 @@ public class CraftBlock implements Block {
|
||||
|
||||
@Override
|
||||
public int getBlockPower(BlockFace face) {
|
||||
+ // SparklyPaper start - parallel world ticking
|
||||
+ if (world instanceof ServerLevel serverWorld) {
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously");
|
||||
+ }
|
||||
+ // SparklyPaper end - parallel world ticking
|
||||
int power = 0;
|
||||
net.minecraft.world.level.Level world = this.world.getMinecraftWorld();
|
||||
int x = this.getX();
|
||||
@@ -484,6 +525,11 @@ public class CraftBlock implements Block {
|
||||
|
||||
@Override
|
||||
public boolean breakNaturally() {
|
||||
+ // SparklyPaper start - parallel world ticking
|
||||
+ if (world instanceof ServerLevel serverWorld) {
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously");
|
||||
+ }
|
||||
+ // SparklyPaper end - parallel world ticking
|
||||
return this.breakNaturally(null);
|
||||
}
|
||||
|
||||
@@ -543,6 +589,11 @@ public class CraftBlock implements Block {
|
||||
|
||||
@Override
|
||||
public boolean applyBoneMeal(BlockFace face) {
|
||||
+ // SparklyPaper start - parallel world ticking
|
||||
+ if (world instanceof ServerLevel serverWorld) {
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously");
|
||||
+ }
|
||||
+ // SparklyPaper end - parallel world ticking
|
||||
Direction direction = CraftBlock.blockFaceToNotch(face);
|
||||
BlockFertilizeEvent event = null;
|
||||
ServerLevel world = this.getCraftWorld().getHandle();
|
||||
@@ -554,8 +605,8 @@ public class CraftBlock implements Block {
|
||||
world.captureTreeGeneration = false;
|
||||
|
||||
if (world.capturedBlockStates.size() > 0) {
|
||||
- TreeType treeType = SaplingBlock.treeType;
|
||||
- SaplingBlock.treeType = null;
|
||||
+ TreeType treeType = SaplingBlock.treeTypeRT.get(); // SparklyPaper - parallel world ticking
|
||||
+ SaplingBlock.treeTypeRT.set(null); // SparklyPaper - parallel world ticking
|
||||
List<BlockState> blocks = new ArrayList<>(world.capturedBlockStates.values());
|
||||
world.capturedBlockStates.clear();
|
||||
StructureGrowEvent structureEvent = null;
|
||||
@@ -644,6 +695,11 @@ public class CraftBlock implements Block {
|
||||
|
||||
@Override
|
||||
public RayTraceResult rayTrace(Location start, Vector direction, double maxDistance, FluidCollisionMode fluidCollisionMode) {
|
||||
+ // SparklyPaper start - parallel world ticking
|
||||
+ if (world instanceof ServerLevel serverWorld) {
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously");
|
||||
+ }
|
||||
+ // SparklyPaper end - parallel world ticking
|
||||
Preconditions.checkArgument(start != null, "Location start cannot be null");
|
||||
Preconditions.checkArgument(this.getWorld().equals(start.getWorld()), "Location start cannot be a different world");
|
||||
start.checkFinite();
|
||||
@@ -685,6 +741,11 @@ public class CraftBlock implements Block {
|
||||
|
||||
@Override
|
||||
public boolean canPlace(BlockData data) {
|
||||
+ // SparklyPaper start - parallel world ticking
|
||||
+ if (world instanceof ServerLevel serverWorld) {
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously");
|
||||
+ }
|
||||
+ // SparklyPaper end - parallel world ticking
|
||||
Preconditions.checkArgument(data != null, "BlockData cannot be null");
|
||||
net.minecraft.world.level.block.state.BlockState iblockdata = ((CraftBlockData) data).getState();
|
||||
net.minecraft.world.level.Level world = this.world.getMinecraftWorld();
|
||||
@@ -719,6 +780,11 @@ public class CraftBlock implements Block {
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
+ // SparklyPaper start - parallel world ticking
|
||||
+ if (world instanceof ServerLevel serverWorld) {
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously");
|
||||
+ }
|
||||
+ // SparklyPaper end - parallel world ticking
|
||||
final ServerLevel level = this.world.getMinecraftWorld();
|
||||
this.getNMS().tick(level, this.position, level.random);
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
|
||||
index 04ae258a2f8e98421340d29d5cceedec045171b7..3e90f16d303a8f3d1e2b01e7cbd62cbd991d3f06 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
|
||||
@@ -25,7 +25,7 @@ public abstract class CraftBlockEntityState<T extends BlockEntity> extends Craft
|
||||
private final T tileEntity;
|
||||
private final T snapshot;
|
||||
public boolean snapshotDisabled; // Paper
|
||||
- public static boolean DISABLE_SNAPSHOT = false; // Paper
|
||||
+ public static ThreadLocal<Boolean> DISABLE_SNAPSHOT = ThreadLocal.withInitial(() -> Boolean.FALSE); // SparklyPaper - parallel world ticking
|
||||
|
||||
public CraftBlockEntityState(World world, T tileEntity) {
|
||||
super(world, tileEntity.getBlockPos(), tileEntity.getBlockState());
|
||||
@@ -34,8 +34,8 @@ public abstract class CraftBlockEntityState<T extends BlockEntity> extends Craft
|
||||
|
||||
try { // Paper - Show blockstate location if we failed to read it
|
||||
// Paper start
|
||||
- this.snapshotDisabled = DISABLE_SNAPSHOT;
|
||||
- if (DISABLE_SNAPSHOT) {
|
||||
+ this.snapshotDisabled = DISABLE_SNAPSHOT.get(); // SparklyPaper - parallel world ticking
|
||||
+ if (DISABLE_SNAPSHOT.get()) { // SparklyPaper - parallel world ticking
|
||||
this.snapshot = this.tileEntity;
|
||||
} else {
|
||||
this.snapshot = this.createSnapshot(tileEntity);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java
|
||||
index fa63a6cfcfcc4eee4503a82d85333c139c8c8b2b..9856860ee2987738bbcad5d752670e30f569ba74 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java
|
||||
@@ -215,6 +215,12 @@ public class CraftBlockState implements BlockState {
|
||||
LevelAccessor access = this.getWorldHandle();
|
||||
CraftBlock block = this.getBlock();
|
||||
|
||||
+ // SparklyPaper start - parallel world ticking
|
||||
+ if (access instanceof net.minecraft.server.level.ServerLevel serverWorld) {
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously");
|
||||
+ }
|
||||
+ // SparklyPaper end - parallel world ticking
|
||||
+
|
||||
if (block.getType() != this.getType()) {
|
||||
if (!force) {
|
||||
return false;
|
||||
@@ -350,6 +356,7 @@ public class CraftBlockState implements BlockState {
|
||||
|
||||
@Override
|
||||
public java.util.Collection<org.bukkit.inventory.ItemStack> getDrops(org.bukkit.inventory.ItemStack item, org.bukkit.entity.Entity entity) {
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(world.getHandle(), position, "Cannot modify world asynchronously"); // SparklyPaper - parallel world ticking
|
||||
this.requirePlaced();
|
||||
net.minecraft.world.item.ItemStack nms = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(item);
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java
|
||||
index 56453454cbd4b9e9270fc833f8ab38d5fa7a3763..ad507c36d89ce8639fbedbb1df0da66bdc96affa 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java
|
||||
@@ -249,8 +249,8 @@ public final class CraftBlockStates {
|
||||
net.minecraft.world.level.block.state.BlockState blockData = craftBlock.getNMS();
|
||||
BlockEntity tileEntity = craftBlock.getHandle().getBlockEntity(blockPosition);
|
||||
// Paper start - block state snapshots
|
||||
- boolean prev = CraftBlockEntityState.DISABLE_SNAPSHOT;
|
||||
- CraftBlockEntityState.DISABLE_SNAPSHOT = !useSnapshot;
|
||||
+ boolean prev = CraftBlockEntityState.DISABLE_SNAPSHOT.get(); // SparklyPaper - parallel world ticking
|
||||
+ CraftBlockEntityState.DISABLE_SNAPSHOT.set(!useSnapshot); // SparklyPaper - parallel world ticking
|
||||
try {
|
||||
// Paper end
|
||||
CraftBlockState blockState = CraftBlockStates.getBlockState(world, blockPosition, blockData, tileEntity);
|
||||
@@ -258,7 +258,7 @@ public final class CraftBlockStates {
|
||||
return blockState;
|
||||
// Paper start
|
||||
} finally {
|
||||
- CraftBlockEntityState.DISABLE_SNAPSHOT = prev;
|
||||
+ CraftBlockEntityState.DISABLE_SNAPSHOT.set(prev); // SparklyPaper - parallel world ticking
|
||||
}
|
||||
// Paper end
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
index bbd000e3a3e9112e10a09e5d3ef6851b28e900fa..6b91661e920b80fb2ddf2b3e9e2c2839a7986b01 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
@@ -951,7 +951,7 @@ public class CraftEventFactory {
|
||||
return CraftEventFactory.handleBlockSpreadEvent(world, source, target, block, 2);
|
||||
}
|
||||
|
||||
- public static BlockPos sourceBlockOverride = null; // SPIGOT-7068: Add source block override, not the most elegant way but better than passing down a BlockPosition up to five methods deep.
|
||||
+ public static final ThreadLocal<BlockPos> sourceBlockOverrideRT = new ThreadLocal<>(); // SPIGOT-7068: Add source block override, not the most elegant way but better than passing down a BlockPosition up to five methods deep. // SparklyPaper - parallel world ticking (this is from Folia, fixes concurrency bugs with sculk catalysts)
|
||||
|
||||
public static boolean handleBlockSpreadEvent(LevelAccessor world, BlockPos source, BlockPos target, net.minecraft.world.level.block.state.BlockState block, int flag) {
|
||||
// Suppress during worldgen
|
||||
@@ -963,7 +963,7 @@ public class CraftEventFactory {
|
||||
CraftBlockState state = CraftBlockStates.getBlockState(world, target, flag);
|
||||
state.setData(block);
|
||||
|
||||
- BlockSpreadEvent event = new BlockSpreadEvent(state.getBlock(), CraftBlock.at(world, CraftEventFactory.sourceBlockOverride != null ? CraftEventFactory.sourceBlockOverride : source), state);
|
||||
+ BlockSpreadEvent event = new BlockSpreadEvent(state.getBlock(), CraftBlock.at(world, CraftEventFactory.sourceBlockOverrideRT.get() != null ? CraftEventFactory.sourceBlockOverrideRT.get() : source), state); // SparklyPaper - parallel world ticking
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
|
||||
if (!event.isCancelled()) {
|
||||
@@ -2248,7 +2248,7 @@ public class CraftEventFactory {
|
||||
CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemStack.copyWithCount(1));
|
||||
|
||||
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), CraftVector.toBukkit(to));
|
||||
- if (!net.minecraft.world.level.block.DispenserBlock.eventFired) {
|
||||
+ if (!net.minecraft.world.level.block.DispenserBlock.eventFired.get()) { // SparklyPaper - parallel world ticking
|
||||
if (!event.callEvent()) {
|
||||
return itemStack;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||
Date: Wed, 12 Jun 2024 11:53:09 -0300
|
||||
Subject: [PATCH] SPARKLYPOWER Add custom blocks
|
||||
|
||||
|
||||
diff --git a/src/test/java/org/bukkit/craftbukkit/legacy/LegacyTest.java b/src/test/java/org/bukkit/craftbukkit/legacy/LegacyTest.java
|
||||
index 002e635137a8b015af9799d6a8854ebc6330bfb4..0f02a9793937a492003bbfff827ac6483c1baa14 100644
|
||||
--- a/src/test/java/org/bukkit/craftbukkit/legacy/LegacyTest.java
|
||||
+++ b/src/test/java/org/bukkit/craftbukkit/legacy/LegacyTest.java
|
||||
@@ -135,6 +135,9 @@ public class LegacyTest {
|
||||
// 1.21.4
|
||||
Material.OPEN_EYEBLOSSOM, Material.CLOSED_EYEBLOSSOM, Material.RESIN_CLUMP, Material.RESIN_BLOCK, Material.RESIN_BRICKS, Material.RESIN_BRICK_STAIRS, Material.RESIN_BRICK_SLAB, Material.RESIN_BRICK_WALL, Material.CHISELED_RESIN_BRICKS,
|
||||
Material.RESIN_BRICK, Material.POTTED_OPEN_EYEBLOSSOM, Material.POTTED_CLOSED_EYEBLOSSOM,
|
||||
+ // SparklyPower custom blocks
|
||||
+ Material.SPARKLYPOWER_RAINBOW_WOOL, Material.SPARKLYPOWER_RAINBOW_CONCRETE, Material.SPARKLYPOWER_RAINBOW_TERRACOTTA, Material.SPARKLYPOWER_ASPHALT_PLAYER, Material.SPARKLYPOWER_ASPHALT_SERVER, Material.SPARKLYPOWER_ASPHALT_PLAYER_SLAB,
|
||||
+ Material.SPARKLYPOWER_ASPHALT_SERVER_SLAB,
|
||||
//
|
||||
Material.LEGACY_AIR, Material.LEGACY_DEAD_BUSH, Material.LEGACY_BURNING_FURNACE, Material.LEGACY_WALL_SIGN, Material.LEGACY_REDSTONE_TORCH_OFF, Material.LEGACY_SKULL, Material.LEGACY_REDSTONE_COMPARATOR_ON, Material.LEGACY_WALL_BANNER, Material.LEGACY_MONSTER_EGG));
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
--- a/src/main/resources/data/.paperassetsroot
|
||||
+++ b/src/main/resources/data/.paperassetsroot
|
||||
@@ -1,0 +_,0 @@
|
||||
@@ -0,0 +1,98 @@
|
||||
package net.sparklypower.sparklypaper;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import net.minecraft.world.level.block.entity.TickingBlockEntity;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* A list for ServerLevel's blockEntityTickers
|
||||
* <p>
|
||||
* This list is behaves identically to ObjectArrayList, but it has an additional method, `removeAllByIndex`, that allows a list of integers to be passed indicating what
|
||||
* indexes should be deleted from the list
|
||||
* <p>
|
||||
* This is faster than using removeAll, since we don't need to compare the identity of each block entity, and faster than looping thru each index manually and deleting with remove,
|
||||
* since we don't need to resize the array every single remove.
|
||||
*/
|
||||
public final class BlockEntityTickersList extends ObjectArrayList<TickingBlockEntity> {
|
||||
private final IntOpenHashSet toRemove = new IntOpenHashSet();
|
||||
private int startSearchFromIndex = -1;
|
||||
|
||||
/** Creates a new array list with {@link #DEFAULT_INITIAL_CAPACITY} capacity. */
|
||||
public BlockEntityTickersList() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new array list and fills it with a given collection.
|
||||
*
|
||||
* @param c a collection that will be used to fill the array list.
|
||||
*/
|
||||
public BlockEntityTickersList(final Collection<? extends TickingBlockEntity> c) {
|
||||
super(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks an entry as removed
|
||||
*
|
||||
* @param index the index of the item on the list to be marked as removed
|
||||
*/
|
||||
public void markAsRemoved(final int index) {
|
||||
// The block entities list always loop starting from 0, so we only need to check if the startSearchFromIndex is -1 and that's it
|
||||
if (this.startSearchFromIndex == -1)
|
||||
this.startSearchFromIndex = index;
|
||||
this.toRemove.add(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes elements that have been marked as removed.
|
||||
*/
|
||||
public void removeMarkedEntries() {
|
||||
if (this.startSearchFromIndex == -1) // No entries in the list, skip
|
||||
return;
|
||||
|
||||
removeAllByIndex(startSearchFromIndex, toRemove);
|
||||
toRemove.clear();
|
||||
this.startSearchFromIndex = -1; // Reset the start search index
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes elements by their index.
|
||||
*/
|
||||
private void removeAllByIndex(final int startSearchFromIndex, final IntOpenHashSet c) { // can't use Set<Integer> because we want to avoid autoboxing when using contains
|
||||
final int requiredMatches = c.size();
|
||||
if (requiredMatches == 0)
|
||||
return; // exit early, we don't need to do anything
|
||||
|
||||
final Object[] a = this.a;
|
||||
int j = startSearchFromIndex;
|
||||
int matches = 0;
|
||||
for (int i = startSearchFromIndex; i < size; i++) { // If the user knows the first index to be removed, we can skip a lot of unnecessary comparsions
|
||||
if (!c.contains(i)) {
|
||||
// TODO: It can be possible to optimize this loop by tracking the start/finish and then using arraycopy to "skip" the elements,
|
||||
// this would optimize cases where the index to be removed are far apart, HOWEVER it does have a big performance impact if you are doing
|
||||
// "arraycopy" for each element
|
||||
a[j++] = a[i];
|
||||
} else {
|
||||
matches++;
|
||||
}
|
||||
|
||||
if (matches == requiredMatches) { // Exit the loop if we already removed everything, we don't need to check anything else
|
||||
// We need to update the final size here, because we know that we already found everything!
|
||||
// Because we know that the size must be currentSize - requiredMatches (because we have matched everything), let's update the value
|
||||
// However, we need to copy the rest of the stuff over
|
||||
if (i != (size - 1)) { // If it isn't the last index...
|
||||
// i + 1 because we want to copy the *next* element over
|
||||
// and the size - i - 1 is because we want to get the current size, minus the current index (which is i), and then - 1 because we want to copy -1 ahead (remember, we are adding +1 to copy the *next* element)
|
||||
System.arraycopy(a, i + 1, a, j, size - i - 1);
|
||||
}
|
||||
j = size - requiredMatches;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Arrays.fill(a, j, size, null);
|
||||
size = j;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package net.sparklypower.sparklypaper.commands;
|
||||
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.sparklypower.sparklypaper.configs.SparklyPaperConfigUtils;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class SparklyPaperCommand extends Command {
|
||||
public SparklyPaperCommand(String name) {
|
||||
super(name);
|
||||
this.description = "SparklyPaper related commands";
|
||||
this.usageMessage = "/sparklypaper [reload | version]";
|
||||
this.setPermission("bukkit.command.sparklypaper");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> tabComplete(CommandSender sender, String alias, String[] args, Location location) throws IllegalArgumentException {
|
||||
if (args.length == 1) {
|
||||
return Stream.of("reload", "version")
|
||||
.filter(arg -> arg.startsWith(args[0].toLowerCase()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(CommandSender sender, String commandLabel, String[] args) {
|
||||
if (!testPermission(sender)) return true;
|
||||
|
||||
if (args.length != 1) {
|
||||
sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (args[0].equalsIgnoreCase("reload")) {
|
||||
Command.broadcastCommandMessage(sender, ChatColor.RED + "Please note that this command is not supported and may cause issues.");
|
||||
Command.broadcastCommandMessage(sender, ChatColor.RED + "If you encounter any issues please use the /stop command to restart your server.");
|
||||
|
||||
MinecraftServer console = MinecraftServer.getServer();
|
||||
SparklyPaperConfigUtils.INSTANCE.init((File) console.options.valueOf("sparklypaper-settings"));
|
||||
for (ServerLevel level : console.getAllLevels()) {
|
||||
level.sparklyPaperConfig = SparklyPaperConfigUtils.INSTANCE.getWorldSettings(level.serverLevelData.getLevelName());
|
||||
}
|
||||
console.server.reloadCount++;
|
||||
|
||||
Command.broadcastCommandMessage(sender, ChatColor.GREEN + "SparklyPaper config reload complete.");
|
||||
} else if (args[0].equalsIgnoreCase("version")) {
|
||||
Command verCmd = org.bukkit.Bukkit.getServer().getCommandMap().getCommand("version");
|
||||
if (verCmd != null) {
|
||||
return verCmd.execute(sender, commandLabel, new String[0]);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package net.sparklypower.sparklypaper
|
||||
|
||||
import com.mojang.logging.LogUtils
|
||||
import java.time.LocalDateTime
|
||||
import java.time.Month
|
||||
import java.time.ZoneOffset
|
||||
import java.util.concurrent.*
|
||||
|
||||
class HalloweenManager {
|
||||
companion object {
|
||||
private val LOGGER = LogUtils.getLogger()
|
||||
}
|
||||
private var spookySeasonStartEpoch = 0L
|
||||
private var spookySeasonEndEpoch = 0L
|
||||
private var halloweenStartEpoch = 0L
|
||||
private var halloweenEndEpoch = 0L
|
||||
private var executor = Executors.newSingleThreadScheduledExecutor(object: ThreadFactory {
|
||||
override fun newThread(p0: Runnable): Thread {
|
||||
val thread = Thread(p0)
|
||||
thread.name = "halloween-timer-updater"
|
||||
thread.priority = 1 // Minimum priority
|
||||
return thread
|
||||
}
|
||||
})
|
||||
private var latch = CountDownLatch(1)
|
||||
|
||||
fun startHalloweenEpochTask() {
|
||||
var isFirst = true
|
||||
executor.scheduleAtFixedRate({
|
||||
updateEpoch()
|
||||
if (isFirst)
|
||||
latch.countDown()
|
||||
isFirst = false
|
||||
}, 0L, 90L, TimeUnit.DAYS) // Every 90 days
|
||||
}
|
||||
|
||||
fun waitUntilEpochHasBeenUpdated() {
|
||||
latch.await()
|
||||
}
|
||||
|
||||
fun updateEpoch() {
|
||||
LOGGER.info("Updating Spooky Season and Halloween Time")
|
||||
this.spookySeasonStartEpoch = getEpochMillisAtDate(20, Month.OCTOBER, false)
|
||||
this.spookySeasonEndEpoch = getEpochMillisAtDate(3, Month.NOVEMBER, true)
|
||||
this.halloweenStartEpoch = getEpochMillisAtDate(31, Month.OCTOBER, false)
|
||||
this.halloweenEndEpoch = getEpochMillisAtDate(31, Month.OCTOBER, true)
|
||||
LOGGER.info("Updated Spooky Season and Halloween Time!")
|
||||
}
|
||||
|
||||
fun isSpookySeason() = System.currentTimeMillis() in spookySeasonStartEpoch until spookySeasonEndEpoch
|
||||
fun isHalloween() = System.currentTimeMillis() in halloweenStartEpoch until halloweenEndEpoch
|
||||
|
||||
private fun getEpochMillisAtDate(dayOfMonth: Int, month: Month, isEnd: Boolean): Long {
|
||||
// Get the current year
|
||||
val currentYear = LocalDateTime.now().year
|
||||
|
||||
// Define the target date (20/10/CurrentYear at midnight)
|
||||
val targetDate = LocalDateTime.of(
|
||||
currentYear,
|
||||
month,
|
||||
dayOfMonth,
|
||||
if (isEnd)
|
||||
23
|
||||
else
|
||||
0,
|
||||
if (isEnd)
|
||||
59
|
||||
else
|
||||
0,
|
||||
if (isEnd)
|
||||
59
|
||||
else
|
||||
0,
|
||||
if (isEnd)
|
||||
999_999_999
|
||||
else
|
||||
0,
|
||||
)
|
||||
|
||||
// Check if the target date is in the past
|
||||
val now = LocalDateTime.now()
|
||||
val adjustedDate = if (now.isAfter(targetDate)) {
|
||||
// If in the past, adjust to the same date in the next year
|
||||
targetDate.plusYears(1)
|
||||
} else {
|
||||
// If in the future or today, use the original target date
|
||||
targetDate
|
||||
}
|
||||
|
||||
// Convert the adjusted date to epoch time in milliseconds
|
||||
return adjustedDate.atZone(ZoneOffset.systemDefault()).toInstant().toEpochMilli()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package net.sparklypower.sparklypaper
|
||||
|
||||
import ca.spottedleaf.dataconverter.types.MapType
|
||||
|
||||
object LegacyNBTRemapper {
|
||||
/**
|
||||
* Remaps hacky direct NBT storage used in SparklyPower to proper PersistentDataContainer data
|
||||
*/
|
||||
fun remap(tag: MapType<String>) {
|
||||
val perfectDreamsMap = tag.getMap<String>("PerfectDreams")
|
||||
|
||||
if (perfectDreamsMap != null) {
|
||||
val publicBukkitValuesMap = tag.getOrCreateMap<String>("PublicBukkitValues")
|
||||
|
||||
// The "setBoolean" functions do set bytes behind the scenes, just like how we do the things in SparklyPower
|
||||
perfectDreamsMap.getStringAndRemove("isJetpack")?.let {
|
||||
publicBukkitValuesMap.setBoolean("sparklypower:is_jetpack", it.toBoolean())
|
||||
}
|
||||
|
||||
perfectDreamsMap.getStringAndRemove("disallowCrafting")?.let {
|
||||
publicBukkitValuesMap.setBoolean("sparklypower:disallow_crafting", it.toBoolean())
|
||||
}
|
||||
|
||||
perfectDreamsMap.getStringAndRemove("poop")?.let {
|
||||
publicBukkitValuesMap.setBoolean("sparklypower:is_poop", it.toBoolean())
|
||||
}
|
||||
|
||||
perfectDreamsMap.getStringAndRemove("renamedBySeuZe")?.let {
|
||||
publicBukkitValuesMap.setBoolean("sparklypower:is_renamed_by_seu_ze", it.toBoolean())
|
||||
}
|
||||
|
||||
perfectDreamsMap.getStringAndRemove("isMonsterPickaxe")?.let {
|
||||
publicBukkitValuesMap.setBoolean("sparklypower:is_monster_tool", it.toBoolean())
|
||||
}
|
||||
|
||||
perfectDreamsMap.getStringAndRemove("itemOwner")?.let {
|
||||
publicBukkitValuesMap.setString("sparklypower:item_owner", it)
|
||||
}
|
||||
|
||||
perfectDreamsMap.getStringAndRemove("DreamFusca")?.let {
|
||||
publicBukkitValuesMap.setString("sparklypower:fusca_info", it)
|
||||
}
|
||||
|
||||
perfectDreamsMap.getStringAndRemove("isFusca")?.let {
|
||||
publicBukkitValuesMap.setBoolean("sparklypower:is_fusca", it.toBoolean())
|
||||
}
|
||||
|
||||
perfectDreamsMap.getStringAndRemove("fancyLeatherArmor")?.let {
|
||||
publicBukkitValuesMap.setBoolean("sparklypower:is_fancy_leather_armor", it.toBoolean())
|
||||
}
|
||||
|
||||
perfectDreamsMap.getStringAndRemove("caixaSecretaLevel")?.let {
|
||||
publicBukkitValuesMap.setInt("sparklypower:caixa_secreta_level", it.toInt())
|
||||
}
|
||||
|
||||
perfectDreamsMap.getStringAndRemove("caixaSecretaWorld")?.let {
|
||||
publicBukkitValuesMap.setString("sparklypower:caixa_secreta_world", it)
|
||||
}
|
||||
|
||||
perfectDreamsMap.getStringAndRemove("isMoveSpawners")?.let {
|
||||
publicBukkitValuesMap.setBoolean("sparklypower:is_move_spawners_tool", it.toBoolean())
|
||||
}
|
||||
|
||||
perfectDreamsMap.getStringAndRemove("spawnerType")?.let {
|
||||
publicBukkitValuesMap.setString("sparklypower:spawner_type", it)
|
||||
}
|
||||
|
||||
perfectDreamsMap.getStringAndRemove("isMochila")?.let {
|
||||
publicBukkitValuesMap.setBoolean("sparklypower:is_mochila", it.toBoolean())
|
||||
}
|
||||
|
||||
perfectDreamsMap.getStringAndRemove("mochilaId")?.let {
|
||||
publicBukkitValuesMap.setLong("sparklypower:mochila_id", it.toLong())
|
||||
}
|
||||
|
||||
perfectDreamsMap.getStringAndRemove("customMapOwner")?.let {
|
||||
publicBukkitValuesMap.setString("sparklypower:map_custom_owner", it)
|
||||
}
|
||||
|
||||
perfectDreamsMap.getStringAndRemove("quickTeleport")?.let {
|
||||
publicBukkitValuesMap.setBoolean("sparklypower:is_quick_resources_teleport", it.toBoolean())
|
||||
}
|
||||
|
||||
// If it is empty, then it means that we have migrated everything and we can remove the old PerfectDreams tag, yay!
|
||||
if (perfectDreamsMap.isEmpty)
|
||||
tag.remove("PerfectDreams")
|
||||
}
|
||||
}
|
||||
|
||||
private fun MapType<String>.getStringAndRemove(key: String): String? {
|
||||
val v = getString(key)
|
||||
remove(key)
|
||||
return v
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package net.sparklypower.sparklypaper
|
||||
|
||||
import ca.spottedleaf.moonrise.common.util.TickThread
|
||||
import java.util.concurrent.ThreadFactory
|
||||
|
||||
class ServerLevelTickExecutorThreadFactory(private val worldName: String) : ThreadFactory {
|
||||
override fun newThread(p0: Runnable): Thread {
|
||||
val tickThread = TickThread.ServerLevelTickThread(p0, "serverlevel-tick-worker [$worldName]")
|
||||
|
||||
if (tickThread.isDaemon) {
|
||||
tickThread.isDaemon = false
|
||||
}
|
||||
|
||||
if (tickThread.priority != 5) {
|
||||
tickThread.priority = 5
|
||||
}
|
||||
|
||||
return tickThread
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package net.sparklypower.sparklypaper
|
||||
|
||||
import net.minecraft.server.MinecraftServer
|
||||
import net.sparklypower.sparklypaper.commands.SparklyPaperCommand
|
||||
import org.bukkit.command.Command
|
||||
import org.checkerframework.checker.nullness.qual.NonNull
|
||||
import org.checkerframework.framework.qual.DefaultQualifier
|
||||
|
||||
@DefaultQualifier(NonNull::class)
|
||||
object SparklyPaperCommands {
|
||||
private val COMMANDS = mapOf(
|
||||
"sparklypaper" to SparklyPaperCommand("sparklypaper")
|
||||
)
|
||||
|
||||
fun registerCommands(server: MinecraftServer) {
|
||||
COMMANDS.forEach { (s: String, command: Command) ->
|
||||
server.server.commandMap.register(
|
||||
s, "SparklyPaper", command
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package net.sparklypower.sparklypaper.configs
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
class SparklyPaperConfig(
|
||||
@SerialName("config-version")
|
||||
override val configVersion: Int,
|
||||
@SerialName("parallel-world-ticking")
|
||||
val parallelWorldTicking: ParallelWorldTicking,
|
||||
@SerialName("world-settings")
|
||||
val worldSettings: Map<String, SparklyPaperWorldConfig>
|
||||
) : UpgradeableConfig {
|
||||
override fun isNewest() = true
|
||||
|
||||
override fun upgradeToNext() = error("This config is already the newest version!")
|
||||
|
||||
@Serializable
|
||||
class ParallelWorldTicking(
|
||||
val threads: Int
|
||||
)
|
||||
|
||||
@Serializable
|
||||
class SparklyPaperWorldConfig(
|
||||
@SerialName("skip-map-item-data-updates-if-map-does-not-have-craftmaprenderer")
|
||||
val skipMapItemDataUpdatesIfMapDoesNotHaveCraftMapRenderer: Boolean,
|
||||
@SerialName("blazingly-simple-farm-checks")
|
||||
val blazinglySimpleFarmChecks: BlazinglySimpleFarmChecks,
|
||||
@SerialName("ticks-per")
|
||||
val ticksPer: TicksPer,
|
||||
) {
|
||||
@Serializable
|
||||
data class BlazinglySimpleFarmChecks(
|
||||
val enabled: Boolean,
|
||||
@SerialName("default-growth-speed")
|
||||
val defaultGrowthSpeed: Float,
|
||||
@SerialName("moist-growth-speed")
|
||||
val moistGrowthSpeed: Float,
|
||||
@SerialName("skip-middle-aging-stages-for-crops")
|
||||
val skipMiddleAgingStagesForCrops: Boolean
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class TicksPer(
|
||||
@SerialName("hopper-cooldown-when-target-container-is-full")
|
||||
val hopperCooldownWhenTargetContainerIsFull: Int
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package net.sparklypower.sparklypaper.configs
|
||||
|
||||
import com.charleskorn.kaml.*
|
||||
import com.google.common.base.Throwables
|
||||
import kotlinx.serialization.SerializationException
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.encodeToString
|
||||
import net.sparklypower.sparklypaper.configs.previous.SparklyPaperConfigV1
|
||||
import org.bukkit.Bukkit
|
||||
import java.io.File
|
||||
import java.util.logging.Level
|
||||
|
||||
object SparklyPaperConfigUtils {
|
||||
private const val CURRENT_CONFIG_VERSION = 2
|
||||
val yaml = Yaml(
|
||||
configuration = YamlConfiguration(
|
||||
strictMode = false
|
||||
)
|
||||
)
|
||||
val deserializationStrategiesForVersions = mapOf(
|
||||
1 to SparklyPaperConfigV1.serializer(),
|
||||
CURRENT_CONFIG_VERSION to SparklyPaperConfig.serializer()
|
||||
)
|
||||
|
||||
lateinit var config: SparklyPaperConfig
|
||||
val logContainerCreationStacktraces = java.lang.Boolean.getBoolean("sparklypaper.logContainerCreationStacktraces")
|
||||
|
||||
fun init(configFile: File) {
|
||||
// Write default config if the file doesn't exist
|
||||
if (!configFile.exists()) {
|
||||
configFile.writeText(
|
||||
yaml.encodeToString(
|
||||
SparklyPaperConfig(
|
||||
CURRENT_CONFIG_VERSION,
|
||||
SparklyPaperConfig.ParallelWorldTicking(
|
||||
threads = 8
|
||||
),
|
||||
mapOf(
|
||||
"default" to SparklyPaperConfig.SparklyPaperWorldConfig(
|
||||
skipMapItemDataUpdatesIfMapDoesNotHaveCraftMapRenderer = true,
|
||||
blazinglySimpleFarmChecks = SparklyPaperConfig.SparklyPaperWorldConfig.BlazinglySimpleFarmChecks(
|
||||
enabled = false,
|
||||
defaultGrowthSpeed = 1.0f,
|
||||
moistGrowthSpeed = 5.0f,
|
||||
skipMiddleAgingStagesForCrops = true
|
||||
),
|
||||
SparklyPaperConfig.SparklyPaperWorldConfig.TicksPer(
|
||||
hopperCooldownWhenTargetContainerIsFull = 0
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
val loadedConfig = try {
|
||||
// Read the version file from the config before attempting to parse
|
||||
val yamlNode = yaml.parseToYamlNode(configFile.readText())
|
||||
var configVersion = yamlNode.yamlMap.getScalar("config-version")?.toInt() ?: 1 // The first config version didn't have the "config-version" key
|
||||
|
||||
if (configVersion != CURRENT_CONFIG_VERSION) {
|
||||
var upgradedVersion: UpgradeableConfig? = null
|
||||
|
||||
while (configVersion != CURRENT_CONFIG_VERSION) {
|
||||
Bukkit.getLogger().log(Level.INFO, "Attempting to upgrade SparklyPaper Config from version $configVersion to the next version...")
|
||||
|
||||
val upgradeableConfig = yaml.decodeFromYamlNode(deserializationStrategiesForVersions[configVersion]!!, yamlNode)
|
||||
if (!upgradeableConfig.isNewest()) {
|
||||
upgradedVersion = upgradeableConfig.upgradeToNext()
|
||||
|
||||
Bukkit.getLogger().log(Level.INFO, "Upgraded SparklyPaper Config from version $configVersion to ${upgradedVersion.configVersion}")
|
||||
configVersion = upgradedVersion.configVersion
|
||||
}
|
||||
}
|
||||
|
||||
upgradedVersion as SparklyPaperConfig
|
||||
} else {
|
||||
yaml.decodeFromYamlNode(SparklyPaperConfig.serializer(), yamlNode)
|
||||
}
|
||||
} catch (e: SerializationException) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, "Could not load sparklypaper.yml, please correct your syntax errors", e)
|
||||
throw Throwables.propagate(e)
|
||||
}
|
||||
// Rewrite the config file to remove old fields and stuff
|
||||
// TODO: Maybe handle this in another way? This feels kinda bad
|
||||
configFile.writeText(yaml.encodeToString(loadedConfig))
|
||||
config = loadedConfig
|
||||
}
|
||||
|
||||
fun getWorldSettings(levelName: String): SparklyPaperConfig.SparklyPaperWorldConfig {
|
||||
return config.worldSettings[levelName] ?: config.worldSettings["default"] ?: error("Missing default world-settings in sparklypaper.yml!")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package net.sparklypower.sparklypaper.configs
|
||||
|
||||
interface UpgradeableConfig {
|
||||
abstract val configVersion: Int
|
||||
fun isNewest(): Boolean
|
||||
fun upgradeToNext(): UpgradeableConfig
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package net.sparklypower.sparklypaper.configs.previous
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import net.sparklypower.sparklypaper.configs.SparklyPaperConfig
|
||||
import net.sparklypower.sparklypaper.configs.UpgradeableConfig
|
||||
|
||||
@Serializable
|
||||
class SparklyPaperConfigV1(
|
||||
@SerialName("parallel-world-ticking")
|
||||
val parallelWorldTicking: ParallelWorldTicking,
|
||||
@SerialName("world-settings")
|
||||
val worldSettings: Map<String, SparklyPaperWorldConfig>
|
||||
) : UpgradeableConfig {
|
||||
override val configVersion = 1
|
||||
|
||||
override fun isNewest() = false
|
||||
|
||||
override fun upgradeToNext(): UpgradeableConfig {
|
||||
return SparklyPaperConfig(
|
||||
2,
|
||||
SparklyPaperConfig.ParallelWorldTicking(
|
||||
this.parallelWorldTicking.threads
|
||||
),
|
||||
worldSettings.mapValues {
|
||||
SparklyPaperConfig.SparklyPaperWorldConfig(
|
||||
it.value.skipMapItemDataUpdatesIfMapDoesNotHaveCraftMapRenderer,
|
||||
SparklyPaperConfig.SparklyPaperWorldConfig.BlazinglySimpleFarmChecks(
|
||||
it.value.blazinglySimpleFarmChecks.enabled,
|
||||
it.value.blazinglySimpleFarmChecks.defaultGrowthSpeed,
|
||||
it.value.blazinglySimpleFarmChecks.moistGrowthSpeed,
|
||||
it.value.blazinglySimpleFarmChecks.skipMiddleAgingStagesForCrops,
|
||||
),
|
||||
SparklyPaperConfig.SparklyPaperWorldConfig.TicksPer(
|
||||
0
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class ParallelWorldTicking(
|
||||
val threads: Int
|
||||
)
|
||||
|
||||
@Serializable
|
||||
class SparklyPaperWorldConfig(
|
||||
@SerialName("skip-map-item-data-updates-if-map-does-not-have-craftmaprenderer")
|
||||
val skipMapItemDataUpdatesIfMapDoesNotHaveCraftMapRenderer: Boolean,
|
||||
@SerialName("blazingly-simple-farm-checks")
|
||||
val blazinglySimpleFarmChecks: BlazinglySimpleFarmChecks
|
||||
) {
|
||||
@Serializable
|
||||
data class BlazinglySimpleFarmChecks(
|
||||
val enabled: Boolean,
|
||||
@SerialName("default-growth-speed")
|
||||
val defaultGrowthSpeed: Float,
|
||||
@SerialName("moist-growth-speed")
|
||||
val moistGrowthSpeed: Float,
|
||||
@SerialName("skip-middle-aging-stages-for-crops")
|
||||
val skipMiddleAgingStagesForCrops: Boolean
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user