ksys/evt: Add ResourceFlowchart

This commit is contained in:
Léo Lam 2021-06-17 12:23:53 +02:00
parent 4014329dc2
commit 92388bad74
No known key found for this signature in database
GPG Key ID: 0DF30F9081000741
9 changed files with 387 additions and 15 deletions

View File

@ -75807,20 +75807,20 @@
0x0000007100dc4cb4,evt::ActorBindings::dtor,160,_ZN4ksys3evt13ActorBindingsD1Ev 0x0000007100dc4cb4,evt::ActorBindings::dtor,160,_ZN4ksys3evt13ActorBindingsD1Ev
0x0000007100dc4d54,evt::ActorBindings::dtorDelete,168,_ZN4ksys3evt13ActorBindingsD0Ev 0x0000007100dc4d54,evt::ActorBindings::dtorDelete,168,_ZN4ksys3evt13ActorBindingsD0Ev
0x0000007100dc4dfc,evt::ActorBindings::bindActor,448,_ZN4ksys3evt13ActorBindings9bindActorEPKN4evfl8ResActorEPN4sead4HeapE 0x0000007100dc4dfc,evt::ActorBindings::bindActor,448,_ZN4ksys3evt13ActorBindings9bindActorEPKN4evfl8ResActorEPN4sead4HeapE
0x0000007100dc4fbc,ResourceFlowchart::ctor,216, 0x0000007100dc4fbc,ResourceFlowchart::ctor,216,_ZN4ksys3evt17ResourceFlowchartC1Ev
0x0000007100dc5094,sub_7100DC5094,312, 0x0000007100dc5094,sub_7100DC5094,312,_ZN4ksys3evt17ResourceFlowchartD1Ev
0x0000007100dc51cc,sub_7100DC51CC,36, 0x0000007100dc51cc,sub_7100DC51CC,36,_ZN4ksys3evt17ResourceFlowchartD0Ev
0x0000007100dc51f0,ResourceFlowchart::loadBfevfl,688, 0x0000007100dc51f0,ResourceFlowchart::loadBfevfl,688,_ZN4ksys3evt17ResourceFlowchart13loadEventFlowEPN4sead4HeapEPNS_3res6HandleE
0x0000007100dc54a0,ResourceFlowchart::finishLoad,348, 0x0000007100dc54a0,ResourceFlowchart::finishLoad,348,_ZN4ksys3evt17ResourceFlowchart10finishLoadEv
0x0000007100dc55fc,ResourceFlowchart::initFlowchartContext,644, 0x0000007100dc55fc,ResourceFlowchart::initFlowchartContext,644,_ZN4ksys3evt17ResourceFlowchart13setUpBindingsEPNS0_13ActorBindingsEPN4sead4HeapE
0x0000007100dc5880,ResourceFlowchart::buildFlowchart,1488, 0x0000007100dc5880,ResourceFlowchart::buildFlowchart,1488,_ZN4ksys3evt17ResourceFlowchart14buildFlowchartEPN4evfl16FlowchartContextEPN4sead4HeapE
0x0000007100dc5e50,evt::bindActorActions,408, 0x0000007100dc5e50,evt::bindActorActions,408,_ZN4ksys3evt16bindActorActionsERN4evfl16FlowchartContextENS_3res21EventFlowActionBinderE
0x0000007100dc5fe8,nullsub_3848,4, 0x0000007100dc5fe8,nullsub_3848,4,_ZN4ksys3res15EventFlowBinderD2Ev
0x0000007100dc5fec,evt::bindActorQueries,408, 0x0000007100dc5fec,evt::bindActorQueries,408,_ZN4ksys3evt16bindActorQueriesERN4evfl16FlowchartContextENS_3res20EventFlowQueryBinderE
0x0000007100dc6184,sub_7100DC6184,140, 0x0000007100dc6184,sub_7100DC6184,140,_ZNK4ksys3evt17ResourceFlowchart16isResourceLoadedERKN4sead14SafeStringBaseIcEE
0x0000007100dc6210,j__ZdlPv_889,4, 0x0000007100dc6210,j__ZdlPv_889,4,_ZN4ksys3res20EventFlowActorBinderD0Ev
0x0000007100dc6214,j__ZdlPv_890,4, 0x0000007100dc6214,j__ZdlPv_890,4,_ZN4ksys3res21EventFlowActionBinderD0Ev
0x0000007100dc6218,j__ZdlPv_891,4, 0x0000007100dc6218,j__ZdlPv_891,4,_ZN4ksys3res20EventFlowQueryBinderD0Ev
0x0000007100dc621c,ResourceTimeline::ctor,136, 0x0000007100dc621c,ResourceTimeline::ctor,136,
0x0000007100dc62a4,sub_7100DC62A4,180, 0x0000007100dc62a4,sub_7100DC62A4,180,
0x0000007100dc6358,sub_7100DC6358,176, 0x0000007100dc6358,sub_7100DC6358,176,

Can't render this file because it is too large.

@ -1 +1 @@
Subproject commit 18dcfd780faf1d5af5b089b92db5cfd329a306d6 Subproject commit 1bb352ff3e27137c6345f2f9ca71994da3a7abfc

View File

@ -9,6 +9,8 @@ target_sources(uking PRIVATE
evtDemoInfo.h evtDemoInfo.h
evtEvent.cpp evtEvent.cpp
evtEvent.h evtEvent.h
evtEventResource.cpp
evtEventResource.h
evtInfoData.cpp evtInfoData.cpp
evtInfoData.h evtInfoData.h
evtManager.cpp evtManager.cpp
@ -17,4 +19,6 @@ target_sources(uking PRIVATE
evtMetadata.h evtMetadata.h
evtOrderParam.cpp evtOrderParam.cpp
evtOrderParam.h evtOrderParam.h
evtResourceFlowchart.cpp
evtResourceFlowchart.h
) )

View File

@ -25,6 +25,7 @@ public:
ActorBinding* bindActor(const evfl::ResActor* res_actor, sead::Heap* heap); ActorBinding* bindActor(const evfl::ResActor* res_actor, sead::Heap* heap);
int isInitialized() const { return mInitialized; } int isInitialized() const { return mInitialized; }
int getNumBindings() const { return mBindings.size(); }
private: private:
sead::PtrArray<ActorBinding> mBindings; sead::PtrArray<ActorBinding> mBindings;

View File

@ -0,0 +1 @@
#include "KingSystem/Event/evtEventResource.h"

View File

@ -0,0 +1,27 @@
#pragma once
#include <basis/seadTypes.h>
#include <evfl/EvflAllocator.h>
namespace sead {
class Heap;
}
namespace ksys::evt {
// TODO
class EventResource {};
void* eventFlowAlloc(size_t size, size_t alignment, void* userdata);
void eventFlowFree(void* ptr, void* userdata);
inline evfl::AllocateArg makeEvflAllocateArg(sead::Heap* heap) {
evfl::AllocateArg arg{};
arg.alloc = eventFlowAlloc;
arg.free = eventFlowFree;
arg.alloc_userdata = heap;
arg.free_userdata = heap;
return arg;
}
} // namespace ksys::evt

View File

@ -0,0 +1,283 @@
#include "KingSystem/Event/evtResourceFlowchart.h"
#include <array>
#include <evfl/Flowchart.h>
#include <evfl/ResEventFlowFile.h>
#include "KingSystem/Event/evtActorBindings.h"
#include "KingSystem/Event/evtEventResource.h"
#include "KingSystem/Event/evtInfoData.h"
#include "KingSystem/Resource/Event/resEventFlowBinder.h"
#include "KingSystem/Resource/Event/resResourceEventFlow.h"
#include "KingSystem/Resource/resLoadRequest.h"
#include "KingSystem/Resource/resResourceMgrTask.h"
#include "KingSystem/Utils/Byaml/Byaml.h"
#include "KingSystem/Utils/HeapUtil.h"
namespace ksys::evt {
ResourceFlowchart::ResourceFlowchart() {
mLoadFailed = false;
}
ResourceFlowchart::~ResourceFlowchart() {
for (int i = 0; i < mFlowcharts.size(); ++i)
mFlowcharts[i].handle.requestUnload2();
mFlowcharts.freeBuffer();
if (mMissingFlowcharts.isBufferReady()) {
for (int i = 0; i < mFlowcharts.size(); ++i)
mMissingFlowcharts[i].handle.requestUnload2();
mMissingFlowcharts.freeBuffer();
}
}
void ResourceFlowchart::loadEventFlow(sead::Heap* heap, res::Handle* pack_handle) {
al::ByamlIter event_info;
al::ByamlIter subfiles;
int num_flowcharts = 1;
if (InfoData::instance()->getEntry(&event_info, mName, mEntryPoint) &&
event_info.tryGetIterByKey(&subfiles, "subfile")) {
num_flowcharts = subfiles.getSize() + 1;
}
mFlowcharts.allocBufferAssert(num_flowcharts, heap);
res::LoadRequest request;
request.mRequester = "ResourceFlowchart";
request.mPackHandle = pack_handle;
request._22 = true;
// Load the main flowchart.
sead::FixedSafeString<128> path;
mFlowcharts[0].loaded = false;
path.format("EventFlow/%s.bfevfl", mName.cstr());
mFlowcharts[0].handle.requestLoad(path, &request);
// Load any subfiles.
for (int i = 1; i < num_flowcharts; ++i) {
al::ByamlIter file_entry;
subfiles.tryGetIterByIndex(&file_entry, i - 1);
const char* file_name;
file_entry.tryGetStringByKey(&file_name, "file");
mFlowcharts[i].loaded = false;
path.format("EventFlow/%s", file_name);
mFlowcharts[i].handle.requestLoad(path, &request);
}
}
bool ResourceFlowchart::finishLoad() {
bool ready = true;
for (int i = 0; i < mFlowcharts.size(); ++i) {
auto& flowchart = mFlowcharts[i];
if (flowchart.loaded)
continue;
if (flowchart.handle.isReadyOrNeedsParse())
flowchart.handle.parseResource(nullptr);
if (flowchart.handle.isSuccess()) {
auto* evfl_res = sead::DynamicCast<res::EventFlowchart>(flowchart.handle.getResource());
if (evfl_res) {
flowchart.res_event_flow_file = evfl_res->getRes();
flowchart.res_flowchart = flowchart.res_event_flow_file->flowcharts.Get()->Get();
flowchart.loaded = true;
}
} else if (flowchart.handle.checkLoadStatus()) {
flowchart.loaded = true;
mLoadFailed = true;
}
if (!flowchart.loaded)
ready = false;
}
return ready;
}
long bindActorActions(evfl::FlowchartContext& context, res::EventFlowActionBinder binder) {
u8 any_ok = 0;
u8 any_failed = 0;
for (auto it = context.GetObjs().begin(); it != context.GetObjs().end(); ++it) {
bool ok;
bool failed;
auto binder_ = binder;
ok = false;
failed = false;
auto& evfl_bindings = it->GetActBinder().GetBindings();
for (auto b = evfl_bindings.begin(); b != evfl_bindings.end(); ++b) {
if (!b->IsUsed() || !b->IsInitialized())
continue;
const auto* actor = b->GetActor();
for (auto a = b->GetActions().begin(); a != b->GetActions().end(); ++a) {
binder_.bind(a, a->res_action, actor, static_cast<ActorBinding*>(b->GetUserData()));
(a->handler ? ok : failed) = true;
}
}
if (ok)
any_ok = 1;
if (failed)
any_failed = 1;
}
return (int(any_failed) << 8) | int(any_ok);
}
long bindActorQueries(evfl::FlowchartContext& context, res::EventFlowQueryBinder binder) {
u8 any_ok = 0;
u8 any_failed = 0;
for (auto it = context.GetObjs().begin(); it != context.GetObjs().end(); ++it) {
bool ok;
bool failed;
auto binder_ = binder;
ok = false;
failed = false;
auto& evfl_bindings = it->GetActBinder().GetBindings();
for (auto b = evfl_bindings.begin(); b != evfl_bindings.end(); ++b) {
if (!b->IsUsed() || !b->IsInitialized())
continue;
const auto* actor = b->GetActor();
for (auto q = b->GetQueries().begin(); q != b->GetQueries().end(); ++q) {
binder_.bind(q, q->res_query, actor, static_cast<ActorBinding*>(b->GetUserData()));
(q->handler ? ok : failed) = true;
}
}
if (ok)
any_ok = 1;
if (failed)
any_failed = 1;
}
return (int(any_failed) << 8) | int(any_ok);
}
bool ResourceFlowchart::setUpBindings(ActorBindings* bindings, sead::Heap* heap) {
evfl::FlowchartContext context;
if (!buildFlowchart(&context, heap))
return false;
// Bind actors. We do it twice: once in order to figure out how many actor bindings
// need to be allocated, and a second time to actually bind actors.
const auto bind_actors = [&] {
for (auto it = context.GetObjs().begin(); it != context.GetObjs().end(); ++it) {
bool ok;
bool failed;
res::EventFlowActorBinder binder{bindings, heap};
ok = false;
failed = false;
auto& evfl_bindings = it->GetActBinder().GetBindings();
for (auto binding = evfl_bindings.begin(); binding != evfl_bindings.end(); ++binding) {
if (binding->IsUsed() && !binding->IsInitialized()) {
binder.bind(binding, binding->GetActor());
(binding->IsInitialized() ? ok : failed) = true;
}
}
}
};
bind_actors();
bindings->allocBindings(heap);
bind_actors();
// Bind actions.
res::EventFlowActionBinder action_binder_1{bindings, heap};
bindActorActions(context, action_binder_1);
bindings->allocBindingsActions(heap);
res::EventFlowActionBinder action_binder_2{bindings, heap};
bindActorActions(context, action_binder_2);
// Bind queries.
res::EventFlowQueryBinder query_binder_1{bindings, heap};
bindActorQueries(context, query_binder_1);
bindings->allocBindingsQueries(heap);
res::EventFlowQueryBinder query_binder_2{bindings, heap};
bindActorQueries(context, query_binder_2);
context.UnbindAll();
return bindings->getNumBindings() != 0;
}
bool ResourceFlowchart::buildFlowchart(evfl::FlowchartContext* context, sead::Heap* heap) {
std::array<const evfl::ResFlowchart*, 32> flowcharts;
int num_flowcharts = 0;
const auto add_flowcharts = [&] {
for (int i = 0; i < mFlowcharts.size(); ++i)
flowcharts[num_flowcharts++] = mFlowcharts[i].res_flowchart;
};
add_flowcharts();
evfl::FlowchartContext::Builder builder({flowcharts.data(), num_flowcharts});
if (!builder.SetEntryPoint(mName.cstr(), mEntryPoint.cstr()))
return false;
evfl::FlowchartContext::Builder::BuildResult result;
if (builder.Build(&result, context, makeEvflAllocateArg(heap)))
return true;
// Load any missing flowchart.
// Note: this only works in debug builds; in release builds there is no debug heap
// to allocate the mMissingFlowcharts buffer.
mMissingFlowcharts.freeBuffer();
static constexpr int NumFallbackRes = 8;
for (int i = 0; i < NumFallbackRes; ++i) {
if (result.result !=
evfl::FlowchartContext::Builder::BuildResultType::kResFlowchartNotFound) {
continue;
}
sead::FormatFixedSafeString<128> path("EventFlow/%s.bfevfl",
result.missing_flowchart_name.data());
if (!mMissingFlowcharts.isBufferReady())
mMissingFlowcharts.allocBufferAssert(NumFallbackRes, util::getDebugHeap());
res::ResourceMgrTask::instance()->controlField9c0d88(false);
mMissingFlowcharts[i].handle.load(path, nullptr);
res::ResourceMgrTask::instance()->controlField9c0d88(true);
/// @bug Bug? This causes all flowcharts in mFlowcharts to be added more than once...
add_flowcharts();
for (int flow_idx = 0; flow_idx < i + 1; ++flow_idx) {
auto* flowchart = sead::DynamicCast<res::EventFlowchart>(
mMissingFlowcharts[flow_idx].handle.getResource());
flowcharts[num_flowcharts++] = flowchart->getRes()->flowcharts.Get()->Get();
}
evfl::FlowchartContext::Builder builder2({flowcharts.data(), num_flowcharts});
if (!builder2.SetEntryPoint(mName.cstr(), mEntryPoint.cstr()))
continue;
if (!builder2.Build(&result, context, makeEvflAllocateArg(heap)))
continue;
return true;
}
return false;
}
bool ResourceFlowchart::isResourceLoaded(const sead::SafeString& path_substring) const {
for (int i = 0; i < mFlowcharts.size(); ++i) {
auto* unit = mFlowcharts[i].handle.getUnit();
if (unit && unit->getPath().include(path_substring))
return true;
}
return false;
}
} // namespace ksys::evt

View File

@ -0,0 +1,51 @@
#pragma once
#include <container/seadBuffer.h>
#include <prim/seadSafeString.h>
#include "KingSystem/Resource/resHandle.h"
namespace evfl {
class FlowchartContext;
struct ResEventFlowFile;
struct ResFlowchart;
} // namespace evfl
namespace ksys::evt {
class ActorBindings;
class ResourceFlowchart {
public:
ResourceFlowchart();
virtual ~ResourceFlowchart();
/// Loads event flowchart resource files asynchronously.
void loadEventFlow(sead::Heap* heap, res::Handle* pack_handle);
/// @return true if the load completed (succeeded or failed), false if it is still ongoing.
bool finishLoad();
/// @return whether at least one actor was bound.
bool setUpBindings(ActorBindings* bindings, sead::Heap* heap);
/// @return whether the build was successful.
bool buildFlowchart(evfl::FlowchartContext* context, sead::Heap* heap);
bool isResourceLoaded(const sead::SafeString& path_substring) const;
private:
struct Res {
res::Handle handle;
const evfl::ResEventFlowFile* res_event_flow_file;
const evfl::ResFlowchart* res_flowchart;
bool loaded;
};
sead::Buffer<Res> mFlowcharts;
sead::Buffer<Res> mMissingFlowcharts;
bool mLoadFailed;
sead::FixedSafeString<64> mName;
sead::FixedSafeString<128> mEntryPoint;
};
} // namespace ksys::evt

View File

@ -18,6 +18,8 @@ public:
EventFlowBinder(evt::ActorBindings* bindings, sead::Heap* heap) EventFlowBinder(evt::ActorBindings* bindings, sead::Heap* heap)
: mBindings(bindings), mHeap(heap) {} : mBindings(bindings), mHeap(heap) {}
virtual ~EventFlowBinder() = default; virtual ~EventFlowBinder() = default;
EventFlowBinder(const EventFlowBinder&) = default;
EventFlowBinder& operator=(const EventFlowBinder&) = default;
protected: protected:
evt::ActorBindings* mBindings; evt::ActorBindings* mBindings;
@ -26,17 +28,20 @@ protected:
class EventFlowActorBinder : public EventFlowBinder { class EventFlowActorBinder : public EventFlowBinder {
public: public:
using EventFlowBinder::EventFlowBinder;
void bind(evfl::ActorBinding* evfl_binding, const evfl::ResActor* evfl_actor); void bind(evfl::ActorBinding* evfl_binding, const evfl::ResActor* evfl_actor);
}; };
class EventFlowActionBinder : public EventFlowBinder { class EventFlowActionBinder : public EventFlowBinder {
public: public:
using EventFlowBinder::EventFlowBinder;
void bind(evfl::ActorBinding::Action* evfl_binding, const evfl::ResAction* evfl_action, void bind(evfl::ActorBinding::Action* evfl_binding, const evfl::ResAction* evfl_action,
const evfl::ResActor* evfl_actor, evt::ActorBinding* binding); const evfl::ResActor* evfl_actor, evt::ActorBinding* binding);
}; };
class EventFlowQueryBinder : public EventFlowBinder { class EventFlowQueryBinder : public EventFlowBinder {
public: public:
using EventFlowBinder::EventFlowBinder;
void bind(evfl::ActorBinding::Query* evfl_binding, const evfl::ResQuery* evfl_query, void bind(evfl::ActorBinding::Query* evfl_binding, const evfl::ResQuery* evfl_query,
const evfl::ResActor* evfl_actor, evt::ActorBinding* binding); const evfl::ResActor* evfl_actor, evt::ActorBinding* binding);
}; };