-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3 from AlphaSatanOmega/main
Updated Exporter - Auto FlatBuffers Conversion
- Loading branch information
Showing
3 changed files
with
348 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
import os | ||
import subprocess | ||
import re | ||
import json | ||
import sys | ||
import shutil | ||
import copy | ||
import time | ||
# GBFR Blender .json export to .minfo converter | ||
# Version 3.0 | ||
# By AlphaSatanOmega - https://github.com/AlphaSatanOmega | ||
# Drag and drop the original .minfo and the Blender export .json onto this .py file | ||
|
||
# Convert flatc json data string to proper json data string with quotes | ||
def preprocess_flatbuffers_json(json_data): | ||
return re.sub(r'(\w+)(?=\s*:)', r'"\1"', json_data) # Use regular expression to wrap field names in quotes | ||
|
||
def replace_mesh_info(flatc_json, blender_json): | ||
# Load json data from files | ||
flatc_json_data = json.loads(flatc_json) | ||
blender_json_data = json.loads(blender_json) | ||
|
||
# Replace the mesh info in the flatc json with the mesh info from the blender export json | ||
keys_to_replace = ["MeshBuffers", "Chunks", "VertCount", "PolyCountX3", "BufferTypes"] | ||
for lod_index in range(len(flatc_json_data["LODInfos"])): | ||
for key in keys_to_replace: | ||
flatc_json_data["LODInfos"][lod_index][key] = blender_json_data[key] | ||
# Just set the LODInfos array to contain the Highest LOD | ||
flatc_json_data["LODInfos"] = [flatc_json_data["LODInfos"][0]] | ||
|
||
# Replace the BonesToWeightIndices list with the blender export list | ||
flatc_json_data["BonesToWeightIndices"] = blender_json_data["BonesToWeightIndices"] | ||
|
||
# Submeshes | ||
# Get submesh names | ||
blender_json_submesh_names = blender_json_data["SubMeshes"] | ||
flatc_json_submesh_names = [] | ||
for flatc_submesh in flatc_json_data["SubMeshes"]: | ||
flatc_json_submesh_names.append(flatc_submesh["Name"]) | ||
# If a submesh name from blender is not in the flatc submeshes, | ||
# duplicate the last submesh and change its name to match | ||
for blender_submesh_name in blender_json_submesh_names: | ||
if blender_submesh_name not in flatc_json_submesh_names: | ||
new_submesh = copy.deepcopy(flatc_json_data["SubMeshes"][-1]) | ||
new_submesh["Name"] = blender_submesh_name | ||
flatc_json_data["SubMeshes"].append(new_submesh) | ||
|
||
return json.dumps(flatc_json_data, indent=2) # Convert and return | ||
|
||
def convert_minfo(flatc_path, minfo_path, blender_json_path): | ||
print ("Start MInfo Conversion.") | ||
|
||
if os.path.dirname(minfo_path) != os.path.dirname(blender_json_path): | ||
raise Exception("\n\nERROR: A copy of the .minfo needs to be in same location as you are exporting to.") | ||
|
||
script_dir = os.path.dirname(__file__) # Get the script directory | ||
export_dir = os.path.dirname(blender_json_path) # Get blender export directory | ||
flatc_temp_dir = os.path.join(export_dir, "_flatc_temp") | ||
minfo_fbs_path = os.path.join(script_dir,"MInfo_ModelInfo.fbs") # Get the FlatBuffers Schema | ||
# flatc_path = os.path.join(script_dir, "flatc.exe") # Get the path to flatc.exe in the same directory | ||
model_name = os.path.splitext(os.path.basename(minfo_path))[0] # Get the model name from the minfo | ||
|
||
# Generate json from .minfo file using flatc.exe | ||
|
||
print(flatc_path, "-o", f"{flatc_temp_dir}", "--json", f"{minfo_fbs_path}", "--", f"{minfo_path}", "--raw-binary") | ||
|
||
command = [flatc_path, "-o", f"{flatc_temp_dir}", "--json", f"{minfo_fbs_path}", "--", f"{minfo_path}", "--raw-binary"] | ||
subprocess.run(command, check=True) | ||
# flatc json gets stored to a temp folder | ||
flatc_json_path = os.path.join(flatc_temp_dir, f"{model_name}.json") | ||
print(f"Generated: {flatc_json_path}") | ||
|
||
# Open the json files | ||
with open(flatc_json_path, 'r') as flatc_file, open(blender_json_path, 'r') as blender_file: | ||
flatc_json = flatc_file.read() | ||
blender_json = blender_file.read() | ||
flatc_json = preprocess_flatbuffers_json(flatc_json) # Fix flatc json | ||
|
||
# Replace the mesh info of flatc json with blender export json's mesh info | ||
modified_flatc_json = replace_mesh_info(flatc_json, blender_json) | ||
# print(modified_flatc_json) | ||
# Save modified flatc to a file in the same directory as the script | ||
# os.path.join(export_dir, f"{model_name}.json") | ||
modified_flatc_json_file = blender_json_path # Overwrite blender json file | ||
with open(modified_flatc_json_file, 'w') as file: | ||
file.write(modified_flatc_json) | ||
print(f"Replaced mesh info in {flatc_json_path} with mesh info from {minfo_path}") | ||
|
||
# Create output directory next to original .minfo | ||
output_dir = os.path.join(os.path.dirname(minfo_path), "_Exported_MInfo") | ||
os.makedirs(output_dir, exist_ok=True) | ||
|
||
# Run flatc.exe to generate binary minfo from the modified json | ||
command = [flatc_path, "-o", f"{flatc_temp_dir}", "--binary", f"{minfo_fbs_path}", modified_flatc_json_file] | ||
subprocess.run(command, check=True) | ||
# Rename the .bin otuput to .minfo | ||
binary_output_file = os.path.join(flatc_temp_dir, f"{model_name}.bin") | ||
minfo_output_file = binary_output_file.replace(".bin", '.minfo') | ||
os.rename(binary_output_file, minfo_output_file) | ||
print(f"Modified {minfo_output_file} generated.") | ||
# Move minfo to output_dir | ||
try: os.remove(os.path.join(output_dir, f"{model_name}.minfo")) # Remove copy if exists | ||
except: print(f"No copy of {model_name}.minfo found in {output_dir}, moving.") | ||
shutil.move(minfo_output_file, output_dir) | ||
|
||
# Move all the Blender export files into the output_dir | ||
blender_export_file_exts = [".mmesh", ".skeleton", ".json"] | ||
for file_ext in blender_export_file_exts: | ||
original_file_path = os.path.join(export_dir, f"{model_name}{file_ext}") | ||
try: os.remove(os.path.join(output_dir, f"{model_name}{file_ext}")) # Remove copy if exists | ||
except Exception as e: | ||
print(str(e)) | ||
print(f"No copy of {model_name}{file_ext} found in {output_dir}, moving.") | ||
shutil.move(original_file_path, output_dir) | ||
|
||
# Remove _flatc_temp safely | ||
os.remove(os.path.join(flatc_temp_dir, f"{model_name}.json")) # Remove json first | ||
os.rmdir(flatc_temp_dir) # Then delete the folder since it should be empty, fails otherwise | ||
print(f"Removed {flatc_temp_dir}") | ||
|
||
print(f"Modified JSON and binary files moved to: {output_dir}") | ||
|
||
|
||
def main(): | ||
input_file_1 = sys.argv[1] | ||
input_file_2 = sys.argv[2] | ||
# Check which file is the .minfo and which is the .json | ||
if input_file_1.lower().endswith('.minfo') and input_file_2.lower().endswith('.json'): | ||
minfo_path = input_file_1 | ||
blender_json_path = input_file_2 | ||
elif input_file_1.lower().endswith('.json') and input_file_2.lower().endswith('.minfo'): | ||
minfo_path = input_file_2 | ||
blender_json_path = input_file_1 | ||
else: | ||
print("Error: Incorrect files input. The inputs should be an .minfo and a .json file.") | ||
# print(minfo_path, blender_json_path) | ||
|
||
# Process the files | ||
try: | ||
convert_minfo(minfo_path, blender_json_path) | ||
print("\nConversion Complete!") | ||
except Exception as e: | ||
print(str(e)) | ||
|
||
if __name__ == "__main__": | ||
main() | ||
input("\nPress any key to exit...") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
// all FlatSharp FBS attributes start with the 'fs_' prefix. | ||
attribute "fs_serializer"; | ||
|
||
namespace GBFRDataTools.Entities; | ||
|
||
// Main Root Table | ||
table ModelInfo (fs_serializer) { | ||
Magic:uint; // 0x134B249 | ||
LODInfos:[LODInfo]; | ||
LODInfos2:[LODInfo]; | ||
A4:[float]; | ||
SubMeshes:[SubMeshInfo]; | ||
Materials:[Material]; | ||
BonesToWeightIndices:[ushort]; | ||
DeformBoneBoundaryBox:[BoundaryBox]; | ||
A9:Vec4; | ||
A10:ModelInfo_A10; // Used very rarely in bgXXXX files | ||
A11:ModelInfo_A11; | ||
A12:float; | ||
A13:float; | ||
A14:float; | ||
A15:float; | ||
A16:float; | ||
A17:float; | ||
A18:float; | ||
A19:float; | ||
A20:float; | ||
A21:byte; | ||
A22:byte; | ||
// Many of these may just be bools | ||
A23:byte; | ||
A24:byte; | ||
A25:byte; | ||
A26:byte; | ||
A27:byte; | ||
A28:byte; | ||
A29:byte; | ||
A30:byte; | ||
A31:byte; | ||
A32:byte; | ||
} | ||
|
||
table LODInfo | ||
{ | ||
MeshBuffers:[MeshBufferLocator]; | ||
Chunks:[LODChunk]; | ||
VertCount:int; | ||
PolyCountX3:int; | ||
BufferTypes:byte; | ||
A6:byte; | ||
} | ||
|
||
table SubMeshInfo | ||
{ | ||
Name:string; | ||
BBox:BoundaryBox; | ||
} | ||
|
||
table Material | ||
{ | ||
Hash:uint; | ||
Unk:byte; | ||
} | ||
|
||
table ModelInfo_A10 | ||
{ | ||
UnkID:uint; // Not always present | ||
A2:float; | ||
A3:byte; | ||
A4:byte; | ||
} | ||
|
||
///////////////// | ||
// Util structs | ||
///////////////// | ||
struct MeshBufferLocator | ||
{ | ||
Offset:ulong; | ||
Size:ulong; | ||
} | ||
|
||
struct LODChunk | ||
{ | ||
Offset:int; | ||
Count:int; | ||
SubMeshID:byte; | ||
MaterialID:byte; | ||
Unk1:byte; | ||
Unk2:byte; | ||
} | ||
|
||
struct Vec3 { | ||
x:float; | ||
y:float; | ||
z:float; | ||
} | ||
|
||
struct Vec4 { | ||
x:float; | ||
y:float; | ||
z:float; | ||
r:float; | ||
} | ||
|
||
struct BoundaryBox { | ||
Min:Vec3; | ||
Max:Vec3; | ||
} | ||
|
||
struct ModelInfo_A11 | ||
{ | ||
// Maybe just 7 floats instead | ||
A1:int; | ||
A2:Vec3; | ||
A3:Vec3; | ||
} | ||
|
||
root_type ModelInfo; |
Oops, something went wrong.