| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434 |
- /*
- * Copyright (C) 2022 The V-Gears Team
- *
- * This file is part of V-Gears
- *
- * V-Gears is free software: you can redistribute it and/or modify it under
- * terms of the GNU General Public License as published by the Free Software
- * Foundation, version 3.0 (GPLv3) of the License.
- *
- * V-Gears 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.
- */
- #include <iostream>
- #include <boost/filesystem.hpp>
- #include <boost/program_options.hpp>
- #include <OgreConfigFile.h>
- #include <OgreArchiveManager.h>
- #include <OgreMeshSerializer.h>
- #include <OgreMaterialSerializer.h>
- #include <OgreTechnique.h>
- #include <OgreTextureManager.h>
- #include <OgreMaterialManager.h>
- #include <OgreSkeletonSerializer.h>
- #include <OgreMeshManager.h>
- #include <OgreRenderWindow.h>
- #include <OgreHardwarePixelBuffer.h>
- #include <OgreResourceGroupManager.h>
- #include <OgreLog.h>
- #include "ff7DataInstaller.h"
- #include "VGearsGameState.h"
- #include "data/VGearsAFileManager.h"
- #include "data/VGearsBackgroundFileManager.h"
- #include "data/VGearsCameraMatrixFileManager.h"
- #include "data/VGearsHRCFileManager.h"
- #include "data/VGearsLZSFLevelFileManager.h"
- #include "data/VGearsPaletteFileManager.h"
- #include "data/VGearsPFileManager.h"
- #include "data/VGearsRSDFileManager.h"
- #include "data/VGearsTexFile.h"
- #include "data/VGearsTexCodec.h"
- #include "map/VGearsBackground2DFileManager.h"
- #include "map/VGearsWalkmeshFileManager.h"
- #include "data/FinalFantasy7/FF7ModelListFileManager.h"
- #include "data/VGearsLGPArchiveFactory.h"
- #include "common/FinalFantasy7/FF7NameLookup.h"
- #include "data/VGearsTexCodec.h"
- #include "data/VGearsMapListFile.h"
- #include "decompiler/sudm.h"
- #include <memory>
- #include <QtCore/QDir>
- float FF7DataInstaller::LINE_SCALE_FACTOR = 0.0078124970964f;
- FF7DataInstaller::FF7DataInstaller(
- std::string input_dir, std::string output_dir,
- std::function<void(std::string)> write_output_line
- )
- #ifdef _DEBUG
- : application_("plugins_d.cfg", "resources_d.cfg", "install_d.log"),
- #else
- : application_("plugins.cfg", "resources.cfg", "install.log"),
- #endif
- input_dir_(input_dir),
- output_dir_(output_dir),
- write_output_line(write_output_line)
- {
- if (!application_.initOgre(true)) throw std::runtime_error("Ogre init failure");
- Ogre::Log* default_log( Ogre::LogManager::getSingleton().getDefaultLog());
- assert( default_log );
- default_log->setLogDetail(Ogre::LL_LOW);
- }
- FF7DataInstaller::~FF7DataInstaller(){}
- int FF7DataInstaller::CalcProgress(){
- // TODO: Make more accurate with iterator_counter_ and
- // progress_step_num_elements_.
- float curr_step = installation_state_ / static_cast<float>(STATE_COUNT);
- curr_step = curr_step * 100.0f;
- return static_cast<int>(curr_step);
- }
- int FF7DataInstaller::Progress(){
- switch (installation_state_){
- case IDLE:
- write_output_line("Loading flevel.lgp");
- progress_step_num_elements_ = 1;
- iterator_counter_ = 0;
- fields_lgp_ = std::make_unique<ScopedLgp>(
- application_.getRoot(), input_dir_ + "field/flevel.lgp",
- "LGP", "FFVIIFields"
- );
- installation_state_ = SPAWN_POINTS_AND_SCALE_FACTORS_INIT;
- // TODO: DEBUG:
- //installation_state_ = CONVERT_FIELDS;
- return CalcProgress();
- case SPAWN_POINTS_AND_SCALE_FACTORS_INIT:
- write_output_line("Collecting spawn points and scale factors...");
- InitCollectSpawnAndScaleFactors();
- return CalcProgress();
- case SPAWN_POINTS_AND_SCALE_FACTORS:
- CollectionFieldSpawnAndScaleFactors();
- return CalcProgress();
- case CONVERT_FIELDS:
- ConvertFieldsIteration();
- return CalcProgress();
- case WRITE_MAPS_INIT:
- write_output_line("Writing fields...");
- WriteMapsXmlBegin();
- return CalcProgress();
- case WRITE_MAPS:
- WriteMapsXmlIteration();
- return CalcProgress();
- case WRITE_MAPS_CLEAN:
- EndWriteMapsXml();
- return CalcProgress();
- case CONVERT_FIELD_MODELS_INIT:
- write_output_line("Converting field models...");
- ConvertFieldModelsBegin();
- return CalcProgress();
- case CONVERT_FIELD_MODELS:
- ConvertFieldModelsIteration();
- return CalcProgress();
- case DONE:
- default:
- return 100;
- }
- }
- static std::string FieldModelDir(){return "models/ffvii/field/units";}
- std::vector<std::string> materials_;
- /**
- * Converts a tex file to png.
- *
- * The image is saved in data/models/ffvii/field/units/
- *
- * @param name[in] Path to the tex file to convert.
- */
- void TexToPng(const std::string name){
- Ogre::DataStreamPtr stream(
- Ogre::ResourceGroupManager::getSingleton().openResource(name, "FFVIITextures", true, NULL)
- );
- VGears::TexFile* tex = new VGears::TexFile();
- tex->Read(stream);
- Ogre::ImageCodec::ImageData* image_data = tex->GetImageData();
- Ogre::Image* image = new Ogre::Image(
- Ogre::PF_R8G8B8A8_UINT, image_data->width, image_data->height
- );
- for (int y = 0; y < image_data->height; y ++){
- for (int x = 0; x < image_data->width; x ++){
- // This is the position from which to read from the tex file colour data
- // TODO: It doesn't work for non-square images. For example, the lower part of bxje is
- // all wrong.
- int i = (image_data->height * y) + x;
- image->setColourAt(
- Ogre::ColourValue(
- tex->image_data_[i].comp.red / 255.0f,
- tex->image_data_[i].comp.green / 255.0f,
- tex->image_data_[i].comp.blue / 255.0f,
- tex->image_data_[i].comp.alpha),
- x, y, 0
- );
- }
- }
- Ogre::String base_name;
- VGears::StringUtil::splitBase(name, base_name);
- // TODO: Detect path
- image->save("data/models/ffvii/field/units/" + base_name + ".png");
- }
- /**
- * Exports a mesh to a file.
- *
- * The file will have the mesh name.
- *
- * @param outdir[in] Path to the directory where the file will be saved.
- * @param mesh[in] The mesh to export.
- */
- static void ExportMesh(std::string outdir, const Ogre::MeshPtr &mesh){
- // TODO: Share function with pc model exporter
- VGears::String base_mesh_name;
- VGears::StringUtil::splitFull(mesh->getName(), base_mesh_name);
- Ogre::MeshSerializer mesh_serializer;
- Ogre::SkeletonPtr skeleton(mesh->getSkeleton());
- Ogre::SkeletonSerializer skeleton_serializer;
- skeleton_serializer.exportSkeleton(
- skeleton.getPointer(), outdir + base_mesh_name + ".skeleton"
- );
- mesh->setSkeletonName(FieldModelDir() + "/" + base_mesh_name + ".skeleton");
- mesh_serializer.exportMesh(mesh.getPointer(), outdir + mesh->getName());
- Ogre::Mesh::SubMeshIterator it(mesh->getSubMeshIterator());
- Ogre::MaterialSerializer mat_ser;
- size_t i(0);
- std::set<std::string> textures;
- while (it.hasMoreElements()){
- Ogre::SubMesh *sub_mesh(it.getNext());
- Ogre::MaterialPtr mat(Ogre::MaterialManager::getSingleton().getByName(
- sub_mesh->getMaterialName())
- );
- if (mat != nullptr){
- for (size_t techs = 0; techs < mat->getNumTechniques(); techs ++){
- Ogre::Technique* tech = mat->getTechnique(techs);
- if (tech){
- for (size_t pass_num = 0; pass_num < tech->getNumPasses(); pass_num ++){
- Ogre::Pass* pass = tech->getPass(pass_num);
- if (pass){
- for (
- size_t texture_unit_num = 0;
- texture_unit_num < pass->getNumTextureUnitStates();
- texture_unit_num ++
- ){
- Ogre::TextureUnitState* unit
- = pass->getTextureUnitState(texture_unit_num);
- if (unit && unit->getTextureName().empty() == false){
- // Convert the texture from .tex to .png.
- TexToPng(unit->getTextureName());
- // Ensure the output material script references png files
- // rather than tex
- // files.
- Ogre::String base_name;
- VGears::StringUtil::splitBase(
- unit->getTextureName(), base_name
- );
- unit->setTextureName(
- FieldModelDir() + "/" + base_mesh_name
- + "_" + base_name + ".png"
- );
- // Copy subtexture (xxxx.png) to
- // model_xxxx.png
- // TODO: obtain the "data" folder
- // programatically.
- boost::filesystem::copy_file(
- "data/" + FieldModelDir() + "/" + base_name + ".png",
- "data/" + FieldModelDir() + "/"
- + base_mesh_name + "_" + base_name + ".png",
- boost::filesystem::copy_option::overwrite_if_exists
- );
- textures.insert(unit->getTextureName());
- }
- }
- }
- }
- }
- }
- if (std::count(materials_.begin(), materials_.end(), sub_mesh->getMaterialName()) == 0){
- //std::cout << "[MATERIAL] Writting material "
- // << sub_mesh->getMaterialName() << std::endl;
- mat_ser.queueForExport(mat);
- materials_.push_back(sub_mesh->getMaterialName());
- }
- }
- ++ i;
- }
- mat_ser.exportQueued(outdir + base_mesh_name + VGears::EXT_MATERIAL);
- for (auto& texture_name : textures){
- std::string tex_name = texture_name.c_str();
- try{
- Ogre::TexturePtr texture_ptr
- = Ogre::TextureManager::getSingleton().load(tex_name, "FFVIITextures" /*"FFVII"*/);
- Ogre::Image image;
- texture_ptr->convertToImage(image);
- Ogre::String base_name;
- VGears::StringUtil::splitBase(texture_name, base_name);
- image.save(outdir + base_mesh_name + "_" + base_name + ".png");
- }
- catch (std::exception const& ex){
- std::cerr << "[ERROR] Exception: " << ex.what() << std::endl;
- }
- }
- }
- /**
- * Normalizes a field name.
- *
- * It prefixes a name witg "ffvii_".
- *
- * @param name[in] The field name.
- * @return The normalized field name.
- */
- static std::string FieldName(const std::string& name){return "ffvii_" + name;}
- void FF7DataInstaller::CreateDir(const std::string& path){
- QString target = QString::fromStdString(output_dir_ + path);
- QDir dir(target);
- if (!dir.mkpath(".")) throw std::runtime_error("Failed to mkpath");
- }
- /**
- * Retrieves the path to the field map directory.
- *
- * @return The relative path to the field map directory.
- */
- static std::string FieldMapDir(){return "maps/ffvii/field";}
- /**
- * Utilities for formatting field scripts.
- */
- class BaseFF7FieldScriptFormatter : public SUDM::IScriptFormatter{
- public:
- /**
- * Constructor.
- *
- * @param field_name[in] The field name.
- * @param field_id_to_name_lookup[in] Field name lookup table to use.
- * @param spawn_points[in] The list of spawn points.
- */
- BaseFF7FieldScriptFormatter(
- const std::string& field_name, const std::vector<std::string>& field_id_to_name_lookup,
- FieldSpawnPointsMap& spawn_points
- ) :
- field_name_(field_name), field_id_to_name_lookup_(field_id_to_name_lookup),
- spawn_points_(spawn_points)
- {}
- /**
- * Composes a spawn point name
- *
- * The name will have the format
- * {FIELD_NAME}_{ENTITY}_{FUNCTION_NAME}_addr_{ADDRESS}
- *
- * @param map_id[in] Unused.
- * @param entity[in] Entity name.
- * @param function_name[in] Name of the function.
- * @param address[in] @todo Understand and document.
- * @return The composed spawn point name.
- */
- virtual std::string SpawnPointName(
- unsigned int map_id, const std::string& entity,
- const std::string& function_name, unsigned int address
- ) override{
- return
- field_name_ + "_" + entity + "_" + function_name + "_addr_" + std::to_string(address);
- }
- /**
- * Retrieves a map name from it's ID.
- *
- * @param[in] The map ID.
- * @return The map name.
- */
- virtual std::string MapName(unsigned int map_id) override{
- return FieldName(field_id_to_name_lookup_[map_id]);
- }
- /**
- * Retrieves a user friendly variable name.
- *
- * @param bank[in] Variable bank.
- * @param address[in] Variable address.
- * @return Friendly name for the variable, or an empty string if it
- * doesn't have one assigned.
- */
- virtual std::string VarName(
- unsigned int bank, unsigned int addr
- ) override{
- return VGears::FF7::NameLookup::FieldScriptVarName(bank, addr);
- }
- /**
- * Retrieves a user friendly entity name.
- *
- * @param entity[in] Entity name.
- * @return Friendly name for the entity, or the current name if it
- * doesn't have one assigned.
- */
- virtual std::string EntityName(const std::string& entity) override{
- return VGears::FF7::NameLookup::FieldScriptEntityName(entity);
- }
- /**
- * Retrieves a user friendly character name.
- *
- * @param char_id[in] Character ID.
- * @return Friendly name for the entity, or an empty string if it
- * doesn't have one assigned.
- */
- virtual std::string CharName(int char_id) override{
- return VGears::FF7::NameLookup::CharName(char_id);
- }
- /**
- * Retrieves a user friendly function name.
- *
- * @param entity[in] The name of the entity the function belongs to.
- * @param function_name[in] Function name.
- * @return Friendly name for the function, or the current name if it
- * doesn't have one assigned.
- */
- virtual std::string FunctionName(
- const std::string& entity, const std::string& function_name
- ) override{
- return VGears::FF7::NameLookup::FieldScriptFunctionName(
- field_name_, entity, function_name
- );
- }
- /**
- * Retrieves the header comment for a function in an entity.
- *
- * @param entity[in] The name of the entity the function belongs to.
- * @param function_name[in] Function name.
- * @return Friendly comment for the function, or an empty string if it
- * doesn't have one assigned.
- */
- virtual std::string FunctionComment(
- const std::string& entity, const std::string& function_name
- ) override{
- return VGears::FF7::NameLookup::FieldScriptFunctionComment(
- field_name_, entity, function_name
- );
- }
- protected:
- /**
- * The field name.
- */
- std::string field_name_;
- /**
- * The list of spawn points.
- */
- FieldSpawnPointsMap& spawn_points_;
- /**
- * Look up table relatingfield IDs and names.
- */
- const std::vector<std::string>& field_id_to_name_lookup_;
- };
- /**
- * Handles the formatting of field scripts.
- */
- class FF7FieldScriptFormatter : public BaseFF7FieldScriptFormatter{
- public:
- /**
- * Constructor.
- *
- * @param field_name[in] The field name.
- * @param models[in] The list of field models.
- * @param field_id_to_name_lookup[in] Field name lookup table to use.
- * @param spawn_points[in] The list of spawn points.
- */
- FF7FieldScriptFormatter(
- const std::string& field_name, const VGears::ModelListFilePtr& models,
- const std::vector<std::string>& field_id_to_name_lookup,
- FieldSpawnPointsMap& spawn_points
- ) :
- BaseFF7FieldScriptFormatter(field_name, field_id_to_name_lookup, spawn_points),
- model_loader_(models)
- {}
- // Names an animation, can't return empty
- /**
- * Retreieves an animation name from iths ID.
- *
- * @param char_id[in] ID of the character the animation belogs to.
- * @param id[in] Animation ID.
- * @return The animation name. If there is no name assigned, or it
- * can't be found, a string with the animation ID.
- */
- virtual std::string AnimationName(int char_id, int id) override{
- // Get the animation file name, then look up the friendly name of
- // the "raw" animation.
- if (static_cast<unsigned int>(char_id) >= model_loader_->GetModels().size()){
- std::cerr << "FF7FieldScriptFormatter::AnimationName ERROR:"
- << "Char ID " << char_id << " out of bounds" << std::endl;
- return std::to_string(id);
- }
- const auto& model_info = model_loader_->GetModels().at(char_id);
- if (static_cast<unsigned int>(id) >= model_info.animations.size()){
- std::cerr << "FF7FieldScriptFormatter::AnimationName ERROR:"
- << "In field " << field_name_ << " the model " << model_info.name
- << " animation with ID " << id << " is out of bounds ("
- << model_info.animations.size() << ")" << std::endl;
- return std::to_string(id);
- }
- const auto raw_name = model_info.animations.at(id).name;
- // Trim off ".yos" or whatever extension the model loader adds in.
- Ogre::String base_name;
- VGears::StringUtil::splitBase(raw_name, base_name);
- VGears::StringUtil::toLowerCase(base_name);
- return VGears::FF7::NameLookup::Animation(base_name);
- }
- private:
- /**
- * The field model loader.
- */
- const VGears::ModelListFilePtr& model_loader_;
- };
- /**
- * Creates a gateway script.
- *
- * @param gateway_entity_name[in] Name of the gateway entity.
- * @param target_map_name[in] Name of the target map.
- * @param source_spawn_point_name[in] The spawn point name.
- * @return Gateway LUA script.
- */
- static std::string CreateGateWayScript(
- const std::string& gateway_entity_name, const std::string& target_map_name,
- const std::string& source_spawn_point_name
- ){
- return
- "\nEntityContainer[ \"" + gateway_entity_name + "\" ] = {\n"
- "on_start = function(self)\n"
- " return 0\n"
- "end,\n"
- "on_enter_line = function(self, entity)\n"
- " return 0\n"
- "end,\n\n"
- "on_move_to_line = function(self, entity)\n"
- " return 0\n"
- "end,\n\n"
- "on_cross_line = function(self, entity)\n"
- " if entity == \"Cloud\" then\n"
- " if not FFVII.Data.DisableGateways then\n"
- " load_field_map_request(\""
- + target_map_name + "\", \"" + source_spawn_point_name + "\")\n"
- " end\n"
- " end\n\n"
- " return 0\n"
- "end,\n\n"
- "on_leave_line = function(self, entity)\n"
- " return 0\n"
- "end,\n"
- "}\n\n";
- }
- /**
- * Gateways to whis map ID are considered to be inactive.
- */
- const int INACTIVE_GATEWAY_ID = 32767;
- /**
- * Retrieves a field ID from a name.
- *
- * @param name[in] The name of the field.
- * @param field_id_to_name_lookup[in] Lookup table to use.
- * @return The field ID for the specified name.
- * @throws std::runtime_error If there is no ID for the field name.
- */
- static size_t FieldId(
- const std::string& name,
- const std::vector<std::string>& field_id_to_name_lookup
- ){
- for (size_t i = 0; i < field_id_to_name_lookup.size(); i ++)
- if (field_id_to_name_lookup[i] == name) return i;
- throw std::runtime_error("No Id found for field name");
- }
- /**
- * Retrievs a field scale factor.
- *
- * @param name[in] The name of the field.
- * @param field_id_to_name_lookup[in] Lookup table to use.
- * @return The field ID for the specified name.
- * @throws std::runtime_error If there is no ID for the field name.
- */
- static float FieldScaleFactor(
- const FieldScaleFactorMap& scale_factor_map, size_t field_id
- ){
- auto it = scale_factor_map.find(field_id);
- if (it == std::end(scale_factor_map))
- throw std::runtime_error("Scale factor not found for field id");
- return it->second;
- }
- /**
- * Converts a FFVII PC field to a V-Gears field.
- *
- * @param field_text_writter[in] The field text writer.
- * @param field[in] The field map.
- * @param out_dir[in] The path to the directory where to save the map file.
- * @param field_id_to_name_lookup[in] Lookup table used to relate map IDs and
- * names
- * @param spawn_map[in] List of spawn points.
- * @param scale_factor_map[in] List of scale factors.
- * @param model_animation_db[in] Database of model animations.
- * @param maps[out] The list of maps. The converted one will be added at the
- * end.
- * @param write_output_line[in] Functon to print output to console.
- */
- static void FF7PcFieldToVGearsField(
- FF7FieldTextWriter& field_text_writter,
- VGears::FLevelFilePtr& field,
- const std::string& out_dir,
- const std::vector<std::string>& field_id_to_name_lookup,
- FieldSpawnPointsMap& spawn_map,
- const FieldScaleFactorMap& scale_factor_map,
- ModelsAndAnimationsDb& model_animation_db,
- MapCollection& maps,
- std::function<void(std::string)> write_output_line
- ){
- // Generate triggers script to insert into main
- // decompiled FF7 field -> LUA script.
- std::string gateway_script_data;
- const VGears::TriggersFilePtr& triggers = field->GetTriggers();
- const auto& gateways = triggers->GetGateways();
- for (size_t i = 0; i < gateways.size(); i ++){
- const VGears::TriggersFile::Gateway& gateway = gateways[i];
- if (gateway.destination_field_id != INACTIVE_GATEWAY_ID){
- const std::string gateway_entity_name = "Gateway" + std::to_string(i);
- gateway_script_data += CreateGateWayScript(
- gateway_entity_name,
- FieldName(field_id_to_name_lookup.at(gateway.destination_field_id)),
- "Spawn_" + field->getName() + "_" + std::to_string(i)
- );
- }
- }
- const VGears::ModelListFilePtr& models = field->GetModelList();
- SUDM::Field::DecompiledScript decompiled;
- FF7FieldScriptFormatter formatter(field->getName(), models, field_id_to_name_lookup, spawn_map);
- try{
- // Get the raw script bytes.
- const std::vector<u8> raw_field_data = field->GetRawScript();
- // Decompile to LUA.
- decompiled = SUDM::Field::Decompile(
- field->getName(), raw_field_data, formatter, gateway_script_data,
- "EntityContainer = {}\n\n"
- );
- std::ofstream script_file(
- out_dir + "/" + FieldMapDir() + "/" + field->getName() + "/script.lua"
- );
- if (script_file.is_open()){
- script_file << decompiled.luaScript;
- try{field_text_writter.Write(raw_field_data, field->getName());}
- catch (const std::out_of_range& ex){
- write_output_line(
- "[ERROR] Failed to read texts from field " + field->getName() + ": " + ex.what()
- );
- std::cerr << "[ERROR] Failed to read texts from field "
- << field->getName() << ": " << ex.what() << std::endl;
- }
- }
- else{
- write_output_line(
- "[ERROR] Failed to open script file from field " + field->getName() + " for writing."
- );
- std::cerr << "[ERROR] Failed to open script file from field "
- << field->getName() << "for writing." << std::endl;
- }
- }
- catch (const ::InternalDecompilerError& ex){
- write_output_line(
- "[ERROR] Internal decompiler error in field " + field->getName() + ": " + ex.what()
- );
- std::cerr << "[ERROR] Internal decompiler error in field "
- << field->getName() << ": " << ex.what() << std::endl;
- }
- // Write out the map file which links all the other files together for a given field.
- {
- TiXmlDocument doc;
- std::unique_ptr<TiXmlElement> element(new TiXmlElement("map"));
- // Script.
- std::unique_ptr<TiXmlElement> xml_script_element(new TiXmlElement("script"));
- xml_script_element->SetAttribute(
- "file_name", FieldMapDir() + "/" + field->getName() + "/script.lua"
- );
- element->LinkEndChild(xml_script_element.release());
- // Background.
- std::unique_ptr<TiXmlElement> xml_background_2d(new TiXmlElement("background2d"));
- xml_background_2d->SetAttribute(
- "file_name", FieldMapDir() + "/" + field->getName() + "/bg.xml"
- );
- element->LinkEndChild(xml_background_2d.release());
- // Walkmesh.
- std::unique_ptr<TiXmlElement> xml_walkmesh(new TiXmlElement("walkmesh"));
- xml_walkmesh->SetAttribute(
- "file_name", FieldMapDir() + "/" + field->getName() + "/wm.xml"
- );
- element->LinkEndChild(xml_walkmesh.release());
- // Forward direction (angle player moves when "up" is pressed)
- std::unique_ptr<TiXmlElement> xml_forward_direction(new TiXmlElement("movement_rotation"));
- xml_forward_direction->SetAttribute(
- "degree", std::to_string(triggers->MovementRotation())
- );
- element->LinkEndChild(xml_forward_direction.release());
- // Get this fields Id.
- const size_t this_field_id = FieldId(field->getName(), field_id_to_name_lookup);
- // Use the ID to find the pre-computed list of gateways in all other fields that link to
- // this field.
- auto spawn_iterator = spawn_map.find(this_field_id);
- Ogre::Vector3 first_entity_point = Ogre::Vector3::ZERO;
- // If none found it probably just means no other fields have doors to this one.
- if (spawn_iterator != std::end(spawn_map)){
- const std::vector<SpawnPointDb::Record>& spawn_point_records
- = spawn_iterator->second.gateways_to_this_field;
- for (size_t i = 0; i < spawn_point_records.size(); i ++){
- const VGears::TriggersFile::Gateway& gateway = spawn_point_records[i].gateway;
- // Entity_point:
- std::unique_ptr<TiXmlElement> xml_entity_point(new TiXmlElement("entity_point"));
- if (spawn_point_records[i].from_script){
- // Spawn points from map jumps have a another algorithm.
- xml_entity_point->SetAttribute(
- "name",
- field_id_to_name_lookup.at(
- spawn_point_records[i].field_id) + "_" + spawn_point_records[i].entity_name
- + "_" + spawn_point_records[i].script_function_name + "_addr_"
- + std::to_string(spawn_point_records[i].gateway_index_or_map_jump_address)
- );
- }
- else{
- // Must also include the gateway index for the case where 2
- // fields have more than one door linking to each other.
- xml_entity_point->SetAttribute(
- "name",
- "Spawn_"
- + field_id_to_name_lookup.at(spawn_point_records[i].field_id)
- + "_"
- + std::to_string(spawn_point_records[i].gateway_index_or_map_jump_address)
- );
- }
- const float downscaler_next = 128.0f * FieldScaleFactor(
- scale_factor_map, gateway.destination_field_id
- );
- // Position Z is actually the target walkmesh triangle ID, so this is tiny bit more
- // complex. Now "get the Z value of the triangle with that ID". Note that ID
- // actually just means index.
- unsigned int triangle_index = static_cast<unsigned int>(gateway.destination.z);
- if (
- triangle_index >= field->GetWalkmesh()->GetTriangles().size()
- ){
- write_output_line(
- "[WARNING] In field " + field->getName() + ": Map jump triangle ("
- + std::to_string(triangle_index) + ") out of bounds ("
- + std::to_string(field->GetWalkmesh()->GetTriangles().size()) + ")"
- );
- std::cerr << "[WARNING] In field " << field->getName()
- << ": Map jump triangle (" << triangle_index << ") out of bounds ("
- << field->GetWalkmesh()->GetTriangles().size() << ")" << std::endl;
- triangle_index = 0;
- }
- const float z_of_triangle_with_id
- = field->GetWalkmesh()->GetTriangles().at(triangle_index).a.z;
- const Ogre::Vector3 position(
- gateway.destination.x / downscaler_next, gateway.destination.y / downscaler_next,
- z_of_triangle_with_id
- );
- if (position != Ogre::Vector3::ZERO && first_entity_point == Ogre::Vector3::ZERO)
- first_entity_point = position;
- xml_entity_point->SetAttribute(
- "position", Ogre::StringConverter::toString(position)
- );
- const float rotation = (360.0f * static_cast<float>(gateway.dir)) / 255.0f;
- xml_entity_point->SetAttribute("rotation", std::to_string(rotation));
- element->LinkEndChild(xml_entity_point.release());
- }
- }
- // Get lines. Add them to a list, so they aren't processed later as regular entities.
- std::vector<std::string> line_entities;
- for (SUDM::Field::Line line : decompiled.lines){
- std::unique_ptr<TiXmlElement> xml_entity_trigger(new TiXmlElement("entity_trigger"));
- line_entities.push_back(line.name);
- xml_entity_trigger->SetAttribute("name", line.name);
- xml_entity_trigger->SetAttribute(
- "point1",
- std::to_string(line.point_a[0] * FF7DataInstaller::LINE_SCALE_FACTOR)
- + " " + std::to_string(line.point_a[1] * FF7DataInstaller::LINE_SCALE_FACTOR)
- + " " + std::to_string(line.point_a[2] * FF7DataInstaller::LINE_SCALE_FACTOR)
- );
- xml_entity_trigger->SetAttribute(
- "point2",
- std::to_string(line.point_b[0] * FF7DataInstaller::LINE_SCALE_FACTOR)
- + " " + std::to_string(line.point_b[1] * FF7DataInstaller::LINE_SCALE_FACTOR)
- + " " + std::to_string(line.point_b[2] * FF7DataInstaller::LINE_SCALE_FACTOR)
- );
- xml_entity_trigger->SetAttribute("enabled", "true");
- element->LinkEndChild(xml_entity_trigger.release());
- }
- // Get entities.
- for (SUDM::Field::FieldEntity entity : decompiled.entities){
- // If the entity has been added as a line, skip.
- if (line_entities.size() > 0){
- if (*std::find(line_entities.begin(), line_entities.end(), entity.name) == entity.name) {
- continue;
- }
- }
- const int char_id = entity.char_id;
- if (char_id != -1){
- const VGears::ModelListFile::ModelDescription& desc
- = models->GetModels().at(char_id);
- auto& animations = model_animation_db.ModelAnimations(desc.hrc_name);
- for (auto& anim : desc.animations)
- animations.insert(model_animation_db.NormalizeAnimationName(anim.name));
- std::unique_ptr<TiXmlElement> xml_entity_script(new TiXmlElement("entity_model"));
- xml_entity_script->SetAttribute("name", entity.name);
- // TODO: Add to list of HRC's to convert, obtain name of converted .mesh file.
- auto lower_case_hrc_name = desc.hrc_name;
- VGears::StringUtil::toLowerCase(lower_case_hrc_name);
- xml_entity_script->SetAttribute(
- "file_name",
- FieldModelDir() + "/" + model_animation_db.ModelMetaDataName(lower_case_hrc_name)
- );
- xml_entity_script->SetAttribute("index", entity.index);
- if (desc.type == VGears::ModelListFile::PLAYER){
- // For player models the position is set manually in the xml because if a map
- // is loaded manually this is where the player will end up. Hence we set the
- // position to the first entity_point that we have.
- xml_entity_script->SetAttribute(
- "position", Ogre::StringConverter::toString(first_entity_point)
- );
- }
- else{
- xml_entity_script->SetAttribute(
- "position", Ogre::StringConverter::toString(Ogre::Vector3::ZERO)
- );
- }
- xml_entity_script->SetAttribute("direction", "0");
- // TODO: This isn't quite right, the models animation
- // translation seems to be inverted?
- xml_entity_script->SetAttribute("scale", "0.03125 0.03125 0.03125");
- xml_entity_script->SetAttribute(
- "root_orientation", "0.7071067811865476 0.7071067811865476 0 0"
- );
- element->LinkEndChild(xml_entity_script.release());
- }
- else{
- std::unique_ptr<TiXmlElement> xml_entity_script(new TiXmlElement("entity_script"));
- xml_entity_script->SetAttribute("name", entity.name);//it.first);
- element->LinkEndChild(xml_entity_script.release());
- }
- }
- const float downscaler_this = 128.0f * FieldScaleFactor(scale_factor_map, this_field_id);
- const auto& gateways = triggers->GetGateways();
- for (size_t i = 0; i < gateways.size(); i ++){
- const VGears::TriggersFile::Gateway& gateway = gateways[i];
- // If non-inactive gateway:
- if (gateway.destination_field_id != INACTIVE_GATEWAY_ID){
- std::unique_ptr<TiXmlElement> xml_entity_trigger(
- new TiXmlElement("entity_trigger")
- );
- xml_entity_trigger->SetAttribute("name", "Gateway" + std::to_string(i));
- xml_entity_trigger->SetAttribute(
- "point1",
- Ogre::StringConverter::toString(
- Ogre::Vector3(
- gateway.exit_line[0].x,
- gateway.exit_line[0].y,
- gateway.exit_line[0].z) / downscaler_this
- )
- );
- xml_entity_trigger->SetAttribute(
- "point2",
- Ogre::StringConverter::toString(
- Ogre::Vector3(
- gateway.exit_line[1].x,
- gateway.exit_line[1].y,
- gateway.exit_line[1].z) / downscaler_this
- )
- );
- // Enabled is hard coded to true.
- xml_entity_trigger->SetAttribute("enabled", "true");
- element->LinkEndChild(xml_entity_trigger.release());
- }
- }
- doc.LinkEndChild(element.release());
- doc.SaveFile(out_dir + "/" + FieldMapDir() + "/" + field->getName() + "/map.xml");
- const VGears::PaletteFilePtr& pal = field->GetPalette();
- const VGears::BackgroundFilePtr& bg = field->GetBackground();
- std::unique_ptr<Ogre::Image> bg_image(bg->CreateImage(pal));
- bg_image->encode("png");
- bg_image->save(out_dir + "/" + FieldMapDir() + "/" + field->getName() + "/tiles.png");
- {
- TiXmlDocument doc;
- std::unique_ptr<TiXmlElement> element(new TiXmlElement("background2d"));
- // Magic constants.
- const int BG_SCALE_UP_FACTOR = 3;
- const int BG_PSX_SCREEN_WIDTH = 320;
- const int BG_PSX_SCREEN_HEIGHT = 240;
- // Get texture atlas size.
- const int width = bg_image->getWidth();
- const int height = bg_image->getHeight();
- const VGears::CameraMatrixFilePtr& camera_matrix = field->GetCameraMatrix();
- const Ogre::Vector3 position
- = camera_matrix->GetPosition() / FieldScaleFactor(scale_factor_map, this_field_id);
- const Ogre::Quaternion orientation = camera_matrix->GetOrientation();
- const Ogre::Degree fov
- = camera_matrix->GetFov(static_cast<float>(BG_PSX_SCREEN_HEIGHT));
- const int min_x = triggers->GetCameraRange().left * BG_SCALE_UP_FACTOR;
- const int min_y = triggers->GetCameraRange().top * BG_SCALE_UP_FACTOR;
- const int max_x = triggers->GetCameraRange().right * BG_SCALE_UP_FACTOR;
- const int max_y = triggers->GetCameraRange().bottom * BG_SCALE_UP_FACTOR;
- element->SetAttribute("image", FieldMapDir() + "/" + field->getName() + "/tiles.png");
- element->SetAttribute("position", Ogre::StringConverter::toString(position));
- element->SetAttribute("orientation", Ogre::StringConverter::toString(orientation));
- element->SetAttribute("fov", Ogre::StringConverter::toString(fov));
- element->SetAttribute(
- "range",
- std::to_string(min_x) + " " + std::to_string(min_y) + " "
- + std::to_string(max_x) + " " + std::to_string(max_y)
- );
- element->SetAttribute(
- "clip",
- std::to_string(BG_PSX_SCREEN_WIDTH * BG_SCALE_UP_FACTOR) + " "
- + std::to_string(BG_PSX_SCREEN_HEIGHT * BG_SCALE_UP_FACTOR)
- );
- // Write out the *_BG.XML data.
- auto& layers = bg->GetLayers();
- for (const auto& layer : layers){
- // TODO: Should only the tiles to construct enabled layers be outputted?
- // if (layer.enabled){
- for (const VGears::BackgroundFile::SpriteData& sprite : layer.sprites){
- std::unique_ptr<TiXmlElement> xml_element(new TiXmlElement("tile"));
- xml_element->SetAttribute(
- "destination",
- Ogre::StringConverter::toString(sprite.dst.x * BG_SCALE_UP_FACTOR) + " "
- + Ogre::StringConverter::toString(sprite.dst.y * BG_SCALE_UP_FACTOR)
- );
- xml_element->SetAttribute(
- "width", Ogre::StringConverter::toString(sprite.width * BG_SCALE_UP_FACTOR)
- );
- xml_element->SetAttribute(
- "height", Ogre::StringConverter::toString(sprite.height * BG_SCALE_UP_FACTOR)
- );
- // Each tile is added to a big texture atlas with hard coded size of 1024x1024,
- // convert UV's to the 0.0f to 1.0f range.
- const float u0 = static_cast<float>(sprite.src.x) / bg_image->getWidth();
- const float v0 = static_cast<float>(sprite.src.y) / bg_image->getHeight();
- const float u1
- = static_cast<float>(sprite.src.x + sprite.width) / bg_image->getWidth();
- const float v1
- = static_cast<float>(sprite.src.y + sprite.height) / bg_image->getHeight();
- xml_element->SetAttribute(
- "uv",
- Ogre::StringConverter::toString(u0) + " "
- + Ogre::StringConverter::toString(v0) + " "
- + Ogre::StringConverter::toString(u1) + " "
- + Ogre::StringConverter::toString(v1)
- );
- // TODO: It works (on FFVII PC), but why this number?
- xml_element->SetAttribute(
- "depth",
- Ogre::StringConverter::toString(static_cast<float>(sprite.depth) * (0.03125f))
- );
- // TODO: Copied from DatFile::AddTile.
- // Add to common method.
- Ogre::String blending_str = "";
- if (sprite.blending == 0) blending_str = "alpha";
- // 3 is source + 0.25 * destination:
- else if (sprite.blending == 1 || sprite.blending == 3) blending_str = "add";
- else if (sprite.blending == 2) blending_str = "subtract";
- // TODO: Should probably throw to fail conversion:
- else blending_str = "unknown";
- xml_element->SetAttribute("blending", blending_str);
- element->LinkEndChild(xml_element.release());
- }
- //}
- }
- doc.LinkEndChild(element.release());
- doc.SaveFile(out_dir + "/" + FieldMapDir() + "/" + field->getName() + "/bg.xml");
- }
- }
- {
- // Save out the walk mesh as XML.
- const VGears::WalkmeshFilePtr& walkmesh = field->GetWalkmesh();
- TiXmlDocument doc;
- std::unique_ptr<TiXmlElement> element(new TiXmlElement("walkmesh"));
- for (VGears::WalkmeshFile::Triangle& tri : walkmesh->GetTriangles()){
- std::unique_ptr<TiXmlElement> xml_element(new TiXmlElement("triangle"));
- xml_element->SetAttribute("a", Ogre::StringConverter::toString(tri.a));
- xml_element->SetAttribute("b", Ogre::StringConverter::toString(tri.b));
- xml_element->SetAttribute("c", Ogre::StringConverter::toString(tri.c));
- xml_element->SetAttribute("a_b", std::to_string(tri.access_side[0]));
- xml_element->SetAttribute("b_c", std::to_string(tri.access_side[1]));
- xml_element->SetAttribute("c_a", std::to_string(tri.access_side[2]));
- element->LinkEndChild(xml_element.release());
- }
- doc.LinkEndChild(element.release());
- doc.SaveFile(out_dir + "/" + FieldMapDir() + "/" + field->getName() + "/wm.xml");
- }
- maps.insert(field->getName());
- }
- /**
- * Handles the script gateway colection.
- */
- class FF7FieldScriptGatewayCollector : public BaseFF7FieldScriptFormatter{
- // TODO: Move declaration to a .h file.
- public:
- /**
- * Cosntructor.
- */
- FF7FieldScriptGatewayCollector(
- const std::string& field_name, const std::vector<std::string>& field_id_to_name_lookup,
- FieldSpawnPointsMap& spawn_points, size_t this_field_id
- ) :
- BaseFF7FieldScriptFormatter(field_name,field_id_to_name_lookup, spawn_points),
- field_id_(this_field_id)
- {}
- /**
- * Adds an spawn point.
- *
- * If the spawn is new, a new record will be added to the spawn point
- * database. If it was already there, update the record to add the
- * origin.
- *
- * @param map_id[in] The target map ID.
- * @param entity[in] The entity that acts as the spawn point.
- * @param function_name[in] The spawn function name.
- * @param address[in] @todo Understand and document.
- * @param x[in] X coordinate of the field target at which to spawn.
- * @param y[in] Y coordinate of the field target at which to spawn.
- * @param z[in] Z coordinate of the field target at which to spawn.
- * @param angle[in] Orientation at which to spawn.
- */
- virtual void AddSpawnPoint(
- unsigned int map_id, const std::string& entity, const std::string& function_name,
- unsigned int address, int x, int y, int z, int angle
- ) override {
- auto it = spawn_points_.find(map_id);
- VGears::TriggersFile::Gateway gw = {};
- gw.destination_field_id = map_id;
- gw.destination.x = x;
- gw.destination.y = y;
- gw.destination.z = z;
- gw.dir = angle;
- if (it != std::end(spawn_points_)){
- // Add to the list of gateways that link to destination_field_id.
- SpawnPointDb::Record rec;
- rec.from_script = true;
- rec.field_id = field_id_;
- rec.gateway = gw;
- rec.entity_name = entity;
- rec.script_function_name = function_name;
- rec.gateway_index_or_map_jump_address = address;
- it->second.gateways_to_this_field.push_back(rec);
- }
- else{
- // Create a new record for destination_field_id
- SpawnPointDb db;
- db.target_field_id = map_id;
- SpawnPointDb::Record rec;
- rec.from_script = true;
- rec.field_id = field_id_;
- rec.gateway = gw;
- rec.entity_name = entity;
- rec.script_function_name = function_name;
- rec.gateway_index_or_map_jump_address = address;
- db.gateways_to_this_field.push_back(rec);
- spawn_points_.insert(std::make_pair(db.target_field_id, db));
- }
- }
- private:
- /**
- * The field map ID.
- */
- size_t field_id_;
- };
- /**
- * Collects the spawn point from a field.
- *
- * If a spawn is new, a new record will be added to the spawn point database.
- * If it was already there, update the record to add the origin.
- *
- * @param field[in] The field to collect from.
- * @param field_id_to_name_lookup[in] Lookup table to relate field IDs and
- * names.
- * @param spawn_points[out] Spawn points will be added sequentially to the end
- * of this map.
- */
- static void CollectSpawnPoints(
- VGears::FLevelFilePtr& field, const std::vector<std::string>& field_id_to_name_lookup,
- FieldSpawnPointsMap& spawn_points
- ){
- const size_t this_field_id = FieldId(field->getName(), field_id_to_name_lookup);
- // Decompile the script just so the MAPJUMPs can be collected. This is needed to construct the
- // full list of entries to each field.
- try{
- // Get the raw script bytes.
- SUDM::Field::DecompiledScript decompiled;
- const std::vector<u8> raw_field_data = field->GetRawScript();
- // Decompile to LUA.
- FF7FieldScriptGatewayCollector formatter(
- field->getName(), field_id_to_name_lookup, spawn_points, this_field_id
- );
- decompiled = SUDM::Field::Decompile(
- field->getName(), raw_field_data, formatter, "", "EntityContainer = {}\n\n"
- );
- }
- catch (const ::InternalDecompilerError& ex){
- std::cerr << "CollectSpawnPoints: InternalDecompilerError: " << ex.what() << std::endl;
- }
- const VGears::TriggersFilePtr& triggers = field->GetTriggers();
- const auto& gateways = triggers->GetGateways();
- for (size_t i = 0; i < gateways.size(); i ++){
- const VGears::TriggersFile::Gateway& gateway = gateways[i];
- if (gateway.destination_field_id != INACTIVE_GATEWAY_ID){
- auto it = spawn_points.find(gateway.destination_field_id);
- if (it != std::end(spawn_points)){
- // Add to the list of gateways that link to
- // destination_field_id.
- SpawnPointDb::Record rec;
- rec.field_id = this_field_id;
- rec.gateway = gateway;
- rec.gateway_index_or_map_jump_address = i;
- it->second.gateways_to_this_field.push_back(rec);
- }
- else{
- // Create a new record for destination_field_id.
- SpawnPointDb db;
- db.target_field_id = gateway.destination_field_id;
- SpawnPointDb::Record rec;
- rec.field_id = this_field_id;
- rec.gateway = gateway;
- rec.gateway_index_or_map_jump_address = i;
- db.gateways_to_this_field.push_back(rec);
- spawn_points.insert(std::make_pair(db.target_field_id, db));
- }
- }
- }
- }
- /**
- * Checks if a file is a field file.
- *
- * To verify it, it just checks that the extension is not '.tex', '.tut' or
- * '.siz' and that the name is not 'maplist'.
- *
- * @param resource_name[in] The name of the file to test.
- * @return False if the file is surely not a field file, true otherwise.
- */
- static bool IsAFieldFile(Ogre::String& resource_name){
- return (
- !VGears::StringUtil::endsWith(resource_name, ".tex")
- && !VGears::StringUtil::endsWith(resource_name, ".tut")
- && !VGears::StringUtil::endsWith(resource_name, ".siz")
- && resource_name != "maplist"
- );
- }
- /**
- * Checks if a map cause fatal crash bugs.
- *
- * It uses a hardcoded list of maps that are known to cause errors. This can be
- * removed when whatever is causing the crash(s) is fixed.
- *
- * NOTE: Even so, conversion of all models will fail with a bone index out of
- * bounds.
- *
- * @param resource_name[in] The name of the map file to test.
- * @return True if the map will crash, false otherwise.
- */
- static bool WillCrash(Ogre::String& resource_name){
- if (
- resource_name == "bugin1a" // crashes in back ground image generation
- || resource_name == "frcyo" // Hangs in decompliation
- || resource_name == "fr_e" // Background image crash
- || resource_name == "las4_2" // Background image crash
- || resource_name == "las4_3" // Background image crash
- || resource_name == "lastmap" // Background image crash
- || resource_name == "md_e1" // Background image crash
- || resource_name == "trnad_3" // Background image crash
- ){return true;}
- return false;
- }
- /**
- * Checks if a map is a test field.
- *
- * It uses a hardcoded list of maps that are known to be test maps. Unused maps
- * are considered to be test maps.
- *
- * @param resource_name[in] The name of the map file to test.
- * @return True if the map is a test map, false otherwise.
- */
- static bool IsTestField(Ogre::String& resource_name){
- if (
- resource_name == "startmap"
- || resource_name == "md1stin"
- || resource_name == "md1_1"
- || resource_name == "md1_2"
- || resource_name == "md8_1"
- || resource_name == "nmkin_1"
- || resource_name == "nmkin_2"
- || resource_name == "nmkin_3"
- || resource_name == "nmkin_4"
- || resource_name == "nmkin_5"
- || resource_name == "nrthmk"
- || resource_name == "elevtr1"
- || resource_name == "tin_1"
- || resource_name == "tin_2"
- || resource_name == "rootmap"
- || resource_name == "md8_4"
- ){return true;}
- return false;
- }
- /**
- * Collects the scale factor from a map.
- *
- * @param field[in] The field to collect from.
- * @param scale_factors[out] The scale factor for the map will be set here, in
- * the appropiate map entry.
- * @param field_id_to_name_lookup[in] Lookup table to relate field IDs and
- * names.
- */
- static void CollectFieldScaleFactors(
- VGears::FLevelFilePtr& field, FieldScaleFactorMap& scale_factors,
- const std::vector<std::string>& field_id_to_name_lookup
- ){
- scale_factors[FieldId(field->getName(), field_id_to_name_lookup)]
- = ::SUDM::Field::ScaleFactor(field->GetRawScript());
- }
- void FF7DataInstaller::InitCollectSpawnAndScaleFactors(){
- progress_step_num_elements_ = 1;
- CreateDir(FieldMapDir());
- CreateDir(FieldModelDir());
- // List what's in the LGP archive.
- flevel_file_list_ = application_.ResMgr()->listResourceNames("FFVIIFields", "*");
- // Load the map list field.
- VGears::MapListFilePtr map_list
- = VGears::MapListFileManager::GetSingleton().load(
- "maplist", "FFVIIFields"
- ).staticCast<VGears::MapListFile>();
- map_list_ = map_list->GetMapList();
- iterator_counter_ = 0;
- conversion_step_ = 0;
- installation_state_ = SPAWN_POINTS_AND_SCALE_FACTORS;
- }
- void FF7DataInstaller::CollectionFieldSpawnAndScaleFactors(){
- // On the first pass collate required field information.
- progress_step_num_elements_ = flevel_file_list_->size();
- if (iterator_counter_ < flevel_file_list_->size()){
- auto resource_name = (*flevel_file_list_)[iterator_counter_];
- // Exclude things that are not fields.
- //if (IsAFieldFile(resource_name) /*&& IsTestField(resource_name)*/){
- // TODO: DEBUG: Only testing fields.
- if (IsAFieldFile(resource_name) && IsTestField(resource_name)){
- conversion_step_ ++;
- if (conversion_step_ == 1){
- field_ = VGears::LZSFLevelFileManager::GetSingleton().load(
- resource_name, "FFVIIFields"
- ).staticCast<VGears::FLevelFile>();
- //write_output_line("Load field " + resource_name);
- return;
- }
- if (conversion_step_ == 2){
- //write_output_line("Read spawn points from scripts");
- CollectSpawnPoints(field_, map_list_, spawn_points_);
- return;
- }
- if (conversion_step_ == 3){
- //write_output_line("Read scale factor");
- CollectFieldScaleFactors(field_, scale_factors_, map_list_);
- conversion_step_ = 0;
- iterator_counter_ ++;
- return;
- }
- }
- else iterator_counter_ ++;
- }
- else{
- field_.reset();
- iterator_counter_ = 0;
- installation_state_ = CONVERT_FIELDS;
- field_text_writer_.Begin(output_dir_ + "/texts/english/dialogs_mission1.xml");
- }
- }
- void FF7DataInstaller::ConvertFieldsIteration(){
- // Do the full conversion with the collated data.
- progress_step_num_elements_ = flevel_file_list_->size();
- if (iterator_counter_ < flevel_file_list_->size()){
- auto resource_name = (*flevel_file_list_)[iterator_counter_];
- // Exclude things that are not fields.
- if (IsAFieldFile(resource_name)){
- //if (/*IsTestField(resource_name) &&*/ !WillCrash(resource_name)){
- // TODO: DEBUG: Only test fields
- if (IsTestField(resource_name) && !WillCrash(resource_name)){
- //write_output_line("Converting field " + resource_name);
- std::cout << " - Converting field: " << resource_name << std::endl;
- CreateDir(FieldMapDir() + "/" + resource_name);
- VGears::FLevelFilePtr field
- = VGears::LZSFLevelFileManager::GetSingleton().load(
- resource_name, "FFVIIFields"
- ).staticCast<VGears::FLevelFile>();
- FF7PcFieldToVGearsField(
- field_text_writer_, field, output_dir_, map_list_, spawn_points_, scale_factors_,
- used_models_and_anims_, converted_map_list_, write_output_line
- );
- }
- else{
- write_output_line(
- "[ERROR] Skip field " + resource_name + " due to crash or hang issue."
- );
- std::cerr << "[ERROR] Skip field: " << resource_name
- << " due to crash or hang issue." << std::endl;
- }
- }
- iterator_counter_ ++;
- }
- else{
- iterator_counter_ = 0;
- installation_state_ = WRITE_MAPS_INIT;
- field_text_writer_.End();
- }
- }
- void FF7DataInstaller::WriteMapsXmlBegin(){
- // Write out maps.xml.
- progress_step_num_elements_ = 1;
- doc_ = std::make_unique<TiXmlDocument>();
- element_ = std::make_unique<TiXmlElement>("maps");
- iterator_counter_ = 0;
- installation_state_ = WRITE_MAPS;
- iterator_counter_ = 0;
- converted_map_list_iterator_ = converted_map_list_.begin();
- }
- void FF7DataInstaller::WriteMapsXmlIteration(){
- // TODO: Probably need to inject "empty" and "test" fields.
- progress_step_num_elements_ = converted_map_list_.size();
- if (converted_map_list_iterator_ != converted_map_list_.end()){
- auto map = *converted_map_list_iterator_;
- write_output_line("Writing field " + FieldName(map));
- std::unique_ptr<TiXmlElement> xml_element(new TiXmlElement("map"));
- xml_element->SetAttribute("name", FieldName(map));
- xml_element->SetAttribute("file_name", FieldMapDir() + "/" + map + "/map.xml");
- element_->LinkEndChild(xml_element.release());
- iterator_counter_++;
- converted_map_list_iterator_++;
- }
- else installation_state_ = WRITE_MAPS_CLEAN;
- }
- void FF7DataInstaller::EndWriteMapsXml(){
- progress_step_num_elements_ = 1;
- doc_->LinkEndChild(element_.release());
- doc_->SaveFile(output_dir_ + "/maps.xml");
- installation_state_ = CONVERT_FIELD_MODELS_INIT;
- }
- void FF7DataInstaller::ConvertFieldModelsBegin(){
- // TODO: Convert models and animations in model_animation_db.
- progress_step_num_elements_ = 1;
- field_models_lgp_ = std::make_unique<ScopedLgp>(
- application_.getRoot(), input_dir_ + "field/char.lgp", "LGP", "FFVII"
- );
- field_model_file_list_ = application_.ResMgr()->listResourceNames("FFVII", "*");
- iterator_counter_ = 0;
- installation_state_ = CONVERT_FIELD_MODELS;
- iterator_counter_ = 0;
- conversion_step_ = 0;
- model_animation_map_iterator_ = used_models_and_anims_.map.begin();
- }
- void FF7DataInstaller::ConvertFieldModelsIteration(){
- progress_step_num_elements_ = used_models_and_anims_.map.size();
- if (model_animation_map_iterator_ != used_models_and_anims_.map.end()){
- if (conversion_step_ == 0){
- write_output_line("Converting model " + model_animation_map_iterator_->first);
- conversion_step_++;
- }
- else{
- try{
- Ogre::ResourcePtr hrc = VGears::HRCFileManager::GetSingleton().load(
- model_animation_map_iterator_->first, "FFVII"
- );
- Ogre::String base_name;
- VGears::StringUtil::splitBase(model_animation_map_iterator_->first, base_name);
- auto mesh_name = VGears::FF7::NameLookup::model(base_name) + ".mesh";
- Ogre::MeshPtr mesh(Ogre::MeshManager::getSingleton().load(mesh_name, "FFVII"));
- Ogre::SkeletonPtr skeleton(mesh->getSkeleton());
- for (auto& anim : model_animation_map_iterator_->second){
- VGears::AFileManager &afl_mgr(VGears::AFileManager::GetSingleton());
- VGears::AFilePtr a = afl_mgr.load(anim, "FFVII").staticCast<VGears::AFile>();
- // Convert the FF7 name to a more readable name set in the meta data.
- Ogre::String base_name;
- VGears::StringUtil::splitBase(anim, base_name);
- a->AddTo(skeleton, VGears::FF7::NameLookup::Animation(base_name));
- }
- ExportMesh(output_dir_ + "/" + FieldModelDir() + "/", mesh);
- }
- catch (const Ogre::Exception& ex){
- write_output_line(
- "[ERROR] Ogre exception converting model "
- + model_animation_map_iterator_->first + ": " + ex.what()
- );
- std::cerr << "[ERROR] Ogre exception converting model "
- << model_animation_map_iterator_->first <<": " << ex.what() << std::endl;
- }
- catch (const std::exception& ex){
- write_output_line(
- "[ERROR] Exception converting model "
- + model_animation_map_iterator_->first + ": " + ex.what()
- );
- std::cerr << "[ERROR] Exception converting model "
- << model_animation_map_iterator_->first << ": " << ex.what() << std::endl;
- }
- iterator_counter_++;
- model_animation_map_iterator_++;
- conversion_step_ = 0;
- }
- }
- else{
- std::cout << "Installation finished." << std::endl;
- write_output_line("Installation finished.");
- installation_state_ = DONE;
- }
- }
|