[Scummvm-git-logs] scummvm master -> 029b6738cbab7bdb176a6b99db2b3df173200d87

elasota noreply at scummvm.org
Tue Jan 24 06:35:49 UTC 2023


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:
029b6738cb MTROPOLIS: Add support for assigning sound assets and loading assets from other streams.


Commit: 029b6738cbab7bdb176a6b99db2b3df173200d87
    https://github.com/scummvm/scummvm/commit/029b6738cbab7bdb176a6b99db2b3df173200d87
Author: elasota (ejlasota at gmail.com)
Date: 2023-01-23T23:06:49-05:00

Commit Message:
MTROPOLIS: Add support for assigning sound assets and loading assets from other streams.

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


diff --git a/engines/mtropolis/data.cpp b/engines/mtropolis/data.cpp
index 60816e2ace2..aebe8d02650 100644
--- a/engines/mtropolis/data.cpp
+++ b/engines/mtropolis/data.cpp
@@ -740,7 +740,7 @@ DataReadErrorCode PresentationSettings::load(DataReader &reader) {
 AssetCatalog::AssetInfoRev4Fields::AssetInfoRev4Fields() : assetType(0), flags2(0) {
 }
 
-AssetCatalog::AssetInfo::AssetInfo() : flags1(0), nameLength(0), alwaysZero(0), unknown1(0), filePosition(0) {
+AssetCatalog::AssetInfo::AssetInfo() : flags1(0), nameLength(0), alwaysZero(0), streamID(0), filePosition(0) {
 }
 
 AssetCatalog::AssetCatalog() : persistFlags(0), totalNameSizePlus22(0), unknown1{0, 0, 0, 0}, numAssets(0), haveRev4Fields(false) {
@@ -762,7 +762,7 @@ DataReadErrorCode AssetCatalog::load(DataReader& reader) {
 
 	for (size_t i = 0; i < numAssets; i++) {
 		AssetInfo &asset = assets[i];
-		if (!reader.readU32(asset.flags1) || !reader.readU16(asset.nameLength) || !reader.readU16(asset.alwaysZero) || !reader.readU32(asset.unknown1) || !reader.readU32(asset.filePosition))
+		if (!reader.readU32(asset.flags1) || !reader.readU16(asset.nameLength) || !reader.readU16(asset.alwaysZero) || !reader.readU32(asset.streamID) || !reader.readU32(asset.filePosition))
 			return kDataReadErrorReadFailed;
 
 		if (_revision >= 4) {
diff --git a/engines/mtropolis/data.h b/engines/mtropolis/data.h
index 71be2bccefc..e6e6303e1b7 100644
--- a/engines/mtropolis/data.h
+++ b/engines/mtropolis/data.h
@@ -502,7 +502,7 @@ struct AssetCatalog : public DataObject {
 		uint32 flags1;
 		uint16 nameLength;
 		uint16 alwaysZero;
-		uint32 unknown1;	 // Possibly scene ID
+		uint32 streamID;
 		uint32 filePosition; // Contains a static value in Obsidian
 
 		AssetInfoRev4Fields rev4Fields;
diff --git a/engines/mtropolis/elements.cpp b/engines/mtropolis/elements.cpp
index 35a9fc02ef9..92d1f2cf890 100644
--- a/engines/mtropolis/elements.cpp
+++ b/engines/mtropolis/elements.cpp
@@ -2122,6 +2122,9 @@ MiniscriptInstructionOutcome SoundElement::writeRefAttribute(MiniscriptThread *t
 	} else if (attrib == "balance") {
 		DynamicValueWriteFuncHelper<SoundElement, &SoundElement::scriptSetBalance, true>::create(this, writeProxy);
 		return kMiniscriptInstructionOutcomeContinue;
+	} else if (attrib == "asset") {
+		DynamicValueWriteFuncHelper<SoundElement, &SoundElement::scriptSetAsset, true>::create(this, writeProxy);
+		return kMiniscriptInstructionOutcomeContinue;
 	}
 
 	return NonVisualElement::writeRefAttribute(thread, writeProxy, attrib);
@@ -2333,6 +2336,53 @@ MiniscriptInstructionOutcome SoundElement::scriptSetBalance(MiniscriptThread *th
 	return kMiniscriptInstructionOutcomeContinue;
 }
 
+MiniscriptInstructionOutcome SoundElement::scriptSetAsset(MiniscriptThread *thread, const DynamicValue &value) {
+	DynamicValue derefValue = value.dereference();
+
+	if (derefValue.getType() != DynamicValueTypes::kString) {
+		thread->error("Tried to set a sound element's asset to something that wasn't a string");
+		return kMiniscriptInstructionOutcomeFailed;
+	}
+
+	stopPlayer();
+
+	Project *project = thread->getRuntime()->getProject();
+
+	uint32 assetID = 0;
+	if (!project->getAssetIDByName(derefValue.getString(), assetID)) {
+		warning("Sound element references asset '%s' but the asset ID couldn't be resolved", derefValue.getString().c_str());
+		return kMiniscriptInstructionOutcomeFailed;
+	}
+
+	Common::Array<Common::SharedPtr<Asset> > forceLoadedAssets;
+
+	Common::SharedPtr<Asset> asset = project->getAssetByID(assetID).lock();
+
+	if (!asset) {
+		if (thread->getRuntime()->getHacks().allowAssetsFromOtherScenes) {
+			project->forceLoadAsset(assetID, forceLoadedAssets);
+			asset = project->getAssetByID(assetID).lock();
+		}
+	}
+
+	if (!asset) {
+		warning("Sound element references asset '%s' but the asset isn't loaded!", derefValue.getString().c_str());
+		return kMiniscriptInstructionOutcomeFailed;
+	}
+
+	if (asset->getAssetType() != kAssetTypeAudio) {
+		warning("Sound element assigned an asset that isn't audio");
+		return kMiniscriptInstructionOutcomeFailed;
+	}
+
+	_cachedAudio = static_cast<AudioAsset *>(asset.get())->loadAndCacheAudio(getRuntime());
+	_metadata = static_cast<AudioAsset *>(asset.get())->getMetadata();
+	_assetID = asset->getAssetID();
+
+	return kMiniscriptInstructionOutcomeContinue;
+
+}
+
 void SoundElement::setLoop(bool loop) {
 	_loop = loop;
 }
diff --git a/engines/mtropolis/elements.h b/engines/mtropolis/elements.h
index e07dee2a7a4..de89d55721d 100644
--- a/engines/mtropolis/elements.h
+++ b/engines/mtropolis/elements.h
@@ -391,6 +391,7 @@ private:
 	MiniscriptInstructionOutcome scriptSetLoop(MiniscriptThread *thread, const DynamicValue &value);
 	MiniscriptInstructionOutcome scriptSetVolume(MiniscriptThread *thread, const DynamicValue &value);
 	MiniscriptInstructionOutcome scriptSetBalance(MiniscriptThread *thread, const DynamicValue &value);
+	MiniscriptInstructionOutcome scriptSetAsset(MiniscriptThread *thread, const DynamicValue &value);
 
 	struct StartPlayingTaskData {
 		StartPlayingTaskData() : runtime(nullptr) {}
diff --git a/engines/mtropolis/hacks.cpp b/engines/mtropolis/hacks.cpp
index 980ef54a45c..1bcf01908f0 100644
--- a/engines/mtropolis/hacks.cpp
+++ b/engines/mtropolis/hacks.cpp
@@ -41,6 +41,7 @@ Hacks::Hacks() {
 	midiVolumeScale = 256;
 	minTransitionDuration = 0;
 	ignoreMToonMaintainRateFlag = false;
+	allowAssetsFromOtherScenes = false;
 	mtiVariableReferencesHack = false;
 	mtiSceneReturnHack = false;
 }
@@ -1031,6 +1032,9 @@ void addMTIQuirks(const MTropolisGameDescription &desc, Hacks &hacks) {
 	// Given that the flag should not be set, we ignore the flag.
 	hacks.ignoreMToonMaintainRateFlag = true;
 
+	// Needed for piano, the sound assets are in B10 : Notes but the piano is in B10 : Piano
+	hacks.allowAssetsFromOtherScenes = true;
+
 	// MTI initializes variables in a way that doesn't seem to match mTropolis behavior in any explicable way:
 	//
 	// For example, 0010cb0e "Scene Started => init Benbow" looks like this internally, decompiled:
diff --git a/engines/mtropolis/hacks.h b/engines/mtropolis/hacks.h
index 57ce41b65b4..b1751c7a2a8 100644
--- a/engines/mtropolis/hacks.h
+++ b/engines/mtropolis/hacks.h
@@ -51,6 +51,7 @@ struct Hacks {
 	bool ignoreMismatchedProjectNameInObjectLookups;
 	bool removeQuickTimeEdits;
 	bool ignoreMToonMaintainRateFlag;
+	bool allowAssetsFromOtherScenes;
 	bool mtiVariableReferencesHack;
 	bool mtiSceneReturnHack;
 
diff --git a/engines/mtropolis/runtime.cpp b/engines/mtropolis/runtime.cpp
index 1bf6bb88f23..476bb7a6bb8 100644
--- a/engines/mtropolis/runtime.cpp
+++ b/engines/mtropolis/runtime.cpp
@@ -7143,6 +7143,60 @@ Common::WeakPtr<Asset> Project::getAssetByID(uint32 assetID) const {
 	return desc->asset;
 }
 
+void Project::forceLoadAsset(uint32 assetID, Common::Array<Common::SharedPtr<Asset> > &outHoldAssets) {
+	AssetDesc *assetDesc = _assetsByID[assetID];
+	uint32 streamID = assetDesc->streamID;
+
+	size_t streamIndex = streamID - 1;
+
+	const StreamDesc &streamDesc = _streams[streamIndex];
+	uint segmentIndex = streamDesc.segmentIndex;
+
+	openSegmentStream(segmentIndex);
+
+	Common::SeekableSubReadStreamEndian stream(_segments[segmentIndex].weakStream, streamDesc.pos, streamDesc.pos + streamDesc.size, _isBigEndian);
+	Data::DataReader reader(streamDesc.pos, stream, _projectFormat);
+
+	const Data::PlugInModifierRegistry &plugInDataLoaderRegistry = _plugInRegistry.getDataLoaderRegistry();
+
+	reader.seek(assetDesc->filePosition - streamDesc.pos);
+
+	Common::SharedPtr<Data::DataObject> dataObject;
+	Data::loadDataObject(plugInDataLoaderRegistry, reader, dataObject);
+
+	if (!dataObject) {
+		error("Failed to force-load asset data object");
+	}
+
+	Data::DataObjectTypes::DataObjectType dataObjectType = dataObject->getType();
+
+	if (!Data::DataObjectTypes::isAsset(dataObjectType)) {
+		error("Failed to force-load asset, the data object at the expected position wasn't an asset");
+	}
+
+	AssetDefLoaderContext assetDefLoader;
+	loadAssetDef(streamIndex, assetDefLoader, *dataObject.get());
+
+	assignAssets(assetDefLoader.assets, getRuntime()->getHacks());
+
+	outHoldAssets = Common::move(assetDefLoader.assets);
+}
+
+bool Project::getAssetIDByName(const Common::String &assetName, uint32 &outAssetID) const {
+	for (uint32 assetID = 0; assetID < _assetsByID.size(); assetID++) {
+		const AssetDesc *assetDesc = _assetsByID[assetID];
+		if (!assetDesc)
+			continue;
+
+		if (caseInsensitiveEqual(assetName, assetDesc->name)) {
+			outAssetID = assetID;
+			return true;
+		}
+	}
+
+	return false;
+}
+
 size_t Project::getSegmentForStreamIndex(size_t streamIndex) const {
 	return _streams[streamIndex].segmentIndex;
 }
@@ -7385,6 +7439,9 @@ void Project::loadAssetCatalog(const Data::AssetCatalog &assetCatalog) {
 			else
 				assetDesc.typeCode = 0;
 
+			assetDesc.streamID = assetInfo.streamID;
+			assetDesc.filePosition = assetInfo.filePosition;
+
 			_assetsByID[assetDesc.id] = &assetDesc;
 			if (!assetDesc.name.empty())
 				_assetNameToID[assetDesc.name] = assetDesc.id;
diff --git a/engines/mtropolis/runtime.h b/engines/mtropolis/runtime.h
index 3977e97ed43..1e492ec6468 100644
--- a/engines/mtropolis/runtime.h
+++ b/engines/mtropolis/runtime.h
@@ -2391,6 +2391,9 @@ public:
 
 	Common::String getAssetNameByID(uint32 assetID) const;
 	Common::WeakPtr<Asset> getAssetByID(uint32 assetID) const;
+	bool getAssetIDByName(const Common::String &assetName, uint32 &outAssetID) const;
+	void forceLoadAsset(uint32 assetID, Common::Array<Common::SharedPtr<Asset> > &outHoldAssets);
+
 	size_t getSegmentForStreamIndex(size_t streamIndex) const;
 	void openSegmentStream(int segmentIndex);
 	void closeSegmentStream(int segmentIndex);
@@ -2467,6 +2470,8 @@ private:
 		AssetDesc();
 
 		uint32 typeCode;
+		uint32 streamID;
+		uint32 filePosition;
 		size_t id;
 		Common::String name;
 




More information about the Scummvm-git-logs mailing list