Add weather presentation and gameplay UI improvements

This commit is contained in:
Alexander Sellite 2026-08-13 01:31:05 -04:00
parent db6074ddfa
commit 51fa6535b6
28 changed files with 1067 additions and 61 deletions

View file

@ -24,6 +24,7 @@ func _initialize() -> void:
func _run() -> void:
_validate_weather_scheduler()
_validate_authoritative_weather_override()
_validate_weather_persistence()
_validate_snapshot_bounds()
_validate_fishing_weather_seams()
@ -74,6 +75,54 @@ func _duration_is_valid(weather: WorldWeatherServiceType) -> bool:
return false
func _validate_authoritative_weather_override() -> void:
var weather := WorldWeatherServiceType.new()
root.add_child(weather)
assert(not weather.set_authoritative_weather(
WorldWeatherServiceType.Weather.FOGGY
))
weather.begin_authoritative_session(20260812)
assert(weather.set_authoritative_weather(
WorldWeatherServiceType.Weather.FOGGY
))
assert(weather.is_foggy())
assert(_duration_is_valid(weather))
weather.end_session()
assert(not weather.set_authoritative_weather(
WorldWeatherServiceType.Weather.RAINY
))
var clock := WorldTimeServiceType.new()
root.add_child(clock)
clock.begin_session(WorldTimeServiceType.DAY_START_HOUR)
var schedule: Array[Dictionary] = []
for index: int in WorldWeatherServiceType.DAILY_PLAN_SEGMENT_COUNT:
schedule.append({
"start_hour": fposmod(
WorldTimeServiceType.DAY_START_HOUR
+ float(index)
* WorldWeatherServiceType.DAILY_PLAN_SEGMENT_HOURS,
WorldTimeServiceType.HOURS_PER_DAY,
),
"weather": int(WorldWeatherServiceType.Weather.SUNNY),
})
assert(weather.configure_daily_plan("command-test", schedule, clock))
weather.begin_authoritative_session(20260812)
assert(weather.set_authoritative_weather(
WorldWeatherServiceType.Weather.RAINY
))
weather.advance_weather(1.0)
assert(weather.is_raining())
clock.synchronize_time(
WorldTimeServiceType.DAY_START_HOUR
+ WorldWeatherServiceType.DAILY_PLAN_SEGMENT_HOURS
)
weather.advance_weather(0.01)
assert(weather.get_weather() == WorldWeatherServiceType.Weather.SUNNY)
weather.queue_free()
clock.queue_free()
func _validate_weather_persistence() -> void:
var weather := WorldWeatherServiceType.new()
root.add_child(weather)
@ -212,20 +261,118 @@ func _validate_weather_presentation() -> void:
weather.begin_remote_session()
var rain_target := Node3D.new()
world_root.add_child(rain_target)
var rain_camera := Camera3D.new()
world_root.add_child(rain_camera)
rain_target.global_position = Vector3(-18.0, 2.0, 14.0)
rain_camera.global_position = Vector3(24.0, 9.0, -18.0)
var visuals := WorldTimeVisualControllerType.new()
world_root.add_child(visuals)
visuals.setup(
clock, world_environment, sun, weather, rain_target
clock,
world_environment,
sun,
weather,
rain_target,
func() -> Camera3D: return rain_camera,
)
var runtime_environment: Environment = world_environment.environment
var runtime_sky_material := (
runtime_environment.sky.sky_material as ShaderMaterial
)
var clear_background_energy: float = (
runtime_environment.background_energy_multiplier
)
var clear_ambient_energy: float = runtime_environment.ambient_light_energy
var clear_fog_light_energy: float = runtime_environment.fog_light_energy
var clear_brightness: float = runtime_environment.adjustment_brightness
var clear_saturation: float = runtime_environment.adjustment_saturation
var clear_sun_energy: float = sun.light_energy
var clear_water_brightness: float = float(
WorldTimeVisualControllerType.SALT_WATER_MATERIAL.get_shader_parameter(
"environment_brightness"
)
)
assert(not runtime_environment.fog_enabled)
assert(is_zero_approx(float(
WorldTimeVisualControllerType.SALT_WATER_MATERIAL.get_shader_parameter(
"weather_fog_amount"
)
)))
assert(is_equal_approx(runtime_environment.fog_sky_affect, 0.35))
assert(is_zero_approx(float(
runtime_sky_material.get_shader_parameter("cloud_opacity")
)))
var storm_clouds := visuals.get_node("LocalStormClouds") as Node3D
assert(storm_clouds != null)
assert(storm_clouds.call("get_patch_count") == 81)
var cloud_field := storm_clouds.get_node("CloudField") as MultiMeshInstance3D
assert(cloud_field != null)
assert(cloud_field.multimesh != null)
assert(cloud_field.multimesh.instance_count == 81)
assert(cloud_field.multimesh.mesh is ArrayMesh)
var cloud_shader: Shader = preload(
"res://world/environment/local_storm_cloud.gdshader"
)
assert("cull_disabled" in cloud_shader.code)
assert(LocalStormCloudLayer.WRAP_RADIUS >= 315.0)
assert(is_equal_approx(LocalStormCloudLayer.MAXIMUM_OPACITY, 1.0))
assert(
LocalStormCloudLayer.DISTANCE_FADE_END
< LocalStormCloudLayer.WRAP_RADIUS
)
assert(is_zero_approx(float(storm_clouds.call("get_storm_amount"))))
visuals.apply_weather_immediately(
WorldWeatherServiceType.Weather.FOGGY
)
assert(runtime_environment.fog_enabled)
assert(float(
WorldTimeVisualControllerType.SALT_WATER_MATERIAL.get_shader_parameter(
"weather_fog_amount"
)
) > 0.99)
var water_fog_color := (
WorldTimeVisualControllerType.SALT_WATER_MATERIAL.get_shader_parameter(
"weather_fog_color"
) as Color
)
assert(water_fog_color.get_luminance() < 0.05)
assert(runtime_environment.fog_depth_begin <= 4.01)
assert(runtime_environment.fog_depth_end <= 42.01)
assert(is_zero_approx(runtime_environment.fog_sky_affect))
assert(runtime_environment.fog_aerial_perspective >= 0.91)
assert(is_equal_approx(runtime_environment.fog_depth_end, 18.0))
assert(is_equal_approx(runtime_environment.fog_sky_affect, 1.0))
assert(is_zero_approx(runtime_environment.fog_aerial_perspective))
assert(is_zero_approx(float(
runtime_sky_material.get_shader_parameter("cloud_opacity")
)))
assert(is_equal_approx(
runtime_environment.background_energy_multiplier,
clear_background_energy
* WorldTimeVisualControllerType.FOG_DAYLIGHT_SCENE_BRIGHTNESS,
))
assert(is_equal_approx(
runtime_environment.ambient_light_energy,
clear_ambient_energy
* WorldTimeVisualControllerType.FOG_DAYLIGHT_SCENE_BRIGHTNESS,
))
assert(is_equal_approx(
runtime_environment.fog_light_energy,
clear_fog_light_energy
* WorldTimeVisualControllerType.FOG_DAYLIGHT_FOG_LIGHT_BRIGHTNESS,
))
assert(is_equal_approx(
runtime_environment.adjustment_brightness,
clear_brightness
* WorldTimeVisualControllerType.FOG_DAYLIGHT_POST_BRIGHTNESS,
))
assert(is_equal_approx(sun.light_energy, clear_sun_energy * 0.30))
assert(is_equal_approx(
float(
WorldTimeVisualControllerType.SALT_WATER_MATERIAL.get_shader_parameter(
"environment_brightness"
)
),
clear_water_brightness
* WorldTimeVisualControllerType.FOG_DAYLIGHT_WATER_BRIGHTNESS,
))
assert(is_equal_approx(
runtime_environment.adjustment_saturation,
clear_saturation,
@ -233,8 +380,41 @@ func _validate_weather_presentation() -> void:
visuals.apply_weather_immediately(
WorldWeatherServiceType.Weather.RAINY
)
assert(runtime_environment.fog_enabled)
assert(float(
WorldTimeVisualControllerType.SALT_WATER_MATERIAL.get_shader_parameter(
"weather_fog_amount"
)
) > 0.99)
assert(is_equal_approx(runtime_environment.fog_sky_affect, 0.68))
assert(
float(runtime_sky_material.get_shader_parameter("cloud_coverage"))
> 0.98
)
assert(
float(runtime_sky_material.get_shader_parameter("cloud_opacity"))
> 0.99
)
assert(float(storm_clouds.call("get_storm_amount")) > 0.87)
assert(storm_clouds.visible)
assert(is_equal_approx(
runtime_environment.adjustment_brightness,
clear_brightness
* 0.92
* WorldTimeVisualControllerType.RAIN_DAYLIGHT_POST_BRIGHTNESS,
))
var rain := visuals.get_node("LocalRain") as GPUParticles3D
assert(rain != null)
assert(rain.global_position.is_equal_approx(
rain_camera.global_position
+ WorldTimeVisualControllerType.RAIN_EMITTER_OFFSET
))
rain_camera.global_position = Vector3(-31.0, 15.0, 42.0)
visuals.call("_update_rain_position")
assert(rain.global_position.is_equal_approx(
rain_camera.global_position
+ WorldTimeVisualControllerType.RAIN_EMITTER_OFFSET
))
assert(rain.emitting)
assert(rain.amount_ratio > 0.99)
assert(rain.amount == WorldTimeVisualControllerType.RAIN_PARTICLE_AMOUNT)
@ -253,8 +433,52 @@ func _validate_weather_presentation() -> void:
assert(rain_mesh.size.is_equal_approx(
WorldTimeVisualControllerType.RAIN_DROP_SIZE
))
visuals.call(
"_on_weather_changed",
WorldWeatherServiceType.Weather.SUNNY,
60.0,
)
visuals.call(
"_process",
WorldTimeVisualControllerType.WEATHER_TRANSITION_SECONDS * 0.5,
)
var halfway_water_fog: float = float(
WorldTimeVisualControllerType.SALT_WATER_MATERIAL.get_shader_parameter(
"weather_fog_amount"
)
)
assert(halfway_water_fog > 0.49 and halfway_water_fog < 0.51)
assert(is_equal_approx(
float(
WorldTimeVisualControllerType.FRESH_WATER_MATERIAL.get_shader_parameter(
"weather_fog_amount"
)
),
halfway_water_fog,
))
assert(runtime_environment.fog_enabled)
visuals.call(
"_process",
WorldTimeVisualControllerType.WEATHER_TRANSITION_SECONDS * 0.5,
)
assert(is_zero_approx(float(
WorldTimeVisualControllerType.SALT_WATER_MATERIAL.get_shader_parameter(
"weather_fog_amount"
)
)))
assert(not runtime_environment.fog_enabled)
visuals.apply_weather_immediately(
WorldWeatherServiceType.Weather.CLOUDY
)
assert(not runtime_environment.fog_enabled)
assert(is_zero_approx(float(
WorldTimeVisualControllerType.SALT_WATER_MATERIAL.get_shader_parameter(
"weather_fog_amount"
)
)))
visuals.apply_weather_immediately(
WorldWeatherServiceType.Weather.SUNNY
)
assert(not runtime_environment.fog_enabled)
assert(not rain.emitting)
world_root.queue_free()