mirror of
https://github.com/PaperMC/Paper.git
synced 2024-10-30 23:39:58 +01:00
232 lines
11 KiB
Diff
232 lines
11 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Phoenix616 <max@themoep.de>
|
|
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 b9cdbf8acccfd6b207a0116f068168f3b8c8e17d..8c883d2f88acc731734a121ebb76821e66658cc9 100644
|
|
--- a/src/main/java/co/aikar/timings/MinecraftTimings.java
|
|
+++ b/src/main/java/co/aikar/timings/MinecraftTimings.java
|
|
@@ -114,6 +114,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/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
|
index 0e7d29dbbdb862dd5876adee26fbba02267e5276..c334f29c69c1e6e3fe55cd6695e7df400cf36058 100644
|
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
|
@@ -3,14 +3,19 @@ package com.destroystokyo.paper;
|
|
import java.util.Arrays;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
+import java.util.Locale;
|
|
import java.util.Map;
|
|
import java.util.stream.Collectors;
|
|
+
|
|
+import com.google.common.collect.HashBasedTable;
|
|
+import com.google.common.collect.Table;
|
|
import net.minecraft.world.Difficulty;
|
|
import net.minecraft.world.entity.EntityType;
|
|
import net.minecraft.world.entity.monster.Vindicator;
|
|
import net.minecraft.world.entity.monster.Zombie;
|
|
import com.destroystokyo.paper.antixray.ChunkPacketBlockControllerAntiXray.EngineMode;
|
|
import org.bukkit.Bukkit;
|
|
+import org.bukkit.configuration.ConfigurationSection;
|
|
import org.bukkit.configuration.file.YamlConfiguration;
|
|
import org.spigotmc.SpigotWorldConfig;
|
|
|
|
@@ -847,5 +852,58 @@ public class PaperWorldConfig {
|
|
private void playerCrammingDamage() {
|
|
allowPlayerCrammingDamage = getBoolean("allow-player-cramming-damage", allowPlayerCrammingDamage);
|
|
}
|
|
+
|
|
+ private Table<String, String, Integer> sensorTickRates;
|
|
+ private Table<String, String, Integer> behaviorTickRates;
|
|
+ private void tickRates() {
|
|
+ config.addDefault("world-settings.default.tick-rates.sensor.villager.secondarypoisensor", 40);
|
|
+ config.addDefault("world-settings.default.tick-rates.behavior.villager.validatenearbypoi", -1); // Example
|
|
+ log("Tick rates:");
|
|
+ sensorTickRates = loadTickRates("sensor");
|
|
+ behaviorTickRates = loadTickRates("behavior");
|
|
+ }
|
|
+
|
|
+ private Table<String, String, Integer> loadTickRates(String type) {
|
|
+ log(" " + type + ":");
|
|
+ Table<String, String, Integer> table = HashBasedTable.create();
|
|
+
|
|
+ ConfigurationSection typeSection = config.getConfigurationSection("world-settings." + worldName + ".tick-rates." + type);
|
|
+ if (typeSection == null) {
|
|
+ typeSection = config.getConfigurationSection("world-settings.default.tick-rates." + type);
|
|
+ }
|
|
+ if (typeSection != null) {
|
|
+ for (String entity : typeSection.getKeys(false)) {
|
|
+ ConfigurationSection entitySection = typeSection.getConfigurationSection(entity);
|
|
+ if (entitySection != null) {
|
|
+ log(" " + entity + ":");
|
|
+ for (String typeName : entitySection.getKeys(false)) {
|
|
+ if (entitySection.isInt(typeName)) {
|
|
+ int tickRate = entitySection.getInt(typeName);
|
|
+ table.put(entity.toUpperCase(Locale.ROOT), typeName.toUpperCase(Locale.ROOT), tickRate);
|
|
+ log(" " + typeName + ": " + tickRate);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (table.isEmpty()) {
|
|
+ log(" None configured");
|
|
+ }
|
|
+ return table;
|
|
+ }
|
|
+
|
|
+ public int getBehaviorTickRate(String typeName, String entityType, int def) {
|
|
+ return getIntOrDefault(behaviorTickRates, typeName, entityType, def);
|
|
+ }
|
|
+
|
|
+ public int getSensorTickRate(String typeName, String entityType, int def) {
|
|
+ return getIntOrDefault(sensorTickRates, typeName, entityType, def);
|
|
+ }
|
|
+
|
|
+ private int getIntOrDefault(Table<String, String, Integer> table, String rowKey, String columnKey, int def) {
|
|
+ Integer rate = table.get(columnKey, rowKey);
|
|
+ return rate != null && rate > -1 ? rate : def;
|
|
+ }
|
|
}
|
|
|
|
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 b1212e162ba938b3abe0df747a633ba9cbbe57c8..b1928807851a4fca53e117573b25c62a6deeb8e1 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
|
|
@@ -14,6 +14,10 @@ public abstract class Behavior<E extends LivingEntity> {
|
|
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<MemoryModuleType<?>, MemoryStatus> requiredMemoryState) {
|
|
this(requiredMemoryState, 60);
|
|
@@ -27,6 +31,22 @@ public abstract class Behavior<E extends LivingEntity> {
|
|
this.minDuration = minRunTime;
|
|
this.maxDuration = maxRunTime;
|
|
this.entryCondition = requiredMemoryState;
|
|
+ // Paper start - configurable behavior tick rate and timings
|
|
+ String key = this.getClass().getSimpleName();
|
|
+ final var mappings = io.papermc.paper.util.ObfHelper.INSTANCE.mappings();
|
|
+ if (mappings != null) {
|
|
+ final var classMapping = mappings.get(this.getClass().getName());
|
|
+ if (classMapping != null) {
|
|
+ key = classMapping.mojangName();
|
|
+ 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
|
|
}
|
|
|
|
public Behavior.Status getStatus() {
|
|
@@ -34,11 +54,19 @@ public abstract class Behavior<E extends LivingEntity> {
|
|
}
|
|
|
|
public final boolean tryStart(ServerLevel world, E entity, long time) {
|
|
+ // Paper start - behavior tick rate
|
|
+ int tickRate = world.paperConfig.getBehaviorTickRate(this.configKey, entity.getType().id, -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;
|
|
@@ -49,11 +77,13 @@ public abstract class Behavior<E extends LivingEntity> {
|
|
}
|
|
|
|
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 f94aa5147c52d2e36d6018f51b85e9dac7a6208a..8f99a78a55ab8f0ddfa1dd790a9a4a8c23a7f841 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,28 @@ public abstract class Sensor<E extends LivingEntity> {
|
|
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 = this.getClass().getSimpleName();
|
|
+ final var mappings = io.papermc.paper.util.ObfHelper.INSTANCE.mappings();
|
|
+ if (mappings != null) {
|
|
+ final var classMapping = mappings.get(this.getClass().getName());
|
|
+ if (classMapping != null) {
|
|
+ key = classMapping.mojangName();
|
|
+ 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 +51,12 @@ public abstract class Sensor<E extends LivingEntity> {
|
|
|
|
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 = world.paperConfig.getSensorTickRate(this.configKey, entity.getType().id, this.scanRate);
|
|
+ this.timing.startTiming();
|
|
+ // Paper end
|
|
this.doTick(world, entity);
|
|
+ this.timing.stopTiming(); // Paper - sensor timings
|
|
}
|
|
|
|
}
|