From 357ef77879aab586da2e1d8424a0c6429669cc6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Thu, 17 Jun 2021 20:56:37 +0200 Subject: [PATCH] ksys/evt: Add ResourceTimeline --- data/uking_functions.csv | 16 +- ...ngsEPNS0_13ActorBindingsEPN4sead4HeapE.bin | Bin 0 -> 1132 bytes lib/EventFlow | 2 +- src/KingSystem/Event/CMakeLists.txt | 2 + src/KingSystem/Event/evtResourceTimeline.cpp | 172 ++++++++++++++++++ src/KingSystem/Event/evtResourceTimeline.h | 51 ++++++ 6 files changed, 234 insertions(+), 9 deletions(-) create mode 100644 expected/_ZN4ksys3evt16ResourceTimeline13setUpBindingsEPNS0_13ActorBindingsEPN4sead4HeapE.bin create mode 100644 src/KingSystem/Event/evtResourceTimeline.cpp create mode 100644 src/KingSystem/Event/evtResourceTimeline.h diff --git a/data/uking_functions.csv b/data/uking_functions.csv index 4951b2d2..8822e947 100644 --- a/data/uking_functions.csv +++ b/data/uking_functions.csv @@ -75821,14 +75821,14 @@ 0x0000007100dc6210,j__ZdlPv_889,4,_ZN4ksys3res20EventFlowActorBinderD0Ev 0x0000007100dc6214,j__ZdlPv_890,4,_ZN4ksys3res21EventFlowActionBinderD0Ev 0x0000007100dc6218,j__ZdlPv_891,4,_ZN4ksys3res20EventFlowQueryBinderD0Ev -0x0000007100dc621c,ResourceTimeline::ctor,136, -0x0000007100dc62a4,sub_7100DC62A4,180, -0x0000007100dc6358,sub_7100DC6358,176, -0x0000007100dc6408,ResourceTimeline::loadBfevtm,584, -0x0000007100dc6650,ResourceTimeline::x,348, -0x0000007100dc67ac,ResourceTimeline::initTimelineObj,1132, -0x0000007100dc6c18,sub_7100DC6C18,100, -0x0000007100dc6c7c,sub_7100DC6C7C,420, +0x0000007100dc621c,ResourceTimeline::ctor,136,_ZN4ksys3evt16ResourceTimelineC1Ev +0x0000007100dc62a4,sub_7100DC62A4,180,_ZN4ksys3evt16ResourceTimelineD1Ev +0x0000007100dc6358,sub_7100DC6358,176,_ZN4ksys3evt16ResourceTimelineD0Ev +0x0000007100dc6408,ResourceTimeline::loadBfevtm,584,_ZN4ksys3evt16ResourceTimeline13loadEventFlowEPN4sead4HeapERKN2al9ByamlIterEPNS_3res6HandleE +0x0000007100dc6650,ResourceTimeline::x,348,_ZN4ksys3evt16ResourceTimeline10finishLoadEv +0x0000007100dc67ac,ResourceTimeline::initTimelineObj,1132,_ZN4ksys3evt16ResourceTimeline13setUpBindingsEPNS0_13ActorBindingsEPN4sead4HeapE? +0x0000007100dc6c18,sub_7100DC6C18,100,_ZN4ksys3evt16ResourceTimeline13buildTimelineEPN4evfl11TimelineObjEiPN4sead4HeapE +0x0000007100dc6c7c,sub_7100DC6C7C,420,_ZN4ksys3evt16bindActorActionsERN4evfl11TimelineObjENS_3res21EventFlowActionBinderE 0x0000007100dc6e20,EventBgmInfo::ctor,340, 0x0000007100dc6f74,sub_7100DC6F74,268, 0x0000007100dc7080,sub_7100DC7080,256, diff --git a/expected/_ZN4ksys3evt16ResourceTimeline13setUpBindingsEPNS0_13ActorBindingsEPN4sead4HeapE.bin b/expected/_ZN4ksys3evt16ResourceTimeline13setUpBindingsEPNS0_13ActorBindingsEPN4sead4HeapE.bin new file mode 100644 index 0000000000000000000000000000000000000000..553c216ada33d97489f6efbfa1ce24165a0cab3e GIT binary patch literal 1132 zcma)+Uq}=|9LImN)7|aeX+i$Uv-C0_N-F|U^75gTz_g5@HcWbuu*fnK5egB!Ga-`8 zV#_+v;2;ayjiA7Yg}}lWBZ5RQ=%qUeyt|EF)bqx>bNh`NB?R>_%(6TCo!{sC`_7ns zbTZX0s!JE_YNE-Z#v7dK{P7Gm-JPkX4^d@_f_BpB(-)|qr6|$7R_JJ@AV;XHtfgmS z*rcLyb*5{o&kmoO&mCqnw4f|v3+BJy0WV|wgZUzHl)4FYY$w4lVVa{s*a*y{<|u*D zdp97lNVByN-J*RP`5ssl1Z7$fCLfsQtL`4@t_2`_p1QRpj#K!|=US(vyDiYM+X3=v z2fS#+k=I$nJlAU29Da}E;F@(#iFs+R5usvf`1;_Go8%h1NS0sh?H>~NN-Q)&l$m0p zBxX0L3;TdA6kFBDPre6gk#*V%O6Mb@@Or)qqVX(k%6w11737o?7<$6$aNm-)8pd$H ze7o;N9Q8`7L3wkMOwLg#i`szo7rOjj>M{~^t5(%JI26U2%n{;=HdxfCO=8iVz{bY& zD=(gr^r!&kExRSQNJTAXt@daH%40&c=MsU6nL?}=YYn4Mhh8rSBKV$rI-|O6oIJ<6D7EFLQpM-idwZJ@;bI zKP;Q_FMlRxfBSRP_7B}=)NK&d_$FX)QMZ1bZpMmk5VPd8@H6Dr?3kUHt)R?bC}LJb zqZPetYn1fo6v{7`NNfQ67jyv&65`3kObif-jiq~^-p2Wk-KYQXIEKf_M&qn$$^%7` zzOp8BZ4J(Miq@}bL(MCVKK)~befU-pQGz7X2&YWB9{Vp^Kykm@V{k7A@qEsqXDzpz z5)pvWoN(9FO(Dk*M3~$OF!&13>3uw>A)2Lig^WPD` +#include +#include +#include "KingSystem/Event/evtActorBindings.h" +#include "KingSystem/Event/evtEventResource.h" +#include "KingSystem/Resource/Event/resEventFlowBinder.h" +#include "KingSystem/Resource/Event/resResourceEventFlow.h" +#include "KingSystem/Resource/resLoadRequest.h" +#include "KingSystem/Utils/Byaml/Byaml.h" + +namespace ksys::evt { + +ResourceTimeline::ResourceTimeline() { + mLoadFailed = false; +} + +ResourceTimeline::~ResourceTimeline() { + for (int i = 0; i < mTimelines.size(); ++i) + mTimelines[i].handle.requestUnload2(); + + mTimelines.freeBuffer(); +} + +void ResourceTimeline::loadEventFlow(sead::Heap* heap, const al::ByamlIter& event_info, + res::Handle* pack_handle) { + al::ByamlIter sub_timelines; + int num_sub_timelines = 0; + if (event_info.tryGetIterByKey(&sub_timelines, "sub_timelines")) + num_sub_timelines = sub_timelines.getSize(); + + res::LoadRequest request; + request.mRequester = "ResourceTimeline"; + request.mPackHandle = pack_handle; + request._22 = true; + + mTimelines.allocBufferAssert(1 + num_sub_timelines, heap); + + for (int i = 0; i < mTimelines.size(); ++i) + mTimelines[i].loaded = false; + + // Load the main flowchart. + sead::FormatFixedSafeString<128> path("EventFlow/%s.bfevtm", mName.cstr()); + mTimelines[0].handle.requestLoad(path, &request); + + // Load any subfiles. + for (int i = 0; i < num_sub_timelines; ++i) { + al::ByamlIter sub_entry; + sub_timelines.tryGetIterByIndex(&sub_entry, i); + const char* sub_timeline_name; + sub_entry.tryGetStringByKey(&sub_timeline_name, "name"); + + sead::FormatFixedSafeString<128> sub_path("EventFlow/%s.bfevtm", sub_timeline_name); + mTimelines[i + 1].handle.requestLoad(sub_path, &request); + } +} + +bool ResourceTimeline::finishLoad() { + bool ready = true; + + for (int i = 0; i < mTimelines.size(); ++i) { + auto& timeline = mTimelines[i]; + if (timeline.loaded) + continue; + + if (timeline.handle.isReadyOrNeedsParse()) + timeline.handle.parseResource(nullptr); + + if (timeline.handle.isSuccess()) { + auto* evfl_res = sead::DynamicCast(timeline.handle.getResource()); + if (evfl_res) { + timeline.res_event_flow_file = evfl_res->getRes(); + timeline.res_timeline = timeline.res_event_flow_file->timelines.Get()->Get(); + timeline.loaded = true; + } + } else if (timeline.handle.checkLoadStatus()) { + timeline.loaded = true; + mLoadFailed = true; + } + + if (!timeline.loaded) + ready = false; + } + + return ready; +} + +long bindActorActions(evfl::TimelineObj& obj, res::EventFlowActionBinder binder) { + auto* res_timeline = obj.GetTimeline(); + + ore::Array actors{res_timeline->actors.Get(), res_timeline->num_actors}; + for (int actor_idx = 0; actor_idx < actors.size(); ++actor_idx) { + ore::Array actions{actors[actor_idx].actions.Get(), + actors[actor_idx].num_actions}; + for (int i = 0; i < actions.size(); ++i) + obj.GetActBinder().RegisterAction(actor_idx, &actions[i]); + } + + u8 ok; + u8 failed; + auto binder_ = binder; + + ok = false; + failed = false; + + auto& evfl_bindings = obj.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(b->GetUserData())); + (a->handler ? ok : failed) = true; + } + } + + return int(ok) | (int(failed) << 8); +} + +// NON_MATCHING: minor reordering for the buildTimeline loop +bool ResourceTimeline::setUpBindings(ActorBindings* bindings, sead::Heap* heap) { + sead::Buffer timeline_objs; + timeline_objs.allocBufferAssert(mTimelines.size(), heap); + + [&] { + for (int i = 0; i < mTimelines.size(); ++i) + buildTimeline(&timeline_objs[i], i, heap); + }(); + + // Bind actors. (For an explanation of why binding is done twice, see ResourceFlowchart.) + const auto bind_actors = [&] { + for (int i = 0; i < mTimelines.size(); ++i) { + auto& obj = timeline_objs[i]; + res::EventFlowActorBinder binder(bindings, heap); + bool ok = false; + bool failed = false; + + auto& evfl_bindings = obj.GetActBinder().GetBindings(); + for (auto it = evfl_bindings.begin(); it != evfl_bindings.end(); ++it) { + if (it->IsUsed() && !it->IsInitialized()) { + binder.bind(it, it->GetActor()); + (it->IsInitialized() ? ok : failed) = true; + } + } + } + }; + bind_actors(); + bindings->allocBindings(heap); + bind_actors(); + + // Bind actions. + for (int i = 0; i < mTimelines.size(); ++i) + bindActorActions(timeline_objs[i], res::EventFlowActionBinder(bindings, heap)); + bindings->allocBindingsActions(heap); + for (int i = 0; i < mTimelines.size(); ++i) + bindActorActions(timeline_objs[i], res::EventFlowActionBinder(bindings, heap)); + + for (int i = 0; i < mTimelines.size(); ++i) + timeline_objs[i].GetActBinder().UnbindAll(); + + timeline_objs.freeBuffer(); + return true; +} + +bool ResourceTimeline::buildTimeline(evfl::TimelineObj* obj, int idx, sead::Heap* heap) { + auto& timeline = mTimelines[idx]; + evfl::TimelineObj::Builder builder(timeline.res_timeline); + return builder.Build(obj, makeEvflAllocateArg(heap)); +} + +} // namespace ksys::evt diff --git a/src/KingSystem/Event/evtResourceTimeline.h b/src/KingSystem/Event/evtResourceTimeline.h new file mode 100644 index 00000000..21361ecb --- /dev/null +++ b/src/KingSystem/Event/evtResourceTimeline.h @@ -0,0 +1,51 @@ +#pragma once + +#include +#include +#include "KingSystem/Resource/resHandle.h" + +namespace al { +class ByamlIter; +} + +namespace evfl { +struct ResEventFlowFile; +struct ResTimeline; +class TimelineObj; +} // namespace evfl + +namespace ksys::evt { + +class ActorBindings; + +class ResourceTimeline { +public: + ResourceTimeline(); + virtual ~ResourceTimeline(); + + /// Loads event timeline resource files asynchronously. + void loadEventFlow(sead::Heap* heap, const al::ByamlIter& event_info, 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 buildTimeline(evfl::TimelineObj* obj, int idx, sead::Heap* heap); + +private: + struct Res { + res::Handle handle; + const evfl::ResEventFlowFile* res_event_flow_file; + const evfl::ResTimeline* res_timeline; + bool loaded; + }; + + sead::Buffer mTimelines; + bool mLoadFailed; + sead::FixedSafeString<64> mName; +}; + +} // namespace ksys::evt