Fresh start: replace with naxIO/netfox-cs-sample foundation
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>
This commit is contained in:
@@ -1,70 +1,134 @@
|
||||
extends RefCounted
|
||||
class_name _HistoryBuffer
|
||||
|
||||
# Maps ticks (int) to arbitrary data
|
||||
var _buffer: Dictionary = {}
|
||||
# Maps ticks (int) to arbitrary data, stored in a sliding ring buffer
|
||||
|
||||
func get_snapshot(tick: int):
|
||||
if _buffer.has(tick):
|
||||
return _buffer[tick]
|
||||
else:
|
||||
return null
|
||||
var _capacity := 64
|
||||
var _buffer := []
|
||||
var _previous := []
|
||||
|
||||
func set_snapshot(tick: int, data):
|
||||
_buffer[tick] = data
|
||||
var _tail := 0
|
||||
var _head := 0
|
||||
|
||||
func get_buffer() -> Dictionary:
|
||||
return _buffer
|
||||
static func of(capacity: int, data: Dictionary) -> _HistoryBuffer:
|
||||
var history_buffer := _HistoryBuffer.new(capacity)
|
||||
for idx in data:
|
||||
history_buffer.set_at(idx, data[idx])
|
||||
return history_buffer
|
||||
|
||||
func get_earliest_tick() -> int:
|
||||
return _buffer.keys().min()
|
||||
func _init(capacity: int = 64):
|
||||
_capacity = capacity
|
||||
_buffer.resize(_capacity)
|
||||
_previous.resize(_capacity)
|
||||
|
||||
func get_latest_tick() -> int:
|
||||
return _buffer.keys().max()
|
||||
func duplicate(deep: bool = false) -> _HistoryBuffer:
|
||||
var buffer := _HistoryBuffer.new(_capacity)
|
||||
|
||||
func get_closest_tick(tick: int) -> int:
|
||||
if _buffer.has(tick):
|
||||
return tick
|
||||
buffer._buffer = _buffer.duplicate(deep)
|
||||
buffer._previous = _previous.duplicate()
|
||||
buffer._tail = _tail
|
||||
buffer._head = _head
|
||||
|
||||
if _buffer.is_empty():
|
||||
return -1
|
||||
return buffer
|
||||
|
||||
var earliest_tick = get_earliest_tick()
|
||||
if tick < earliest_tick:
|
||||
return earliest_tick
|
||||
func push(value: Variant) -> void:
|
||||
_buffer[_head % _capacity] = value
|
||||
_previous[_head % _capacity] = _head
|
||||
_head += 1
|
||||
_tail += maxi(0, size() - capacity())
|
||||
|
||||
var latest_tick = get_latest_tick()
|
||||
if tick > latest_tick:
|
||||
return latest_tick
|
||||
func pop() -> Variant:
|
||||
assert(is_not_empty(), "History buffer is empty!")
|
||||
|
||||
return _buffer.keys() \
|
||||
.filter(func (key): return key < tick) \
|
||||
.max()
|
||||
var value = _buffer[_tail % _capacity]
|
||||
_tail += 1
|
||||
return value
|
||||
|
||||
func get_history(tick: int):
|
||||
var closest_tick = get_closest_tick(tick)
|
||||
return _buffer.get(closest_tick)
|
||||
func set_at(at: int, value: Variant) -> void:
|
||||
# Why does this need so many branches?
|
||||
if is_empty():
|
||||
# Buffer is empty, jump to specified index
|
||||
_tail = at
|
||||
_head = at
|
||||
push(value)
|
||||
elif at < _head - capacity():
|
||||
# Trying to set something that would wrap back around and overwrite
|
||||
# current data
|
||||
return
|
||||
elif at == _head:
|
||||
# Simply adding a new item
|
||||
push(value)
|
||||
elif at < _head:
|
||||
_buffer[at % _capacity] = value
|
||||
# Update prev-buffer
|
||||
for i in range(at, _head):
|
||||
if _previous[i % _capacity] == i:
|
||||
break
|
||||
_previous[i % _capacity] = at
|
||||
_tail = mini(_tail, at)
|
||||
elif at >= _head + _capacity:
|
||||
# We're leaving all data behind
|
||||
_tail = at
|
||||
_head = at
|
||||
|
||||
func trim(earliest_tick_to_keep: int):
|
||||
var ticks := _buffer.keys()
|
||||
for tick in ticks:
|
||||
if tick < earliest_tick_to_keep:
|
||||
_buffer.erase(tick)
|
||||
_previous.fill(null)
|
||||
_buffer.fill(null)
|
||||
|
||||
func clear():
|
||||
_buffer.clear()
|
||||
push(value)
|
||||
elif at >= _head:
|
||||
# Skipping forward a bit
|
||||
var previous := _head - 1
|
||||
while _head < at:
|
||||
_previous[_head % _capacity] = previous
|
||||
_head += 1
|
||||
_tail += maxi(0, size() - _capacity)
|
||||
|
||||
push(value)
|
||||
|
||||
func has_at(at: int) -> bool:
|
||||
if is_empty(): return false
|
||||
if at < _head - capacity(): return false
|
||||
if at >= _head: return false
|
||||
return _previous[at % _capacity] == at
|
||||
|
||||
func get_at(at: int, default: Variant = null) -> Variant:
|
||||
if not has_at(at):
|
||||
return default
|
||||
return _buffer[at % _capacity]
|
||||
|
||||
func has_latest_at(at: int) -> bool:
|
||||
if is_empty(): return false
|
||||
if at < _tail: return false
|
||||
return true
|
||||
|
||||
func size() -> int:
|
||||
return _buffer.size()
|
||||
return _head - _tail
|
||||
|
||||
func capacity() -> int:
|
||||
return _capacity
|
||||
|
||||
func get_earliest_index() -> int:
|
||||
return _tail
|
||||
|
||||
func get_latest_index() -> int:
|
||||
return _head - 1
|
||||
|
||||
func get_latest_index_at(at: int) -> int:
|
||||
if not has_latest_at(at):
|
||||
return -1
|
||||
if at >= _head:
|
||||
return get_latest_index()
|
||||
|
||||
return _previous[at % _capacity]
|
||||
|
||||
func get_latest_at(at: int) -> Variant:
|
||||
return get_at(get_latest_index_at(at))
|
||||
|
||||
func clear():
|
||||
_tail = _head
|
||||
|
||||
func is_empty() -> bool:
|
||||
return _buffer.is_empty()
|
||||
return size() == 0
|
||||
|
||||
func has(tick) -> bool:
|
||||
return _buffer.has(tick)
|
||||
|
||||
func ticks() -> Array:
|
||||
return _buffer.keys()
|
||||
|
||||
func erase(tick):
|
||||
_buffer.erase(tick)
|
||||
func is_not_empty() -> bool:
|
||||
return not is_empty()
|
||||
|
||||
Reference in New Issue
Block a user