Open source Star Ruler 2 source code!
This commit is contained in:
@@ -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);
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user