2
0
mirror of https://github.com/Laupetin/OpenAssetTools.git synced 2026-06-06 16:52:35 +00:00

Refactor to improve C++ and safe code use

This commit is contained in:
LJW-Dev
2025-10-26 18:20:04 +08:00
committed by Jan Laupetin
parent c839a220b2
commit 014fe103ac
10 changed files with 285 additions and 261 deletions
@@ -27,7 +27,6 @@ namespace BSP
clipMap->dynEntClientList[0] = m_memory.Alloc<DynEntityClient>(clipMap->dynEntCount[0]);
clipMap->dynEntClientList[1] = nullptr;
memset(clipMap->dynEntClientList[0], 0, sizeof(DynEntityClient) * clipMap->dynEntCount[0]);
clipMap->dynEntServerList[0] = nullptr;
clipMap->dynEntServerList[1] = nullptr;
@@ -36,15 +35,12 @@ namespace BSP
clipMap->dynEntCollList[1] = nullptr;
clipMap->dynEntCollList[2] = nullptr;
clipMap->dynEntCollList[3] = nullptr;
memset(clipMap->dynEntCollList[0], 0, sizeof(DynEntityColl) * clipMap->dynEntCount[0]);
clipMap->dynEntPoseList[0] = m_memory.Alloc<DynEntityPose>(clipMap->dynEntCount[0]);
clipMap->dynEntPoseList[1] = nullptr;
memset(clipMap->dynEntPoseList[0], 0, sizeof(DynEntityPose) * clipMap->dynEntCount[0]);
clipMap->dynEntDefList[0] = m_memory.Alloc<DynEntityDef>(clipMap->dynEntCount[0]);
clipMap->dynEntDefList[1] = nullptr;
memset(clipMap->dynEntDefList[0], 0, sizeof(DynEntityDef) * clipMap->dynEntCount[0]);
}
void ClipMapLinker::loadVisibility(clipMap_t* clipMap)
@@ -122,19 +118,18 @@ namespace BSP
void ClipMapLinker::loadRopesAndConstraints(clipMap_t* clipMap)
{
clipMap->num_constraints = 0; // max 511
clipMap->constraints = NULL;
clipMap->constraints = nullptr;
// The game allocates 32 empty ropes
clipMap->max_ropes = 32; // max 300
clipMap->ropes = m_memory.Alloc <rope_t> (clipMap->max_ropes);
memset(clipMap->ropes, 0, sizeof(rope_t) * clipMap->max_ropes);
}
void ClipMapLinker::loadSubModelCollision(clipMap_t* clipMap, BSPData* bsp)
{
// Submodels are used for the world and map ent collision (triggers, bomb zones, etc)
auto gfxWorldAsset = m_context.LoadDependency<AssetGfxWorld>(bsp->bspName);
assert(gfxWorldAsset != NULL);
assert(gfxWorldAsset != nullptr);
GfxWorld* gfxWorld = gfxWorldAsset->Asset();
// Right now there is only one submodel, the world sub model
@@ -166,7 +161,7 @@ namespace BSP
clipMap->cmodels[0].leaf.leafBrushNode = 0;
clipMap->cmodels[0].leaf.cluster = 0;
clipMap->cmodels[0].info = NULL; // always set to 0
clipMap->cmodels[0].info = nullptr; // always set to 0
}
void ClipMapLinker::loadXModelCollision(clipMap_t* clipMap)
@@ -178,7 +173,7 @@ namespace BSP
// WIP code left in for future support
/*
auto gfxWorldAsset = m_context.LoadDependency<AssetGfxWorld>(bsp->bspName);
assert(gfxWorldAsset != NULL);
assert(gfxWorldAsset != nullptr);
GfxWorld* gfxWorld = gfxWorldAsset->Asset();
clipMap->numStaticModels = gfxWorld->dpvs.smodelCount;
@@ -306,7 +301,7 @@ namespace BSP
{
uint16_t vertIndex = tri[l];
vec3_t vertCoord = clipMap->verts[vertIndex];
BSPUtil::calcNewBoundsWithPoint(&vertCoord, &aabbMins, &aabbMaxs);
BSPUtil::updateAABBWithpoint(&vertCoord, &aabbMins, &aabbMaxs);
}
}
}
@@ -343,7 +338,7 @@ namespace BSP
uint16_t currUind = clipMap->info.uinds[aabbPartition->fuind + i];
vec3_t* currVertex = &clipMap->verts[currUind];
BSPUtil::calcNewBoundsWithPoint(currVertex, &mins, &maxs);
BSPUtil::updateAABBWithpoint(currVertex, &mins, &maxs);
}
aabbCalcOriginAndHalfSize(&mins, &maxs, &currAabbTree->origin, &currAabbTree->halfSize);
@@ -631,17 +626,17 @@ namespace BSP
{
// No support for brushes, only tris right now
clipMap->info.numBrushSides = 0;
clipMap->info.brushsides = NULL;
clipMap->info.brushsides = nullptr;
clipMap->info.leafbrushNodesCount = 0;
clipMap->info.leafbrushNodes = NULL;
clipMap->info.leafbrushNodes = nullptr;
clipMap->info.numLeafBrushes = 0;
clipMap->info.leafbrushes = NULL;
clipMap->info.leafbrushes = nullptr;
clipMap->info.numBrushVerts = 0;
clipMap->info.brushVerts = NULL;
clipMap->info.numBrushes = NULL;
clipMap->info.brushes = NULL;
clipMap->info.brushBounds = NULL;
clipMap->info.brushContents = NULL;
clipMap->info.brushVerts = nullptr;
clipMap->info.numBrushes = 0;
clipMap->info.brushes = nullptr;
clipMap->info.brushBounds = nullptr;
clipMap->info.brushContents = nullptr;
// clipmap BSP creation must go last as it depends on unids, tris and verts already being populated
// HACK:
@@ -667,7 +662,7 @@ namespace BSP
for (unsigned int i = 1; i < clipMap->vertCount; i++)
{
vec3_t vertCoord = BSPUtil::convertFromBO2Coords(clipMap->verts[i]);
BSPUtil::calcNewBoundsWithPoint(&vertCoord, &clipMins, &clipMaxs);
BSPUtil::updateAABBWithpoint(&vertCoord, &clipMins, &clipMaxs);
}
BSPTree* tree = new BSPTree(clipMins.x, clipMins.y, clipMins.z, clipMaxs.x, clipMaxs.y, clipMaxs.z, 0);
@@ -697,7 +692,7 @@ namespace BSP
{
uint16_t vertIndex = tri[l];
vec3_t vertCoord = BSPUtil::convertFromBO2Coords(clipMap->verts[vertIndex]);
BSPUtil::calcNewBoundsWithPoint(&vertCoord, &mins, &maxs);
BSPUtil::updateAABBWithpoint(&vertCoord, &mins, &maxs);
}
}
@@ -15,23 +15,22 @@ namespace BSP
ComWorld* comWorld = m_memory.Alloc<ComWorld>();
comWorld->name = m_memory.Dup(bsp->bspName.c_str());
comWorld->isInUse = 1;
comWorld->primaryLightCount = 2;
comWorld->primaryLightCount = BSPGameConstants::BSP_DEFAULT_LIGHT_COUNT;
comWorld->primaryLights = m_memory.Alloc<ComPrimaryLight>(comWorld->primaryLightCount);
// static light is always empty
ComPrimaryLight* staticLight = &comWorld->primaryLights[0];
memset(staticLight, 0, sizeof(ComPrimaryLight));
// first (static) light is always empty
ComPrimaryLight* sunLight = &comWorld->primaryLights[1];
memset(sunLight, 0, sizeof(ComPrimaryLight));
sunLight->type = 1;
sunLight->diffuseColor.r = 0.75f;
sunLight->diffuseColor.g = 0.75f;
sunLight->diffuseColor.b = 0.75f;
sunLight->diffuseColor.a = 1.0f;
sunLight->dir.x = 0.0f;
sunLight->dir.y = 0.0f;
sunLight->dir.z = 0.0f;
const vec4_t sunLightColor = BSPEditableConstants::SUNLIGHT_COLOR;
const vec3_t sunLightDirection = BSPEditableConstants::SUNLIGHT_DIRECTION;
sunLight->type = GFX_LIGHT_TYPE_DIR;
sunLight->diffuseColor.r = sunLightColor.r;
sunLight->diffuseColor.g = sunLightColor.g;
sunLight->diffuseColor.b = sunLightColor.b;
sunLight->diffuseColor.a = sunLightColor.a;
sunLight->dir.x = sunLightDirection.x;
sunLight->dir.y = sunLightDirection.y;
sunLight->dir.z = sunLightDirection.z;
auto comWorldAsset = m_context.AddAsset<AssetComWorld>(comWorld->name, comWorld);
return AssetCreationResult::Success(comWorldAsset);
@@ -21,12 +21,10 @@ namespace BSP
gameWorldMp->path.smoothBytes = 0;
gameWorldMp->path.nodeTreeCount = 0;
int nodeCount = gameWorldMp->path.nodeCount + 128;
gameWorldMp->path.nodes = m_memory.Alloc<pathnode_t>(nodeCount);
gameWorldMp->path.basenodes = m_memory.Alloc<pathbasenode_t>(nodeCount);
memset(gameWorldMp->path.nodes, 0, nodeCount * sizeof(pathnode_t));
memset(gameWorldMp->path.basenodes, 0, nodeCount * sizeof(pathbasenode_t));
// The game has 128 empty nodes allocated
int extraNodeCount = gameWorldMp->path.nodeCount + 128;
gameWorldMp->path.nodes = m_memory.Alloc<pathnode_t>(extraNodeCount);
gameWorldMp->path.basenodes = m_memory.Alloc<pathbasenode_t>(extraNodeCount);
gameWorldMp->path.pathVis = nullptr;
gameWorldMp->path.smoothCache = nullptr;
gameWorldMp->path.nodeTree = nullptr;
@@ -130,7 +130,7 @@ namespace BSP
for (int k = 0; k < currSurface->tris.triCount * 3; k++)
{
uint16_t vertIndex = gfxWorld->draw.indices[currSurface->tris.baseIndex + k];
BSPUtil::calcNewBoundsWithPoint(&firstVert[vertIndex].xyz, &currSurface->bounds[0], &currSurface->bounds[1]);
BSPUtil::updateAABBWithpoint(&firstVert[vertIndex].xyz, &currSurface->bounds[0], &currSurface->bounds[1]);
}
// unused values
@@ -191,68 +191,69 @@ namespace BSP
/*
Models are unsupported right now
Code is left in in case it is supported later on
unsigned int modelCount = projInfo->modelCount;
gfxWorld->dpvs.smodelCount = modelCount;
gfxWorld->dpvs.smodelInsts = new GfxStaticModelInst[modelCount];
gfxWorld->dpvs.smodelDrawInsts = new GfxStaticModelDrawInst[modelCount];
for (unsigned int i = 0; i < modelCount; i++)
{
auto currModel = &gfxWorld->dpvs.smodelDrawInsts[i];
auto currModelInst = &gfxWorld->dpvs.smodelInsts[i];
customMapModel* inModel = &projInfo->models[i];
auto xModelAsset = m_context.LoadDependency<AssetXModel>(inModel->name);
if (xModelAsset == NULL)
{
printf("XModel %s not found!\n", inModel->name.c_str());
currModel->model = NULL;
}
else
currModel->model = (XModel*)xModelAsset->Asset();
currModel->placement.origin.x = inModel->origin.x;
currModel->placement.origin.y = inModel->origin.y;
currModel->placement.origin.z = inModel->origin.z;
currModel->placement.origin = BSPUtil::convertToBO2Coords(currModel->placement.origin);
currModel->placement.scale = inModel->scale;
BSPUtil::convertAnglesToAxis(&inModel->rotation, currModel->placement.axis);
// mins and maxs are calculated in world space not local space
// TODO: this does not account for model rotation or scale
currModelInst->mins.x = currModel->model->mins.x + currModel->placement.origin.x;
currModelInst->mins.y = currModel->model->mins.y + currModel->placement.origin.y;
currModelInst->mins.z = currModel->model->mins.z + currModel->placement.origin.z;
currModelInst->maxs.x = currModel->model->maxs.x + currModel->placement.origin.x;
currModelInst->maxs.y = currModel->model->maxs.y + currModel->placement.origin.y;
currModelInst->maxs.z = currModel->model->maxs.z + currModel->placement.origin.z;
currModel->cullDist = DEFAULT_SMODEL_CULL_DIST;
currModel->flags = DEFAULT_SMODEL_FLAGS;
currModel->primaryLightIndex = DEFAULT_SMODEL_LIGHT;
currModel->reflectionProbeIndex = DEFAULT_SMODEL_REFLECTION_PROBE;
// unknown use / unused
currModel->smid = i;
memset(&currModel->lightingSH, 0, sizeof(GfxLightingSHQuantized));
currModel->invScaleSq = 0.0f;
currModel->lightingHandle = 0;
currModel->colorsIndex = 0;
currModel->visibility = 0;
// setting these to NULL makes any static/baked lighting go black when not rendered by real-time lighting or in a shadow
// TODO: calculate lighting and store it here
currModel->lmapVertexInfo[0].numLmapVertexColors = 0;
currModel->lmapVertexInfo[0].lmapVertexColors = NULL;
currModel->lmapVertexInfo[1].numLmapVertexColors = 0;
currModel->lmapVertexInfo[1].lmapVertexColors = NULL;
currModel->lmapVertexInfo[2].numLmapVertexColors = 0;
currModel->lmapVertexInfo[2].lmapVertexColors = NULL;
currModel->lmapVertexInfo[3].numLmapVertexColors = 0;
currModel->lmapVertexInfo[3].lmapVertexColors = NULL;
}
*/
//unsigned int modelCount = projInfo->modelCount;
//gfxWorld->dpvs.smodelCount = modelCount;
//gfxWorld->dpvs.smodelInsts = new GfxStaticModelInst[modelCount];
//gfxWorld->dpvs.smodelDrawInsts = new GfxStaticModelDrawInst[modelCount];
//
//for (unsigned int i = 0; i < modelCount; i++)
//{
// auto currModel = &gfxWorld->dpvs.smodelDrawInsts[i];
// auto currModelInst = &gfxWorld->dpvs.smodelInsts[i];
// customMapModel* inModel = &projInfo->models[i];
//
// auto xModelAsset = m_context.LoadDependency<AssetXModel>(inModel->name);
// if (xModelAsset == NULL)
// {
// printf("XModel %s not found!\n", inModel->name.c_str());
// currModel->model = NULL;
// }
// else
// currModel->model = (XModel*)xModelAsset->Asset();
//
// currModel->placement.origin.x = inModel->origin.x;
// currModel->placement.origin.y = inModel->origin.y;
// currModel->placement.origin.z = inModel->origin.z;
// currModel->placement.origin = BSPUtil::convertToBO2Coords(currModel->placement.origin);
// currModel->placement.scale = inModel->scale;
//
// BSPUtil::convertAnglesToAxis(&inModel->rotation, currModel->placement.axis);
//
// // mins and maxs are calculated in world space not local space
// // TODO: this does not account for model rotation or scale
// currModelInst->mins.x = currModel->model->mins.x + currModel->placement.origin.x;
// currModelInst->mins.y = currModel->model->mins.y + currModel->placement.origin.y;
// currModelInst->mins.z = currModel->model->mins.z + currModel->placement.origin.z;
// currModelInst->maxs.x = currModel->model->maxs.x + currModel->placement.origin.x;
// currModelInst->maxs.y = currModel->model->maxs.y + currModel->placement.origin.y;
// currModelInst->maxs.z = currModel->model->maxs.z + currModel->placement.origin.z;
//
// currModel->cullDist = DEFAULT_SMODEL_CULL_DIST;
// currModel->flags = DEFAULT_SMODEL_FLAGS;
// currModel->primaryLightIndex = DEFAULT_SMODEL_LIGHT;
// currModel->reflectionProbeIndex = DEFAULT_SMODEL_REFLECTION_PROBE;
//
// // unknown use / unused
// currModel->smid = i;
// memset(&currModel->lightingSH, 0, sizeof(GfxLightingSHQuantized));
// currModel->invScaleSq = 0.0f;
// currModel->lightingHandle = 0;
// currModel->colorsIndex = 0;
// currModel->visibility = 0;
//
// // setting these to NULL makes any static/baked lighting go black when not rendered by real-time lighting or in a shadow
// // TODO: calculate lighting and store it here
// currModel->lmapVertexInfo[0].numLmapVertexColors = 0;
// currModel->lmapVertexInfo[0].lmapVertexColors = NULL;
// currModel->lmapVertexInfo[1].numLmapVertexColors = 0;
// currModel->lmapVertexInfo[1].lmapVertexColors = NULL;
// currModel->lmapVertexInfo[2].numLmapVertexColors = 0;
// currModel->lmapVertexInfo[2].lmapVertexColors = NULL;
// currModel->lmapVertexInfo[3].numLmapVertexColors = 0;
// currModel->lmapVertexInfo[3].lmapVertexColors = NULL;
//}
unsigned int modelCount = 0;
gfxWorld->dpvs.smodelCount = modelCount;
@@ -546,7 +547,7 @@ namespace BSP
for (int i = 0; i < gfxWorld->surfaceCount; i++)
{
BSPUtil::calcNewBounds(&gfxWorld->dpvs.surfaces[i].bounds[0], &gfxWorld->dpvs.surfaces[i].bounds[1], &gfxWorld->mins, &gfxWorld->maxs);
BSPUtil::updateAABB(&gfxWorld->dpvs.surfaces[i].bounds[0], &gfxWorld->dpvs.surfaces[i].bounds[1], &gfxWorld->mins, &gfxWorld->maxs);
}
}
@@ -665,7 +666,7 @@ namespace BSP
gfxWorld->draw.reflectionProbes[0].probeVolumeCount = 0;
gfxWorld->draw.reflectionProbes[0].probeVolumes = NULL;
std::string probeImageName = "*reflection_probe0";
std::string probeImageName = "reflection_probe0";
auto probeImageAsset = m_context.LoadDependency<AssetImage>(probeImageName);
if (probeImageAsset == NULL)
{
@@ -689,7 +690,7 @@ namespace BSP
memset(gfxWorld->draw.lightmapPrimaryTextures, 0, sizeof(GfxTexture) * gfxWorld->draw.lightmapCount);
memset(gfxWorld->draw.lightmapSecondaryTextures, 0, sizeof(GfxTexture) * gfxWorld->draw.lightmapCount);
std::string secondaryTexture = "*lightmap0_secondary";
std::string secondaryTexture = "lightmap0_secondary";
auto secondaryTextureAsset = m_context.LoadDependency<AssetImage>(secondaryTexture);
if (secondaryTextureAsset == NULL)
{
@@ -8,14 +8,14 @@ namespace
{
bool parseMapEntsJSON(json& entArrayJs, std::string& entityString)
{
int entityCount = entArrayJs.size();
for (int i = 0; i < entityCount; i++)
for (size_t entIdx = 0; entIdx < entArrayJs.size(); entIdx++)
{
auto currEntity = entArrayJs[i];
auto& entity = entArrayJs[entIdx];
if (i == 0)
if (entIdx == 0)
{
std::string className = currEntity["classname"];
std::string className;
entity.at("classname").get_to(className);
if (className.compare("worldspawn") != 0)
{
con::error("ERROR: first entity in the map entity string must be the worldspawn class!");
@@ -25,7 +25,7 @@ namespace
entityString.append("{\n");
for (auto& element : currEntity.items())
for (auto& element : entity.items())
{
std::string key = element.key();
std::string value = element.value();
@@ -38,26 +38,31 @@ namespace
return true;
}
void parseSpawnpointJSON(json& entArrayJs, std::string& entityString, const char* spawnpointNames[], int nameCount)
void parseSpawnpointJSON(json& entArrayJs, std::string& entityString, const char* spawnpointNames[], size_t nameCount)
{
int entityCount = entArrayJs.size();
for (int i = 0; i < entityCount; i++)
for (auto& element : entArrayJs.items())
{
auto currEntity = entArrayJs[i];
std::string origin;
std::string angles;
auto& entity = element.value();
entity.at("origin").get_to(origin);
entity.at("angles").get_to(angles);
std::string origin = currEntity["origin"];
std::string angles = currEntity["angles"];
for (int k = 0; k < nameCount; k++)
for (size_t nameIdx = 0; nameIdx < nameCount; nameIdx++)
{
entityString.append("{\n");
entityString.append(std::format("\"origin\" \"{}\"\n", origin));
entityString.append(std::format("\"angles\" \"{}\"\n", angles));
entityString.append(std::format("\"classname\" \"{}\"\n", spawnpointNames[k]));
entityString.append(std::format("\"classname\" \"{}\"\n", spawnpointNames[nameIdx]));
entityString.append("}\n");
}
}
}
std::string loadMapEnts()
{
}
}
namespace BSP
@@ -71,58 +76,65 @@ namespace BSP
AssetCreationResult MapEntsLinker::linkMapEnts(BSPData* bsp)
{
std::string entityString;
try
{
json entJs;
std::string entityFilePath = BSPUtil::getFileNameForBSPAsset("entities.json");
const auto entFile = m_search_path.Open(entityFilePath);
if (!entFile.IsOpen())
{
con::warn("Can't find entity file {}, using default entities instead", entityFilePath);
entJs = json::parse(BSPLinkingConstants::DEFAULT_MAP_ENTS_STRING);
}
else
{
entJs = json::parse(*entFile.m_stream);
}
std::string entityString;
if (!parseMapEntsJSON(entJs["entities"], entityString))
return AssetCreationResult::Failure();
json entJs;
std::string entityFilePath = BSPUtil::getFileNameForBSPAsset("entities.json");
const auto entFile = m_search_path.Open(entityFilePath);
if (!entFile.IsOpen())
{
con::warn("Can't find entity file {}, using default entities instead", entityFilePath);
entJs = json::parse(BSPLinkingConstants::DEFAULT_MAP_ENTS_STRING);
json spawnJs;
std::string spawnFilePath = BSPUtil::getFileNameForBSPAsset("spawns.json");
const auto spawnFile = m_search_path.Open(spawnFilePath);
if (!spawnFile.IsOpen())
{
con::warn("Cant find spawn file {}, setting spawns to 0 0 0", spawnFilePath);
spawnJs = json::parse(BSPLinkingConstants::DEFAULT_SPAWN_POINT_STRING);
}
else
{
spawnJs = json::parse(*spawnFile.m_stream);
}
size_t defenderNameCount = std::extent<decltype(BSPGameConstants::DEFENDER_SPAWN_POINT_NAMES)>::value;
size_t attackerNameCount = std::extent<decltype(BSPGameConstants::ATTACKER_SPAWN_POINT_NAMES)>::value;
size_t ffaNameCount = std::extent<decltype(BSPGameConstants::FFA_SPAWN_POINT_NAMES)>::value;
parseSpawnpointJSON(spawnJs["attackers"], entityString, BSPGameConstants::DEFENDER_SPAWN_POINT_NAMES, defenderNameCount);
parseSpawnpointJSON(spawnJs["defenders"], entityString, BSPGameConstants::ATTACKER_SPAWN_POINT_NAMES, attackerNameCount);
parseSpawnpointJSON(spawnJs["FFA"], entityString, BSPGameConstants::FFA_SPAWN_POINT_NAMES, ffaNameCount);
MapEnts* mapEnts = m_memory.Alloc<MapEnts>();
mapEnts->name = m_memory.Dup(bsp->bspName.c_str());
mapEnts->entityString = m_memory.Dup(entityString.c_str());
mapEnts->numEntityChars = entityString.length() + 1; // numEntityChars includes the null character
// don't need these
mapEnts->trigger.count = 0;
mapEnts->trigger.models = nullptr;
mapEnts->trigger.hullCount = 0;
mapEnts->trigger.hulls = nullptr;
mapEnts->trigger.slabCount = 0;
mapEnts->trigger.slabs = nullptr;
auto mapEntsAsset = m_context.AddAsset<AssetMapEnts>(mapEnts->name, mapEnts);
return AssetCreationResult::Success(mapEntsAsset);
}
else
catch (const json::exception& e)
{
entJs = json::parse(*entFile.m_stream);
}
if (!parseMapEntsJSON(entJs["entities"], entityString))
con::error("JSON error when parsing map ents and spawns: {}", e.what());
return AssetCreationResult::Failure();
json spawnJs;
std::string spawnFilePath = BSPUtil::getFileNameForBSPAsset("spawns.json");
const auto spawnFile = m_search_path.Open(spawnFilePath);
if (!spawnFile.IsOpen())
{
con::warn("Cant find spawn file {}, setting spawns to 0 0 0", spawnFilePath);
spawnJs = json::parse(BSPLinkingConstants::DEFAULT_SPAWN_POINT_STRING);
}
else
{
spawnJs = json::parse(*spawnFile.m_stream);
}
int defenderNameCount = std::extent<decltype(BSPGameConstants::DEFENDER_SPAWN_POINT_NAMES)>::value;
int attackerNameCount = std::extent<decltype(BSPGameConstants::ATTACKER_SPAWN_POINT_NAMES)>::value;
int ffaNameCount = std::extent<decltype(BSPGameConstants::FFA_SPAWN_POINT_NAMES)>::value;
parseSpawnpointJSON(spawnJs["attackers"], entityString, BSPGameConstants::DEFENDER_SPAWN_POINT_NAMES, defenderNameCount);
parseSpawnpointJSON(spawnJs["defenders"], entityString, BSPGameConstants::ATTACKER_SPAWN_POINT_NAMES, attackerNameCount);
parseSpawnpointJSON(spawnJs["FFA"], entityString, BSPGameConstants::FFA_SPAWN_POINT_NAMES, ffaNameCount);
MapEnts* mapEnts = m_memory.Alloc<MapEnts>();
mapEnts->name = m_memory.Dup(bsp->bspName.c_str());
mapEnts->entityString = m_memory.Dup(entityString.c_str());
mapEnts->numEntityChars = entityString.length() + 1; // numEntityChars includes the null character
// don't need these
mapEnts->trigger.count = 0;
mapEnts->trigger.models = nullptr;
mapEnts->trigger.hullCount = 0;
mapEnts->trigger.hulls = nullptr;
mapEnts->trigger.slabCount = 0;
mapEnts->trigger.slabs = nullptr;
auto mapEntsAsset = m_context.AddAsset<AssetMapEnts>(mapEnts->name, mapEnts);
return AssetCreationResult::Success(mapEntsAsset);
}
}