/*
* V-Gears
* Copyright (C) 2022 V-Gears Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#pragma once
#include
#include
#include "FieldScriptFormatter.h"
#include "decompiler/Engine.h"
#include "decompiler/field/FieldDecompiler.h"
/**
* Represents the FF7 Field engine.
*/
class FieldEngine : public Engine{
public:
/**
* Represents an entity.
*
* An entity can be almost anything in a field map: the playable
* character, an NPC, an item, a line...
*/
class Entity{
public:
/**
* Entity constructor.
*
* It doesn't initialize any of the fields.
*/
Entity() = default;
/**
* Entity constructor.
*
* Instantiates an entity with a name.
*
* @param[in] name Entity name.
* @param[in] index Entity index.
*/
Entity(const std::string& name, size_t index);
/**
* Retrieves the entity name.
*
* @return The entity name.
*/
std::string GetName() const;
/**
* Retrieves the entity index.
*
* The index is the one at which appears in the original game
* script.
*
* @return The entity index.
*/
size_t GetIndex() const;
/**
* Retrieves a function.
*
* Retrieves the name of a function from it's index.
*
* @param[in] index Function index.
* @return Function name.
* @throws DecompilerException if there is no function with
* the specified index.
*/
std::string FunctionByIndex(size_t index) const;
/**
* Adds a function to the engine.
*
* Must be added by name and index.
*
* @param[in] name Function name. If the entity is a line, the
* name will be overridden.
* @param[in] index Function index.
*/
void AddFunction(const std::string& name, size_t index);
/**
* Marks the entity as a line.
*
* @param[in] line True to mark the entity as a line, false to
* unmark it.
* @param[in] point_a First point of the line. Can be null if
* line is false.
* @param[in] point_b Second point of the line. Can be null if
* line is false.
*/
void MarkAsLine(bool line, std::vector point_a, std::vector point_b);
/**
* Checks if the entity is a line.
*
* Note that an entity is not considered to be a line until a
* function has been found containing the opcode LINE and
* {@see MarkAsLine} has been called.
*
* @return true if the entity is a line.
*/
bool IsLine();
/**
* Retrieves the first point of the line entity.
*
* If the entity is not a line, the behavior is undefined.
*
* @return The first point of the line entity.
*/
std::vector GetLinePointA();
/**
* Retrieves the second point of the line entity.
*
* If the entity is not a line, the behavior is undefined.
*
* @return The second point of the line entity.
*/
std::vector GetLinePointB();
private:
/**
* Entity name.
*/
std::string name_;
/**
* Entity index.
*/
size_t index_;
/**
* Entity function (script) list.
*/
std::map functions_;
/**
* Indicates if the entity is a line.
*/
bool is_line_;
/**
* The first point of a line entity.
*
* If the entity is not a line, it may not be initializer.
*/
std::vector point_a_;
/**
* The second point of a line entity.
*
* If the entity is not a line, it may not be initializer.
*/
std::vector point_b_;
};
/**
* Constructor.
*
* @param[in] formatter The formatter to be used by the engine.
* @param[in] script_name The script name.
*/
FieldEngine(FieldScriptFormatter& formatter, std::string script_name);
/**
* Copy constructor, disabled.
*
* @param[in] engine The engine to copy.
*/
FieldEngine(const FieldEngine& engine) = delete;
/**
* Copy constructor, disabled.
*
* @param[in] engine The engine to copy.
*/
FieldEngine& operator = (const FieldEngine& engine) = delete;
/**
* Retrieves the disasembler.
*
* @param[in] insts List of instructions.
* @param[in] raw_script_data Script data, raw format.
* @return Pointer to the disasembler.
*/
virtual std::unique_ptr GetDisassembler(
InstVec &insts, const std::vector& raw_script_data
) override;
/**
* Retrieves the dissasembler.
*
* @param[in] insts List of instructions.
* @return Pointer to the dissasembler.
*/
virtual std::unique_ptr GetDisassembler(InstVec &insts) override;
/**
* Retrieves the code generator.
*
* @param[in] insts List of instructions.
* @param[in] output Pointer to the output (file, stream...).
* @return Pointer to the generator.
*/
virtual std::unique_ptr GetCodeGenerator(
const InstVec& insts, std::ostream &output
) override;
/**
* Post-processing actions to apply to the scripts.
*
* It actually does nothing. CFG stands for control flow group.
*
* @param[in] insts Instruction list.
* @param[in] graph Code graph.
*/
virtual void PostCFG(InstVec &insts, Graph graph) override;
/**
* Indicates if instructions are purely grouped.
*
* @return True if instructions are purely grouped. Always false.
*/
virtual bool UsePureGrouping() const override;
/**
* Retrieves all entities in the map.
*
* @return A map of entities, with the name and index.
*/
std::map GetEntities() const;
/**
* Retrieves all non-line entities in the map.
*
* @return A list of non-line entities.
*/
std::vector GetEntityList() const;
/**
* Retrieves all line entities in the map.
*
* @return A list of line entities.
*/
std::vector GetLineList() const;
/**
* Retrieves all entities in the map.
*
* @return A map of entities, with the name and index.
*/
std::map GetEntityIndexMap() const{return entity_index_map_;}
/**
* Adds a function to an entity.
*
* @param[in] entity_name Name of the entity.
* @param[in] entity_index Index of the entity.
* @param[in] func_name Name of the function.
* @param[in] func_index Index of the function.
*/
void AddEntityFunction(
const std::string& entity_name, size_t entity_index,
const std::string& func_name, size_t func_index
);
/**
* Marks an entity as a line.
*
* @param entity_index Index of the entity.
* @param[in] line True to mark the entity as a line, false to unmark
* it.
* @param[in] point_a First point of the line. Can be null if line is
* false.
* @param[in] point_b Second point of the line. Can be null if line is
* false.
*/
void MarkEntityAsLine(
size_t entity_index, bool line, std::vector point_a, std::vector point_b
);
/**
* Checks if an entity has been marked as a line.
*
* @param[in] entity_index 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.
*
* @param[in] index Index of the entity to retrieve.
* @throws DecompilerException if there is no entity at the specified
* index.
*/
const Entity& EntityByIndex(size_t index) const;
/**
* Retrieves the scale factor for the map.
*
* @return Map scale factor.
*/
float GetScaleFactor() const;
/**
* Retrieves the script name.
*
* @return The script name.
*/
const std::string& GetScriptName() const;
private:
/**
* Removes extraneous return statements.
*
* Useful for scripts that only contain one one return statement.
*
* @param[in,out] insts List of instructions to process. Extraneous
* return statements will be deleted from the instructions.
* @param[in] graph Code graph. Unused.
*/
void RemoveExtraneousReturnStatements(InstVec& insts, Graph graph);
/**
* Removes trailing infinite loops.
*
* In FF7 some scripts ends with an infinite loop to keep it alive. In
* VGears this isn't required, and can cause infinite loops, so they
* can be removed.
*
* @param[in,out] insts List of instructions to proccess. Trailing
* infinite loops will be deleted from the instructions.
* @param[in] graph Code graph.
*/
void RemoveTrailingInfiniteLoops(InstVec& insts, Graph graph);
/**
* Tries to detect scripts with trailing infinite loops.
*
* In FF7 some scripts ends with an infinite loop to keep it alive. In
* VGears this isn't required, and can cause infinite loops, so they
* can be removed. This function marks them, so they can be deleted
* with @{see FieldEngine::RemoveTrailingInfiniteLoops}.
*/
void MarkInfiniteLoopGroups(InstVec& insts, Graph graph);
/**
* The script formatter.
*/
FieldScriptFormatter& formatter_;
/**
* The entity index map for the field.
*/
std::map entity_index_map_;
/**
* The map scale factor.
*/
float scale_factor_;
/**
* The script name.
*/
std::string script_name_;
};