[Scummvm-git-logs] scummvm master -> b0a73381c7138439ce0c264d8a7182ef4dee8cef
elasota
noreply at scummvm.org
Mon Sep 2 00:17:32 UTC 2024
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
b0a73381c7 MTROPOLIS: Convert message propagation to coroutines
Commit: b0a73381c7138439ce0c264d8a7182ef4dee8cef
https://github.com/scummvm/scummvm/commit/b0a73381c7138439ce0c264d8a7182ef4dee8cef
Author: elasota (1137273+elasota at users.noreply.github.com)
Date: 2024-09-01T20:17:14-04:00
Commit Message:
MTROPOLIS: Convert message propagation to coroutines
Changed paths:
engines/mtropolis/coroutines.h
engines/mtropolis/runtime.cpp
engines/mtropolis/runtime.h
diff --git a/engines/mtropolis/coroutines.h b/engines/mtropolis/coroutines.h
index 48f8a34b876..8f8532197cc 100644
--- a/engines/mtropolis/coroutines.h
+++ b/engines/mtropolis/coroutines.h
@@ -238,11 +238,11 @@ void type::compileCoroutine(ICoroutineCompiler *compiler) {
(nextExpr); \
CORO_END_CODE_BLOCK \
CORO_START_CODE_BLOCK(CoroOps::ForCond) \
- coroRuntime._condition = !!(condExpr)); \
+ coroRuntime._condition = !!(condExpr); \
CORO_END_CODE_BLOCK \
CORO_START_CODE_BLOCK(CoroOps::ForBody)
-#define CORO_END_FOR(expr) \
+#define CORO_END_FOR \
CORO_END_CODE_BLOCK \
CORO_START_CODE_BLOCK(CoroOps::EndFor)
diff --git a/engines/mtropolis/runtime.cpp b/engines/mtropolis/runtime.cpp
index b7e1ca4b8f2..b22418810b6 100644
--- a/engines/mtropolis/runtime.cpp
+++ b/engines/mtropolis/runtime.cpp
@@ -4161,7 +4161,7 @@ SceneTransitionEffect::SceneTransitionEffect()
}
MessageDispatch::MessageDispatch(const Common::SharedPtr<MessageProperties> &msgProps, Structural *root, bool cascade, bool relay, bool couldBeCommand)
- : _cascade(cascade), _relay(relay), _terminated(false), _msg(msgProps), _isCommand(false) {
+ : _cascade(cascade), _relay(relay), _terminated(false), _msg(msgProps), _isCommand(false), _rootType(RootType::Structural) {
if (couldBeCommand && EventIDs::isCommand(msgProps->getEvent().eventType)) {
_isCommand = true;
@@ -4171,6 +4171,8 @@ MessageDispatch::MessageDispatch(const Common::SharedPtr<MessageProperties> &msg
topEntry.ptr.structural = root;
_propagationStack.push_back(topEntry);
+
+ _rootType = RootType::Command;
} else {
PropagationStack topEntry;
topEntry.index = 0;
@@ -4184,7 +4186,7 @@ MessageDispatch::MessageDispatch(const Common::SharedPtr<MessageProperties> &msg
}
MessageDispatch::MessageDispatch(const Common::SharedPtr<MessageProperties> &msgProps, Modifier *root, bool cascade, bool relay, bool couldBeCommand)
- : _cascade(cascade), _relay(relay), _terminated(false), _msg(msgProps), _isCommand(false) {
+ : _cascade(cascade), _relay(relay), _terminated(false), _msg(msgProps), _isCommand(false), _rootType(RootType::Modifier) {
// Apparently if a command message is sent to a modifier, it's handled as a message.
// SPQR depends on this to send "Element Select" messages to pick the palette.
@@ -4362,6 +4364,14 @@ bool MessageDispatch::isRelay() const {
return _relay;
}
+MessageDispatch::RootType MessageDispatch::getRootType() const {
+ return _rootType;
+}
+
+const Common::WeakPtr<RuntimeObject> &MessageDispatch::getRootWeakPtr() const {
+ return _root;
+}
+
RuntimeObject *MessageDispatch::getRootPropagator() const {
if (_propagationStack.size() > 0) {
@@ -6348,10 +6358,121 @@ void Runtime::sendMessageOnVThread(const Common::SharedPtr<MessageDispatch> &dis
}
#endif
- DispatchMethodTaskData *taskData = _vthread->pushTask("Runtime::dispatchMessageTask", this, &Runtime::dispatchMessageTask);
- taskData->dispatch = dispatch;
+ _vthread->pushCoroutine<DispatchMessageCoroutine>(this, dispatch);
}
+CORO_BEGIN_DEFINITION(Runtime::DispatchMessageCoroutine)
+ struct Locals {
+ bool isTerminated = false;
+ RuntimeObject *rootObject = nullptr;
+ MessageDispatch::RootType rootType = MessageDispatch::RootType::Invalid;
+ };
+
+ CORO_BEGIN_FUNCTION
+ locals->rootObject = params->dispatch->getRootWeakPtr().lock().get();
+ CORO_IF(locals->rootObject != nullptr)
+ locals->rootType = params->dispatch->getRootType();
+ CORO_IF (locals->rootType == MessageDispatch::RootType::Command)
+ CORO_AWAIT(static_cast<Structural *>(locals->rootObject)->asyncConsumeCommand(params->runtime, params->dispatch->getMsg()));
+ CORO_ELSE_IF (locals->rootType == MessageDispatch::RootType::Structural)
+ CORO_CALL(SendMessageToStructuralCoroutine, params->runtime, &locals->isTerminated, static_cast<Structural *>(locals->rootObject), params->dispatch.get());
+ CORO_ELSE
+ if (params->dispatch->getRootType() != MessageDispatch::RootType::Modifier)
+ error("Internal error: Message propagation target was something other than structural or modifier");
+
+ CORO_CALL(SendMessageToModifierCoroutine, params->runtime, &locals->isTerminated, static_cast<Modifier *>(locals->rootObject), params->dispatch.get());
+ CORO_END_IF
+ CORO_END_IF
+ CORO_END_FUNCTION
+CORO_END_DEFINITION
+
+CORO_BEGIN_DEFINITION(Runtime::SendMessageToStructuralCoroutine)
+ struct Locals {
+ const Common::Array<Common::SharedPtr<Structural> > *childrenArray = nullptr;
+ uint childIndex = 0;
+ };
+
+ CORO_BEGIN_FUNCTION
+ // Send to the structural object. Structural objects only consume commands.
+ CORO_IF (params->structural->respondsToEvent(params->dispatch->getMsg()->getEvent()))
+ CORO_AWAIT(params->runtime->postConsumeCommandTask(params->structural, params->dispatch->getMsg()));
+
+ CORO_IF (!params->dispatch->isRelay())
+ *params->isTerminatedPtr = true;
+ CORO_RETURN;
+ CORO_END_IF
+ CORO_END_IF
+
+ // Send to modifiers
+ if (params->structural->getSceneLoadState() == Structural::SceneLoadState::kSceneNotLoaded)
+ params->runtime->hotLoadScene(params->structural);
+
+ CORO_IF (params->structural->getModifiers().size() > 0)
+ CORO_CALL(Runtime::SendMessageToModifierContainerCoroutine, params->runtime, params->isTerminatedPtr, params->structural, params->dispatch);
+
+ CORO_IF(*params->isTerminatedPtr)
+ CORO_RETURN;
+ CORO_END_IF
+ CORO_END_IF
+
+ // Send to children if cascade
+ CORO_IF(params->dispatch->isCascade())
+ CORO_FOR((locals->childrenArray = ¶ms->structural->getChildren()), (locals->childIndex < locals->childrenArray->size()), (locals->childIndex++))
+ debug("traversing into child %u: %s", locals->childIndex, (*locals->childrenArray)[locals->childIndex]->debugGetName().c_str());
+ CORO_CALL(Runtime::SendMessageToStructuralCoroutine, params->runtime, params->isTerminatedPtr, (*locals->childrenArray)[locals->childIndex].get(), params->dispatch);
+
+ CORO_IF (*params->isTerminatedPtr)
+ CORO_RETURN;
+ CORO_END_IF
+ CORO_END_FOR
+ CORO_END_IF
+ CORO_END_FUNCTION
+CORO_END_DEFINITION
+
+CORO_BEGIN_DEFINITION(Runtime::SendMessageToModifierContainerCoroutine)
+ struct Locals {
+ const Common::Array<Common::SharedPtr<Modifier> > *childrenArray = nullptr;
+ uint childIndex = 0;
+ };
+
+ CORO_BEGIN_FUNCTION
+ locals->childrenArray = ¶ms->modifierContainer->getModifiers();
+
+ CORO_FOR((locals->childIndex = 0), (locals->childIndex < locals->childrenArray->size() && !*(params->isTerminatedPtr)), (locals->childIndex++))
+ CORO_CALL(SendMessageToModifierCoroutine, params->runtime, params->isTerminatedPtr, (*locals->childrenArray)[locals->childIndex].get(), params->dispatch);
+ CORO_END_FOR
+ CORO_END_FUNCTION
+CORO_END_DEFINITION
+
+CORO_BEGIN_DEFINITION(Runtime::SendMessageToModifierCoroutine)
+ struct Locals {
+ bool responds = false;
+ IModifierContainer *childContainer = nullptr;
+ };
+
+ CORO_BEGIN_FUNCTION
+ // Handle the action in the VThread
+ locals->responds = params->modifier->respondsToEvent(params->dispatch->getMsg()->getEvent());
+
+ // Queue propagation to children, if any, when the VThread task is done
+ if (locals->responds && !params->dispatch->isRelay()) {
+ *params->isTerminatedPtr = true;
+ } else {
+ locals->childContainer = params->modifier->getMessagePropagationContainer();
+ }
+
+ // Post to the message action itself to VThread
+ CORO_IF (locals->responds)
+ debug(3, "Modifier %x '%s' consumed message (%i,%i)", params->modifier->getStaticGUID(), params->modifier->getName().c_str(), params->dispatch->getMsg()->getEvent().eventType, params->dispatch->getMsg()->getEvent().eventInfo);
+ CORO_AWAIT(params->runtime->postConsumeMessageTask(params->modifier, params->dispatch->getMsg()));
+ CORO_END_IF
+
+ CORO_IF(locals->childContainer && !(*params->isTerminatedPtr))
+ CORO_CALL(SendMessageToModifierContainerCoroutine, params->runtime, params->isTerminatedPtr, locals->childContainer, params->dispatch);
+ CORO_END_IF
+ CORO_END_FUNCTION
+CORO_END_DEFINITION
+
VThreadState Runtime::dispatchMessageTask(const DispatchMethodTaskData &data) {
Common::SharedPtr<MessageDispatch> dispatchPtr = data.dispatch;
MessageDispatch &dispatch = *dispatchPtr.get();
diff --git a/engines/mtropolis/runtime.h b/engines/mtropolis/runtime.h
index dd009759f8a..a79e7053999 100644
--- a/engines/mtropolis/runtime.h
+++ b/engines/mtropolis/runtime.h
@@ -1384,6 +1384,14 @@ struct SceneTransitionEffect {
class MessageDispatch {
public:
+ enum class RootType {
+ Invalid,
+
+ Command,
+ Structural,
+ Modifier,
+ };
+
MessageDispatch(const Common::SharedPtr<MessageProperties> &msgProps, Structural *root, bool cascade, bool relay, bool couldBeCommand);
MessageDispatch(const Common::SharedPtr<MessageProperties> &msgProps, Modifier *root, bool cascade, bool relay, bool couldBeCommand);
@@ -1396,6 +1404,9 @@ public:
bool isCascade() const;
bool isRelay() const;
+ RootType getRootType() const;
+ const Common::WeakPtr<RuntimeObject> &getRootWeakPtr() const;
+
private:
struct PropagationStack {
union Ptr {
@@ -1433,6 +1444,8 @@ private:
bool _relay; // Fire on multiple modifiers
bool _terminated;
bool _isCommand;
+
+ RootType _rootType;
};
class KeyEventDispatch {
@@ -1881,6 +1894,26 @@ private:
void unloadProject();
void refreshPlayTime(); // Updates play time to be in sync with the system clock. Used so that events occurring after storage access don't skip.
+ struct DispatchMessageCoroutine {
+ CORO_DEFINE_RETURN_TYPE(void);
+ CORO_DEFINE_PARAMS_2(Runtime *, runtime, Common::SharedPtr<MessageDispatch>, dispatch);
+ };
+
+ struct SendMessageToStructuralCoroutine {
+ CORO_DEFINE_RETURN_TYPE(void);
+ CORO_DEFINE_PARAMS_4(Runtime *, runtime, bool *, isTerminatedPtr, Structural *, structural, MessageDispatch *, dispatch);
+ };
+
+ struct SendMessageToModifierContainerCoroutine {
+ CORO_DEFINE_RETURN_TYPE(void);
+ CORO_DEFINE_PARAMS_4(Runtime *, runtime, bool *, isTerminatedPtr, IModifierContainer *, modifierContainer, MessageDispatch *, dispatch);
+ };
+
+ struct SendMessageToModifierCoroutine {
+ CORO_DEFINE_RETURN_TYPE(void);
+ CORO_DEFINE_PARAMS_4(Runtime *, runtime, bool *, isTerminatedPtr, Modifier *, modifier, MessageDispatch *, dispatch);
+ };
+
VThreadState dispatchMessageTask(const DispatchMethodTaskData &data);
VThreadState dispatchKeyTask(const DispatchKeyTaskData &data);
VThreadState dispatchActionTask(const DispatchActionTaskData &data);
More information about the Scummvm-git-logs
mailing list