Edit TrackInfo Properties (#594)

* Fix finishline for toads turnpike in extra

* Fixed trash bin in extra

* Refactor fov

* Update scene.json

* Allow setting fog

* impl fog save & load

* Fix modifying resourceName and rename editor namespace to trackeditor

* small change
This commit is contained in:
MegaMech
2025-12-15 12:29:58 -07:00
committed by GitHub
parent 2995361eb1
commit eb11374093
41 changed files with 219 additions and 117 deletions
+1 -1
View File
@@ -25,7 +25,7 @@ void AActor::BeginPlay() {
if ((nullptr != Model) && (Model[0] != '\0')) {
// Prevent collision mesh from being generated extra times.
if (Triangles.size() == 0) {
Editor::GenerateCollisionMesh(this, (Gfx*)LOAD_ASSET_RAW(Model), 1.0f);
TrackEditor::GenerateCollisionMesh(this, (Gfx*)LOAD_ASSET_RAW(Model), 1.0f);
}
}
}
+1 -1
View File
@@ -495,7 +495,7 @@ void RegisterTracks(Registry<TrackInfo>& r) {
r.Add(info, []() { GetWorld()->SetCurrentTrack(std::make_unique<BigDonut>()); });
info = {
.ResourceName = "mk:test_track",
.ResourceName = "hm:test_track",
.Name = "test track",
.DebugName = "test track",
.Length = "100m",
+11
View File
@@ -97,6 +97,17 @@ public:
return list;
}
// Returns true if item succesfully removed
// Note that mCounter is not decremented on remove
bool Remove(const std::string& resourceName) {
auto it = mMap.find(resourceName);
if (it != mMap.end()) {
mMap.erase(it);
return true;
}
return false;
}
void Clear() {
mMap.clear();
mCounter = 0;
+48 -49
View File
@@ -1,6 +1,7 @@
#include "TrackBrowser.h"
#include "port/Engine.h"
#include "engine/editor/SceneManager.h"
#include <imgui.h>
TrackBrowser* TrackBrowser::Instance;
@@ -8,65 +9,63 @@ void TrackBrowser::FindCustomTracks() {
auto manager = GameEngine::Instance->context->GetResourceManager()->GetArchiveManager();
auto ptr2 = manager->ListDirectories("tracks/*");
if (ptr2) {
auto dirs = *ptr2;
if (!ptr2) {
return;
}
auto dirs = *ptr2;
for (const std::string& dir : dirs) {
std::string name = dir.substr(dir.find_last_of('/') + 1);
std::string sceneFile = dir + "/scene.json";
std::string minimapFile = dir + "/minimap.png";
for (const std::string& dir : dirs) {
std::string name = dir.substr(dir.find_last_of('/') + 1);
std::string sceneFile = dir + "/scene.json";
std::string minimapFile = dir + "/minimap.png";
// The track has a valid scene file, add it to the registry
if (manager->HasFile(sceneFile)) {
auto archive = manager->GetArchiveFromFile(sceneFile);
// The track has a valid scene file, add it to the registry
if (manager->HasFile(sceneFile)) {
auto archive = manager->GetArchiveFromFile(sceneFile);
TrackInfo info;
info.Path = dir;
TrackEditor::LoadTrackInfo(info, archive, sceneFile);
printf("[TrackBrowser] Added custom track %s\n", info.Name.c_str());
gTrackRegistry.Add(info, [info, archive]() {
auto track = std::make_unique<Track>();
track->ResourceName = info.ResourceName;
track->Archive = archive;
GetWorld()->SetCurrentTrack(std::move(track));
});
} else { // The track does not have a valid scene file
const std::string file = dir + "/data_track_sections";
// If the track has a data_track_sections file,
// then it must at least be a valid track.
// So lets add it as an uninitialized track.
if (manager->HasFile(file)) {
printf("[TrackBrowser] [FindCustomTracks] Found a new custom track!\n");
printf(" Creating scene.json so the track can be configured in the editor\n");
TrackInfo info;
std::string resName = std::string("mods:") + name;
info.ResourceName = resName;
info.Name = name;
info.DebugName = name;
info.Path = dir;
Editor::LoadTrackInfo(info, archive, sceneFile);
printf("Added custom track %s\n", info.Name.c_str());
// Create the track
auto archive = manager->GetArchiveFromFile(file);
auto track = std::make_unique<Track>();
track->Archive = archive;
track->ResourceName = info.ResourceName;
TrackEditor::SaveLevel(track.get(), static_cast<const TrackInfo*>(&info)); // Write scene file so it will show up in the track browser
printf("[TrackBrowser] [FindCustomTracks] Saved scene.json to new track!\n");
// Passing these through seems kinda bad. But it works?
gTrackRegistry.Add(info, [info, archive]() {
auto track = std::make_unique<Track>();
track->ResourceName = info.ResourceName;
track->Archive = archive;
track->ResourceName = info.ResourceName;
GetWorld()->SetCurrentTrack(std::move(track));
});
} else { // The track does not have a valid scene file
const std::string file = dir + "/data_track_sections";
// If the track has a data_track_sections file,
// then it must at least be a valid track.
// So lets add it as an uninitialized track.
if (manager->HasFile(file)) {
printf("[TrackBrowser] [FindCustomTracks] Found a new custom track!\n");
printf(" Creating scene.json so the track can be configured in the editor\n");
TrackInfo info;
std::string resName = std::string("mods:") + name;
info.ResourceName = resName;
info.Name = name;
info.DebugName = name;
info.Path = dir;
auto archive = manager->GetArchiveFromFile(file);
//mNewTracks.push_back({info, "", dir, archive});
auto track = std::make_unique<Track>();
track->Archive = archive;
track->ResourceName = info.ResourceName;
Editor::SaveLevel(track.get(), &info); // Write scene file so it will show up in the track browser
printf("[TrackBrowser] [FindCustomTracks] Saved scene.json to new track!\n");
// Passing these through seems kinda bad. But it works?
gTrackRegistry.Add(info, [info, archive]() {
auto track = std::make_unique<Track>();
track->Archive = archive;
track->ResourceName = info.ResourceName;
GetWorld()->SetCurrentTrack(std::move(track));
});
} else {
printf("ContentBrowser.cpp: Track '%s' missing required track files. Cannot add to game\n Missing %s/data_track_sections file\n", name.c_str(), dir.c_str());
}
} else {
printf("[TrackBrowser] Track '%s' missing required track files. Cannot add to game\n Missing %s/data_track_sections file\n", name.c_str(), dir.c_str());
}
}
}
+1 -1
View File
@@ -50,7 +50,7 @@ void ACloud::BeginPlay() {
// Prevent collision mesh from being generated extra times.
if (Editor_IsEnabled()) {
if (Triangles.size() == 0) {
Editor::GenerateCollisionMesh(this, (Gfx*)cloud_mesh, 1.0f);
TrackEditor::GenerateCollisionMesh(this, (Gfx*) cloud_mesh, 1.0f);
}
}
}
+1 -1
View File
@@ -53,7 +53,7 @@ void AFinishline::BeginPlay() {
// Prevent collision mesh from being generated extra times.
if (Editor_IsEnabled()) {
if (Triangles.size() == 0) {
Editor::GenerateCollisionMesh(this, (Gfx*)LOAD_ASSET_RAW(D_0D001B90), 1.0f);
TrackEditor::GenerateCollisionMesh(this, (Gfx*)LOAD_ASSET_RAW(D_0D001B90), 1.0f);
}
}
}
+1 -1
View File
@@ -55,7 +55,7 @@ void AShip::BeginPlay() {
// Prevent collision mesh from being generated extra times.
if (Editor_IsEnabled()) {
if (Triangles.size() == 0) {
Editor::GenerateCollisionMesh(this, (Gfx*)_skin, Scale.y);
TrackEditor::GenerateCollisionMesh(this, (Gfx*) _skin, Scale.y);
}
}
}
+1 -1
View File
@@ -35,7 +35,7 @@ void AStarship::BeginPlay() {
// Prevent collision mesh from being generated extra times.
if (Editor_IsEnabled()) {
if (Triangles.size() == 0) {
Editor::GenerateCollisionMesh(this, (Gfx*)Model, 1.0f);
TrackEditor::GenerateCollisionMesh(this, (Gfx*)Model, 1.0f);
}
}
}
+1 -1
View File
@@ -14,7 +14,7 @@ extern "C" {
#include "assets/textures/other_textures.h"
}
namespace Editor {
namespace TrackEditor {
void GenerateCollisionMesh(std::variant<AActor*, OObject*, GameObject*> object, Gfx* model, float scale) {
int8_t opcode;
uintptr_t lo;
+1 -1
View File
@@ -19,7 +19,7 @@
#define EDITOR_GFX_GET_OPCODE(var) ((uint32_t) ((var) & 0xFF000000))
namespace Editor {
namespace TrackEditor {
void GenerateCollisionMesh(std::variant<AActor*, OObject*, GameObject*> object, Gfx* model, float scale);
void DebugCollision(GameObject* obj, FVector pos, IRotator rot, FVector scale, const std::vector<Triangle>& triangles);
}
+1 -1
View File
@@ -24,7 +24,7 @@ extern "C" {
#include "camera.h"
}
namespace Editor {
namespace TrackEditor {
Editor* Editor::Instance;
Editor::Editor() {
+2 -2
View File
@@ -12,7 +12,7 @@ extern "C" {
}
#include "ObjectPicker.h"
namespace Editor {
namespace TrackEditor {
class ObjectPicker;
class Editor {
@@ -54,7 +54,7 @@ private:
void Copy(MtxF* src, MtxF* dest);
void Clear(MtxF* mf);
};
} // namespace Editor
} // namespace TrackEditor
#endif // __cplusplus
+2 -2
View File
@@ -1,7 +1,7 @@
#include <libultraship/libultraship.h>
#include "GameObject.h"
namespace Editor {
namespace TrackEditor {
GameObject::GameObject(FVector pos, IRotator rot, FVector scale, const char* model, std::vector<Triangle> triangles, CollisionType collision, float boundingBoxSize) {
Pos = pos;
@@ -38,4 +38,4 @@ namespace Editor {
Scale = scale;
};
} // namespace Editor
} // namespace TrackEditor
+1 -1
View File
@@ -16,7 +16,7 @@ extern "C" {
struct Triangle;
namespace Editor {
namespace TrackEditor {
class GameObject {
public:
enum class CollisionType {
+1 -1
View File
@@ -29,7 +29,7 @@ extern "C" {
#include "math_util.h"
}
namespace Editor {
namespace TrackEditor {
void Gizmo::Load() {
/* Translate handle collision */
+1 -1
View File
@@ -8,7 +8,7 @@
#include "engine/objects/Object.h"
#include <variant>
namespace Editor {
namespace TrackEditor {
class Gizmo {
public:
+1 -1
View File
@@ -3,7 +3,7 @@
#include "Handles.h"
namespace Editor {
namespace TrackEditor {
Handles::Handles() {
}
+1 -1
View File
@@ -4,7 +4,7 @@
#include <libultra/gbi.h>
#include "GameObject.h"
namespace Editor {
namespace TrackEditor {
class Handles : public GameObject {
Handles();
+1 -1
View File
@@ -27,7 +27,7 @@ extern "C" {
#include "math_util_2.h"
}
namespace Editor {
namespace TrackEditor {
size_t LightObject::NumLights = 0;
+1 -1
View File
@@ -5,7 +5,7 @@
#include "Collision.h"
#include "GameObject.h"
namespace Editor {
namespace TrackEditor {
class LightObject : public GameObject {
public:
+2 -2
View File
@@ -25,7 +25,7 @@ extern "C" {
#include "camera.h"
}
namespace Editor {
namespace TrackEditor {
void ObjectPicker::Load() {
eGizmo.Load();
@@ -230,7 +230,7 @@ std::pair<GameObject*, float> ObjectPicker::CheckEditorObjectRay(Ray ray) {
break;
}
case GameObject::CollisionType::BOUNDING_SPHERE:
printf("Editor::ObjectPicker.cpp Bounding sphere collision type not yet supported\n");
printf("[ObjectPicker] [CheckEditorObjectRay] Bounding sphere collision type not yet supported\n");
break;
}
}
+1 -1
View File
@@ -7,7 +7,7 @@
#include "GameObject.h"
#include "engine/Matrix.h"
namespace Editor {
namespace TrackEditor {
class ObjectPicker {
public:
void SelectObject(std::vector<GameObject*> objects);
+3 -1
View File
@@ -33,7 +33,7 @@ extern "C" {
#include "render_courses.h"
}
namespace Editor {
namespace TrackEditor {
void SaveLevel(Track* track, const TrackInfo* info) {
nlohmann::json data;
@@ -42,6 +42,7 @@ namespace Editor {
*/
try {
data["Props"] = track->Props.to_json();
data["Props"]["ResourceName"] = track->ResourceName.c_str();
} catch (...) {
SPDLOG_ERROR("[SceneManager] [SaveLevel] Failed serializing track Props");
}
@@ -331,6 +332,7 @@ namespace Editor {
try {
track->Props.from_json(data["Props"]);
track->ResourceName = data["Props"].at("ResourceName").get<std::string>();
} 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;
+1 -1
View File
@@ -6,7 +6,7 @@
#include <optional>
#include <nlohmann/json.hpp>
namespace Editor {
namespace TrackEditor {
void SaveLevel(Track* track, const TrackInfo* info);
void LoadTrackDataFromJson(Track* track, const std::string& trackPath);
void LoadTrackInfo(TrackInfo& info, std::shared_ptr<Ship::Archive> archive, std::string sceneFile);
+1 -1
View File
@@ -71,7 +71,7 @@ TestTrack::TestTrack() {
Props.Minimap.Colour = {255, 255, 255};
ResizeMinimap(&Props.Minimap);
ResourceName = "mk:test_track";
ResourceName = "hm:test_track";
Props.SetText(Props.Name, "Test Track", sizeof(Props.Name));
Props.SetText(Props.DebugName, "test track", sizeof(Props.DebugName));
+6 -3
View File
@@ -350,7 +350,6 @@ bool IsTriangleWindingInverted() {
return !gModifiedGfxSet.empty();
}
Track::Track() {
Props.SetText(Props.ResourceName, "mod:blank_track", sizeof(Props.ResourceName));
Props.SetText(Props.Name, "Blank Track", sizeof(Props.Name));
@@ -358,7 +357,7 @@ Track::Track() {
Props.SetText(Props.TrackLength, "100m", sizeof(Props.TrackLength));
// Props.Cup = FLOWER_CUP;
// Props.CupIndex = 3;
ResourceName = "";
ResourceName = "mod:blank_track";
Props.Minimap.Texture = minimap_mario_raceway;
Props.Minimap.Width = ResourceGetTexWidthByName(Props.Minimap.Texture);
Props.Minimap.Height = ResourceGetTexHeightByName(Props.Minimap.Texture);
@@ -450,7 +449,7 @@ void Track::Load() {
} else { // Load custom track
bIsMod = true;
Editor::LoadTrackDataFromJson(this, trackPath);
TrackEditor::LoadTrackDataFromJson(this, trackPath);
const std::string trackSectionPath = (trackPath + "/data_track_sections");
TrackSections* sections = (TrackSections*) LOAD_ASSET_RAW(trackSectionPath.c_str());
@@ -647,6 +646,10 @@ void Track::Draw(ScreenContext* arg0) {
}
const TrackInfo* info = gTrackRegistry.GetInfo(ResourceName);
if (nullptr == info) {
printf("[Track] [Draw] Resource name did not return a valid TrackInfo %s\n", ResourceName.c_str());
return;
}
std::string res = info->Path + "/data_track_sections";
TrackSections* sections = (TrackSections*) LOAD_ASSET_RAW(res.c_str());
-10
View File
@@ -86,7 +86,6 @@ typedef struct {
} TrackSections;
typedef struct Properties {
char ResourceName[128];
char Name[128];
char DebugName[128];
char TrackLength[128];
@@ -116,8 +115,6 @@ typedef struct Properties {
#ifdef __cplusplus
nlohmann::json to_json() const {
nlohmann::json j;
// j["Id"] = Id ? Id : "";
j["ResourceName"] = ResourceName ? ResourceName : "";
j["Name"] = Name ? Name : "";
j["DebugName"] = DebugName ? DebugName : "";
j["TrackLength"] = TrackLength ? TrackLength : "";
@@ -180,19 +177,12 @@ typedef struct Properties {
// Function to load struct from JSON
void from_json(const nlohmann::json& j) {
//Id = j.at("Id").get<std::string>().c_str();
// Name = j.at("Name").get<std::string>().c_str();
strncpy(ResourceName, j.at("ResourceName").get<std::string>().c_str(), sizeof(ResourceName) - 1);
ResourceName[sizeof(ResourceName) - 1] = '\0'; // Ensure null termination
strncpy(Name, j.at("Name").get<std::string>().c_str(), sizeof(Name) - 1);
Name[sizeof(Name) - 1] = '\0'; // Ensure null termination
// DebugName = j.at("DebugName").get<std::string>().c_str();
strncpy(DebugName, j.at("DebugName").get<std::string>().c_str(), sizeof(DebugName) - 1);
DebugName[sizeof(DebugName) - 1] = '\0'; // Ensure null termination
// TrackLength = j.at("TrackLength").get<std::string>().c_str();
strncpy(TrackLength, j.at("TrackLength").get<std::string>().c_str(), sizeof(TrackLength) - 1);
TrackLength[sizeof(TrackLength) - 1] = '\0'; // Ensure null termination