9
0
mirror of https://github.com/LeavesMC/Leaves.git synced 2025-12-19 14:59:32 +00:00
Files
LeavesMC/patches/server/0031-Use-aging-cache-for-biome-temperatures.patch
2024-07-19 20:38:04 +08:00

237 lines
8.8 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: violetc <58360096+s-yh-china@users.noreply.github.com>
Date: Thu, 18 Aug 2022 16:53:45 +0800
Subject: [PATCH] Use aging cache for biome temperatures
This patch is Powered by Pufferfish(https://github.com/pufferfish-gg/Pufferfish)
diff --git a/src/main/java/net/minecraft/world/level/biome/Biome.java b/src/main/java/net/minecraft/world/level/biome/Biome.java
index 90c165c890a2d998e3b0af9b4310e3995ede6f64..6db6f96af0058d5eaf725e743d3019e3a3b8604c 100644
--- a/src/main/java/net/minecraft/world/level/biome/Biome.java
+++ b/src/main/java/net/minecraft/world/level/biome/Biome.java
@@ -63,7 +63,17 @@ public final class Biome {
private final BiomeGenerationSettings generationSettings;
private final MobSpawnSettings mobSettings;
private final BiomeSpecialEffects specialEffects;
- private final ThreadLocal<Long2FloatLinkedOpenHashMap> temperatureCache = ThreadLocal.withInitial(() -> Util.make(() -> {
+ // Leaves start - use our cache
+ private final ThreadLocal<Long2FloatLinkedOpenHashMap> temperatureCache;
+ private final ThreadLocal<org.leavesmc.leaves.structs.Long2FloatAgingCache> temperatureAgingCache;
+
+ Biome(Biome.ClimateSettings weather, BiomeSpecialEffects effects, BiomeGenerationSettings generationSettings, MobSpawnSettings spawnSettings) {
+ this.climateSettings = weather;
+ this.generationSettings = generationSettings;
+ this.mobSettings = spawnSettings;
+ this.specialEffects = effects;
+
+ temperatureCache = ThreadLocal.withInitial(() -> Util.make(() -> {
Long2FloatLinkedOpenHashMap long2FloatLinkedOpenHashMap = new Long2FloatLinkedOpenHashMap(1024, 0.25F) {
protected void rehash(int i) {
}
@@ -71,13 +81,13 @@ public final class Biome {
long2FloatLinkedOpenHashMap.defaultReturnValue(Float.NaN);
return long2FloatLinkedOpenHashMap;
}));
-
- Biome(Biome.ClimateSettings weather, BiomeSpecialEffects effects, BiomeGenerationSettings generationSettings, MobSpawnSettings spawnSettings) {
- this.climateSettings = weather;
- this.generationSettings = generationSettings;
- this.mobSettings = spawnSettings;
- this.specialEffects = effects;
+ temperatureAgingCache = ThreadLocal.withInitial(() -> {
+ return Util.make(() -> {
+ return new org.leavesmc.leaves.structs.Long2FloatAgingCache(TEMPERATURE_CACHE_SIZE);
+ });
+ });
}
+ // Leaves end - use our cache
public int getSkyColor() {
return this.specialEffects.getSkyColor();
@@ -111,7 +121,33 @@ public final class Biome {
@Deprecated
public float getTemperature(BlockPos blockPos) {
- return this.getHeightAdjustedTemperature(blockPos); // Paper - optimise random ticking
+ long l = blockPos.asLong();
+ // Leaves start - use our cache
+ if (org.leavesmc.leaves.LeavesConfig.biomeTemperaturesUseAgingCache) {
+ org.leavesmc.leaves.structs.Long2FloatAgingCache cache = this.temperatureAgingCache.get();
+ float f = cache.getValue(l);
+ if (!Float.isNaN(f)) {
+ return f;
+ } else {
+ float g = this.getHeightAdjustedTemperature(blockPos);
+ cache.putValue(l, g);
+ return g;
+ }
+ } else {
+ Long2FloatLinkedOpenHashMap long2FloatLinkedOpenHashMap = this.temperatureCache.get();
+ float f = long2FloatLinkedOpenHashMap.get(l);
+ if (!Float.isNaN(f)) {
+ return f;
+ } else {
+ float g = this.getHeightAdjustedTemperature(blockPos);
+ if (long2FloatLinkedOpenHashMap.size() == 1024) {
+ long2FloatLinkedOpenHashMap.removeFirstFloat();
+ }
+ long2FloatLinkedOpenHashMap.put(l, g);
+ return g;
+ }
+ }
+ // Leaves end - use our cache
}
public boolean shouldFreeze(LevelReader world, BlockPos blockPos) {
@@ -139,6 +175,7 @@ public final class Biome {
return false;
}
+ // Leaves end - use our cache
}
public boolean coldEnoughToSnow(BlockPos pos) {
@@ -166,6 +203,7 @@ public final class Biome {
return false;
}
+ // Leaves end - use our cache
}
public BiomeGenerationSettings getGenerationSettings() {
@@ -317,6 +355,7 @@ public final class Biome {
+ this.generationSettings
+ ",\n}";
}
+ // Leaves end - use our cache
}
public static record ClimateSettings(boolean hasPrecipitation, float temperature, Biome.TemperatureModifier temperatureModifier, float downfall) {
diff --git a/src/main/java/org/leavesmc/leaves/structs/Long2FloatAgingCache.java b/src/main/java/org/leavesmc/leaves/structs/Long2FloatAgingCache.java
new file mode 100644
index 0000000000000000000000000000000000000000..cd8b1bbfe553c28b75ea92d344364650756e9fdd
--- /dev/null
+++ b/src/main/java/org/leavesmc/leaves/structs/Long2FloatAgingCache.java
@@ -0,0 +1,121 @@
+package org.leavesmc.leaves.structs;
+
+import it.unimi.dsi.fastutil.HashCommon;
+
+// Powered by Pufferfish(https://github.com/pufferfish-gg/Pufferfish)
+
+/**
+ * A replacement for the cache used in Biome.
+ */
+public class Long2FloatAgingCache {
+
+ private static class AgingEntry {
+ private long data;
+ private float value;
+ private int uses = 0;
+ private int age = 0;
+
+ private AgingEntry(long data, float value) {
+ this.data = data;
+ this.value = value;
+ }
+
+ public void replace(long data, float flag) {
+ this.data = data;
+ this.value = flag;
+ }
+
+ public int getValue() {
+ return this.uses - (this.age >> 1); // age isn't as important as uses
+ }
+
+ public void incrementUses() {
+ this.uses = this.uses + 1 & Integer.MAX_VALUE;
+ }
+
+ public void incrementAge() {
+ this.age = this.age + 1 & Integer.MAX_VALUE;
+ }
+ }
+
+ private final AgingEntry[] entries;
+ private final int mask;
+ private final int maxDistance; // the most amount of entries to check for a value
+
+ public Long2FloatAgingCache(int size) {
+ int arraySize = HashCommon.nextPowerOfTwo(size);
+ this.entries = new AgingEntry[arraySize];
+ this.mask = arraySize - 1;
+ this.maxDistance = Math.min(arraySize, 4);
+ }
+
+ public float getValue(long data) {
+ AgingEntry curr;
+ int pos;
+
+ if ((curr = this.entries[pos = HashCommon.mix(HashCommon.long2int(data)) & this.mask]) == null) {
+ return Float.NaN;
+ } else if (data == curr.data) {
+ curr.incrementUses();
+ return curr.value;
+ }
+
+ int checked = 1; // start at 1 because we already checked the first spot above
+
+ while ((curr = this.entries[pos = (pos + 1) & this.mask]) != null) {
+ if (data == curr.data) {
+ curr.incrementUses();
+ return curr.value;
+ } else if (++checked >= this.maxDistance) {
+ break;
+ }
+ }
+
+ return Float.NaN;
+ }
+
+ public void putValue(long data, float value) {
+ AgingEntry curr;
+ int pos;
+
+ if ((curr = this.entries[pos = HashCommon.mix(HashCommon.long2int(data)) & this.mask]) == null) {
+ this.entries[pos] = new AgingEntry(data, value); // add
+ return;
+ } else if (data == curr.data) {
+ curr.incrementUses();
+ return;
+ }
+
+ int checked = 1; // start at 1 because we already checked the first spot above
+
+ while ((curr = this.entries[pos = (pos + 1) & this.mask]) != null) {
+ if (data == curr.data) {
+ curr.incrementUses();
+ return;
+ } else if (++checked >= this.maxDistance) {
+ this.forceAdd(data, value);
+ return;
+ }
+ }
+
+ this.entries[pos] = new AgingEntry(data, value); // add
+ }
+
+ private void forceAdd(long data, float value) {
+ int expectedPos = HashCommon.mix(HashCommon.long2int(data)) & this.mask;
+ AgingEntry entryToRemove = this.entries[expectedPos];
+
+ for (int i = expectedPos + 1; i < expectedPos + this.maxDistance; i++) {
+ int pos = i & this.mask;
+ AgingEntry entry = this.entries[pos];
+ if (entry.getValue() < entryToRemove.getValue()) {
+ entryToRemove = entry;
+ }
+
+ entry.incrementAge(); // use this as a mechanism to age the other entries
+ }
+
+ // remove the least used/oldest entry
+ entryToRemove.replace(data, value);
+ }
+}