Open source Star Ruler 2 source code!
This commit is contained in:
@@ -0,0 +1,694 @@
|
||||
import empire_ai.weasel.WeaselAI;
|
||||
import empire_ai.weasel.ImportData;
|
||||
|
||||
import resources;
|
||||
import planet_levels;
|
||||
import system_pathing;
|
||||
import systems;
|
||||
|
||||
interface RaceResources {
|
||||
void levelRequirements(Object& obj, int targetLevel, array<ResourceSpec@>& specs);
|
||||
};
|
||||
|
||||
final class Resources : AIComponent {
|
||||
RaceResources@ race;
|
||||
|
||||
array<ImportData@> requested;
|
||||
array<ImportData@> active;
|
||||
int nextImportId = 0;
|
||||
|
||||
array<ExportData@> available;
|
||||
array<ExportData@> used;
|
||||
int nextExportId = 0;
|
||||
|
||||
void create() {
|
||||
@race = cast<RaceResources>(ai.race);
|
||||
}
|
||||
|
||||
void save(SaveFile& file) {
|
||||
file << nextImportId;
|
||||
file << nextExportId;
|
||||
|
||||
uint cnt = 0;
|
||||
|
||||
cnt = requested.length;
|
||||
file << cnt;
|
||||
for(uint i = 0; i < cnt; ++i) {
|
||||
saveImport(file, requested[i]);
|
||||
file << requested[i];
|
||||
}
|
||||
|
||||
cnt = active.length;
|
||||
file << cnt;
|
||||
for(uint i = 0; i < cnt; ++i) {
|
||||
saveImport(file, active[i]);
|
||||
file << active[i];
|
||||
}
|
||||
|
||||
cnt = available.length;
|
||||
file << cnt;
|
||||
for(uint i = 0; i < cnt; ++i) {
|
||||
saveExport(file, available[i]);
|
||||
file << available[i];
|
||||
saveImport(file, available[i].request);
|
||||
}
|
||||
|
||||
cnt = used.length;
|
||||
file << cnt;
|
||||
for(uint i = 0; i < cnt; ++i) {
|
||||
saveExport(file, used[i]);
|
||||
file << used[i];
|
||||
saveImport(file, used[i].request);
|
||||
}
|
||||
}
|
||||
|
||||
void load(SaveFile& file) {
|
||||
file >> nextImportId;
|
||||
file >> nextExportId;
|
||||
|
||||
uint cnt = 0;
|
||||
|
||||
file >> cnt;
|
||||
for(uint i = 0; i < cnt; ++i) {
|
||||
auto@ data = loadImport(file);
|
||||
file >> data;
|
||||
requested.insertLast(data);
|
||||
}
|
||||
|
||||
file >> cnt;
|
||||
for(uint i = 0; i < cnt; ++i) {
|
||||
auto@ data = loadImport(file);
|
||||
file >> data;
|
||||
active.insertLast(data);
|
||||
}
|
||||
|
||||
file >> cnt;
|
||||
for(uint i = 0; i < cnt; ++i) {
|
||||
auto@ data = loadExport(file);
|
||||
file >> data;
|
||||
@data.request = loadImport(file);
|
||||
available.insertLast(data);
|
||||
}
|
||||
|
||||
file >> cnt;
|
||||
for(uint i = 0; i < cnt; ++i) {
|
||||
auto@ data = loadExport(file);
|
||||
file >> data;
|
||||
@data.request = loadImport(file);
|
||||
used.insertLast(data);
|
||||
}
|
||||
}
|
||||
|
||||
array<ImportData@> importIds;
|
||||
ImportData@ loadImport(int id) {
|
||||
if(id == -1)
|
||||
return null;
|
||||
for(uint i = 0, cnt = importIds.length; i < cnt; ++i) {
|
||||
if(importIds[i].id == id)
|
||||
return importIds[i];
|
||||
}
|
||||
ImportData data;
|
||||
data.id = id;
|
||||
importIds.insertLast(data);
|
||||
return data;
|
||||
}
|
||||
ImportData@ loadImport(SaveFile& file) {
|
||||
int id = -1;
|
||||
file >> id;
|
||||
if(id == -1)
|
||||
return null;
|
||||
else
|
||||
return loadImport(id);
|
||||
}
|
||||
void saveImport(SaveFile& file, ImportData@ data) {
|
||||
int id = -1;
|
||||
if(data !is null)
|
||||
id = data.id;
|
||||
file << id;
|
||||
}
|
||||
array<ExportData@> exportIds;
|
||||
ExportData@ loadExport(int id) {
|
||||
if(id == -1)
|
||||
return null;
|
||||
for(uint i = 0, cnt = exportIds.length; i < cnt; ++i) {
|
||||
if(exportIds[i].id == id)
|
||||
return exportIds[i];
|
||||
}
|
||||
ExportData data;
|
||||
data.id = id;
|
||||
exportIds.insertLast(data);
|
||||
return data;
|
||||
}
|
||||
ExportData@ loadExport(SaveFile& file) {
|
||||
int id = -1;
|
||||
file >> id;
|
||||
if(id == -1)
|
||||
return null;
|
||||
else
|
||||
return loadExport(id);
|
||||
}
|
||||
void saveExport(SaveFile& file, ExportData@ data) {
|
||||
int id = -1;
|
||||
if(data !is null)
|
||||
id = data.id;
|
||||
file << id;
|
||||
}
|
||||
void postLoad(AI& ai) {
|
||||
importIds.length = 0;
|
||||
exportIds.length = 0;
|
||||
}
|
||||
|
||||
void start() {
|
||||
focusTick(0);
|
||||
}
|
||||
|
||||
void tick(double time) {
|
||||
}
|
||||
|
||||
uint checkIdx = 0;
|
||||
void focusTick(double time) {
|
||||
//Do a check to make sure our resource export setup is still correct
|
||||
if(used.length != 0) {
|
||||
checkIdx = (checkIdx+1) % used.length;
|
||||
ExportData@ res = used[checkIdx];
|
||||
if(res.request !is null && res.request.obj !is null && !res.isExportedTo(res.request.obj)) {
|
||||
if(log)
|
||||
ai.print("Break export to "+res.request.obj.name+": link changed underfoot", res.obj);
|
||||
breakImport(res);
|
||||
}
|
||||
else {
|
||||
bool valid = true;
|
||||
if(res.obj is null || res.obj.owner !is ai.empire || !res.obj.valid)
|
||||
valid = false;
|
||||
//Don't break these imports, we want to wait for the decay to happen
|
||||
else if((res.request is null || !res.request.obj.hasSurfaceComponent || res.request.obj.decayTime <= 0) && !res.obj.isAsteroid && !res.usable) {
|
||||
valid = false;
|
||||
}
|
||||
else if(res.request !is null) {
|
||||
if(res.request.obj.owner !is ai.empire || !res.request.obj.valid)
|
||||
valid = false;
|
||||
}
|
||||
if(!valid)
|
||||
breakImport(res);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//TODO: Make sure universal unique only applies once per planet
|
||||
|
||||
//Match requested with available
|
||||
for(uint i = 0, cnt = requested.length; i < cnt; ++i) {
|
||||
auto@ req = requested[i];
|
||||
req.cycled = true;
|
||||
|
||||
if(req.obj is null)
|
||||
continue;
|
||||
if(req.beingMet) {
|
||||
ai.print("Error: Requested is being met", req.obj);
|
||||
continue;
|
||||
}
|
||||
|
||||
ExportData@ source;
|
||||
double sourceWeight = 0.0;
|
||||
|
||||
for(uint j = 0, jcnt = available.length; j < jcnt; ++j) {
|
||||
auto@ av = available[j];
|
||||
if(av.request !is null) {
|
||||
ai.print("Error: Available is being used", av.obj);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!req.spec.meets(av.resource, av.obj, req.obj))
|
||||
continue;
|
||||
if(!av.usable || av.obj is null || !av.obj.valid || av.obj.owner !is ai.empire)
|
||||
continue;
|
||||
if(!canTradeBetween(av.obj, req.obj))
|
||||
continue;
|
||||
if(av.localOnly && av.obj !is req.obj)
|
||||
continue;
|
||||
|
||||
double weight = 1.0;
|
||||
if(req.obj is av.obj)
|
||||
weight = INFINITY;
|
||||
|
||||
if(weight > sourceWeight) {
|
||||
sourceWeight = weight;
|
||||
@source = av;
|
||||
}
|
||||
}
|
||||
|
||||
if(source !is null) {
|
||||
link(req, source);
|
||||
--i; --cnt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void turn() {
|
||||
}
|
||||
|
||||
bool get_hasOpenRequests() {
|
||||
for(uint i = 0, cnt = requested.length; i < cnt; ++i) {
|
||||
auto@ req = requested[i];
|
||||
if(req.isOpen)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
TradePath tradePather;
|
||||
int tradeDistance(Region& fromRegion, Region& toRegion) {
|
||||
@tradePather.forEmpire = ai.empire;
|
||||
tradePather.generate(getSystem(fromRegion), getSystem(toRegion), keepCache=true);
|
||||
if(!tradePather.valid)
|
||||
return -1;
|
||||
return tradePather.pathSize - 1;
|
||||
}
|
||||
|
||||
bool canTradeBetween(Object& fromObj, Object& toObj) {
|
||||
Region@ fromRegion = fromObj.region;
|
||||
if(fromRegion is null)
|
||||
return false;
|
||||
Region@ toRegion = toObj.region;
|
||||
if(toRegion is null)
|
||||
return false;
|
||||
return canTradeBetween(fromRegion, toRegion);
|
||||
}
|
||||
|
||||
bool canTradeBetween(Region& fromRegion, Region& toRegion) {
|
||||
if(fromRegion.sharesTerritory(ai.empire, toRegion))
|
||||
return true;
|
||||
int dist = tradeDistance(fromRegion, toRegion);
|
||||
if(dist < 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void link(ImportData@ req, ExportData@ source) {
|
||||
//Manage the data
|
||||
@source.request = req;
|
||||
@source.developUse = null;
|
||||
req.set(source);
|
||||
|
||||
requested.remove(req);
|
||||
active.insertLast(req);
|
||||
|
||||
req.beingMet = true;
|
||||
|
||||
available.remove(source);
|
||||
used.insertLast(source);
|
||||
|
||||
if(log)
|
||||
ai.print("link "+source.resource.name+" from "+source.obj.name+" to "+req.obj.name);
|
||||
|
||||
//Perform the actual export
|
||||
if(source.obj !is req.obj)
|
||||
source.obj.exportResourceByID(source.resourceId, req.obj);
|
||||
else
|
||||
source.obj.exportResourceByID(source.resourceId, null);
|
||||
}
|
||||
|
||||
ImportData@ requestResource(Object& toObject, ResourceSpec& spec, bool forLevel = false, bool activate = true, bool prioritize = false) {
|
||||
ImportData data;
|
||||
data.idleSince = gameTime;
|
||||
data.id = nextImportId++;
|
||||
@data.obj = toObject;
|
||||
@data.spec = spec;
|
||||
data.forLevel = forLevel;
|
||||
|
||||
if(log)
|
||||
ai.print("requested resource: "+spec.dump(), toObject);
|
||||
|
||||
if(activate) {
|
||||
if(prioritize)
|
||||
requested.insertAt(0, data);
|
||||
else
|
||||
requested.insertLast(data);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
ExportData@ availableResource(Object& fromObject, const ResourceType& resource, int id) {
|
||||
ExportData data;
|
||||
data.id = nextExportId++;
|
||||
@data.obj = fromObject;
|
||||
@data.resource = resource;
|
||||
data.resourceId = id;
|
||||
|
||||
if(log)
|
||||
ai.print("available resource: "+resource.name, fromObject);
|
||||
|
||||
available.insertLast(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
void checkReplaceCurrent(ExportData@ res) {
|
||||
//If the planet that this resource is on is currently importing this same resource, switch it around
|
||||
if(res.request !is null)
|
||||
return;
|
||||
|
||||
for(uint i = 0, cnt = used.length; i < cnt; ++i) {
|
||||
auto@ other = used[i];
|
||||
auto@ request = other.request;
|
||||
if(request is null)
|
||||
continue;
|
||||
if(request.obj !is res.obj)
|
||||
continue;
|
||||
|
||||
if(request.spec.meets(res.resource, res.obj, res.obj)) {
|
||||
//Swap the import with using the local resource
|
||||
if(other.resource.exportable) {
|
||||
breakImport(other);
|
||||
link(request, res);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
array<Resource> checkResources;
|
||||
array<ExportData@>@ availableResource(Object& fromObject) {
|
||||
array<ExportData@> list;
|
||||
|
||||
checkResources.syncFrom(fromObject.getNativeResources());
|
||||
|
||||
uint nativeCount = checkResources.length;
|
||||
for(uint i = 0; i < nativeCount; ++i) {
|
||||
auto@ r = checkResources[i].type;
|
||||
if(r !is null)
|
||||
list.insertLast(availableResource(fromObject, r, checkResources[i].id));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
ExportData@ findResource(Object@ obj, int resourceId) {
|
||||
for(uint i = 0, cnt = available.length; i < cnt; ++i) {
|
||||
if(available[i].obj is obj && available[i].resourceId == resourceId)
|
||||
return available[i];
|
||||
}
|
||||
for(uint i = 0, cnt = used.length; i < cnt; ++i) {
|
||||
if(used[i].obj is obj && used[i].resourceId == resourceId)
|
||||
return used[i];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
ImportData@ findUnclaimed(ExportData@ forResource) {
|
||||
for(uint i = 0, cnt = requested.length; i < cnt; ++i) {
|
||||
auto@ req = requested[i];
|
||||
if(req.claimedFor)
|
||||
continue;
|
||||
if(req.beingMet)
|
||||
continue;
|
||||
|
||||
if(!req.spec.meets(forResource.resource, forResource.obj, req.obj))
|
||||
continue;
|
||||
if(!canTradeBetween(req.obj, forResource.obj))
|
||||
continue;
|
||||
|
||||
return req;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void breakImport(ImportData@ data) {
|
||||
if(data.fromObject !is null) {
|
||||
auto@ source = findResource(data.fromObject, data.resourceId);
|
||||
if(source !is null) {
|
||||
breakImport(source);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@data.fromObject = null;
|
||||
data.resourceId = -1;
|
||||
data.beingMet = false;
|
||||
data.idleSince = gameTime;
|
||||
|
||||
active.remove(data);
|
||||
requested.insertAt(0, data);
|
||||
}
|
||||
|
||||
void breakImport(ExportData@ data) {
|
||||
if(data.request !is null) {
|
||||
if(data.request.obj !is data.obj)
|
||||
data.obj.exportResource(data.resourceId, null);
|
||||
|
||||
data.request.beingMet = false;
|
||||
@data.request.fromObject = null;
|
||||
data.request.resourceId = -1;
|
||||
data.request.idleSince = gameTime;
|
||||
|
||||
active.remove(data.request);
|
||||
requested.insertAt(0, data.request);
|
||||
|
||||
@data.request = null;
|
||||
}
|
||||
|
||||
used.remove(data);
|
||||
available.insertLast(data);
|
||||
}
|
||||
|
||||
void cancelRequest(ImportData@ data) {
|
||||
if(data.beingMet) {
|
||||
breakImport(data);
|
||||
active.remove(data);
|
||||
}
|
||||
else {
|
||||
requested.remove(data);
|
||||
}
|
||||
}
|
||||
|
||||
void removeResource(ExportData@ data) {
|
||||
if(data.request !is null) {
|
||||
breakImport(data);
|
||||
used.remove(data);
|
||||
@data.obj = null;
|
||||
}
|
||||
else {
|
||||
available.remove(data);
|
||||
@data.obj = null;
|
||||
}
|
||||
}
|
||||
|
||||
ImportData@ claimImport(ImportData@ data) {
|
||||
data.beingMet = true;
|
||||
requested.remove(data);
|
||||
active.insertLast(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
void relinquishImport(ImportData@ data) {
|
||||
data.beingMet = false;
|
||||
active.remove(data);
|
||||
requested.insertLast(data);
|
||||
}
|
||||
|
||||
void organizeImports(Object& obj, int targetLevel, ImportData@ before = null) {
|
||||
//Organize any imports for this object so it tries to get to a particular target level
|
||||
if(log)
|
||||
ai.print("Organizing imports for level", obj, targetLevel);
|
||||
|
||||
//Get the requirement list
|
||||
const PlanetLevel@ lvl = getPlanetLevel(obj, targetLevel);
|
||||
if(lvl is null) {
|
||||
ai.print("Error: could not find planet level", obj, targetLevel);
|
||||
return; //Welp, can't do nothing here
|
||||
}
|
||||
|
||||
//Collect all the requests this planet currently has outstanding
|
||||
array<ImportData@> activeRequests;
|
||||
for(uint i = 0, cnt = requested.length; i < cnt; ++i) {
|
||||
auto@ req = requested[i];
|
||||
if(req.obj !is obj)
|
||||
continue;
|
||||
if(!req.forLevel)
|
||||
continue;
|
||||
|
||||
activeRequests.insertLast(req);
|
||||
}
|
||||
for(uint i = 0, cnt = active.length; i < cnt; ++i) {
|
||||
auto@ req = active[i];
|
||||
if(req.obj !is obj)
|
||||
continue;
|
||||
if(!req.forLevel)
|
||||
continue;
|
||||
|
||||
activeRequests.insertLast(req);
|
||||
}
|
||||
|
||||
//TODO: This needs to be able to deal with dummy resources
|
||||
|
||||
//Match import requests with level requirements
|
||||
array<ResourceSpec@> addSpecs;
|
||||
const ResourceRequirements@ reqs = lvl.reqs;
|
||||
|
||||
for(uint i = 0, cnt = reqs.reqs.length; i < cnt; ++i) {
|
||||
auto@ need = reqs.reqs[i];
|
||||
for(uint n = 0; n < need.amount; ++n)
|
||||
addSpecs.insertLast(implementSpec(need));
|
||||
}
|
||||
|
||||
if(race !is null)
|
||||
race.levelRequirements(obj, targetLevel, addSpecs);
|
||||
|
||||
for(uint i = 0, cnt = addSpecs.length; i < cnt; ++i) {
|
||||
auto@ spec = addSpecs[i];
|
||||
|
||||
bool foundMatch = false;
|
||||
for(uint j = 0, jcnt = activeRequests.length; j < jcnt; ++j) {
|
||||
if(activeRequests[j].spec == spec) {
|
||||
foundMatch = true;
|
||||
activeRequests.removeAt(j);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(foundMatch) {
|
||||
addSpecs.removeAt(i);
|
||||
--i; --cnt;
|
||||
}
|
||||
}
|
||||
|
||||
//Cancel any import requests that we don't need anymore
|
||||
for(uint i = 0, cnt = activeRequests.length; i < cnt; ++i)
|
||||
cancelRequest(activeRequests[i]);
|
||||
|
||||
//Insert any imports above any imports of the planet we're exporting to
|
||||
int place = -1;
|
||||
if(before !is null) {
|
||||
for(uint i = 0, cnt = requested.length; i < cnt; ++i) {
|
||||
if(requested[i] is before) {
|
||||
place = int(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Insert everything we need to add
|
||||
addSpecs.sortDesc();
|
||||
for(uint i = 0, cnt = addSpecs.length; i < cnt; ++i) {
|
||||
ImportData@ req = requestResource(obj, addSpecs[i], forLevel=true, activate=false);
|
||||
if(place == -1) {
|
||||
requested.insertLast(req);
|
||||
}
|
||||
else {
|
||||
requested.insertAt(place, req);
|
||||
place += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void killImportsTo(Object& obj) {
|
||||
for(uint i = 0, cnt = requested.length; i < cnt; ++i) {
|
||||
if(requested[i].obj is obj) {
|
||||
cancelRequest(requested[i]);
|
||||
--i; --cnt;
|
||||
}
|
||||
}
|
||||
for(uint i = 0, cnt = active.length; i < cnt; ++i) {
|
||||
if(active[i].obj is obj) {
|
||||
cancelRequest(active[i]);
|
||||
--i; --cnt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void killResourcesFrom(Object& obj) {
|
||||
for(uint i = 0, cnt = available.length; i < cnt; ++i) {
|
||||
if(available[i].obj is obj) {
|
||||
removeResource(available[i]);
|
||||
--i; --cnt;
|
||||
}
|
||||
}
|
||||
for(uint i = 0, cnt = used.length; i < cnt; ++i) {
|
||||
if(used[i].obj is obj) {
|
||||
removeResource(used[i]);
|
||||
--i; --cnt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImportData@ getImport(const string& fromName, uint index = 0) {
|
||||
for(uint i = 0, cnt = requested.length; i < cnt; ++i) {
|
||||
if(requested[i].obj.name.equals_nocase(fromName)) {
|
||||
if(index == 0)
|
||||
return requested[i];
|
||||
else
|
||||
index -= 1;
|
||||
}
|
||||
}
|
||||
for(uint i = 0, cnt = active.length; i < cnt; ++i) {
|
||||
if(active[i].obj.name.equals_nocase(fromName)) {
|
||||
if(index == 0)
|
||||
return active[i];
|
||||
else
|
||||
index -= 1;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
ExportData@ getExport(const string& fromName, uint index = 0) {
|
||||
for(uint i = 0, cnt = available.length; i < cnt; ++i) {
|
||||
if(available[i].obj.name.equals_nocase(fromName)) {
|
||||
if(index == 0)
|
||||
return available[i];
|
||||
else
|
||||
index -= 1;
|
||||
}
|
||||
}
|
||||
for(uint i = 0, cnt = used.length; i < cnt; ++i) {
|
||||
if(used[i].obj.name.equals_nocase(fromName)) {
|
||||
if(index == 0)
|
||||
return used[i];
|
||||
else
|
||||
index -= 1;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void getImportsOf(array<ImportData@>& output, uint resType, Planet@ toPlanet = null) {
|
||||
for(uint i = 0, cnt = active.length; i < cnt; ++i) {
|
||||
auto@ req = active[i];
|
||||
if(req.spec.type != RST_Specific)
|
||||
continue;
|
||||
if(req.spec.resource.id != resType)
|
||||
continue;
|
||||
if(toPlanet !is null && req.obj !is toPlanet)
|
||||
continue;
|
||||
output.insertLast(req);
|
||||
}
|
||||
for(uint i = 0, cnt = requested.length; i < cnt; ++i) {
|
||||
auto@ req = requested[i];
|
||||
if(req.spec.type != RST_Specific)
|
||||
continue;
|
||||
if(req.spec.resource.id != resType)
|
||||
continue;
|
||||
if(toPlanet !is null && req.obj !is toPlanet)
|
||||
continue;
|
||||
output.insertLast(req);
|
||||
}
|
||||
}
|
||||
|
||||
void dumpRequests(Object@ forObject = null) {
|
||||
for(uint i = 0, cnt = requested.length; i < cnt; ++i) {
|
||||
if(forObject !is null && requested[i].obj !is forObject)
|
||||
continue;
|
||||
print(requested[i].obj.name+" requests "+requested[i].spec.dump());
|
||||
}
|
||||
if(forObject !is null) {
|
||||
for(uint i = 0, cnt = used.length; i < cnt; ++i) {
|
||||
if(used[i].request is null || used[i].request.obj !is forObject)
|
||||
continue;
|
||||
print(used[i].request.obj.name+" is getting "+used[i].request.spec.dump()+" from "+used[i].obj.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
AIComponent@ createResources() {
|
||||
return Resources();
|
||||
}
|
||||
Reference in New Issue
Block a user