Files
ElHombreAlex 35cdf71054 V0.1
First publishable version of the mod
2026-10-03 12:59:33 +02:00

141 lines
7.3 KiB
GDScript

extends SceneTree
const ShipModel = preload("res://scripts/ship_model.gd")
func _initialize() -> void:
call_deferred("_run")
func _run() -> void:
root.size = Vector2i(1280, 720)
var args := OS.get_cmdline_user_args()
var state_path := "res://local_game_data/live_state.json"
var output_path := ""
for argument in args:
if argument.begins_with("--state="):
state_path = argument.trim_prefix("--state=")
elif argument.begins_with("--output="):
output_path = argument.trim_prefix("--output=")
var data: Dictionary = JSON.parse_string(FileAccess.get_file_as_string(state_path))
var side := "enemy" if args.has("--enemy") else "player"
if not data.has(side):
push_error("No native %s ship in the current snapshot" % side)
quit(1)
return
var native_ship: Dictionary = data[side]
var ship := ShipModel.new()
root.add_child(ship)
ship.build(str(native_ship.get("asset_key", native_ship.layout)), side == "enemy")
ship.inspect_rooms = true
ship.apply_live(native_ship)
ship.simulation_paused = true
var environment := WorldEnvironment.new()
var settings := Environment.new()
settings.background_mode = Environment.BG_COLOR
settings.background_color = Color("101822")
settings.ambient_light_source = Environment.AMBIENT_SOURCE_COLOR
settings.ambient_light_color = Color("d4e7f2")
settings.ambient_light_energy = 0.45
environment.environment = settings
root.add_child(environment)
var light := DirectionalLight3D.new()
light.rotation_degrees = Vector3(-35, -25, 0)
light.light_energy = 1.5
root.add_child(light)
var camera := Camera3D.new()
camera.projection = Camera3D.PROJECTION_ORTHOGONAL
camera.size = maxf(2.0, maxf(ship.shield_radii.x, ship.shield_radii.z) * 2.35)
var view_center := Vector3(ship.shield_center.x, 0, ship.shield_center.z)
camera.position = view_center + Vector3(1.2, 2.3, 2.1)
root.add_child(camera)
camera.look_at(view_center)
ship.set_viewer_position(camera.global_position)
for i in range(12):
await process_frame
await RenderingServer.frame_post_draw
var path := ProjectSettings.globalize_path("res://local_game_data/native_models%s_preview.png" % ("_enemy" if side == "enemy" else ""))
if not output_path.is_empty():
path = ProjectSettings.globalize_path(output_path)
root.get_texture().get_image().save_png(path)
print("NATIVE_MODEL_CAPTURE ", side, " ", path, " crew=", ship.crew_nodes.size(), " doors=", ship.door_nodes.size(), " drones=", ship.drone_nodes.size(), " hull_voxels=", ship.hull_voxel_count)
var weapon_charge_state: Array = []
for slot in range(mini(ship.weapon_nodes.size(), native_ship.get("weapons", []).size())):
var weapon: Node3D = ship.weapon_nodes[slot]
weapon_charge_state.append({"slot": slot, "name": weapon.weapon_name, "powered": weapon.powered,
"charge_fraction": weapon.charge, "stored_shots": weapon.charge_level, "stored_max": weapon.charge_max})
var door_tiers: Dictionary = {}
for door in ship.door_nodes.values():
var tier: int = door.get_meta("blast_tier", 0)
door_tiers[tier] = int(door_tiers.get(tier, 0)) + 1
print("NATIVE_VISUAL_STATE weapons=", weapon_charge_state, " fire_tiles=", ship.room_hazards.fire_points.size(),
" breach_tiles=", ship.room_hazards.breach_points.size(), " effective_door_tiers=", door_tiers)
var crew_facing: Array = []
for miniature in ship.crew_nodes.values():
var model: Node3D = miniature.get_node("Model")
if model.has_method("face_viewer"):
var direction: Vector3 = ship.to_local(camera.global_position) - miniature.position
crew_facing.append({"id": miniature.get_meta("crew_id"), "state": model.animation_state,
"visible": miniature.visible,
"yaw_error": absf(wrapf(model.rotation.y - atan2(-direction.x, -direction.z), -PI, PI)),
"body_pitch": model.rotation.x, "body_roll": model.rotation.z})
elif model.get("family") != null:
crew_facing.append({"id": miniature.get_meta("crew_id"), "drone_family": model.family, "visible": miniature.visible})
print("NATIVE_CREW_FACING ", crew_facing)
var drone_models: Array = []
for native_drone in native_ship.get("drones", []):
var drone_id := str(native_drone.get("id", ""))
if ship.drone_nodes.has(drone_id):
var model: Node3D = ship.drone_nodes[drone_id]
drone_models.append({"id": drone_id, "name": model.drone_name, "family": model.family,
"position_error": model.position.distance_to(ship.pixel_point(native_drone, 0.3)),
"angle_error": absf(wrapf(model.rotation.y + deg_to_rad(float(native_drone.get("angle", 0))), -PI, PI))})
print("NATIVE_DRONE_MODELS ", drone_models)
var outside_footprint := 0
var outside_volume := 0
var outside_native_footprint := 0
var max_native_radial := 0.0
var shape: Dictionary = native_ship.get("shield_shape", {})
var native_radii := Vector2(float(shape.get("a", 0)) / 35.0 * ship.TILE, float(shape.get("b", 0)) / 35.0 * ship.TILE)
var hull: MultiMeshInstance3D = ship.get_node_or_null("ExtrudedHull")
if hull != null:
for i in range(hull.multimesh.instance_count):
var transform := hull.multimesh.get_instance_transform(i)
if native_radii.x > 0 and native_radii.y > 0:
var delta := transform.origin - ship.shield_center
var radial := Vector2(delta.x / native_radii.x, delta.z / native_radii.y).length()
max_native_radial = maxf(max_native_radial, radial)
outside_native_footprint += 1 if radial > 1.0 else 0
var local := (transform.origin - ship.shield_center) / ship.shield_radii
if local.x * local.x + local.z * local.z > 1.0:
outside_footprint += 1
local.y -= transform.basis.y.length() * 0.5 / ship.shield_radii.y
if local.length_squared() > 1.0:
outside_volume += 1
var max_room_alignment_px := 0.0
var max_mount_alignment_px := 0.0
var native_weapons: Array = native_ship.get("weapons", [])
var source_mounts: Array = ship.layout_data.get("weapon_mounts", [])
for slot in range(mini(native_weapons.size(), source_mounts.size())):
var native_mount: Dictionary = native_weapons[slot].get("mount", {})
if not native_mount.is_empty():
var source_mount: Dictionary = source_mounts[slot]
max_mount_alignment_px = maxf(max_mount_alignment_px, Vector2(float(native_mount.x) - float(source_mount.x), float(native_mount.y) - float(source_mount.y)).length())
var outside_corners := 0
var max_corner_radius := 0.0
for point in ship.shield_fit_points:
var radius: float = ((point - ship.shield_center) / ship.shield_radii).length()
max_corner_radius = maxf(max_corner_radius, radius)
outside_corners += 1 if radius > 1.001 else 0
for room in native_ship.get("rooms", []):
if ship.room_nodes.has(int(room["id"])):
var native_center: Vector3 = ship.pixel_point(room.get("center", {}), 0.065)
var error: Vector3 = native_center - ship.room_nodes[int(room["id"])].position
max_room_alignment_px = maxf(max_room_alignment_px, Vector2(error.x, error.z).length() * 35.0 / ship.TILE)
print("SHIELD_MODEL_GEOMETRY native=", shape, " local_center=", ship.shield_center, " radii=", ship.shield_radii, " padding=", ship.shield_fit_padding,
" native_outside_footprint=", outside_native_footprint, " native_radial_max=", max_native_radial, " outside_footprint=", outside_footprint,
" outside_keel=", outside_volume, " outside_hull_wall_corners=", outside_corners, " corner_radial_max=", max_corner_radius,
" room_alignment_max_px=", max_room_alignment_px, " weapon_mount_alignment_max_px=", max_mount_alignment_px,
" texture=", ship.layout_data.get("image_source_path", ""), " image_rect=", ship.layout_data.get("image_rect", {}))
quit()