From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Phoenix616 Date: Mon, 28 Jun 2021 22:38:29 +0100 Subject: [PATCH] Rate options and timings for sensors and behaviors This adds config options to specify the tick rate for sensors and behaviors of different entity types as well as timings for those in order to be able to have some metrics as to which ones might need tweaking. diff --git a/src/main/java/co/aikar/timings/MinecraftTimings.java b/src/main/java/co/aikar/timings/MinecraftTimings.java index 59affb62cb487d60e8c3e32decf89d6cb7d22f8d..4d861f9a58f8ea238471af22f387854d855b1801 100644 --- a/src/main/java/co/aikar/timings/MinecraftTimings.java +++ b/src/main/java/co/aikar/timings/MinecraftTimings.java @@ -115,6 +115,14 @@ public final class MinecraftTimings { return Timings.ofSafe("Minecraft", "## tickEntity - " + entityType + " - " + type, tickEntityTimer); } + public static Timing getBehaviorTimings(String type) { + return Timings.ofSafe("## Behavior - " + type); + } + + public static Timing getSensorTimings(String type, int rate) { + return Timings.ofSafe("## Sensor - " + type + " (Default rate: " + rate + ")"); + } + /** * Get a named timer for the specified tile entity type to track type specific timings. * @param entity diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/Behavior.java b/src/main/java/net/minecraft/world/entity/ai/behavior/Behavior.java index a298dde4e870176256986c58dc00afb350c62aa8..532d4b9e260ebea70e724bc2bf1e941d1450a1c7 100644 --- a/src/main/java/net/minecraft/world/entity/ai/behavior/Behavior.java +++ b/src/main/java/net/minecraft/world/entity/ai/behavior/Behavior.java @@ -13,6 +13,10 @@ public abstract class Behavior implements BehaviorContro private long endTimestamp; private final int minDuration; private final int maxDuration; + // Paper start - configurable behavior tick rate and timings + private final String configKey; + private final co.aikar.timings.Timing timing; + // Paper end public Behavior(Map, MemoryStatus> requiredMemoryState) { this(requiredMemoryState, 60); @@ -26,6 +30,15 @@ public abstract class Behavior implements BehaviorContro this.minDuration = minRunTime; this.maxDuration = maxRunTime; this.entryCondition = requiredMemoryState; + // Paper start - configurable behavior tick rate and timings + String key = io.papermc.paper.util.ObfHelper.INSTANCE.deobfClassName(this.getClass().getName()); + int lastSeparator = key.lastIndexOf('.'); + if (lastSeparator != -1) { + key = key.substring(lastSeparator + 1); + } + this.configKey = key.toLowerCase(java.util.Locale.ROOT); + this.timing = co.aikar.timings.MinecraftTimings.getBehaviorTimings(configKey); + // Paper end } @Override @@ -35,11 +48,19 @@ public abstract class Behavior implements BehaviorContro @Override public final boolean tryStart(ServerLevel world, E entity, long time) { + // Paper start - behavior tick rate + int tickRate = java.util.Objects.requireNonNullElse(world.paperConfig().tickRates.behavior.get(entity.getType(), this.configKey), -1); + if (tickRate > -1 && time < this.endTimestamp + tickRate) { + return false; + } + // Paper end if (this.hasRequiredMemories(entity) && this.checkExtraStartConditions(world, entity)) { this.status = Behavior.Status.RUNNING; int i = this.minDuration + world.getRandom().nextInt(this.maxDuration + 1 - this.minDuration); this.endTimestamp = time + (long)i; + this.timing.startTiming(); // Paper - behavior timings this.start(world, entity, time); + this.timing.stopTiming(); // Paper - behavior timings return true; } else { return false; @@ -51,11 +72,13 @@ public abstract class Behavior implements BehaviorContro @Override public final void tickOrStop(ServerLevel world, E entity, long time) { + this.timing.startTiming(); // Paper - behavior timings if (!this.timedOut(time) && this.canStillUse(world, entity, time)) { this.tick(world, entity, time); } else { this.doStop(world, entity, time); } + this.timing.stopTiming(); // Paper - behavior timings } diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/Sensor.java b/src/main/java/net/minecraft/world/entity/ai/sensing/Sensor.java index afae9bca181cfc34f859016bf7a612794695d718..57d8397b9d2f087b7a0f271ad88487781a5ed44e 100644 --- a/src/main/java/net/minecraft/world/entity/ai/sensing/Sensor.java +++ b/src/main/java/net/minecraft/world/entity/ai/sensing/Sensor.java @@ -19,8 +19,21 @@ public abstract class Sensor { private static final TargetingConditions ATTACK_TARGET_CONDITIONS_IGNORE_INVISIBILITY_AND_LINE_OF_SIGHT = TargetingConditions.forCombat().range(16.0D).ignoreLineOfSight().ignoreInvisibilityTesting(); private final int scanRate; private long timeToTick; + // Paper start - configurable sensor tick rate and timings + private final String configKey; + private final co.aikar.timings.Timing timing; + // Paper end public Sensor(int senseInterval) { + // Paper start - configurable sensor tick rate and timings + String key = io.papermc.paper.util.ObfHelper.INSTANCE.deobfClassName(this.getClass().getName()); + int lastSeparator = key.lastIndexOf('.'); + if (lastSeparator != -1) { + key = key.substring(lastSeparator + 1); + } + this.configKey = key.toLowerCase(java.util.Locale.ROOT); + this.timing = co.aikar.timings.MinecraftTimings.getSensorTimings(configKey, senseInterval); + // Paper end this.scanRate = senseInterval; this.timeToTick = (long)RANDOM.nextInt(senseInterval); } @@ -31,8 +44,12 @@ public abstract class Sensor { public final void tick(ServerLevel world, E entity) { if (--this.timeToTick <= 0L) { - this.timeToTick = (long)this.scanRate; + // Paper start - configurable sensor tick rate and timings + this.timeToTick = java.util.Objects.requireNonNullElse(world.paperConfig().tickRates.sensor.get(entity.getType(), this.configKey), this.scanRate); + this.timing.startTiming(); + // Paper end this.doTick(world, entity); + this.timing.stopTiming(); // Paper - sensor timings } }