mirror of
https://github.com/LeavesMC/Leaves.git
synced 2025-12-19 14:59:32 +00:00
231 lines
8.8 KiB
Diff
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);
|
|
+ }
|
|
+}
|