Merge branch 'main' into improve-ui

This commit is contained in:
2026-06-06 15:25:00 +02:00
210 changed files with 4736 additions and 1438 deletions

View File

@@ -7,6 +7,8 @@
[node name="AiCow" unique_id=1228675528 node_paths=PackedStringArray("anim_player") instance=ExtResource("1_p2hpa")]
anim_player = NodePath("CowMannequin/AnimationPlayer")
entity_type = 1
entity_name = "Cow"
[node name="StateMachine" parent="." index="1" unique_id=1286404264 node_paths=PackedStringArray("initial_state")]
initial_state = NodePath("IdleState")

View File

@@ -15,6 +15,8 @@ _data = {
[node name="AiHorse" unique_id=1228675528 node_paths=PackedStringArray("anim_player") instance=ExtResource("1_e5v3h")]
anim_player = NodePath("HorseMannequin/AnimationPlayer")
entity_type = 1
entity_name = "Horse"
[node name="StateMachine" parent="." index="1" unique_id=1286404264 node_paths=PackedStringArray("initial_state")]
initial_state = NodePath("IdleState")
@@ -35,7 +37,7 @@ exit_on_action_finished = true
[node name="HorseMannequin" parent="." index="3" unique_id=1289880358 instance=ExtResource("2_4t6jw")]
transform = Transform3D(0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, -0.9, 0)
[node name="Skeleton3D" parent="HorseMannequin/Armature" parent_id_path=PackedInt32Array(1289880358, 245823720) index="0" unique_id=494955820]
[node name="Skeleton3D" parent="HorseMannequin/Armature" parent_id_path=PackedInt32Array(1289880358, 1841497289) index="0" unique_id=1502661928]
bones/1/rotation = Quaternion(0.7071068, -6.209646e-07, -6.209645e-07, 0.7071067)
bones/4/rotation = Quaternion(0.0012952884, -0.0012955684, 0.7071056, 0.7071057)
bones/5/rotation = Quaternion(0.70685357, -0.70227593, -0.04508998, 0.07164877)
@@ -63,7 +65,7 @@ bones/33/rotation = Quaternion(0.7071068, -6.209646e-07, -6.209645e-07, 0.707106
bones/35/rotation = Quaternion(0.7071068, -9.581396e-07, -9.581394e-07, 0.7071067)
bones/37/rotation = Quaternion(0.7071068, -9.581396e-07, -9.581394e-07, 0.7071067)
[node name="AnimationPlayer" parent="HorseMannequin" index="1" unique_id=272680130]
[node name="AnimationPlayer" parent="HorseMannequin" index="1" unique_id=1876493257]
libraries/custom = SubResource("AnimationLibrary_or6xs")
[editable path="HorseMannequin"]

View File

@@ -3,8 +3,6 @@
[ext_resource type="PackedScene" uid="uid://mvh2v6v72stt" path="res://core/ai/agents/human/ai_human.tscn" id="1_awhwq"]
[node name="AiCitizen" unique_id=1228675528 instance=ExtResource("1_awhwq")]
[node name="StateMachine" parent="." index="3" unique_id=1286404264 node_paths=PackedStringArray("initial_state")]
initial_state = NodePath("")
entity_name = "Citizen"
[editable path="HumanMannequin"]

View File

@@ -3,11 +3,12 @@
[ext_resource type="PackedScene" uid="uid://bdqeshcwwnyc4" path="res://core/ai/agents/human/ai_citizen.tscn" id="1_cduuu"]
[node name="AiCitizenSitter" unique_id=1228675528 instance=ExtResource("1_cduuu")]
entity_name = "CitizenSitter"
[node name="SK_Mannequin" parent="HumanMannequin" parent_id_path=PackedInt32Array(333236377) index="0" unique_id=377304892]
[node name="SK_Mannequin" parent="HumanMannequin" parent_id_path=PackedInt32Array(333236377) index="0" unique_id=1085647626]
transform = Transform3D(0.99906886, 0.025971904, -0.03444738, 0.038254507, -0.16420224, 0.98568463, 0.019943757, -0.98608464, -0.1650429, 0.034450583, -0.44864154, 0.18535595)
[node name="Skeleton3D" parent="HumanMannequin/SK_Mannequin" index="0" unique_id=427572412]
[node name="Skeleton3D" parent="HumanMannequin/SK_Mannequin" index="0" unique_id=1674820390]
bones/2/rotation = Quaternion(-0.007029906, 0.032859802, -0.23654123, 0.97104025)
bones/3/rotation = Quaternion(-0.000884556, 0.0033522977, 0.10280211, 0.99469584)
bones/4/rotation = Quaternion(-0.00040807336, 0.0034836144, 0.0045103733, 0.9999837)
@@ -47,7 +48,7 @@ bones/55/rotation = Quaternion(0.0132777635, 0.10731075, 0.71409845, -0.6916441)
bones/56/rotation = Quaternion(0.03920827, -0.09832406, -0.75485575, 0.64729285)
bones/58/rotation = Quaternion(0.01656407, -0.06386153, 0.030505493, 0.9973549)
[node name="AnimationPlayer" parent="HumanMannequin" parent_id_path=PackedInt32Array(333236377) index="1" unique_id=233699491]
[node name="AnimationPlayer" parent="HumanMannequin" parent_id_path=PackedInt32Array(333236377) index="1" unique_id=1460197763]
autoplay = &"custom/sit"
[editable path="HumanMannequin"]

View File

@@ -5,8 +5,9 @@
[ext_resource type="Script" uid="uid://bngfthvt04ivv" path="res://core/ai/framework/patrol_state.gd" id="3_8d0tj"]
[node name="AiCitizenWalker" unique_id=1228675528 instance=ExtResource("1_dms8s")]
entity_name = "CitizenWalker"
[node name="StateMachine" parent="." index="3" unique_id=1286404264 node_paths=PackedStringArray("initial_state")]
[node name="StateMachine" parent="." index="1" unique_id=1286404264 node_paths=PackedStringArray("initial_state")]
initial_state = NodePath("IdleState")
[node name="IdleState" type="Node" parent="StateMachine" index="0" unique_id=42226979]

View File

@@ -5,8 +5,10 @@
[ext_resource type="Script" uid="uid://d3hy70ec8vqo5" path="res://core/ai/framework/run_animation_state.gd" id="4_2oda6"]
[node name="AiFarmer" unique_id=1228675528 instance=ExtResource("1_l2y7m")]
entity_name = "Farmer"
allowed_biomes = Array[String](["countryside"])
[node name="StateMachine" parent="." index="3" unique_id=1286404264 node_paths=PackedStringArray("initial_state")]
[node name="StateMachine" parent="." index="1" unique_id=1286404264 node_paths=PackedStringArray("initial_state")]
initial_state = NodePath("GatherState")
[node name="PatrolState" type="Node" parent="StateMachine" index="0" unique_id=930272128]

View File

@@ -15,6 +15,8 @@ _data = {
[node name="AiPig" unique_id=1228675528 node_paths=PackedStringArray("anim_player") instance=ExtResource("1_j8spt")]
anim_player = NodePath("PigMannequin/AnimationPlayer")
entity_type = 1
entity_name = "Pig"
[node name="StateMachine" parent="." index="1" unique_id=1286404264 node_paths=PackedStringArray("initial_state")]
initial_state = NodePath("IdleState")
@@ -35,7 +37,7 @@ exit_on_action_finished = true
[node name="PigMannequin" parent="." index="3" unique_id=926755470 instance=ExtResource("2_qmc2e")]
transform = Transform3D(0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, -0.9, 0)
[node name="Skeleton3D" parent="PigMannequin/Armature" parent_id_path=PackedInt32Array(926755470, 695496535) index="0" unique_id=725647261]
[node name="Skeleton3D" parent="PigMannequin/Armature" parent_id_path=PackedInt32Array(926755470, 2144155651) index="0" unique_id=1681287116]
bones/1/rotation = Quaternion(0.7071068, -7.052583e-07, -7.052583e-07, 0.7071067)
bones/3/position = Vector3(5.37765e-05, 0.017809996, -0.007695386)
bones/3/rotation = Quaternion(-0.027121998, 0, 0, 0.99963224)
@@ -70,7 +72,7 @@ bones/31/rotation = Quaternion(0.7071068, -1.0424332e-06, -1.0424329e-06, 0.7071
bones/33/position = Vector3(0.010670463, 0.0010000349, -0.03166372)
bones/33/rotation = Quaternion(0.70755845, -7.1388774e-07, -1.0355643e-06, 0.7066547)
[node name="AnimationPlayer" parent="PigMannequin" index="1" unique_id=904091745]
[node name="AnimationPlayer" parent="PigMannequin" index="1" unique_id=1489956231]
libraries/custom = SubResource("AnimationLibrary_lvpc5")
[editable path="PigMannequin"]

View File

@@ -15,6 +15,8 @@ _data = {
[node name="AiPug" unique_id=1228675528 node_paths=PackedStringArray("anim_player") instance=ExtResource("1_0bu1i")]
anim_player = NodePath("PugMannequin/AnimationPlayer")
entity_type = 1
entity_name = "Pug"
[node name="StateMachine" parent="." index="1" unique_id=1286404264 node_paths=PackedStringArray("initial_state")]
initial_state = NodePath("IdleState")
@@ -35,7 +37,7 @@ exit_on_action_finished = true
[node name="PugMannequin" parent="." index="3" unique_id=1732134047 instance=ExtResource("2_n0mit")]
transform = Transform3D(0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, -0.9, 0)
[node name="Skeleton3D" parent="PugMannequin/Armature" parent_id_path=PackedInt32Array(1732134047, 199608791) index="0" unique_id=33809722]
[node name="Skeleton3D" parent="PugMannequin/Armature" parent_id_path=PackedInt32Array(1732134047, 413342048) index="0" unique_id=1846443987]
bones/8/position = Vector3(-0.0054483665, 0.008346455, -0.020266803)
bones/8/rotation = Quaternion(-0.007561639, 0.007561228, 0.70706636, 0.70706636)
bones/9/rotation = Quaternion(0.6665347, -0.6790185, 0.20055033, -0.23333457)
@@ -49,7 +51,7 @@ bones/20/rotation = Quaternion(0.6013276, -0.007656022, 0.017799761, 0.79876757)
bones/24/rotation = Quaternion(-0.45064288, -0.22904137, 0.090387635, 0.858074)
bones/27/rotation = Quaternion(0.05229574, 5.703821e-05, -0.025155801, 0.99831474)
[node name="AnimationPlayer" parent="PugMannequin" index="1" unique_id=1653203922]
[node name="AnimationPlayer" parent="PugMannequin" index="1" unique_id=1265653636]
libraries/custom = SubResource("AnimationLibrary_iapui")
[editable path="PugMannequin"]

View File

@@ -15,6 +15,8 @@ _data = {
[node name="AiSheep" unique_id=1228675528 node_paths=PackedStringArray("anim_player") instance=ExtResource("1_smbiq")]
anim_player = NodePath("SheepMannequin/AnimationPlayer")
entity_type = 1
entity_name = "Sheep"
[node name="StateMachine" parent="." index="1" unique_id=1286404264 node_paths=PackedStringArray("initial_state")]
initial_state = NodePath("IdleState")
@@ -35,10 +37,10 @@ exit_on_action_finished = true
[node name="SheepMannequin" parent="." index="3" unique_id=1153770042 instance=ExtResource("2_hnenk")]
transform = Transform3D(0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, -0.9, 0)
[node name="Armature" parent="SheepMannequin" index="0" unique_id=62421163]
[node name="Armature" parent="SheepMannequin" index="0" unique_id=1455361254]
transform = Transform3D(100, 0, 0, 0, -4.3711384e-06, 99.99999, 0, -99.99999, -4.3711384e-06, 0, 0, 0)
[node name="AnimationPlayer" parent="SheepMannequin" index="1" unique_id=676833932]
[node name="AnimationPlayer" parent="SheepMannequin" index="1" unique_id=2025108985]
libraries/custom = SubResource("AnimationLibrary_vlyix")
[editable path="SheepMannequin"]

View File

@@ -39,9 +39,12 @@ const RIVER_NEIGHBOUR_OFFSETS: Dictionary = {
}
@export_group("Generation")
@export var chunk_generation_frame_budget_usec: int = 1500 #2 ms/frame to generate chunks
@export var chunk_cleanup_frame_budget_usec: int = 1000 #1 ms/frame per cleanup
@export var lampost_wire_frame_budget_usec: int = 1000 #1 ms/frame per i fili dei lampioni
#ms/frame to generate chunks
@export var chunk_generation_frame_budget_usec: int = 1500
#ms/frame per cleanup
@export var chunk_cleanup_frame_budget_usec: int = 1000
#ms/frame per i fili dei lampioni
@export var lampost_wire_frame_budget_usec: int = 1000
#(about 4 ms of work for frame)
#Se compaiono chunk troppo lentamente davanti al treno:
#aumentare generazione a 3000 o 4000
@@ -53,35 +56,55 @@ const RIVER_NEIGHBOUR_OFFSETS: Dictionary = {
#abbassare cleanup a 500
@export_group("Rails")
@export var rail_path: Path3D #rail path
##rail path
@export var rail_path: Path3D
##list of railways to choose from
@export var railway_pool: Resource
@export_group("Biomes")
@export var biome_list: Array[Biome] #list of scenes for the biome
##list of scenes for the biome
@export var biome_list: Array[Biome]
@export_group("Entities")
##list of entities to choose from
@export var entity_pool: Resource
##propability of entity spawn (e.g. entity_spawn_probability 0.6 * spawn_chance 1.0 = 60%)
@export_range(0.0, 1.0, 0.01) var entity_spawn_probability: float = 0.6
##max spawnable entities per chunk
@export_range(0, 20, 1) var max_entities_per_chunk: int = 3
@export_group("Grid and Area")
@export var chunk_size: float = 20.0 #size of a cell; default 20 (global position is defined dividing x and z for this value)
@export var eye_line: int = 3 #cells to be considerated around the train (e.g. 3 => a square of cells from -3 to 3 around train cell)
@export var district_scale: float = 0.05 #noise value to distribuite biome; low values create large area, high values create biome with more variants
##size of a cell; default 20 (global position is defined dividing x and z for this value)
@export var chunk_size: float = 20.0
##cells to be considerated around the train (e.g. 3 => a square of cells from -3 to 3 around train cell)
@export var eye_line: int = 3
##noise value to distribuite biome; low values create large area, high values create biome with more variants
@export var district_scale: float = 0.05
@export_group("Lamppost")
##lampost wire material
@export var lamppost_wire_material: ShaderMaterial
##lampost wire thickness
@export_range(0.01, 1.0) var wire_thickness: float = 0.05
@export var lamppost_dist_factor: int = 10 #max distance of connections
##max distance of connections
@export var lamppost_dist_factor: int = 10
##max cells to search around a lamppost chunk
@export_range(1, 6, 1) var lamppost_search_radius_cells: int = 3
##max allowed distance between lamppost pairs
@export var lamppost_max_wire_distance: float = 60.0
##if true wire connections blocked by colliders are discarded
@export var lamppost_obstacle_check_enabled: bool = true
var board: Dictionary = {}
var last_pos_train: Vector2i = Vector2i(999999, 999999)
var noise_generator: FastNoiseLite
var altitude_generator: FastNoiseLite
var wire_connections: Dictionary = {}
var wire_connection_pairs: Dictionary = {}
var chunk_candidate_cache: Dictionary = {} #node cache (metadata)
var prop_candidate_cache: Dictionary = {}
var entity_candidate_cache: Dictionary = {}
var static_entity_spawn_roots: Dictionary = {}
var pending_generation_cells: Array[Vector2i] = []
var pending_cleanup_cells: Array[Vector2i] = []
var pending_wire_cells: Array[Vector2i] = []
@@ -116,6 +139,7 @@ func _ready() -> void:
_warm_rail_chunk_catalogue()
#set unique pieces
_update_set_pieces()
_spawn_entities_for_static_spawn_points()
func _update_set_pieces() -> void:
var set_pieces = get_tree().get_nodes_in_group("set_pieces")
@@ -163,6 +187,7 @@ func _destroy_and_regenrate_world() -> void:
#Clean board and wire connections
board.clear()
wire_connections.clear()
wire_connection_pairs.clear()
#Create train
last_pos_train = Vector2i(999999, 999999)
@@ -540,6 +565,18 @@ func _queue_lamppost_wire_connection(grid_pos: Vector2i) -> void:
pending_wire_lookup[grid_pos] = true
pending_wire_cells.append(grid_pos)
func _queue_lamppost_wire_connections_around(grid_pos: Vector2i) -> void:
_queue_lamppost_wire_connection(grid_pos)
for x in range(-lamppost_search_radius_cells, lamppost_search_radius_cells + 1):
for z in range(-lamppost_search_radius_cells, lamppost_search_radius_cells + 1):
if x == 0 and z == 0:
continue
var near_pos = grid_pos + Vector2i(x, z)
if board.has(near_pos) and board[near_pos].get("have_lamppost", false):
_queue_lamppost_wire_connection(near_pos)
func _drain_wire_queue() -> void:
var processed: int = 0
var start_usec: int = Time.get_ticks_usec()
@@ -714,15 +751,11 @@ func _get_prop_scene_uniqueness(scene: PackedScene) -> int:
prop_candidate_cache[key] = uniqueness
return uniqueness
func _get_marker_prop_uniqueness(marker: Node) -> int:
var uniqueness = _get_prop_uniqueness_from_info(marker)
if uniqueness == -1:
return 0
return uniqueness
func _pick_weighted_prop_scene(marker: Node) -> PackedScene:
var candidates = []
var fallback_uniqueness = _get_marker_prop_uniqueness(marker)
var fallback_uniqueness = _get_prop_uniqueness_from_info(marker)
if fallback_uniqueness == -1:
fallback_uniqueness = 0
for prop_scene in marker.available_props:
if prop_scene == null:
@@ -766,6 +799,71 @@ func _spawn_prop_for_marker(marker: Node) -> void:
marker.add_child(prop_node)
prop_node.transform = Transform3D.IDENTITY
func _get_static_entity_spawn_root(root: Node) -> Node:
var current: Node = root
while current != null and current != get_tree().root:
var spawn_points: Array[Node] = []
collect_all_entity_spawn_points(current, spawn_points)
if not spawn_points.is_empty():
return current
current = current.get_parent()
return null
func _get_static_spawn_chunk_root_from_point(spawn_point: Node) -> Node:
var current: Node = spawn_point
while current != null and current != get_tree().root:
var info_list: Array[Node] = []
collect_all_chunkinfo(current, info_list)
if not info_list.is_empty():
return current
current = current.get_parent()
return null
func _get_static_entity_spawn_key(spawn_root: Node) -> String:
if spawn_root.scene_file_path != "":
return spawn_root.scene_file_path
return "instance:%s" % spawn_root.get_instance_id()
func _spawn_entities_for_static_spawn_points() -> void:
var current_scene = get_tree().current_scene
if current_scene == null:
return
var spawn_points: Array[Node] = []
collect_all_entity_spawn_points(current_scene, spawn_points)
for spawn_point in spawn_points:
var spawn_root = _get_static_spawn_chunk_root_from_point(spawn_point)
if spawn_root == null:
continue
var point_node = spawn_point as Node3D
var grid_pos = Vector2i.ZERO
if point_node != null:
grid_pos = Vector2i(roundi(point_node.global_position.x / chunk_size), roundi(point_node.global_position.z / chunk_size))
_spawn_entities_for_static_obstacle(spawn_root, grid_pos)
func _spawn_entities_for_static_obstacle(root: Node, grid_pos: Vector2i) -> void:
if root == null or not is_instance_valid(root):
return
var spawn_root = _get_static_entity_spawn_root(root)
if spawn_root == null or not is_instance_valid(spawn_root):
return
var root_key: String = _get_static_entity_spawn_key(spawn_root)
if static_entity_spawn_roots.has(root_key):
var tracked_root = static_entity_spawn_roots[root_key]
if is_instance_valid(tracked_root):
return
static_entity_spawn_roots.erase(root_key)
static_entity_spawn_roots[root_key] = spawn_root
_spawn_entities_for_chunk(spawn_root, _choose_biome_name_by_cell(grid_pos))
func _spawn_entities_for_chunk(root: Node, biome_name: String) -> void:
if entity_pool == null or not "available_entities" in entity_pool:
return
@@ -929,7 +1027,9 @@ func _register_cell_with_ray(grid_pos: Vector2i) -> bool:
}
if have_lamppost:
_queue_lamppost_wire_connection(grid_pos)
_queue_lamppost_wire_connections_around(grid_pos)
_spawn_entities_for_static_obstacle(root_chunk, grid_pos)
return true
return false
@@ -1036,7 +1136,8 @@ func _add_compatible_biome(grid_pos: Vector2i) -> void:
have_lamppost = info_new.have_lamppost
var river_flow_direction = _calculate_river_flow_direction(grid_pos, choise.data["river_connections"])
_apply_river_flow_direction(new_chunk, river_flow_direction)
if !river_flow_direction.is_zero_approx():
_set_river_flow_direction_recursive(new_chunk, river_flow_direction.normalized())
board[grid_pos] = {
"type": "biome",
@@ -1051,7 +1152,7 @@ func _add_compatible_biome(grid_pos: Vector2i) -> void:
}
if have_lamppost:
_queue_lamppost_wire_connection(grid_pos)
_queue_lamppost_wire_connections_around(grid_pos)
else:
var backup_scene = _pick_backup_scene(zone_catalogue, grid_pos)
@@ -1167,11 +1268,6 @@ func _get_average_river_side_direction(sides: Array[String]) -> Vector2:
return Vector2.ZERO
return direction / float(sides.size())
func _apply_river_flow_direction(root: Node, flow_direction: Vector2) -> void:
if flow_direction.is_zero_approx():
return
_set_river_flow_direction_recursive(root, flow_direction.normalized())
func _set_river_flow_direction_recursive(node: Node, flow_direction: Vector2) -> void:
if node is MeshInstance3D and node.name.begins_with("Water_F"):
var mesh_instance := node as MeshInstance3D
@@ -1211,6 +1307,13 @@ func _get_lampposts(info_node: Node, side: String) -> Array[Node3D]:
if is_instance_valid(p): lampposts.append(p)
return lampposts
func _get_wire_connection_pair_key(root_a: Node, root_b: Node) -> String:
var id_a: int = root_a.get_instance_id()
var id_b: int = root_b.get_instance_id()
if id_a < id_b:
return str(id_a, ":", id_b)
return str(id_b, ":", id_a)
func _connect_lamppost_wires(new_board_pos: Vector2i) -> void:
var new_cell = board[new_board_pos]
var new_root = new_cell["node"]
@@ -1228,12 +1331,11 @@ func _connect_lamppost_wires(new_board_pos: Vector2i) -> void:
if wire_connections[new_id] >= 2: return
var p_sx_my_best = null; var p_dx_my_best = null
var p_sx_your_best = null; var p_dx_your_best = null
var best_closest_to_root = null
var best_candidate: Dictionary = {}
var best_distance = 999999.0
var ray_research = 6
var ray_research: int = lamppost_search_radius_cells
var max_dist: float = minf(lamppost_max_wire_distance, chunk_size * lamppost_dist_factor)
for x in range(-ray_research, ray_research + 1):
for z in range(-ray_research, ray_research + 1):
if x == 0 and z == 0: continue
@@ -1247,9 +1349,10 @@ func _connect_lamppost_wires(new_board_pos: Vector2i) -> void:
var closest_id = closest_root.get_instance_id()
var closest_connections = wire_connections.get(closest_id, 0)
var pair_key = _get_wire_connection_pair_key(new_root, closest_root)
if wire_connection_pairs.has(pair_key): continue
if closest_connections >= 2: continue
if closest_info is Node3D: closest_info.force_update_transform()
var closest_sx = _get_lampposts(closest_info, "sx")
var closest_dx = _get_lampposts(closest_info, "dx")
@@ -1260,32 +1363,99 @@ func _connect_lamppost_wires(new_board_pos: Vector2i) -> void:
var my_c = (new_sx[i_m].global_position + new_dx[i_m].global_position) / 2.0
var your_c = (closest_sx[i_t].global_position + closest_dx[i_t].global_position) / 2.0
var dist = my_c.distance_to(your_c)
if dist > max_dist:
continue
var p_sx_my = new_sx[i_m]
var p_dx_my = new_dx[i_m]
var p_sx_your = closest_sx[i_t]
var p_dx_your = closest_dx[i_t]
var dist_streight = p_sx_my.global_position.distance_to(p_sx_your.global_position) + p_dx_my.global_position.distance_to(p_dx_your.global_position)
var dist_cross = p_sx_my.global_position.distance_to(p_dx_your.global_position) + p_dx_my.global_position.distance_to(p_sx_your.global_position)
var use_cross = dist_cross < dist_streight
if use_cross:
if _is_wire_path_blocked(p_sx_my.global_position, p_dx_your.global_position, [new_root, closest_root]):
continue
if _is_wire_path_blocked(p_dx_my.global_position, p_sx_your.global_position, [new_root, closest_root]):
continue
else:
if _is_wire_path_blocked(p_sx_my.global_position, p_sx_your.global_position, [new_root, closest_root]):
continue
if _is_wire_path_blocked(p_dx_my.global_position, p_dx_your.global_position, [new_root, closest_root]):
continue
if dist < best_distance:
best_distance = dist
best_closest_to_root = closest_root
p_sx_my_best = new_sx[i_m]
p_dx_my_best = new_dx[i_m]
p_sx_your_best = closest_sx[i_t]
p_dx_your_best = closest_dx[i_t]
var max_dist = chunk_size * lamppost_dist_factor
if best_closest_to_root != null and best_distance < max_dist:
var dist_streight = p_sx_my_best.global_position.distance_to(p_sx_your_best.global_position) + p_dx_my_best.global_position.distance_to(p_dx_your_best.global_position)
var dist_cross = p_sx_my_best.global_position.distance_to(p_dx_your_best.global_position) + p_dx_my_best.global_position.distance_to(p_sx_your_best.global_position)
if dist_streight <= dist_cross:
_draw_parable(p_sx_my_best.global_position, p_sx_your_best.global_position, new_root)
_draw_parable(p_dx_my_best.global_position, p_dx_your_best.global_position, new_root)
best_candidate = {
"closest_root": closest_root,
"pair_key": pair_key,
"p_sx_my": p_sx_my,
"p_dx_my": p_dx_my,
"p_sx_your": p_sx_your,
"p_dx_your": p_dx_your,
"use_cross": use_cross,
}
if not best_candidate.is_empty():
if best_candidate["use_cross"]:
_draw_parable(best_candidate["p_sx_my"].global_position, best_candidate["p_dx_your"].global_position, new_root)
_draw_parable(best_candidate["p_dx_my"].global_position, best_candidate["p_sx_your"].global_position, new_root)
else:
_draw_parable(p_sx_my_best.global_position, p_dx_your_best.global_position, new_root)
_draw_parable(p_dx_my_best.global_position, p_sx_your_best.global_position, new_root)
_draw_parable(best_candidate["p_sx_my"].global_position, best_candidate["p_sx_your"].global_position, new_root)
_draw_parable(best_candidate["p_dx_my"].global_position, best_candidate["p_dx_your"].global_position, new_root)
wire_connections[new_id] += 1
var closest_id = best_closest_to_root.get_instance_id()
wire_connection_pairs[best_candidate["pair_key"]] = true
var closest_id = best_candidate["closest_root"].get_instance_id()
if not wire_connections.has(closest_id): wire_connections[closest_id] = 0
wire_connections[closest_id] += 1
if wire_connections[new_id] < 2:
_queue_lamppost_wire_connection(new_board_pos)
func _get_wire_sample_point(p1: Vector3, p2: Vector3, t: float) -> Vector3:
var lowering: float = 1.5
var point: Vector3 = p1.lerp(p2, t)
var gravity: float = lowering * (1.0 - pow(2.0 * t - 1.0, 2.0))
point.y -= gravity
return point
func _collect_wire_excluded_rids(root: Node, excluded_rids: Array[RID]) -> void:
if root == null:
return
var collision_object = root as CollisionObject3D
if collision_object != null:
excluded_rids.append(collision_object.get_rid())
for child in root.get_children():
_collect_wire_excluded_rids(child, excluded_rids)
func _get_wire_excluded_rids(excluded_roots: Array) -> Array[RID]:
var excluded_rids: Array[RID] = []
for root in excluded_roots:
_collect_wire_excluded_rids(root, excluded_rids)
return excluded_rids
func _is_wire_path_blocked(p1: Vector3, p2: Vector3, excluded_roots: Array = []) -> bool:
if not lamppost_obstacle_check_enabled:
return false
var space_state = get_world_3d().direct_space_state
var excluded_rids: Array[RID] = _get_wire_excluded_rids(excluded_roots)
var previous_point: Vector3 = _get_wire_sample_point(p1, p2, 0.08)
var segments: int = 12
for i in range(1, segments + 1):
var t: float = lerpf(0.08, 0.92, float(i) / float(segments))
var next_point: Vector3 = _get_wire_sample_point(p1, p2, t)
var query = PhysicsRayQueryParameters3D.create(previous_point, next_point)
query.exclude = excluded_rids
query.collide_with_areas = true
var result = space_state.intersect_ray(query)
if not result.is_empty():
return true
previous_point = next_point
return false
#draw lamppost wires
func _draw_parable(p1: Vector3, p2: Vector3, parent: Node3D) -> void:

View File

@@ -1,9 +1,18 @@
[gd_resource type="Resource" script_class="EntityPool" format=3 uid="uid://cmd6s6thq4f7r"]
[ext_resource type="PackedScene" uid="uid://clx701xdwelgx" path="res://core/ai/agents/base/ai_base.tscn" id="1_0kfj8"]
[ext_resource type="PackedScene" uid="uid://dd8wn62anbts8" path="res://core/ai/agents/cow/ai_cow.tscn" id="1_iqga3"]
[ext_resource type="Script" uid="uid://53ryr0fsqiq7" path="res://core/biome_generator/entity_pool.gd" id="1_vccp2"]
[ext_resource type="PackedScene" uid="uid://c2hg6hu2y5srb" path="res://core/ai/agents/pig/ai_pig.tscn" id="2_76rvd"]
[ext_resource type="PackedScene" uid="uid://2md4l83fy8kr" path="res://core/ai/agents/pug/ai_pug.tscn" id="3_hq17p"]
[ext_resource type="PackedScene" uid="uid://cayakdk7gmlyg" path="res://core/ai/agents/horse/ai_horse.tscn" id="4_5yjl1"]
[ext_resource type="PackedScene" uid="uid://mvh2v6v72stt" path="res://core/ai/agents/human/ai_human.tscn" id="5_xd1cg"]
[ext_resource type="PackedScene" uid="uid://bs1bdtm7jdtgb" path="res://core/ai/agents/sheep/ai_sheep.tscn" id="6_ql0wl"]
[ext_resource type="PackedScene" uid="uid://ceqxsqfiotm5j" path="res://core/ai/agents/human/ai_farmer.tscn" id="7_hhs8l"]
[ext_resource type="PackedScene" uid="uid://bdqeshcwwnyc4" path="res://core/ai/agents/human/ai_citizen.tscn" id="8_8l6th"]
[ext_resource type="PackedScene" uid="uid://bbseno7clbepx" path="res://core/ai/agents/human/ai_citizen_sitter.tscn" id="9_x3pn3"]
[ext_resource type="PackedScene" uid="uid://bnnuke5e7e1yr" path="res://core/ai/agents/human/ai_citizen_walker.tscn" id="10_ctysb"]
[resource]
script = ExtResource("1_vccp2")
name = "Entity Pool"
available_entities = Array[PackedScene]([ExtResource("1_0kfj8")])
available_entities = Array[PackedScene]([ExtResource("1_iqga3"), ExtResource("2_76rvd"), ExtResource("3_hq17p"), ExtResource("4_5yjl1"), ExtResource("5_xd1cg"), ExtResource("6_ql0wl"), ExtResource("7_hhs8l"), ExtResource("8_8l6th"), ExtResource("9_x3pn3"), ExtResource("10_ctysb")])

View File

@@ -538,10 +538,6 @@ func _snap_wagons_to_progress(total_length: float = 0.0) -> void:
if total_length <= 0.0:
return
var direction: float = 1.0
if train_speed < 0.0:
direction = -1.0
for i in range(wagon_instances.size()):
var wagon: Node3D = wagon_instances[i]
if not is_instance_valid(wagon):
@@ -551,7 +547,7 @@ func _snap_wagons_to_progress(total_length: float = 0.0) -> void:
if i < wagon_progress_offsets.size():
wagon_offset = wagon_progress_offsets[i]
var wagon_progress: float = train_progress - direction * wagon_offset
var wagon_progress: float = train_progress - wagon_offset
var vehicle_progress: float = wrapf(wagon_progress, 0.0, total_length)
var center_position: Vector3 = to_global(curve.sample_baked(vehicle_progress, true))

View File

@@ -10,9 +10,8 @@
[ext_resource type="PackedScene" uid="uid://fi6faw7ag1i0" path="res://tgcc/chunk/railway/scene/chunk_railway_curve_3.tscn" id="8_r0882"]
[ext_resource type="PackedScene" uid="uid://dglpoh63x2lpy" path="res://tgcc/chunk/railway/scene/chunk_railway_curve_4.tscn" id="9_3auto"]
[ext_resource type="Script" uid="uid://c374rv220mvh1" path="res://core/biome_generator/railway_pool.gd" id="9_8tdc7"]
[ext_resource type="PackedScene" uid="uid://bup6gwlxos0w2" path="res://tgcc/chunk/railway/hero/chunk_railway_station_hero.tscn" id="10_3auto"]
[resource]
script = ExtResource("9_8tdc7")
name = "Railway Pool"
available_railways = Array[PackedScene]([ExtResource("1_86h1y"), ExtResource("3_3auto"), ExtResource("4_i1umq"), ExtResource("5_x44at"), ExtResource("6_vrrkw"), ExtResource("7_l17bw"), ExtResource("8_qcl5o"), ExtResource("8_r0882"), ExtResource("9_3auto"), ExtResource("10_3auto")])
available_railways = Array[PackedScene]([ExtResource("1_86h1y"), ExtResource("3_3auto"), ExtResource("4_i1umq"), ExtResource("5_x44at"), ExtResource("6_vrrkw"), ExtResource("7_l17bw"), ExtResource("8_qcl5o"), ExtResource("8_r0882"), ExtResource("9_3auto")])

View File

@@ -1,6 +1,9 @@
class_name EdgeDetectionCompositor
extends CompositorEffect
# --- MODIFICATO: Parametro esportato per l'Inspector ---
@export_range(0.0, 5.0, 0.1) var line_thickness: float = 1.0
var rd: RenderingDevice
var shader: RID
var pipeline: RID
@@ -78,8 +81,8 @@ func _render_callback(p_effect_callback_type: EffectCallbackType, p_render_data:
var texture_sampler = RDSamplerState.new()
texture_sampler = rd.sampler_create(texture_sampler)
var parameters := PackedFloat32Array([size.x, size.y, 0.0, 0.0])
# --- MODIFICATO: Inviato il parametro line_thickness nel buffer GPU ---
var parameters := PackedFloat32Array([size.x, size.y, line_thickness, 0.0])
var inv_proj_mat := p_render_data.get_render_scene_data().get_cam_projection().inverse()
var inv_proj_mat_array := PackedVector4Array([inv_proj_mat.x, inv_proj_mat.y, inv_proj_mat.z, inv_proj_mat.w])

View File

@@ -4,9 +4,11 @@
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
// --- MODIFICATO: Inserito line_thickness e mantenuto il padding (reserved) ---
layout(set = 0, binding = 0, std430) readonly buffer Params {
vec2 raster_size;
vec2 reserved;
float line_thickness;
float reserved;
mat4 inv_proj_mat;
} params;
@@ -89,12 +91,13 @@ void main() {
// Da qui in poi, il codice prosegue normalmente solo per gli altri oggetti
// UV ofssets
// --- MODIFICATO: Aggiunto multiplier "thickness" agli UV offsets ---
float thickness = params.line_thickness;
vec2 uv_offsets[4];
uv_offsets[0] = uv_normalized + vec2(0.0, -1.0) * texel_size + offset;
uv_offsets[1] = uv_normalized + vec2(0.0, 1.0) * texel_size + offset;
uv_offsets[2] = uv_normalized + vec2(1.0, 0.0) * texel_size + offset;
uv_offsets[3] = uv_normalized + vec2(-1.0, 0.0) * texel_size + offset;
uv_offsets[0] = uv_normalized + vec2(0.0, -1.0) * texel_size * thickness + offset;
uv_offsets[1] = uv_normalized + vec2(0.0, 1.0) * texel_size * thickness + offset;
uv_offsets[2] = uv_normalized + vec2(1.0, 0.0) * texel_size * thickness + offset;
uv_offsets[3] = uv_normalized + vec2(-1.0, 0.0) * texel_size * thickness + offset;
float mask = ceil(raw_roughness);

View File

@@ -56,7 +56,7 @@ void fragment() {
} else {
vec2 projected_xz = world_pos.xz + (world_pos.y * sun_angle);
vec2 uv = projected_xz * cloud_scale;
uv += TIME * cloud_speed * direction;
uv -= TIME * cloud_speed * direction;
float n = texture(noise_texture, uv).r;
@@ -71,4 +71,4 @@ void fragment() {
}
}
}
}
}

View File

@@ -118,7 +118,7 @@ void sky() {
//Clouds
vec2 cloud_uv = EYEDIR.xz / (EYEDIR.y + 0.5);
cloud_uv = cloud_uv * cloud_scale + (TIME * cloud_direction * cloud_speed);
cloud_uv = cloud_uv * cloud_scale - (TIME * cloud_direction * cloud_speed);
float noise = texture(cloud_noise, cloud_uv).r;
float cloud_alpha = smoothstep(cloud_threshold, cloud_threshold + cloud_edge_softness, noise);
float color_gradient = smoothstep(cloud_threshold, cloud_threshold + cloud_edge_thickness, noise);
@@ -136,4 +136,4 @@ void sky() {
final_sky = mix(final_sky, current_cloud_color, cloud_alpha);
COLOR = final_sky;
}
}

View File

@@ -1,6 +1,8 @@
class_name WeatherController
extends Node
signal wind_parameters_changed(speed: float, strength: float, fade: float, direction: Vector2)
var thunder_audio_player: AudioStreamPlayer
var thunder_sounds: Array[AudioStream]
var rain_sounds: Array[AudioStream]
@@ -101,6 +103,8 @@ func _init(wind: GPUParticles3D, snow: GPUParticles3D,
camera_pivot.get_node("pivot").camera_changed.connect(_set_camera)
func _ready() -> void:
#used for wind change state (wind_decoration)
add_to_group("weather_controller")
#connect events
UIEvents.toggle_rain.connect(toggle_rain)
@@ -439,7 +443,7 @@ func _apply_wind_config() -> void:
else:
wind_cross = wind_cross.normalized()
var wind_up := wind_cross.cross(wind_axis).normalized()
proc_mat_wind.direction = wind_axis
proc_mat_wind.direction = Vector3.UP
particles_wind.global_transform = Transform3D(Basis(wind_cross, wind_axis, wind_up), particles_wind.global_position)
_apply_wind_state(true)
@@ -469,14 +473,23 @@ func _apply_wind_state(immediate: bool = false) -> void:
func _set_current_wind_speed(value: float) -> void:
current_wind_speed = value
RenderingServer.global_shader_parameter_set("global_wind_speed", value)
_sync_wind_event_state()
func _set_current_wind_strength(value: float) -> void:
current_wind_strength = value
RenderingServer.global_shader_parameter_set("global_wind_strength", value)
_sync_wind_event_state()
func _set_current_wind_fade(value: float) -> void:
current_wind_fade = value
RenderingServer.global_shader_parameter_set("global_wind_fade", value)
_sync_wind_event_state()
func _sync_wind_event_state() -> void:
if environment_config == null:
return
#used to notify wind_decoration when wind change state
wind_parameters_changed.emit(current_wind_speed, current_wind_strength, current_wind_fade, environment_config.wind_direction)
func _finish_wind_fade_out() -> void:
if is_windy: