43 Commits

Author SHA1 Message Date
8f00ee24e8 add animals 2026-05-21 22:59:25 +02:00
1adc0ef5b7 add human fbx and idle/walking animation 2026-05-18 23:23:55 +02:00
fcab02469a add main menu and scene manager 2026-05-18 19:17:21 +00:00
0e56a84a95 add game menu 2026-05-15 20:33:21 +00:00
22877bffbe Merge pull request 'biome generation optimization' (#18) from generation_optimization into main
Reviewed-on: #18
2026-05-14 10:30:22 +00:00
b4a2bb6144 biome generation optimization 2026-05-14 12:29:41 +02:00
90b9739ee0 Merge branch 'main' of https://gitea.jmpgames.it/jmp-games/tgcc 2026-05-13 18:15:58 +02:00
43556ac110 add uniqueness par for props 2026-05-13 18:15:37 +02:00
7ea515c824 Merge branch 'polish3' into main 2026-05-13 15:50:14 +00:00
4658250206 fix 2026-05-13 17:05:29 +02:00
c25e3bb4f6 add uniqueness property to chunk and manage it on biome generator 2026-05-13 12:25:16 +02:00
Matteo Sonaglioni
c796ea289d well 2026-05-12 16:54:20 +02:00
Matteo Sonaglioni
a18dc64a4f prop1 2026-05-12 16:44:21 +02:00
c52b11388a add chunks
chunk river
hero chunk
2026-05-11 13:32:31 +00:00
ce8a977541 Merge pull request 'fix river water direction2' (#15) from river_direction into main
Reviewed-on: #15
2026-05-10 16:45:11 +00:00
8ceb6cb16b fix river water direction2 2026-05-10 18:44:43 +02:00
bcf854fd74 Merge branch 'main' of https://gitea.jmpgames.it/jmp-games/tgcc 2026-05-10 11:09:41 +02:00
10b437d236 add fog update based on day 2026-05-10 11:09:27 +02:00
9c41da14a6 Merge pull request 'fix_snow_rain_fog' (#14) from fix_snow_rain_fog into main
Reviewed-on: #14
2026-05-10 09:02:01 +00:00
2aa7d1f7d4 fix snow 2026-05-10 11:01:22 +02:00
040ded5f0b fix rain 2026-05-09 14:57:07 +02:00
ddec91d515 update cloud density when is rainy or snowy 2026-05-06 23:14:51 +02:00
d8efa735dd Merge pull request 'polish2' (#12) from polish2 into main
Reviewed-on: #12
2026-05-06 20:29:12 +00:00
Matteo Sonaglioni
9bc7f38d07 add river curve 2026-05-06 22:27:54 +02:00
Matteo Sonaglioni
f4c8775a45 add river chunk 2026-05-06 21:43:34 +02:00
70d3dfe15c add ai, photo_mode and radio 2026-05-05 20:33:00 +00:00
Matteo Sonaglioni
9827b98b3e river water shader 2026-05-05 18:45:16 +02:00
Matteo Sonaglioni
977e8012aa river chunk 2026-05-05 17:03:24 +02:00
72d06560b1 add groups to scenes 2026-05-05 00:04:02 +02:00
9d62d97422 Merge pull request 'biome_gen_river' (#10) from biome_gen_river into main
Reviewed-on: #10
2026-05-04 22:00:08 +00:00
c1e99a3b8e fix merge scenes 2026-05-04 23:59:27 +02:00
8e1ba915a2 add scenes 2026-05-04 23:43:22 +02:00
Matteo Sonaglioni
577b4570da add river chunk 2026-05-04 23:35:29 +02:00
36dff9c070 remove train radar 2026-05-04 10:09:20 +02:00
56591bb907 fix snow cap 2026-05-02 18:10:51 +02:00
9f254d9725 Merge pull request 'polish1' (#6) from polish1 into main
Reviewed-on: #6
2026-05-02 16:09:44 +00:00
abae8434fc add river bioma gen + label weather random 2026-04-30 23:23:49 +02:00
Matteo Sonaglioni
e211f89fca revamp pylon 2026-04-30 17:48:08 +02:00
3c7cbdc662 Merge pull request 'biome_gen_overload' (#5) from biome_gen_overload into main
Reviewed-on: #5
2026-04-30 14:42:30 +00:00
Matteo Sonaglioni
d709d9236c Merge branch 'main' into polish1 2026-04-30 11:24:50 +02:00
Matteo Sonaglioni
9ee6d08918 chunk fix 2026-04-30 11:05:18 +02:00
Matteo Sonaglioni
3521839ed9 add bambu 2026-04-29 17:54:13 +02:00
Matteo Sonaglioni
6a62f92ed5 fog planes 2026-04-29 14:14:58 +02:00
411 changed files with 50251 additions and 442 deletions

13
.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,13 @@
# Default ignored files
/shelf/
/workspace.xml
# Rider ignored files
/contentModel.xml
/modules.xml
/projectSettingsUpdater.xml
/.idea.tgcc.iml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

4
.idea/encodings.xml generated Normal file
View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
</project>

8
.idea/indexLayout.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="UserContentModel">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />
</component>
</project>

6
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View File

@@ -0,0 +1,68 @@
extends CharacterBody3D
class_name AIBase
@export var speed: float = 4.0
var _enable_state_machine: bool = true
@export var enable_state_machine: bool:
set(value):
_enable_state_machine = value
toggle_enable_state_machine()
get:
return _enable_state_machine
@export var anim_player: AnimationPlayer
@onready var patrol_radius_shape: CollisionShape3D = $%PatrolRadiusShape
@onready var nav_agent: NavigationAgent3D = $%NavigationAgent3D
@onready var state_machine: StateMachine = $%StateMachine
func _ready() -> void:
randomize()
toggle_enable_state_machine()
func toggle_enable_state_machine() -> void:
state_machine.enable = _enable_state_machine
func _physics_process(delta: float) -> void:
if !_enable_state_machine:
return
state_machine.physics_process(delta)
if nav_agent.is_navigation_finished():
velocity = Vector3.ZERO
move_and_slide()
return
var next_point = nav_agent.get_next_path_position()
var direction = global_position.direction_to(next_point)
velocity.x = direction.x * speed
velocity.z = direction.z * speed
if velocity.length_squared() > 0.1:
var look_dir = Vector3(velocity.x, 0, velocity.z)
var target_transform = global_transform.looking_at(global_position - look_dir, Vector3.UP)
global_transform = global_transform.interpolate_with(target_transform, delta * 10.0)
move_and_slide()
func navigate_to_random_point() -> void:
var nav_map_rid = get_world_3d().get_navigation_map()
var patrol_radius = patrol_radius_shape.shape.radius
var target_point_in_space = global_position + Vector3(randf_range(-1, 1), 0, randf_range(-1, 1)).normalized() * randf_range(0, patrol_radius)
var closest_valid_point = NavigationServer3D.map_get_closest_point(nav_map_rid, target_point_in_space)
nav_agent.target_position = closest_valid_point
func run_walking_animation() -> void:
if anim_player and anim_player.has_animation("custom/walking"):
var anim = anim_player.get_animation("custom/walking")
anim.loop_mode = Animation.LOOP_LINEAR
anim_player.play("custom/walking")
func run_idle_animation() -> void:
if anim_player and anim_player.has_animation("custom/idle"):
var anim = anim_player.get_animation("custom/idle")
anim.loop_mode = Animation.LOOP_LINEAR
anim_player.play("custom/idle")

View File

@@ -0,0 +1 @@
uid://b30p1yqojbbbk

View File

@@ -0,0 +1,44 @@
[gd_scene format=3 uid="uid://clx701xdwelgx"]
[ext_resource type="Script" uid="uid://b30p1yqojbbbk" path="res://core/ai/agents/base/ai_base.gd" id="1_4d1nn"]
[ext_resource type="Script" uid="uid://ps3vlu2qvmop" path="res://core/ai/framework/state_machine.gd" id="2_q1hg3"]
[ext_resource type="Script" uid="uid://nga8qx56iwgu" path="res://core/ai/agents/base/idle_state.gd" id="3_26faq"]
[ext_resource type="Script" uid="uid://bngfthvt04ivv" path="res://core/ai/agents/base/patrol_state.gd" id="4_lim44"]
[sub_resource type="CapsuleMesh" id="CapsuleMesh_mh3lg"]
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_mh3lg"]
[sub_resource type="SphereShape3D" id="SphereShape3D_lim44"]
radius = 20.0
[node name="AiBase" type="CharacterBody3D" unique_id=1228675528]
script = ExtResource("1_4d1nn")
[node name="MeshInstance3D" type="MeshInstance3D" parent="." unique_id=214482161]
mesh = SubResource("CapsuleMesh_mh3lg")
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=92811823]
shape = SubResource("CapsuleShape3D_mh3lg")
[node name="NavigationAgent3D" type="NavigationAgent3D" parent="." unique_id=1370024449]
unique_name_in_owner = true
[node name="StateMachine" type="Node" parent="." unique_id=1286404264 node_paths=PackedStringArray("initial_state")]
unique_name_in_owner = true
script = ExtResource("2_q1hg3")
initial_state = NodePath("IdleState")
[node name="IdleState" type="Node" parent="StateMachine" unique_id=763668255]
script = ExtResource("3_26faq")
state_id = &"idle"
[node name="PatrolState" type="Node" parent="StateMachine" unique_id=2054606629]
script = ExtResource("4_lim44")
state_id = &"patrol"
[node name="PatrolRadiusShape" type="CollisionShape3D" parent="." unique_id=1379515938]
unique_name_in_owner = true
shape = SubResource("SphereShape3D_lim44")
disabled = true
debug_color = Color(1, 1, 0, 1)

View File

@@ -0,0 +1,28 @@
extends State
const PATROL_STATE_ID: StringName = &"patrol"
@onready var agent: AIBase = owner
@export var wait_time: float = 3.0
var runtime_timer: Timer
func enter() -> void:
agent.run_idle_animation()
runtime_timer = Timer.new()
runtime_timer.name = "IdleTimer"
add_child(runtime_timer)
runtime_timer.one_shot = true
runtime_timer.timeout.connect(_on_timer_timeout)
runtime_timer.start(wait_time)
func exit() -> void:
if runtime_timer:
if runtime_timer.is_connected("timeout", _on_timer_timeout):
runtime_timer.timeout.disconnect(_on_timer_timeout)
runtime_timer.queue_free()
runtime_timer = null
func _on_timer_timeout() -> void:
transitioned.emit(self, PATROL_STATE_ID)

View File

@@ -0,0 +1 @@
uid://nga8qx56iwgu

View File

@@ -0,0 +1,13 @@
extends State
const IDLE_STATE_ID: StringName = &"idle"
@onready var agent: AIBase = owner
func enter() -> void:
agent.navigate_to_random_point()
agent.run_walking_animation()
func physics_update(_delta) -> void:
if agent.nav_agent.is_navigation_finished():
transitioned.emit(self, IDLE_STATE_ID)

View File

@@ -0,0 +1 @@
uid://bngfthvt04ivv

View File

@@ -0,0 +1,53 @@
[gd_scene format=3 uid="uid://dd8wn62anbts8"]
[ext_resource type="PackedScene" uid="uid://clx701xdwelgx" path="res://core/ai/agents/base/ai_base.tscn" id="1_p2hpa"]
[ext_resource type="PackedScene" uid="uid://bjp8wbrtfl4v2" path="res://core/ai/agents/cow/cow_mannequin.tscn" id="2_6gadt"]
[sub_resource type="BoxShape3D" id="BoxShape3D_6gadt"]
size = Vector3(1, 1.4033203, 2.201294)
[node name="AiCow" unique_id=1228675528 node_paths=PackedStringArray("anim_player") instance=ExtResource("1_p2hpa")]
anim_player = NodePath("CowMannequin/AnimationPlayer")
[node name="MeshInstance3D" parent="." index="0" unique_id=214482161]
visible = false
[node name="CollisionShape3D" parent="." index="1" unique_id=92811823]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.20166016, 0.24859619)
shape = SubResource("BoxShape3D_6gadt")
[node name="CowMannequin" parent="." index="5" unique_id=1390675137 instance=ExtResource("2_6gadt")]
transform = Transform3D(0.25, 0, 0, 0, 0.25, 0, 0, 0, 0.25, 0, -0.9, 0)
[node name="Skeleton3D" parent="CowMannequin/Armature" parent_id_path=PackedInt32Array(1390675137, 698629112) index="0" unique_id=1122133347]
bones/1/position = Vector3(-0.00911771, 0.0010000349, 0.006467142)
bones/3/position = Vector3(0.0017672703, 0.020791268, -0.0029404918)
bones/4/position = Vector3(-0.0032468068, 0.0023884464, 0.01873094)
bones/4/rotation = Quaternion(0.10042217, -0.10042243, 0.69993955, 0.69993955)
bones/5/rotation = Quaternion(0.67686933, -0.7237772, -0.07669845, 0.11005373)
bones/6/rotation = Quaternion(0.2912588, -0.018159404, 0.0055299345, 0.95645595)
bones/8/position = Vector3(-0.0032468068, 0.003527336, -0.02178527)
bones/8/rotation = Quaternion(-0.13840333, 0.13840266, 0.6934296, 0.6934297)
bones/9/rotation = Quaternion(0.63873273, -0.71572495, 0.1725141, -0.22360067)
bones/10/rotation = Quaternion(-0.5624951, 0.015998652, 0.010887203, 0.82657415)
bones/12/position = Vector3(0.0026304817, 0.0015686632, 0.01873094)
bones/12/rotation = Quaternion(0.69003975, 0.6900398, -0.15441875, 0.15441847)
bones/13/rotation = Quaternion(-0.06197851, -0.1282304, 0.73018706, 0.6682384)
bones/14/rotation = Quaternion(0.1410681, 0.051763278, -0.0073862504, 0.9886182)
bones/16/position = Vector3(0.0026304817, 0.005057063, -0.02178527)
bones/16/rotation = Quaternion(0.70645297, 0.7064531, 0.030399354, -0.030400336)
bones/17/rotation = Quaternion(0.198508, 0.20028433, 0.69889957, 0.65728253)
bones/18/rotation = Quaternion(-0.4085358, -0.008673466, -0.0038824743, 0.9126928)
bones/20/position = Vector3(-0.0003228268, 0.009853916, -0.026626632)
bones/26/position = Vector3(-0.00072195934, 0.0076745725, 0.016512236)
bones/26/rotation = Quaternion(0.0042201285, 0.8477673, 0.5299017, -0.021842854)
bones/27/rotation = Quaternion(0.1513493, -0.04170839, -0.04666066, 0.9864972)
bones/28/rotation = Quaternion(-0.6312453, -0.17917253, 0.17600863, 0.73378986)
bones/30/position = Vector3(-0.0003228271, 0.011335416, -0.01734586)
bones/33/position = Vector3(-0.008358625, 0.004613471, -0.013200058)
bones/33/rotation = Quaternion(0.76341635, -5.672201e-07, -6.704141e-07, 0.6459068)
bones/35/position = Vector3(0.008608938, 0.0010000349, 0.028441517)
bones/35/rotation = Quaternion(0.7071068, -6.866289e-07, -1.22965e-06, 0.7071067)
bones/37/position = Vector3(0.007849856, 0.0010000349, -0.02901155)
[editable path="CowMannequin"]

BIN
core/ai/agents/cow/cow.fbx Normal file

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,81 @@
[gd_scene format=3 uid="uid://bjp8wbrtfl4v2"]
[ext_resource type="PackedScene" uid="uid://b7d57tyxi41r1" path="res://core/ai/agents/cow/cow.fbx" id="1_60f5q"]
[ext_resource type="Animation" uid="uid://bsuoywknbbnm0" path="res://core/ai/agents/cow/idle.res" id="2_5ukcj"]
[ext_resource type="Animation" uid="uid://ckmybsnuf4stp" path="res://core/ai/agents/cow/walking.res" id="3_0mu5m"]
[sub_resource type="AnimationLibrary" id="AnimationLibrary_lowte"]
_data = {
&"idle": ExtResource("2_5ukcj"),
&"walking": ExtResource("3_0mu5m")
}
[node name="CowMannequin" unique_id=786985233 instance=ExtResource("1_60f5q")]
[node name="Skeleton3D" parent="Armature" parent_id_path=PackedInt32Array(698629112) index="0" unique_id=1122133347]
bones/1/rotation = Quaternion(0.7071068, -6.209646e-07, -6.209645e-07, 0.7071067)
bones/1/scale = Vector3(1, 1, 1)
bones/4/rotation = Quaternion(0.0015316998, -0.0015319793, 0.70710516, 0.70710516)
bones/5/position = Vector3(1.3183898e-16, 0.006025583, -6.675722e-10)
bones/5/rotation = Quaternion(0.703962, -0.69745475, -0.08083715, 0.10705068)
bones/5/scale = Vector3(1, 0.99999976, 1)
bones/6/position = Vector3(-1.403955e-10, 0.009248152, 3.7406075e-11)
bones/6/rotation = Quaternion(0.18324056, -0.018661192, 0.0034790868, 0.98288476)
bones/6/scale = Vector3(1, 1, 1)
bones/8/scale = Vector3(0.99999994, 0.99999994, 1)
bones/9/position = Vector3(-3.8163916e-17, 0.0046958304, 1.907358e-10)
bones/9/rotation = Quaternion(0.6754388, -0.68119305, 0.18401879, -0.21423234)
bones/9/scale = Vector3(1, 0.99999994, 1.0000001)
bones/10/position = Vector3(7.2902e-10, 0.011755081, -3.0995417e-10)
bones/10/rotation = Quaternion(-0.35146433, 0.018116632, 0.0068026204, 0.9360013)
bones/10/scale = Vector3(0.9999999, 1, 1.0000001)
bones/12/rotation = Quaternion(0.707105, 0.70710486, 0.0016303749, -0.0016306548)
bones/12/scale = Vector3(1, 1, 1)
bones/13/position = Vector3(-1.5265567e-16, 0.0060255853, 6.6757205e-10)
bones/13/rotation = Quaternion(-0.057434652, -0.13032891, 0.70625645, 0.69348216)
bones/13/scale = Vector3(0.99999994, 1, 0.9999999)
bones/14/position = Vector3(-4.5945833e-10, 0.009248151, -5.7053273e-09)
bones/14/rotation = Quaternion(0.18302466, 0.051401887, -0.0095829815, 0.9817169)
bones/14/scale = Vector3(1, 1.0000001, 0.99999994)
bones/16/rotation = Quaternion(0.7071062, 0.7071063, 0.0008663558, -0.0008670737)
bones/16/scale = Vector3(1, 1, 1)
bones/17/position = Vector3(1.7347235e-17, 0.0046958304, -1.9073432e-10)
bones/17/rotation = Quaternion(0.1907959, 0.2076444, 0.67355627, 0.6832297)
bones/17/scale = Vector3(1, 1, 1.0000001)
bones/18/position = Vector3(1.834215e-10, 0.011755081, -1.7500804e-09)
bones/18/rotation = Quaternion(-0.35151497, -0.0088962475, -0.003340601, 0.93613404)
bones/18/scale = Vector3(1, 1.0000001, 0.99999994)
bones/20/rotation = Quaternion(0.60080343, -0.03016121, 0.03526711, 0.7980488)
bones/21/position = Vector3(0.00011168665, 0.0039693406, -0.013754063)
bones/21/rotation = Quaternion(0.98885596, 3.1474094e-08, 2.23642e-07, -0.14887528)
bones/21/scale = Vector3(1, 1.0000001, 1.0000001)
bones/22/position = Vector3(-2.5714557e-11, 0.00836347, -9.433328e-09)
bones/22/rotation = Quaternion(-0.6231534, 9.0575064e-08, -7.589477e-08, 0.78209966)
bones/22/scale = Vector3(1, 0.9999999, 0.99999994)
bones/23/position = Vector3(-2.1545942e-12, 0.0072733457, -2.594807e-09)
bones/23/rotation = Quaternion(-1.8223004e-08, 0.98608583, -0.16623694, 2.7314604e-07)
bones/23/scale = Vector3(1, 0.9999997, 0.9999997)
bones/24/position = Vector3(3.3663968e-13, 0.006993335, -2.8376712e-09)
bones/24/rotation = Quaternion(-0.048028953, 2.6759114e-08, 4.5447155e-08, 0.998846)
bones/24/scale = Vector3(1, 0.99999994, 1.0000001)
bones/26/rotation = Quaternion(0.0054439656, 0.86556005, 0.50029516, -0.021930087)
bones/26/scale = Vector3(1, 1.0000002, 1)
bones/27/position = Vector3(1.8971762e-10, 0.013189232, -5.7312505e-10)
bones/27/rotation = Quaternion(0.15129425, -0.018451845, -0.013046658, 0.9882304)
bones/27/scale = Vector3(0.99999994, 0.99999994, 1.0000001)
bones/28/position = Vector3(-2.1601461e-10, 0.013573305, 4.8459786e-10)
bones/28/rotation = Quaternion(-0.6245376, -0.19781438, 0.16660775, 0.7369289)
bones/28/scale = Vector3(1, 0.9999999, 1.0000001)
bones/30/rotation = Quaternion(3.5765906e-06, 0.67050743, 0.7419029, 3.2289404e-06)
bones/31/position = Vector3(-1.2499713e-14, 0.01925819, -1.2902629e-09)
bones/31/rotation = Quaternion(0.086390205, 0.0012038474, -0.013495129, 0.99616927)
bones/31/scale = Vector3(0.9999999, 0.99999994, 1)
bones/33/rotation = Quaternion(0.7071068, -6.209646e-07, -6.209645e-07, 0.7071067)
bones/33/scale = Vector3(1, 1, 1)
bones/35/rotation = Quaternion(0.7071068, -9.581396e-07, -9.581394e-07, 0.7071067)
bones/35/scale = Vector3(1, 1, 1)
bones/37/rotation = Quaternion(0.7071068, -9.581396e-07, -9.581394e-07, 0.7071067)
bones/37/scale = Vector3(1, 1, 1)
[node name="AnimationPlayer" parent="." index="1" unique_id=1944296898]
libraries/custom = SubResource("AnimationLibrary_lowte")

BIN
core/ai/agents/cow/idle.res Normal file

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,61 @@
[gd_scene format=3 uid="uid://cayakdk7gmlyg"]
[ext_resource type="PackedScene" uid="uid://clx701xdwelgx" path="res://core/ai/agents/base/ai_base.tscn" id="1_e5v3h"]
[ext_resource type="PackedScene" uid="uid://dqhueybnlrrqx" path="res://core/ai/agents/horse/horse_mannequin.tscn" id="2_4t6jw"]
[ext_resource type="Animation" uid="uid://doyi6etqvy4n2" path="res://core/ai/agents/horse/idle.res" id="3_qe4rt"]
[ext_resource type="Animation" uid="uid://hotr7r3fd1sq" path="res://core/ai/agents/horse/walking.res" id="4_q8m0v"]
[sub_resource type="BoxShape3D" id="BoxShape3D_4t6jw"]
size = Vector3(1, 1.4991455, 1.7949219)
[sub_resource type="AnimationLibrary" id="AnimationLibrary_or6xs"]
_data = {
&"idle": ExtResource("3_qe4rt"),
&"walking": ExtResource("4_q8m0v")
}
[node name="AiHorse" unique_id=1228675528 node_paths=PackedStringArray("anim_player") instance=ExtResource("1_e5v3h")]
anim_player = NodePath("HorseMannequin/AnimationPlayer")
[node name="MeshInstance3D" parent="." index="0" unique_id=214482161]
visible = false
[node name="CollisionShape3D" parent="." index="1" unique_id=92811823]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.2074585, 0.14794922)
shape = SubResource("BoxShape3D_4t6jw")
[node name="HorseMannequin" parent="." index="5" 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, 502167939) index="0" unique_id=972507008]
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)
bones/6/rotation = Quaternion(0.13314606, -0.018813655, 0.0025279524, 0.9909147)
bones/8/rotation = Quaternion(0.00078355736, -0.00078427553, 0.70710635, 0.70710635)
bones/9/rotation = Quaternion(0.6711558, -0.6744515, 0.20213859, -0.23195927)
bones/10/rotation = Quaternion(-0.3574636, 0.018072592, 0.006918765, 0.9337266)
bones/12/rotation = Quaternion(0.7071054, 0.7071055, 0.0013743625, -0.0013746425)
bones/13/rotation = Quaternion(-0.02159133, -0.09508795, 0.70796114, 0.69948786)
bones/14/rotation = Quaternion(0.13298893, 0.051821847, -0.0069631753, 0.9897374)
bones/16/rotation = Quaternion(0.7071064, 0.70710653, 0.00066260004, -0.00066331815)
bones/17/rotation = Quaternion(0.20885532, 0.22542001, 0.6690968, 0.6766645)
bones/18/rotation = Quaternion(-0.3575147, -0.008874607, -0.003397635, 0.9338592)
bones/20/rotation = Quaternion(0.6010642, -0.021428203, 0.02848876, 0.79840535)
bones/21/rotation = Quaternion(0.99267024, 2.482745e-08, 2.2239277e-07, -0.12085533)
bones/22/rotation = Quaternion(-0.6165577, 9.507701e-08, -7.2693986e-08, 0.7873097)
bones/23/rotation = Quaternion(-1.5614631e-08, 0.9891947, -0.14660779, 2.7153942e-07)
bones/24/rotation = Quaternion(0.03904001, 3.5621138e-08, 1.47960275e-08, 0.99923766)
bones/26/rotation = Quaternion(0.008421451, 0.95973384, 0.27944198, -0.027427308)
bones/27/rotation = Quaternion(-0.08868468, -0.022488868, -0.01781765, 0.9956465)
bones/28/rotation = Quaternion(-0.62453747, -0.1978144, 0.1666077, 0.736929)
bones/30/rotation = Quaternion(3.4527793e-06, 0.6944211, 0.71956885, 3.3297817e-06)
bones/31/rotation = Quaternion(0.053752482, 0.0007617086, -0.013526975, 0.9984624)
bones/33/rotation = Quaternion(0.7071068, -6.209646e-07, -6.209645e-07, 0.7071067)
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=868895357]
libraries/custom = SubResource("AnimationLibrary_or6xs")
[editable path="HorseMannequin"]

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,5 @@
[gd_scene format=3 uid="uid://dqhueybnlrrqx"]
[ext_resource type="PackedScene" uid="uid://be1ql8okme4n7" path="res://core/ai/agents/horse/horse.fbx" id="1_fbqil"]
[node name="HorseMannequin" unique_id=1289880358 instance=ExtResource("1_fbqil")]

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,58 @@
[gd_scene format=3 uid="uid://mvh2v6v72stt"]
[ext_resource type="PackedScene" uid="uid://clx701xdwelgx" path="res://core/ai/agents/base/ai_base.tscn" id="1_hko2w"]
[ext_resource type="PackedScene" uid="uid://legcajdd0jsy" path="res://core/ai/agents/human/human_mannequin.tscn" id="2_cnrgi"]
[node name="AiHuman" unique_id=1228675528 node_paths=PackedStringArray("anim_player") instance=ExtResource("1_hko2w")]
anim_player = NodePath("HumanMannequin/AnimationPlayer")
[node name="MeshInstance3D" parent="." index="0" unique_id=214482161]
visible = false
[node name="HumanMannequin" parent="." index="5" unique_id=333236377 instance=ExtResource("2_cnrgi")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.9, 0)
[node name="SK_Mannequin" parent="HumanMannequin" index="0" unique_id=377304892]
transform = Transform3D(0.99999994, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 0, 0, 0)
[node name="Skeleton3D" parent="HumanMannequin/SK_Mannequin" index="0" unique_id=427572412]
bones/2/rotation = Quaternion(-2.1971985e-24, 0, -0.062388558, 0.99805194)
bones/3/rotation = Quaternion(4.135903e-25, 1.6543612e-24, 0.12241964, 0.99247843)
bones/4/rotation = Quaternion(2.2850868e-23, 0, 0.024252614, 0.9997059)
bones/5/rotation = Quaternion(0.20891805, 0.7294167, 0.12304399, 0.6396598)
bones/6/rotation = Quaternion(0.11299576, 0.33062968, -0.16141911, 0.92296255)
bones/7/rotation = Quaternion(-0.05401651, -0.079182714, -0.26340967, 0.9599103)
bones/8/rotation = Quaternion(-0.61789525, 0.019371983, 0.010653294, 0.7859496)
bones/9/rotation = Quaternion(0.1333045, -0.0031801206, 0.22317973, 0.96561414)
bones/10/rotation = Quaternion(0.012043531, -0.0029058352, 0.10444825, 0.9944532)
bones/12/rotation = Quaternion(0.028522171, -0.05687394, 0.19848494, 0.9780366)
bones/13/rotation = Quaternion(-0.018628873, 0.007972199, 0.10711657, 0.99404)
bones/15/rotation = Quaternion(-0.1295377, -0.18789689, 0.14421311, 0.9628693)
bones/16/rotation = Quaternion(0.010359715, -0.010519396, 0.09774818, 0.9951017)
bones/18/rotation = Quaternion(-0.095480494, -0.116765715, 0.18851167, 0.9704188)
bones/19/rotation = Quaternion(0.00430111, -0.0141675975, 0.11596311, 0.9931432)
bones/21/rotation = Quaternion(0.6303091, 0.37152508, -0.07729015, 0.6772783)
bones/22/rotation = Quaternion(0.0026046867, 0.086798474, 0.13014112, 0.98768544)
bones/26/rotation = Quaternion(0.7294168, -0.20891781, -0.6396598, 0.12304417)
bones/27/rotation = Quaternion(0.11299576, 0.33062968, -0.16141911, 0.92296255)
bones/28/rotation = Quaternion(-0.05401651, -0.079182714, -0.26340967, 0.9599103)
bones/29/rotation = Quaternion(-0.61789525, 0.019371983, 0.010653294, 0.7859496)
bones/30/rotation = Quaternion(0.1333045, -0.0031801206, 0.22317973, 0.96561414)
bones/31/rotation = Quaternion(0.012043531, -0.0029058352, 0.10444825, 0.9944532)
bones/33/rotation = Quaternion(0.028522171, -0.05687394, 0.19848494, 0.9780366)
bones/34/rotation = Quaternion(-0.018628873, 0.007972199, 0.10711657, 0.99404)
bones/36/rotation = Quaternion(-0.1295377, -0.18789689, 0.14421311, 0.9628693)
bones/37/rotation = Quaternion(0.010359715, -0.010519396, 0.09774818, 0.9951017)
bones/39/rotation = Quaternion(-0.095480494, -0.116765715, 0.18851167, 0.9704188)
bones/40/rotation = Quaternion(0.00430111, -0.0141675975, 0.11596311, 0.9931432)
bones/42/rotation = Quaternion(0.6303091, 0.37152508, -0.07729015, 0.6772783)
bones/43/rotation = Quaternion(0.0026047025, 0.08679848, 0.13014114, 0.98768544)
bones/47/rotation = Quaternion(-1.5923227e-23, 0, -0.20371072, 0.97903115)
bones/49/rotation = Quaternion(0.07370486, -0.062138822, -0.008584324, 0.9953053)
bones/50/rotation = Quaternion(-0.048884246, 0.018863896, -0.06552225, 0.99647444)
bones/52/rotation = Quaternion(-0.0058857696, 0.03199128, 0.07035475, 0.9969916)
bones/55/rotation = Quaternion(0.062138822, 0.07370486, 0.9953054, 0.008584333)
bones/56/rotation = Quaternion(-0.048884246, 0.018863896, -0.06552225, 0.99647444)
bones/58/rotation = Quaternion(-0.0058857696, 0.03199128, 0.07035475, 0.9969916)
[editable path="HumanMannequin"]

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,90 @@
[gd_scene format=3 uid="uid://legcajdd0jsy"]
[ext_resource type="PackedScene" uid="uid://ys8pesrqeyv2" path="res://core/ai/agents/human/human_mannequin_mixamo.fbx" id="1_561x5"]
[ext_resource type="Animation" uid="uid://b2wo1mpqihko6" path="res://core/ai/agents/human/idle.res" id="2_b4vfe"]
[ext_resource type="Animation" uid="uid://cd02fn4tl8pxt" path="res://core/ai/agents/human/walking.res" id="3_jl3mr"]
[sub_resource type="AnimationLibrary" id="AnimationLibrary_3r4wv"]
_data = {
&"idle": ExtResource("2_b4vfe"),
&"walking": ExtResource("3_jl3mr")
}
[node name="HumanMannequin" unique_id=1583776159 instance=ExtResource("1_561x5")]
[node name="SK_Mannequin" parent="." index="0" unique_id=377304892]
transform = Transform3D(0.9976258, -0.04861942, 0.048771314, -0.04795494, 0.017819177, 0.99869055, -0.049424794, -0.9986584, 0.015445333, -0.05003774, -0.025284957, -0.009851909)
[node name="Skeleton3D" parent="SK_Mannequin" index="0" unique_id=427572412]
bones/2/rotation = Quaternion(0.0031313226, -0.013143469, -0.06403692, 0.9978561)
bones/3/rotation = Quaternion(0.0060529755, -0.0043215775, 0.11905511, 0.9928599)
bones/4/position = Vector3(0.13407329, 0.004204774, -5.584202e-15)
bones/4/rotation = Quaternion(0.005354738, -0.005161587, 0.020867111, 0.9997546)
bones/5/rotation = Quaternion(0.15400349, 0.7897888, 0.010658391, 0.59363556)
bones/6/position = Vector3(0.15784872, 1.4317955e-11, 6.3591354e-11)
bones/6/rotation = Quaternion(0.04945157, 0.4279849, -0.15578857, 0.8888832)
bones/7/position = Vector3(0.3033993, 8.407472e-11, 3.197531e-11)
bones/7/rotation = Quaternion(0.1100848, 0.10641666, -0.25697437, 0.95421225)
bones/8/position = Vector3(0.26975143, 1.572964e-11, -9.6207486e-11)
bones/8/rotation = Quaternion(-0.46975335, -0.009780162, -0.20075577, 0.8596124)
bones/9/rotation = Quaternion(0.11536587, 0.112830326, 0.39687443, 0.9035766)
bones/10/position = Vector3(0.04287498, -2.9850333e-10, 5.048406e-11)
bones/10/rotation = Quaternion(-0.0044350666, 0.31514773, 0.57789063, 0.752798)
bones/11/position = Vector3(0.0339379, 1.1695445e-10, -2.349232e-11)
bones/12/rotation = Quaternion(-0.026846388, 0.13234028, 0.54907507, 0.82479215)
bones/13/position = Vector3(0.046403743, -3.648193e-11, 1.830866e-11)
bones/13/rotation = Quaternion(-0.017277073, 0.20109688, 0.7544296, 0.62457794)
bones/14/position = Vector3(0.036488436, -1.9989443e-10, 1.6076356e-11)
bones/15/rotation = Quaternion(-0.26582807, -0.019897597, 0.63471824, 0.7253084)
bones/16/position = Vector3(0.03570981, 1.8669866e-10, 3.9181436e-12)
bones/16/rotation = Quaternion(0.036874738, -0.06492835, 0.74109465, 0.66723555)
bones/17/position = Vector3(0.029856307, -3.005879e-10, -4.0375425e-11)
bones/18/rotation = Quaternion(-0.1965758, 0.008460626, 0.5697997, 0.7978814)
bones/19/position = Vector3(0.04430177, 4.6665116e-11, -9.4033115e-12)
bones/19/rotation = Quaternion(0.008596869, -0.008138666, 0.79523915, 0.6061805)
bones/20/position = Vector3(0.034766525, -1.6786372e-10, 2.768652e-11)
bones/21/rotation = Quaternion(0.601964, 0.35209224, 0.09299817, 0.7106489)
bones/22/position = Vector3(0.038696717, 5.0118687e-11, 9.9849684e-11)
bones/22/rotation = Quaternion(0.0021266919, -0.004949208, 0.064930424, 0.9978753)
bones/23/position = Vector3(0.040621713, 1.0721979e-11, -5.127232e-12)
bones/24/position = Vector3(0.14, 1.110223e-16, 2.220446e-16)
bones/24/rotation = Quaternion(-2.7755576e-17, -6.938894e-17, -6.938894e-18, 1)
bones/25/position = Vector3(0.005, -2.7755576e-17, 0)
bones/25/rotation = Quaternion(-9.540979e-18, -2.7755576e-17, 9.540979e-18, 1)
bones/26/rotation = Quaternion(0.7842187, -0.19943702, -0.5848191, 0.056679882)
bones/27/rotation = Quaternion(0.052973837, 0.44702604, -0.029942662, 0.8924489)
bones/28/rotation = Quaternion(0.06465698, 0.12901439, -0.19377781, 0.97037363)
bones/29/position = Vector3(-0.26975244, 2.563412e-07, -1.1905385e-08)
bones/29/rotation = Quaternion(-0.4454563, -0.012538448, -0.12649484, 0.8862339)
bones/30/rotation = Quaternion(0.09673716, 0.06657806, 0.37996292, 0.91751707)
bones/31/rotation = Quaternion(-0.017224751, 0.24962947, 0.49292365, 0.8333155)
bones/33/rotation = Quaternion(-0.026649816, 0.050389662, 0.4562443, 0.888027)
bones/34/rotation = Quaternion(-0.0493639, 0.13757928, 0.58074373, 0.80085707)
bones/36/rotation = Quaternion(-0.14342895, 0.025572311, 0.42342505, 0.89413947)
bones/37/rotation = Quaternion(0.050029494, -0.01992205, 0.69104576, 0.7208023)
bones/39/rotation = Quaternion(-0.115030825, 0.01676327, 0.45154506, 0.88464344)
bones/40/rotation = Quaternion(0.020354148, 0.009153387, 0.6477204, 0.76155126)
bones/42/rotation = Quaternion(0.6151735, 0.28622907, 0.016048126, 0.7344229)
bones/43/rotation = Quaternion(0.19211918, 0.11141997, 0.124592975, 0.9670328)
bones/45/rotation = Quaternion(-0.1176271, 1.3974802e-16, -6.288661e-17, 0.99305785)
bones/46/rotation = Quaternion(-0.17323487, -2.099698e-25, 1.9374898e-17, 0.9848805)
bones/47/rotation = Quaternion(-0.0043949056, 0.010375962, -0.20370215, 0.97896814)
bones/48/position = Vector3(0.092836134, 0.0036415688, 2.7747754e-17)
bones/48/rotation = Quaternion(1.2661336e-17, 9.989056e-18, 0.13354194, 0.99104315)
bones/49/rotation = Quaternion(0.13130783, -0.05036935, 0.24724077, 0.95869356)
bones/50/position = Vector3(-0.42572036, 1.7074263e-12, -4.667877e-12)
bones/50/rotation = Quaternion(-0.048483394, -0.038352683, -0.5716499, 0.81816554)
bones/51/position = Vector3(-0.20476776, -1.3877788e-17, 0)
bones/52/position = Vector3(-0.4019669, -3.933849e-11, 1.899425e-12)
bones/52/rotation = Quaternion(-0.00021856392, -0.0061088647, 0.036131103, 0.9993284)
bones/54/position = Vector3(-0.22094238, 4.7704896e-18, 0)
bones/55/rotation = Quaternion(-0.041710682, 0.15009321, 0.97912854, -0.13053581)
bones/56/rotation = Quaternion(-0.11438767, 0.007083657, -0.2708839, 0.95576525)
bones/57/position = Vector3(0.20476907, 0, -5.551115e-17)
bones/58/rotation = Quaternion(-0.00023867, -0.056162532, 0.13990264, 0.98857117)
bones/60/position = Vector3(0.22094241, 3.035766e-18, -2.7755576e-17)
bones/67/position = Vector3(-4.440892e-16, 0, 7.632783e-17)
bones/67/rotation = Quaternion(-2.8449465e-16, 8.326673e-17, 2.7755576e-17, 1)
[node name="AnimationPlayer" parent="." index="1" unique_id=233699491]
libraries/custom = SubResource("AnimationLibrary_3r4wv")

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,68 @@
[gd_scene format=3 uid="uid://c2hg6hu2y5srb"]
[ext_resource type="PackedScene" uid="uid://clx701xdwelgx" path="res://core/ai/agents/base/ai_base.tscn" id="1_j8spt"]
[ext_resource type="PackedScene" uid="uid://b0xb7kl4rjd66" path="res://core/ai/agents/pig/pig_mannequin.tscn" id="2_qmc2e"]
[ext_resource type="Animation" uid="uid://cneiflmpalcg5" path="res://core/ai/agents/pig/idle.res" id="3_lvpc5"]
[ext_resource type="Animation" uid="uid://0563r715lmw1" path="res://core/ai/agents/pig/walking.res" id="4_3f3hl"]
[sub_resource type="BoxShape3D" id="BoxShape3D_lvpc5"]
size = Vector3(1, 1.4848633, 1.960083)
[sub_resource type="AnimationLibrary" id="AnimationLibrary_lvpc5"]
_data = {
&"idle": ExtResource("3_lvpc5"),
&"walking": ExtResource("4_3f3hl")
}
[node name="AiPig" unique_id=1228675528 node_paths=PackedStringArray("anim_player") instance=ExtResource("1_j8spt")]
anim_player = NodePath("PigMannequin/AnimationPlayer")
[node name="MeshInstance3D" parent="." index="0" unique_id=214482161]
visible = false
[node name="CollisionShape3D" parent="." index="1" unique_id=92811823]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.24243164, 0.10699463)
shape = SubResource("BoxShape3D_lvpc5")
[node name="PigMannequin" parent="." index="5" 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, 1135672511) index="0" unique_id=689596368]
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)
bones/4/position = Vector3(-0.004269575, -0.0009057691, 0.018837402)
bones/4/rotation = Quaternion(-0.20850496, 0.20850474, 0.675667, 0.6756669)
bones/5/rotation = Quaternion(0.70767504, -0.7007484, -0.04928623, 0.07562217)
bones/6/rotation = Quaternion(0.5074964, -0.016355418, 0.009635334, 0.86144483)
bones/8/position = Vector3(-0.004269574, 0.0008725248, -0.02819033)
bones/8/rotation = Quaternion(-0.021000031, 0.020999499, 0.7067949, 0.7067949)
bones/9/rotation = Quaternion(0.6762797, -0.7030302, 0.13760945, -0.17163305)
bones/10/rotation = Quaternion(-0.76131815, 0.012544005, 0.014735432, 0.64808965)
bones/12/position = Vector3(0.0036532492, -0.0009057691, 0.018837402)
bones/12/rotation = Quaternion(0.67572093, 0.6757209, -0.20832984, 0.20832963)
bones/13/rotation = Quaternion(-0.025831472, -0.099082425, 0.70891863, 0.6978179)
bones/14/rotation = Quaternion(0.50689334, 0.045050938, -0.026540417, 0.8604216)
bones/16/position = Vector3(0.0036521717, 0.0008013838, -0.028183708)
bones/16/rotation = Quaternion(0.7068031, 0.7068031, -0.020723455, 0.020722982)
bones/17/rotation = Quaternion(0.1443776, 0.16487122, 0.6747477, 0.7047611)
bones/18/rotation = Quaternion(-0.7649948, -0.0061196624, -0.0072699804, 0.64396644)
bones/20/position = Vector3(-0.00042349403, 0.0063493187, -0.030968314)
bones/20/rotation = Quaternion(0.60138106, 0.012805484, 0.0019118772, 0.79885745)
bones/22/position = Vector3(-0.0002038494, 0.0041766805, 0.0044565103)
bones/22/rotation = Quaternion(0.0076635648, 0.7548352, 0.6556045, -0.018651871)
bones/23/rotation = Quaternion(0.065689825, -0.010677165, -0.019551655, 0.99759144)
bones/24/rotation = Quaternion(-0.24106143, -0.2388839, 0.03569213, 0.9399734)
bones/26/position = Vector3(-0.00032282702, 0.010153349, -0.021613695)
bones/26/rotation = Quaternion(3.6196245e-06, 0.6452338, 0.7639852, 3.2175833e-06)
bones/27/rotation = Quaternion(0.0455184, 0.00040800165, -0.025042463, 0.99864954)
bones/29/position = Vector3(-0.01117923, 0.0010000349, -0.03163386)
bones/29/rotation = Quaternion(0.7071068, -6.178108e-07, -6.178107e-07, 0.7071067)
bones/31/rotation = Quaternion(0.7071068, -1.0424332e-06, -1.0424329e-06, 0.7071067)
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=1348500176]
libraries/custom = SubResource("AnimationLibrary_lvpc5")
[editable path="PigMannequin"]

BIN
core/ai/agents/pig/idle.res Normal file

Binary file not shown.

BIN
core/ai/agents/pig/pig.fbx Normal file

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,5 @@
[gd_scene format=3 uid="uid://b0xb7kl4rjd66"]
[ext_resource type="PackedScene" uid="uid://bi5f24frndw7j" path="res://core/ai/agents/pig/pig.fbx" id="1_ptg6h"]
[node name="PigMannequin" unique_id=926755470 instance=ExtResource("1_ptg6h")]

Binary file not shown.

View File

@@ -0,0 +1,40 @@
[gd_scene format=3 uid="uid://2md4l83fy8kr"]
[ext_resource type="PackedScene" uid="uid://clx701xdwelgx" path="res://core/ai/agents/base/ai_base.tscn" id="1_0bu1i"]
[ext_resource type="PackedScene" uid="uid://c16j3umhplew4" path="res://core/ai/agents/pug/pug_mannequin.tscn" id="2_n0mit"]
[ext_resource type="Animation" uid="uid://cwrfo6h44qghm" path="res://core/ai/agents/pug/idle.res" id="3_hv1px"]
[ext_resource type="Animation" uid="uid://dbv2ikwa8h4nb" path="res://core/ai/agents/pug/walking.res" id="4_cjq2y"]
[sub_resource type="AnimationLibrary" id="AnimationLibrary_iapui"]
_data = {
&"idle": ExtResource("3_hv1px"),
&"walking": ExtResource("4_cjq2y")
}
[node name="AiPug" unique_id=1228675528 node_paths=PackedStringArray("anim_player") instance=ExtResource("1_0bu1i")]
anim_player = NodePath("PugMannequin/AnimationPlayer")
[node name="MeshInstance3D" parent="." index="0" unique_id=214482161]
visible = false
[node name="PugMannequin" parent="." index="5" 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, 251322627) index="0" unique_id=1067550931]
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)
bones/10/rotation = Quaternion(-0.37439552, 0.017943675, 0.007246467, 0.92706716)
bones/14/rotation = Quaternion(0.13296904, 0.051822018, -0.0069621373, 0.9897401)
bones/16/position = Vector3(0.0048320387, 0.008252437, -0.02027757)
bones/16/rotation = Quaternion(0.7070978, 0.7070978, -0.0035577225, 0.0035573125)
bones/17/rotation = Quaternion(0.20727697, 0.22687204, 0.66435784, 0.68131787)
bones/18/rotation = Quaternion(-0.38250104, -0.0087800585, -0.0036350952, 0.9239062)
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=2146190163]
libraries/custom = SubResource("AnimationLibrary_iapui")
[editable path="PugMannequin"]

BIN
core/ai/agents/pug/idle.res Normal file

Binary file not shown.

BIN
core/ai/agents/pug/pug.fbx Normal file

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,29 @@
[gd_scene format=3 uid="uid://c16j3umhplew4"]
[ext_resource type="PackedScene" uid="uid://buqmw5lbfom07" path="res://core/ai/agents/pug/pug.fbx" id="1_3c2yk"]
[node name="PugMannequin" unique_id=1732134047 instance=ExtResource("1_3c2yk")]
[node name="Skeleton3D" parent="Armature" parent_id_path=PackedInt32Array(251322627) index="0" unique_id=1067550931]
bones/1/rotation = Quaternion(0.7071068, -8.7384586e-07, -8.7384575e-07, 0.7071067)
bones/3/position = Vector3(5.37765e-05, 0.023020823, -0.0001735416)
bones/4/rotation = Quaternion(0.0013124894, -0.0013127187, 0.7071056, 0.7071056)
bones/5/rotation = Quaternion(0.7071125, -0.70201516, -0.045116592, 0.07163183)
bones/6/rotation = Quaternion(0.13312602, -0.018813718, 0.0025276097, 0.9909174)
bones/8/rotation = Quaternion(0.0006567046, -0.0006571151, 0.7071065, 0.7071065)
bones/9/rotation = Quaternion(0.66675293, -0.67880416, 0.20062506, -0.23327015)
bones/10/rotation = Quaternion(-0.35678986, 0.01807761, 0.006905738, 0.9339843)
bones/12/rotation = Quaternion(0.70710534, 0.70710546, 0.0014091316, -0.0014093613)
bones/13/rotation = Quaternion(-0.021626502, -0.09508007, 0.7082199, 0.6992257)
bones/14/rotation = Quaternion(0.13296904, 0.051822014, -0.0069621364, 0.98974)
bones/16/rotation = Quaternion(0.7071066, 0.7071067, 0.00044525132, -0.00044566192)
bones/17/rotation = Quaternion(0.20738536, 0.2267729, 0.6646832, 0.6810004)
bones/18/rotation = Quaternion(-0.35684106, -0.008877046, -0.003391197, 0.93411684)
bones/20/rotation = Quaternion(0.6013276, -0.007656024, 0.017799761, 0.79876757)
bones/22/rotation = Quaternion(0.0076703057, 0.9327372, 0.3595561, -0.025732514)
bones/23/rotation = Quaternion(-0.089636706, -0.019697238, -0.01825219, 0.99561244)
bones/24/rotation = Quaternion(-0.44343108, -0.23039742, 0.11800072, 0.85811526)
bones/26/rotation = Quaternion(5.170388e-06, 0.6954638, 0.7185612, 5.0026606e-06)
bones/27/rotation = Quaternion(0.052304644, 0.00074447604, -0.01352817, 0.99853927)
bones/29/rotation = Quaternion(0.7071068, -9.581396e-07, -9.581394e-07, 0.7071067)
bones/31/rotation = Quaternion(0.7071068, -1.2110207e-06, -1.2110205e-06, 0.7071067)

Binary file not shown.

View File

@@ -0,0 +1,36 @@
[gd_scene format=3 uid="uid://bs1bdtm7jdtgb"]
[ext_resource type="PackedScene" uid="uid://clx701xdwelgx" path="res://core/ai/agents/base/ai_base.tscn" id="1_smbiq"]
[ext_resource type="PackedScene" uid="uid://58u6viv3qd63" path="res://core/ai/agents/sheep/sheep_mannequin.tscn" id="2_hnenk"]
[ext_resource type="Animation" uid="uid://ifn4akvcgaua" path="res://core/ai/agents/sheep/idle.res" id="3_i3d22"]
[ext_resource type="Animation" uid="uid://52eg4664eik0" path="res://core/ai/agents/sheep/walking.res" id="4_hxh1r"]
[sub_resource type="BoxShape3D" id="BoxShape3D_hnenk"]
size = Vector3(1, 1.4770508, 1.3725281)
[sub_resource type="AnimationLibrary" id="AnimationLibrary_vlyix"]
_data = {
&"idle": ExtResource("3_i3d22"),
&"walking": ExtResource("4_hxh1r")
}
[node name="AiSheep" unique_id=1228675528 node_paths=PackedStringArray("anim_player") instance=ExtResource("1_smbiq")]
anim_player = NodePath("SheepMannequin/AnimationPlayer")
[node name="MeshInstance3D" parent="." index="0" unique_id=214482161]
visible = false
[node name="CollisionShape3D" parent="." index="1" unique_id=92811823]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.23852539, 0.11299133)
shape = SubResource("BoxShape3D_hnenk")
[node name="SheepMannequin" parent="." index="5" 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=1644576745]
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=770197846]
libraries/custom = SubResource("AnimationLibrary_vlyix")
[editable path="SheepMannequin"]

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,29 @@
[gd_scene format=3 uid="uid://58u6viv3qd63"]
[ext_resource type="PackedScene" uid="uid://oog8biov508a" path="res://core/ai/agents/sheep/sheep.fbx" id="1_pnkxh"]
[node name="SheepMannequin" unique_id=1153770042 instance=ExtResource("1_pnkxh")]
[node name="Skeleton3D" parent="Armature" parent_id_path=PackedInt32Array(1644576745) index="0" unique_id=811031257]
bones/1/rotation = Quaternion(0.7071068, -7.052583e-07, -7.052583e-07, 0.7071067)
bones/4/rotation = Quaternion(0.0017592248, -0.0017595046, 0.7071046, 0.7071046)
bones/5/rotation = Quaternion(0.706397, -0.7005701, -0.057003256, 0.08339989)
bones/6/rotation = Quaternion(0.17354831, -0.018694565, 0.003295098, 0.98464245)
bones/8/rotation = Quaternion(0.0011415672, -0.0011422854, 0.7071059, 0.7071059)
bones/9/rotation = Quaternion(0.66940695, -0.67618734, 0.20153745, -0.23248184)
bones/10/rotation = Quaternion(-0.38440856, 0.017864142, 0.0074402345, 0.92296034)
bones/12/rotation = Quaternion(0.70710427, 0.7071044, 0.001866237, -0.0018665171)
bones/13/rotation = Quaternion(-0.033540055, -0.106803544, 0.7078988, 0.6973861)
bones/14/rotation = Quaternion(0.17334078, 0.051493812, -0.009075931, 0.9834729)
bones/16/rotation = Quaternion(0.70710605, 0.7071062, 0.0009843343, -0.0009850523)
bones/17/rotation = Quaternion(0.2082713, 0.22595985, 0.6673435, 0.67839366)
bones/18/rotation = Quaternion(-0.384463, -0.008772296, -0.0036537221, 0.92309153)
bones/20/rotation = Quaternion(0.6012591, 0.022893472, -0.005923484, 0.7987042)
bones/22/rotation = Quaternion(0.006586622, 0.9146406, 0.40345904, -0.02469813)
bones/23/rotation = Quaternion(0.07927493, -0.021147288, -0.014362239, 0.996525)
bones/24/rotation = Quaternion(-0.6495659, -0.19198355, 0.17329836, 0.71496445)
bones/26/rotation = Quaternion(3.4527793e-06, 0.6944211, 0.71956885, 3.3297817e-06)
bones/27/rotation = Quaternion(0.0651835, 0.0008379451, -0.017830681, 0.9977136)
bones/29/rotation = Quaternion(0.7071068, -7.052583e-07, -7.052583e-07, 0.7071067)
bones/31/rotation = Quaternion(0.7071068, -1.0424332e-06, -1.0424329e-06, 0.7071067)
bones/33/rotation = Quaternion(0.7071068, -1.0424332e-06, -1.0424329e-06, 0.7071067)

Binary file not shown.

View File

@@ -0,0 +1,20 @@
extends Node
class_name State
@export var state_id: StringName = &""
@warning_ignore("unused_signal")
signal transitioned(state: State, new_state_id: StringName)
func enter() -> void:
pass
func exit() -> void:
pass
func update(_delta) -> void:
pass
func physics_update(_delta) -> void:
pass

View File

@@ -0,0 +1 @@
uid://dpso7abi5ftyw

View File

@@ -0,0 +1,61 @@
extends Node
class_name StateMachine
@export var initial_state: State
var current_state: State
var states: Dictionary[StringName, State] = {}
var is_initialized: bool = false
var _enabled: bool = true
var enable: bool:
set(value):
_enabled = value
_set_enabled(value)
get:
return _enabled
func _ready() -> void:
_initialize_states()
_set_enabled(enable)
func _initialize_states() -> void:
if is_initialized:
return
for state in get_children():
if state is State:
states[state.state_id] = state
state.transitioned.connect(_on_state_transition)
is_initialized = true
func _set_enabled(value: bool) -> void:
_enabled = value
if not _enabled:
return
_initialize_states()
if initial_state and current_state == null:
current_state = initial_state
current_state.enter()
func physics_process(delta) -> void:
if current_state and _enabled:
current_state.physics_update(delta)
func _on_state_transition(state: State, new_state_id: StringName) -> void:
if state != current_state:
return
var new_state = states.get(new_state_id)
if not new_state:
return
if current_state:
current_state.exit()
current_state = new_state
current_state.enter()

View File

@@ -0,0 +1 @@
uid://ps3vlu2qvmop

View File

@@ -0,0 +1,31 @@
extends Node
const MIN_VOLUME: float = 0.0
const MAX_VOLUME: float = 1.0
func _ready() -> void:
load_save_data()
func load_save_data() -> void:
for bus_name in GameState.save_data.audio_bus_volumes:
_apply_audio_bus_volume(bus_name, GameState.save_data.audio_bus_volumes[bus_name])
func set_audio_bus_volume(bus_name: StringName, linear_value: float) -> void:
var normalized_bus_name := str(bus_name)
var clamped_value := clampf(linear_value, MIN_VOLUME, MAX_VOLUME)
GameState.save_data.audio_bus_volumes[normalized_bus_name] = clamped_value
_apply_audio_bus_volume(normalized_bus_name, clamped_value)
GameState.save_game()
func get_audio_bus_volume(bus_name: StringName, default_value: float = 1.0) -> float:
return float(GameState.save_data.audio_bus_volumes.get(str(bus_name), default_value))
func _apply_audio_bus_volume(bus_name: String, linear_value: float) -> void:
var bus_index := AudioServer.get_bus_index(bus_name)
if bus_index == -1:
return
var clamped_value := clampf(linear_value, MIN_VOLUME, MAX_VOLUME)
AudioServer.set_bus_volume_db(bus_index, linear_to_db(clamped_value))
AudioServer.set_bus_mute(bus_index, is_zero_approx(clamped_value))

View File

@@ -0,0 +1 @@
uid://dcttbbavtwtsg

View File

@@ -1,41 +1,79 @@
extends Node3D
const CHUNK_GENERATION_STEPS_PER_FRAME: int = 2
const CHUNK_CLEANUP_STEPS_PER_FRAME: int = 4
const LAMPPOST_WIRE_STEPS_PER_FRAME: int = 1
const CHUNK_TYPE_BIOME: int = 0
const CHUNK_TYPE_STRAIGHT_TRACK: int = 1
const CHUNK_TYPE_CURVED_TRACK: int = 2
const CHUNK_GENERATION_FRAME_BUDGET_USEC: int = 2000 #2 ms/frame to generate chunks
const CHUNK_CLEANUP_FRAME_BUDGET_USEC: int = 1000 #1 ms/frame per cleanup
const LAMPPOST_WIRE_FRAME_BUDGET_USEC: int = 1000 #1 ms/frame per i fili dei lampioni
#(about 4 ms o work for frame)
#Se compaiono chunk troppo lentamente davanti al treno:
#aumentare generazione a 3000 o 4000
#Se ci sono micro-scatti:
#abbassare generazione a 1000 o 1500
#Se i fili appaiono in ritardo:
#aumentare wire a 1500 o 2000
#Se il cleanup causa scatti:
#abbassare cleanup a 500
const MAX_CHUNK_UNIQUENESS: int = 5
const RAILWAY_SCENE_DIRECTORY: String = "res://tgcc/chunk/railway/scene"
const RIVER_SIDE_ORDER: Array[String] = ["north", "est", "south", "west"]
const RIVER_DIRECTIONS: Dictionary = {
"north": Vector2(0.0, -1.0),
"est": Vector2(1.0, 0.0),
"south": Vector2(0.0, 1.0),
"west": Vector2(-1.0, 0.0),
}
const RIVER_NEIGHBOUR_OFFSETS: Dictionary = {
"north": Vector2i(0, -1),
"est": Vector2i(1, 0),
"south": Vector2i(0, 1),
"west": Vector2i(-1, 0),
}
@export_group("Rails")
@export var rail_path: Path3D
@export var rail_path: Path3D #rail path
@export_group("Biomes")
@export var biome_list: Array[Biome]
@export var biome_list: Array[Biome] #list of scenes for the biome
@export_group("Grid and Area")
@export var chunk_size: float = 20.0
@export var eye_line: int = 3
@export var district_scale: float = 0.05
@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
@export_group("Lamppost")
@export var lamppost_wire_material: ShaderMaterial
@export_range(0.01, 1.0) var wire_thickness: float = 0.05
@export var lamppost_dist_factor: int = 10 #max distance of connections
var board: Dictionary = {}
var last_pos_train: Vector2i = Vector2i(999999, 999999)
var noise_generator: FastNoiseLite
var altitude_generator: FastNoiseLite
var wire_connections: Dictionary = {}
var chunk_candidate_cache: Dictionary = {}
var chunk_candidate_cache: Dictionary = {} #node cache (metadata)
var prop_candidate_cache: Dictionary = {}
var pending_generation_cells: Array[Vector2i] = []
var pending_cleanup_cells: Array[Vector2i] = []
var pending_wire_cells: Array[Vector2i] = []
var pending_generation_cursor: int = 0
var pending_cleanup_cursor: int = 0
var pending_wire_cursor: int = 0
var pending_wire_lookup: Dictionary = {}
var pending_radar_update: bool = false
var rail_chunk_catalogue: Dictionary = {} #rails chunk list
var manual_biome: Biome = null
func _ready() -> void:
if biome_list.is_empty() or rail_path == null: return
#connect events
UIEvents.update_rail_chunks.connect(_update_rail_chunks)
#noise generator for biome and altitute
noise_generator = FastNoiseLite.new()
noise_generator.noise_type = FastNoiseLite.TYPE_PERLIN
noise_generator.seed = randi()
@@ -46,7 +84,10 @@ func _ready() -> void:
altitude_generator.seed = randi()
altitude_generator.frequency = district_scale * 0.5
#fill cache with available chunk
_warm_chunk_candidate_cache()
_warm_rail_chunk_catalogue()
#set unique pieces
_update_set_pieces()
func _update_set_pieces() -> void:
@@ -61,7 +102,7 @@ func _update_set_pieces() -> void:
var local_biome = ""
if manual_biome != null:
local_biome = manual_biome.nome
local_biome = manual_biome.name
else:
var grid_x = roundi(sp.global_position.x / chunk_size)
var grid_z = roundi(sp.global_position.z / chunk_size)
@@ -87,7 +128,7 @@ func _destroy_and_regenrate_world() -> void:
#Destroy all models
for pos in board.keys():
var cella = board[pos]
if cella["type"] != "obstacle":
if not _is_persistent_obstacle(cella):
if cella.has("node") and is_instance_valid(cella["node"]):
cella["node"].queue_free()
@@ -100,18 +141,14 @@ func _destroy_and_regenrate_world() -> void:
if rail_path != null and rail_path.train_instance != null:
var train_pos = rail_path.train_instance.global_position
var current_pos = Vector2i(roundi(train_pos.x / chunk_size), roundi(train_pos.z / chunk_size))
_refresh_world_work(current_pos)
pending_radar_update = true
_refresh_world(current_pos)
func _process(_delta: float) -> void:
#based on time budgets the queues are evaluated by frame and not all together
_drain_cleanup_queue()
_drain_generation_queue()
_drain_wire_queue()
if pending_radar_update:
pending_radar_update = false
_train_radar()
func _physics_process(_delta: float) -> void:
if rail_path == null or rail_path.train_instance == null: return
@@ -122,8 +159,7 @@ func _physics_process(_delta: float) -> void:
if current_pos != last_pos_train:
last_pos_train = current_pos
_refresh_world_work(current_pos)
pending_radar_update = true
_refresh_world(current_pos)
func collect_all_chunkinfo(root: Node, list: Array[Node]) -> void:
if root == null: return
@@ -134,6 +170,15 @@ func collect_all_chunkinfo(root: Node, list: Array[Node]) -> void:
for child in root.get_children():
collect_all_chunkinfo(child, list)
func collect_all_propinfo(root: Node, list: Array[Node]) -> void:
if root == null: return
if "available_props" in root:
list.append(root)
for child in root.get_children():
collect_all_propinfo(child, list)
func _warm_chunk_candidate_cache() -> void:
var unique_scenes: Dictionary = {}
@@ -154,6 +199,28 @@ func _warm_chunk_candidate_cache() -> void:
for scene in unique_scenes.values():
_get_chunk_scene_metadata(scene)
func _warm_rail_chunk_catalogue() -> void:
rail_chunk_catalogue.clear()
var directory := DirAccess.open(RAILWAY_SCENE_DIRECTORY)
if directory == null:
return
directory.list_dir_begin()
var file_name := directory.get_next()
while file_name != "":
if not directory.current_is_dir() and file_name.ends_with(".tscn"):
var scene_path := "%s/%s" % [RAILWAY_SCENE_DIRECTORY, file_name]
var scene := load(scene_path) as PackedScene
if scene != null:
var chunk_type = _get_chunk_type_from_scene(scene)
if chunk_type == CHUNK_TYPE_STRAIGHT_TRACK or chunk_type == CHUNK_TYPE_CURVED_TRACK:
if not rail_chunk_catalogue.has(chunk_type):
rail_chunk_catalogue[chunk_type] = []
rail_chunk_catalogue[chunk_type].append(scene)
file_name = directory.get_next()
directory.list_dir_end()
func _get_chunk_scene_cache_key(scene: PackedScene) -> String:
if scene == null:
return ""
@@ -194,6 +261,7 @@ func _get_chunk_scene_metadata(scene: PackedScene) -> Dictionary:
"info_path": info_path,
"rotations": rotations,
"has_lamppost": "have_lamppost" in info_node and info_node.have_lamppost,
"uniqueness": _get_chunk_uniqueness_from_info(info_node),
}
preview_chunk.queue_free()
chunk_candidate_cache[key] = metadata
@@ -209,19 +277,129 @@ func _get_cached_chunk_info(instance: Node, scene: PackedScene) -> Node:
return instance
return instance.get_node_or_null(info_path)
func _get_chunk_type_from_scene(scene: PackedScene) -> int:
if scene == null:
return CHUNK_TYPE_BIOME
var preview_chunk = scene.instantiate()
var info_list: Array[Node] = []
collect_all_chunkinfo(preview_chunk, info_list)
var info_node = info_list[0] if info_list.size() > 0 else null
var chunk_type = CHUNK_TYPE_BIOME
if info_node != null and "chunk_type" in info_node:
chunk_type = info_node.chunk_type
preview_chunk.queue_free()
return chunk_type
func _clear_pending_world_work() -> void:
pending_generation_cells.clear()
pending_cleanup_cells.clear()
pending_wire_cells.clear()
pending_generation_cursor = 0
pending_cleanup_cursor = 0
pending_wire_cursor = 0
pending_wire_lookup.clear()
pending_radar_update = false
func _refresh_world_work(center: Vector2i) -> void:
func _collect_replaceable_rail_chunks(root: Node, result: Array[Node3D]) -> void:
if root == null:
return
if root is Node3D:
var node_3d := root as Node3D
if node_3d.scene_file_path.begins_with(RAILWAY_SCENE_DIRECTORY):
var info_list: Array[Node] = []
collect_all_chunkinfo(node_3d, info_list)
var info_node = info_list[0] if info_list.size() > 0 else null
if info_node != null and "chunk_type" in info_node:
var chunk_type = info_node.chunk_type
if chunk_type == CHUNK_TYPE_STRAIGHT_TRACK or chunk_type == CHUNK_TYPE_CURVED_TRACK:
result.append(node_3d)
return
for child in root.get_children():
_collect_replaceable_rail_chunks(child, result)
func _pick_replacement_rail_scene(chunk_type: int, current_scene_path: String) -> PackedScene:
var candidates: Array = rail_chunk_catalogue.get(chunk_type, [])
if candidates.is_empty():
return null
var alternatives: Array[PackedScene] = []
for candidate in candidates:
var scene := candidate as PackedScene
if scene != null and scene.resource_path != current_scene_path:
alternatives.append(scene)
if not alternatives.is_empty():
return alternatives.pick_random()
return candidates.pick_random() as PackedScene
func _replace_rail_chunk_instance(chunk_root: Node3D) -> bool:
if chunk_root == null or not is_instance_valid(chunk_root):
return false
var info_list: Array[Node] = []
collect_all_chunkinfo(chunk_root, info_list)
var info_node = info_list[0] if info_list.size() > 0 else null
if info_node == null or not "chunk_type" in info_node:
return false
var replacement_scene = _pick_replacement_rail_scene(info_node.chunk_type, chunk_root.scene_file_path)
if replacement_scene == null:
return false
var chunk_parent = chunk_root.get_parent()
var replacement = replacement_scene.instantiate() as Node3D
if chunk_parent == null or replacement == null:
return false
var chunk_index = chunk_root.get_index()
var chunk_name = chunk_root.name
chunk_root.name = "%s_old" % chunk_name
replacement.transform = chunk_root.transform
chunk_parent.add_child(replacement)
chunk_parent.move_child(replacement, chunk_index)
replacement.name = chunk_name
replacement.owner = chunk_root.owner
chunk_root.queue_free()
return true
#rebuild the scene catalogue from res://tgcc/chunk/railway/scene,
#than serach on the current scene which chunks can be changed and for each one chose a new scene (the same kind)
func _refresh_rail_chunks() -> void:
print("update rail chunks")
_warm_rail_chunk_catalogue()
var current_scene: Node = get_tree().current_scene
if current_scene == null:
return
var replaceable_chunks: Array[Node3D] = []
_collect_replaceable_rail_chunks(current_scene, replaceable_chunks)
var replaced_count = 0
for chunk_root in replaceable_chunks:
if _replace_rail_chunk_instance(chunk_root):
replaced_count += 1
if replaced_count > 0:
await get_tree().process_frame
_destroy_and_regenrate_world()
func _update_rail_chunks() -> void:
call_deferred("_refresh_rail_chunks")
func _refresh_world(center: Vector2i) -> void:
_rebuild_generation_queue(center)
_rebuild_cleanup_queue(center)
#check cells around the train by rings:
#first the center, then borders with distance = 1, the distance = 2 and so to eye_line.
#Use maxi(abs(x), abs(z)) to know the border of the ring. Cells closest to the train have more priority
func _rebuild_generation_queue(center: Vector2i) -> void:
pending_generation_cells.clear()
pending_generation_cursor = 0
for radius in range(eye_line + 1):
for x in range(-radius, radius + 1):
@@ -234,13 +412,17 @@ func _rebuild_generation_queue(center: Vector2i) -> void:
continue
pending_generation_cells.append(grid_pos)
#For each cells add to cleanup queue the cells too far
#Use eye_line plus a margin value to hide chunks not instantly when go out of the eye line
#Persistent obstacle cells are not deleted (rails or set_pieces)
func _rebuild_cleanup_queue(center: Vector2i) -> void:
pending_cleanup_cells.clear()
pending_cleanup_cursor = 0
var safe_margin = 2
for grid_pos in board.keys():
var cell = board[grid_pos]
if cell["type"] == "obstacle":
if _is_persistent_obstacle(cell):
continue
var dist_x = abs(grid_pos.x - center.x)
@@ -248,10 +430,16 @@ func _rebuild_cleanup_queue(center: Vector2i) -> void:
if dist_x > eye_line + safe_margin or dist_z > eye_line + safe_margin:
pending_cleanup_cells.append(grid_pos)
#Check if a queue can continue to work based on time budget setted
func _queue_has_frame_budget(start_usec: int, budget_usec: int, processed: int) -> bool:
return processed == 0 or Time.get_ticks_usec() - start_usec < budget_usec
func _drain_generation_queue() -> void:
var processed = 0
while processed < CHUNK_GENERATION_STEPS_PER_FRAME and not pending_generation_cells.is_empty():
var grid_pos = pending_generation_cells.pop_front()
var processed: int = 0
var start_usec: int = Time.get_ticks_usec()
while pending_generation_cursor < pending_generation_cells.size() and _queue_has_frame_budget(start_usec, CHUNK_GENERATION_FRAME_BUDGET_USEC, processed):
var grid_pos: Vector2i = pending_generation_cells[pending_generation_cursor]
pending_generation_cursor += 1
if board.has(grid_pos):
continue
@@ -260,15 +448,21 @@ func _drain_generation_queue() -> void:
_add_compatible_biome(grid_pos)
processed += 1
if pending_generation_cursor >= pending_generation_cells.size():
pending_generation_cells.clear()
pending_generation_cursor = 0
func _drain_cleanup_queue() -> void:
var processed = 0
while processed < CHUNK_CLEANUP_STEPS_PER_FRAME and not pending_cleanup_cells.is_empty():
var grid_pos = pending_cleanup_cells.pop_front()
var processed: int = 0
var start_usec: int = Time.get_ticks_usec()
while pending_cleanup_cursor < pending_cleanup_cells.size() and _queue_has_frame_budget(start_usec, CHUNK_CLEANUP_FRAME_BUDGET_USEC, processed):
var grid_pos: Vector2i = pending_cleanup_cells[pending_cleanup_cursor]
pending_cleanup_cursor += 1
if not board.has(grid_pos):
continue
var cell = board[grid_pos]
if cell["type"] == "obstacle":
if _is_persistent_obstacle(cell):
continue
if cell.has("node") and is_instance_valid(cell["node"]):
@@ -276,6 +470,10 @@ func _drain_cleanup_queue() -> void:
board.erase(grid_pos)
processed += 1
if pending_cleanup_cursor >= pending_cleanup_cells.size():
pending_cleanup_cells.clear()
pending_cleanup_cursor = 0
func _queue_lamppost_wire_connection(grid_pos: Vector2i) -> void:
if pending_wire_lookup.has(grid_pos):
return
@@ -283,9 +481,11 @@ func _queue_lamppost_wire_connection(grid_pos: Vector2i) -> void:
pending_wire_cells.append(grid_pos)
func _drain_wire_queue() -> void:
var processed = 0
while processed < LAMPPOST_WIRE_STEPS_PER_FRAME and not pending_wire_cells.is_empty():
var grid_pos = pending_wire_cells.pop_front()
var processed: int = 0
var start_usec: int = Time.get_ticks_usec()
while pending_wire_cursor < pending_wire_cells.size() and _queue_has_frame_budget(start_usec, LAMPPOST_WIRE_FRAME_BUDGET_USEC, processed):
var grid_pos: Vector2i = pending_wire_cells[pending_wire_cursor]
pending_wire_cursor += 1
pending_wire_lookup.erase(grid_pos)
if not board.has(grid_pos):
@@ -296,6 +496,10 @@ func _drain_wire_queue() -> void:
_connect_lamppost_wires(grid_pos)
processed += 1
if pending_wire_cursor >= pending_wire_cells.size():
pending_wire_cells.clear()
pending_wire_cursor = 0
func _generate_pieces_around_train(center: Vector2i) -> void:
for x in range(-eye_line, eye_line + 1):
for z in range(-eye_line, eye_line + 1):
@@ -306,6 +510,8 @@ func _generate_pieces_around_train(center: Vector2i) -> void:
if not ce_obstacle:
_add_compatible_biome(grid_pos)
#Decice which catalogue of chunks use for a cell. If manual_biome is set use always it
#Otherwise read noise_generator.get_noise_2d to give an index for biome_list
func _choose_catalogue_by_cell(grid_pos: Vector2i) -> Array[PackedScene]:
if manual_biome != null:
return manual_biome.available_chunks
@@ -323,6 +529,143 @@ func _get_procedural_biome_name(value: float) -> String:
var index = clamp(int(normalized_value * biome_list.size()), 0, biome_list.size() - 1)
return biome_list[index].name
func _get_chunk_uniqueness_from_info(info_node: Node) -> int:
if info_node != null and "uniqueness" in info_node:
return clampi(info_node.uniqueness, 0, MAX_CHUNK_UNIQUENESS)
return 0
func _get_prop_uniqueness_from_info(info_node: Node) -> int:
if info_node != null and "uniqueness" in info_node:
return clampi(info_node.uniqueness, 0, MAX_CHUNK_UNIQUENESS)
return -1
func _is_persistent_obstacle(cell: Dictionary) -> bool:
return cell.get("type", "") == "obstacle" and cell.get("persistent", true)
func _has_nearby_unique_chunk(grid_pos: Vector2i, uniqueness: int) -> bool:
if uniqueness <= 0:
return false
for nearby_pos in board.keys():
var nearby_uniqueness = int(board[nearby_pos].get("uniqueness", 0))
if nearby_uniqueness <= 0:
continue
var min_distance = maxi(uniqueness, nearby_uniqueness)
var dist_x = abs(nearby_pos.x - grid_pos.x)
var dist_z = abs(nearby_pos.y - grid_pos.y)
if dist_x <= min_distance and dist_z <= min_distance:
return true
return false
func _get_uniqueness_pick_weight(uniqueness: int) -> float:
return 1.0 / pow(float(uniqueness + 1), 2.0)
func _pick_weighted_candidate(candidates: Array) -> Dictionary:
var total_weight = 0.0
for candidate in candidates:
total_weight += candidate.weight
if total_weight <= 0.0:
return candidates.pick_random()
var target_weight = randf() * total_weight
var current_weight = 0.0
for candidate in candidates:
current_weight += candidate.weight
if current_weight >= target_weight:
return candidate
return candidates.back()
func _pick_backup_scene(zone_catalogue: Array[PackedScene], grid_pos: Vector2i) -> PackedScene:
for scene in zone_catalogue:
var metadata = _get_chunk_scene_metadata(scene)
var uniqueness = int(metadata.get("uniqueness", 0))
if not _has_nearby_unique_chunk(grid_pos, uniqueness):
return scene
return zone_catalogue[0]
func _get_prop_scene_cache_key(scene: PackedScene) -> String:
if scene == null:
return ""
if scene.resource_path != "":
return scene.resource_path
return "prop_scene_%s" % scene.get_instance_id()
func _get_prop_scene_uniqueness(scene: PackedScene) -> int:
if scene == null:
return -1
var key = _get_prop_scene_cache_key(scene)
if prop_candidate_cache.has(key):
return prop_candidate_cache[key]
var preview_prop = scene.instantiate()
var uniqueness = _get_prop_uniqueness_from_info(preview_prop)
if uniqueness == -1:
var prop_info_list: Array[Node] = []
collect_all_propinfo(preview_prop, prop_info_list)
if not prop_info_list.is_empty():
uniqueness = _get_prop_uniqueness_from_info(prop_info_list[0])
preview_prop.queue_free()
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)
for prop_scene in marker.available_props:
if prop_scene == null:
continue
var uniqueness = _get_prop_scene_uniqueness(prop_scene)
if uniqueness == -1:
uniqueness = fallback_uniqueness
candidates.append({
"scene": prop_scene,
"weight": _get_uniqueness_pick_weight(uniqueness),
"uniqueness": uniqueness
})
if candidates.is_empty():
return null
return _pick_weighted_candidate(candidates).scene
func _spawn_props_for_chunk(root: Node) -> void:
var prop_markers: Array[Node] = []
collect_all_propinfo(root, prop_markers)
for marker in prop_markers:
_spawn_prop_for_marker(marker)
func _spawn_prop_for_marker(marker: Node) -> void:
if marker.available_props.is_empty():
return
var prop_scene = _pick_weighted_prop_scene(marker)
if prop_scene == null:
return
var prop_instance = prop_scene.instantiate()
var prop_node = prop_instance as Node3D
if prop_node == null:
prop_instance.queue_free()
return
marker.add_child(prop_node)
prop_node.transform = Transform3D.IDENTITY
#Using a vertical raycast from the top to the bottom at the center of the cell
#If there is a collision search for a new chunk node
func _register_cell_with_ray(grid_pos: Vector2i) -> bool:
if board.has(grid_pos): return true
@@ -367,8 +710,10 @@ func _register_cell_with_ray(grid_pos: Vector2i) -> bool:
right_info_node = info_list[0]
var exit_found = {"north": false, "est": false, "south": false, "west": false}
var river_exit_found = {"north": false, "est": false, "south": false, "west": false}
var height_found = {"north": 0, "est": 0, "south": 0, "west": 0}
var have_lamppost = false
var uniqueness = 0
#Get node info
if right_info_node != null:
@@ -376,19 +721,25 @@ func _register_cell_with_ray(grid_pos: Vector2i) -> bool:
var rotation_steps = roundi(rad_to_deg(right_info_node.global_rotation.y) / -90.0)
var data = right_info_node.get_rotated_data(rotation_steps)
exit_found = data["connections"]
river_exit_found = data["river_connections"]
height_found = data["heights"]
if "have_lamppost" in right_info_node:
have_lamppost = right_info_node.have_lamppost
uniqueness = _get_chunk_uniqueness_from_info(right_info_node)
#Add piece to the grid
board[grid_pos] = {
"type": "obstacle",
"exit": exit_found,
"river_exit": river_exit_found,
"heights": height_found,
"node": root_chunk,
"info": right_info_node,
"have_lamppost": have_lamppost
"have_lamppost": have_lamppost,
"uniqueness": uniqueness,
"persistent": true
}
if have_lamppost:
@@ -397,11 +748,20 @@ func _register_cell_with_ray(grid_pos: Vector2i) -> bool:
return true
return false
#For the cell to fill check the contrains for the four neighbors:
#If the neighbor at north have and exit on south then new chunk should have exit to north (the same for east and ovest)
#Contrains: 1 -> connection is mandatory; 0 -> no connection; -1 -> no contrain because there is no neighbor or it already exits
#When generator know the contrains take all chunks and try all different rotations
#A candidate is valid only if all contrains are correct
func _add_compatible_biome(grid_pos: Vector2i) -> void:
var req_conn_north = _needed_connection(grid_pos + Vector2i(0, -1), "south")
var req_conn_est = _needed_connection(grid_pos + Vector2i(1, 0), "west")
var req_conn_south = _needed_connection(grid_pos + Vector2i(0, 1), "north")
var req_conn_west = _needed_connection(grid_pos + Vector2i(-1, 0), "est")
var req_river_north = _needed_river_connection(grid_pos + Vector2i(0, -1), "south")
var req_river_est = _needed_river_connection(grid_pos + Vector2i(1, 0), "west")
var req_river_south = _needed_river_connection(grid_pos + Vector2i(0, 1), "north")
var req_river_west = _needed_river_connection(grid_pos + Vector2i(-1, 0), "est")
var req_height_north = _needed_heights(grid_pos + Vector2i(0, -1), "south")
var req_height_est = _needed_heights(grid_pos + Vector2i(1, 0), "west")
@@ -423,12 +783,20 @@ func _add_compatible_biome(grid_pos: Vector2i) -> void:
var rot = candidate["rotation"]
var data = candidate["data"]
var u_conn = data["connections"]
var u_river_conn = data["river_connections"]
var u_height = data["heights"]
var uniqueness = int(metadata.get("uniqueness", 0))
if _has_nearby_unique_chunk(grid_pos, uniqueness):
continue
var match_conn_n = (req_conn_north == -1) or ((req_conn_north == 1) == u_conn["north"])
var match_conn_e = (req_conn_est == -1) or ((req_conn_est == 1) == u_conn["est"])
var match_conn_s = (req_conn_south == -1) or ((req_conn_south == 1) == u_conn["south"])
var match_conn_o = (req_conn_west == -1) or ((req_conn_west == 1) == u_conn["west"])
var match_river_n = (req_river_north == -1) or ((req_river_north == 1) == u_river_conn["north"])
var match_river_e = (req_river_est == -1) or ((req_river_est == 1) == u_river_conn["est"])
var match_river_s = (req_river_south == -1) or ((req_river_south == 1) == u_river_conn["south"])
var match_river_o = (req_river_west == -1) or ((req_river_west == 1) == u_river_conn["west"])
var match_alt_n = (req_height_north == -1) or (req_height_north == u_height["north"])
var match_alt_e = (req_height_est == -1) or (req_height_est == u_height["est"])
@@ -441,14 +809,21 @@ func _add_compatible_biome(grid_pos: Vector2i) -> void:
var diff_o = abs(u_height["west"] - height_target) if req_height_west == -1 else 0
var excessive_jumps = diff_n > 1 or diff_e > 1 or diff_s > 1 or diff_o > 1
if match_conn_n and match_conn_e and match_conn_s and match_conn_o and match_alt_n and match_alt_e and match_alt_s and match_alt_o and not excessive_jumps:
if match_conn_n and match_conn_e and match_conn_s and match_conn_o and match_river_n and match_river_e and match_river_s and match_river_o and match_alt_n and match_alt_e and match_alt_s and match_alt_o and not excessive_jumps:
var score = 0
if req_height_north == -1 and u_height["north"] == height_target: score += 1
if req_height_est == -1 and u_height["est"] == height_target: score += 1
if req_height_south == -1 and u_height["south"] == height_target: score += 1
if req_height_west == -1 and u_height["west"] == height_target: score += 1
valid_candidates.append({"scene": scene, "rotation": rot, "data": data, "score": score})
valid_candidates.append({
"scene": scene,
"rotation": rot,
"data": data,
"score": score,
"weight": _get_uniqueness_pick_weight(uniqueness),
"uniqueness": uniqueness
})
if valid_candidates.size() > 0:
var max_score = -1
@@ -459,36 +834,46 @@ func _add_compatible_biome(grid_pos: Vector2i) -> void:
for c in valid_candidates:
if c.score == max_score: best_candidate.append(c)
var choise = best_candidate.pick_random()
var choise = _pick_weighted_candidate(best_candidate)
var new_chunk = choise.scene.instantiate()
new_chunk.position = Vector3(grid_pos.x * chunk_size, 0, grid_pos.y * chunk_size)
new_chunk.rotation.y = choise.rotation * (-PI / 2.0)
add_child(new_chunk)
_spawn_props_for_chunk(new_chunk)
var info_new = _get_cached_chunk_info(new_chunk, choise.scene)
var have_lamppost = false
if info_new != null and "have_lamppost" in info_new:
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)
board[grid_pos] = {
"type": "bioma",
"type": "biome",
"exit": choise.data["connections"],
"river_exit": choise.data["river_connections"],
"river_flow_direction": river_flow_direction,
"heights": choise.data["heights"],
"node": new_chunk,
"info": info_new,
"have_lamppost": have_lamppost
"have_lamppost": have_lamppost,
"uniqueness": choise.uniqueness
}
if have_lamppost:
_queue_lamppost_wire_connection(grid_pos)
else:
var backup = zone_catalogue[0].instantiate()
var backup_scene = _pick_backup_scene(zone_catalogue, grid_pos)
var backup = backup_scene.instantiate()
backup.position = Vector3(grid_pos.x * chunk_size, 0, grid_pos.y * chunk_size)
add_child(backup)
_spawn_props_for_chunk(backup)
var info_backup = _get_cached_chunk_info(backup, zone_catalogue[0])
var info_backup = _get_cached_chunk_info(backup, backup_scene)
var backup_uniqueness = _get_chunk_uniqueness_from_info(info_backup)
var safe_heights = {
"north": req_height_north if req_height_north != -1 else height_target,
@@ -499,12 +884,113 @@ func _add_compatible_biome(grid_pos: Vector2i) -> void:
board[grid_pos] = {
"type": "biome",
"exit": {"north":false, "est":false, "south":false, "west":false},
"river_exit": {"north":false, "est":false, "south":false, "west":false},
"river_flow_direction": Vector2.ZERO,
"heights": safe_heights,
"node": backup,
"info": info_backup,
"have_lamppost": false
"have_lamppost": false,
"uniqueness": backup_uniqueness
}
#Check if a neighbors have a river direction: if yes try to continue it,
#otherwise create a direction based on connections
func _calculate_river_flow_direction(grid_pos: Vector2i, river_connections: Dictionary) -> Vector2:
var connected_sides: Array[String] = []
for side in RIVER_SIDE_ORDER:
if river_connections.has(side) and river_connections[side]:
connected_sides.append(side)
if connected_sides.is_empty():
return Vector2.ZERO
var neighbour_flow = _get_connected_neighbour_river_flow(grid_pos, connected_sides)
if not neighbour_flow.is_zero_approx():
var continued_flow = _continue_river_flow_from_neighbour(grid_pos, connected_sides, neighbour_flow)
if not continued_flow.is_zero_approx():
return continued_flow.normalized()
var default_flow = _get_default_river_flow(connected_sides)
if default_flow.is_zero_approx():
return Vector2.ZERO
return default_flow.normalized()
func _get_connected_neighbour_river_flow(grid_pos: Vector2i, connected_sides: Array[String]) -> Vector2:
for side in connected_sides:
var neighbour_pos: Vector2i = grid_pos + RIVER_NEIGHBOUR_OFFSETS[side]
if not board.has(neighbour_pos):
continue
var neighbour = board[neighbour_pos]
if not neighbour.has("river_flow_direction"):
continue
var neighbour_flow: Vector2 = neighbour["river_flow_direction"]
if not neighbour_flow.is_zero_approx():
return neighbour_flow.normalized()
return Vector2.ZERO
func _continue_river_flow_from_neighbour(grid_pos: Vector2i, connected_sides: Array[String], neighbour_flow: Vector2) -> Vector2:
for side in connected_sides:
var neighbour_pos: Vector2i = grid_pos + RIVER_NEIGHBOUR_OFFSETS[side]
if not board.has(neighbour_pos):
continue
var neighbour = board[neighbour_pos]
if not neighbour.has("river_flow_direction"):
continue
var side_direction: Vector2 = RIVER_DIRECTIONS[side]
var neighbour_direction: Vector2 = neighbour["river_flow_direction"]
if neighbour_direction.is_zero_approx():
continue
neighbour_direction = neighbour_direction.normalized()
var other_sides = connected_sides.duplicate()
other_sides.erase(side)
if other_sides.is_empty():
return neighbour_direction
var other_direction = _get_average_river_side_direction(other_sides)
if neighbour_direction.dot(-side_direction) > 0.25:
return other_direction - side_direction
if neighbour_direction.dot(side_direction) > 0.25:
return side_direction - other_direction
var default_flow = _get_default_river_flow(connected_sides)
if default_flow.dot(neighbour_flow) < 0.0:
return -default_flow
return default_flow
func _get_default_river_flow(connected_sides: Array[String]) -> Vector2:
if connected_sides.size() == 1:
return RIVER_DIRECTIONS[connected_sides[0]]
if connected_sides.has("north") and connected_sides.has("south"):
return Vector2(0.0, 1.0)
if connected_sides.has("est") and connected_sides.has("west"):
return Vector2(1.0, 0.0)
var start_direction: Vector2 = RIVER_DIRECTIONS[connected_sides[0]]
var end_direction = _get_average_river_side_direction(connected_sides.slice(1))
return end_direction - start_direction
func _get_average_river_side_direction(sides: Array[String]) -> Vector2:
var direction := Vector2.ZERO
for side in sides:
direction += RIVER_DIRECTIONS[side]
if direction.is_zero_approx():
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
mesh_instance.set_instance_shader_parameter("river_flow_direction", flow_direction)
for child in node.get_children():
_set_river_flow_direction_recursive(child, flow_direction)
func _needed_connection(near_pos: Vector2i, side_needed: String) -> int:
if not board.has(near_pos):
_register_cell_with_ray(near_pos)
@@ -512,36 +998,17 @@ func _needed_connection(near_pos: Vector2i, side_needed: String) -> int:
return 1 if board[near_pos]["exit"][side_needed] else 0
return -1
func _needed_river_connection(near_pos: Vector2i, side_needed: String) -> int:
if not board.has(near_pos):
_register_cell_with_ray(near_pos)
if board.has(near_pos) and board[near_pos].has("river_exit"):
return 1 if board[near_pos]["river_exit"][side_needed] else 0
return -1
func _needed_heights(near_pos: Vector2i, side_needed: String) -> int:
if board.has(near_pos) and board[near_pos].has("heights"):
return board[near_pos]["heights"][side_needed]
return -1
func _train_radar() -> void:
if rail_path == null or rail_path.curve == null or rail_path.train_instance == null: return
if manual_biome != null:
return
var train_pos = rail_path.train_instance.global_position
var grid_x = roundi(train_pos.x / chunk_size)
var grid_z = roundi(train_pos.z / chunk_size)
var current_biome = _get_procedural_biome_name(noise_generator.get_noise_2d(grid_x, grid_z))
var current_progress = rail_path.train_progress
var total_length = rail_path.curve.get_baked_length()
for step in range(1, 31):
var next_progress = wrapf(current_progress + (step * chunk_size), 0.0, total_length)
var next_local_pos = rail_path.curve.sample_baked(next_progress, true)
var next_global_pos = rail_path.to_global(next_local_pos)
var f_x = roundi(next_global_pos.x / chunk_size)
var f_z = roundi(next_global_pos.z / chunk_size)
var future_biome = _get_procedural_biome_name(noise_generator.get_noise_2d(f_x, f_z))
if future_biome != current_biome:
break
func _get_lampposts(info_node: Node, side: String) -> Array[Node3D]:
var lampposts: Array[Node3D] = []
@@ -576,7 +1043,7 @@ func _connect_lamppost_wires(new_board_pos: Vector2i) -> void:
var p_sx_your_best = null; var p_dx_your_best = null
var best_closest_to_root = null
var best_distance = 999999.0
var ray_research = 3
var ray_research = 6
for x in range(-ray_research, ray_research + 1):
for z in range(-ray_research, ray_research + 1):
@@ -613,38 +1080,7 @@ func _connect_lamppost_wires(new_board_pos: Vector2i) -> void:
p_sx_your_best = closest_sx[i_t]
p_dx_your_best = closest_dx[i_t]
if best_closest_to_root == null:
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
var closest_pos = new_board_pos + Vector2i(x, z)
if board.has(closest_pos) and board[closest_pos].get("have_lamppost", false):
var closest_root = board[closest_pos]["node"]
var closest_info = board[closest_pos]["info"]
if not is_instance_valid(closest_root) or closest_root == new_root or closest_info == null: 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")
if closest_sx.is_empty() or closest_dx.is_empty(): continue
for i_m in range(new_sx.size()):
for i_t in range(closest_sx.size()):
var c_mio = (new_sx[i_m].global_position + new_dx[i_m].global_position) / 2.0
var c_tuo = (closest_sx[i_t].global_position + closest_dx[i_t].global_position) / 2.0
var dist = c_mio.distance_to(c_tuo)
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 * 8.0
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)
@@ -662,6 +1098,7 @@ func _connect_lamppost_wires(new_board_pos: Vector2i) -> void:
if not wire_connections.has(closest_id): wire_connections[closest_id] = 0
wire_connections[closest_id] += 1
#draw lamppost wires
func _draw_parable(p1: Vector3, p2: Vector3, parent: Node3D) -> void:
var segments = 15
var lowering = 1.5

View File

@@ -5,6 +5,7 @@ class_name ChunkInfo
@export_group("Set Piece Rules (Unique pieces)")
@export var exclusive_biome: String = "" # Es: "Forest"
@export_range(0, 5, 1) var uniqueness: int = 0 #0=common; 5=unique
@export_group("Base exit")
@export var north: bool = false
@@ -12,6 +13,12 @@ class_name ChunkInfo
@export var south: bool = false
@export var west: bool = false
@export_group("River exit")
@export var river_north: bool = false
@export var river_est: bool = false
@export var river_south: bool = false
@export var river_west: bool = false
@export_group("Margin heights (level 0, 1, 2)")
@export_range(0, 2, 1) var height_north: int = 0
@export_range(0, 2, 1) var height_est: int = 0
@@ -29,14 +36,17 @@ func _ready() -> void:
func get_rotated_data(steps_90: int) -> Dictionary:
var original_exit = [north, est, south, west]
var original_river_exit = [river_north, river_est, river_south, river_west]
var original_height = [height_north, height_est, height_south, height_west]
var calculated_exit = []
var calculated_river_exit = []
var calculated_height = []
for i in range(4):
var index = (i - steps_90 + 4) % 4
calculated_exit.append(original_exit[index])
calculated_river_exit.append(original_river_exit[index])
calculated_height.append(original_height[index])
return {
@@ -44,6 +54,10 @@ func get_rotated_data(steps_90: int) -> Dictionary:
"north": calculated_exit[0], "est": calculated_exit[1],
"south": calculated_exit[2], "west": calculated_exit[3]
},
"river_connections": {
"north": calculated_river_exit[0], "est": calculated_river_exit[1],
"south": calculated_river_exit[2], "west": calculated_river_exit[3]
},
"heights": {
"north": calculated_height[0], "est": calculated_height[1],
"south": calculated_height[2], "west": calculated_height[3]

View File

@@ -0,0 +1,5 @@
extends Marker3D
class_name PropInfo
@export var available_props: Array[PackedScene]
@export_range(0, 5, 1) var uniqueness: int = 0 #0=common; 5=unique

View File

@@ -0,0 +1 @@
uid://dg6ngy4pmtsyc

View File

@@ -32,6 +32,7 @@ render_priority = 0
shader = ExtResource("2_r4tfj")
shader_parameter/use_red_as_alpha = true
shader_parameter/fog_color = Color(0.8, 0.85, 0.9, 0.5)
shader_parameter/fog_density = 0.25
shader_parameter/scroll_speed = Vector2(0.05, 0.01)
shader_parameter/texture_scale = Vector2(1, 1)
shader_parameter/edge_softness_y = 0.2
@@ -66,12 +67,12 @@ grad_intensity_morning = 0.05
grad_intensity_afternoon = 0.1
grad_intensity_night = 0.5
fog_color_morning = Color(0.7490196, 0.8509804, 0.9490196, 1)
fog_color_afternoon = Color(0.9647059, 0.5882353, 0.7607843, 1)
fog_color_night = Color(0.14901961, 0.101960786, 0.2509804, 1)
fog_color_afternoon = Color(0.9823975, 0.8034449, 0.8778439, 1)
fog_color_night = Color(0.38409987, 0.28720453, 0.5907528, 1)
fog_density_morning = 0.01
fog_density_afternoon = 0.02
glow_morning = 0.4
glow_night = 0.6
glow_night = 0.8
material_fog = SubResource("ShaderMaterial_b5atu")
material_drops = SubResource("StandardMaterial3D_r4tfj")
material_clouds = SubResource("ShaderMaterial_ruhh7")
@@ -80,7 +81,7 @@ lightning_min = 2
lightning_max = 4
lightning_scale_min = 2.0
lightning_scale_max = 5.0
godray_max_rain = 60
godray_max_rain = 30
godray_spawn_radius = 100.0
godray_spawn_offset = Vector3(20, 80, 20)
godray_rotation_degrees = Vector3(50, 30, 0)
@@ -90,6 +91,9 @@ wind_amount = 50
cloud_speed = 0.01
fireflies_amount = 550
fireflies_spawn_ray = 60.0
water_color_morning = Color(0.33333334, 0.654902, 0.5294118, 1)
water_color_afternoon = Color(0.5803922, 0.5137255, 0.2901961, 1)
water_color_night = Color(0.48235294, 0.45490196, 0.69411767, 1)
metadata/_custom_type_script = "uid://butda6k2tli3o"
[sub_resource type="Gradient" id="Gradient_i3hjl"]
@@ -258,6 +262,7 @@ shader = ExtResource("2_r4tfj")
shader_parameter/fog_noise = ExtResource("11_tuauy")
shader_parameter/use_red_as_alpha = true
shader_parameter/fog_color = Color(0.8, 0.8509804, 0.9019608, 0.2509804)
shader_parameter/fog_density = 0.25
shader_parameter/scroll_speed = Vector2(0, 0.01)
shader_parameter/texture_scale = Vector2(1, 1)
shader_parameter/edge_softness_y = 0.16400000779

View File

@@ -3,7 +3,6 @@ extends Node3D
const NOISE_TEXTURE: Texture2D = preload("res://core/daynight/noise.tres")
const WEATHER_SHADER: Material = preload("res://core/daynight/weather_overlay.tres")
const WEATHER_PLAIN_SHADER: Material = preload("res://core/daynight/weather_plain_shader.tres")
const DYNAMIC_ENVIRONMENT_UPDATES_PER_FRAME: int = 2 #how many update of the environment (apply materials) will be done per frame
@export var environment_config: EnvironmentConfig
@@ -134,7 +133,7 @@ func _apply_dynamic_environment_materials(node: Node) -> void:
_apply_weather_overlay_to_node(node, WEATHER_SHADER)
if node.is_in_group("weather_vegetables_node"):
_apply_weather_overlay_to_node(node, WEATHER_PLAIN_SHADER)
_clear_weather_overlay_from_node(node)
func ApplyWindNoiseToMaterials():
for node in get_tree().get_nodes_in_group("wind_node"):
@@ -160,15 +159,54 @@ func ApplyWeatherShaderToMaterials():
_apply_weather_overlay_to_node(node, WEATHER_SHADER)
for node in get_tree().get_nodes_in_group("weather_vegetables_node"):
_apply_weather_overlay_to_node(node, WEATHER_PLAIN_SHADER)
_clear_weather_overlay_from_node(node)
func _apply_weather_overlay_to_node(node: Node, material: Material) -> void:
if node.is_in_group("weather_vegetables_node"):
_clear_weather_overlay_from_node(node)
return
if node is GeometryInstance3D:
node.material_overlay = material
if _geometry_uses_alpha_texture(node):
node.material_overlay = null
else:
node.material_overlay = material
for child in node.get_children():
_apply_weather_overlay_to_node(child, material)
func _clear_weather_overlay_from_node(node: Node) -> void:
if node is GeometryInstance3D:
node.material_overlay = null
for child in node.get_children():
_clear_weather_overlay_from_node(child)
func _geometry_uses_alpha_texture(node: GeometryInstance3D) -> bool:
var material_override := node.material_override as ShaderMaterial
if _shader_material_uses_alpha_texture(material_override):
return true
if node is MeshInstance3D:
for surface_index in node.get_surface_override_material_count():
var surface_material := node.get_surface_override_material(surface_index) as ShaderMaterial
if _shader_material_uses_alpha_texture(surface_material):
return true
if node.mesh:
for surface_index in node.mesh.get_surface_count():
var mesh_material := node.mesh.surface_get_material(surface_index) as ShaderMaterial
if _shader_material_uses_alpha_texture(mesh_material):
return true
return false
func _shader_material_uses_alpha_texture(material: ShaderMaterial) -> bool:
if material == null or material.shader == null:
return false
return material.shader.code.find("alpha_texture") != -1
func select_day_time(normalized_time: float) -> void:
#set show_day_time_debug = true to show debug on screen
#normalized_time is a value between 0 and 1; the time of the day is calculate as "normalized_time" * 1440; day_time is the step to pass from sunrise, to day, to sunset, to night

View File

@@ -67,7 +67,6 @@ void fragment() {
float is_center = step(center_sharpness, internal_n);
ALBEDO = shadow_color;
ALPHA = mix(opacity_edge, opacity_center, is_center) * final_fade;
}
}

View File

@@ -7,6 +7,7 @@ uniform bool use_red_as_alpha = true;
group_uniforms Settings;
uniform vec4 fog_color : source_color = vec4(0.8, 0.85, 0.9, 0.5);
uniform float fog_density : hint_range(0.0, 1.0) = 0.25;
uniform vec2 scroll_speed = vec2(0.05, 0.01);
uniform vec2 texture_scale = vec2(1.0, 1.0);
@@ -36,5 +37,5 @@ void fragment() {
vec3 dark_fog = tinted_fog * 0.5;
ALBEDO = mix(tinted_fog, dark_fog, night_intensity);
ALPHA = fog_color.a * noise_alpha * edge_mask;
}
ALPHA = fog_color.a * fog_density * noise_alpha * edge_mask;
}

View File

@@ -8,10 +8,12 @@ global uniform float global_wind_speed;
global uniform float global_wind_strength;
global uniform vec2 global_wind_direction;
//global uniform sampler2D global_wind_noise : filter_linear_mipmap;
global uniform float global_snow_start_time;
global uniform float global_snow_accumulation_speed;
global uniform float global_snow_melt_time;
global uniform float global_snow_melt_speed;
global uniform float global_snow_start_time = -1.0;
global uniform float global_snow_accumulation_speed = 0.005;
global uniform float global_snow_melt_time = -1.0;
global uniform float global_snow_melt_speed = 0.1;
global uniform float global_snow_amount = 0.0;
global uniform float global_rain_intensity;
// --- PARAMETRI ESTETICI ---
uniform bool billboard_enabled = true;
@@ -31,6 +33,7 @@ uniform vec4 variance_color : source_color = vec4(0.3, 0.5, 0.2, 1.0); // Colore
uniform float variance_intensity : hint_range(0.0, 1.0) = 0.4; // Quanto si vedono le chiazze
uniform vec4 snow_color : source_color = vec4(0.85, 0.9, 0.95, 1.0);
uniform float snow_visibility : hint_range(0.0, 1.0) = 1.0;
// --- CONTROLLO GRADIENTE E RANDOM ---
uniform float height_min = 0.0;
@@ -41,6 +44,7 @@ uniform float light_steps : hint_range(1.0, 10.0) = 4.0;
uniform float random_mix : hint_range(0.0, 1.0) = 0.3;
uniform float cast_shadow_strength : hint_range(0.0, 1.0) = 0.6;
uniform float wetness_darkening : hint_range(0.0, 0.5) = 0.25;
varying vec3 v_final_color;
varying float v_shade_factor;
@@ -52,6 +56,21 @@ float hash(vec3 p) {
return fract((p.x + p.y) * p.z);
}
float get_snow_progress() {
float snow_progress = clamp(global_snow_amount, 0.0, 1.0);
if (global_snow_start_time >= 0.0) {
float timed_progress = clamp((TIME - global_snow_start_time) * global_snow_accumulation_speed, 0.0, 1.0);
snow_progress = max(snow_progress, timed_progress);
}
if (global_snow_melt_time >= 0.0) {
float melt = clamp((TIME - global_snow_melt_time) * global_snow_melt_speed, 0.0, 1.0);
snow_progress = min(snow_progress, 1.0 - melt);
}
return snow_progress;
}
void vertex() {
vec3 instance_pos = MODEL_MATRIX[3].xyz;
v_world_pos = instance_pos; // Salviamo la posizione dell'istanza
@@ -113,17 +132,10 @@ void fragment() {
// Applichiamo la variazione al colore finale dell'erba
vec3 varied_grass_color = mix(v_final_color, variance_color.rgb, noise_sample * variance_intensity);
float snow_amount = 0.0;
if (global_snow_start_time >= 0.0) {
snow_amount = clamp((TIME - global_snow_start_time) * global_snow_accumulation_speed, 0.0, 1.0);
}
if (global_snow_melt_time >= 0.0) {
float melt = clamp((TIME - global_snow_melt_time) * global_snow_melt_speed, 0.0, 1.0);
snow_amount *= (1.0 - melt);
}
float snow_amount = smoothstep(0.0, 1.0, get_snow_progress());
float top_mask = 1.0 - shifted_uv.y;
float snow_mask = smoothstep(1.0 - snow_amount, 1.2 - snow_amount, top_mask);
float snow_mask = smoothstep(0.65, 1.0, top_mask) * snow_amount * snow_visibility;
snow_mask *= step(0.01, snow_amount);
vec3 dark_snow = snow_color.rgb * (1.0 - shadow_intensity);
@@ -131,12 +143,15 @@ void fragment() {
// Mescoliamo il colore variato con la neve
vec3 final_albedo = mix(varied_grass_color, shaded_snow, snow_mask);
float rain_int = clamp(global_rain_intensity, 0.0, 1.0);
final_albedo *= mix(1.0, 1.0 - wetness_darkening, rain_int);
float final_roughness = mix(0.02, 0.005, rain_int);
ALBEDO = final_albedo;
ALPHA = tex.r * opacity;
ALPHA_SCISSOR_THRESHOLD = 0.5;
ROUGHNESS = 0.02;
ROUGHNESS = final_roughness;
}
void light() {

View File

@@ -20,17 +20,14 @@ const SNOW_CAP_SHADER: Shader = preload("res://core/daynight/snow_cap.gdshader")
var _mesh_instance: MeshInstance3D
func _ready() -> void:
add_to_group("weather_overlay_ignore")
_ensure_mesh_instance()
_rebuild()
func rebuild() -> void:
_rebuild()
func _ensure_mesh_instance() -> void:
_mesh_instance = get_node_or_null("SnowCapMesh") as MeshInstance3D
if _mesh_instance != null:
@@ -41,7 +38,6 @@ func _ensure_mesh_instance() -> void:
_mesh_instance.add_to_group("weather_overlay_ignore")
add_child(_mesh_instance)
func _rebuild() -> void:
var cap_width: float = 0.0
var cap_depth: float = 0.0
@@ -78,7 +74,6 @@ func _rebuild() -> void:
_mesh_instance.material_override = _build_material(cap_width, cap_depth)
_mesh_instance.visible = true
func _build_material(cap_width: float, cap_depth: float) -> ShaderMaterial:
var material := ShaderMaterial.new()
material.shader = SNOW_CAP_SHADER
@@ -87,7 +82,6 @@ func _build_material(cap_width: float, cap_depth: float) -> ShaderMaterial:
material.set_shader_parameter("half_depth", cap_depth * 0.5)
return material
func _get_target_aabb(target_mesh: MeshInstance3D) -> AABB:
var points: Array[Vector3] = []
for point in _get_aabb_points(target_mesh.get_aabb()):
@@ -98,7 +92,6 @@ func _get_target_aabb(target_mesh: MeshInstance3D) -> AABB:
merged = merged.expand(point)
return merged
func _get_aabb_points(aabb: AABB) -> Array[Vector3]:
var p: Vector3 = aabb.position
var s: Vector3 = aabb.size

View File

@@ -2,9 +2,10 @@ shader_type spatial;
render_mode blend_mix, cull_back, depth_draw_opaque;
global uniform float global_snow_start_time = -1.0;
global uniform float global_snow_accumulation_speed = 0.1;
global uniform float global_snow_accumulation_speed = 0.005;
global uniform float global_snow_melt_time = -1.0;
global uniform float global_snow_melt_speed = 0.1;
global uniform float global_snow_amount = 0.0;
global uniform vec4 global_snow_color = vec4(0.92, 0.96, 1.0, 1.0);
uniform float max_height : hint_range(0.02, 1.0) = 0.2;
@@ -51,17 +52,18 @@ float fbm(vec2 p) {
}
float get_snow_amount() {
float snow_amount = 0.0;
float snow_amount = clamp(global_snow_amount, 0.0, 1.0);
if (global_snow_start_time >= 0.0) {
snow_amount = clamp(
float timed_amount = clamp(
(TIME - global_snow_start_time) * global_snow_accumulation_speed,
0.0,
1.0
);
snow_amount = max(snow_amount, timed_amount);
}
if (global_snow_melt_time >= 0.0) {
float melt = clamp((TIME - global_snow_melt_time) * global_snow_melt_speed, 0.0, 1.0);
snow_amount *= (1.0 - melt);
snow_amount = min(snow_amount, 1.0 - melt);
}
return snow_amount;
}

View File

@@ -6,12 +6,12 @@ global uniform vec2 global_wind_direction;
global uniform float global_wind_scale;
global uniform float global_wind_strength;
global uniform float global_wind_fade;
/*
global uniform float global_snow_start_time;
global uniform float global_snow_accumulation_speed;
global uniform float global_snow_melt_time;
global uniform float global_snow_melt_speed;
global uniform vec4 global_snow_color;*/
global uniform float global_snow_start_time = -1.0;
global uniform float global_snow_accumulation_speed = 0.005;
global uniform float global_snow_melt_time = -1.0;
global uniform float global_snow_melt_speed = 0.1;
global uniform float global_snow_amount = 0.0;
global uniform vec4 global_snow_color;
global uniform float global_rain_intensity;
uniform sampler2D wind_noise : filter_linear_mipmap;
@@ -31,6 +31,7 @@ uniform float light_steps : hint_range(1.0, 10.0) = 4.0;
uniform float random_mix : hint_range(0.0, 1.0) = 0.3;
uniform float cast_shadow_strength : hint_range(0.0, 1.0) = 0.6;
uniform float wetness_darkening : hint_range(0.0, 0.5) = 0.25;
uniform float snow_visibility : hint_range(0.0, 1.0) = 1.0;
varying vec3 v_final_color;
varying float v_shade_factor;
@@ -41,6 +42,21 @@ float hash(vec3 p) {
return fract((p.x + p.y) * p.z);
}
float get_snow_progress() {
float snow_progress = clamp(global_snow_amount, 0.0, 1.0);
if (global_snow_start_time >= 0.0) {
float timed_progress = clamp((TIME - global_snow_start_time) * global_snow_accumulation_speed, 0.0, 1.0);
snow_progress = max(snow_progress, timed_progress);
}
if (global_snow_melt_time >= 0.0) {
float melt = clamp((TIME - global_snow_melt_time) * global_snow_melt_speed, 0.0, 1.0);
snow_progress = min(snow_progress, 1.0 - melt);
}
return snow_progress;
}
void vertex() {
vec3 instance_pos = MODEL_MATRIX[3].xyz;
@@ -88,24 +104,16 @@ void fragment() {
vec2 shifted_uv = UV + texture_offset;
vec4 tex = texture(alpha_texture, shifted_uv);
//// Snow accumulation
//float snow_amount = 0.0;
//if (global_snow_start_time >= 0.0) {
//snow_amount = clamp((TIME - global_snow_start_time) * global_snow_accumulation_speed, 0.0, 1.0);
//}
//if (global_snow_melt_time >= 0.0) {
//float melt = clamp((TIME - global_snow_melt_time) * global_snow_melt_speed, 0.0, 1.0);
//snow_amount *= (1.0 - melt);
//}
//
//float top_mask = 1.0 - shifted_uv.y;
//float snow_mask = smoothstep(1.0 - snow_amount, 1.2 - snow_amount, top_mask);
//snow_mask *= step(0.01, snow_amount);
// Snow accumulation
float snow_amount = pow(get_snow_progress(), 0.55);
//vec3 dark_snow = global_snow_color.rgb * (1.0 - shadow_intensity);
//vec3 shaded_snow = mix(dark_snow, global_snow_color.rgb, v_shade_factor);
//vec3 final_albedo = mix(v_final_color, shaded_snow, snow_mask);
vec3 final_albedo = v_final_color;
float top_mask = 1.0 - shifted_uv.y;
float snow_mask = smoothstep(1.0 - snow_amount * 1.35, 1.08 - snow_amount * 1.35, top_mask) * snow_visibility;
snow_mask *= step(0.01, snow_amount);
vec3 dark_snow = global_snow_color.rgb * (1.0 - shadow_intensity);
vec3 shaded_snow = mix(dark_snow, global_snow_color.rgb, v_shade_factor);
vec3 final_albedo = mix(v_final_color, shaded_snow, snow_mask);
// Rain wetness: darken and make shinier
float rain_int = clamp(global_rain_intensity, 0.0, 1.0);

View File

@@ -3,6 +3,12 @@ render_mode blend_mix, depth_draw_always;
global uniform float global_rain_intensity;
global uniform vec4 global_water_color = vec4(0.285, 0.534, 0.487, 1.0);
global uniform float global_snow_start_time = -1.0;
global uniform float global_snow_accumulation_speed = 0.005;
global uniform float global_snow_melt_time = -1.0;
global uniform float global_snow_melt_speed = 0.1;
global uniform float global_snow_amount = 0.0;
global uniform vec4 global_snow_color = vec4(0.92, 0.96, 1.0, 1.0);
//Water color
uniform vec4 deep_water_color : source_color = vec4(0.0, 0.1, 0.2, 1.0);
@@ -29,6 +35,21 @@ uniform sampler2D depth_texture : hint_depth_texture, filter_linear_mipmap;
varying vec2 world_pos_xz;
varying vec2 local_uv;
float get_snow_progress() {
float snow_progress = clamp(global_snow_amount, 0.0, 1.0);
if (global_snow_start_time >= 0.0) {
float timed_progress = clamp((TIME - global_snow_start_time) * global_snow_accumulation_speed, 0.0, 1.0);
snow_progress = max(snow_progress, timed_progress);
}
if (global_snow_melt_time >= 0.0) {
float melt = clamp((TIME - global_snow_melt_time) * global_snow_melt_speed, 0.0, 1.0);
snow_progress = min(snow_progress, 1.0 - melt);
}
return snow_progress;
}
void vertex() {
world_pos_xz = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xz;
local_uv = UV;
@@ -82,8 +103,15 @@ void fragment() {
float is_sky = step(ref_depth_raw, 0.00001); // Protezione anti-cielo
reflection_mask *= (1.0 - is_sky);
vec3 final_rgb = mix(base_water.rgb, screen_ref, reflection_strength * reflection_mask);
float snow_progress = get_snow_progress();
float active_snowfall = step(0.0, global_snow_start_time) * (1.0 - step(0.0, global_snow_melt_time));
float reflection_snow_damping = max(smoothstep(0.0, 0.08, snow_progress), active_snowfall * 0.75);
float effective_reflection_strength = reflection_strength * (1.0 - reflection_snow_damping * 0.85);
vec3 final_rgb = mix(base_water.rgb, screen_ref, effective_reflection_strength * reflection_mask);
final_rgb = mix(final_rgb, ripple_color.rgb, ring * ripple_color.a);
float water_snow_amount = smoothstep(0.15, 1.0, snow_progress) * 0.18;
final_rgb = mix(final_rgb, global_snow_color.rgb, water_snow_amount);
ALBEDO = final_rgb;

View File

@@ -0,0 +1,241 @@
#define USE_CAUSTICS 1
#define USE_REFRACTION 1
#define USE_DISPLACEMENT 1
#define USE_STYLIZED_LIGHTING 0
#define USE_UNSHADED 0
shader_type spatial;
#if USE_UNSHADED
render_mode unshaded, depth_draw_never;
#else
render_mode depth_draw_never;
#endif
uniform sampler2D DEPTH_TEXTURE: hint_depth_texture;
group_uniforms Color;
uniform vec4 surface_color : source_color = vec4(0.2,1.0,0.8,1.0);
uniform vec4 depth_color : source_color = vec4(0.08,0.2,0.4,1.0);
uniform vec4 foam_color : source_color = vec4(1.0);
uniform float depth_size = 12.0;
group_uniforms Roughness;
uniform float surface_roughness : hint_range(0.0, 1.0, 0.01) = 0.05;
uniform float foam_roughness : hint_range(0.0, 1.0, 0.01) = 0.05;
#if USE_CAUSTICS
group_uniforms Caustics;
uniform sampler2D caustics_texture;
uniform float caustics_strength = 2.0;
uniform vec2 caustics_scale = vec2(0.5);
#endif
group_uniforms Wave;
uniform sampler2D wave_texture;
uniform float wave_softness : hint_range(0.0, 10.0, 0.1) = 3.0;
uniform vec2 wave_scale = vec2(0.2);
uniform vec2 wave_layer_scale = vec2(1.5);
uniform float wave_highlight : hint_range(0.0, 1.0, 0.05) = 0.5;
group_uniforms Wave.Motion;
uniform vec2 wave_velocity = vec2(0.02);
instance uniform vec2 river_flow_direction = vec2(0.0, 0.0);
group_uniforms Foam;
uniform sampler2D foam_texture;
uniform float edge_foam_depth_size = 1.0;
uniform float wave_foam_amount : hint_range(0.0, 1.0, 0.01) = 0.8;
uniform float foam_start : hint_range(0.0, 1.0, 0.05) = 0.15;
uniform float foam_end : hint_range(0.0, 1.0, 0.05) = 0.3;
uniform float foam_exponent = 2.0;
#if USE_REFRACTION
group_uniforms Refraction;
uniform float refraction_amount = 0.5;
uniform float refraction_exponent = 0.5;
#endif
#if USE_DISPLACEMENT
group_uniforms Displacement;
uniform float displacement_amount = 0.3;
#endif
#if USE_STYLIZED_LIGHTING && !USE_UNSHADED
group_uniforms Lighting;
uniform float diffuse_steps = 12.0;
uniform float diffuse_smoothness : hint_range(0.0, 1.0, 0.01) = 0.2;
uniform float specular_steps = 12.0;
uniform float specular_smoothness : hint_range(0.0, 1.0, 0.01) = 0.2;
#endif
uniform sampler2D screen_texture : hint_screen_texture;
varying vec3 world_pos;
varying vec2 world_wave_velocity;
#if USE_CAUSTICS
vec3 sample_caustics(vec2 uv){
vec2 caustics_uv = uv * caustics_scale;
return vec3(
texture(caustics_texture, caustics_uv).r,
texture(caustics_texture, caustics_uv+vec2(0.02,0.02)).r,
texture(caustics_texture, caustics_uv+vec2(0.03,0.01)).r
);
}
#endif
vec4 sample_world_dpos(vec2 screen_uv, mat4 inv_proj_mat, mat4 inv_view_mat){
vec4 clip_pos = vec4(screen_uv * 2.0 - 1.0, texture(DEPTH_TEXTURE, screen_uv).r, 1.0);
vec4 view_pos = inv_proj_mat * clip_pos;
view_pos /= view_pos.w;
vec4 world_dpos = inv_view_mat * view_pos;
return world_dpos;
}
vec4 sample_wave(sampler2D tex, vec2 uv, vec2 velocity, float lod){
vec2 base_uv = uv * wave_scale;
vec2 wave_uv1 = (base_uv * wave_layer_scale) + (TIME * -velocity);
float wave1 = textureLod(tex, wave_uv1, lod).r;
vec2 wave_uv2 = base_uv + (TIME * velocity);
vec4 wave2 = textureLod(tex, wave_uv2 - (wave1 * 0.1), lod);
return wave2;
}
vec3 sample_wave_normal(vec2 uv, vec2 velocity, float center_wave) {
vec2 normal_offset = vec2(0.25, 0.0);
float wave_x = sample_wave(wave_texture, uv + normal_offset.xy, velocity, wave_softness).r;
float wave_z = sample_wave(wave_texture, uv + normal_offset.yx, velocity, wave_softness).r;
vec2 slope = vec2(center_wave - wave_x, center_wave - wave_z) * 0.35;
return normalize(vec3(slope, 1.0)) * 0.5 + 0.5;
}
vec2 get_world_wave_velocity(mat4 model_matrix) {
float velocity_length = length(wave_velocity);
if (velocity_length <= 0.0001) {
return vec2(0.0);
}
float flow_direction_length = length(river_flow_direction);
if (flow_direction_length > 0.0001) {
return (river_flow_direction / flow_direction_length) * velocity_length;
}
vec3 world_direction_3d = (model_matrix * vec4(0.0, 1.0, 0.0, 0.0)).xyz;
vec2 world_direction = world_direction_3d.xz;
float world_direction_length = length(world_direction);
if (world_direction_length <= 0.0001) {
return wave_velocity;
}
return (world_direction / world_direction_length) * velocity_length;
}
void vertex(){
world_pos = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
world_wave_velocity = get_world_wave_velocity(MODEL_MATRIX);
#if USE_DISPLACEMENT
float wave = sample_wave(wave_texture, world_pos.xz, world_wave_velocity, wave_softness).r;
VERTEX.y += wave*displacement_amount;
#endif
}
void fragment() {
float wave = sample_wave(wave_texture, world_pos.xz, world_wave_velocity, wave_softness).r;
wave = smoothstep(0.0,1.0,wave);
vec2 screen_uv = SCREEN_UV;
// Refraction
#if USE_REFRACTION
screen_uv += ((pow(wave, refraction_exponent)*2.0 - 0.5) * 0.01 * refraction_amount);
vec4 world_dpos = sample_world_dpos(screen_uv, INV_PROJECTION_MATRIX, INV_VIEW_MATRIX);
float pre_depth = pow(clamp((world_dpos.y - world_pos.y + depth_size)/depth_size, 0.0, 1.0), 4.0);
screen_uv = mix(screen_uv, SCREEN_UV, pre_depth);
if(world_dpos.y - world_pos.y > 0.0){
screen_uv = SCREEN_UV;
}
#else
vec4 world_dpos = sample_world_dpos(screen_uv, INV_PROJECTION_MATRIX, INV_VIEW_MATRIX);
#endif
world_dpos = sample_world_dpos(screen_uv, INV_PROJECTION_MATRIX, INV_VIEW_MATRIX);
vec2 surface_uv = world_dpos.xz * 0.2;
float depth = pow(clamp((world_dpos.y - world_pos.y + depth_size)/depth_size, 0.0, 1.0), 4.0);
// Caustics
#if USE_CAUSTICS
vec3 caustics1 = sample_caustics(surface_uv + (TIME * -world_wave_velocity));
vec3 caustics2 = sample_caustics((surface_uv + (caustics1.r*0.05)) + (TIME * (world_wave_velocity*0.5)));
vec3 caustics = caustics2 * (1.0 - depth);
#endif
// Edge Foam
float edge_foam_depth = clamp((world_dpos.y - world_pos.y + edge_foam_depth_size)/edge_foam_depth_size, 0.0, 1.0);
// Wave Foam
float wave_foam = wave;
float foam = max(edge_foam_depth, wave_foam * wave_foam_amount);
float foam_shape = 1.0 - texture(foam_texture, world_pos.xz* 0.5).r;
foam = clamp((foam - foam_start) / (foam_end - foam_start), 0.0, 1.0);
foam = clamp((foam - foam_shape) / (1.0 - foam_shape), 0.0, 1.0);
foam = pow(foam, foam_exponent);
vec3 flat_color = mix(depth_color, surface_color, depth).rgb;
vec4 screen = texture(screen_texture, screen_uv);
vec3 color = screen.rgb;
#if USE_CAUSTICS
color += vec3(pow(caustics * caustics_strength, vec3(2.0)));
#endif
color = mix(flat_color, color, 0.4 * depth);
color = mix(color, surface_color.rgb, wave * wave_highlight);
color = mix(color, foam_color.rgb, foam);
#if !USE_UNSHADED
vec3 wave_normal_map = sample_wave_normal(world_pos.xz, world_wave_velocity, wave);
NORMAL_MAP = wave_normal_map;
#endif
ROUGHNESS = mix(surface_roughness, foam_roughness, foam);
ALBEDO = color;
}
#if USE_STYLIZED_LIGHTING && !USE_UNSHADED
void light(){
float ndotl = dot(NORMAL, LIGHT) * ATTENUATION;
//ndotl = smoothstep(0.0,1.0-ROUGHNESS,ndotl);
float light = ndotl;
float light_mult = light * diffuse_steps;
float light_step_base = floor(light_mult);
float light_factor = light_mult - light_step_base;
light_factor = smoothstep(0.5 - diffuse_smoothness * 0.5, 0.5 + diffuse_smoothness * 0.5, light_factor);
light = (light_step_base + light_factor) / diffuse_steps;
DIFFUSE_LIGHT += (LIGHT_COLOR+ALBEDO) * light / PI;
float roughness = mix(0.01, 0.99, ROUGHNESS);
vec3 h = normalize(VIEW + LIGHT);
float ndoth = clamp(dot(NORMAL, h), 0.0, 1.0) * ATTENUATION;
float specular = clamp(pow(ndoth, 16.0/(roughness)), 0.1, 0.99);
specular = mix(pow(specular, 2.0-roughness),0.00,pow(roughness, 0.1));
float specular_mult = specular * specular_steps;
float specular_step_base = floor(specular_mult);
float specular_factor = specular_mult - specular_step_base;
specular_factor = smoothstep(0.5 - specular_smoothness * 0.5, 0.5 + specular_smoothness * 0.5, specular_factor);
specular = (specular_step_base + specular_factor) / specular_steps;
SPECULAR_LIGHT += (LIGHT_COLOR + ALBEDO) * specular;
}
#endif

View File

@@ -0,0 +1 @@
uid://cb12c2j8rfu6a

View File

@@ -34,12 +34,15 @@ var rain_tween: Tween
var rain_audio_tween: Tween
var puddle_tween: Tween
var puddle_amount: float = 0.0
var clouds_tween: Tween
var snow_tween: Tween
var snow_weather_tween: Tween
var snow_particles_tween: Tween
var is_snowing: bool = false
var is_snow_accumulated: bool = false
var actual_snow_amount: float = 0.0
var snow_weather_amount: float = 0.0
var is_storm: bool = false
var cold_tween: Tween
@@ -51,6 +54,8 @@ var current_wind_strength: float = 0.0
var current_wind_fade: float = 0.0
var max_wind_amount: int = 0
var random_weather_restore_tween: Tween
var random_event_remaining: float = 0.0
var random_event_label_seconds: int = -1
func _init(wind: GPUParticles3D, snow: GPUParticles3D,
fireflies: GPUParticles3D, rain: GPUParticles3D, ray: PackedScene,
@@ -112,6 +117,7 @@ func _ready() -> void:
_emit_weather_event_label()
func _process(delta: float) -> void:
_update_random_event_label(delta)
_follow_camera()
@@ -185,10 +191,10 @@ func _process(delta: float) -> void:
var final_fog_density = lerp(base_fog_density, base_fog_density * 4.0, clamp(rain_intensity, 0.0, 1.0))
var final_water_color = base_water_color.darkened(clamp(environment_config.water_darkening_rain, 0.0, 1.0) * clamp(rain_intensity, 0.0, 1.0))
final_tint = final_tint.lerp(final_tint * environment_config.snow_mode_color, actual_snow_amount)
final_sky_top = final_sky_top.lerp(final_sky_top * environment_config.snow_mode_color, actual_snow_amount)
final_sky_horizon = final_sky_horizon.lerp(final_sky_horizon * environment_config.snow_mode_color, actual_snow_amount)
final_fog_color = final_fog_color.lerp(final_fog_color * environment_config.snow_mode_color, actual_snow_amount)
final_tint = final_tint.lerp(final_tint * environment_config.snow_mode_color, snow_weather_amount)
final_sky_top = final_sky_top.lerp(final_sky_top * environment_config.snow_mode_color, snow_weather_amount)
final_sky_horizon = final_sky_horizon.lerp(final_sky_horizon * environment_config.snow_mode_color, snow_weather_amount)
final_fog_color = final_fog_color.lerp(final_fog_color * environment_config.snow_mode_color, snow_weather_amount)
#Shader parameters for global trunk_shader
var final_grad_top = base_grad_top.lerp(base_grad_top * weather_color, clamp(rain_intensity, 0.0, 1.0))
@@ -202,8 +208,8 @@ func _process(delta: float) -> void:
var night_val = clamp(day_time - 2.0, 0.0, 1.0)
#Snow exposure compensation
var snow_light_attenuation = lerp(1.0, 0.55, actual_snow_amount * (1.0 - night_val))
var snow_glow_attenuation = lerp(1.0, 0.5, actual_snow_amount)
var snow_light_attenuation = lerp(1.0, 0.55, snow_weather_amount * (1.0 - night_val))
var snow_glow_attenuation = lerp(1.0, 0.5, snow_weather_amount)
var final_bloom = lerp(base_bloom, base_bloom * 0.5, rain_intensity) * snow_glow_attenuation
# We calculate the final exposure by applying snow damping directly to the camera exposure
@@ -244,15 +250,36 @@ func _process(delta: float) -> void:
sky_mat.set_shader_parameter("sun_color", final_tint)
sky_mat.set_shader_parameter("night_intensity", night_val)
var cloud_density_amount: float = maxf(clamp(rain_intensity, 0.0, 1.0), clamp(snow_weather_amount, 0.0, 1.0))
var current_cloud_density: float = lerp(environment_config.base_cloud_density, environment_config.rain_cloud_density, cloud_density_amount)
if environment_config.material_clouds:
var current_density = lerp(0.4, 1.0, rain_intensity)
environment_config.material_clouds.set_shader_parameter("cloud_density", current_density)
var current_sharpness = lerp(0.14, 0.0, rain_intensity)
environment_config.material_clouds.set_shader_parameter("cloud_density", current_cloud_density)
var current_sharpness = lerp(0.14, 0.0, cloud_density_amount)
environment_config.material_clouds.set_shader_parameter("center_sharpness", current_sharpness)
var env_shadow_mat = environment_shadows.get_surface_override_material(0) if environment_shadows else null
if env_shadow_mat:
env_shadow_mat.set_shader_parameter("cloud_density", current_cloud_density)
if environment_config.material_fog:
environment_config.material_fog.set_shader_parameter("fog_color", final_fog_color)
environment_config.material_fog.set_shader_parameter("fog_density", clamp(final_fog_density * 25.0, 0.0, 1.0))
environment_config.material_fog.set_shader_parameter("night_intensity", night_val)
environment_config.material_fog.set_shader_parameter("sun_color", final_tint)
if fog:
for child in fog.get_children():
var fog_mesh := child as MeshInstance3D
if fog_mesh == null:
continue
var fog_material := fog_mesh.get_surface_override_material(0) as ShaderMaterial
if fog_material == null:
continue
fog_material.set_shader_parameter("fog_color", final_fog_color)
fog_material.set_shader_parameter("fog_density", clamp(final_fog_density * 25.0, 0.0, 1.0))
fog_material.set_shader_parameter("night_intensity", night_val)
fog_material.set_shader_parameter("sun_color", final_tint)
func create_sound_players():
rain_audio_player = AudioStreamPlayer.new()
@@ -449,6 +476,8 @@ func _update_wind_amount_from_strength(value: float) -> void:
func trigger_random_weather_event(duration: float = 0.0) -> void:
if random_weather_restore_tween and random_weather_restore_tween.is_valid():
random_weather_restore_tween.kill()
random_event_remaining = 0.0
random_event_label_seconds = -1
var previous_rain: bool = is_raining
var previous_snow: bool = is_snowing
@@ -466,12 +495,26 @@ func trigger_random_weather_event(duration: float = 0.0) -> void:
_apply_weather_event_state(true, false, false, true)
if duration > 0.0:
random_event_remaining = duration
_emit_weather_event_label()
random_weather_restore_tween = create_tween()
random_weather_restore_tween.tween_interval(duration)
random_weather_restore_tween.tween_callback(func():
random_event_remaining = 0.0
random_event_label_seconds = -1
_apply_weather_event_state(previous_rain, previous_snow, previous_wind, previous_storm)
)
func _update_random_event_label(delta: float) -> void:
if random_event_remaining <= 0.0:
return
random_event_remaining = maxf(random_event_remaining - delta, 0.0)
var display_seconds: int = ceili(random_event_remaining)
if display_seconds != random_event_label_seconds:
random_event_label_seconds = display_seconds
_emit_weather_event_label()
func _apply_weather_event_state(rain_enabled: bool, snow_enabled: bool, wind_enabled: bool, storm_enabled: bool = false) -> void:
if is_storm and not storm_enabled:
toggle_storm(false)
@@ -647,7 +690,7 @@ func toggle_rain(value: bool):
if puddle_tween and puddle_tween.is_valid():
puddle_tween.kill()
if is_raining:
particles_rain.amount_ratio = 0.0
particles_rain.emitting = true
@@ -767,8 +810,23 @@ func toggle_snow(value: bool):
var target_snow_amount: float = 1.0 if is_snowing else 0.0
if snow_tween and snow_tween.is_valid():
snow_tween.kill()
if snow_weather_tween and snow_weather_tween.is_valid():
snow_weather_tween.kill()
var snow_amount_transition_duration: float = _get_snow_amount_transition_duration(is_snowing)
snow_tween = create_tween()
snow_tween.tween_method(init_snow_amount, actual_snow_amount, target_snow_amount, environment_config.snow_transaction_time)
snow_tween.tween_method(
init_snow_amount,
actual_snow_amount,
target_snow_amount,
snow_amount_transition_duration
)
snow_weather_tween = create_tween()
snow_weather_tween.tween_method(
init_snow_weather_amount,
snow_weather_amount,
target_snow_amount,
environment_config.snow_fade_time
)
_emit_weather_event_label()
func _emit_weather_event_label() -> void:
@@ -785,11 +843,14 @@ func _emit_weather_event_label() -> void:
active_events.append("Wind")
if not active_events.is_empty():
weather_label = "Weather: %s" % " + ".join(active_events)
if random_event_remaining > 0.0:
weather_label += " (%s'')" % ceili(random_event_remaining)
UIEvents.weather_event_changed.emit(weather_label)
#disable snow and set default values and shader
func init_snow(value: float = 0.0):
actual_snow_amount = value
snow_weather_amount = value
RenderingServer.global_shader_parameter_set("global_snow_amount", value)
if particles_snow:
@@ -814,6 +875,9 @@ func init_snow_amount(value: float):
actual_snow_amount = value
RenderingServer.global_shader_parameter_set("global_snow_amount", value)
func init_snow_weather_amount(value: float):
snow_weather_amount = value
func start_snow_accumulation() -> void:
RenderingServer.global_shader_parameter_set("global_snow_melt_time", -1.0)
RenderingServer.global_shader_parameter_set("global_snow_start_time", Time.get_ticks_msec() / 1000.0)
@@ -822,6 +886,18 @@ func start_snow_melt() -> void:
RenderingServer.global_shader_parameter_set("global_snow_melt_time", Time.get_ticks_msec() / 1000.0)
RenderingServer.global_shader_parameter_set("global_snow_melt_speed", environment_config.snow_melt_speed)
func _get_snow_amount_transition_duration(is_accumulating: bool) -> float:
if environment_config == null:
return 0.0
var speed: float = environment_config.snow_melt_speed
if is_accumulating:
speed = environment_config.snow_accumulation_speed
if speed <= 0.0:
return environment_config.snow_transaction_time
return 1.0 / speed
#endregion
#region Post-Process

View File

@@ -3,7 +3,7 @@ render_mode blend_mix, depth_draw_never;
//Snow globals
global uniform float global_snow_start_time = -1.0;
global uniform float global_snow_accumulation_speed = 0.1;
global uniform float global_snow_accumulation_speed = 0.005;
global uniform float global_snow_melt_time = -1.0;
global uniform float global_snow_melt_speed = 0.1;
global uniform float global_snow_amount = 0.0;
@@ -72,18 +72,15 @@ float fbm(vec2 p) {
}
float get_snow_progress() {
bool has_snow_timeline = global_snow_start_time >= 0.0 || global_snow_melt_time >= 0.0;
float snow_progress = clamp(global_snow_amount, 0.0, 1.0);
if (has_snow_timeline) {
snow_progress = 0.0;
if (global_snow_start_time >= 0.0) {
snow_progress = clamp((TIME - global_snow_start_time) * global_snow_accumulation_speed, 0.0, 1.0);
}
if (global_snow_melt_time >= 0.0) {
float melt = clamp((TIME - global_snow_melt_time) * global_snow_melt_speed, 0.0, 1.0);
snow_progress *= (1.0 - melt);
}
if (global_snow_start_time >= 0.0) {
float timed_progress = clamp((TIME - global_snow_start_time) * global_snow_accumulation_speed, 0.0, 1.0);
snow_progress = max(snow_progress, timed_progress);
}
if (global_snow_melt_time >= 0.0) {
float melt = clamp((TIME - global_snow_melt_time) * global_snow_melt_speed, 0.0, 1.0);
snow_progress = min(snow_progress, 1.0 - melt);
}
return snow_progress;
@@ -130,12 +127,13 @@ void fragment() {
float snow_edge = smoothstep(
global_snow_threshold - snow_edge_softness,
global_snow_threshold + snow_edge_softness,
facing_up + (noise_val - 0.5) * 0.4
facing_up
);
float flat_accumulation = smoothstep(0.0, 0.35, v_snow_cap_mask) * snow_accumulation;
float snow_coverage = smoothstep(0.0, 0.6, noise_val + snow_progress - 0.4 + flat_accumulation * 0.25);
float snow_factor = max(snow_edge * snow_coverage * snow_progress, flat_accumulation);
float snow_opacity = smoothstep(0.04, 0.28, snow_factor);
float snow_variation = mix(0.75, 1.15, noise_val);
float snow_coverage = clamp(snow_progress * snow_variation + flat_accumulation * 0.25, 0.0, 1.0);
float snow_factor = max(snow_edge * snow_coverage, flat_accumulation);
float snow_opacity = clamp(snow_factor, 0.0, 1.0);
snow_opacity = max(snow_opacity, flat_accumulation * 0.9);
float shade = mix(-snow_color_variation, snow_color_variation, noise_val);

View File

@@ -2,10 +2,11 @@ shader_type spatial;
render_mode blend_mix, depth_draw_never, cull_disabled;
// Snow globals
global uniform float global_snow_start_time;
global uniform float global_snow_accumulation_speed;
global uniform float global_snow_melt_time;
global uniform float global_snow_melt_speed;
global uniform float global_snow_start_time = -1.0;
global uniform float global_snow_accumulation_speed = 0.005;
global uniform float global_snow_melt_time = -1.0;
global uniform float global_snow_melt_speed = 0.1;
global uniform float global_snow_amount = 0.0;
global uniform vec4 global_snow_color;
uniform float snow_edge_softness : hint_range(0.01, 0.5) = 0.15;
uniform float snow_color_variation : hint_range(0.0, 0.15) = 0.05;
@@ -34,6 +35,21 @@ float ripple_ring(vec2 uv, float time_offset) {
return ring * fade;
}
float get_snow_progress() {
float snow_progress = clamp(global_snow_amount, 0.0, 1.0);
if (global_snow_start_time >= 0.0) {
float timed_progress = clamp((TIME - global_snow_start_time) * global_snow_accumulation_speed, 0.0, 1.0);
snow_progress = max(snow_progress, timed_progress);
}
if (global_snow_melt_time >= 0.0) {
float melt = clamp((TIME - global_snow_melt_time) * global_snow_melt_speed, 0.0, 1.0);
snow_progress = min(snow_progress, 1.0 - melt);
}
return snow_progress;
}
void fragment() {
vec3 world_pos = (INV_VIEW_MATRIX * vec4(VERTEX, 1.0)).xyz;
@@ -41,18 +57,10 @@ void fragment() {
float facing_up = 1.0;
// Snow accumulation
float snow_amount = 0.0;
if (global_snow_start_time >= 0.0) {
snow_amount = clamp((TIME - global_snow_start_time) * global_snow_accumulation_speed, 0.0, 1.0);
}
if (global_snow_melt_time >= 0.0) {
float melt = clamp((TIME - global_snow_melt_time) * global_snow_melt_speed, 0.0, 1.0);
snow_amount *= (1.0 - melt);
}
float snow_amount = get_snow_progress();
// UV-based snow mask: accumulates from the top of the quad
float top_mask = 1.0 - UV.y;
float snow_mask = smoothstep(1.0 - snow_amount, 1.0 - snow_amount + snow_edge_softness, top_mask);
// Plain surfaces fade in uniformly to avoid patchy strip-like accumulation.
float snow_mask = smoothstep(0.0, 1.0, snow_amount);
snow_mask *= step(0.01, snow_amount);
// Snow color with slight variation

View File

@@ -98,6 +98,7 @@ extends Resource
@export var material_fog: ShaderMaterial #Fog overlay shader material
@export var material_drops: StandardMaterial3D #Rain drops material (albedo tinted by sky)
@export var material_clouds: ShaderMaterial #Cloud layer shader material
@export var base_cloud_density: float = 0.4 #default cloud density
#Rain weather settings
@export_group("Rain")
@@ -106,6 +107,7 @@ extends Resource
@export var rain_audio_volume_db: float = -10.0 #Target rain loop volume in decibels
@export var puddle_form_time: float = 15.0 #Seconds for puddles to fully form
@export var puddle_dry_time: float = 20.0 #Seconds for puddles to fully dry after rain stops
@export var rain_cloud_density: float = 1.0 #the cloud density when is rainy
#Storm settings (applied on top of rain when storm is active)
@export_group("Storm")
@@ -136,7 +138,7 @@ extends Resource
#Train start settings
@export_group("Train Start")
@export var train_start_from_random_position: bool = false #When enabled the train starts from a random offset on the rail curve instead of a stop
@export var train_start_from_random_position: bool = true #When enabled the train starts from a random offset on the rail curve instead of a stop
@export_range(0, 64, 1, "or_greater") var train_start_stop_index: int = 1 #Stop index used for the train start when random start is disabled
#Snow settings
@@ -145,7 +147,7 @@ extends Resource
@export var snow_transaction_time: float = 10.0 #Seconds for snow shader to fully transition in/out
@export var snow_fade_time: float = 5.0 #Seconds for snow particles to fade in/out
@export var snow_threshold: float = 0.4 #Normal Y threshold for snow accumulation on surfaces
@export var snow_accumulation_speed: float = 0.014 #Accumulation speed: 0.1 -> 10s, 0.05 -> 20s, 0.02 -> 50s, 0.012 -> ~83s
@export var snow_accumulation_speed: float = 0.005 #Accumulation speed: 0.005 -> ~200s, 0.01 -> 100s, 0.02 -> 50s
@export var snow_melt_speed: float = 0.05 #Speed at which accumulated snow melts away
@export var show_snow_accumulation_volume: bool = true #Enables vertex snow buildup; when false snow only changes surface color
@export var snow_max_accumulation: float = 0.25 #Maximum accumulated snow factor applied to coverage and thickness
@@ -184,3 +186,7 @@ extends Resource
@export var water_color_afternoon: Color = Color(0.889, 0.733, 0.205, 1.0) #Tint for afternoon (sunset)
@export var water_color_night: Color = Color(0.728, 0.54, 0.986, 1.0); #Tint for night
@export var water_darkening_rain: float = 0.7 #Percentage of darkening when is rainy
#Random events
@export_group("Random Events")
@export var random_event_duration: float = 30.0 #Duration time for random event

View File

@@ -0,0 +1,29 @@
@tool
extends Control
class_name ArrowButton
signal on_pressed
@export var image: Texture:
set(value):
image = value
if is_inside_tree() and has_node("%Texture"):
$%Texture.texture = image
@export var flip_h: bool = false:
set(value):
flip_h = value
if is_inside_tree() and has_node("%Texture"):
if $%Texture != null:
$%Texture.flip_h = flip_h
func _ready():
if image != null and has_node("%Texture"):
$%Texture.texture = image
$%Texture.flip_h = flip_h
func _on_gui_input(event: InputEvent) -> void:
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
on_pressed.emit()

View File

@@ -0,0 +1 @@
uid://3uxuhvua1036

View File

@@ -0,0 +1,38 @@
[gd_scene format=3 uid="uid://dm3skv22c60tm"]
[ext_resource type="Texture2D" uid="uid://cm7fok7lhrano" path="res://core/game_menu/assets/page_1/freccetta.png" id="1_vbu0v"]
[ext_resource type="Script" uid="uid://3uxuhvua1036" path="res://core/game_menu/arrow_button.gd" id="2_xq7pl"]
[ext_resource type="PackedScene" uid="uid://dxun0jk5t0n6" path="res://core/game_menu/hoover_tween.tscn" id="3_hu4cn"]
[node name="ArrowButton" type="Control" unique_id=1696751730]
custom_minimum_size = Vector2(101, 124)
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
pivot_offset = Vector2(0.5, 0.5)
script = ExtResource("2_xq7pl")
image = ExtResource("1_vbu0v")
[node name="Texture" type="TextureRect" parent="." unique_id=91599097]
unique_name_in_owner = true
layout_mode = 1
anchors_preset = -1
anchor_left = 0.47369793
anchor_top = 0.4425926
anchor_right = 0.5263021
anchor_bottom = 0.5574074
grow_horizontal = 2
grow_vertical = 2
pivot_offset_ratio = Vector2(0.5, 0.5)
mouse_filter = 2
texture = ExtResource("1_vbu0v")
metadata/_edit_use_anchors_ = true
[node name="HooverTween" parent="." unique_id=2115829120 node_paths=PackedStringArray("detector_node", "visual_node") instance=ExtResource("3_hu4cn")]
detector_node = NodePath("..")
visual_node = NodePath("../Texture")
[connection signal="gui_input" from="." to="." method="_on_gui_input"]

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dqqnfnero7ckl"
path="res://.godot/imported/chooseyourbiome_text.png-4b7f54401f26c8523f3a3effe8f6caa4.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://core/game_menu/assets/page_1/chooseyourbiome_text.png"
dest_files=["res://.godot/imported/chooseyourbiome_text.png-4b7f54401f26c8523f3a3effe8f6caa4.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bjqp8kmb5y7px"
path="res://.godot/imported/chooseyourtrain_text.png-ee3b98a7555062fc260ab8ebbed86f06.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://core/game_menu/assets/page_1/chooseyourtrain_text.png"
dest_files=["res://.godot/imported/chooseyourtrain_text.png-ee3b98a7555062fc260ab8ebbed86f06.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

View File

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://c3qcivnwuisju"
path="res://.godot/imported/color_dx_biome.png-3cc724dd240e512429a7cefd5adc1412.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://core/game_menu/assets/page_1/color_dx_biome.png"
dest_files=["res://.godot/imported/color_dx_biome.png-3cc724dd240e512429a7cefd5adc1412.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

View File

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dc0sl04wem136"
path="res://.godot/imported/color_main_biome.png-89de4f4e7d123065cf25b299bcc8cc19.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://core/game_menu/assets/page_1/color_main_biome.png"
dest_files=["res://.godot/imported/color_main_biome.png-89de4f4e7d123065cf25b299bcc8cc19.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

View File

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cin3kt42e6w3u"
path="res://.godot/imported/color_sx_biome.png-4c5ebaa4d4bd430214af8b874b4dcc9f.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://core/game_menu/assets/page_1/color_sx_biome.png"
dest_files=["res://.godot/imported/color_sx_biome.png-4c5ebaa4d4bd430214af8b874b4dcc9f.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 B

View File

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cdjwvwst3f10a"
path="res://.godot/imported/customizecolor-1.png-abb88424ec3f49b90a0ab001b55b0613.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://core/game_menu/assets/page_1/customizecolor-1.png"
dest_files=["res://.godot/imported/customizecolor-1.png-abb88424ec3f49b90a0ab001b55b0613.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 B

View File

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://d4l5ih723j3md"
path="res://.godot/imported/customizecolor-2.png-fdc9e8b7a1a6738945f62225133a5f93.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://core/game_menu/assets/page_1/customizecolor-2.png"
dest_files=["res://.godot/imported/customizecolor-2.png-fdc9e8b7a1a6738945f62225133a5f93.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 B

View File

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://b5arobd7gl4u4"
path="res://.godot/imported/customizecolor-3.png-bd0e0603c54a8be9173c4384e6c383e0.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://core/game_menu/assets/page_1/customizecolor-3.png"
dest_files=["res://.godot/imported/customizecolor-3.png-bd0e0603c54a8be9173c4384e6c383e0.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 B

View File

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://el88fib24nl0"
path="res://.godot/imported/customizecolor-4.png-f5e40c0772c10048e3a4e0128aeb8a8b.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://core/game_menu/assets/page_1/customizecolor-4.png"
dest_files=["res://.godot/imported/customizecolor-4.png-f5e40c0772c10048e3a4e0128aeb8a8b.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 B

View File

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bv07xhpe3kh0r"
path="res://.godot/imported/customizecolor-5.png-e5eb95a46b9ee7054e655b899a6ab240.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://core/game_menu/assets/page_1/customizecolor-5.png"
dest_files=["res://.godot/imported/customizecolor-5.png-e5eb95a46b9ee7054e655b899a6ab240.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 B

Some files were not shown because too many files have changed in this diff Show More