diff options
| author | MegaMech <MegaMech@users.noreply.github.com> | 2025-12-07 13:14:45 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-12-07 13:14:45 -0700 |
| commit | 65853330926fa5c77ad75effab8c479ba1d96952 (patch) | |
| tree | b2bd8f865401a8d7c4ce9f78b94f34bfb778dbaf /src/engine/editor/SceneManager.cpp | |
| parent | 02ad54ca72f5baf4614cb9b7c30f8dd780764d90 (diff) | |
Camera Refactor --> Adds Track Tour Camera (#568)
* Impl SpawnParams
* Added json submodule
* Update json
* Update
* Works
* Remove comment
* Works refactor
* Snowman and thwomp working
* Impl hot air balloon
* More progress
* All OObjects are done
* cleanup
* Refactor 2Dpath to normal path
* Update nlohmann json & fix compile
* Rest of actors
* MORE CHANGES
* Finish actors
* Done PR, some fix to collision viewer
* Impl falling rocks
* Add const
* wip editor refactor
* Property work
* continue
* Overridable editor properties
* Actor saving/loading works now
* Fix light alignment
* Clarification
* Impl penguin
* params impl signs
* properties impl falling rock
* More property impls
* impl air balloon
* Add spawnParams to OObject Translate
* Snowman translate better
* impl hedgehog properly
* properties impl trophy
* thwomp progress
* Finish impl properties
* Fix compile
* Fix cursor collisions
* Move registered actors
* Rename pathPoint XYZ to xyz
* Fix editor pause bug
* Clean up
* Review comments
* Remove SpawnParams struct from actor classes
* Rename
* Player Label First Iteration
* Work now
* Working 3d text
* Fix boo bug
* Finish AText actor
* Fix spawnparams compile
* Register AText
* Finish Text Actor
* Fix thwomp interpolation
* Fix compile
* Fix crab and hedgehog
* Fix loading flagpole
* Fix Hot Air Balloon
* Turn zbuffer on for AText
* Update
* Camera Refactor
* Camera Refactor Complete
* Place Lookbehind behind a CVar
* Make Tour CVar
* Fix Tour Camera Billboarding
* micro optimization
* Impl tour cam in imgui editor and add to scenefile
* As per review
* Revert cleanWorld change as per review
* Cleanup SceneManager
* Func rename
* Proper enabling of freecam and wip zoom fix
* Couple fix
* Fix credits
* Fix podium ceremony
* Stop music on reset & label new play sequence func
* Rename func_800C8EF8 to play_sequence2
* Rename func_800CA414 to play_sequences
* Fix compile
* Label play_sequences
* Clean up
* Verify lakitu access
* Renames
* Fix tour enable logic
* Add Audio
* tour camera impl ending transition
* As per review
* Fix linux compile, probably
* Update TourCamera.cpp
* Update TourCamera.cpp
* Update TrackProperties.cpp
* Update TrackProperties.cpp
* Update Game.cpp
* Update SceneManager.cpp
* Update camera.c
* Update render_objects.h
* Update render_objects.h
* Update code_80057C60.h
* fixing compile
* addition
---------
Co-authored-by: MegaMech <7255464+MegaMech@users.noreply.github.com>
Diffstat (limited to 'src/engine/editor/SceneManager.cpp')
| -rw-r--r-- | src/engine/editor/SceneManager.cpp | 303 |
1 files changed, 195 insertions, 108 deletions
diff --git a/src/engine/editor/SceneManager.cpp b/src/engine/editor/SceneManager.cpp index f34b18adb..90a33f48f 100644 --- a/src/engine/editor/SceneManager.cpp +++ b/src/engine/editor/SceneManager.cpp @@ -1,4 +1,5 @@ #include "SceneManager.h" + #include "port/Game.h" #include "engine/CoreMath.h" #include "World.h" @@ -19,7 +20,7 @@ #include "engine/objects/Object.h" #include "engine/objects/Thwomp.h" #include "engine/objects/Snowman.h" -#include <iostream> +#include "engine/cameras/TourCamera.h" extern "C" { #include "common_structs.h" @@ -28,112 +29,98 @@ extern "C" { } namespace Editor { - std::shared_ptr<Ship::Archive> CurrentArchive; std::string SceneFile = ""; void SaveLevel() { - auto props = gWorldInstance.GetCurrentCourse()->Props; + if ((!CurrentArchive) || (SceneFile.empty())) { + SPDLOG_INFO("[SceneManager] [SaveLevel] Could not save scene file, SceneFile or CurrentArchive not set"); + return; + } + nlohmann::json data; - if ((CurrentArchive) && (!SceneFile.empty())) { - nlohmann::json data; - - data["Props"] = props.to_json(); + /** + * Save track properties, static mesh actors, actors, and tour camera + */ + data["Props"] = gWorldInstance.GetCurrentCourse()->Props.to_json(); - nlohmann::json staticMesh; + nlohmann::json staticMesh; + SaveStaticMeshActors(staticMesh); + data["StaticMeshActors"] = staticMesh; - for (const auto& mesh : gWorldInstance.StaticMeshActors) { - staticMesh.push_back(mesh->to_json()); - } - data["StaticMeshActors"] = staticMesh; - nlohmann::json actors; + nlohmann::json actors; + SaveActors(actors); + data["Actors"] = actors; - SaveActors(actors); - data["Actors"] = actors; - - try { - auto dat = data.dump(2); - std::vector<uint8_t> stringify; - stringify.assign(dat.begin(), dat.end()); + if (gWorldInstance.GetCurrentCourse()->TourShots.size() != 0) { + nlohmann::json tour; + SaveTour(tour); + data["Tour"] = tour; + } - bool wrote = GameEngine::Instance->context->GetResourceManager()->GetArchiveManager()->WriteFile(CurrentArchive, SceneFile, stringify); - if (wrote) { - // Tell the cache this needs to be reloaded - auto resource = GameEngine::Instance->context->GetResourceManager()->GetCachedResource(SceneFile); - if (resource) { - resource->Dirty(); - } - } else { - printf("[SceneManager::SaveLevel] Failed to write scene file!\n"); + /** + * Write data to file + */ + try { + std::string jsonStr = data.dump(2); + std::vector<uint8_t> bytes; // Turn the str into raw data + bytes.assign(jsonStr.begin(), jsonStr.end()); + + // Write file to disk + bool wrote = GameEngine::Instance->context->GetResourceManager()->GetArchiveManager()->WriteFile(CurrentArchive, SceneFile, bytes); + if (wrote) { + // Tell the cache this file needs to be reloaded + auto resource = GameEngine::Instance->context->GetResourceManager()->GetCachedResource(SceneFile); + if (resource) { + resource->Dirty(); } - } catch (const nlohmann::json::exception& e) { - printf("[SceneManager::SaveLevel]\n JSON error during dump: %s\n", e.what()); + } else { + SPDLOG_INFO("[SceneManager] [SaveLevel] Failed to write scene file!"); } - } else { - printf("Could not save scene file, SceneFile or CurrentArchive not set\n"); + } catch (const nlohmann::json::exception& e) { + SPDLOG_INFO("[SceneManager] [SaveLevel] JSON error during dump: {}", e.what()); } } - /** Do not use gWorldInstance.CurrentCourse during loading! The current track is not guaranteed! **/ void LoadLevel(Course* course, std::string sceneFile) { SceneFile = sceneFile; - if ((nullptr != course) && (nullptr != course->RootArchive)) { - auto initData = std::make_shared<Ship::ResourceInitData>(); - initData->Parent = course->RootArchive; - initData->Format = RESOURCE_FORMAT_BINARY; - initData->ByteOrder = Ship::Endianness::Little; - initData->Type = static_cast<uint32_t>(Ship::ResourceType::Json); - initData->ResourceVersion = 0; - - nlohmann::json data = std::static_pointer_cast<Ship::Json>( - GameEngine::Instance->context->GetResourceManager()->LoadResource(sceneFile, true, initData))->Data; - - if (data.is_null() || data.empty()) { - return; - } + if ((nullptr == course) || (nullptr == course->RootArchive)) { + SPDLOG_INFO("[SceneManager] [LoadLevel] Failed to load scenefile, course or rootarchive were null"); + return; + } - // Load the Props (deserialize it) - if (data.contains("Props")) { - auto& propsJson = data["Props"]; - try { - course->Props.from_json(propsJson); - } catch(const std::exception& e) { - std::cerr << "SceneManager::LoadLevel() Error parsing track properties: " << e.what() << std::endl; - std::cerr << " Is your scene.json file out of date?" << std::endl; - } - } else { - std::cerr << "Props data not found in the JSON file!" << std::endl; - } + /* + * Manually loading a custom asset file (scene.json) with no extractor class means that + * the init data needs to be manually populated + */ + auto initData = std::make_shared<Ship::ResourceInitData>(); + initData->Parent = course->RootArchive; + initData->Format = RESOURCE_FORMAT_BINARY; + initData->ByteOrder = Ship::Endianness::Little; + initData->Type = static_cast<uint32_t>(Ship::ResourceType::Json); + initData->ResourceVersion = 0; + + // Load the scene file and return the json data + nlohmann::json data = std::static_pointer_cast<Ship::Json>( + GameEngine::Instance->context->GetResourceManager()->LoadResource(sceneFile, true, initData))->Data; + + // Check that the data is valid + if (data.is_null() || !data.is_object() || data.empty()) { + SPDLOG_INFO("[SceneManager] [LoadLevel] Scenefile corrupted or contained no data"); + return; + } - /** Populate Track SpawnParams for spawning actors **/ - if (data.contains("Actors")) { - auto & actorsJson = data["Actors"]; - course->SpawnList.clear(); - for (const auto& actor : actorsJson) { - SpawnParams params; - params.from_json(actor); //<SpawnParams>(); - if (!params.Name.empty()) { - course->SpawnList.push_back(params); - } - } - SPDLOG_INFO("[SceneManager] Loaded Scene File!"); - } + SPDLOG_INFO("[SceneManager] [LoadLevel] Loading track scenefile..."); - // Load the Actors (deserialize them) - if (data.contains("StaticMeshActors")) { - auto& actorsJson = data["StaticMeshActors"]; - gWorldInstance.StaticMeshActors.clear(); // Clear existing actors, if any - - for (const auto& actorJson : actorsJson) { - Load_AddStaticMeshActor(actorJson); - } - } else { - SPDLOG_INFO("[SceneManager::LoadLevel] [scene.json] This track contains no StaticMeshActors!"); - } - } + // Load the Props, and populate actors + LoadProps(course, data); + LoadActors(course, data); + LoadStaticMeshActors(course, data); + LoadTour(course, data); + SPDLOG_INFO("[SceneManager] [LoadLevel] Scene File Loaded!"); } void Load_AddStaticMeshActor(const nlohmann::json& actorJson) { @@ -150,31 +137,46 @@ namespace Editor { SceneFile = sceneFile; } + // Called from ContentBrowser.cpp void LoadMinimap(Course* course, std::string filePath) { - printf("LOADING MINIMAP %s\n", filePath.c_str()); - if ((nullptr != course) && (nullptr != course->RootArchive)) { - auto initData = std::make_shared<Ship::ResourceInitData>(); - initData->Parent = course->RootArchive; - initData->Format = RESOURCE_FORMAT_BINARY; - initData->ByteOrder = Ship::Endianness::Little; - initData->Type = static_cast<uint32_t>(MK64::ResourceType::Minimap); - initData->ResourceVersion = 0; - - std::shared_ptr<MK64::Minimap> ptr = std::static_pointer_cast<MK64::Minimap>( - GameEngine::Instance->context->GetResourceManager()->LoadResource(filePath, true, initData)); - - if (ptr) { - printf("LOADED MINIMAP!\n"); - MK64::MinimapTexture texture = ptr->Texture; - course->Props.Minimap.Texture = (const char*)texture.Data; - course->Props.Minimap.Width = texture.Width; - course->Props.Minimap.Height = texture.Height; - } else { // Fallback - course->Props.Minimap.Texture = minimap_mario_raceway; - course->Props.Minimap.Width = ResourceGetTexWidthByName(course->Props.Minimap.Texture); - course->Props.Minimap.Height = ResourceGetTexHeightByName(course->Props.Minimap.Texture); - } + SPDLOG_INFO(" Loading {} minimap...", filePath); + if (nullptr == course->RootArchive) { + SPDLOG_INFO("[SceneManager] [LoadMinimap] Root archive is nullptr"); + SetDefaultMinimap(course); + return; } + + /* + * Manually loading a custom asset file with no extractor class means that + * the init data needs to be manually populated + */ + auto initData = std::make_shared<Ship::ResourceInitData>(); + initData->Parent = course->RootArchive; + initData->Format = RESOURCE_FORMAT_BINARY; + initData->ByteOrder = Ship::Endianness::Little; + initData->Type = static_cast<uint32_t>(MK64::ResourceType::Minimap); + initData->ResourceVersion = 0; + + std::shared_ptr<MK64::Minimap> ptr = std::static_pointer_cast<MK64::Minimap>( + GameEngine::Instance->context->GetResourceManager()->LoadResource(filePath, true, initData)); + + if (ptr) { + SPDLOG_INFO(" Minimap Loaded!"); + MK64::MinimapTexture texture = ptr->Texture; + course->Props.Minimap.Texture = (const char*)texture.Data; + course->Props.Minimap.Width = texture.Width; + course->Props.Minimap.Height = texture.Height; + } else { // Fallback + SetDefaultMinimap(course); + } + } + + // Sets the default minimap if none has been set + void SetDefaultMinimap(Course* course) { + course->Props.Minimap.Texture = minimap_mario_raceway; + course->Props.Minimap.Width = ResourceGetTexWidthByName(course->Props.Minimap.Texture); + course->Props.Minimap.Height = ResourceGetTexHeightByName(course->Props.Minimap.Texture); + SPDLOG_INFO(" No minimap found! Falling back to default minimap"); } void SaveActors(nlohmann::json& actorList) { @@ -243,4 +245,89 @@ namespace Editor { } } } + + void SaveStaticMeshActors(nlohmann::json& actorList) { + for (const auto& mesh : gWorldInstance.StaticMeshActors) { + actorList.push_back(mesh->to_json()); + } + } + + void SaveTour(nlohmann::json& tour) { + tour["Enabled"] = gWorldInstance.GetCurrentCourse()->bTourEnabled; + + // Camera shots + tour["Shots"] = nlohmann::json::array(); + for (const auto& shot : gWorldInstance.GetCurrentCourse()->TourShots) { + tour["Shots"].push_back(ToJson(shot)); + } + } + + void LoadProps(Course* course, nlohmann::json& data) { + if (!data.contains("Props") || !data["Props"].is_object()) { + SPDLOG_INFO("Track is missing props data. Is the scene.json file corrupt?"); + return; + } + + try { + course->Props.from_json(data["Props"]); + } catch(const std::exception& e) { + std::cerr << " Error parsing track properties: " << e.what() << std::endl; + std::cerr << " Is your scene.json file out of date?" << std::endl; + } + } + + void LoadActors(Course* course, nlohmann::json& data) { + if (!data.contains("Actors") || !data["Actors"].is_object()) { + SPDLOG_INFO(" This track contains no actors"); + return; + } + + course->SpawnList.clear(); // Clear existing actors, if any + + for (const auto& actor : data["Actors"]) { + SpawnParams params; + params.from_json(actor); //<SpawnParams>(); + if (!params.Name.empty()) { + course->SpawnList.push_back(params); + } + } + } + + void LoadStaticMeshActors(Course* course, nlohmann::json& data) { + if (!data.contains("StaticMeshActors") || !data["StaticMeshActors"].is_object()) { + SPDLOG_INFO(" This track contains no StaticMeshActors!"); + return; + } + + gWorldInstance.StaticMeshActors.clear(); // Clear existing actors, if any + + for (const auto& actorJson : data["StaticMeshActors"]) { + Load_AddStaticMeshActor(actorJson); + } + } + + void LoadTour(Course* course, nlohmann::json& data) { + if (!data.contains("Tour") || !data["Tour"].is_object()) { + SPDLOG_INFO(" This track does not contain a camera tour"); + return; + } + + nlohmann::json& tours = data["Tour"]; + + // Enable flag + if (tours.contains("Enabled")) { + course->bTourEnabled = tours["Enabled"].get<bool>(); + } else { + course->bTourEnabled = false; + } + + // Camera shots + if (tours.contains("Shots") && tours["Shots"].is_array()) { + course->TourShots.clear(); + + for (const auto& shotJson : tours["Shots"]) { + course->TourShots.push_back(FromJsonCameraShot(shotJson)); + } + } + } } |
