mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2026-06-06 08:42:35 +00:00
feat: spawn points are now defined in the GLTF file using custom properties. Initial xmodel implementation also included.
This commit is contained in:
@@ -74,6 +74,35 @@ namespace BSP
|
|||||||
float outerConeAngle;
|
float outerConeAngle;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct BSPXModel
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
|
||||||
|
vec3_t origin;
|
||||||
|
float scale;
|
||||||
|
vec3_t forward;
|
||||||
|
vec3_t right;
|
||||||
|
vec3_t up;
|
||||||
|
|
||||||
|
bool areBoundsValid;
|
||||||
|
vec3_t mins;
|
||||||
|
vec3_t maxs;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum BSPSpawnPointType
|
||||||
|
{
|
||||||
|
SPAWNPOINT_TYPE_DEFENDER,
|
||||||
|
SPAWNPOINT_TYPE_ATTACKER,
|
||||||
|
SPAWNPOINT_TYPE_ALL,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BSPSpawnPoint
|
||||||
|
{
|
||||||
|
vec3_t origin;
|
||||||
|
vec3_t forward;
|
||||||
|
BSPSpawnPointType type;
|
||||||
|
};
|
||||||
|
|
||||||
struct BSPData
|
struct BSPData
|
||||||
{
|
{
|
||||||
std::string name;
|
std::string name;
|
||||||
@@ -83,6 +112,8 @@ namespace BSP
|
|||||||
BSPWorld colWorld;
|
BSPWorld colWorld;
|
||||||
|
|
||||||
std::vector<BSPLight> lights;
|
std::vector<BSPLight> lights;
|
||||||
|
std::vector<BSPXModel> xmodels;
|
||||||
|
std::vector<BSPSpawnPoint> spawnpoints;
|
||||||
};
|
};
|
||||||
|
|
||||||
// BSPGameConstants:
|
// BSPGameConstants:
|
||||||
@@ -99,32 +130,6 @@ namespace BSP
|
|||||||
SUN_LIGHT_INDEX = 1,
|
SUN_LIGHT_INDEX = 1,
|
||||||
BSP_DEFAULT_LIGHT_COUNT = 2
|
BSP_DEFAULT_LIGHT_COUNT = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
inline const char* DEFENDER_SPAWN_POINT_NAMES[] = {"mp_ctf_spawn_allies",
|
|
||||||
"mp_ctf_spawn_allies_start",
|
|
||||||
"mp_sd_spawn_defender",
|
|
||||||
"mp_dom_spawn_allies_start",
|
|
||||||
"mp_dem_spawn_defender_start",
|
|
||||||
"mp_dem_spawn_defenderOT_start",
|
|
||||||
"mp_dem_spawn_defender",
|
|
||||||
"mp_tdm_spawn_allies_start",
|
|
||||||
"mp_tdm_spawn_team1_start",
|
|
||||||
"mp_tdm_spawn_team2_start",
|
|
||||||
"mp_tdm_spawn_team3_start"};
|
|
||||||
|
|
||||||
inline const char* ATTACKER_SPAWN_POINT_NAMES[] = {"mp_ctf_spawn_axis",
|
|
||||||
"mp_ctf_spawn_axis_start",
|
|
||||||
"mp_sd_spawn_attacker",
|
|
||||||
"mp_dom_spawn_axis_start",
|
|
||||||
"mp_dem_spawn_attacker_start",
|
|
||||||
"mp_dem_spawn_attackerOT_start",
|
|
||||||
"mp_dem_spawn_defender",
|
|
||||||
"mp_tdm_spawn_axis_start",
|
|
||||||
"mp_tdm_spawn_team4_start",
|
|
||||||
"mp_tdm_spawn_team5_start",
|
|
||||||
"mp_tdm_spawn_team6_start"};
|
|
||||||
|
|
||||||
inline const char* FFA_SPAWN_POINT_NAMES[] = {"mp_tdm_spawn", "mp_dm_spawn", "mp_dom_spawn"};
|
|
||||||
} // namespace BSPGameConstants
|
} // namespace BSPGameConstants
|
||||||
|
|
||||||
// BSPLinkingConstants:
|
// BSPLinkingConstants:
|
||||||
@@ -133,45 +138,6 @@ namespace BSP
|
|||||||
{
|
{
|
||||||
constexpr const char* MISSING_IMAGE_NAME = ",mc/lambert1";
|
constexpr const char* MISSING_IMAGE_NAME = ",mc/lambert1";
|
||||||
constexpr const char* COLOR_ONLY_IMAGE_NAME = ",mc/lambert1";
|
constexpr const char* COLOR_ONLY_IMAGE_NAME = ",mc/lambert1";
|
||||||
|
|
||||||
constexpr const char* DEFAULT_SPAWN_POINT_STRING = R"({
|
|
||||||
"attackers": [
|
|
||||||
{
|
|
||||||
"origin": "0 0 0",
|
|
||||||
"angles": "0 0 0"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"defenders": [
|
|
||||||
{
|
|
||||||
"origin": "0 0 0",
|
|
||||||
"angles": "0 0 0"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"FFA": [
|
|
||||||
{
|
|
||||||
"origin": "0 0 0",
|
|
||||||
"angles": "0 0 0"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})";
|
|
||||||
|
|
||||||
constexpr const char* DEFAULT_MAP_ENTS_STRING = R"({
|
|
||||||
"entities": [
|
|
||||||
{
|
|
||||||
"classname": "worldspawn"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"angles": "0 0 0",
|
|
||||||
"classname": "info_player_start",
|
|
||||||
"origin": "0 0 0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"angles": "0 0 0",
|
|
||||||
"classname": "mp_global_intermission",
|
|
||||||
"origin": "0 0 0"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})";
|
|
||||||
} // namespace BSPLinkingConstants
|
} // namespace BSPLinkingConstants
|
||||||
|
|
||||||
// BSPEditableConstants:
|
// BSPEditableConstants:
|
||||||
|
|||||||
@@ -191,8 +191,7 @@ namespace
|
|||||||
return T.matrix();
|
return T.matrix();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned CreateVertices(
|
unsigned CreateVertices(const AccessorsForVertex& accessorsForVertex, Eigen::Matrix4f& nodeMatrix, BSPSurface& surface, vec4_t vertexColor)
|
||||||
const AccessorsForVertex& accessorsForVertex, const gltf::JsonNode& node, Eigen::Matrix4f& nodeMatrix, BSPSurface& surface, vec4_t vertexColor)
|
|
||||||
{
|
{
|
||||||
// clang-format off
|
// clang-format off
|
||||||
const auto* positionAccessor = GetAccessorForIndex(
|
const auto* positionAccessor = GetAccessorForIndex(
|
||||||
@@ -320,12 +319,14 @@ namespace
|
|||||||
return vertexOffset;
|
return vertexOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool addNodeToBSP(const JsonRoot& jRoot, const gltf::JsonNode& node)
|
bool addLightNode(const gltf::JsonNode& node)
|
||||||
{
|
{
|
||||||
|
assert(m_is_world_gfx);
|
||||||
|
assert(node.extensions);
|
||||||
|
assert(node.extensions->KHR_lights_punctual);
|
||||||
|
|
||||||
Eigen::Matrix4f nodeMatrix = createNodeMatrix(node);
|
Eigen::Matrix4f nodeMatrix = createNodeMatrix(node);
|
||||||
|
|
||||||
if (m_is_world_gfx && node.extensions && node.extensions->KHR_lights_punctual)
|
|
||||||
{
|
|
||||||
int lightIndex = node.extensions->KHR_lights_punctual->light;
|
int lightIndex = node.extensions->KHR_lights_punctual->light;
|
||||||
|
|
||||||
assert(lightIndex >= 0);
|
assert(lightIndex >= 0);
|
||||||
@@ -350,9 +351,13 @@ namespace
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node.mesh)
|
bool addMeshNode(const JsonRoot& jRoot, const gltf::JsonNode& node)
|
||||||
{
|
{
|
||||||
|
assert(node.mesh);
|
||||||
assert(jRoot.meshes);
|
assert(jRoot.meshes);
|
||||||
|
|
||||||
|
Eigen::Matrix4f nodeMatrix = createNodeMatrix(node);
|
||||||
|
|
||||||
const auto& mesh = jRoot.meshes.value()[node.mesh.value()];
|
const auto& mesh = jRoot.meshes.value()[node.mesh.value()];
|
||||||
for (const auto& primitive : mesh.primitives)
|
for (const auto& primitive : mesh.primitives)
|
||||||
{
|
{
|
||||||
@@ -379,18 +384,83 @@ namespace
|
|||||||
else
|
else
|
||||||
surface.materialIndex = m_curr_bsp_world->materials.size() - 1; // last material is used for colour only meshes
|
surface.materialIndex = m_curr_bsp_world->materials.size() - 1; // last material is used for colour only meshes
|
||||||
vec4_t vertexColour = m_curr_bsp_world->materials.at(surface.materialIndex).materialColour;
|
vec4_t vertexColour = m_curr_bsp_world->materials.at(surface.materialIndex).materialColour;
|
||||||
CreateVertices(accessorsForVertex, node, nodeMatrix, surface, vertexColour);
|
CreateVertices(accessorsForVertex, nodeMatrix, surface, vertexColour);
|
||||||
|
|
||||||
m_curr_bsp_world->surfaces.emplace_back(surface);
|
m_curr_bsp_world->surfaces.emplace_back(surface);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool addXModelNode(const gltf::JsonNode& node)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool addSpawnPointNode(const gltf::JsonNode& node)
|
||||||
|
{
|
||||||
|
assert(node.extras);
|
||||||
|
assert(node.extras->spawnpoint);
|
||||||
|
|
||||||
|
Eigen::Matrix4f nodeMatrix = createNodeMatrix(node);
|
||||||
|
BSPSpawnPoint spawnPoint;
|
||||||
|
|
||||||
|
if (!node.extras->spawnpoint->compare("attacker"))
|
||||||
|
spawnPoint.type = SPAWNPOINT_TYPE_ATTACKER;
|
||||||
|
else if (!node.extras->spawnpoint->compare("defender"))
|
||||||
|
spawnPoint.type = SPAWNPOINT_TYPE_DEFENDER;
|
||||||
|
else if (!node.extras->spawnpoint->compare("all"))
|
||||||
|
spawnPoint.type = SPAWNPOINT_TYPE_ALL;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
con::warn("Ignoring spawn point with an invalid type (must be attacker, defender or all)");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Eigen::Vector4f position(0, 0, 0, 1.0f);
|
||||||
|
Eigen::Vector4f transformedPosition = nodeMatrix * position;
|
||||||
|
spawnPoint.origin.x = transformedPosition.x();
|
||||||
|
spawnPoint.origin.y = transformedPosition.y();
|
||||||
|
spawnPoint.origin.z = transformedPosition.z();
|
||||||
|
RhcToLhcCoordinates(spawnPoint.origin.v);
|
||||||
|
|
||||||
|
// GLTF default direction is +Y up
|
||||||
|
Eigen::Vector3f defaultDirection(0.0f, 1.0f, 0.0f);
|
||||||
|
Eigen::Affine3f affineTransform(nodeMatrix);
|
||||||
|
Eigen::Matrix3f rotationMatrix = affineTransform.rotation();
|
||||||
|
Eigen::Vector3f outputDirection = rotationMatrix * defaultDirection;
|
||||||
|
outputDirection.normalize();
|
||||||
|
spawnPoint.forward.x = outputDirection.x();
|
||||||
|
spawnPoint.forward.y = outputDirection.y();
|
||||||
|
spawnPoint.forward.z = outputDirection.z();
|
||||||
|
RhcToLhcCoordinates(spawnPoint.forward.v);
|
||||||
|
|
||||||
|
m_bsp->spawnpoints.emplace_back(spawnPoint);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool addNodeToBSP(const JsonRoot& jRoot, const gltf::JsonNode& node)
|
||||||
|
{
|
||||||
|
if (m_is_world_gfx && node.extensions && node.extensions->KHR_lights_punctual)
|
||||||
|
return addLightNode(node);
|
||||||
|
|
||||||
|
if (node.extras)
|
||||||
|
{
|
||||||
|
if (m_is_world_gfx && node.extras->xmodel)
|
||||||
|
return addXModelNode(node);
|
||||||
|
|
||||||
|
if (m_is_world_gfx && node.extras->spawnpoint)
|
||||||
|
return addSpawnPointNode(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.mesh)
|
||||||
|
return addMeshNode(jRoot, node);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<unsigned> GetRootNodes(const JsonRoot& jRoot)
|
static std::vector<unsigned> GetRootNodes(const JsonRoot& jRoot)
|
||||||
|
|
||||||
{
|
{
|
||||||
if (!jRoot.nodes || jRoot.nodes->empty())
|
if (!jRoot.nodes || jRoot.nodes->empty())
|
||||||
return {};
|
return {};
|
||||||
@@ -488,14 +558,16 @@ namespace
|
|||||||
|
|
||||||
void LoadLights(const JsonRoot& jRoot)
|
void LoadLights(const JsonRoot& jRoot)
|
||||||
{
|
{
|
||||||
|
if (!m_is_world_gfx)
|
||||||
|
return;
|
||||||
if (!jRoot.extensions)
|
if (!jRoot.extensions)
|
||||||
return;
|
return;
|
||||||
if (!jRoot.extensions->KHR_lights_punctual)
|
if (!jRoot.extensions->KHR_lights_punctual)
|
||||||
return;
|
return;
|
||||||
if (!jRoot.extensions->KHR_lights_punctual->lights)
|
if (!jRoot.extensions->KHR_lights_punctual->lights)
|
||||||
return;
|
return;
|
||||||
const std::vector<JsonPunctualLight>& jsLightArray = jRoot.extensions->KHR_lights_punctual->lights.value();
|
|
||||||
|
|
||||||
|
const std::vector<JsonPunctualLight>& jsLightArray = jRoot.extensions->KHR_lights_punctual->lights.value();
|
||||||
m_bsp->lights.reserve(jsLightArray.size());
|
m_bsp->lights.reserve(jsLightArray.size());
|
||||||
for (const JsonPunctualLight& jsLight : jsLightArray)
|
for (const JsonPunctualLight& jsLight : jsLightArray)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <format>
|
#include <format>
|
||||||
|
#include <numbers>
|
||||||
|
|
||||||
namespace BSP
|
namespace BSP
|
||||||
{
|
{
|
||||||
@@ -123,6 +124,28 @@ namespace BSP
|
|||||||
axis[2].z = cosZ * cosX;
|
axis[2].z = cosZ * cosX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vec3_t BSPUtil::convertForwardVectorToViewAngles(vec3_t& forwardVec)
|
||||||
|
{
|
||||||
|
vec3_t viewAngles;
|
||||||
|
|
||||||
|
float xAndYDist = sqrtf((forwardVec.x * forwardVec.x) + (forwardVec.y * forwardVec.y));
|
||||||
|
float atanXRadians = atan2f(forwardVec.z, xAndYDist);
|
||||||
|
float atanXDegrees = atanXRadians * (-180.0f / std::numbers::pi_v<float>);
|
||||||
|
if (atanXDegrees < 0.0f)
|
||||||
|
atanXDegrees += 360.0f;
|
||||||
|
viewAngles.x = atanXDegrees;
|
||||||
|
|
||||||
|
float atanYRadians = atan2f(forwardVec.y, forwardVec.x);
|
||||||
|
float atanYDegrees = atanYRadians * (180.0f / std::numbers::pi_v<float>);
|
||||||
|
if (atanYDegrees < 0.0f)
|
||||||
|
atanYDegrees += 360.0f;
|
||||||
|
viewAngles.y = atanYDegrees;
|
||||||
|
|
||||||
|
viewAngles.z = 0.0f;
|
||||||
|
|
||||||
|
return viewAngles;
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
||||||
@@ -161,7 +184,7 @@ namespace BSP
|
|||||||
|
|
||||||
std::string BSPUtil::convertVec3ToString(vec3_t& vec)
|
std::string BSPUtil::convertVec3ToString(vec3_t& vec)
|
||||||
{
|
{
|
||||||
std::string result = std::format("{} {} {}", vec.x, vec.y, vec.z);
|
std::string result = std::format("{} {} {}", roundf(vec.x), roundf(vec.y), roundf(vec.z));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ namespace BSP
|
|||||||
static size_t allignBy128(size_t size);
|
static size_t allignBy128(size_t size);
|
||||||
static float distBetweenPoints(vec3_t& p1, vec3_t& p2);
|
static float distBetweenPoints(vec3_t& p1, vec3_t& p2);
|
||||||
static void convertAnglesToAxis(vec3_t* angles, vec3_t* axis);
|
static void convertAnglesToAxis(vec3_t* angles, vec3_t* axis);
|
||||||
|
static vec3_t convertForwardVectorToViewAngles(vec3_t& forwardVec);
|
||||||
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);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ using namespace nlohmann;
|
|||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
bool parseMapEntsJSON(json& entArrayJs, std::string& entityString)
|
bool addJSONToEntString(json& entArrayJs, std::string& entityString)
|
||||||
{
|
{
|
||||||
for (size_t entIdx = 0; entIdx < entArrayJs.size(); entIdx++)
|
for (size_t entIdx = 0; entIdx < entArrayJs.size(); entIdx++)
|
||||||
{
|
{
|
||||||
@@ -39,28 +39,99 @@ namespace
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void parseSpawnpointJSON(json& entArrayJs, std::string& entityString, const char* spawnpointNames[], size_t nameCount)
|
inline const std::vector<const char*> DEFENDER_SPAWN_POINT_NAMES = {"mp_ctf_spawn_allies",
|
||||||
{
|
"mp_ctf_spawn_allies_start",
|
||||||
for (auto& element : entArrayJs.items())
|
"mp_sd_spawn_defender",
|
||||||
{
|
"mp_dom_spawn_allies_start",
|
||||||
std::string origin;
|
"mp_dem_spawn_defender_start",
|
||||||
std::string angles;
|
"mp_dem_spawn_defenderOT_start",
|
||||||
auto& entity = element.value();
|
"mp_dem_spawn_defender",
|
||||||
entity.at("origin").get_to(origin);
|
"mp_tdm_spawn_allies_start",
|
||||||
entity.at("angles").get_to(angles);
|
"mp_tdm_spawn_team1_start",
|
||||||
|
"mp_tdm_spawn_team2_start",
|
||||||
|
"mp_tdm_spawn_team3_start"};
|
||||||
|
|
||||||
for (size_t nameIdx = 0; nameIdx < nameCount; nameIdx++)
|
inline const std::vector<const char*> ATTACKER_SPAWN_POINT_NAMES = {"mp_ctf_spawn_axis",
|
||||||
|
"mp_ctf_spawn_axis_start",
|
||||||
|
"mp_sd_spawn_attacker",
|
||||||
|
"mp_dom_spawn_axis_start",
|
||||||
|
"mp_dem_spawn_attacker_start",
|
||||||
|
"mp_dem_spawn_attackerOT_start",
|
||||||
|
"mp_dem_spawn_attacker",
|
||||||
|
"mp_tdm_spawn_axis_start",
|
||||||
|
"mp_tdm_spawn_team4_start",
|
||||||
|
"mp_tdm_spawn_team5_start",
|
||||||
|
"mp_tdm_spawn_team6_start"};
|
||||||
|
|
||||||
|
inline const std::vector<const char*> FFA_SPAWN_POINT_NAMES = {"mp_tdm_spawn", "mp_dm_spawn", "mp_dom_spawn"};
|
||||||
|
|
||||||
|
void addSpawnsToEntString(BSP::BSPData* bsp, std::string& entityString)
|
||||||
|
{
|
||||||
|
if (bsp->spawnpoints.size() == 0)
|
||||||
|
{
|
||||||
|
BSP::BSPSpawnPoint defaultSpawnPoint;
|
||||||
|
defaultSpawnPoint.origin.x = 0.0f;
|
||||||
|
defaultSpawnPoint.origin.y = 0.0f;
|
||||||
|
defaultSpawnPoint.origin.z = 0.0f;
|
||||||
|
defaultSpawnPoint.forward.x = 1.0f;
|
||||||
|
defaultSpawnPoint.forward.y = 0.0f;
|
||||||
|
defaultSpawnPoint.forward.z = 0.0f;
|
||||||
|
defaultSpawnPoint.type = BSP::BSPSpawnPointType::SPAWNPOINT_TYPE_DEFENDER;
|
||||||
|
bsp->spawnpoints.emplace_back(defaultSpawnPoint);
|
||||||
|
defaultSpawnPoint.type = BSP::BSPSpawnPointType::SPAWNPOINT_TYPE_ATTACKER;
|
||||||
|
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 attackerNameCount = std::extent<decltype(ATTACKER_SPAWN_POINT_NAMES)>::value;
|
||||||
|
size_t ffaNameCount = std::extent<decltype(FFA_SPAWN_POINT_NAMES)>::value;
|
||||||
|
|
||||||
|
for (auto& spawnPoint : bsp->spawnpoints)
|
||||||
|
{
|
||||||
|
vec3_t origin = spawnPoint.origin;
|
||||||
|
vec3_t angles = BSP::BSPUtil::convertForwardVectorToViewAngles(spawnPoint.forward);
|
||||||
|
|
||||||
|
std::string originStr = std::format("\"origin\" \"{}\"\n", BSP::BSPUtil::convertVec3ToString(origin));
|
||||||
|
std::string anglesStr = std::format("\"angles\" \"{}\"\n", BSP::BSPUtil::convertVec3ToString(angles));
|
||||||
|
|
||||||
|
const std::vector<const char*>* spawnPointList;
|
||||||
|
if (spawnPoint.type == BSP::BSPSpawnPointType::SPAWNPOINT_TYPE_DEFENDER)
|
||||||
|
spawnPointList = &DEFENDER_SPAWN_POINT_NAMES;
|
||||||
|
else if (spawnPoint.type == BSP::BSPSpawnPointType::SPAWNPOINT_TYPE_ATTACKER)
|
||||||
|
spawnPointList = &ATTACKER_SPAWN_POINT_NAMES;
|
||||||
|
else // SPAWNPOINT_TYPE_ALL
|
||||||
|
spawnPointList = &FFA_SPAWN_POINT_NAMES;
|
||||||
|
|
||||||
|
for (const char* spawnName : *spawnPointList)
|
||||||
{
|
{
|
||||||
entityString.append("{\n");
|
entityString.append("{\n");
|
||||||
entityString.append(std::format("\"origin\" \"{}\"\n", origin));
|
entityString.append(originStr);
|
||||||
entityString.append(std::format("\"angles\" \"{}\"\n", angles));
|
entityString.append(anglesStr);
|
||||||
entityString.append(std::format("\"classname\" \"{}\"\n", spawnpointNames[nameIdx]));
|
entityString.append(std::format("\"classname\" \"{}\"\n", spawnName));
|
||||||
entityString.append("}\n");
|
entityString.append("}\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string loadMapEnts() {}
|
constexpr const char* DEFAULT_MAP_ENTS_STRING = R"({
|
||||||
|
"entities": [
|
||||||
|
{
|
||||||
|
"classname": "worldspawn"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"angles": "0 0 0",
|
||||||
|
"classname": "info_player_start",
|
||||||
|
"origin": "0 0 0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"angles": "0 0 0",
|
||||||
|
"classname": "mp_global_intermission",
|
||||||
|
"origin": "0 0 0"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})";
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace BSP
|
namespace BSP
|
||||||
@@ -83,35 +154,17 @@ namespace BSP
|
|||||||
if (!entFile.IsOpen())
|
if (!entFile.IsOpen())
|
||||||
{
|
{
|
||||||
con::warn("Can't find entity file {}, using default entities instead", entityFilePath);
|
con::warn("Can't find entity file {}, using default entities instead", entityFilePath);
|
||||||
entJs = json::parse(BSPLinkingConstants::DEFAULT_MAP_ENTS_STRING);
|
entJs = json::parse(DEFAULT_MAP_ENTS_STRING);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
entJs = json::parse(*entFile.m_stream);
|
entJs = json::parse(*entFile.m_stream);
|
||||||
}
|
}
|
||||||
std::string entityString;
|
std::string entityString;
|
||||||
if (!parseMapEntsJSON(entJs["entities"], entityString))
|
if (!addJSONToEntString(entJs["entities"], entityString))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
json spawnJs;
|
addSpawnsToEntString(bsp, entityString);
|
||||||
std::string spawnFileName = "spawns.json";
|
|
||||||
std::string spawnFilePath = BSPUtil::getFileNameForBSPAsset(spawnFileName);
|
|
||||||
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* mapEnts = m_memory.Alloc<MapEnts>();
|
||||||
mapEnts->name = m_memory.Dup(bsp->bspName.c_str());
|
mapEnts->name = m_memory.Dup(bsp->bspName.c_str());
|
||||||
@@ -119,7 +172,7 @@ namespace BSP
|
|||||||
mapEnts->entityString = m_memory.Dup(entityString.c_str());
|
mapEnts->entityString = m_memory.Dup(entityString.c_str());
|
||||||
mapEnts->numEntityChars = static_cast<int>(entityString.length() + 1); // numEntityChars includes the null character
|
mapEnts->numEntityChars = static_cast<int>(entityString.length() + 1); // numEntityChars includes the null character
|
||||||
|
|
||||||
// don't need these
|
// don't need these, unused by the game
|
||||||
mapEnts->trigger.count = 0;
|
mapEnts->trigger.count = 0;
|
||||||
mapEnts->trigger.models = nullptr;
|
mapEnts->trigger.models = nullptr;
|
||||||
mapEnts->trigger.hullCount = 0;
|
mapEnts->trigger.hullCount = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user