ソースを参照

Installer fixes:
- Prevented infinite loops in on_start scripts, so entities can be talked to.
- Line entities have their functions renamed to the standard names.

Iñigo Valentin 3 年 前
コミット
699d9b43b3

+ 10 - 0
lib/SUDM/decompiler/ff7_field/ff7_field_codegen.cpp

@@ -148,6 +148,16 @@ void FF7::FF7SimpleCodeGenerator::generate(InstVec& insts, const Graph& /*g*/){
                     );
                     addOutputLine("do return 0 end");
                 }
+                // Prevent backward jumps in the on_start script.
+                else if (
+                  "on_start" == function->first._name
+                  && (*instruction)->getDestAddress() <= (*instruction)->_address
+                ){
+                    addOutputLine("-- No infinite loops in the on_start script.");
+                    addOutputLine((
+                      boost::format("-- goto label_0x%1$X") % (*instruction)->getDestAddress()
+                    ).str());
+                }
                 else{
                     addOutputLine(
                       (boost::format("goto label_0x%1$X") % (*instruction)->getDestAddress()).str()

+ 31 - 1
lib/SUDM/decompiler/ff7_field/ff7_field_disassembler.cpp

@@ -107,6 +107,21 @@ std::unique_ptr<Function> FF7::FF7Disassembler::StartFunction(size_t scriptIndex
     return func;
 }
 
+std::unique_ptr<Function> FF7::FF7Disassembler::StartLineFunction(size_t script_index){
+    auto func = std::make_unique<Function>();
+    func->_retVal = false;
+    func->_args = 0;
+    switch (script_index){
+        case 2: func->_name = "on_enter_line"; break;
+        case 3: func->_name = "on_move_to_line"; break;
+        case 4: func->_name = "on_cross_line"; break;
+        case 5: func->_name = "on_leave_line"; break;
+        default: func->_name = "script_" + std::to_string(script_index);
+    }
+    func->mStartAddr = _address;
+    return func;
+}
+
 struct ScriptInfo
 {
     uint16 mEntryPoint;
@@ -188,7 +203,9 @@ void FF7::FF7Disassembler::AddFunc(
 
     // Read each block of opcodes up to a return.
     const size_t old_num_instructions = _insts.size();
-    auto func = StartFunction(script_index);
+    std::unique_ptr<Function> func;
+    if (mEngine->EntityIsLine(entity_index)) func = StartLineFunction(script_index);
+    else func = StartFunction(script_index);
     if (to_return_only){
         // Read opcodes to the end or bail at the first return.
         is_line = ReadOpCodesToPositionOrReturn(
@@ -218,7 +235,20 @@ void FF7::FF7Disassembler::AddFunc(
     const size_t new_num_instructions = _insts.size();
     func->mNumInstructions = new_num_instructions - old_num_instructions;
     func->mEndAddr = _insts.back()->_address;
+
+
     if (!func_name.empty()) func->_name = func_name;
+
+    // TODO: Remove and test. Should be applied in StartLineFunction
+    if (is_line){
+        switch (script_index){
+            case 2: func->_name = "on_enter_line"; break;
+            case 3: func->_name = "on_move_to_line"; break;
+            case 4: func->_name = "on_cross_line"; break;
+            case 5: func->_name = "on_leave_line"; break;
+        }
+    }
+
     int id = FindId(func->mStartAddr, func->mEndAddr, _insts);
 
     // If there is no ID check if there was an ID for this entity in any of

+ 18 - 1
lib/SUDM/decompiler/ff7_field/ff7_field_disassembler.h

@@ -336,7 +336,9 @@ namespace FF7
          * @param is_end[in] @todo Understand and document.
          * @param to_return_only[in] True to read the script only until the
          * first return.
-         * @param func_name[in] Name of the function.
+         * @param func_name[in] Name of the function. If the entity is a line,
+         * the provided name will be overridden and set to the standard line
+         * entity script names.
          */
         void AddFunc(
           std::string entity_name, size_t entity_index, size_t script_index,
@@ -363,8 +365,23 @@ namespace FF7
           size_t end_pos, std::vector<float>& point_a, std::vector<float>& point_b
         );
 
+        /**
+         * Initializes a function for a non-line entity.
+         *
+         * @param script_index[in] Index of the script.
+         */
         std::unique_ptr<Function> StartFunction(size_t scriptIndex);
 
+        /**
+         * Initializes a function for a line entity.
+         *
+         * The name is set according to the script index, using line standard
+         * names.
+         *
+         * @param script_index[in] Index of the script.
+         */
+        std::unique_ptr<Function> StartLineFunction(size_t script_index);
+
         FF7FieldEngine* mEngine;
 
         uint32 mHeaderEndPos = 0;

+ 8 - 1
lib/SUDM/decompiler/ff7_field/ff7_field_engine.cpp

@@ -150,6 +150,12 @@ void FF7::FF7FieldEngine::MarkEntityAsLine(
     }
 }
 
+bool FF7::FF7FieldEngine::EntityIsLine(size_t entity_index){
+    auto it = mEntityIndexMap.find(entity_index);
+    if (it != std::end(mEntityIndexMap)) return (*it).second.is_line_;
+    return false;
+}
+
 void FF7::FF7FieldEngine::RemoveExtraneousReturnStatements(InstVec& insts, Graph g)
 {
     for (auto& f : _functions)
@@ -1886,6 +1892,7 @@ void FF7::FF7WalkmeshInstruction::processLINE(CodeGenerator* codeGen, const std:
       + ")-(" + std::to_string(xb) + ", " +std::to_string(yb) + ", " + std::to_string(zb) + ")"
     );
 
+    /*
     // HACK:
     //   on_enter_line executes on_update
     //   on_move_to_line executes on_interact
@@ -1919,7 +1926,7 @@ void FF7::FF7WalkmeshInstruction::processLINE(CodeGenerator* codeGen, const std:
     );
     //codeGen->addOutputLine("    do return 0 end");
     //codeGen->addOutputLine("end,");
-
+    */
 
 }
 

+ 22 - 2
lib/SUDM/decompiler/ff7_field/ff7_field_engine.h

@@ -114,12 +114,23 @@ namespace FF7{
                      *
                      * Must be added by name and index.
                      *
-                     * @param name[in] Function name.
+                     * @param name[in] Function name. If the entity is a line,
+                     * the name will be overridden.
                      * @param index[in] Function index.
                      * @todo What is a function here? An Opcode?
                      */
                     void AddFunction(const std::string& name, size_t index){
-                        mFunctions[index] = name;
+                        // TODO: Delete renaming and test. It should work.
+                        std::string new_name = name;
+                        if (is_line_){
+                            switch (index){
+                                case 2: new_name = "on_enter_line"; break;
+                                case 3: new_name = "on_move_to_line"; break;
+                                case 4: new_name = "on_cross_line"; break;
+                                case 5: new_name = "on_leave_line"; break;
+                            }
+                        }
+                        mFunctions[index] = new_name;
                     }
 
                     /**
@@ -261,6 +272,15 @@ namespace FF7{
                 std::vector<float> point_a, std::vector<float> point_b
             );
 
+            /**
+             * Checks if an entity has been marked as a line.
+             *
+             * @param entity_index[in] Index of the entity to check.
+             * @return True if the entity is a line. False if it isn't, or if
+             * there is no such entity.
+             */
+            bool EntityIsLine(size_t entity_index);
+
             /**
              * Retrieves an entity.
              *