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

feat: fully customisable entities through gltf

This commit is contained in:
LJW-Dev
2026-04-15 21:41:13 +08:00
committed by Jan Laupetin
parent f0ea5dad7d
commit 1dcd553905
6 changed files with 202 additions and 230 deletions
+1 -1
View File
@@ -125,7 +125,7 @@ namespace gltf
std::optional<unsigned> mesh; std::optional<unsigned> mesh;
std::optional<JsonNodeExtension> extensions; std::optional<JsonNodeExtension> extensions;
std::optional<JsonNodeExtras> extras; std::optional<nlohmann::json> extras;
}; };
NLOHMANN_DEFINE_TYPE_EXTENSION(JsonNode, name, translation, rotation, scale, matrix, children, skin, mesh, extensions, extras); NLOHMANN_DEFINE_TYPE_EXTENSION(JsonNode, name, translation, rotation, scale, matrix, children, skin, mesh, extensions, extras);
+16 -32
View File
@@ -107,44 +107,25 @@ namespace BSP
float outerConeAngle; float outerConeAngle;
}; };
enum BSPSpawnPointType
{
SPAWNPOINT_TYPE_DEFENDER,
SPAWNPOINT_TYPE_ATTACKER,
SPAWNPOINT_TYPE_ALL,
};
struct BSPSpawnPoint struct BSPSpawnPoint
{ {
vec3_t origin; vec3_t origin;
vec3_t forward; vec3_t forward;
BSPSpawnPointType type; std::string spawnpointGroupName;
};
struct BSPPathNode
{
vec3_t origin;
}; };
struct BSPZoneZM struct BSPZoneZM
{ {
vec3_t origin; vec3_t origin;
std::string zoneName; std::string zoneName;
std::string zSpawnerGroupName; std::string spawnerGroupName;
std::string spawnpointGroupName; std::string spawnpointGroupName;
size_t modelIndex; size_t modelIndex;
}; };
struct BSPSpawnPointZM
{
std::string spawnpointGroupName;
vec3_t origin;
vec3_t forward;
};
struct BSPZSpawnerZM struct BSPZSpawnerZM
{ {
std::string zSpawnerGroupName; std::string spawnerGroupName;
vec3_t origin; vec3_t origin;
vec3_t forward; vec3_t forward;
}; };
@@ -160,11 +141,19 @@ namespace BSP
size_t brushIndex; size_t brushIndex;
}; };
struct BSPTriggerBox struct BSPEntityEntry
{
std::string key;
std::string value;
};
struct BSPEntity
{ {
vec3_t origin; vec3_t origin;
vec4_t rotationQuaternion;
size_t modelIndex; size_t modelIndex;
std::string triggerName;
std::vector<BSPEntityEntry> entries;
}; };
struct BSPData struct BSPData
@@ -178,14 +167,9 @@ namespace BSP
std::vector<BSPLight> lights; std::vector<BSPLight> lights;
std::vector<BSPSpawnPoint> spawnpoints; std::vector<BSPSpawnPoint> spawnpoints;
std::vector<BSPPathNode> pathnodes; std::vector<BSPZoneZM> zm_zones;
std::vector<BSPZSpawnerZM> zm_spawners;
std::vector<BSPSpawnPointZM> zSpawnPoints; std::vector<BSPEntity> entities;
std::vector<BSPZSpawnerZM> zSpawners;
std::vector<BSPZoneZM> zZones;
std::vector<BSPTriggerBox> useTriggers;
std::vector<BSPTriggerBox> triggerMultiples;
std::vector<BSPModel> models; std::vector<BSPModel> models;
}; };
+99 -136
View File
@@ -443,10 +443,10 @@ namespace
if (primitive.material) if (primitive.material)
{ {
size_t originalMaterialIdx = *primitive.material; size_t originalMaterialIdx = *primitive.material;
if (node.extras && node.extras->flags) if (node.extras && node.extras->contains("flags"))
{ {
bool isNoDrawFlagSet = false; bool isNoDrawFlagSet = false;
materialIndex = createMaterialWithFlags(originalMaterialIdx, *node.extras->flags, isNoDrawFlagSet); materialIndex = createMaterialWithFlags(originalMaterialIdx, node.extras->at("flags"), isNoDrawFlagSet);
if (isNoDrawFlagSet && m_is_world_gfx) if (isNoDrawFlagSet && m_is_world_gfx)
continue; // noDraw flag doesn't work, so remove the surface from the graphics data instead continue; // noDraw flag doesn't work, so remove the surface from the graphics data instead
} }
@@ -492,12 +492,12 @@ namespace
throw GltfLoadException("Requires primitives attribute POSITION"); throw GltfLoadException("Requires primitives attribute POSITION");
// clang-format off // clang-format off
const auto* positionAccessor = GetAccessorForIndex( const auto* positionAccessor = GetAccessorForIndex(
"POSITION", "POSITION",
primitive.attributes.POSITION, primitive.attributes.POSITION,
{ JsonAccessorType::VEC3 }, { JsonAccessorType::VEC3 },
{ JsonAccessorComponentType::FLOAT } { JsonAccessorComponentType::FLOAT }
).value_or(nullptr); ).value_or(nullptr);
// clang-format on // clang-format on
assert(positionAccessor != nullptr); assert(positionAccessor != nullptr);
@@ -539,19 +539,17 @@ namespace
bool addXModelNode(const JsonRoot& jRoot, const gltf::JsonNode& node) bool addXModelNode(const JsonRoot& jRoot, const gltf::JsonNode& node)
{ {
assert(node.extras); assert(node.extras);
assert(node.extras->xmodel); assert(node.extras->contains("xmodel"));
Eigen::Matrix4f nodeMatrix = createNodeMatrix(node); Eigen::Matrix4f nodeMatrix = createNodeMatrix(node);
BSPXModel xmodel; BSPXModel xmodel;
if (node.extras->xmodel->size() == 0) xmodel.name = node.extras->at("xmodel");
throw GltfLoadException("Xmodel has no name.");
xmodel.name = *node.extras->xmodel;
xmodel.doesCastShadow = true; xmodel.doesCastShadow = true;
if (node.extras->flags) if (node.extras->contains("flags"))
{ {
std::vector<std::string> flagStrVec = utils::StringSplit(*node.extras->flags, ','); std::vector<std::string> flagStrVec = utils::StringSplit(node.extras->at("flags"), ',');
for (std::string& flag : flagStrVec) for (std::string& flag : flagStrVec)
if (!flag.compare(surfaceTypeToNameMap[SURF_TYPE_NOCASTSHADOW])) if (!flag.compare(surfaceTypeToNameMap[SURF_TYPE_NOCASTSHADOW]))
{ {
@@ -573,7 +571,7 @@ namespace
xmodel.rotationQuaternion.x = rotationQuat.x(); xmodel.rotationQuaternion.x = rotationQuat.x();
xmodel.rotationQuaternion.y = rotationQuat.y(); xmodel.rotationQuaternion.y = rotationQuat.y();
xmodel.rotationQuaternion.z = rotationQuat.z(); xmodel.rotationQuaternion.z = rotationQuat.z();
xmodel.rotationQuaternion.w = rotationQuat.w(); // Eigen is WXYZ, game is XYZW xmodel.rotationQuaternion.w = rotationQuat.w();
RhcToLhcQuaternion(xmodel.rotationQuaternion.v); RhcToLhcQuaternion(xmodel.rotationQuaternion.v);
con::warn("XModels don't support scale currently, keep it at 1 in your editor"); con::warn("XModels don't support scale currently, keep it at 1 in your editor");
@@ -586,30 +584,10 @@ namespace
return true; return true;
} }
bool addPathNode_Node(const gltf::JsonNode& node)
{
assert(node.extras);
assert(node.extras->pathnode);
BSPPathNode pathnode;
Eigen::Matrix4f nodeMatrix = createNodeMatrix(node);
Eigen::Vector4f position(0, 0, 0, 1.0f);
Eigen::Vector4f transformedPosition = nodeMatrix * position;
pathnode.origin.x = transformedPosition.x();
pathnode.origin.y = transformedPosition.y();
pathnode.origin.z = transformedPosition.z();
RhcToLhcCoordinates(pathnode.origin.v);
m_bsp->pathnodes.emplace_back(pathnode);
return true;
}
bool addSpawnPointNode(const gltf::JsonNode& node) bool addSpawnPointNode(const gltf::JsonNode& node)
{ {
assert(node.extras); assert(node.extras);
assert(node.extras->spawnpoint); assert(node.extras->contains("spawnpoint"));
Eigen::Matrix4f nodeMatrix = createNodeMatrix(node); Eigen::Matrix4f nodeMatrix = createNodeMatrix(node);
@@ -633,34 +611,18 @@ namespace
forward.z = outputDirection.z(); forward.z = outputDirection.z();
RhcToLhcCoordinates(forward.v); RhcToLhcCoordinates(forward.v);
if (m_bsp->isZombiesMap) std::string team = node.extras->at("spawnpoint");
if (!m_bsp->isZombiesMap && team.compare("attacker") && team.compare("defender") && team.compare("all"))
{ {
BSPSpawnPointZM spawnPoint; con::warn("Ignoring spawn point with an invalid type (must be attacker, defender or all)");
spawnPoint.origin = origin; return false;
spawnPoint.forward = forward;
spawnPoint.spawnpointGroupName = *node.extras->spawnpoint;
m_bsp->zSpawnPoints.emplace_back(spawnPoint);
} }
else
{
BSPSpawnPoint spawnPoint;
spawnPoint.origin = origin;
spawnPoint.forward = forward;
if (!node.extras->spawnpoint->compare("attacker")) BSPSpawnPoint spawnPoint;
spawnPoint.type = SPAWNPOINT_TYPE_ATTACKER; spawnPoint.origin = origin;
else if (!node.extras->spawnpoint->compare("defender")) spawnPoint.forward = forward;
spawnPoint.type = SPAWNPOINT_TYPE_DEFENDER; spawnPoint.spawnpointGroupName = team;
else if (!node.extras->spawnpoint->compare("all")) m_bsp->spawnpoints.emplace_back(spawnPoint);
spawnPoint.type = SPAWNPOINT_TYPE_ALL;
else
{
con::warn("Ignoring spawn point with an invalid type (must be attacker, defender or all)");
return false;
}
m_bsp->spawnpoints.emplace_back(spawnPoint);
}
return true; return true;
} }
@@ -697,12 +659,12 @@ namespace
throw GltfLoadException("Requires primitives attribute POSITION"); throw GltfLoadException("Requires primitives attribute POSITION");
// clang-format off // clang-format off
const auto* positionAccessor = GetAccessorForIndex( const auto* positionAccessor = GetAccessorForIndex(
"POSITION", "POSITION",
primitive.attributes.POSITION, primitive.attributes.POSITION,
{ JsonAccessorType::VEC3 }, { JsonAccessorType::VEC3 },
{ JsonAccessorComponentType::FLOAT } { JsonAccessorComponentType::FLOAT }
).value_or(nullptr); ).value_or(nullptr);
// clang-format on // clang-format on
assert(positionAccessor != nullptr); assert(positionAccessor != nullptr);
@@ -807,7 +769,13 @@ namespace
bool addZoneNode(const JsonRoot& jRoot, const gltf::JsonNode& node) bool addZoneNode(const JsonRoot& jRoot, const gltf::JsonNode& node)
{ {
assert(node.extras); assert(node.extras);
assert(node.extras->zone); assert(node.extras->contains("zone"));
if (!node.extras->contains("spawner_group") || !node.extras->contains("spawnpoint_group"))
{
con::error("ignoring zone: Zone object must have a valid spawner_group and spawnpoint_group property");
return false;
}
Eigen::Matrix4f nodeMatrix = createNodeMatrix(node); Eigen::Matrix4f nodeMatrix = createNodeMatrix(node);
@@ -821,11 +789,11 @@ namespace
BSPZoneZM zone; BSPZoneZM zone;
zone.origin = origin; zone.origin = origin;
zone.zoneName = *node.extras->zone; zone.zoneName = node.extras->at("zone");
zone.zSpawnerGroupName = node.extras->zspawner_group.value_or(""); zone.spawnerGroupName = node.extras->at("spawner_group");
zone.spawnpointGroupName = node.extras->spawnpoint_group.value_or(""); zone.spawnpointGroupName = node.extras->at("spawnpoint_group");
zone.modelIndex = addScriptBrushModel(jRoot, node); zone.modelIndex = addScriptBrushModel(jRoot, node);
m_bsp->zZones.emplace_back(zone); m_bsp->zm_zones.emplace_back(zone);
return true; return true;
} }
@@ -833,7 +801,7 @@ namespace
bool addZSpawnerNode(const gltf::JsonNode& node) bool addZSpawnerNode(const gltf::JsonNode& node)
{ {
assert(node.extras); assert(node.extras);
assert(node.extras->zspawner); assert(node.extras->contains("spawner"));
Eigen::Matrix4f nodeMatrix = createNodeMatrix(node); Eigen::Matrix4f nodeMatrix = createNodeMatrix(node);
@@ -860,57 +828,55 @@ namespace
BSPZSpawnerZM spawner; BSPZSpawnerZM spawner;
spawner.origin = origin; spawner.origin = origin;
spawner.forward = forward; spawner.forward = forward;
spawner.zSpawnerGroupName = *node.extras->zspawner; spawner.spawnerGroupName = node.extras->at("spawner");
m_bsp->zSpawners.emplace_back(spawner); m_bsp->zm_spawners.emplace_back(spawner);
return true; return true;
} }
bool addTriggerUseNode(const JsonRoot& jRoot, const gltf::JsonNode& node) bool addClassNode(const JsonRoot& jRoot, const gltf::JsonNode& node)
{ {
assert(node.extras); BSPEntity entity;
assert(node.extras->trigger_use); bool doesClassContainModel = false;
for (auto& element : node.extras->items())
{
std::string key = element.key();
if (!key.compare("origin") || !key.compare("angles"))
continue;
if (!key.compare("model"))
doesClassContainModel = true;
BSPEntityEntry entry;
entry.key = key;
entry.value = element.value();
entity.entries.emplace_back(entry);
}
if (node.mesh && !doesClassContainModel)
entity.modelIndex = addScriptBrushModel(jRoot, node);
else
entity.modelIndex = 0;
Eigen::Matrix4f nodeMatrix = createNodeMatrix(node); Eigen::Matrix4f nodeMatrix = createNodeMatrix(node);
Eigen::Vector4f position(0, 0, 0, 1.0f); Eigen::Vector4f position(0, 0, 0, 1.0f);
Eigen::Vector4f transformedPosition = nodeMatrix * position; Eigen::Vector4f transformedPosition = nodeMatrix * position;
vec3_t origin; entity.origin.x = transformedPosition.x();
origin.x = transformedPosition.x(); entity.origin.y = transformedPosition.y();
origin.y = transformedPosition.y(); entity.origin.z = transformedPosition.z();
origin.z = transformedPosition.z(); RhcToLhcCoordinates(entity.origin.v);
RhcToLhcCoordinates(origin.v);
BSPTriggerBox trigger; Eigen::Affine3f affineTransform(nodeMatrix);
trigger.origin = origin; Eigen::Quaternionf rotationQuat(affineTransform.rotation());
trigger.triggerName = *node.extras->trigger_use; rotationQuat.normalize();
trigger.modelIndex = addScriptBrushModel(jRoot, node); entity.rotationQuaternion.x = rotationQuat.x();
m_bsp->useTriggers.emplace_back(trigger); entity.rotationQuaternion.y = rotationQuat.y();
entity.rotationQuaternion.z = rotationQuat.z();
return true; entity.rotationQuaternion.w = rotationQuat.w();
} RhcToLhcQuaternion(entity.rotationQuaternion.v);
bool addTriggerMultipleNode(const JsonRoot& jRoot, const gltf::JsonNode& node)
{
assert(node.extras);
assert(node.extras->trigger_multiple);
Eigen::Matrix4f nodeMatrix = createNodeMatrix(node);
Eigen::Vector4f position(0, 0, 0, 1.0f);
Eigen::Vector4f transformedPosition = nodeMatrix * position;
vec3_t origin;
origin.x = transformedPosition.x();
origin.y = transformedPosition.y();
origin.z = transformedPosition.z();
RhcToLhcCoordinates(origin.v);
BSPTriggerBox trigger;
trigger.origin = origin;
trigger.triggerName = *node.extras->trigger_multiple;
trigger.modelIndex = addScriptBrushModel(jRoot, node);
m_bsp->triggerMultiples.emplace_back(trigger);
m_bsp->entities.emplace_back(entity);
return true; return true;
} }
@@ -921,34 +887,31 @@ namespace
if (node.extras) if (node.extras)
{ {
if (node.extras->xmodel) if (!m_is_world_gfx)
{
if (node.extras->contains("classname"))
return addClassNode(jRoot, node);
if (node.extras->contains("spawnpoint"))
return addSpawnPointNode(node);
if (m_bsp->isZombiesMap)
{
if (node.extras->contains("zone"))
return addZoneNode(jRoot, node);
if (node.extras->contains("spawner"))
return addZSpawnerNode(node);
}
}
if (node.extras->contains("xmodel"))
return addXModelNode(jRoot, node); return addXModelNode(jRoot, node);
if (!m_is_world_gfx && node.extras->spawnpoint) if (node.mesh)
return addSpawnPointNode(node); return addMeshNode(jRoot, node);
if (!m_is_world_gfx && node.extras->pathnode)
return addPathNode_Node(node);
if (!m_is_world_gfx && node.extras->trigger_use)
return addTriggerUseNode(jRoot, node);
if (!m_is_world_gfx && node.extras->trigger_multiple)
return addTriggerMultipleNode(jRoot, node);
if (!m_is_world_gfx && m_bsp->isZombiesMap)
{
if (node.extras->zone)
return addZoneNode(jRoot, node);
if (node.extras->zspawner)
return addZSpawnerNode(node);
}
} }
if (node.mesh)
return addMeshNode(jRoot, node);
return false; return false;
} }
+52
View File
@@ -196,6 +196,17 @@ namespace BSP
{ {
vec3_t viewAngles; vec3_t viewAngles;
if (forwardVec.x == 0.0f && forwardVec.y == 0.0f)
{
if (-forwardVec.z < 0.0f)
viewAngles.x = 270.0f;
else
viewAngles.x = 90.0f;
viewAngles.y = 0.0f;
viewAngles.z = 0.0f;
return viewAngles;
}
float xAndYDist = sqrtf((forwardVec.x * forwardVec.x) + (forwardVec.y * forwardVec.y)); float xAndYDist = sqrtf((forwardVec.x * forwardVec.x) + (forwardVec.y * forwardVec.y));
float atanXRadians = atan2f(forwardVec.z, xAndYDist); float atanXRadians = atan2f(forwardVec.z, xAndYDist);
float atanXDegrees = atanXRadians * (-180.0f / std::numbers::pi_v<float>); float atanXDegrees = atanXRadians * (-180.0f / std::numbers::pi_v<float>);
@@ -214,6 +225,47 @@ namespace BSP
return viewAngles; return viewAngles;
} }
float BSPUtil::getPitchFromVector(vec3_t& vector)
{
if (vector.x == 0.0f && vector.y == 0.0f)
{
if (-vector.z < 0.0f)
return -90.0f;
else
return 90.0f;
}
float xAndYDist = sqrtf((vector.x * vector.x) + (vector.y * vector.y));
float pitchRadians = atan2f(vector.z, xAndYDist);
float pitchDegrees = pitchRadians * (-180.0f / std::numbers::pi_v<float>);
return pitchDegrees;
}
vec3_t BSPUtil::convertAxisToAngles(vec3_t axis[3])
{
vec3_t tempAngles = convertForwardVectorToViewAngles(axis[0]);
float xRadiansNeg = -tempAngles.x * (std::numbers::pi_v<float> / 180.0f);
float yRadiansNeg = -tempAngles.y * (std::numbers::pi_v<float> / 180.0f);
float cosX = cos(xRadiansNeg);
float sinX = sin(xRadiansNeg);
float cosY = cos(yRadiansNeg);
float sinY = sin(yRadiansNeg);
vec3_t tempVec;
float tempFloat = (axis[1].x * cosY) - (axis[1].y * sinY);
tempVec.x = (axis[1].z * sinX) + (tempFloat * cosX);
tempVec.y = (axis[1].x * sinY) + (axis[1].y * cosY);
tempVec.z = (axis[1].z * cosX) - (tempFloat * sinX);
float pitch = getPitchFromVector(tempVec);
if (tempVec.y >= 0.0f)
tempAngles.z = -pitch;
else if (pitch >= 0.0f)
tempAngles.z = pitch - 180.0f;
else
tempAngles.z = pitch + 180.0f;
return tempAngles;
}
void BSPUtil::matrixTranspose3x3(const vec3_t* in, vec3_t* out) void BSPUtil::matrixTranspose3x3(const vec3_t* in, vec3_t* out)
{ {
out[0].x = in[0].x; out[0].x = in[0].x;
+2
View File
@@ -20,6 +20,8 @@ namespace BSP
static void convertAnglesToAxis(vec3_t* angles, vec3_t axis[3]); static void convertAnglesToAxis(vec3_t* angles, vec3_t axis[3]);
static void convertQuaternionToAxis(vec4_t* quat, vec3_t axis[3]); static void convertQuaternionToAxis(vec4_t* quat, vec3_t axis[3]);
static vec3_t convertForwardVectorToViewAngles(vec3_t& forwardVec); static vec3_t convertForwardVectorToViewAngles(vec3_t& forwardVec);
static float getPitchFromVector(vec3_t& vector);
static vec3_t convertAxisToAngles(vec3_t axis[3]);
static void matrixTranspose3x3(const vec3_t* in, vec3_t* out); static void matrixTranspose3x3(const vec3_t* in, vec3_t* out);
static vec3_t convertStringToVec3(std::string& str); static vec3_t convertStringToVec3(std::string& str);
static std::string convertVec3ToString(vec3_t& vec); static std::string convertVec3ToString(vec3_t& vec);
@@ -67,22 +67,19 @@ namespace
void addSpawnsToEntString(BSP::BSPData* bsp, std::string& entityString) void addSpawnsToEntString(BSP::BSPData* bsp, std::string& entityString)
{ {
if (!bsp->isZombiesMap && bsp->spawnpoints.size() == 0) if (bsp->isZombiesMap)
{ {
con::info("No spawnpoints found, setting all spawns to (0, 0, 0)"); for (auto& spawnPoint : bsp->spawnpoints)
BSP::BSPSpawnPoint defaultSpawnPoint; {
defaultSpawnPoint.origin.x = 0.0f; entityString.append("{\n");
defaultSpawnPoint.origin.y = 0.0f; entityString.append("\"classname\" \"script_struct\"\n");
defaultSpawnPoint.origin.z = 0.0f; entityString.append(std::format("\"targetname\" \"{}\"\n", spawnPoint.spawnpointGroupName));
defaultSpawnPoint.forward.x = 1.0f; entityString.append(std::format("\"origin\" \"{}\"\n", BSP::BSPUtil::convertVec3ToString(spawnPoint.origin)));
defaultSpawnPoint.forward.y = 0.0f; vec3_t angles = BSP::BSPUtil::convertForwardVectorToViewAngles(spawnPoint.forward);
defaultSpawnPoint.forward.z = 0.0f; entityString.append(std::format("\"angles\" \"{}\"\n", BSP::BSPUtil::convertVec3ToString(angles)));
defaultSpawnPoint.type = BSP::BSPSpawnPointType::SPAWNPOINT_TYPE_DEFENDER; entityString.append("}\n");
bsp->spawnpoints.emplace_back(defaultSpawnPoint); }
defaultSpawnPoint.type = BSP::BSPSpawnPointType::SPAWNPOINT_TYPE_ATTACKER; return;
bsp->spawnpoints.emplace_back(defaultSpawnPoint);
defaultSpawnPoint.type = BSP::BSPSpawnPointType::SPAWNPOINT_TYPE_ALL;
bsp->spawnpoints.emplace_back(defaultSpawnPoint);
} }
size_t defenderNameCount = std::extent<decltype(DEFENDER_SPAWN_POINT_NAMES)>::value; size_t defenderNameCount = std::extent<decltype(DEFENDER_SPAWN_POINT_NAMES)>::value;
@@ -98,9 +95,9 @@ namespace
std::string anglesStr = std::format("\"angles\" \"{}\"\n", BSP::BSPUtil::convertVec3ToString(angles)); std::string anglesStr = std::format("\"angles\" \"{}\"\n", BSP::BSPUtil::convertVec3ToString(angles));
const std::vector<const char*>* spawnPointList; const std::vector<const char*>* spawnPointList;
if (spawnPoint.type == BSP::BSPSpawnPointType::SPAWNPOINT_TYPE_DEFENDER) if (!spawnPoint.spawnpointGroupName.compare("defender"))
spawnPointList = &DEFENDER_SPAWN_POINT_NAMES; spawnPointList = &DEFENDER_SPAWN_POINT_NAMES;
else if (spawnPoint.type == BSP::BSPSpawnPointType::SPAWNPOINT_TYPE_ATTACKER) else if (!spawnPoint.spawnpointGroupName.compare("attacker"))
spawnPointList = &ATTACKER_SPAWN_POINT_NAMES; spawnPointList = &ATTACKER_SPAWN_POINT_NAMES;
else // SPAWNPOINT_TYPE_ALL else // SPAWNPOINT_TYPE_ALL
spawnPointList = &FFA_SPAWN_POINT_NAMES; spawnPointList = &FFA_SPAWN_POINT_NAMES;
@@ -116,26 +113,15 @@ namespace
} }
} }
void addPathNodesToEntString(BSP::BSPData* bsp, std::string& entityString)
{
for (auto& pathnode : bsp->pathnodes)
{
entityString.append("{\n");
entityString.append(std::format("\"origin\" \"{}\"\n", BSP::BSPUtil::convertVec3ToString(pathnode.origin)));
entityString.append(std::format("\"classname\" \"{}\"\n", "node_pathnode"));
entityString.append("}\n");
}
}
void addZombiesEntitiesToEntString(BSP::BSPData* bsp, std::string& entityString) void addZombiesEntitiesToEntString(BSP::BSPData* bsp, std::string& entityString)
{ {
for (auto& zone : bsp->zZones) for (auto& zone : bsp->zm_zones)
{ {
entityString.append("{\n"); entityString.append("{\n");
entityString.append("\"classname\" \"info_volume\"\n"); entityString.append("\"classname\" \"info_volume\"\n");
entityString.append("\"script_noteworthy\" \"player_volume\"\n"); entityString.append("\"script_noteworthy\" \"player_volume\"\n");
entityString.append(std::format("\"targetname\" \"{}\"\n", zone.zoneName)); entityString.append(std::format("\"targetname\" \"{}\"\n", zone.zoneName));
entityString.append(std::format("\"target\" \"{}\"\n", zone.zSpawnerGroupName)); entityString.append(std::format("\"target\" \"{}\"\n", zone.spawnerGroupName));
entityString.append(std::format("\"origin\" \"{}\"\n", BSP::BSPUtil::convertVec3ToString(zone.origin))); entityString.append(std::format("\"origin\" \"{}\"\n", BSP::BSPUtil::convertVec3ToString(zone.origin)));
entityString.append(std::format("\"model\" \"*{}\"\n", zone.modelIndex)); entityString.append(std::format("\"model\" \"*{}\"\n", zone.modelIndex));
entityString.append("}\n"); entityString.append("}\n");
@@ -148,50 +134,37 @@ namespace
entityString.append("}\n"); entityString.append("}\n");
} }
for (auto& zSpawner : bsp->zSpawners) for (auto& zSpawner : bsp->zm_spawners)
{ {
entityString.append("{\n"); entityString.append("{\n");
entityString.append("\"classname\" \"script_struct\"\n"); entityString.append("\"classname\" \"script_struct\"\n");
entityString.append("\"script_noteworthy\" \"riser_location\"\n"); entityString.append("\"script_noteworthy\" \"riser_location\"\n");
entityString.append("\"script_string\" \"find_flesh\"\n"); entityString.append("\"script_string\" \"find_flesh\"\n");
entityString.append(std::format("\"targetname\" \"{}\"\n", zSpawner.zSpawnerGroupName)); entityString.append(std::format("\"targetname\" \"{}\"\n", zSpawner.spawnerGroupName));
entityString.append(std::format("\"origin\" \"{}\"\n", BSP::BSPUtil::convertVec3ToString(zSpawner.origin))); entityString.append(std::format("\"origin\" \"{}\"\n", BSP::BSPUtil::convertVec3ToString(zSpawner.origin)));
vec3_t angles = BSP::BSPUtil::convertForwardVectorToViewAngles(zSpawner.forward); vec3_t angles = BSP::BSPUtil::convertForwardVectorToViewAngles(zSpawner.forward);
entityString.append(std::format("\"angles\" \"{}\"\n", BSP::BSPUtil::convertVec3ToString(angles))); entityString.append(std::format("\"angles\" \"{}\"\n", BSP::BSPUtil::convertVec3ToString(angles)));
entityString.append("}\n"); entityString.append("}\n");
} }
for (auto& spawnPoint : bsp->zSpawnPoints)
{
entityString.append("{\n");
entityString.append("\"classname\" \"script_struct\"\n");
entityString.append(std::format("\"targetname\" \"{}\"\n", spawnPoint.spawnpointGroupName));
entityString.append(std::format("\"origin\" \"{}\"\n", BSP::BSPUtil::convertVec3ToString(spawnPoint.origin)));
vec3_t angles = BSP::BSPUtil::convertForwardVectorToViewAngles(spawnPoint.forward);
entityString.append(std::format("\"angles\" \"{}\"\n", BSP::BSPUtil::convertVec3ToString(angles)));
entityString.append("}\n");
}
} }
void addScriptingToEntString(BSP::BSPData* bsp, std::string& entityString) void addClassEntitiesToEntString(BSP::BSPData* bsp, std::string& entityString)
{ {
for (auto& useTrigger : bsp->useTriggers) for (auto& entity : bsp->entities)
{ {
entityString.append("{\n"); vec3_t origin = entity.origin;
entityString.append("\"classname\" \"trigger_use\"\n"); vec3_t axis[3];
entityString.append(std::format("\"targetname\" \"{}\"\n", useTrigger.triggerName)); BSP::BSPUtil::convertQuaternionToAxis(&entity.rotationQuaternion, axis);
entityString.append(std::format("\"origin\" \"{}\"\n", BSP::BSPUtil::convertVec3ToString(useTrigger.origin))); vec3_t angles = BSP::BSPUtil::convertAxisToAngles(axis);
entityString.append(std::format("\"model\" \"*{}\"\n", useTrigger.modelIndex));
entityString.append("}\n");
}
for (auto& useTrigger : bsp->triggerMultiples)
{
entityString.append("{\n"); entityString.append("{\n");
entityString.append("\"classname\" \"trigger_multiple\"\n"); entityString.append(std::format("\"origin\" \"{}\"\n", BSP::BSPUtil::convertVec3ToString(origin)));
entityString.append(std::format("\"targetname\" \"{}\"\n", useTrigger.triggerName)); entityString.append(std::format("\"angles\" \"{}\"\n", BSP::BSPUtil::convertVec3ToString(angles)));
entityString.append(std::format("\"origin\" \"{}\"\n", BSP::BSPUtil::convertVec3ToString(useTrigger.origin))); for (auto& entry : entity.entries)
entityString.append(std::format("\"model\" \"*{}\"\n", useTrigger.modelIndex)); entityString.append(std::format("\"{}\" \"{}\"\n", entry.key, entry.value));
if (entity.modelIndex != 0)
entityString.append(std::format("\"model\" \"*{}\"\n", entity.modelIndex));
entityString.append("}\n"); entityString.append("}\n");
} }
} }
@@ -247,12 +220,10 @@ namespace BSP
addSpawnsToEntString(bsp, entityString); addSpawnsToEntString(bsp, entityString);
addPathNodesToEntString(bsp, entityString);
if (bsp->isZombiesMap) if (bsp->isZombiesMap)
addZombiesEntitiesToEntString(bsp, entityString); addZombiesEntitiesToEntString(bsp, entityString);
addScriptingToEntString(bsp, entityString); addClassEntitiesToEntString(bsp, entityString);
MapEnts* mapEnts = m_memory.Alloc<MapEnts>(); MapEnts* mapEnts = m_memory.Alloc<MapEnts>();
mapEnts->name = m_memory.Dup(bsp->bspName.c_str()); mapEnts->name = m_memory.Dup(bsp->bspName.c_str());