Просмотр исходного кода

Implement most of IScriptFormatter

Paul 11 лет назад
Родитель
Сommit
a9a6eab1e5

+ 182 - 5
SupportedGames/FinalFantasy7/include/common/FF7NameLookup.h

@@ -25,17 +25,17 @@ namespace QGears
 {
     namespace FF7
     {
-        class FF7FiledModelsAndAnimationMetadata : public XmlFile
+        class FF7Metadata : public XmlFile
         {
         public:
-            FF7FiledModelsAndAnimationMetadata(Ogre::String file)
+            FF7Metadata(Ogre::String file)
                 : XmlFile(file)
             {
                 TiXmlNode* node = m_File.RootElement();
 
                 if (node == nullptr || node->ValueStr() != "metadata")
                 {
-                    throw std::runtime_error("FF7FiledModelsAndAnimationMetadata: " + m_File.ValueStr() + " is not a valid metadata file! No <metadata> in root.");
+                    throw std::runtime_error("FF7Metadata: " + m_File.ValueStr() + " is not a valid metadata file! No <metadata> in root.");
                 }
 
                 node = node->FirstChild();
@@ -49,6 +49,11 @@ namespace QGears
                     {
                         ReadAnimations(node->FirstChild());
                     }
+                    else if (node->Type() == TiXmlNode::TINYXML_ELEMENT && node->ValueStr() == "scripts")
+                    {
+                        ReadScripts(node->FirstChild());
+                    }
+
                     node = node->NextSibling();
                 }
             }
@@ -112,9 +117,139 @@ namespace QGears
                 }
             }
 
+            void ReadScripts(TiXmlNode* node)
+            {
+                while (node)
+                {
+                    if (node->Type() == TiXmlNode::TINYXML_ELEMENT && node->ValueStr() == "CharacterIds")
+                    {
+                        ReadCharacterIds(node->FirstChild());
+                    }
+                    else if (node->Type() == TiXmlNode::TINYXML_ELEMENT && node->ValueStr() == "var_names")
+                    {
+                        ReadVarNames(node->FirstChild());
+                    }
+                    else if (node->Type() == TiXmlNode::TINYXML_ELEMENT && node->ValueStr() == "entity_names")
+                    {
+                        ReadEntityNames(node->FirstChild());
+                    }
+                    else if (node->Type() == TiXmlNode::TINYXML_ELEMENT && node->ValueStr() == "field")
+                    {
+                        const auto name = GetString(node, "name");
+                        ReadField(node->FirstChild(), name);
+                    }
+                    node = node->NextSibling();
+                }
+            }
+
+            void ReadField(TiXmlNode* node, const std::string& name)
+            {
+                while (node)
+                {
+                    if (node->Type() == TiXmlNode::TINYXML_ELEMENT && node->ValueStr() == "function")
+                    {
+                        ReadFunction(node, name);
+                    }
+                    else if (node->Type() == TiXmlNode::TINYXML_ELEMENT && node->ValueStr() == "entity")
+                    {
+                        const auto oldName = GetString(node, "name");
+                        const auto newName = GetString(node, "new");
+                        mFieldData[name].mEntityNameMap[oldName] = newName;
+                    }
+                    node = node->NextSibling();
+                }
+            }
+
+            void ReadFunction(TiXmlNode* node, const std::string& fieldName)
+            {
+                const auto entityName = GetString(node, "entity_name");
+                const auto oldFuncName = GetString(node, "name");
+                const auto newFuncName = GetString(node, "new");
+                const auto funcComment = GetString(node, "Comment");
+                mFieldData[fieldName].mFunctionMap[entityName][oldFuncName] = std::make_pair(newFuncName, funcComment);
+            }
+
+
+            void ReadEntityNames(TiXmlNode* node)
+            {
+                while (node)
+                {
+                    if (node->Type() == TiXmlNode::TINYXML_ELEMENT && node->ValueStr() == "entity")
+                    {
+                        const auto oldName = GetString(node, "name");
+                        const auto newName = GetString(node, "new");
+                        mEntityNameMap[oldName] = newName;
+                    }
+                    node = node->NextSibling();
+                }
+            }
+
+            void ReadVarNames(TiXmlNode* node)
+            {
+                while (node)
+                {
+                    if (node->Type() == TiXmlNode::TINYXML_ELEMENT && node->ValueStr() == "var")
+                    {
+                        const auto bank = GetInt(node, "Bank");
+                        const auto address = GetInt(node, "Address");
+                        const auto name = GetString(node, "Name");
+                        mVarMap[bank][address] = name;
+                    }
+                    node = node->NextSibling();
+                }
+            }
+
+            void ReadCharacterIds(TiXmlNode* node)
+            {
+                while (node)
+                {
+                    if (node->Type() == TiXmlNode::TINYXML_ELEMENT && node->ValueStr() == "char")
+                    {
+                        const auto id = GetInt(node, "Id");
+                        const auto name = GetString(node, "Name");
+                        mCharacterIds[id] = name;
+                        node = node->NextSibling();
+                    }
+                    node = node->NextSibling();
+                }
+            }
+
+            std::pair<String,String> FieldScriptFunctionData(const String& fieldName, const String& entityName, const String& oldFunctionName)
+            {
+                // Find a collection of field data for this field
+                auto fieldIt = mFieldData.find(fieldName);
+                if (fieldIt != std::end(mFieldData))
+                {
+                    // See if there is any info for this entity
+                    auto entityIt = fieldIt->second.mFunctionMap.find(entityName);
+                    if (entityIt != std::end(fieldIt->second.mFunctionMap))
+                    {
+                        // See if there is any info for this function in this entity
+                        auto functionIt = entityIt->second.find(oldFunctionName);
+                        if (functionIt != std::end(entityIt->second))
+                        {
+                            return  functionIt->second;
+                        }
+                    }
+                }
+                return std::make_pair("", "");
+            }
+
+
             typedef std::map<String, String> LookupMap;
             LookupMap mModels;
             LookupMap mAnimations;
+            std::map<int, String> mCharacterIds;
+            std::map<int, std::map<int, String>> mVarMap;
+            LookupMap mEntityNameMap;
+
+            struct FieldMetaData
+            {
+                std::map<String, std::map<String, std::pair<String,String>>> mFunctionMap; // entity name to old function name finds new function name and comment
+                LookupMap mEntityNameMap; // old name finds new name
+            };
+            std::map<String, FieldMetaData> mFieldData;
+            friend class NameLookup;
         };
 
         class NameLookup
@@ -132,9 +267,51 @@ namespace QGears
                 return Data().Model(key);
             }
 
-            static FF7FiledModelsAndAnimationMetadata& Data()
+            static String FieldScriptVarName(int bank, int addr)
+            {
+                auto bankIt = Data().mVarMap.find(bank);
+                if (bankIt != std::end(Data().mVarMap))
+                {
+                    auto addrIt = bankIt->second.find(addr);
+                    if (addrIt != std::end(bankIt->second))
+                    {
+                        if (addrIt->second.empty() == false)
+                        {
+                            return addrIt->second;
+                        }
+                    }
+                }
+                return "";
+            }
+
+            static String FieldScriptEntityName(const String& oldEntityName)
+            {
+                auto it = Data().mEntityNameMap.find(oldEntityName);
+                if (it != std::end(Data().mEntityNameMap))
+                {
+                    return it->second;
+                }
+                return oldEntityName;
+            }
+
+            static String FieldScriptFunctionComment(const String& fieldName, const String& entityName, const String& oldFunctionName)
+            {
+                return Data().FieldScriptFunctionData(fieldName, entityName, oldFunctionName).second;
+            }
+
+            static String FieldScriptFunctionName(const String& fieldName, const String& entityName, const String& oldFunctionName)
+            {
+                auto name = Data().FieldScriptFunctionData(fieldName, entityName, oldFunctionName).first;
+                if (name.empty())
+                {
+                    return oldFunctionName;
+                }
+                return name;
+            }
+
+            static FF7Metadata& Data()
             {
-                static FF7FiledModelsAndAnimationMetadata data("field_models_and_animation_metadata.xml");
+                static FF7Metadata data("field_models_and_animation_metadata.xml");
                 return data;
             }
         };

+ 142 - 1
output/field_models_and_animation_metadata.xml

@@ -1,9 +1,150 @@
 <metadata>
+	<!-- Renames functions/entities in scripts and script var names to something more readable -->
+	<scripts>
+		<!-- Used by PRTYE and other OpCodes -->
+		<CharacterIds>
+		    <char Id="0" Name="Cloud"/>
+			<char Id="1" Name="Barret"/>
+			<char Id="2" Name="Tifa"/>
+			<char Id="3" Name="Aeris"/>
+			<char Id="4" Name="Red XIII"/>
+			<char Id="5" Name="Yuffie"/>
+			<char Id="6" Name="Cait Sith"/>
+			<char Id="7" Name="Vincent"/>
+			<char Id="8" Name="Cid"/>
+			<char Id="9" Name="Young Cloud"/>
+			<char Id="10" Name="Sephiroth"/>
+			<char Id="11" Name="Chocobo"/>
+		</CharacterIds>
+	
+		<!-- Applies to all fields or any field that hasn't got field specific data -->
+		<var_names>
+			<var Bank="1" Address="3" Name="love_point_aeris"/>
+			<var Bank="1" Address="4" Name="love_point_tifa"/>
+			<var Bank="1" Address="5" Name="love_point_yuffie"/>
+			<var Bank="1" Address="6" Name="love_point_barret"/>
+			<var Bank="1" Address="20" Name="timer_hours"/>
+			<var Bank="1" Address="21" Name="timer_minutes"/>
+			<var Bank="1" Address="22" Name="timer_seconds"/>
+			<var Bank="1" Address="23" Name="timer_frames"/>
+			<var Bank="1" Address="36" Name="graveyard_item"/>
+			<var Bank="1" Address="48" Name="item_mask2"/>
+			<var Bank="1" Address="80" Name="battle_love_aeris"/>
+			<var Bank="1" Address="81" Name="battle_love_tifa"/>
+			<var Bank="1" Address="82" Name="battle_love_yuffie"/>
+			<var Bank="1" Address="83" Name="battle_love_barret"/>
+			<var Bank="1" Address="164" Name="graveyard_train"/>
+			<var Bank="1" Address="225" Name="act1_1_flags1"/>
+			<var Bank="1" Address="226" Name="act1_1_flags2"/>
+			
+			<var Bank="2" Address="0" Name="progress_game"/>
+			<var Bank="2" Address="28" Name="menu_appear"/>
+			<var Bank="2" Address="30" Name="menu_selectable"/>
+			
+			<var Bank="3" Address="66" Name="act1_1_flags3"/>
+			<var Bank="3" Address="111" Name="flower_flag"/>
+			<var Bank="3" Address="112" Name="act1_3_flags5"/>
+			<var Bank="3" Address="126" Name="act1_3_unknown"/>
+			<var Bank="3" Address="127" Name="tunnel_room"/>
+			<var Bank="3" Address="128" Name="act1_3_flags1"/>
+			<var Bank="3" Address="129" Name="act1_3_flags2"/>
+			<var Bank="3" Address="130" Name="act1_3_flags3"/>
+			<var Bank="3" Address="131" Name="act1_3_flags4"/>
+			<var Bank="3" Address="208" Name="act1_2_flags1"/>
+			<var Bank="3" Address="209" Name="act1_2_flags2"/>
+			<var Bank="3" Address="210" Name="act1_2_flags3"/>
+			<var Bank="3" Address="211" Name="act1_2_flags4"/>
+			<var Bank="3" Address="212" Name="act1_2_flags5"/>
+			<var Bank="3" Address="213" Name="act1_2_flags6"/>
+			<var Bank="3" Address="214" Name="act1_2_flags7"/>
+			<var Bank="3" Address="215" Name="act1_2_flags8"/>
+			<var Bank="3" Address="216" Name="act1_2_flags9"/>
+			<var Bank="3" Address="217" Name="act1_7_flags1"/>
+			<var Bank="3" Address="223" Name="act1_1_flags4"/>
+			
+			<var Bank="13" Address="30" Name="pointer"/>
+			<var Bank="13" Address="31" Name="materia_full"/>
+			<var Bank="13" Address="91" Name="save_flag"/>
+			
+			<var Bank="15" Address="32" Name="sector1_item"/>
+			<var Bank="15" Address="33" Name="sector5_item"/>
+			<var Bank="15" Address="80" Name="subway_item"/>
+		
+		</var_names>
+
+		<entity_names>
+			<entity name="dir" new="Director"/>
+			<entity name="cl" new="Cloud"/>
+			<entity name="av_b" new="Biggs"/>
+			<entity name="av_c" new="Jessie"/>
+			<entity name="av_w" new="Wedge"/>
+		</entity_names>
+		
+		<!-- Apply only to the given field, overrides the "global data -->
+		<field name="md1stin">
+			<function entity_name="test" name="f1" new="action1" />
+			
+			<function entity_name="test" name="f2" new="action1" Comment="Barret run from train and invite Cloud" />
+			<function entity_name="test" name="f3" new="action2" Comment="Barret run to next field" />
+			
+		
+			<entity name="Hei0" new="Hei0" Comment="1st army man that attacks Cloud as we approach next field."/>
+			<function entity_name="test" name="f4" new="action1" Comment="Army man run from gate to Cloud." />
+
+			<entity name="Hei1" new="Hei1" Comment="2nd army man that attacks Cloud as we approach next field."/>
+			<function entity_name="test" name="f5" new="action1" Comment="Army man run from gate to Cloud." />
+
+
+			<function entity_name="test" name="f6" new="action1" Comment="This is all action that does Biggs. At first he jumps from train, then he throws guard and a bit later run to next map." />
+			<function entity_name="test" name="f7" new="action1" Comment="This is all action that does Jessie. At first she run from train, then she kicks guard and a bit later run to next map." />
+			<function entity_name="test" name="f8" new="action1" Comment="This is all action that does Wedge. At first he jumps from train, then he looks around and a bit later run to next map." />
+			
+			<entity name="Gu0" new="Gu0" Comment="One of two guards thas stays on train station at the very beginning.This one is closest to camera. Jessie takes him off." />
+			<function entity_name="test" name="f9" new="action1" Comment="This is what Gu0 do. First Gu0 look to Jessie and then run to her. Jessie kicks Gu0 away and then Gu0 stay on the ground." />
+			
+			<entity name="Gu1" new="Gu1" Comment="One of two guards thas stays on train station at the very beginning. This one stay far from camera. Biggs takes him off." />
+			<function entity_name="test" name="f10" new="action1" Comment="This is what Gu1 do after Biggs jumps from the train. First Gu1 look to Biggs and then run to him. Biggs throw Gu1 to the ground and then Gu1 stay on it." />
+			<function entity_name="test" name="f11" new="activate" Comment="his will activate Gu1 in place of Gu0. Don't know why it is done this way." />
+		
+			<entity name="GuAdd" new="GuAdd" Comment="Additional guard model used when script switch model. Don't know why it is dome this way." />
+			<function entity_name="test" name="f12" new="activate" Comment="We activate this entity after deactivation of Gu1. Don't know why we need to do this, but FFVII handle it this way. " />
+			
+			
+		</field>
+		
+		<field name="md1_1">
+			<function name="f1" new="scene_part_1" Comment="Move Cloud to talk position for the scene." />
+			<function name="f2" new="scene_part_5" Comment="Cloud reply his name to Avalanche." />
+			<function name="f3" new="scene_part_9" />
+			<function name="f4" new="scene_part_14" />
+			<function name="f5" new="scene_part_16" Comment="look at reactor and run after Barret and others." />
+			
+			<function name="f6" new="scene_part_8" />
+			<function name="f7" new="scene_part_13" />
+			<function name="f8" new="scene_part_15" />
+			
+			<function name="f9" new="scene_part_2" Comment="Turn to Cloud and start talk to him." />
+			<function name="f10" new="scene_part_4" Comment="Dialog with Jessie and Cloud. We input Cloud name during this scene and call Cloud reply." />
+			
+			<function name="f11" new="scene_part_7" />
+			<function name="f12" new="scene_part_11" />
+		
+			<function name="f13" new="scene_part_3" Comment="Stop breaking gate for a while and talk." />
+			<function name="f14" new="scene_part_10" />
+			
+			<function name="f15" new="scene_part_12" />
+		
+		</field>
+		
+	</scripts>
+
+	<!-- Renames for models to something more readable -->
 	<models>
 		<model name="aaaa" target="n_cloud"></model>
 		<model name="adda" target="sd_red"></model>
 	</models>
-    
+
+	<!-- Renames for animations to something more readable -->
 	<animations>
 		<animation name="acfe" target="Idle"></animation>
 		<animation name="aaff" target="Walk"></animation>

+ 32 - 22
utilities/q-gears-launcher/src/ff7DataInstaller.cpp

@@ -63,16 +63,25 @@ void FF7DataInstaller::Convert(std::string inputDir, std::string outputDir, cons
     }
 }
 
+static std::string FieldModelDir()
+{
+    return "models/ffvii/field/units";
+}
+
+
 // TOOD: Share with pc model exporter
 static void exportMesh(std::string outdir, const Ogre::MeshPtr &mesh)
 {
     Ogre::MeshSerializer        mesh_ser;
-    mesh_ser.exportMesh(mesh.getPointer(), outdir +  mesh->getName());
 
     Ogre::SkeletonPtr           skeleton(mesh->getSkeleton());
     Ogre::SkeletonSerializer    sk_ser;
     sk_ser.exportSkeleton(skeleton.getPointer(), outdir +  skeleton->getName());
 
+    mesh->setSkeletonName(FieldModelDir() + "/" + mesh->getSkeletonName());
+    mesh_ser.exportMesh(mesh.getPointer(), outdir + mesh->getName());
+
+
     Ogre::Mesh::SubMeshIterator it(mesh->getSubMeshIterator());
     Ogre::MaterialSerializer    mat_ser;
     size_t i(0);
@@ -104,7 +113,7 @@ static void exportMesh(std::string outdir, const Ogre::MeshPtr &mesh)
                                         textures.insert(unit->getTextureName());
                                         Ogre::String baseName;
                                         QGears::StringUtil::splitBase(unit->getTextureName(), baseName);
-                                        unit->setTextureName(baseName + ".png");
+                                        unit->setTextureName(FieldModelDir() + "/" + baseName + ".png");
                                     }
                                 }
                             }
@@ -153,44 +162,53 @@ static std::string FieldMapDir()
     return "maps/ffvii/field";
 }
 
-static std::string FieldModelDir()
-{
-    return "models/ffvii/field/units";
-}
 
 class FF7FieldScriptFormatter : public SUDM::IScriptFormatter
 {
 public:
+    FF7FieldScriptFormatter(const std::string& fieldName, const QGears::ModelListFilePtr& models)
+        : mFieldName(fieldName), mModelLoader(models)
+    {
+
+    }
+
     // Renames a variable, return empty string for generated name
     virtual std::string VarName(unsigned int bank, unsigned int addr) override
     {
-        return "";
+        return QGears::FF7::NameLookup::FieldScriptVarName(bank, addr);
     }
 
     // Renames an entity
     virtual std::string EntityName(const std::string& entity) override
     {
-        return entity;
+        return QGears::FF7::NameLookup::FieldScriptEntityName(entity);
     }
 
     // Renames an animation, return empty string for generated name
     virtual std::string AnimationName(int id) override
     {
+        // TODO: How do we get this info?
+        //mModelLoader->getModels().at(???).animations.at(id);
         return "";
     }
 
+    // TODO: Add CharacterId to the interface
+
     // Renames a function in an entity
     virtual std::string FunctionName(const std::string& entity, const std::string& funcName) override
     {
-        return funcName;
+        return QGears::FF7::NameLookup::FieldScriptFunctionName(mFieldName, entity, funcName);
     }
 
     // Sets the header comment for a function in an entity
     virtual std::string FunctionComment(const std::string& entity, const std::string& funcName) override
     {
-        return "";
+        return QGears::FF7::NameLookup::FieldScriptFunctionComment(mFieldName, entity, funcName);
     }
 
+private:
+    std::string mFieldName;
+    const QGears::ModelListFilePtr& mModelLoader;
 };
 
 static std::string CreateGateWayScript(const std::string& gatewayEntityName, const std::string& targetMapName, const std::string& sourceSpawnPointName)
@@ -317,6 +335,7 @@ static void FF7PcFieldToQGearsField(
         }
     }
 
+    const QGears::ModelListFilePtr& models = field->getModelList();
     SUDM::FF7::Field::DecompiledScript decompiled;
     try
     {
@@ -324,7 +343,7 @@ static void FF7PcFieldToQGearsField(
         const std::vector<u8> rawFieldData = field->getRawScript();
 
         // Decompile to LUA
-        FF7FieldScriptFormatter formatter;
+        FF7FieldScriptFormatter formatter(field->getName(), models);
         decompiled = SUDM::FF7::Field::Decompile(field->getName(), rawFieldData, formatter, gatewayScriptData, "EntityContainer = {}\n\n");
         std::ofstream scriptFile(outDir + "/" + FieldMapDir() + "/" + field->getName() + "/script.lua");
         if (scriptFile.is_open())
@@ -367,7 +386,6 @@ static void FF7PcFieldToQGearsField(
         xmlMovementRotation->SetAttribute("degree", std::to_string(triggers->MovementRotation()));
         element->LinkEndChild(xmlMovementRotation.release());
 
-        const QGears::ModelListFilePtr& models = field->getModelList();
         for (const auto& it : decompiled.entities)
         {
             const int charId = it.second;
@@ -648,16 +666,8 @@ static bool IsAFieldFile(Ogre::String& resourceName)
 static bool IsTestField(Ogre::String& resourceName)
 {
     if (
-        resourceName == "startmap" ||
-        resourceName == "md1stin" ||
-        resourceName == "md1_1" ||
-        resourceName == "md1_2" ||
-        resourceName == "nrthmk" ||
-        resourceName == "nmkin_1" ||
-        resourceName == "elevtr1" ||
-        resourceName == "nmkin_2" ||
-        resourceName == "nmkin_3" ||
-        resourceName == "tin_2"
+       // resourceName == "startmap" ||
+        resourceName == "md1stin"
         )
     {
         return true;