From 12317c4c36c8b2c04f083cc52ae377b876716b59 Mon Sep 17 00:00:00 2001 From: rt Date: Wed, 20 Feb 2019 22:34:43 +0100 Subject: [PATCH] reduce ExplGenHandler string wrangling --- rts/Lua/LuaSyncedCtrl.cpp | 14 +--- rts/Lua/LuaSyncedRead.cpp | 4 +- .../Env/Particles/ProjectileDrawer.cpp | 8 +- rts/Rendering/UnitDrawer.cpp | 9 +-- .../Projectiles/ExpGenSpawnableMemberInfo.h | 2 +- rts/Sim/Projectiles/ExplosionGenerator.cpp | 80 ++++++++++--------- rts/Sim/Projectiles/ExplosionGenerator.h | 20 ++--- rts/Sim/Units/Scripts/LuaUnitScript.cpp | 8 +- rts/Sim/Units/UnitDef.cpp | 20 +++-- rts/Sim/Units/UnitDef.h | 6 +- 10 files changed, 82 insertions(+), 89 deletions(-) diff --git a/rts/Lua/LuaSyncedCtrl.cpp b/rts/Lua/LuaSyncedCtrl.cpp index 556dcb557ed..7de4b9cf0e5 100644 --- a/rts/Lua/LuaSyncedCtrl.cpp +++ b/rts/Lua/LuaSyncedCtrl.cpp @@ -3406,7 +3406,7 @@ int LuaSyncedCtrl::SetProjectileCEG(lua_State* L) unsigned int cegID = CExplosionGeneratorHandler::EXPGEN_ID_INVALID; if (lua_isstring(L, 2)) { - cegID = explGenHandler.LoadGeneratorID(std::string(CEG_PREFIX_STRING) + lua_tostring(L, 2)); + cegID = explGenHandler.LoadCustomGeneratorID(lua_tostring(L, 2)); } else { cegID = luaL_checknumber(L, 2); } @@ -4517,15 +4517,9 @@ int LuaSyncedCtrl::SpawnCEG(lua_State* L) const float damage = luaL_optfloat(L, 9, 0.0f); const float dmgMod = luaL_optfloat(L, 10, 1.0f); - unsigned int cegID = CExplosionGeneratorHandler::EXPGEN_ID_INVALID; - - if (lua_isstring(L, 1)) { - // args from Lua are assumed not to include the prefix - // (Spawn*C*EG implies only custom generators can fire) - cegID = explGenHandler.LoadGeneratorID(std::string(CEG_PREFIX_STRING) + lua_tostring(L, 1)); - } else { - cegID = luaL_checknumber(L, 1); - } + // args from Lua are assumed not to include the prefix + // (Spawn*C*EG implies only custom generators can fire) + const unsigned int cegID = lua_isstring(L, 1)? explGenHandler.LoadCustomGeneratorID(lua_tostring(L, 1)): luaL_checkint(L, 1); lua_pushboolean(L, explGenHandler.GenExplosion(cegID, pos, dir, damage, radius, dmgMod, nullptr, nullptr)); lua_pushnumber(L, cegID); diff --git a/rts/Lua/LuaSyncedRead.cpp b/rts/Lua/LuaSyncedRead.cpp index 650c240c8a1..bbfc3a5cebc 100644 --- a/rts/Lua/LuaSyncedRead.cpp +++ b/rts/Lua/LuaSyncedRead.cpp @@ -3976,9 +3976,7 @@ int LuaSyncedRead::GetUnitDefDimensions(lua_State* L) int LuaSyncedRead::GetCEGID(lua_State* L) { - const unsigned int cegID = explGenHandler.LoadGeneratorID(std::string(CEG_PREFIX_STRING) + lua_tostring(L, 1)); - - lua_pushnumber(L, cegID); + lua_pushnumber(L, explGenHandler.LoadCustomGeneratorID(lua_tostring(L, 1))); return 1; } diff --git a/rts/Rendering/Env/Particles/ProjectileDrawer.cpp b/rts/Rendering/Env/Particles/ProjectileDrawer.cpp index eb407815df7..0fc750e23e1 100644 --- a/rts/Rendering/Env/Particles/ProjectileDrawer.cpp +++ b/rts/Rendering/Env/Particles/ProjectileDrawer.cpp @@ -409,15 +409,15 @@ void CProjectileDrawer::LoadWeaponTextures() { if (!wd.visuals.texNames[2].empty()) { wd.visuals.texture3 = &textureAtlas->GetTexture(wd.visuals.texNames[2]); } if (!wd.visuals.texNames[3].empty()) { wd.visuals.texture4 = &textureAtlas->GetTexture(wd.visuals.texNames[3]); } - // these can only be custom EG's so prefix is not required game-side + // trails can only be custom EG's, prefix is not required game-side if (!wd.visuals.ptrailExpGenTag.empty()) - wd.ptrailExplosionGeneratorID = explGenHandler.LoadGeneratorID(CEG_PREFIX_STRING + wd.visuals.ptrailExpGenTag); + wd.ptrailExplosionGeneratorID = explGenHandler.LoadCustomGeneratorID(wd.visuals.ptrailExpGenTag.c_str()); if (!wd.visuals.impactExpGenTag.empty()) - wd.impactExplosionGeneratorID = explGenHandler.LoadGeneratorID(wd.visuals.impactExpGenTag); + wd.impactExplosionGeneratorID = explGenHandler.LoadGeneratorID(wd.visuals.impactExpGenTag.c_str()); if (!wd.visuals.bounceExpGenTag.empty()) - wd.bounceExplosionGeneratorID = explGenHandler.LoadGeneratorID(wd.visuals.bounceExpGenTag); + wd.bounceExplosionGeneratorID = explGenHandler.LoadGeneratorID(wd.visuals.bounceExpGenTag.c_str()); } } diff --git a/rts/Rendering/UnitDrawer.cpp b/rts/Rendering/UnitDrawer.cpp index e4abfc36a02..7daf5b8f43f 100644 --- a/rts/Rendering/UnitDrawer.cpp +++ b/rts/Rendering/UnitDrawer.cpp @@ -72,15 +72,14 @@ static FixedDynMemPool*addExplGenID)(explGenHandler.LoadGeneratorID(explGenPrefix + explGenTag)); + (ud->*addExplGenID)(explGenHandler.LoadGeneratorID(explGenTag, explGenPrefix)); } }; diff --git a/rts/Sim/Projectiles/ExpGenSpawnableMemberInfo.h b/rts/Sim/Projectiles/ExpGenSpawnableMemberInfo.h index 22781e650f6..5ca8881a93f 100644 --- a/rts/Sim/Projectiles/ExpGenSpawnableMemberInfo.h +++ b/rts/Sim/Projectiles/ExpGenSpawnableMemberInfo.h @@ -64,7 +64,7 @@ struct SExpGenSpawnableMemberInfo #define CHECK_MEMBER_INFO_PTR(t, member, callback) \ static_assert(std::is_same::value, "Member and callback type mismatch"); \ - SET_MEMBER_INFO(memberInfo, MEMBER_HASH(member), offsetof_expgen(t, member), sizeof_expgen(t, member), 1, SExpGenSpawnableMemberInfo::TYPE_PTR, [](const std::string& s) { return (void *) callback(s); } ); + SET_MEMBER_INFO(memberInfo, MEMBER_HASH(member), offsetof_expgen(t, member), sizeof_expgen(t, member), 1, SExpGenSpawnableMemberInfo::TYPE_PTR, [](const std::string& s) { return (void *) callback(s.c_str()); } ); #define CHECK_MEMBER_INFO_BOOL(type, member) CHECK_MEMBER_INFO_INT(type, member) #define CHECK_MEMBER_INFO_SCOLOR(type, member) CHECK_MEMBER_INFO_INT(type, member.i) diff --git a/rts/Sim/Projectiles/ExplosionGenerator.cpp b/rts/Sim/Projectiles/ExplosionGenerator.cpp index 3930c42261b..8b41bfbed02 100644 --- a/rts/Sim/Projectiles/ExplosionGenerator.cpp +++ b/rts/Sim/Projectiles/ExplosionGenerator.cpp @@ -37,6 +37,7 @@ #include "System/Exceptions.h" #include "System/myMath.h" #include "System/SafeUtil.h" +#include "System/StringHash.h" CR_BIND_INTERFACE(IExplosionGenerator) @@ -86,6 +87,8 @@ static uint8_t exploParserMem[sizeof(LuaParser)]; static uint8_t aliasParserMem[sizeof(LuaParser)]; static uint8_t explTblRootMem[sizeof(LuaTable )]; +static constexpr size_t CEG_PREFIX_STRLEN = strlen(CEG_PREFIX_STRING); + CExplosionGeneratorHandler explGenHandler; @@ -222,8 +225,8 @@ void CExplosionGeneratorHandler::Kill() explosionGenerators.clear(); - expGenTagIdentMap.clear(); // never iterated - expGenIdentTagMap.clear(); // never iterated + expGenHashIdentMap.clear(); // never iterated + expGenIdentNameMap.clear(); // never iterated } void CExplosionGeneratorHandler::ParseExplosionTables() @@ -267,9 +270,9 @@ void CExplosionGeneratorHandler::ReloadGenerators(const std::string& tag) { // but the Lua subtables that define each CEG are // only indexed by tag postfix if (!tag.empty()) { - const auto it = expGenTagIdentMap.find(tag); + const auto it = expGenHashIdentMap.find(hashString(tag.c_str())); - if (it == expGenTagIdentMap.end()) { + if (it == expGenHashIdentMap.end()) { LOG_L(L_WARNING, "[%s] no CEG named \"%s\" (forgot the \"%s\" prefix?)", __func__, tag.c_str(), CEG_PREFIX_STRING); return; } @@ -277,7 +280,7 @@ void CExplosionGeneratorHandler::ReloadGenerators(const std::string& tag) { assert(explosionGenerators[it->second]->GetGeneratorID() == it->second); LOG(preFmt, __func__, it->second, tag.c_str()); - if (!explosionGenerators[it->second]->Reload(this, tag.substr(7))) + if (!explosionGenerators[it->second]->Reload(this, tag.c_str() + CEG_PREFIX_STRLEN)) LOG_L(L_WARNING, pstFmt, __func__, it->second, tag.c_str()); return; @@ -287,24 +290,24 @@ void CExplosionGeneratorHandler::ReloadGenerators(const std::string& tag) { IExplosionGenerator* eg = explosionGenerators[n]; // standard EG's (empty postfix) do not need to be reloaded - if (expGenIdentTagMap.find(n) == expGenIdentTagMap.end()) + if (expGenIdentNameMap.find(n) == expGenIdentNameMap.end()) continue; assert(eg->GetGeneratorID() == n); - LOG(preFmt, __func__, n, expGenIdentTagMap[n].c_str()); + LOG(preFmt, __func__, n, expGenIdentNameMap[n].data()); - if (eg->Reload(this, expGenIdentTagMap[n].substr(7))) + if (eg->Reload(this, expGenIdentNameMap[n].data() + CEG_PREFIX_STRLEN)) continue; - LOG_L(L_WARNING, pstFmt, __func__, n, expGenIdentTagMap[n].c_str()); + LOG_L(L_WARNING, pstFmt, __func__, n, expGenIdentNameMap[n]); } } -unsigned int CExplosionGeneratorHandler::LoadGeneratorID(const std::string& tag) +unsigned int CExplosionGeneratorHandler::LoadGeneratorID(const char* tag, const char* pre) { - IExplosionGenerator* eg = LoadGenerator(tag); + IExplosionGenerator* eg = LoadGenerator(tag, pre); if (eg == nullptr) return EXPGEN_ID_INVALID; @@ -317,32 +320,32 @@ unsigned int CExplosionGeneratorHandler::LoadGeneratorID(const std::string& tag) // can be called recursively for custom instances (LoadGenerator -> // Load -> ParseExplosionCode -> LoadGenerator -> ...), generators // must NOT be overwritten -IExplosionGenerator* CExplosionGeneratorHandler::LoadGenerator(const string& tag) +IExplosionGenerator* CExplosionGeneratorHandler::LoadGenerator(const char* tag, const char* pre) { - const auto it = expGenTagIdentMap.find(tag); + decltype(expGenIdentNameMap)::mapped_type key = {0}; + + char* ptr = key.data(); + char* sep = nullptr; + + ptr += snprintf(ptr, sizeof(key) - (ptr - key.data()), "%s", pre); + ptr += snprintf(ptr, sizeof(key) - (ptr - key.data()), "%s", tag); - if (it != expGenTagIdentMap.end()) - return explosionGenerators[it->second]; + const auto hash = hashString(key.data()); + const auto iter = expGenHashIdentMap.find(hash); + + if (iter != expGenHashIdentMap.end()) + return explosionGenerators[iter->second]; // tag is either "CStdExplosionGenerator" (or some sub-string, eg. // "std") which maps to CStdExplosionGenerator or "custom:postfix" // which maps to CCustomExplosionGenerator, all others cause NULL // to be returned - string prefix; - string postfix; - - const string::size_type seppos = tag.find(':'); - - IExplosionGenerator* explGen; + IExplosionGenerator* explGen = nullptr; - if (seppos != string::npos) { + if ((sep = strstr(key.data(), ":")) != nullptr) { // grab the "custom" prefix (the only supported value) - prefix = tag.substr(0, seppos); - postfix = tag.substr(seppos + 1); - assert((prefix + ":") == CEG_PREFIX_STRING); explGen = egMemPool.alloc(); } else { - prefix = tag; explGen = egMemPool.alloc(); } @@ -354,13 +357,13 @@ IExplosionGenerator* CExplosionGeneratorHandler::LoadGenerator(const string& tag // save generator so ID is valid *before* possible recursion explosionGenerators.push_back(explGen); - if (!postfix.empty()) { + if (sep != nullptr) { // standard EG's have no postfix (nor always a prefix) // custom EG's always have CEG_PREFIX_STRING in front - expGenTagIdentMap[tag] = explGen->GetGeneratorID(); - expGenIdentTagMap[explGen->GetGeneratorID()] = tag; + expGenHashIdentMap.insert(hash, explGen->GetGeneratorID()); + expGenIdentNameMap.insert(explGen->GetGeneratorID(), key); - explGen->Load(this, postfix); + explGen->Load(this, sep + 1); } return explGen; @@ -830,8 +833,7 @@ void CCustomExplosionGenerator::ParseExplosionCode( else if (c == 'q') { opcode = OP_POWBUFF; useInt = true; } else if (isdigit(c) || c == '.' || c == '-') { opcode = OP_ADD; p--; } else { - const char* fmt = "[CCEG::ParseExplosionCode] unknown op-code \"%c\" in \"%s\" at index %d"; - LOG_L(L_WARNING, fmt, c, script.c_str(), p); + LOG_L(L_WARNING, "[CCEG::%s] unknown op-code \"%c\" in \"%s\" at index %d", __func__, c, script.c_str(), p); continue; } @@ -869,14 +871,14 @@ void CCustomExplosionGenerator::ParseExplosionCode( -bool CCustomExplosionGenerator::Load(CExplosionGeneratorHandler* handler, const string& tag) +bool CCustomExplosionGenerator::Load(CExplosionGeneratorHandler* handler, const char* tag) { const LuaTable* root = handler->GetExplosionTableRoot(); const LuaTable& expTable = (root != nullptr)? root->SubTable(tag): LuaTable(); if (!expTable.IsValid()) { // not a fatal error: any calls to Explosion will just return early - LOG_L(L_WARNING, "[CCEG::%s] table for CEG \"%s\" invalid (parse errors?)", __func__, tag.c_str()); + LOG_L(L_WARNING, "[CCEG::%s] table for CEG \"%s\" invalid (parse errors?)", __func__, tag); return false; } @@ -889,7 +891,7 @@ bool CCustomExplosionGenerator::Load(CExplosionGeneratorHandler* handler, const for (unsigned int n = 0; n < spawns.size(); n++) { ProjectileSpawnInfo psi; - const string& spawnName = spawns[n]; + const std::string& spawnName = spawns[n]; const LuaTable& spawnTable = expTable.SubTable(spawnName); // NOTE: @@ -903,14 +905,14 @@ bool CCustomExplosionGenerator::Load(CExplosionGeneratorHandler* handler, const const string& className = handler->GetProjectileClasses().ResolveAlias(spawnTable.GetString("class", spawnName)); if ((psi.spawnableID = CExpGenSpawnable::GetSpawnableID(className)) == -1u) { - LOG_L(L_WARNING, "[CCEG::%s] %s: Unknown class \"%s\"", __func__, tag.c_str(), className.c_str()); + LOG_L(L_WARNING, "[CCEG::%s] %s: unknown class \"%s\"", __func__, tag, className.c_str()); continue; } psi.flags = GetFlagsFromTable(spawnTable); psi.count = std::max(0, spawnTable.GetInt("count", 1)); - string code; + std::string code; spring::unordered_map props; spawnTable.SubTable("properties").GetMap(props); @@ -921,7 +923,7 @@ bool CCustomExplosionGenerator::Load(CExplosionGeneratorHandler* handler, const if (CExpGenSpawnable::GetSpawnableMemberInfo(className, memberInfo)) { ParseExplosionCode(&psi, propIt.second, memberInfo, code); } else { - LOG_L(L_WARNING, "[CCEG::%s] %s: Unknown tag %s::%s", __func__, tag.c_str(), className.c_str(), propIt.first.c_str()); + LOG_L(L_WARNING, "[CCEG::%s] %s: unknown tag %s::%s", __func__, tag, className.c_str(), propIt.first.c_str()); } } @@ -950,7 +952,7 @@ bool CCustomExplosionGenerator::Load(CExplosionGeneratorHandler* handler, const return true; } -bool CCustomExplosionGenerator::Reload(CExplosionGeneratorHandler* handler, const std::string& tag) { +bool CCustomExplosionGenerator::Reload(CExplosionGeneratorHandler* handler, const char* tag) { const ExpGenParams oldParams = expGenParams; if (!Load(handler, tag)) { diff --git a/rts/Sim/Projectiles/ExplosionGenerator.h b/rts/Sim/Projectiles/ExplosionGenerator.h index 1a97c3d2e99..a8cb19e40fd 100644 --- a/rts/Sim/Projectiles/ExplosionGenerator.h +++ b/rts/Sim/Projectiles/ExplosionGenerator.h @@ -50,8 +50,10 @@ class CExplosionGeneratorHandler void ParseExplosionTables(); void ReloadGenerators(const std::string&); - unsigned int LoadGeneratorID(const std::string& tag); - IExplosionGenerator* LoadGenerator(const std::string& tag); + unsigned int LoadCustomGeneratorID(const char* tag) { return (LoadGeneratorID(tag, CEG_PREFIX_STRING)); } + unsigned int LoadGeneratorID(const char* tag, const char* pre = ""); + + IExplosionGenerator* LoadGenerator(const char* tag, const char* pre = ""); IExplosionGenerator* GetGenerator(unsigned int expGenID); bool GenExplosion( @@ -77,8 +79,8 @@ class CExplosionGeneratorHandler std::vector explosionGenerators; - spring::unordered_map expGenTagIdentMap; - spring::unordered_map expGenIdentTagMap; + spring::unordered_map expGenHashIdentMap; // hash->id + spring::unordered_map> expGenIdentNameMap; // id->name }; @@ -92,8 +94,8 @@ class IExplosionGenerator IExplosionGenerator(): generatorID(CExplosionGeneratorHandler::EXPGEN_ID_INVALID) {} virtual ~IExplosionGenerator() {} - virtual bool Load(CExplosionGeneratorHandler* handler, const std::string& tag) = 0; - virtual bool Reload(CExplosionGeneratorHandler* handler, const std::string& tag) { return true; } + virtual bool Load(CExplosionGeneratorHandler* handler, const char* tag) = 0; + virtual bool Reload(CExplosionGeneratorHandler* handler, const char* tag) { return true; } virtual bool Explosion( const float3& pos, const float3& dir, @@ -121,7 +123,7 @@ class CStdExplosionGenerator: public IExplosionGenerator public: CStdExplosionGenerator(): IExplosionGenerator() {} - bool Load(CExplosionGeneratorHandler* handler, const std::string& tag) override { return false; } + bool Load(CExplosionGeneratorHandler* handler, const char* tag) override { return false; } bool Explosion( const float3& pos, const float3& dir, @@ -186,8 +188,8 @@ class CCustomExplosionGenerator: public IExplosionGenerator static unsigned int GetFlagsFromHeight(float height, float groundHeight); /// @throws content_error/runtime_error on errors - bool Load(CExplosionGeneratorHandler* handler, const std::string& tag) override; - bool Reload(CExplosionGeneratorHandler* handler, const std::string& tag) override; + bool Load(CExplosionGeneratorHandler* handler, const char* tag) override; + bool Reload(CExplosionGeneratorHandler* handler, const char* tag) override; bool Explosion(const float3& pos, const float3& dir, float damage, float radius, float gfxMod, CUnit* owner, CUnit* hit) override; // spawn-flags diff --git a/rts/Sim/Units/Scripts/LuaUnitScript.cpp b/rts/Sim/Units/Scripts/LuaUnitScript.cpp index 5530874a8a0..e6b9dfe2c1f 100644 --- a/rts/Sim/Units/Scripts/LuaUnitScript.cpp +++ b/rts/Sim/Units/Scripts/LuaUnitScript.cpp @@ -1197,13 +1197,7 @@ int CLuaUnitScript::EmitSfx(lua_State* L) // note: the arguments are reversed compared to the C++ (and COB?) function const int piece = luaL_checkint(L, 1) - 1; - int type = CExplosionGeneratorHandler::EXPGEN_ID_INVALID; - - if (lua_isstring(L, 2)) { - type = explGenHandler.LoadGeneratorID(std::string(CEG_PREFIX_STRING) + lua_tostring(L, 2)) & SFX_GLOBAL; - } else { - type = luaL_checkint(L, 2); - } + const int type = lua_isnumber(L, 2)? luaL_checkint(L, 2): (explGenHandler.LoadCustomGeneratorID(lua_tostring(L, 2)) & SFX_GLOBAL); activeScript->EmitSfx(type, piece); return 0; diff --git a/rts/Sim/Units/UnitDef.cpp b/rts/Sim/Units/UnitDef.cpp index 4c1abe0d028..06427fee3e7 100644 --- a/rts/Sim/Units/UnitDef.cpp +++ b/rts/Sim/Units/UnitDef.cpp @@ -611,28 +611,32 @@ UnitDef::UnitDef(const LuaTable& udTable, const std::string& unitName, int id) paramsTable.GetMap(customParams); } { - const LuaTable& sfxTable = udTable.SubTable("SFXTypes"); + const LuaTable& sfxTable = udTable.SubTable("SFXTypes"); const LuaTable& modelCEGTable = sfxTable.SubTable( "explosionGenerators"); const LuaTable& pieceCEGTable = sfxTable.SubTable("pieceExplosionGenerators"); const LuaTable& crashCEGTable = sfxTable.SubTable("crashExplosionGenerators"); std::vector cegKeys; std::array cegTbls = {&modelCEGTable, &pieceCEGTable, &crashCEGTable}; - std::array* cegTags[3] = {&modelCEGTags, &pieceCEGTags, &crashCEGTags}; + std::array* cegTags[3] = {&modelCEGTags, &pieceCEGTags, &crashCEGTags}; for (int i = 0; i < 3; i++) { + auto& tagStrs = *cegTags[i]; + cegKeys.clear(); - cegKeys.reserve(cegTags[i]->size()); + cegKeys.reserve(tagStrs.size()); cegTbls[i]->GetKeys(cegKeys); // get at most N tags, discard the rest - for (unsigned int j = 0, n = std::min(cegTags[i]->size(), cegKeys.size()); j < n; j++) { - (*cegTags[i])[j] = cegTbls[i]->GetString(cegKeys[j], ""); - } + for (unsigned int j = 0, k = 0; j < cegKeys.size() && k < tagStrs.size(); j++) { + const std::string& tag = cegTbls[i]->GetString(cegKeys[j], ""); - // move empty tags to the back - std::remove_if(cegTags[i]->begin(), cegTags[i]->end(), [](const std::string& tag) { return (tag.empty()); }); + if (tag.empty()) + continue; + + strncpy(tagStrs[k++], tag.c_str(), sizeof(tagStrs[0])); + } } // filled in later by UnitDrawer diff --git a/rts/Sim/Units/UnitDef.h b/rts/Sim/Units/UnitDef.h index 181d7d3c0b1..50af7a8859b 100644 --- a/rts/Sim/Units/UnitDef.h +++ b/rts/Sim/Units/UnitDef.h @@ -218,9 +218,9 @@ struct UnitDef: public SolidObjectDef ///< buildingMask used to disallow construction on certain map squares std::uint16_t buildingMask; - std::array modelCEGTags; - std::array pieceCEGTags; - std::array crashCEGTags; + std::array modelCEGTags = {0}; + std::array pieceCEGTags = {0}; + std::array crashCEGTags = {0}; // *ExplGenIDs[0] stores the number of valid CEG's (TODO: privatize) // valid CEG id's are all in front s.t. they can be randomly sampled