[Scummvm-git-logs] scummvm master -> 850e92343dedbd37c55cf53d4c909334256074e2

elasota noreply at scummvm.org
Fri Aug 30 02:08:21 UTC 2024


This automated email contains information about 4 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
92759aa113 MTROPOLIS: Convert mToon element tasks into coroutines
590844d4d4 MTROPOLIS: Convert sound element tasks to coroutines
fdaa96daba MTROPOLIS: Convert Miniscript program runs from tasks to coroutines
850e92343d MTROPOLIS: Fix some data readers not returning error codes on read failure


Commit: 92759aa113d0e5ebfb5145f138e2ec4323ab7ab6
    https://github.com/scummvm/scummvm/commit/92759aa113d0e5ebfb5145f138e2ec4323ab7ab6
Author: elasota (1137273+elasota at users.noreply.github.com)
Date: 2024-08-29T22:07:46-04:00

Commit Message:
MTROPOLIS: Convert mToon element tasks into coroutines

Changed paths:
    engines/mtropolis/elements.cpp
    engines/mtropolis/elements.h
    engines/mtropolis/miniscript.cpp
    engines/mtropolis/miniscript.h


diff --git a/engines/mtropolis/elements.cpp b/engines/mtropolis/elements.cpp
index 4d92d5fb0d3..c382938e6e9 100644
--- a/engines/mtropolis/elements.cpp
+++ b/engines/mtropolis/elements.cpp
@@ -1419,43 +1419,53 @@ MiniscriptInstructionOutcome MToonElement::writeRefAttribute(MiniscriptThread *t
 	return VisualElement::writeRefAttribute(thread, result, attrib);
 }
 
-VThreadState MToonElement::asyncConsumeCommand(Runtime *runtime, const Common::SharedPtr<MessageProperties> &msg) {
-	if (Event(EventIDs::kPlay, 0).respondsTo(msg->getEvent())) {
-		// If the range set fails, then the mToon should play anyway, so ignore the result
-		(void)scriptSetRange(nullptr, msg->getValue());
+CORO_BEGIN_DEFINITION(MToonElement::MToonConsumeCommandCoroutine)
+	struct Locals {
+	};
 
-		StartPlayingTaskData *startPlayingTaskData = runtime->getVThread().pushTask("MToonElement::startPlayingTask", this, &MToonElement::startPlayingTask);
-		startPlayingTaskData->runtime = runtime;
+	CORO_BEGIN_FUNCTION
+		CORO_IF (Event(EventIDs::kPlay, 0).respondsTo(params->msg->getEvent()))
+			// If the range set fails, then the mToon should play anyway, so ignore the result
+			CORO_AWAIT_MINISCRIPT(miniscriptIgnoreFailure(params->self->scriptSetRange(nullptr, params->msg->getValue())));
 
-		ChangeFlagTaskData *becomeVisibleTaskData = runtime->getVThread().pushTask("MToonElement::changeVisibilityTask", static_cast<VisualElement *>(this), &MToonElement::changeVisibilityTask);
-		becomeVisibleTaskData->desiredFlag = true;
-		becomeVisibleTaskData->runtime = runtime;
+			MToonElement *self = params->self;
 
-		if (_isStopped) {
-			_isStopped = false;
-			runtime->setSceneGraphDirty();
-		}
+			if (self->_isStopped) {
+				self->_isStopped = false;
+				params->runtime->setSceneGraphDirty();
+			}
 
-		return kVThreadReturn;
-	}
-	if (Event(EventIDs::kStop, 0).respondsTo(msg->getEvent())) {
-		// mTropolis 1.0 will not fire a Hidden event when an mToon is stopped even though it is hidden in the process.
-		// MTI depends on this, otherwise 2 hints will play at once when clicking a song button on the piano.
-		// This same bug does NOT apply to the "Shown" event firing on Play (as happens above).
-		if (runtime->getProject()->getRuntimeVersion() > kRuntimeVersion100) {
-			ChangeFlagTaskData *hideTaskData = runtime->getVThread().pushTask("MToonElement::changeVisibilityTask", static_cast<VisualElement *>(this), &MToonElement::changeVisibilityTask);
-			hideTaskData->desiredFlag = false;
-			hideTaskData->runtime = runtime;
-		} else
-			setVisible(runtime, false);
+			CORO_CALL(MToonElement::ChangeVisibilityCoroutine, params->self, params->runtime, true);
 
-		StopPlayingTaskData *stopPlayingTaskData = runtime->getVThread().pushTask("MToonElement::stopPlayingTask", this, &MToonElement::stopPlayingTask);
-		stopPlayingTaskData->runtime = runtime;
+			CORO_CALL(MToonElement::StartPlayingCoroutine, params->self, params->runtime);
 
-		return kVThreadReturn;
-	}
+			CORO_RETURN;
+		CORO_ELSE_IF(Event(EventIDs::kStop, 0).respondsTo(params->msg->getEvent()))
+			// mTropolis 1.0 will not fire a Hidden event when an mToon is stopped even though it is hidden in the process.
+			// MTI depends on this, otherwise 2 hints will play at once when clicking a song button on the piano.
+			// This same bug does NOT apply to the "Shown" event firing on Play (as happens above).
+			
+			MToonElement *self = params->self;
+			
+			if (params->runtime->getProject()->getRuntimeVersion() <= kRuntimeVersion100)
+				self->setVisible(params->runtime, false);
+
+			CORO_CALL(MToonElement::StopPlayingCoroutine, params->self, params->runtime);
+
+			CORO_IF (params->runtime->getProject()->getRuntimeVersion() > kRuntimeVersion100)
+				CORO_CALL(MToonElement::ChangeVisibilityCoroutine, params->self, params->runtime, false);
+			CORO_END_IF
 
-	return VisualElement::asyncConsumeCommand(runtime, msg);
+			CORO_RETURN;
+		CORO_END_IF
+
+		CORO_CALL(VisualElement::VisualElementConsumeCommandCoroutine, params->self, params->runtime, params->msg);
+	CORO_END_FUNCTION
+CORO_END_DEFINITION
+
+VThreadState MToonElement::asyncConsumeCommand(Runtime *runtime, const Common::SharedPtr<MessageProperties> &msg) {
+	runtime->getVThread().pushCoroutine<MToonElement::MToonConsumeCommandCoroutine>(this, runtime, msg);
+	return kVThreadReturn;
 }
 
 void MToonElement::activate() {
@@ -1653,50 +1663,59 @@ void MToonElement::debugInspect(IDebugInspectionReport *report) const {
 }
 #endif
 
-VThreadState MToonElement::startPlayingTask(const StartPlayingTaskData &taskData) {
-	if (_rateTimes100000 < 0)
-		_cel = _playRange.max;
-	else
-		_cel = _playRange.min;
+CORO_BEGIN_DEFINITION(MToonElement::StartPlayingCoroutine)
+	struct Locals {
+	};
 
-	_paused = false;
-	_isPlaying = false;	// Reset play state, it starts for real in playMedia
+	CORO_BEGIN_FUNCTION
+		MToonElement *self = params->self;
 
-	_contentsDirty = true;
+		if (self->_rateTimes100000 < 0)
+			self->_cel = self->_playRange.max;
+		else
+			self->_cel = self->_playRange.min;
 
-	// These send in reverse order
-	{
-		Common::SharedPtr<MessageProperties> msgProps(new MessageProperties(Event(EventIDs::kAtFirstCel, 0), DynamicValue(), getSelfReference()));
-		Common::SharedPtr<MessageDispatch> dispatch(new MessageDispatch(msgProps, this, false, true, false));
-		taskData.runtime->sendMessageOnVThread(dispatch);
-	}
+		self->_paused = false;
+		self->_isPlaying = false; // Reset play state, it starts for real in playMedia
 
-	{
-		Common::SharedPtr<MessageProperties> msgProps(new MessageProperties(Event(EventIDs::kPlay, 0), DynamicValue(), getSelfReference()));
-		Common::SharedPtr<MessageDispatch> dispatch(new MessageDispatch(msgProps, this, false, true, false));
-		taskData.runtime->sendMessageOnVThread(dispatch);
-	}
+		self->_contentsDirty = true;
 
-	return kVThreadReturn;
-}
+		Common::SharedPtr<MessageProperties> playMsgProps(new MessageProperties(Event(EventIDs::kPlay, 0), DynamicValue(), self->getSelfReference()));
+		Common::SharedPtr<MessageDispatch> playDispatch(new MessageDispatch(playMsgProps, self, false, true, false));
+		CORO_CALL(Runtime::SendMessageOnVThreadCoroutine, params->runtime, playDispatch);
 
-VThreadState MToonElement::stopPlayingTask(const StopPlayingTaskData &taskData) {
-	_contentsDirty = true;
-	_isPlaying = false;
+		Common::SharedPtr<MessageProperties> afcMsgProps(new MessageProperties(Event(EventIDs::kAtFirstCel, 0), DynamicValue(), params->self->getSelfReference()));
+		Common::SharedPtr<MessageDispatch> afcDispatch(new MessageDispatch(afcMsgProps, params->self, false, true, false));
+		CORO_CALL(Runtime::SendMessageOnVThreadCoroutine, params->runtime, afcDispatch);
+	CORO_END_FUNCTION
+CORO_END_DEFINITION
 
-	if (!_isStopped) {
-		_isStopped = true;
 
-		Common::SharedPtr<MessageProperties> msgProps(new MessageProperties(Event(EventIDs::kStop, 0), DynamicValue(), getSelfReference()));
-		Common::SharedPtr<MessageDispatch> dispatch(new MessageDispatch(msgProps, this, false, true, false));
-		taskData.runtime->sendMessageOnVThread(dispatch);
-	}
+CORO_BEGIN_DEFINITION(MToonElement::StopPlayingCoroutine)
+	struct Locals {
+		bool needsStop = false;
+	};
 
-	if (_hooks)
-		_hooks->onStopPlayingMToon(this, _visible, _isStopped, _renderSurface.get());
+	CORO_BEGIN_FUNCTION
+		MToonElement *self = params->self;
 
-	return kVThreadReturn;
-}
+		self->_contentsDirty = true;
+		self->_isPlaying = false;
+
+		locals->needsStop = !self->_isStopped;
+
+		self->_isStopped = true;
+
+		if (self->_hooks)
+			self->_hooks->onStopPlayingMToon(self, self->_visible, self->_isStopped, self->_renderSurface.get());
+
+		CORO_IF (locals->needsStop)
+			Common::SharedPtr<MessageProperties> msgProps(new MessageProperties(Event(EventIDs::kStop, 0), DynamicValue(), params->self->getSelfReference()));
+			Common::SharedPtr<MessageDispatch> dispatch(new MessageDispatch(msgProps, params->self, false, true, false));
+			CORO_CALL(Runtime::SendMessageOnVThreadCoroutine, params->runtime, dispatch);
+		CORO_END_IF
+	CORO_END_FUNCTION
+CORO_END_DEFINITION
 
 void MToonElement::playMedia(Runtime *runtime, Project *project) {
 	if (_paused)
diff --git a/engines/mtropolis/elements.h b/engines/mtropolis/elements.h
index 0a253afa178..86c0259e331 100644
--- a/engines/mtropolis/elements.h
+++ b/engines/mtropolis/elements.h
@@ -263,27 +263,25 @@ public:
 private:
 	MToonElement(const MToonElement &other);
 
-	struct StartPlayingTaskData {
-		StartPlayingTaskData() : runtime(nullptr) {}
-
-		Runtime *runtime;
+	struct MToonConsumeCommandCoroutine {
+		CORO_DEFINE_RETURN_TYPE(void);
+		CORO_DEFINE_PARAMS_3(MToonElement *, self, Runtime *, runtime, Common::SharedPtr<MessageProperties>, msg);
 	};
 
-	struct StopPlayingTaskData {
-		StopPlayingTaskData() : runtime(nullptr) {}
-
-		Runtime *runtime;
+	struct StartPlayingCoroutine {
+		CORO_DEFINE_RETURN_TYPE(void);
+		CORO_DEFINE_PARAMS_2(MToonElement *, self, Runtime *, runtime);
 	};
 
-	struct ChangeFrameTaskData {
-		ChangeFrameTaskData() : runtime(nullptr), frame(0) {}
-
-		Runtime *runtime;
-		uint32 frame;
+	struct StopPlayingCoroutine {
+		CORO_DEFINE_RETURN_TYPE(void);
+		CORO_DEFINE_PARAMS_2(MToonElement *, self, Runtime *, runtime);
 	};
 
-	VThreadState startPlayingTask(const StartPlayingTaskData &taskData);
-	VThreadState stopPlayingTask(const StopPlayingTaskData &taskData);
+	struct ChangeFrameCoroutine {
+		CORO_DEFINE_RETURN_TYPE(void);
+		CORO_DEFINE_PARAMS_3(MToonElement *, self, Runtime *, runtime, uint32, frame);
+	};
 
 	void playMedia(Runtime *runtime, Project *project) override;
 	MiniscriptInstructionOutcome scriptSetRate(MiniscriptThread *thread, const DynamicValue &value);
diff --git a/engines/mtropolis/miniscript.cpp b/engines/mtropolis/miniscript.cpp
index ae9fd7e9fa0..fc9412c9914 100644
--- a/engines/mtropolis/miniscript.cpp
+++ b/engines/mtropolis/miniscript.cpp
@@ -2100,4 +2100,11 @@ MiniscriptInstructionOutcome MiniscriptThread::tryLoadVariable(MiniscriptStackVa
 	return kMiniscriptInstructionOutcomeContinue;
 }
 
+MiniscriptInstructionOutcome miniscriptIgnoreFailure(MiniscriptInstructionOutcome outcome) {
+	if (outcome == kMiniscriptInstructionOutcomeFailed)
+		return kMiniscriptInstructionOutcomeContinue;
+
+	return outcome;
+}
+
 } // End of namespace MTropolis
diff --git a/engines/mtropolis/miniscript.h b/engines/mtropolis/miniscript.h
index 49c06fddfea..523a210edc8 100644
--- a/engines/mtropolis/miniscript.h
+++ b/engines/mtropolis/miniscript.h
@@ -471,6 +471,8 @@ private:
 	bool _failed;
 };
 
+MiniscriptInstructionOutcome miniscriptIgnoreFailure(MiniscriptInstructionOutcome outcome);
+
 } // End of namespace MTropolis
 
 #endif


Commit: 590844d4d4f10f82fcd6ecaf8f12c33f5e7a76f9
    https://github.com/scummvm/scummvm/commit/590844d4d4f10f82fcd6ecaf8f12c33f5e7a76f9
Author: elasota (1137273+elasota at users.noreply.github.com)
Date: 2024-08-29T22:07:46-04:00

Commit Message:
MTROPOLIS: Convert sound element tasks to coroutines

Changed paths:
    engines/mtropolis/elements.cpp
    engines/mtropolis/elements.h
    engines/mtropolis/runtime.h


diff --git a/engines/mtropolis/elements.cpp b/engines/mtropolis/elements.cpp
index c382938e6e9..a6ff61e52bc 100644
--- a/engines/mtropolis/elements.cpp
+++ b/engines/mtropolis/elements.cpp
@@ -2472,21 +2472,26 @@ MiniscriptInstructionOutcome SoundElement::writeRefAttribute(MiniscriptThread *t
 	return NonVisualElement::writeRefAttribute(thread, writeProxy, attrib);
 }
 
-VThreadState SoundElement::asyncConsumeCommand(Runtime *runtime, const Common::SharedPtr<MessageProperties> &msg) {
-	if (Event(EventIDs::kPlay, 0).respondsTo(msg->getEvent())) {
-		StartPlayingTaskData *startPlayingTaskData = runtime->getVThread().pushTask("SoundElement::startPlayingTask", this, &SoundElement::startPlayingTask);
-		startPlayingTaskData->runtime = runtime;
+CORO_BEGIN_DEFINITION(SoundElement::SoundElementConsumeCommandCoroutine)
+	struct Locals {
+	};
 
-		return kVThreadReturn;
-	}
-	if (Event(EventIDs::kStop, 0).respondsTo(msg->getEvent())) {
-		StartPlayingTaskData *startPlayingTaskData = runtime->getVThread().pushTask("SoundElement::stopPlayingTask", this, &SoundElement::stopPlayingTask);
-		startPlayingTaskData->runtime = runtime;
+	CORO_BEGIN_FUNCTION
+		CORO_IF (Event(EventIDs::kPlay, 0).respondsTo(params->msg->getEvent()))
+			CORO_CALL(SoundElement::StartPlayingCoroutine, params->self, params->runtime);
+			CORO_RETURN
+		CORO_ELSE_IF(Event(EventIDs::kStop, 0).respondsTo(params->msg->getEvent()))
+			CORO_CALL(SoundElement::StopPlayingCoroutine, params->self, params->runtime);
+			CORO_RETURN;
+		CORO_END_IF
 
-		return kVThreadReturn;
-	}
+		CORO_CALL(NonVisualElement::NonVisualElementConsumeCommandCoroutine, params->self, params->runtime, params->msg);
+	CORO_END_FUNCTION
+CORO_END_DEFINITION
 
-	return NonVisualElement::asyncConsumeCommand(runtime, msg);
+VThreadState SoundElement::asyncConsumeCommand(Runtime *runtime, const Common::SharedPtr<MessageProperties> &msg) {
+	runtime->getVThread().pushCoroutine<SoundElementConsumeCommandCoroutine>(this, runtime, msg);
+	return kVThreadReturn;
 }
 
 void SoundElement::initSubtitles() {
@@ -2760,39 +2765,47 @@ void SoundElement::setBalance(int16 balance) {
 	setVolume((_leftVolume + _rightVolume) / 2);
 }
 
-VThreadState SoundElement::startPlayingTask(const StartPlayingTaskData &taskData) {
-	// Pushed in reverse order, actual order is Unpaused -> Played
-	{
-		Common::SharedPtr<MessageProperties> msgProps(new MessageProperties(Event(EventIDs::kPlay, 0), DynamicValue(), getSelfReference()));
-		Common::SharedPtr<MessageDispatch> dispatch(new MessageDispatch(msgProps, this, false, true, false));
-		taskData.runtime->sendMessageOnVThread(dispatch);
-	}
+CORO_BEGIN_DEFINITION(SoundElement::StartPlayingCoroutine)
+	struct Locals {
+	};
 
-	if (_paused) {
-		Common::SharedPtr<MessageProperties> msgProps(new MessageProperties(Event(EventIDs::kUnpause, 0), DynamicValue(), getSelfReference()));
-		Common::SharedPtr<MessageDispatch> dispatch(new MessageDispatch(msgProps, this, false, true, false));
-		taskData.runtime->sendMessageOnVThread(dispatch);
+	CORO_BEGIN_FUNCTION
+		// Unpaused -> Played
 
-		_paused = false;
-	}
+		params->self->_shouldPlayIfNotPaused = true;
+		params->self->_needsReset = true;
 
-	_shouldPlayIfNotPaused = true;
-	_needsReset = true;
+		CORO_IF (params->self->_paused)
+			params->self->_paused = false;
+		
+			Common::SharedPtr<MessageProperties> msgProps(new MessageProperties(Event(EventIDs::kUnpause, 0), DynamicValue(), params->self->getSelfReference()));
+			Common::SharedPtr<MessageDispatch> dispatch(new MessageDispatch(msgProps, params->self, false, true, false));
 
-	return kVThreadReturn;
-}
+			CORO_CALL(Runtime::SendMessageOnVThreadCoroutine, params->runtime, dispatch);
+		CORO_END_IF
 
-VThreadState SoundElement::stopPlayingTask(const StartPlayingTaskData &taskData) {
-	if (_shouldPlayIfNotPaused) {
-		Common::SharedPtr<MessageProperties> msgProps(new MessageProperties(Event(EventIDs::kStop, 0), DynamicValue(), getSelfReference()));
-		Common::SharedPtr<MessageDispatch> dispatch(new MessageDispatch(msgProps, this, false, true, false));
-		taskData.runtime->sendMessageOnVThread(dispatch);
+		Common::SharedPtr<MessageProperties> msgProps(new MessageProperties(Event(EventIDs::kPlay, 0), DynamicValue(), params->self->getSelfReference()));
+		Common::SharedPtr<MessageDispatch> dispatch(new MessageDispatch(msgProps, params->self, false, true, false));
 
-		_shouldPlayIfNotPaused = false;
-		_needsReset = true;
-	}
+		CORO_CALL(Runtime::SendMessageOnVThreadCoroutine, params->runtime, dispatch);
+	CORO_END_FUNCTION
+CORO_END_DEFINITION
 
-	return kVThreadReturn;
-}
+CORO_BEGIN_DEFINITION(SoundElement::StopPlayingCoroutine)
+	struct Locals {
+	};
+
+	CORO_BEGIN_FUNCTION
+		CORO_IF (params->self->_shouldPlayIfNotPaused)
+			params->self->_shouldPlayIfNotPaused = false;
+			params->self->_needsReset = true;
+
+			Common::SharedPtr<MessageProperties> msgProps(new MessageProperties(Event(EventIDs::kStop, 0), DynamicValue(), params->self->getSelfReference()));
+			Common::SharedPtr<MessageDispatch> dispatch(new MessageDispatch(msgProps, params->self, false, true, false));
+
+			CORO_CALL(Runtime::SendMessageOnVThreadCoroutine, params->runtime, dispatch);
+		CORO_END_IF
+	CORO_END_FUNCTION
+CORO_END_DEFINITION
 
 } // End of namespace MTropolis
diff --git a/engines/mtropolis/elements.h b/engines/mtropolis/elements.h
index 86c0259e331..9ac7c156835 100644
--- a/engines/mtropolis/elements.h
+++ b/engines/mtropolis/elements.h
@@ -441,14 +441,20 @@ private:
 	MiniscriptInstructionOutcome scriptSetBalance(MiniscriptThread *thread, const DynamicValue &value);
 	MiniscriptInstructionOutcome scriptSetAsset(MiniscriptThread *thread, const DynamicValue &value);
 
-	struct StartPlayingTaskData {
-		StartPlayingTaskData() : runtime(nullptr) {}
+	struct SoundElementConsumeCommandCoroutine {
+		CORO_DEFINE_RETURN_TYPE(void);
+		CORO_DEFINE_PARAMS_3(SoundElement *, self, Runtime *, runtime, Common::SharedPtr<MessageProperties>, msg);
+	};
 
-		Runtime *runtime;
+	struct StartPlayingCoroutine {
+		CORO_DEFINE_RETURN_TYPE(void);
+		CORO_DEFINE_PARAMS_2(SoundElement *, self, Runtime *, runtime);
 	};
 
-	VThreadState startPlayingTask(const StartPlayingTaskData &taskData);
-	VThreadState stopPlayingTask(const StartPlayingTaskData &taskData);
+	struct StopPlayingCoroutine {
+		CORO_DEFINE_RETURN_TYPE(void);
+		CORO_DEFINE_PARAMS_2(SoundElement *, self, Runtime *, runtime);
+	};
 
 	void setLoop(bool loop);
 	void setVolume(uint16 volume);
diff --git a/engines/mtropolis/runtime.h b/engines/mtropolis/runtime.h
index 213ba8e8aa4..dd009759f8a 100644
--- a/engines/mtropolis/runtime.h
+++ b/engines/mtropolis/runtime.h
@@ -2996,6 +2996,8 @@ public:
 	bool isVisual() const override;
 
 	bool loadCommon(const Common::String &name, uint32 guid, uint32 elementFlags);
+
+	typedef ElementConsumeCommandCoroutine NonVisualElementConsumeCommandCoroutine;
 };
 
 struct ModifierFlags {


Commit: fdaa96dabaeb0cc98d0fd84f54d0a009e40432af
    https://github.com/scummvm/scummvm/commit/fdaa96dabaeb0cc98d0fd84f54d0a009e40432af
Author: elasota (1137273+elasota at users.noreply.github.com)
Date: 2024-08-29T22:07:46-04:00

Commit Message:
MTROPOLIS: Convert Miniscript program runs from tasks to coroutines

Changed paths:
    engines/mtropolis/coroutine_exec.cpp
    engines/mtropolis/coroutine_protos.h
    engines/mtropolis/coroutines.h
    engines/mtropolis/elements.cpp
    engines/mtropolis/miniscript.cpp
    engines/mtropolis/miniscript.h
    engines/mtropolis/miniscript_protos.h
    engines/mtropolis/modifiers.cpp
    engines/mtropolis/modifiers.h
    engines/mtropolis/runtime.cpp


diff --git a/engines/mtropolis/coroutine_exec.cpp b/engines/mtropolis/coroutine_exec.cpp
index eff85063b7c..f8485bf3506 100644
--- a/engines/mtropolis/coroutine_exec.cpp
+++ b/engines/mtropolis/coroutine_exec.cpp
@@ -79,7 +79,7 @@ VThreadState CoroutineStackFrame2::execute(VThread *thread) {
 				return kVThreadError;
 			else if (runtimeState._miniscriptOutcome == kMiniscriptInstructionOutcomeContinue)
 				break;
-			else if (runtimeState._miniscriptOutcome == kMiniscriptInstructionOutcomeYieldToVThreadNoRetry) {
+			else if (runtimeState._miniscriptOutcome == kMiniscriptInstructionOutcomeYieldToVThread) {
 				_nextInstr = ip;
 				return kVThreadReturn;
 			} else {
diff --git a/engines/mtropolis/coroutine_protos.h b/engines/mtropolis/coroutine_protos.h
index 087b5f7abb3..688b9c22b82 100644
--- a/engines/mtropolis/coroutine_protos.h
+++ b/engines/mtropolis/coroutine_protos.h
@@ -104,6 +104,27 @@ struct CoroutineParamsBase {
 		Params() = delete;																\
 	}
 
+#define CORO_DEFINE_PARAMS_4(type1, name1, type2, name2, type3, name3, type4, name4)	\
+	CORO_STUB																			\
+	struct Params : public CoroutineParamsBase {										\
+		typedef type1 ParamType1_t;														\
+		typedef type2 ParamType2_t;														\
+		typedef type3 ParamType3_t;														\
+		typedef type4 ParamType4_t;														\
+																						\
+		ParamType1_t name1;																\
+		ParamType2_t name2;																\
+		ParamType3_t name3;																\
+		ParamType4_t name4;																\
+																						\
+		explicit Params(const ParamType1_t &p_##name1, const ParamType2_t &p_##name2, const ParamType3_t &p_##name3, const ParamType4_t &p_##name4)	\
+			: name1(p_##name1), name2(p_##name2), name3(p_##name3), name4(p_##name4) {	\
+		}																				\
+																						\
+	private:																			\
+		Params() = delete;																\
+	}
+
 #define CORO_DEFINE_RETURN_TYPE(type)	\
 	typedef type ReturnValue_t
 
diff --git a/engines/mtropolis/coroutines.h b/engines/mtropolis/coroutines.h
index 7b0c179d9e7..48f8a34b876 100644
--- a/engines/mtropolis/coroutines.h
+++ b/engines/mtropolis/coroutines.h
@@ -129,7 +129,10 @@ struct ICoroutineCompiler {
 		Locals *locals = &static_cast<CoroStackFrame *>(coroRuntime._frame)->_locals;											\
 		CoroutineReturnValueRef<ReturnValue_t> coroReturnValueRef = (static_cast<CoroStackFrame *>(coroRuntime._frame)->_rvRef);
 
-#define CORO_DISUSE_CODE_BLOCK_VARS	\
+#define CORO_AWAIT_PUSHED_TASK					\
+	return kVThreadReturn
+
+#define CORO_DISUSE_CODE_BLOCK_VARS				\
 		(void)params;							\
 		(void)locals;							\
 		(void)coroReturnValueRef;
@@ -209,11 +212,11 @@ void type::compileCoroutine(ICoroutineCompiler *compiler) {
 #define CORO_WHILE(expr)						\
 	CORO_END_CODE_BLOCK							\
 	CORO_START_CODE_BLOCK(CoroOps::WhileCond)	\
-		coroCondition = !!(expr);				\
+		coroRuntime._condition = !!(expr);		\
 	CORO_END_CODE_BLOCK							\
 	CORO_START_CODE_BLOCK(CoroOps::WhileBody)
 
-#define CORO_END_WHILE(expr)					\
+#define CORO_END_WHILE							\
 	CORO_END_CODE_BLOCK							\
 	CORO_START_CODE_BLOCK(CoroOps::EndWhile)
 
diff --git a/engines/mtropolis/elements.cpp b/engines/mtropolis/elements.cpp
index a6ff61e52bc..fd1504c51eb 100644
--- a/engines/mtropolis/elements.cpp
+++ b/engines/mtropolis/elements.cpp
@@ -1057,7 +1057,7 @@ MiniscriptInstructionOutcome MovieElement::scriptSetTimestamp(MiniscriptThread *
 
 	if (asInteger != (int32)_currentTimestamp) {
 		thread->getRuntime()->getVThread().pushCoroutine<MovieElement::SeekToTimeCoroutine>(this, getRuntime(), asInteger);
-		return kMiniscriptInstructionOutcomeYieldToVThreadNoRetry;
+		return kMiniscriptInstructionOutcomeYieldToVThread;
 	}
 
 	return kMiniscriptInstructionOutcomeContinue;
@@ -1128,7 +1128,7 @@ MiniscriptInstructionOutcome MovieElement::scriptSetRangeTyped(MiniscriptThread
 
 	if (targetTS != _currentTimestamp) {
 		thread->getRuntime()->getVThread().pushCoroutine<MovieElement::SeekToTimeCoroutine>(this, getRuntime(), targetTS);
-		return kMiniscriptInstructionOutcomeYieldToVThreadNoRetry;
+		return kMiniscriptInstructionOutcomeYieldToVThread;
 	}
 
 	return kMiniscriptInstructionOutcomeContinue;
diff --git a/engines/mtropolis/miniscript.cpp b/engines/mtropolis/miniscript.cpp
index fc9412c9914..4a61691a5ab 100644
--- a/engines/mtropolis/miniscript.cpp
+++ b/engines/mtropolis/miniscript.cpp
@@ -24,6 +24,7 @@
 #include "common/random.h"
 #include "common/memstream.h"
 
+#include "mtropolis/coroutines.h"
 #include "mtropolis/miniscript.h"
 
 namespace MTropolis {
@@ -630,7 +631,7 @@ MiniscriptInstructionOutcome Send::execute(MiniscriptThread *thread) const {
 
 	if (_messageFlags.immediate) {
 		thread->getRuntime()->sendMessageOnVThread(dispatch);
-		return kMiniscriptInstructionOutcomeYieldToVThreadNoRetry;
+		return kMiniscriptInstructionOutcomeYieldToVThread;
 	} else {
 		thread->getRuntime()->queueMessage(dispatch);
 		return kMiniscriptInstructionOutcomeContinue;
@@ -1907,12 +1908,7 @@ MiniscriptInstructionOutcome Jump::execute(MiniscriptThread *thread) const {
 } // End of namespace MiniscriptInstructions
 
 MiniscriptThread::MiniscriptThread(Runtime *runtime, const Common::SharedPtr<MessageProperties> &msgProps, const Common::SharedPtr<MiniscriptProgram> &program, const Common::SharedPtr<MiniscriptReferences> &refs, Modifier *modifier)
-	: _runtime(runtime), _msgProps(msgProps), _program(program), _refs(refs), _modifier(modifier), _currentInstruction(0), _failed(false) {
-}
-
-void MiniscriptThread::runOnVThread(VThread &vthread, const Common::SharedPtr<MiniscriptThread> &thread) {
-	ResumeTaskData *taskData = vthread.pushTask("MiniscriptThread::resumeTask", resumeTask);
-	taskData->thread = thread;
+	: _runtime(runtime), _msgProps(msgProps), _program(program), _instructions(program->getInstructions()), _refs(refs), _modifier(modifier), _currentInstruction(0), _failed(false) {
 }
 
 void MiniscriptThread::error(const Common::String &message) {
@@ -2026,6 +2022,10 @@ void MiniscriptThread::createWriteIncomingDataProxy(DynamicValueWriteProxy &prox
 	proxy.pod.ptrOrOffset = 0;
 }
 
+void MiniscriptThread::retryInstruction() {
+	_currentInstruction--;
+}
+
 MiniscriptInstructionOutcome MiniscriptThread::IncomingDataWriteInterface::write(MiniscriptThread *thread, const DynamicValue &value, void *objectRef, uintptr ptrOrOffset) {
 	thread->_msgProps->setValue(value);
 
@@ -2042,50 +2042,40 @@ MiniscriptInstructionOutcome MiniscriptThread::IncomingDataWriteInterface::refAt
 	return kMiniscriptInstructionOutcomeFailed;
 }
 
+CORO_BEGIN_DEFINITION(MiniscriptThread::ResumeThreadCoroutine)
+	struct Locals {
+		MiniscriptThread *self = nullptr;
+		size_t numInstrs = 0;
+		size_t instrNum = 0;
+	};
 
-VThreadState MiniscriptThread::resumeTask(const ResumeTaskData &data) {
-	return data.thread->resume(data);
-}
-
-VThreadState MiniscriptThread::resume(const ResumeTaskData &taskData) {
-	const Common::Array<MiniscriptInstruction *> &instrsArray = _program->getInstructions();
-
-	if (instrsArray.size() == 0)
-		return kVThreadReturn;
-
-	MiniscriptInstruction *const *instrs = &instrsArray[0];
-	size_t numInstrs = instrsArray.size();
+	CORO_BEGIN_FUNCTION
+		locals->self = params->thread.get();
+		locals->numInstrs = locals->self->_program->getInstructions().size();
 
-	if (_currentInstruction >= numInstrs || _failed)
-		return kVThreadReturn;
+		CORO_IF (locals->numInstrs == 0)
+			CORO_RETURN;
+		CORO_END_IF
 
-	// Requeue now so that any VThread tasks queued by instructions run in front of the resume
-	{
-		ResumeTaskData *requeueData = _runtime->getVThread().pushTask("MiniscriptThread::resumeTask", resumeTask);
-		requeueData->thread = taskData.thread;
-	}
-
-	while (_currentInstruction < numInstrs && !_failed) {
-		size_t instrNum = _currentInstruction++;
-		MiniscriptInstruction *instr = instrs[instrNum];
+		CORO_WHILE (locals->self->_currentInstruction < locals->numInstrs && !locals->self->_failed)
+			CORO_AWAIT_MINISCRIPT(locals->self->runNextInstruction());
+		CORO_END_WHILE
+	CORO_END_FUNCTION
+CORO_END_DEFINITION
 
-		MiniscriptInstructionOutcome outcome = instr->execute(this);
-		if (outcome == kMiniscriptInstructionOutcomeFailed) {
-			// Should this also interrupt the message dispatch?
-			_failed = true;
-			return kVThreadReturn;
-		}
+MiniscriptInstructionOutcome MiniscriptThread::runNextInstruction() {
+	const MiniscriptInstruction *instr = _instructions[_currentInstruction++];
 
-		if (outcome == kMiniscriptInstructionOutcomeYieldToVThreadAndRetry) {
-			_currentInstruction = instrNum;
-			return kVThreadReturn;
-		}
+	MiniscriptInstructionOutcome outcome = instr->execute(this);
 
-		if (outcome == kMiniscriptInstructionOutcomeYieldToVThreadNoRetry)
-			return kVThreadReturn;
+	if (outcome == kMiniscriptInstructionOutcomeFailed) {
+		// Treat this as non-fatal but bail out of the execution loop
+		_failed = true;
+		return kMiniscriptInstructionOutcomeContinue;
 	}
 
-	return kVThreadReturn;
+	// Otherwise continue
+	return outcome;
 }
 
 MiniscriptInstructionOutcome MiniscriptThread::tryLoadVariable(MiniscriptStackValue &stackValue) {
diff --git a/engines/mtropolis/miniscript.h b/engines/mtropolis/miniscript.h
index 523a210edc8..401f1140555 100644
--- a/engines/mtropolis/miniscript.h
+++ b/engines/mtropolis/miniscript.h
@@ -422,8 +422,6 @@ class MiniscriptThread {
 public:
 	MiniscriptThread(Runtime *runtime, const Common::SharedPtr<MessageProperties> &msgProps, const Common::SharedPtr<MiniscriptProgram> &program, const Common::SharedPtr<MiniscriptReferences> &refs, Modifier *modifier);
 
-	static void runOnVThread(VThread &vthread, const Common::SharedPtr<MiniscriptThread> &thread);
-
 	void error(const Common::String &message);
 
 	const Common::SharedPtr<MiniscriptProgram> &getProgram() const;
@@ -444,6 +442,13 @@ public:
 
 	void createWriteIncomingDataProxy(DynamicValueWriteProxy &proxy);
 
+	void retryInstruction();
+
+	struct ResumeThreadCoroutine {
+		CORO_DEFINE_RETURN_TYPE(void);
+		CORO_DEFINE_PARAMS_1(Common::SharedPtr<MiniscriptThread>, thread);
+	};
+
 private:
 	struct IncomingDataWriteInterface {
 		static MiniscriptInstructionOutcome write(MiniscriptThread *thread, const DynamicValue &dest, void *objectRef, uintptr ptrOrOffset);
@@ -451,18 +456,17 @@ private:
 		static MiniscriptInstructionOutcome refAttribIndexed(MiniscriptThread *thread, DynamicValueWriteProxy &proxy, void *objectRef, uintptr ptrOrOffset, const Common::String &attrib, const DynamicValue &index);
 	};
 
-	struct ResumeTaskData {
-		Common::SharedPtr<MiniscriptThread> thread;
-	};
+	MiniscriptInstructionOutcome runNextInstruction();
 
-	static VThreadState resumeTask(const ResumeTaskData &data);
-	VThreadState resume(const ResumeTaskData &data);
+	VThreadState resume(MiniscriptThread *thread);
 
 	MiniscriptInstructionOutcome tryLoadVariable(MiniscriptStackValue &stackValue);
 
 	Common::SharedPtr<MiniscriptProgram> _program;
 	Common::SharedPtr<MiniscriptReferences> _refs;
 	Common::SharedPtr<MessageProperties> _msgProps;
+
+	const Common::Array<MiniscriptInstruction *> &_instructions;
 	Modifier *_modifier;
 	Runtime *_runtime;
 	Common::Array<MiniscriptStackValue> _stack;
diff --git a/engines/mtropolis/miniscript_protos.h b/engines/mtropolis/miniscript_protos.h
index df445fdd9bc..ae082a1bac7 100644
--- a/engines/mtropolis/miniscript_protos.h
+++ b/engines/mtropolis/miniscript_protos.h
@@ -25,10 +25,9 @@
 namespace MTropolis {
 
 enum MiniscriptInstructionOutcome {
-	kMiniscriptInstructionOutcomeContinue,               // Continue executing next instruction
-	kMiniscriptInstructionOutcomeYieldToVThreadNoRetry,  // Instruction pushed a VThread task and should be retried when the task completes
-	kMiniscriptInstructionOutcomeYieldToVThreadAndRetry, // Instruction pushed a VThread task and completed
-	kMiniscriptInstructionOutcomeFailed,                 // Instruction errored
+	kMiniscriptInstructionOutcomeContinue,			// Continue executing next instruction
+	kMiniscriptInstructionOutcomeYieldToVThread,	// Instruction pushed a VThread task
+	kMiniscriptInstructionOutcomeFailed,			// Instruction errored
 };
 
 } // End of namespace MTropolis
diff --git a/engines/mtropolis/modifiers.cpp b/engines/mtropolis/modifiers.cpp
index aecd38a350f..e1799f25393 100644
--- a/engines/mtropolis/modifiers.cpp
+++ b/engines/mtropolis/modifiers.cpp
@@ -26,6 +26,7 @@
 
 #include "mtropolis/assets.h"
 #include "mtropolis/audio_player.h"
+#include "mtropolis/coroutines.h"
 #include "mtropolis/miniscript.h"
 #include "mtropolis/modifiers.h"
 #include "mtropolis/modifier_factory.h"
@@ -252,7 +253,7 @@ bool MiniscriptModifier::respondsToEvent(const Event &evt) const {
 VThreadState MiniscriptModifier::consumeMessage(Runtime *runtime, const Common::SharedPtr<MessageProperties> &msg) {
 	if (_enableWhen.respondsTo(msg->getEvent())) {
 		Common::SharedPtr<MiniscriptThread> thread(new MiniscriptThread(runtime, msg, _program, _references, this));
-		MiniscriptThread::runOnVThread(runtime->getVThread(), thread);
+		runtime->getVThread().pushCoroutine<MiniscriptThread::ResumeThreadCoroutine>(thread);
 	}
 
 	return kVThreadReturn;
@@ -1855,18 +1856,36 @@ bool IfMessengerModifier::respondsToEvent(const Event &evt) const {
 	return _when.respondsTo(evt);
 }
 
-VThreadState IfMessengerModifier::consumeMessage(Runtime *runtime, const Common::SharedPtr<MessageProperties> &msg) {
-	if (_when.respondsTo(msg->getEvent())) {
-		Common::SharedPtr<MiniscriptThread> thread(new MiniscriptThread(runtime, msg, _program, _references, this));
+CORO_BEGIN_DEFINITION(IfMessengerModifier::RunEvaluateAndSendCoroutine)
+	struct Locals {
+		Common::WeakPtr<RuntimeObject> triggerSource;
+		DynamicValue incomingData;
+		bool isTrue = false;
+		Common::SharedPtr<MiniscriptThread> thread;
+	};
 
-		EvaluateAndSendTaskData *evalAndSendData = runtime->getVThread().pushTask("IfMessengerModifier::evaluateAndSendTask", this, &IfMessengerModifier::evaluateAndSendTask);
-		evalAndSendData->thread = thread;
-		evalAndSendData->runtime = runtime;
-		evalAndSendData->incomingData = msg->getValue();
-		evalAndSendData->triggerSource = msg->getSource();
+	CORO_BEGIN_FUNCTION
+		// Is this the right place for this?  Not sure if Miniscript can change incomingData
+		locals->triggerSource = params->msg->getSource();
+		locals->incomingData = params->msg->getValue();
 
-		MiniscriptThread::runOnVThread(runtime->getVThread(), thread);
-	}
+		locals->thread.reset(new MiniscriptThread(params->runtime, params->msg, params->self->_program, params->self->_references, params->self));
+
+		CORO_CALL(MiniscriptThread::ResumeThreadCoroutine, locals->thread);
+
+		CORO_IF (!locals->thread->evaluateTruthOfResult(locals->isTrue))
+			CORO_ERROR;
+		CORO_END_IF
+
+		CORO_IF(locals->isTrue)
+			CORO_AWAIT(params->self->_sendSpec.sendFromMessenger(params->runtime, params->self, locals->triggerSource.lock().get(), locals->incomingData, nullptr));
+		CORO_END_IF
+	CORO_END_FUNCTION
+CORO_END_DEFINITION
+
+VThreadState IfMessengerModifier::consumeMessage(Runtime *runtime, const Common::SharedPtr<MessageProperties> &msg) {
+	if (_when.respondsTo(msg->getEvent()))
+		runtime->getVThread().pushCoroutine<IfMessengerModifier::RunEvaluateAndSendCoroutine>(this, runtime, msg);
 
 	return kVThreadReturn;
 }
@@ -1895,20 +1914,6 @@ void IfMessengerModifier::visitInternalReferences(IStructuralReferenceVisitor *v
 	_references->visitInternalReferences(visitor);
 }
 
-
-VThreadState IfMessengerModifier::evaluateAndSendTask(const EvaluateAndSendTaskData &taskData) {
-	MiniscriptThread *thread = taskData.thread.get();
-
-	bool isTrue = false;
-	if (!thread->evaluateTruthOfResult(isTrue))
-		return kVThreadError;
-
-	if (isTrue)
-		_sendSpec.sendFromMessenger(taskData.runtime, this, taskData.triggerSource.lock().get(), taskData.incomingData, nullptr);
-
-	return kVThreadReturn;
-}
-
 TimerMessengerModifier::TimerMessengerModifier() : _milliseconds(0), _looping(false) {
 }
 
diff --git a/engines/mtropolis/modifiers.h b/engines/mtropolis/modifiers.h
index ce3590b1c27..f7527d50bd1 100644
--- a/engines/mtropolis/modifiers.h
+++ b/engines/mtropolis/modifiers.h
@@ -707,13 +707,9 @@ public:
 #endif
 
 private:
-	struct EvaluateAndSendTaskData {
-		EvaluateAndSendTaskData() : runtime(nullptr) {}
-
-		Common::SharedPtr<MiniscriptThread> thread;
-		Common::WeakPtr<RuntimeObject> triggerSource;
-		Runtime *runtime;
-		DynamicValue incomingData;
+	struct RunEvaluateAndSendCoroutine {
+		CORO_DEFINE_RETURN_TYPE(void);
+		CORO_DEFINE_PARAMS_3(IfMessengerModifier *, self, Runtime *, runtime, Common::SharedPtr<MessageProperties>, msg);
 	};
 
 	Common::SharedPtr<Modifier> shallowClone() const override;
@@ -721,8 +717,6 @@ private:
 	void linkInternalReferences(ObjectLinkingScope *scope) override;
 	void visitInternalReferences(IStructuralReferenceVisitor *visitor) override;
 
-	VThreadState evaluateAndSendTask(const EvaluateAndSendTaskData &taskData);
-
 	Event _when;
 	MessengerSendSpec _sendSpec;
 
diff --git a/engines/mtropolis/runtime.cpp b/engines/mtropolis/runtime.cpp
index 54c4173392e..b7e1ca4b8f2 100644
--- a/engines/mtropolis/runtime.cpp
+++ b/engines/mtropolis/runtime.cpp
@@ -4006,7 +4006,7 @@ MiniscriptInstructionOutcome Structural::scriptSetPaused(MiniscriptThread *threa
 		thread->getRuntime()->sendMessageOnVThread(dispatch);
 	}
 
-	return kMiniscriptInstructionOutcomeYieldToVThreadNoRetry;
+	return kMiniscriptInstructionOutcomeYieldToVThread;
 }
 
 MiniscriptInstructionOutcome Structural::scriptSetLoop(MiniscriptThread *thread, const DynamicValue &value) {


Commit: 850e92343dedbd37c55cf53d4c909334256074e2
    https://github.com/scummvm/scummvm/commit/850e92343dedbd37c55cf53d4c909334256074e2
Author: elasota (1137273+elasota at users.noreply.github.com)
Date: 2024-08-29T22:07:46-04:00

Commit Message:
MTROPOLIS: Fix some data readers not returning error codes on read failure

Changed paths:
    engines/mtropolis/data.cpp


diff --git a/engines/mtropolis/data.cpp b/engines/mtropolis/data.cpp
index 4d23e87554d..338ee8450af 100644
--- a/engines/mtropolis/data.cpp
+++ b/engines/mtropolis/data.cpp
@@ -1575,7 +1575,7 @@ DataReadErrorCode VectorMotionModifier::load(DataReader &reader) {
 		|| !reader.readU16(unknown1) || !reader.readU8(vecSourceLength) || !reader.readU8(vecStringLength)
 		|| !reader.readNonTerminatedStr(vecSource, vecSourceLength)
 		/*|| !reader.readNonTerminatedStr(vecString, vecStringLength)*/)	// mTropolis bug!
-		return kDataReadErrorNone;
+		return kDataReadErrorReadFailed;
 
 	return kDataReadErrorNone;
 }
@@ -1594,7 +1594,7 @@ DataReadErrorCode SceneTransitionModifier::load(DataReader &reader) {
 	if (!enableWhen.load(reader) || !disableWhen.load(reader) || !reader.readU16(transitionType)
 		|| !reader.readU16(direction) || !reader.readU16(unknown3) || !reader.readU16(steps)
 		|| !reader.readU32(duration) || !reader.readBytes(unknown5))
-		return kDataReadErrorNone;
+		return kDataReadErrorReadFailed;
 
 	return kDataReadErrorNone;
 }
@@ -1614,7 +1614,7 @@ DataReadErrorCode ElementTransitionModifier::load(DataReader &reader) {
 	if (!enableWhen.load(reader) || !disableWhen.load(reader) || !reader.readU16(revealType)
 		|| !reader.readU16(transitionType) || !reader.readU16(unknown3) || !reader.readU16(unknown4)
 		|| !reader.readU16(steps) || !reader.readU16(rate))
-		return kDataReadErrorNone;
+		return kDataReadErrorReadFailed;
 
 	return kDataReadErrorNone;
 }




More information about the Scummvm-git-logs mailing list