Improved network code

This commit is contained in:
Eduard Urbach 2024-01-15 17:08:26 +01:00
parent 9b47e374c7
commit b885d70625
Signed by: akyoto
GPG Key ID: C874F672B1AF20C0
17 changed files with 241 additions and 72 deletions

View File

@ -5,6 +5,23 @@ var udp := PacketPeerUDP.new()
func _ready():
udp.connect_to_host("127.0.0.1", 4242)
send_login()
func _process(_delta):
if Client.udp.get_available_packet_count() <= 0:
return
var packet := Client.udp.get_packet()
var type := packet.decode_u8(0)
print("Packet type %d data size %d" % [type, packet.size()-1])
func send_login():
var login_data = PackedByteArray()
login_data.push_back(2)
udp.put_packet(login_data)
print("Connecting...")
func spawn_player():
var player = PLAYER.instantiate()
add_child(player)
print("Ready.")

View File

@ -3,5 +3,5 @@ extends Node3D
func _ready():
pass
func _process(delta):
rotate_y(delta)
func _process(_delta):
pass

View File

@ -11,7 +11,7 @@ config_version=5
[application]
config/name="Battle of Mages"
run/main_scene="res://world/World.tscn"
run/main_scene="res://world/Game.tscn"
config/features=PackedStringArray("4.2", "Forward Plus")
config/icon="res://ui/icon.svg"

View File

@ -3,6 +3,8 @@ package core
import (
"fmt"
"net"
"sync"
"sync/atomic"
"time"
)
@ -12,15 +14,38 @@ type Handler func([]byte, *Client)
// Server represents a UDP server.
type Server struct {
socket *net.UDPConn
clients map[string]*Client
handlers [256]Handler
clients sync.Map
count atomic.Int64
}
// New creates a new server.
func New() *Server {
return &Server{
clients: make(map[string]*Client),
timeout := 3 * time.Second
interval := time.Second
server := &Server{}
go func() {
ticker := time.NewTicker(interval)
defer ticker.Stop()
for range ticker.C {
now := time.Now()
server.clients.Range(func(key, value interface{}) bool {
item := value.(*Client)
if !item.lastPacket.IsZero() && now.After(item.lastPacket.Add(timeout)) {
server.clients.Delete(key)
server.count.Add(-1)
}
return true
})
}
}()
return server
}
// AddHandler adds the handler for the given byte code.
@ -28,8 +53,14 @@ func (s *Server) AddHandler(code byte, handler Handler) {
s.handlers[code] = handler
}
// SendTo sends the data to a client.
func (s *Server) SendTo(data []byte, client *Client) {
// Count returns the number of connected clients.
func (s *Server) Count() int {
return int(s.count.Load())
}
// Send sends the data prefixed with the byte code to the client.
func (s *Server) Send(code byte, data []byte, client *Client) {
data = append([]byte{code}, data...)
_, err := s.socket.WriteToUDP(data, client.address)
if err != nil {
@ -91,25 +122,26 @@ func (s *Server) handle(data []byte, addr *net.UDPAddr) {
handler := s.handlers[data[0]]
if handler == nil {
fmt.Println("Unknown packet type.")
fmt.Printf("No callback registered for packet type %d\n", data[0])
return
}
handler(data, c)
handler(data[1:], c)
}
// getClient either returns a new or existing client for the requested address.
func (s *Server) getClient(addr *net.UDPAddr) *Client {
c, exists := s.clients[addr.String()]
obj, exists := s.clients.Load(addr.String())
if exists {
return c
return obj.(*Client)
}
c = &Client{
client := &Client{
address: addr,
}
s.clients[addr.String()] = c
return c
s.clients.Store(addr.String(), client)
s.count.Add(1)
return client
}

13
server/login.go Normal file
View File

@ -0,0 +1,13 @@
package main
import (
"fmt"
"server/core"
"server/packet"
)
// login checks the account credentials and gives a network peer access to an account.
func login(data []byte, client *core.Client) {
fmt.Println("2 - login!")
server.Send(packet.LOGIN, nil, client)
}

View File

@ -2,16 +2,13 @@ package main
import (
"server/core"
"server/packet"
)
var server = core.New()
func main() {
server := core.New()
server.AddHandler(0, func(data []byte, client *core.Client) {
// count := data[1]
// fmt.Println(count)
server.SendTo(data, client)
})
server.AddHandler(packet.PING, ping)
server.AddHandler(packet.LOGIN, login)
server.Run(4242)
}

8
server/packet/types.go Normal file
View File

@ -0,0 +1,8 @@
package packet
const (
PING = 1
LOGIN = 2
LOGOUT = 3
MOVE = 10
)

14
server/ping.go Normal file
View File

@ -0,0 +1,14 @@
package main
import (
"fmt"
"server/core"
"server/packet"
)
// ping is used as a heartbeat and latency check.
func ping(data []byte, client *core.Client) {
fmt.Println("1 - ping!")
server.Send(packet.PING, data, client)
fmt.Println(server.Count(), "clients")
}

View File

@ -8,7 +8,6 @@ var pingSent: Array[float] = []
func _ready():
var timer := Timer.new()
add_child(timer)
timer.autostart = true
timer.wait_time = 1
timer.connect("timeout", self._ping)
timer.start()
@ -16,18 +15,18 @@ func _ready():
pingSent.resize(HISTORY_SIZE)
func _process(_delta):
if Client.udp.get_available_packet_count() > 0:
#print("Received: %s" % udp.get_packet().get_string_from_utf8())
var bytes := Client.udp.get_packet()
var count := bytes.decode_u8(1)
var timeSent := pingSent[count]
var duration := Time.get_unix_time_from_system() - timeSent
var ping := duration * 1000
text = str(snapped(ping, 0.01))
pass
#if Client.udp.get_available_packet_count() > 0:
#var bytes := Client.udp.get_packet()
#var count := bytes.decode_u8(1)
#var timeSent := pingSent[count]
#var duration := Time.get_unix_time_from_system() - timeSent
#var ping := duration * 1000
#text = str(snapped(ping, 0.01))
func _ping():
var buffer := StreamPeerBuffer.new()
buffer.put_8(0)
buffer.put_8(1)
buffer.put_8(pingCount)
Client.udp.put_packet(buffer.data_array)

View File

@ -1,8 +1,10 @@
[gd_resource type="Environment" load_steps=2 format=3 uid="uid://dixa0yso2s1u3"]
[ext_resource type="Sky" uid="uid://b0q75qnaj0r5h" path="res://world/Sky.tres" id="1_utnj1"]
[gd_resource type="Environment" format=3 uid="uid://dixa0yso2s1u3"]
[resource]
sky = ExtResource("1_utnj1")
background_mode = 1
background_color = Color(0.317647, 0.541176, 0.713726, 1)
ambient_light_source = 3
reflected_light_source = 2
ambient_light_color = Color(0.607843, 0.756863, 0.92549, 1)
ambient_light_sky_contribution = 0.17
tonemap_mode = 2
adjustment_saturation = 0.01

108
world/Game.tscn Normal file
View File

@ -0,0 +1,108 @@
[gd_scene load_steps=16 format=3 uid="uid://b40y7iuskv1ar"]
[ext_resource type="Script" path="res://world/Game.gd" id="1_xmqq4"]
[ext_resource type="PackedScene" uid="uid://bxotvk73tbgw0" path="res://ui/UI.tscn" id="2_x1l7l"]
[ext_resource type="Script" path="res://world/RotateY.gd" id="3_4gn6n"]
[ext_resource type="Shader" path="res://world/shader/Outline.gdshader" id="4_gweie"]
[ext_resource type="Environment" uid="uid://dixa0yso2s1u3" path="res://world/Environment.tres" id="5_bll74"]
[ext_resource type="Script" path="res://world/Sun.gd" id="5_pf5uw"]
[ext_resource type="CameraAttributesPractical" uid="uid://b835orxyqq6w5" path="res://world/CameraAttributes.tres" id="6_8wfwf"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_r8n03"]
diffuse_mode = 3
albedo_color = Color(0.482353, 0.470588, 0.47451, 1)
[sub_resource type="BoxMesh" id="BoxMesh_0bujj"]
material = SubResource("StandardMaterial3D_r8n03")
size = Vector3(20, 0.5, 20)
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_4w7ln"]
diffuse_mode = 3
albedo_color = Color(0.294118, 0.356863, 0.439216, 1)
[sub_resource type="BoxMesh" id="BoxMesh_hf021"]
material = SubResource("StandardMaterial3D_4w7ln")
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_ahmjh"]
diffuse_mode = 3
albedo_color = Color(0.14902, 0.517647, 1, 1)
roughness = 0.08
[sub_resource type="TorusMesh" id="TorusMesh_mu45b"]
material = SubResource("StandardMaterial3D_ahmjh")
[sub_resource type="ShaderMaterial" id="ShaderMaterial_qm56v"]
render_priority = 0
shader = ExtResource("4_gweie")
shader_parameter/depth_threshold = 0.05
shader_parameter/reverse_depth_threshold = 0.25
shader_parameter/normal_threshold = 0.6
shader_parameter/darken_amount = 0.3
shader_parameter/lighten_amount = 1.5
shader_parameter/light_direction = Vector3(0.122788, -0.707107, -0.696364)
[sub_resource type="QuadMesh" id="QuadMesh_7yiqd"]
material = SubResource("ShaderMaterial_qm56v")
flip_faces = true
size = Vector2(2, 2)
[node name="Game" type="Node"]
script = ExtResource("1_xmqq4")
[node name="World" type="Node3D" parent="."]
[node name="Ground" type="MeshInstance3D" parent="World"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.25, 0)
mesh = SubResource("BoxMesh_0bujj")
skeleton = NodePath("../..")
[node name="Box" type="MeshInstance3D" parent="World"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, -4)
mesh = SubResource("BoxMesh_hf021")
skeleton = NodePath("../../SubViewportContainer/SubViewport")
[node name="Torus" type="MeshInstance3D" parent="World"]
transform = Transform3D(0.7, 0, 0, 0, -3.0598e-08, -0.7, 0, 0.7, -3.0598e-08, 0, 1.79933, -4)
mesh = SubResource("TorusMesh_mu45b")
skeleton = NodePath("../../SubViewportContainer/SubViewport")
script = ExtResource("3_4gn6n")
[node name="UI" parent="." instance=ExtResource("2_x1l7l")]
[node name="SubViewportContainer" type="SubViewportContainer" parent="."]
texture_filter = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
stretch = true
stretch_shrink = 3
[node name="SubViewport" type="SubViewport" parent="SubViewportContainer"]
handle_input_locally = false
size = Vector2i(384, 216)
render_target_update_mode = 4
[node name="Camera" type="Camera3D" parent="SubViewportContainer/SubViewport"]
transform = Transform3D(0.707107, 0.331966, -0.624338, 0, 0.882947, 0.469472, 0.707107, -0.331966, 0.624338, -5, 5, 5)
projection = 1
current = true
fov = 90.0
size = 9.6
near = 0.001
[node name="PostProcessing" type="MeshInstance3D" parent="SubViewportContainer/SubViewport/Camera"]
unique_name_in_owner = true
extra_cull_margin = 16384.0
mesh = SubResource("QuadMesh_7yiqd")
[node name="Sun" type="DirectionalLight3D" parent="SubViewportContainer/SubViewport"]
transform = Transform3D(0.984808, 0.122788, -0.122788, 0, 0.707107, 0.707107, 0.173648, -0.696364, 0.696364, 0, 5, 0)
shadow_enabled = true
directional_shadow_split_1 = 0.028
script = ExtResource("5_pf5uw")
[node name="Environment" type="WorldEnvironment" parent="SubViewportContainer/SubViewport"]
environment = ExtResource("5_bll74")
camera_attributes = ExtResource("6_8wfwf")

View File

@ -1,4 +0,0 @@
[gd_resource type="ProceduralSkyMaterial" format=3 uid="uid://b7q6crweeh3jv"]
[resource]
ground_bottom_color = Color(0.0313726, 0.0470588, 0.160784, 1)

6
world/RotateY.gd Normal file
View File

@ -0,0 +1,6 @@
extends Node3D
@export var speed: float = 1.0
func _process(delta):
rotate_y(speed * delta)

View File

@ -1,6 +0,0 @@
[gd_resource type="Sky" load_steps=2 format=3 uid="uid://b0q75qnaj0r5h"]
[ext_resource type="Material" uid="uid://b7q6crweeh3jv" path="res://world/ProceduralSky.tres" id="1_7mt7h"]
[resource]
sky_material = ExtResource("1_7mt7h")

5
world/Sun.gd Normal file
View File

@ -0,0 +1,5 @@
@tool
extends DirectionalLight3D
func _process(_delta):
(%PostProcessing as MeshInstance3D).mesh.surface_get_material(0).set_shader_parameter("light_direction", -global_basis.z)

View File

@ -1,22 +0,0 @@
[gd_scene load_steps=5 format=3 uid="uid://b40y7iuskv1ar"]
[ext_resource type="Script" path="res://world/World.gd" id="1_2lci4"]
[ext_resource type="Environment" uid="uid://dixa0yso2s1u3" path="res://world/Environment.tres" id="1_qb8w4"]
[ext_resource type="CameraAttributesPractical" uid="uid://b835orxyqq6w5" path="res://world/CameraAttributes.tres" id="2_1nt3m"]
[ext_resource type="PackedScene" uid="uid://bxotvk73tbgw0" path="res://ui/UI.tscn" id="4_c6x8y"]
[node name="World" type="Node"]
script = ExtResource("1_2lci4")
[node name="UI" parent="." instance=ExtResource("4_c6x8y")]
[node name="Camera" type="Camera3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 5)
fov = 90.0
[node name="Sun" type="DirectionalLight3D" parent="."]
transform = Transform3D(0.904299, 0.26004, -0.33856, 0, 0.793066, 0.609135, 0.4269, -0.55084, 0.717169, 0, 0, 0)
[node name="Environment" type="WorldEnvironment" parent="."]
environment = ExtResource("1_qb8w4")
camera_attributes = ExtResource("2_1nt3m")