Protobuf changes
This commit is contained in:
parent
4f36c2ee1f
commit
4012a2ed92
32
actions.proto
Normal file
32
actions.proto
Normal file
@ -0,0 +1,32 @@
|
||||
syntax = "proto3";
|
||||
package actions;
|
||||
|
||||
option go_package = "gitea.boner.be/bdnugget/goonserver/actions";
|
||||
|
||||
message Action {
|
||||
enum ActionType {
|
||||
MOVE = 0;
|
||||
}
|
||||
ActionType type = 1;
|
||||
int32 x = 2;
|
||||
int32 y = 3;
|
||||
int32 player_id = 4;
|
||||
}
|
||||
|
||||
message ActionBatch {
|
||||
int32 player_id = 1;
|
||||
repeated Action actions = 2;
|
||||
int64 tick = 3;
|
||||
}
|
||||
|
||||
message PlayerState {
|
||||
int32 player_id = 1;
|
||||
int32 x = 2;
|
||||
int32 y = 3;
|
||||
}
|
||||
|
||||
message ServerMessage {
|
||||
int32 player_id = 1;
|
||||
repeated PlayerState players = 2;
|
||||
int64 current_tick = 3;
|
||||
}
|
@ -9,4 +9,13 @@ const (
|
||||
TileHeight = 2.0
|
||||
TickRate = 600 * time.Millisecond // Server tick rate (600ms)
|
||||
serverAddr = "localhost:6969"
|
||||
|
||||
// RuneScape-style tick rate (600ms)
|
||||
ServerTickRate = 600 * time.Millisecond
|
||||
|
||||
// Client might run at a higher tick rate for smooth rendering
|
||||
ClientTickRate = 50 * time.Millisecond
|
||||
|
||||
// Maximum number of ticks we can get behind before forcing a resync
|
||||
MaxTickDesync = 5
|
||||
)
|
||||
|
4
go.mod
4
go.mod
@ -1,4 +1,4 @@
|
||||
module goonscape
|
||||
module gitea.boner.be/bdnugget/goonscape
|
||||
|
||||
go 1.23.0
|
||||
|
||||
@ -13,3 +13,5 @@ require (
|
||||
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect
|
||||
golang.org/x/sys v0.26.0 // indirect
|
||||
)
|
||||
|
||||
replace gitea.boner.be/bdnugget/goonserver => ./goonserver
|
||||
|
2
go.sum
2
go.sum
@ -1,5 +1,3 @@
|
||||
gitea.boner.be/bdnugget/goonserver v0.0.0-20241011195320-f16e8647dc6b h1:hdhCZH0YGqCsnSl6ru+8I7rxvCyOj5pCtf92urwyruA=
|
||||
gitea.boner.be/bdnugget/goonserver v0.0.0-20241011195320-f16e8647dc6b/go.mod h1:inR1bKrr/vcTba+G1KzmmY6vssMq9oGNOk836VwPa4c=
|
||||
github.com/ebitengine/purego v0.8.0 h1:JbqvnEzRvPpxhCJzJJ2y0RbiZ8nyjccVUrSM3q+GvvE=
|
||||
github.com/ebitengine/purego v0.8.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/gen2brain/raylib-go/raylib v0.0.0-20240930075631-c66f9e2942fe h1:mInjrbJkUglTM7tBmXG+epnPCE744aj15J7vjJwM4gs=
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 1d6d3ab2eadf488d6ec0e5ba85005b3e57e372ea
|
||||
Subproject commit f91f72c05d779b99c65b86abdfda205ef8e8f7c0
|
8
input.go
8
input.go
@ -3,6 +3,7 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
pb "gitea.boner.be/bdnugget/goonserver/actions"
|
||||
rl "github.com/gen2brain/raylib-go/raylib"
|
||||
)
|
||||
|
||||
@ -40,7 +41,12 @@ func HandleInput(player *Player, camera *rl.Camera) {
|
||||
// Exclude the first tile (current position)
|
||||
if len(path) > 1 {
|
||||
player.TargetPath = path[1:]
|
||||
player.ActionQueue = append(player.ActionQueue, Action{Type: MoveAction, X: clickedTile.X, Y: clickedTile.Y})
|
||||
player.ActionQueue = append(player.ActionQueue, &pb.Action{
|
||||
Type: pb.Action_MOVE,
|
||||
X: int32(clickedTile.X),
|
||||
Y: int32(clickedTile.Y),
|
||||
PlayerId: player.ID,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
77
network.go
77
network.go
@ -6,7 +6,6 @@ import (
|
||||
"time"
|
||||
|
||||
pb "gitea.boner.be/bdnugget/goonserver/actions"
|
||||
rl "github.com/gen2brain/raylib-go/raylib"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
@ -42,39 +41,51 @@ func ConnectToServer() (net.Conn, int32, error) {
|
||||
}
|
||||
|
||||
func HandleServerCommunication(conn net.Conn, playerID int32, player *Player, otherPlayers map[int32]*Player) {
|
||||
// Ticker for sending actions aligned with server ticks
|
||||
ticker := time.NewTicker(ServerTickRate)
|
||||
defer ticker.Stop()
|
||||
|
||||
// Goroutine to handle sending player's actions to the server
|
||||
go func() {
|
||||
for {
|
||||
for range ticker.C {
|
||||
if len(player.ActionQueue) > 0 {
|
||||
// Process the first action in the queue
|
||||
actionData := player.ActionQueue[0]
|
||||
action := &pb.Action{
|
||||
PlayerId: playerID,
|
||||
Type: pb.Action_MOVE,
|
||||
X: int32(actionData.X),
|
||||
Y: int32(actionData.Y),
|
||||
// Bundle all actions that occurred during this tick
|
||||
actions := make([]*pb.Action, 0, len(player.ActionQueue))
|
||||
|
||||
for _, actionData := range player.ActionQueue {
|
||||
action := &pb.Action{
|
||||
PlayerId: playerID,
|
||||
Type: pb.Action_MOVE,
|
||||
X: int32(actionData.X),
|
||||
Y: int32(actionData.Y),
|
||||
}
|
||||
actions = append(actions, action)
|
||||
}
|
||||
|
||||
// Serialize the action
|
||||
data, err := proto.Marshal(action)
|
||||
// Create a batch message
|
||||
batch := &pb.ActionBatch{
|
||||
PlayerId: playerID,
|
||||
Actions: actions,
|
||||
Tick: player.CurrentTick,
|
||||
}
|
||||
|
||||
// Serialize the batch
|
||||
data, err := proto.Marshal(batch)
|
||||
if err != nil {
|
||||
log.Printf("Failed to marshal action: %v", err)
|
||||
log.Printf("Failed to marshal action batch: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Send action to server
|
||||
// Send batch to server
|
||||
_, err = conn.Write(data)
|
||||
if err != nil {
|
||||
log.Printf("Failed to send action to server: %v", err)
|
||||
log.Printf("Failed to send actions to server: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Remove the action from the queue once it's sent
|
||||
player.ActionQueue = player.ActionQueue[1:]
|
||||
// Clear the action queue after sending
|
||||
player.ActionQueue = player.ActionQueue[:0]
|
||||
}
|
||||
|
||||
// Add a delay to match the server's tick rate
|
||||
time.Sleep(TickRate)
|
||||
}
|
||||
}()
|
||||
|
||||
@ -93,27 +104,25 @@ func HandleServerCommunication(conn net.Conn, playerID int32, player *Player, ot
|
||||
continue
|
||||
}
|
||||
|
||||
// Check for tick synchronization
|
||||
tickDiff := serverMessage.CurrentTick - player.CurrentTick
|
||||
if tickDiff > MaxTickDesync {
|
||||
log.Printf("Client too far behind (tick diff: %d), forcing resync", tickDiff)
|
||||
player.ForceResync(serverMessage.Players[playerID])
|
||||
}
|
||||
|
||||
// Update player's current tick
|
||||
player.CurrentTick = serverMessage.CurrentTick
|
||||
|
||||
// Update other players' states
|
||||
for _, state := range serverMessage.Players {
|
||||
if state.PlayerId != playerID {
|
||||
if otherPlayer, exists := otherPlayers[state.PlayerId]; exists {
|
||||
// Instead of directly setting position, set up path for smooth movement
|
||||
targetTile := Tile{X: int(state.X), Y: int(state.Y)}
|
||||
if otherPlayer.PosTile != targetTile {
|
||||
otherPlayer.TargetPath = []Tile{targetTile}
|
||||
}
|
||||
// Calculate interpolation based on server tick
|
||||
otherPlayer.UpdatePosition(state, ServerTickRate)
|
||||
} else {
|
||||
// Initialize new player
|
||||
otherPlayers[state.PlayerId] = &Player{
|
||||
PosTile: Tile{X: int(state.X), Y: int(state.Y)},
|
||||
PosActual: rl.Vector3{
|
||||
X: float32(state.X * TileSize),
|
||||
Y: float32(state.Y * TileHeight),
|
||||
Z: float32(state.Y * TileSize),
|
||||
},
|
||||
ID: state.PlayerId,
|
||||
Speed: 50.0, // Make sure to set the speed for smooth movement
|
||||
}
|
||||
otherPlayers[state.PlayerId] = NewPlayer(state)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
38
player.go
38
player.go
@ -1,6 +1,9 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
pb "gitea.boner.be/bdnugget/goonserver/actions"
|
||||
rl "github.com/gen2brain/raylib-go/raylib"
|
||||
)
|
||||
|
||||
@ -61,3 +64,38 @@ func (player *Player) MoveTowards(target Tile, deltaTime float32) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Player) UpdatePosition(state *pb.PlayerState, tickRate time.Duration) {
|
||||
targetTile := Tile{X: int(state.X), Y: int(state.Y)}
|
||||
if p.PosTile != targetTile {
|
||||
p.PosTile = targetTile
|
||||
p.LastUpdateTime = time.Now()
|
||||
p.InterpolationProgress = 0
|
||||
p.TargetPath = []Tile{targetTile}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Player) ForceResync(state *pb.PlayerState) {
|
||||
p.PosTile = Tile{X: int(state.X), Y: int(state.Y)}
|
||||
p.PosActual = rl.Vector3{
|
||||
X: float32(state.X * TileSize),
|
||||
Y: float32(state.Y * TileHeight),
|
||||
Z: float32(state.Y * TileSize),
|
||||
}
|
||||
p.TargetPath = nil
|
||||
p.ActionQueue = nil
|
||||
p.InterpolationProgress = 1.0
|
||||
}
|
||||
|
||||
func NewPlayer(state *pb.PlayerState) *Player {
|
||||
return &Player{
|
||||
PosActual: rl.Vector3{
|
||||
X: float32(state.X * TileSize),
|
||||
Y: float32(state.Y * TileHeight),
|
||||
Z: float32(state.Y * TileSize),
|
||||
},
|
||||
PosTile: Tile{X: int(state.X), Y: int(state.Y)},
|
||||
Speed: 50.0,
|
||||
ID: state.PlayerId,
|
||||
}
|
||||
}
|
||||
|
37
types.go
37
types.go
@ -1,6 +1,11 @@
|
||||
package main
|
||||
|
||||
import rl "github.com/gen2brain/raylib-go/raylib"
|
||||
import (
|
||||
pb "gitea.boner.be/bdnugget/goonserver/actions"
|
||||
rl "github.com/gen2brain/raylib-go/raylib"
|
||||
|
||||
time "time"
|
||||
)
|
||||
|
||||
type Tile struct {
|
||||
X, Y int
|
||||
@ -8,24 +13,16 @@ type Tile struct {
|
||||
Walkable bool
|
||||
}
|
||||
|
||||
type ActionType int
|
||||
|
||||
const (
|
||||
MoveAction ActionType = iota
|
||||
)
|
||||
|
||||
type Action struct {
|
||||
Type ActionType
|
||||
X, Y int // Target position for movement
|
||||
}
|
||||
|
||||
type Player struct {
|
||||
PosActual rl.Vector3
|
||||
PosTile Tile
|
||||
TargetPath []Tile
|
||||
Speed float32
|
||||
ActionQueue []Action // Queue for player actions
|
||||
Model rl.Model
|
||||
Texture rl.Texture2D
|
||||
ID int32
|
||||
PosActual rl.Vector3
|
||||
PosTile Tile
|
||||
TargetPath []Tile
|
||||
ActionQueue []*pb.Action
|
||||
Speed float32
|
||||
Model rl.Model
|
||||
Texture rl.Texture2D
|
||||
ID int32
|
||||
CurrentTick int64
|
||||
LastUpdateTime time.Time
|
||||
InterpolationProgress float32
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user