Harden home exits and interior presentation
This commit is contained in:
parent
76b4f19e4d
commit
ac82a28f3b
4 changed files with 114 additions and 32 deletions
|
|
@ -1,6 +1,8 @@
|
|||
class_name HomeDecorController
|
||||
extends Node
|
||||
|
||||
signal exit_requested
|
||||
|
||||
const DecorCatalogType = preload("res://homes/decor_catalog.gd")
|
||||
const DRAG_RESPONSE: float = 22.0
|
||||
const DRAG_POSITION_EPSILON: float = 0.005
|
||||
|
|
@ -64,6 +66,8 @@ func setup(
|
|||
_toolbar.rotate_requested.connect(_rotate_selected)
|
||||
_toolbar.store_requested.connect(_store_selected)
|
||||
_toolbar.cancel_requested.connect(_clear_selection)
|
||||
if not _toolbar.exit_requested.is_connected(exit_requested.emit):
|
||||
_toolbar.exit_requested.connect(exit_requested.emit)
|
||||
_toolbar.set_mode(_mode)
|
||||
_refresh_toolbar()
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,13 @@ const INTERIOR_SPACING: float = 14.0
|
|||
const INTERIOR_MAX_SPAWN_SLOTS: int = 64
|
||||
const TENT_INTERIOR_SIZE := Vector2(4.0, 4.0)
|
||||
const STARTER_RV_INTERIOR_SIZE := Vector2(4.0, 6.0)
|
||||
const STARTER_RV_EXIT_LOCAL_X: float = 1.45
|
||||
const INTERIOR_EXIT_LOCAL_Y: float = 0.35
|
||||
const INTERIOR_EXIT_DOORWAY_HALF_WIDTH: float = 0.48
|
||||
const INTERIOR_EXIT_TRIGGER_DEPTH: float = 0.45
|
||||
const INTERIOR_SHELL_COLLISION_META: StringName = (
|
||||
&"home_interior_shell_collision"
|
||||
)
|
||||
const MIN_EXTERIOR_TRIANGLE_AREA: float = 1.0
|
||||
const MIN_EXTERIOR_SEPARATION: float = 14.6
|
||||
const EXTERIOR_FOOTPRINT_HALF_EXTENTS := Vector2(6.65, 3.73)
|
||||
|
|
@ -585,9 +592,14 @@ func is_avatar_near_interior_exit(
|
|||
) -> bool:
|
||||
if avatar == null:
|
||||
return false
|
||||
return avatar.global_position.distance_to(
|
||||
get_interior_exit_position(owner_fingerprint)
|
||||
) <= INTERIOR_EXIT_DISTANCE
|
||||
for exit_position: Vector3 in get_interior_exit_positions(
|
||||
owner_fingerprint
|
||||
):
|
||||
if avatar.global_position.distance_to(exit_position) <= (
|
||||
INTERIOR_EXIT_DISTANCE
|
||||
):
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
func has_avatar_crossed_interior_exit_threshold(
|
||||
|
|
@ -597,22 +609,30 @@ func has_avatar_crossed_interior_exit_threshold(
|
|||
if avatar == null:
|
||||
return false
|
||||
var local_position: Vector3 = interior_global_to_local(
|
||||
owner_fingerprint,
|
||||
avatar.global_position,
|
||||
owner_fingerprint, avatar.global_position
|
||||
)
|
||||
var threshold_position: Vector3 = interior_global_to_local(
|
||||
owner_fingerprint,
|
||||
get_interior_exit_position(owner_fingerprint),
|
||||
)
|
||||
var exit_direction: Vector3 = get_interior_exit_direction(
|
||||
for exit_position: Vector3 in get_interior_exit_positions(
|
||||
owner_fingerprint
|
||||
)
|
||||
return (
|
||||
(local_position - threshold_position).dot(exit_direction) >= 0.0
|
||||
and absf(local_position.z - threshold_position.z) <= 0.85
|
||||
and local_position.y >= -0.25
|
||||
and local_position.y <= 2.25
|
||||
)
|
||||
):
|
||||
var threshold_position: Vector3 = interior_global_to_local(
|
||||
owner_fingerprint, exit_position
|
||||
)
|
||||
var exit_direction: Vector3 = get_interior_exit_direction_near(
|
||||
owner_fingerprint, exit_position
|
||||
)
|
||||
var outward_distance: float = (
|
||||
(local_position - threshold_position).dot(exit_direction)
|
||||
)
|
||||
if (
|
||||
outward_distance >= 0.0
|
||||
and outward_distance <= INTERIOR_EXIT_TRIGGER_DEPTH
|
||||
and absf(local_position.z - threshold_position.z)
|
||||
<= INTERIOR_EXIT_DOORWAY_HALF_WIDTH
|
||||
and local_position.y >= -0.25
|
||||
and local_position.y <= 2.25
|
||||
):
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
func get_interior_exit_direction(owner_fingerprint: String) -> Vector3:
|
||||
|
|
@ -625,11 +645,41 @@ func get_interior_exit_direction(owner_fingerprint: String) -> Vector3:
|
|||
|
||||
|
||||
func get_interior_exit_position(owner_fingerprint: String) -> Vector3:
|
||||
var tier: int = _home_tier(owner_fingerprint)
|
||||
return get_interior_anchor(owner_fingerprint) + (
|
||||
Vector3(-STARTER_RV_INTERIOR_SIZE.x * 0.5 + 0.6, 0.35, 0.0)
|
||||
if tier >= PlayerHomeStateType.STARTER_RV_TIER
|
||||
else Vector3(TENT_INTERIOR_SIZE.x * 0.5 - 0.55, 0.35, 0.0)
|
||||
return get_interior_exit_positions(owner_fingerprint)[0]
|
||||
|
||||
|
||||
func get_interior_exit_positions(
|
||||
owner_fingerprint: String,
|
||||
) -> Array[Vector3]:
|
||||
var anchor: Vector3 = get_interior_anchor(owner_fingerprint)
|
||||
if _home_tier(owner_fingerprint) >= PlayerHomeStateType.STARTER_RV_TIER:
|
||||
return [
|
||||
anchor + Vector3(
|
||||
-STARTER_RV_EXIT_LOCAL_X, INTERIOR_EXIT_LOCAL_Y, 0.0
|
||||
),
|
||||
anchor + Vector3(
|
||||
STARTER_RV_EXIT_LOCAL_X, INTERIOR_EXIT_LOCAL_Y, 0.0
|
||||
),
|
||||
]
|
||||
return [
|
||||
anchor + Vector3(
|
||||
TENT_INTERIOR_SIZE.x * 0.5 - 0.55,
|
||||
INTERIOR_EXIT_LOCAL_Y,
|
||||
0.0,
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
func get_interior_exit_direction_near(
|
||||
owner_fingerprint: String,
|
||||
world_position: Vector3,
|
||||
) -> Vector3:
|
||||
if _home_tier(owner_fingerprint) < PlayerHomeStateType.STARTER_RV_TIER:
|
||||
return Vector3.RIGHT
|
||||
return (
|
||||
Vector3.RIGHT
|
||||
if world_position.x >= get_interior_anchor(owner_fingerprint).x
|
||||
else Vector3.LEFT
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -1200,9 +1250,14 @@ func _add_imported_mesh_collision(mesh_instance: MeshInstance3D) -> void:
|
|||
var shape: ConcavePolygonShape3D = mesh_instance.mesh.create_trimesh_shape()
|
||||
if shape == null:
|
||||
return
|
||||
# Imported room shells are authored to render from both sides, but concave
|
||||
# collision defaults to front faces only. Interior walls therefore need
|
||||
# back-face collision or the player can walk through their inward side.
|
||||
shape.backface_collision = true
|
||||
var body := StaticBody3D.new()
|
||||
body.name = "%sCollision" % mesh_instance.name
|
||||
body.transform = mesh_instance.transform
|
||||
body.set_meta(INTERIOR_SHELL_COLLISION_META, true)
|
||||
var collision := CollisionShape3D.new()
|
||||
collision.shape = shape
|
||||
body.add_child(collision)
|
||||
|
|
|
|||
|
|
@ -63,6 +63,8 @@ func setup(
|
|||
_session.peer_authenticated.connect(_on_peer_authenticated)
|
||||
if not _session.peer_removed.is_connected(_on_peer_removed):
|
||||
_session.peer_removed.connect(_on_peer_removed)
|
||||
if not _spawn_service.avatar_spawned.is_connected(_on_avatar_spawned):
|
||||
_spawn_service.avatar_spawned.connect(_on_avatar_spawned)
|
||||
if not _local_home.changed.is_connected(_on_local_home_changed):
|
||||
_local_home.changed.connect(_on_local_home_changed)
|
||||
|
||||
|
|
@ -1126,11 +1128,8 @@ func _process_transition_request(peer_id: int, data: Dictionary) -> void:
|
|||
if (
|
||||
_session.get_peer_space(peer_id)
|
||||
!= NetworkHomeProtocolType.make_space_id(owner_fingerprint)
|
||||
or not _world_service.is_avatar_near_interior_exit(
|
||||
avatar, owner_fingerprint
|
||||
)
|
||||
):
|
||||
_send_transition_rejection(peer_id, "Move closer to the home door.")
|
||||
_send_transition_rejection(peer_id, "You are not inside that home.")
|
||||
return
|
||||
_apply_host_transition(
|
||||
peer_id,
|
||||
|
|
@ -1276,6 +1275,15 @@ func _refresh_peer_visibility() -> void:
|
|||
)
|
||||
|
||||
|
||||
func _on_avatar_spawned(peer_id: int, _avatar: Player) -> void:
|
||||
var local_peer_id: int = _session.get_local_peer_id()
|
||||
if local_peer_id <= 0 or peer_id == local_peer_id:
|
||||
return
|
||||
_spawn_service.set_peer_presentation_visible(
|
||||
peer_id, _session.peers_share_space(local_peer_id, peer_id)
|
||||
)
|
||||
|
||||
|
||||
func _on_local_home_changed() -> void:
|
||||
if _suppress_local_submission or _publish_queued:
|
||||
return
|
||||
|
|
|
|||
|
|
@ -5,26 +5,34 @@ signal placement_mode_requested(mode: int)
|
|||
signal rotate_requested
|
||||
signal store_requested
|
||||
signal cancel_requested
|
||||
signal exit_requested
|
||||
|
||||
var _mode_button: Button
|
||||
var _selection_label: Label
|
||||
var _rotate_button: Button
|
||||
var _store_button: Button
|
||||
var _clear_button: Button
|
||||
var _exit_button: Button
|
||||
var _mode: PlayerHomeState.PlacementMode = PlayerHomeState.PlacementMode.GRID
|
||||
var _interactive: bool = true
|
||||
var _selection_active: bool = false
|
||||
var _active: bool = false
|
||||
var _menu_obscured: bool = false
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
_build_ui()
|
||||
hide()
|
||||
_refresh_visibility()
|
||||
|
||||
|
||||
func set_active(active: bool) -> void:
|
||||
if visible == active:
|
||||
return
|
||||
visible = active
|
||||
_active = active
|
||||
_refresh_visibility()
|
||||
|
||||
|
||||
func set_menu_obscured(obscured: bool) -> void:
|
||||
_menu_obscured = obscured
|
||||
_refresh_visibility()
|
||||
|
||||
|
||||
func set_interactive(interactive: bool) -> void:
|
||||
|
|
@ -59,13 +67,17 @@ func report_status(message: String) -> void:
|
|||
_selection_label.text = message
|
||||
|
||||
|
||||
func _refresh_visibility() -> void:
|
||||
visible = _active and not _menu_obscured
|
||||
|
||||
|
||||
func _build_ui() -> void:
|
||||
set_anchors_preset(Control.PRESET_TOP_RIGHT)
|
||||
offset_left = -500.0
|
||||
offset_left = -610.0
|
||||
offset_top = 0.0
|
||||
offset_right = 0.0
|
||||
offset_bottom = 106.0
|
||||
custom_minimum_size = Vector2(500.0, 0.0)
|
||||
custom_minimum_size = Vector2(610.0, 0.0)
|
||||
z_index = 85
|
||||
mouse_filter = Control.MOUSE_FILTER_STOP
|
||||
var panel_style: StyleBoxFlat = UtilityPageStyle.panel_style()
|
||||
|
|
@ -102,6 +114,9 @@ func _build_ui() -> void:
|
|||
_store_button.pressed.connect(store_requested.emit)
|
||||
_clear_button = _add_tool_button(row, "clear", "clear selection", 82.0)
|
||||
_clear_button.pressed.connect(cancel_requested.emit)
|
||||
_exit_button = _add_tool_button(row, "Exit RV", "exit the RV", 100.0)
|
||||
_exit_button.name = "ExitRVButton"
|
||||
_exit_button.pressed.connect(exit_requested.emit)
|
||||
_selection_label = Label.new()
|
||||
_selection_label.text = "use held decor to place; click or drag to edit"
|
||||
_selection_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue