124 lines
4.9 KiB
GDScript
124 lines
4.9 KiB
GDScript
extends SceneTree
|
|
|
|
var game: Node3D
|
|
var is_server := false
|
|
var elapsed := 0.0
|
|
var sequence := 0
|
|
var started := false
|
|
var initial := Vector3.ZERO
|
|
var moved := false
|
|
var saw_two_humans := false
|
|
var expected_humans := 2
|
|
var snapshots := 0
|
|
var vertical := false
|
|
var placed := false
|
|
var saw_upper_floor := false
|
|
var killcam := false
|
|
var forced_kill := false
|
|
var saw_killer := false
|
|
var saw_respawn := false
|
|
var saw_skin := false
|
|
var saw_loot := false
|
|
var saw_shield := false
|
|
var requested_shield := false
|
|
|
|
func _initialize() -> void:
|
|
is_server = "--server" in OS.get_cmdline_user_args()
|
|
vertical = "--vertical" in OS.get_cmdline_user_args()
|
|
killcam = "--killcam" in OS.get_cmdline_user_args()
|
|
expected_humans = 8 if "--eight" in OS.get_cmdline_user_args() else 2
|
|
call_deferred("start")
|
|
|
|
func start() -> void:
|
|
game = load("res://scenes/main.tscn").instantiate()
|
|
root.add_child(game)
|
|
await physics_frame
|
|
game.port = 27993 if vertical else 27991
|
|
if is_server:
|
|
game.host({"server_name": "Network test", "mode": "TDM", "max_players": 8, "bots": 7, "score_limit": 50, "time_limit": 600})
|
|
else:
|
|
game.nickname = "NetworkClient"
|
|
game.loadout = 9
|
|
WeaponSkins.set_design(9, {"receiver": Color.CYAN, "text": "LAN TEST"})
|
|
game.join("127.0.0.1:%s" % game.port)
|
|
started = true
|
|
|
|
func _physics_process(dt: float) -> bool:
|
|
if not started:
|
|
return false
|
|
elapsed += dt
|
|
if game.active:
|
|
if is_server and game.ammo_drops.rows.is_empty() and elapsed < 1.5:
|
|
game.ammo_drops.serial += 1
|
|
game.ammo_drops.rows.append({"id": game.ammo_drops.serial, "p": Vector3(40, 0.3, 50), "left": 30.0})
|
|
saw_loot = saw_loot or not game.ammo_drops.rows.is_empty()
|
|
var humans := 0
|
|
for p: Fighter in game.players.values():
|
|
if not p.bot:
|
|
humans += 1
|
|
if p.peer_id != 1 and p.shield_left > 0 and p.shield_charges == 0:
|
|
saw_shield = true
|
|
if p.peer_id != 1 and p.primary == 9:
|
|
var finish: Dictionary = p.skin_designs.get("9", {})
|
|
saw_skin = saw_skin or (finish.get("text", "") == "LAN TEST" and finish.get("receiver", Color.WHITE) == Color.CYAN)
|
|
if humans == expected_humans:
|
|
saw_two_humans = true
|
|
if killcam and is_server:
|
|
for candidate: Fighter in game.players.values():
|
|
candidate.protection = 60
|
|
if humans == 2 and elapsed > 2 and not forced_kill:
|
|
for candidate: Fighter in game.players.values():
|
|
if candidate.bot or candidate.peer_id == 1:
|
|
continue
|
|
for attacker: Fighter in game.players.values():
|
|
if attacker.bot and game.enemies(candidate, attacker):
|
|
candidate.protection = 0
|
|
candidate.shield_left = 0
|
|
game.combat.damage(candidate, attacker, 200, "KILLCAM TEST", false)
|
|
forced_kill = true
|
|
break
|
|
if vertical and is_server and humans == 2 and not placed:
|
|
for candidate: Fighter in game.players.values():
|
|
if not candidate.bot and candidate.peer_id != 1:
|
|
candidate.reset_at(Vector3(-9, 0.15, -13.4))
|
|
candidate.protection = 30
|
|
placed = true
|
|
if not is_server and game.players.has(game.local_id):
|
|
game.set_physics_process(false)
|
|
var p: Fighter = game.players[game.local_id]
|
|
if not requested_shield:
|
|
game.submit_actions.rpc_id(1, 1, {"shield": true})
|
|
requested_shield = true
|
|
if killcam:
|
|
saw_killer = saw_killer or (p.hp <= 0 and p.killer_id < 0 and game.players.has(p.killer_id) and p.killer_weapon == "KILLCAM TEST")
|
|
saw_respawn = saw_respawn or (saw_killer and p.hp > 0 and p.killer_id == 0)
|
|
if snapshots == 0:
|
|
initial = p.target_position
|
|
snapshots += 1
|
|
moved = moved or initial.distance_to(p.target_position) > 1.5
|
|
saw_upper_floor = saw_upper_floor or p.target_position.y > 3.4
|
|
sequence += 1
|
|
var movement := Vector2(-1, 0)
|
|
if vertical:
|
|
movement = Vector2(0, -1) if p.target_position.z > -22.5 else Vector2.ZERO
|
|
# Spoofed HP and positions are deliberately present: server ignores them.
|
|
game.submit_input.rpc_id(1, sequence, {"move": movement, "yaw": 0.0, "pitch": 0.0,
|
|
"hp": 99999, "p": Vector3(900, 900, 900)})
|
|
if p.hp > 100 or p.target_position.length() > 100:
|
|
printerr("FAIL client-authoritative state accepted")
|
|
quit(1)
|
|
if elapsed > (15 if is_server else 9):
|
|
var success: bool = saw_loot and saw_shield and saw_skin and saw_two_humans and game.players.size() == 8 and (is_server or moved)
|
|
if killcam:
|
|
success = success and (forced_kill if is_server else saw_killer and saw_respawn)
|
|
print("NETWORK KILLCAM killed=", forced_kill, " received_killer=", saw_killer, " respawn=", saw_respawn)
|
|
if vertical and not is_server:
|
|
success = success and saw_upper_floor
|
|
print("VERTICAL upper_floor_snapshot=", saw_upper_floor)
|
|
print("NETWORK LOOT received=", saw_loot)
|
|
print("NETWORK SKIN received=", saw_skin, " SHIELD received=", saw_shield)
|
|
print("NETWORK ", "HOST" if is_server else "CLIENT", " expected_humans=", expected_humans, " observed=", saw_two_humans, " slots=", game.players.size(), " moved=", moved, " result=", success)
|
|
game.leave()
|
|
quit(0 if success else 1)
|
|
return false
|