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

281 lines
6.4 KiB
ActionScript 3

Region@[] regions;
RegionSplit regionGroup(true);
tidy class RegionSplit {
planed plane;
RegionSplit@ back, front;
array<Region@> regs;
bool xSplit;
double maxRegionSize = 0;
RegionSplit() {
xSplit = true;
}
RegionSplit(bool useXSplit) {
xSplit = useXSplit;
}
Region@ findClosest(const vec3d& point, double& nearest) const {
Region@ closest;
if(back !is null) {
double dist = plane.distFromPlane(point);
if(dist > 0.0) {
if(dist > -nearest)
@closest = front.findClosest(point, nearest);
if(dist < nearest) {
Region@ c = back.findClosest(point, nearest);
if(c !is null)
@closest = c;
}
}
else {
if(dist < nearest)
@closest = back.findClosest(point, nearest);
if(dist > -nearest) {
Region@ c = front.findClosest(point, nearest);
if(c !is null)
@closest = c;
}
}
}
for(uint i = 0, cnt = regs.length; i < cnt; ++i) {
Region@ reg = regs[i];
double dist = reg.position.distanceTo(point) - reg.OuterRadius;
if(dist < nearest) {
@closest = reg;
nearest = dist;
}
}
return closest;
}
Region@ findRegion(const vec3d& point) const {
if(back !is null) {
double dist = plane.distFromPlane(point);
if(dist < maxRegionSize) {
Region@ region = back.findRegion(point);
if(region !is null)
return region;
}
if(dist > -maxRegionSize) {
Region@ region = front.findRegion(point);
if(region !is null)
return region;
}
return null;
}
else {
for(uint i = 0, cnt = regs.length; i < cnt; ++i) {
Region@ region = regs[i];
if(point.distanceToSQ(region.position) < region.OuterRadius * region.OuterRadius)
return region;
}
return null;
}
}
void addRegion(Region@ region) {
if(region.OuterRadius > maxRegionSize)
maxRegionSize = region.OuterRadius;
if(back !is null) {
if(plane.inFront(region.position))
front.addRegion(region);
else
back.addRegion(region);
}
else {
regs.insertLast(region);
//Once we have enough regions, split into two nodes
if(regs.length > 4) {
//TODO: Decide a better middle point (median, rather than mean)
vec3d avg;
for(uint i = 0, cnt = regs.length; i < cnt; ++i)
avg += regs[i].position;
avg /= double(regs.length);
if(xSplit)
plane = planed(avg, vec3d_front());
else
plane = planed(avg, vec3d_right());
@back = RegionSplit(!xSplit);
@front = RegionSplit(!xSplit);
for(uint i = 0, cnt = regs.length; i < cnt; ++i)
addRegion(regs[i]);
regs.length = 0;
}
}
}
};
Region@ findNearestRegion(const vec3d& point) {
double dist = 1.0e35;
return regionGroup.findClosest(point, dist);
}
void regenerateRegionGroups() {
RegionSplit newSplit(true);
for(uint i = 0, cnt = regions.length; i < cnt; ++i)
newSplit.addRegion(regions[i]);
regionGroup = newSplit;
calcGalaxyExtents();
}
void addRegion(Region@ region) {
regions.insertLast(region);
regionGroup.addRegion(region);
}
bool inRegion(Region@ region, Object& obj) {
return obj.position.distanceToSQ(region.position) < region.OuterRadius * region.OuterRadius;
}
bool inRegion(Region@ region, const vec3d& position) {
return position.distanceToSQ(region.position) < region.OuterRadius * region.OuterRadius;
}
bool updateRegion(Object& obj, bool takeVision = true) {
Region@ prevRegion = obj.region;
if(prevRegion !is null) {
if(takeVision)
obj.donatedVision |= prevRegion.DonateVisionMask;
if(inRegion(prevRegion, obj))
return false;
prevRegion.leaveRegion(obj);
}
Region@ newRegion = getRegion(obj.position);
if(newRegion is null && prevRegion is null)
return false;
@obj.region = newRegion;
if(newRegion !is null) {
newRegion.enterRegion(obj);
Node@ node = obj.getNode();
if(node !is null)
node.hintParentObject(newRegion);
}
else {
Node@ node = obj.getNode();
if(node !is null)
node.reparent(null);
}
return true;
}
void leaveRegion(Object& obj) {
Region@ reg = obj.region;
if(reg !is null) {
obj.region.leaveRegion(obj);
@obj.region = null;
}
}
void regionOwnerChange(Object& obj, Empire@ prevOwner) {
if(obj.region !is null)
obj.region.regionObjectOwnerChange(obj, prevOwner, obj.owner);
}
Region@ getRegion(const vec3d& point) {
return regionGroup.findRegion(point);
}
Region@ getRegion_client(vec3d point) {
return regionGroup.findRegion(point);
}
bool calcExtents = true;
vec3d extentMin, extentMax;
void calcGalaxyExtents() {
if(calcExtents) {
for(uint i = 0, cnt = regions.length; i < cnt; ++i) {
auto@ sys = regions[i];
if(i == 0) {
extentMin = sys.position - vec3d(sys.radius);
extentMax = sys.position + vec3d(sys.radius);
}
else {
insertExtent(sys.position - vec3d(sys.radius), sys.position + vec3d(sys.radius));
}
}
calcExtents = false;
}
}
void insertExtent(const vec3d& lower, const vec3d& upper) {
if(extentMin.x > lower.x)
extentMin.x = lower.x;
if(extentMin.y > lower.y)
extentMin.y = lower.y;
if(extentMin.z > lower.z)
extentMin.z = lower.z;
if(extentMax.x < upper.x)
extentMax.x = upper.x;
if(extentMax.y < upper.y)
extentMax.y = upper.y;
if(extentMax.z < upper.z)
extentMax.z = upper.z;
}
bool isOutsideUniverseExtents_client(vec3d pos, double margin = 500.0) {
return isOutsideUniverseExtents(pos, margin);
}
bool isOutsideUniverseExtents(const vec3d& pos, double margin = 500.0) {
return pos.x < extentMin.x-margin || pos.y < extentMin.y-margin || pos.z < extentMin.z-margin
|| pos.x > extentMax.x+margin || pos.y > extentMax.y+margin || pos.z > extentMax.z+margin;
}
void limitToUniverseExtents(vec3d& pos, double margin = 500.0) {
pos.x = clamp(pos.x, extentMin.x-margin, extentMax.x+margin);
pos.y = clamp(pos.y, extentMin.y-margin, extentMax.y+margin);
pos.z = clamp(pos.z, extentMin.z-margin, extentMax.z+margin);
}
#section server
void syncInitial(Message& msg) {
uint cnt = regions.length;
msg << cnt;
for(uint i = 0; i < cnt; ++i)
msg << regions[i];
}
void save(SaveFile& msg) {
uint cnt = regions.length;
msg << cnt;
for(uint i = 0; i < cnt; ++i)
msg << regions[i];
}
void load(SaveFile& msg) {
uint cnt = 0;
msg >> cnt;
regions.length = cnt;
for(uint i = 0; i < cnt; ++i) {
msg >> regions[i];
regionGroup.addRegion(regions[i]);
}
calcGalaxyExtents();
}
#section shadow
void syncInitial(Message& msg) {
//Read systems
uint cnt = 0;
msg >> cnt;
regions.length = cnt;
for(uint i = 0; i < cnt; ++i) {
msg >> regions[i];
regionGroup.addRegion(regions[i]);
}
calcGalaxyExtents();
}