оптимизация рендера
This commit is contained in:
@@ -17,6 +17,9 @@
|
||||
# Offline WMO scene cache
|
||||
/data/cache/wmo_tscn/
|
||||
|
||||
# Offline WMO render cache
|
||||
/data/cache/wmo_render_v1/
|
||||
|
||||
# Root cache dir (генерируется скриптом)
|
||||
/cache/
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ const USE_GEOMETRY_NORMALS := true
|
||||
static var _terrain_shader: Shader
|
||||
static var _single_texture_shader: Shader
|
||||
static var _empty_alpha_texture: Texture2D
|
||||
static var _native_adt_baker: Object
|
||||
static var _fallback_material: StandardMaterial3D
|
||||
static var _single_texture_material_cache: Dictionary = {}
|
||||
static var _baked_texture_material_cache: Dictionary = {}
|
||||
@@ -109,6 +110,24 @@ static func build_baked_tile_render_payload(
|
||||
return _build_baked_tile_payload(data, image_cache, extracted_dir, lod, texture_size)
|
||||
|
||||
|
||||
static func build_baked_tile_render_payload_pair(
|
||||
data: Dictionary,
|
||||
image_cache: Dictionary,
|
||||
extracted_dir: String = "",
|
||||
full_lod: int = 0,
|
||||
full_texture_size: int = 2048,
|
||||
coarse_lod: int = 3,
|
||||
coarse_texture_size: int = 512) -> Dictionary:
|
||||
return _build_baked_tile_payload_pair(
|
||||
data,
|
||||
image_cache,
|
||||
extracted_dir,
|
||||
full_lod,
|
||||
full_texture_size,
|
||||
coarse_lod,
|
||||
coarse_texture_size)
|
||||
|
||||
|
||||
static func get_tile_origin(data: Dictionary) -> Vector3:
|
||||
var found := false
|
||||
var min_x := 0.0
|
||||
@@ -441,6 +460,48 @@ static func _build_baked_tile_payload(
|
||||
lod: int,
|
||||
texture_size: int) -> Dictionary:
|
||||
|
||||
var payload := _build_baked_tile_geometry_payload(data, lod)
|
||||
if payload.is_empty():
|
||||
return {}
|
||||
|
||||
var baked_image := _build_tile_baked_albedo(data, image_cache, extracted_dir, texture_size)
|
||||
_apply_baked_albedo_material(payload.get("mesh", null), baked_image)
|
||||
return payload
|
||||
|
||||
|
||||
static func _build_baked_tile_payload_pair(
|
||||
data: Dictionary,
|
||||
image_cache: Dictionary,
|
||||
extracted_dir: String,
|
||||
full_lod: int,
|
||||
full_texture_size: int,
|
||||
coarse_lod: int,
|
||||
coarse_texture_size: int) -> Dictionary:
|
||||
|
||||
var full_payload := _build_baked_tile_geometry_payload(data, full_lod)
|
||||
if full_payload.is_empty():
|
||||
return {}
|
||||
|
||||
var coarse_payload := _build_baked_tile_geometry_payload(data, coarse_lod)
|
||||
var full_image := _build_tile_baked_albedo(data, image_cache, extracted_dir, full_texture_size)
|
||||
var coarse_image: Image = null
|
||||
if full_image != null:
|
||||
coarse_image = full_image.duplicate()
|
||||
var coarse_size := _get_baked_albedo_size(coarse_texture_size)
|
||||
if coarse_image.get_width() != coarse_size or coarse_image.get_height() != coarse_size:
|
||||
coarse_image.resize(coarse_size, coarse_size, Image.INTERPOLATE_BILINEAR)
|
||||
|
||||
_apply_baked_albedo_material(full_payload.get("mesh", null), full_image)
|
||||
if not coarse_payload.is_empty():
|
||||
_apply_baked_albedo_material(coarse_payload.get("mesh", null), coarse_image)
|
||||
|
||||
return {
|
||||
"full": full_payload,
|
||||
"coarse": coarse_payload,
|
||||
}
|
||||
|
||||
|
||||
static func _build_baked_tile_geometry_payload(data: Dictionary, lod: int) -> Dictionary:
|
||||
var tile_origin := get_tile_origin(data)
|
||||
var verts := PackedVector3Array()
|
||||
var nrms := PackedVector3Array()
|
||||
@@ -491,7 +552,16 @@ static func _build_baked_tile_payload(
|
||||
var mesh := ArrayMesh.new()
|
||||
mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays)
|
||||
|
||||
var baked_image := _build_tile_baked_albedo(data, image_cache, extracted_dir, texture_size)
|
||||
return {
|
||||
"mesh": mesh,
|
||||
"position": Vector3.ZERO,
|
||||
"name": "TileLOD%d" % lod,
|
||||
}
|
||||
|
||||
|
||||
static func _apply_baked_albedo_material(mesh: Mesh, baked_image: Image) -> void:
|
||||
if mesh == null:
|
||||
return
|
||||
if baked_image:
|
||||
baked_image.generate_mipmaps()
|
||||
var baked_texture := ImageTexture.create_from_image(baked_image)
|
||||
@@ -499,12 +569,6 @@ static func _build_baked_tile_payload(
|
||||
else:
|
||||
mesh.surface_set_material(0, _build_fallback_material())
|
||||
|
||||
return {
|
||||
"mesh": mesh,
|
||||
"position": Vector3.ZERO,
|
||||
"name": "TileLOD%d" % lod,
|
||||
}
|
||||
|
||||
|
||||
static func _build_mesh_instance_from_payload(payload: Dictionary) -> MeshInstance3D:
|
||||
if payload.is_empty():
|
||||
@@ -881,7 +945,15 @@ static func _build_tile_baked_albedo(
|
||||
extracted_dir: String,
|
||||
texture_size: int) -> Image:
|
||||
|
||||
var chunk_pixels := maxi(8, int(ceil(float(maxi(texture_size, 16)) / 16.0)))
|
||||
var native_image := _build_tile_baked_albedo_native(
|
||||
data,
|
||||
image_cache,
|
||||
extracted_dir,
|
||||
texture_size)
|
||||
if native_image != null:
|
||||
return native_image
|
||||
|
||||
var chunk_pixels := int(_get_baked_albedo_size(texture_size) / 16)
|
||||
var size := chunk_pixels * 16
|
||||
var image := Image.create(size, size, false, Image.FORMAT_RGB8)
|
||||
image.fill(Color(0.4, 0.55, 0.3))
|
||||
@@ -914,6 +986,30 @@ static func _build_tile_baked_albedo(
|
||||
return image
|
||||
|
||||
|
||||
static func _build_tile_baked_albedo_native(
|
||||
data: Dictionary,
|
||||
image_cache: Dictionary,
|
||||
extracted_dir: String,
|
||||
texture_size: int) -> Image:
|
||||
|
||||
if not ClassDB.class_exists("ADTBaker"):
|
||||
return null
|
||||
if _native_adt_baker == null:
|
||||
_native_adt_baker = ClassDB.instantiate("ADTBaker")
|
||||
if _native_adt_baker == null:
|
||||
return null
|
||||
return _native_adt_baker.call(
|
||||
"bake_tile_albedo",
|
||||
data,
|
||||
image_cache,
|
||||
extracted_dir,
|
||||
texture_size) as Image
|
||||
|
||||
|
||||
static func _get_baked_albedo_size(texture_size: int) -> int:
|
||||
return maxi(8, int(ceil(float(maxi(texture_size, 16)) / 16.0))) * 16
|
||||
|
||||
|
||||
static func _sample_chunk_baked_albedo(
|
||||
chunk: Dictionary,
|
||||
tex_names: PackedStringArray,
|
||||
@@ -1110,6 +1206,7 @@ static func _load_texture(
|
||||
cache[blp_path] = null
|
||||
return null
|
||||
|
||||
img.generate_mipmaps()
|
||||
var tex := ImageTexture.create_from_image(img)
|
||||
cache[blp_path] = tex
|
||||
return tex
|
||||
|
||||
@@ -7,6 +7,8 @@ class_name WMOBuilder
|
||||
|
||||
const M2_BUILDER_SCRIPT := preload("res://addons/mpq_extractor/loaders/m2_builder.gd")
|
||||
const M2_RIGHT_YAW_OFFSET := PI * 0.5
|
||||
const BUILD_OCCLUDERS := false
|
||||
const OCCLUDER_MIN_TRIANGLES := 16
|
||||
|
||||
static var _texture_cache: Dictionary = {}
|
||||
# rel_path → Node3D prototype (built once, duplicated per usage)
|
||||
@@ -45,6 +47,7 @@ static func build(data: Dictionary, extracted_dir: String = "") -> Node3D:
|
||||
|
||||
# Build one MeshInstance3D per group, plus optional liquid mesh as sibling
|
||||
var groups: Array = data.get("groups", [])
|
||||
var occluder_root: Node3D = null
|
||||
for gi in groups.size():
|
||||
var g: Dictionary = groups[gi]
|
||||
if g.is_empty():
|
||||
@@ -53,6 +56,16 @@ static func build(data: Dictionary, extracted_dir: String = "") -> Node3D:
|
||||
mesh_inst.name = "Group_%d" % gi
|
||||
root.add_child(mesh_inst)
|
||||
|
||||
if BUILD_OCCLUDERS:
|
||||
var occluder_inst := _build_group_occluder(g, materials)
|
||||
if occluder_inst != null:
|
||||
if occluder_root == null:
|
||||
occluder_root = Node3D.new()
|
||||
occluder_root.name = "Occluders"
|
||||
root.add_child(occluder_root)
|
||||
occluder_inst.name = "Group_%d_Occluder" % gi
|
||||
occluder_root.add_child(occluder_inst)
|
||||
|
||||
var liquid_dict: Variant = g.get("liquid", null)
|
||||
if liquid_dict is Dictionary and not (liquid_dict as Dictionary).is_empty():
|
||||
var liquid_inst := _build_group_liquid(liquid_dict)
|
||||
@@ -67,8 +80,7 @@ static func build(data: Dictionary, extracted_dir: String = "") -> Node3D:
|
||||
return root
|
||||
|
||||
|
||||
# Instantiates M2 doodads for set 0. Each placement is a M2 prototype
|
||||
# duplicated under the WMO root with a local Transform3D.
|
||||
# Instantiates M2 doodads for set 0 as one MultiMesh per M2 path.
|
||||
static func _build_default_doodads(root: Node3D, data: Dictionary,
|
||||
extracted_dir: String) -> void:
|
||||
|
||||
@@ -83,10 +95,7 @@ static func _build_default_doodads(root: Node3D, data: Dictionary,
|
||||
if count <= 0:
|
||||
return
|
||||
|
||||
var doodad_root := Node3D.new()
|
||||
doodad_root.name = "Doodads"
|
||||
root.add_child(doodad_root)
|
||||
|
||||
var groups: Dictionary = {}
|
||||
var end: int = mini(start + count, placements.size())
|
||||
for i in range(start, end):
|
||||
var p: Dictionary = placements[i]
|
||||
@@ -97,22 +106,53 @@ static func _build_default_doodads(root: Node3D, data: Dictionary,
|
||||
if rel_path.ends_with(".mdx") or rel_path.ends_with(".mdl"):
|
||||
rel_path = rel_path.get_basename() + ".m2"
|
||||
|
||||
var prototype: Node3D = _get_or_load_m2_prototype(rel_path, extracted_dir)
|
||||
if prototype == null:
|
||||
continue
|
||||
|
||||
var inst := prototype.duplicate() as Node3D
|
||||
if inst == null:
|
||||
continue
|
||||
inst.name = "%s_%d" % [rel_path.get_file().get_basename(), i]
|
||||
|
||||
var pos: Vector3 = p.get("pos", Vector3.ZERO)
|
||||
var rot_q: Quaternion = p.get("rot", Quaternion.IDENTITY)
|
||||
var scl: float = float(p.get("scale", 1.0))
|
||||
var basis := (Basis(rot_q) * Basis(Vector3.UP, M2_RIGHT_YAW_OFFSET)).scaled(Vector3.ONE * maxf(scl, 0.001))
|
||||
inst.transform = Transform3D(basis, pos)
|
||||
var xform := Transform3D(basis, pos)
|
||||
if not groups.has(rel_path):
|
||||
groups[rel_path] = []
|
||||
(groups[rel_path] as Array).append(xform)
|
||||
|
||||
if groups.is_empty():
|
||||
return
|
||||
|
||||
var doodad_root := Node3D.new()
|
||||
doodad_root.name = "Doodads"
|
||||
root.add_child(doodad_root)
|
||||
|
||||
for rel_path in groups.keys():
|
||||
var mesh := _get_or_load_m2_mesh(rel_path, extracted_dir)
|
||||
if mesh == null:
|
||||
continue
|
||||
var transforms: Array = groups[rel_path]
|
||||
var mm := MultiMesh.new()
|
||||
mm.transform_format = MultiMesh.TRANSFORM_3D
|
||||
mm.mesh = mesh
|
||||
mm.instance_count = transforms.size()
|
||||
for i in transforms.size():
|
||||
mm.set_instance_transform(i, transforms[i])
|
||||
|
||||
var inst := MultiMeshInstance3D.new()
|
||||
inst.name = rel_path.get_file().get_basename()
|
||||
inst.multimesh = mm
|
||||
inst.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF
|
||||
doodad_root.add_child(inst)
|
||||
|
||||
if doodad_root.get_child_count() == 0:
|
||||
doodad_root.queue_free()
|
||||
|
||||
|
||||
static func _get_or_load_m2_mesh(rel_path: String, extracted_dir: String) -> Mesh:
|
||||
var prototype: Node3D = _get_or_load_m2_prototype(rel_path, extracted_dir)
|
||||
if prototype == null:
|
||||
return null
|
||||
for child in prototype.get_children():
|
||||
if child is MeshInstance3D:
|
||||
return (child as MeshInstance3D).mesh
|
||||
return null
|
||||
|
||||
|
||||
static func _get_or_load_m2_prototype(rel_path: String,
|
||||
extracted_dir: String) -> Node3D:
|
||||
@@ -178,6 +218,7 @@ static func _build_group_mesh(
|
||||
if verts.is_empty() or indices.is_empty():
|
||||
var empty := MeshInstance3D.new()
|
||||
empty.mesh = mesh
|
||||
empty.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF
|
||||
return empty
|
||||
|
||||
if batches.is_empty():
|
||||
@@ -227,9 +268,65 @@ static func _build_group_mesh(
|
||||
|
||||
var mi := MeshInstance3D.new()
|
||||
mi.mesh = mesh
|
||||
mi.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF
|
||||
return mi
|
||||
|
||||
|
||||
static func _build_group_occluder(g: Dictionary, material_defs: Array) -> OccluderInstance3D:
|
||||
var verts: PackedVector3Array = g.get("vertices", PackedVector3Array())
|
||||
var indices: PackedInt32Array = g.get("indices", PackedInt32Array())
|
||||
if verts.is_empty() or indices.is_empty():
|
||||
return null
|
||||
|
||||
var batches: Array = g.get("batches", [])
|
||||
var occluder_indices := PackedInt32Array()
|
||||
if batches.is_empty():
|
||||
for i in range(0, indices.size(), 3):
|
||||
if i + 2 >= indices.size():
|
||||
break
|
||||
occluder_indices.append(indices[i + 0])
|
||||
occluder_indices.append(indices[i + 2])
|
||||
occluder_indices.append(indices[i + 1])
|
||||
else:
|
||||
for batch_variant in batches:
|
||||
if not (batch_variant is Dictionary):
|
||||
continue
|
||||
var batch: Dictionary = batch_variant
|
||||
if not _material_can_occlude(int(batch.get("material_id", -1)), material_defs):
|
||||
continue
|
||||
var idx_start: int = int(batch.get("index_start", 0))
|
||||
var idx_count: int = int(batch.get("index_count", 0))
|
||||
if idx_count <= 0 or idx_start >= indices.size():
|
||||
continue
|
||||
for i in range(idx_start, mini(idx_start + idx_count, indices.size()), 3):
|
||||
if i + 2 >= indices.size():
|
||||
break
|
||||
occluder_indices.append(indices[i + 0])
|
||||
occluder_indices.append(indices[i + 2])
|
||||
occluder_indices.append(indices[i + 1])
|
||||
|
||||
if occluder_indices.size() < OCCLUDER_MIN_TRIANGLES * 3:
|
||||
return null
|
||||
|
||||
var occluder := ArrayOccluder3D.new()
|
||||
occluder.set_arrays(verts, occluder_indices)
|
||||
|
||||
var inst := OccluderInstance3D.new()
|
||||
inst.set_occluder(occluder)
|
||||
return inst
|
||||
|
||||
|
||||
static func _material_can_occlude(mat_id: int, material_defs: Array) -> bool:
|
||||
if mat_id < 0:
|
||||
return true
|
||||
if mat_id >= material_defs.size():
|
||||
return false
|
||||
var mat_def: Variant = material_defs[mat_id]
|
||||
if not (mat_def is Dictionary):
|
||||
return false
|
||||
return int((mat_def as Dictionary).get("blend_mode", 0)) == 0
|
||||
|
||||
|
||||
static func _build_material(
|
||||
mat_def: Dictionary,
|
||||
textures: PackedStringArray,
|
||||
@@ -342,6 +439,7 @@ static func _build_group_liquid(liquid: Dictionary) -> MeshInstance3D:
|
||||
|
||||
var mi := MeshInstance3D.new()
|
||||
mi.mesh = mesh
|
||||
mi.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF
|
||||
return mi
|
||||
|
||||
|
||||
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
@@ -0,0 +1,410 @@
|
||||
Godot Engine v4.6.1.stable.official.14d19694e - https://godotengine.org
|
||||
|
||||
Scanning ADT tiles...
|
||||
Found 368 unique WMO models from 687 tiles.
|
||||
WMOLoader: loaded 6 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_shipwreck/transport_shipwreck.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/collidabledoodads/darkshore/wreckedelvendestroyer/elvendestroyerwreckback.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/collidabledoodads/darkshore/wreckedelvendestroyer/elvendestroyerwreckfront.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/guardtower/guardtower.wmo
|
||||
WMOLoader: loaded 6 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/duskwoodabandoned_humantwostory/duskwoodabandoned_humantwostory.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/chapel/duskwoodchapel.wmo
|
||||
WMOLoader: loaded 12 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_spidermine/md_spidermine_nokobolds.wmo
|
||||
WMOLoader: loaded 5 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_cryptonerm/md_cryptonerm.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/duskwoodabandoned_human_farm/duskwoodabandoned_human_farm.wmo
|
||||
WMOLoader: loaded 12 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_spidermine/md_spidermine.wmo
|
||||
[10/368] baked=10 skipped=0 failed=0
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_shipwreck/shipwreck_a.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/duskwood_human_farm/duskwood_human_farm.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/duskwood_stable/duskwood_stable.wmo
|
||||
WMOLoader: loaded 11 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/duskwood_inn/duskwood_inn.wmo
|
||||
WMOLoader: loaded 10 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/ld_shadowfang/ld_shadowfang.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/buildings/greatwall/greatwall_wall_04.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/buildings/greatwall/greatwall_gate.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/stormwind/sw_harbor_lighthouse.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_shipwreck/shipwreck_b.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/westfall_human_farm_burnt/westfallfarmhouseburnt.wmo
|
||||
[20/368] baked=20 skipped=0 failed=0
|
||||
WMOLoader: loaded 8 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_mountaincave/md_mountaincave_medium.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/human_barn_silo/silo.wmo
|
||||
WMOLoader: loaded 3 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/westfall_barn/westfall_barn.wmo
|
||||
WMOLoader: loaded 38 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/az_deadmines/az_deadmines_a.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/collidable doodads/wetlands/wetlandshumandock01/wetlandshumandock01.wmo
|
||||
WMOLoader: loaded 9 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/az_deadmines/az_deadmines_c.wmo
|
||||
WMOLoader: loaded 3 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/duskwoodabandoned_barn/duskwoodabandoned_barn.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/collidable doodads/westfall/westfallgrainsilo01/westfallgrainsilo01.wmo
|
||||
WMOLoader: loaded 6 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/duskwood_humantwostory/duskwood_humantwostory.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/duskwoodabandoned_blacksmith/duskwoodabandoned_blacksmith.wmo
|
||||
[30/368] baked=30 skipped=0 failed=0
|
||||
WMOLoader: loaded 3 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/duskwood_barn/duskwood_barn.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/collidable doodads/duskwood/chasmbridge/duskwoodchasmbridge.wmo
|
||||
WMOLoader: loaded 5 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_goldmine/md_goldmine_1room.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/duskwood_blacksmith/duskwood_blacksmith.wmo
|
||||
WMOLoader: loaded 5 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/duskwood_townhall_nowall/duskwood_townhall_nowall.wmo
|
||||
WMOLoader: loaded 27 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/kz_gnomeragon/kz_gnomeragon.wmo
|
||||
WMOLoader: loaded 286 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/stormwind/stormwind.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/keepwall/wallpiece01.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/keepwall/wallpost01.wmo
|
||||
WMOLoader: loaded 4 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/transports/transport_ship/transportship.wmo
|
||||
[40/368] baked=40 skipped=0 failed=0
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/stormwind/sw_harbor_lowmain.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/stormwind/sw_harbor_lowstair.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/stormwind/sw_harbor_lowtwr.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/stormwind/sw_harbor_shipshelter.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/stormwind/sw_harbor_docks.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/stormwind/sw_harbor_lowstr.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/northrend/buildings/human/icebreaker/transport_icebreaker_ship_nomasts.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/stormwind/stormwindhangar.wmo
|
||||
WMOLoader: loaded 10 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_goldmine/md_goldmine.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/westfall_human_farm/westfall_human_farm.wmo
|
||||
[50/368] baked=50 skipped=0 failed=0
|
||||
WMOLoader: loaded 6 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/westfall_humantwostory/westfall_humantwostory.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/moonbrook_human_farm/moonbrook_human_farm.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/westfall_stable/westfall_stable.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/westfall_lumbermill/westfall_lumbermill.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/prison_camp/prisonlonghouse.wmo
|
||||
WMOLoader: loaded 6 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/moonbrook_humantwostory/moonbrook_humantwostory.wmo
|
||||
WMOLoader: loaded 11 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/moonbrook_inn/moonbrook_inn.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/moonbrook_blacksmith/moonbrook_blacksmith.wmo
|
||||
WMOLoader: loaded 5 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/moonbrook_townhall_nowall/moonbrook_townhall_nowall.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/buildings/greatwall/greatwall_tower_01.wmo
|
||||
[60/368] baked=60 skipped=0 failed=0
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/collidable doodads/swampofsorrows/swampdock01/swampdock01.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/buildings/trollshop/trollshop01.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/collidable doodads/swampofsorrows/swampbridge01/swampbridge01.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/buildings/trollshoppingmall/trollshoppingmall01.wmo
|
||||
WMOLoader: loaded 10 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_crypt/md_crypt.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/collidable doodads/duskwood/coveredbridge/duskwoodcoveredbridge.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/guardtower_ruined/ruinedhumanguardtower01.wmo
|
||||
WMOLoader: loaded 206 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/lorderon/undercity/undercity.wmo
|
||||
WMOLoader: loaded 26 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/duskwood_barracks/duskwood_barracks.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/lorderon/buildings/tirisfalglade/fenriskeep/fenriskeep.wmo
|
||||
[70/368] baked=70 skipped=0 failed=0
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/duskwood_human_farm_burnt/duskwoodfarmhouseburnt.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/duskwoodabandoned_lumbermill/duskwoodabandoned_lumbermill.wmo
|
||||
WMOLoader: loaded 5 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/duskwood_townhall/duskwood_townhall.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/gnomehut/gnomehut.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/collidabledoodads/stonetalon/landingpad/landingpad01.wmo
|
||||
WMOLoader: loaded 7 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_mountaincave/md_icecave02.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/collidabledoodads/tanaris/trolltent/trolltentsand01.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/human_farm/farm.wmo
|
||||
WMOLoader: loaded 28 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/human_barracks/human_barracks.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/collidable doodads/elwynn/widebridge/elwynnwidebridge.wmo
|
||||
[80/368] baked=80 skipped=0 failed=0
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/collidable doodads/elwynn/lionbridge/elwynnlionbridge.wmo
|
||||
WMOLoader: loaded 5 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/westfall_magetower/westfall_magetower.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/collidable doodads/stranglethorn/stranglethornruins16/stranglethornruins16.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/collidable doodads/stranglethorn/stranglethornruins12/stranglethornruins12.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/collidable doodads/stranglethorn/stranglethornruins11/stranglethornruins11.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/collidable doodads/stranglethorn/stranglethornruins04/stranglethornruins04.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/collidabledoodads/darkshore/giantseaturtle02/giantseaturtle02.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/stranglethorn_ruins/stranglethorn_ruins12.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/collidabledoodads/darkshore/snakespine/snakespinegiantarch.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/stranglethorn_ruins/stranglethorn_ruins05.wmo
|
||||
[90/368] baked=90 skipped=0 failed=0
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/stranglethorn_ruins/stranglethorn_ruins16.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/stranglethorn_bootybay/bootybay_fortress2.wmo
|
||||
WMOLoader: loaded 46 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/stranglethorn_bootybay/bootybay.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/lorderon/buildings/tirisfalglade/mausoleum/mausoleumactive.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/lorderon/undercity/undercitywall01.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/lorderon/buildings/tirisfalglade/lorderonzeppelintower/lorderonzeppelin.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/lorderon/buildings/tirisfalglade/lorderonzeppelintower/lorderonzeppelin_nd_transport.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/keepwall/wallpieceruin02.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/keepwall/wallpostruined01.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/keepwall/wallposttunnel01.wmo
|
||||
[100/368] baked=100 skipped=0 failed=0
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/lorderon/collidabledoodads/arathihighlands/humanruinedbuildings/huruinedbuildingsmed01.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/lorderon/collidabledoodads/arathihighlands/humanruinedbuildings/huruinedbuildingssmall01.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/lorderon/collidabledoodads/arathihighlands/humanruinedbuildings/huruinedbuildingsmed02.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/keepwall/wallpiecestairs01.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/lorderon/collidabledoodads/arathihighlands/humanruinedbuildings/huruinedbuildingssmall02.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/lorderon/collidabledoodads/arathihighlands/humanruinedbuildings/huruinedbuildingsbig03.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/lorderon/collidabledoodads/arathihighlands/humanruinedbuildings/huruinedbuildingsbig02.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/northrend/dalaran/dalaran_sewer_oldworld_architecture.wmo
|
||||
WMOLoader: loaded 6 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/humantwostory/humantwostory.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/prison_camp/prisonguardtower.wmo
|
||||
[110/368] baked=110 skipped=0 failed=0
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/lorderon/buildings/alterac/greenhouse01.wmo
|
||||
WMOLoader: loaded 5 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/townhall/townhall.wmo
|
||||
WMOLoader: loaded 3 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/prison_camp/prisonhq.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/goldshireblacksmith/goldshireblacksmith.wmo
|
||||
WMOLoader: loaded 11 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_goldmine/md_goldmine_variantb.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_animalden/animalden.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/gnomehut/gnomehuttwostory.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_caveden/md_iceden.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/buildings/trollhut/trollhut_desert.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/collidabledoodads/tanaris/trolltent/trolltentdesert01.wmo
|
||||
[120/368] baked=120 skipped=0 failed=0
|
||||
WMOLoader: loaded 13 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_anvilmarpass/anvilmarpass.wmo
|
||||
WMOLoader: loaded 6 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/buildings/anvilmar/anvilmar.wmo
|
||||
WMOLoader: loaded 13 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_mountaincave/md_icecave.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/collidable doodads/elwynn/abbeygate/abbeygate01.wmo
|
||||
WMOLoader: loaded 12 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/goldshireinn/goldshireinn.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/stable/stable.wmo
|
||||
WMOLoader: loaded 3 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/human_barn_silo/barn.wmo
|
||||
WMOLoader: loaded 22 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_goldmine/md_goldmine_varianta.wmo
|
||||
WMOLoader: loaded 13 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_crypt/md_crypt_c.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/collidable doodads/duskwood/opengrave/duskwoodopengrave.wmo
|
||||
[130/368] baked=130 skipped=0 failed=0
|
||||
WMOLoader: loaded 11 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/duskwoodabandoned_inn/duskwoodabandoned_inn.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/collidabledoodads/darkshore/darkshoredocks/darkshoredocks01.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/buildings/orczeppelinhouse/orczeppelinhouse.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/buildings/orctower/orctower.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/buildings/orcblacksmith/orcblacksmith.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/collidable doodads/stranglethorn/stranglethornarena/stranglegladiatorarena.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_caveden/md_trollden.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/collidable doodads/stranglethorn/stranglethornarenagate/stranglearenagate01.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/collidable doodads/stranglethorn/ropebridge/ropebridgesmall.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/stranglethorn_bootybay/bootybay_railing.wmo
|
||||
[140/368] baked=140 skipped=0 failed=0
|
||||
WMOLoader: loaded 3 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/stranglethorn_bootybay/bootybay_house1.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/stranglethorn_bootybay/bootybay_house2.wmo
|
||||
WMOLoader: loaded 10 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_pirateship/pirateship_plank.wmo
|
||||
WMOLoader: loaded 6 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/redridge_humantwostory/redridge_humantwostory.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/collidable doodads/redridge/redridgedocks02/redridgedocks02.wmo
|
||||
WMOLoader: loaded 5 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/duskwoodabandoned_townhall_nowall/duskwoodabandoned_townhall_nowall.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/keepwall/wallpieceruin01.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/keepwall/gateruined01.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/redridge_human_farm/redridge_human_farm.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_ogremound/md_snogremound1room.wmo
|
||||
[150/368] baked=150 skipped=0 failed=0
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_caveden/md_mushroomden.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/intactprisontower/intactprisontower.wmo
|
||||
WMOLoader: loaded 3 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_cavetunnels/pvp_alterac_ent01.wmo
|
||||
WMOLoader: loaded 4 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_mountaincave/md_mountaincave_medium_e.wmo
|
||||
WMOLoader: loaded 5 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/westfall_townhall_nowall/westfall_townhall_nowall.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/collidabledoodads/menethildocks/menethildocks.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/collidable doodads/ironforge/footbridge/ironfootbridge.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/collidable doodads/ironforge/ironforgeropebridge01/ironforgeropebridge01.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/buildings/dwarven_blacksmith/snow_blacksmith/snow_blacksmith.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/buildings/dwarven_1story_hovel/snow_hovel/hovel_machine.wmo
|
||||
[160/368] baked=160 skipped=0 failed=0
|
||||
WMOLoader: loaded 8 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_mountaincave/md_icecave03.wmo
|
||||
WMOLoader: loaded 7 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/buildings/dwarven_inn/snow_inn/snow_inn.wmo
|
||||
WMOLoader: loaded 7 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_mountaincave/md_mushroomcave02.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/redridge_stable/redridge_stable.wmo
|
||||
WMOLoader: loaded 14 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/nsabbey/nsabbey.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/collidable doodads/elwynn/abbeygate02/abbeygate02.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/worldtree/duskworldtree.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/buildings/nightelfmoonwell/dsnightelfmoonwellornate.wmo
|
||||
WMOLoader: loaded 9 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_ogremound/md_ogremound.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/collidable doodads/stranglethorn/ropebridge/ropebridge.wmo
|
||||
[170/368] baked=170 skipped=0 failed=0
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/oilplatform/oilplatformsmall.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/buildings/trollhut/trollhut01.wmo
|
||||
WMOLoader: loaded 7 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_mountaincave/md_mushroomcave03.wmo
|
||||
WMOLoader: loaded 13 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/scarlet_monestary/scarlet_monestary.wmo
|
||||
WMOLoader: loaded 9 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_ogremound/md_snogremound.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/collidabledoodads/wetlandsfootbridge/wetlandsfootbridge01.wmo
|
||||
WMOLoader: loaded 11 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/westfall_inn/westfall_inn.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/lorderon/buildings/wetlands/bridgebigwhite/bridgebigwhite.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/keepwall/wallpiece03.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/keepwall/wallpiece02.wmo
|
||||
[180/368] baked=180 skipped=0 failed=0
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/keepwall/gate03.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/keepwall/wallpost02.wmo
|
||||
WMOLoader: loaded 4 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/transports/passengership/transportship_a.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/buildings/dwarven_stable/dwarven_stable.wmo
|
||||
WMOLoader: loaded 104 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/cities/ironforge/ironforge.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/buildings/dwarven_1story_hovel/snow_hovel/snow_hovel.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/buildings/dwarven_2story_hovel/snow_2story/snow_2story.wmo
|
||||
WMOLoader: loaded 13 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_goldmine/md_goldmine_variante.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/buildings/searinggorge/darkirontower.wmo
|
||||
WMOLoader: loaded 45 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/az_blackrock/blackrock.wmo
|
||||
[190/368] baked=190 skipped=0 failed=0
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/altarofstorms/altarofstorms.wmo
|
||||
WMOLoader: loaded 5 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/magetower/magetower.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/collidabledoodads/mulgore/taurentent01/taurentent01.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/duskwood_lumbermill/duskwood_lumbermill.wmo
|
||||
WMOLoader: loaded 9 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_mountaincave/md_mushroomcave05.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/collidable doodads/stranglethorn/holdingpen/holdingpenbamboo.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/buildings/orctower/swamporctower.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/zulgurub/zulgurubentrance.wmo
|
||||
WMOLoader: loaded 9 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_ogremound/md_grogremound.wmo
|
||||
WMOLoader: loaded 5 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/redridge_townhall_nowall/redridge_townhall_nowall.wmo
|
||||
[200/368] baked=200 skipped=0 failed=0
|
||||
WMOLoader: loaded 5 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/redridge_magetower/redridge_magetower.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/redridge_lumbermill/redridge_lumbermill.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/westfall_guardtower/westfall_guardtower.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/redridge_blacksmith/redridge_blacksmith.wmo
|
||||
WMOLoader: loaded 26 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/redridge_barracks/redridge_barracks.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/keepwall/gate01.wmo
|
||||
WMOLoader: loaded 11 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/duskwoodabandoned_inn/andorhalabandoned_inn.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/lorderon/collidabledoodads/arathihighlands/humanruinedbuildings/huruinedbuildingsbig01.wmo
|
||||
WMOLoader: loaded 4 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_cavetunnels/md_cavetunnel01.wmo
|
||||
WMOLoader: loaded 3 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/guildhouses/guildhouseb.wmo
|
||||
[210/368] baked=210 skipped=0 failed=0
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/hillsbradterracewall/hillsbradterracewall.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/outland/humanbuildings/outlandruinedmagetower.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/outland/humanbuildings/outlandruinhumanbarracks01.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/lorderon/collidabledoodads/arathihighlands/durnholdedestroyedwalls/durnholdedestroyedwall.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/buildings/greatwall/greatwall_wall_02.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/buildings/greatwall/greatwall_wall_01.wmo
|
||||
WMOLoader: loaded 12 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/buildings/dwarven_barracks/wetlands_barracks/wet_dwarfbarracks.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/buildings/greatwall/greatwall_tower_02.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/lorderon/collidabledoodads/arathihighlands/stromguard/stromguard.wmo
|
||||
WMOLoader: loaded 5 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/duskwood_magetower/duskwood_magetower.wmo
|
||||
[220/368] baked=220 skipped=0 failed=0
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/buildings/dwarven_1story_hovel/mud_hovel/mud_hovel.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/buildings/dwarven_2story_hovel/mud_2story/mud_2story.wmo
|
||||
WMOLoader: loaded 8 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_dwarven tunnels/smalltunnel.wmo
|
||||
WMOLoader: loaded 10 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_dwarven tunnels/mediumtunnel.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/buildings/dwarven_snowstable/dwarven_snowstable.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/collidable doodads/golbolarplatform/golbolarplatform.wmo
|
||||
WMOLoader: loaded 4 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_mountaincave/md_icecave04.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/buildings/searinggorge/darkironcrane.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/collidable doodads/searinggorge/searinggorgescaffold/searinggorgescaffold.wmo
|
||||
WMOLoader: loaded 4 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/az_blackrock/blackrock2.wmo
|
||||
[230/368] baked=230 skipped=0 failed=0
|
||||
WMOLoader: loaded 21 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/buildings/orcfortress/blackrockorcfortress.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/buildings/trollburrow/trollburrow.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/lumbermill/lumbermill.wmo
|
||||
WMOLoader: loaded 19 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_crypt/md_crypt_d.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/buildings/trollhut/trollhutsmall01.wmo
|
||||
WMOLoader: loaded 3 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/zulgurub/zulgurubcity.wmo
|
||||
WMOLoader: loaded 4 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/stranglethorn_ruins/stranglethorn_ruins02.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/ziggurat/trollziggurat.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/stranglethorn_ruins/stranglethorn_ruins04.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/stranglethorn_ruins/stranglethorn_ruins08.wmo
|
||||
[240/368] baked=240 skipped=0 failed=0
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/stranglethorn_ruins/stranglethorn_ruins09.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/stranglethorn_ruins/stranglethorn_ruins11.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/collidable doodads/stranglethorn/ropebridge/ropebridgeshort.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/stranglethorn_ruins/stranglethorn_ruins15.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_ogremound/md_ogremound1room.wmo
|
||||
WMOLoader: loaded 12 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_cryptschool/md_cryptschool.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/lorderon/buildings/tirisfalglade/uthershrine/uthershrine.wmo
|
||||
WMOLoader: loaded 5 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/buildings/dwarven_griffonaviary/dwarven_griffonaviary.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/buildings/dwarven_blacksmith/wetland_blacksmith/wetland_blacksmith.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/buildings/greatwall/greatwall_wall_03.wmo
|
||||
[250/368] baked=250 skipped=0 failed=0
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/lorderon/collidabledoodads/arathihighlands/wreckedbuildinghcorner02/wreckedbuildinghcorner02.wmo
|
||||
WMOLoader: loaded 16 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_ruinedkeep/ruinedkeep.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/lorderon/collidabledoodads/arathihighlands/wreckedbuildinghcorner01/wreckedbuildinghcorner01.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/collidable doodads/redridge/redridgedocks01/redridgedocks01.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/collidable doodads/redridge/redridgedocks03/redridgedocks03.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/buildings/dwarven_snowtower/dwarven_snowtower.wmo
|
||||
WMOLoader: loaded 22 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_dwarven tunnels/largetunnel.wmo
|
||||
WMOLoader: loaded 3 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/buildings/orcmedium/orcmedium.wmo
|
||||
WMOLoader: loaded 5 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/buildings/orcmagetower/orcmagetower.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/buildings/orckennel/orckennel.wmo
|
||||
[260/368] baked=260 skipped=0 failed=0
|
||||
WMOLoader: loaded 13 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_mountaincave/md_mushroomcave.wmo
|
||||
WMOLoader: loaded 12 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/az_karazahn/kharazan.wmo
|
||||
WMOLoader: loaded 7 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/lorderon/collidabledoodads/arathihighlands/humanruinedbuildings/huruinedbuildingssm01_winecellar.wmo
|
||||
WMOLoader: loaded 4 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/lorderon/collidabledoodads/arathihighlands/humanruinedbuildings/huruinedbuilding_collapsed.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/collidable doodads/stranglethorn/strangleruinstair/strangleruinstair.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/stranglethorn_ruins/stranglethorn_ruins17.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/buildings/trollhotel/troll_hotel01.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/stranglethorn_ruins/stranglethorn_ruins14.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/collidable doodads/stranglethorn/stranglethornruins01/stranglethornruins01.wmo
|
||||
WMOLoader: loaded 25 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_stratholme_plaguewood_tunnel/md_stratholme_plaguewood_tunnel.wmo
|
||||
[270/368] baked=270 skipped=0 failed=0
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/lorderon/collidabledoodads/plaguelandbridge/plaguelandsbridge.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/collidable doodads/redridge/redridgedocks/redridgesmalldock01.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/keepwall/lowwallpost01.wmo
|
||||
WMOLoader: loaded 15 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_ruinedkeep/ruinedkeep_crypt.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_ruinedkeep/ruinedkeep_crypt_facade.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/buildings/dwarven_guardtower/dwarven_guardtower.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/lorderon/collidabledoodads/arathihighlands/bridge/arathistonebridge02.wmo
|
||||
WMOLoader: loaded 5 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/buildings/dwarven_tavern/wetlands_tavern/wet_tavern.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/collidabledoodads/dustwallowmarsh/crashedzippelin/final/crashedzippelin.wmo
|
||||
WMOLoader: loaded 7 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/buildings/thandolspan_bridge/thandolspan.wmo
|
||||
[280/368] baked=280 skipped=0 failed=0
|
||||
WMOLoader: loaded 8 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_mountaincave/md_mushroomcave04.wmo
|
||||
WMOLoader: loaded 8 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_dwarven tunnels/smalltunnel_snow.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/collidable doodads/lochmodan/dwarvensentinels/dwarvensentinel01.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/collidable doodads/lochmodan/dwarvensentinels/dwarvensentinel02.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_caveden/md_warmden.wmo
|
||||
WMOLoader: loaded 9 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_ogremound/md_brogremound.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/buildings/orctower/blackrockorctower.wmo
|
||||
WMOLoader: loaded 11 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/redridge_inn/redridge_inn.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/collidable doodads/redridge/redridgedamagedbridge/redridgedamagedbridge.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/collidable doodads/redridge/redridgedocks/redridgesmalldock02.wmo
|
||||
[290/368] baked=290 skipped=0 failed=0
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_ogremound/md_grogremound1room.wmo
|
||||
WMOLoader: loaded 4 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/buildings/orcbarracks/abandonedorcbarracks.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/buildings/classicalelfruins/azrclassicalelfruin10.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/buildings/classicalelfruins/azrclassicalelfruin01.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/lorderon/buildings/easternplaguelands/undeadziggurat/undeadziggurat.wmo
|
||||
WMOLoader: loaded 4 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_cavetunnels/md_warmcavetunnel01.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/buildings/nightelfhunterslodge/nightelfhunterslodge.wmo
|
||||
WMOLoader: loaded 3 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/buildings/nightelfsmallhouse/nightelfsmallhouse.wmo
|
||||
WMOLoader: loaded 5 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_ogremound/md_ogremound_medium.wmo
|
||||
WMOLoader: loaded 3 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_mountaincave/md_mountaincave_medium_d.wmo
|
||||
[300/368] baked=300 skipped=0 failed=0
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/collidable doodads/wetlands/wetlandswagon/final/wetlandsbustedwagon.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/collidable doodads/lochmodan/dwarvendam/dwarvendam01.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/collidable doodads/lochmodan/dwarvendock/dwarvendock01.wmo
|
||||
WMOLoader: loaded 8 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/buildings/dwarven_inn/wetlands_inn/wet_inn.wmo
|
||||
WMOLoader: loaded 23 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/kz_uldaman/kz_uldaman_a.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/collidable doodads/redridge/redridgefootbridge/redridgefootbridge.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/outland/draenibuildings/outland_draeni_hut_1.wmo
|
||||
WMOLoader: loaded 3 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/outland/draenibuildings/draenihuthooded01.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/buildings/trollburrow/swamptrollburrow.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/collidable doodads/swampofsorrows/bridgestranglethorn/bridgestranglethorn.wmo
|
||||
[310/368] baked=310 skipped=0 failed=0
|
||||
WMOLoader: loaded 13 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_goldmine/md_goldmine_variantd.wmo
|
||||
WMOLoader: loaded 3 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/buildings/orctower/abandonedorctower.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/outland/orcbuildings/outlandorctower04.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_ogremound/md_brogremound1room.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/outland/darkportal/darkportal.wmo
|
||||
WMOLoader: loaded 12 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/lorderon/buildings/easternplaguelands/undeadslaughterhouse/slaughterhouse.wmo
|
||||
WMOLoader: loaded 5 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/ld_stratholme/stratholme_a.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/lorderon/buildings/easternplaguelands/naxportal/epl_portal.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/worldtree/worldtree.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/buildings/trollhut/trolltent.wmo
|
||||
[320/368] baked=320 skipped=0 failed=0
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/lorderon/collidabledoodads/hinterlands/trollcitypieces/aerietrollcitylevel7.wmo
|
||||
WMOLoader: loaded 5 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_mountaincave/md_mushroomcave08.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/buildings/wetlands_grimbatol/wetlands_grimbatol.wmo
|
||||
WMOLoader: loaded 5 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_cryptsimpleent/md_cryptsimpleent.wmo
|
||||
WMOLoader: loaded 6 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/kz_uldaman/kz_uldaman_c.wmo
|
||||
WMOLoader: loaded 36 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/sunkentemple/az_sunkentemple.wmo
|
||||
WMOLoader: loaded 3 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/buildings/orcmedium/swamporcmedium.wmo
|
||||
WMOLoader: loaded 4 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/buildings/orcgreathall/swamporcgreathall.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/buildings/orcblacksmith/swamporcblacksmith.wmo
|
||||
WMOLoader: loaded 6 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_mountaincave/md_mushroomcave07.wmo
|
||||
[330/368] baked=330 skipped=0 failed=0
|
||||
WMOLoader: loaded 26 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/westfall_barracks/westfall_barracks.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/westfall_blacksmith/westfall_blacksmith.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/prison_camp/prisonoubliette.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/westfall_stable/westfall_stableb.wmo
|
||||
WMOLoader: loaded 13 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_hordemine/md_hordemine.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/outland/orcbuildings/outlandorctower02.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/outland/orcbuildings/outlandorctower01.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/outland/orcbuildings/outlandorcpigfarm01.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/pvp/collidabledoodads/netents/nightelftent02_pvp.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/buildings/nightelfhunterslodge/dsnightelfhunterslodge.wmo
|
||||
[340/368] baked=340 skipped=0 failed=0
|
||||
WMOLoader: loaded 7 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/ld_stratholme/stratholme_c.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/buildings/classicalelfruins/classicalelfruin10.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/buildings/classicalelfruins/classicalelfruin01.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/buildings/classicalelfruins/classicalelfruin02.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/buildings/classicalelfruins/classicalelfruin03.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/buildings/classicalelfruins/classicalelfruin05.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/lorderon/collidabledoodads/hinterlands/trollcitypieces/aerietrollcitylevel1.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/lorderon/collidabledoodads/hinterlands/trollcitypieces/aerietrollcitylevel2.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/lorderon/collidabledoodads/hinterlands/trollcitypieces/aerietrollcitylevel3.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/lorderon/collidabledoodads/hinterlands/trollcitypieces/aerietrollcitylevel4.wmo
|
||||
[350/368] baked=350 skipped=0 failed=0
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/lorderon/collidabledoodads/hinterlands/trollcitypieces/aerietrollcitylevel5.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/lorderon/collidabledoodads/hinterlands/trollcitypieces/aerietrollcitylevel6.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/lorderon/collidabledoodads/hinterlands/trollcitypieces/aerietrollcityarena.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/lorderon/collidabledoodads/hinterlands/trollcitypieces/aerietrollcityampatheater.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/collidable doodads/lochmodan/excavationsite/excavationplatform02.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/collidable doodads/lochmodan/excavationsite/excavationplatform01.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/khazmodan/collidable doodads/lochmodan/excavationsite/excavationplatform03.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/collidabledoodads/darkshore/giantseaturtle01/giantseaturtle01.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/kalimdor/buildings/trollhut/trollhut_burn01.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/stranglethorn_bootybay/ratchet_dock.wmo
|
||||
[360/368] baked=360 skipped=0 failed=0
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/md_shipwreck/shipwreck_c.wmo
|
||||
WMOLoader: loaded 6 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/nd_necropolis/deathknightnecropolis.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/duskwood_human_farm/duskwood_human_farm_closed.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/dungeon/nd_necropolis/nd_necropolisteleport02.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/duskwood_barn/duskwood_barn_closed.wmo
|
||||
WMOLoader: loaded 7 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/lorderon/buildings/easternplaguelands/cathedral/cathedral.wmo
|
||||
WMOLoader: loaded 2 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/chapel/redridgechapel.wmo
|
||||
WMOLoader: loaded 1 groups from C:/Users/sindo/open-wc/data/extracted/world/wmo/azeroth/buildings/guardtower/guardtower_damaged.wmo
|
||||
[368/368] baked=368 skipped=0 failed=0
|
||||
WMO render cache finished. baked=368 skipped=0 failed=0 elapsed=37.26s
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
-1
@@ -1 +0,0 @@
|
||||
{"baked":77,"done":false,"failed":0,"last_tile":"33_26","processed":77,"skipped":0,"total":172,"worker":0,"workers":4}
|
||||
-1
@@ -1 +0,0 @@
|
||||
{"baked":79,"done":false,"failed":0,"last_tile":"33_35","processed":79,"skipped":0,"total":172,"worker":1,"workers":4}
|
||||
-1
@@ -1 +0,0 @@
|
||||
{"baked":80,"done":false,"failed":0,"last_tile":"33_40","processed":80,"skipped":0,"total":172,"worker":2,"workers":4}
|
||||
-1
@@ -1 +0,0 @@
|
||||
{"baked":78,"done":false,"failed":0,"last_tile":"33_33","processed":78,"skipped":0,"total":171,"worker":3,"workers":4}
|
||||
Submodule
+1
Submodule reference/open-realm added at dfe316d3b0
@@ -0,0 +1,243 @@
|
||||
#include "adt_baker.h"
|
||||
#include "blp_loader.h"
|
||||
|
||||
#include <godot_cpp/core/class_db.hpp>
|
||||
#include <godot_cpp/variant/array.hpp>
|
||||
#include <godot_cpp/variant/utility_functions.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
using namespace godot;
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr float FALLBACK_R = 0.4f;
|
||||
constexpr float FALLBACK_G = 0.55f;
|
||||
constexpr float FALLBACK_B = 0.3f;
|
||||
|
||||
static float clamp01(float v) {
|
||||
return std::max(0.0f, std::min(1.0f, v));
|
||||
}
|
||||
|
||||
static int32_t positive_mod(int32_t value, int32_t mod) {
|
||||
int32_t result = value % mod;
|
||||
return result < 0 ? result + mod : result;
|
||||
}
|
||||
|
||||
static float wrap01(float v) {
|
||||
return v - std::floor(v);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Ref<Image> ADTBaker::bake_tile_albedo(
|
||||
const Dictionary &data,
|
||||
Dictionary image_cache,
|
||||
const String &extracted_dir,
|
||||
int32_t texture_size) {
|
||||
|
||||
const int32_t size = get_baked_albedo_size(texture_size);
|
||||
const int32_t chunk_pixels = size / 16;
|
||||
if (size <= 0 || chunk_pixels <= 0) {
|
||||
return Ref<Image>();
|
||||
}
|
||||
|
||||
PackedByteArray out;
|
||||
out.resize(size * size * 3);
|
||||
uint8_t *out_ptr = out.ptrw();
|
||||
for (int32_t i = 0; i < size * size; ++i) {
|
||||
out_ptr[i * 3 + 0] = static_cast<uint8_t>(FALLBACK_R * 255.0f);
|
||||
out_ptr[i * 3 + 1] = static_cast<uint8_t>(FALLBACK_G * 255.0f);
|
||||
out_ptr[i * 3 + 2] = static_cast<uint8_t>(FALLBACK_B * 255.0f);
|
||||
}
|
||||
|
||||
const PackedStringArray tex_names = data.get("textures", PackedStringArray());
|
||||
const Array chunks = data.get("chunks", Array());
|
||||
|
||||
for (int64_t ci = 0; ci < chunks.size(); ++ci) {
|
||||
const Dictionary chunk = chunks[ci];
|
||||
if (chunk.is_empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const int32_t chunk_x = int32_t(chunk.get("index_x", -1));
|
||||
const int32_t chunk_y = int32_t(chunk.get("index_y", -1));
|
||||
if (chunk_x < 0 || chunk_x >= 16 || chunk_y < 0 || chunk_y >= 16) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const Array layers = chunk.get("layers", Array());
|
||||
if (layers.is_empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
TextureData textures[4];
|
||||
const int32_t layer_count = std::min<int32_t>(int32_t(layers.size()), 4);
|
||||
for (int32_t li = 0; li < layer_count; ++li) {
|
||||
const Dictionary layer = layers[li];
|
||||
const int32_t tex_id = int32_t(layer.get("texture_id", -1));
|
||||
if (tex_id >= 0 && tex_id < tex_names.size()) {
|
||||
textures[li] = load_texture_data(tex_names[tex_id], image_cache, extracted_dir);
|
||||
}
|
||||
}
|
||||
if (!textures[0].valid) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const Array alpha_maps = chunk.get("alpha_maps", Array());
|
||||
const int32_t base_x = chunk_x * chunk_pixels;
|
||||
const int32_t base_y = chunk_y * chunk_pixels;
|
||||
|
||||
for (int32_t py = 0; py < chunk_pixels; ++py) {
|
||||
const float local_v = (float(py) + 0.5f) / float(chunk_pixels);
|
||||
const int32_t ay = std::max(0, std::min(63, int32_t(std::floor(local_v * 63.999f))));
|
||||
|
||||
for (int32_t px = 0; px < chunk_pixels; ++px) {
|
||||
const float local_u = (float(px) + 0.5f) / float(chunk_pixels);
|
||||
const int32_t ax = std::max(0, std::min(63, int32_t(std::floor(local_u * 63.999f))));
|
||||
|
||||
float weights[4] = {1.0f, 0.0f, 0.0f, 0.0f};
|
||||
for (int32_t li = 1; li < layer_count; ++li) {
|
||||
PackedByteArray alpha;
|
||||
if (li - 1 < alpha_maps.size()) {
|
||||
alpha = alpha_maps[li - 1];
|
||||
}
|
||||
if (alpha.size() == 64 * 64) {
|
||||
weights[li] = float(alpha[ay * 64 + ax]) / 255.0f;
|
||||
}
|
||||
}
|
||||
|
||||
weights[0] = std::max(0.0f, 1.0f - weights[1] - weights[2] - weights[3]);
|
||||
const float sum = weights[0] + weights[1] + weights[2] + weights[3];
|
||||
if (sum > 0.0f) {
|
||||
for (float &weight : weights) {
|
||||
weight /= sum;
|
||||
}
|
||||
}
|
||||
|
||||
const float tiled_u = local_u * 8.0f;
|
||||
const float tiled_v = local_v * 8.0f;
|
||||
float rgb[3] = {0.0f, 0.0f, 0.0f};
|
||||
for (int32_t li = 0; li < layer_count; ++li) {
|
||||
if (!textures[li].valid || weights[li] <= 0.0f) {
|
||||
continue;
|
||||
}
|
||||
float sample[3];
|
||||
sample_image_repeat(textures[li], tiled_u, tiled_v, sample);
|
||||
rgb[0] += sample[0] * weights[li];
|
||||
rgb[1] += sample[1] * weights[li];
|
||||
rgb[2] += sample[2] * weights[li];
|
||||
}
|
||||
|
||||
const int32_t out_index = ((base_y + py) * size + (base_x + px)) * 3;
|
||||
out_ptr[out_index + 0] = static_cast<uint8_t>(clamp01(rgb[0]) * 255.0f + 0.5f);
|
||||
out_ptr[out_index + 1] = static_cast<uint8_t>(clamp01(rgb[1]) * 255.0f + 0.5f);
|
||||
out_ptr[out_index + 2] = static_cast<uint8_t>(clamp01(rgb[2]) * 255.0f + 0.5f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Image::create_from_data(size, size, false, Image::FORMAT_RGB8, out);
|
||||
}
|
||||
|
||||
int32_t ADTBaker::get_baked_albedo_size(int32_t texture_size) {
|
||||
const int32_t safe_size = std::max(texture_size, 16);
|
||||
const int32_t chunk_pixels = std::max(8, int32_t(std::ceil(float(safe_size) / 16.0f)));
|
||||
return chunk_pixels * 16;
|
||||
}
|
||||
|
||||
String ADTBaker::normalize_rel_path(const String &path) {
|
||||
return path.replace("\\", "/");
|
||||
}
|
||||
|
||||
ADTBaker::TextureData ADTBaker::load_texture_data(
|
||||
const String &blp_path,
|
||||
Dictionary &image_cache,
|
||||
const String &extracted_dir) {
|
||||
|
||||
TextureData texture;
|
||||
if (blp_path.is_empty()) {
|
||||
return texture;
|
||||
}
|
||||
|
||||
Ref<Image> image;
|
||||
if (image_cache.has(blp_path)) {
|
||||
image = image_cache[blp_path];
|
||||
} else {
|
||||
const String rel_path = normalize_rel_path(blp_path);
|
||||
String abs_path = extracted_dir;
|
||||
if (!abs_path.ends_with("/") && !abs_path.ends_with("\\")) {
|
||||
abs_path += "/";
|
||||
}
|
||||
abs_path += rel_path;
|
||||
|
||||
Ref<BLPLoader> loader;
|
||||
loader.instantiate();
|
||||
image = loader->load_image(abs_path);
|
||||
image_cache[blp_path] = image;
|
||||
}
|
||||
|
||||
if (image.is_null() || image->is_empty()) {
|
||||
return texture;
|
||||
}
|
||||
|
||||
if (image->get_format() != Image::FORMAT_RGBA8) {
|
||||
image = image->duplicate();
|
||||
image->convert(Image::FORMAT_RGBA8);
|
||||
}
|
||||
|
||||
texture.image = image;
|
||||
texture.width = image->get_width();
|
||||
texture.height = image->get_height();
|
||||
texture.bytes = image->get_data();
|
||||
texture.valid = texture.width > 0 && texture.height > 0 && texture.bytes.size() >= texture.width * texture.height * 4;
|
||||
return texture;
|
||||
}
|
||||
|
||||
void ADTBaker::sample_image_repeat(
|
||||
const TextureData &texture,
|
||||
float u,
|
||||
float v,
|
||||
float out_rgb[3]) {
|
||||
|
||||
if (!texture.valid) {
|
||||
out_rgb[0] = 1.0f;
|
||||
out_rgb[1] = 1.0f;
|
||||
out_rgb[2] = 1.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
const float fu = wrap01(u);
|
||||
const float fv = wrap01(v);
|
||||
const float px = fu * float(texture.width) - 0.5f;
|
||||
const float py = fv * float(texture.height) - 0.5f;
|
||||
const int32_t x0 = positive_mod(int32_t(std::floor(px)), texture.width);
|
||||
const int32_t y0 = positive_mod(int32_t(std::floor(py)), texture.height);
|
||||
const int32_t x1 = positive_mod(x0 + 1, texture.width);
|
||||
const int32_t y1 = positive_mod(y0 + 1, texture.height);
|
||||
const float tx = px - std::floor(px);
|
||||
const float ty = py - std::floor(py);
|
||||
|
||||
const uint8_t *bytes = texture.bytes.ptr();
|
||||
const int32_t i00 = (y0 * texture.width + x0) * 4;
|
||||
const int32_t i10 = (y0 * texture.width + x1) * 4;
|
||||
const int32_t i01 = (y1 * texture.width + x0) * 4;
|
||||
const int32_t i11 = (y1 * texture.width + x1) * 4;
|
||||
|
||||
for (int32_t c = 0; c < 3; ++c) {
|
||||
const float c00 = float(bytes[i00 + c]) / 255.0f;
|
||||
const float c10 = float(bytes[i10 + c]) / 255.0f;
|
||||
const float c01 = float(bytes[i01 + c]) / 255.0f;
|
||||
const float c11 = float(bytes[i11 + c]) / 255.0f;
|
||||
const float cx0 = c00 + (c10 - c00) * tx;
|
||||
const float cx1 = c01 + (c11 - c01) * tx;
|
||||
out_rgb[c] = cx0 + (cx1 - cx0) * ty;
|
||||
}
|
||||
}
|
||||
|
||||
void ADTBaker::_bind_methods() {
|
||||
ClassDB::bind_method(
|
||||
D_METHOD("bake_tile_albedo", "data", "image_cache", "extracted_dir", "texture_size"),
|
||||
&ADTBaker::bake_tile_albedo);
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
#include <godot_cpp/classes/image.hpp>
|
||||
#include <godot_cpp/classes/ref_counted.hpp>
|
||||
#include <godot_cpp/variant/dictionary.hpp>
|
||||
#include <godot_cpp/variant/packed_byte_array.hpp>
|
||||
#include <godot_cpp/variant/packed_string_array.hpp>
|
||||
#include <godot_cpp/variant/string.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class ADTBaker : public RefCounted {
|
||||
GDCLASS(ADTBaker, RefCounted)
|
||||
|
||||
public:
|
||||
Ref<Image> bake_tile_albedo(
|
||||
const Dictionary &data,
|
||||
Dictionary image_cache,
|
||||
const String &extracted_dir,
|
||||
int32_t texture_size);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
private:
|
||||
struct TextureData {
|
||||
Ref<Image> image;
|
||||
PackedByteArray bytes;
|
||||
int32_t width = 0;
|
||||
int32_t height = 0;
|
||||
bool valid = false;
|
||||
};
|
||||
|
||||
static int32_t get_baked_albedo_size(int32_t texture_size);
|
||||
static String normalize_rel_path(const String &path);
|
||||
static TextureData load_texture_data(
|
||||
const String &blp_path,
|
||||
Dictionary &image_cache,
|
||||
const String &extracted_dir);
|
||||
static void sample_image_repeat(
|
||||
const TextureData &texture,
|
||||
float u,
|
||||
float v,
|
||||
float out_rgb[3]);
|
||||
};
|
||||
|
||||
} // namespace godot
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "mpq_manager.h"
|
||||
#include "wmo_loader.h"
|
||||
#include "adt_loader.h"
|
||||
#include "adt_baker.h"
|
||||
#include "blp_loader.h"
|
||||
#include "m2_loader.h"
|
||||
#include "wdt_loader.h"
|
||||
@@ -16,6 +17,7 @@ void initialize_mpq_extractor_module(ModuleInitializationLevel p_level) {
|
||||
ClassDB::register_class<MPQManager>();
|
||||
ClassDB::register_class<WMOLoader>();
|
||||
ClassDB::register_class<ADTLoader>();
|
||||
ClassDB::register_class<ADTBaker>();
|
||||
ClassDB::register_class<BLPLoader>();
|
||||
ClassDB::register_class<M2Loader>();
|
||||
ClassDB::register_class<WDTLoader>();
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
*
|
||||
!.gitignore
|
||||
!.gitignore
|
||||
!wmo_streaming_resource.gd
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
extends Resource
|
||||
class_name WMOStreamingResource
|
||||
|
||||
const FORMAT_VERSION := 1
|
||||
|
||||
@export var format_version: int = FORMAT_VERSION
|
||||
@export var source_path: String = ""
|
||||
@export var mesh_names: PackedStringArray = PackedStringArray()
|
||||
@export var meshes: Array[Mesh] = []
|
||||
@export var mesh_transforms: Array[Transform3D] = []
|
||||
@export var multimesh_names: PackedStringArray = PackedStringArray()
|
||||
@export var multimeshes: Array[MultiMesh] = []
|
||||
@export var multimesh_transforms: Array[Transform3D] = []
|
||||
@@ -16,12 +16,29 @@ ambient_light_energy = 0.5
|
||||
script = ExtResource("1_stream")
|
||||
camera_path = NodePath("Camera3D")
|
||||
update_interval = 0.1
|
||||
max_concurrent_tile_tasks = 4
|
||||
chunk_ops_per_tick = 64
|
||||
tiles_per_tick = 1
|
||||
max_concurrent_tile_tasks = 1
|
||||
chunk_ops_per_tick = 16
|
||||
tile_lod_remove_ops_per_tick = 1
|
||||
tile_finalize_ops_per_tick = 1
|
||||
detail_asset_ops_per_tick = 1
|
||||
m2_build_groups_per_tick = 1
|
||||
m2_multimesh_batch_size = 32
|
||||
m2_mesh_finalize_ops_per_tick = 1
|
||||
wmo_build_instances_per_tick = 1
|
||||
wmo_render_group_ops_per_tick = 24
|
||||
wmo_max_runtime_scene_mb = 8.0
|
||||
prewarm_tile_margin = 2
|
||||
retain_tile_margin = 3
|
||||
boundary_prefetch_threshold = 0.4
|
||||
streaming_tile_cache_dir = "res://data/cache/baked_terrain_stream_v1"
|
||||
cached_tile_mesh_limit = 48
|
||||
editor_follow_view_camera = false
|
||||
wmo_render_cache_dir = "res://data/cache/wmo_render_v1"
|
||||
enable_occlusion_culling = false
|
||||
enable_water = true
|
||||
terrain_cast_shadows = true
|
||||
enable_wmo = true
|
||||
hitch_profiler_enabled = true
|
||||
hitch_profiler_threshold_ms = 20.0
|
||||
|
||||
[node name="Camera3D" type="Camera3D" parent="." unique_id=502573687]
|
||||
transform = Transform3D(1, 0, 0, 0, 0.707107, 0.707107, 0, -0.707107, 0.707107, 0, 300, 300)
|
||||
@@ -34,7 +51,6 @@ fast_mult = 8.0
|
||||
[node name="Sun" type="DirectionalLight3D" parent="." unique_id=1436804627]
|
||||
transform = Transform3D(0.866025, -0.353553, 0.353553, 0, 0.707107, 0.707107, -0.5, -0.612372, 0.612372, 0, 0, 0)
|
||||
light_energy = 1.5
|
||||
shadow_enabled = true
|
||||
directional_shadow_mode = 1
|
||||
directional_shadow_fade_start = 0.85
|
||||
directional_shadow_max_distance = 2200.0
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@ extends SceneTree
|
||||
|
||||
## Usage:
|
||||
## godot --headless --path <project> --script res://src/tools/bake_adt_terrain_cache.gd -- \
|
||||
## --map Azeroth --jobs 4 --force
|
||||
## --map Azeroth --jobs auto --force
|
||||
##
|
||||
## `--jobs N` starts N separate Godot worker processes. Process isolation keeps
|
||||
## ResourceSaver/Image/loader state independent while using multiple CPU cores.
|
||||
@@ -37,7 +37,7 @@ func _initialize() -> void:
|
||||
_get_arg_value(
|
||||
args,
|
||||
"--full-texture-size",
|
||||
str(legacy_texture_size if legacy_texture_size != null else 4196)
|
||||
str(legacy_texture_size if legacy_texture_size != null else 2048)
|
||||
).to_int()
|
||||
)
|
||||
var coarse_texture_size := maxi(
|
||||
@@ -48,11 +48,12 @@ func _initialize() -> void:
|
||||
str(legacy_texture_size if legacy_texture_size != null else 512)
|
||||
).to_int()
|
||||
)
|
||||
var tile_x: Variant = _get_optional_int_arg(args, "--tile-x")
|
||||
var tile_y: Variant = _get_optional_int_arg(args, "--tile-y")
|
||||
var jobs := maxi(1, _get_arg_value(args, "--jobs", "1").to_int())
|
||||
var worker_index: Variant = _get_optional_int_arg(args, "--worker-index")
|
||||
var worker_count := maxi(1, _get_arg_value(args, "--worker-count", "1").to_int())
|
||||
var tile_x: Variant = _get_optional_int_arg(args, "--tile-x")
|
||||
var tile_y: Variant = _get_optional_int_arg(args, "--tile-y")
|
||||
var default_jobs := "1" if tile_x != null or tile_y != null else "auto"
|
||||
var jobs := _parse_jobs_arg(_get_arg_value(args, "--jobs", default_jobs))
|
||||
var force := args.has("--force")
|
||||
|
||||
if jobs > 1 and worker_index == null:
|
||||
@@ -127,18 +128,16 @@ func _initialize() -> void:
|
||||
_progress_update(tx, ty, baked, skipped, failed)
|
||||
continue
|
||||
|
||||
var full_payload: Dictionary = _builder.build_baked_tile_render_payload(
|
||||
var payloads: Dictionary = _builder.build_baked_tile_render_payload_pair(
|
||||
data,
|
||||
_image_cache,
|
||||
ProjectSettings.globalize_path(extracted_dir),
|
||||
0,
|
||||
full_texture_size)
|
||||
var coarse_payload: Dictionary = _builder.build_baked_tile_render_payload(
|
||||
data,
|
||||
_image_cache,
|
||||
ProjectSettings.globalize_path(extracted_dir),
|
||||
full_texture_size,
|
||||
3,
|
||||
coarse_texture_size)
|
||||
var full_payload: Dictionary = payloads.get("full", {})
|
||||
var coarse_payload: Dictionary = payloads.get("coarse", {})
|
||||
|
||||
if full_payload.is_empty():
|
||||
push_warning("Bake produced empty full mesh: %s" % source_res_path)
|
||||
@@ -396,6 +395,13 @@ func _get_optional_int_arg(args: PackedStringArray, name: String):
|
||||
return null
|
||||
|
||||
|
||||
func _parse_jobs_arg(value: String) -> int:
|
||||
var normalized := value.strip_edges().to_lower()
|
||||
if normalized == "auto":
|
||||
return clampi(OS.get_processor_count() - 2, 1, 8)
|
||||
return maxi(1, normalized.to_int())
|
||||
|
||||
|
||||
func _normalize_res_path(path: String) -> String:
|
||||
if path.begins_with("res://"):
|
||||
return path
|
||||
|
||||
+10
-4
@@ -114,10 +114,16 @@ func _bake_terrain(map_name: String, map_dir: String, extracted: String,
|
||||
if data.is_empty() or not data.has("chunks"):
|
||||
failed += 1; continue
|
||||
|
||||
var full_payload := builder.build_baked_tile_render_payload(
|
||||
data, _image_cache, ProjectSettings.globalize_path(extracted), 0, full_tex)
|
||||
var coarse_payload := builder.build_baked_tile_render_payload(
|
||||
data, _image_cache, ProjectSettings.globalize_path(extracted), 3, coarse_tex)
|
||||
var payloads: Dictionary = builder.build_baked_tile_render_payload_pair(
|
||||
data,
|
||||
_image_cache,
|
||||
ProjectSettings.globalize_path(extracted),
|
||||
0,
|
||||
full_tex,
|
||||
3,
|
||||
coarse_tex)
|
||||
var full_payload: Dictionary = payloads.get("full", {})
|
||||
var coarse_payload: Dictionary = payloads.get("coarse", {})
|
||||
if full_payload.is_empty():
|
||||
failed += 1; continue
|
||||
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
extends SceneTree
|
||||
|
||||
## Converts the heavy baked ADT cache into a lightweight runtime streaming cache.
|
||||
##
|
||||
## Usage:
|
||||
## godot --headless --path <project> --script res://src/tools/build_adt_streaming_cache.gd -- \
|
||||
## --map Azeroth --input res://data/cache/baked_terrain_v2 --output res://data/cache/baked_terrain_stream_v1 --force
|
||||
|
||||
const BAKED_TILE_SCRIPT := preload("res://src/resources/baked_adt_tile.gd")
|
||||
const STREAMING_TILE_SCRIPT := preload("res://src/resources/streaming_adt_tile.gd")
|
||||
|
||||
|
||||
func _initialize() -> void:
|
||||
var args := OS.get_cmdline_user_args()
|
||||
var map_name := _arg(args, "--map", "Azeroth")
|
||||
var input_dir := _res(_arg(args, "--input", "res://data/cache/baked_terrain_v2"))
|
||||
var output_dir := _res(_arg(args, "--output", "res://data/cache/baked_terrain_stream_v1"))
|
||||
var force := args.has("--force")
|
||||
|
||||
var in_map_dir := input_dir.path_join(map_name)
|
||||
var out_map_dir := output_dir.path_join(map_name)
|
||||
var in_map_abs := ProjectSettings.globalize_path(in_map_dir)
|
||||
var out_map_abs := ProjectSettings.globalize_path(out_map_dir)
|
||||
if not DirAccess.dir_exists_absolute(in_map_abs):
|
||||
push_error("Input baked terrain cache not found: %s" % in_map_dir)
|
||||
quit(1)
|
||||
return
|
||||
DirAccess.make_dir_recursive_absolute(out_map_abs)
|
||||
|
||||
var dir := DirAccess.open(in_map_dir)
|
||||
if dir == null:
|
||||
push_error("Cannot open input cache dir: %s" % in_map_dir)
|
||||
quit(1)
|
||||
return
|
||||
|
||||
var files := dir.get_files()
|
||||
files.sort()
|
||||
var converted := 0
|
||||
var skipped := 0
|
||||
var failed := 0
|
||||
var started_ms := Time.get_ticks_msec()
|
||||
|
||||
for file_name in files:
|
||||
if not file_name.ends_with(".res"):
|
||||
continue
|
||||
var in_path := in_map_dir.path_join(file_name)
|
||||
var out_path := out_map_dir.path_join(file_name)
|
||||
if not force and ResourceLoader.exists(out_path):
|
||||
skipped += 1
|
||||
continue
|
||||
|
||||
var baked: Resource = load(in_path)
|
||||
if baked == null or baked.get_script() != BAKED_TILE_SCRIPT:
|
||||
push_warning("Invalid baked tile: %s" % in_path)
|
||||
failed += 1
|
||||
continue
|
||||
|
||||
var stream_tile: Resource = STREAMING_TILE_SCRIPT.new()
|
||||
stream_tile.set("format_version", STREAMING_TILE_SCRIPT.FORMAT_VERSION)
|
||||
stream_tile.set("map_name", str(baked.get("map_name")))
|
||||
stream_tile.set("tile_x", int(baked.get("tile_x")))
|
||||
stream_tile.set("tile_y", int(baked.get("tile_y")))
|
||||
stream_tile.set("tile_origin", baked.get("tile_origin"))
|
||||
stream_tile.set("texture_size", int(baked.get("coarse_texture_size")))
|
||||
stream_tile.set("wmo_names", baked.get("wmo_names"))
|
||||
stream_tile.set("wmo_placements", baked.get("wmo_placements"))
|
||||
stream_tile.set("m2_names", baked.get("m2_names"))
|
||||
stream_tile.set("m2_placements", baked.get("m2_placements"))
|
||||
stream_tile.set("terrain_mesh", baked.get("coarse_mesh"))
|
||||
|
||||
var err := ResourceSaver.save(stream_tile, out_path)
|
||||
if err != OK:
|
||||
push_warning("Failed to save streaming tile %s (err=%d)" % [out_path, err])
|
||||
failed += 1
|
||||
continue
|
||||
|
||||
converted += 1
|
||||
if converted % 25 == 0:
|
||||
print("Converted %d tiles..." % converted)
|
||||
|
||||
var elapsed_ms := Time.get_ticks_msec() - started_ms
|
||||
print("Streaming cache finished. converted=%d skipped=%d failed=%d elapsed=%.2fs" % [
|
||||
converted, skipped, failed, float(elapsed_ms) / 1000.0
|
||||
])
|
||||
quit(0 if failed == 0 else 2)
|
||||
|
||||
|
||||
func _arg(args: PackedStringArray, name: String, default: String) -> String:
|
||||
var idx := args.find(name)
|
||||
if idx >= 0 and idx + 1 < args.size():
|
||||
return args[idx + 1]
|
||||
return default
|
||||
|
||||
|
||||
func _res(path: String) -> String:
|
||||
if path.begins_with("res://") or path.begins_with("user://"):
|
||||
return path
|
||||
return "res://" + path.trim_prefix("./").trim_prefix("/")
|
||||
@@ -0,0 +1 @@
|
||||
uid://ctokf2tfwftl7
|
||||
@@ -0,0 +1,182 @@
|
||||
extends SceneTree
|
||||
|
||||
## Builds a lightweight WMO render cache for runtime streaming.
|
||||
##
|
||||
## Usage:
|
||||
## godot --headless --path <project> --script res://src/tools/build_wmo_streaming_cache.gd -- \
|
||||
## --map Azeroth --extracted res://data/extracted --output res://data/cache/wmo_render_v1 --force
|
||||
|
||||
const WMO_BUILDER_SCRIPT := preload("res://addons/mpq_extractor/loaders/wmo_builder.gd")
|
||||
const WMO_STREAMING_SCRIPT := preload("res://src/resources/wmo_streaming_resource.gd")
|
||||
|
||||
|
||||
func _initialize() -> void:
|
||||
var args := OS.get_cmdline_user_args()
|
||||
var map_name := _arg(args, "--map", "Azeroth")
|
||||
var extracted := _res(_arg(args, "--extracted", "res://data/extracted"))
|
||||
var output_dir := _res(_arg(args, "--output", "res://data/cache/wmo_render_v1"))
|
||||
var force := args.has("--force")
|
||||
|
||||
if not ClassDB.class_exists("ADTLoader") or not ClassDB.class_exists("WMOLoader"):
|
||||
push_error("GDExtension not loaded. Rebuild first.")
|
||||
quit(1)
|
||||
return
|
||||
|
||||
DirAccess.make_dir_recursive_absolute(ProjectSettings.globalize_path(output_dir))
|
||||
|
||||
var unique := _collect_unique_wmos(map_name, extracted)
|
||||
if unique.is_empty():
|
||||
push_error("No WMO references found for map: %s" % map_name)
|
||||
quit(1)
|
||||
return
|
||||
|
||||
var wmo_loader = ClassDB.instantiate("WMOLoader")
|
||||
var baked := 0
|
||||
var skipped := 0
|
||||
var failed := 0
|
||||
var total := unique.size()
|
||||
var index := 0
|
||||
var started_ms := Time.get_ticks_msec()
|
||||
|
||||
for rel_path_variant in unique.keys():
|
||||
index += 1
|
||||
var rel_path := String(rel_path_variant)
|
||||
var out_path := _get_wmo_render_path(output_dir, rel_path)
|
||||
if not force and ResourceLoader.exists(out_path):
|
||||
skipped += 1
|
||||
continue
|
||||
|
||||
var abs_wmo := ProjectSettings.globalize_path(extracted.path_join(rel_path))
|
||||
if not FileAccess.file_exists(abs_wmo):
|
||||
failed += 1
|
||||
continue
|
||||
|
||||
var data: Dictionary = wmo_loader.call("load_wmo", abs_wmo)
|
||||
if data.is_empty():
|
||||
failed += 1
|
||||
continue
|
||||
|
||||
var node: Node3D = WMO_BUILDER_SCRIPT.build(data, extracted)
|
||||
if node == null:
|
||||
failed += 1
|
||||
continue
|
||||
|
||||
var render_resource: Resource = WMO_STREAMING_SCRIPT.new()
|
||||
render_resource.set("format_version", WMO_STREAMING_SCRIPT.FORMAT_VERSION)
|
||||
render_resource.set("source_path", rel_path)
|
||||
_collect_render_payload(node, render_resource)
|
||||
node.free()
|
||||
|
||||
if (render_resource.get("meshes") as Array).is_empty() and (render_resource.get("multimeshes") as Array).is_empty():
|
||||
failed += 1
|
||||
continue
|
||||
|
||||
DirAccess.make_dir_recursive_absolute(ProjectSettings.globalize_path(out_path.get_base_dir()))
|
||||
var err := ResourceSaver.save(render_resource, out_path)
|
||||
if err != OK:
|
||||
push_warning("save failed for %s: %d" % [out_path, err])
|
||||
failed += 1
|
||||
continue
|
||||
|
||||
baked += 1
|
||||
if index % 10 == 0 or index == total:
|
||||
print("[%d/%d] baked=%d skipped=%d failed=%d" % [index, total, baked, skipped, failed])
|
||||
|
||||
var elapsed_ms := Time.get_ticks_msec() - started_ms
|
||||
print("WMO render cache finished. baked=%d skipped=%d failed=%d elapsed=%.2fs" % [
|
||||
baked,
|
||||
skipped,
|
||||
failed,
|
||||
float(elapsed_ms) / 1000.0,
|
||||
])
|
||||
WMO_BUILDER_SCRIPT.clear_caches()
|
||||
quit(0 if failed == 0 else 2)
|
||||
|
||||
|
||||
func _collect_unique_wmos(map_name: String, extracted: String) -> Dictionary:
|
||||
var unique: Dictionary = {}
|
||||
var adt_loader = ClassDB.instantiate("ADTLoader")
|
||||
var map_dir := extracted.path_join("World/Maps/%s" % map_name)
|
||||
var dir := DirAccess.open(map_dir)
|
||||
if dir == null:
|
||||
push_error("Cannot open map dir: %s" % map_dir)
|
||||
return unique
|
||||
|
||||
print("Scanning ADT tiles...")
|
||||
var scanned := 0
|
||||
for file_name in dir.get_files():
|
||||
if not file_name.ends_with(".adt"):
|
||||
continue
|
||||
var parts := file_name.trim_suffix(".adt").split("_")
|
||||
if parts.size() != 3 or parts[0] != map_name:
|
||||
continue
|
||||
var data: Dictionary = adt_loader.call("load_adt",
|
||||
ProjectSettings.globalize_path(map_dir.path_join(file_name)))
|
||||
if data.is_empty():
|
||||
continue
|
||||
for rel in data.get("wmo_names", PackedStringArray()):
|
||||
var normalized := str(rel).replace("\\", "/").to_lower()
|
||||
if not normalized.is_empty():
|
||||
unique[normalized] = true
|
||||
scanned += 1
|
||||
|
||||
print("Found %d unique WMO models from %d tiles." % [unique.size(), scanned])
|
||||
return unique
|
||||
|
||||
|
||||
func _collect_render_payload(
|
||||
node: Node,
|
||||
render_resource: Resource,
|
||||
parent_transform: Transform3D = Transform3D.IDENTITY) -> void:
|
||||
if node.name == "Occluders":
|
||||
return
|
||||
|
||||
var node_transform := parent_transform
|
||||
if node is Node3D:
|
||||
node_transform = parent_transform * (node as Node3D).transform
|
||||
|
||||
if node is MeshInstance3D:
|
||||
var mesh_instance := node as MeshInstance3D
|
||||
if mesh_instance.mesh != null:
|
||||
var names: PackedStringArray = render_resource.get("mesh_names")
|
||||
var meshes: Array = render_resource.get("meshes")
|
||||
var transforms: Array = render_resource.get("mesh_transforms")
|
||||
names.append(mesh_instance.name)
|
||||
meshes.append(mesh_instance.mesh)
|
||||
transforms.append(node_transform)
|
||||
render_resource.set("mesh_names", names)
|
||||
render_resource.set("meshes", meshes)
|
||||
render_resource.set("mesh_transforms", transforms)
|
||||
elif node is MultiMeshInstance3D:
|
||||
var multimesh_instance := node as MultiMeshInstance3D
|
||||
if multimesh_instance.multimesh != null:
|
||||
var names: PackedStringArray = render_resource.get("multimesh_names")
|
||||
var multimeshes: Array = render_resource.get("multimeshes")
|
||||
var transforms: Array = render_resource.get("multimesh_transforms")
|
||||
names.append(multimesh_instance.name)
|
||||
multimeshes.append(multimesh_instance.multimesh)
|
||||
transforms.append(node_transform)
|
||||
render_resource.set("multimesh_names", names)
|
||||
render_resource.set("multimeshes", multimeshes)
|
||||
render_resource.set("multimesh_transforms", transforms)
|
||||
|
||||
for child in node.get_children():
|
||||
_collect_render_payload(child, render_resource, node_transform)
|
||||
|
||||
|
||||
func _get_wmo_render_path(output_dir: String, rel_path: String) -> String:
|
||||
var normalized := rel_path.replace("\\", "/")
|
||||
return output_dir.path_join(normalized.get_basename() + ".res")
|
||||
|
||||
|
||||
func _arg(args: PackedStringArray, name: String, default: String) -> String:
|
||||
var idx := args.find(name)
|
||||
if idx >= 0 and idx + 1 < args.size():
|
||||
return args[idx + 1]
|
||||
return default
|
||||
|
||||
|
||||
func _res(path: String) -> String:
|
||||
if path.begins_with("res://") or path.begins_with("user://"):
|
||||
return path
|
||||
return "res://" + path.trim_prefix("./").trim_prefix("/")
|
||||
@@ -0,0 +1 @@
|
||||
uid://d16p5f4t34jpy
|
||||
Vendored
+1
-1
Submodule third_party/StormLib updated: 448dd9a824...06d13e5c1b
Reference in New Issue
Block a user