[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