Open source Star Ruler 2 source code!
This commit is contained in:
@@ -0,0 +1,242 @@
|
||||
import saving;
|
||||
import Node@ getCullingNode(const vec3d& pos) from "map_generation";
|
||||
import system_flags;
|
||||
|
||||
tidy class RegionScript {
|
||||
bool delta = false;
|
||||
|
||||
array<int> systemFlags(getEmpireCount() * getSystemFlagCount(), 0);
|
||||
bool flagDelta = false;
|
||||
|
||||
void postInit(Region& region) {
|
||||
region.initRegion();
|
||||
}
|
||||
|
||||
void save(Region& region, SaveFile& file) {
|
||||
file << cast<Savable>(region.RegionObjects);
|
||||
file << region.AngleOffset;
|
||||
file << region.InnerRadius;
|
||||
file << region.OuterRadius;
|
||||
file << region.SystemId;
|
||||
file << region.PrimaryEmpire;
|
||||
file << region.TradeMask;
|
||||
file << region.PlanetsMask;
|
||||
file << region.MemoryMask;
|
||||
file << region.VisionMask;
|
||||
file << region.ShipyardMask;
|
||||
file << region.ProtectedMask;
|
||||
file << region.FreeFTLMask;
|
||||
file << region.SiegedMask;
|
||||
file << region.SiegingMask;
|
||||
file << region.CoreSystemMask;
|
||||
file << region.GateMask.value;
|
||||
file << region.BasicVisionMask;
|
||||
file << region.TargetCostMod;
|
||||
file << region.BlockFTLMask.value;
|
||||
file << region.EngagedMask;
|
||||
file << region.CombatMask;
|
||||
file << region.SeenMask;
|
||||
|
||||
file << region.ScoutingMask.value;
|
||||
file << region.ExploredMask.value;
|
||||
|
||||
uint fCount = getSystemFlagCount();
|
||||
file << fCount;
|
||||
for(uint i = 0; i < fCount; ++i) {
|
||||
file.writeIdentifier(SI_SystemFlag, i);
|
||||
for(uint n = 0, ncnt = getEmpireCount(); n < ncnt; ++n)
|
||||
file << systemFlags[i*ncnt + n];
|
||||
}
|
||||
}
|
||||
|
||||
void load(Region& region, SaveFile& file) {
|
||||
file >> cast<Savable>(region.RegionObjects);
|
||||
file >> region.AngleOffset;
|
||||
file >> region.InnerRadius;
|
||||
file >> region.OuterRadius;
|
||||
file >> region.SystemId;
|
||||
file >> region.PrimaryEmpire;
|
||||
file >> region.TradeMask;
|
||||
if(file >= SV_0059) {
|
||||
file >> region.PlanetsMask;
|
||||
file >> region.MemoryMask;
|
||||
}
|
||||
file >> region.VisionMask;
|
||||
file >> region.ShipyardMask;
|
||||
file >> region.ProtectedMask;
|
||||
file >> region.FreeFTLMask;
|
||||
file >> region.SiegedMask;
|
||||
file >> region.SiegingMask;
|
||||
file >> region.CoreSystemMask;
|
||||
file >> region.GateMask.value;
|
||||
file >> region.BasicVisionMask;
|
||||
file >> region.TargetCostMod;
|
||||
file >> region.BlockFTLMask.value;
|
||||
file >> region.EngagedMask;
|
||||
file >> region.CombatMask;
|
||||
if(file >= SV_0047)
|
||||
file >> region.SeenMask;
|
||||
else
|
||||
region.SeenMask = region.VisionMask;
|
||||
|
||||
if(file >= SV_0099) {
|
||||
file >> region.ScoutingMask.value;
|
||||
file >> region.ExploredMask.value;
|
||||
}
|
||||
else {
|
||||
region.ExploredMask.value = int(~0);
|
||||
}
|
||||
|
||||
bindCullingNode(region, region.position, region.radius+128.0);
|
||||
|
||||
if(file >= SV_0094) {
|
||||
uint fCount = 0;
|
||||
file >> fCount;
|
||||
for(uint i = 0; i < fCount; ++i) {
|
||||
uint index = file.readIdentifier(SI_SystemFlag);
|
||||
if(index < getSystemFlagCount()) {
|
||||
for(uint n = 0, ncnt = getEmpireCount(); n < ncnt; ++n)
|
||||
file >> systemFlags[index*ncnt + n];
|
||||
}
|
||||
else {
|
||||
int dummy = 0;
|
||||
for(uint n = 0, ncnt = getEmpireCount(); n < ncnt; ++n)
|
||||
file >> dummy;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void postLoad(Region& region) {
|
||||
region.regionPostLoad();
|
||||
auto cnode = region.getNode();
|
||||
if(cnode !is null)
|
||||
cnode.reparent(getCullingNode(region.position));
|
||||
}
|
||||
|
||||
double tick(Region& region, double time) {
|
||||
region.tickRegion(time);
|
||||
return 0.2;
|
||||
}
|
||||
|
||||
void writeTypicalMask(Message& msg, uint mask) const {
|
||||
msg.writeBit(mask != 0);
|
||||
if(mask != 0)
|
||||
msg << mask;
|
||||
}
|
||||
|
||||
void writeMasks(const Region& region, Message& msg) {
|
||||
msg << region.VisionMask;
|
||||
|
||||
writeTypicalMask(msg, region.ProtectedMask.value);
|
||||
writeTypicalMask(msg, region.FreeFTLMask.value);
|
||||
writeTypicalMask(msg, region.SiegedMask.value);
|
||||
writeTypicalMask(msg, region.SiegingMask.value);
|
||||
writeTypicalMask(msg, region.GateMask.value);
|
||||
writeTypicalMask(msg, region.BlockFTLMask.value);
|
||||
writeTypicalMask(msg, region.CombatMask);
|
||||
writeTypicalMask(msg, region.TradeMask);
|
||||
writeTypicalMask(msg, region.MemoryMask);
|
||||
writeTypicalMask(msg, region.ExploredMask.value);
|
||||
}
|
||||
|
||||
void syncInitial(const Region& region, Message& msg) {
|
||||
msg.writeSmall(region.SystemId);
|
||||
msg.writeFixed(region.AngleOffset, 0.0, twopi);
|
||||
msg << region.OuterRadius;
|
||||
msg.writeFixed(region.InnerRadius, 0.0, region.OuterRadius);
|
||||
msg.writeSignedSmall(region.TargetCostMod);
|
||||
|
||||
writeMasks(region, msg);
|
||||
|
||||
msg.writeSmall(systemFlags.length);
|
||||
for(uint i = 0, cnt = systemFlags.length; i < cnt; ++i)
|
||||
msg.writeBit(systemFlags[i] > 0);
|
||||
}
|
||||
|
||||
bool getSystemFlag(Empire@ emp, uint flagIndex) const {
|
||||
if(emp is null || !emp.valid)
|
||||
return false;
|
||||
if(flagIndex >= getSystemFlagCount())
|
||||
return false;
|
||||
return systemFlags[flagIndex * getEmpireCount() + emp.index] > 0;
|
||||
}
|
||||
|
||||
bool getSystemFlagAny(uint flagIndex) const {
|
||||
if(flagIndex >= getSystemFlagCount())
|
||||
return false;
|
||||
for(uint i = 0, cnt = getEmpireCount(); i < cnt; ++i) {
|
||||
if(systemFlags[flagIndex * cnt + i] > 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void setSystemFlag(Empire@ emp, uint flagIndex, bool value) {
|
||||
if(emp is null || !emp.valid)
|
||||
return;
|
||||
if(flagIndex >= getSystemFlagCount())
|
||||
return;
|
||||
systemFlags[flagIndex * getEmpireCount() + emp.index] += value ? +1 : -1;
|
||||
flagDelta = true;
|
||||
}
|
||||
|
||||
void syncDetailed(const Region& region, Message& msg) {
|
||||
msg.writeSignedSmall(region.TargetCostMod);
|
||||
|
||||
writeMasks(region, msg);
|
||||
|
||||
msg.writeSmall(systemFlags.length);
|
||||
for(uint i = 0, cnt = systemFlags.length; i < cnt; ++i)
|
||||
msg.writeBit(systemFlags[i] > 0);
|
||||
}
|
||||
|
||||
void modTargetCostMod(Region& region, int mod) {
|
||||
region.TargetCostMod += mod;
|
||||
delta = true;
|
||||
}
|
||||
|
||||
int prevProtected = 0, prevFTL = 0, prevSieged = 0, prevSieging = 0, prevGate = 0, prevBlock = 0, prevCombat = 0;
|
||||
uint prevVision = 0, prevTrade = 0;
|
||||
|
||||
bool syncDelta(const Region& region, Message& msg) {
|
||||
bool used = false;
|
||||
if(prevProtected != region.ProtectedMask.value || prevFTL != region.FreeFTLMask.value
|
||||
|| prevSieged != region.SiegedMask.value || prevSieging != region.SiegingMask.value
|
||||
|| prevVision != region.VisionMask || prevGate != region.GateMask.value
|
||||
|| prevBlock != region.BlockFTLMask.value || prevCombat != region.CombatMask
|
||||
|| prevTrade != region.TradeMask
|
||||
|| delta)
|
||||
{
|
||||
msg.write1();
|
||||
msg.writeSignedSmall(region.TargetCostMod);
|
||||
writeMasks(region, msg);
|
||||
|
||||
prevProtected = region.ProtectedMask.value;
|
||||
prevFTL = region.FreeFTLMask.value;
|
||||
prevSieged = region.SiegedMask.value;
|
||||
prevSieging = region.SiegingMask.value;
|
||||
prevVision = region.VisionMask;
|
||||
prevGate = region.GateMask.value;
|
||||
prevBlock = region.BlockFTLMask.value;
|
||||
prevCombat = region.CombatMask;
|
||||
prevTrade = region.TradeMask;
|
||||
delta = false;
|
||||
used = true;
|
||||
}
|
||||
else {
|
||||
msg.write0();
|
||||
}
|
||||
if(flagDelta) {
|
||||
used = true;
|
||||
flagDelta = false;
|
||||
msg.write1();
|
||||
for(uint i = 0, cnt = systemFlags.length; i < cnt; ++i)
|
||||
msg.writeBit(systemFlags[i] > 0);
|
||||
}
|
||||
else {
|
||||
msg.write0();
|
||||
}
|
||||
return used;
|
||||
}
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,280 @@
|
||||
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();
|
||||
}
|
||||
Reference in New Issue
Block a user