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

348 lines
7.2 KiB
ActionScript 3

from settings.map_lib import SystemDesc;
#section gui
from navigation.systems import get_systemCount, getSystem;
#section server-side
import SystemDesc@ getSystem(uint index) from "game_start";
import SystemDesc@ getSystem(Region@ region) from "game_start";
import uint get_systemCount() from "game_start";
#section menu
uint get_systemCount() { return 0; }
SystemDesc@ getSystem(uint index) { return null; }
SystemDesc@ getSystem(Region@ region) { return null; }
#section all
const double MAX_LINK_DISTANCE = INFINITY;
class SystemPath : Serializable {
int[] path;
SystemDesc@ goal;
SystemDesc@ origin;
double maxLinkDistance = MAX_LINK_DISTANCE;
priority_queue q;
double[] dist;
int[] previous;
bool[] visited;
SystemPath() {
}
bool get_valid() {
return path.length != 0;
}
void read(Message& msg) {
if(msg.readBit()) {
uint ind = 0;
msg >> ind;
@goal = getSystem(ind);
}
else {
@goal = null;
}
if(msg.readBit()) {
uint ind = 0;
msg >> ind;
@origin = getSystem(ind);
}
else {
@origin = null;
}
uint cnt = msg.readSmall();
path.length = cnt;
for(uint i = 0; i < cnt; ++i)
msg >> path[i];
maxLinkDistance = msg.read_float();
}
void write(Message& msg) {
if(goal !is null) {
msg.write1();
msg << goal.index;
}
else {
msg.write0();
}
if(origin !is null) {
msg.write1();
msg << origin.index;
}
else {
msg.write0();
}
uint cnt = path.length;
msg.writeSmall(cnt);
for(uint i = 0; i < cnt; ++i)
msg << path[i];
msg << float(maxLinkDistance);
}
void clear() {
@goal = null;
@origin = null;
path.length = 0;
}
uint get_pathSize() {
return path.length;
}
SystemDesc@ get_pathNode(uint index) {
if(index >= path.length)
return null;
int sysindex = path[index];
return getSystem(uint(sysindex));
}
void itLink(SystemDesc@ node, SystemDesc@ other, double distance) {
//Don't consider links over the maximum distance
if(distance > maxLinkDistance)
return;
//Don't consider already visited nodes
if(visited[other.index])
return;
//If the path through here is faster,
//run it through here instead
double pthlen = dist[node.index] + distance;
if(pthlen < dist[other.index]) {
dist[other.index] = pthlen;
previous[other.index] = int(node.index);
q.push(int(other.index), -dist[other.index]);
}
}
void itNodes(SystemDesc@ node) {
//Add adjacencies
uint ncnt = node.adjacent.length;
for(uint j = 0; j < ncnt; ++j) {
SystemDesc@ other = getSystem(node.adjacent[j]);
double dist = node.adjacentDist[j];
itLink(node, other, dist);
}
//Add wormholes
ncnt = node.wormholes.length;
for(uint j = 0; j < ncnt; ++j) {
SystemDesc@ other = getSystem(node.wormholes[j]);
itLink(node, other, 0.0);
}
}
//Run dijkstra and generate a path
bool generate(SystemDesc@ from, SystemDesc@ to, bool keepCache = false) {
@origin = from;
@goal = to;
return generate(keepCache);
}
bool generate(bool keepCache = false) {
uint cnt = systemCount;
while(!q.empty())
q.pop();
path.length = 0;
if(origin is null || goal is null)
return false;
if(origin is goal) {
path.insertLast(goal.index);
return true;
}
dist.length = cnt;
previous.length = cnt;
visited.length = cnt;
for(uint i = 0; i < cnt; ++i) {
dist[i] = INFINITY;
previous[i] = -1;
visited[i] = false;
}
dist[origin.index] = 0;
q.push(int(origin.index), 0);
//Run dijkstra
while(!q.empty()) {
//Retrieve the highest priority node
uint index = uint(q.top());
SystemDesc@ node = getSystem(index);
//Stop if all the nodes are unreachable
if(dist[index] == INFINITY)
break;
q.pop();
//Only visit nodes once
if(visited[index])
continue;
visited[index] = true;
//Check all neighbours
itNodes(node);
}
//Check if a path was found
if(previous[goal.index] == -1)
return false;
//Generate the path in reverse form
uint current = goal.index;
uint orig = origin.index;
while(current != orig) {
path.insertLast(current);
current = previous[current];
}
path.insertLast(current);
path.reverse();
if(!keepCache) {
dist.length = 0;
previous.length = 0;
visited.length = 0;
}
return true;
}
void printPath() {
if(goal is null || origin is null) {
print("Uninitialized path.");
return;
}
print(origin.name+" --> "+goal.name);
if(path.length == 0) {
print("Invalid path.");
return;
}
for(uint i = 0, cnt = path.length; i < cnt; ++i)
print(" . "+pathNode[i].name);
}
};
class TradePath : SystemPath {
Empire@ forEmpire;
bool onlyValid = true;
bool foundGate = false;
TradePath() {
}
TradePath(Empire@ emp) {
@forEmpire = emp;
}
void read(Message& msg) {
msg >> forEmpire;
msg >> onlyValid;
SystemPath::read(msg);
}
void write(Message& msg) {
msg << forEmpire;
msg << onlyValid;
SystemPath::write(msg);
}
bool canLink(SystemDesc@ node, SystemDesc@ other) {
if(node is other || forEmpire is null)
return true;
if(node.isAdjacent(other)) {
if(forEmpire.GlobalTrade)
return true;
if(node !is origin && node.object.TradeMask & forEmpire.TradeMask.value == 0)
return false;
if(other !is goal && other.object.TradeMask & forEmpire.TradeMask.value == 0)
return false;
}
else {
if(node.object.GateMask.value & forEmpire.mask == 0)
return false;
if(other.object.GateMask.value & forEmpire.mask == 0)
return false;
}
return true;
}
bool get_isUsablePath() {
if(!valid)
return false;
if(forEmpire !is null) {
uint cnt = path.length;
SystemDesc@ prev = origin;
for(uint i = 0, cnt = path.length; i < cnt; ++i) {
SystemDesc@ desc = getSystem(path[i]);
if(!canLink(prev, desc))
return false;
@prev = desc;
}
}
return true;
}
bool generate(bool keepCache = false) override {
onlyValid = true;
foundGate = false;
return SystemPath::generate(keepCache=keepCache);
}
bool generate(bool OnlyValid, bool keepCache) {
onlyValid = OnlyValid;
foundGate = false;
return SystemPath::generate(keepCache=keepCache);
}
void itLink(SystemDesc@ node, SystemDesc@ other, double distance) override {
if(forEmpire !is null && onlyValid && !canLink(node, other))
return;
SystemPath::itLink(node, other, distance);
}
void itNodes(SystemDesc@ node) override {
if(forEmpire !is null && !foundGate) {
if(node.object.GateMask.value & forEmpire.mask != 0) {
foundGate = true;
for(uint i = 0, cnt = systemCount; i < cnt; ++i) {
auto@ other = getSystem(i);
if(other is node)
continue;
if(other.object.GateMask.value & forEmpire.mask != 0)
SystemPath::itLink(node, other, 0.05);
}
}
}
SystemPath::itNodes(node);
}
};
const SystemDesc@ getClosestSystem(const vec3d& point, Empire& presence, bool trade = false) {
const SystemDesc@ best;
double bestDist = INFINITY;
for(uint i = 0, cnt = systemCount; i < cnt; ++i) {
auto@ sys = getSystem(i);
if(trade) {
if(sys.object.TradeMask & presence.TradeMask.value == 0)
continue;
}
else {
if(sys.object.PlanetsMask & presence.mask == 0)
continue;
}
double d = sys.object.position.distanceToSQ(point);
if(d < bestDist) {
@best = sys;
bestDist = d;
}
}
return best;
}