Compare commits

..

No commits in common. "a4e612c1d37e9f4c650c66704509614d0fc3e2c8" and "1dabdd0d232d05df1ad78c4599ed9e7b95770f1d" have entirely different histories.

30 changed files with 1106 additions and 746 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 554 B

View file

@ -1,41 +0,0 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://btxhq3rdlum2"
path.s3tc="res://.godot/imported/grass_olive_tile.png-72072a382d0948818df97773afa5493f.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
[deps]
source_file="res://art/exported/environment/textures/grass_olive_tile.png"
dest_files=["res://.godot/imported/grass_olive_tile.png-72072a382d0948818df97773afa5493f.s3tc.ctex"]
[params]
compress/mode=2
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=true
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=0

View file

@ -118,7 +118,7 @@ var _new_cast_press_armed: bool = true
var _bobber_water_position: Vector3
var _fight_start_position: Vector3
var _cooldown_status: String = ""
var _fishable_query_shape: CylinderShape3D = CylinderShape3D.new()
var _fishable_query_shape: SphereShape3D = SphereShape3D.new()
var _fish_selector: FishSelectorType = FishSelectorType.new()
var _selected_water_region: FishableWaterRegionType
var _selection_context: FishingContextType
@ -966,7 +966,7 @@ func _calculate_cast_target(distance: float) -> Vector3:
target
)
if water_region != null:
target.y = water_region.get_surface_height()
target.y = water_region.surface_height
_presentation.set_water_surface_height(target.y)
else:
_presentation.reset_water_surface_height()
@ -982,12 +982,11 @@ func get_fishable_water_region(
target: Vector3,
) -> FishableWaterRegionType:
_fishable_query_shape.radius = fishable_query_radius
_fishable_query_shape.height = preview_ray_length
var query := PhysicsShapeQueryParameters3D.new()
query.shape = _fishable_query_shape
query.transform = Transform3D(
Basis.IDENTITY,
Vector3(target.x, target.y, target.z)
Vector3(target.x, _presentation.get_water_surface_height(), target.z)
)
query.collision_mask = fishable_surface_mask
query.collide_with_areas = true

View file

@ -1,88 +0,0 @@
# World authoring
The active test world uses the human-authored starter island through
`world/regions/starter_island_region.tscn`.
## Active composition
`world/test_world.tscn` owns the gameplay-wide environment, sun, world bounds,
and below-world failsafe. `StarterIslandRegion` owns the placed island content:
```text
StarterIslandRegion
├── Terrain
│ ├── Visual
│ └── Collision
├── WaterBodies
│ ├── Pond
│ │ ├── VisualWater
│ │ ├── FishingRegion
│ │ └── RecoveryRegion
│ └── Ocean
│ ├── VisualWater
│ ├── FishingRegions
│ └── RecoveryRegions
├── PlayerSpawn
├── SafeRespawns
└── Interactables
├── FishingShopWorld
└── PelicanCoolerPerch
```
Move the meaningful feature root rather than one of its implementation
children. Child transforms are local offsets owned by that feature.
## Water bodies
Select `WaterBodies/Pond` to move or resize the pond. Its transform is the
authoritative surface position. The `surface_size`, fishing padding, recovery
padding, and recovery depth properties update the visible water and gameplay
coverage together. Fishing and recovery derive the surface height from the
owned surface transform.
Select `WaterBodies/Ocean` to move the surrounding water as one feature. Its
visual, fishing lobes, and recovery lobes use local transforms beneath the
ocean root. The existing multi-lobe footprint remains intentionally explicit;
changing that footprint still requires editing its owned lobe children.
## Placed features
- `PlayerSpawn` is the authoritative initial player transform. Its rotation
controls initial facing.
- Each marker under `SafeRespawns` is an authoritative recovery destination.
Recovery preserves the player's current facing; marker rotation is
intentionally not applied.
- `Interactables/FishingShopWorld` owns the shop visual, collision,
interaction area, prompt, and entrance marker.
- `Interactables/PelicanCoolerPerch` owns the complete Pelican landmark visual.
Pelican selling remains a Cooler action and has no world interaction area.
- `Terrain` owns both the imported visual and generated terrain collision.
- `BelowWorldFailsafe/Coverage` exposes the below-world recovery coverage as a
saved collision shape in `world/test_world.tscn`.
The active `Environment`, `Sun`, and external starter-island grass material
remain directly editable through the Inspector. Their tuning is not recreated
by runtime scripts.
## Reusable world props
Use a single placed `WorldProp` root for trees, rocks, buildings, benches,
signs, vegetation, and similar landmarks:
```text
WorldProp
├── Visual
└── Collision
└── CollisionShape3D
```
Add optional interaction areas, labels, and markers beneath the same root.
Instance imported GLB visuals beneath `Visual`; keep gameplay collision
Godot-owned beneath `Collision`. Place and duplicate the complete prop scene,
not its visual child.
Author reusable assets at scale `(1, 1, 1)`. Uniform root scaling is acceptable
for provisional props when visual and collision scale together. Avoid
non-uniform root scaling because it can deform collision and imported geometry
unpredictably. Make mutable per-instance shapes, meshes, and materials local to
the scene so editing one prop does not change unrelated instances.

View file

@ -0,0 +1,73 @@
# NETFISHING test world
`world/test_world.tscn` remains the active world composition. It currently
instances `world/regions/starter_island_region.tscn`, a Godot-owned gameplay
wrapper around the human-authored starter-island GLB.
## Starter-island ownership
```text
TestWorld
├── Environment
├── Regions
│ └── StarterIslandRegion
│ ├── Visuals
│ │ ├── StarterIslandModel
│ │ ├── OceanWater
│ │ └── PondWater
│ ├── StaticCollision
│ ├── FishingWater
│ ├── WaterRecovery
│ ├── SafeRespawns
│ ├── PlayerSpawn
│ └── Interactables
├── Safety
└── WorldBounds
```
The imported GLB is visual source content and remains at identity scale. The
wrapper creates concave static collision from its explicit mesh reference and
owns all water, fishing, recovery, spawn, and service placement.
Move the complete `StarterIslandRegion` root to keep visuals and gameplay
volumes synchronized. When editing inside the wrapper, keep each water mesh
aligned with its matching `FishingWater` and `WaterRecovery` shapes. Safe
respawns and `PlayerSpawn` must remain on broad upper terrain.
Rename-sensitive paths:
- `TestWorld/Regions`
- `TestWorld/Regions/StarterIslandRegion`
- the NodePaths exported by `StarterIslandRegion`
- each region's `FishingWater`, `WaterRecovery`, and `SafeRespawns` roots
## Reverting to the modular graybox
The previous region scenes remain unchanged under `world/regions/`. To restore
the prior holdover world, restore `world/test_world.tscn` and
`world/test_world.gd` from commit `633bbd9`, then remove the player-spawn
composition line added to `main/main.gd`. That composition instances:
- `village_region.tscn`
- `starter_pond_region.tscn`
- `river_region.tscn`
- `lake_region.tscn`
- `marsh_region.tscn`
- `coastal_dock_region.tscn`
No region asset needs to be reconstructed or recovered from deleted content.
## Water and recovery
The pond and surrounding ocean remain separate fishable regions using the
existing test pool. Ocean fishing and recovery use four collision shapes so
the raised island interior is not classified as ocean. Regional recovery is
supplemented by `TestWorld/Safety/BelowWorldFailsafe`.
The pond surface is at `y=2.10`. The ocean is at `y=-0.45`, between the
authored upper beach and submerged shelf rings. Fishable regions explicitly
provide their surface heights to the shared fishing presentation.
The Fishing Shop remains a complete instanced interactable. The Pelican perch
remains convenience signage only; Pelican selling is available through the
Cooler from anywhere.

View file

@ -1,24 +0,0 @@
@tool
class_name BelowWorldFailsafe
extends PlayerWaterTrigger
@export_group("Failsafe Authoring")
## Saved coverage volume that catches players below the playable world.
@export_node_path("CollisionShape3D")
var coverage_shape_path: NodePath = ^"Coverage"
func _ready() -> void:
super()
if Engine.is_editor_hint():
update_configuration_warnings()
func _get_configuration_warnings() -> PackedStringArray:
var warnings := PackedStringArray()
var coverage := get_node_or_null(coverage_shape_path) as CollisionShape3D
if coverage == null:
warnings.append("Add the saved Coverage collision shape.")
elif coverage.shape == null:
warnings.append("Assign a shape to the failsafe Coverage node.")
return warnings

View file

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

View file

@ -1,38 +1,9 @@
@tool
class_name FishableWaterRegion
extends Area3D
const FishPoolType = preload("res://fish/fish_pool.gd")
enum SurfaceHeightMode {
EXPLICIT,
PARENT_GLOBAL_Y,
}
@export var location_tags: Array[StringName] = []
@export var fish_pool: FishPoolType
@export var selection_priority: int = 0
@export_group("Surface")
@export var surface_height_mode: SurfaceHeightMode = SurfaceHeightMode.EXPLICIT:
set(value):
surface_height_mode = value
if Engine.is_editor_hint():
notify_property_list_changed()
## Legacy explicit height used when Surface Height Mode is Explicit.
@export var surface_height: float = 0.3
func get_surface_height() -> float:
if surface_height_mode == SurfaceHeightMode.PARENT_GLOBAL_Y:
var surface_owner := get_parent() as Node3D
if surface_owner != null:
return surface_owner.global_position.y
return surface_height
func _validate_property(property: Dictionary) -> void:
if (
property.name == "surface_height"
and surface_height_mode == SurfaceHeightMode.PARENT_GLOBAL_Y
):
property.usage = int(property.usage) & ~PROPERTY_USAGE_EDITOR

View file

@ -1,78 +1,64 @@
[gd_scene load_steps=11 format=3]
[gd_scene load_steps=10 format=3]
[ext_resource type="Script" path="res://world/fishing_shop_interaction.gd" id="1_shop"]
[ext_resource type="Script" path="res://world/world_prop.gd" id="2_prop"]
[sub_resource type="BoxMesh" id="CounterMesh"]
resource_local_to_scene = true
size = Vector3(4.2, 1.25, 1.8)
[sub_resource type="BoxMesh" id="RoofMesh"]
resource_local_to_scene = true
size = Vector3(5.2, 0.35, 3.2)
[sub_resource type="BoxMesh" id="PostMesh"]
resource_local_to_scene = true
size = Vector3(0.28, 3.2, 0.28)
[sub_resource type="BoxMesh" id="BackMesh"]
resource_local_to_scene = true
size = Vector3(5, 2.8, 0.25)
[sub_resource type="StandardMaterial3D" id="PrimaryMaterial"]
resource_local_to_scene = true
albedo_color = Color(0.12, 0.68, 0.62, 1)
[sub_resource type="StandardMaterial3D" id="AccentMaterial"]
resource_local_to_scene = true
albedo_color = Color(1, 0.68, 0.18, 1)
[sub_resource type="StandardMaterial3D" id="BackMaterial"]
resource_local_to_scene = true
albedo_color = Color(0.13, 0.34, 0.38, 1)
[sub_resource type="SphereShape3D" id="InteractionShape"]
resource_local_to_scene = true
radius = 3.0
[sub_resource type="BoxShape3D" id="CounterShape"]
resource_local_to_scene = true
size = Vector3(4.2, 1.25, 1.8)
[node name="FishingShopWorld" type="Node3D"]
script = ExtResource("2_prop")
collision_root_path = NodePath("Collision")
interaction_area_path = NodePath("InteractionArea")
entrance_marker_path = NodePath("EntranceMarker")
[node name="Visual" type="Node3D" parent="."]
[node name="Visuals" type="Node3D" parent="."]
[node name="Counter" type="MeshInstance3D" parent="Visual"]
[node name="Counter" type="MeshInstance3D" parent="Visuals"]
position = Vector3(0, 0.625, 0)
mesh = SubResource("CounterMesh")
material_override = SubResource("PrimaryMaterial")
[node name="Back" type="MeshInstance3D" parent="Visual"]
[node name="Back" type="MeshInstance3D" parent="Visuals"]
position = Vector3(0, 1.4, 1.25)
mesh = SubResource("BackMesh")
material_override = SubResource("BackMaterial")
[node name="Roof" type="MeshInstance3D" parent="Visual"]
[node name="Roof" type="MeshInstance3D" parent="Visuals"]
position = Vector3(0, 3.15, 0.35)
mesh = SubResource("RoofMesh")
material_override = SubResource("AccentMaterial")
[node name="WestPost" type="MeshInstance3D" parent="Visual"]
[node name="WestPost" type="MeshInstance3D" parent="Visuals"]
position = Vector3(-2.15, 1.6, -0.8)
mesh = SubResource("PostMesh")
material_override = SubResource("PrimaryMaterial")
[node name="EastPost" type="MeshInstance3D" parent="Visual"]
[node name="EastPost" type="MeshInstance3D" parent="Visuals"]
position = Vector3(2.15, 1.6, -0.8)
mesh = SubResource("PostMesh")
material_override = SubResource("PrimaryMaterial")
[node name="ShopName" type="Label3D" parent="Visual"]
[node name="ShopName" type="Label3D" parent="Visuals"]
position = Vector3(0, 3.7, 0)
text = "fishing shop"
font_size = 42
@ -80,21 +66,18 @@ outline_size = 9
billboard = 1
no_depth_test = true
[node name="Collision" type="StaticBody3D" parent="."]
[node name="StaticCollision" type="StaticBody3D" parent="."]
[node name="CounterShape" type="CollisionShape3D" parent="Collision"]
[node name="CounterShape" type="CollisionShape3D" parent="StaticCollision"]
position = Vector3(0, 0.625, 0)
shape = SubResource("CounterShape")
[node name="InteractionArea" type="Area3D" parent="."]
[node name="FishingShopInteraction" type="Area3D" parent="."]
unique_name_in_owner = true
position = Vector3(0, 1, -0.3)
collision_layer = 0
collision_mask = 2
script = ExtResource("1_shop")
[node name="InteractionShape" type="CollisionShape3D" parent="InteractionArea"]
[node name="CollisionShape3D" type="CollisionShape3D" parent="FishingShopInteraction"]
shape = SubResource("InteractionShape")
[node name="EntranceMarker" type="Marker3D" parent="."]
position = Vector3(0, 0, -2)

View file

@ -1,46 +1,39 @@
[gd_scene load_steps=6 format=3]
[ext_resource type="Script" path="res://world/world_prop.gd" id="1_prop"]
[gd_scene load_steps=5 format=3]
[sub_resource type="BoxMesh" id="PerchMesh"]
resource_local_to_scene = true
size = Vector3(5, 0.7, 2.2)
[sub_resource type="CylinderMesh" id="PostMesh"]
resource_local_to_scene = true
top_radius = 0.18
bottom_radius = 0.24
height = 2.5
[sub_resource type="StandardMaterial3D" id="WoodMaterial"]
resource_local_to_scene = true
albedo_color = Color(0.46, 0.28, 0.13, 1)
[sub_resource type="StandardMaterial3D" id="SignMaterial"]
resource_local_to_scene = true
albedo_color = Color(0.95, 0.82, 0.42, 1)
[node name="PelicanCoolerPerch" type="Node3D"]
script = ExtResource("1_prop")
[node name="Visual" type="Node3D" parent="."]
[node name="Visuals" type="Node3D" parent="."]
[node name="Perch" type="MeshInstance3D" parent="Visual"]
[node name="Perch" type="MeshInstance3D" parent="Visuals"]
position = Vector3(0, 1.65, 0)
mesh = SubResource("PerchMesh")
material_override = SubResource("WoodMaterial")
[node name="WestPost" type="MeshInstance3D" parent="Visual"]
[node name="WestPost" type="MeshInstance3D" parent="Visuals"]
position = Vector3(-1.8, 0.7, 0)
mesh = SubResource("PostMesh")
material_override = SubResource("WoodMaterial")
[node name="EastPost" type="MeshInstance3D" parent="Visual"]
[node name="EastPost" type="MeshInstance3D" parent="Visuals"]
position = Vector3(1.8, 0.7, 0)
mesh = SubResource("PostMesh")
material_override = SubResource("WoodMaterial")
[node name="Sign" type="Label3D" parent="Visual"]
[node name="Sign" type="Label3D" parent="Visuals"]
position = Vector3(0, 2.55, 0)
text = "sell to pelicans\nfrom the cooler"
font_size = 30
@ -48,7 +41,7 @@ outline_size = 8
billboard = 1
no_depth_test = true
[node name="ConvenienceLabel" type="Label3D" parent="Visual"]
[node name="ConvenienceLabel" type="Label3D" parent="Visuals"]
position = Vector3(0, 1.65, -1.15)
text = "available anywhere • 0.25x"
font_size = 20

View file

@ -1,10 +0,0 @@
[gd_resource type="StandardMaterial3D" load_steps=2 format=3]
[ext_resource type="Texture2D" path="res://art/exported/environment/textures/grass_olive_tile.png" id="1_texture"]
[resource]
resource_name = "Starter Island Grass"
texture_filter = 4
albedo_texture = ExtResource("1_texture")
roughness = 1.0
uv1_scale = Vector3(21.406, 21.406, 21.406)

View file

@ -1,24 +1,9 @@
@tool
class_name PlayerWaterTrigger
extends Area3D
signal recovery_requested(player: Player, surface_height: float)
enum SurfaceHeightMode {
EXPLICIT,
PARENT_GLOBAL_Y,
}
@export_group("Surface")
@export var surface_height_mode: SurfaceHeightMode = SurfaceHeightMode.EXPLICIT:
set(value):
surface_height_mode = value
if Engine.is_editor_hint():
notify_property_list_changed()
## Legacy explicit height used when Surface Height Mode is Explicit.
@export var surface_height: float = 0.2
@export_group("Recovery Trigger")
## Recovery begins when the player's body center reaches this depth.
@export_range(0.0, 2.0, 0.05) var entry_depth_threshold: float = 0.35
var _tracked_players: Array[Player] = []
@ -26,15 +11,11 @@ var _triggered_players: Dictionary[StringName, bool] = {}
func _ready() -> void:
if Engine.is_editor_hint():
set_physics_process(false)
return
body_entered.connect(_on_body_entered)
body_exited.connect(_on_body_exited)
func _physics_process(_delta: float) -> void:
var active_surface_height: float = get_surface_height()
for player: Player in _tracked_players.duplicate():
if not is_instance_valid(player):
_tracked_players.erase(player)
@ -44,26 +25,10 @@ func _physics_process(_delta: float) -> void:
continue
if (
player.get_body_center_position().y
<= active_surface_height - entry_depth_threshold
<= surface_height - entry_depth_threshold
):
_triggered_players[player_key] = true
recovery_requested.emit(player, active_surface_height)
func get_surface_height() -> float:
if surface_height_mode == SurfaceHeightMode.PARENT_GLOBAL_Y:
var surface_owner := get_parent() as Node3D
if surface_owner != null:
return surface_owner.global_position.y
return surface_height
func _validate_property(property: Dictionary) -> void:
if (
property.name == "surface_height"
and surface_height_mode == SurfaceHeightMode.PARENT_GLOBAL_Y
):
property.usage = int(property.usage) & ~PROPERTY_USAGE_EDITOR
recovery_requested.emit(player, surface_height)
func _on_body_entered(body: Node3D) -> void:

View file

@ -0,0 +1,140 @@
[gd_scene load_steps=21 format=3]
[ext_resource type="Script" path="res://world/regions/graybox_region.gd" id="1_region"]
[ext_resource type="Script" path="res://world/fishable_water_region.gd" id="2_water"]
[ext_resource type="Resource" path="res://fish/pools/test_water_pool.tres" id="3_pool"]
[ext_resource type="Script" path="res://world/player_water_trigger.gd" id="4_trigger"]
[ext_resource type="Script" path="res://world/safe_respawn_point.gd" id="5_safe"]
[sub_resource type="BoxShape3D" id="ShoreShape"]
size = Vector3(90, 6, 18)
[sub_resource type="BoxMesh" id="ShoreMesh"]
size = Vector3(90, 6, 18)
[sub_resource type="BoxShape3D" id="DockShape"]
size = Vector3(7, 0.4, 25)
[sub_resource type="BoxMesh" id="DockMesh"]
size = Vector3(7, 0.4, 25)
[sub_resource type="BoxShape3D" id="DockRampShape"]
size = Vector3(7, 0.35, 4)
[sub_resource type="BoxMesh" id="DockRampMesh"]
size = Vector3(7, 0.35, 4)
[sub_resource type="CylinderMesh" id="TowerMesh"]
top_radius = 2.4
bottom_radius = 3.4
height = 13
[sub_resource type="CylinderMesh" id="BeaconMesh"]
top_radius = 1.4
bottom_radius = 1.4
height = 2.5
[sub_resource type="BoxMesh" id="CraneArmMesh"]
size = Vector3(1, 1, 10)
[sub_resource type="PlaneMesh" id="WaterMesh"]
size = Vector2(90, 54)
[sub_resource type="BoxShape3D" id="WaterShape"]
size = Vector3(90, 0.2, 54)
[sub_resource type="BoxShape3D" id="RecoveryShape"]
size = Vector3(90, 5, 54)
[sub_resource type="StandardMaterial3D" id="ShoreMaterial"]
albedo_color = Color(0.7, 0.66, 0.5, 1)
[sub_resource type="StandardMaterial3D" id="DockMaterial"]
albedo_color = Color(0.58, 0.4, 0.2, 1)
[sub_resource type="StandardMaterial3D" id="TowerMaterial"]
albedo_color = Color(0.92, 0.9, 0.76, 1)
[sub_resource type="StandardMaterial3D" id="BeaconMaterial"]
albedo_color = Color(0.95, 0.28, 0.22, 1)
[sub_resource type="StandardMaterial3D" id="WaterMaterial"]
transparency = 1
albedo_color = Color(0.04, 0.3, 0.62, 0.84)
[node name="CoastalDockRegion" type="Node3D"]
script = ExtResource("1_region")
region_id = &"coast"
[node name="Visuals" type="Node3D" parent="."]
[node name="Shore" type="MeshInstance3D" parent="Visuals"]
position = Vector3(0, -3, 22)
mesh = SubResource("ShoreMesh")
material_override = SubResource("ShoreMaterial")
[node name="Ocean" type="MeshInstance3D" parent="Visuals"]
position = Vector3(0, 0.2, -14)
mesh = SubResource("WaterMesh")
material_override = SubResource("WaterMaterial")
[node name="MainDock" type="MeshInstance3D" parent="Visuals"]
position = Vector3(0, 0.45, -3.5)
mesh = SubResource("DockMesh")
material_override = SubResource("DockMaterial")
[node name="DockApproachRamp" type="MeshInstance3D" parent="Visuals"]
position = Vector3(0, 0.155, 11)
rotation_degrees = Vector3(9, 0, 0)
mesh = SubResource("DockRampMesh")
material_override = SubResource("DockMaterial")
[node name="Lighthouse" type="MeshInstance3D" parent="Visuals"]
position = Vector3(-32, 6.5, 20)
mesh = SubResource("TowerMesh")
material_override = SubResource("TowerMaterial")
[node name="Beacon" type="MeshInstance3D" parent="Visuals"]
position = Vector3(-32, 14, 20)
mesh = SubResource("BeaconMesh")
material_override = SubResource("BeaconMaterial")
[node name="CraneArm" type="MeshInstance3D" parent="Visuals"]
position = Vector3(17, 5, 19)
rotation_degrees = Vector3(0, 0, 60)
mesh = SubResource("CraneArmMesh")
material_override = SubResource("BeaconMaterial")
[node name="CoastLabel" type="Label3D" parent="Visuals"]
position = Vector3(25, 3.2, 23)
text = "coast"
font_size = 38
outline_size = 8
billboard = 1
no_depth_test = true
[node name="StaticCollision" type="Node3D" parent="."]
[node name="Shore" type="StaticBody3D" parent="StaticCollision"]
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/Shore"]
position = Vector3(0, -3, 22)
shape = SubResource("ShoreShape")
[node name="MainDock" type="StaticBody3D" parent="StaticCollision"]
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/MainDock"]
position = Vector3(0, 0.45, -3.5)
shape = SubResource("DockShape")
[node name="DockApproachRamp" type="StaticBody3D" parent="StaticCollision"]
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/DockApproachRamp"]
position = Vector3(0, 0.155, 11)
rotation_degrees = Vector3(9, 0, 0)
shape = SubResource("DockRampShape")
[node name="FishingWater" type="Node3D" parent="."]
[node name="CoastalWater" type="Area3D" parent="FishingWater"]
position = Vector3(0, 0.2, -14)
collision_layer = 4
collision_mask = 0
monitoring = false
script = ExtResource("2_water")
location_tags = Array[StringName]([&"coast"])
fish_pool = ExtResource("3_pool")
[node name="Shape" type="CollisionShape3D" parent="FishingWater/CoastalWater"]
shape = SubResource("WaterShape")
[node name="WaterRecovery" type="Node3D" parent="."]
[node name="CoastalRecovery" type="Area3D" parent="WaterRecovery"]
position = Vector3(0, -2.3, -14)
collision_layer = 8
collision_mask = 2
script = ExtResource("4_trigger")
surface_height = 0.2
[node name="Shape" type="CollisionShape3D" parent="WaterRecovery/CoastalRecovery"]
shape = SubResource("RecoveryShape")
[node name="SafeRespawns" type="Node3D" parent="."]
[node name="DockApproach" type="Marker3D" parent="SafeRespawns"]
position = Vector3(8, 0.58, 23)
rotation_degrees = Vector3(0, 180, 0)
script = ExtResource("5_safe")
[node name="DockMidpoint" type="Marker3D" parent="SafeRespawns"]
position = Vector3(0, 1.23, 0)
rotation_degrees = Vector3(0, 180, 0)
script = ExtResource("5_safe")
[node name="LighthouseShore" type="Marker3D" parent="SafeRespawns"]
position = Vector3(-24, 0.58, 24)
rotation_degrees = Vector3(0, -135, 0)
script = ExtResource("5_safe")

View file

@ -1,5 +1,4 @@
@tool
class_name WorldRegion
class_name GrayboxRegion
extends Node3D
@export var region_id: StringName
@ -13,7 +12,10 @@ func get_fishable_water_regions() -> Array[FishableWaterRegion]:
var root: Node = get_node_or_null(fishable_water_root)
if root == null:
return regions
_collect_fishable_water_regions(root, regions)
for child: Node in root.get_children():
var water: FishableWaterRegion = child as FishableWaterRegion
if water != null:
regions.append(water)
return regions
@ -22,7 +24,10 @@ func get_water_recovery_triggers() -> Array[PlayerWaterTrigger]:
var root: Node = get_node_or_null(water_recovery_root)
if root == null:
return triggers
_collect_water_recovery_triggers(root, triggers)
for child: Node in root.get_children():
var trigger: PlayerWaterTrigger = child as PlayerWaterTrigger
if trigger != null:
triggers.append(trigger)
return triggers
@ -36,25 +41,3 @@ func get_safe_respawn_points() -> Array[SafeRespawnPoint]:
if point != null:
points.append(point)
return points
func _collect_fishable_water_regions(
root: Node,
regions: Array[FishableWaterRegion],
) -> void:
for child: Node in root.get_children():
var water := child as FishableWaterRegion
if water != null:
regions.append(water)
_collect_fishable_water_regions(child, regions)
func _collect_water_recovery_triggers(
root: Node,
triggers: Array[PlayerWaterTrigger],
) -> void:
for child: Node in root.get_children():
var trigger := child as PlayerWaterTrigger
if trigger != null:
triggers.append(trigger)
_collect_water_recovery_triggers(child, triggers)

View file

@ -0,0 +1,141 @@
[gd_scene load_steps=17 format=3]
[ext_resource type="Script" path="res://world/regions/graybox_region.gd" id="1_region"]
[ext_resource type="Script" path="res://world/fishable_water_region.gd" id="2_water"]
[ext_resource type="Resource" path="res://fish/pools/test_water_pool.tres" id="3_pool"]
[ext_resource type="Script" path="res://world/player_water_trigger.gd" id="4_trigger"]
[ext_resource type="Script" path="res://world/safe_respawn_point.gd" id="5_safe"]
[sub_resource type="BoxShape3D" id="BankNSShape"]
size = Vector3(58, 6, 10)
[sub_resource type="BoxShape3D" id="BankEWShape"]
size = Vector3(8, 6, 36)
[sub_resource type="BoxMesh" id="BankNSMesh"]
size = Vector3(58, 6, 10)
[sub_resource type="BoxMesh" id="BankEWMesh"]
size = Vector3(8, 6, 36)
[sub_resource type="BoxShape3D" id="DockShape"]
size = Vector3(10, 0.4, 7)
[sub_resource type="BoxMesh" id="DockMesh"]
size = Vector3(10, 0.4, 7)
[sub_resource type="BoxShape3D" id="DockRampShape"]
size = Vector3(4, 0.35, 7)
[sub_resource type="BoxMesh" id="DockRampMesh"]
size = Vector3(4, 0.35, 7)
[sub_resource type="PlaneMesh" id="WaterMesh"]
size = Vector2(42, 36)
[sub_resource type="BoxShape3D" id="WaterShape"]
size = Vector3(42, 0.2, 36)
[sub_resource type="BoxShape3D" id="RecoveryShape"]
size = Vector3(42, 5, 36)
[sub_resource type="StandardMaterial3D" id="GrassMaterial"]
albedo_color = Color(0.34, 0.65, 0.3, 1)
[sub_resource type="StandardMaterial3D" id="DockMaterial"]
albedo_color = Color(0.55, 0.34, 0.16, 1)
[sub_resource type="StandardMaterial3D" id="WaterMaterial"]
transparency = 1
albedo_color = Color(0.08, 0.43, 0.75, 0.82)
[node name="LakeRegion" type="Node3D"]
script = ExtResource("1_region")
region_id = &"lake"
[node name="Visuals" type="Node3D" parent="."]
[node name="NorthBank" type="MeshInstance3D" parent="Visuals"]
position = Vector3(0, -3, 23)
mesh = SubResource("BankNSMesh")
material_override = SubResource("GrassMaterial")
[node name="SouthBank" type="MeshInstance3D" parent="Visuals"]
position = Vector3(0, -3, -23)
mesh = SubResource("BankNSMesh")
material_override = SubResource("GrassMaterial")
[node name="WestBank" type="MeshInstance3D" parent="Visuals"]
position = Vector3(-25, -3, 0)
mesh = SubResource("BankEWMesh")
material_override = SubResource("GrassMaterial")
[node name="EastBank" type="MeshInstance3D" parent="Visuals"]
position = Vector3(25, -3, 0)
mesh = SubResource("BankEWMesh")
material_override = SubResource("GrassMaterial")
[node name="Water" type="MeshInstance3D" parent="Visuals"]
position = Vector3(0, 0.2, 0)
mesh = SubResource("WaterMesh")
material_override = SubResource("WaterMaterial")
[node name="WestDock" type="MeshInstance3D" parent="Visuals"]
position = Vector3(-12, 0.45, 0)
mesh = SubResource("DockMesh")
material_override = SubResource("DockMaterial")
[node name="WestDockRamp" type="MeshInstance3D" parent="Visuals"]
position = Vector3(-19, 0.155, 0)
rotation_degrees = Vector3(0, 0, 9)
mesh = SubResource("DockRampMesh")
material_override = SubResource("DockMaterial")
[node name="LakeLabel" type="Label3D" parent="Visuals"]
position = Vector3(-25, 3, 20)
text = "lake"
font_size = 38
outline_size = 8
billboard = 1
no_depth_test = true
[node name="StaticCollision" type="Node3D" parent="."]
[node name="NorthBank" type="StaticBody3D" parent="StaticCollision"]
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/NorthBank"]
position = Vector3(0, -3, 23)
shape = SubResource("BankNSShape")
[node name="SouthBank" type="StaticBody3D" parent="StaticCollision"]
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/SouthBank"]
position = Vector3(0, -3, -23)
shape = SubResource("BankNSShape")
[node name="WestBank" type="StaticBody3D" parent="StaticCollision"]
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/WestBank"]
position = Vector3(-25, -3, 0)
shape = SubResource("BankEWShape")
[node name="EastBank" type="StaticBody3D" parent="StaticCollision"]
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/EastBank"]
position = Vector3(25, -3, 0)
shape = SubResource("BankEWShape")
[node name="WestDock" type="StaticBody3D" parent="StaticCollision"]
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/WestDock"]
position = Vector3(-12, 0.45, 0)
shape = SubResource("DockShape")
[node name="WestDockRamp" type="StaticBody3D" parent="StaticCollision"]
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/WestDockRamp"]
position = Vector3(-19, 0.155, 0)
rotation_degrees = Vector3(0, 0, 9)
shape = SubResource("DockRampShape")
[node name="FishingWater" type="Node3D" parent="."]
[node name="LakeWater" type="Area3D" parent="FishingWater"]
position = Vector3(0, 0.2, 0)
collision_layer = 4
collision_mask = 0
monitoring = false
script = ExtResource("2_water")
location_tags = Array[StringName]([&"lake"])
fish_pool = ExtResource("3_pool")
[node name="Shape" type="CollisionShape3D" parent="FishingWater/LakeWater"]
shape = SubResource("WaterShape")
[node name="WaterRecovery" type="Node3D" parent="."]
[node name="LakeRecovery" type="Area3D" parent="WaterRecovery"]
position = Vector3(0, -2.3, 0)
collision_layer = 8
collision_mask = 2
script = ExtResource("4_trigger")
surface_height = 0.2
[node name="Shape" type="CollisionShape3D" parent="WaterRecovery/LakeRecovery"]
shape = SubResource("RecoveryShape")
[node name="SafeRespawns" type="Node3D" parent="."]
[node name="WestDockApproach" type="Marker3D" parent="SafeRespawns"]
position = Vector3(-25, 0.58, 8)
rotation_degrees = Vector3(0, -90, 0)
script = ExtResource("5_safe")
[node name="NorthShore" type="Marker3D" parent="SafeRespawns"]
position = Vector3(0, 0.58, 24)
rotation_degrees = Vector3(0, 180, 0)
script = ExtResource("5_safe")
[node name="SouthEastShore" type="Marker3D" parent="SafeRespawns"]
position = Vector3(25, 0.58, -23)
rotation_degrees = Vector3(0, 45, 0)
script = ExtResource("5_safe")

View file

@ -0,0 +1,164 @@
[gd_scene load_steps=20 format=3]
[ext_resource type="Script" path="res://world/regions/graybox_region.gd" id="1_region"]
[ext_resource type="Script" path="res://world/fishable_water_region.gd" id="2_water"]
[ext_resource type="Resource" path="res://fish/pools/test_water_pool.tres" id="3_pool"]
[ext_resource type="Script" path="res://world/player_water_trigger.gd" id="4_trigger"]
[ext_resource type="Script" path="res://world/safe_respawn_point.gd" id="5_safe"]
[sub_resource type="BoxShape3D" id="BankNSShape"]
size = Vector3(50, 6, 8)
[sub_resource type="BoxShape3D" id="BankEWShape"]
size = Vector3(8, 6, 30)
[sub_resource type="BoxMesh" id="BankNSMesh"]
size = Vector3(50, 6, 8)
[sub_resource type="BoxMesh" id="BankEWMesh"]
size = Vector3(8, 6, 30)
[sub_resource type="BoxShape3D" id="BoardwalkShape"]
size = Vector3(6, 0.4, 22)
[sub_resource type="BoxMesh" id="BoardwalkMesh"]
size = Vector3(6, 0.4, 22)
[sub_resource type="BoxShape3D" id="BoardwalkRampShape"]
size = Vector3(6, 0.35, 4)
[sub_resource type="BoxMesh" id="BoardwalkRampMesh"]
size = Vector3(6, 0.35, 4)
[sub_resource type="CylinderMesh" id="ReedMesh"]
top_radius = 0.06
bottom_radius = 0.1
height = 2.2
[sub_resource type="PlaneMesh" id="WaterMesh"]
size = Vector2(38, 30)
[sub_resource type="BoxShape3D" id="WaterShape"]
size = Vector3(38, 0.2, 30)
[sub_resource type="BoxShape3D" id="RecoveryShape"]
size = Vector3(38, 5, 30)
[sub_resource type="StandardMaterial3D" id="BankMaterial"]
albedo_color = Color(0.38, 0.53, 0.27, 1)
[sub_resource type="StandardMaterial3D" id="BoardwalkMaterial"]
albedo_color = Color(0.48, 0.32, 0.18, 1)
[sub_resource type="StandardMaterial3D" id="ReedMaterial"]
albedo_color = Color(0.59, 0.67, 0.2, 1)
[sub_resource type="StandardMaterial3D" id="WaterMaterial"]
transparency = 1
albedo_color = Color(0.1, 0.48, 0.48, 0.8)
[node name="MarshRegion" type="Node3D"]
script = ExtResource("1_region")
region_id = &"marsh"
[node name="Visuals" type="Node3D" parent="."]
[node name="NorthBank" type="MeshInstance3D" parent="Visuals"]
position = Vector3(0, -3, 19)
mesh = SubResource("BankNSMesh")
material_override = SubResource("BankMaterial")
[node name="SouthBank" type="MeshInstance3D" parent="Visuals"]
position = Vector3(0, -3, -19)
mesh = SubResource("BankNSMesh")
material_override = SubResource("BankMaterial")
[node name="WestBank" type="MeshInstance3D" parent="Visuals"]
position = Vector3(-23, -3, 0)
mesh = SubResource("BankEWMesh")
material_override = SubResource("BankMaterial")
[node name="EastBank" type="MeshInstance3D" parent="Visuals"]
position = Vector3(23, -3, 0)
mesh = SubResource("BankEWMesh")
material_override = SubResource("BankMaterial")
[node name="Water" type="MeshInstance3D" parent="Visuals"]
position = Vector3(0, 0.2, 0)
mesh = SubResource("WaterMesh")
material_override = SubResource("WaterMaterial")
[node name="Boardwalk" type="MeshInstance3D" parent="Visuals"]
position = Vector3(0, 0.45, 0)
mesh = SubResource("BoardwalkMesh")
material_override = SubResource("BoardwalkMaterial")
[node name="BoardwalkNorthRamp" type="MeshInstance3D" parent="Visuals"]
position = Vector3(0, 0.155, 13)
rotation_degrees = Vector3(9, 0, 0)
mesh = SubResource("BoardwalkRampMesh")
material_override = SubResource("BoardwalkMaterial")
[node name="BoardwalkSouthRamp" type="MeshInstance3D" parent="Visuals"]
position = Vector3(0, 0.155, -13)
rotation_degrees = Vector3(-9, 0, 0)
mesh = SubResource("BoardwalkRampMesh")
material_override = SubResource("BoardwalkMaterial")
[node name="ReedWest" type="MeshInstance3D" parent="Visuals"]
position = Vector3(-13, 1.1, -8)
mesh = SubResource("ReedMesh")
material_override = SubResource("ReedMaterial")
[node name="ReedEast" type="MeshInstance3D" parent="Visuals"]
position = Vector3(12, 1.1, 7)
mesh = SubResource("ReedMesh")
material_override = SubResource("ReedMaterial")
[node name="MarshLabel" type="Label3D" parent="Visuals"]
position = Vector3(21, 3, 17)
text = "marsh"
font_size = 36
outline_size = 8
billboard = 1
no_depth_test = true
[node name="StaticCollision" type="Node3D" parent="."]
[node name="NorthBank" type="StaticBody3D" parent="StaticCollision"]
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/NorthBank"]
position = Vector3(0, -3, 19)
shape = SubResource("BankNSShape")
[node name="SouthBank" type="StaticBody3D" parent="StaticCollision"]
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/SouthBank"]
position = Vector3(0, -3, -19)
shape = SubResource("BankNSShape")
[node name="WestBank" type="StaticBody3D" parent="StaticCollision"]
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/WestBank"]
position = Vector3(-23, -3, 0)
shape = SubResource("BankEWShape")
[node name="EastBank" type="StaticBody3D" parent="StaticCollision"]
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/EastBank"]
position = Vector3(23, -3, 0)
shape = SubResource("BankEWShape")
[node name="Boardwalk" type="StaticBody3D" parent="StaticCollision"]
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/Boardwalk"]
position = Vector3(0, 0.45, 0)
shape = SubResource("BoardwalkShape")
[node name="BoardwalkNorthRamp" type="StaticBody3D" parent="StaticCollision"]
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/BoardwalkNorthRamp"]
position = Vector3(0, 0.155, 13)
rotation_degrees = Vector3(9, 0, 0)
shape = SubResource("BoardwalkRampShape")
[node name="BoardwalkSouthRamp" type="StaticBody3D" parent="StaticCollision"]
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/BoardwalkSouthRamp"]
position = Vector3(0, 0.155, -13)
rotation_degrees = Vector3(-9, 0, 0)
shape = SubResource("BoardwalkRampShape")
[node name="FishingWater" type="Node3D" parent="."]
[node name="MarshWater" type="Area3D" parent="FishingWater"]
position = Vector3(0, 0.2, 0)
collision_layer = 4
collision_mask = 0
monitoring = false
script = ExtResource("2_water")
location_tags = Array[StringName]([&"marsh"])
fish_pool = ExtResource("3_pool")
[node name="Shape" type="CollisionShape3D" parent="FishingWater/MarshWater"]
shape = SubResource("WaterShape")
[node name="WaterRecovery" type="Node3D" parent="."]
[node name="MarshRecovery" type="Area3D" parent="WaterRecovery"]
position = Vector3(0, -2.3, 0)
collision_layer = 8
collision_mask = 2
script = ExtResource("4_trigger")
surface_height = 0.2
[node name="Shape" type="CollisionShape3D" parent="WaterRecovery/MarshRecovery"]
shape = SubResource("RecoveryShape")
[node name="SafeRespawns" type="Node3D" parent="."]
[node name="BoardwalkNorth" type="Marker3D" parent="SafeRespawns"]
position = Vector3(8, 0.58, 19)
rotation_degrees = Vector3(0, 180, 0)
script = ExtResource("5_safe")
[node name="BoardwalkSouth" type="Marker3D" parent="SafeRespawns"]
position = Vector3(-8, 0.58, -19)
script = ExtResource("5_safe")
[node name="EastBank" type="Marker3D" parent="SafeRespawns"]
position = Vector3(23, 0.58, 7)
rotation_degrees = Vector3(0, 90, 0)
script = ExtResource("5_safe")

View file

@ -0,0 +1,143 @@
[gd_scene load_steps=19 format=3]
[ext_resource type="Script" path="res://world/regions/graybox_region.gd" id="1_region"]
[ext_resource type="Script" path="res://world/fishable_water_region.gd" id="2_water"]
[ext_resource type="Resource" path="res://fish/pools/test_water_pool.tres" id="3_pool"]
[ext_resource type="Script" path="res://world/player_water_trigger.gd" id="4_trigger"]
[ext_resource type="Script" path="res://world/safe_respawn_point.gd" id="5_safe"]
[sub_resource type="BoxShape3D" id="BankShape"]
size = Vector3(13, 6, 61)
[sub_resource type="BoxMesh" id="BankMesh"]
size = Vector3(13, 6, 61)
[sub_resource type="BoxShape3D" id="BridgeShape"]
size = Vector3(6, 0.4, 7)
[sub_resource type="BoxMesh" id="BridgeMesh"]
size = Vector3(6, 0.4, 7)
[sub_resource type="BoxShape3D" id="BridgeRampShape"]
size = Vector3(4, 0.35, 7)
[sub_resource type="BoxMesh" id="BridgeRampMesh"]
size = Vector3(4, 0.35, 7)
[sub_resource type="BoxMesh" id="RailMesh"]
size = Vector3(14, 0.25, 0.25)
[sub_resource type="PlaneMesh" id="WaterMesh"]
size = Vector2(14, 58)
[sub_resource type="BoxShape3D" id="WaterShape"]
size = Vector3(14, 0.2, 58)
[sub_resource type="BoxShape3D" id="RecoveryShape"]
size = Vector3(14, 5, 58)
[sub_resource type="StandardMaterial3D" id="BankMaterial"]
albedo_color = Color(0.31, 0.61, 0.37, 1)
[sub_resource type="StandardMaterial3D" id="BridgeMaterial"]
albedo_color = Color(0.58, 0.58, 0.54, 1)
[sub_resource type="StandardMaterial3D" id="RailMaterial"]
albedo_color = Color(0.3, 0.32, 0.34, 1)
[sub_resource type="StandardMaterial3D" id="WaterMaterial"]
transparency = 1
albedo_color = Color(0.12, 0.48, 0.72, 0.8)
[node name="RiverRegion" type="Node3D"]
script = ExtResource("1_region")
region_id = &"river"
[node name="Visuals" type="Node3D" parent="."]
[node name="WestBank" type="MeshInstance3D" parent="Visuals"]
position = Vector3(-13.5, -3, -1.5)
mesh = SubResource("BankMesh")
material_override = SubResource("BankMaterial")
[node name="EastBank" type="MeshInstance3D" parent="Visuals"]
position = Vector3(13.5, -3, -1.5)
mesh = SubResource("BankMesh")
material_override = SubResource("BankMaterial")
[node name="Water" type="MeshInstance3D" parent="Visuals"]
position = Vector3(0, 0.2, 0)
mesh = SubResource("WaterMesh")
material_override = SubResource("WaterMaterial")
[node name="Bridge" type="MeshInstance3D" parent="Visuals"]
position = Vector3(0, 0.45, 7)
mesh = SubResource("BridgeMesh")
material_override = SubResource("BridgeMaterial")
[node name="WestBridgeRamp" type="MeshInstance3D" parent="Visuals"]
position = Vector3(-5, 0.155, 7)
rotation_degrees = Vector3(0, 0, 9)
mesh = SubResource("BridgeRampMesh")
material_override = SubResource("BridgeMaterial")
[node name="EastBridgeRamp" type="MeshInstance3D" parent="Visuals"]
position = Vector3(5, 0.155, 7)
rotation_degrees = Vector3(0, 0, -9)
mesh = SubResource("BridgeRampMesh")
material_override = SubResource("BridgeMaterial")
[node name="NorthRail" type="MeshInstance3D" parent="Visuals"]
position = Vector3(0, 1.15, 10.2)
mesh = SubResource("RailMesh")
material_override = SubResource("RailMaterial")
[node name="SouthRail" type="MeshInstance3D" parent="Visuals"]
position = Vector3(0, 1.15, 3.8)
mesh = SubResource("RailMesh")
material_override = SubResource("RailMaterial")
[node name="RiverLabel" type="Label3D" parent="Visuals"]
position = Vector3(-16, 3, 20)
text = "river"
font_size = 34
outline_size = 7
billboard = 1
no_depth_test = true
[node name="StaticCollision" type="Node3D" parent="."]
[node name="WestBank" type="StaticBody3D" parent="StaticCollision"]
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/WestBank"]
position = Vector3(-13.5, -3, -1.5)
shape = SubResource("BankShape")
[node name="EastBank" type="StaticBody3D" parent="StaticCollision"]
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/EastBank"]
position = Vector3(13.5, -3, -1.5)
shape = SubResource("BankShape")
[node name="Bridge" type="StaticBody3D" parent="StaticCollision"]
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/Bridge"]
position = Vector3(0, 0.45, 7)
shape = SubResource("BridgeShape")
[node name="WestBridgeRamp" type="StaticBody3D" parent="StaticCollision"]
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/WestBridgeRamp"]
position = Vector3(-5, 0.155, 7)
rotation_degrees = Vector3(0, 0, 9)
shape = SubResource("BridgeRampShape")
[node name="EastBridgeRamp" type="StaticBody3D" parent="StaticCollision"]
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/EastBridgeRamp"]
position = Vector3(5, 0.155, 7)
rotation_degrees = Vector3(0, 0, -9)
shape = SubResource("BridgeRampShape")
[node name="FishingWater" type="Node3D" parent="."]
[node name="RiverWater" type="Area3D" parent="FishingWater"]
position = Vector3(0, 0.2, 0)
collision_layer = 4
collision_mask = 0
monitoring = false
script = ExtResource("2_water")
location_tags = Array[StringName]([&"river"])
fish_pool = ExtResource("3_pool")
[node name="Shape" type="CollisionShape3D" parent="FishingWater/RiverWater"]
shape = SubResource("WaterShape")
[node name="WaterRecovery" type="Node3D" parent="."]
[node name="RiverRecovery" type="Area3D" parent="WaterRecovery"]
position = Vector3(0, -2.3, 0)
collision_layer = 8
collision_mask = 2
script = ExtResource("4_trigger")
surface_height = 0.2
[node name="Shape" type="CollisionShape3D" parent="WaterRecovery/RiverRecovery"]
shape = SubResource("RecoveryShape")
[node name="SafeRespawns" type="Node3D" parent="."]
[node name="BridgeWest" type="Marker3D" parent="SafeRespawns"]
position = Vector3(-15, 0.58, 14)
rotation_degrees = Vector3(0, -90, 0)
script = ExtResource("5_safe")
[node name="NorthEastBank" type="Marker3D" parent="SafeRespawns"]
position = Vector3(14, 0.58, 24)
rotation_degrees = Vector3(0, 90, 0)
script = ExtResource("5_safe")
[node name="SouthWestBank" type="Marker3D" parent="SafeRespawns"]
position = Vector3(-14, 0.58, -25)
rotation_degrees = Vector3(0, -90, 0)
script = ExtResource("5_safe")

View file

@ -1,41 +1,27 @@
@tool
class_name StarterIslandRegion
extends WorldRegion
extends GrayboxRegion
const FishingShopInteractionType = preload(
"res://world/fishing_shop_interaction.gd"
)
@export_group("Owned Nodes")
@export_node_path("MeshInstance3D")
var visual_mesh_path: NodePath = (
^"Terrain/Visual/starter_island"
@export var visual_mesh_path: NodePath = (
^"Visuals/StarterIslandModel/starter_island"
)
@export_node_path("CollisionShape3D")
var terrain_collision_shape_path: NodePath = (
^"Terrain/Collision/Shape"
@export var terrain_collision_shape_path: NodePath = (
^"StaticCollision/Terrain/Shape"
)
@export_node_path("Marker3D")
var player_spawn_path: NodePath = ^"PlayerSpawn"
@export_node_path("Area3D")
var fishing_shop_path: NodePath = (
^"Interactables/FishingShopWorld/InteractionArea"
@export var player_spawn_path: NodePath = ^"PlayerSpawn"
@export var fishing_shop_path: NodePath = (
^"Interactables/FishingShopWorld/FishingShopInteraction"
)
@export_node_path("Node3D")
var pelican_landmark_path: NodePath = (
@export var pelican_landmark_path: NodePath = (
^"Interactables/PelicanCoolerPerch"
)
@export_group("Grass Surface")
@export var grass_material: Material
@export_range(0, 16, 1) var grass_surface_index: int = 0
func _ready() -> void:
_apply_grass_material()
_build_terrain_collision()
if Engine.is_editor_hint():
update_configuration_warnings()
func get_player_spawn_transform() -> Transform3D:
@ -58,28 +44,6 @@ func has_terrain_collision() -> bool:
return collision_shape != null and collision_shape.shape != null
func _apply_grass_material() -> void:
var visual_mesh: MeshInstance3D = (
get_node_or_null(visual_mesh_path) as MeshInstance3D
)
if visual_mesh == null or visual_mesh.mesh == null:
push_error("Starter island visual mesh is unavailable.")
return
if grass_material == null:
push_error("Starter island grass material is unavailable.")
return
if grass_surface_index >= visual_mesh.mesh.get_surface_count():
push_error("Starter island grass surface index is invalid.")
return
if visual_mesh.mesh.surface_get_name(grass_surface_index) != "grass":
push_error("Starter island grass surface name does not match.")
return
visual_mesh.set_surface_override_material(
grass_surface_index,
grass_material
)
func _build_terrain_collision() -> void:
var visual_mesh: MeshInstance3D = (
get_node_or_null(visual_mesh_path) as MeshInstance3D
@ -100,25 +64,3 @@ func _build_terrain_collision() -> void:
push_error("Starter island terrain collision could not be created.")
return
collision_shape.shape = terrain_shape
func _get_configuration_warnings() -> PackedStringArray:
var warnings := PackedStringArray()
var visual_mesh := get_node_or_null(visual_mesh_path) as MeshInstance3D
if visual_mesh == null or visual_mesh.mesh == null:
warnings.append("Terrain/Visual must provide the island mesh.")
elif grass_surface_index >= visual_mesh.mesh.get_surface_count():
warnings.append("Grass surface index is outside the terrain mesh.")
elif visual_mesh.mesh.surface_get_name(grass_surface_index) != "grass":
warnings.append("Grass surface index must identify the grass surface.")
if grass_material == null:
warnings.append("Assign the starter-island grass material.")
if get_node_or_null(terrain_collision_shape_path) == null:
warnings.append("Terrain/Collision must provide a collision shape.")
if get_node_or_null(player_spawn_path) == null:
warnings.append("PlayerSpawn marker is missing.")
if get_node_or_null(fishing_shop_path) == null:
warnings.append("Fishing Shop placement is missing.")
if get_node_or_null(pelican_landmark_path) == null:
warnings.append("Pelican placement is missing.")
return warnings

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,114 @@
[gd_scene load_steps=14 format=3]
[ext_resource type="Script" path="res://world/regions/graybox_region.gd" id="1_region"]
[ext_resource type="Script" path="res://world/fishable_water_region.gd" id="2_water"]
[ext_resource type="Resource" path="res://fish/pools/test_water_pool.tres" id="3_pool"]
[ext_resource type="Script" path="res://world/player_water_trigger.gd" id="4_trigger"]
[ext_resource type="Script" path="res://world/safe_respawn_point.gd" id="5_safe"]
[sub_resource type="BoxShape3D" id="BankNSShape"]
size = Vector3(36, 6, 8)
[sub_resource type="BoxShape3D" id="BankEWShape"]
size = Vector3(6, 6, 20)
[sub_resource type="BoxMesh" id="BankNSMesh"]
size = Vector3(36, 6, 8)
[sub_resource type="BoxMesh" id="BankEWMesh"]
size = Vector3(6, 6, 20)
[sub_resource type="PlaneMesh" id="WaterMesh"]
size = Vector2(24, 20)
[sub_resource type="BoxShape3D" id="WaterShape"]
size = Vector3(24, 0.2, 20)
[sub_resource type="BoxShape3D" id="RecoveryShape"]
size = Vector3(24, 5, 20)
[sub_resource type="StandardMaterial3D" id="GrassMaterial"]
albedo_color = Color(0.43, 0.75, 0.34, 1)
[sub_resource type="StandardMaterial3D" id="WaterMaterial"]
transparency = 1
albedo_color = Color(0.16, 0.58, 0.78, 0.78)
roughness = 0.25
[node name="StarterPondRegion" type="Node3D"]
script = ExtResource("1_region")
region_id = &"starter_pond"
[node name="Visuals" type="Node3D" parent="."]
[node name="NorthBank" type="MeshInstance3D" parent="Visuals"]
position = Vector3(0, -3, 14)
mesh = SubResource("BankNSMesh")
material_override = SubResource("GrassMaterial")
[node name="SouthBank" type="MeshInstance3D" parent="Visuals"]
position = Vector3(0, -3, -14)
mesh = SubResource("BankNSMesh")
material_override = SubResource("GrassMaterial")
[node name="WestBank" type="MeshInstance3D" parent="Visuals"]
position = Vector3(-15, -3, 0)
mesh = SubResource("BankEWMesh")
material_override = SubResource("GrassMaterial")
[node name="EastBank" type="MeshInstance3D" parent="Visuals"]
position = Vector3(15, -3, 0)
mesh = SubResource("BankEWMesh")
material_override = SubResource("GrassMaterial")
[node name="Water" type="MeshInstance3D" parent="Visuals"]
position = Vector3(0, 0.2, 0)
mesh = SubResource("WaterMesh")
material_override = SubResource("WaterMaterial")
[node name="PondLabel" type="Label3D" parent="Visuals"]
position = Vector3(-14, 2.4, 11)
text = "pond"
font_size = 34
outline_size = 7
billboard = 1
no_depth_test = true
[node name="StaticCollision" type="Node3D" parent="."]
[node name="NorthBank" type="StaticBody3D" parent="StaticCollision"]
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/NorthBank"]
position = Vector3(0, -3, 14)
shape = SubResource("BankNSShape")
[node name="SouthBank" type="StaticBody3D" parent="StaticCollision"]
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/SouthBank"]
position = Vector3(0, -3, -14)
shape = SubResource("BankNSShape")
[node name="WestBank" type="StaticBody3D" parent="StaticCollision"]
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/WestBank"]
position = Vector3(-15, -3, 0)
shape = SubResource("BankEWShape")
[node name="EastBank" type="StaticBody3D" parent="StaticCollision"]
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/EastBank"]
position = Vector3(15, -3, 0)
shape = SubResource("BankEWShape")
[node name="FishingWater" type="Node3D" parent="."]
[node name="StarterPondWater" type="Area3D" parent="FishingWater"]
position = Vector3(0, 0.2, 0)
collision_layer = 4
collision_mask = 0
monitoring = false
script = ExtResource("2_water")
location_tags = Array[StringName]([&"starter_pond"])
fish_pool = ExtResource("3_pool")
[node name="Shape" type="CollisionShape3D" parent="FishingWater/StarterPondWater"]
shape = SubResource("WaterShape")
[node name="WaterRecovery" type="Node3D" parent="."]
[node name="StarterPondRecovery" type="Area3D" parent="WaterRecovery"]
position = Vector3(0, -2.3, 0)
collision_layer = 8
collision_mask = 2
script = ExtResource("4_trigger")
surface_height = 0.2
[node name="Shape" type="CollisionShape3D" parent="WaterRecovery/StarterPondRecovery"]
shape = SubResource("RecoveryShape")
[node name="SafeRespawns" type="Node3D" parent="."]
[node name="EastShore" type="Marker3D" parent="SafeRespawns"]
position = Vector3(15, 0.58, 4)
rotation_degrees = Vector3(0, 90, 0)
script = ExtResource("5_safe")
[node name="NorthShore" type="Marker3D" parent="SafeRespawns"]
position = Vector3(0, 0.58, 14)
rotation_degrees = Vector3(0, 180, 0)
script = ExtResource("5_safe")
[node name="SouthShore" type="Marker3D" parent="SafeRespawns"]
position = Vector3(0, 0.58, -14)
script = ExtResource("5_safe")

View file

@ -0,0 +1,179 @@
[gd_scene load_steps=16 format=3]
[ext_resource type="Script" path="res://world/regions/graybox_region.gd" id="1_region"]
[ext_resource type="Script" path="res://world/safe_respawn_point.gd" id="2_safe"]
[ext_resource type="PackedScene" path="res://world/interactables/fishing_shop_world.tscn" id="3_shop"]
[ext_resource type="PackedScene" path="res://world/interactables/pelican_buyer_world.tscn" id="4_pelican"]
[sub_resource type="BoxShape3D" id="GroundShape"]
size = Vector3(48, 6, 36)
[sub_resource type="BoxShape3D" id="BuildingShape"]
size = Vector3(8, 5, 7)
[sub_resource type="BoxMesh" id="GroundMesh"]
size = Vector3(48, 6, 36)
[sub_resource type="BoxMesh" id="PlazaMesh"]
size = Vector3(22, 0.02, 18)
[sub_resource type="BoxMesh" id="BuildingMesh"]
size = Vector3(8, 5, 7)
[sub_resource type="CylinderMesh" id="RoofMesh"]
top_radius = 0
bottom_radius = 5.5
height = 3
radial_segments = 4
[sub_resource type="CylinderMesh" id="TowerMesh"]
top_radius = 2.4
bottom_radius = 2.4
height = 8
[sub_resource type="CylinderMesh" id="TowerTankMesh"]
top_radius = 3.2
bottom_radius = 3.2
height = 3.2
[sub_resource type="BoxMesh" id="PavilionRoofMesh"]
size = Vector3(9, 0.35, 7)
[sub_resource type="BoxMesh" id="PavilionPostMesh"]
size = Vector3(0.3, 3.2, 0.3)
[sub_resource type="StandardMaterial3D" id="GrassMaterial"]
albedo_color = Color(0.37, 0.68, 0.3, 1)
[sub_resource type="StandardMaterial3D" id="PlazaMaterial"]
albedo_color = Color(0.76, 0.69, 0.54, 1)
[sub_resource type="StandardMaterial3D" id="BuildingMaterial"]
albedo_color = Color(0.92, 0.55, 0.34, 1)
[sub_resource type="StandardMaterial3D" id="RoofMaterial"]
albedo_color = Color(0.2, 0.46, 0.53, 1)
[sub_resource type="StandardMaterial3D" id="LandmarkMaterial"]
albedo_color = Color(0.95, 0.82, 0.28, 1)
[node name="VillageRegion" type="Node3D"]
script = ExtResource("1_region")
region_id = &"village"
[node name="Visuals" type="Node3D" parent="."]
[node name="Ground" type="MeshInstance3D" parent="Visuals"]
position = Vector3(0, -3, 0)
mesh = SubResource("GroundMesh")
material_override = SubResource("GrassMaterial")
[node name="Plaza" type="MeshInstance3D" parent="Visuals"]
position = Vector3(0, 0.011, 0)
mesh = SubResource("PlazaMesh")
material_override = SubResource("PlazaMaterial")
[node name="WestBuilding" type="MeshInstance3D" parent="Visuals"]
position = Vector3(-17, 2.5, 9)
mesh = SubResource("BuildingMesh")
material_override = SubResource("BuildingMaterial")
[node name="WestRoof" type="MeshInstance3D" parent="Visuals"]
position = Vector3(-17, 6.1, 9)
rotation_degrees = Vector3(0, 45, 0)
mesh = SubResource("RoofMesh")
material_override = SubResource("RoofMaterial")
[node name="NorthBuilding" type="MeshInstance3D" parent="Visuals"]
position = Vector3(-7, 2.5, 13)
mesh = SubResource("BuildingMesh")
material_override = SubResource("BuildingMaterial")
[node name="NorthRoof" type="MeshInstance3D" parent="Visuals"]
position = Vector3(-7, 6.1, 13)
rotation_degrees = Vector3(0, 45, 0)
mesh = SubResource("RoofMesh")
material_override = SubResource("RoofMaterial")
[node name="WaterTower" type="MeshInstance3D" parent="Visuals"]
position = Vector3(18, 4, 11)
mesh = SubResource("TowerMesh")
material_override = SubResource("RoofMaterial")
[node name="WaterTank" type="MeshInstance3D" parent="Visuals"]
position = Vector3(18, 8.5, 11)
mesh = SubResource("TowerTankMesh")
material_override = SubResource("LandmarkMaterial")
[node name="PavilionRoof" type="MeshInstance3D" parent="Visuals"]
position = Vector3(-12, 3.3, -10)
mesh = SubResource("PavilionRoofMesh")
material_override = SubResource("LandmarkMaterial")
[node name="PavilionPostNW" type="MeshInstance3D" parent="Visuals"]
position = Vector3(-15.5, 1.6, -12.5)
mesh = SubResource("PavilionPostMesh")
material_override = SubResource("RoofMaterial")
[node name="PavilionPostSE" type="MeshInstance3D" parent="Visuals"]
position = Vector3(-8.5, 1.6, -7.5)
mesh = SubResource("PavilionPostMesh")
material_override = SubResource("RoofMaterial")
[node name="VillageLabel" type="Label3D" parent="Visuals"]
position = Vector3(0, 3.2, 7)
text = "village"
font_size = 42
outline_size = 8
billboard = 1
no_depth_test = true
[node name="StaticCollision" type="Node3D" parent="."]
[node name="Ground" type="StaticBody3D" parent="StaticCollision"]
[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticCollision/Ground"]
position = Vector3(0, -3, 0)
shape = SubResource("GroundShape")
[node name="WestBuilding" type="StaticBody3D" parent="StaticCollision"]
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/WestBuilding"]
position = Vector3(-17, 2.5, 9)
shape = SubResource("BuildingShape")
[node name="NorthBuilding" type="StaticBody3D" parent="StaticCollision"]
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/NorthBuilding"]
position = Vector3(-7, 2.5, 13)
shape = SubResource("BuildingShape")
[node name="FishingWater" type="Node3D" parent="."]
[node name="WaterRecovery" type="Node3D" parent="."]
[node name="SafeRespawns" type="Node3D" parent="."]
[node name="VillageCenter" type="Marker3D" parent="SafeRespawns"]
position = Vector3(0, 0.58, 2)
script = ExtResource("2_safe")
[node name="VillageWest" type="Marker3D" parent="SafeRespawns"]
position = Vector3(-19, 0.58, -2)
rotation_degrees = Vector3(0, -90, 0)
script = ExtResource("2_safe")
[node name="VillageSouth" type="Marker3D" parent="SafeRespawns"]
position = Vector3(5, 0.58, -14)
rotation_degrees = Vector3(0, 180, 0)
script = ExtResource("2_safe")
[node name="Interactables" type="Node3D" parent="."]
[node name="FishingShopWorld" parent="Interactables" instance=ExtResource("3_shop")]
position = Vector3(12, 0, 3)
rotation_degrees = Vector3(0, -25, 0)
[node name="PelicanCoolerPerch" parent="Interactables" instance=ExtResource("4_pelican")]
position = Vector3(-19, 0, -9)
rotation_degrees = Vector3(0, 20, 0)

View file

@ -19,7 +19,7 @@ const FishingShopInteractionType = preload(
func get_player_water_triggers() -> Array[PlayerWaterTrigger]:
var triggers: Array[PlayerWaterTrigger] = []
for region: WorldRegion in _get_regions():
for region: GrayboxRegion in _get_regions():
triggers.append_array(region.get_water_recovery_triggers())
triggers.append(_below_world_failsafe)
return triggers
@ -27,7 +27,7 @@ func get_player_water_triggers() -> Array[PlayerWaterTrigger]:
func get_safe_respawn_points() -> Array[SafeRespawnPoint]:
var points: Array[SafeRespawnPoint] = []
for region: WorldRegion in _get_regions():
for region: GrayboxRegion in _get_regions():
points.append_array(region.get_safe_respawn_points())
return points
@ -42,7 +42,7 @@ func get_player_spawn_transform() -> Transform3D:
func get_fishable_water_regions() -> Array[FishableWaterRegion]:
var waters: Array[FishableWaterRegion] = []
for region: WorldRegion in _get_regions():
for region: GrayboxRegion in _get_regions():
waters.append_array(region.get_fishable_water_regions())
return waters
@ -51,10 +51,10 @@ func get_pelican_convenience_landmark() -> Node3D:
return _starter_island.get_pelican_landmark()
func _get_regions() -> Array[WorldRegion]:
var regions: Array[WorldRegion] = []
func _get_regions() -> Array[GrayboxRegion]:
var regions: Array[GrayboxRegion] = []
for child: Node in _regions_root.get_children():
var region: WorldRegion = child as WorldRegion
var region: GrayboxRegion = child as GrayboxRegion
if region != null:
regions.append(region)
return regions

View file

@ -2,25 +2,14 @@
[ext_resource type="Script" path="res://world/test_world.gd" id="1_world"]
[ext_resource type="PackedScene" path="res://world/regions/starter_island_region.tscn" id="2_island"]
[ext_resource type="Script" path="res://world/below_world_failsafe.gd" id="3_water_trigger"]
[ext_resource type="Script" path="res://world/player_water_trigger.gd" id="3_water_trigger"]
[sub_resource type="Environment" id="Environment"]
background_mode = 1
background_color = Color(0.58, 0.72, 0.82, 1)
background_energy_multiplier = 0.85
background_color = Color(0.48, 0.74, 0.92, 1)
ambient_light_source = 3
ambient_light_color = Color(0.78, 0.84, 0.92, 1)
ambient_light_energy = 0.95
fog_enabled = true
fog_light_color = Color(0.62, 0.73, 0.8, 1)
fog_light_energy = 0.75
fog_density = 0.0025
fog_aerial_perspective = 0.2
fog_sky_affect = 0.15
adjustment_enabled = true
adjustment_brightness = 0.9
adjustment_contrast = 0.89
adjustment_saturation = 0.91
ambient_light_color = Color(0.72, 0.78, 0.84, 1)
ambient_light_energy = 0.72
[sub_resource type="BoxShape3D" id="NorthSouthBoundsShape"]
size = Vector3(120, 14, 2)
@ -41,11 +30,8 @@ environment = SubResource("Environment")
[node name="Sun" type="DirectionalLight3D" parent="Environment"]
rotation_degrees = Vector3(-54, -32, 0)
light_color = Color(1, 0.94, 0.88, 1)
light_energy = 0.68
light_energy = 1.1
shadow_enabled = true
shadow_opacity = 0.58
shadow_blur = 2.0
[node name="Regions" type="Node3D" parent="."]
@ -60,7 +46,7 @@ collision_mask = 2
script = ExtResource("3_water_trigger")
surface_height = 0.3
[node name="Coverage" type="CollisionShape3D" parent="Safety/BelowWorldFailsafe"]
[node name="FailsafeShape" type="CollisionShape3D" parent="Safety/BelowWorldFailsafe"]
shape = SubResource("FailsafeShape")
[node name="WorldBounds" type="Node3D" parent="."]

View file

@ -1,158 +0,0 @@
@tool
class_name WaterBodyAuthoring
extends Node3D
@export_group("Surface")
## Visible water footprint in meters.
@export_custom(
PROPERTY_HINT_RANGE,
"0.1,200.0,0.1,or_greater,suffix:m",
)
var surface_size: Vector2 = Vector2(10.0, 10.0):
set(value):
surface_size = Vector2(maxf(value.x, 0.1), maxf(value.y, 0.1))
_sync_owned_nodes()
## Material applied to the visible water surface.
@export var water_material: Material:
set(value):
water_material = value
_sync_owned_nodes()
@export_group("Fishing Coverage")
## Extra fishable coverage beyond each edge of the visible surface.
@export_custom(
PROPERTY_HINT_RANGE,
"0.0,20.0,0.1,or_greater,suffix:m",
)
var fishing_padding: Vector2 = Vector2.ZERO:
set(value):
fishing_padding = Vector2(maxf(value.x, 0.0), maxf(value.y, 0.0))
_sync_owned_nodes()
@export_range(0.1, 20.0, 0.1, "or_greater", "suffix:m")
var fishing_depth: float = 4.0:
set(value):
fishing_depth = maxf(value, 0.1)
_sync_owned_nodes()
@export_group("Recovery Coverage")
## Extra recovery coverage beyond each edge of the visible surface.
@export_custom(
PROPERTY_HINT_RANGE,
"0.0,20.0,0.1,or_greater,suffix:m",
)
var recovery_padding: Vector2 = Vector2.ZERO:
set(value):
recovery_padding = Vector2(maxf(value.x, 0.0), maxf(value.y, 0.0))
_sync_owned_nodes()
@export_range(0.1, 20.0, 0.1, "or_greater", "suffix:m")
var recovery_depth: float = 4.8:
set(value):
recovery_depth = maxf(value, 0.1)
_sync_owned_nodes()
@export_group("Owned Nodes")
@export_node_path("MeshInstance3D")
var visual_water_path: NodePath = ^"VisualWater"
@export_node_path("CollisionShape3D")
var fishing_shape_path: NodePath = ^"FishingRegion/Shape"
@export_node_path("Area3D")
var recovery_region_path: NodePath = ^"RecoveryRegion"
@export_node_path("CollisionShape3D")
var recovery_shape_path: NodePath = ^"RecoveryRegion/Shape"
func _ready() -> void:
_sync_owned_nodes()
if Engine.is_editor_hint():
update_configuration_warnings()
func _sync_owned_nodes() -> void:
if not is_inside_tree():
return
var visual_water := get_node_or_null(visual_water_path) as MeshInstance3D
if visual_water != null:
var plane_mesh := visual_water.mesh as PlaneMesh
if plane_mesh != null:
plane_mesh.size = surface_size
visual_water.material_override = water_material
var fishing_shape_node := (
get_node_or_null(fishing_shape_path) as CollisionShape3D
)
if fishing_shape_node != null:
var fishing_shape := fishing_shape_node.shape as BoxShape3D
if fishing_shape != null:
fishing_shape.size = Vector3(
surface_size.x + fishing_padding.x * 2.0,
fishing_depth,
surface_size.y + fishing_padding.y * 2.0
)
var recovery_region := (
get_node_or_null(recovery_region_path) as Area3D
)
if recovery_region != null:
recovery_region.position.y = -recovery_depth * 0.5
var recovery_shape_node := (
get_node_or_null(recovery_shape_path) as CollisionShape3D
)
if recovery_shape_node != null:
var recovery_shape := recovery_shape_node.shape as BoxShape3D
if recovery_shape != null:
recovery_shape.size = Vector3(
surface_size.x + recovery_padding.x * 2.0,
recovery_depth,
surface_size.y + recovery_padding.y * 2.0
)
if Engine.is_editor_hint():
update_configuration_warnings()
func _get_configuration_warnings() -> PackedStringArray:
var warnings := PackedStringArray()
if not scale.is_equal_approx(Vector3.ONE):
warnings.append(
"Keep root scale at 1; resize water with Surface Size."
)
var visual_water := get_node_or_null(visual_water_path) as MeshInstance3D
if visual_water == null or not visual_water.mesh is PlaneMesh:
warnings.append("VisualWater must provide a PlaneMesh.")
var fishing_shape := get_node_or_null(fishing_shape_path) as CollisionShape3D
if fishing_shape == null or not fishing_shape.shape is BoxShape3D:
warnings.append("FishingRegion must provide a BoxShape3D.")
var recovery_region := (
get_node_or_null(recovery_region_path) as PlayerWaterTrigger
)
if recovery_region == null:
warnings.append("RecoveryRegion must use PlayerWaterTrigger.")
elif (
recovery_region.surface_height_mode
!= PlayerWaterTrigger.SurfaceHeightMode.PARENT_GLOBAL_Y
):
warnings.append(
"RecoveryRegion must derive surface height from its parent."
)
var recovery_shape := (
get_node_or_null(recovery_shape_path) as CollisionShape3D
)
if recovery_shape == null or not recovery_shape.shape is BoxShape3D:
warnings.append("RecoveryRegion must provide a BoxShape3D.")
var fishing_region := (
fishing_shape.get_parent() as FishableWaterRegion
if fishing_shape != null
else null
)
if fishing_region == null:
warnings.append("FishingRegion must use FishableWaterRegion.")
elif (
fishing_region.surface_height_mode
!= FishableWaterRegion.SurfaceHeightMode.PARENT_GLOBAL_Y
):
warnings.append(
"FishingRegion must derive surface height from its parent."
)
if water_material == null:
warnings.append("Assign a water material.")
return warnings

View file

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

View file

@ -1,62 +0,0 @@
@tool
class_name WorldProp
extends Node3D
@export_group("Owned Nodes")
@export_node_path("Node3D")
var visual_root_path: NodePath = ^"Visual"
@export_node_path("Node3D")
var collision_root_path: NodePath
@export_node_path("Area3D")
var interaction_area_path: NodePath
@export_node_path("Marker3D")
var entrance_marker_path: NodePath
@export_group("Scaling")
## Enable only when this prop explicitly supports non-uniform root scaling.
@export var allow_non_uniform_scale: bool = false
func _ready() -> void:
if not Engine.is_editor_hint():
return
set_notify_transform(true)
update_configuration_warnings()
func _notification(what: int) -> void:
if Engine.is_editor_hint() and what == NOTIFICATION_TRANSFORM_CHANGED:
update_configuration_warnings()
func _get_configuration_warnings() -> PackedStringArray:
var warnings := PackedStringArray()
if get_node_or_null(visual_root_path) == null:
warnings.append("Assign a valid Visual root.")
if (
not collision_root_path.is_empty()
and get_node_or_null(collision_root_path) == null
):
warnings.append("Assign a valid Collision root.")
if (
not interaction_area_path.is_empty()
and get_node_or_null(interaction_area_path) == null
):
warnings.append("Assign a valid InteractionArea.")
if (
not entrance_marker_path.is_empty()
and get_node_or_null(entrance_marker_path) == null
):
warnings.append("Assign a valid EntranceMarker.")
if not allow_non_uniform_scale and not _has_uniform_scale():
warnings.append(
"Use uniform root scale so visuals and collision stay aligned."
)
return warnings
func _has_uniform_scale() -> bool:
return (
is_equal_approx(scale.x, scale.y)
and is_equal_approx(scale.y, scale.z)
)

View file

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