Initial recovery of MeleeBullet in online battle.

This commit is contained in:
genxium
2022-12-29 12:21:01 +08:00
parent 11d001465d
commit 69f0ddc171
11 changed files with 300 additions and 292 deletions

View File

@@ -10,12 +10,13 @@ func toPbRoomDownsyncFrame(rdf *battle.RoomDownsyncFrame) *pb.RoomDownsyncFrame
return nil
}
ret := &pb.RoomDownsyncFrame{
Id: rdf.Id,
PlayersArr: make([]*pb.PlayerDownsync, len(rdf.PlayersArr), len(rdf.PlayersArr)),
MeleeBullets: make([]*pb.MeleeBullet, len(rdf.MeleeBullets), len(rdf.MeleeBullets)),
CountdownNanos: rdf.CountdownNanos,
BackendUnconfirmedMask: rdf.BackendUnconfirmedMask,
ShouldForceResync: rdf.ShouldForceResync,
Id: rdf.Id,
PlayersArr: make([]*pb.PlayerDownsync, len(rdf.PlayersArr), len(rdf.PlayersArr)),
MeleeBullets: make([]*pb.MeleeBullet, len(rdf.MeleeBullets), len(rdf.MeleeBullets)),
CountdownNanos: rdf.CountdownNanos,
BackendUnconfirmedMask: rdf.BackendUnconfirmedMask,
ShouldForceResync: rdf.ShouldForceResync,
PlayerOpPatternToSkillId: make(map[int32]int32),
}
for i, last := range rdf.PlayersArr {
@@ -65,6 +66,10 @@ func toPbRoomDownsyncFrame(rdf *battle.RoomDownsyncFrame) *pb.RoomDownsyncFrame
ret.MeleeBullets[i] = pbBullet
}
for i, last := range rdf.PlayerOpPatternToSkillId {
ret.PlayerOpPatternToSkillId[int32(i)] = int32(last)
}
return ret
}

View File

@@ -88,14 +88,15 @@ func calRoomScore(inRoomPlayerCount int32, roomPlayerCnt int, currentRoomBattleS
}
type Room struct {
Id int32
Capacity int
collisionSpaceOffsetX float64
collisionSpaceOffsetY float64
Players map[int32]*Player
PlayersArr []*Player // ordered by joinIndex
Space *resolv.Space
CollisionSysMap map[int32]*resolv.Object
Id int32
Capacity int
collisionSpaceOffsetX float64
collisionSpaceOffsetY float64
playerOpPatternToSkillId map[int]int
Players map[int32]*Player
PlayersArr []*Player // ordered by joinIndex
Space *resolv.Space
CollisionSysMap map[int32]*resolv.Object
/**
* The following `PlayerDownsyncSessionDict` is NOT individually put
* under `type Player struct` for a reason.
@@ -125,9 +126,9 @@ type Room struct {
CurDynamicsRenderFrameId int32 // [WARNING] The dynamics of backend is ALWAYS MOVING FORWARD BY ALL-CONFIRMED INPUTFRAMES (either by upsync or forced), i.e. no rollback; Moreover when "true == BackendDynamicsEnabled" we always have "Room.CurDynamicsRenderFrameId >= Room.RenderFrameId" because each "all-confirmed inputFrame" is applied on "all applicable renderFrames" in one-go hence often sees a future "renderFrame" earlier
EffectivePlayerCount int32
DismissalWaitGroup sync.WaitGroup
InputsBuffer *RingBuffer // Indices are STRICTLY consecutive
InputsBufferLock sync.Mutex // Guards [InputsBuffer, LatestPlayerUpsyncedInputFrameId, LastAllConfirmedInputFrameId, LastAllConfirmedInputList, LastAllConfirmedInputFrameIdWithChange]
RenderFrameBuffer *RingBuffer // Indices are STRICTLY consecutive
InputsBuffer *battle.RingBuffer // Indices are STRICTLY consecutive
InputsBufferLock sync.Mutex // Guards [InputsBuffer, LatestPlayerUpsyncedInputFrameId, LastAllConfirmedInputFrameId, LastAllConfirmedInputList, LastAllConfirmedInputFrameIdWithChange]
RenderFrameBuffer *battle.RingBuffer // Indices are STRICTLY consecutive
LatestPlayerUpsyncedInputFrameId int32
LastAllConfirmedInputFrameId int32
LastAllConfirmedInputFrameIdWithChange int32
@@ -396,12 +397,19 @@ func (pR *Room) StartBattle() {
pR.RenderFrameId = 0
// [WARNING] Only since battle starts do we have all players bound to certain joinIndexes.
for _, player := range pR.Players {
opJoinIndexPrefix := (int(player.JoinIndex) << uint(8))
pR.playerOpPatternToSkillId[opJoinIndexPrefix+0] = 1 // Hardcoded for now
}
// Initialize the "collisionSys" as well as "RenderFrameBuffer"
pR.CurDynamicsRenderFrameId = 0
kickoffFrameJs := &battle.RoomDownsyncFrame{
Id: pR.RenderFrameId,
PlayersArr: toJsPlayers(pR.Players),
CountdownNanos: pR.BattleDurationNanos,
Id: pR.RenderFrameId,
PlayersArr: toJsPlayers(pR.Players),
PlayerOpPatternToSkillId: pR.playerOpPatternToSkillId,
CountdownNanos: pR.BattleDurationNanos,
}
pR.RenderFrameBuffer.Put(kickoffFrameJs)
@@ -597,7 +605,7 @@ func (pR *Room) OnBattleCmdReceived(pReq *pb.WsReq) {
}
}
func (pR *Room) onInputFrameDownsyncAllConfirmed(inputFrameDownsync *pb.InputFrameDownsync, playerId int32) {
func (pR *Room) onInputFrameDownsyncAllConfirmed(inputFrameDownsync *battle.InputFrameDownsync, playerId int32) {
// [WARNING] This function MUST BE called while "pR.InputsBufferLock" is locked!
inputFrameId := inputFrameDownsync.InputFrameId
if -1 == pR.LastAllConfirmedInputFrameIdWithChange || false == pR.equalInputLists(inputFrameDownsync.InputList, pR.LastAllConfirmedInputList) {
@@ -741,6 +749,7 @@ func (pR *Room) OnDismissed() {
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.PlayersArr = make([]*Player, pR.Capacity)
pR.CollisionSysMap = make(map[int32]*resolv.Object)
@@ -756,8 +765,8 @@ func (pR *Room) OnDismissed() {
pR.PlayerSignalToCloseDict = make(map[int32]SignalToCloseConnCbType)
pR.JoinIndexBooleanArr = make([]bool, pR.Capacity)
pR.RenderCacheSize = 1024
pR.RenderFrameBuffer = NewRingBuffer(pR.RenderCacheSize)
pR.InputsBuffer = NewRingBuffer((pR.RenderCacheSize >> 1) + 1)
pR.RenderFrameBuffer = battle.NewRingBuffer(pR.RenderCacheSize)
pR.InputsBuffer = battle.NewRingBuffer((pR.RenderCacheSize >> 1) + 1)
pR.rdfIdToActuallyUsedInput = make(map[int32]*pb.InputFrameDownsync)
pR.LatestPlayerUpsyncedInputFrameId = -1
@@ -782,30 +791,6 @@ func (pR *Room) OnDismissed() {
pR.BackendDynamicsEnabled = true // [WARNING] When "false", recovery upon reconnection wouldn't work!
pR.ForceAllResyncOnAnyActiveSlowTicker = true // See tradeoff discussion in "downsyncToAllPlayers"
punchSkillId := int32(1)
pR.MeleeSkillConfig = make(map[int32]*pb.MeleeBullet, 0)
pR.MeleeSkillConfig[punchSkillId] = &pb.MeleeBullet{
// for offender
StartupFrames: int32(10),
ActiveFrames: int32(10),
RecoveryFrames: int32(34),
RecoveryFramesOnBlock: int32(34),
RecoveryFramesOnHit: int32(34),
HitboxOffset: float64(12.0), // should be about the radius of the PlayerCollider
// for defender
HitStunFrames: int32(18),
BlockStunFrames: int32(9),
Pushback: float64(8.0),
ReleaseTriggerType: int32(1), // 1: rising-edge, 2: falling-edge
Damage: int32(5),
SelfMoveforwardX: 0,
SelfMoveforwardY: 0,
HitboxSizeX: 24.0,
HitboxSizeY: 32.0,
}
pR.SnapIntoPlatformOverlap = float64(0.1)
pR.SnapIntoPlatformThreshold = float64(0.5)
pR.JumpingInitVelY = int32(float64(7) * pR.WorldToVirtualGridRatio)
@@ -1067,7 +1052,7 @@ func (pR *Room) shouldPrefabInputFrameDownsync(prevRenderFrameId int32, renderFr
return false, -1
}
func (pR *Room) getOrPrefabInputFrameDownsync(inputFrameId int32) *pb.InputFrameDownsync {
func (pR *Room) getOrPrefabInputFrameDownsync(inputFrameId int32) *battle.InputFrameDownsync {
/*
[WARNING] This function MUST BE called while "pR.InputsBufferLock" is locked.
@@ -1076,12 +1061,12 @@ func (pR *Room) getOrPrefabInputFrameDownsync(inputFrameId int32) *pb.InputFrame
- OR there's no change w.r.t. to its prev cmd.
*/
var currInputFrameDownsync *pb.InputFrameDownsync = nil
var currInputFrameDownsync *battle.InputFrameDownsync = nil
tmp1 := pR.InputsBuffer.GetByFrameId(inputFrameId) // Would be nil if "pR.InputsBuffer.EdFrameId <= inputFrameId", else if "pR.InputsBuffer.EdFrameId > inputFrameId" is already met, then by now we can just return "tmp1.(*InputFrameDownsync)"
if nil == tmp1 {
for pR.InputsBuffer.EdFrameId <= inputFrameId {
j := pR.InputsBuffer.EdFrameId
currInputFrameDownsync = &pb.InputFrameDownsync{
currInputFrameDownsync = &battle.InputFrameDownsync{
InputFrameId: j,
InputList: make([]uint64, pR.Capacity),
ConfirmedList: uint64(0),
@@ -1093,7 +1078,7 @@ func (pR *Room) getOrPrefabInputFrameDownsync(inputFrameId int32) *pb.InputFrame
}
tmp2 := pR.InputsBuffer.GetByFrameId(j2)
if nil != tmp2 {
prevInputFrameDownsync := tmp2.(*pb.InputFrameDownsync)
prevInputFrameDownsync := tmp2.(*battle.InputFrameDownsync)
for i, _ := range currInputFrameDownsync.InputList {
currInputFrameDownsync.InputList[i] = (prevInputFrameDownsync.InputList[i] & uint64(15)) // Don't predict attack input!
}
@@ -1102,7 +1087,7 @@ func (pR *Room) getOrPrefabInputFrameDownsync(inputFrameId int32) *pb.InputFrame
pR.InputsBuffer.Put(currInputFrameDownsync)
}
} else {
currInputFrameDownsync = tmp1.(*pb.InputFrameDownsync)
currInputFrameDownsync = tmp1.(*battle.InputFrameDownsync)
}
return currInputFrameDownsync
@@ -1148,7 +1133,7 @@ func (pR *Room) markConfirmationIfApplicable(inputFrameUpsyncBatch []*pb.InputFr
panic(fmt.Sprintf("inputFrameId=%v doesn't exist for roomId=%v! InputsBuffer=%v", inputFrameId, pR.Id, pR.InputsBufferString(false)))
}
shouldBreakConfirmation := false
inputFrameDownsync := tmp.(*pb.InputFrameDownsync)
inputFrameDownsync := tmp.(*battle.InputFrameDownsync)
if allConfirmedMask != inputFrameDownsync.ConfirmedList {
for _, player := range pR.PlayersArr {
@@ -1207,7 +1192,7 @@ func (pR *Room) forceConfirmationIfApplicable(prevRenderFrameId int32) uint64 {
if nil == tmp {
panic(fmt.Sprintf("inputFrameId=%v doesn't exist for roomId=%v! InputsBuffer=%v", j, pR.Id, pR.InputsBufferString(false)))
}
inputFrameDownsync := tmp.(*pb.InputFrameDownsync)
inputFrameDownsync := tmp.(*battle.InputFrameDownsync)
unconfirmedMask |= (allConfirmedMask ^ inputFrameDownsync.ConfirmedList)
inputFrameDownsync.ConfirmedList = allConfirmedMask
pR.onInputFrameDownsyncAllConfirmed(inputFrameDownsync, -1)
@@ -1265,8 +1250,6 @@ func (pR *Room) applyInputFrameDownsyncDynamics(fromRenderFrameId int32, toRende
}
currRenderFrame := currRenderFrameTmp.(*battle.RoomDownsyncFrame)
delayedInputFrameId := pR.ConvertToInputFrameId(collisionSysRenderFrameId, pR.InputDelayFrames)
var delayedInputList *[]uint64 = nil
var delayedInputListForPrevRenderFrame *[]uint64 = nil
if 0 <= delayedInputFrameId {
if delayedInputFrameId > pR.LastAllConfirmedInputFrameId {
panic(fmt.Sprintf("delayedInputFrameId=%v is not yet all-confirmed for roomId=%v, this is abnormal because it's to be used for applying dynamics to [fromRenderFrameId:%v, toRenderFrameId:%v) @ collisionSysRenderFrameId=%v! InputsBuffer=%v", delayedInputFrameId, pR.Id, fromRenderFrameId, toRenderFrameId, collisionSysRenderFrameId, pR.InputsBufferString(false)))
@@ -1275,21 +1258,11 @@ func (pR *Room) applyInputFrameDownsyncDynamics(fromRenderFrameId int32, toRende
if nil == tmp {
panic(fmt.Sprintf("delayedInputFrameId=%v doesn't exist for roomId=%v, this is abnormal because it's to be used for applying dynamics to [fromRenderFrameId:%v, toRenderFrameId:%v) @ collisionSysRenderFrameId=%v! InputsBuffer=%v", delayedInputFrameId, pR.Id, fromRenderFrameId, toRenderFrameId, collisionSysRenderFrameId, pR.InputsBufferString(false)))
}
delayedInputFrame := tmp.(*pb.InputFrameDownsync)
delayedInputList = &delayedInputFrame.InputList
delayedInputFrameIdForPrevRenderFrame := pR.ConvertToInputFrameId(collisionSysRenderFrameId-1, pR.InputDelayFrames)
if 0 <= delayedInputFrameIdForPrevRenderFrame {
tmp = pR.InputsBuffer.GetByFrameId(delayedInputFrameIdForPrevRenderFrame)
if nil == tmp {
panic(fmt.Sprintf("delayedInputFrameIdForPrevRenderFrame=%v doesn't exist for roomId=%v, this is abnormal because it's to be used for applying dynamics to [fromRenderFrameId:%v, toRenderFrameId:%v) @ collisionSysRenderFrameId-1=%v! InputsBuffer=%v", delayedInputFrameIdForPrevRenderFrame, pR.Id, fromRenderFrameId, toRenderFrameId, collisionSysRenderFrameId-1, pR.InputsBufferString(false)))
}
delayedInputFrameForPrevRenderFrame := tmp.(*pb.InputFrameDownsync)
delayedInputListForPrevRenderFrame = &delayedInputFrameForPrevRenderFrame.InputList
}
if pR.FrameDataLoggingEnabled {
actuallyUsedInputClone := make([]uint64, len(*delayedInputList), len(*delayedInputList))
for i, v := range *delayedInputList {
delayedInputFrame := tmp.(*battle.InputFrameDownsync)
actuallyUsedInputClone := make([]uint64, len(delayedInputFrame.InputList), len(delayedInputFrame.InputList))
for i, v := range delayedInputFrame.InputList {
actuallyUsedInputClone[i] = v
}
pR.rdfIdToActuallyUsedInput[currRenderFrame.Id] = &pb.InputFrameDownsync{
@@ -1300,7 +1273,7 @@ func (pR *Room) applyInputFrameDownsyncDynamics(fromRenderFrameId int32, toRende
}
}
nextRenderFrame := battle.ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(*delayedInputList, *delayedInputListForPrevRenderFrame, currRenderFrame, pR.Space, pR.CollisionSysMap, pR.GravityX, pR.GravityY, pR.JumpingInitVelY, pR.InputDelayFrames, pR.InputScaleFrames, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY, pR.SnapIntoPlatformOverlap, pR.SnapIntoPlatformThreshold, pR.WorldToVirtualGridRatio, pR.VirtualGridToWorldRatio)
nextRenderFrame := battle.ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(pR.InputsBuffer, currRenderFrame, pR.Space, pR.CollisionSysMap, pR.GravityX, pR.GravityY, pR.JumpingInitVelY, pR.InputDelayFrames, pR.InputScaleFrames, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY, pR.SnapIntoPlatformOverlap, pR.SnapIntoPlatformThreshold, pR.WorldToVirtualGridRatio, pR.VirtualGridToWorldRatio, pR.playerOpPatternToSkillId)
pR.RenderFrameBuffer.Put(nextRenderFrame)
pR.CurDynamicsRenderFrameId++
}
@@ -1497,6 +1470,7 @@ func (pR *Room) downsyncToSinglePlayer(playerId int32, player *Player, refRender
}
refRenderFrame := tmp.(*battle.RoomDownsyncFrame)
refRenderFrame.PlayerOpPatternToSkillId = pR.playerOpPatternToSkillId
for i, player := range pR.PlayersArr {
refRenderFrame.PlayersArr[i].ColliderRadius = player.ColliderRadius // hardcoded for now
}
@@ -1534,7 +1508,7 @@ func (pR *Room) cloneInputsBuffer(stFrameId, edFrameId int32) []*pb.InputFrameDo
}
}
prevFrameFound = true
foo := tmp.(*pb.InputFrameDownsync)
foo := tmp.(*battle.InputFrameDownsync)
bar := &pb.InputFrameDownsync{
InputFrameId: foo.InputFrameId,