perf: stop heap-allocating mob restriction state and Path nodes

Inlines restrictCenter and leashRestrictionGoal as value members and
stores Path nodes by value, removing per-mob and per-path malloc churn.
This commit is contained in:
MatthewBeshay 2026-04-09 13:23:02 +10:00
parent fe77d9c2a0
commit 45c85fcf79
5 changed files with 40 additions and 62 deletions

View file

@ -26,25 +26,20 @@ AttributeModifier* PathfinderMob::SPEED_MODIFIER_FLEEING =
AttributeModifier::OPERATION_MULTIPLY_TOTAL))
->setSerialize(false);
PathfinderMob::PathfinderMob(Level* level) : Mob(level) {
path = nullptr;
attackTarget = nullptr;
holdGround = false;
fleeTime = 0;
restrictRadius = -1;
restrictCenter = new Pos(0, 0, 0);
addedLeashRestrictionGoal = false;
leashRestrictionGoal = new MoveTowardsRestrictionGoal(this, 1.0f);
}
PathfinderMob::PathfinderMob(Level* level)
: Mob(level),
path(nullptr),
attackTarget(nullptr),
holdGround(false),
fleeTime(0),
restrictCenter(0, 0, 0),
restrictRadius(-1),
leashRestrictionGoal(this, 1.0f),
addedLeashRestrictionGoal(false) {}
bool PathfinderMob::shouldHoldGround() { return false; }
PathfinderMob::~PathfinderMob() {
delete path;
delete restrictCenter;
delete leashRestrictionGoal;
}
PathfinderMob::~PathfinderMob() { delete path; }
void PathfinderMob::serverAiStep() {
if (fleeTime > 0) {
@ -264,15 +259,15 @@ bool PathfinderMob::isWithinRestriction() {
bool PathfinderMob::isWithinRestriction(int x, int y, int z) {
if (restrictRadius == -1) return true;
return restrictCenter->distSqr(x, y, z) < restrictRadius * restrictRadius;
return restrictCenter.distSqr(x, y, z) < restrictRadius * restrictRadius;
}
void PathfinderMob::restrictTo(int x, int y, int z, int radius) {
restrictCenter->set(x, y, z);
restrictCenter.set(x, y, z);
restrictRadius = radius;
}
Pos* PathfinderMob::getRestrictCenter() { return restrictCenter; }
Pos* PathfinderMob::getRestrictCenter() { return &restrictCenter; }
float PathfinderMob::getRestrictRadius() { return restrictRadius; }
@ -305,7 +300,7 @@ void PathfinderMob::tickLeash() {
}
if (!addedLeashRestrictionGoal) {
goalSelector.addGoal(2, leashRestrictionGoal, false);
goalSelector.addGoal(2, &leashRestrictionGoal, false);
getNavigation()->setAvoidWater(false);
addedLeashRestrictionGoal = true;
}
@ -332,7 +327,7 @@ void PathfinderMob::tickLeash() {
} else if (!isLeashed() && addedLeashRestrictionGoal) {
addedLeashRestrictionGoal = false;
goalSelector.removeGoal(leashRestrictionGoal);
goalSelector.removeGoal(&leashRestrictionGoal);
getNavigation()->setAvoidWater(true);
clearRestriction();
}

View file

@ -3,14 +3,14 @@
#include <memory>
#include "Mob.h"
#include "minecraft/Pos.h"
#include "minecraft/world/entity/Entity.h"
#include "minecraft/world/entity/Mob.h"
#include "minecraft/world/entity/ai/goal/MoveTowardsRestrictionGoal.h"
class Level;
class Path;
class AttributeModifier;
class Goal;
class Pos;
class PathfinderMob : public Mob {
public:
@ -32,9 +32,9 @@ protected:
int fleeTime;
private:
Pos* restrictCenter;
Pos restrictCenter;
float restrictRadius;
Goal* leashRestrictionGoal;
MoveTowardsRestrictionGoal leashRestrictionGoal;
bool addedLeashRestrictionGoal;
protected:

View file

@ -11,10 +11,10 @@ class Node {
friend class EnderDragon;
public:
const int x, y, z;
int x, y, z;
private:
const int hash;
int hash;
protected:
int heapIdx;

View file

@ -1,31 +1,12 @@
#include "Path.h"
#include <string.h>
#include "minecraft/world/entity/Entity.h"
#include "minecraft/world/level/pathfinder/Node.h"
#include "minecraft/world/phys/Vec3.h"
Path::~Path() {
for (size_t i = 0; i < nodes.size(); i++) delete nodes[i];
}
Path::Path(std::vector<Node*>& nodes) {
index = 0;
length = nodes.size();
// 4J - copying these nodes over from a std::vector<Node*> (which is an
// array of Node
// * references) to just a straight array of Nodes, so that this Path is no
// longer dependent of Nodes allocated elsewhere and can handle its own
// destruction Note: cameFrom pointer will be useless now but that isn't
// used once this is just a path
this->nodes = std::vector<Node*>(length);
for (int i = 0; i < length; i++) {
this->nodes[i] = new Node();
memcpy(this->nodes[i], nodes[i], sizeof(Node));
}
Path::Path(std::vector<Node*>& src)
: nodes(src.size()), index(0), length(static_cast<int>(src.size())) {
for (int i = 0; i < length; i++) nodes[i] = *src[i];
}
void Path::next() { index++; }
@ -34,12 +15,12 @@ bool Path::isDone() { return index >= length; }
Node* Path::last() {
if (length > 0) {
return nodes[length - 1];
return &nodes[length - 1];
}
return nullptr;
}
Node* Path::get(int i) { return nodes[i]; }
Node* Path::get(int i) { return &nodes[i]; }
int Path::getSize() { return length; }
@ -50,25 +31,25 @@ int Path::getIndex() { return index; }
void Path::setIndex(int index) { this->index = index; }
Vec3 Path::getPos(std::shared_ptr<Entity> e, int index) {
double x = nodes[index]->x + (int)(e->bbWidth + 1) * 0.5;
double y = nodes[index]->y;
double z = nodes[index]->z + (int)(e->bbWidth + 1) * 0.5;
double x = nodes[index].x + (int)(e->bbWidth + 1) * 0.5;
double y = nodes[index].y;
double z = nodes[index].z + (int)(e->bbWidth + 1) * 0.5;
return Vec3(x, y, z);
}
Vec3 Path::currentPos(std::shared_ptr<Entity> e) { return getPos(e, index); }
Vec3 Path::currentPos() {
return Vec3(nodes[index]->x, nodes[index]->y, nodes[index]->z);
return Vec3(nodes[index].x, nodes[index].y, nodes[index].z);
}
bool Path::sameAs(Path* path) {
if (path == nullptr) return false;
if (path->nodes.size() != nodes.size()) return false;
for (int i = 0; i < nodes.size(); ++i)
if (nodes[i]->x != path->nodes[i]->x ||
nodes[i]->y != path->nodes[i]->y ||
nodes[i]->z != path->nodes[i]->z)
for (size_t i = 0; i < nodes.size(); ++i)
if (nodes[i].x != path->nodes[i].x ||
nodes[i].y != path->nodes[i].y ||
nodes[i].z != path->nodes[i].z)
return false;
return true;
}

View file

@ -13,13 +13,16 @@ class Path {
friend class PathFinder;
private:
std::vector<Node*> nodes;
// Nodes are stored by value. The vector is sized once in the constructor
// and never resized, so Node* returned by get()/last() remain valid for
// the lifetime of the Path.
std::vector<Node> nodes;
int index;
int length;
public:
Path(std::vector<Node*>& nodes);
~Path();
~Path() = default;
void next();
bool isDone();
@ -30,7 +33,6 @@ public:
int getIndex();
void setIndex(int index);
Vec3 getPos(std::shared_ptr<Entity> e, int index);
std::vector<Node*> Getarray();
Vec3 currentPos(std::shared_ptr<Entity> e);
Vec3 currentPos();
bool sameAs(Path* path);