mirror of
https://github.com/SparklyPower/SparklyPaper.git
synced 2025-12-19 15:09:27 +00:00
Blazingly Simple Farm Checks
This commit is contained in:
@@ -18,6 +18,7 @@ SparklyPaper's config file is `sparklypaper.yml`, the file is, by default, place
|
||||
|
||||
* Configurable Farm Land moisture tick rate when the block is already moisturised
|
||||
* The `isNearWater` check is costly, especially if you have a lot of farm lands. If the block is already moistured, we can change the tick rate of it to avoid these expensive `isNearWater` checks.
|
||||
* (Incompatible with the Blazingly Simple Farm Checks feature)
|
||||
* 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. Currently, we only check if both Vec3 objects have the same identity, that means, if they are literally the same object. (that works because Minecraft's code reuses the Vec3 object when caching the current delta movement)
|
||||
* Skip `MapItem#update()` if the map does not have the default `CraftMapRenderer` present
|
||||
@@ -42,6 +43,11 @@ SparklyPaper's config file is `sparklypaper.yml`, the file is, by default, place
|
||||
* Then, we check if the scheduler has any pending tasks by checking if `currentlyExecuting` is not empty or if `oneTimeDelayed` is not empty. This avoids the thread checks and unnecessary `size()` calls.
|
||||
* 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). With this change, the `executeTick` loop in `tickChildren` CPU % usage drops from 2.48% to 0.61% in a server with ~12k entities!
|
||||
* Of course, this doesn't mean that `ArrayDeque#size()` is slow! It is mostly that because the `executeTick` function is called each tick for each entity, it would be better for us to avoid as many useless calls as possible.
|
||||
* Blazingly Simple Farm Checks
|
||||
* Changes Minecraft's farm checks for crops, stem blocks, and farm lands to be simpler and less resource intensive
|
||||
* If a farm land is moisturised, the farm land won't check if there's water nearby to avoid intensive block checks. Now, instead of the farm land checking for moisture, the crops themselves will check when attempting to grow, this way, farms with fully grown crops won't cause lag.
|
||||
* The growth speed of crops and stems are now fixed based on if the block below them is moist or not, instead of doing vanilla's behavior of "check all blocks nearby to see if at least one of them is moist" and "if the blocks nearby are of the same time, make them grow slower".
|
||||
* In my opinion: Who cares about the vanilla behavior lol, most players only care about farm land + crop = crop go brrrr
|
||||
* Check how much MSPT (milliseconds per tick) each world is using in `/mspt`
|
||||
* Useful to figure out which worlds are lagging your server.
|
||||

|
||||
|
||||
@@ -5,7 +5,7 @@ Subject: [PATCH] SparklyPaper config files
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
index cf605aa56adf7f80d3b409f60a92a5ca7ae8fd07..8c20221736419bcb9c3e570af624eef8e6fc3b09 100644
|
||||
index 1c9742ad81f04052d2c3bc18c7636f45b2fc5160..9a6915a87ae8aa4ffefea575d7a7d5199c800799 100644
|
||||
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -218,6 +218,15 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
@@ -225,10 +225,10 @@ index 0000000000000000000000000000000000000000..6398c7b40ba82ffc8588eca458ce92c2
|
||||
\ No newline at end of file
|
||||
diff --git a/src/main/kotlin/net/sparklypower/sparklypaper/configs/SparklyPaperConfigUtils.kt b/src/main/kotlin/net/sparklypower/sparklypaper/configs/SparklyPaperConfigUtils.kt
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..4c736abcf64855e8fdfdeb2ba646288283ae278a
|
||||
index 0000000000000000000000000000000000000000..250b19027db75b1ba44383621215fd2c3370c967
|
||||
--- /dev/null
|
||||
+++ b/src/main/kotlin/net/sparklypower/sparklypaper/configs/SparklyPaperConfigUtils.kt
|
||||
@@ -0,0 +1,50 @@
|
||||
@@ -0,0 +1,55 @@
|
||||
+package net.sparklypower.sparklypaper.configs
|
||||
+
|
||||
+import com.charleskorn.kaml.Yaml
|
||||
@@ -256,6 +256,11 @@ index 0000000000000000000000000000000000000000..4c736abcf64855e8fdfdeb2ba6462882
|
||||
+ mapOf(
|
||||
+ "default" to SparklyPaperWorldConfig(
|
||||
+ skipMapItemDataUpdatesIfMapDoesNotHaveCraftMapRenderer = true,
|
||||
+ blazinglySimpleFarmChecks = SparklyPaperWorldConfig.BlazinglySimpleFarmChecks(
|
||||
+ false,
|
||||
+ 1.0f,
|
||||
+ 5.0f,
|
||||
+ ),
|
||||
+ SparklyPaperWorldConfig.TickRates(
|
||||
+ farmWhenMoisturised = 1
|
||||
+ )
|
||||
@@ -282,10 +287,10 @@ index 0000000000000000000000000000000000000000..4c736abcf64855e8fdfdeb2ba6462882
|
||||
\ No newline at end of file
|
||||
diff --git a/src/main/kotlin/net/sparklypower/sparklypaper/configs/SparklyPaperWorldConfig.kt b/src/main/kotlin/net/sparklypower/sparklypaper/configs/SparklyPaperWorldConfig.kt
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..1b0851f6c66910773f99e9a6c6a99abc90164f51
|
||||
index 0000000000000000000000000000000000000000..41f2482097d7b835dcec85bb33ab0ce5f6f48eec
|
||||
--- /dev/null
|
||||
+++ b/src/main/kotlin/net/sparklypower/sparklypaper/configs/SparklyPaperWorldConfig.kt
|
||||
@@ -0,0 +1,18 @@
|
||||
@@ -0,0 +1,29 @@
|
||||
+package net.sparklypower.sparklypaper.configs
|
||||
+
|
||||
+import kotlinx.serialization.SerialName
|
||||
@@ -295,10 +300,21 @@ index 0000000000000000000000000000000000000000..1b0851f6c66910773f99e9a6c6a99abc
|
||||
+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("tick-rates")
|
||||
+ val tickRates: TickRates
|
||||
+) {
|
||||
+ @Serializable
|
||||
+ data class BlazinglySimpleFarmChecks(
|
||||
+ val enabled: Boolean,
|
||||
+ @SerialName("default-growth-speed")
|
||||
+ val defaultGrowthSpeed: Float,
|
||||
+ @SerialName("moist-growth-speed")
|
||||
+ val moistGrowthSpeed: Float
|
||||
+ )
|
||||
+
|
||||
+ @Serializable
|
||||
+ data class TickRates(
|
||||
+ @SerialName("farm-when-moisturised")
|
||||
+ val farmWhenMoisturised: Int
|
||||
|
||||
174
patches/server/0011-Blazingly-Simple-Farm-Checks.patch
Normal file
174
patches/server/0011-Blazingly-Simple-Farm-Checks.patch
Normal file
@@ -0,0 +1,174 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||
Date: Mon, 20 Nov 2023 20:17:56 -0300
|
||||
Subject: [PATCH] Blazingly Simple Farm Checks
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/CropBlock.java b/src/main/java/net/minecraft/world/level/block/CropBlock.java
|
||||
index 6365ddea0c23bc5d4009d98915f2b39aed2a0328..2e39555a9202bd1474dd2229ece4ebab3d35f898 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/CropBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/CropBlock.java
|
||||
@@ -74,6 +74,49 @@ public class CropBlock extends BushBlock implements BonemealableBlock {
|
||||
int i = this.getAge(state);
|
||||
|
||||
if (i < this.getMaxAge()) {
|
||||
+ // SparklyPaper start - Blazingly simple farm checks
|
||||
+ if (world.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 = world.getBlockState(farmlandBelowTheCurrentBlock);
|
||||
+ float f = world.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 = world.sparklyPaperConfig.getBlazinglySimpleFarmChecks().getMoistGrowthSpeed();
|
||||
+ isCurrentFarmlandStateMoist = true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // Spigot start
|
||||
+ int modifier;
|
||||
+ if (this == Blocks.BEETROOTS) {
|
||||
+ modifier = world.spigotConfig.beetrootModifier;
|
||||
+ } else if (this == Blocks.CARROTS) {
|
||||
+ modifier = world.spigotConfig.carrotModifier;
|
||||
+ } else if (this == Blocks.POTATOES) {
|
||||
+ modifier = world.spigotConfig.potatoModifier;
|
||||
+ // Paper start
|
||||
+ } else if (this == Blocks.TORCHFLOWER_CROP) {
|
||||
+ modifier = world.spigotConfig.torchFlowerModifier;
|
||||
+ // Paper end
|
||||
+ } else {
|
||||
+ modifier = world.spigotConfig.wheatModifier;
|
||||
+ }
|
||||
+
|
||||
+ if (random.nextFloat() < (modifier / (100.0f * (Math.floor((25.0F / f) + 1))))) { // Spigot - SPIGOT-7159: Better modifier resolution
|
||||
+ // Spigot 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 (i + 1 == getMaxAge() && isCurrentFarmlandStateMoist && !FarmBlock.isNearWater(world, farmlandBelowTheCurrentBlock)) {
|
||||
+ // Whoops, farm land ain't moist!
|
||||
+ // From FarmBlock, set the moisture to 0
|
||||
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleMoistureChangeEvent(world, farmlandBelowTheCurrentBlock, (BlockState) farmlandBelowTheCurrentBlockData.setValue(FarmBlock.MOISTURE, 0), 2); // CraftBukkit
|
||||
+ }
|
||||
+ CraftEventFactory.handleBlockGrowEvent(world, pos, this.getStateForAge(i + 1), 2); // CraftBukkit
|
||||
+ }
|
||||
+ } else {
|
||||
float f = CropBlock.getGrowthSpeed(this, world, pos);
|
||||
|
||||
// Spigot start
|
||||
@@ -96,6 +139,8 @@ public class CropBlock extends BushBlock implements BonemealableBlock {
|
||||
// Spigot end
|
||||
CraftEventFactory.handleBlockGrowEvent(world, pos, this.getStateForAge(i + 1), 2); // CraftBukkit
|
||||
}
|
||||
+ }
|
||||
+ // SparklyPaper end
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/FarmBlock.java b/src/main/java/net/minecraft/world/level/block/FarmBlock.java
|
||||
index 590a573a9b5099d3062031dc54978993cdd912ad..544131216aff2b2b54b8690d4321a194deab1589 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/FarmBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/FarmBlock.java
|
||||
@@ -1,6 +1,5 @@
|
||||
package net.minecraft.world.level.block;
|
||||
|
||||
-import java.util.Iterator;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
@@ -85,6 +84,19 @@ public class FarmBlock extends Block {
|
||||
@Override
|
||||
public void randomTick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
|
||||
int i = (Integer) state.getValue(FarmBlock.MOISTURE);
|
||||
+ // SparklyPaper start - Blazingly simple farm checks
|
||||
+ if (world.sparklyPaperConfig.getBlazinglySimpleFarmChecks().getEnabled()) {
|
||||
+ if (i == 0) { // We only care about non-moisturised farm blocks
|
||||
+ if (FarmBlock.isNearWater(world, pos)) {
|
||||
+ // Make it MOIST!
|
||||
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleMoistureChangeEvent(world, pos, (BlockState) state.setValue(FarmBlock.MOISTURE, 7), 2); // CraftBukkit
|
||||
+ } else if (!FarmBlock.shouldMaintainFarmland(world, pos)) {
|
||||
+ FarmBlock.turnToDirt((Entity) null, state, world, pos);
|
||||
+ }
|
||||
+ }
|
||||
+ return;
|
||||
+ }
|
||||
+ // SparklyPaper end
|
||||
if (i > 0 && world.sparklyPaperConfig.getTickRates().getFarmWhenMoisturised() != 1 && (world.sparklyPaperConfig.getTickRates().getFarmWhenMoisturised() < 1 || (net.minecraft.server.MinecraftServer.currentTick + pos.hashCode()) % world.sparklyPaperConfig.getTickRates().getFarmWhenMoisturised() != 0)) { return; } // SparklyPaper
|
||||
|
||||
if (!FarmBlock.isNearWater(world, pos) && !world.isRainingAt(pos.above())) {
|
||||
@@ -142,7 +154,7 @@ public class FarmBlock extends Block {
|
||||
return world.getBlockState(pos.above()).is(BlockTags.MAINTAINS_FARMLAND);
|
||||
}
|
||||
|
||||
- private static boolean isNearWater(LevelReader world, BlockPos pos) {
|
||||
+ public static boolean isNearWater(LevelReader world, BlockPos pos) { // SparklyPaper - make public for the Blazingly simple farm checks
|
||||
// Paper start - remove abstract block iteration
|
||||
int xOff = pos.getX();
|
||||
int yOff = pos.getY();
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/StemBlock.java b/src/main/java/net/minecraft/world/level/block/StemBlock.java
|
||||
index 0d9be3b28ba4957c3f4da5455283fca903836c91..d20af373521636a0fb42712effd09619b9c78960 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/StemBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/StemBlock.java
|
||||
@@ -51,6 +51,50 @@ public class StemBlock extends BushBlock implements BonemealableBlock {
|
||||
@Override
|
||||
public void randomTick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
|
||||
if (world.getRawBrightness(pos, 0) >= 9) {
|
||||
+ // SparklyPaper start - Blazingly simple farm checks
|
||||
+ if (world.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 = world.getBlockState(farmlandBelowTheCurrentBlock);
|
||||
+ float f = world.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 = world.sparklyPaperConfig.getBlazinglySimpleFarmChecks().getMoistGrowthSpeed();
|
||||
+ isCurrentFarmlandStateMoist = true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (random.nextFloat() < ((this == Blocks.PUMPKIN_STEM ? world.spigotConfig.pumpkinModifier : world.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);
|
||||
+ CraftEventFactory.handleBlockGrowEvent(world, pos, state, 2); // CraftBukkit
|
||||
+ } else {
|
||||
+ Direction enumdirection = Direction.Plane.HORIZONTAL.getRandomDirection(random);
|
||||
+ BlockPos blockposition1 = pos.relative(enumdirection);
|
||||
+ BlockState iblockdata1 = world.getBlockState(blockposition1.below());
|
||||
+
|
||||
+ if (world.getBlockState(blockposition1).isAir() && (iblockdata1.is(Blocks.FARMLAND) || iblockdata1.is(BlockTags.DIRT))) {
|
||||
+ // CraftBukkit start
|
||||
+ if (!CraftEventFactory.handleBlockGrowEvent(world, blockposition1, this.fruit.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(world, farmlandBelowTheCurrentBlock)) {
|
||||
+ // Whoops, farm land ain't moist!
|
||||
+ // From FarmBlock, set the moisture to 0
|
||||
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleMoistureChangeEvent(world, farmlandBelowTheCurrentBlock, (BlockState) farmlandBelowTheCurrentBlockData.setValue(FarmBlock.MOISTURE, 0), 2); // CraftBukkit
|
||||
+ }
|
||||
+ world.setBlockAndUpdate(pos, (BlockState) this.fruit.getAttachedStem().defaultBlockState().setValue(HorizontalDirectionalBlock.FACING, enumdirection));
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ } else {
|
||||
float f = CropBlock.getGrowthSpeed(this, world, pos);
|
||||
|
||||
if (random.nextFloat() < ((this == Blocks.PUMPKIN_STEM ? world.spigotConfig.pumpkinModifier : world.spigotConfig.melonModifier) / (100.0f * (Math.floor((25.0F / f) + 1))))) { // Spigot - SPIGOT-7159: Better modifier resolution
|
||||
@@ -74,7 +118,8 @@ public class StemBlock extends BushBlock implements BonemealableBlock {
|
||||
}
|
||||
}
|
||||
}
|
||||
-
|
||||
+ }
|
||||
+ // SparklyPaper end
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user