Implement server-side movement
This commit is contained in:
parent
6e95246b83
commit
439eeac8a5
@ -3,6 +3,7 @@ package control
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
"github.com/heroiclabs/nakama-common/runtime"
|
"github.com/heroiclabs/nakama-common/runtime"
|
||||||
"github.com/josephbmanley/family/server/plugin/entities"
|
"github.com/josephbmanley/family/server/plugin/entities"
|
||||||
"github.com/josephbmanley/family/server/plugin/gamemap"
|
"github.com/josephbmanley/family/server/plugin/gamemap"
|
||||||
@ -17,6 +18,8 @@ type OpCode int64
|
|||||||
const (
|
const (
|
||||||
// OpCodeTileUpdate is used for tile updates
|
// OpCodeTileUpdate is used for tile updates
|
||||||
OpCodeTileUpdate = 1
|
OpCodeTileUpdate = 1
|
||||||
|
// OpCodeUpdatePosition is used for player position updates
|
||||||
|
OpCodeUpdatePosition = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
// Match is the object registered
|
// Match is the object registered
|
||||||
@ -32,6 +35,15 @@ type MatchState struct {
|
|||||||
worldMap *gamemap.WorldMap
|
worldMap *gamemap.WorldMap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetPrecenseList returns an array of current precenes in an array
|
||||||
|
func (state *MatchState) GetPrecenseList() []runtime.Presence {
|
||||||
|
precenseList := []runtime.Presence{}
|
||||||
|
for _, precense := range state.presences {
|
||||||
|
precenseList = append(precenseList, precense)
|
||||||
|
}
|
||||||
|
return precenseList
|
||||||
|
}
|
||||||
|
|
||||||
// MatchInit is called when a new match is created
|
// MatchInit is called when a new match is created
|
||||||
func (m *Match) MatchInit(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, params map[string]interface{}) (interface{}, int, string) {
|
func (m *Match) MatchInit(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, params map[string]interface{}) (interface{}, int, string) {
|
||||||
|
|
||||||
@ -79,8 +91,9 @@ func (m *Match) MatchJoin(ctx context.Context, logger runtime.Logger, db *sql.DB
|
|||||||
mState.presences[precense.GetUserId()] = precense
|
mState.presences[precense.GetUserId()] = precense
|
||||||
|
|
||||||
player := entities.PlayerEntity{
|
player := entities.PlayerEntity{
|
||||||
X: 16,
|
X: 16,
|
||||||
Y: 16,
|
Y: 16,
|
||||||
|
Presence: precense,
|
||||||
}
|
}
|
||||||
|
|
||||||
mState.players[precense.GetUserId()] = player
|
mState.players[precense.GetUserId()] = player
|
||||||
@ -108,18 +121,32 @@ func (m *Match) MatchLeave(ctx context.Context, logger runtime.Logger, db *sql.D
|
|||||||
}
|
}
|
||||||
for _, presence := range presences {
|
for _, presence := range presences {
|
||||||
delete(mState.presences, presence.GetUserId())
|
delete(mState.presences, presence.GetUserId())
|
||||||
|
delete(mState.players, presence.GetUserId())
|
||||||
}
|
}
|
||||||
return mState
|
return mState
|
||||||
}
|
}
|
||||||
|
|
||||||
// MatchLoop is code that is executed every tick
|
// MatchLoop is code that is executed every tick
|
||||||
func (m *Match) MatchLoop(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, dispatcher runtime.MatchDispatcher, tick int64, state interface{}, messages []runtime.MatchData) interface{} {
|
func (m *Match) MatchLoop(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, dispatcher runtime.MatchDispatcher, tick int64, state interface{}, messages []runtime.MatchData) interface{} {
|
||||||
// Custom code to:
|
mState, ok := state.(*MatchState)
|
||||||
// - Process the messages received.
|
if !ok {
|
||||||
// - Update the match state based on the messages and time elapsed.
|
logger.Error("Invalid match state on leave!")
|
||||||
// - Broadcast new data messages to match participants.
|
return state
|
||||||
|
}
|
||||||
|
for _, message := range messages {
|
||||||
|
if message.GetOpCode() == OpCodeUpdatePosition {
|
||||||
|
player := mState.players[message.GetUserId()]
|
||||||
|
|
||||||
return state
|
if response, err := player.ParsePositionRequest(message.GetData()); err == nil {
|
||||||
|
player.UpdateBasedOnResponse(response)
|
||||||
|
dispatcher.BroadcastMessage(OpCodeUpdatePosition, []byte{}, mState.GetPrecenseList(), player.Presence, false)
|
||||||
|
logger.Info("Yes")
|
||||||
|
} else {
|
||||||
|
logger.Error(fmt.Sprintf("Failed to parse update pos request: %s", err.Error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mState
|
||||||
}
|
}
|
||||||
|
|
||||||
// MatchTerminate is code that is executed when the match ends
|
// MatchTerminate is code that is executed when the match ends
|
||||||
|
@ -1,7 +1,55 @@
|
|||||||
package entities
|
package entities
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"github.com/heroiclabs/nakama-common/runtime"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
// PlayerEntity is the go struct representing the player's location
|
// PlayerEntity is the go struct representing the player's location
|
||||||
type PlayerEntity struct {
|
type PlayerEntity struct {
|
||||||
X int
|
Presence runtime.Presence
|
||||||
Y int
|
X float64
|
||||||
|
Y float64
|
||||||
|
}
|
||||||
|
|
||||||
|
// PlayerPosResponse struct that represents client data
|
||||||
|
type PlayerPosResponse struct {
|
||||||
|
X string
|
||||||
|
Y string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParsePositionRequest parses data from client
|
||||||
|
func (p *PlayerEntity) ParsePositionRequest(data []byte) (PlayerPosResponse, error) {
|
||||||
|
var response PlayerPosResponse
|
||||||
|
err := json.Unmarshal(data, &response)
|
||||||
|
return response, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//UpdateBasedOnResponse updates the player object based on a response object
|
||||||
|
func (p *PlayerEntity) UpdateBasedOnResponse(response PlayerPosResponse) error {
|
||||||
|
if fx, err := strconv.ParseFloat(response.X, 64); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
p.X = fx
|
||||||
|
if fy, err := strconv.ParseFloat(response.Y, 64); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
p.Y = fy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPosJSON returns the player's position as a JSON object
|
||||||
|
func (p *PlayerEntity) GetPosJSON() ([]byte, error) {
|
||||||
|
playerMap := map[string]string{
|
||||||
|
"player": p.Presence.GetUserId(),
|
||||||
|
"x": fmt.Sprintf("%f", p.X),
|
||||||
|
"y": fmt.Sprintf("%f", p.Y),
|
||||||
|
}
|
||||||
|
jsonData, err := json.Marshal(playerMap)
|
||||||
|
return jsonData, err
|
||||||
}
|
}
|
||||||
|
@ -27,11 +27,10 @@ func (m WorldMap) GetJSONRegion(startX, endX, startY, endY int) ([]byte, error)
|
|||||||
for x := startX; x < endX; x++ {
|
for x := startX; x < endX; x++ {
|
||||||
regionMap[x] = map[int]int{}
|
regionMap[x] = map[int]int{}
|
||||||
for y := startY; y < endY; y++ {
|
for y := startY; y < endY; y++ {
|
||||||
if result, err := m.GetTile(x, y); err != nil {
|
|
||||||
return nil, err
|
// GetTile and ignore out of bounds errors
|
||||||
} else {
|
result, _ := m.GetTile(x, y)
|
||||||
regionMap[x][y] = result
|
regionMap[x][y] = result
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,8 +39,10 @@ func (m WorldMap) GetJSONRegion(startX, endX, startY, endY int) ([]byte, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetJSONRegionAround returns a JSON object of tile data from a center point
|
// GetJSONRegionAround returns a JSON object of tile data from a center point
|
||||||
func (m WorldMap) GetJSONRegionAround(centerX, centerY, regionRadius int) ([]byte, error) {
|
func (m WorldMap) GetJSONRegionAround(centerX float64, centerY float64, regionRadius int) ([]byte, error) {
|
||||||
jsonString, err := m.GetJSONRegion(centerX-regionRadius, centerX+regionRadius, centerY-regionRadius, centerY+regionRadius)
|
var xCenter int = int(centerX)
|
||||||
|
var yCenter int = int(centerY)
|
||||||
|
jsonString, err := m.GetJSONRegion(xCenter-regionRadius, xCenter+regionRadius, yCenter-regionRadius, yCenter+regionRadius)
|
||||||
return jsonString, err
|
return jsonString, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user