Initial attempt integrating online battle.

This commit is contained in:
genxium 2023-01-02 23:35:56 +08:00
parent 69581009ee
commit 80c6e05731
14 changed files with 198 additions and 124 deletions

View File

@ -77,7 +77,6 @@ func toPbRoomDownsyncFrame(rdf *battle.RoomDownsyncFrame) *pb.RoomDownsyncFrame
return ret return ret
} }
/*
func toPbPlayers(modelInstances map[int32]*Player, withMetaInfo bool) []*pb.PlayerDownsync { func toPbPlayers(modelInstances map[int32]*Player, withMetaInfo bool) []*pb.PlayerDownsync {
toRet := make([]*pb.PlayerDownsync, len(modelInstances), len(modelInstances)) toRet := make([]*pb.PlayerDownsync, len(modelInstances), len(modelInstances))
if nil == modelInstances { if nil == modelInstances {
@ -93,6 +92,10 @@ func toPbPlayers(modelInstances map[int32]*Player, withMetaInfo bool) []*pb.Play
DirY: last.DirY, DirY: last.DirY,
VelX: last.VelX, VelX: last.VelX,
VelY: last.VelY, VelY: last.VelY,
FramesToRecover: last.FramesToRecover,
FramesInChState: last.FramesInChState,
ActiveSkillId: last.ActiveSkillId,
ActiveSkillHit: last.ActiveSkillHit,
Speed: last.Speed, Speed: last.Speed,
BattleState: last.BattleState, BattleState: last.BattleState,
CharacterState: last.CharacterState, CharacterState: last.CharacterState,
@ -101,8 +104,6 @@ func toPbPlayers(modelInstances map[int32]*Player, withMetaInfo bool) []*pb.Play
ColliderRadius: last.ColliderRadius, ColliderRadius: last.ColliderRadius,
Score: last.Score, Score: last.Score,
Removed: last.Removed, Removed: last.Removed,
FramesToRecover: last.FramesToRecover,
FramesInChState: last.FramesInChState,
} }
if withMetaInfo { if withMetaInfo {
pbPlayer.Name = last.Name pbPlayer.Name = last.Name
@ -114,7 +115,6 @@ func toPbPlayers(modelInstances map[int32]*Player, withMetaInfo bool) []*pb.Play
return toRet return toRet
} }
*/
func toJsPlayers(modelInstances map[int32]*Player) []*battle.PlayerDownsync { func toJsPlayers(modelInstances map[int32]*Player) []*battle.PlayerDownsync {
toRet := make([]*battle.PlayerDownsync, len(modelInstances), len(modelInstances)) toRet := make([]*battle.PlayerDownsync, len(modelInstances), len(modelInstances))

View File

@ -90,8 +90,12 @@ func calRoomScore(inRoomPlayerCount int32, roomPlayerCnt int, currentRoomBattleS
type Room struct { type Room struct {
Id int32 Id int32
Capacity int Capacity int
BattleDurationFrames int32
NstDelayFrames int32
Players map[int32]*Player Players map[int32]*Player
PlayersArr []*Player // ordered by joinIndex PlayersArr []*Player // ordered by joinIndex
SpeciesIdList []int32 // ordered by joinIndex
CharacterConfigsArr []*battle.CharacterConfig // ordered by joinIndex
Space *resolv.Space Space *resolv.Space
CollisionSysMap map[int32]*resolv.Object CollisionSysMap map[int32]*resolv.Object
/** /**
@ -135,7 +139,6 @@ type Room struct {
BackendDynamicsEnabled bool BackendDynamicsEnabled bool
ForceAllResyncOnAnyActiveSlowTicker bool ForceAllResyncOnAnyActiveSlowTicker bool
LastRenderFrameIdTriggeredAt int64 LastRenderFrameIdTriggeredAt int64
PlayerDefaultSpeed int32
BulletBattleLocalIdCounter int32 BulletBattleLocalIdCounter int32
dilutedRollbackEstimatedDtNanos int64 dilutedRollbackEstimatedDtNanos int64
@ -165,11 +168,12 @@ func (pR *Room) AddPlayerIfPossible(pPlayerFromDbInit *Player, session *websocke
} }
defer pR.onPlayerAdded(playerId) defer pR.onPlayerAdded(playerId)
pPlayerFromDbInit.AckingFrameId = -1 pPlayerFromDbInit.AckingFrameId = -1
pPlayerFromDbInit.AckingInputFrameId = -1 pPlayerFromDbInit.AckingInputFrameId = -1
pPlayerFromDbInit.LastSentInputFrameId = MAGIC_LAST_SENT_INPUT_FRAME_ID_NORMAL_ADDED pPlayerFromDbInit.LastSentInputFrameId = MAGIC_LAST_SENT_INPUT_FRAME_ID_NORMAL_ADDED
pPlayerFromDbInit.BattleState = PlayerBattleStateIns.ADDED_PENDING_BATTLE_COLLIDER_ACK pPlayerFromDbInit.BattleState = PlayerBattleStateIns.ADDED_PENDING_BATTLE_COLLIDER_ACK
pPlayerFromDbInit.Speed = pR.PlayerDefaultSpeed // Hardcoded
pPlayerFromDbInit.ColliderRadius = DEFAULT_PLAYER_RADIUS // Hardcoded pPlayerFromDbInit.ColliderRadius = DEFAULT_PLAYER_RADIUS // Hardcoded
pPlayerFromDbInit.InAir = true // Hardcoded pPlayerFromDbInit.InAir = true // Hardcoded
@ -207,7 +211,7 @@ func (pR *Room) ReAddPlayerIfPossible(pTmpPlayerInstance *Player, session *webso
pEffectiveInRoomPlayerInstance.AckingInputFrameId = -1 pEffectiveInRoomPlayerInstance.AckingInputFrameId = -1
pEffectiveInRoomPlayerInstance.LastSentInputFrameId = MAGIC_LAST_SENT_INPUT_FRAME_ID_READDED pEffectiveInRoomPlayerInstance.LastSentInputFrameId = MAGIC_LAST_SENT_INPUT_FRAME_ID_READDED
pEffectiveInRoomPlayerInstance.BattleState = PlayerBattleStateIns.READDED_PENDING_BATTLE_COLLIDER_ACK pEffectiveInRoomPlayerInstance.BattleState = PlayerBattleStateIns.READDED_PENDING_BATTLE_COLLIDER_ACK
pEffectiveInRoomPlayerInstance.Speed = pR.PlayerDefaultSpeed // Hardcoded
pEffectiveInRoomPlayerInstance.ColliderRadius = DEFAULT_PLAYER_RADIUS // Hardcoded pEffectiveInRoomPlayerInstance.ColliderRadius = DEFAULT_PLAYER_RADIUS // Hardcoded
pEffectiveInRoomPlayerInstance.InAir = true // Hardcoded pEffectiveInRoomPlayerInstance.InAir = true // Hardcoded
@ -373,6 +377,14 @@ func (pR *Room) StartBattle() {
pR.RenderFrameId = 0 pR.RenderFrameId = 0
for _, player := range pR.Players {
speciesId := int(player.JoinIndex - 1) // FIXME: Hardcoded the values for now
chosenCh := battle.Characters[speciesId]
pR.CharacterConfigsArr[player.JoinIndex-1] = chosenCh
pR.SpeciesIdList[player.JoinIndex-1] = int32(speciesId)
}
Logger.Info("[StartBattle] ", zap.Any("roomId", pR.Id), zap.Any("roomState", pR.State), zap.Any("SpeciesIdList", pR.SpeciesIdList))
// Initialize the "collisionSys" as well as "RenderFrameBuffer" // Initialize the "collisionSys" as well as "RenderFrameBuffer"
pR.CurDynamicsRenderFrameId = 0 pR.CurDynamicsRenderFrameId = 0
kickoffFrameJs := &battle.RoomDownsyncFrame{ kickoffFrameJs := &battle.RoomDownsyncFrame{
@ -446,7 +458,9 @@ func (pR *Room) StartBattle() {
continue continue
} }
kickoffFrameJs := pR.RenderFrameBuffer.GetByFrameId(0).(*battle.RoomDownsyncFrame) kickoffFrameJs := pR.RenderFrameBuffer.GetByFrameId(0).(*battle.RoomDownsyncFrame)
pR.sendSafely(toPbRoomDownsyncFrame(kickoffFrameJs), nil, DOWNSYNC_MSG_ACT_BATTLE_START, playerId, true) pbKickOffRenderFrame := toPbRoomDownsyncFrame(kickoffFrameJs)
pbKickOffRenderFrame.SpeciesIdList = pR.SpeciesIdList
pR.sendSafely(pbKickOffRenderFrame, nil, DOWNSYNC_MSG_ACT_BATTLE_START, playerId, true)
} }
Logger.Info(fmt.Sprintf("In `battleMainLoop` for roomId=%v sent out kickoffFrame", pR.Id)) Logger.Info(fmt.Sprintf("In `battleMainLoop` for roomId=%v sent out kickoffFrame", pR.Id))
} }
@ -515,10 +529,6 @@ func (pR *Room) StartBattle() {
}) })
} }
func (pR *Room) toDiscreteInputsBufferIndex(inputFrameId int32, joinIndex int32) int32 {
return (inputFrameId << 2) + joinIndex // allowing joinIndex upto 15
}
func (pR *Room) OnBattleCmdReceived(pReq *pb.WsReq) { func (pR *Room) OnBattleCmdReceived(pReq *pb.WsReq) {
/* /*
[WARNING] This function "OnBattleCmdReceived" could be called by different ws sessions and thus from different threads! [WARNING] This function "OnBattleCmdReceived" could be called by different ws sessions and thus from different threads!
@ -709,14 +719,11 @@ 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. // Always instantiates new HeapRAM blocks and let the old blocks die out due to not being retained by any root reference.
pR.BulletBattleLocalIdCounter = 0 pR.BulletBattleLocalIdCounter = 0
pR.WorldToVirtualGridRatio = battle.WORLD_TO_VIRTUAL_GRID_RATIO pR.CollisionMinStep = 8 // the approx minimum distance a player can move per frame in world coordinate
pR.VirtualGridToWorldRatio = float64(1.0) / pR.WorldToVirtualGridRatio // this is a one-off computation, should avoid division in iterations
pR.SpAtkLookupFrames = 5
pR.PlayerDefaultSpeed = int32(float64(1) * pR.WorldToVirtualGridRatio) // in virtual grids per frame
pR.CollisionMinStep = (int32(float64(pR.PlayerDefaultSpeed)*pR.VirtualGridToWorldRatio) << 3) // the approx minimum distance a player can move per frame in world coordinate
pR.playerOpPatternToSkillId = make(map[int]int)
pR.Players = make(map[int32]*Player) pR.Players = make(map[int32]*Player)
pR.PlayersArr = make([]*Player, pR.Capacity) pR.PlayersArr = make([]*Player, pR.Capacity)
pR.SpeciesIdList = make([]int32, pR.Capacity)
pR.CharacterConfigsArr = make([]*battle.CharacterConfig, pR.Capacity)
pR.CollisionSysMap = make(map[int32]*resolv.Object) pR.CollisionSysMap = make(map[int32]*resolv.Object)
pR.PlayerDownsyncSessionDict = make(map[int32]*websocket.Conn) pR.PlayerDownsyncSessionDict = make(map[int32]*websocket.Conn)
for _, oldWatchdog := range pR.PlayerActiveWatchdogDict { for _, oldWatchdog := range pR.PlayerActiveWatchdogDict {
@ -741,17 +748,16 @@ func (pR *Room) OnDismissed() {
pR.RenderFrameId = 0 pR.RenderFrameId = 0
pR.CurDynamicsRenderFrameId = 0 pR.CurDynamicsRenderFrameId = 0
pR.InputDelayFrames = 8
pR.NstDelayFrames = 16 pR.NstDelayFrames = 16
pR.InputScaleFrames = uint32(2)
pR.ServerFps = 60 serverFps := 60
pR.RollbackEstimatedDtMillis = 16.667 // 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 logging FAST FRAME pR.RollbackEstimatedDtNanos = 16666666 // A little smaller than the actual per frame time, just for logging FAST FRAME
dilutedServerFps := float64(58.0) // Don't set this value too small, otherwise we might miss force confirmation needs for slow tickers! dilutedServerFps := float64(58.0) // Don't set this value too small, otherwise we might miss force confirmation needs for slow tickers!
pR.dilutedRollbackEstimatedDtNanos = int64(float64(pR.RollbackEstimatedDtNanos) * float64(pR.ServerFps) / dilutedServerFps) pR.dilutedRollbackEstimatedDtNanos = int64(float64(pR.RollbackEstimatedDtNanos) * float64(serverFps) / dilutedServerFps)
pR.BattleDurationFrames = 60 * pR.ServerFps pR.BattleDurationFrames = int32(60 * serverFps)
pR.BattleDurationNanos = int64(pR.BattleDurationFrames) * (pR.RollbackEstimatedDtNanos + 1) pR.BattleDurationNanos = int64(pR.BattleDurationFrames) * (pR.RollbackEstimatedDtNanos + 1)
pR.InputFrameUpsyncDelayTolerance = (pR.NstDelayFrames >> pR.InputScaleFrames) - 1 // this value should be strictly smaller than (NstDelayFrames >> InputScaleFrames), otherwise "type#1 forceConfirmation" might become a lag avalanche pR.InputFrameUpsyncDelayTolerance = battle.ConvertToNoDelayInputFrameId(pR.NstDelayFrames) - 1 // this value should be strictly smaller than (NstDelayFrames >> InputScaleFrames), otherwise "type#1 forceConfirmation" might become a lag avalanche
pR.MaxChasingRenderFramesPerUpdate = 12 // Don't set this value too high to avoid exhausting frontend CPU within a single frame pR.MaxChasingRenderFramesPerUpdate = 12 // Don't set this value too high to avoid exhausting frontend CPU within a single frame
pR.BackendDynamicsEnabled = true // [WARNING] When "false", recovery upon reconnection wouldn't work! pR.BackendDynamicsEnabled = true // [WARNING] When "false", recovery upon reconnection wouldn't work!
@ -874,6 +880,10 @@ func (pR *Room) onPlayerAdded(playerId int32) {
pR.Players[playerId].JoinIndex = int32(index) + 1 pR.Players[playerId].JoinIndex = int32(index) + 1
pR.JoinIndexBooleanArr[index] = true pR.JoinIndexBooleanArr[index] = true
speciesId := index // FIXME
chosenCh := battle.Characters[speciesId]
pR.Players[playerId].Speed = chosenCh.Speed
// Lazily assign the initial position of "Player" for "RoomDownsyncFrame". // Lazily assign the initial position of "Player" for "RoomDownsyncFrame".
playerPosList := *pR.TmxPointsMap["PlayerStartingPos"] playerPosList := *pR.TmxPointsMap["PlayerStartingPos"]
if index > len(playerPosList) { if index > len(playerPosList) {
@ -884,7 +894,7 @@ func (pR *Room) onPlayerAdded(playerId int32) {
if nil == playerPos { 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)) 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].VirtualGridX, pR.Players[playerId].VirtualGridY = battle.WorldToVirtualGridPos(playerPos.X, playerPos.Y, pR.WorldToVirtualGridRatio) pR.Players[playerId].VirtualGridX, pR.Players[playerId].VirtualGridY = battle.WorldToVirtualGridPos(playerPos.X, playerPos.Y)
// Hardcoded initial character orientation/facing // Hardcoded initial character orientation/facing
if 0 == (pR.Players[playerId].JoinIndex % 2) { if 0 == (pR.Players[playerId].JoinIndex % 2) {
pR.Players[playerId].DirX = -2 pR.Players[playerId].DirX = -2
@ -1121,7 +1131,7 @@ func (pR *Room) markConfirmationIfApplicable(inputFrameUpsyncBatch []*pb.InputFr
*/ */
snapshotStFrameId := (pR.LastAllConfirmedInputFrameId - newAllConfirmedCount) snapshotStFrameId := (pR.LastAllConfirmedInputFrameId - newAllConfirmedCount)
refRenderFrameIdIfNeeded := pR.CurDynamicsRenderFrameId - 1 refRenderFrameIdIfNeeded := pR.CurDynamicsRenderFrameId - 1
refSnapshotStFrameId := battle.ConvertToInputFrameId(refRenderFrameIdIfNeeded, battle.INPUT_DELAY_FRAMES, battle.INPUT_SCALE_FRAMES) refSnapshotStFrameId := battle.ConvertToDelayedInputFrameId(refRenderFrameIdIfNeeded)
if refSnapshotStFrameId < snapshotStFrameId { if refSnapshotStFrameId < snapshotStFrameId {
snapshotStFrameId = refSnapshotStFrameId snapshotStFrameId = refSnapshotStFrameId
} }
@ -1137,7 +1147,7 @@ func (pR *Room) forceConfirmationIfApplicable(prevRenderFrameId int32) uint64 {
totPlayerCnt := uint32(pR.Capacity) totPlayerCnt := uint32(pR.Capacity)
allConfirmedMask := uint64((1 << totPlayerCnt) - 1) allConfirmedMask := uint64((1 << totPlayerCnt) - 1)
unconfirmedMask := uint64(0) unconfirmedMask := uint64(0)
if pR.LatestPlayerUpsyncedInputFrameId > (pR.LastAllConfirmedInputFrameId + (pR.NstDelayFrames >> pR.InputScaleFrames)) { if pR.LatestPlayerUpsyncedInputFrameId > (pR.LastAllConfirmedInputFrameId + pR.InputFrameUpsyncDelayTolerance + 1) {
// Type#1 check whether there's a significantly slow ticker among players // Type#1 check whether there's a significantly slow ticker among players
oldLastAllConfirmedInputFrameId := pR.LastAllConfirmedInputFrameId oldLastAllConfirmedInputFrameId := pR.LastAllConfirmedInputFrameId
for j := pR.LastAllConfirmedInputFrameId + 1; j <= pR.LatestPlayerUpsyncedInputFrameId; j++ { for j := pR.LastAllConfirmedInputFrameId + 1; j <= pR.LatestPlayerUpsyncedInputFrameId; j++ {
@ -1151,7 +1161,7 @@ func (pR *Room) forceConfirmationIfApplicable(prevRenderFrameId int32) uint64 {
pR.onInputFrameDownsyncAllConfirmed(inputFrameDownsync, -1) pR.onInputFrameDownsyncAllConfirmed(inputFrameDownsync, -1)
} }
if 0 < unconfirmedMask { if 0 < unconfirmedMask {
Logger.Info(fmt.Sprintf("[type#1 forceConfirmation] For roomId=%d@renderFrameId=%d, curDynamicsRenderFrameId=%d, LatestPlayerUpsyncedInputFrameId:%d, oldLastAllConfirmedInputFrameId:%d, newLastAllConfirmedInputFrameId:%d, (pR.NstDelayFrames >> pR.InputScaleFrames):%d, InputFrameUpsyncDelayTolerance:%d, unconfirmedMask=%d; there's a slow ticker suspect, forcing all-confirmation", pR.Id, pR.RenderFrameId, pR.CurDynamicsRenderFrameId, pR.LatestPlayerUpsyncedInputFrameId, oldLastAllConfirmedInputFrameId, pR.LastAllConfirmedInputFrameId, (pR.NstDelayFrames >> pR.InputScaleFrames), pR.InputFrameUpsyncDelayTolerance, unconfirmedMask)) Logger.Info(fmt.Sprintf("[type#1 forceConfirmation] For roomId=%d@renderFrameId=%d, curDynamicsRenderFrameId=%d, LatestPlayerUpsyncedInputFrameId:%d, oldLastAllConfirmedInputFrameId:%d, newLastAllConfirmedInputFrameId:%d, InputFrameUpsyncDelayTolerance:%d, unconfirmedMask=%d; there's a slow ticker suspect, forcing all-confirmation", pR.Id, pR.RenderFrameId, pR.CurDynamicsRenderFrameId, pR.LatestPlayerUpsyncedInputFrameId, oldLastAllConfirmedInputFrameId, pR.LastAllConfirmedInputFrameId, pR.InputFrameUpsyncDelayTolerance, unconfirmedMask))
} }
} else { } else {
// Type#2 helps resolve the edge case when all players are disconnected temporarily // Type#2 helps resolve the edge case when all players are disconnected temporarily
@ -1226,7 +1236,7 @@ func (pR *Room) applyInputFrameDownsyncDynamics(fromRenderFrameId int32, toRende
} }
} }
nextRenderFrame := battle.ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(pR.InputsBuffer, currRenderFrame, pR.Space, pR.CollisionSysMap, pR.SpaceOffsetX, pR.SpaceOffsetY) nextRenderFrame := battle.ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(pR.InputsBuffer, currRenderFrame, pR.Space, pR.CollisionSysMap, pR.SpaceOffsetX, pR.SpaceOffsetY, pR.CharacterConfigsArr)
pR.RenderFrameBuffer.Put(nextRenderFrame) pR.RenderFrameBuffer.Put(nextRenderFrame)
pR.CurDynamicsRenderFrameId++ pR.CurDynamicsRenderFrameId++
} }
@ -1248,7 +1258,7 @@ func (pR *Room) refreshColliders() {
// For debug-printing only. // For debug-printing only.
Logger.Info("ChooseStage printing polygon2D for barrierPolygon2DList", zap.Any("barrierLocalIdInBattle", barrierLocalIdInBattle), zap.Any("polygon2D.Anchor", polygon2D.Anchor), zap.Any("polygon2D.Points", polygon2D.Points)) Logger.Info("ChooseStage printing polygon2D for barrierPolygon2DList", zap.Any("barrierLocalIdInBattle", barrierLocalIdInBattle), zap.Any("polygon2D.Anchor", polygon2D.Anchor), zap.Any("polygon2D.Points", polygon2D.Points))
*/ */
barrierCollider := battle.GenerateConvexPolygonCollider(polygon2DUnaligned, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY, nil, "Barrier") barrierCollider := battle.GenerateConvexPolygonCollider(polygon2DUnaligned, pR.SpaceOffsetX, pR.SpaceOffsetY, nil, "Barrier")
pR.Space.Add(barrierCollider) pR.Space.Add(barrierCollider)
} }
} }
@ -1280,7 +1290,7 @@ func (pR *Room) doBattleMainLoopPerTickBackendDynamicsWithProperLocking(prevRend
dynamicsStartedAt := utils.UnixtimeNano() dynamicsStartedAt := utils.UnixtimeNano()
// Apply "all-confirmed inputFrames" to move forward "pR.CurDynamicsRenderFrameId" // Apply "all-confirmed inputFrames" to move forward "pR.CurDynamicsRenderFrameId"
nextDynamicsRenderFrameId := battle.ConvertToLastUsedRenderFrameId(pR.LastAllConfirmedInputFrameId) + 1 nextDynamicsRenderFrameId := battle.ConvertToLastUsedRenderFrameId(pR.LastAllConfirmedInputFrameId) + 1
Logger.Debug(fmt.Sprintf("roomId=%v, room.RenderFrameId=%v, room.CurDynamicsRenderFrameId=%v, LastAllConfirmedInputFrameId=%v, InputDelayFrames=%v, nextDynamicsRenderFrameId=%v", pR.Id, pR.RenderFrameId, pR.CurDynamicsRenderFrameId, pR.LastAllConfirmedInputFrameId, pR.InputDelayFrames, nextDynamicsRenderFrameId)) Logger.Debug(fmt.Sprintf("roomId=%v, room.RenderFrameId=%v, room.CurDynamicsRenderFrameId=%v, LastAllConfirmedInputFrameId=%v, nextDynamicsRenderFrameId=%v", pR.Id, pR.RenderFrameId, pR.CurDynamicsRenderFrameId, pR.LastAllConfirmedInputFrameId, nextDynamicsRenderFrameId))
pR.applyInputFrameDownsyncDynamics(pR.CurDynamicsRenderFrameId, nextDynamicsRenderFrameId) pR.applyInputFrameDownsyncDynamics(pR.CurDynamicsRenderFrameId, nextDynamicsRenderFrameId)
*pDynamicsDuration = utils.UnixtimeNano() - dynamicsStartedAt *pDynamicsDuration = utils.UnixtimeNano() - dynamicsStartedAt
} }
@ -1410,14 +1420,13 @@ func (pR *Room) downsyncToSinglePlayer(playerId int32, player *Player, refRender
} }
refRenderFrame := tmp.(*battle.RoomDownsyncFrame) refRenderFrame := tmp.(*battle.RoomDownsyncFrame)
for i, player := range pR.PlayersArr {
refRenderFrame.PlayersArr[i].ColliderRadius = player.ColliderRadius // hardcoded for now
}
if shouldResync3 { if shouldResync3 {
refRenderFrame.ShouldForceResync = true refRenderFrame.ShouldForceResync = true
} }
refRenderFrame.BackendUnconfirmedMask = unconfirmedMask refRenderFrame.BackendUnconfirmedMask = unconfirmedMask
pR.sendSafely(toPbRoomDownsyncFrame(refRenderFrame), toSendInputFrameDownsyncsSnapshot, DOWNSYNC_MSG_ACT_FORCED_RESYNC, playerId, false) pbRefRenderFrame := toPbRoomDownsyncFrame(refRenderFrame)
pbRefRenderFrame.SpeciesIdList = pR.SpeciesIdList
pR.sendSafely(pbRefRenderFrame, toSendInputFrameDownsyncsSnapshot, DOWNSYNC_MSG_ACT_FORCED_RESYNC, playerId, false)
//Logger.Warn(fmt.Sprintf("Sent refRenderFrameId=%v & inputFrameIds [%d, %d), for roomId=%v, playerId=%d, playerJoinIndex=%d, renderFrameId=%d, curDynamicsRenderFrameId=%d, playerLastSentInputFrameId=%d: InputsBuffer=%v", refRenderFrameId, toSendInputFrameIdSt, toSendInputFrameIdEd, pR.Id, playerId, player.JoinIndex, pR.RenderFrameId, pR.CurDynamicsRenderFrameId, player.LastSentInputFrameId, pR.InputsBufferString(false))) //Logger.Warn(fmt.Sprintf("Sent refRenderFrameId=%v & inputFrameIds [%d, %d), for roomId=%v, playerId=%d, playerJoinIndex=%d, renderFrameId=%d, curDynamicsRenderFrameId=%d, playerLastSentInputFrameId=%d: InputsBuffer=%v", refRenderFrameId, toSendInputFrameIdSt, toSendInputFrameIdEd, pR.Id, playerId, player.JoinIndex, pR.RenderFrameId, pR.CurDynamicsRenderFrameId, player.LastSentInputFrameId, pR.InputsBufferString(false)))
if shouldResync1 { if shouldResync1 {
Logger.Warn(fmt.Sprintf("Sent refRenderFrameId=%v & inputFrameIds [%d, %d), for roomId=%v, playerId=%d, playerJoinIndex=%d, renderFrameId=%d, curDynamicsRenderFrameId=%d, playerLastSentInputFrameId=%d: shouldResync1=%v, shouldResync2=%v, shouldResync3=%v, playerBattleState=%d", refRenderFrameId, toSendInputFrameIdSt, toSendInputFrameIdEd, pR.Id, playerId, player.JoinIndex, pR.RenderFrameId, pR.CurDynamicsRenderFrameId, player.LastSentInputFrameId, shouldResync1, shouldResync2, shouldResync3, playerBattleState)) Logger.Warn(fmt.Sprintf("Sent refRenderFrameId=%v & inputFrameIds [%d, %d), for roomId=%v, playerId=%d, playerJoinIndex=%d, renderFrameId=%d, curDynamicsRenderFrameId=%d, playerLastSentInputFrameId=%d: shouldResync1=%v, shouldResync2=%v, shouldResync3=%v, playerBattleState=%d", refRenderFrameId, toSendInputFrameIdSt, toSendInputFrameIdEd, pR.Id, playerId, player.JoinIndex, pR.RenderFrameId, pR.CurDynamicsRenderFrameId, player.LastSentInputFrameId, shouldResync1, shouldResync2, shouldResync3, playerBattleState))

View File

@ -1103,6 +1103,7 @@ type RoomDownsyncFrame struct {
MeleeBullets []*MeleeBullet `protobuf:"bytes,4,rep,name=meleeBullets,proto3" json:"meleeBullets,omitempty"` // I don't know how to mimic inheritance/composition in protobuf by far, thus using an array for each type of bullet as a compromise MeleeBullets []*MeleeBullet `protobuf:"bytes,4,rep,name=meleeBullets,proto3" json:"meleeBullets,omitempty"` // I don't know how to mimic inheritance/composition in protobuf by far, thus using an array for each type of bullet as a compromise
BackendUnconfirmedMask uint64 `protobuf:"varint,5,opt,name=backendUnconfirmedMask,proto3" json:"backendUnconfirmedMask,omitempty"` // Indexed by "joinIndex", same compression concern as stated in InputFrameDownsync BackendUnconfirmedMask uint64 `protobuf:"varint,5,opt,name=backendUnconfirmedMask,proto3" json:"backendUnconfirmedMask,omitempty"` // Indexed by "joinIndex", same compression concern as stated in InputFrameDownsync
ShouldForceResync bool `protobuf:"varint,6,opt,name=shouldForceResync,proto3" json:"shouldForceResync,omitempty"` ShouldForceResync bool `protobuf:"varint,6,opt,name=shouldForceResync,proto3" json:"shouldForceResync,omitempty"`
SpeciesIdList []int32 `protobuf:"varint,7,rep,packed,name=speciesIdList,proto3" json:"speciesIdList,omitempty"`
} }
func (x *RoomDownsyncFrame) Reset() { func (x *RoomDownsyncFrame) Reset() {
@ -1179,6 +1180,13 @@ func (x *RoomDownsyncFrame) GetShouldForceResync() bool {
return false return false
} }
func (x *RoomDownsyncFrame) GetSpeciesIdList() []int32 {
if x != nil {
return x.SpeciesIdList
}
return nil
}
var File_room_downsync_frame_proto protoreflect.FileDescriptor var File_room_downsync_frame_proto protoreflect.FileDescriptor
var file_room_downsync_frame_proto_rawDesc = []byte{ var file_room_downsync_frame_proto_rawDesc = []byte{
@ -1396,7 +1404,7 @@ var file_room_downsync_frame_proto_rawDesc = []byte{
0x12, 0x39, 0x0a, 0x17, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x61, 0x74, 0x61, 0x4c, 0x6f, 0x67, 0x12, 0x39, 0x0a, 0x17, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x61, 0x74, 0x61, 0x4c, 0x6f, 0x67,
0x67, 0x69, 0x6e, 0x67, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0xe7, 0x07, 0x20, 0x01, 0x67, 0x69, 0x6e, 0x67, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0xe7, 0x07, 0x20, 0x01,
0x28, 0x08, 0x52, 0x17, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x61, 0x74, 0x61, 0x4c, 0x6f, 0x67, 0x28, 0x08, 0x52, 0x17, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x61, 0x74, 0x61, 0x4c, 0x6f, 0x67,
0x67, 0x69, 0x6e, 0x67, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0xa2, 0x02, 0x0a, 0x11, 0x67, 0x69, 0x6e, 0x67, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0xc8, 0x02, 0x0a, 0x11,
0x52, 0x6f, 0x6f, 0x6d, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x46, 0x72, 0x61, 0x6d, 0x52, 0x6f, 0x6f, 0x6d, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x46, 0x72, 0x61, 0x6d,
0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69,
0x64, 0x12, 0x36, 0x0a, 0x0a, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x41, 0x72, 0x72, 0x18, 0x64, 0x12, 0x36, 0x0a, 0x0a, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x41, 0x72, 0x72, 0x18,
@ -1415,8 +1423,11 @@ var file_room_downsync_frame_proto_rawDesc = []byte{
0x73, 0x6b, 0x12, 0x2c, 0x0a, 0x11, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x46, 0x6f, 0x72, 0x63, 0x73, 0x6b, 0x12, 0x2c, 0x0a, 0x11, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x46, 0x6f, 0x72, 0x63,
0x65, 0x52, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x73, 0x65, 0x52, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x73,
0x68, 0x6f, 0x75, 0x6c, 0x64, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x79, 0x6e, 0x63,
0x42, 0x13, 0x5a, 0x11, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x5f, 0x73, 0x72, 0x76, 0x2f, 0x70, 0x12, 0x24, 0x0a, 0x0d, 0x73, 0x70, 0x65, 0x63, 0x69, 0x65, 0x73, 0x49, 0x64, 0x4c, 0x69, 0x73,
0x72, 0x6f, 0x74, 0x6f, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x74, 0x18, 0x07, 0x20, 0x03, 0x28, 0x05, 0x52, 0x0d, 0x73, 0x70, 0x65, 0x63, 0x69, 0x65, 0x73,
0x49, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x13, 0x5a, 0x11, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65,
0x5f, 0x73, 0x72, 0x76, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x33,
} }
var ( var (

View File

@ -249,12 +249,11 @@ func Serve(c *gin.Context) {
InputFrameUpsyncDelayTolerance: pRoom.InputFrameUpsyncDelayTolerance, InputFrameUpsyncDelayTolerance: pRoom.InputFrameUpsyncDelayTolerance,
MaxChasingRenderFramesPerUpdate: pRoom.MaxChasingRenderFramesPerUpdate, MaxChasingRenderFramesPerUpdate: pRoom.MaxChasingRenderFramesPerUpdate,
PlayerBattleState: pThePlayer.BattleState, // For frontend to know whether it's rejoining
RollbackEstimatedDtMillis: pRoom.RollbackEstimatedDtMillis, RollbackEstimatedDtMillis: pRoom.RollbackEstimatedDtMillis,
RollbackEstimatedDtNanos: pRoom.RollbackEstimatedDtNanos, RollbackEstimatedDtNanos: pRoom.RollbackEstimatedDtNanos,
InputDelayFrames: pRoom.InputDelayFrames, SpaceOffsetX: pRoom.SpaceOffsetX,
InputScaleFrames: pRoom.InputScaleFrames, SpaceOffsetY: pRoom.SpaceOffsetY,
RenderCacheSize: pRoom.RenderCacheSize, RenderCacheSize: pRoom.RenderCacheSize,
CollisionMinStep: pRoom.CollisionMinStep, CollisionMinStep: pRoom.CollisionMinStep,

View File

@ -4968,7 +4968,7 @@ $packages["jsexport/battle"] = (function() {
this.Eles = Eles_; this.Eles = Eles_;
}); });
SkillMapperType = $pkg.SkillMapperType = $newType(4, $kindFunc, "battle.SkillMapperType", true, "jsexport/battle", true, null); SkillMapperType = $pkg.SkillMapperType = $newType(4, $kindFunc, "battle.SkillMapperType", true, "jsexport/battle", true, null);
CharacterConfig = $pkg.CharacterConfig = $newType(0, $kindStruct, "battle.CharacterConfig", true, "jsexport/battle", true, function(SpeciesId_, SpeciesName_, InAirIdleFrameIdxTurningPoint_, InAirIdleFrameIdxTurnedCycle_, LayDownFrames_, LayDownFramesToRecover_, GetUpFrames_, GetUpFramesToRecover_, JumpingInitVelY_, SkillMapper_) { CharacterConfig = $pkg.CharacterConfig = $newType(0, $kindStruct, "battle.CharacterConfig", true, "jsexport/battle", true, function(SpeciesId_, SpeciesName_, InAirIdleFrameIdxTurningPoint_, InAirIdleFrameIdxTurnedCycle_, LayDownFrames_, LayDownFramesToRecover_, GetUpFrames_, GetUpFramesToRecover_, Speed_, JumpingInitVelY_, SkillMapper_) {
this.$val = this; this.$val = this;
if (arguments.length === 0) { if (arguments.length === 0) {
this.SpeciesId = 0; this.SpeciesId = 0;
@ -4979,6 +4979,7 @@ $packages["jsexport/battle"] = (function() {
this.LayDownFramesToRecover = 0; this.LayDownFramesToRecover = 0;
this.GetUpFrames = 0; this.GetUpFrames = 0;
this.GetUpFramesToRecover = 0; this.GetUpFramesToRecover = 0;
this.Speed = 0;
this.JumpingInitVelY = 0; this.JumpingInitVelY = 0;
this.SkillMapper = $throwNilPointerError; this.SkillMapper = $throwNilPointerError;
return; return;
@ -4991,6 +4992,7 @@ $packages["jsexport/battle"] = (function() {
this.LayDownFramesToRecover = LayDownFramesToRecover_; this.LayDownFramesToRecover = LayDownFramesToRecover_;
this.GetUpFrames = GetUpFrames_; this.GetUpFrames = GetUpFrames_;
this.GetUpFramesToRecover = GetUpFramesToRecover_; this.GetUpFramesToRecover = GetUpFramesToRecover_;
this.Speed = Speed_;
this.JumpingInitVelY = JumpingInitVelY_; this.JumpingInitVelY = JumpingInitVelY_;
this.SkillMapper = SkillMapper_; this.SkillMapper = SkillMapper_;
}); });
@ -6006,7 +6008,7 @@ $packages["jsexport/battle"] = (function() {
InputFrameDownsync.init("", [{prop: "InputFrameId", name: "InputFrameId", embedded: false, exported: true, typ: $Int32, tag: ""}, {prop: "InputList", name: "InputList", embedded: false, exported: true, typ: sliceType$5, tag: ""}, {prop: "ConfirmedList", name: "ConfirmedList", embedded: false, exported: true, typ: $Uint64, tag: ""}]); InputFrameDownsync.init("", [{prop: "InputFrameId", name: "InputFrameId", embedded: false, exported: true, typ: $Int32, tag: ""}, {prop: "InputList", name: "InputList", embedded: false, exported: true, typ: sliceType$5, tag: ""}, {prop: "ConfirmedList", name: "ConfirmedList", embedded: false, exported: true, typ: $Uint64, tag: ""}]);
RingBuffer.init("", [{prop: "Ed", name: "Ed", embedded: false, exported: true, typ: $Int32, tag: ""}, {prop: "St", name: "St", embedded: false, exported: true, typ: $Int32, tag: ""}, {prop: "EdFrameId", name: "EdFrameId", embedded: false, exported: true, typ: $Int32, tag: ""}, {prop: "StFrameId", name: "StFrameId", embedded: false, exported: true, typ: $Int32, tag: ""}, {prop: "N", name: "N", embedded: false, exported: true, typ: $Int32, tag: ""}, {prop: "Cnt", name: "Cnt", embedded: false, exported: true, typ: $Int32, tag: ""}, {prop: "Eles", name: "Eles", embedded: false, exported: true, typ: sliceType$2, tag: ""}]); RingBuffer.init("", [{prop: "Ed", name: "Ed", embedded: false, exported: true, typ: $Int32, tag: ""}, {prop: "St", name: "St", embedded: false, exported: true, typ: $Int32, tag: ""}, {prop: "EdFrameId", name: "EdFrameId", embedded: false, exported: true, typ: $Int32, tag: ""}, {prop: "StFrameId", name: "StFrameId", embedded: false, exported: true, typ: $Int32, tag: ""}, {prop: "N", name: "N", embedded: false, exported: true, typ: $Int32, tag: ""}, {prop: "Cnt", name: "Cnt", embedded: false, exported: true, typ: $Int32, tag: ""}, {prop: "Eles", name: "Eles", embedded: false, exported: true, typ: sliceType$2, tag: ""}]);
SkillMapperType.init([$Int, ptrType$5], [$Int], false); SkillMapperType.init([$Int, ptrType$5], [$Int], false);
CharacterConfig.init("", [{prop: "SpeciesId", name: "SpeciesId", embedded: false, exported: true, typ: $Int, tag: ""}, {prop: "SpeciesName", name: "SpeciesName", embedded: false, exported: true, typ: $String, tag: ""}, {prop: "InAirIdleFrameIdxTurningPoint", name: "InAirIdleFrameIdxTurningPoint", embedded: false, exported: true, typ: $Int, tag: ""}, {prop: "InAirIdleFrameIdxTurnedCycle", name: "InAirIdleFrameIdxTurnedCycle", embedded: false, exported: true, typ: $Int, tag: ""}, {prop: "LayDownFrames", name: "LayDownFrames", embedded: false, exported: true, typ: $Int32, tag: ""}, {prop: "LayDownFramesToRecover", name: "LayDownFramesToRecover", embedded: false, exported: true, typ: $Int32, tag: ""}, {prop: "GetUpFrames", name: "GetUpFrames", embedded: false, exported: true, typ: $Int32, tag: ""}, {prop: "GetUpFramesToRecover", name: "GetUpFramesToRecover", embedded: false, exported: true, typ: $Int32, tag: ""}, {prop: "JumpingInitVelY", name: "JumpingInitVelY", embedded: false, exported: true, typ: $Int32, tag: ""}, {prop: "SkillMapper", name: "SkillMapper", embedded: false, exported: true, typ: SkillMapperType, tag: ""}]); CharacterConfig.init("", [{prop: "SpeciesId", name: "SpeciesId", embedded: false, exported: true, typ: $Int, tag: ""}, {prop: "SpeciesName", name: "SpeciesName", embedded: false, exported: true, typ: $String, tag: ""}, {prop: "InAirIdleFrameIdxTurningPoint", name: "InAirIdleFrameIdxTurningPoint", embedded: false, exported: true, typ: $Int, tag: ""}, {prop: "InAirIdleFrameIdxTurnedCycle", name: "InAirIdleFrameIdxTurnedCycle", embedded: false, exported: true, typ: $Int, tag: ""}, {prop: "LayDownFrames", name: "LayDownFrames", embedded: false, exported: true, typ: $Int32, tag: ""}, {prop: "LayDownFramesToRecover", name: "LayDownFramesToRecover", embedded: false, exported: true, typ: $Int32, tag: ""}, {prop: "GetUpFrames", name: "GetUpFrames", embedded: false, exported: true, typ: $Int32, tag: ""}, {prop: "GetUpFramesToRecover", name: "GetUpFramesToRecover", embedded: false, exported: true, typ: $Int32, tag: ""}, {prop: "Speed", name: "Speed", embedded: false, exported: true, typ: $Int32, tag: ""}, {prop: "JumpingInitVelY", name: "JumpingInitVelY", embedded: false, exported: true, typ: $Int32, tag: ""}, {prop: "SkillMapper", name: "SkillMapper", embedded: false, exported: true, typ: SkillMapperType, tag: ""}]);
SatResult.init("", [{prop: "Overlap", name: "Overlap", embedded: false, exported: true, typ: $Float64, tag: ""}, {prop: "OverlapX", name: "OverlapX", embedded: false, exported: true, typ: $Float64, tag: ""}, {prop: "OverlapY", name: "OverlapY", embedded: false, exported: true, typ: $Float64, tag: ""}, {prop: "AContainedInB", name: "AContainedInB", embedded: false, exported: true, typ: $Bool, tag: ""}, {prop: "BContainedInA", name: "BContainedInA", embedded: false, exported: true, typ: $Bool, tag: ""}, {prop: "Axis", name: "Axis", embedded: false, exported: true, typ: resolv.Vector, tag: ""}]); SatResult.init("", [{prop: "Overlap", name: "Overlap", embedded: false, exported: true, typ: $Float64, tag: ""}, {prop: "OverlapX", name: "OverlapX", embedded: false, exported: true, typ: $Float64, tag: ""}, {prop: "OverlapY", name: "OverlapY", embedded: false, exported: true, typ: $Float64, tag: ""}, {prop: "AContainedInB", name: "AContainedInB", embedded: false, exported: true, typ: $Bool, tag: ""}, {prop: "BContainedInA", name: "BContainedInA", embedded: false, exported: true, typ: $Bool, tag: ""}, {prop: "Axis", name: "Axis", embedded: false, exported: true, typ: resolv.Vector, tag: ""}]);
$init = function() { $init = function() {
$pkg.$init = function() {}; $pkg.$init = function() {};
@ -6015,7 +6017,7 @@ $packages["jsexport/battle"] = (function() {
$r = resolv.$init(); /* */ $s = 2; case 2: if($c) { $c = false; $r = $r.$blk(); } if ($r && $r.$blk !== undefined) { break s; } $r = resolv.$init(); /* */ $s = 2; case 2: if($c) { $c = false; $r = $r.$blk(); } if ($r && $r.$blk !== undefined) { break s; }
$pkg.DIRECTION_DECODER = new sliceType$1([new sliceType([0, 0]), new sliceType([0, 2]), new sliceType([0, -2]), new sliceType([2, 0]), new sliceType([-2, 0]), new sliceType([1, 1]), new sliceType([-1, -1]), new sliceType([1, -1]), new sliceType([-1, 1])]); $pkg.DIRECTION_DECODER = new sliceType$1([new sliceType([0, 0]), new sliceType([0, 2]), new sliceType([0, -2]), new sliceType([2, 0]), new sliceType([-2, 0]), new sliceType([1, 1]), new sliceType([-1, -1]), new sliceType([1, -1]), new sliceType([-1, 1])]);
skills = $makeMap($Int.keyFor, [{ k: 1, v: new Skill.ptr(0, 30, 30, 30, 1, 2, new sliceType$2([new MeleeBullet.ptr(new Bullet.ptr(0, 0, 7, 13, 30, 22, 13, 9, 50, 0, 5, 0, 0, 1200, 0, 2400, 3200, false, $makeMap($Int.keyFor, [{ k: 1, v: 2 }])))])) }, { k: 2, v: new Skill.ptr(0, 36, 36, 36, 1, 11, new sliceType$2([new MeleeBullet.ptr(new Bullet.ptr(0, 0, 18, 22, 36, 18, 18, 9, 50, 0, 5, 0, 0, 1800, 0, 2400, 3200, false, $makeMap($Int.keyFor, [{ k: 1, v: 3 }])))])) }, { k: 3, v: new Skill.ptr(0, 60, 60, 60, 1, 12, new sliceType$2([new MeleeBullet.ptr(new Bullet.ptr(0, 0, 15, 0, 0, 40, 999999999, 9, 200, 700, 10, 0, 0, 2400, 0, 3200, 3200, true, false))])) }, { k: 4, v: new Skill.ptr(0, 30, 30, 30, 1, 2, new sliceType$2([new MeleeBullet.ptr(new Bullet.ptr(0, 0, 7, 13, 30, 22, 13, 9, 50, 0, 5, 0, 0, 1200, 0, 2400, 3200, false, $makeMap($Int.keyFor, [{ k: 1, v: 5 }])))])) }, { k: 5, v: new Skill.ptr(0, 36, 36, 36, 1, 11, new sliceType$2([new MeleeBullet.ptr(new Bullet.ptr(0, 0, 18, 22, 36, 18, 18, 9, 50, 0, 5, 0, 0, 1800, 0, 2400, 3200, false, $makeMap($Int.keyFor, [{ k: 1, v: 6 }])))])) }, { k: 6, v: new Skill.ptr(0, 60, 60, 60, 1, 12, new sliceType$2([new MeleeBullet.ptr(new Bullet.ptr(0, 0, 15, 0, 0, 40, 999999999, 9, 200, 700, 10, 0, 0, 2400, 0, 3200, 3200, true, false))])) }, { k: 255, v: new Skill.ptr(0, 34, 34, 34, 1, 6, new sliceType$2([new MeleeBullet.ptr(new Bullet.ptr(0, 0, 3, 0, 0, 20, 18, 9, 50, 0, 5, 0, 0, 1200, 0, 3200, 2400, false, false))])) }, { k: 256, v: new Skill.ptr(0, 34, 34, 34, 1, 6, new sliceType$2([new MeleeBullet.ptr(new Bullet.ptr(0, 0, 3, 0, 0, 20, 18, 9, 50, 0, 5, 0, 0, 1200, 0, 3200, 2400, false, false))])) }]); skills = $makeMap($Int.keyFor, [{ k: 1, v: new Skill.ptr(0, 30, 30, 30, 1, 2, new sliceType$2([new MeleeBullet.ptr(new Bullet.ptr(0, 0, 7, 13, 30, 22, 13, 9, 50, 0, 5, 0, 0, 1200, 0, 2400, 3200, false, $makeMap($Int.keyFor, [{ k: 1, v: 2 }])))])) }, { k: 2, v: new Skill.ptr(0, 36, 36, 36, 1, 11, new sliceType$2([new MeleeBullet.ptr(new Bullet.ptr(0, 0, 18, 22, 36, 18, 18, 9, 50, 0, 5, 0, 0, 1800, 0, 2400, 3200, false, $makeMap($Int.keyFor, [{ k: 1, v: 3 }])))])) }, { k: 3, v: new Skill.ptr(0, 60, 60, 60, 1, 12, new sliceType$2([new MeleeBullet.ptr(new Bullet.ptr(0, 0, 15, 0, 0, 40, 999999999, 9, 200, 700, 10, 0, 0, 2400, 0, 3200, 3200, true, false))])) }, { k: 4, v: new Skill.ptr(0, 30, 30, 30, 1, 2, new sliceType$2([new MeleeBullet.ptr(new Bullet.ptr(0, 0, 7, 13, 30, 22, 13, 9, 50, 0, 5, 0, 0, 1200, 0, 2400, 3200, false, $makeMap($Int.keyFor, [{ k: 1, v: 5 }])))])) }, { k: 5, v: new Skill.ptr(0, 36, 36, 36, 1, 11, new sliceType$2([new MeleeBullet.ptr(new Bullet.ptr(0, 0, 18, 22, 36, 18, 18, 9, 50, 0, 5, 0, 0, 1800, 0, 2400, 3200, false, $makeMap($Int.keyFor, [{ k: 1, v: 6 }])))])) }, { k: 6, v: new Skill.ptr(0, 60, 60, 60, 1, 12, new sliceType$2([new MeleeBullet.ptr(new Bullet.ptr(0, 0, 15, 0, 0, 40, 999999999, 9, 200, 700, 10, 0, 0, 2400, 0, 3200, 3200, true, false))])) }, { k: 255, v: new Skill.ptr(0, 34, 34, 34, 1, 6, new sliceType$2([new MeleeBullet.ptr(new Bullet.ptr(0, 0, 3, 0, 0, 20, 18, 9, 50, 0, 5, 0, 0, 1200, 0, 3200, 2400, false, false))])) }, { k: 256, v: new Skill.ptr(0, 34, 34, 34, 1, 6, new sliceType$2([new MeleeBullet.ptr(new Bullet.ptr(0, 0, 3, 0, 0, 20, 18, 9, 50, 0, 5, 0, 0, 1200, 0, 3200, 2400, false, false))])) }]);
$pkg.Characters = $makeMap($Int.keyFor, [{ k: 0, v: new CharacterConfig.ptr(0, "MonkGirl", 11, 1, 16, 16, 33, 30, 800, (function(patternId, currPlayerDownsync) { $pkg.Characters = $makeMap($Int.keyFor, [{ k: 0, v: new CharacterConfig.ptr(0, "MonkGirl", 11, 1, 16, 16, 33, 30, 120, 800, (function(patternId, currPlayerDownsync) {
var _entry, _entry$1, _ref, _tuple, _tuple$1, currPlayerDownsync, existent1, existent2, nextSkillId, patternId, skillConfig, v, x, x$1; var _entry, _entry$1, _ref, _tuple, _tuple$1, currPlayerDownsync, existent1, existent2, nextSkillId, patternId, skillConfig, v, x, x$1;
if (1 === patternId) { if (1 === patternId) {
if (0 === currPlayerDownsync.FramesToRecover) { if (0 === currPlayerDownsync.FramesToRecover) {
@ -6045,7 +6047,7 @@ $packages["jsexport/battle"] = (function() {
} }
} }
return -1; return -1;
})) }, { k: 1, v: new CharacterConfig.ptr(1, "KnifeGirl", 9, 1, 16, 16, 30, 27, 750, (function(patternId, currPlayerDownsync) { })) }, { k: 1, v: new CharacterConfig.ptr(1, "KnifeGirl", 9, 1, 16, 16, 30, 27, 140, 750, (function(patternId, currPlayerDownsync) {
var _entry, _entry$1, _ref, _tuple, _tuple$1, currPlayerDownsync, existent1, existent2, nextSkillId, patternId, skillConfig, v, x, x$1; var _entry, _entry$1, _ref, _tuple, _tuple$1, currPlayerDownsync, existent1, existent2, nextSkillId, patternId, skillConfig, v, x, x$1;
if (1 === patternId) { if (1 === patternId) {
if (0 === currPlayerDownsync.FramesToRecover) { if (0 === currPlayerDownsync.FramesToRecover) {

View File

@ -9,10 +9,10 @@
</data> </data>
</layer> </layer>
<objectgroup id="1" name="PlayerStartingPos"> <objectgroup id="1" name="PlayerStartingPos">
<object id="135" x="865" y="1447"> <object id="135" x="800" y="1447">
<point/> <point/>
</object> </object>
<object id="137" x="909" y="1447"> <object id="137" x="1000" y="1447">
<point/> <point/>
</object> </object>
</objectgroup> </objectgroup>

View File

@ -139,4 +139,5 @@ message RoomDownsyncFrame {
repeated MeleeBullet meleeBullets = 4; // I don't know how to mimic inheritance/composition in protobuf by far, thus using an array for each type of bullet as a compromise repeated MeleeBullet meleeBullets = 4; // I don't know how to mimic inheritance/composition in protobuf by far, thus using an array for each type of bullet as a compromise
uint64 backendUnconfirmedMask = 5; // Indexed by "joinIndex", same compression concern as stated in InputFrameDownsync uint64 backendUnconfirmedMask = 5; // Indexed by "joinIndex", same compression concern as stated in InputFrameDownsync
bool shouldForceResync = 6; bool shouldForceResync = 6;
repeated int32 speciesIdList = 7;
} }

View File

@ -440,7 +440,7 @@
"array": [ "array": [
0, 0,
0, 0,
216.50135522089343, 216.79917701871616,
0, 0,
0, 0,
0, 0,

View File

@ -461,7 +461,7 @@
"array": [ "array": [
0, 0,
0, 0,
210.4441731196186, 209.83528025849938,
0, 0,
0, 0,
0, 0,

View File

@ -279,7 +279,7 @@ cc.Class({
self.collisionPlayerIndexPrefix = (1 << 17); // For tracking the movements of players self.collisionPlayerIndexPrefix = (1 << 17); // For tracking the movements of players
if (null != self.playerRichInfoDict) { if (null != self.playerRichInfoDict) {
self.playerRichInfoDict.forEach((playerRichInfo, playerId) => { self.playerRichInfoDict.forEach((playerRichInfo, playerId) => {
if (playerRichInfo.node.parent) { if (playerRichInfo.node && playerRichInfo.node.parent) {
playerRichInfo.node.parent.removeChild(playerRichInfo.node); playerRichInfo.node.parent.removeChild(playerRichInfo.node);
} }
}); });

View File

@ -5161,6 +5161,7 @@ $root.protos = (function() {
* @property {Array.<protos.MeleeBullet>|null} [meleeBullets] RoomDownsyncFrame meleeBullets * @property {Array.<protos.MeleeBullet>|null} [meleeBullets] RoomDownsyncFrame meleeBullets
* @property {number|Long|null} [backendUnconfirmedMask] RoomDownsyncFrame backendUnconfirmedMask * @property {number|Long|null} [backendUnconfirmedMask] RoomDownsyncFrame backendUnconfirmedMask
* @property {boolean|null} [shouldForceResync] RoomDownsyncFrame shouldForceResync * @property {boolean|null} [shouldForceResync] RoomDownsyncFrame shouldForceResync
* @property {Array.<number>|null} [speciesIdList] RoomDownsyncFrame speciesIdList
*/ */
/** /**
@ -5174,6 +5175,7 @@ $root.protos = (function() {
function RoomDownsyncFrame(properties) { function RoomDownsyncFrame(properties) {
this.playersArr = []; this.playersArr = [];
this.meleeBullets = []; this.meleeBullets = [];
this.speciesIdList = [];
if (properties) if (properties)
for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
if (properties[keys[i]] != null) if (properties[keys[i]] != null)
@ -5228,6 +5230,14 @@ $root.protos = (function() {
*/ */
RoomDownsyncFrame.prototype.shouldForceResync = false; RoomDownsyncFrame.prototype.shouldForceResync = false;
/**
* RoomDownsyncFrame speciesIdList.
* @member {Array.<number>} speciesIdList
* @memberof protos.RoomDownsyncFrame
* @instance
*/
RoomDownsyncFrame.prototype.speciesIdList = $util.emptyArray;
/** /**
* Creates a new RoomDownsyncFrame instance using the specified properties. * Creates a new RoomDownsyncFrame instance using the specified properties.
* @function create * @function create
@ -5266,6 +5276,12 @@ $root.protos = (function() {
writer.uint32(/* id 5, wireType 0 =*/40).uint64(message.backendUnconfirmedMask); writer.uint32(/* id 5, wireType 0 =*/40).uint64(message.backendUnconfirmedMask);
if (message.shouldForceResync != null && Object.hasOwnProperty.call(message, "shouldForceResync")) if (message.shouldForceResync != null && Object.hasOwnProperty.call(message, "shouldForceResync"))
writer.uint32(/* id 6, wireType 0 =*/48).bool(message.shouldForceResync); writer.uint32(/* id 6, wireType 0 =*/48).bool(message.shouldForceResync);
if (message.speciesIdList != null && message.speciesIdList.length) {
writer.uint32(/* id 7, wireType 2 =*/58).fork();
for (var i = 0; i < message.speciesIdList.length; ++i)
writer.int32(message.speciesIdList[i]);
writer.ldelim();
}
return writer; return writer;
}; };
@ -5328,6 +5344,17 @@ $root.protos = (function() {
message.shouldForceResync = reader.bool(); message.shouldForceResync = reader.bool();
break; break;
} }
case 7: {
if (!(message.speciesIdList && message.speciesIdList.length))
message.speciesIdList = [];
if ((tag & 7) === 2) {
var end2 = reader.uint32() + reader.pos;
while (reader.pos < end2)
message.speciesIdList.push(reader.int32());
} else
message.speciesIdList.push(reader.int32());
break;
}
default: default:
reader.skipType(tag & 7); reader.skipType(tag & 7);
break; break;
@ -5393,6 +5420,13 @@ $root.protos = (function() {
if (message.shouldForceResync != null && message.hasOwnProperty("shouldForceResync")) if (message.shouldForceResync != null && message.hasOwnProperty("shouldForceResync"))
if (typeof message.shouldForceResync !== "boolean") if (typeof message.shouldForceResync !== "boolean")
return "shouldForceResync: boolean expected"; return "shouldForceResync: boolean expected";
if (message.speciesIdList != null && message.hasOwnProperty("speciesIdList")) {
if (!Array.isArray(message.speciesIdList))
return "speciesIdList: array expected";
for (var i = 0; i < message.speciesIdList.length; ++i)
if (!$util.isInteger(message.speciesIdList[i]))
return "speciesIdList: integer[] expected";
}
return null; return null;
}; };
@ -5450,6 +5484,13 @@ $root.protos = (function() {
message.backendUnconfirmedMask = new $util.LongBits(object.backendUnconfirmedMask.low >>> 0, object.backendUnconfirmedMask.high >>> 0).toNumber(true); message.backendUnconfirmedMask = new $util.LongBits(object.backendUnconfirmedMask.low >>> 0, object.backendUnconfirmedMask.high >>> 0).toNumber(true);
if (object.shouldForceResync != null) if (object.shouldForceResync != null)
message.shouldForceResync = Boolean(object.shouldForceResync); message.shouldForceResync = Boolean(object.shouldForceResync);
if (object.speciesIdList) {
if (!Array.isArray(object.speciesIdList))
throw TypeError(".protos.RoomDownsyncFrame.speciesIdList: array expected");
message.speciesIdList = [];
for (var i = 0; i < object.speciesIdList.length; ++i)
message.speciesIdList[i] = object.speciesIdList[i] | 0;
}
return message; return message;
}; };
@ -5469,6 +5510,7 @@ $root.protos = (function() {
if (options.arrays || options.defaults) { if (options.arrays || options.defaults) {
object.playersArr = []; object.playersArr = [];
object.meleeBullets = []; object.meleeBullets = [];
object.speciesIdList = [];
} }
if (options.defaults) { if (options.defaults) {
object.id = 0; object.id = 0;
@ -5508,6 +5550,11 @@ $root.protos = (function() {
object.backendUnconfirmedMask = options.longs === String ? $util.Long.prototype.toString.call(message.backendUnconfirmedMask) : options.longs === Number ? new $util.LongBits(message.backendUnconfirmedMask.low >>> 0, message.backendUnconfirmedMask.high >>> 0).toNumber(true) : message.backendUnconfirmedMask; object.backendUnconfirmedMask = options.longs === String ? $util.Long.prototype.toString.call(message.backendUnconfirmedMask) : options.longs === Number ? new $util.LongBits(message.backendUnconfirmedMask.low >>> 0, message.backendUnconfirmedMask.high >>> 0).toNumber(true) : message.backendUnconfirmedMask;
if (message.shouldForceResync != null && message.hasOwnProperty("shouldForceResync")) if (message.shouldForceResync != null && message.hasOwnProperty("shouldForceResync"))
object.shouldForceResync = message.shouldForceResync; object.shouldForceResync = message.shouldForceResync;
if (message.speciesIdList && message.speciesIdList.length) {
object.speciesIdList = [];
for (var j = 0; j < message.speciesIdList.length; ++j)
object.speciesIdList[j] = message.speciesIdList[j];
}
return object; return object;
}; };

View File

@ -25,6 +25,8 @@ const (
INPUT_SCALE_FRAMES = uint32(2) // inputDelayedAndScaledFrameId = ((originalFrameId - InputDelayFrames) >> InputScaleFrames) INPUT_SCALE_FRAMES = uint32(2) // inputDelayedAndScaledFrameId = ((originalFrameId - InputDelayFrames) >> InputScaleFrames)
NST_DELAY_FRAMES = int32(16) // 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" NST_DELAY_FRAMES = int32(16) // 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"
SP_ATK_LOOKUP_FRAMES = int32(5)
SNAP_INTO_PLATFORM_OVERLAP = float64(0.1) SNAP_INTO_PLATFORM_OVERLAP = float64(0.1)
SNAP_INTO_PLATFORM_THRESHOLD = float64(0.5) SNAP_INTO_PLATFORM_THRESHOLD = float64(0.5)

View File

@ -15,6 +15,7 @@ type CharacterConfig struct {
GetUpFrames int32 GetUpFrames int32
GetUpFramesToRecover int32 GetUpFramesToRecover int32
Speed int32
JumpingInitVelY int32 JumpingInitVelY int32
SkillMapper SkillMapperType SkillMapper SkillMapperType
@ -34,6 +35,7 @@ var Characters = map[int]*CharacterConfig{
GetUpFrames: int32(33), GetUpFrames: int32(33),
GetUpFramesToRecover: int32(30), // 3 invinsible frames for just-blown-up character to make a comeback GetUpFramesToRecover: int32(30), // 3 invinsible frames for just-blown-up character to make a comeback
Speed: int32(float64(1.2) * WORLD_TO_VIRTUAL_GRID_RATIO),
JumpingInitVelY: int32(float64(8) * WORLD_TO_VIRTUAL_GRID_RATIO), JumpingInitVelY: int32(float64(8) * WORLD_TO_VIRTUAL_GRID_RATIO),
SkillMapper: func(patternId int, currPlayerDownsync *PlayerDownsync) int { SkillMapper: func(patternId int, currPlayerDownsync *PlayerDownsync) int {
@ -76,6 +78,7 @@ var Characters = map[int]*CharacterConfig{
GetUpFrames: int32(30), GetUpFrames: int32(30),
GetUpFramesToRecover: int32(27), // 3 invinsible frames for just-blown-up character to make a comeback GetUpFramesToRecover: int32(27), // 3 invinsible frames for just-blown-up character to make a comeback
Speed: int32(float64(1.4) * WORLD_TO_VIRTUAL_GRID_RATIO),
JumpingInitVelY: int32(float64(7.5) * WORLD_TO_VIRTUAL_GRID_RATIO), JumpingInitVelY: int32(float64(7.5) * WORLD_TO_VIRTUAL_GRID_RATIO),
SkillMapper: func(patternId int, currPlayerDownsync *PlayerDownsync) int { SkillMapper: func(patternId int, currPlayerDownsync *PlayerDownsync) int {