Add networked crab gathering prototype

This commit is contained in:
Alexander Sellite 2026-08-14 22:11:49 -04:00
parent f55663c105
commit a62cce6404
56 changed files with 2692 additions and 56 deletions

View file

@ -4,6 +4,7 @@ extends Node
const FishingRodDataType = preload("res://items/fishing_rod_data.gd")
const ArtShopStockType = preload("res://economy/art_shop_stock.gd")
const FishingShopStockType = preload("res://economy/fishing_shop_stock.gd")
const MAX_LEDGER_ENTRIES: int = 64
@ -292,6 +293,13 @@ func get_effects_for_peer(peer_id: int) -> PlayerItemEffects:
return avatar.item_effects if avatar != null else null
func get_equipped_item_id(peer_id: int) -> StringName:
var state: Dictionary = _equipped_states.get(peer_id, {})
if state.is_empty() or not bool(state.get("owns_item", false)):
return StringName()
return StringName(str(state.get("item_id", "")))
func submit_local_equipped(item_id: StringName, owns_item: bool) -> void:
if _session == null or not _session.is_gameplay_session_active():
return
@ -377,6 +385,10 @@ func _apply_equipped(data: Dictionary) -> void:
item.icon if item != null else null,
item_id == ArtShopStockType.ART_KIT_ITEM_ID and bool(data["owns_item"]),
)
avatar.set_active_catching_net(
item_id == FishingShopStockType.CRAB_NET_ID
and bool(data["owns_item"]),
)
equipped_state_changed.emit(
peer_id, StringName(str(data["item_id"])), int(data["category"])
)

View file

@ -1,7 +1,7 @@
class_name NetworkProtocol
extends RefCounted
const PROTOCOL_VERSION: int = 4
const PROTOCOL_VERSION: int = 5
const GAME_BUILD: String = "prealpha"
const MAX_GAME_VERSION_LENGTH: int = 64
const MAX_DISPLAY_NAME_LENGTH: int = 24
@ -25,6 +25,7 @@ const WORLD_TIME_CAPABILITY: String = "world_time_v1"
const WORLD_WEATHER_CAPABILITY: String = "world_weather_v1"
const FISH_QUALITY_CAPABILITY: String = "fish_quality_v1"
const JOBS_CAPABILITY: String = "jobs_v1"
const WORLD_SPAWN_CAPABILITY: String = "world_spawn_envelope_v1"
enum RejectionCode {
NONE,
@ -172,6 +173,7 @@ static func make_client_hello(
WORLD_TIME_CAPABILITY,
WORLD_WEATHER_CAPABILITY,
JOBS_CAPABILITY,
WORLD_SPAWN_CAPABILITY,
]),
"cosmetic_snapshot": cosmetic_snapshot,
"identity_fingerprint": identity_fingerprint,
@ -313,6 +315,7 @@ static func make_server_hello(
WORLD_TIME_CAPABILITY,
WORLD_WEATHER_CAPABILITY,
JOBS_CAPABILITY,
WORLD_SPAWN_CAPABILITY,
"chat_v1",
"mail_v1",
"profile_v1",

View file

@ -267,6 +267,7 @@ func _register_player_host() -> void:
NetworkProtocol.WORLD_TIME_CAPABILITY,
NetworkProtocol.WORLD_WEATHER_CAPABILITY,
NetworkProtocol.JOBS_CAPABILITY,
NetworkProtocol.WORLD_SPAWN_CAPABILITY,
]),
)
_registry.update_appearance(1, _local_appearance_snapshot)
@ -555,6 +556,7 @@ func supports_server_capability(capability: StringName) -> bool:
NetworkProtocol.SURFACE_DRAWING_CAPABILITY,
NetworkProtocol.WORLD_TIME_CAPABILITY,
NetworkProtocol.WORLD_WEATHER_CAPABILITY,
NetworkProtocol.WORLD_SPAWN_CAPABILITY,
"chat_v1",
"mail_v1",
"profile_v1",

View file

@ -0,0 +1,94 @@
class_name NetworkWorldSpawnProtocol
extends RefCounted
const CAPABILITY: StringName = &"world_spawn_envelope_v1"
const ENVELOPE_VERSION: int = 1
const RELIABLE_CHANNEL: int = NetworkProtocol.ITEM_RELIABLE_CHANNEL
const SNAPSHOT_CHANNEL: int = 4
const MAX_SESSION_ID_LENGTH: int = 96
const MAX_EVENT_ID_LENGTH: int = 48
const MAX_ENTITY_ID_LENGTH: int = 128
const MAX_TYPE_ID_LENGTH: int = 96
const MAX_ENTITIES_PER_SNAPSHOT: int = 128
## Keeps unreliable movement envelopes below ENet's practical MTU while
## allowing reliable population envelopes to carry a larger initial state.
const SNAPSHOT_ENTITIES_PER_ENVELOPE: int = 4
static func make_envelope(
session_id: String,
sequence: int,
event_id: StringName,
payload: Dictionary,
) -> Dictionary:
return {
"envelope_version": ENVELOPE_VERSION,
"session_id": session_id,
"sequence": sequence,
"event_id": str(event_id),
"payload": payload.duplicate(true),
}
static func validate_envelope(value: Variant) -> bool:
if typeof(value) != TYPE_DICTIONARY:
return false
var data: Dictionary = value
return (
typeof(data.get("envelope_version")) == TYPE_INT
and int(data["envelope_version"]) == ENVELOPE_VERSION
and typeof(data.get("session_id")) == TYPE_STRING
and not str(data["session_id"]).is_empty()
and str(data["session_id"]).length() <= MAX_SESSION_ID_LENGTH
and typeof(data.get("sequence")) == TYPE_INT
and int(data["sequence"]) >= 0
and typeof(data.get("event_id")) == TYPE_STRING
and not str(data["event_id"]).is_empty()
and str(data["event_id"]).length() <= MAX_EVENT_ID_LENGTH
and typeof(data.get("payload")) == TYPE_DICTIONARY
)
static func validate_entity_state(value: Variant) -> bool:
if typeof(value) != TYPE_DICTIONARY:
return false
var data: Dictionary = value
var position: Variant = data.get("position")
if typeof(position) != TYPE_ARRAY or position.size() != 3:
return false
for component: Variant in position:
if typeof(component) not in [TYPE_FLOAT, TYPE_INT]:
return false
if not is_finite(float(component)):
return false
return (
typeof(data.get("entity_id")) == TYPE_STRING
and not str(data["entity_id"]).is_empty()
and str(data["entity_id"]).length() <= MAX_ENTITY_ID_LENGTH
and typeof(data.get("type_id")) == TYPE_STRING
and not str(data["type_id"]).is_empty()
and str(data["type_id"]).length() <= MAX_TYPE_ID_LENGTH
and typeof(data.get("yaw")) in [TYPE_FLOAT, TYPE_INT]
and is_finite(float(data["yaw"]))
and typeof(data.get("revision")) == TYPE_INT
and int(data["revision"]) >= 0
)
static func vector3_to_array(value: Vector3) -> Array[float]:
return [value.x, value.y, value.z]
static func array_to_vector3(value: Variant) -> Vector3:
if typeof(value) != TYPE_ARRAY or value.size() != 3:
return Vector3(INF, INF, INF)
for component: Variant in value:
if typeof(component) not in [TYPE_FLOAT, TYPE_INT]:
return Vector3(INF, INF, INF)
if not is_finite(float(component)):
return Vector3(INF, INF, INF)
return _array_to_vector3(value)
static func _array_to_vector3(value: Array) -> Vector3:
return Vector3(float(value[0]), float(value[1]), float(value[2]))

View file

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

File diff suppressed because it is too large Load diff

View file

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