b0c83af092
Complete replacement of the tactical-shooter project with the netfox-cs-sample (MIT) — a CS 1.6 inspired multiplayer FPS built with Godot 4 and netfox. ## What's new - Full CS-style gameplay: teams (T/CT), rounds, economy, buy menu - 6 weapons: Knife, Glock, USP, AK-47, M4A1, AWP - Bomb plant/defuse with 2 bombsites - Flashbang & smoke grenades - Proper netfox rollback netcode at 64 tick - Network popup UI for host/join - HUD, crosshair, round timer, scoreboard - All netfox singletons registered as autoloads (works in exported builds) ## Architecture - Listen-server (host from client, no dedicated server binary) - Multiplayer-fps game lives at examples/multiplayer-fps/ - Netfox addons registered as autoloads for exported build compat - Godot 4.7 with Forward+ renderer ## Removed - Old headless-server architecture (client_main, server_main, player.gd, etc.) - Custom netfox bootstrap with ENet fallback - Old ChaffGames FPS template (2,420 lines, 844 KB) - SimulationServer GDExtension stub - Godot-jolt physics (netfox sample uses default Godot physics) - Duplicate weapon_data.gd, anti_cheat.gd, round_manager.gd, etc. - Server browser API Python venv (87 MB) - test_range map and modular assets ## Preserved - Git history - Server config at config/default_server_config.cfg - Windows export preset - Build directory (gitignored) Co-authored-by: naxIO <naxIO@users.noreply.github.com>
129 lines
3.2 KiB
GDScript
129 lines
3.2 KiB
GDScript
@tool
|
|
extends Object
|
|
|
|
# Serializes any data into Godot builtin types ( strings, dicts, arrays, etc. ),
|
|
# so they can be safely transmitted over the network when running tests from
|
|
# the editor.
|
|
#
|
|
# See examples/custom-data-types.test.gd
|
|
|
|
const MAX_DEPTH := 128
|
|
|
|
static func serialize(data: Variant, max_depth: int = MAX_DEPTH) -> Variant:
|
|
if max_depth <= 0:
|
|
push_error("Data structure too deep to serialize! Is there a circular reference?")
|
|
return str(data)
|
|
|
|
var depth := max_depth - 1
|
|
|
|
if data == null:
|
|
return null
|
|
|
|
match typeof(data):
|
|
# Numbers
|
|
TYPE_BOOL, TYPE_INT, TYPE_FLOAT:
|
|
return data
|
|
|
|
# Strings
|
|
TYPE_STRING, TYPE_STRING_NAME, TYPE_NODE_PATH:
|
|
return str(data)
|
|
|
|
# Linalg
|
|
TYPE_VECTOR2, TYPE_VECTOR2I:
|
|
return [data.x, data.y]
|
|
|
|
TYPE_VECTOR3, TYPE_VECTOR3I:
|
|
return [data.x, data.y, data.z]
|
|
|
|
TYPE_VECTOR4, TYPE_VECTOR4I, TYPE_QUATERNION:
|
|
return [data.x, data.y, data.z, data.w]
|
|
|
|
TYPE_RECT2, TYPE_RECT2I, TYPE_AABB:
|
|
return [serialize(data.position, depth), serialize(data.size, depth)]
|
|
|
|
TYPE_PLANE:
|
|
var plane := data as Plane
|
|
return [plane.x, plane.y, plane.z, plane.d, serialize(plane.normal, depth)]
|
|
|
|
TYPE_TRANSFORM2D:
|
|
var xform := data as Transform2D
|
|
return [
|
|
serialize(xform.x, depth),
|
|
serialize(xform.y, depth),
|
|
serialize(xform.origin, depth)
|
|
]
|
|
|
|
TYPE_TRANSFORM3D:
|
|
var xform := data as Transform3D
|
|
return [serialize(xform.basis, depth)] + [serialize(xform.origin, depth)]
|
|
|
|
TYPE_BASIS:
|
|
var basis := data as Basis
|
|
return [
|
|
serialize(basis.x, depth),
|
|
serialize(basis.y, depth),
|
|
serialize(basis.z, depth)
|
|
]
|
|
|
|
TYPE_PROJECTION:
|
|
var projection := data as Projection
|
|
return [
|
|
serialize(projection.x, depth),
|
|
serialize(projection.y, depth),
|
|
serialize(projection.z, depth),
|
|
serialize(projection.w, depth)
|
|
]
|
|
|
|
# Other
|
|
TYPE_COLOR:
|
|
var color := data as Color
|
|
return [color.r, color.g, color.b, color.a]
|
|
|
|
TYPE_RID, TYPE_CALLABLE, TYPE_SIGNAL:
|
|
return str(data)
|
|
|
|
# Complex
|
|
TYPE_OBJECT:
|
|
var object := data as Object
|
|
if object.has_method("_to_vest"):
|
|
return serialize(object._to_vest(), depth)
|
|
|
|
return serialize(_object_to_map(object), depth)
|
|
|
|
# Arrays
|
|
TYPE_PACKED_BYTE_ARRAY, TYPE_PACKED_INT32_ARRAY, TYPE_PACKED_INT64_ARRAY, \
|
|
TYPE_PACKED_FLOAT32_ARRAY, TYPE_PACKED_FLOAT64_ARRAY, TYPE_PACKED_STRING_ARRAY, \
|
|
TYPE_PACKED_VECTOR2_ARRAY, TYPE_PACKED_VECTOR3_ARRAY, TYPE_PACKED_COLOR_ARRAY:
|
|
return serialize(Array(data), depth)
|
|
|
|
TYPE_ARRAY:
|
|
var array := data as Array
|
|
return array.map(func(it): return serialize(it, depth))
|
|
|
|
# Dictionary
|
|
TYPE_DICTIONARY:
|
|
var dict := data as Dictionary
|
|
var result := {}
|
|
|
|
for key in dict:
|
|
var value = dict.get(key)
|
|
result[serialize(key, max_depth - 1)] = serialize(value, depth)
|
|
return result
|
|
|
|
# Default
|
|
_: return str(data)
|
|
|
|
static func _object_to_map(object: Object) -> Dictionary:
|
|
var properties := object.get_property_list().map(func(prop): return prop["name"])
|
|
var script := object.get_script() as Script
|
|
|
|
if script != null:
|
|
properties = script.get_script_property_list().map(func(prop): return prop["name"])
|
|
|
|
var result := {}
|
|
for property in properties:
|
|
if property.contains(" "): continue # Skip invalid props
|
|
result[property] = object.get(property)
|
|
|
|
return result
|