diff --git a/gradle.properties b/gradle.properties index 3fed9a36..1f07d64b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ group = org.dreeam.leaf version = 1.20.4-R0.1-SNAPSHOT -galeCommit = 07a2ca6b82a3b809d6b89213b0648ef9067858b6 +galeCommit = 78098840227379410ccc610bddafa6a7956c6ddd org.gradle.caching = true org.gradle.parallel = true diff --git a/patches/unapplied/todo-server/0042-Optimize-explosions.patch b/patches/unapplied/todo-server/0042-Optimize-explosions.patch new file mode 100644 index 00000000..a4cf45a3 --- /dev/null +++ b/patches/unapplied/todo-server/0042-Optimize-explosions.patch @@ -0,0 +1,86 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Dreeam <61569423+Dreeam-qwq@users.noreply.github.com> +Date: Thu, 7 Sep 2023 06:21:32 -0400 +Subject: [PATCH] Optimize explosions + + +diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java +index d3c20e4ae510028d25a05915e4662b03e6d0b128..fd195f38f239e322114a794e30b7f5032ac2c18c 100644 +--- a/src/main/java/net/minecraft/world/level/Explosion.java ++++ b/src/main/java/net/minecraft/world/level/Explosion.java +@@ -82,9 +82,11 @@ public class Explosion { + } + + public Explosion(Level world, @Nullable Entity entity, @Nullable DamageSource damageSource, @Nullable ExplosionDamageCalculator behavior, double x, double y, double z, float power, boolean createFire, Explosion.BlockInteraction destructionType) { +- this.random = world == null || world.random == null ? RandomSource.create() : world.random; // Gale - Patina - reduce RandomSource instances +- this.toBlow = new ObjectArrayList(); +- this.hitPlayers = Maps.newHashMap(); ++ // Leaf start - Optimize explosion ++ this.random = world == null || world.random == null ? RandomSource.createThreadSafe() : world.random; // Gale - Patina - reduce RandomSource instances ++ this.toBlow = new ObjectArrayList<>(); ++ this.hitPlayers = Maps.newConcurrentMap(); ++ // Leaf end + this.level = world; + this.source = entity; + this.radius = (float) (world == null || world.purpurConfig.explosionClampRadius ? Math.max(power, 0.0) : power); // CraftBukkit - clamp bad values // Purpur +@@ -425,7 +427,7 @@ public class Explosion { + //Purpur end + + this.level.gameEvent(this.source, GameEvent.EXPLODE, new Vec3(this.x, this.y, this.z)); +- Set set = Sets.newHashSet(); ++ Set set = Sets.newConcurrentHashSet(); // Leaf - Optimize explosion - Use ConcurrentHashSet + boolean flag = true; + + int i; +@@ -757,10 +759,7 @@ public class Explosion { + } + + if (this.fire) { +- ObjectListIterator objectlistiterator1 = this.toBlow.iterator(); +- +- while (objectlistiterator1.hasNext()) { +- BlockPos blockposition2 = (BlockPos) objectlistiterator1.next(); ++ for (BlockPos blockposition2 : this.toBlow) { + + if (this.random.nextInt(3) == 0 && this.level.getBlockState(blockposition2).isAir() && this.level.getBlockState(blockposition2.below()).isSolidRender(this.level, blockposition2.below())) { + // CraftBukkit start - Ignition by explosion +@@ -868,11 +867,7 @@ public class Explosion { + return this.getSeenFraction(vec3d, entity, blockCache, blockPos); // Paper - optimise explosions + } + CacheKey key = new CacheKey(this, entity.getBoundingBox()); +- Float blockDensity = this.level.explosionDensityCache.get(key); +- if (blockDensity == null) { +- blockDensity = this.getSeenFraction(vec3d, entity, blockCache, blockPos); // Paper - optimise explosions; +- this.level.explosionDensityCache.put(key, blockDensity); +- } ++ Float blockDensity = this.level.explosionDensityCache.computeIfAbsent(key, k -> this.getSeenFraction(vec3d, entity, blockCache, blockPos)); // Paper - optimise explosions; // Leaf - Optimize explosion - Reduce cache key check load + + return blockDensity; + } +diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java +index 275557da9faa7f27dd2fbfbdfbda620d4add0f8a..039a0f3af6907974031c2b568b396246aee201f9 100644 +--- a/src/main/java/net/minecraft/world/level/Level.java ++++ b/src/main/java/net/minecraft/world/level/Level.java +@@ -3,11 +3,13 @@ package net.minecraft.world.level; + import com.destroystokyo.paper.event.server.ServerExceptionEvent; + import com.destroystokyo.paper.exception.ServerInternalException; + import com.google.common.collect.Lists; ++import com.google.common.collect.Maps; + import com.mojang.serialization.Codec; + import java.io.IOException; + import java.util.Iterator; + import java.util.List; + import java.util.Objects; ++import java.util.concurrent.ConcurrentHashMap; + import java.util.function.Consumer; + import java.util.function.Predicate; + import java.util.function.Supplier; +@@ -181,7 +183,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + private org.spigotmc.TickLimiter entityLimiter; + private org.spigotmc.TickLimiter tileLimiter; + private int tileTickPosition; +- public final Map explosionDensityCache = new HashMap<>(); // Paper - Optimize explosions ++ public final Map explosionDensityCache = Maps.newConcurrentMap(); // Paper - Optimize explosions // Leaf - Optimize explosion + public java.util.ArrayDeque redstoneUpdateInfos; // Paper - Move from Map in BlockRedstoneTorch to here + + public final io.papermc.paper.util.math.ThreadUnsafeRandom randomTickRandom = new io.papermc.paper.util.math.ThreadUnsafeRandom(this.random.nextLong()); // Gale - Pufferfish - move random tick random diff --git a/patches/unapplied/todo-server/0043-JettPack-Fix-McDev-Decomp.patch b/patches/unapplied/todo-server/0043-JettPack-Fix-McDev-Decomp.patch new file mode 100644 index 00000000..829f708e --- /dev/null +++ b/patches/unapplied/todo-server/0043-JettPack-Fix-McDev-Decomp.patch @@ -0,0 +1,77 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: rafaelflromao <12960698+rafaelflromao@users.noreply.github.com> +Date: Sat, 24 Jun 2023 13:53:38 +0100 +Subject: [PATCH] JettPack Fix McDev Decomp + + +diff --git a/src/main/java/net/minecraft/world/entity/ai/Brain.java b/src/main/java/net/minecraft/world/entity/ai/Brain.java +index dea20f16ac97402f754c8e47d03e9ef38de73190..9cdfe4c9d4487082c9b3577ff572675d9b8fc9b9 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/Brain.java ++++ b/src/main/java/net/minecraft/world/entity/ai/Brain.java +@@ -72,16 +72,16 @@ public class Brain { + } + + public DataResult> decode(DynamicOps dynamicOps, MapLike mapLike) { +- MutableObject>>> mutableObject = new MutableObject<>(DataResult.success(ImmutableList.builder())); ++ MutableObject>>> decode_mutableObject = new MutableObject<>(DataResult.success(ImmutableList.builder())); // JettPack - decomp fix + mapLike.entries().forEach((pair) -> { + DataResult> dataResult = BuiltInRegistries.MEMORY_MODULE_TYPE.byNameCodec().parse(dynamicOps, pair.getFirst()); + DataResult> dataResult2 = dataResult.flatMap((memoryType) -> { + return this.captureRead(memoryType, dynamicOps, (T)pair.getSecond()); + }); +- mutableObject.setValue(mutableObject.getValue().apply2(ImmutableList.Builder::add, dataResult2)); ++ decode_mutableObject.setValue(decode_mutableObject.getValue().apply2(ImmutableList.Builder::add, dataResult2)); // JettPack - decomp fix + }); +- ImmutableList> immutableList = mutableObject.getValue().resultOrPartial(Brain.LOGGER::error).map(ImmutableList.Builder::build).orElseGet(ImmutableList::of); +- return DataResult.success(new Brain<>(memoryModules, sensors, immutableList, mutableObject::getValue)); ++ ImmutableList> immutableList = decode_mutableObject.getValue().resultOrPartial(Brain.LOGGER::error).map(ImmutableList.Builder::build).orElseGet(ImmutableList::of); // JettPack - decomp fix ++ return DataResult.success(new Brain(memoryModules, sensors, immutableList, mutableObject::getValue)); // JettPack - decomp fix + } + + private DataResult> captureRead(MemoryModuleType memoryType, DynamicOps ops, T value) { +@@ -135,7 +135,7 @@ public class Brain { + + Stream> memories() { + return this.memories.entrySet().stream().map((entry) -> { +- return Brain.MemoryValue.createUnchecked(entry.getKey(), entry.getValue()); ++ return Brain.MemoryValue.createUnchecked((MemoryModuleType)entry.getKey(), (Optional)entry.getValue()); // JettPack - decomp fix + }); + } + +@@ -181,14 +181,14 @@ public class Brain { + if (optional == null) { + throw new IllegalStateException("Unregistered memory fetched: " + type); + } else { +- return optional.map(ExpirableValue::getValue); ++ return (Optional) optional.map(object -> ((ExpirableValue)object).getValue()); // JettPack - decomp fix + } + } + + @Nullable + public Optional getMemoryInternal(MemoryModuleType type) { + Optional> optional = this.memories.get(type); +- return optional == null ? null : optional.map(ExpirableValue::getValue); ++ return optional == null ? null : (Optional) optional.map(ExpirableValue::getValue); + } + + public long getTimeUntilExpiry(MemoryModuleType type) { +@@ -371,7 +371,7 @@ public class Brain { + } + + public Brain copyWithoutBehaviors() { +- Brain brain = new Brain<>(this.memories.keySet(), this.sensors.keySet(), ImmutableList.of(), this.codec); ++ Brain brain = new Brain(this.memories.keySet(), this.sensors. keySet(), ImmutableList.of(), this.codec); // JettPack - decomp fix + + for(Map.Entry, Optional>> entry : this.memories.entrySet()) { + MemoryModuleType memoryModuleType = entry.getKey(); +@@ -482,8 +482,8 @@ public class Brain { + private final MemoryModuleType type; + private final Optional> value; + +- static Brain.MemoryValue createUnchecked(MemoryModuleType type, Optional> data) { +- return new Brain.MemoryValue<>(type, data); ++ static Brain.MemoryValue createUnchecked(MemoryModuleType type, Optional> data) { // JettPack - decomp fix ++ return new Brain.MemoryValue(type, data); // JettPack - decomp fix + } + + MemoryValue(MemoryModuleType type, Optional> data) { diff --git a/patches/unapplied/todo-server/0044-Distribute-workload-for-villager-s-AI.patch b/patches/unapplied/todo-server/0044-Distribute-workload-for-villager-s-AI.patch new file mode 100644 index 00000000..62aa6b25 --- /dev/null +++ b/patches/unapplied/todo-server/0044-Distribute-workload-for-villager-s-AI.patch @@ -0,0 +1,150 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: rafaelflromao <12960698+rafaelflromao@users.noreply.github.com> +Date: Sat, 24 Jun 2023 13:46:45 +0100 +Subject: [PATCH] Distribute workload for villager's AI + + +diff --git a/src/main/java/dev/etil/mirai/ai/WorkloadDistribution.java b/src/main/java/dev/etil/mirai/ai/WorkloadDistribution.java +new file mode 100644 +index 0000000000000000000000000000000000000000..8cc57b5ce8f8f8e6e73880e992794e2bbca5f193 +--- /dev/null ++++ b/src/main/java/dev/etil/mirai/ai/WorkloadDistribution.java +@@ -0,0 +1,39 @@ ++package dev.etil.mirai.ai; ++ ++import java.util.ArrayDeque; ++import java.util.Objects; ++ ++public class WorkloadDistribution { ++ ++ private final long taskTime; ++ private final long maxTasks; ++ ++ private final long tickDelay; ++ ++ private long desiredStart = System.nanoTime(); ++ public WorkloadDistribution(long taskTime, long maxTasks, long tickDelay) { ++ this.taskTime = taskTime; ++ this.maxTasks = maxTasks; ++ this.tickDelay = tickDelay; ++ } ++ ArrayDeque tasks = new ArrayDeque<>(); ++ ++ public void addTask(Runnable task) { ++ tasks.offer(task); ++ if(tasks.size() > maxTasks) tasks.poll(); ++ } ++ ++ public void tick() { ++ if(tasks.isEmpty()) return; ++ if(System.nanoTime() < desiredStart) return; ++ long initialSize = tasks.size(); ++ long start = System.nanoTime(); ++ while(!tasks.isEmpty() && System.nanoTime() - start < taskTime) { ++ Objects.requireNonNull(tasks.poll()).run(); ++ } ++ desiredStart = System.nanoTime() + tickDelay; ++ // System.out.println("Took " + (System.nanoTime() - start) + "ns to run " + (initialSize - tasks.size()) + " tasks"); ++ } ++ ++ ++} +diff --git a/src/main/java/net/minecraft/world/entity/ai/Brain.java b/src/main/java/net/minecraft/world/entity/ai/Brain.java +index 9cdfe4c9d4487082c9b3577ff572675d9b8fc9b9..a2f7cdf08cfaf46204eca47fb39e08bd47049462 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/Brain.java ++++ b/src/main/java/net/minecraft/world/entity/ai/Brain.java +@@ -14,6 +14,7 @@ import com.mojang.serialization.DynamicOps; + import com.mojang.serialization.MapCodec; + import com.mojang.serialization.MapLike; + import com.mojang.serialization.RecordBuilder; ++import dev.etil.mirai.ai.WorkloadDistribution; + import it.unimi.dsi.fastutil.objects.ObjectArrayList; + import java.util.Collection; + import java.util.List; +@@ -43,6 +44,7 @@ public class Brain { + static final Logger LOGGER = LogUtils.getLogger(); + private final Supplier>> codec; + private static final int SCHEDULE_UPDATE_DELAY = 20; ++ private final WorkloadDistribution workloadDistribution = new WorkloadDistribution(20000L, 500L, 10000L); + private final Map, Optional>> memories = Maps.newHashMap(); + private final Map>, Sensor> sensors = Maps.newLinkedHashMap(); + private final Map>>> availableBehaviorsByPriority = Maps.newTreeMap(); +@@ -384,29 +386,34 @@ public class Brain { + } + + public void tick(ServerLevel world, E entity) { +- this.forgetOutdatedMemories(); +- this.tickSensors(world, entity); +- this.startEachNonRunningBehavior(world, entity); +- this.tickEachRunningBehavior(world, entity); ++ // Mirai Start - Distribute workload ++ this.forgetOutdatedMemories(); ++ this.tickSensors(world, entity); ++ this.startEachNonRunningBehavior(world, entity); ++ this.tickEachRunningBehavior(world, entity); ++ workloadDistribution.tick(); ++ // Mirai End + } + + private void tickSensors(ServerLevel world, E entity) { + for(Sensor sensor : this.sensors.values()) { +- sensor.tick(world, entity); ++ workloadDistribution.addTask(() -> sensor.tick(world, entity)); + } + + } + + private void forgetOutdatedMemories() { + for(Map.Entry, Optional>> entry : this.memories.entrySet()) { +- if (entry.getValue().isPresent()) { +- ExpirableValue expirableValue = entry.getValue().get(); +- if (expirableValue.hasExpired()) { +- this.eraseMemory(entry.getKey()); +- } ++ workloadDistribution.addTask(() -> { ++ if (entry.getValue().isPresent()) { ++ ExpirableValue expirableValue = entry.getValue().get(); ++ if (expirableValue.hasExpired()) { ++ this.eraseMemory(entry.getKey()); ++ } + +- expirableValue.tick(); +- } ++ expirableValue.tick(); ++ } ++ }); + } + + } +@@ -425,14 +432,16 @@ public class Brain { + + for(Map>> map : this.availableBehaviorsByPriority.values()) { + for(Map.Entry>> entry : map.entrySet()) { +- Activity activity = entry.getKey(); +- if (this.activeActivities.contains(activity)) { +- for(BehaviorControl behaviorControl : entry.getValue()) { +- if (behaviorControl.getStatus() == Behavior.Status.STOPPED) { +- behaviorControl.tryStart(world, entity, l); ++ workloadDistribution.addTask(() -> { ++ Activity activity = entry.getKey(); ++ if (this.activeActivities.contains(activity)) { ++ for(BehaviorControl behaviorControl : entry.getValue()) { ++ if (behaviorControl.getStatus() == Behavior.Status.STOPPED) { ++ behaviorControl.tryStart(world, entity, l); ++ } + } + } +- } ++ }); + } + } + +@@ -442,7 +451,7 @@ public class Brain { + long l = world.getGameTime(); + + for(BehaviorControl behaviorControl : this.getRunningBehaviors()) { +- behaviorControl.tickOrStop(world, entity, l); ++ workloadDistribution.addTask(() -> behaviorControl.tickOrStop(world, entity, l)); + } + + }