import unreal as u,json,math,time from pathlib import Path ROOT=Path(__file__).resolve().parents[3];DATA=json.loads((ROOT/'transfer/homestead-manifest.json').read_text());LIB=u.EditorAssetLibrary;MAT=u.MaterialEditingLibrary;TOOLS=u.AssetToolsHelpers.get_asset_tools();ACT=u.get_editor_subsystem(u.EditorActorSubsystem);LEVEL=u.get_editor_subsystem(u.LevelEditorSubsystem) u.EditorPythonScripting.set_keep_python_script_alive(True) def prop(o,k,v):o.set_editor_property(k,v) def log(s):u.log('HOMESTEAD: '+s) def imp(file,dest,options=None): t=u.AssetImportTask() for k,v in dict(filename=str(file),destination_path=dest,automated=True,replace_existing=True,save=True).items():prop(t,k,v) if options:prop(t,'options',options) TOOLS.import_asset_tasks([t]);return [LIB.load_asset(p) for p in t.imported_object_paths] def scalar(m,n,out): a=MAT.create_material_expression(m,u.MaterialExpressionConstant);prop(a,'r',n);MAT.connect_material_property(a,'',out) def material(name,r): path='/Game/Homestead/Materials';m=LIB.load_asset(path+'/'+name) or TOOLS.create_asset(name,path,u.Material,u.MaterialFactoryNew());MAT.delete_all_material_expressions(m);prop(m,'two_sided',True) if r.get('base_color_texture'): tex=imp(ROOT/'transfer'/r['base_color_texture'],'/Game/Homestead/Textures')[0];a=MAT.create_material_expression(m,u.MaterialExpressionTextureSample);prop(a,'texture',tex);out='RGB' else: a=MAT.create_material_expression(m,u.MaterialExpressionConstant3Vector);prop(a,'constant',u.LinearColor(*r['base_color']));out='' MAT.connect_material_property(a,out,u.MaterialProperty.MP_BASE_COLOR) if r.get('normal_texture'): tex=imp(ROOT/'transfer'/r['normal_texture'],'/Game/Homestead/Textures')[0];prop(tex,'compression_settings',u.TextureCompressionSettings.TC_NORMALMAP);prop(tex,'srgb',False);prop(tex,'flip_green_channel',True);LIB.save_loaded_asset(tex);a=MAT.create_material_expression(m,u.MaterialExpressionTextureSample);prop(a,'texture',tex);prop(a,'sampler_type',u.MaterialSamplerType.SAMPLERTYPE_NORMAL);MAT.connect_material_property(a,'RGB',u.MaterialProperty.MP_NORMAL) scalar(m,r['roughness'],u.MaterialProperty.MP_ROUGHNESS);scalar(m,r['metallic'],u.MaterialProperty.MP_METALLIC) if r.get('transmission',0)>0 or 'translucent footprint' in r['source']: prop(m,'blend_mode',u.BlendMode.BLEND_TRANSLUCENT);scalar(m,.13,u.MaterialProperty.MP_OPACITY) if r.get('emission',0)>0: a=MAT.create_material_expression(m,u.MaterialExpressionConstant3Vector);prop(a,'constant',u.LinearColor(*[v*r['emission'] for v in r['base_color'][:3]],1));MAT.connect_material_property(a,'',u.MaterialProperty.MP_EMISSIVE_COLOR) MAT.recompile_material(m);LIB.save_loaded_asset(m);return m materials={n:(LIB.load_asset('/Game/Homestead/Materials/'+n) if LIB.does_asset_exist('/Game/Homestead/Materials/'+n) else material(n,r)) for n,r in DATA['materials'].items()};log('Materials saved') opts=u.FbxImportUI() for k,v in dict(import_mesh=True,import_materials=False,import_textures=False,import_as_skeletal=False,import_animations=False,mesh_type_to_import=u.FBXImportType.FBXIT_STATIC_MESH).items():prop(opts,k,v) for k,v in dict(combine_meshes=False,auto_generate_collision=False,generate_lightmap_u_vs=False,convert_scene=True,force_front_x_axis=False).items():prop(opts.static_mesh_import_data,k,v) if len(LIB.list_assets('/Game/Homestead/Meshes',recursive=True))!=len(DATA['objects']):imp(ROOT/'transfer/SamfordHomestead.fbx','/Game/Homestead/Meshes',opts) meshes=[LIB.load_asset(p) for p in LIB.list_assets('/Game/Homestead/Meshes',recursive=True)];meshes=[m for m in meshes if isinstance(m,u.StaticMesh)];assert len(meshes)==len(DATA['objects']),(len(meshes),len(DATA['objects'])) LEVEL.new_level('/Game/Homestead/SamfordHomestead');records={r['name']:r for r in DATA['objects']};collision_meshes=0 for mesh in meshes: rec=records[mesh.get_name().removeprefix('SamfordHomestead_')];mesh.set_material(0,materials[rec['material']]);body=mesh.get_editor_property('body_setup') if rec['collision']: prop(body,'collision_trace_flag',u.CollisionTraceFlag.CTF_USE_COMPLEX_AS_SIMPLE);prop(body,'double_sided_geometry',True);u.get_editor_subsystem(u.StaticMeshEditorSubsystem).enable_section_collision(mesh,True,0,0);collision_meshes+=1 actor=ACT.spawn_actor_from_class(u.StaticMeshActor,u.Vector(0,0,0));actor.static_mesh_component.set_static_mesh(mesh);actor.set_actor_label(mesh.get_name());actor.set_folder_path(rec['category']);actor.static_mesh_component.set_collision_profile_name('BlockAll' if rec['collision'] else 'NoCollision');LIB.save_loaded_asset(mesh) # Check known main-floor origin and all coordinate units from FBX bounds. main=next(m for m in meshes if '01_Living' in m.get_name() and 'concrete' in records[m.get_name().removeprefix('SamfordHomestead_')]['material'].lower());b=main.get_bounds();assert abs(b.origin.x)<5 and abs(b.origin.y)<5 and 50