Open source Star Ruler 2 source code!

This commit is contained in:
Lucas de Vries
2018-07-17 14:15:37 +02:00
commit cc307720ff
4342 changed files with 2365070 additions and 0 deletions
+383
View File
@@ -0,0 +1,383 @@
import designs;
import design_settings;
const int DESIGN_SERIALIZE_VERSION = 1;
JSONTree@ serialize_design(const Design@ dsg, const DesignClass@ cls = null) {
JSONTree tree;
JSONNode@ root = tree.root.makeObject();
root["__VERSION__"] = DESIGN_SERIALIZE_VERSION;
root["name"] = dsg.name;
root["size"] = int(dsg.size);
root["hull"] = dsg.hull.baseHull.ident;
root["type"] = getHullTypeTag(dsg.hull);
root["gridWidth"] = dsg.hull.active.width;
root["gridHeight"] = dsg.hull.active.height;
if(dsg.forceHull)
root["forceHull"].setBool(true);
if(cls !is null)
root["class"] = cls.name;
else if(dsg.cls !is null)
root["class"] = dsg.cls.name;
JSONNode@ sysList = root["subsystems"].makeArray();
auto@ settings = cast<const DesignSettings>(dsg.settings);
if(settings !is null) {
JSONNode@ node = root["settings"].makeObject();
settings.write(node);
}
uint sysCnt = dsg.subsystemCount;
for(uint i = 0; i < sysCnt; ++i) {
const Subsystem@ sys = dsg.subsystems[i];
if(sys.type.isHull)
continue;
if(sys.type.isApplied)
continue;
JSONNode@ node = sysList.pushBack().makeObject();
node["type"] = sys.type.id;
if(sys.direction != vec3d_front()) {
JSONNode@ dir = node["direction"].makeArray();
dir.pushBack() = sys.direction.x;
dir.pushBack() = sys.direction.y;
dir.pushBack() = sys.direction.z;
}
JSONNode@ hexes = node["hexes"].makeArray();
uint hexCnt = sys.hexCount;
for(uint j = 0; j < hexCnt; ++j) {
vec2u hex = sys.hexagon(j);
JSONNode@ coord = hexes.pushBack().makeArray();
coord.pushBack() = hex.x;
coord.pushBack() = hex.y;
if(sys.module(j) !is sys.type.defaultModule)
coord.pushBack() = sys.module(j).id;
}
}
@sysList = null;
for(uint i = 0; i < sysCnt; ++i) {
const Subsystem@ sys = dsg.subsystems[i];
if(!sys.type.isApplied)
continue;
if(sysList is null)
@sysList = root["appliedSubsystems"].makeArray();
sysList.pushBack() = sys.type.id;
}
return tree;
}
void write_design(const Design@ dsg, const string& filename, const DesignClass@ cls = null, bool pretty = true) {
serialize_design(dsg, cls).writeFile(filename, pretty);
}
bool unserialize_design(JSONTree@ tree, DesignDescriptor& desc) {
JSONNode@ root = tree.root;
if(!root.isObject() || !root["name"].isString() || !root["size"].isInt() || !root["hull"].isString())
return false;
desc.name = root["name"].getString();
desc.size = root["size"].getInt();
if(desc.size < 1)
return false;
desc.forceHull = false;
auto@ force = root.findMember("forceHull");
if(force !is null && force.isBool())
desc.forceHull = force.getBool();
JSONNode@ cls = root.findMember("class");
if(cls !is null && cls.isString())
desc.className = cls.getString();
desc.hullName = root["hull"].getString();
@desc.hull = getHullDefinition(desc.hullName);
JSONNode@ sysList = root["subsystems"];
if(!sysList.isArray())
return false;
uint sysCnt = sysList.size();
for(uint i = 0; i < sysCnt; ++i) {
JSONNode@ node = sysList[i];
if(!node["type"].isString())
return false;
const SubsystemDef@ def = getSubsystemDef(node["type"].getString());
if(def is null)
continue;
desc.addSystem(def);
JSONNode@ dir = node["direction"];
if(dir.isArray() && dir.size() == 3)
desc.setDirection(vec3d(dir[0].getNumber(), dir[1].getNumber(), dir[2].getNumber()));
JSONNode@ hexes = node["hexes"];
if(!hexes.isArray())
return false;
uint hexCnt = hexes.size();
for(uint j = 0; j < hexCnt; ++j) {
JSONNode@ coord = hexes[j];
if(!coord.isArray() || coord.size() < 2)
return false;
vec2u pos(coord[0].getUint(), coord[1].getUint());
if(coord.size() == 2) {
desc.addHex(pos);
}
else {
const ModuleDef@ mod = def.module(coord[2].getString());
if(mod !is null)
desc.addHex(pos, mod);
else
desc.addHex(pos);
}
}
}
@sysList = root["appliedSubsystems"];
if(sysList !is null && sysList.isArray()) {
uint sysCnt = sysList.size();
for(uint i = 0; i < sysCnt; ++i) {
JSONNode@ node = sysList[i];
if(node is null || !node.isString())
continue;
const SubsystemDef@ def = getSubsystemDef(node.getString());
if(def !is null)
desc.applySubsystem(def);
}
}
if(desc.hull is null) {
JSONNode@ type = root.findMember("type");
if(type !is null && type.isString())
@desc.hull = getBestHull(desc, type.getString());
if(desc.hull is null)
return false;
}
JSONNode@ stNode = root.findMember("settings");
if(stNode !is null && stNode.isObject()) {
DesignSettings settings;
settings.read(stNode);
@desc.settings = settings;
}
else {
@desc.settings = null;
}
JSONNode@ w = root.findMember("gridWidth");
JSONNode@ h = root.findMember("gridHeight");
if(w !is null && w.isUint() && h !is null && h.isUint())
desc.gridSize = vec2u(w.getUint(), h.getUint());
else
desc.gridSize = getDesignGridSize(desc.hull, desc.size);
return true;
}
int upload_design(const Design@ design, const string& description = "", bool waitId = false) {
#section client
WebData dat;
dat.addPost("name", design.name);
dat.addPost("size", toString(design.size, 0));
dat.addPost("author", settings::sNickname);
dat.addPost("description", description);
dat.addPost("color", toString(design.color));
dat.addPost("data", serialize_design(design).toString());
webAPICall("designs/submit", dat);
if(waitId) {
while(!dat.completed)
sleep(100);
return toInt(dat.result);
}
#section all
return -1;
}
bool read_design(const string& filename, DesignDescriptor& desc) {
JSONTree tree;
tree.readFile(filename);
return unserialize_design(tree, desc);
}
string uniqueDesignName(string name, Empire@ emp) {
int num = 1;
string oldName = name;
int pos = oldName.findLast(" Mk");
if(pos != -1)
oldName = oldName.substr(0, pos);
while(emp.getDesign(name) !is null) {
string newName = oldName;
newName += " Mk";
appendRoman(num, newName);
name = newName;
++num;
}
return name;
}
string getHullTypeTag(const Hull@ hull) {
if(hull is null)
return "";
if(hull.hasTag("Flagship"))
return "Flagship";
if(hull.hasTag("Support"))
return "Support";
if(hull.hasTag("Satellite"))
return "Satellite";
if(hull.hasTag("Station"))
return "Station";
return "";
}
const Hull@ getBestHull(DesignDescriptor& desc, const string& hullTag, Empire@ emp = playerEmpire) {
const Shipset@ shipset;
if(emp is null || emp.shipset is null)
@shipset = getShipset("Volkur");
else
@shipset = emp.shipset;
if(shipset is null)
return null;
const Hull@ bestHull;
double bestHullDist = INFINITY;
for(uint i = 0, cnt = shipset.hullCount; i < cnt; ++i) {
const Hull@ hull = shipset.hulls[i];
//Check if it matches the tag
if(!hull.hasTag(hullTag))
continue;
if(bestHull is null)
@bestHull = hull;
//Make sure we can use this hull
if(hull.minSize >= 0 && hull.minSize > desc.size)
continue;
if(hull.maxSize >= 0 && hull.maxSize < desc.size)
continue;
//Check distance
double d = hull.getMatchDistance(desc);
if(hull is desc.hull)
d -= 0.1;
if(d < bestHullDist) {
bestHullDist = d;
@bestHull = hull;
}
}
return bestHull;
}
void describeDesign(const Design@ orig, DesignDescriptor& desc) {
desc.name = orig.name;
desc.className = orig.cls.name;
desc.gridSize = vec2u(orig.hull.gridSize);
desc.size = orig.size;
@desc.hull = orig.hull;
@desc.owner = orig.owner;
uint sysCnt = orig.subsystemCount;
for(uint i = 0; i < sysCnt; ++i) {
const Subsystem@ sys = orig.subsystems[i];
if(sys.type.isHull)
continue;
if(sys.type.isApplied) {
desc.applySubsystem(sys.type);
continue;
}
desc.addSystem(sys.type);
desc.setDirection(sys.direction);
uint hexCnt = sys.hexCount;
for(uint j = 0; j < hexCnt; ++j) {
vec2u hex = sys.hexagon(j);
desc.addHex(hex, sys.module(j));
}
}
}
void resizeDesign(const Design@ orig, int newSize, DesignDescriptor& desc) {
describeDesign(orig, desc);
desc.size = newSize;
}
class DesignSet {
DesignDescriptor[] designs;
bool limitShipset = false;
bool softLimitRetry = false;
bool log = false;
void readDirectory(const string& directory) {
FileList list(directory, "*.design", true);
uint cnt = list.length;
designs.resize(cnt);
for(uint i = 0; i < cnt; ++i)
read_design(list.path[i], designs[i]);
}
void createFor(Empire@ emp, bool overrideLimit = false) const {
bool foundAny = false;
for(uint i = 0, cnt = designs.length; i < cnt; ++i) {
DesignDescriptor desc = designs[i];
@desc.owner = emp;
string hullName = format(desc.hullName, emp.shipset.ident);
@desc.hull = getHullDefinition(hullName);
if(desc.hull is null) {
hullName = format("$1FlagTiny", emp.shipset.ident);
@desc.hull = getHullDefinition(hullName);
if(desc.hull is null) {
if(!limitShipset || overrideLimit) {
hullName = format(desc.hullName, "Volkur");
@desc.hull = getHullDefinition(hullName);
if(desc.hull is null) {
if(desc.hull is null)
@desc.hull = getHullDefinition("VolkurFlagTiny");
}
}
if(desc.hull is null)
continue;
}
}
if(limitShipset && !overrideLimit) {
if(emp.shipset is null || !emp.shipset.hasHull(desc.hull))
continue;
}
else {
if(emp.shipset !is null && !emp.shipset.hasHull(desc.hull))
@desc.hull = getBestHull(desc, getHullTypeTag(desc.hull), emp);
}
if(desc.hull is null)
continue;
if(desc.className.length == 0)
desc.className = "Default";
const Design@ dsg = makeDesign(desc);
if(log && dsg !is null && dsg.hasFatalErrors()) {
print(emp.name+" Importing "+desc.name+":");
for(uint i = 0, cnt = dsg.errorCount; i < cnt; ++i)
print(" "+dsg.errors[i].text);
}
if(dsg is null || dsg.hasFatalErrors())
continue;
if(emp.getDesign(dsg.name) !is null)
continue;
if(desc.settings !is null)
dsg.setSettings(desc.settings);
const DesignClass@ cls = emp.getDesignClass(desc.className);
emp.addDesign(cls, dsg);
foundAny = true;
}
if(softLimitRetry && !foundAny && !overrideLimit)
createFor(emp, overrideLimit=true);
}
};