mirror of
https://github.com/genxium/DelayNoMore
synced 2025-10-09 00:26:39 +00:00
A broken commit.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
module server
|
||||
module battle_srv
|
||||
|
||||
go 1.19
|
||||
|
||||
|
@@ -7,13 +7,13 @@ import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"server/api"
|
||||
"server/api/v1"
|
||||
. "server/common"
|
||||
"server/env_tools"
|
||||
"server/models"
|
||||
"server/storage"
|
||||
"server/ws"
|
||||
"battle_srv/api"
|
||||
"battle_srv/api/v1"
|
||||
. "battle_srv/common"
|
||||
"battle_srv/env_tools"
|
||||
"battle_srv/models"
|
||||
"battle_srv/storage"
|
||||
"battle_srv/ws"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
|
@@ -68,9 +68,9 @@ func toPbPlayers(modelInstances map[int32]*Player) map[int32]*pb.Player {
|
||||
|
||||
for k, last := range modelInstances {
|
||||
toRet[k] = &pb.Player{
|
||||
Id: last.Id,
|
||||
X: last.X,
|
||||
Y: last.Y,
|
||||
Id: last.Id,
|
||||
VirtualGridX: last.VirtualGridX,
|
||||
VirtualGridY: last.VirtualGridY,
|
||||
Dir: &pb.Direction{
|
||||
Dx: last.Dir.Dx,
|
||||
Dy: last.Dir.Dy,
|
||||
|
@@ -33,30 +33,31 @@ func InitPlayerBattleStateIns() {
|
||||
}
|
||||
|
||||
type Player struct {
|
||||
Id int32 `json:"id,omitempty" db:"id"`
|
||||
X float64 `json:"x,omitempty"`
|
||||
Y float64 `json:"y,omitempty"`
|
||||
Dir *Direction `json:"dir,omitempty"`
|
||||
Speed float64 `json:"speed,omitempty"`
|
||||
BattleState int32 `json:"battleState,omitempty"`
|
||||
LastMoveGmtMillis int32 `json:"lastMoveGmtMillis,omitempty"`
|
||||
Score int32 `json:"score,omitempty"`
|
||||
Removed bool `json:"removed,omitempty"`
|
||||
JoinIndex int32
|
||||
|
||||
// Meta info fields
|
||||
Id int32 `json:"id,omitempty" db:"id"`
|
||||
Name string `json:"name,omitempty" db:"name"`
|
||||
DisplayName string `json:"displayName,omitempty" db:"display_name"`
|
||||
Avatar string `json:"avatar,omitempty"`
|
||||
|
||||
FrozenAtGmtMillis int64 `json:"-" db:"-"`
|
||||
AddSpeedAtGmtMillis int64 `json:"-" db:"-"`
|
||||
CreatedAt int64 `json:"-" db:"created_at"`
|
||||
UpdatedAt int64 `json:"-" db:"updated_at"`
|
||||
DeletedAt NullInt64 `json:"-" db:"deleted_at"`
|
||||
TutorialStage int `json:"-" db:"tutorial_stage"`
|
||||
AckingFrameId int32 `json:"ackingFrameId"`
|
||||
AckingInputFrameId int32 `json:"-"`
|
||||
LastSentInputFrameId int32 `json:"-"`
|
||||
// DB only fields
|
||||
CreatedAt int64 `db:"created_at"`
|
||||
UpdatedAt int64 `db:"updated_at"`
|
||||
DeletedAt NullInt64 `db:"deleted_at"`
|
||||
TutorialStage int `db:"tutorial_stage"`
|
||||
|
||||
// in-battle info fields
|
||||
VirtualGridX int32
|
||||
VirtualGridY int32
|
||||
Dir *Direction
|
||||
Speed int32
|
||||
BattleState int32
|
||||
LastMoveGmtMillis int32
|
||||
Score int32
|
||||
Removed bool
|
||||
JoinIndex int32
|
||||
AckingFrameId int32
|
||||
AckingInputFrameId int32
|
||||
LastSentInputFrameId int32
|
||||
}
|
||||
|
||||
func ExistPlayerByName(name string) (bool, error) {
|
||||
|
@@ -13,9 +13,9 @@ import (
|
||||
"math/rand"
|
||||
"os"
|
||||
"path/filepath"
|
||||
. "server/common"
|
||||
"server/common/utils"
|
||||
pb "server/pb_output"
|
||||
. "battle_srv/common"
|
||||
"battle_srv/common/utils"
|
||||
pb "battle_srv/protos"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
@@ -82,10 +82,10 @@ var DIRECTION_DECODER_INVERSE_LENGTH = []float64{
|
||||
1.0,
|
||||
0.5,
|
||||
0.5,
|
||||
0.4472,
|
||||
0.4472,
|
||||
0.4472,
|
||||
0.4472,
|
||||
0.44, // Actually it should be "0.4472", but truncated for better precision sync as well as a reduction of speed in diagonal direction
|
||||
0.44,
|
||||
0.44,
|
||||
0.44,
|
||||
0.5,
|
||||
0.5,
|
||||
1.0,
|
||||
@@ -128,12 +128,14 @@ func calRoomScore(inRoomPlayerCount int32, roomPlayerCnt int, currentRoomBattleS
|
||||
}
|
||||
|
||||
type Room struct {
|
||||
Id int32
|
||||
Capacity int
|
||||
playerColliderRadius float64
|
||||
Players map[int32]*Player
|
||||
PlayersArr []*Player // ordered by joinIndex
|
||||
CollisionSysMap map[int32]*resolv.Object
|
||||
Id int32
|
||||
Capacity int
|
||||
playerColliderRadius float64
|
||||
collisionSpaceOffsetX float64
|
||||
collisionSpaceOffsetY float64
|
||||
Players map[int32]*Player
|
||||
PlayersArr []*Player // ordered by joinIndex
|
||||
CollisionSysMap map[int32]*resolv.Object
|
||||
/**
|
||||
* The following `PlayerDownsyncSessionDict` is NOT individually put
|
||||
* under `type Player struct` for a reason.
|
||||
@@ -177,11 +179,15 @@ type Room struct {
|
||||
NstDelayFrames int32 // network-single-trip delay in the count of render frames, proposed to be (InputDelayFrames >> 1) because we expect a round-trip delay to be exactly "InputDelayFrames"
|
||||
InputScaleFrames uint32 // inputDelayedAndScaledFrameId = ((originalFrameId - InputDelayFrames) >> InputScaleFrames)
|
||||
JoinIndexBooleanArr []bool
|
||||
RollbackEstimatedDt float64
|
||||
RollbackEstimatedDtMillis float64
|
||||
RollbackEstimatedDtNanos int64
|
||||
LastRenderFrameIdTriggeredAt int64
|
||||
|
||||
WorldToVirtualGridRatio float64
|
||||
VirtualGridToWorldRatio float64
|
||||
|
||||
PlayerDefaultSpeed int32
|
||||
|
||||
StageName string
|
||||
StageDiscreteW int32
|
||||
StageDiscreteH int32
|
||||
@@ -192,11 +198,6 @@ type Room struct {
|
||||
BackendDynamicsEnabled bool
|
||||
}
|
||||
|
||||
const (
|
||||
PLAYER_DEFAULT_SPEED = float64(200) // Hardcoded
|
||||
ADD_SPEED = float64(100) // Hardcoded
|
||||
)
|
||||
|
||||
func (pR *Room) updateScore() {
|
||||
pR.Score = calRoomScore(pR.EffectivePlayerCount, pR.Capacity, pR.State)
|
||||
}
|
||||
@@ -218,9 +219,7 @@ func (pR *Room) AddPlayerIfPossible(pPlayerFromDbInit *Player, session *websocke
|
||||
pPlayerFromDbInit.AckingInputFrameId = -1
|
||||
pPlayerFromDbInit.LastSentInputFrameId = MAGIC_LAST_SENT_INPUT_FRAME_ID_NORMAL_ADDED
|
||||
pPlayerFromDbInit.BattleState = PlayerBattleStateIns.ADDED_PENDING_BATTLE_COLLIDER_ACK
|
||||
pPlayerFromDbInit.FrozenAtGmtMillis = -1 // Hardcoded temporarily.
|
||||
pPlayerFromDbInit.Speed = PLAYER_DEFAULT_SPEED // Hardcoded temporarily.
|
||||
pPlayerFromDbInit.AddSpeedAtGmtMillis = -1 // Hardcoded temporarily.
|
||||
pPlayerFromDbInit.Speed = pR.PlayerDefaultSpeed
|
||||
|
||||
pR.Players[playerId] = pPlayerFromDbInit
|
||||
pR.PlayerDownsyncSessionDict[playerId] = session
|
||||
@@ -421,7 +420,7 @@ func (pR *Room) StartBattle() {
|
||||
|
||||
spaceOffsetX := float64(spaceW) * 0.5
|
||||
spaceOffsetY := float64(spaceH) * 0.5
|
||||
pR.refreshColliders(spaceW, spaceH, spaceOffsetX, spaceOffsetY)
|
||||
pR.refreshColliders(spaceW, spaceH)
|
||||
|
||||
/**
|
||||
* Will be triggered from a goroutine which executes the critical `Room.AddPlayerIfPossible`, thus the `battleMainLoop` should be detached.
|
||||
@@ -799,6 +798,9 @@ func (pR *Room) OnDismissed() {
|
||||
|
||||
// Always instantiates new HeapRAM blocks and let the old blocks die out due to not being retained by any root reference.
|
||||
pR.playerColliderRadius = float64(12) // hardcoded
|
||||
pR.WorldToVirtualGridRatio = float64(10)
|
||||
pR.VirtualGridToWorldRatio = float64(1.0) / pR.WorldToVirtualGridRatio // this is a one-off computation, should avoid division in iterations
|
||||
pR.PlayerDefaultSpeed = int32(3 * pR.WorldToVirtualGridRatio) // Hardcoded in virtual grids per frame
|
||||
pR.Players = make(map[int32]*Player)
|
||||
pR.PlayersArr = make([]*Player, pR.Capacity)
|
||||
pR.CollisionSysMap = make(map[int32]*resolv.Object)
|
||||
@@ -820,7 +822,6 @@ func (pR *Room) OnDismissed() {
|
||||
pR.NstDelayFrames = 8
|
||||
pR.InputScaleFrames = uint32(2)
|
||||
pR.ServerFps = 60
|
||||
pR.RollbackEstimatedDt = 0.016667 // Use fixed-and-low-precision to mitigate the inconsistent floating-point-number issue between Golang and JavaScript
|
||||
pR.RollbackEstimatedDtMillis = 16.667 // Use fixed-and-low-precision to mitigate the inconsistent floating-point-number issue between Golang and JavaScript
|
||||
pR.RollbackEstimatedDtNanos = 16666666 // A little smaller than the actual per frame time, just for preventing FAST FRAME
|
||||
pR.BattleDurationFrames = 30 * pR.ServerFps
|
||||
@@ -947,8 +948,7 @@ func (pR *Room) onPlayerAdded(playerId int32) {
|
||||
if nil == playerPos {
|
||||
panic(fmt.Sprintf("onPlayerAdded error, nil == playerPos, roomId=%v, playerId=%v, roomState=%v, roomEffectivePlayerCount=%v", pR.Id, playerId, pR.State, pR.EffectivePlayerCount))
|
||||
}
|
||||
pR.Players[playerId].X = playerPos.X
|
||||
pR.Players[playerId].Y = playerPos.Y
|
||||
pR.Players[playerId].VirtualGridX, pR.Players[playerId].VirtualGridY = pR.worldToVirtualGridPos(playerPos.X, playerPos.Y)
|
||||
|
||||
break
|
||||
}
|
||||
@@ -1215,12 +1215,15 @@ func (pR *Room) applyInputFrameDownsyncDynamics(fromRenderFrameId int32, toRende
|
||||
if 0.0 == decodedInputSpeedFactor {
|
||||
continue
|
||||
}
|
||||
baseChange := player.Speed * pR.RollbackEstimatedDt * decodedInputSpeedFactor
|
||||
baseChange := float64(player.Speed) * pR.VirtualGridToWorldRatio * decodedInputSpeedFactor
|
||||
oldDx, oldDy := baseChange*float64(decodedInput[0]), baseChange*float64(decodedInput[1])
|
||||
dx, dy := oldDx, oldDy
|
||||
|
||||
collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex
|
||||
playerCollider := pR.CollisionSysMap[collisionPlayerIndex]
|
||||
// Reset playerCollider position from the "virtual grid position"
|
||||
playerCollider.X, playerCollider.Y = pR.virtualGridToPlayerColliderPos(player.VirtualGridX, player.VirtualGridY)
|
||||
|
||||
if collision := playerCollider.Check(oldDx, oldDy, "Barrier"); collision != nil {
|
||||
playerShape := playerCollider.Shape.(*resolv.ConvexPolygon)
|
||||
for _, obj := range collision.Objects {
|
||||
@@ -1242,8 +1245,7 @@ func (pR *Room) applyInputFrameDownsyncDynamics(fromRenderFrameId int32, toRende
|
||||
|
||||
player.Dir.Dx = decodedInput[0]
|
||||
player.Dir.Dy = decodedInput[1]
|
||||
player.X = playerCollider.X + pR.playerColliderRadius - spaceOffsetX
|
||||
player.Y = playerCollider.Y + pR.playerColliderRadius - spaceOffsetY
|
||||
player.VirtualGridX, player.VirtualGridY = pR.playerColliderAnchorToVirtualGridPos(playerCollider.X, playerCollider.Y)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1261,13 +1263,14 @@ func (pR *Room) inputFrameIdDebuggable(inputFrameId int32) bool {
|
||||
return 0 == (inputFrameId % 10)
|
||||
}
|
||||
|
||||
func (pR *Room) refreshColliders(spaceW, spaceH int32, spaceOffsetX, spaceOffsetY float64) {
|
||||
func (pR *Room) refreshColliders(spaceW, spaceH int32) {
|
||||
// Kindly note that by now, we've already got all the shapes in the tmx file into "pR.(Players | Barriers)" from "ParseTmxLayersAndGroups"
|
||||
|
||||
minStep := int(3) // the approx minimum distance a player can move per frame
|
||||
minStep := int(3) // the approx minimum distance a player can move per frame in world coordinate
|
||||
space := resolv.NewSpace(int(spaceW), int(spaceH), minStep, minStep) // allocate a new collision space everytime after a battle is settled
|
||||
for _, player := range pR.Players {
|
||||
playerCollider := GenerateRectCollider(player.X, player.Y, pR.playerColliderRadius*2, pR.playerColliderRadius*2, spaceOffsetX, spaceOffsetY, "Player")
|
||||
wx, wy := pR.virtualGridToWorldPos(player.VirtualGridX, player.VirtualGridY)
|
||||
playerCollider := GenerateRectCollider(wx, wy, pR.playerColliderRadius*2, pR.playerColliderRadius*2, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY, "Player")
|
||||
space.Add(playerCollider)
|
||||
// Keep track of the collider in "pR.CollisionSysMap"
|
||||
joinIndex := player.JoinIndex
|
||||
@@ -1278,7 +1281,7 @@ func (pR *Room) refreshColliders(spaceW, spaceH int32, spaceOffsetX, spaceOffset
|
||||
|
||||
for _, barrier := range pR.Barriers {
|
||||
boundaryUnaligned := barrier.Boundary
|
||||
barrierCollider := GenerateConvexPolygonCollider(boundaryUnaligned, spaceOffsetX, spaceOffsetY, "Barrier")
|
||||
barrierCollider := GenerateConvexPolygonCollider(boundaryUnaligned, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY, "Barrier")
|
||||
space.Add(barrierCollider)
|
||||
}
|
||||
}
|
||||
@@ -1286,3 +1289,35 @@ func (pR *Room) refreshColliders(spaceW, spaceH int32, spaceOffsetX, spaceOffset
|
||||
func (pR *Room) printBarrier(barrierCollider *resolv.Object) {
|
||||
Logger.Info(fmt.Sprintf("Barrier in roomId=%v: w=%v, h=%v, shape=%v", pR.Id, barrierCollider.W, barrierCollider.H, barrierCollider.Shape))
|
||||
}
|
||||
|
||||
func (pR *Room) worldToVirtualGridPos(x, y float64) (int32, int32) {
|
||||
// In JavaScript floating numbers suffer from seemingly non-deterministic arithmetics, and even if certain libs solved this issue by approaches such as fixed-point-number, they might not be used in other libs -- e.g. the "collision libs" we're interested in -- thus couldn't kill all pains.
|
||||
var virtualGridX int32 = int32(x * pR.WorldToVirtualGridRatio)
|
||||
var virtualGridY int32 = int32(y * pR.WorldToVirtualGridRatio)
|
||||
return virtualGridX, virtualGridY
|
||||
}
|
||||
|
||||
func (pR *Room) virtualGridToWorldPos(vx, vy int32) (float64, float64) {
|
||||
var x float64 = float64(vx) * pR.VirtualGridToWorldRatio
|
||||
var y float64 = float64(vy) * pR.VirtualGridToWorldRatio
|
||||
return x, y
|
||||
}
|
||||
|
||||
func (pR *Room) playerWorldToCollisionPos(wx, wy float64) (float64, float64) {
|
||||
// TODO: remove this duplicate code w.r.t. "dnmshared/resolv_helper.go"
|
||||
return wx - pR.playerColliderRadius + pR.collisionSpaceOffsetX, wy - pR.playerColliderRadius + pR.collisionSpaceOffsetY
|
||||
}
|
||||
|
||||
func (pR *Room) playerColliderAnchorToWorldPos(cx, cy float64) (float64, float64) {
|
||||
return cx + pR.playerColliderRadius - pR.collisionSpaceOffsetX, cy + pR.playerColliderRadius - pR.collisionSpaceOffsetY
|
||||
}
|
||||
|
||||
func (pR *Room) playerColliderAnchorToVirtualGridPos(cx, cy float64) (int32, int32) {
|
||||
wx, wy := pR.playerColliderAnchorToWorldPos(cx, cy)
|
||||
return pR.worldToVirtualGridPos(wx, wy)
|
||||
}
|
||||
|
||||
func (pR *Room) virtualGridToPlayerColliderPos(vx, vy int32) (float64, float64) {
|
||||
wx, wy := pR.virtualGridToWorldPos(vx, vy)
|
||||
return pR.playerWorldToCollisionPos(wx, wy)
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
1250
battle_srv/protos/room_downsync_frame.pb.go
Normal file
1250
battle_srv/protos/room_downsync_frame.pb.go
Normal file
File diff suppressed because it is too large
Load Diff
@@ -8,9 +8,9 @@ import (
|
||||
"github.com/gorilla/websocket"
|
||||
"go.uber.org/zap"
|
||||
"net/http"
|
||||
. "server/common"
|
||||
"server/models"
|
||||
pb "server/pb_output"
|
||||
. "battle_srv/common"
|
||||
"battle_srv/models"
|
||||
pb "battle_srv/protos"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
@@ -263,9 +263,11 @@ func Serve(c *gin.Context) {
|
||||
InputFrameUpsyncDelayTolerance: pRoom.InputFrameUpsyncDelayTolerance,
|
||||
MaxChasingRenderFramesPerUpdate: pRoom.MaxChasingRenderFramesPerUpdate,
|
||||
PlayerBattleState: pThePlayer.BattleState, // For frontend to know whether it's rejoining
|
||||
RollbackEstimatedDt: pRoom.RollbackEstimatedDt,
|
||||
RollbackEstimatedDtMillis: pRoom.RollbackEstimatedDtMillis,
|
||||
RollbackEstimatedDtNanos: pRoom.RollbackEstimatedDtNanos,
|
||||
|
||||
WorldToVirtualGridRatio: pRoom.WorldToVirtualGridRatio,
|
||||
VirtualGridToWorldRatio: pRoom.VirtualGridToWorldRatio,
|
||||
}
|
||||
|
||||
resp := &pb.WsResp{
|
||||
|
Reference in New Issue
Block a user