mirror of https://github.com/zeldaret/botw.git
ksys/phys: Add RagdollControllerMgr
Also contains readability/accuracy fixes to LockFreeQueue.
This commit is contained in:
parent
9f8530ec90
commit
783e6a510f
|
@ -95329,14 +95329,14 @@ Address,Quality,Size,Name
|
||||||
0x00000071012ac688,O,000084,_ZN4ksys4phys24RagdollControllerKeyList20RagdollControllerKeyD2Ev
|
0x00000071012ac688,O,000084,_ZN4ksys4phys24RagdollControllerKeyList20RagdollControllerKeyD2Ev
|
||||||
0x00000071012ac6dc,O,000004,_ZN4ksys4phys24RagdollControllerKeyList20RagdollControllerKeyD0Ev
|
0x00000071012ac6dc,O,000004,_ZN4ksys4phys24RagdollControllerKeyList20RagdollControllerKeyD0Ev
|
||||||
0x00000071012ac6e0,O,000372,_ZN4ksys4phys24RagdollControllerKeyList33checkDerivedRuntimeTypeInfoStaticEPKN4sead15RuntimeTypeInfo9InterfaceE
|
0x00000071012ac6e0,O,000372,_ZN4ksys4phys24RagdollControllerKeyList33checkDerivedRuntimeTypeInfoStaticEPKN4sead15RuntimeTypeInfo9InterfaceE
|
||||||
0x00000071012ac854,U,000040,
|
0x00000071012ac854,O,000040,_ZN4ksys4phys20RagdollControllerMgrC1Ev
|
||||||
0x00000071012ac87c,U,000068,
|
0x00000071012ac87c,O,000068,_ZN4ksys4phys20RagdollControllerMgrD1Ev
|
||||||
0x00000071012ac8c0,U,000076,
|
0x00000071012ac8c0,O,000076,_ZN4ksys4phys20RagdollControllerMgrD0Ev
|
||||||
0x00000071012ac90c,U,000188,
|
0x00000071012ac90c,O,000188,_ZN4ksys4phys20RagdollControllerMgr4initEPN4sead4HeapE
|
||||||
0x00000071012ac9c8,U,000148,
|
0x00000071012ac9c8,O,000148,_ZN4ksys4phys20RagdollControllerMgr13addControllerEPNS0_17RagdollControllerE
|
||||||
0x00000071012aca5c,U,000128,
|
0x00000071012aca5c,O,000128,_ZN4ksys4phys20RagdollControllerMgr16removeControllerEPNS0_17RagdollControllerE
|
||||||
0x00000071012acadc,U,000348,
|
0x00000071012acadc,M,000348,_ZN4ksys4phys20RagdollControllerMgr4calcEv
|
||||||
0x00000071012acc38,U,000004,nullsub_4772
|
0x00000071012acc38,O,000004,_ZN4ksys4phys20RagdollControllerMgr5calc1Ev
|
||||||
0x00000071012acc3c,O,000048,_ZN4ksys4phys15RagdollResourceC1Ev
|
0x00000071012acc3c,O,000048,_ZN4ksys4phys15RagdollResourceC1Ev
|
||||||
0x00000071012acc6c,O,000004,_ZN4ksys4phys15RagdollResourceD1Ev
|
0x00000071012acc6c,O,000004,_ZN4ksys4phys15RagdollResourceD1Ev
|
||||||
0x00000071012acc70,O,000036,_ZN4ksys4phys15RagdollResourceD0Ev
|
0x00000071012acc70,O,000036,_ZN4ksys4phys15RagdollResourceD0Ev
|
||||||
|
|
Can't render this file because it is too large.
|
|
@ -11,6 +11,10 @@ target_sources(uking PRIVATE
|
||||||
Ragdoll/physRagdollConfig.h
|
Ragdoll/physRagdollConfig.h
|
||||||
Ragdoll/physRagdollControllerKeyList.h
|
Ragdoll/physRagdollControllerKeyList.h
|
||||||
Ragdoll/physRagdollControllerKeyList.cpp
|
Ragdoll/physRagdollControllerKeyList.cpp
|
||||||
|
Ragdoll/physRagdollController.cpp
|
||||||
|
Ragdoll/physRagdollController.h
|
||||||
|
Ragdoll/physRagdollControllerMgr.cpp
|
||||||
|
Ragdoll/physRagdollControllerMgr.h
|
||||||
Ragdoll/physRagdollParam.cpp
|
Ragdoll/physRagdollParam.cpp
|
||||||
Ragdoll/physRagdollParam.h
|
Ragdoll/physRagdollParam.h
|
||||||
Ragdoll/physRagdollResource.cpp
|
Ragdoll/physRagdollResource.cpp
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
#include "KingSystem/Physics/Ragdoll/physRagdollController.h"
|
|
@ -0,0 +1,11 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace ksys::phys {
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
class RagdollController {
|
||||||
|
public:
|
||||||
|
void update();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ksys::phys
|
|
@ -0,0 +1,49 @@
|
||||||
|
#include "KingSystem/Physics/Ragdoll/physRagdollControllerMgr.h"
|
||||||
|
#include <prim/seadScopedLock.h>
|
||||||
|
#include "KingSystem/Physics/Ragdoll/physRagdollController.h"
|
||||||
|
#include "KingSystem/Physics/System/physSystem.h"
|
||||||
|
|
||||||
|
namespace ksys::phys {
|
||||||
|
|
||||||
|
RagdollControllerMgr::RagdollControllerMgr() = default;
|
||||||
|
|
||||||
|
RagdollControllerMgr::~RagdollControllerMgr() {
|
||||||
|
mControllers.freeBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RagdollControllerMgr::init(sead::Heap* heap) {
|
||||||
|
mControllers.alloc(0x400, heap);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RagdollControllerMgr::addController(RagdollController* controller) {
|
||||||
|
return mControllers.push(controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RagdollControllerMgr::removeController(RagdollController* controller) {
|
||||||
|
auto lock = sead::makeScopedLock(mCS);
|
||||||
|
mControllers.erase(controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RagdollControllerMgr::calc() {
|
||||||
|
ScopedWorldLock world_lock{ContactLayerType::Entity};
|
||||||
|
auto lock = sead::makeScopedLock(mCS);
|
||||||
|
|
||||||
|
RagdollController* first_processed = nullptr;
|
||||||
|
|
||||||
|
while (auto* ctrl = mControllers.pop()) {
|
||||||
|
mControllers.push(ctrl);
|
||||||
|
|
||||||
|
// If we have processed the entire buffer and wrapped around, stop.
|
||||||
|
if (first_processed == ctrl)
|
||||||
|
break;
|
||||||
|
|
||||||
|
ctrl->update();
|
||||||
|
|
||||||
|
if (first_processed == nullptr)
|
||||||
|
first_processed = ctrl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RagdollControllerMgr::calc1() {}
|
||||||
|
|
||||||
|
} // namespace ksys::phys
|
|
@ -0,0 +1,32 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <thread/seadCriticalSection.h>
|
||||||
|
#include "KingSystem/Utils/Container/LockFreeQueue.h"
|
||||||
|
|
||||||
|
namespace sead {
|
||||||
|
class Heap;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ksys::phys {
|
||||||
|
|
||||||
|
class RagdollController;
|
||||||
|
|
||||||
|
class RagdollControllerMgr {
|
||||||
|
public:
|
||||||
|
RagdollControllerMgr();
|
||||||
|
virtual ~RagdollControllerMgr();
|
||||||
|
|
||||||
|
void init(sead::Heap* heap);
|
||||||
|
|
||||||
|
bool addController(RagdollController* controller);
|
||||||
|
void removeController(RagdollController* controller);
|
||||||
|
|
||||||
|
void calc();
|
||||||
|
void calc1();
|
||||||
|
|
||||||
|
private:
|
||||||
|
util::LockFreeQueue<RagdollController> mControllers;
|
||||||
|
sead::CriticalSection mCS;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ksys::phys
|
|
@ -32,30 +32,25 @@ public:
|
||||||
|
|
||||||
/// Pop an element from the front of the queue. Non-blocking.
|
/// Pop an element from the front of the queue. Non-blocking.
|
||||||
/// @returns a non-null pointer to an element or nullptr if the queue is empty.
|
/// @returns a non-null pointer to an element or nullptr if the queue is empty.
|
||||||
|
// NON_MATCHING: control flow is a total mess
|
||||||
T* pop() {
|
T* pop() {
|
||||||
while (true) {
|
while (getSize() > 0) {
|
||||||
int read_idx = mReadIdx;
|
|
||||||
if (mWriteIdx - read_idx <= 0) {
|
|
||||||
// The queue is empty.
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// No need to check if mWriteIdx has changed: the only thing that *could*
|
// No need to check if mWriteIdx has changed: the only thing that *could*
|
||||||
// happen is mWriteIdx being incremented by a producer. In that situation
|
// happen is mWriteIdx being incremented by a producer. In that situation
|
||||||
// mWriteIdx - read_idx > 0 still holds.
|
// mWriteIdx - read_idx > 0 still holds.
|
||||||
|
|
||||||
T* value = get(read_idx);
|
T* value = get(mReadIdx);
|
||||||
if (!value) {
|
if (!value) {
|
||||||
SEAD_ASSERT_MSG(false, "corrupted buffer");
|
SEAD_ASSERT_MSG(false, "corrupted buffer");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Advance the read position and return the value if it's not a dummy pointer.
|
// Advance the read position and return the value if it's not a dummy pointer.
|
||||||
mReadIdx = read_idx + 1;
|
get(mReadIdx++) = nullptr;
|
||||||
get(read_idx) = nullptr;
|
|
||||||
if (uintptr_t(value) != uintptr_t(-1))
|
if (uintptr_t(value) != uintptr_t(-1))
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Push a new element at the back of the queue. Non-blocking: may fail if the queue is full.
|
/// Push a new element at the back of the queue. Non-blocking: may fail if the queue is full.
|
||||||
|
@ -65,8 +60,8 @@ public:
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const int write_idx = mWriteIdx;
|
const u32 write_idx = mWriteIdx;
|
||||||
if (write_idx - mReadIdx >= getCapacity()) {
|
if (int(write_idx) - int(mReadIdx) >= getCapacity()) {
|
||||||
// The buffer is full.
|
// The buffer is full.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -85,19 +80,28 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
/// Erase an element from the queue.
|
||||||
T*& get(int idx) { return mBuffer(moduloCapacity(idx)); }
|
/// @warning Not thread safe!
|
||||||
const T*& get(int idx) const { return mBuffer(moduloCapacity(idx)); }
|
void erase(T* value) {
|
||||||
|
for (u32 i = mReadIdx; i < mWriteIdx; ++i) {
|
||||||
|
if (get(i) == value)
|
||||||
|
get(i) = reinterpret_cast<T*>(uintptr_t(-1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int moduloCapacity(int idx) const {
|
private:
|
||||||
|
T*& get(u32 idx) { return mBuffer(moduloCapacity(idx)); }
|
||||||
|
const T*& get(u32 idx) const { return mBuffer(moduloCapacity(idx)); }
|
||||||
|
|
||||||
|
int moduloCapacity(u32 idx) const {
|
||||||
// Because the capacity is a power of 2, we can avoid costly divisions
|
// Because the capacity is a power of 2, we can avoid costly divisions
|
||||||
// and instead rely on x % 2^n being equal to x & (2^n - 1).
|
// and instead rely on x % 2^n being equal to x & (2^n - 1).
|
||||||
return idx & (getCapacity() - 1);
|
return idx & (getCapacity() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
sead::Buffer<T*> mBuffer;
|
sead::Buffer<T*> mBuffer;
|
||||||
sead::Atomic<int> mWriteIdx;
|
sead::Atomic<u32> mWriteIdx;
|
||||||
int mReadIdx{};
|
u32 mReadIdx{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ksys::util
|
} // namespace ksys::util
|
||||||
|
|
Loading…
Reference in New Issue