9
0
mirror of https://github.com/LeavesMC/Leaves.git synced 2025-12-19 14:59:32 +00:00
Files
LeavesMC/patches/server/0038-Use-aging-cache-for-biome-temperatures.patch
2023-09-28 18:12:42 +08:00

231 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 65012a12e1430956ef55ced56773e6354ac26444..fe43432da26a3570c993b5592b7b8020331bdb74 100644
--- a/src/main/java/net/minecraft/world/level/biome/Biome.java
+++ b/src/main/java/net/minecraft/world/level/biome/Biome.java
@@ -66,23 +66,37 @@ public final class Biome {
private final BiomeGenerationSettings generationSettings;
private final MobSpawnSettings mobSettings;
private final BiomeSpecialEffects specialEffects;
- private final ThreadLocal<Long2FloatLinkedOpenHashMap> temperatureCache = ThreadLocal.withInitial(() -> {
- return Util.make(() -> {
- Long2FloatLinkedOpenHashMap long2FloatLinkedOpenHashMap = new Long2FloatLinkedOpenHashMap(1024, 0.25F) {
- protected void rehash(int i) {
- }
- };
- long2FloatLinkedOpenHashMap.defaultReturnValue(Float.NaN);
- return long2FloatLinkedOpenHashMap;
- });
- });
+ // Leaves start - use our cache
+ private final ThreadLocal<Long2FloatLinkedOpenHashMap> temperatureCache;
+ private final ThreadLocal<top.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;
+ if (top.leavesmc.leaves.LeavesConfig.biomeTemperaturesUseAgingCache) {
+ temperatureCache = null;
+ temperatureAgingCache = ThreadLocal.withInitial(() -> {
+ return Util.make(() -> {
+ return new top.leavesmc.leaves.structs.Long2FloatAgingCache(TEMPERATURE_CACHE_SIZE);
+ });
+ });
+ } else {
+ temperatureCache = ThreadLocal.withInitial(() -> {
+ return Util.make(() -> {
+ Long2FloatLinkedOpenHashMap long2FloatLinkedOpenHashMap = new Long2FloatLinkedOpenHashMap(1024, 0.25F) {
+ protected void rehash(int i) {
+ }
+ };
+ long2FloatLinkedOpenHashMap.defaultReturnValue(Float.NaN);
+ return long2FloatLinkedOpenHashMap;
+ });
+ });
+ temperatureAgingCache = null;
+ }
}
+ // Leaves end - use our cache
public int getSkyColor() {
return this.specialEffects.getSkyColor();
@@ -118,19 +132,33 @@ public final class Biome {
@Deprecated
public float getTemperature(BlockPos blockPos) {
long l = blockPos.asLong();
- 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();
+ // Leaves start - use our cache
+ if (top.leavesmc.leaves.LeavesConfig.biomeTemperaturesUseAgingCache) {
+ top.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;
+ long2FloatLinkedOpenHashMap.put(l, g);
+ return g;
+ }
}
+ // Leaves end - use our cache
}
public boolean shouldFreeze(LevelReader world, BlockPos blockPos) {
diff --git a/src/main/java/top/leavesmc/leaves/structs/Long2FloatAgingCache.java b/src/main/java/top/leavesmc/leaves/structs/Long2FloatAgingCache.java
new file mode 100644
index 0000000000000000000000000000000000000000..26f9d4d9099739d6ddc159184a20e2ae9abde5cd
--- /dev/null
+++ b/src/main/java/top/leavesmc/leaves/structs/Long2FloatAgingCache.java
@@ -0,0 +1,121 @@
+package top.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);
+ }
+}