27#include <SDL3/SDL_filesystem.h>
28#include <SDL3/SDL_log.h>
30#include <assimp/Importer.hpp>
31#include <assimp/postprocess.h>
32#include <assimp/scene.h>
105 const char*
const base = SDL_GetBasePath();
106 return std::string(base ? base :
"") +
"assets/" +
kMapAsset.filename;
162 if (node ==
nullptr) {
166 for (
int i = 0; i < depth; i++) {
170 std::cout << node->mName.C_Str() <<
"\n";
172 for (
unsigned int i = 0; i < node->mNumChildren; i++) {
179 if (metadata ==
nullptr) {
183 for (
unsigned int i = 0; i < metadata->mNumProperties; i++) {
184 if (key == metadata->mKeys[i].C_Str()) {
185 return metadata->mValues[i].mData;
195inline float getMetadataFloat(
const aiMetadata* metadata,
const std::string& key,
float fallback)
197 if (metadata ==
nullptr)
199 for (
unsigned int i = 0; i < metadata->mNumProperties; i++) {
200 if (key != metadata->mKeys[i].C_Str())
202 const aiMetadataEntry& entry = metadata->mValues[i];
203 switch (entry.mType) {
205 return *
static_cast<float*
>(entry.mData);
207 return static_cast<float>(*
static_cast<double*
>(entry.mData));
209 return static_cast<float>(*
static_cast<int32_t*
>(entry.mData));
232 SDL_Log(
"[%s] WARNING: map collision load failed (%s) — falling back to testWorld()", tag,
kMapAsset.filename);
236 SDL_Log(
"[%s] map collision loaded (%s): %zu planes, %zu boxes, %zu brushes, %zu cylinders, %zu spheres, "
248 Assimp::Importer importer;
249 const aiScene* scene = importer.ReadFile(path, 0 );
251 if (scene ==
nullptr)
254 std::function<void(
const aiNode*,
int)> traverse = [&](
const aiNode* node,
int depth) {
255 if (node ==
nullptr) {
259 if (node->mMetaData) {
261 if (entity_type_ptr !=
nullptr) {
262 const int32_t entity_type = *
static_cast<int32_t*
>(entity_type_ptr);
263 const char*
const nodeName = node->mName.C_Str();
264 switch (entity_type) {
267 const aiMatrix4x4& t = node->mTransformation;
268 glm::vec3 pos = glm::vec3(t.a4, t.b4, t.c4) *
kMapAsset.loadScale;
273 const glm::vec3 fwd{-t.a3, -t.b3, -t.c3};
275 if (std::abs(fwd.x) > 1e-4f || std::abs(fwd.z) > 1e-4f) {
276 yaw = std::atan2(fwd.x, fwd.z);
284 if (weapon_type_ptr ==
nullptr) {
285 SDL_Log(
"Weapon spawner '%s' missing 'weapon_type' metadata — skipping", nodeName);
288 const aiMatrix4x4& t = node->mTransformation;
290 glm::vec3 pos = glm::vec3(t.a4, t.b4, t.c4) *
kMapAsset.loadScale;
297 if (powerup_type_ptr ==
nullptr) {
298 SDL_Log(
"Powerup spawner '%s' missing 'powerup_type' metadata — skipping", nodeName);
301 const aiMatrix4x4& t = node->mTransformation;
303 glm::vec3 pos = glm::vec3(t.a4, t.b4, t.c4) *
kMapAsset.loadScale;
309 const aiMatrix4x4& t = node->mTransformation;
310 glm::vec3 pos = glm::vec3(t.a4, t.b4, t.c4) *
kMapAsset.loadScale;
324 const aiMatrix4x4& t = node->mTransformation;
325 glm::vec3 pos = glm::vec3(t.a4, t.b4, t.c4) *
kMapAsset.loadScale;
336 const aiMatrix4x4& t = node->mTransformation;
337 glm::vec3 pos = glm::vec3(t.a4, t.b4, t.c4) *
kMapAsset.loadScale;
342 SDL_Log(
"Unknown entity_type %d on node '%s' — skipping", entity_type, nodeName);
348 for (
unsigned int i = 0; i < node->mNumChildren; i++) {
349 traverse(node->mChildren[i], depth + 1);
353 traverse(scene->mRootNode, 0);
355 std::ofstream out_file(
"spawn_points.txt");
357 if (out_file.is_open()) {
358 out_file <<
"Spawn Points (" <<
spawnPoints_.size() <<
")\n";
363 out_file << i <<
": (" << p.x <<
", " << p.y <<
", " << p.z <<
") yaw=" <<
spawnPoints_[i].yaw <<
"\n";
Static asset loading and render-default metadata.
const AssetDefinition kMapAsset
Definition AssetCatalog.hpp:27
Load collision geometry (and optionally visual data) from a map GLB file.
PowerupType
Definition PowerupSpawner.hpp:8
Powerup state information.
WeaponType
Weapon type — determines tracer style, damage, sound, and impact effects.
Definition WeaponState.hpp:12
Definition MapConfig.hpp:39
bool loadConfiguredMap(physics::MapCollisionData &out, const char *tag)
Load the configured map's collision into out.
Definition MapConfig.hpp:226
constexpr bool k_useVhacd
Run V-HACD convex decomposition on non-convex prop meshes?
Definition MapConfig.hpp:81
float getMetadataFloat(const aiMetadata *metadata, const std::string &key, float fallback)
Read a numeric custom property as float.
Definition MapConfig.hpp:195
void traverseNodeTree(const aiNode *node, int depth=0)
Definition MapConfig.hpp:160
std::string mapAbsolutePath()
Resolve the absolute path of the configured map file.
Definition MapConfig.hpp:103
std::vector< PowerupSpawner > powerupSpawner_
Definition MapConfig.hpp:129
void * getMetadataValue(const aiMetadata *metadata, const std::string &key)
Definition MapConfig.hpp:177
constexpr bool k_separatedCollisionMap
Does this map use SEPARATED collision and visual meshes?
Definition MapConfig.hpp:53
physics::MapLoadOptions makeLoadOptions()
Build the MapLoadOptions used by both client and server.
Definition MapConfig.hpp:88
std::vector< KillzoneSpawner > killzoneSpawner_
Definition MapConfig.hpp:158
constexpr const char * k_collisionPattern
Substring that identifies collision-only nodes in separated mode.
Definition MapConfig.hpp:57
std::vector< SpawnPoint > spawnPoints_
Definition MapConfig.hpp:115
std::vector< HealthPackSpawner > healthPackSpawner_
Definition MapConfig.hpp:135
std::vector< JumpPadSpawner > jumpPadSpawner_
Definition MapConfig.hpp:148
std::vector< WeaponSpawner > weaponSpawner_
Definition MapConfig.hpp:122
bool loadMapCollision(const std::string &path, MapCollisionData &out, const MapLoadOptions &opts)
API.
Definition MapLoader.cpp:1210
Definition MapConfig.hpp:132
glm::vec3 pos
Definition MapConfig.hpp:133
Jump pad authored in Blender (entity_type = 3).
Definition MapConfig.hpp:143
glm::vec3 pos
Definition MapConfig.hpp:144
glm::vec3 velocity
Definition MapConfig.hpp:145
glm::vec3 halfExtents
Definition MapConfig.hpp:146
Killzone authored in Blender (entity_type = 4).
Definition MapConfig.hpp:154
glm::vec3 pos
Definition MapConfig.hpp:155
glm::vec3 halfExtents
Definition MapConfig.hpp:156
Definition MapConfig.hpp:125
glm::vec3 pos
Definition MapConfig.hpp:127
PowerupType type
Definition MapConfig.hpp:126
A player spawn point: world position plus an authored facing yaw.
Definition MapConfig.hpp:111
float yaw
Facing direction in radians (matches InputSnapshot.yaw: 0 = +Z, atan2(fwd.x, fwd.z)).
Definition MapConfig.hpp:113
glm::vec3 pos
Definition MapConfig.hpp:112
Definition MapConfig.hpp:118
glm::vec3 pos
Definition MapConfig.hpp:120
WeaponType type
Definition MapConfig.hpp:119
Collision data.
Definition MapLoader.hpp:36
std::vector< WorldTriMesh > triMeshes
Definition MapLoader.hpp:42
std::vector< WorldAABB > boxes
Definition MapLoader.hpp:38
std::vector< WorldSphere > spheres
Definition MapLoader.hpp:41
std::vector< WorldBrush > brushes
Definition MapLoader.hpp:39
std::vector< WorldCylinder > cylinders
Definition MapLoader.hpp:40
std::vector< Plane > planes
Definition MapLoader.hpp:37
Load options.
Definition MapLoader.hpp:66
bool allMeshesAreCollision
When true, every mesh in the file is treated as both visual and collision geometry.
Definition MapLoader.hpp:79
std::string collisionCollection
Name of the Blender collection (= Assimp parent node) whose children are collision geometry.
Definition MapLoader.hpp:74
float scale
Uniform scale applied to every vertex position (e.g. 39.37 for m → in).
Definition MapLoader.hpp:68
bool addFloorPlane
When true, an infinite floor plane is added at the lowest Y coordinate found across all collision geo...
Definition MapLoader.hpp:84