So, here is how to use the model importer. I guess it will answer your questions, Incinerator
Intro A - Supported Model FormatsYou can only import FBX Binary and FBX ASCII files properly, much like exporting. Encrypted FBX are not supported. In general, the other formats have problems with animations or even bones so you should always convert your models to FBX beforehand. 3DS Max is the normal program you would need to create/edit models that can be imported, but it's not free. There is a free version, called Gmax, but I'm not sure if it supports FBX versions that are recent enough. Also, FBX ASCII format is a text file that can be edited with Notepad but it's tedious and won't bring you very far.
The FBX versions supported are:
- FBX ASCII versions 5, 6 and 7 up to 7.4
- FBX Binary versions 5 and 6 up to 6.1
Also, only (polygonal) Meshes are supported. No Nurbs, no Patches.
The Tangents, Normals and - more importantly - the UV coordinates must be stored by Control Points (not by Polygon vertex). I guess it's a simple setting to check in 3DS Max.
For animations, I wasn't able to import properly the Bezier interpolation data: animations will have a close-to-linear interpolation (it usually doesn't look very different).
Note that texture animations are not supported yet. They are stored in different files for which I didn't investigate the format.
And also, some animations have sounds in-game, like footsteps or a sword unsheathing. These are not inside the animation's data but in the Field script codes (usually either in the object's "Init" function, or in its "Reinit" function).
Intro B - The optionsIn the Unity Assets Viewer, you have the following options for importing models:
-) Only Update Existing Nodes: You will surely have no interest in this function except in very specific situations. It expects the imported model to have exactly the same nodes (mostly bones) as the one in-place. It popups a warning if not. Using this option, you're 100% sure that no new asset will be imported when you replace a model.
-) Update Existing and Import New: The default one. It will compare the hierarchy of the new model with the old one and keep as much as it can from the old one, adding a minimal number of assets to the archive.
-) Import All Nodes in New Files: With this, except for the top-level GameObject (the file selected), all the nodes of the new models will be imported in new assets. When you add a whole new model, that's also what happens except that the top-level GameObject is also new in that case.
-) Keep Unused Nodes: Doesn't remove any asset, even if they become dummied and unusable after replacing a model.
-) Delete Unused Nodes: Clean up the assets that are not used anymore after replacing a model. This option is not implemented yet and the only way to remove assets is to replace the whole Unity archive by a backup (or download it back).
-) Import Mesh/Material: Import the geometry, skeleton, material, UV mapping, etc... You may uncheck this option if you only want to update a model's animations and speed up the process.
-) Import Animations: Import the animations in the p0data5.bin archive file (the one dedicated to the game's animations). You may unckeck this if you only update the geometry, etc...
Also, you'll need to import/update the textures separatly. If you add new textures, you must check the "Bundle Info" flag and give it a path (anything not already used will be fine). Besides that, you must choose the options for Image Quality Conversion. The main ones are:
-) RGB: Full quality images without alpha channel,
-) RGBA: Full quality images with alpha channel, resulting in bigger files,
-) DXT5 - Medium Quality: Compressed images with DXT5 format, resulting in low-sized files. Medium quality is fast and still very good,
-) DXT5 - High Quality: A slightly better quality than the previous one, with the same file size but slower to process.
If the "Default Compression Method" is checked when importing new files, the RGBA format will be used (when replacing existing textures, this option use the same compression as the old texture).
I - Replacing an existing model with existing animationsThe easiest thing to do is to replace a model and don't add more animations than those already there. I've tested the model importer on the models of the p0data4 archive only (the most important one). There are also the weapon models (I think it should work) and Battle Scenes (maybe it won't work) in p0data2, and World Map model in p0data3. That last one can't be replaced and can't even be exported properly for now (it mainly consists of plenty of .prefab files, that are parts of the ground and I didn't investigate how all these parts are placed to draw the big thing).
The importing option for this should be either "Only Update Existing Nodes" or "Update Existing and Import New".
The animations of your model must match with the old model's animation internal names ("ANH_" something ; that's the names of the animations when you export the old model).
First, if you use a new texture, you must start by importing that texture. In the same archive as your model (surely p0data4), right-click on the asset list and select "Add". Once you selected your texture, choose "Texture2D" as the file type, give it a name and give it a Full Name. The Full Name is not very important but remember what you chose and be sure to use a full name that is not already used.
Typically, Full Names of the models' textures are "assets/resources/models/[MODEL_TYPE]/[MODEL_ID]/[MODEL_ID]_[TEXTURE_NUMBER].png".
Also, it may be a good idea to remember what was the Internal File ID.
Once you have all the textures set, verify that your updated model is placed in the "HadesWorkshopAssets" folder at the right place and with the right name. It must be at the same place as where the model is exported with the Unity Assets Viewer.
Right-click on the model you want to replace (Reminder: the relevant asset is the one of type "1 (GameObject)" and with the .fbx extension in his file name) then "Import Selection".
Warning: due to a bug that will take a little time to fix, you should never import more than 1 model at a time.
It is possible that the program will ask you to select the texture assets. Select the texture in the asset list or you may also copy/paste the file internal ID that was used when adding that texture.
Then wait for it and it's done!
If the program popups the window for importing assets, displaying the animation names of your model, that means you have more animations than expected and/or they don't have the right names. If your goal was not to add new animations but only replace existing ones, you can choose Full Names that you'll remember and confirm the importations. Then go in the archive "p0data5", export the .anim assets that you just added, identify the animations of the old model and replace them by the .anim you just exported (rename them with the right name and move them in the right folder, like for replacing the model).
You may also hit "Cancel" when the popups for importing new animations appears: it will cancel the update of all the animations and only update the model instead.
If your new model is lacking animations, the related old ones won't be modified at all and will still be valid.
I bis - Adding a new animation by taking advantage of dummied dataIf the model you want to update as dummied animations, you can do exactly the same as in I and still add one or a few animations.
The dummied animations appear in the Field script animation list with the description "Unexisting". They are registered by the game's engine and only await to have a related asset to be usable. Here is a list of dummied animations:
// Enemy Basilisk
5458, 379, "ANH_MON_B3_011_B", "Unexisting B"
// Enemy LizardMan
5459, 390, "ANH_MON_B3_019_B", "Unexisting B"
// Enemy Carve Spider
5460, 376, "ANH_MON_B3_021_015", "UnexistingA"
5460, 360, "ANH_MON_B3_021_040", "UnexistingB 1"
5460, 366, "ANH_MON_B3_021_041", "UnexistingB 2"
5460, 354, "ANH_MON_B3_021_042", "UnexistingB 3"
// Enemy Clipper
150, 8693, "ANH_MON_B3_039_P", "Unexisting P"
// Enemy Blazer Beetle
84, 9257, "ANH_MON_B3_042_B", "Unexisting B"
// Enemy Cactuar
244, 9239, "ANH_MON_B3_061_B", "Unexisting B"
244, 9900, "ANH_MON_B3_061_TEST", "Unexisting Test"
// Enemy Valia Pira
354, 9340, "ANH_MON_B3_130_B", "Unexisting B"
354, 13578, "ANH_MON_B3_130_ILLUST","Unexisting Illust"
354, 8833, "ANH_MON_B3_130_P", "Unexisting P"
354, 13581, "ANH_MON_B3_130_TEST", "Unexisting Test"
// Enemy Vivi
558, 12302, "ANH_MON_B3_151_001", "UnexistingA"
558, 12306, "ANH_MON_B3_151_005", "UnexistingB"
558, 9675, "ANH_MON_B3_151_B", "Unexisting B"
558, 9677, "ANH_MON_B3_151_P", "Unexisting P"
// Enemy Dagger
671, 9957, "ANH_MON_B3_169_002", "Unexisting"
// Enemy Freya
297, 10317, "ANH_MON_B3_174_B", "Unexisting B"
297, 10319, "ANH_MON_B3_174_P", "Unexisting P"
// Enemy Gigan Toad B
663, 8374, "ANH_MON_B3_197_034", "Unexisting"
// Battle Steiner B
655, 6744, "ANH_MAIN_B0_018_000", "Unexisting 000"
655, 6746, "ANH_MAIN_B0_018_001", "Unexisting 001"
655, 6747, "ANH_MAIN_B0_018_002", "Unexisting 002"
655, 6750, "ANH_MAIN_B0_018_010", "Unexisting 010"
655, 6752, "ANH_MAIN_B0_018_011", "Unexisting 011"
655, 6753, "ANH_MAIN_B0_018_020", "Unexisting 020"
655, 6755, "ANH_MAIN_B0_018_021", "Unexisting 021"
655, 6758, "ANH_MAIN_B0_018_022", "Unexisting 022"
655, 6759, "ANH_MAIN_B0_018_023", "Unexisting 023"
655, 6761, "ANH_MAIN_B0_018_032", "Unexisting 032"
655, 6763, "ANH_MAIN_B0_018_033", "Unexisting 033"
655, 6766, "ANH_MAIN_B0_018_040", "Unexisting 040"
655, 6768, "ANH_MAIN_B0_018_050", "Unexisting 050"
655, 6769, "ANH_MAIN_B0_018_100", "Unexisting 100"
655, 6771, "ANH_MAIN_B0_018_101", "Unexisting 101"
655, 6774, "ANH_MAIN_B0_018_102", "Unexisting 102"
655, 6776, "ANH_MAIN_B0_018_103", "Unexisting 103"
655, 6777, "ANH_MAIN_B0_018_104", "Unexisting 104"
655, 6779, "ANH_MAIN_B0_018_105", "Unexisting 105"
655, 6782, "ANH_MAIN_B0_018_200", "Unexisting 200"
655, 6784, "ANH_MAIN_B0_018_201", "Unexisting 201"
655, 6785, "ANH_MAIN_B0_018_202", "Unexisting 202"
655, 6787, "ANH_MAIN_B0_018_210", "Unexisting 210"
655, 6789, "ANH_MAIN_B0_018_220", "Unexisting 220"
655, 6791, "ANH_MAIN_B0_018_300", "Unexisting 300"
655, 6794, "ANH_MAIN_B0_018_310", "Unexisting 310"
655, 6795, "ANH_MAIN_B0_018_400", "Unexisting 400"
655, 6797, "ANH_MAIN_B0_018_401", "Unexisting 401"
655, 6799, "ANH_MAIN_B0_018_402", "Unexisting 402"
655, 6802, "ANH_MAIN_B0_018_410", "Unexisting 410"
655, 6803, "ANH_MAIN_B0_018_420", "Unexisting 420"
655, 6805, "ANH_MAIN_B0_018_430", "Unexisting 430"
655, 6807, "ANH_MAIN_B0_018_500", "Unexisting 500"
655, 6809, "ANH_MAIN_B0_018_501", "Unexisting 501"
655, 6812, "ANH_MAIN_B0_018_600", "Unexisting 600"
// Unexisting Battle model 002
568, 12511, "ANH_MAIN_B2_003_ALL", "Unexisting All"
// Unexisting Battle model Cam
649, 14461, "ANH_MAIN_B2_CAM_011_1ST", "Unexisting 1st"
649, 14460, "ANH_MAIN_B2_CAM_011_2ND", "Unexisting 2nd"
649, 14463, "ANH_MAIN_B2_CAM_011_DOWN", "Unexisting Down"
649, 14458, "ANH_MAIN_B2_CAM_011_END", "Unexisting End"
649, 14451, "ANH_MAIN_B2_CAM_011_JUMP", "Unexisting Jump"
649, 14454, "ANH_MAIN_B2_CAM_011_OPENING", "Unexisting Opening"
649, 14455, "ANH_MAIN_B2_CAM_011_RUN", "Unexisting Run"
649, 14462, "ANM_MAIN_B2_CAM_011_1ST", "Unexisting 1st"
649, 14459, "ANM_MAIN_B2_CAM_011_2ND", "Unexisting 2nd"
649, 14464, "ANM_MAIN_B2_CAM_011_DOWN", "Unexisting Down"
649, 14457, "ANM_MAIN_B2_CAM_011_END", "Unexisting End"
649, 14452, "ANM_MAIN_B2_CAM_011_JUMP", "Unexisting Jump"
649, 14453, "ANM_MAIN_B2_CAM_011_OPENING", "Unexisting Opening"
649, 14456, "ANM_MAIN_B2_CAM_011_RUN", "Unexisting Run"
// Unexisting Battle model 001
29, 838, "ANM_MAIN_B2_001", "Unexisting 001"
// Gargant
306, 4650, "ANH_ACC_F1_GRG_B", "Unexisting B"
306, 6132, "ANH_ACC_F1_GRG_RUN_1F", "Unexisting Run_1f"
// Zidane
98, 179, "ANH_MAIN_F0_ZDN_JUMP1", "Unexisting Jump1"
// King Leo
5501, 1135, "ANH_SUB_F1_BAK_ANXIETY_3", "Unexisting Anxiety_3"
5501, 9435, "ANH_SUB_F1_BAK_B", "Unexisting B"
5501, 9154, "ANH_SUB_F1_BAK_P", "Unexisting P"
// Puck
121, 2195, "ANH_NPC_F0_RTC_SK_ANGRY", "Unexisting Sk_Angry"
121, 2192, "ANH_NPC_F0_RTC_SK_CRUSH", "Unexisting Sk_Crush"
121, 2183, "ANH_NPC_F0_RTC_SK_GET_LD", "Unexisting Sk_Get_Ld"
121, 2193, "ANH_NPC_F0_RTC_SK_GO_UP1_LD", "Unexisting Sk_Go_Up1_Ld"
121, 2194, "ANH_NPC_F0_RTC_SK_GO_UP2_LD", "Unexisting Sk_Go_Up2_Ld"
121, 2187, "ANH_NPC_F0_RTC_SK_HURRY_UP_LD","Unexisting Sk_Hurry_Up_Ld"
121, 2177, "ANH_NPC_F0_RTC_SK_IDLE", "Unexisting Sk_Idle"
121, 2184, "ANH_NPC_F0_RTC_SK_IDL_LD", "Unexisting Sk_Idl_Ld"
121, 2188, "ANH_NPC_F0_RTC_SK_LIFT_LD", "Unexisting Sk_Lift_Ld"
121, 2191, "ANH_NPC_F0_RTC_SK_PUT_LD", "Unexisting Sk_Put_Ld"
121, 2181, "ANH_NPC_F0_RTC_SK_ROGER", "Unexisting Sk_Roger"
121, 2186, "ANH_NPC_F0_RTC_SK_RUN", "Unexisting Sk_Run"
121, 2190, "ANH_NPC_F0_RTC_SK_RUN_LD", "Unexisting Sk_Run_Ld"
121, 2182, "ANH_NPC_F0_RTC_SK_TURN_", "Unexisting Sk_Turn_"
121, 2179, "ANH_NPC_F0_RTC_SK_TURN_L_LD", "Unexisting Sk_Turn_L_Ld"
121, 2185, "ANH_NPC_F0_RTC_SK_TURN_R", "Unexisting Sk_Turn_R"
121, 2180, "ANH_NPC_F0_RTC_SK_TURN_R_LD", "Unexisting Sk_Turn_R_Ld"
121, 2196, "ANH_NPC_F0_RTC_SK_WALK", "Unexisting Sk_Walk"
121, 2189, "ANH_NPC_F0_RTC_SK_WALK_LD", "Unexisting Sk_Walk_Ld"
121, 2178, "ANH_NPC_F0_RTC_SK_WHICH_LD", "Unexisting Sk_Which_Ld"
The first number is the MODEL_ID, the second number is the ANIM_ID, the "ANH_" string is the internal animation name and the last string is the description as you find it in the field script.
So, in order to import one of these animations, do like in section I, but expect for a window to popup to import the new animation. As a full name, use the following:
assets/resources/animations/[MODEL_ID]/[ANIM_ID].anim
For instance, if you have a whole new animation to Zidane, import it with the full name "assets/resources/animations/98/179.anim". Then, in the field script, you can use the animation ID 179 to refer to it (in a "RunAnimation" line for instance).
Note that:
- There are also dummied models. I guess that you can use these as well in order to import a whole new model without the need to change the engine's code. I didn't try it though.
- there are other "dummied" animations: somes are described as "Unused", meaning that they exist and are all good, but never used in the game (unless I missed something). For now, only the animations of the enemy models were spotted as "Unused" ; some animations of the field models may be unused but not flagged (I know that Steiner at least has an unused animation that I used in AF). There are also "Dummy" animations, which means one thing: it's a very quick animation consisting of only 2 frames. Most of the time ("Dummy P", "Dummy B"...), they are also unused in the sense that they are default animations that are never actually played in-game. You can replace them as well without any regrets.
II - Importing whole new animationsDo the same as in section I, but be sure to use the following when asked to import your new animations:
assets/resources/animations/[MODEL_ID]/[NEW_ANIM_ID].anim
The NEW_ANIM_ID should be some unused animation ID. I think that it's safe to use any number between 20000 and 30000.
Once you've done that, you also need to register the animation in the engine's database. In the engine's source code (available through Albeoris's Memoria tool), go in the class "FF9DBAll". There is a Dictionary definition that takes most of the class's script:
public static Dictionary<int, string> AnimationDB
In this dictionary, add the following entry:
{ [NEW_ANIM_ID], [NEW_ANIM_STRING_ID] },
The NEW_ANIM_ID is the one you've already chosen. The NEW_ANIM_STRING_ID must follow some pattern:
ANH_[MODEL_SHORT_STRING_ID]_[Anything you want that's not already used]
The MODEL_SHORT_STRING_ID is like "MAIN_ZDN" or something. You can easily retrieve it because all the animations of that same model share the same part. You can thus search for another animation ID that belongs to the same model.
III - Importing a whole new modelDo the same as in section I (in particular, don't forget to add your model's texture first). You must import the model with the GameObject type and the following full name:
assets/resources/models/[TYPE]/[NEW_MODEL_ID]/[NEW_MODEL_ID].fbx
The full names of the animations must also follow the same pattern as in section II (with your NEW_MODEL_ID instead).
The TYPE is 1, 2, 3, 4 or 5 depending on whether the model type is an Accessory, a "Main" model, an Enemy, a NPC or a "Sub" model. Main models are typically the main characters' field models. Sub models are pretty much the remains. I don't think the model type has such an importance but you should remember what is your choice.
Also, in p0data2, there's a TYPE of 6 for Weapon models.
NEW_MODEL_ID must be an unused one. You can choose it between 6000 and 10000 without problem normally.
Then, you must register the model in the engine's code. This time, it's in the class "FF9BattleDB". There's the following dictionary:
public static Dictionary<int, string> GEO
Add an entry to it:
{ [NEW_MODEL_ID], "GEO_[MODEL_SHORT_STRING_ID]" },
The MODEL_SHORT_STRING_ID must itself follow a pattern:
[TYPE_STR]_[F/B/W][VERSION]_[Anything you want that's not already used]
TYPE_STR must be either one of these depending on the chosen model's type:
ACC, MAIN, MON, NPC, SUB, WEP
F/B/W is one letter depending on whether it's supposed to be a Field model, a Battle model or a World model. It doesn't seem too strict as some Battle models are also used inside Fields.
VERSION is a 1-digit number ; I'm not sure what it corresponds to...
The tail of the string ID can be anything you want without special character.
Example:
{ 6000, "GEO_MAIN_F0_RED_DOG" },
This model's animations must use the same pattern as in section II but with the MODEL_SHORT_STRING_ID that you've chosen.
Example:
{ 20000, "ANH_MAIN_F0_RED_DOG_TALK" },
{ 20001, "ANH_MAIN_F0_RED_DOG_RUN" },
etc...
IV - Using a whole new model and/or animation in-gameNow, hopefully, everything is correctly set but if the animation or the model never appear in-game, that wasn't worth it.
If your model/animation is supposed to be used in a Field or in a World Map, you can simply edit the script of this Field/World Map in Hades Workshop and use these assets in "SetModel" or "RunAnimation" lines. You only need to have a list of the IDs next to you because new models and new animations won't appear in the drop-list menu (unless it was "Unexisting") and you need to write the ID yourself.
However, since Hades Workshop and Memoria are not compatible, you'll need to do that on a fresh backup of your game, without Memoria installed. Then, export the mod as Steam files ; it will create a p0data7.bin archive that contains the script. You may either extract the script asset out of it using the Unity Assets Viewer (in the archive p0data7, there are descriptions that should be more than enough to spot the right asset corresponding to the Field script) or, even simpler, just replace the whole p0data7.bin file of the Memoria-modded game (but it will replace all the scripts at once so it can cancel other changes if that's not the first time you replace it).
You can't use new models/animations for enemies yet. I'm also planning on enabling it for the next version.
Finally, using other animations for the party's characters is all done in the game's engine. Maybe I'll describe how to do it another day.
I didn't lie when I said it would be a wall of text