Add collectible fish quality tiers
This commit is contained in:
parent
7661b057bc
commit
35d00e8035
30 changed files with 834 additions and 73 deletions
|
|
@ -7,6 +7,7 @@ const MAX_SESSION_ID_LENGTH: int = 96
|
|||
const MAX_FISH_ID_LENGTH: int = 96
|
||||
const MAX_WEIGHT_LB: float = 1000.0
|
||||
const MAX_DISPLAY_SCALE: float = 20.0
|
||||
const FishQualityType = preload("res://fish/fish_quality.gd")
|
||||
|
||||
|
||||
static func validate_state(data: Variant) -> bool:
|
||||
|
|
@ -20,6 +21,7 @@ static func validate_state(data: Variant) -> bool:
|
|||
"fish_id",
|
||||
"weight_lb",
|
||||
"display_scale",
|
||||
"quality",
|
||||
"revision",
|
||||
]:
|
||||
if not value.has(key):
|
||||
|
|
@ -37,6 +39,8 @@ static func validate_state(data: Variant) -> bool:
|
|||
or not is_finite(float(value["weight_lb"]))
|
||||
or typeof(value["display_scale"]) not in [TYPE_FLOAT, TYPE_INT]
|
||||
or not is_finite(float(value["display_scale"]))
|
||||
or typeof(value["quality"]) != TYPE_INT
|
||||
or not FishQualityType.is_valid(int(value["quality"]))
|
||||
or typeof(value["revision"]) != TYPE_INT
|
||||
or int(value["revision"]) < 0
|
||||
):
|
||||
|
|
@ -53,4 +57,5 @@ static func validate_state(data: Variant) -> bool:
|
|||
str(value["fish_id"]).is_empty()
|
||||
and is_zero_approx(float(value["weight_lb"]))
|
||||
and is_zero_approx(float(value["display_scale"]))
|
||||
and int(value["quality"]) == FishQualityType.Tier.BORING
|
||||
)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ extends Node
|
|||
const FishPoolType = preload("res://fish/fish_pool.gd")
|
||||
const FishDataType = preload("res://fish/fish_data.gd")
|
||||
const FishCatchType = preload("res://fish/fish_catch.gd")
|
||||
const FishQualityType = preload("res://fish/fish_quality.gd")
|
||||
const FishInventoryType = preload("res://inventory/fish_inventory.gd")
|
||||
const PlayerHotbarType = preload("res://inventory/player_hotbar.gd")
|
||||
|
||||
|
|
@ -80,6 +81,11 @@ func _submit_local_state(fish_catch: FishCatchType, should_show: bool) -> void:
|
|||
"display_scale": (
|
||||
fish_catch.display_scale if fish_catch != null else 0.0
|
||||
),
|
||||
"quality": (
|
||||
fish_catch.quality
|
||||
if fish_catch != null
|
||||
else FishQualityType.Tier.BORING
|
||||
),
|
||||
"revision": _local_revision,
|
||||
}
|
||||
_local_visible = bool(data["visible"])
|
||||
|
|
|
|||
|
|
@ -761,7 +761,10 @@ func _apply_target_outcome(data: Dictionary) -> void:
|
|||
return
|
||||
if not already_owned:
|
||||
_local_inventory.add_catch(fish_catch)
|
||||
_local_collection.mark_discovered(fish_id)
|
||||
_local_collection.mark_quality_discovered(
|
||||
fish_id,
|
||||
fish_catch.quality,
|
||||
)
|
||||
if not _save_manager.save_if_dirty():
|
||||
return
|
||||
_result_ledgers[result_id] = true
|
||||
|
|
|
|||
|
|
@ -144,6 +144,7 @@ static func attachment_signature_fields(value: Variant) -> Array:
|
|||
result.append(str(fish.get("fish_id", "")))
|
||||
result.append(str(fish.get("weight_lb", "")))
|
||||
result.append(str(fish.get("display_scale", "")))
|
||||
result.append(int(fish.get("quality", -1)))
|
||||
result.append(int(fish.get("sale_value", 0)))
|
||||
result.append(bool(fish.get("is_favorited", false)))
|
||||
3:
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ signal operation_finished(success: bool, message: String)
|
|||
signal peers_changed
|
||||
|
||||
const MAX_LEDGER: int = 256
|
||||
const FishQualityType = preload("res://fish/fish_quality.gd")
|
||||
|
||||
var _session: NetworkSession
|
||||
var _reservations: PlayerAssetReservationService
|
||||
|
|
@ -950,7 +951,10 @@ func _apply_award(attachment: Dictionary) -> bool:
|
|||
PlayerAssetReservationService.AttachmentType.FISH:
|
||||
var fish_catch := _decode_catch(attachment)
|
||||
_inventory.add_catch(fish_catch)
|
||||
_collection_log.mark_discovered(fish_catch.fish_id)
|
||||
_collection_log.mark_quality_discovered(
|
||||
fish_catch.fish_id,
|
||||
fish_catch.quality,
|
||||
)
|
||||
return _inventory.contains_catch_id(fish_catch.catch_id)
|
||||
PlayerAssetReservationService.AttachmentType.CONSUMABLE:
|
||||
return _bag.add_item(
|
||||
|
|
@ -962,10 +966,26 @@ func _apply_award(attachment: Dictionary) -> bool:
|
|||
|
||||
func _decode_catch(attachment: Dictionary) -> FishCatch:
|
||||
var data: Dictionary = attachment.get("catch", {})
|
||||
var fish := _fish_catalog.get_fish_by_id(
|
||||
var fish: FishData = _fish_catalog.get_fish_by_id(
|
||||
StringName(str(data.get("fish_id", "")))
|
||||
)
|
||||
return FishCatch.from_network_dict(data, fish)
|
||||
var fish_catch: FishCatch = FishCatch.from_network_dict(data, fish)
|
||||
if fish_catch == null or fish == null:
|
||||
return null
|
||||
if (
|
||||
fish_catch.weight_lb < fish.get_minimum_weight()
|
||||
or fish_catch.weight_lb > fish.get_maximum_weight()
|
||||
or not is_equal_approx(
|
||||
fish_catch.display_scale,
|
||||
fish.get_display_scale_for_weight(fish_catch.weight_lb),
|
||||
)
|
||||
or fish_catch.sale_value != FishQualityType.apply_sale_value(
|
||||
fish.get_sale_value_for_weight(fish_catch.weight_lb),
|
||||
fish_catch.quality,
|
||||
)
|
||||
):
|
||||
return null
|
||||
return fish_catch
|
||||
|
||||
|
||||
func _capture_assets() -> Dictionary:
|
||||
|
|
@ -975,6 +995,7 @@ func _capture_assets() -> Dictionary:
|
|||
"catches": _inventory.get_all_catches(),
|
||||
"next_sequence": _inventory.get_next_catch_sequence(),
|
||||
"discovered": _collection_log.get_discovered_ids(),
|
||||
"quality_masks": _collection_log.get_discovered_quality_masks(),
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -984,7 +1005,10 @@ func _restore_assets(snapshot: Dictionary) -> void:
|
|||
_inventory.replace_all_catches(
|
||||
snapshot["catches"], int(snapshot["next_sequence"])
|
||||
)
|
||||
_collection_log.replace_discovered_ids(snapshot["discovered"])
|
||||
_collection_log.replace_discovery_state(
|
||||
snapshot["discovered"],
|
||||
snapshot["quality_masks"],
|
||||
)
|
||||
|
||||
|
||||
func _emit_mailbox() -> void:
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ const SURFACE_DRAWING_CAPABILITY: String = "surface_drawing_v2"
|
|||
const ART_SHOP_CAPABILITY: String = "art_shop_v1"
|
||||
const WORLD_TIME_CAPABILITY: String = "world_time_v1"
|
||||
const WORLD_WEATHER_CAPABILITY: String = "world_weather_v1"
|
||||
const FISH_QUALITY_CAPABILITY: String = "fish_quality_v1"
|
||||
|
||||
enum RejectionCode {
|
||||
NONE,
|
||||
|
|
@ -88,6 +89,7 @@ static func make_client_hello(
|
|||
"display_name": display_name,
|
||||
"client_nonce": client_nonce,
|
||||
"capability_flags": PackedStringArray([
|
||||
FISH_QUALITY_CAPABILITY,
|
||||
SURFACE_DRAWING_CAPABILITY,
|
||||
WORLD_TIME_CAPABILITY,
|
||||
WORLD_WEATHER_CAPABILITY,
|
||||
|
|
@ -207,6 +209,7 @@ static func make_server_hello(
|
|||
"item_use_v1",
|
||||
"equipment_v1",
|
||||
"fish_showcase_v1",
|
||||
FISH_QUALITY_CAPABILITY,
|
||||
SURFACE_DRAWING_CAPABILITY,
|
||||
WORLD_TIME_CAPABILITY,
|
||||
WORLD_WEATHER_CAPABILITY,
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ static func validate_request(data: Variant) -> String:
|
|||
var evidence: Dictionary = value
|
||||
for key: String in [
|
||||
"catch_id", "fish_id", "weight_lb", "display_scale",
|
||||
"sale_value", "is_favorited",
|
||||
"quality", "sale_value", "is_favorited",
|
||||
]:
|
||||
if not evidence.has(key):
|
||||
return "Sale could not be completed."
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ class_name NetworkSaleService
|
|||
extends Node
|
||||
|
||||
const FishCatchType = preload("res://fish/fish_catch.gd")
|
||||
const FishQualityType = preload("res://fish/fish_quality.gd")
|
||||
const FishDataType = preload("res://fish/fish_data.gd")
|
||||
const FishPoolType = preload("res://fish/fish_pool.gd")
|
||||
const FishBuyerProfileType = preload("res://economy/fish_buyer_profile.gd")
|
||||
|
|
@ -252,8 +253,10 @@ func _build_authoritative_result(
|
|||
not str(decoded.catch_id).begins_with("%s:" % fish_id)
|
||||
or decoded.weight_lb < fish.get_minimum_weight()
|
||||
or decoded.weight_lb > fish.get_maximum_weight()
|
||||
or decoded.sale_value < fish.sell_value_min
|
||||
or decoded.sale_value > fish.sell_value_max
|
||||
or decoded.sale_value != FishQualityType.apply_sale_value(
|
||||
fish.get_sale_value_for_weight(decoded.weight_lb),
|
||||
decoded.quality,
|
||||
)
|
||||
):
|
||||
return _rejected_result(
|
||||
request_id, "Sale could not be completed."
|
||||
|
|
@ -262,7 +265,13 @@ func _build_authoritative_result(
|
|||
return _rejected_result(
|
||||
request_id, "Favorite catches cannot be sold."
|
||||
)
|
||||
var offer: int = buyer.get_offer(decoded.sale_value)
|
||||
var ordinary_value: int = fish.get_sale_value_for_weight(
|
||||
decoded.weight_lb
|
||||
)
|
||||
var offer: int = buyer.get_quality_offer(
|
||||
ordinary_value,
|
||||
decoded.quality,
|
||||
)
|
||||
if (
|
||||
offer < 0
|
||||
or base_value > 9223372036854775807 - decoded.sale_value
|
||||
|
|
|
|||
|
|
@ -169,6 +169,7 @@ func start_private_host(port: int = DEFAULT_PORT) -> bool:
|
|||
_player_identity.fingerprint,
|
||||
_player_identity.public_pem,
|
||||
PackedStringArray([
|
||||
NetworkProtocol.FISH_QUALITY_CAPABILITY,
|
||||
NetworkProtocol.SURFACE_DRAWING_CAPABILITY,
|
||||
NetworkProtocol.WORLD_TIME_CAPABILITY,
|
||||
NetworkProtocol.WORLD_WEATHER_CAPABILITY,
|
||||
|
|
@ -367,6 +368,7 @@ func supports_server_capability(capability: StringName) -> bool:
|
|||
"movement_v1", "fishing_v1", "sale_v1", "shop_v1",
|
||||
NetworkProtocol.ART_SHOP_CAPABILITY,
|
||||
"item_use_v1", "equipment_v1", "fish_showcase_v1",
|
||||
NetworkProtocol.FISH_QUALITY_CAPABILITY,
|
||||
NetworkProtocol.SURFACE_DRAWING_CAPABILITY,
|
||||
NetworkProtocol.WORLD_TIME_CAPABILITY,
|
||||
NetworkProtocol.WORLD_WEATHER_CAPABILITY,
|
||||
|
|
@ -915,6 +917,15 @@ func submit_client_hello(data: Dictionary) -> void:
|
|||
if not validation_error.is_empty():
|
||||
_reject_peer(sender_id, NetworkProtocol.RejectionCode.MALFORMED_HANDSHAKE)
|
||||
return
|
||||
var client_capabilities: PackedStringArray = _sanitized_capabilities(
|
||||
data.get("capability_flags", [])
|
||||
)
|
||||
if NetworkProtocol.FISH_QUALITY_CAPABILITY not in client_capabilities:
|
||||
_reject_peer(
|
||||
sender_id,
|
||||
NetworkProtocol.RejectionCode.UNSUPPORTED_CLIENT,
|
||||
)
|
||||
return
|
||||
var identity: Dictionary = _authenticated_identity_cache.get(sender_id, {})
|
||||
if identity.is_empty():
|
||||
_reject_peer(sender_id, NetworkProtocol.RejectionCode.INVALID_IDENTITY_PROOF)
|
||||
|
|
@ -948,7 +959,7 @@ func submit_client_hello(data: Dictionary) -> void:
|
|||
NetworkProtocol.PROTOCOL_VERSION,
|
||||
identity["fingerprint"],
|
||||
identity["public_key"],
|
||||
_sanitized_capabilities(data.get("capability_flags", [])),
|
||||
client_capabilities,
|
||||
):
|
||||
_reject_peer(
|
||||
sender_id,
|
||||
|
|
@ -1071,6 +1082,10 @@ func receive_server_hello(data: Dictionary) -> void:
|
|||
for value: Variant in advertised_capabilities:
|
||||
if typeof(value) in [TYPE_STRING, TYPE_STRING_NAME]:
|
||||
_server_capabilities.append(str(value))
|
||||
if NetworkProtocol.FISH_QUALITY_CAPABILITY not in _server_capabilities:
|
||||
_teardown_peer()
|
||||
_fail("This server does not support fish quality data.")
|
||||
return
|
||||
var local_peer_id: int = multiplayer.get_unique_id()
|
||||
_registry.clear()
|
||||
_registry.add_peer(
|
||||
|
|
@ -1081,6 +1096,7 @@ func receive_server_hello(data: Dictionary) -> void:
|
|||
_player_identity.fingerprint,
|
||||
_player_identity.public_pem,
|
||||
PackedStringArray([
|
||||
NetworkProtocol.FISH_QUALITY_CAPABILITY,
|
||||
NetworkProtocol.SURFACE_DRAWING_CAPABILITY,
|
||||
NetworkProtocol.WORLD_TIME_CAPABILITY,
|
||||
NetworkProtocol.WORLD_WEATHER_CAPABILITY,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue