This commit is contained in:
Marek Le
2026-05-09 23:37:26 +02:00
parent 6d28b04c12
commit 2d4002bd3f
263 changed files with 5250 additions and 4597 deletions

124
autoloads/stats.gd Normal file
View File

@@ -0,0 +1,124 @@
extends Node
const SYNCED_STATS: Array = [
"health", "shield", "max_health", "max_shield",
"role", "level", "xp", "xp_to_next",
"buff_damage", "buff_heal", "buff_shield",
]
const SYNC_INTERVAL: float = 0.10
var _entities: Dictionary = {}
var _player_cache: Dictionary = {}
var _dirty: Dictionary = {}
var _accum: float = 0.0
func _ready() -> void:
set_process(true)
func _process(delta: float) -> void:
_accum += delta
if _accum < SYNC_INTERVAL:
return
_accum = 0.0
if multiplayer.multiplayer_peer == null or multiplayer.multiplayer_peer is OfflineMultiplayerPeer or not multiplayer.is_server():
_dirty.clear()
return
if _dirty.is_empty():
return
for entity in _dirty.keys():
if not is_instance_valid(entity) or not entity.is_inside_tree():
continue
_sync_stats_batch.rpc(String(entity.get_path()), _dirty[entity])
_dirty.clear()
@rpc("authority", "unreliable_ordered")
func _sync_stats_batch(path_str: String, changes: Dictionary) -> void:
var entity := get_node_or_null(NodePath(path_str))
if entity == null or not entity in _entities:
return
for stat in changes.keys():
_entities[entity][stat] = changes[stat]
match stat:
"health":
EventBus.health_changed.emit(entity, changes[stat], _entities[entity].get("max_health", 100.0))
"shield":
EventBus.shield_changed.emit(entity, changes[stat], _entities[entity].get("max_shield", 0.0))
"role":
EventBus.role_changed.emit(entity, changes[stat])
"level":
EventBus.level_up.emit(entity, changes[stat])
"buff_damage", "buff_heal", "buff_shield":
EventBus.buff_changed.emit(entity, StringName(stat), changes[stat])
func register(entity: Node, base_resource: Resource) -> void:
if not is_instance_valid(entity):
return
var data: Dictionary = {}
for prop in base_resource.get_property_list():
var name: String = prop.name
if not (prop.usage & PROPERTY_USAGE_STORAGE):
continue
if name in ["resource_local_to_scene", "resource_path", "resource_name", "resource_scene_unique_id", "script"]:
continue
data[name] = base_resource.get(name)
data["health"] = data.get("max_health", 100.0)
data["shield"] = data.get("max_shield", 0.0)
data["shield_regen_timer"] = 0.0
data["base_resource"] = base_resource
_entities[entity] = data
EventBus.entity_registered.emit(entity)
func deregister(entity: Node) -> void:
if entity in _entities:
_entities.erase(entity)
EventBus.entity_deregistered.emit(entity)
func has(entity: Node) -> bool:
return entity in _entities
func get_stat(entity: Node, stat: String, default: Variant = 0.0) -> Variant:
if entity in _entities:
return _entities[entity].get(stat, default)
return default
func set_stat(entity: Node, stat: String, value: Variant) -> void:
if not entity in _entities:
return
var prev: Variant = _entities[entity].get(stat)
_entities[entity][stat] = value
if stat in SYNCED_STATS and prev != value and multiplayer.multiplayer_peer != null and not (multiplayer.multiplayer_peer is OfflineMultiplayerPeer) and multiplayer.is_server() and is_instance_valid(entity) and entity.is_inside_tree():
if not entity in _dirty:
_dirty[entity] = {}
_dirty[entity][stat] = value
func get_all(entity: Node) -> Dictionary:
return _entities.get(entity, {})
func entities() -> Array:
return _entities.keys()
func entities_in_group(group: StringName) -> Array:
var out: Array = []
for e in _entities.keys():
if is_instance_valid(e) and e.is_in_group(group):
out.append(e)
return out
func cache_player(peer_id: int, entity: Node) -> void:
if entity in _entities:
_player_cache[peer_id] = _entities[entity].duplicate(true)
func restore_player(peer_id: int, entity: Node) -> void:
if peer_id in _player_cache:
_entities[entity] = _player_cache[peer_id].duplicate(true)
func clear_player_cache(peer_id: int = -1) -> void:
if peer_id == -1:
_player_cache.clear()
else:
_player_cache.erase(peer_id)
func clear_all() -> void:
_entities.clear()
_player_cache.clear()