mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2025-04-28 13:17:58 +03:00
Add ObjectExtension system
This commit is contained in:
parent
c5e0e32391
commit
2b284f4b07
6 changed files with 190 additions and 1 deletions
|
@ -15,6 +15,7 @@
|
||||||
#include <libultraship/libultraship.h>
|
#include <libultraship/libultraship.h>
|
||||||
#include "soh/OTRGlobals.h"
|
#include "soh/OTRGlobals.h"
|
||||||
#include "soh/cvar_prefixes.h"
|
#include "soh/cvar_prefixes.h"
|
||||||
|
#include "soh/ObjectExtension/ActorListIndex.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <z64.h>
|
#include <z64.h>
|
||||||
|
@ -924,6 +925,7 @@ void ActorViewerWindow::DrawElement() {
|
||||||
ImGui::Text("Category: %s", acMapping[display->category]);
|
ImGui::Text("Category: %s", acMapping[display->category]);
|
||||||
ImGui::Text("ID: %d", display->id);
|
ImGui::Text("ID: %d", display->id);
|
||||||
ImGui::Text("Parameters: %d", display->params);
|
ImGui::Text("Parameters: %d", display->params);
|
||||||
|
ImGui::Text("Actor List Index: %d", GetActorListIndex(display));
|
||||||
},
|
},
|
||||||
"Selected Actor");
|
"Selected Actor");
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
16
soh/soh/ObjectExtension/ActorListIndex.cpp
Normal file
16
soh/soh/ObjectExtension/ActorListIndex.cpp
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#include "ActorListIndex.h"
|
||||||
|
#include "soh/ObjectExtension/ObjectExtension.h"
|
||||||
|
|
||||||
|
struct ActorListIndex {
|
||||||
|
s16 index = -1;
|
||||||
|
};
|
||||||
|
static ObjectExtension::Register<ActorListIndex> ActorListIndexRegister;
|
||||||
|
|
||||||
|
int16_t GetActorListIndex(const Actor* actor) {
|
||||||
|
const ActorListIndex* index = ObjectExtension::GetInstance().Get<ActorListIndex>(actor);
|
||||||
|
return index != nullptr ? index->index : ActorListIndex{}.index;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetActorListIndex(const Actor* actor, int16_t index) {
|
||||||
|
ObjectExtension::GetInstance().Set<ActorListIndex>(actor, ActorListIndex{ index });
|
||||||
|
}
|
16
soh/soh/ObjectExtension/ActorListIndex.h
Normal file
16
soh/soh/ObjectExtension/ActorListIndex.h
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#ifndef ACTOR_LIST_INDEX_H
|
||||||
|
#define ACTOR_LIST_INDEX_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#include "z64actor.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int16_t GetActorListIndex(const Actor* actor);
|
||||||
|
void SetActorListIndex(const Actor* actor, int16_t index);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // ACTOR_LIST_INDEX_H
|
25
soh/soh/ObjectExtension/ObjectExtension.cpp
Normal file
25
soh/soh/ObjectExtension/ObjectExtension.cpp
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#include "ObjectExtension.h"
|
||||||
|
|
||||||
|
ObjectExtension& ObjectExtension::GetInstance() {
|
||||||
|
static ObjectExtension instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectExtension::Id ObjectExtension::RegisterId() {
|
||||||
|
return NextId++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjectExtension::Free(const void* object) {
|
||||||
|
if (object == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::erase_if(Data, [&object](const auto& iter) {
|
||||||
|
auto const& [key, value] = iter;
|
||||||
|
return key.first == object;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void ObjectExtension_Free(const void* object) {
|
||||||
|
ObjectExtension::GetInstance().Free(object);
|
||||||
|
}
|
116
soh/soh/ObjectExtension/ObjectExtension.h
Normal file
116
soh/soh/ObjectExtension/ObjectExtension.h
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
#include <libultraship/libultraship.h>
|
||||||
|
|
||||||
|
#include <any>
|
||||||
|
#include <limits>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This class can attach additional data to pointers. It can only attach a single instance of each type of data.
|
||||||
|
* Use the ObjectExtension::Register class to register a type to be used as an object extension.
|
||||||
|
* An example usage is:
|
||||||
|
*
|
||||||
|
* struct MyData {
|
||||||
|
* s32 data = -1;
|
||||||
|
* };
|
||||||
|
* static ObjectExtension::Register<MyData> MyDataRegister;
|
||||||
|
*
|
||||||
|
* Then you can get with
|
||||||
|
* ObjectExtension::GetInstance().Get<MyData>(ptr);
|
||||||
|
* and set with
|
||||||
|
* ObjectExtension::GetInstance().Set<MyData>(ptr, MyData{});
|
||||||
|
* (or with the returned pointer from Get()).
|
||||||
|
*/
|
||||||
|
class ObjectExtension {
|
||||||
|
public:
|
||||||
|
using Id = uint32_t;
|
||||||
|
|
||||||
|
static constexpr Id InvalidId = std::numeric_limits<Id>::max();
|
||||||
|
|
||||||
|
// Registers type T to be used as an object extension
|
||||||
|
template <typename T> class Register {
|
||||||
|
public:
|
||||||
|
Register() {
|
||||||
|
Id = ObjectExtension::GetInstance().RegisterId();
|
||||||
|
}
|
||||||
|
|
||||||
|
static ObjectExtension::Id Id;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Gets the singleton ObjectExtension instance
|
||||||
|
static ObjectExtension& GetInstance();
|
||||||
|
|
||||||
|
// Gets the data of type T associated with an object, or nullptr if no such data has been attached
|
||||||
|
template <typename T> T* Get(const void* object) {
|
||||||
|
assert(ObjectExtension::Register<T>::Id != InvalidId);
|
||||||
|
if (object == nullptr) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto it = Data.find(std::make_pair(object, ObjectExtension::Register<T>::Id));
|
||||||
|
if (it == Data.end()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::any_cast<T>(&(it->second));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets the data of type T for an object. Data will be copied.
|
||||||
|
template <typename T> void Set(const void* object, const T&& data) {
|
||||||
|
assert(ObjectExtension::Register<T>::Id != InvalidId);
|
||||||
|
if (object != nullptr) {
|
||||||
|
Data[std::make_pair(object, ObjectExtension::Register<T>::Id)] = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if an object has data of type T associated with it
|
||||||
|
template <typename T> bool Has(const void* object) {
|
||||||
|
assert(ObjectExtension::Register<T>::Id != InvalidId);
|
||||||
|
if (object == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Data.contains(std::make_pair(object, ObjectExtension::Register<T>::Id));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removes data of type T from an object
|
||||||
|
template <typename T> void Remove(const void* object) {
|
||||||
|
assert(ObjectExtension::Register<T>::Id != InvalidId);
|
||||||
|
|
||||||
|
Data.erase(std::make_pair(object, ObjectExtension::Register<T>::Id));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removes all data from an object
|
||||||
|
void Free(const void* object);
|
||||||
|
|
||||||
|
private:
|
||||||
|
ObjectExtension() = default;
|
||||||
|
|
||||||
|
// Returns the next free object extension Id
|
||||||
|
Id RegisterId();
|
||||||
|
|
||||||
|
ObjectExtension::Id NextId = 0;
|
||||||
|
|
||||||
|
struct KeyHash {
|
||||||
|
std::size_t operator()(const std::pair<const void*, ObjectExtension::Id>& key) const {
|
||||||
|
return std::hash<const void*>{}(key.first) ^ (std::hash<ObjectExtension::Id>{}(key.second) << 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Collection of all object extension data.
|
||||||
|
std::unordered_map<std::pair<const void*, ObjectExtension::Id>, std::any, KeyHash> Data;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Static template globals
|
||||||
|
template <typename T> ObjectExtension::Id ObjectExtension::Register<T>::Id = ObjectExtension::InvalidId;
|
||||||
|
|
||||||
|
#else // __cplusplus
|
||||||
|
|
||||||
|
void ObjectExtension_Free(const void* object);
|
||||||
|
|
||||||
|
#endif // __cplusplus
|
|
@ -7,6 +7,8 @@
|
||||||
#include "objects/gameplay_keep/gameplay_keep.h"
|
#include "objects/gameplay_keep/gameplay_keep.h"
|
||||||
#include "objects/gameplay_dangeon_keep/gameplay_dangeon_keep.h"
|
#include "objects/gameplay_dangeon_keep/gameplay_dangeon_keep.h"
|
||||||
#include "objects/object_bdoor/object_bdoor.h"
|
#include "objects/object_bdoor/object_bdoor.h"
|
||||||
|
#include "soh/ObjectExtension/ObjectExtension.h"
|
||||||
|
#include "soh/ObjectExtension/ActorListIndex.h"
|
||||||
#include "soh/frame_interpolation.h"
|
#include "soh/frame_interpolation.h"
|
||||||
#include "soh/Enhancements/cosmetics/cosmeticsTypes.h"
|
#include "soh/Enhancements/cosmetics/cosmeticsTypes.h"
|
||||||
#include "soh/Enhancements/enemyrandomizer.h"
|
#include "soh/Enhancements/enemyrandomizer.h"
|
||||||
|
@ -2574,7 +2576,11 @@ void Actor_UpdateAll(PlayState* play, ActorContext* actorCtx) {
|
||||||
if (play->numSetupActors != 0) {
|
if (play->numSetupActors != 0) {
|
||||||
actorEntry = &play->setupActorList[0];
|
actorEntry = &play->setupActorList[0];
|
||||||
for (i = 0; i < play->numSetupActors; i++) {
|
for (i = 0; i < play->numSetupActors; i++) {
|
||||||
Actor_SpawnEntry(&play->actorCtx, actorEntry++, play);
|
Actor* spawnedActor = Actor_SpawnEntry(&play->actorCtx, actorEntry++, play);
|
||||||
|
|
||||||
|
// #region SOH [ObjectExtension] ActorListIndex tracking
|
||||||
|
SetActorListIndex(spawnedActor, (s16)i);
|
||||||
|
// #endregion
|
||||||
}
|
}
|
||||||
play->numSetupActors = 0;
|
play->numSetupActors = 0;
|
||||||
GameInteractor_ExecuteOnSceneSpawnActors();
|
GameInteractor_ExecuteOnSceneSpawnActors();
|
||||||
|
@ -3352,6 +3358,10 @@ Actor* Actor_Spawn(ActorContext* actorCtx, PlayState* play, s16 actorId, f32 pos
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #region SOH [ObjectExtension]
|
||||||
|
SetActorListIndex(actor, -1);
|
||||||
|
// #endregion
|
||||||
|
|
||||||
assert(dbEntry->numLoaded < 255);
|
assert(dbEntry->numLoaded < 255);
|
||||||
|
|
||||||
dbEntry->numLoaded++;
|
dbEntry->numLoaded++;
|
||||||
|
@ -3494,6 +3504,10 @@ Actor* Actor_Delete(ActorContext* actorCtx, Actor* actor, PlayState* play) {
|
||||||
|
|
||||||
newHead = Actor_RemoveFromCategory(play, actorCtx, actor);
|
newHead = Actor_RemoveFromCategory(play, actorCtx, actor);
|
||||||
|
|
||||||
|
// #region SOH [ObjectExtension]
|
||||||
|
ObjectExtension_Free(actor);
|
||||||
|
// #endregion
|
||||||
|
|
||||||
ZELDA_ARENA_FREE_DEBUG(actor);
|
ZELDA_ARENA_FREE_DEBUG(actor);
|
||||||
|
|
||||||
dbEntry->numLoaded--;
|
dbEntry->numLoaded--;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue