summaryrefslogtreecommitdiff
path: root/src/KingSystem/Event/evtResourceTimeline.cpp
diff options
context:
space:
mode:
authorLéo Lam <leo@leolam.fr>2021-06-17 20:56:37 +0200
committerLéo Lam <leo@leolam.fr>2021-06-17 23:42:21 +0200
commit357ef77879aab586da2e1d8424a0c6429669cc6f (patch)
tree0fc49211b0f9f4b4c939aae305b0ee816b5a51f8 /src/KingSystem/Event/evtResourceTimeline.cpp
parent92388bad74ae726c5581b31c23c2090a4b34623f (diff)
ksys/evt: Add ResourceTimeline
Diffstat (limited to 'src/KingSystem/Event/evtResourceTimeline.cpp')
-rw-r--r--src/KingSystem/Event/evtResourceTimeline.cpp172
1 files changed, 172 insertions, 0 deletions
diff --git a/src/KingSystem/Event/evtResourceTimeline.cpp b/src/KingSystem/Event/evtResourceTimeline.cpp
new file mode 100644
index 00000000..a7156334
--- /dev/null
+++ b/src/KingSystem/Event/evtResourceTimeline.cpp
@@ -0,0 +1,172 @@
+#include "KingSystem/Event/evtResourceTimeline.h"
+#include <evfl/ResEventFlowFile.h>
+#include <evfl/ResTimeline.h>
+#include <evfl/TimelineObj.h>
+#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<res::EventTimeline>(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<const evfl::ResActor> actors{res_timeline->actors.Get(), res_timeline->num_actors};
+ for (int actor_idx = 0; actor_idx < actors.size(); ++actor_idx) {
+ ore::Array<const evfl::ResAction> 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<ActorBinding*>(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<evfl::TimelineObj> 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