mirror of
https://github.com/HarbourMasters/SpaghettiKart
synced 2026-08-17 21:53:17 -04:00
Editor tooling wip
This commit is contained in:
@@ -1287,7 +1287,6 @@ s32 func_800088D8(s32 playerId, s16 lapNum, s16 currRank) {
|
||||
if (var_t1 < 0 || var_t1 >= 8) {
|
||||
return false;
|
||||
}
|
||||
printf("T1 %d\n", var_t1);
|
||||
if (arg1_times_8 < 24) {
|
||||
temp_a3 = &temp_a3[var_t1];
|
||||
interp = gLapCompletionPercentByPlayerId[playerId];
|
||||
|
||||
@@ -71,6 +71,7 @@ void func_80280038(void) {
|
||||
render_set_position(matrix, 0);
|
||||
render_course(D_800DC5EC);
|
||||
render_course_actors(D_800DC5EC);
|
||||
CM_DrawStaticMeshActors();
|
||||
render_object(PLAYER_ONE + SCREEN_MODE_1P);
|
||||
render_player_snow_effect(PLAYER_ONE + SCREEN_MODE_1P);
|
||||
ceremony_transition_sliding_borders();
|
||||
|
||||
+16
-6
@@ -10,7 +10,11 @@
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Applies pos, rot, and scale
|
||||
*
|
||||
*/
|
||||
struct FVector {
|
||||
float x, y, z;
|
||||
|
||||
@@ -108,19 +112,25 @@ typedef struct IVector2D {
|
||||
#endif // __cplusplus
|
||||
} IVector2D;
|
||||
|
||||
struct FRotation {
|
||||
float pitch, yaw, roll;
|
||||
// IRot is an int16_t not a float.
|
||||
struct IRotator {
|
||||
int16_t pitch, yaw, roll;
|
||||
|
||||
#ifdef __cplusplus
|
||||
FRotation& operator=(const FRotation& other) {
|
||||
IRotator& operator=(const IRotator& other) {
|
||||
pitch = other.pitch;
|
||||
yaw = other.yaw;
|
||||
roll = other.roll;
|
||||
return *this;
|
||||
}
|
||||
|
||||
FRotation() : pitch(0), yaw(0), roll(0) {}
|
||||
FRotation(float p, float y, float r) : pitch(p), yaw(y), roll(r) {}
|
||||
// Convert to binary rotator 0 --> INT16_MAX
|
||||
[[nodiscard]] IRotator ToBinary() const {
|
||||
return IRotator(pitch * INT16_MAX / 180, yaw * INT16_MAX / 180, roll * INT16_MAX / 180);
|
||||
}
|
||||
|
||||
IRotator() : pitch(0), yaw(0), roll(0) {}
|
||||
IRotator(int16_t p, int16_t y, int16_t r) : pitch(p), yaw(y), roll(r) {}
|
||||
#endif // __cplusplus
|
||||
};
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
void RunGarbageCollector() {
|
||||
//CleanActors();
|
||||
CleanObjects();
|
||||
CleanStaticMeshActors();
|
||||
}
|
||||
|
||||
void CleanActors() {
|
||||
@@ -18,14 +19,27 @@ void CleanActors() {
|
||||
// }
|
||||
}
|
||||
|
||||
void CleanStaticMeshActors() {
|
||||
for (auto actor = gWorldInstance.StaticMeshActors.begin(); actor != gWorldInstance.StaticMeshActors.end();) {
|
||||
StaticMeshActor* act = *actor; // Get a mutable copy
|
||||
if (act->bPendingDestroy) {
|
||||
delete act;
|
||||
actor = gWorldInstance.StaticMeshActors.erase(actor); // Remove from container
|
||||
continue;
|
||||
} else {
|
||||
actor++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CleanObjects() {
|
||||
for (auto object = gWorldInstance.Objects.begin(); object != gWorldInstance.Objects.end();) {
|
||||
OObject* obj = *object; // Get a mutable copy
|
||||
if (obj->PendingDestroy) {
|
||||
if (obj->bPendingDestroy) {
|
||||
delete obj;
|
||||
object = gWorldInstance.Objects.erase(object); // Remove from container
|
||||
continue;
|
||||
}
|
||||
object++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,4 +8,5 @@
|
||||
|
||||
void RunGarbageCollector();
|
||||
void CleanActors();
|
||||
void CleanStaticMeshActors();
|
||||
void CleanObjects();
|
||||
|
||||
@@ -39,21 +39,21 @@ void HarbourMastersIntro::HM_InitIntro() {
|
||||
_cameraAcceleration = 1.0f;
|
||||
|
||||
_pos = FVector(-1000, -205, -800); // -1000, -210, -800
|
||||
_rot = FRotation(-5, 100, 0);
|
||||
_rot = IRotator(-5, 100, 0);
|
||||
_scale = 0.7f;
|
||||
_trackScale = 2.0f;
|
||||
|
||||
_ship2Pos = FVector(300, -210, -1960);
|
||||
_ship2Rot = FRotation(0, 45, 0);
|
||||
_ship2Rot = IRotator(0, 45, 0);
|
||||
|
||||
_shipPos = FVector(20, -210, -1650);
|
||||
_shipRot = FRotation(0, 45, 0);
|
||||
_shipRot = IRotator(0, 45, 0);
|
||||
|
||||
_posHM64 = FVector(0, -500, -1000);
|
||||
_rotHM64 = FRotation(0, -90, -4); // -0x2100
|
||||
_rotHM64 = IRotator(0, -90, -4); // -0x2100
|
||||
|
||||
_hPos = FVector(-2000, 100, -4900);
|
||||
_hRot = FRotation(0, 0, 0);
|
||||
_hRot = IRotator(0, 0, 0);
|
||||
|
||||
ground_f3d_material_013_lights = gdSPDefLights1(
|
||||
0x7F, 0x30, 0x80,
|
||||
@@ -94,7 +94,7 @@ void HarbourMastersIntro::HM_TickIntro() {
|
||||
}
|
||||
|
||||
// @args amplitudes
|
||||
void HarbourMastersIntro::Bob(FVector& pos, FRotation& rot, f32 bobAmp, f32 bobSpeed, f32 tiltAmp, f32 tiltSpeed, f32 rollAmp, f32 rollSpeed) {
|
||||
void HarbourMastersIntro::Bob(FVector& pos, IRotator& rot, f32 bobAmp, f32 bobSpeed, f32 tiltAmp, f32 tiltSpeed, f32 rollAmp, f32 rollSpeed) {
|
||||
float time = (float)gGlobalTimer;
|
||||
|
||||
pos.y = -210 + bobAmp * sin(time * bobSpeed);
|
||||
@@ -104,7 +104,7 @@ void HarbourMastersIntro::Bob(FVector& pos, FRotation& rot, f32 bobAmp, f32 bobS
|
||||
rot.roll = rollAmp * sin(time * rollSpeed);
|
||||
}
|
||||
|
||||
void HarbourMastersIntro::SpagBob(FVector& pos, FRotation& rot, f32 bobAmp, f32 bobSpeed, f32 tiltAmp, f32 tiltSpeed, f32 rollAmp, f32 rollSpeed) {
|
||||
void HarbourMastersIntro::SpagBob(FVector& pos, IRotator& rot, f32 bobAmp, f32 bobSpeed, f32 tiltAmp, f32 tiltSpeed, f32 rollAmp, f32 rollSpeed) {
|
||||
float time = (float)gGlobalTimer;
|
||||
|
||||
pos.y = -205 + bobAmp * sin(time * bobSpeed);
|
||||
|
||||
@@ -24,8 +24,8 @@ public:
|
||||
private:
|
||||
void Setup();
|
||||
void Sync();
|
||||
void Bob(FVector& pos, FRotation& rot, f32 bobAmp, f32 bobSpeed, f32 tiltAmp, f32 tiltSpeed, f32 rollAmp, f32 rollSpeed);
|
||||
void SpagBob(FVector& pos, FRotation& rot, f32 bobAmp, f32 bobSpeed, f32 tiltAmp, f32 tiltSpeed, f32 rollAmp, f32 rollSpeed);
|
||||
void Bob(FVector& pos, IRotator& rot, f32 bobAmp, f32 bobSpeed, f32 tiltAmp, f32 tiltSpeed, f32 rollAmp, f32 rollSpeed);
|
||||
void SpagBob(FVector& pos, IRotator& rot, f32 bobAmp, f32 bobSpeed, f32 tiltAmp, f32 tiltSpeed, f32 rollAmp, f32 rollSpeed);
|
||||
void MoveCloserToCamera(float moveSpeed);
|
||||
|
||||
struct HMCamera {
|
||||
@@ -42,21 +42,21 @@ private:
|
||||
FVector _pos;
|
||||
f32 _scale;
|
||||
f32 _trackScale;
|
||||
FRotation _rot;
|
||||
IRotator _rot;
|
||||
|
||||
FVector _shipPos;
|
||||
FRotation _shipRot;
|
||||
IRotator _shipRot;
|
||||
|
||||
FVector _ship2Pos;
|
||||
FRotation _ship2Rot;
|
||||
IRotator _ship2Rot;
|
||||
|
||||
s32 _water = 0;
|
||||
|
||||
FVector _posHM64;
|
||||
FRotation _rotHM64;
|
||||
IRotator _rotHM64;
|
||||
|
||||
FVector _hPos;
|
||||
FRotation _hRot;
|
||||
IRotator _hRot;
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
extern "C" {
|
||||
#include "common_structs.h"
|
||||
#include "math_util.h"
|
||||
#include "math_util_2.h"
|
||||
}
|
||||
|
||||
void AddMatrix(std::vector<Mtx>& stack, Mat4 mtx, s32 flags) {
|
||||
@@ -58,6 +60,49 @@ Mtx* SetTextMatrix(f32 arg1, f32 arg2, f32 arg3, f32 arg4) {
|
||||
return mtx;
|
||||
}
|
||||
|
||||
void ApplyMatrixTransformations(Mat4 mtx, FVector pos, IRotator rot, FVector scale) {
|
||||
f32 sine1, cosine1;
|
||||
f32 sine2, cosine2;
|
||||
f32 sine3, cosine3;
|
||||
|
||||
rot = rot.ToBinary();
|
||||
|
||||
// Compute the sine and cosine of the orientation (Euler angles)
|
||||
sine1 = sins(rot.pitch);
|
||||
cosine1 = coss(rot.pitch);
|
||||
sine2 = sins(rot.yaw);
|
||||
cosine2 = coss(rot.yaw);
|
||||
sine3 = sins(rot.roll);
|
||||
cosine3 = coss(rot.roll);
|
||||
|
||||
// Compute the rotation matrix
|
||||
mtx[0][0] = (cosine2 * cosine3) + ((sine1 * sine2) * sine3);
|
||||
mtx[1][0] = (-cosine2 * sine3) + ((sine1 * sine2) * cosine3);
|
||||
mtx[2][0] = cosine1 * sine2;
|
||||
mtx[3][0] = pos.x;
|
||||
|
||||
mtx[0][1] = cosine1 * sine3;
|
||||
mtx[1][1] = cosine1 * cosine3;
|
||||
mtx[2][1] = -sine1;
|
||||
mtx[3][1] = pos.y;
|
||||
|
||||
mtx[0][2] = (-sine2 * cosine3) + ((sine1 * cosine2) * sine3);
|
||||
mtx[1][2] = (sine2 * sine3) + ((sine1 * cosine2) * cosine3);
|
||||
mtx[2][2] = cosine1 * cosine2;
|
||||
mtx[3][2] = pos.z;
|
||||
|
||||
// Apply scaling: modify the diagonal of the rotation matrix
|
||||
mtx[0][0] *= scale.x;
|
||||
mtx[1][1] *= scale.y;
|
||||
mtx[2][2] *= scale.z;
|
||||
|
||||
// Set the last row and column for the homogeneous coordinate system
|
||||
mtx[0][3] = 0.0f;
|
||||
mtx[1][3] = 0.0f;
|
||||
mtx[2][3] = 0.0f;
|
||||
mtx[3][3] = 1.0f;
|
||||
}
|
||||
|
||||
// API
|
||||
extern "C" {
|
||||
|
||||
@@ -122,3 +167,4 @@ extern "C" {
|
||||
gWorldInstance.Mtx.Objects.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,9 +4,11 @@
|
||||
#include <libultraship.h>
|
||||
|
||||
#include "common_structs.h"
|
||||
#include "CoreMath.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
void ApplyMatrixTransformations(Mat4 mtx, FVector pos, IRotator rot, FVector scale);
|
||||
#endif
|
||||
void ClearMatrixPools(void);
|
||||
void AddHudMatrix(Mat4 mtx, s32 flags);
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
#include "StaticMeshActor.h"
|
||||
#include <libultra/gbi.h>
|
||||
#include "Matrix.h"
|
||||
|
||||
extern "C" {
|
||||
#include "main.h"
|
||||
#include "math_util.h"
|
||||
#include "math_util_2.h"
|
||||
}
|
||||
|
||||
StaticMeshActor::StaticMeshActor(std::string name, FVector pos, IRotator rot, FVector scale, std::string model, int32_t* collision) : Name(name), Pos(pos), Rot(rot), Scale(scale), Model(""), Collision(collision) {
|
||||
|
||||
}
|
||||
|
||||
void StaticMeshActor::Draw() {
|
||||
Mat4 mtx;
|
||||
printf("DRAWING \n");
|
||||
gSPSetGeometryMode(gDisplayListHead++, G_SHADING_SMOOTH);
|
||||
gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING);
|
||||
if (!Model.empty()) {
|
||||
ApplyMatrixTransformations(mtx, Pos, Rot, Scale);
|
||||
if (render_set_position(mtx, 0) != 0) {
|
||||
gSPDisplayList(gDisplayListHead++, (Gfx*)Model.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
FVector test = FVector(cameras[0].pos[0], cameras[0].pos[1], cameras[0].pos[2]);
|
||||
FVector diff = test - Pos;
|
||||
printf("Cam dist: %f", diff.Magnitude());
|
||||
}
|
||||
|
||||
void StaticMeshActor::Destroy() {
|
||||
bPendingDestroy = true;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
|
||||
#include <libultraship.h>
|
||||
#include <libultra/gbi.h>
|
||||
#include "CoreMath.h"
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
// todo: Make this class AStaticMeshActor : public AActor
|
||||
class StaticMeshActor {
|
||||
public:
|
||||
std::string Name;
|
||||
FVector Pos;
|
||||
IRotator Rot;
|
||||
FVector Scale;
|
||||
std::string Model;
|
||||
int32_t* Collision;
|
||||
bool bPendingDestroy = false;
|
||||
StaticMeshActor(std::string name, FVector pos, IRotator rot, FVector scale, std::string model, int32_t* collision);
|
||||
|
||||
nlohmann::json to_json() const {
|
||||
nlohmann::json j;
|
||||
|
||||
// Serialize each field of the class
|
||||
j["Name"] = Name;
|
||||
j["Position"] = {Pos.x, Pos.y, Pos.z}; // Assuming FVector has x, y, z fields
|
||||
j["Rotation"] = {Rot.pitch, Rot.yaw, Rot.roll}; // Assuming IRotator has pitch, yaw, roll fields
|
||||
j["Scale"] = {Scale.x, Scale.y, Scale.z}; // Assuming FVector has x, y, z fields
|
||||
j["Model"] = Model;
|
||||
|
||||
// If Collision is not null, serialize it
|
||||
if (Collision != nullptr) {
|
||||
j["Collision"] = *Collision; // Serialize the value that Collision points to
|
||||
} else {
|
||||
j["Collision"] = nullptr; // Handle the case where Collision is nullptr
|
||||
}
|
||||
|
||||
return j;
|
||||
}
|
||||
|
||||
void from_json(const nlohmann::json& j) {
|
||||
Name = j.at("Name").get<std::string>();
|
||||
Pos = FVector(j.at("Position")[0].get<float>(), j.at("Position")[1].get<float>(), j.at("Position")[2].get<float>());
|
||||
Rot = IRotator(j.at("Rotation")[0].get<float>(), j.at("Rotation")[1].get<float>(), j.at("Rotation")[2].get<float>());
|
||||
Scale = FVector(j.at("Scale")[0].get<float>(), j.at("Scale")[1].get<float>(), j.at("Scale")[2].get<float>());
|
||||
|
||||
// Deserialize the Model string
|
||||
Model = j.at("Model").get<std::string>();
|
||||
|
||||
// Check if Collision is present in the JSON and deserialize it
|
||||
//if (j.contains("Collision") && !j["Collision"].is_null()) {
|
||||
// If Collision is a valid value, allocate memory for it and assign the value
|
||||
// Collision = new int32_t(j.at("Collision").get<int32_t>());
|
||||
//} else {
|
||||
// If Collision is not present or is null, set it to nullptr
|
||||
Collision = nullptr;
|
||||
//}
|
||||
}
|
||||
|
||||
virtual void Draw();
|
||||
virtual void Destroy();
|
||||
};
|
||||
@@ -175,6 +175,31 @@ void World::TickActors() {
|
||||
}
|
||||
}
|
||||
|
||||
StaticMeshActor* World::AddStaticMeshActor(std::string name, FVector pos, IRotator rot, FVector scale, std::string model, int32_t* collision) {
|
||||
StaticMeshActors.push_back(new StaticMeshActor(name, pos, rot, scale, model, collision));
|
||||
auto actor = StaticMeshActors.back();
|
||||
gEditor.AddObject(actor->Name.c_str(), &actor->Pos, (Vec3s*) &actor->Rot, &actor->Scale, (Gfx*) LOAD_ASSET_RAW(actor->Model.c_str()), 1.0f,
|
||||
Editor::GameObject::CollisionType::VTX_INTERSECT, 0.0f, (int32_t*) &actor->bPendingDestroy, (int32_t) true);
|
||||
return actor;
|
||||
}
|
||||
|
||||
void World::DrawStaticMeshActors() {
|
||||
for (const auto& actor: StaticMeshActors) {
|
||||
actor->Draw();
|
||||
}
|
||||
}
|
||||
|
||||
void World::DeleteStaticMeshActors() {
|
||||
for (auto it = StaticMeshActors.begin(); it != StaticMeshActors.end();) {
|
||||
if ((*it)->bPendingDestroy) {
|
||||
delete *it; // Deallocate memory for the actor
|
||||
it = StaticMeshActors.erase(it); // Remove the pointer from the vector
|
||||
} else {
|
||||
++it; // Only increment the iterator if we didn't erase an element
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OObject* World::AddObject(OObject* object) {
|
||||
Objects.push_back(object);
|
||||
|
||||
@@ -242,3 +267,15 @@ Object* World::GetObjectByIndex(size_t index) {
|
||||
//}
|
||||
return nullptr; // Or handle the error as needed
|
||||
}
|
||||
|
||||
void World::ClearWorld(void) {
|
||||
World::DeleteStaticMeshActors();
|
||||
CM_CleanWorld();
|
||||
|
||||
// for (size_t i = 0; i < ARRAY_COUNT(gCollisionMesh); i++) {
|
||||
|
||||
// }
|
||||
|
||||
// gCollisionMesh
|
||||
// Paths
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include "Actor.h"
|
||||
#include "StaticMeshActor.h"
|
||||
#include "particles/ParticleEmitter.h"
|
||||
|
||||
#include "editor/Editor.h"
|
||||
@@ -31,6 +32,7 @@ extern "C" {
|
||||
class Cup; // <-- Forward declaration
|
||||
class OObject;
|
||||
class Course;
|
||||
class StaticMeshActor;
|
||||
class AVehicle;
|
||||
class OBombKart;
|
||||
class TrainCrossing;
|
||||
@@ -60,6 +62,10 @@ public:
|
||||
AActor* ConvertActorToAActor(Actor* actor);
|
||||
Actor* ConvertAActorToActor(AActor* actor);
|
||||
|
||||
void DrawStaticMeshActors();
|
||||
StaticMeshActor* AddStaticMeshActor(std::string name, FVector pos, IRotator rot, FVector scale, std::string model, int32_t* collision);
|
||||
void DeleteStaticMeshActors();
|
||||
|
||||
OObject* AddObject(OObject* object);
|
||||
|
||||
void TickObjects();
|
||||
@@ -81,6 +87,7 @@ public:
|
||||
void SetCourseFromCup();
|
||||
|
||||
World* GetWorld(void);
|
||||
void ClearWorld(void);
|
||||
|
||||
|
||||
// These are only for browsing through the course list
|
||||
@@ -98,6 +105,7 @@ public:
|
||||
std::vector<Cup*> Cups;
|
||||
size_t CupIndex = 1;
|
||||
|
||||
std::vector<StaticMeshActor*> StaticMeshActors;
|
||||
std::vector<AActor*> Actors;
|
||||
std::vector<OObject*> Objects;
|
||||
std::vector<ParticleEmitter*> Emitters;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "Ship.h"
|
||||
|
||||
#include <libultra/gbi.h>
|
||||
#include "CoreMath.h"
|
||||
|
||||
extern "C" {
|
||||
#include "common_structs.h"
|
||||
@@ -47,12 +48,13 @@ void AShip::Tick() {
|
||||
void AShip::Draw(Camera *camera) {
|
||||
Mat4 shipMtx;
|
||||
Vec3f hullPos = {Pos.x, Pos.y, Pos.z};
|
||||
Vec3s hullRot = {Rot.pitch, Rot.yaw, Rot.roll};
|
||||
//Vec3s hullRot = {Rot.pitch, Rot.yaw, Rot.roll};
|
||||
|
||||
gSPSetGeometryMode(gDisplayListHead++, G_SHADING_SMOOTH);
|
||||
gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING);
|
||||
|
||||
mtxf_pos_rotation_xyz(shipMtx, hullPos, hullRot);
|
||||
IRotator rot = Rot.ToBinary();
|
||||
mtxf_pos_rotation_xyz(shipMtx, hullPos, *(Vec3s*) &Rot);
|
||||
mtxf_scale(shipMtx, 0.4);
|
||||
if (render_set_position(shipMtx, 0) != 0) {
|
||||
gSPDisplayList(gDisplayListHead++, _skin);
|
||||
|
||||
@@ -28,7 +28,7 @@ public:
|
||||
|
||||
FVector Spawn;
|
||||
FVector Pos;
|
||||
FRotation Rot = {0, 0, 0};
|
||||
IRotator Rot = {0, 0, 0};
|
||||
private:
|
||||
Gfx* _skin;
|
||||
};
|
||||
|
||||
@@ -45,7 +45,8 @@ void ASpaghettiShip::Draw(Camera *camera) {
|
||||
gSPClearGeometryMode(gDisplayListHead++, G_LIGHTING);
|
||||
|
||||
// empty/null mtx as a base
|
||||
mtxf_pos_rotation_xyz(shipMtx, hullPos, hullRot);
|
||||
IRotator iRot = Rot.ToBinary();
|
||||
mtxf_pos_rotation_xyz(shipMtx, hullPos, *(Vec3s*)&iRot);
|
||||
mtxf_scale(shipMtx, 0.4);
|
||||
if (render_set_position(shipMtx, 0) != 0) {}
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@ public:
|
||||
|
||||
FVector Spawn;
|
||||
FVector Pos;
|
||||
FRotation Rot = {0, 0, 0};
|
||||
FRotation WheelRot = {0, 0, 0};
|
||||
IRotator Rot = {0, 0, 0};
|
||||
IRotator WheelRot = {0, 0, 0};
|
||||
private:
|
||||
f32 scale;
|
||||
};
|
||||
|
||||
@@ -21,5 +21,5 @@ public:
|
||||
|
||||
FVector Spawn;
|
||||
FVector Pos;
|
||||
FRotation Rot = {0, 0, 0};
|
||||
IRotator Rot = {0, 0, 0};
|
||||
};
|
||||
|
||||
@@ -73,9 +73,11 @@ BansheeBoardwalk::BansheeBoardwalk() {
|
||||
Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture));
|
||||
|
||||
Props.Id = "mk:banshee_boardwalk";
|
||||
Props.Name = "banshee boardwalk";
|
||||
Props.DebugName = "ghost";
|
||||
Props.CourseLength = "747m";
|
||||
|
||||
Props.SetText(Props.Name, "banshee boardwalk", sizeof(Props.Name));
|
||||
Props.SetText(Props.DebugName, "ghost", sizeof(Props.DebugName));
|
||||
Props.SetText(Props.CourseLength, "747m", sizeof(Props.CourseLength));
|
||||
|
||||
Props.AIBehaviour = D_0D009058;
|
||||
Props.AIMaximumSeparation = 40.0f;
|
||||
Props.AIMinimumSeparation = 0.4f;
|
||||
@@ -162,13 +164,13 @@ void BansheeBoardwalk::BeginPlay() {
|
||||
}
|
||||
|
||||
if (gIsMirrorMode) {
|
||||
gWorldInstance.AddObject(new OTrashBin(FVector(1765.0f, 45.0f, 195.0f), FRotation(0, 180.0f, 0), 1.0f, bhv));
|
||||
gWorldInstance.AddObject(new OTrashBin(FVector(1765.0f, 45.0f, 195.0f), IRotator(0, 180, 0), 1.0f, bhv));
|
||||
} else {
|
||||
gWorldInstance.AddObject(new OTrashBin(FVector(-1765.0f, 45.0f, 70.0f), FRotation(0, 0, 0), 1.0f, bhv));
|
||||
gWorldInstance.AddObject(new OTrashBin(FVector(-1765.0f, 45.0f, 70.0f), IRotator(0, 0, 0), 1.0f, bhv));
|
||||
}
|
||||
|
||||
if ((gGamestate != CREDITS_SEQUENCE) && (gModeSelection != TIME_TRIALS)) {
|
||||
gWorldInstance.AddObject(new OBat(FVector(0,0,0), FRotation(0, 0, 90.0f)));
|
||||
gWorldInstance.AddObject(new OBat(FVector(0,0,0), IRotator(0, 0, 90)));
|
||||
gWorldInstance.AddObject(new OBoos(5, IPathSpan(180, 190), IPathSpan(200, 210), IPathSpan(280, 290)));
|
||||
gWorldInstance.AddObject(new OBoos(5, IPathSpan(490, 500), IPathSpan(510, 520), IPathSpan(620, 630)));
|
||||
}
|
||||
|
||||
@@ -46,9 +46,10 @@ BigDonut::BigDonut() {
|
||||
Props.MinimapTexture = gTextureCourseOutlineBigDonut;
|
||||
Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture));
|
||||
|
||||
Props.Name = "big donut";
|
||||
Props.DebugName = "doughnut";
|
||||
Props.CourseLength = "";
|
||||
Props.SetText(Props.Name, "big donut", sizeof(Props.Name));
|
||||
Props.SetText(Props.DebugName, "doughnut", sizeof(Props.DebugName));
|
||||
Props.SetText(Props.CourseLength, "", sizeof(Props.CourseLength));
|
||||
|
||||
Props.AIBehaviour = D_0D008F18;
|
||||
Props.AIMaximumSeparation = -1.0f;
|
||||
Props.AIMinimumSeparation = 0.5f;
|
||||
|
||||
@@ -48,10 +48,10 @@ BlockFort::BlockFort() {
|
||||
Props.MinimapTexture = gTextureCourseOutlineBlockFort;
|
||||
Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture));
|
||||
|
||||
Props.SetText(Props.Name, "block fort", sizeof(Props.Name));
|
||||
Props.SetText(Props.DebugName, "block", sizeof(Props.DebugName));
|
||||
Props.SetText(Props.CourseLength, "", sizeof(Props.CourseLength));
|
||||
|
||||
Props.Name = "block fort";
|
||||
Props.DebugName = "block";
|
||||
Props.CourseLength = "";
|
||||
Props.AIBehaviour = D_0D008F18;
|
||||
Props.AIMaximumSeparation = -1.0f;
|
||||
Props.AIMinimumSeparation = 0.1f;
|
||||
|
||||
@@ -75,9 +75,11 @@ BowsersCastle::BowsersCastle() {
|
||||
Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture));
|
||||
|
||||
Props.Id = "mk:bowsers_castle";
|
||||
Props.Name = "bowser's castle";
|
||||
Props.DebugName = "castle";
|
||||
Props.CourseLength = "777m";
|
||||
|
||||
Props.SetText(Props.Name, "bowser's castle", sizeof(Props.Name));
|
||||
Props.SetText(Props.DebugName, "castle", sizeof(Props.DebugName));
|
||||
Props.SetText(Props.CourseLength, "777m", sizeof(Props.CourseLength));
|
||||
|
||||
Props.AIBehaviour = D_0D008FB8;
|
||||
Props.AIMaximumSeparation = 35.0f;
|
||||
Props.AIMinimumSeparation = 0.2f;
|
||||
|
||||
@@ -67,9 +67,10 @@ ChocoMountain::ChocoMountain() {
|
||||
Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture));
|
||||
|
||||
Props.Id = "mk:choco_mountain";
|
||||
Props.Name = "choco mountain";
|
||||
Props.DebugName = "mountain";
|
||||
Props.CourseLength = "687m";
|
||||
Props.SetText(Props.Name, "choco mountain", sizeof(Props.Name));
|
||||
Props.SetText(Props.DebugName, "mountain", sizeof(Props.DebugName));
|
||||
Props.SetText(Props.CourseLength, "687m", sizeof(Props.CourseLength));
|
||||
|
||||
Props.AIBehaviour = D_0D008F80;
|
||||
Props.AIMaximumSeparation = 35.0f;
|
||||
Props.AIMinimumSeparation = 0.3f;
|
||||
|
||||
@@ -19,6 +19,7 @@ extern "C" {
|
||||
#include "staff_ghosts.h"
|
||||
#include "code_800029B0.h"
|
||||
#include "render_courses.h"
|
||||
#include "collision.h"
|
||||
extern StaffGhost* d_mario_raceway_staff_ghost;
|
||||
}
|
||||
|
||||
@@ -28,6 +29,7 @@ Course::Course() {
|
||||
// Props.CourseLength = "567m";
|
||||
// Props.Cup = FLOWER_CUP;
|
||||
// Props.CupIndex = 3;
|
||||
Props.TrackModel = NULL;
|
||||
Props.LakituTowType = (s32) OLakitu::LakituTowType::NORMAL;
|
||||
Props.AIBehaviour = D_0D008F28;
|
||||
Props.AIMaximumSeparation = 50.0f;
|
||||
@@ -86,6 +88,11 @@ void Course::Load(Vtx* vtx, Gfx* gfx) {
|
||||
|
||||
void Course::Load() {
|
||||
|
||||
if (Props.TrackModel) {
|
||||
generate_collision_mesh_with_defaults((Gfx*)LOAD_ASSET_RAW(Props.TrackModel));
|
||||
return;
|
||||
}
|
||||
|
||||
size_t vtxSize = (ResourceGetSizeByName(this->vtx) / sizeof(CourseVtx)) * sizeof(Vtx);
|
||||
size_t texSegSize;
|
||||
|
||||
@@ -227,7 +234,11 @@ void Course::Waypoints(Player* player, int8_t playerId) {
|
||||
}
|
||||
|
||||
void Course::Render(struct UnkStruct_800DC5EC* arg0) {
|
||||
if (Props.TrackModel) {
|
||||
gSPDisplayList(gDisplayListHead++, (Gfx*)LOAD_ASSET_RAW(Props.TrackModel));
|
||||
}
|
||||
}
|
||||
|
||||
void Course::RenderCredits() {
|
||||
}
|
||||
void Course::Collision() {
|
||||
|
||||
+139
-4
@@ -36,12 +36,12 @@ typedef struct SkyboxColours {
|
||||
|
||||
typedef struct Properties {
|
||||
const char* Id;
|
||||
const char* Name;
|
||||
const char* DebugName;
|
||||
const char* CourseLength;
|
||||
char Name[128];
|
||||
char DebugName[128];
|
||||
char CourseLength[128];
|
||||
const char* AIBehaviour;
|
||||
const char* MinimapTexture;
|
||||
s32 LakituTowType;
|
||||
int32_t LakituTowType;
|
||||
IVector2D MinimapDimensions;
|
||||
float AIMaximumSeparation;
|
||||
float AIMinimumSeparation;
|
||||
@@ -63,6 +63,141 @@ typedef struct Properties {
|
||||
SkyboxColours Skybox;
|
||||
const course_texture *textures;
|
||||
enum MusicSeq Sequence;
|
||||
const char* TrackModel;
|
||||
|
||||
#ifdef __cplusplus
|
||||
nlohmann::json to_json() const {
|
||||
nlohmann::json j;
|
||||
j["Id"] = Id ? Id : "";
|
||||
j["Name"] = Name ? Name : "";
|
||||
j["DebugName"] = DebugName ? DebugName : "";
|
||||
j["CourseLength"] = CourseLength ? CourseLength : "";
|
||||
j["AIBehaviour"] = AIBehaviour ? AIBehaviour : "";
|
||||
j["MinimapTexture"] = MinimapTexture ? MinimapTexture : "";
|
||||
j["LakituTowType"] = LakituTowType;
|
||||
j["MinimapDimensions"] = {MinimapDimensions.X, MinimapDimensions.Z};
|
||||
j["AIMaximumSeparation"] = AIMaximumSeparation;
|
||||
j["AIMinimumSeparation"] = AIMinimumSeparation;
|
||||
j["NearPersp"] = NearPersp;
|
||||
j["FarPersp"] = FarPersp;
|
||||
|
||||
// AIDistance as a JSON array
|
||||
j["AIDistance"] = std::vector<int16_t>(AIDistance, AIDistance + 32); // gAIDistances array size of 32
|
||||
|
||||
j["AISteeringSensitivity"] = AISteeringSensitivity;
|
||||
|
||||
// PathSizes - Assuming _struct_gCoursePathSizes_0x10 can be serialized similarly
|
||||
// j["PathSizes"] = PathSizes; // Implement your serialization logic here
|
||||
|
||||
j["D_0D009418"] = { D_0D009418[0], D_0D009418[1], D_0D009418[2], D_0D009418[3] };
|
||||
j["D_0D009568"] = { D_0D009568[0], D_0D009568[1], D_0D009568[2], D_0D009568[3] };
|
||||
j["D_0D0096B8"] = { D_0D0096B8[0], D_0D0096B8[1], D_0D0096B8[2], D_0D0096B8[3] };
|
||||
j["D_0D009808"] = { D_0D009808[0], D_0D009808[1], D_0D009808[2], D_0D009808[3] };
|
||||
|
||||
// Serialize arrays PathTable and PathTable2 (convert pointers into a JSON array if possible)
|
||||
//j["PathTable"] = {{}};
|
||||
//j["PathTable2"] = {{}};
|
||||
// Populate PathTable and PathTable2
|
||||
|
||||
//j["Clouds"] = Clouds ? nlohmann::json{{"x", Clouds->x, "y", Clouds->y, "z", Clouds->z}} : nullptr;
|
||||
//j["CloudList"] = CloudList ? nlohmann::json{{"x", CloudList->x, "y", CloudList->y, "z", CloudList->z}} : nullptr;
|
||||
|
||||
j["MinimapFinishlineX"] = MinimapFinishlineX;
|
||||
j["MinimapFinishlineY"] = MinimapFinishlineY;
|
||||
// SkyboxColors - assuming SkyboxColors can be serialized similarly
|
||||
// j["Skybox"] = Skybox; // Implement your serialization logic here
|
||||
j["Sequence"] = static_cast<int>(Sequence);
|
||||
|
||||
return j;
|
||||
}
|
||||
|
||||
// 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(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
|
||||
|
||||
// CourseLength = j.at("CourseLength").get<std::string>().c_str();
|
||||
strncpy(CourseLength, j.at("CourseLength").get<std::string>().c_str(), sizeof(CourseLength) - 1);
|
||||
CourseLength[sizeof(CourseLength) - 1] = '\0'; // Ensure null termination
|
||||
|
||||
AIBehaviour = j.at("AIBehaviour").get<std::string>().c_str();
|
||||
MinimapTexture = j.at("MinimapTexture").get<std::string>().c_str();
|
||||
LakituTowType = j.at("LakituTowType").get<int>();
|
||||
MinimapDimensions.X = j.at("MinimapDimensions")[0].get<float>();
|
||||
MinimapDimensions.Z = j.at("MinimapDimensions")[1].get<float>();
|
||||
|
||||
AIMaximumSeparation = j.at("AIMaximumSeparation").get<float>();
|
||||
AIMinimumSeparation = j.at("AIMinimumSeparation").get<float>();
|
||||
NearPersp = j.at("NearPersp").get<float>();
|
||||
FarPersp = j.at("FarPersp").get<float>();
|
||||
|
||||
const auto temp = j.at("AIDistance").get<std::vector<int16_t>>();
|
||||
|
||||
// Ensure the vector has 32 entries
|
||||
if (temp.size() == 32) {
|
||||
// Copy the data into the existing AIDistances array
|
||||
std::copy(temp.begin(), temp.end(), AIDistance);
|
||||
} else {
|
||||
printf("Course::from_json() AIDistance array not size of 32\n");
|
||||
}
|
||||
|
||||
AISteeringSensitivity = j.at("AISteeringSensitivity").get<uint32_t>();
|
||||
|
||||
// Deserialize PathSizes and other custom structs if needed
|
||||
|
||||
D_0D009418[0] = j.at("D_0D009418")[0].get<float>();
|
||||
D_0D009418[1] = j.at("D_0D009418")[1].get<float>();
|
||||
D_0D009418[2] = j.at("D_0D009418")[2].get<float>();
|
||||
D_0D009418[3] = j.at("D_0D009418")[3].get<float>();
|
||||
|
||||
D_0D009568[0] = j.at("D_0D009568")[0].get<float>();
|
||||
D_0D009568[1] = j.at("D_0D009568")[1].get<float>();
|
||||
D_0D009568[2] = j.at("D_0D009568")[2].get<float>();
|
||||
D_0D009568[3] = j.at("D_0D009568")[3].get<float>();
|
||||
|
||||
D_0D0096B8[0] = j.at("D_0D0096B8")[0].get<float>();
|
||||
D_0D0096B8[1] = j.at("D_0D0096B8")[1].get<float>();
|
||||
D_0D0096B8[2] = j.at("D_0D0096B8")[2].get<float>();
|
||||
D_0D0096B8[3] = j.at("D_0D0096B8")[3].get<float>();
|
||||
|
||||
D_0D009808[0] = j.at("D_0D009808")[0].get<float>();
|
||||
D_0D009808[1] = j.at("D_0D009808")[1].get<float>();
|
||||
D_0D009808[2] = j.at("D_0D009808")[2].get<float>();
|
||||
D_0D009808[3] = j.at("D_0D009808")[3].get<float>();
|
||||
|
||||
// Deserialize arrays PathTable and PathTable2 similarly
|
||||
|
||||
//Clouds = nullptr; // Deserialize if data is present
|
||||
//CloudList = nullptr; // Deserialize if data is present
|
||||
|
||||
MinimapFinishlineX = j.at("MinimapFinishlineX").get<float>();
|
||||
MinimapFinishlineY = j.at("MinimapFinishlineY").get<float>();
|
||||
//textures = nullptr; // Deserialize textures if present
|
||||
Sequence = static_cast<MusicSeq>(j.at("Sequence").get<int>());
|
||||
}
|
||||
void SetText(char* name, const char* title, size_t bufferSize) {
|
||||
// Copy the title into the name buffer, ensuring it's null-terminated and within bounds
|
||||
std::strncpy(name, title, bufferSize - 1);
|
||||
name[bufferSize - 1] = '\0'; // Ensure the string is null-terminated
|
||||
}
|
||||
|
||||
const char* GetName() {
|
||||
return Name;
|
||||
}
|
||||
|
||||
void New() {
|
||||
SetText(Name, "", sizeof(Name));
|
||||
SetText(DebugName, "", sizeof(DebugName));
|
||||
SetText(CourseLength, "", sizeof(CourseLength));
|
||||
}
|
||||
#endif
|
||||
|
||||
} Properties;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -74,9 +74,10 @@ DKJungle::DKJungle() {
|
||||
Props.MinimapTexture = gTextureCourseOutlineDksJungleParkway;
|
||||
Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture));
|
||||
|
||||
Props.Name = "d.k.'s jungle parkway";
|
||||
Props.DebugName = "jungle";
|
||||
Props.CourseLength = "893m";
|
||||
Props.SetText(Props.Name, "d.k.'s jungle parkway", sizeof(Props.Name));
|
||||
Props.SetText(Props.DebugName, "jungle", sizeof(Props.DebugName));
|
||||
Props.SetText(Props.CourseLength, "893m", sizeof(Props.CourseLength));
|
||||
|
||||
Props.AIBehaviour = D_0D0093C0;
|
||||
Props.AIMaximumSeparation = 40.0f;
|
||||
Props.AIMinimumSeparation = 0.1f;
|
||||
|
||||
@@ -46,9 +46,11 @@ DoubleDeck::DoubleDeck() {
|
||||
Props.MinimapTexture = gTextureCourseOutlineDoubleDeck;
|
||||
Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture));
|
||||
|
||||
Props.Name = "double deck";
|
||||
Props.DebugName = "deck";
|
||||
Props.CourseLength = "";
|
||||
Props.SetText(Props.Name, "double deck", sizeof(Props.Name));
|
||||
Props.SetText(Props.DebugName, "deck", sizeof(Props.DebugName));
|
||||
Props.SetText(Props.CourseLength, "", sizeof(Props.CourseLength));
|
||||
|
||||
|
||||
Props.AIBehaviour = D_0D008F18;
|
||||
Props.AIMaximumSeparation = -1.0f;
|
||||
Props.AIMinimumSeparation = 0.5f;
|
||||
|
||||
@@ -54,9 +54,10 @@ FrappeSnowland::FrappeSnowland() {
|
||||
Props.MinimapTexture = gTextureCourseOutlineFrappeSnowland;
|
||||
Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture));
|
||||
|
||||
Props.Name = "frappe snowland";
|
||||
Props.DebugName = "snow";
|
||||
Props.CourseLength = "734m";
|
||||
Props.SetText(Props.Name, "frappe snowland", sizeof(Props.Name));
|
||||
Props.SetText(Props.DebugName, "snow", sizeof(Props.DebugName));
|
||||
Props.SetText(Props.CourseLength, "734m", sizeof(Props.CourseLength));
|
||||
|
||||
Props.AIBehaviour = D_0D0090F8;
|
||||
Props.AIMaximumSeparation = 50.0f;
|
||||
Props.AIMinimumSeparation = 0.3f;
|
||||
|
||||
@@ -527,9 +527,9 @@ Harbour::Harbour() {
|
||||
Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture));
|
||||
|
||||
Props.Id = "mk:harbour";
|
||||
Props.Name = "Harbour";
|
||||
Props.DebugName = "harbour";
|
||||
Props.CourseLength = "99m";
|
||||
Props.SetText(Props.Name, "Harbour", sizeof(Props.Name));
|
||||
Props.SetText(Props.DebugName, "harbour", sizeof(Props.DebugName));
|
||||
Props.SetText(Props.CourseLength, "99m", sizeof(Props.CourseLength));
|
||||
|
||||
Props.AIBehaviour = D_0D008F28;
|
||||
Props.AIMaximumSeparation = 50.0f;
|
||||
@@ -727,7 +727,7 @@ void Harbour::BeginPlay() {
|
||||
// gWorldInstance.AddObject(new OCheepCheep(FVector(0, 40, 0), OCheepCheep::CheepType::RACE, IPathSpan(0, 10)));
|
||||
// gWorldInstance.AddObject(new OTrophy(FVector(0,0,0), OTrophy::TrophyType::GOLD, OTrophy::Behaviour::GO_FISH));
|
||||
//gWorldInstance.AddObject(new OSnowman(FVector(0, 0, 0)));
|
||||
//gWorldInstance.AddObject(new OTrashBin(FVector(0.0f, 0.0f, 0.0f), FRotation(0, 90, 0), 1.0f, OTrashBin::Behaviour::MUNCHING));
|
||||
//gWorldInstance.AddObject(new OTrashBin(FVector(0.0f, 0.0f, 0.0f), IRotator(0, 90, 0), 1.0f, OTrashBin::Behaviour::MUNCHING));
|
||||
|
||||
//gWorldInstance.AddObject(new OHedgehog(FVector(0, 0, 0), FVector2D(0, -200), 9));
|
||||
//gWorldInstance.AddObject(new OFlagpole(FVector(0, 0, -200), 0x400));
|
||||
|
||||
@@ -59,9 +59,10 @@ KalimariDesert::KalimariDesert() {
|
||||
Props.MinimapTexture = gTextureCourseOutlineKalimariDesert;
|
||||
Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture));
|
||||
|
||||
Props.Name = "kalimari desert";
|
||||
Props.DebugName = "desert";
|
||||
Props.CourseLength = "753m";
|
||||
Props.SetText(Props.Name, "kalimari desert", sizeof(Props.Name));
|
||||
Props.SetText(Props.DebugName, "desert", sizeof(Props.DebugName));
|
||||
Props.SetText(Props.CourseLength, "753m", sizeof(Props.CourseLength));
|
||||
|
||||
Props.AIBehaviour = D_0D009260;
|
||||
Props.AIMaximumSeparation = 50.0f;
|
||||
Props.AIMinimumSeparation = 0.3f;
|
||||
|
||||
@@ -65,9 +65,10 @@ KoopaTroopaBeach::KoopaTroopaBeach() {
|
||||
Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture));
|
||||
|
||||
Props.Id = "mk:koopa_beach";
|
||||
Props.Name = "koopa troopa beach";
|
||||
Props.DebugName = "beach";
|
||||
Props.CourseLength = "691m";
|
||||
Props.SetText(Props.Name, "koopa troopa beach", sizeof(Props.Name));
|
||||
Props.SetText(Props.DebugName, "beach", sizeof(Props.DebugName));
|
||||
Props.SetText(Props.CourseLength, "691m", sizeof(Props.CourseLength));
|
||||
|
||||
Props.AIBehaviour = D_0D009158;
|
||||
Props.AIMaximumSeparation = 50.0f;
|
||||
Props.AIMinimumSeparation = 0.5f;
|
||||
|
||||
@@ -91,9 +91,10 @@ LuigiRaceway::LuigiRaceway() {
|
||||
Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture));
|
||||
|
||||
Props.Id = "mk:luigi_raceway";
|
||||
Props.Name = "luigi raceway";
|
||||
Props.DebugName = "l circuit";
|
||||
Props.CourseLength = "717m";
|
||||
Props.SetText(Props.Name, "luigi raceway", sizeof(Props.Name));
|
||||
Props.SetText(Props.DebugName, "l circuit", sizeof(Props.DebugName));
|
||||
Props.SetText(Props.CourseLength, "717m", sizeof(Props.CourseLength));
|
||||
|
||||
Props.AIBehaviour = D_0D0091E8;
|
||||
Props.AIMaximumSeparation = 50.0f;
|
||||
Props.AIMinimumSeparation = 0.7f;
|
||||
|
||||
@@ -77,9 +77,9 @@ MarioRaceway::MarioRaceway() {
|
||||
Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture));
|
||||
|
||||
Props.Id = "mk:mario_raceway";
|
||||
Props.Name = "Mario Raceway";
|
||||
Props.DebugName = "m circuit";
|
||||
Props.CourseLength = "567m";
|
||||
Props.SetText(Props.Name, "mario raceway", sizeof(Props.Name));
|
||||
Props.SetText(Props.DebugName, "m circuit", sizeof(Props.DebugName));
|
||||
Props.SetText(Props.CourseLength, "567m", sizeof(Props.CourseLength));
|
||||
|
||||
Props.AIBehaviour = D_0D008F28;
|
||||
Props.AIMaximumSeparation = 50.0f;
|
||||
|
||||
@@ -77,9 +77,10 @@ MooMooFarm::MooMooFarm() {
|
||||
Props.MinimapTexture = gTextureCourseOutlineMooMooFarm;
|
||||
Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture));
|
||||
|
||||
Props.Name = "moo moo farm";
|
||||
Props.DebugName = "farm";
|
||||
Props.CourseLength = "527m";
|
||||
Props.SetText(Props.Name, "moo moo farm", sizeof(Props.Name));
|
||||
Props.SetText(Props.DebugName, "farm", sizeof(Props.DebugName));
|
||||
Props.SetText(Props.CourseLength, "527m", sizeof(Props.CourseLength));
|
||||
|
||||
Props.AIBehaviour = D_0D009210;
|
||||
Props.AIMaximumSeparation = 50.0f;
|
||||
Props.AIMinimumSeparation = 0.5f;
|
||||
|
||||
@@ -92,9 +92,10 @@ PodiumCeremony::PodiumCeremony() {
|
||||
Props.textures = podium_ceremony_textures;
|
||||
Props.MinimapDimensions = IVector2D(0, 0);
|
||||
|
||||
Props.Name = "royal raceway";
|
||||
Props.DebugName = "p circuit";
|
||||
Props.CourseLength = "1025m";
|
||||
Props.SetText(Props.Name, "royal raceway", sizeof(Props.Name));
|
||||
Props.SetText(Props.DebugName, "p circuit", sizeof(Props.DebugName));
|
||||
Props.SetText(Props.CourseLength, "1025m", sizeof(Props.CourseLength));
|
||||
|
||||
Props.AIBehaviour = D_0D009188;
|
||||
Props.AIMaximumSeparation = 50.0f;
|
||||
Props.AIMinimumSeparation = 0.4f;
|
||||
|
||||
@@ -51,9 +51,10 @@ RainbowRoad::RainbowRoad() {
|
||||
Props.MinimapTexture = gTextureCourseOutlineRainbowRoad;
|
||||
Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture));
|
||||
|
||||
Props.Name = "rainbow road";
|
||||
Props.DebugName = "rainbow";
|
||||
Props.CourseLength = "2000m";
|
||||
Props.SetText(Props.Name, "rainbow road", sizeof(Props.Name));
|
||||
Props.SetText(Props.DebugName, "rainbow", sizeof(Props.DebugName));
|
||||
Props.SetText(Props.CourseLength, "2000m", sizeof(Props.CourseLength));
|
||||
|
||||
Props.AIBehaviour = D_0D0092C8;
|
||||
Props.AIMaximumSeparation = 50.0f;
|
||||
Props.AIMinimumSeparation = 0.4f;
|
||||
|
||||
@@ -88,9 +88,10 @@ RoyalRaceway::RoyalRaceway() {
|
||||
Props.MinimapTexture = gTextureCourseOutlineRoyalRaceway;
|
||||
Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture));
|
||||
|
||||
Props.Name = "royal raceway";
|
||||
Props.DebugName = "p circuit";
|
||||
Props.CourseLength = "1025m";
|
||||
Props.SetText(Props.Name, "royal raceway", sizeof(Props.Name));
|
||||
Props.SetText(Props.DebugName, "p circuit", sizeof(Props.DebugName));
|
||||
Props.SetText(Props.CourseLength, "1025m", sizeof(Props.CourseLength));
|
||||
|
||||
Props.AIBehaviour = D_0D009188;
|
||||
Props.AIMaximumSeparation = 50.0f;
|
||||
Props.AIMinimumSeparation = 0.4f;
|
||||
|
||||
@@ -51,9 +51,9 @@ SherbetLand::SherbetLand() {
|
||||
Props.MinimapTexture = gTextureCourseOutlineSherbetLand;
|
||||
Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture));
|
||||
|
||||
Props.Name = "sherbet land";
|
||||
Props.DebugName = "sherbet";
|
||||
Props.CourseLength = "756m";
|
||||
Props.SetText(Props.Name, "sherbet land", sizeof(Props.Name));
|
||||
Props.SetText(Props.DebugName, "sherbet", sizeof(Props.DebugName));
|
||||
Props.SetText(Props.CourseLength, "756m", sizeof(Props.CourseLength));
|
||||
|
||||
Props.LakituTowType = (s32)OLakitu::LakituTowType::ICE;
|
||||
|
||||
|
||||
@@ -67,9 +67,10 @@ Skyscraper::Skyscraper() {
|
||||
Props.MinimapTexture = gTextureCourseOutlineSkyscraper;
|
||||
Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture));
|
||||
|
||||
Props.Name = "skyscraper";
|
||||
Props.DebugName = "skyscraper";
|
||||
Props.CourseLength = "";
|
||||
Props.SetText(Props.Name, "skyscraper", sizeof(Props.Name));
|
||||
Props.SetText(Props.DebugName, "skyscraper", sizeof(Props.DebugName));
|
||||
Props.SetText(Props.CourseLength, "", sizeof(Props.CourseLength));
|
||||
|
||||
Props.AIBehaviour = D_0D008F18;
|
||||
Props.AIMaximumSeparation = -1.0f;
|
||||
Props.AIMinimumSeparation = 0.5f;
|
||||
|
||||
@@ -69,9 +69,10 @@ TestCourse::TestCourse() {
|
||||
Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture));
|
||||
|
||||
Props.Id = "mk:test_course";
|
||||
Props.Name = "Test Course";
|
||||
Props.DebugName = "test track";
|
||||
Props.CourseLength = "100m";
|
||||
|
||||
Props.SetText(Props.Name, "Test Course", sizeof(Props.Name));
|
||||
Props.SetText(Props.DebugName, "test track", sizeof(Props.DebugName));
|
||||
Props.SetText(Props.CourseLength, "100m", sizeof(Props.CourseLength));
|
||||
|
||||
Props.AIBehaviour = D_0D008F28;
|
||||
Props.AIMaximumSeparation = 50.0f;
|
||||
@@ -266,7 +267,7 @@ void TestCourse::BeginPlay() {
|
||||
// gWorldInstance.AddObject(new OCheepCheep(FVector(0, 40, 0), OCheepCheep::CheepType::RACE, IPathSpan(0, 10)));
|
||||
// gWorldInstance.AddObject(new OTrophy(FVector(0,0,0), OTrophy::TrophyType::GOLD, OTrophy::Behaviour::GO_FISH));
|
||||
//gWorldInstance.AddObject(new OSnowman(FVector(0, 0, 0)));
|
||||
//gWorldInstance.AddObject(new OTrashBin(FVector(0.0f, 0.0f, 0.0f), FRotation(0, 90, 0), 1.0f, OTrashBin::Behaviour::MUNCHING));
|
||||
//gWorldInstance.AddObject(new OTrashBin(FVector(0.0f, 0.0f, 0.0f), IRotator(0, 90, 0), 1.0f, OTrashBin::Behaviour::MUNCHING));
|
||||
|
||||
//gWorldInstance.AddObject(new OHedgehog(FVector(0, 0, 0), FVector2D(0, -200), 9));
|
||||
//gWorldInstance.AddObject(new OFlagpole(FVector(0, 0, -200), 0x400));
|
||||
|
||||
@@ -72,9 +72,10 @@ ToadsTurnpike::ToadsTurnpike() {
|
||||
Props.MinimapTexture = gTextureCourseOutlineToadsTurnpike;
|
||||
Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture));
|
||||
|
||||
Props.Name = "toad's turnpike";
|
||||
Props.DebugName = "highway";
|
||||
Props.CourseLength = "1036m";
|
||||
Props.SetText(Props.Name, "toad's turnpike", sizeof(Props.Name));
|
||||
Props.SetText(Props.DebugName, "highway", sizeof(Props.DebugName));
|
||||
Props.SetText(Props.CourseLength, "1036m", sizeof(Props.CourseLength));
|
||||
|
||||
Props.AIBehaviour = D_0D009238;
|
||||
Props.AIMaximumSeparation = 50.0f;
|
||||
Props.AIMinimumSeparation = 0.5f;
|
||||
|
||||
@@ -68,9 +68,10 @@ WarioStadium::WarioStadium() {
|
||||
Props.MinimapTexture = gTextureCourseOutlineWarioStadium;
|
||||
Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture));
|
||||
|
||||
Props.Name = "wario stadium";
|
||||
Props.DebugName = "stadium";
|
||||
Props.CourseLength = "1591m";
|
||||
Props.SetText(Props.Name, "wario stadium", sizeof(Props.Name));
|
||||
Props.SetText(Props.DebugName, "stadium", sizeof(Props.DebugName));
|
||||
Props.SetText(Props.CourseLength, "1591m", sizeof(Props.CourseLength));
|
||||
|
||||
Props.AIBehaviour = D_0D009310;
|
||||
Props.AIMaximumSeparation = 50.0f;
|
||||
Props.AIMinimumSeparation = 0.6f;
|
||||
|
||||
@@ -63,9 +63,10 @@ YoshiValley::YoshiValley() {
|
||||
Props.MinimapTexture = gTextureCourseOutlineYoshiValley;
|
||||
Props.MinimapDimensions = IVector2D(ResourceGetTexWidthByName(Props.MinimapTexture), ResourceGetTexHeightByName(Props.MinimapTexture));
|
||||
|
||||
Props.Name = "yoshi valley";
|
||||
Props.DebugName = "maze";
|
||||
Props.CourseLength = "772m";
|
||||
Props.SetText(Props.Name, "yoshi valley", sizeof(Props.Name));
|
||||
Props.SetText(Props.DebugName, "maze", sizeof(Props.DebugName));
|
||||
Props.SetText(Props.CourseLength, "772m", sizeof(Props.CourseLength));
|
||||
|
||||
Props.AIBehaviour = D_0D0090B8;
|
||||
Props.AIMaximumSeparation = 35.0f;
|
||||
Props.AIMinimumSeparation = 0.0f;
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace Editor {
|
||||
|
||||
void Editor::Load() {
|
||||
printf("Editor: Loading Editor...\n");
|
||||
eObjectPicker.Load();;
|
||||
eObjectPicker.Load();
|
||||
for (auto& object : eGameObjects) {
|
||||
GenerateCollisionMesh(object, object->Model, 1.0f);
|
||||
object->Load();
|
||||
@@ -52,7 +52,7 @@ namespace Editor {
|
||||
|
||||
eGameObjects.erase(
|
||||
std::remove_if(eGameObjects.begin(), eGameObjects.end(),
|
||||
[](const auto& object) { return (*object->DespawnFlag) == object->DespawnValue; printf("DELETED OBJ\n"); }),
|
||||
[](const auto& object) { return (*object->DespawnFlag) == object->DespawnValue; }),
|
||||
eGameObjects.end());
|
||||
|
||||
if (isMouseDown && !wasMouseDown) {
|
||||
@@ -100,7 +100,9 @@ namespace Editor {
|
||||
}
|
||||
|
||||
void Editor::AddObject(const char* name, FVector* pos, Vec3s* rot, FVector* scale, Gfx* model, float collScale, GameObject::CollisionType collision, float boundingBoxSize, int32_t* despawnFlag, int32_t despawnValue) {
|
||||
if (model != NULL) {
|
||||
//printf("After AddObj: Pos(%f, %f, %f), Name: %s, Model: %s\n",
|
||||
// pos->x, pos->y, pos->z, name, model);
|
||||
if (model != nullptr) {
|
||||
eGameObjects.push_back(new GameObject(name, pos, rot, scale, model, {}, collision, boundingBoxSize, despawnFlag, despawnValue));
|
||||
GenerateCollisionMesh(eGameObjects.back(), model, collScale);
|
||||
} else { // to bounding box or sphere collision
|
||||
@@ -117,6 +119,17 @@ namespace Editor {
|
||||
for (auto& obj : eGameObjects) {
|
||||
delete obj;
|
||||
}
|
||||
eGameObjects.clear();
|
||||
}
|
||||
|
||||
void Editor::DeleteObject() {
|
||||
GameObject* obj = eObjectPicker.eGizmo._selected;
|
||||
|
||||
if (obj) {
|
||||
*obj->DespawnFlag = obj->DespawnValue;
|
||||
obj = nullptr;
|
||||
eObjectPicker._selected = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Editor::ClearMatrixPool() {
|
||||
@@ -137,4 +150,8 @@ namespace Editor {
|
||||
eObjectPicker.eGizmo.dimensions.MinZ = minZ + -1000;
|
||||
eObjectPicker.eGizmo.dimensions.MaxZ = maxZ + 1000;
|
||||
}
|
||||
void Editor::NewTrack() {
|
||||
auto course = gWorldInstance.CurrentCourse = new Course();
|
||||
course->Props.New();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include "ObjectPicker.h"
|
||||
namespace Editor {
|
||||
class ObjectPicker;
|
||||
|
||||
|
||||
class Editor {
|
||||
public:
|
||||
Editor();
|
||||
@@ -29,6 +29,8 @@ public:
|
||||
void SelectObjectFromSceneExplorer(GameObject* object);
|
||||
void SetLevelDimensions(s16 minX, s16 maxX, s16 minZ, s16 maxZ, s16 minY, s16 maxY);
|
||||
void ClearMatrixPool();
|
||||
void DeleteObject();
|
||||
void NewTrack();
|
||||
|
||||
private:
|
||||
bool _draw = false;
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
#include "SaveLevel.h"
|
||||
#include "port/Game.h"
|
||||
#include "CoreMath.h"
|
||||
#include "World.h"
|
||||
#include "GameObject.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace Editor {
|
||||
|
||||
// SaveLevel::SaveLevel() {}
|
||||
|
||||
void SaveLevel() {
|
||||
auto props = gWorldInstance.CurrentCourse->Props;
|
||||
|
||||
nlohmann::json data;
|
||||
|
||||
data["Props"] = props.to_json();
|
||||
|
||||
nlohmann::json actors;
|
||||
|
||||
/* for (const auto& actor : gWorldInstance.StaticMeshActors) {
|
||||
actors.push_back(actor->to_json());
|
||||
}
|
||||
|
||||
data["Actors"] = actors;*/
|
||||
|
||||
std::ofstream file("track.json");
|
||||
file << data.dump(4); // Pretty print with indent
|
||||
}
|
||||
|
||||
void LoadLevel() {
|
||||
// Open the JSON file
|
||||
std::ifstream file("track.json");
|
||||
if (!file.is_open()) {
|
||||
std::cerr << "Failed to open track.json for reading!" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if level data file is empty
|
||||
if (file.peek() == std::ifstream::traits_type::eof()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the JSON file into a nlohmann::json object
|
||||
nlohmann::json data;
|
||||
file >> data;
|
||||
|
||||
|
||||
// Load the Props (deserialize it)
|
||||
if (data.contains("Props")) {
|
||||
auto& propsJson = data["Props"];
|
||||
gWorldInstance.CurrentCourse->Props.from_json(propsJson); // Assuming you have a `from_json` function
|
||||
} else {
|
||||
std::cerr << "Props data not found in the JSON file!" << std::endl;
|
||||
}
|
||||
|
||||
// Load the Actors (deserialize them)
|
||||
if (data.contains("Actors")) {
|
||||
auto& actorsJson = data["Actors"];
|
||||
gWorldInstance.StaticMeshActors.clear(); // Clear existing actors, if any
|
||||
|
||||
for (const auto& actorJson : actorsJson) {
|
||||
Load_AddStaticMeshActor(actorJson);
|
||||
}
|
||||
} else {
|
||||
std::cerr << "Actors data not found in the JSON file!" << std::endl;
|
||||
}
|
||||
// Close the file after loading
|
||||
file.close();
|
||||
}
|
||||
|
||||
void Load_AddStaticMeshActor(const nlohmann::json& actorJson) {
|
||||
gWorldInstance.StaticMeshActors.push_back(new StaticMeshActor("", FVector(0, 0, 0), IRotator(0, 0, 0), FVector(1, 1, 1), "", nullptr));
|
||||
auto actor = gWorldInstance.StaticMeshActors.back();
|
||||
actor->from_json(actorJson);
|
||||
|
||||
printf("After from_json: Pos(%f, %f, %f), Name: %s, Model: %s\n",
|
||||
actor->Pos.x, actor->Pos.y, actor->Pos.z, actor->Name.c_str(), actor->Model.c_str());
|
||||
gEditor.AddObject(actor->Name.c_str(), &actor->Pos, (Vec3s*)&actor->Rot, &actor->Scale, (Gfx*) nullptr, 1.0f,
|
||||
GameObject::CollisionType::BOUNDING_BOX, 20.0f, (int32_t*) &actor->bPendingDestroy, (int32_t) 1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#include <libultraship.h>
|
||||
#include "Course.h"
|
||||
|
||||
namespace Editor {
|
||||
void SaveLevel();
|
||||
void LoadLevel();
|
||||
void Load_AddStaticMeshActor(const nlohmann::json& actorJson);
|
||||
}
|
||||
@@ -18,7 +18,7 @@ const char* sBoardwalkTexList[] = { gTextureBat1, gTextureBat2, gTextureBat3, gT
|
||||
|
||||
size_t OBat::_count = 0;
|
||||
|
||||
OBat::OBat(const FVector& pos, const FRotation& rot) {
|
||||
OBat::OBat(const FVector& pos, const IRotator& rot) {
|
||||
Name = "Bat";
|
||||
find_unused_obj_index(&_objectIndex);
|
||||
|
||||
|
||||
@@ -21,14 +21,14 @@ extern "C" {
|
||||
/**
|
||||
* OBat
|
||||
*
|
||||
* FRotation does not appear to do anything.
|
||||
* IRotator does not appear to do anything.
|
||||
* Could not find where origin_pos was at.
|
||||
* So pos does not work either
|
||||
*
|
||||
*/
|
||||
class OBat : public OObject {
|
||||
public:
|
||||
explicit OBat(const FVector& pos, const FRotation& rot);
|
||||
explicit OBat(const FVector& pos, const IRotator& rot);
|
||||
|
||||
~OBat() {
|
||||
_count--;
|
||||
|
||||
@@ -18,6 +18,6 @@ void OObject::Tick60fps() {}
|
||||
void OObject::Draw(s32 cameraId) { }
|
||||
void OObject::Expire() { }
|
||||
void OObject::Destroy() {
|
||||
PendingDestroy = true;
|
||||
bPendingDestroy = true;
|
||||
}
|
||||
void OObject::Reset() { }
|
||||
|
||||
@@ -12,7 +12,7 @@ public:
|
||||
uint8_t uuid[16];
|
||||
Object o;
|
||||
const char* Name = "";
|
||||
bool PendingDestroy = false;
|
||||
bool bPendingDestroy = false;
|
||||
s32 _objectIndex = -1;
|
||||
|
||||
virtual ~OObject() = default;
|
||||
|
||||
@@ -20,7 +20,7 @@ extern "C" {
|
||||
|
||||
#define DEGREES_FLOAT_TO_SHORT(Degrees) ((s16)((Degrees) * (0x8000 / 180.0f)))
|
||||
|
||||
OTrashBin::OTrashBin(const FVector& pos, const FRotation& rotation, f32 scale, OTrashBin::Behaviour bhv) {
|
||||
OTrashBin::OTrashBin(const FVector& pos, const IRotator& rotation, f32 scale, OTrashBin::Behaviour bhv) {
|
||||
Name = "Trashbin";
|
||||
_pos = pos;
|
||||
_rot = rotation;
|
||||
|
||||
@@ -24,7 +24,7 @@ public:
|
||||
STATIC, // The lid stays shut
|
||||
MUNCHING // The lid opens/closes in a scary munching manner
|
||||
};
|
||||
explicit OTrashBin(const FVector& pos, const FRotation& rotation, f32 scale, OTrashBin::Behaviour bhv);
|
||||
explicit OTrashBin(const FVector& pos, const IRotator& rotation, f32 scale, OTrashBin::Behaviour bhv);
|
||||
|
||||
virtual void Tick() override;
|
||||
virtual void Draw(s32 cameraId) override;
|
||||
@@ -38,7 +38,7 @@ private:
|
||||
|
||||
Behaviour _bhv;
|
||||
FVector _pos;
|
||||
FRotation _rot;
|
||||
IRotator _rot;
|
||||
float _scale;
|
||||
size_t _idx;
|
||||
bool _drawBin = false;
|
||||
|
||||
@@ -45,8 +45,6 @@ float gInterpolationStep = 0.0f;
|
||||
GameEngine* GameEngine::Instance;
|
||||
|
||||
GameEngine::GameEngine() {
|
||||
std::vector<std::string> archiveFiles;
|
||||
|
||||
const std::string main_path = Ship::Context::GetPathRelativeToAppDirectory("spaghetti.o2r");
|
||||
const std::string assets_path = Ship::Context::GetPathRelativeToAppDirectory("ship.o2r");
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ class GameEngine {
|
||||
std::vector<CtlEntry*> banksTable;
|
||||
std::vector<std::string> sequenceTable;
|
||||
std::vector<AudioSequenceData*> audioSequenceTable;
|
||||
std::vector<std::string> archiveFiles;
|
||||
|
||||
ImFont* fontStandard;
|
||||
ImFont* fontStandardLarger;
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
|
||||
#include "engine/editor/Editor.h"
|
||||
#include "engine/editor/EditorMath.h"
|
||||
#include "engine/editor/SaveLevel.h"
|
||||
|
||||
extern "C" {
|
||||
#include "main.h"
|
||||
@@ -211,6 +212,9 @@ void HM_DrawIntro() {
|
||||
gMenuIntro.HM_DrawIntro();
|
||||
}
|
||||
|
||||
void CM_LoadLevelProps() {
|
||||
Editor::LoadLevel();
|
||||
}
|
||||
|
||||
World* GetWorld(void) {
|
||||
return &gWorldInstance;
|
||||
@@ -377,6 +381,11 @@ void CM_DrawActors(Camera* camera, struct Actor* actor) {
|
||||
}
|
||||
}
|
||||
|
||||
void CM_DrawStaticMeshActors() {
|
||||
printf("DRAW\n");
|
||||
gWorldInstance.DrawStaticMeshActors();
|
||||
}
|
||||
|
||||
void CM_BeginPlay() {
|
||||
Course* course = gWorldInstance.CurrentCourse;
|
||||
|
||||
@@ -674,8 +683,14 @@ void CM_CleanWorld(void) {
|
||||
for (auto& emitter : world->Emitters) {
|
||||
delete emitter;
|
||||
}
|
||||
|
||||
for (auto& actor : world->StaticMeshActors) {
|
||||
delete actor;
|
||||
}
|
||||
|
||||
gEditor.ClearObjects();
|
||||
gWorldInstance.Actors.clear();
|
||||
gWorldInstance.StaticMeshActors.clear();
|
||||
gWorldInstance.Objects.clear();
|
||||
gWorldInstance.Emitters.clear();
|
||||
gWorldInstance.Lakitus.clear();
|
||||
|
||||
@@ -26,6 +26,8 @@ void HM_InitIntro(void);
|
||||
void HM_TickIntro(void);
|
||||
void HM_DrawIntro(void);
|
||||
|
||||
void CM_LoadLevelProps();
|
||||
|
||||
void CM_DisplayBattleBombKart(s32 playerId, s32 primAlpha);
|
||||
void CM_DrawBattleBombKarts(s32 cameraId);
|
||||
|
||||
@@ -65,6 +67,7 @@ bool CM_DoesFinishlineExist();
|
||||
void CM_InitClouds();
|
||||
|
||||
void CM_DrawActors(Camera* camera, struct Actor* actor);
|
||||
void CM_DrawStaticMeshActors();
|
||||
|
||||
void CM_TickObjects();
|
||||
void CM_TickObjects60fps();
|
||||
|
||||
@@ -2,14 +2,19 @@
|
||||
#include "port/ui/PortMenu.h"
|
||||
#include "UIWidgets.h"
|
||||
#include "libultraship/src/Context.h"
|
||||
#include "port/Engine.h"
|
||||
|
||||
#include <imgui.h>
|
||||
#include <map>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <libultraship/libultraship.h>
|
||||
#include <spdlog/fmt/fmt.h>
|
||||
#include "spdlog/formatter.h"
|
||||
#include <common_structs.h>
|
||||
#include <defines.h>
|
||||
#include "CoreMath.h"
|
||||
#include "World.h"
|
||||
|
||||
namespace Editor {
|
||||
|
||||
@@ -18,9 +23,65 @@ namespace Editor {
|
||||
}
|
||||
|
||||
void ContentBrowserWindow::DrawElement() {
|
||||
ImGui::Text("This is your Content browser Lab editor window!");
|
||||
if (ImGui::Button("Click Me")) {
|
||||
// Handle button click (example)
|
||||
static bool refresh = true;
|
||||
// List the available mods/o2r files
|
||||
// for (size_t i = 0; i < GameEngine::Instance->archiveFiles.size(); i++) {
|
||||
// auto str = GameEngine::Instance->archiveFiles[i];
|
||||
// if (str.starts_with("./mods/")) {
|
||||
// ImGui::Text(GameEngine::Instance->archiveFiles[i].c_str());
|
||||
// }
|
||||
// }
|
||||
|
||||
if (ImGui::Button(ICON_FA_REFRESH)) {
|
||||
refresh = true;
|
||||
}
|
||||
|
||||
// Query content in o2r and add them to Content
|
||||
if (refresh) {
|
||||
refresh = false;
|
||||
FindContent();
|
||||
return;
|
||||
}
|
||||
|
||||
// Display entries in Content
|
||||
for (const auto& file : Content) {
|
||||
if (ImGui::Button(file.c_str())) {
|
||||
int coll;
|
||||
//printf("ContentBrowser.cpp: name: %s\n", test.c_str());
|
||||
printf("TEST %s\n", file.c_str());
|
||||
std::string name = file.substr(file.find_last_of('/') + 1);
|
||||
printf("NAME %s\n", name.c_str());
|
||||
auto actor = gWorldInstance.AddStaticMeshActor(name, FVector(50, 100, 0), IRotator(0, 90, 0), FVector(1, 1, 1), "__OTR__" + file, &coll);
|
||||
// This is required because ptr gets cleaned up.
|
||||
actor->Model = "__OTR__" + file;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ContentBrowserWindow::FindContent() {
|
||||
std::list<std::string> myList = {"objects/*"};
|
||||
std::list<std::string> myList2 = {""};
|
||||
|
||||
Content.clear();
|
||||
|
||||
auto ptr = GameEngine::Instance->context->GetResourceManager()->GetArchiveManager()->ListFiles(myList, myList2);
|
||||
if (ptr) {
|
||||
auto files = *ptr;
|
||||
for (const auto& file : files) {
|
||||
if (file.find("/mat_") != std::string::npos) {
|
||||
continue;
|
||||
} else if (file.size() >= 6 && file.substr(file.size() - 6, 5) == "_tri_" && isdigit(file.back())) {
|
||||
// ends with _tri_#
|
||||
continue;
|
||||
} else if (file.size() >= 6 && file.substr(file.size() - 6, 5) == "_vtx_" && isdigit(file.back())) {
|
||||
// ends with _vtx_#
|
||||
continue;
|
||||
}
|
||||
|
||||
Content.push_back(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,9 +7,12 @@ class ContentBrowserWindow : public Ship::GuiWindow {
|
||||
public:
|
||||
using Ship::GuiWindow::GuiWindow;
|
||||
~ContentBrowserWindow();
|
||||
|
||||
std::vector<std::string> Content;
|
||||
protected:
|
||||
void InitElement() override {};
|
||||
void DrawElement() override;
|
||||
void UpdateElement() override {};
|
||||
void FindContent();
|
||||
};
|
||||
}
|
||||
+25
-2
@@ -10,6 +10,8 @@
|
||||
#include "spdlog/formatter.h"
|
||||
#include <common_structs.h>
|
||||
#include <defines.h>
|
||||
#include "port/Game.h"
|
||||
#include "engine/editor/SaveLevel.h"
|
||||
|
||||
extern "C" {
|
||||
#include "code_800029B0.h"
|
||||
@@ -30,8 +32,22 @@ namespace Editor {
|
||||
static bool toggleGroundSnap = CVarGetInteger("gEditorSnapToGround", 0);
|
||||
static bool toggleBoundary = CVarGetInteger("gEditorBoundary", 0);
|
||||
static int selectedTool = 0; // 0: Move, 1: Rotate, 2: Scale
|
||||
static int selectedPlayTool = 0; // 0: Play, 1: Paused
|
||||
|
||||
|
||||
if (ImGui::Button(ICON_FA_FILE_TEXT_O, ImVec2(50, 25))) {
|
||||
gEditor.NewTrack();
|
||||
gWorldInstance.ClearWorld();
|
||||
gIsEditorPaused = true;
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
// Save button
|
||||
if (ImGui::Button(ICON_FA_FLOPPY_O, ImVec2(50, 25))) {
|
||||
SaveLevel();
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
ImVec4 defaultColor = ImGui::GetStyle().Colors[ImGuiCol_Button];
|
||||
// Function to check and highlight the selected button
|
||||
auto ToolButton = [&](const char* label, int id) {
|
||||
@@ -141,5 +157,12 @@ namespace Editor {
|
||||
gIsHUDVisible = !gIsHUDVisible;
|
||||
}
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
// Delete
|
||||
if (ImGui::Button(ICON_FA_TRASH_O, ImVec2(50, 25))) {
|
||||
gEditor.DeleteObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,15 +28,15 @@ namespace Editor {
|
||||
}
|
||||
|
||||
void TrackPropertiesWindow::DrawElement() {
|
||||
static char idBuffer[128] = "mk:mario_raceway";
|
||||
static char nameBuffer[128] = "Mario Raceway";
|
||||
static char debugNameBuffer[128] = "m circuit";
|
||||
static char lengthBuffer[128] = "567m";
|
||||
static char idBuffer[256] = "mk:mario_raceway";
|
||||
static char nameBuffer[256] = "Mario Raceway";
|
||||
static char debugNameBuffer[256] = "m circuit";
|
||||
static char lengthBuffer[256] = "567m";
|
||||
|
||||
ImGui::InputText("ID", idBuffer, IM_ARRAYSIZE(idBuffer));
|
||||
ImGui::InputText("Name", nameBuffer, IM_ARRAYSIZE(nameBuffer));
|
||||
ImGui::InputText("Debug Name", debugNameBuffer, IM_ARRAYSIZE(debugNameBuffer));
|
||||
ImGui::InputText("Course Length", lengthBuffer, IM_ARRAYSIZE(lengthBuffer));
|
||||
ImGui::InputText("Name", gWorldInstance.CurrentCourse->Props.Name, IM_ARRAYSIZE(nameBuffer));
|
||||
ImGui::InputText("Debug Name", gWorldInstance.CurrentCourse->Props.DebugName, IM_ARRAYSIZE(debugNameBuffer));
|
||||
ImGui::InputText("Course Length", gWorldInstance.CurrentCourse->Props.CourseLength, IM_ARRAYSIZE(lengthBuffer));
|
||||
ImGui::InputFloat("Minimap Finishline X Offset", &gWorldInstance.CurrentCourse->Props.MinimapFinishlineX);
|
||||
ImGui::InputFloat("Minimap Finishline Y Offset", &gWorldInstance.CurrentCourse->Props.MinimapFinishlineY);
|
||||
|
||||
@@ -55,12 +55,17 @@ namespace Editor {
|
||||
TrackPropertiesWindow::DrawLight();
|
||||
}
|
||||
|
||||
|
||||
if (ImGui::CollapsingHeader("AI")) {
|
||||
|
||||
ImGui::InputFloat("AI Max Separation", &gWorldInstance.CurrentCourse->Props.AIMaximumSeparation);
|
||||
ImGui::InputFloat("AI Min Separation", &gWorldInstance.CurrentCourse->Props.AIMinimumSeparation);
|
||||
ImGui::InputInt("AI Steering Sensitivity", (int*)&gWorldInstance.CurrentCourse->Props.AISteeringSensitivity);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
for (size_t i = 0; i < 32; i++) {
|
||||
ImGui::InputScalar(("Element " + std::to_string(i)).c_str(), ImGuiDataType_S16, &gWorldInstance.CurrentCourse->Props.AIDistance[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::CollapsingHeader("Random Junk")) {
|
||||
@@ -72,20 +77,20 @@ namespace Editor {
|
||||
|
||||
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
ImGui::InputFloat(fmt::format("D_0D009418[{}]", i).c_str(), &gWorldInstance.CurrentCourse->Props.D_0D009568[i]);
|
||||
ImGui::InputFloat(fmt::format("D_0D009568[{}]", i).c_str(), &gWorldInstance.CurrentCourse->Props.D_0D009568[i]);
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
ImGui::InputFloat(fmt::format("D_0D009418[{}]", i).c_str(), &gWorldInstance.CurrentCourse->Props.D_0D0096B8[i]);
|
||||
ImGui::InputFloat(fmt::format("D_0D0096B8[{}]", i).c_str(), &gWorldInstance.CurrentCourse->Props.D_0D0096B8[i]);
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
ImGui::InputFloat(fmt::format("D_0D009418[{}]", i).c_str(), &gWorldInstance.CurrentCourse->Props.D_0D009808[i]);
|
||||
ImGui::InputFloat(fmt::format("D_0D009808[{}]", i).c_str(), &gWorldInstance.CurrentCourse->Props.D_0D009808[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -1227,6 +1227,7 @@ void init_actors_and_load_textures(void) {
|
||||
init_red_shell_texture();
|
||||
destroy_all_actors();
|
||||
CM_CleanWorld();
|
||||
CM_LoadLevelProps();
|
||||
|
||||
CM_BeginPlay();
|
||||
spawn_course_actors();
|
||||
@@ -1387,7 +1388,7 @@ s16 try_remove_destructable_item(Vec3f pos, Vec3s rot, Vec3f velocity, s16 actor
|
||||
return -1;
|
||||
}
|
||||
|
||||
// returns actor index if any slot avaible returns -1
|
||||
// returns actor index if any available actor type is -1
|
||||
s16 add_actor_to_empty_slot(Vec3f pos, Vec3s rot, Vec3f velocity, s16 actorType) {
|
||||
size_t index;
|
||||
|
||||
|
||||
@@ -854,6 +854,7 @@ void render_screens(s32 mode, s32 cameraId, s32 playerId) {
|
||||
render_set_position(matrix, 0);
|
||||
}
|
||||
render_course_actors(screen);
|
||||
CM_DrawStaticMeshActors();
|
||||
render_object(mode);
|
||||
switch (screenId) {
|
||||
case 0:
|
||||
|
||||
Reference in New Issue
Block a user