diff --git a/go.mod b/go.mod index 59b3467..f484b26 100644 --- a/go.mod +++ b/go.mod @@ -2,10 +2,14 @@ module goonscape go 1.23.0 -require github.com/gen2brain/raylib-go/raylib v0.0.0-20240916050633-6bc3d79c96ad +require ( + gitea.boner.be/bdnugget/goonserver v0.0.0-20241011122434-4bd5303cfd46 + github.com/gen2brain/raylib-go/raylib v0.0.0-20240930075631-c66f9e2942fe + google.golang.org/protobuf v1.35.1 +) require ( - github.com/ebitengine/purego v0.7.1 // indirect - golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect - golang.org/x/sys v0.20.0 // indirect + github.com/ebitengine/purego v0.8.0 // indirect + golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect + golang.org/x/sys v0.26.0 // indirect ) diff --git a/go.sum b/go.sum index 97afe30..63d861e 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,14 @@ -github.com/ebitengine/purego v0.7.1 h1:6/55d26lG3o9VCZX8lping+bZcmShseiqlh2bnUDiPA= -github.com/ebitengine/purego v0.7.1/go.mod h1:ah1In8AOtksoNK6yk5z1HTJeUkC1Ez4Wk2idgGslMwQ= -github.com/gen2brain/raylib-go/raylib v0.0.0-20240916050633-6bc3d79c96ad h1:kmIjqc2wOOn+MXw/pyuoYhhzfRFsZ+ESfkMWVt+WE7Y= -github.com/gen2brain/raylib-go/raylib v0.0.0-20240916050633-6bc3d79c96ad/go.mod h1:BaY76bZk7nw1/kVOSQObPY1v1iwVE1KHAGMfvI6oK1Q= -golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= -golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +gitea.boner.be/bdnugget/goonserver v0.0.0-20241011122434-4bd5303cfd46 h1:T2D4QcmvBqzGoHO0VJGNUd1k2lLmUcyg6Rc/vN4/Im8= +gitea.boner.be/bdnugget/goonserver v0.0.0-20241011122434-4bd5303cfd46/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= +github.com/gen2brain/raylib-go/raylib v0.0.0-20240930075631-c66f9e2942fe/go.mod h1:BaY76bZk7nw1/kVOSQObPY1v1iwVE1KHAGMfvI6oK1Q= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY= +golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= diff --git a/main.go b/main.go index 68e15d9..4fcb812 100644 --- a/main.go +++ b/main.go @@ -2,9 +2,14 @@ package main import ( "fmt" + "log" "math" + "net" + "time" + pb "gitea.boner.be/bdnugget/goonserver/actions" rl "github.com/gen2brain/raylib-go/raylib" + "google.golang.org/protobuf/proto" ) const ( @@ -12,6 +17,8 @@ const ( MapHeight = 50 TileSize = 32 TileHeight = 2.0 + TickRate = 2600 * time.Millisecond // Server tick rate (600ms) + serverAddr = "localhost:6969" ) var ( @@ -26,11 +33,23 @@ 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 + PosActual rl.Vector3 + PosTile Tile + TargetPath []Tile + Speed float32 + ActionQueue []Action // Queue for player actions } // Initialize the map with some height data @@ -209,6 +228,7 @@ func HandleInput(player *Player, mapGrid [][]Tile, 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}) } } } @@ -267,18 +287,6 @@ func main() { rl.InitAudioDevice() defer rl.CloseAudioDevice() - playerModel := rl.LoadModel("resources/models/goonion.obj") - defer rl.UnloadModel(playerModel) - playerTexture := rl.LoadTexture("resources/models/goonion.png") - defer rl.UnloadTexture(playerTexture) - rl.SetMaterialTexture(playerModel.Materials, rl.MapDiffuse, playerTexture) - - coomerModel := rl.LoadModel("resources/models/coomer.obj") - defer rl.UnloadModel(coomerModel) - coomerTexture := rl.LoadTexture("resources/models/coomer.png") - defer rl.UnloadTexture(coomerTexture) - rl.SetMaterialTexture(coomerModel.Materials, rl.MapDiffuse, coomerTexture) - mapGrid := InitMap() player := Player{ @@ -296,6 +304,27 @@ func main() { Projection: rl.CameraPerspective, } + conn, playerID, err := ConnectToServer() + if err != nil { + log.Fatalf("Failed to connect to server: %v", err) + } + log.Printf("Player ID: %d", playerID) + defer conn.Close() + + go HandleServerCommunication(conn, playerID, &player) + + playerModel := rl.LoadModel("resources/models/goonion.obj") + defer rl.UnloadModel(playerModel) + playerTexture := rl.LoadTexture("resources/models/goonion.png") + defer rl.UnloadTexture(playerTexture) + rl.SetMaterialTexture(playerModel.Materials, rl.MapDiffuse, playerTexture) + + coomerModel := rl.LoadModel("resources/models/coomer.obj") + defer rl.UnloadModel(coomerModel) + coomerTexture := rl.LoadTexture("resources/models/coomer.png") + defer rl.UnloadTexture(coomerTexture) + rl.SetMaterialTexture(coomerModel.Materials, rl.MapDiffuse, coomerTexture) + rl.SetTargetFPS(60) // Music @@ -305,6 +334,7 @@ func main() { defer rl.UnloadMusicStream(music) for !rl.WindowShouldClose() { + rl.UpdateMusicStream(music) // Time management @@ -337,6 +367,73 @@ func main() { } } +func ConnectToServer() (net.Conn, int32, error) { + // Attempt to connect to the server + conn, err := net.Dial("tcp", serverAddr) + if err != nil { + log.Printf("Failed to dial server: %v", err) + return nil, 0, err + } + + log.Println("Connected to server. Waiting for player ID...") + // Buffer for incoming server message + buf := make([]byte, 1024) + n, err := conn.Read(buf) + if err != nil { + log.Printf("Error reading player ID from server: %v", err) + return nil, 0, err + } + + log.Printf("Received data: %x", buf[:n]) + + // Unmarshal server message to extract the player ID + var response pb.ServerMessage + if err := proto.Unmarshal(buf[:n], &response); err != nil { + log.Printf("Failed to unmarshal server response: %v", err) + return nil, 0, err + } + + playerID := response.GetPlayerId() + log.Printf("Successfully connected with player ID: %d", playerID) + return conn, playerID, nil +} + +func HandleServerCommunication(conn net.Conn, playerID int32, player *Player) { + for { + // Check if there are actions in the player's queue + 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), + } + + // Serialize the action + data, err := proto.Marshal(action) + if err != nil { + log.Printf("Failed to marshal action: %v", err) + continue + } + + // Send action to server + _, err = conn.Write(data) + if err != nil { + log.Printf("Failed to send action to server: %v", err) + return + } + + // Remove the action from the queue once it's sent + player.ActionQueue = player.ActionQueue[1:] + } + + // Add a delay based on the server's tick rate + time.Sleep(TickRate) + } +} + // pathfinding type Node struct { Tile Tile