Files
Trinittu/dynamic-sky/scripts/dynamic_sky_root.gd
Overside srl b158a646c3 revert
2026-02-17 08:37:55 +01:00

544 lines
15 KiB
GDScript

@tool
class_name DynamicSkyRoot
extends Node3D
signal time_of_day_changed(time: float)
signal weather_changed(state: WeatherProfile.WeatherState)
signal preset_changed(preset: SkyPreset)
@export_group("Controllers")
@export var preset_library: SkyboxPresetLibrary
@export var day_night_controller: DayNightController
@export var weather_controller: WeatherController
@export var cloud_system: CloudSystem2D
@export var post_process_controller: PostProcessController
@export var vfx_controller: VFXController
@export var shadow_proxy_system: ShadowProxySystem
@export var weather_vfx: WeatherVFX
@export_group("Environment")
@export var world_environment: WorldEnvironment
@export var sun_light: DirectionalLight3D
@export var moon_light: DirectionalLight3D
@export_group("Global Settings")
@export var auto_create_controllers: bool = true
@export var deterministic_seed: int = 0:
set(value):
deterministic_seed = value
_apply_seed()
@export_group("Debug")
@export var show_debug_panel: bool = false
@export var debug_time_override: float = -1.0
var _current_config: SkyConfig
var preset_name: String = ""
var _updating_preset_name: bool = false
var _debug_panel: SkyDebugPanel
var _debug_canvas_layer: CanvasLayer
func _ready() -> void:
if auto_create_controllers:
_ensure_controllers_exist()
_connect_signals()
_apply_seed()
_ensure_post_process_environment()
_load_initial_preset()
notify_property_list_changed()
_sync_all_systems()
func _process(delta: float) -> void:
_sync_all_systems()
if show_debug_panel:
_update_debug_info()
elif _debug_panel != null:
_debug_panel.visible = false
func _ensure_controllers_exist() -> void:
if preset_library == null:
preset_library = SkyboxPresetLibrary.new()
preset_library.name = "PresetLibrary"
add_child(preset_library)
if day_night_controller == null:
day_night_controller = DayNightController.new()
day_night_controller.name = "DayNightController"
add_child(day_night_controller)
if weather_controller == null:
weather_controller = WeatherController.new()
weather_controller.name = "WeatherController"
add_child(weather_controller)
if cloud_system == null:
cloud_system = CloudSystem2D.new()
cloud_system.name = "CloudSystem"
add_child(cloud_system)
if post_process_controller == null:
post_process_controller = PostProcessController.new()
post_process_controller.name = "PostProcessController"
add_child(post_process_controller)
if vfx_controller == null:
vfx_controller = VFXController.new()
vfx_controller.name = "VFXController"
add_child(vfx_controller)
if shadow_proxy_system == null:
shadow_proxy_system = ShadowProxySystem.new()
shadow_proxy_system.name = "ShadowProxySystem"
add_child(shadow_proxy_system)
if weather_vfx == null:
weather_vfx = WeatherVFX.new()
weather_vfx.name = "WeatherVFX"
add_child(weather_vfx)
if world_environment == null:
_create_default_environment()
if sun_light == null:
_create_sun_light()
if moon_light == null:
_create_moon_light()
func _create_default_environment() -> void:
world_environment = WorldEnvironment.new()
world_environment.name = "WorldEnvironment"
world_environment.environment = Environment.new()
world_environment.environment.background_mode = Environment.BG_SKY
world_environment.environment.sky = Sky.new()
add_child(world_environment)
if post_process_controller:
post_process_controller.target_environment = world_environment.environment
func _create_sun_light() -> void:
sun_light = DirectionalLight3D.new()
sun_light.name = "SunLight"
sun_light.light_color = Color(1.0, 0.95, 0.85)
sun_light.light_energy = 1.0
sun_light.shadow_enabled = true
add_child(sun_light)
func _create_moon_light() -> void:
moon_light = DirectionalLight3D.new()
moon_light.name = "MoonLight"
moon_light.light_color = Color(0.7, 0.8, 1.0)
moon_light.light_energy = 0.3
moon_light.shadow_enabled = false
add_child(moon_light)
func _connect_signals() -> void:
if day_night_controller:
day_night_controller.time_changed.connect(_on_time_changed)
if weather_controller:
weather_controller.weather_state_changed.connect(_on_weather_state_changed)
if preset_library:
preset_library.preset_changed.connect(_on_preset_changed)
func _on_time_changed(time: float) -> void:
time_of_day_changed.emit(time)
if vfx_controller:
vfx_controller.set_night_mode(day_night_controller.is_nighttime())
func _on_weather_state_changed(old_state: WeatherProfile.WeatherState, new_state: WeatherProfile.WeatherState) -> void:
weather_changed.emit(new_state)
func _on_preset_changed(preset: SkyPreset) -> void:
preset_changed.emit(preset)
if preset.config:
_current_config = preset.config
_sync_preset_name()
_apply_preset_assets(preset)
func _apply_seed() -> void:
if deterministic_seed != 0:
seed(deterministic_seed)
func _sync_all_systems() -> void:
if day_night_controller == null:
return
var time := day_night_controller.time_of_day
if debug_time_override >= 0:
time = debug_time_override
_sync_sun_moon()
_sync_clouds()
_sync_post_process()
_sync_shadows()
_sync_weather_vfx()
func _sync_sun_moon() -> void:
if day_night_controller == null:
return
var sun_dir := day_night_controller.get_sun_direction()
var moon_dir := day_night_controller.get_moon_direction()
var sun_color: Color
var sun_energy: float
var moon_color: Color
var moon_energy: float
var ambient_color: Color
var ambient_energy: float
if _current_config:
sun_color = _current_config.sun_color
sun_energy = _current_config.sun_intensity
moon_color = _current_config.moon_color
moon_energy = _current_config.moon_intensity
ambient_color = _current_config.ambient_color
ambient_energy = _current_config.ambient_intensity
else:
sun_color = day_night_controller.get_sun_color()
sun_energy = day_night_controller.get_sun_intensity()
moon_color = day_night_controller.get_moon_color()
moon_energy = day_night_controller.get_moon_intensity()
ambient_color = day_night_controller.get_ambient_color()
ambient_energy = day_night_controller.get_ambient_intensity()
if weather_controller:
var wp := weather_controller.get_current_profile()
if wp:
ambient_color *= wp.ambient_color_multiplier
ambient_energy *= wp.ambient_intensity_multiplier
if sun_light:
sun_light.look_at(global_position - sun_dir, Vector3.UP)
sun_light.light_color = sun_color
sun_light.light_energy = sun_energy
sun_light.visible = sun_energy > 0.01
if moon_light:
moon_light.look_at(global_position - moon_dir, Vector3.UP)
moon_light.light_color = moon_color
moon_light.light_energy = moon_energy
moon_light.visible = moon_energy > 0.01
if world_environment and world_environment.environment:
world_environment.environment.ambient_light_color = ambient_color
world_environment.environment.ambient_light_energy = ambient_energy
func _sync_clouds() -> void:
if cloud_system == null:
return
if day_night_controller:
var sun_color: Color
var sun_intensity: float
var moon_color: Color
var moon_intensity: float
if _current_config:
sun_color = _current_config.sun_color
sun_intensity = _current_config.sun_intensity
moon_color = _current_config.moon_color
moon_intensity = _current_config.moon_intensity
else:
sun_color = day_night_controller.get_sun_color()
sun_intensity = day_night_controller.get_sun_intensity()
moon_color = day_night_controller.get_moon_color()
moon_intensity = day_night_controller.get_moon_intensity()
cloud_system.set_sun_lighting(
day_night_controller.get_sun_direction(),
sun_color,
sun_intensity
)
cloud_system.set_moon_lighting(
day_night_controller.get_moon_direction(),
moon_color,
moon_intensity
)
if weather_controller:
cloud_system.global_coverage = weather_controller.get_cloud_coverage()
elif _current_config:
cloud_system.global_coverage = _current_config.cloud_coverage
if weather_controller:
cloud_system.set_global_wind(
weather_controller.get_wind_direction(),
weather_controller.get_wind_speed()
)
func _sync_post_process() -> void:
if post_process_controller == null or day_night_controller == null:
return
var sun_dir := day_night_controller.get_sun_direction()
if _current_config:
post_process_controller.set_sun_glow(
sun_dir,
_current_config.sun_color,
_current_config.sun_glow_intensity,
_current_config.sun_glow_size
)
post_process_controller.set_fog_settings(
_current_config.fog_color,
_current_config.fog_density
)
post_process_controller.set_dawn_dusk_blend(0.0)
post_process_controller.set_stars_visibility(
_current_config.stars_visibility,
_current_config.stars_tint
)
post_process_controller.set_sky_colors(
_current_config.sky_top_color,
_current_config.sky_horizon_color,
_current_config.sky_bottom_color
)
post_process_controller.gradient_intensity = _current_config.gradient_intensity
post_process_controller.apply_config(_current_config)
else:
var sun_color := day_night_controller.get_sun_color()
post_process_controller.set_sun_glow(
sun_dir,
sun_color,
day_night_controller.get_sun_intensity() * 0.5,
0.2
)
var fog_color := day_night_controller.get_fog_color()
var fog_density := day_night_controller.get_fog_density()
if weather_controller:
var wp := weather_controller.get_current_profile()
if wp:
fog_color *= wp.fog_color_multiplier
fog_density *= wp.fog_density_multiplier
post_process_controller.set_fog_settings(fog_color, fog_density)
var dawn_dusk_blend := 0.0
if day_night_controller.is_dawn() or day_night_controller.is_dusk():
dawn_dusk_blend = 1.0
post_process_controller.set_dawn_dusk_blend(dawn_dusk_blend)
post_process_controller.set_stars_visibility(
day_night_controller.get_stars_visibility()
)
post_process_controller.set_sky_colors(
day_night_controller.get_sky_top_color(),
day_night_controller.get_sky_horizon_color(),
day_night_controller.get_sky_bottom_color()
)
func _apply_preset_assets(preset: SkyPreset) -> void:
if preset == null:
return
if post_process_controller:
post_process_controller.skybox_texture = preset.skybox_texture
if preset.post_process_profile:
post_process_controller.profile = preset.post_process_profile
if cloud_system and preset.cloud_layer_configs.size() > 0:
cloud_system.layer_configs = preset.cloud_layer_configs
cloud_system.rebuild_layers()
func _resolve_preset_library() -> SkyboxPresetLibrary:
if preset_library != null:
return preset_library
if has_node(NodePath("PresetLibrary")):
return get_node(NodePath("PresetLibrary")) as SkyboxPresetLibrary
return null
func _get_property_list() -> Array:
var properties := []
var names: PackedStringArray = []
var lib := _resolve_preset_library()
if lib:
names = lib.get_preset_names()
var hint_string := ""
if names.size() > 0:
hint_string = ",".join(names)
properties.append({
"name": "preset_name",
"type": TYPE_STRING,
"usage": PROPERTY_USAGE_EDITOR,
"hint": PROPERTY_HINT_ENUM,
"hint_string": hint_string,
})
return properties
func _set(property: StringName, value: Variant) -> bool:
if property == "preset_name":
if preset_name == value:
return true
preset_name = value
if _updating_preset_name:
return true
var lib := _resolve_preset_library()
if lib and String(preset_name) != "":
lib.apply_preset(String(preset_name))
var p := lib.get_current_preset()
if p:
_on_preset_changed(p)
_sync_all_systems()
return true
return false
func _get(property: StringName) -> Variant:
if property == "preset_name":
return preset_name
return null
func _sync_preset_name() -> void:
if preset_library == null:
return
var current := preset_library.get_current_preset()
if current == null:
return
_updating_preset_name = true
preset_name = current.preset_name
_updating_preset_name = false
func _ensure_post_process_environment() -> void:
if post_process_controller and world_environment and world_environment.environment:
if post_process_controller.target_environment == null:
post_process_controller.target_environment = world_environment.environment
post_process_controller._setup_environment()
func _load_initial_preset() -> void:
if preset_library == null:
return
var current := preset_library.get_current_preset()
if current == null:
return
_sync_preset_name()
if current.config:
_current_config = current.config
_apply_preset_assets(current)
func _sync_shadows() -> void:
if shadow_proxy_system == null:
return
if weather_controller:
shadow_proxy_system.set_cloud_coverage(weather_controller.get_cloud_coverage())
if cloud_system:
shadow_proxy_system.sync_with_cloud_system(cloud_system)
func _sync_weather_vfx() -> void:
if weather_vfx == null or weather_controller == null:
return
weather_vfx.set_rain_intensity(weather_controller.get_rain_intensity())
weather_vfx.set_snow_intensity(weather_controller.get_snow_intensity())
func _update_debug_info() -> void:
if Engine.is_editor_hint():
return
if _debug_panel == null:
_create_debug_panel()
_debug_panel.visible = true
func _create_debug_panel() -> void:
_debug_canvas_layer = CanvasLayer.new()
_debug_canvas_layer.name = "DebugCanvasLayer"
_debug_canvas_layer.layer = 100
add_child(_debug_canvas_layer)
_debug_panel = SkyDebugPanel.new()
_debug_panel.name = "SkyDebugPanel"
_debug_panel.dynamic_sky = self
_debug_panel.anchor_left = 0.0
_debug_panel.anchor_top = 0.0
_debug_panel.anchor_right = 0.0
_debug_panel.anchor_bottom = 0.0
_debug_panel.offset_left = 10.0
_debug_panel.offset_top = 10.0
_debug_canvas_layer.add_child(_debug_panel)
func set_time_of_day(time: float) -> void:
_current_config = null
if day_night_controller:
day_night_controller.time_of_day = time
func set_weather(state: WeatherProfile.WeatherState, transition_time: float = -1.0) -> void:
_current_config = null
if weather_controller:
weather_controller.set_weather(state, transition_time)
func apply_preset(preset_name: String) -> void:
if preset_library:
preset_library.apply_preset(preset_name)
func pause_time() -> void:
if day_night_controller:
day_night_controller.paused = true
func resume_time() -> void:
if day_night_controller:
day_night_controller.paused = false
func trigger_meteor_shower(duration: float = 60.0) -> void:
if vfx_controller:
vfx_controller.start_meteor_shower(duration)
func get_time_of_day() -> float:
if day_night_controller:
return day_night_controller.time_of_day
return 0.0
func get_current_weather() -> WeatherProfile.WeatherState:
if weather_controller:
return weather_controller.current_weather
return WeatherProfile.WeatherState.CLEAR
func is_daytime() -> bool:
if day_night_controller:
return day_night_controller.is_daytime()
return true
func is_nighttime() -> bool:
if day_night_controller:
return day_night_controller.is_nighttime()
return false