Add synchronized time and weather systems
This commit is contained in:
parent
30ad9215ca
commit
58fb3d6605
37 changed files with 1900 additions and 17 deletions
|
|
@ -107,12 +107,17 @@ func _validate_catalog_and_pools() -> void:
|
|||
var pond_context := FishingContextType.new()
|
||||
pond_context.location_tags = [&"starter_pond"]
|
||||
pond_context.water_type = WaterType.Type.FRESH_WATER
|
||||
var night_pond_context := FishingContextType.new()
|
||||
night_pond_context.location_tags = [&"starter_pond"]
|
||||
night_pond_context.water_type = WaterType.Type.FRESH_WATER
|
||||
night_pond_context.is_night = true
|
||||
var ocean_context := FishingContextType.new()
|
||||
ocean_context.location_tags = [&"coast", &"ocean"]
|
||||
ocean_context.water_type = WaterType.Type.SALT_WATER
|
||||
for fish_id: StringName in CATFISH_IDS:
|
||||
var fish: FishDataType = Catalog.get_fish_by_id(fish_id)
|
||||
assert(fish.availability.is_available(pond_context))
|
||||
assert(not fish.availability.is_available(pond_context))
|
||||
assert(fish.availability.is_available(night_pond_context))
|
||||
assert(not fish.availability.is_available(ocean_context))
|
||||
var single_species_pool := FishPoolType.new()
|
||||
single_species_pool.candidates = [fish]
|
||||
|
|
@ -122,7 +127,7 @@ func _validate_catalog_and_pools() -> void:
|
|||
selector.begin_roll()
|
||||
assert(
|
||||
selector.select_fish(
|
||||
single_species_pool, pond_context, collection
|
||||
single_species_pool, night_pond_context, collection
|
||||
) == fish
|
||||
)
|
||||
collection.free()
|
||||
|
|
|
|||
|
|
@ -11,7 +11,11 @@ func _initialize() -> void:
|
|||
func _run() -> void:
|
||||
var main := MainScene.instantiate()
|
||||
root.add_child(main)
|
||||
for _frame: int in 6:
|
||||
for _frame: int in 4:
|
||||
await process_frame
|
||||
if not bool(main.get("_application_initialized")):
|
||||
main.call("_activate_selected_data_path", "", true)
|
||||
for _frame: int in 8:
|
||||
await process_frame
|
||||
assert(bool(main.get("_application_initialized")))
|
||||
var save_manager := main.get("_save_manager") as PlayerSaveManager
|
||||
|
|
@ -45,7 +49,7 @@ func _run() -> void:
|
|||
assert(not hotbar.visible)
|
||||
|
||||
var entry_buttons: Dictionary = logbook.get("_entry_buttons")
|
||||
assert(entry_buttons.size() == 0)
|
||||
assert(entry_buttons.size() == 6)
|
||||
await _capture_if_requested("-unknown")
|
||||
logbook.call(
|
||||
"_select_category", WaterType.Type.FRESH_WATER
|
||||
|
|
|
|||
186
tests/world_time_multiplayer_validation.gd
Normal file
186
tests/world_time_multiplayer_validation.gd
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
extends SceneTree
|
||||
|
||||
const MainScene = preload("res://main/main.tscn")
|
||||
const TEST_PORT: int = 17983
|
||||
const INITIAL_HOST_TIME: float = 19.75
|
||||
const UPDATED_HOST_TIME: float = 20.75
|
||||
const TIME_TOLERANCE_HOURS: float = 0.05
|
||||
|
||||
|
||||
func _initialize() -> void:
|
||||
call_deferred("_run")
|
||||
|
||||
|
||||
func _run() -> void:
|
||||
var arguments: PackedStringArray = OS.get_cmdline_user_args()
|
||||
if arguments.has("host"):
|
||||
await _run_host()
|
||||
return
|
||||
if arguments.has("client"):
|
||||
await _run_client()
|
||||
return
|
||||
push_error("World time multiplayer validation needs host or client mode.")
|
||||
quit(1)
|
||||
|
||||
|
||||
func _run_host() -> void:
|
||||
var main: Node = await _create_initialized_main()
|
||||
var session := main.get_node("%NetworkSession") as NetworkSession
|
||||
var world_time := main.get_node("%WorldTimeService") as WorldTimeService
|
||||
var world_weather := (
|
||||
main.get_node("%WorldWeatherService") as WorldWeatherService
|
||||
)
|
||||
assert(session.start_private_host(TEST_PORT))
|
||||
world_time.synchronize_time(INITIAL_HOST_TIME)
|
||||
world_weather.apply_authoritative_snapshot(
|
||||
WorldWeatherService.Weather.RAINY, 300.0
|
||||
)
|
||||
assert(session.set_host_open(true))
|
||||
|
||||
var remote_peer_id: int = 0
|
||||
var join_deadline: int = Time.get_ticks_msec() + 20000
|
||||
while Time.get_ticks_msec() < join_deadline and remote_peer_id == 0:
|
||||
await process_frame
|
||||
for peer_id: int in session.get_authenticated_peer_ids():
|
||||
if peer_id != session.get_local_peer_id():
|
||||
remote_peer_id = peer_id
|
||||
break
|
||||
assert(remote_peer_id > 1)
|
||||
assert(session.peer_supports_capability(
|
||||
remote_peer_id, NetworkProtocol.WORLD_TIME_CAPABILITY
|
||||
))
|
||||
assert(session.peer_supports_capability(
|
||||
remote_peer_id, NetworkProtocol.WORLD_WEATHER_CAPABILITY
|
||||
))
|
||||
assert(world_time.get_phase() == WorldTimeService.Phase.DUSK)
|
||||
|
||||
await create_timer(1.0).timeout
|
||||
world_time.synchronize_time(UPDATED_HOST_TIME)
|
||||
world_weather.apply_authoritative_snapshot(
|
||||
WorldWeatherService.Weather.FOGGY, 300.0
|
||||
)
|
||||
var disconnect_deadline: int = Time.get_ticks_msec() + 12000
|
||||
while (
|
||||
Time.get_ticks_msec() < disconnect_deadline
|
||||
and session.is_authenticated_peer(remote_peer_id)
|
||||
):
|
||||
await process_frame
|
||||
assert(not session.is_authenticated_peer(remote_peer_id))
|
||||
print("World time multiplayer host validation: PASS")
|
||||
session.disconnect_session("")
|
||||
main.queue_free()
|
||||
await process_frame
|
||||
quit()
|
||||
|
||||
|
||||
func _run_client() -> void:
|
||||
var main: Node = await _create_initialized_main()
|
||||
main.call(
|
||||
"_on_title_join_game_requested",
|
||||
"127.0.0.1:%d" % TEST_PORT,
|
||||
)
|
||||
var session := main.get_node("%NetworkSession") as NetworkSession
|
||||
var world_time := main.get_node("%WorldTimeService") as WorldTimeService
|
||||
var world_weather := (
|
||||
main.get_node("%WorldWeatherService") as WorldWeatherService
|
||||
)
|
||||
var join_deadline: int = Time.get_ticks_msec() + 20000
|
||||
while Time.get_ticks_msec() < join_deadline:
|
||||
await process_frame
|
||||
if session.state == NetworkSession.State.VERIFYING_SERVER_IDENTITY:
|
||||
main.call("_confirm_server_trust")
|
||||
if session.is_joined_client() and bool(main.get("_gameplay_started")):
|
||||
break
|
||||
assert(session.is_joined_client())
|
||||
assert(session.supports_server_capability(
|
||||
NetworkProtocol.WORLD_TIME_CAPABILITY
|
||||
))
|
||||
assert(session.supports_server_capability(
|
||||
NetworkProtocol.WORLD_WEATHER_CAPABILITY
|
||||
))
|
||||
|
||||
var initial_deadline: int = Time.get_ticks_msec() + 8000
|
||||
while (
|
||||
Time.get_ticks_msec() < initial_deadline
|
||||
and _wrapped_time_difference(
|
||||
world_time.get_time_hours(), INITIAL_HOST_TIME
|
||||
) > TIME_TOLERANCE_HOURS
|
||||
):
|
||||
await process_frame
|
||||
assert(_wrapped_time_difference(
|
||||
world_time.get_time_hours(), INITIAL_HOST_TIME
|
||||
) <= TIME_TOLERANCE_HOURS)
|
||||
assert(world_time.get_phase() == WorldTimeService.Phase.DUSK)
|
||||
var weather_deadline: int = Time.get_ticks_msec() + 8000
|
||||
while (
|
||||
Time.get_ticks_msec() < weather_deadline
|
||||
and not world_weather.is_raining()
|
||||
):
|
||||
await process_frame
|
||||
assert(world_weather.is_raining())
|
||||
var game_ui := main.get_node("%GameUI") as CanvasLayer
|
||||
var chat_ui := game_ui.get_node("%ChatUI") as Control
|
||||
var clock_panel := chat_ui.get_node("WorldClockPanel") as PanelContainer
|
||||
var clock_label := clock_panel.get_node("WorldClockLabel") as Label
|
||||
var weather_icon := chat_ui.get_node("WorldWeatherIcon") as WeatherIcon
|
||||
var chat_panel := chat_ui.get_node("ChatPanel") as PanelContainer
|
||||
assert(clock_panel.visible)
|
||||
assert(clock_label.text == world_time.get_clock_text())
|
||||
assert(clock_label.text.ends_with(" pm"))
|
||||
assert(weather_icon.visible)
|
||||
assert(weather_icon.get_weather() == WorldWeatherService.Weather.RAINY)
|
||||
assert(clock_panel.position.y + clock_panel.size.y < chat_panel.position.y)
|
||||
|
||||
var update_deadline: int = Time.get_ticks_msec() + 10000
|
||||
while (
|
||||
Time.get_ticks_msec() < update_deadline
|
||||
and _wrapped_time_difference(
|
||||
world_time.get_time_hours(), UPDATED_HOST_TIME
|
||||
) > TIME_TOLERANCE_HOURS
|
||||
):
|
||||
await process_frame
|
||||
assert(_wrapped_time_difference(
|
||||
world_time.get_time_hours(), UPDATED_HOST_TIME
|
||||
) <= TIME_TOLERANCE_HOURS)
|
||||
assert(world_time.get_phase() == WorldTimeService.Phase.NIGHT)
|
||||
assert(clock_label.text == world_time.get_clock_text())
|
||||
var fog_deadline: int = Time.get_ticks_msec() + 8000
|
||||
while (
|
||||
Time.get_ticks_msec() < fog_deadline
|
||||
and not world_weather.is_foggy()
|
||||
):
|
||||
await process_frame
|
||||
assert(world_weather.is_foggy())
|
||||
assert(weather_icon.get_weather() == WorldWeatherService.Weather.FOGGY)
|
||||
chat_ui.call("set_dock_right", true)
|
||||
await process_frame
|
||||
assert(clock_panel.position.x > 1000.0)
|
||||
assert(weather_icon.position.x < clock_panel.position.x)
|
||||
chat_ui.call("set_dock_right", false)
|
||||
await process_frame
|
||||
assert(clock_panel.position.x < 20.0)
|
||||
assert(weather_icon.position.x > clock_panel.position.x)
|
||||
print("World time multiplayer client validation: PASS")
|
||||
session.disconnect_session("")
|
||||
main.queue_free()
|
||||
await process_frame
|
||||
quit()
|
||||
|
||||
|
||||
func _create_initialized_main() -> Node:
|
||||
root.size = Vector2i(1280, 720)
|
||||
var main := MainScene.instantiate()
|
||||
root.add_child(main)
|
||||
for _frame: int in 4:
|
||||
await process_frame
|
||||
if not bool(main.get("_application_initialized")):
|
||||
main.call("_activate_selected_data_path", "", true)
|
||||
for _frame: int in 8:
|
||||
await process_frame
|
||||
assert(bool(main.get("_application_initialized")))
|
||||
return main
|
||||
|
||||
|
||||
func _wrapped_time_difference(left: float, right: float) -> float:
|
||||
var direct: float = absf(left - right)
|
||||
return minf(direct, WorldTimeService.HOURS_PER_DAY - direct)
|
||||
1
tests/world_time_multiplayer_validation.gd.uid
Normal file
1
tests/world_time_multiplayer_validation.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://6fal0btp6sgr
|
||||
182
tests/world_time_validation.gd
Normal file
182
tests/world_time_validation.gd
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
extends SceneTree
|
||||
|
||||
const WorldTimeServiceType = preload("res://world/world_time_service.gd")
|
||||
const WorldTimeVisualControllerType = preload(
|
||||
"res://world/world_time_visual_controller.gd"
|
||||
)
|
||||
const NetworkWorldTimeServiceType = preload(
|
||||
"res://network/network_world_time_service.gd"
|
||||
)
|
||||
const FishingContextType = preload("res://fishing/fishing_context.gd")
|
||||
const FishDataType = preload("res://fish/fish_data.gd")
|
||||
const FishPoolType = preload("res://fish/fish_pool.gd")
|
||||
const FishingSpotType = preload("res://fishing/fishing_spot.gd")
|
||||
const FishableWaterRegionType = preload(
|
||||
"res://world/fishable_water_region.gd"
|
||||
)
|
||||
|
||||
const Catalog: FishPoolType = preload("res://fish/pools/fish_catalog.tres")
|
||||
|
||||
|
||||
func _initialize() -> void:
|
||||
call_deferred("_run")
|
||||
|
||||
|
||||
func _run() -> void:
|
||||
_validate_clock_boundaries_and_duration()
|
||||
_validate_fishing_availability()
|
||||
_validate_fishing_spot_context()
|
||||
_validate_network_snapshot_bounds()
|
||||
_validate_environment_presentation()
|
||||
print("World time validation: PASS")
|
||||
quit()
|
||||
|
||||
|
||||
func _validate_clock_boundaries_and_duration() -> void:
|
||||
assert(WorldTimeServiceType.REAL_SECONDS_PER_CYCLE == 3600.0)
|
||||
assert(
|
||||
WorldTimeServiceType.phase_for_hour(7.49)
|
||||
== WorldTimeServiceType.Phase.NIGHT
|
||||
)
|
||||
assert(
|
||||
WorldTimeServiceType.phase_for_hour(7.5)
|
||||
== WorldTimeServiceType.Phase.DAWN
|
||||
)
|
||||
assert(
|
||||
WorldTimeServiceType.phase_for_hour(8.49)
|
||||
== WorldTimeServiceType.Phase.DAWN
|
||||
)
|
||||
assert(
|
||||
WorldTimeServiceType.phase_for_hour(8.5)
|
||||
== WorldTimeServiceType.Phase.DAY
|
||||
)
|
||||
assert(
|
||||
WorldTimeServiceType.phase_for_hour(19.5)
|
||||
== WorldTimeServiceType.Phase.DUSK
|
||||
)
|
||||
assert(
|
||||
WorldTimeServiceType.phase_for_hour(20.5)
|
||||
== WorldTimeServiceType.Phase.NIGHT
|
||||
)
|
||||
assert(WorldTimeServiceType.format_clock_time(0.0) == "12:00 am")
|
||||
assert(WorldTimeServiceType.format_clock_time(8.0) == "8:00 am")
|
||||
assert(WorldTimeServiceType.format_clock_time(20.5) == "8:30 pm")
|
||||
|
||||
var clock := WorldTimeServiceType.new()
|
||||
root.add_child(clock)
|
||||
clock.begin_session(8.0)
|
||||
clock.advance_time(1800.0)
|
||||
assert(is_equal_approx(clock.get_time_hours(), 20.0))
|
||||
assert(clock.is_night_period())
|
||||
assert(clock.is_transition())
|
||||
clock.advance_time(1800.0)
|
||||
assert(is_equal_approx(clock.get_time_hours(), 8.0))
|
||||
assert(not clock.is_night_period())
|
||||
assert(clock.is_transition())
|
||||
clock.queue_free()
|
||||
|
||||
|
||||
func _validate_fishing_availability() -> void:
|
||||
var day_context := FishingContextType.new()
|
||||
day_context.location_tags = [&"starter_pond"]
|
||||
day_context.is_night = false
|
||||
var night_context := FishingContextType.new()
|
||||
night_context.location_tags = [&"starter_pond"]
|
||||
night_context.is_night = true
|
||||
var transition_context := FishingContextType.new()
|
||||
transition_context.location_tags = [&"starter_pond"]
|
||||
transition_context.is_night = true
|
||||
transition_context.is_day_night_transition = true
|
||||
|
||||
for fish_id: StringName in [&"bluegill", &"sunfish"]:
|
||||
var day_fish: FishDataType = Catalog.get_fish_by_id(fish_id)
|
||||
assert(day_fish.availability.is_available(day_context))
|
||||
assert(not day_fish.availability.is_available(night_context))
|
||||
assert(day_fish.availability.is_available(transition_context))
|
||||
for fish_id: StringName in [
|
||||
&"catfish_blue",
|
||||
&"catfish_channel",
|
||||
&"catfish_flathead",
|
||||
&"catfish_white",
|
||||
]:
|
||||
var night_fish: FishDataType = Catalog.get_fish_by_id(fish_id)
|
||||
assert(not night_fish.availability.is_available(day_context))
|
||||
assert(night_fish.availability.is_available(night_context))
|
||||
assert(night_fish.availability.is_available(transition_context))
|
||||
for fish_id: StringName in [&"bass", &"carp"]:
|
||||
var all_time_fish: FishDataType = Catalog.get_fish_by_id(fish_id)
|
||||
assert(all_time_fish.availability.is_available(day_context))
|
||||
assert(all_time_fish.availability.is_available(night_context))
|
||||
assert(all_time_fish.availability.is_available(transition_context))
|
||||
|
||||
|
||||
func _validate_fishing_spot_context() -> void:
|
||||
var clock := WorldTimeServiceType.new()
|
||||
clock.begin_session(20.25)
|
||||
var fishing_spot := FishingSpotType.new()
|
||||
fishing_spot.set("_world_time", clock)
|
||||
var region := FishableWaterRegionType.new()
|
||||
region.location_tags = [&"starter_pond"]
|
||||
region.water_type = WaterType.Type.FRESH_WATER
|
||||
var dusk_context: FishingContext = fishing_spot.build_network_context(region)
|
||||
assert(dusk_context.is_night)
|
||||
assert(dusk_context.is_day_night_transition)
|
||||
clock.synchronize_time(14.0)
|
||||
var day_context: FishingContext = fishing_spot.build_network_context(region)
|
||||
assert(not day_context.is_night)
|
||||
assert(not day_context.is_day_night_transition)
|
||||
region.free()
|
||||
fishing_spot.free()
|
||||
clock.free()
|
||||
|
||||
|
||||
func _validate_network_snapshot_bounds() -> void:
|
||||
assert(NetworkWorldTimeServiceType.validate_snapshot({
|
||||
"session_id": "session",
|
||||
"time_hours": 8.25,
|
||||
"sequence": 1,
|
||||
}))
|
||||
assert(not NetworkWorldTimeServiceType.validate_snapshot({
|
||||
"session_id": "session",
|
||||
"time_hours": 24.0,
|
||||
"sequence": 1,
|
||||
}))
|
||||
assert(not NetworkWorldTimeServiceType.validate_snapshot({
|
||||
"session_id": "",
|
||||
"time_hours": 8.0,
|
||||
"sequence": 1,
|
||||
}))
|
||||
|
||||
|
||||
func _validate_environment_presentation() -> void:
|
||||
var world_root := Node3D.new()
|
||||
root.add_child(world_root)
|
||||
var world_environment := WorldEnvironment.new()
|
||||
var environment := Environment.new()
|
||||
var sky := Sky.new()
|
||||
sky.sky_material = ProceduralSkyMaterial.new()
|
||||
environment.sky = sky
|
||||
environment.adjustment_enabled = true
|
||||
environment.fog_enabled = true
|
||||
world_environment.environment = environment
|
||||
world_root.add_child(world_environment)
|
||||
var sun := DirectionalLight3D.new()
|
||||
world_root.add_child(sun)
|
||||
var clock := WorldTimeServiceType.new()
|
||||
world_root.add_child(clock)
|
||||
var visuals := WorldTimeVisualControllerType.new()
|
||||
world_root.add_child(visuals)
|
||||
visuals.setup(clock, world_environment, sun)
|
||||
visuals.apply_time_immediately(12.0)
|
||||
var runtime_environment: Environment = world_environment.environment
|
||||
var runtime_sky_material := (
|
||||
runtime_environment.sky.sky_material as ProceduralSkyMaterial
|
||||
)
|
||||
var day_horizon: Color = runtime_sky_material.sky_horizon_color
|
||||
var day_ambient_energy: float = runtime_environment.ambient_light_energy
|
||||
visuals.apply_time_immediately(0.0)
|
||||
assert(runtime_sky_material.sky_horizon_color != day_horizon)
|
||||
assert(runtime_environment.ambient_light_energy < day_ambient_energy)
|
||||
visuals.apply_time_immediately(20.0)
|
||||
assert(runtime_sky_material.sky_horizon_color.r > day_horizon.r)
|
||||
world_root.queue_free()
|
||||
1
tests/world_time_validation.gd.uid
Normal file
1
tests/world_time_validation.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://buiitafgrgm4b
|
||||
190
tests/world_weather_validation.gd
Normal file
190
tests/world_weather_validation.gd
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
extends SceneTree
|
||||
|
||||
const WorldWeatherServiceType = preload(
|
||||
"res://world/world_weather_service.gd"
|
||||
)
|
||||
const NetworkWorldWeatherServiceType = preload(
|
||||
"res://network/network_world_weather_service.gd"
|
||||
)
|
||||
const WorldTimeServiceType = preload("res://world/world_time_service.gd")
|
||||
const WorldTimeVisualControllerType = preload(
|
||||
"res://world/world_time_visual_controller.gd"
|
||||
)
|
||||
const FishingContextType = preload("res://fishing/fishing_context.gd")
|
||||
const FishingSpotType = preload("res://fishing/fishing_spot.gd")
|
||||
const FishAvailabilityType = preload("res://fish/fish_availability.gd")
|
||||
const FishableWaterRegionType = preload(
|
||||
"res://world/fishable_water_region.gd"
|
||||
)
|
||||
|
||||
|
||||
func _initialize() -> void:
|
||||
call_deferred("_run")
|
||||
|
||||
|
||||
func _run() -> void:
|
||||
_validate_weather_scheduler()
|
||||
_validate_snapshot_bounds()
|
||||
_validate_fishing_weather_seams()
|
||||
_validate_fishing_spot_context()
|
||||
_validate_weather_presentation()
|
||||
print("World weather validation: PASS")
|
||||
quit()
|
||||
|
||||
|
||||
func _validate_weather_scheduler() -> void:
|
||||
var weather := WorldWeatherServiceType.new()
|
||||
root.add_child(weather)
|
||||
weather.begin_authoritative_session(20260802)
|
||||
assert(weather.get_weather() == WorldWeatherServiceType.Weather.SUNNY)
|
||||
assert(_duration_is_valid(weather))
|
||||
weather.advance_weather(weather.get_seconds_remaining() + 0.01)
|
||||
assert(weather.get_weather() == WorldWeatherServiceType.Weather.CLOUDY)
|
||||
assert(_duration_is_valid(weather))
|
||||
weather.advance_weather(weather.get_seconds_remaining() + 0.01)
|
||||
assert(weather.get_weather() in [
|
||||
WorldWeatherServiceType.Weather.SUNNY,
|
||||
WorldWeatherServiceType.Weather.RAINY,
|
||||
WorldWeatherServiceType.Weather.FOGGY,
|
||||
])
|
||||
assert(_duration_is_valid(weather))
|
||||
weather.apply_authoritative_snapshot(
|
||||
WorldWeatherServiceType.Weather.RAINY, 120.0
|
||||
)
|
||||
assert(weather.is_raining())
|
||||
assert(not weather.is_foggy())
|
||||
weather.apply_authoritative_snapshot(
|
||||
WorldWeatherServiceType.Weather.FOGGY, 120.0
|
||||
)
|
||||
assert(weather.is_foggy())
|
||||
assert(not weather.is_raining())
|
||||
weather.queue_free()
|
||||
|
||||
|
||||
func _duration_is_valid(weather: WorldWeatherServiceType) -> bool:
|
||||
var seconds: float = weather.get_seconds_remaining()
|
||||
match weather.get_weather():
|
||||
WorldWeatherServiceType.Weather.SUNNY:
|
||||
return seconds >= 480.0 and seconds <= 900.0
|
||||
WorldWeatherServiceType.Weather.CLOUDY:
|
||||
return seconds >= 300.0 and seconds <= 720.0
|
||||
WorldWeatherServiceType.Weather.RAINY, WorldWeatherServiceType.Weather.FOGGY:
|
||||
return seconds >= 300.0 and seconds <= 600.0
|
||||
return false
|
||||
|
||||
|
||||
func _validate_snapshot_bounds() -> void:
|
||||
assert(NetworkWorldWeatherServiceType.validate_snapshot({
|
||||
"session_id": "session",
|
||||
"weather": int(WorldWeatherServiceType.Weather.FOGGY),
|
||||
"seconds_remaining": 300.0,
|
||||
"sequence": 2,
|
||||
}))
|
||||
assert(not NetworkWorldWeatherServiceType.validate_snapshot({
|
||||
"session_id": "session",
|
||||
"weather": 99,
|
||||
"seconds_remaining": 300.0,
|
||||
"sequence": 2,
|
||||
}))
|
||||
assert(not NetworkWorldWeatherServiceType.validate_snapshot({
|
||||
"session_id": "session",
|
||||
"weather": int(WorldWeatherServiceType.Weather.RAINY),
|
||||
"seconds_remaining": 1801.0,
|
||||
"sequence": 2,
|
||||
}))
|
||||
|
||||
|
||||
func _validate_fishing_weather_seams() -> void:
|
||||
var clear_context := FishingContextType.new()
|
||||
var rain_context := FishingContextType.new()
|
||||
rain_context.is_raining = true
|
||||
var fog_context := FishingContextType.new()
|
||||
fog_context.is_foggy = true
|
||||
fog_context.is_night = true
|
||||
var rain_only := FishAvailabilityType.new()
|
||||
rain_only.require_rain = true
|
||||
assert(not rain_only.is_available(clear_context))
|
||||
assert(rain_only.is_available(rain_context))
|
||||
var fog_only := FishAvailabilityType.new()
|
||||
fog_only.allow_day = false
|
||||
fog_only.require_fog = true
|
||||
assert(not fog_only.is_available(clear_context))
|
||||
assert(fog_only.is_available(fog_context))
|
||||
var no_fog := FishAvailabilityType.new()
|
||||
no_fog.forbid_fog = true
|
||||
assert(no_fog.is_available(clear_context))
|
||||
assert(not no_fog.is_available(fog_context))
|
||||
|
||||
|
||||
func _validate_fishing_spot_context() -> void:
|
||||
var weather := WorldWeatherServiceType.new()
|
||||
weather.begin_remote_session()
|
||||
weather.apply_authoritative_snapshot(
|
||||
WorldWeatherServiceType.Weather.FOGGY, 200.0
|
||||
)
|
||||
var fishing_spot := FishingSpotType.new()
|
||||
fishing_spot.set("_world_weather", weather)
|
||||
var region := FishableWaterRegionType.new()
|
||||
region.location_tags = [&"starter_pond"]
|
||||
var context: FishingContext = fishing_spot.build_network_context(region)
|
||||
assert(context.is_foggy)
|
||||
assert(not context.is_raining)
|
||||
weather.apply_authoritative_snapshot(
|
||||
WorldWeatherServiceType.Weather.RAINY, 200.0
|
||||
)
|
||||
context = fishing_spot.build_network_context(region)
|
||||
assert(context.is_raining)
|
||||
assert(not context.is_foggy)
|
||||
region.free()
|
||||
fishing_spot.free()
|
||||
weather.free()
|
||||
|
||||
|
||||
func _validate_weather_presentation() -> void:
|
||||
var world_root := Node3D.new()
|
||||
root.add_child(world_root)
|
||||
var world_environment := WorldEnvironment.new()
|
||||
var environment := Environment.new()
|
||||
var sky := Sky.new()
|
||||
sky.sky_material = ProceduralSkyMaterial.new()
|
||||
environment.sky = sky
|
||||
environment.adjustment_enabled = true
|
||||
environment.fog_enabled = true
|
||||
world_environment.environment = environment
|
||||
world_root.add_child(world_environment)
|
||||
var sun := DirectionalLight3D.new()
|
||||
world_root.add_child(sun)
|
||||
var clock := WorldTimeServiceType.new()
|
||||
world_root.add_child(clock)
|
||||
clock.begin_session(14.0)
|
||||
var weather := WorldWeatherServiceType.new()
|
||||
world_root.add_child(weather)
|
||||
weather.begin_remote_session()
|
||||
var rain_target := Node3D.new()
|
||||
world_root.add_child(rain_target)
|
||||
var visuals := WorldTimeVisualControllerType.new()
|
||||
world_root.add_child(visuals)
|
||||
visuals.setup(
|
||||
clock, world_environment, sun, weather, rain_target
|
||||
)
|
||||
visuals.apply_weather_immediately(
|
||||
WorldWeatherServiceType.Weather.FOGGY
|
||||
)
|
||||
var runtime_environment: Environment = world_environment.environment
|
||||
assert(runtime_environment.fog_depth_begin <= 4.01)
|
||||
assert(runtime_environment.fog_depth_end <= 42.01)
|
||||
assert(runtime_environment.fog_sky_affect >= 0.93)
|
||||
assert(runtime_environment.fog_aerial_perspective >= 0.91)
|
||||
assert(runtime_environment.adjustment_saturation < 0.70)
|
||||
visuals.apply_weather_immediately(
|
||||
WorldWeatherServiceType.Weather.RAINY
|
||||
)
|
||||
var rain := visuals.get_node("LocalRain") as GPUParticles3D
|
||||
assert(rain != null)
|
||||
assert(rain.emitting)
|
||||
assert(rain.amount_ratio > 0.99)
|
||||
visuals.apply_weather_immediately(
|
||||
WorldWeatherServiceType.Weather.SUNNY
|
||||
)
|
||||
assert(not rain.emitting)
|
||||
world_root.queue_free()
|
||||
1
tests/world_weather_validation.gd.uid
Normal file
1
tests/world_weather_validation.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://cdbmbag58okjb
|
||||
Loading…
Add table
Add a link
Reference in a new issue