Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions early/src/main/java/cc/irori/refixes/early/EarlyOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ public final class EarlyOptions {
public static final Value<Boolean> SHARED_INSTANCES_ENABLED = new Value<>();
public static final Value<String[]> SHARED_INSTANCES_EXCLUDED_PREFIXES = new Value<>();

/* Pathfinding */
public static final Value<Integer> PATHFINDING_MAX_PATH_LENGTH = new Value<>();
public static final Value<Integer> PATHFINDING_OPEN_NODES_LIMIT = new Value<>();
public static final Value<Integer> PATHFINDING_TOTAL_NODES_LIMIT = new Value<>();

// Private constructor to prevent instantiation
private EarlyOptions() {}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package cc.irori.refixes.early.mixin;

import cc.irori.refixes.early.EarlyOptions;
import com.hypixel.hytale.server.npc.navigation.AStarBase;
import com.hypixel.hytale.server.npc.navigation.AStarNode;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import java.util.List;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

/**
* Optimizes A* pathfinding:
* Binary search insert for open nodes (replaces O(n) linear scan)
* Configurable limits for maxPathLength, openNodesLimit, totalNodesLimit
*/
@Mixin(AStarBase.class)
public class MixinAStarBase {

@Shadow
protected List<AStarNode> openNodes;

@Shadow
protected Long2ObjectMap<AStarNode> visitedBlocks;

@Shadow
protected int maxPathLength;

@Shadow
protected int openNodesLimit;

@Shadow
protected int totalNodesLimit;

@Inject(
method = "addOpenNode(Lcom/hypixel/hytale/server/npc/navigation/AStarNode;J)V",
at = @At("HEAD"),
cancellable = true)
private void refixes$binarySearchInsert(AStarNode node, long index, CallbackInfo ci) {
float totalCost = node.getTotalCost();

int lo = 0, hi = openNodes.size();
while (lo < hi) {
int mid = (lo + hi) >>> 1;
if (openNodes.get(mid).getTotalCost() < totalCost) {
hi = mid;
} else {
lo = mid + 1;
}
}
openNodes.add(lo, node);
visitedBlocks.put(index, node);

ci.cancel();
}

@Inject(method = "initComputePath", at = @At("HEAD"))
private void refixes$applyPathfindingLimits(CallbackInfoReturnable<?> cir) {
if (!EarlyOptions.isAvailable()) {
return;
}
this.maxPathLength = EarlyOptions.PATHFINDING_MAX_PATH_LENGTH.get();
this.openNodesLimit = EarlyOptions.PATHFINDING_OPEN_NODES_LIMIT.get();
this.totalNodesLimit = EarlyOptions.PATHFINDING_TOTAL_NODES_LIMIT.get();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package cc.irori.refixes.early.mixin;

import com.hypixel.hytale.server.core.modules.entity.repulsion.RepulsionSystems;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;

// Pools the ObjectArrayList allocated per entity per tick to reduce GC pressure
@Mixin(RepulsionSystems.RepulsionTicker.class)
public class MixinRepulsionTicker {

@Unique
private static final ThreadLocal<ObjectArrayList> refixes$resultList =
ThreadLocal.withInitial(ObjectArrayList::new);

@Redirect(method = "tick", at = @At(value = "NEW", target = "it/unimi/dsi/fastutil/objects/ObjectArrayList"))
private ObjectArrayList refixes$poolResults() {
ObjectArrayList list = refixes$resultList.get();
list.clear();
return list;
}
}
4 changes: 3 additions & 1 deletion early/src/main/resources/refixes.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
"MixinWorld",
"MixinWorldConfig",
"MixinWorldMapTracker",
"MixinWorldSpawningSystem"
"MixinWorldSpawningSystem",
"MixinAStarBase",
"MixinRepulsionTicker"
]
}
7 changes: 7 additions & 0 deletions plugin/src/main/java/cc/irori/refixes/Refixes.java
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,13 @@ private void registerEarlyOptions() {
EarlyOptions.PARALLEL_ENTITY_TICKING.setSupplier(
() -> experimentalConfig.getValue(ExperimentalConfig.PARALLEL_ENTITY_TICKING));

EarlyOptions.PATHFINDING_MAX_PATH_LENGTH.setSupplier(
() -> config.getValue(EarlyConfig.PATHFINDING_MAX_PATH_LENGTH));
EarlyOptions.PATHFINDING_OPEN_NODES_LIMIT.setSupplier(
() -> config.getValue(EarlyConfig.PATHFINDING_OPEN_NODES_LIMIT));
EarlyOptions.PATHFINDING_TOTAL_NODES_LIMIT.setSupplier(
() -> config.getValue(EarlyConfig.PATHFINDING_TOTAL_NODES_LIMIT));

EarlyOptions.setAvailable(true);

/* Tick Sleep Optimization */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ public class EarlyConfig extends Configuration<EarlyConfig> {
public static final ConfigurationKey<EarlyConfig, Integer> MAX_CHUNKS_PER_TICK =
new ConfigurationKey<>("MaxChunksPerTick", ConfigField.INTEGER, 4);

public static final ConfigurationKey<EarlyConfig, Integer> PATHFINDING_MAX_PATH_LENGTH =
new ConfigurationKey<>("PathfindingMaxPathLength", ConfigField.INTEGER, 200);
public static final ConfigurationKey<EarlyConfig, Integer> PATHFINDING_OPEN_NODES_LIMIT =
new ConfigurationKey<>("PathfindingOpenNodesLimit", ConfigField.INTEGER, 80);
public static final ConfigurationKey<EarlyConfig, Integer> PATHFINDING_TOTAL_NODES_LIMIT =
new ConfigurationKey<>("PathfindingTotalNodesLimit", ConfigField.INTEGER, 400);

private static final EarlyConfig INSTANCE = new EarlyConfig();

public EarlyConfig() {
Expand All @@ -35,7 +42,10 @@ public EarlyConfig() {
DISABLE_FLUID_PRE_PROCESS,
ASYNC_BLOCK_PRE_PROCESS,
MAX_CHUNKS_PER_SECOND,
MAX_CHUNKS_PER_TICK);
MAX_CHUNKS_PER_TICK,
PATHFINDING_MAX_PATH_LENGTH,
PATHFINDING_OPEN_NODES_LIMIT,
PATHFINDING_TOTAL_NODES_LIMIT);
}

public static EarlyConfig get() {
Expand Down