[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 = &params->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 = &params->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