Added player identification
This commit is contained in:
parent
0172a81bdf
commit
2cd93f2a39
@ -2,3 +2,6 @@ extends Node
|
|||||||
|
|
||||||
var camera: Camera3D
|
var camera: Camera3D
|
||||||
var player: Player
|
var player: Player
|
||||||
|
var instance_id := OS.get_process_id() % 4
|
||||||
|
var username := "user%d" % instance_id
|
||||||
|
var account_id: String
|
||||||
|
@ -1,21 +1,28 @@
|
|||||||
extends PacketHandler
|
extends PacketHandler
|
||||||
|
|
||||||
var auth_token: String
|
var auth_token: String
|
||||||
var instance_id := OS.get_process_id() % 4
|
|
||||||
var username := "user%d" % instance_id
|
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
DisplayServer.window_set_title(username)
|
DisplayServer.window_set_title(Global.username)
|
||||||
send_login()
|
send_login()
|
||||||
|
|
||||||
func handle_packet(data: PackedByteArray, _peer: PacketPeer):
|
func handle_packet(data: PackedByteArray, _peer: PacketPeer):
|
||||||
if data[0] != 0:
|
var buffer := StreamPeerBuffer.new()
|
||||||
print("[Client] Login failed.")
|
buffer.data_array = data
|
||||||
|
|
||||||
|
var error := buffer.get_8()
|
||||||
|
if error != 0:
|
||||||
|
print("[%s] Login failed." % Global.username)
|
||||||
return
|
return
|
||||||
|
|
||||||
print("[Client] Login succeeded.")
|
Global.account_id = buffer.get_string()
|
||||||
auth_token = data.slice(1).get_string_from_ascii()
|
auth_token = buffer.get_string()
|
||||||
print("[Client] Auth token: %s" % auth_token)
|
|
||||||
|
print("[%s] Login succeeded." % Global.username)
|
||||||
|
print("[%s] ID: %s" % [Global.username, Global.account_id])
|
||||||
|
print("[%s] Auth token: %s" % [Global.username, auth_token])
|
||||||
|
|
||||||
|
DisplayServer.window_set_title("%s - %s" % [Global.username, Global.account_id])
|
||||||
|
|
||||||
func send_login():
|
func send_login():
|
||||||
if is_logged_in():
|
if is_logged_in():
|
||||||
@ -24,9 +31,9 @@ func send_login():
|
|||||||
var password := "password"
|
var password := "password"
|
||||||
var buffer := StreamPeerBuffer.new()
|
var buffer := StreamPeerBuffer.new()
|
||||||
buffer.put_8(Packet.LOGIN)
|
buffer.put_8(Packet.LOGIN)
|
||||||
buffer.put_data(JSON.stringify([username, password]).to_utf8_buffer())
|
buffer.put_data(JSON.stringify([Global.username, password]).to_utf8_buffer())
|
||||||
%Client.socket.put_packet(buffer.data_array)
|
%Client.socket.put_packet(buffer.data_array)
|
||||||
print("[Client] Connecting...")
|
print("[%s] Connecting..." % Global.username)
|
||||||
|
|
||||||
func is_logged_in() -> bool:
|
func is_logged_in() -> bool:
|
||||||
return auth_token != ""
|
return auth_token != ""
|
@ -6,21 +6,24 @@ func _ready():
|
|||||||
assert(player_scene)
|
assert(player_scene)
|
||||||
|
|
||||||
func handle_packet(data: PackedByteArray, _peer: PacketPeer):
|
func handle_packet(data: PackedByteArray, _peer: PacketPeer):
|
||||||
var player_name := data.get_string_from_utf8()
|
var buffer := StreamPeerBuffer.new()
|
||||||
print(player_name)
|
buffer.data_array = data
|
||||||
|
|
||||||
|
var player_id := buffer.get_string()
|
||||||
|
var player_name := buffer.get_string()
|
||||||
|
|
||||||
var position_data := data.slice(player_name.length() + 1)
|
|
||||||
var server_position := Vector3()
|
var server_position := Vector3()
|
||||||
server_position.x = position_data.decode_float(0)
|
server_position.x = buffer.get_float()
|
||||||
server_position.y = position_data.decode_float(4)
|
server_position.y = buffer.get_float()
|
||||||
server_position.z = position_data.decode_float(8)
|
server_position.z = buffer.get_float()
|
||||||
print(server_position)
|
|
||||||
|
print("[%s] Add player: %s %s @ %v" % [Global.username, player_id, player_name, server_position])
|
||||||
|
|
||||||
var player := spawn_player()
|
var player := spawn_player()
|
||||||
player.position = server_position
|
player.position = server_position
|
||||||
player.set_character_name(player_name)
|
player.set_character_name(player_name)
|
||||||
|
|
||||||
if false:
|
if player_id == Global.account_id:
|
||||||
Global.player = player
|
Global.player = player
|
||||||
var controller := PlayerController.new()
|
var controller := PlayerController.new()
|
||||||
controller.character = Global.player
|
controller.character = Global.player
|
@ -6,8 +6,9 @@ enum Packet {
|
|||||||
PING = 1,
|
PING = 1,
|
||||||
LOGIN = 2,
|
LOGIN = 2,
|
||||||
LOGOUT = 3,
|
LOGOUT = 3,
|
||||||
PLAYER_STATE = 10,
|
PLAYER_ADD = 10,
|
||||||
PLAYER_MOVE = 11,
|
PLAYER_REMOVE = 11,
|
||||||
|
PLAYER_MOVE = 12,
|
||||||
}
|
}
|
||||||
|
|
||||||
@export var packet_type: Packet
|
@export var packet_type: Packet
|
||||||
|
@ -29,6 +29,6 @@ shape = SubResource("CapsuleShape3D_2f50n")
|
|||||||
[node name="Health" parent="." instance=ExtResource("2_np5ag")]
|
[node name="Health" parent="." instance=ExtResource("2_np5ag")]
|
||||||
|
|
||||||
[node name="Label" type="Label3D" parent="."]
|
[node name="Label" type="Label3D" parent="."]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.8, 0)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, 0)
|
||||||
billboard = 1
|
billboard = 1
|
||||||
text = "ABC"
|
text = "Player"
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
[ext_resource type="Script" path="res://network/Client.gd" id="2_1ofik"]
|
[ext_resource type="Script" path="res://network/Client.gd" id="2_1ofik"]
|
||||||
[ext_resource type="Script" path="res://network/Ping.gd" id="3_4h5la"]
|
[ext_resource type="Script" path="res://network/Ping.gd" id="3_4h5la"]
|
||||||
[ext_resource type="Script" path="res://network/Login.gd" id="4_k8n1i"]
|
[ext_resource type="Script" path="res://network/Login.gd" id="4_k8n1i"]
|
||||||
|
[ext_resource type="Script" path="res://network/PlayerAdd.gd" id="5_1dcs7"]
|
||||||
[ext_resource type="PackedScene" uid="uid://2lcnu3dy54lx" path="res://player/Player.tscn" id="5_22pku"]
|
[ext_resource type="PackedScene" uid="uid://2lcnu3dy54lx" path="res://player/Player.tscn" id="5_22pku"]
|
||||||
[ext_resource type="Script" path="res://network/PlayerState.gd" id="5_wttxq"]
|
|
||||||
[ext_resource type="Environment" uid="uid://dixa0yso2s1u3" path="res://world/Environment.tres" id="8_5uta8"]
|
[ext_resource type="Environment" uid="uid://dixa0yso2s1u3" path="res://world/Environment.tres" id="8_5uta8"]
|
||||||
[ext_resource type="CameraAttributesPractical" uid="uid://b835orxyqq6w5" path="res://camera/CameraAttributes.tres" id="9_w4cdu"]
|
[ext_resource type="CameraAttributesPractical" uid="uid://b835orxyqq6w5" path="res://camera/CameraAttributes.tres" id="9_w4cdu"]
|
||||||
[ext_resource type="PackedScene" uid="uid://tgmbtt7u172g" path="res://world/Arena.blend" id="10_cje7b"]
|
[ext_resource type="PackedScene" uid="uid://tgmbtt7u172g" path="res://world/Arena.blend" id="10_cje7b"]
|
||||||
@ -46,8 +46,8 @@ packet_type = 2
|
|||||||
wait_time = 5.0
|
wait_time = 5.0
|
||||||
autostart = true
|
autostart = true
|
||||||
|
|
||||||
[node name="PlayerState" type="Node" parent="Client"]
|
[node name="PlayerAdd" type="Node" parent="Client"]
|
||||||
script = ExtResource("5_wttxq")
|
script = ExtResource("5_1dcs7")
|
||||||
player_scene = ExtResource("5_22pku")
|
player_scene = ExtResource("5_22pku")
|
||||||
packet_type = 10
|
packet_type = 10
|
||||||
|
|
||||||
|
9
server/game/Account.go
Normal file
9
server/game/Account.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package game
|
||||||
|
|
||||||
|
// Account represents a player account
|
||||||
|
type Account struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
Position Vector3 `json:"position"`
|
||||||
|
}
|
33
server/game/Database.go
Normal file
33
server/game/Database.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package game
|
||||||
|
|
||||||
|
var accounts = map[string]*Account{
|
||||||
|
"user0": {
|
||||||
|
ID: "4J6qpK1ve",
|
||||||
|
Name: "user0",
|
||||||
|
Password: "password",
|
||||||
|
Position: Vector3{5, 0, 0},
|
||||||
|
},
|
||||||
|
"user1": {
|
||||||
|
ID: "I_vyeZamg",
|
||||||
|
Name: "user1",
|
||||||
|
Password: "password",
|
||||||
|
Position: Vector3{-5, 0, 0},
|
||||||
|
},
|
||||||
|
"user2": {
|
||||||
|
ID: "VJOK1ckvx",
|
||||||
|
Name: "user2",
|
||||||
|
Password: "password",
|
||||||
|
Position: Vector3{0, 0, 5},
|
||||||
|
},
|
||||||
|
"user3": {
|
||||||
|
ID: "EkCcqbwFl",
|
||||||
|
Name: "user3",
|
||||||
|
Password: "password",
|
||||||
|
Position: Vector3{0, 0, -5},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAccountByName retrieves the account with the given name.
|
||||||
|
func GetAccountByName(name string) *Account {
|
||||||
|
return accounts[name]
|
||||||
|
}
|
@ -3,61 +3,75 @@ package game
|
|||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"encoding/binary"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"net"
|
"net"
|
||||||
"server/game/packet"
|
"server/game/packet"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
const (
|
||||||
LoginSuccess = []byte{0}
|
Success = 0
|
||||||
LoginFailure = []byte{1}
|
Failure = 1
|
||||||
)
|
)
|
||||||
|
|
||||||
// Login checks the account credentials and gives a network peer access to an account.
|
// Login checks the account credentials and gives a network peer access to an account.
|
||||||
func (game *Game) Login(data []byte, address *net.UDPAddr, server *Server) error {
|
func (game *Game) Login(data []byte, address *net.UDPAddr, server *Server) error {
|
||||||
|
if game.players.Get(address) != nil {
|
||||||
|
server.Send(packet.Login, []byte{Failure}, address)
|
||||||
|
return errors.New("already logged in")
|
||||||
|
}
|
||||||
|
|
||||||
username, password, err := getLoginData(data)
|
username, password, err := getLoginData(data)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
server.Send(packet.Login, LoginFailure, address)
|
server.Send(packet.Login, []byte{Failure}, address)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
account := GetAccountByName(username)
|
||||||
|
|
||||||
|
if account == nil {
|
||||||
|
server.Send(packet.Login, []byte{Failure}, address)
|
||||||
|
return errors.New("unknown account name")
|
||||||
|
}
|
||||||
|
|
||||||
if password != "password" {
|
if password != "password" {
|
||||||
server.Send(packet.Login, LoginFailure, address)
|
server.Send(packet.Login, []byte{Failure}, address)
|
||||||
return errors.New("login failure")
|
return errors.New("login failure")
|
||||||
}
|
}
|
||||||
|
|
||||||
player := game.players.Get(address)
|
player := game.players.Add(address, account)
|
||||||
player.AuthToken = createAuthToken()
|
player.authToken = createAuthToken()
|
||||||
player.Name = username
|
|
||||||
player.KeepAlive()
|
player.KeepAlive()
|
||||||
|
|
||||||
if username == "user0" {
|
response := []byte{Success}
|
||||||
player.Position.X = 5.0
|
response = appendString(response, account.ID)
|
||||||
}
|
response = appendString(response, player.authToken)
|
||||||
|
server.Send(packet.Login, response, address)
|
||||||
|
|
||||||
if username == "user1" {
|
game.onLogin(player)
|
||||||
player.Position.X = -5.0
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if username == "user2" {
|
func appendString(data []byte, str string) []byte {
|
||||||
player.Position.Z = -5.0
|
data = binary.LittleEndian.AppendUint32(data, uint32(len(str)))
|
||||||
}
|
data = append(data, []byte(str)...)
|
||||||
|
return data
|
||||||
if username == "user3" {
|
}
|
||||||
player.Position.Z = 5.0
|
|
||||||
}
|
|
||||||
|
|
||||||
server.Send(packet.Login, append(LoginSuccess, []byte(player.AuthToken)...), address)
|
|
||||||
player.OnConnect()
|
|
||||||
|
|
||||||
|
// Inform the newly logged in player about existing players.
|
||||||
|
// Also inform existing players about the newly logged in player.
|
||||||
|
func (game *Game) onLogin(player *Player) {
|
||||||
game.players.Each(func(other *Player) bool {
|
game.players.Each(func(other *Player) bool {
|
||||||
server.Send(packet.PlayerState, other.State(), address)
|
game.server.Send(packet.PlayerAdd, other.State(), player.address)
|
||||||
|
|
||||||
|
if other != player {
|
||||||
|
game.server.Send(packet.PlayerAdd, player.State(), other.address)
|
||||||
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLoginData(data []byte) (string, string, error) {
|
func getLoginData(data []byte) (string, string, error) {
|
||||||
|
@ -8,16 +8,16 @@ import (
|
|||||||
|
|
||||||
// Player represents a logged in client.
|
// Player represents a logged in client.
|
||||||
type Player struct {
|
type Player struct {
|
||||||
Name string `json:"name"`
|
*Account
|
||||||
Position Vector3 `json:"position"`
|
authToken string
|
||||||
AuthToken string
|
|
||||||
address *net.UDPAddr
|
address *net.UDPAddr
|
||||||
lastPacket time.Time
|
lastPacket time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClient creates a new client.
|
// NewPlayer creates a new player.
|
||||||
func NewClient(address *net.UDPAddr) *Player {
|
func NewPlayer(account *Account, address *net.UDPAddr) *Player {
|
||||||
return &Player{
|
return &Player{
|
||||||
|
Account: account,
|
||||||
address: address,
|
address: address,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -37,9 +37,11 @@ func (c *Player) Tick() {
|
|||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
|
|
||||||
// State returns the player state (name and position).
|
// State returns the player state (ID, name and position).
|
||||||
func (player *Player) State() []byte {
|
func (player *Player) State() []byte {
|
||||||
state := []byte(player.Name + "\u0000")
|
state := []byte{}
|
||||||
|
state = appendString(state, player.ID)
|
||||||
|
state = appendString(state, player.Name)
|
||||||
state = appendVector3(state, player.Position)
|
state = appendVector3(state, player.Position)
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
@ -43,9 +43,18 @@ func NewPlayerManager() *PlayerManager {
|
|||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add adds a new player with the given address and account.
|
||||||
|
func (m *PlayerManager) Add(address *net.UDPAddr, account *Account) *Player {
|
||||||
|
player := NewPlayer(account, address)
|
||||||
|
m.players.Store(address.String(), player)
|
||||||
|
m.count.Add(1)
|
||||||
|
player.OnConnect()
|
||||||
|
return player
|
||||||
|
}
|
||||||
|
|
||||||
// Contains tells you whether the address is already a registered client.
|
// Contains tells you whether the address is already a registered client.
|
||||||
func (m *PlayerManager) Contains(addr *net.UDPAddr) bool {
|
func (m *PlayerManager) Contains(address *net.UDPAddr) bool {
|
||||||
_, exists := m.players.Load(addr.String())
|
_, exists := m.players.Load(address.String())
|
||||||
return exists
|
return exists
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,15 +71,12 @@ func (m *PlayerManager) Each(callback func(*Player) bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get either returns a new or existing client for the requested address.
|
// Get either returns a new or existing client for the requested address.
|
||||||
func (m *PlayerManager) Get(addr *net.UDPAddr) *Player {
|
func (m *PlayerManager) Get(address *net.UDPAddr) *Player {
|
||||||
obj, exists := m.players.Load(addr.String())
|
obj, exists := m.players.Load(address.String())
|
||||||
|
|
||||||
if exists {
|
if !exists {
|
||||||
return obj.(*Player)
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
client := NewClient(addr)
|
return obj.(*Player)
|
||||||
m.players.Store(addr.String(), client)
|
|
||||||
m.count.Add(1)
|
|
||||||
return client
|
|
||||||
}
|
}
|
||||||
|
@ -4,5 +4,7 @@ const (
|
|||||||
Ping = 1
|
Ping = 1
|
||||||
Login = 2
|
Login = 2
|
||||||
Logout = 3
|
Logout = 3
|
||||||
PlayerState = 10
|
PlayerAdd = 10
|
||||||
|
PlayerRemove = 11
|
||||||
|
PlayerMove = 12
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user