فهرست منبع

Merge pull request #122 from paulsapps/installer

Implements MAPJUMP
paulsapps 11 سال پیش
والد
کامیت
38c5f297f0
2فایلهای تغییر یافته به همراه180 افزوده شده و 50 حذف شده
  1. 1 1
      dependencies/SUDM
  2. 179 49
      utilities/q-gears-launcher/src/ff7DataInstaller.cpp

+ 1 - 1
dependencies/SUDM

@@ -1 +1 @@
-Subproject commit 2e7487e2b1db5665f237235cb4cf1404fb5180c0
+Subproject commit a9aa8eb8e4bb7bdce7aa7a8a495da24c834914d1

+ 179 - 49
utilities/q-gears-launcher/src/ff7DataInstaller.cpp

@@ -163,13 +163,54 @@ static std::string FieldMapDir()
     return "maps/ffvii/field";
 }
 
-class FF7FieldScriptFormatter : public SUDM::IScriptFormatter
+typedef std::set<std::string> MapCollection;
+
+class SpawnPointDb
+{
+public:
+    // Id of the field the gateways records from N other number of fields are linking to
+    u16 mTargetFieldId = 0;
+
+    class Record
+    {
+    public:
+        // Field that wants to link to mTargetFieldId
+        u16 mFieldId = 0;
+
+        // Index of the gateway in mFieldId
+        u32 GatewayIndexOrMapJumpAddress = 0;
+
+        // Gateway data
+        QGears::TriggersFile::Gateway mGateway;
+
+        bool mFromScript = false;
+
+        // Only used from script calls
+        std::string mEntityName;
+        std::string mScriptFunctionName;
+    };
+
+    std::vector<Record> mGatewaysToThisField;
+};
+typedef std::map<u16, SpawnPointDb> FieldSpawnPointsMap;
+
+class BaseFF7FieldScriptFormatter : public SUDM::IScriptFormatter
 {
 public:
-    FF7FieldScriptFormatter(const std::string& fieldName, const QGears::ModelListFilePtr& models)
-        : mFieldName(fieldName), mModelLoader(models)
+    BaseFF7FieldScriptFormatter(const std::string& fieldName, const std::vector<std::string>& fieldIdToNameLookup, FieldSpawnPointsMap& spawnPoints)
+        : mFieldName(fieldName), mFieldIdToNameLookup(fieldIdToNameLookup), mSpawnPoints(spawnPoints)
+    {
+
+    }
+
+    virtual std::string SpawnPointName(unsigned int /*targetMapId*/, const std::string& entity, const std::string& funcName, unsigned int address) override
     {
+        return mFieldName + "_" + entity + "_" + funcName + "_addr_" + std::to_string(address);
+    }
 
+    virtual std::string MapName(unsigned int mapId) override
+    {
+        return FieldName(mFieldIdToNameLookup[mapId]);
     }
 
     // Renames a variable, return empty string for generated name
@@ -184,18 +225,51 @@ public:
         return QGears::FF7::NameLookup::FieldScriptEntityName(entity);
     }
 
+    // Get name of char from its id, can't return empty
+    virtual std::string CharName(int charId) override
+    {
+        return QGears::FF7::NameLookup::CharName(charId);
+    }
+
+    // Renames a function in an entity
+    virtual std::string FunctionName(const std::string& entity, const std::string& funcName) override
+    {
+        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 QGears::FF7::NameLookup::FieldScriptFunctionComment(mFieldName, entity, funcName);
+    }
+
+protected:
+    std::string mFieldName;
+    FieldSpawnPointsMap& mSpawnPoints;
+    const std::vector<std::string>& mFieldIdToNameLookup;
+};
+
+class FF7FieldScriptFormatter : public BaseFF7FieldScriptFormatter
+{
+public:
+    FF7FieldScriptFormatter(const std::string& fieldName, const QGears::ModelListFilePtr& models, const std::vector<std::string>& fieldIdToNameLookup, FieldSpawnPointsMap& spawnPoints)
+        : BaseFF7FieldScriptFormatter(fieldName, fieldIdToNameLookup, spawnPoints), mModelLoader(models)
+    {
+
+    }
+
     // Names an animation, can't return empty
     virtual std::string AnimationName(int charId, int id) override
     {
         // Get the animation file name, then look up the friendly name of the "raw" animation
-        if (charId >= mModelLoader->getModels().size())
+        if (static_cast<unsigned int>(charId) >= mModelLoader->getModels().size())
         {
             std::cout << "ERROR CHAR ID IS OUT OF BOUNDS" << std::endl;
             return std::to_string(id);
         }
 
         const auto& modelInfo = mModelLoader->getModels().at(charId);
-        if (id >= modelInfo.animations.size())
+        if (static_cast<unsigned int>(id) >= modelInfo.animations.size())
         {
             std::cout << "ERROR ANIMATION ID IS OUT OF BOUNDS" << std::endl;
             return std::to_string(id);
@@ -211,26 +285,7 @@ public:
         return QGears::FF7::NameLookup::animation(baseName);
     }
 
-    // Get name of char from its id, can't return empty
-    virtual std::string CharName(int charId) override
-    {
-        return QGears::FF7::NameLookup::CharName(charId);
-    }
-
-    // Renames a function in an entity
-    virtual std::string FunctionName(const std::string& entity, const std::string& funcName) override
-    {
-        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 QGears::FF7::NameLookup::FieldScriptFunctionComment(mFieldName, entity, funcName);
-    }
-
 private:
-    std::string mFieldName;
     const QGears::ModelListFilePtr& mModelLoader;
 };
 
@@ -248,7 +303,9 @@ static std::string CreateGateWayScript(const std::string& gatewayEntityName, con
         "end,\n\n"
         "on_cross_line = function(self, entity)\n"
         "   if entity == \"Cloud\" then\n"
-        "       load_field_map_request(\"" + targetMapName + "\", \"" + sourceSpawnPointName + "\")\n"
+        "       if not FFVII.Data.DisableGateways then\n"
+        "           load_field_map_request(\"" + targetMapName + "\", \"" + sourceSpawnPointName + "\")\n"
+        "       end\n"
         "   end\n\n"
         "   return 0\n"
         "end,\n\n"
@@ -261,22 +318,7 @@ static std::string CreateGateWayScript(const std::string& gatewayEntityName, con
 
 const int kInactiveGateWayId = 32767;
 
-class SpawnPointDb
-{
-public:
-    // Id of the field the gateways records from N other number of fields are linking to
-    u16 mTargetFieldId = 0;
 
-    class Record
-    {
-    public:
-        u16 mFieldId = 0;
-        u32 GatewayIndex = 0;
-        QGears::TriggersFile::Gateway mGateway;
-    };
-    std::vector<Record> mGatewaysToThisField;
-};
-typedef std::map<u16, SpawnPointDb> FieldSpawnPointsMap;
 typedef std::map<u16, float> FieldScaleFactorMap;
 
 
@@ -313,7 +355,6 @@ public:
     ModelAnimationMap mMap;
 };
 
-typedef std::set<std::string> MapCollection;
 
 
 static size_t FieldId(const std::string& name, const std::vector<std::string>& fieldIdToNameLookup)
@@ -342,7 +383,7 @@ static void FF7PcFieldToQGearsField(
     QGears::FLevelFilePtr& field,
     const std::string& outDir,
     const std::vector<std::string>& fieldIdToNameLookup,
-    const FieldSpawnPointsMap& spawnMap,
+    FieldSpawnPointsMap& spawnMap,
     const FieldScaleFactorMap& scaleFactorMap,
     ModelsAndAnimationsDb& modelAnimationDb,
     MapCollection& maps)
@@ -364,13 +405,13 @@ static void FF7PcFieldToQGearsField(
 
     const QGears::ModelListFilePtr& models = field->getModelList();
     SUDM::FF7::Field::DecompiledScript decompiled;
+    FF7FieldScriptFormatter formatter(field->getName(), models, fieldIdToNameLookup, spawnMap);
     try
     {
         // Get the raw script bytes
         const std::vector<u8> rawFieldData = field->getRawScript();
 
         // Decompile to LUA
-        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())
@@ -505,14 +546,30 @@ static void FF7PcFieldToQGearsField(
                 // entity_point
                 std::unique_ptr<TiXmlElement> xmlEntityPoint(new TiXmlElement("entity_point"));
 
-                // Must also include the gateway index for the case where 2 fields have more than one door linking to each other
-                xmlEntityPoint->SetAttribute("name", "Spawn_" + fieldIdToNameLookup.at(spawnPointRecords[i].mFieldId) + "_" + std::to_string(spawnPointRecords[i].GatewayIndex));
+                if (spawnPointRecords[i].mFromScript)
+                {
+                    // Spawn points from map jumps have a another algorithm
+                    
+
+                    xmlEntityPoint->SetAttribute("name", fieldIdToNameLookup.at(spawnPointRecords[i].mFieldId) + "_" + spawnPointRecords[i].mEntityName + "_" + spawnPointRecords[i].mScriptFunctionName + "_addr_" + std::to_string(spawnPointRecords[i].GatewayIndexOrMapJumpAddress));
+                }
+                else
+                {
+                    // Must also include the gateway index for the case where 2 fields have more than one door linking to each other
+                    xmlEntityPoint->SetAttribute("name", "Spawn_" + fieldIdToNameLookup.at(spawnPointRecords[i].mFieldId) + "_" + std::to_string(spawnPointRecords[i].GatewayIndexOrMapJumpAddress));
+                }
 
                 const float downscaler_next = 128.0f * FieldScaleFactor(scaleFactorMap, gateway.destinationFieldId);
 
                 // Position Z is actually the target walkmesh triangle ID, so this is tiny bit more
                 // complex as we have to say "get the Z value of the triangle with that ID". Note that ID actually just means index.
-                const float zOfTriangleWithId = field->getWalkmesh()->getTriangles().at(static_cast<unsigned int>(gateway.destination.z)).a.z;
+                unsigned int triIndex = static_cast<unsigned int>(gateway.destination.z);
+                if (triIndex >= field->getWalkmesh()->getTriangles().size())
+                {
+                    std::cout << "WARNING MAP JUMP TRIANGLE OUT OF BOUNDS" << std::endl;
+                    triIndex = 0;
+                }
+                const float zOfTriangleWithId = field->getWalkmesh()->getTriangles().at(triIndex).a.z;
 
                 const Ogre::Vector3 posVec(gateway.destination.x / downscaler_next, gateway.destination.y / downscaler_next, zOfTriangleWithId);
 
@@ -654,11 +711,82 @@ static void FF7PcFieldToQGearsField(
     maps.insert(field->getName());
 }
 
+class FF7FieldScriptGatewayCollector : public BaseFF7FieldScriptFormatter
+{
+public:
+    FF7FieldScriptGatewayCollector(const std::string& fieldName, const std::vector<std::string>& fieldIdToNameLookup, FieldSpawnPointsMap& spawnPoints, size_t thisFieldId)
+        : BaseFF7FieldScriptFormatter(fieldName, fieldIdToNameLookup, spawnPoints), mThisFieldId(thisFieldId)
+    {
+
+    }
+
+    virtual void AddSpawnPoint(unsigned int targetMapId, const std::string& entity, const std::string& funcName, unsigned int address, int x, int y, int z, int angle) override
+    {
+        auto it = mSpawnPoints.find(targetMapId);
+
+        QGears::TriggersFile::Gateway gw = {};
+        gw.destinationFieldId = targetMapId;
+        gw.destination.x = x;
+        gw.destination.y = y;
+        gw.destination.z = z;
+        gw.dir = angle;
 
+        if (it != std::end(mSpawnPoints))
+        {
+            // Add to the list of gateways that link to destinationFieldId
+            SpawnPointDb::Record rec;
+            rec.mFromScript = true;
+            rec.mFieldId = mThisFieldId;
+            rec.mGateway = gw;
+            rec.mEntityName = entity;
+            rec.mScriptFunctionName = funcName;
+            rec.GatewayIndexOrMapJumpAddress = address;
+            it->second.mGatewaysToThisField.push_back(rec);
+        }
+        else
+        {
+            // Create a new record for destinationFieldId
+            SpawnPointDb db;
+            db.mTargetFieldId = targetMapId;
+
+            SpawnPointDb::Record rec;
+            rec.mFromScript = true;
+            rec.mFieldId = mThisFieldId;
+            rec.mGateway = gw;
+            rec.mEntityName = entity;
+            rec.mScriptFunctionName = funcName;
+            rec.GatewayIndexOrMapJumpAddress = address;
+            db.mGatewaysToThisField.push_back(rec);
+
+            mSpawnPoints.insert(std::make_pair(db.mTargetFieldId, db));
+        }
+    }
+private:
+    size_t mThisFieldId;
+
+};
 
 static void CollectSpawnPoints(QGears::FLevelFilePtr& field, const std::vector<std::string>& fieldIdToNameLookup, FieldSpawnPointsMap& spawnPoints)
 {
     const size_t thisFieldId = FieldId(field->getName(), fieldIdToNameLookup);
+
+    // Decompile the script just so we can collect up the MAPJUMP's we need this to construct the full list of entries
+    // to each field
+    try
+    {
+        // Get the raw script bytes
+        SUDM::FF7::Field::DecompiledScript decompiled;
+        const std::vector<u8> rawFieldData = field->getRawScript();
+
+        // Decompile to LUA
+        FF7FieldScriptGatewayCollector formatter(field->getName(), fieldIdToNameLookup, spawnPoints, thisFieldId);
+        decompiled = SUDM::FF7::Field::Decompile(field->getName(), rawFieldData, formatter, "", "EntityContainer = {}\n\n");
+    }
+    catch (const ::InternalDecompilerError& ex)
+    {
+        std::cerr << "InternalDecompilerError: " << ex.what() << std::endl;
+    }
+
     const QGears::TriggersFilePtr& triggers = field->getTriggers();
     const auto& gateways = triggers->GetGateways();
     for (size_t i = 0; i < gateways.size(); i++)
@@ -673,7 +801,7 @@ static void CollectSpawnPoints(QGears::FLevelFilePtr& field, const std::vector<s
                 SpawnPointDb::Record rec;
                 rec.mFieldId = thisFieldId;
                 rec.mGateway = gateway;
-                rec.GatewayIndex = i;
+                rec.GatewayIndexOrMapJumpAddress = i;
                 it->second.mGatewaysToThisField.push_back(rec);
             }
             else
@@ -685,7 +813,7 @@ static void CollectSpawnPoints(QGears::FLevelFilePtr& field, const std::vector<s
                 SpawnPointDb::Record rec;
                 rec.mFieldId = thisFieldId;
                 rec.mGateway = gateway;
-                rec.GatewayIndex = i;
+                rec.GatewayIndexOrMapJumpAddress = i;
                 db.mGatewaysToThisField.push_back(rec);
 
                 spawnPoints.insert(std::make_pair(db.mTargetFieldId, db));
@@ -740,7 +868,9 @@ static bool IsTestField(Ogre::String& resourceName)
         resourceName == "nmkin_3" ||
         resourceName == "nrthmk" ||
         resourceName == "elevtr1" ||
+        resourceName == "tin_1" ||
         resourceName == "tin_2" ||
+        resourceName == "rootmap" ||
         resourceName == "md8_4"
         )
     {
@@ -773,7 +903,7 @@ void FF7DataInstaller::ConvertFields(std::string archive, std::string inputDir,
     for (auto& resourceName : *resources)
     {
         // Exclude things that are not fields
-        if (IsAFieldFile(resourceName) /*&& IsTestField(resourceName)*/)
+        if (IsAFieldFile(resourceName) && /*IsTestField(resourceName) &&*/ !WillCrash(resourceName))
         {
             QGears::FLevelFilePtr field = QGears::LZSFLevelFileManager::getSingleton().load(resourceName, "FFVIIFields").staticCast<QGears::FLevelFile>();
             CollectSpawnPoints(field, mapList->GetMapList(), spawnPoints);