Files
starruler-linux/scripts/shared/oddity_navigation.as
T
2018-07-17 14:15:37 +02:00

341 lines
8.4 KiB
ActionScript

export PathNode;
import saving;
final class PathNode : Serializable, Savable {
Object@ pathEntry;
Object@ pathExit;
vec3d pathTo;
float dist = 0;
void write(Message& msg) {
msg.writeBit(pathEntry !is null);
if(pathEntry !is null) {
msg << pathEntry;
msg << pathExit;
}
else {
msg.writeMedVec3(pathTo);
msg << dist;
}
}
void read(Message& msg) {
if(msg.readBit()) {
msg >> pathEntry;
msg >> pathExit;
}
else {
@pathEntry = null;
@pathExit = null;
pathTo = msg.readMedVec3();
msg >> dist;
}
}
void save(SaveFile& file) {
file << pathEntry;
file << pathExit;
file << pathTo;
file << dist;
}
void load(SaveFile& file) {
file >> pathEntry;
file >> pathExit;
file >> pathTo;
if(file >= SV_0086)
file >> dist;
}
vec3d pathOut() {
if(pathExit !is null)
return pathExit.position;
return pathTo;
}
#section server-side
uint get_visionMask() const {
if(pathExit !is null)
return pathExit.visibleMask;
return 0;
}
#section all
bool valid(Object& obj) {
if(pathEntry !is null && !pathEntry.valid)
return false;
if(pathExit !is null && !pathExit.valid)
return false;
/*Orbital@ orb = cast<Orbital>(pathEntry);*/
/*if(orb !is null && orb.Disabled)*/
/* return false;*/
/*if(pathExit !is null) {*/
/* if(!pathExit.valid)*/
/* return false;*/
/* @orb = cast<Orbital>(pathExit);*/
/* if(orb !is null && orb.Disabled)*/
/* return false;*/
/*}*/
return true;
}
};
#section server-side
ReadWriteMutex mutex;
array<Oddity@> gates;
export addOddityGate;
void addOddityGate(Oddity& gate) {
WriteLock lock(mutex);
gates.insertLast(gate);
}
export removeOddityGate;
void removeOddityGate(Oddity& gate) {
WriteLock lock(mutex);
gates.remove(gate);
}
export pathOddityGates;
double pathOddityGates(Empire@ emp, array<PathNode@>@ path, const vec3d& from, const vec3d& to, double accel = 0.0) {
if(path !is null)
path.length = 0;
ReadLock lock(mutex);
double eta = 0.0;
doPathing(gates, emp, from, to, 0, path, eta, accel);
return eta;
}
double pathOddityGates(array<Oddity@>& gates, Empire@ emp, array<PathNode@>@ path, const vec3d& from, const vec3d& to, double accel = 0.0) {
if(path !is null)
path.length = 0;
double eta = 0.0;
doPathing(gates, emp, from, to, 0, path, eta, accel);
return eta;
}
export getOddityGates;
void getOddityGates(array<Oddity@>& output) {
ReadLock lock(mutex);
output = gates;
}
export grantOddityGateVision;
void grantOddityGateVision(Empire& emp) {
ReadLock lck(mutex);
for(uint i = 0, cnt = gates.length; i < cnt; ++i)
gates[i].donatedVision |= emp.mask;
}
double dumbETA(double dist, double accel) {
return sqrt(4.0 * (dist / accel));
}
export hasOddityLink;
bool hasOddityLink(Region@ fromRegion, Region@ toRegion, double minDuration = 0.0) {
if(fromRegion is null || toRegion is null)
return false;
ReadLock lck(mutex);
for(uint i = 0, cnt = gates.length; i < cnt; ++i) {
auto@ obj = gates[i];
if(obj.region !is fromRegion)
continue;
if(minDuration > 0 && obj.getTimer() < minDuration)
continue;
vec3d dest = obj.getGateDest();
if(dest.distanceTo(toRegion.position) < toRegion.radius)
return true;
}
return false;
}
bool hasOddityLink(array<Oddity@>& gates, Region@ fromRegion, Region@ toRegion, double minDuration = 0.0) {
if(fromRegion is null || toRegion is null)
return false;
ReadLock lck(mutex);
for(uint i = 0, cnt = gates.length; i < cnt; ++i) {
auto@ obj = gates[i];
if(obj.region !is fromRegion)
continue;
if(minDuration > 0 && obj.getTimer() < minDuration)
continue;
vec3d dest = obj.getGateDest();
if(dest.distanceTo(toRegion.position) < toRegion.radius)
return true;
}
return false;
}
bool hasOddityLink(Region@ fromRegion, const vec3d& nearPosition, double maxDistance, double minDuration = 0.0) {
if(fromRegion is null)
return false;
ReadLock lck(mutex);
for(uint i = 0, cnt = gates.length; i < cnt; ++i) {
auto@ obj = gates[i];
if(obj.region !is fromRegion)
continue;
if(minDuration > 0 && obj.getTimer() < minDuration)
continue;
vec3d dest = obj.getGateDest();
if(dest.distanceTo(nearPosition) < maxDistance)
return true;
}
return false;
}
export getPathDistance;
double getPathDistance_client(Player& pl, vec3d from, vec3d to) {
Empire@ emp = pl.emp;
if(emp is null || !emp.valid)
return from.distanceTo(to);
return getPathDistance(emp, from, to);
}
double getPathDistance(Empire@ emp, const vec3d& from, const vec3d& to) {
array<PathNode@> path;
pathOddityGates(emp, path, from, to, 1.0);
return getPathDistance(from, to, path);
}
double getPathDistance(const vec3d& startPos, const vec3d& endPos, array<PathNode@>@ path = null) {
double distance = 0.0;
vec3d pos = startPos;
if(path !is null) {
for(uint i = 0, cnt = path.length; i < cnt; ++i) {
auto@ node = path[i];
if(node.pathEntry !is null)
distance += node.pathEntry.position.distanceTo(pos);
else
distance += node.pathTo.distanceTo(pos);
if(node.pathExit !is null)
pos = node.pathExit.position;
else
pos = node.pathTo;
}
}
distance += pos.distanceTo(endPos);
return distance;
}
double getPathDistance(array<Oddity@>& gates, Empire@ emp, const vec3d& from, const vec3d& to) {
array<PathNode@> path;
pathOddityGates(gates, emp, path, from, to, 1.0);
return getPathDistance(from, to, path);
}
export getPathETA;
double getPathETA(const vec3d& startPos, const vec3d& endPos, double accel, array<PathNode@>@ path = null) {
double eta = 0.0;
vec3d pos = startPos;
if(path !is null) {
for(uint i = 0, cnt = path.length; i < cnt; ++i) {
auto@ node = path[i];
if(node.pathEntry !is null)
eta += dumbETA(node.pathEntry.position.distanceTo(pos), accel);
else
eta += dumbETA(node.pathTo.distanceTo(pos), accel);
if(node.pathExit !is null)
pos = node.pathExit.position;
else
pos = node.pathTo;
}
}
eta += dumbETA(pos.distanceTo(endPos), accel);
return eta;
}
const double SQRT_2 = sqrt(2.0);
uint doPathing(array<Oddity@>& gates, Empire@ emp, const vec3d& from, const vec3d& to, uint index, array<PathNode@>@ path, double& eta, double accel) {
//Check which gate jump makes this journey shorter by the most
Oddity@ shortest;
Object@ shortestGateIn; Object@ shortestGateOut;
double shortestDist = from.distanceTo(to);
if(emp.hasStargates()) {
Object@ entryGate = emp.getStargate(from);
Object@ exitGate = emp.getStargate(to);
if(entryGate !is null && exitGate !is null && entryGate !is exitGate) {
double gateDist = from.distanceTo(entryGate.position);
gateDist += exitGate.position.distanceTo(to);
gateDist *= SQRT_2;
if(gateDist < shortestDist) {
shortestDist = gateDist;
@shortestGateIn = entryGate;
@shortestGateOut = exitGate;
}
}
}
for(uint i = 0, cnt = gates.length; i < cnt; ++i) {
Oddity@ gate = gates[i];
if(emp !is null && !gate.isKnownTo(emp))
continue;
vec3d enter = gate.position;
vec3d exit = gate.getGateDest();
double enterDist = enter.distanceTo(from);
double exitDist = exit.distanceTo(to);
double dist = (enterDist + exitDist) * SQRT_2;
if(accel > 0) {
double timer = gate.getTimer();
if(timer >= 0) {
double curETA = eta + dumbETA(enterDist, accel);
if(curETA >= timer - 20.0)
continue;
}
}
if(dist < shortestDist) {
shortestDist = dist;
@shortest = gate;
}
}
if(shortest !is null) {
//Add to path
PathNode node;
@node.pathEntry = shortest;
@node.pathExit = shortest.getLink();
if(index > path.length)
path.length = index+1;
path.insertAt(index, node);
//Recurse into more paths
uint amount = 1;
amount += doPathing(gates, emp, from, shortest.position, index, path, eta, accel);
eta += dumbETA(path[index+amount-1].pathOut().distanceTo(shortest.position), accel);
amount += doPathing(gates, emp, shortest.getGateDest(), to, index+amount, path, eta, accel);
return amount;
}
else if(shortestGateIn !is null) {
//Add to path
PathNode node;
@node.pathEntry = shortestGateIn;
@node.pathExit = shortestGateOut;
if(index > path.length)
path.length = index+1;
path.insertAt(index, node);
//Recurse into more paths
uint amount = 1;
amount += doPathing(gates, emp, from, shortestGateIn.position, index, path, eta, accel);
eta += dumbETA(path[index+amount-1].pathOut().distanceTo(shortestGateIn.position), accel);
amount += doPathing(gates, emp, shortestGateOut.position, to, index+amount, path, eta, accel);
return amount;
}
return 0;
}