Improved reconnect flow
This commit is contained in:
parent
bf08205c7d
commit
b22d0b1367
@ -1,26 +1,40 @@
|
||||
extends Node
|
||||
|
||||
func _ready():
|
||||
pause(true)
|
||||
|
||||
Global.instance_id = OS.get_process_id() % 4
|
||||
Global.username = "user%d" % Global.instance_id
|
||||
|
||||
%Login.success.connect(on_login)
|
||||
%Logout.success.connect(on_logout)
|
||||
%Login.send_login()
|
||||
|
||||
mute_audio()
|
||||
|
||||
func _input(event):
|
||||
if event.is_action_pressed("toggle_fullscreen"):
|
||||
toggle_fullscreen()
|
||||
get_viewport().set_input_as_handled()
|
||||
|
||||
func mute_audio():
|
||||
var master_sound = AudioServer.get_bus_index("Master")
|
||||
AudioServer.set_bus_mute(master_sound, true)
|
||||
|
||||
func on_login():
|
||||
print("[%s] Login succeeded." % Global.username)
|
||||
print("[%s] ID: %s" % [Global.username, Global.account_id])
|
||||
print("[%s] Auth token: %s" % [Global.username, Global.auth_token])
|
||||
|
||||
DisplayServer.window_set_title("%s - %s" % [Global.username, Global.account_id])
|
||||
DisplayServer.window_set_position(Vector2((Global.instance_id % 2) * 960, (Global.instance_id / 2 % 2) * 540))
|
||||
pause(false)
|
||||
|
||||
func on_logout():
|
||||
print("[%s] Logout." % Global.username)
|
||||
pause(true)
|
||||
|
||||
func pause(enabled: bool):
|
||||
get_tree().paused = enabled
|
||||
mute_audio(enabled)
|
||||
|
||||
func mute_audio(enabled: bool):
|
||||
var master_sound = AudioServer.get_bus_index("Master")
|
||||
AudioServer.set_bus_mute(master_sound, enabled)
|
||||
|
||||
func toggle_fullscreen():
|
||||
var mode = DisplayServer.window_get_mode()
|
||||
|
@ -1,10 +1,11 @@
|
||||
[gd_scene load_steps=24 format=3 uid="uid://b40y7iuskv1ar"]
|
||||
[gd_scene load_steps=25 format=3 uid="uid://b40y7iuskv1ar"]
|
||||
|
||||
[ext_resource type="Script" path="res://Main.gd" id="1_cw3ws"]
|
||||
[ext_resource type="Script" path="res://network/Client.gd" id="2_8hxcx"]
|
||||
[ext_resource type="Script" path="res://network/Ping.gd" id="3_d6qf1"]
|
||||
[ext_resource type="Script" path="res://network/Login.gd" id="4_fsx7a"]
|
||||
[ext_resource type="Script" path="res://network/PlayerAdd.gd" id="5_376ik"]
|
||||
[ext_resource type="Script" path="res://network/Logout.gd" id="5_au5w3"]
|
||||
[ext_resource type="PackedScene" uid="uid://2lcnu3dy54lx" path="res://player/Player.tscn" id="6_cdj8w"]
|
||||
[ext_resource type="Script" path="res://network/PlayerRemove.gd" id="7_2r42o"]
|
||||
[ext_resource type="Script" path="res://network/PlayerMove.gd" id="8_ke1yy"]
|
||||
@ -40,6 +41,7 @@ script = ExtResource("1_cw3ws")
|
||||
|
||||
[node name="Client" type="Node" parent="."]
|
||||
unique_name_in_owner = true
|
||||
process_mode = 3
|
||||
script = ExtResource("2_8hxcx")
|
||||
|
||||
[node name="Ping" type="Node" parent="Client"]
|
||||
@ -59,6 +61,11 @@ packet_type = 2
|
||||
wait_time = 5.0
|
||||
autostart = true
|
||||
|
||||
[node name="Logout" type="Node" parent="Client"]
|
||||
unique_name_in_owner = true
|
||||
script = ExtResource("5_au5w3")
|
||||
packet_type = 3
|
||||
|
||||
[node name="PlayerAdd" type="Node" parent="Client"]
|
||||
unique_name_in_owner = true
|
||||
script = ExtResource("5_376ik")
|
||||
@ -71,7 +78,6 @@ packet_type = 11
|
||||
|
||||
[node name="PlayerMove" type="Node" parent="Client"]
|
||||
script = ExtResource("8_ke1yy")
|
||||
delay = null
|
||||
packet_type = 12
|
||||
|
||||
[node name="PlayerJump" type="Node" parent="Client"]
|
||||
@ -131,6 +137,7 @@ unique_name_in_owner = true
|
||||
script = ExtResource("16_dp6bj")
|
||||
|
||||
[node name="UI" parent="." instance=ExtResource("17_43qhq")]
|
||||
process_mode = 3
|
||||
|
||||
[node name="Viewport" type="SubViewportContainer" parent="."]
|
||||
texture_filter = 1
|
||||
|
@ -8,7 +8,7 @@ func send_message(message: String):
|
||||
buffer.put_data(message.to_utf8_buffer())
|
||||
%Client.send(buffer.data_array)
|
||||
|
||||
func handle_packet(data: PackedByteArray, _peer: PacketPeer):
|
||||
func handle_packet(data: PackedByteArray):
|
||||
var buffer := StreamPeerBuffer.new()
|
||||
buffer.data_array = data
|
||||
|
||||
|
@ -21,7 +21,7 @@ func _enter_tree():
|
||||
func _process(_delta):
|
||||
while socket.get_available_packet_count() > 0:
|
||||
var packet := socket.get_packet()
|
||||
handle_packet(packet, socket)
|
||||
handle_packet(packet)
|
||||
|
||||
func update_statistics():
|
||||
download_changed.emit(download)
|
||||
@ -31,4 +31,4 @@ func update_statistics():
|
||||
|
||||
func send(data: PackedByteArray):
|
||||
socket.put_packet(data)
|
||||
upload += data.size()
|
||||
upload += data.size()
|
||||
|
@ -3,7 +3,7 @@ extends PacketHandler
|
||||
signal success
|
||||
signal failure
|
||||
|
||||
func handle_packet(data: PackedByteArray, _peer: PacketPeer):
|
||||
func handle_packet(data: PackedByteArray):
|
||||
var buffer := StreamPeerBuffer.new()
|
||||
buffer.data_array = data
|
||||
|
||||
@ -15,10 +15,6 @@ func handle_packet(data: PackedByteArray, _peer: PacketPeer):
|
||||
|
||||
Global.account_id = buffer.get_string()
|
||||
Global.auth_token = buffer.get_string()
|
||||
|
||||
print("[%s] Login succeeded." % Global.username)
|
||||
print("[%s] ID: %s" % [Global.username, Global.account_id])
|
||||
print("[%s] Auth token: %s" % [Global.username, Global.auth_token])
|
||||
|
||||
success.emit()
|
||||
|
||||
|
12
client/network/Logout.gd
Normal file
12
client/network/Logout.gd
Normal file
@ -0,0 +1,12 @@
|
||||
extends PacketHandler
|
||||
|
||||
signal success
|
||||
|
||||
func handle_packet(_data: PackedByteArray):
|
||||
logout()
|
||||
success.emit()
|
||||
|
||||
func logout():
|
||||
Global.auth_token = ""
|
||||
Global.account_id = ""
|
||||
Global.player = null
|
@ -10,7 +10,7 @@ var history: Array[float] = []
|
||||
func _init():
|
||||
history.resize(HISTORY_SIZE)
|
||||
|
||||
func handle_packet(data: PackedByteArray, _peer: PacketPeer):
|
||||
func handle_packet(data: PackedByteArray):
|
||||
var id := data[0]
|
||||
var ping := get_time() - history[id]
|
||||
changed.emit(ping)
|
||||
|
@ -7,7 +7,7 @@ signal main_player_spawned(player: Player)
|
||||
func _ready():
|
||||
assert(player_scene)
|
||||
|
||||
func handle_packet(data: PackedByteArray, _peer: PacketPeer):
|
||||
func handle_packet(data: PackedByteArray):
|
||||
var buffer := StreamPeerBuffer.new()
|
||||
buffer.data_array = data
|
||||
|
||||
@ -24,19 +24,29 @@ func handle_packet(data: PackedByteArray, _peer: PacketPeer):
|
||||
var player := spawn_player(player_id)
|
||||
player.position = server_position
|
||||
player.set_character_name(player_name)
|
||||
Global.players.add(player)
|
||||
|
||||
func spawn_player(id: String) -> Player:
|
||||
var player = player_scene.instantiate()
|
||||
var player: Player
|
||||
|
||||
if Global.players.has(id):
|
||||
player = Global.players.get_player(id)
|
||||
|
||||
if id == Global.account_id:
|
||||
Global.player = player
|
||||
|
||||
return player
|
||||
|
||||
player = player_scene.instantiate()
|
||||
player.id = id
|
||||
|
||||
if id == Global.account_id:
|
||||
Global.player = player
|
||||
player.controller = PlayerController.new()
|
||||
Global.player = player
|
||||
main_player_spawned.emit(player)
|
||||
else:
|
||||
player.controller = ProxyController.new()
|
||||
|
||||
player.controller.character = player
|
||||
player.add_child(player.controller)
|
||||
%Players.add(player)
|
||||
return player
|
||||
|
@ -11,7 +11,7 @@ func on_jump():
|
||||
buffer.put_8(PacketHandler.Packet.PLAYER_JUMP)
|
||||
%Client.send(buffer.data_array)
|
||||
|
||||
func handle_packet(data: PackedByteArray, _peer: PacketPeer):
|
||||
func handle_packet(data: PackedByteArray):
|
||||
var player_id := data.get_string_from_ascii()
|
||||
var player := Global.players.get_player(player_id)
|
||||
player.jump()
|
||||
|
@ -5,7 +5,7 @@ extends PacketHandler
|
||||
var last_sent := Time.get_ticks_msec()
|
||||
var last_sent_position := Vector3.ZERO
|
||||
|
||||
func handle_packet(data: PackedByteArray, _peer: PacketPeer):
|
||||
func handle_packet(data: PackedByteArray):
|
||||
var buffer := StreamPeerBuffer.new()
|
||||
buffer.data_array = data
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
extends PacketHandler
|
||||
|
||||
func handle_packet(data: PackedByteArray, _peer: PacketPeer):
|
||||
func handle_packet(data: PackedByteArray):
|
||||
var player_id := data.get_string_from_ascii()
|
||||
print("[%s] Remove player: %s" % [Global.username, player_id])
|
||||
%Players.remove(player_id)
|
||||
Global.players.remove(player_id)
|
@ -13,7 +13,7 @@ func get_handler(index: int) -> PacketHandler:
|
||||
func set_handler(index: int, node: PacketHandler):
|
||||
handlers[index] = node
|
||||
|
||||
func handle_packet(packet: PackedByteArray, peer: PacketPeer):
|
||||
func handle_packet(packet: PackedByteArray):
|
||||
var type := packet.decode_u8(0)
|
||||
var handler := get_handler(type)
|
||||
|
||||
@ -21,5 +21,5 @@ func handle_packet(packet: PackedByteArray, peer: PacketPeer):
|
||||
push_warning("Unknown packet type %d" % type)
|
||||
return
|
||||
|
||||
handler.handle_packet(packet.slice(1), peer)
|
||||
handler.handle_packet(packet.slice(1))
|
||||
download += packet.size()
|
||||
|
@ -16,5 +16,5 @@ enum Packet {
|
||||
|
||||
@export var packet_type: Packet
|
||||
|
||||
func handle_packet(_data: PackedByteArray, _peer: PacketPeer):
|
||||
func handle_packet(_data: PackedByteArray):
|
||||
pass
|
5
client/player/controller/Controller.gd
Normal file
5
client/player/controller/Controller.gd
Normal file
@ -0,0 +1,5 @@
|
||||
class_name Controller
|
||||
extends Node
|
||||
|
||||
## The character that we're controlling.
|
||||
@export var character: Character
|
@ -1,8 +1,5 @@
|
||||
class_name PlayerController
|
||||
extends Node
|
||||
|
||||
## The character that we're controlling.
|
||||
@export var character: Character
|
||||
extends Controller
|
||||
|
||||
var move: Vector2
|
||||
|
||||
|
@ -1,20 +1,19 @@
|
||||
class_name ProxyController
|
||||
extends Node
|
||||
|
||||
## The character that we're controlling.
|
||||
@export var character: Character
|
||||
extends Controller
|
||||
|
||||
## The authoritative position on the server.
|
||||
var server_position: Vector3
|
||||
|
||||
func _ready():
|
||||
print(character.name, ".old: ", server_position)
|
||||
server_position = character.position
|
||||
print(character.name, ".new: ", server_position)
|
||||
|
||||
func _process(_delta):
|
||||
var move := server_position - character.position
|
||||
move.y = 0.0
|
||||
|
||||
if move.length_squared() < 0.01:
|
||||
# character.position = server_position
|
||||
character.direction = Vector3.ZERO
|
||||
return
|
||||
|
||||
|
@ -7,9 +7,13 @@ var ping_changed: Signal
|
||||
var download_changed: Signal
|
||||
var upload_changed: Signal
|
||||
var message_received: Signal
|
||||
var login: Signal
|
||||
var logout: Signal
|
||||
|
||||
func _enter_tree():
|
||||
ping_changed = %Ping.changed
|
||||
download_changed = %Client.download_changed
|
||||
upload_changed = %Client.upload_changed
|
||||
message_received = %Chat.message_received
|
||||
login = %Login.success
|
||||
logout = %Logout.success
|
||||
|
@ -1,4 +1,4 @@
|
||||
[gd_scene load_steps=11 format=3 uid="uid://dagn5bf7ou3sd"]
|
||||
[gd_scene load_steps=12 format=3 uid="uid://dagn5bf7ou3sd"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://cch67vqpsmtej" path="res://ui/debug/DebugLabel.tscn" id="1_7s8uu"]
|
||||
[ext_resource type="Script" path="res://ui/UI.gd" id="1_l5b6o"]
|
||||
@ -10,6 +10,7 @@
|
||||
[ext_resource type="Script" path="res://ui/chat/ChatInput.gd" id="6_cg2h5"]
|
||||
[ext_resource type="Script" path="res://ui/debug/UploadLabel.gd" id="7_cfnpx"]
|
||||
[ext_resource type="Script" path="res://ui/debug/DownloadLabel.gd" id="8_ogt38"]
|
||||
[ext_resource type="Script" path="res://ui/connect/ConnectPanel.gd" id="11_cwl0t"]
|
||||
|
||||
[node name="UI" type="Control"]
|
||||
layout_mode = 3
|
||||
@ -102,6 +103,29 @@ layout_mode = 2
|
||||
alignment = 2
|
||||
script = ExtResource("5_8lm6a")
|
||||
|
||||
[node name="ConnectPanel" type="Panel" parent="CanvasLayer"]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("11_cwl0t")
|
||||
|
||||
[node name="ConnectLabel" type="Label" parent="CanvasLayer/ConnectPanel"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -47.5
|
||||
offset_top = -10.0
|
||||
offset_right = 47.5
|
||||
offset_bottom = 10.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
text = "Connecting..."
|
||||
|
||||
[connection signal="focus_entered" from="CanvasLayer/BottomLeft/Chat/ChatInput" to="CanvasLayer/BottomLeft/Chat/ChatInput" method="_on_focus_entered"]
|
||||
[connection signal="focus_exited" from="CanvasLayer/BottomLeft/Chat/ChatInput" to="CanvasLayer/BottomLeft/Chat/ChatInput" method="_on_focus_exited"]
|
||||
[connection signal="text_submitted" from="CanvasLayer/BottomLeft/Chat/ChatInput" to="CanvasLayer/BottomLeft/Chat/ChatInput" method="_on_text_submitted"]
|
||||
|
11
client/ui/connect/ConnectPanel.gd
Normal file
11
client/ui/connect/ConnectPanel.gd
Normal file
@ -0,0 +1,11 @@
|
||||
extends Panel
|
||||
|
||||
func _ready():
|
||||
owner.login.connect(on_login)
|
||||
owner.logout.connect(on_logout)
|
||||
|
||||
func on_login():
|
||||
hide()
|
||||
|
||||
func on_logout():
|
||||
show()
|
@ -7,12 +7,18 @@ func _ready():
|
||||
Global.players = self
|
||||
|
||||
func add(player: Player):
|
||||
if has(player.id):
|
||||
return
|
||||
|
||||
add_child(player)
|
||||
players[player.id] = player
|
||||
|
||||
func get_player(id: String) -> Player:
|
||||
return players[id] as Player
|
||||
|
||||
func has(id: String) -> bool:
|
||||
return players.has(id)
|
||||
|
||||
func remove(id: String):
|
||||
if !players.has(id):
|
||||
return
|
||||
|
@ -2,6 +2,7 @@ package game
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Chat is used for chat messages.
|
||||
@ -12,9 +13,30 @@ func (game *Game) Chat(data []byte, address *net.UDPAddr) error {
|
||||
return ErrUnknownAddress
|
||||
}
|
||||
|
||||
message := string(data)
|
||||
|
||||
if game.ChatCommand(player, message) {
|
||||
return nil
|
||||
}
|
||||
|
||||
newData := []byte{}
|
||||
newData = AppendString(newData, player.ID)
|
||||
newData = AppendStringBytes(newData, data)
|
||||
newData = AppendString(newData, message)
|
||||
game.Broadcast(Chat, newData)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ChatCommand executes chat commands and returns true if it was one.
|
||||
func (game *Game) ChatCommand(player *Player, message string) bool {
|
||||
if strings.HasPrefix(message, "/") {
|
||||
switch message {
|
||||
case "/logout":
|
||||
game.server.Send(Logout, nil, player.address)
|
||||
game.players.Remove(player)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
// Game represents the entire state of the game server.
|
||||
type Game struct {
|
||||
server *Server
|
||||
router Router
|
||||
router *Router
|
||||
players *PlayerManager
|
||||
}
|
||||
|
||||
@ -21,19 +21,26 @@ func New() *Game {
|
||||
players: NewPlayerManager(),
|
||||
}
|
||||
|
||||
game.router.Get(Ping, game.Ping)
|
||||
game.router.Get(Login, game.Login)
|
||||
game.router.Get(Move, game.Move)
|
||||
game.router.Get(Jump, game.Jump)
|
||||
game.router.Get(Chat, game.Chat)
|
||||
game.router = NewRouter(game)
|
||||
return game
|
||||
}
|
||||
|
||||
// NewRouter creates a new router.
|
||||
func NewRouter(game *Game) *Router {
|
||||
router := &Router{}
|
||||
router.Get(Ping, game.Ping)
|
||||
router.Get(Login, game.Login)
|
||||
router.Get(Move, game.Move)
|
||||
router.Get(Jump, game.Jump)
|
||||
router.Get(Chat, game.Chat)
|
||||
return router
|
||||
}
|
||||
|
||||
// Run starts all game systems.
|
||||
func (game *Game) Run() {
|
||||
physics := time.NewTicker(20 * time.Millisecond)
|
||||
statistics := time.NewTicker(time.Second)
|
||||
clean := time.NewTicker(time.Second)
|
||||
physics := time.NewTicker(20 * time.Millisecond).C
|
||||
statistics := time.NewTicker(time.Second).C
|
||||
clean := time.NewTicker(time.Second).C
|
||||
close := make(chan os.Signal, 1)
|
||||
signal.Notify(close, os.Interrupt)
|
||||
|
||||
@ -44,16 +51,16 @@ func (game *Game) Run() {
|
||||
case p := <-game.server.incoming:
|
||||
game.router.handle(p)
|
||||
|
||||
case <-physics.C:
|
||||
case <-physics:
|
||||
game.players.Each(func(c *Player) {
|
||||
c.Tick()
|
||||
})
|
||||
|
||||
case <-statistics.C:
|
||||
case <-statistics:
|
||||
fmt.Printf("%d players | %d packets\n", game.players.Count(), game.server.PacketCount())
|
||||
game.server.ResetPacketCount()
|
||||
|
||||
case <-clean.C:
|
||||
case <-clean:
|
||||
game.players.Clean(5 * time.Second)
|
||||
|
||||
case <-close:
|
||||
|
@ -50,21 +50,14 @@ func (game *Game) Login(data []byte, address *net.UDPAddr) error {
|
||||
player = game.players.ByAccount(account.ID)
|
||||
|
||||
if player != nil {
|
||||
game.reconnect(player, address)
|
||||
} else {
|
||||
game.connect(account, address)
|
||||
game.server.Send(Login, []byte{Failure}, address)
|
||||
return ErrAlreadyLoggedIn
|
||||
}
|
||||
|
||||
game.connect(account, address)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (game *Game) reconnect(player *Player, address *net.UDPAddr) {
|
||||
player.KeepAlive()
|
||||
game.players.ChangeAddress(player, address)
|
||||
game.sendLoginSuccess(player)
|
||||
player.OnConnect()
|
||||
}
|
||||
|
||||
func (game *Game) connect(account *Account, address *net.UDPAddr) {
|
||||
player := NewPlayer(address, account, game)
|
||||
player.authToken = createAuthToken()
|
||||
|
@ -48,6 +48,7 @@ func (player *Player) State() []byte {
|
||||
return state
|
||||
}
|
||||
|
||||
// OnConnect is executed when a connection has been established.
|
||||
func (player *Player) OnConnect() {
|
||||
fmt.Printf("%s connected.\n", player.Name)
|
||||
players := player.game.players
|
||||
@ -62,6 +63,7 @@ func (player *Player) OnConnect() {
|
||||
})
|
||||
}
|
||||
|
||||
// OnDisconnect is executed when the connection has been closed.
|
||||
func (player *Player) OnDisconnect() {
|
||||
fmt.Printf("%s disconnected.\n", player.Name)
|
||||
player.game.BroadcastOthers(PlayerRemove, []byte(player.ID), player)
|
||||
|
@ -2,92 +2,96 @@ package game
|
||||
|
||||
import (
|
||||
"net"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
// PlayerManager keeps tracks of all players.
|
||||
type PlayerManager struct {
|
||||
players sync.Map
|
||||
accounts sync.Map
|
||||
count atomic.Int64
|
||||
players map[string]*Player
|
||||
accounts map[string]*Player
|
||||
count int
|
||||
}
|
||||
|
||||
// NewPlayerManager creates a new player manager.
|
||||
func NewPlayerManager() *PlayerManager {
|
||||
return &PlayerManager{}
|
||||
}
|
||||
|
||||
func (m *PlayerManager) Clean(timeout time.Duration) {
|
||||
now := time.Now()
|
||||
|
||||
m.players.Range(func(key, value interface{}) bool {
|
||||
player := value.(*Player)
|
||||
|
||||
if !player.lastPacket.IsZero() && now.After(player.lastPacket.Add(timeout)) {
|
||||
m.players.Delete(key)
|
||||
m.accounts.Delete(player.ID)
|
||||
m.count.Add(-1)
|
||||
player.OnDisconnect()
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
return &PlayerManager{
|
||||
players: map[string]*Player{},
|
||||
accounts: map[string]*Player{},
|
||||
}
|
||||
}
|
||||
|
||||
// Add adds a new player.
|
||||
func (m *PlayerManager) Add(player *Player) {
|
||||
m.players.Store(player.address.String(), player)
|
||||
m.accounts.Store(player.ID, player)
|
||||
m.count.Add(1)
|
||||
m.players[player.address.String()] = player
|
||||
m.accounts[player.ID] = player
|
||||
m.count++
|
||||
player.OnConnect()
|
||||
}
|
||||
|
||||
// ChangeAddress changes the address of a player.
|
||||
func (m *PlayerManager) ChangeAddress(player *Player, address *net.UDPAddr) {
|
||||
m.players.Delete(player.address.String())
|
||||
delete(m.players, player.address.String())
|
||||
player.address = address
|
||||
m.players.Store(player.address.String(), player)
|
||||
m.players[player.address.String()] = player
|
||||
}
|
||||
|
||||
// Clean checks for players who haven't responded in the timeout duration and disconnects them.
|
||||
func (m *PlayerManager) Clean(timeout time.Duration) {
|
||||
now := time.Now()
|
||||
|
||||
for _, player := range m.players {
|
||||
if player.lastPacket.IsZero() || now.Before(player.lastPacket.Add(timeout)) {
|
||||
continue
|
||||
}
|
||||
|
||||
m.Remove(player)
|
||||
}
|
||||
}
|
||||
|
||||
// Remove removes a player.
|
||||
func (m *PlayerManager) Remove(player *Player) {
|
||||
delete(m.players, player.address.String())
|
||||
delete(m.accounts, player.ID)
|
||||
m.count--
|
||||
player.OnDisconnect()
|
||||
}
|
||||
|
||||
// Contains tells you whether the address is already a registered client.
|
||||
func (m *PlayerManager) Contains(address *net.UDPAddr) bool {
|
||||
_, exists := m.players.Load(address.String())
|
||||
_, exists := m.players[address.String()]
|
||||
return exists
|
||||
}
|
||||
|
||||
// Count returns the number of clients.
|
||||
func (m *PlayerManager) Count() int {
|
||||
return int(m.count.Load())
|
||||
return m.count
|
||||
}
|
||||
|
||||
// Each calls the callback function for each client.
|
||||
func (m *PlayerManager) Each(callback func(*Player)) {
|
||||
m.players.Range(func(key, value any) bool {
|
||||
callback(value.(*Player))
|
||||
return true
|
||||
})
|
||||
for _, player := range m.players {
|
||||
callback(player)
|
||||
}
|
||||
}
|
||||
|
||||
// ByAddress returns an existing client for the requested address.
|
||||
func (m *PlayerManager) ByAddress(address *net.UDPAddr) *Player {
|
||||
obj, exists := m.players.Load(address.String())
|
||||
player, exists := m.players[address.String()]
|
||||
|
||||
if !exists {
|
||||
return nil
|
||||
}
|
||||
|
||||
return obj.(*Player)
|
||||
return player
|
||||
}
|
||||
|
||||
// ByAccount returns the player with the given account ID.
|
||||
func (m *PlayerManager) ByAccount(id string) *Player {
|
||||
obj, exists := m.accounts.Load(id)
|
||||
player, exists := m.accounts[id]
|
||||
|
||||
if !exists {
|
||||
return nil
|
||||
}
|
||||
|
||||
return obj.(*Player)
|
||||
return player
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user