From b19d5a930ed7f32728892009a3bd17c046788de6 Mon Sep 17 00:00:00 2001 From: Etil <81570777+etil2jz@users.noreply.github.com> Date: Sun, 19 Dec 2021 14:23:53 +0100 Subject: [PATCH] More Lithium patches --- ...0080-lithium-chunk-structure-storage.patch | 87 +++++++++++ .../0081-lithium-ai-task-goat-jump.patch | 147 ++++++++++++++++++ 2 files changed, 234 insertions(+) create mode 100644 patches/server/0080-lithium-chunk-structure-storage.patch create mode 100644 patches/server/0081-lithium-ai-task-goat-jump.patch diff --git a/patches/server/0080-lithium-chunk-structure-storage.patch b/patches/server/0080-lithium-chunk-structure-storage.patch new file mode 100644 index 0000000..8e154f6 --- /dev/null +++ b/patches/server/0080-lithium-chunk-structure-storage.patch @@ -0,0 +1,87 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Etil <81570777+etil2jz@users.noreply.github.com> +Date: Sun, 19 Dec 2021 13:49:51 +0100 +Subject: [PATCH] lithium: chunk structure storage + +Original code by CaffeineMC, licensed under GNU Lesser General Public License v3.0 +You can find the original code on https://github.com/CaffeineMC/lithium-fabric (Yarn mappings) + +diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java b/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java +index 5aeaaae6f15050a2da271fe196d0a234ecafc8a1..15b645403bb3d5125a02c75d608e83b48c8bbd4d 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java ++++ b/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java +@@ -51,6 +51,8 @@ import net.minecraft.world.ticks.SerializableTickContainer; + import net.minecraft.world.ticks.TickContainerAccess; + import org.apache.logging.log4j.LogManager; + import org.apache.logging.log4j.Logger; ++import java.util.HashMap; // JettPack ++import it.unimi.dsi.fastutil.longs.LongSets; // JettPack + + public abstract class ChunkAccess implements BlockGetter, BiomeManager.NoiseBiomeSource, FeatureAccess { + +@@ -71,7 +73,7 @@ public abstract class ChunkAccess implements BlockGetter, BiomeManager.NoiseBiom + protected BlendingData blendingData; + public final Map heightmaps = Maps.newEnumMap(Heightmap.Types.class); + private final Map, StructureStart> structureStarts = Maps.newHashMap(); +- private final Map, LongSet> structuresRefences = Maps.newHashMap(); ++ private final Map, LongSet> structureReferences = Maps.newHashMap(); // JettPack - fix typo in mojmap + protected final Map pendingBlockEntities = Maps.newHashMap(); + public final Map blockEntities = Maps.newHashMap(); + protected final LevelHeightAccessor levelHeightAccessor; +@@ -258,6 +260,11 @@ public abstract class ChunkAccess implements BlockGetter, BiomeManager.NoiseBiom + } + + public void setAllStarts(Map, StructureStart> structureStarts) { ++ // JettPack start - lithium: chunk.structure_storage ++ if (structureStarts instanceof HashMap) { ++ structureStarts.values().removeIf(structureStart -> structureStart == null || structureStart == StructureStart.INVALID_START); ++ } ++ // JettPack end + this.structureStarts.clear(); + this.structureStarts.putAll(structureStarts); + this.unsaved = true; +@@ -265,14 +272,12 @@ public abstract class ChunkAccess implements BlockGetter, BiomeManager.NoiseBiom + + @Override + public LongSet getReferencesForFeature(StructureFeature structure) { +- return (LongSet) this.structuresRefences.computeIfAbsent(structure, (structuregenerator1) -> { +- return new LongOpenHashSet(); +- }); ++ return this.structureReferences.getOrDefault(structure, LongSets.EMPTY_SET); // JettPack - lithium: chunk.structure_storage + } + + @Override + public void addReferenceForFeature(StructureFeature structure, long reference) { +- ((LongSet) this.structuresRefences.computeIfAbsent(structure, (structuregenerator1) -> { ++ ((LongSet) this.structureReferences.computeIfAbsent(structure, (structuregenerator1) -> { + return new LongOpenHashSet(); + })).add(reference); + this.unsaved = true; +@@ -280,13 +285,24 @@ public abstract class ChunkAccess implements BlockGetter, BiomeManager.NoiseBiom + + @Override + public Map, LongSet> getAllReferences() { +- return Collections.unmodifiableMap(this.structuresRefences); ++ // JettPack start - lithium: chunk.structure_storage ++ Map, LongSet> structureReferences = this.structureReferences; ++ if (structureReferences.isEmpty()) { ++ return Collections.emptyMap(); ++ } ++ return Collections.unmodifiableMap(structureReferences); ++ // JettPack end + } + + @Override + public void setAllReferences(Map, LongSet> structureReferences) { +- this.structuresRefences.clear(); +- this.structuresRefences.putAll(structureReferences); ++ // JettPack start - lithium: chunk.structure_storage ++ if (structureReferences instanceof HashMap) { ++ structureReferences.values().removeIf(longs -> longs == null || longs.isEmpty()); ++ } ++ // JettPack end ++ this.structureReferences.clear(); ++ this.structureReferences.putAll(structureReferences); + this.unsaved = true; + } + diff --git a/patches/server/0081-lithium-ai-task-goat-jump.patch b/patches/server/0081-lithium-ai-task-goat-jump.patch new file mode 100644 index 0000000..d5242f8 --- /dev/null +++ b/patches/server/0081-lithium-ai-task-goat-jump.patch @@ -0,0 +1,147 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Etil <81570777+etil2jz@users.noreply.github.com> +Date: Sun, 19 Dec 2021 14:08:38 +0100 +Subject: [PATCH] lithium: ai task goat jump + +Original code by CaffeineMC, licensed under GNU Lesser General Public License v3.0 +You can find the original code on https://github.com/CaffeineMC/lithium-fabric (Yarn mappings) + +diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/LongJumpToRandomPos.java b/src/main/java/net/minecraft/world/entity/ai/behavior/LongJumpToRandomPos.java +index 76e4258b13482d081a0e7452d39edae00b348add..a498eb480ccdf76543bedbd79623ac9bf41f6613 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/behavior/LongJumpToRandomPos.java ++++ b/src/main/java/net/minecraft/world/entity/ai/behavior/LongJumpToRandomPos.java +@@ -25,6 +25,8 @@ import net.minecraft.world.level.pathfinder.Path; + import net.minecraft.world.level.pathfinder.WalkNodeEvaluator; + import net.minecraft.world.phys.AABB; + import net.minecraft.world.phys.Vec3; ++import it.unimi.dsi.fastutil.longs.LongArrayList; // JettPack ++import it.unimi.dsi.fastutil.shorts.ShortArrayList; // JettPack + + public class LongJumpToRandomPos extends Behavior { + private static final int FIND_JUMP_TRIES = 20; +@@ -41,12 +43,26 @@ public class LongJumpToRandomPos extends Behavior { + private int findJumpTries; + private long prepareJumpStart; + private Function getJumpSound; ++ private final LongArrayList potentialTargets = new LongArrayList(); // JettPack ++ private final ShortArrayList potentialWeights = new ShortArrayList(); // JettPack + +- public LongJumpToRandomPos(UniformInt cooldownRange, int verticalRange, int horizontalRange, float maxRange, Function entityToSound) { ++ // JettPack start ++ private static int findIndex(ShortArrayList weights, int weightedIndex) { ++ for (int i = 0; i < weights.size(); i++) { ++ weightedIndex -= weights.getShort(i); ++ if (weightedIndex < 0) { ++ return i; ++ } ++ } ++ return -1; ++ } ++ // JettPack end ++ ++ public LongJumpToRandomPos(UniformInt cooldownRange, int maxLongJumpHeight, int maxLongJumpWidth, float maxRange, Function entityToSound) { + super(ImmutableMap.of(MemoryModuleType.LOOK_TARGET, MemoryStatus.REGISTERED, MemoryModuleType.LONG_JUMP_COOLDOWN_TICKS, MemoryStatus.VALUE_ABSENT, MemoryModuleType.LONG_JUMP_MID_JUMP, MemoryStatus.VALUE_ABSENT), 200); + this.timeBetweenLongJumps = cooldownRange; +- this.maxLongJumpHeight = verticalRange; +- this.maxLongJumpWidth = horizontalRange; ++ this.maxLongJumpHeight = maxLongJumpHeight; ++ this.maxLongJumpWidth = maxLongJumpWidth; + this.maxJumpVelocity = maxRange; + this.getJumpSound = entityToSound; + } +@@ -66,30 +82,63 @@ public class LongJumpToRandomPos extends Behavior { + return bl; + } + ++ // JettPack start ++ /** ++ * @author 2No2Name ++ * @reason only evaluate 20+ instead of ~100 possible jumps without affecting behavior ++ * [VanillaCopy] the whole method, commented changes ++ */ + @Override + protected void start(ServerLevel serverLevel, Mob mob, long l) { ++ this.potentialTargets.clear(); ++ this.potentialWeights.clear(); ++ int potentialTotalWeight = 0; + this.chosenJump = Optional.empty(); +- this.findJumpTries = 20; ++ this.findJumpTries = FIND_JUMP_TRIES; + this.jumpCandidates.clear(); + this.initialPosition = Optional.of(mob.position()); +- BlockPos blockPos = mob.blockPosition(); +- int i = blockPos.getX(); +- int j = blockPos.getY(); +- int k = blockPos.getZ(); +- Iterable iterable = BlockPos.betweenClosed(i - this.maxLongJumpWidth, j - this.maxLongJumpHeight, k - this.maxLongJumpWidth, i + this.maxLongJumpWidth, j + this.maxLongJumpHeight, k + this.maxLongJumpWidth); +- PathNavigation pathNavigation = mob.getNavigation(); +- +- for(BlockPos blockPos2 : iterable) { +- double d = blockPos2.distSqr(blockPos); +- if ((i != blockPos2.getX() || k != blockPos2.getZ()) && pathNavigation.isStableDestination(blockPos2) && mob.getPathfindingMalus(WalkNodeEvaluator.getBlockPathTypeStatic(mob.level, blockPos2.mutable())) == 0.0F) { +- Optional optional = this.calculateOptimalJumpVector(mob, Vec3.atCenterOf(blockPos2)); +- optional.ifPresent((vel) -> { +- this.jumpCandidates.add(new LongJumpToRandomPos.PossibleJump(new BlockPos(blockPos2), vel, Mth.ceil(d))); +- }); ++ BlockPos goatPos = mob.blockPosition(); ++ int goatX = goatPos.getX(); ++ int goatY = goatPos.getY(); ++ int goatZ = goatPos.getZ(); ++ Iterable iterable = BlockPos.betweenClosed(goatX - this.maxLongJumpWidth, goatY - this.maxLongJumpHeight, goatZ - this.maxLongJumpWidth, goatX + this.maxLongJumpWidth, goatY + this.maxLongJumpHeight, goatZ + this.maxLongJumpWidth); ++ PathNavigation entityNavigation = mob.getNavigation(); ++ ++ BlockPos.MutableBlockPos targetPosCopy = new BlockPos.MutableBlockPos(); ++ for (BlockPos targetPos : iterable) { ++ if (goatX == targetPos.getX() && goatZ == targetPos.getZ()) { ++ continue; + } +- } ++ double squaredDistance = targetPos.distSqr(goatPos); + ++ //Optimization: Evaluate the flight path check later (after random selection, but before world can be modified) ++ if (entityNavigation.isStableDestination(targetPos) && mob.getPathfindingMalus(WalkNodeEvaluator.getBlockPathTypeStatic(mob.level, targetPosCopy.set(targetPos))) == 0.0F) { ++ this.potentialTargets.add(targetPos.asLong()); ++ int weight = Mth.ceil(squaredDistance); ++ this.potentialWeights.add((short) weight); ++ potentialTotalWeight += weight; ++ } ++ } ++ // Optimization: Do the random picking of positions before doing the expensive the jump flight path validity check. ++ // up to FIND_JUMP_TRIES random jumpCandidates can be selected in keepRunning, so only this number of jumpCandidates needs to be generated ++ while (this.jumpCandidates.size() < FIND_JUMP_TRIES) { ++ // the number of random calls will be different from vanilla, but this is not reasonably detectable (not affecting world generation) ++ if (potentialTotalWeight == 0) { ++ return; // collection is empty/fully consumed, no more possible jumpCandidates available ++ } ++ int chosenIndex = findIndex(this.potentialWeights, serverLevel.random.nextInt(potentialTotalWeight)); ++ long chosenPos = this.potentialTargets.getLong(chosenIndex); ++ short chosenWeight = this.potentialWeights.set(chosenIndex, (short) 0); ++ potentialTotalWeight -= chosenWeight; ++ // Very expensive method call, it shifts bounding boxes around and checks for collisions with them ++ Optional optional = this.calculateOptimalJumpVector(mob, Vec3.atCenterOf(targetPosCopy.set(chosenPos))); ++ if (optional.isPresent()) { ++ //the weight in Target should be unused, as the random selection already took place ++ this.jumpCandidates.add(new LongJumpToRandomPos.PossibleJump(new BlockPos(targetPosCopy), optional.get(), chosenWeight)); ++ } ++ } + } ++ // JettPack end + + @Override + protected void tick(ServerLevel serverLevel, E mob, long l) { +@@ -106,7 +155,14 @@ public class LongJumpToRandomPos extends Behavior { + } + } else { + --this.findJumpTries; +- Optional optional = WeightedRandom.getRandomItem(serverLevel.random, this.jumpCandidates); ++ // JettPack start ++ Optional optional; ++ if (this.jumpCandidates.isEmpty()) { ++ optional = Optional.empty(); ++ } else { ++ optional = Optional.of(this.jumpCandidates.get(0)); ++ } ++ // JettPack end + if (optional.isPresent()) { + this.jumpCandidates.remove(optional.get()); + mob.getBrain().setMemory(MemoryModuleType.LOOK_TARGET, new BlockPosTracker(optional.get().getJumpTarget()));