Merge pull request #13 from genxium/downsync-order-preservation

Fixes for downsync order preservation.
This commit is contained in:
Wing 2022-12-06 11:54:49 +08:00 committed by GitHub
commit d113cffc7d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 750 additions and 325 deletions

View File

@ -147,7 +147,7 @@ type Room struct {
* Moreover, during the invocation of `PlayerSignalToCloseDict`, the `Player` instance is supposed to be deallocated (though not synchronously).
*/
PlayerDownsyncSessionDict map[int32]*websocket.Conn
PlayerDownsyncSessionLock map[int32]*sync.Mutex // Guards [PlayerDownsyncSessionDict, each player.LastSentInputFrameId]
PlayerDownsyncChanDict map[int32](chan InputsBufferSnapshot)
PlayerSignalToCloseDict map[int32]SignalToCloseConnCbType
Score float32
State int32
@ -201,7 +201,6 @@ func (pR *Room) AddPlayerIfPossible(pPlayerFromDbInit *Player, session *websocke
pR.Players[playerId] = pPlayerFromDbInit
pR.PlayerDownsyncSessionDict[playerId] = session
pR.PlayerDownsyncSessionLock[playerId] = &sync.Mutex{}
pR.PlayerSignalToCloseDict[playerId] = signalToCloseConnOfThisPlayer
return true
}
@ -232,7 +231,6 @@ func (pR *Room) ReAddPlayerIfPossible(pTmpPlayerInstance *Player, session *webso
pEffectiveInRoomPlayerInstance.ColliderRadius = DEFAULT_PLAYER_RADIUS // Hardcoded
pR.PlayerDownsyncSessionDict[playerId] = session
pR.PlayerDownsyncSessionLock[playerId] = &sync.Mutex{}
pR.PlayerSignalToCloseDict[playerId] = signalToCloseConnOfThisPlayer
Logger.Warn("ReAddPlayerIfPossible finished.", zap.Any("roomId", pR.Id), zap.Any("playerId", playerId), zap.Any("joinIndex", pEffectiveInRoomPlayerInstance.JoinIndex), zap.Any("playerBattleState", pEffectiveInRoomPlayerInstance.BattleState), zap.Any("roomState", pR.State), zap.Any("roomEffectivePlayerCount", pR.EffectivePlayerCount), zap.Any("AckingFrameId", pEffectiveInRoomPlayerInstance.AckingFrameId), zap.Any("AckingInputFrameId", pEffectiveInRoomPlayerInstance.AckingInputFrameId), zap.Any("LastSentInputFrameId", pEffectiveInRoomPlayerInstance.LastSentInputFrameId))
@ -466,11 +464,7 @@ func (pR *Room) StartBattle() {
// Prefab and buffer backend inputFrameDownsync
if pR.BackendDynamicsEnabled {
unconfirmedMask, refRenderFrameId, inputsBufferSnapshot := pR.doBattleMainLoopPerTickBackendDynamicsWithProperLocking(prevRenderFrameId, &dynamicsDuration)
if 0 < unconfirmedMask {
Logger.Warn(fmt.Sprintf("roomId=%v, room.RenderFrameId=%v, room.CurDynamicsRenderFrameId=%v, room.LastAllConfirmedInputFrameId=%v, unconfirmedMask=%v", pR.Id, pR.RenderFrameId, pR.CurDynamicsRenderFrameId, pR.LastAllConfirmedInputFrameId, unconfirmedMask))
pR.downsyncToAllPlayers(refRenderFrameId, unconfirmedMask, inputsBufferSnapshot)
}
pR.doBattleMainLoopPerTickBackendDynamicsWithProperLocking(prevRenderFrameId, &dynamicsDuration)
}
pR.LastRenderFrameIdTriggeredAt = utils.UnixtimeNano()
@ -486,6 +480,46 @@ func (pR *Room) StartBattle() {
}
}
downsyncLoop := func(playerId int32, player *Player, playerDownsyncChan chan InputsBufferSnapshot) {
defer func() {
if r := recover(); r != nil {
Logger.Error("downsyncLoop, recovery spot#1, recovered from: ", zap.Any("roomId", pR.Id), zap.Any("playerId", playerId), zap.Any("panic", r))
}
Logger.Info(fmt.Sprintf("The `downsyncLoop` for (roomId=%v, playerId=%v) is stopped@renderFrameId=%v", pR.Id, playerId, pR.RenderFrameId))
}()
Logger.Debug(fmt.Sprintf("Started downsyncLoop for (roomId: %d, playerId:%d, playerDownsyncChan:%p)", pR.Id, playerId, playerDownsyncChan))
for {
select {
case inputsBufferSnapshot := <-playerDownsyncChan:
nowBattleState := atomic.LoadInt32(&pR.State)
switch nowBattleState {
case RoomBattleStateIns.IDLE:
case RoomBattleStateIns.STOPPING_BATTLE_FOR_SETTLEMENT:
case RoomBattleStateIns.IN_SETTLEMENT:
case RoomBattleStateIns.IN_DISMISSAL:
Logger.Warn(fmt.Sprintf("Battle is not waiting/preparing/active for playerDownsyncChan for (roomId: %d, playerId:%d)", pR.Id, playerId))
return
}
pR.downsyncToSinglePlayer(playerId, player, inputsBufferSnapshot.RefRenderFrameId, inputsBufferSnapshot.UnconfirmedMask, inputsBufferSnapshot.ToSendInputFrameDownsyncs)
Logger.Debug(fmt.Sprintf("Sent inputsBufferSnapshot(refRenderFrameId:%d, unconfirmedMask:%v) to for (roomId: %d, playerId:%d)#2", inputsBufferSnapshot.RefRenderFrameId, inputsBufferSnapshot.UnconfirmedMask, pR.Id, playerId))
default:
}
}
}
for playerId, player := range pR.Players {
/*
Always instantiates a new channel and let the old one die out due to not being retained by any root reference.
Each "playerDownsyncChan" stays alive through out the lifecycle of room instead of each "playerDownsyncSession", i.e. not closed or dereferenced upon disconnection.
*/
pR.PlayerDownsyncChanDict[playerId] = make(chan InputsBufferSnapshot, pR.InputsBuffer.N)
go downsyncLoop(playerId, player, pR.PlayerDownsyncChanDict[playerId])
}
pR.onBattlePrepare(func() {
pR.onBattleStarted() // NOTE: Deliberately not using `defer`.
go battleMainLoop()
@ -497,7 +531,18 @@ func (pR *Room) toDiscreteInputsBufferIndex(inputFrameId int32, joinIndex int32)
}
func (pR *Room) OnBattleCmdReceived(pReq *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!
That said, "markConfirmationIfApplicable" will still work as expected. Here's an example of weird call orders.
---------------------------------------------------
now lastAllConfirmedInputFrameId: 42; each "()" below indicates a "Lock/Unlock cycle of InputsBufferLock", and "x" indicates no new all-confirmed snapshot is created
A: ([44,50],x) ([49,54],snapshot=[51,53])
B: ([54,58],x)
C: ([42,53],snapshot=[43,50])
D: ([51,55],x)
---------------------------------------------------
*/
// TODO: Put a rate limiter on this function!
if swapped := atomic.CompareAndSwapInt32(&pR.State, RoomBattleStateIns.IN_BATTLE, RoomBattleStateIns.IN_BATTLE); !swapped {
return
@ -518,15 +563,17 @@ func (pR *Room) OnBattleCmdReceived(pReq *WsReq) {
atomic.StoreInt32(&(player.AckingFrameId), ackingFrameId)
atomic.StoreInt32(&(player.AckingInputFrameId), ackingInputFrameId)
newAllConfirmedCount, refRenderFrameIdIfNeeded, inputsBufferSnapshot := pR.markConfirmationIfApplicable(inputFrameUpsyncBatch, playerId, player)
Logger.Debug(fmt.Sprintf("OnBattleCmdReceived-InputsBufferLock about to lock: roomId=%v, fromPlayerId=%v", pR.Id, playerId))
pR.InputsBufferLock.Lock()
Logger.Debug(fmt.Sprintf("OnBattleCmdReceived-InputsBufferLock locked: roomId=%v, fromPlayerId=%v", pR.Id, playerId))
defer func() {
pR.InputsBufferLock.Unlock()
Logger.Debug(fmt.Sprintf("OnBattleCmdReceived-InputsBufferLock unlocked: roomId=%v, fromPlayerId=%v", pR.Id, playerId))
}()
if swapped := atomic.CompareAndSwapInt32(&pR.State, RoomBattleStateIns.IN_BATTLE, RoomBattleStateIns.IN_BATTLE); !swapped {
return
}
// [WARNING] By now "pR.InputsBufferLock" is unlocked
if 0 < newAllConfirmedCount {
// Downsync new all-confirmed inputFrames asap
pR.downsyncToAllPlayers(refRenderFrameIdIfNeeded, uint64(0), inputsBufferSnapshot)
inputsBufferSnapshot := pR.markConfirmationIfApplicable(inputFrameUpsyncBatch, playerId, player)
if nil != inputsBufferSnapshot {
pR.downsyncToAllPlayers(inputsBufferSnapshot)
}
}
@ -677,7 +724,10 @@ func (pR *Room) OnDismissed() {
pR.PlayersArr = make([]*Player, pR.Capacity)
pR.CollisionSysMap = make(map[int32]*resolv.Object)
pR.PlayerDownsyncSessionDict = make(map[int32]*websocket.Conn)
pR.PlayerDownsyncSessionLock = make(map[int32]*sync.Mutex, pR.Capacity)
for _, oldChan := range pR.PlayerDownsyncChanDict {
close(oldChan)
}
pR.PlayerDownsyncChanDict = make(map[int32](chan InputsBufferSnapshot))
pR.PlayerSignalToCloseDict = make(map[int32]SignalToCloseConnCbType)
pR.JoinIndexBooleanArr = make([]bool, pR.Capacity)
pR.Barriers = make(map[int32]*Barrier)
@ -739,7 +789,7 @@ func (pR *Room) OnDismissed() {
pR.State = RoomBattleStateIns.IDLE
pR.updateScore()
Logger.Info("The room is completely dismissed:", zap.Any("roomId", pR.Id))
Logger.Info("The room is completely dismissed(all playerDownsyncChan closed):", zap.Any("roomId", pR.Id))
}
func (pR *Room) expelPlayerDuringGame(playerId int32) {
@ -830,7 +880,7 @@ func (pR *Room) onPlayerLost(playerId int32) {
func (pR *Room) clearPlayerNetworkSession(playerId int32) {
if _, y := pR.PlayerDownsyncSessionDict[playerId]; y {
Logger.Debug("clearPlayerNetworkSession:", zap.Any("roomId", pR.Id), zap.Any("playerId", playerId))
// [WARNING] No need to delete "pR.PlayerDownsyncSessionLock[playerId]" here!
// [WARNING] No need to close "pR.PlayerDownsyncChanDict[playerId]" immediately!
delete(pR.PlayerDownsyncSessionDict, playerId)
delete(pR.PlayerSignalToCloseDict, playerId)
}
@ -952,20 +1002,12 @@ func (pR *Room) OnPlayerBattleColliderAcked(playerId int32) bool {
}
func (pR *Room) sendSafely(roomDownsyncFrame *RoomDownsyncFrame, toSendInputFrameDownsyncs []*InputFrameDownsync, act int32, playerId int32, needLockExplicitly bool) {
// [WARNING] This function MUST BE called while "pR.PlayerDownsyncSessionLock[player.JoinIndex-1]" is locked!
defer func() {
if r := recover(); r != nil {
Logger.Error("sendSafely, recovered from: ", zap.Any("roomId", pR.Id), zap.Any("playerId", playerId), zap.Any("panic", r))
}
}()
if needLockExplicitly {
pR.PlayerDownsyncSessionLock[playerId].Lock()
defer func() {
pR.PlayerDownsyncSessionLock[playerId].Unlock()
}()
}
if playerDownsyncSession, existent := pR.PlayerDownsyncSessionDict[playerId]; existent {
pResp := &WsResp{
Ret: int32(Constants.RetCode.Ok),
@ -996,49 +1038,43 @@ func (pR *Room) shouldPrefabInputFrameDownsync(prevRenderFrameId int32, renderFr
func (pR *Room) prefabInputFrameDownsync(inputFrameId int32) *InputFrameDownsync {
/*
[WARNING] This function MUST BE called while "pR.InputsBufferLock" is locked.
Kindly note that on backend the prefab is much simpler than its frontend counterpart, because frontend will upsync its latest command immediately if there's any change w.r.t. its own prev cmd, thus if no upsync received from a frontend,
- EITHER it's due to local lag and bad network,
- OR there's no change w.r.t. to its prev cmd.
*/
var currInputFrameDownsync *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 = &InputFrameDownsync{
InputFrameId: j,
InputList: make([]uint64, pR.Capacity),
ConfirmedList: uint64(0),
}
if 0 == inputFrameId && 0 == pR.InputsBuffer.Cnt {
currInputFrameDownsync = &InputFrameDownsync{
InputFrameId: 0,
InputList: make([]uint64, pR.Capacity),
ConfirmedList: uint64(0),
tmp2 := pR.InputsBuffer.GetByFrameId(j - 1) // There's no need for the backend to find the "lastAllConfirmed inputs" for prefabbing, either "BackendDynamicsEnabled" is true or false
if nil != tmp2 {
prevInputFrameDownsync := tmp2.(*InputFrameDownsync)
for i, _ := range currInputFrameDownsync.InputList {
currInputFrameDownsync.InputList[i] = (prevInputFrameDownsync.InputList[i] & uint64(15)) // Don't predict attack input!
}
}
pR.InputsBuffer.Put(currInputFrameDownsync)
}
} else {
tmp := pR.InputsBuffer.GetByFrameId(inputFrameId - 1) // There's no need for the backend to find the "lastAllConfirmed inputs" for prefabbing, either "BackendDynamicsEnabled" is true or false
if nil == tmp {
panic(fmt.Sprintf("Error prefabbing inputFrameDownsync: roomId=%v, InputsBuffer=%v", pR.Id, pR.InputsBufferString(false)))
}
prevInputFrameDownsync := tmp.(*InputFrameDownsync)
currInputList := make([]uint64, pR.Capacity) // Would be a clone of the values
for i, _ := range currInputList {
currInputList[i] = (prevInputFrameDownsync.InputList[i] & uint64(15)) // Don't predict attack input!
}
currInputFrameDownsync = &InputFrameDownsync{
InputFrameId: inputFrameId,
InputList: currInputList,
ConfirmedList: uint64(0),
}
currInputFrameDownsync = tmp1.(*InputFrameDownsync)
}
pR.InputsBuffer.Put(currInputFrameDownsync)
return currInputFrameDownsync
}
func (pR *Room) markConfirmationIfApplicable(inputFrameUpsyncBatch []*InputFrameUpsync, playerId int32, player *Player) (int32, int32, []*InputFrameDownsync) {
Logger.Debug(fmt.Sprintf("markConfirmationIfApplicable-InputsBufferLock about to lock: roomId=%v, fromPlayerId=%v", pR.Id, playerId))
pR.InputsBufferLock.Lock()
Logger.Debug(fmt.Sprintf("markConfirmationIfApplicable-InputsBufferLock locked: roomId=%v, fromPlayerId=%v", pR.Id, playerId))
defer func() {
pR.InputsBufferLock.Unlock()
Logger.Debug(fmt.Sprintf("markConfirmationIfApplicable-InputsBufferLock unlocked: roomId=%v, fromPlayerId=%v", pR.Id, playerId))
}()
func (pR *Room) markConfirmationIfApplicable(inputFrameUpsyncBatch []*InputFrameUpsync, playerId int32, player *Player) *InputsBufferSnapshot {
// [WARNING] This function MUST BE called while "pR.InputsBufferLock" is locked!
for _, inputFrameUpsync := range inputFrameUpsyncBatch {
clientInputFrameId := inputFrameUpsync.InputFrameId
if clientInputFrameId < pR.InputsBuffer.StFrameId {
@ -1102,44 +1138,36 @@ func (pR *Room) markConfirmationIfApplicable(inputFrameUpsyncBatch []*InputFrame
}
}
refRenderFrameIdIfNeeded := pR.CurDynamicsRenderFrameId - 1
var inputsBufferSnapshot []*InputFrameDownsync = nil
if 0 < newAllConfirmedCount {
refRenderFrameIdIfNeeded := pR.CurDynamicsRenderFrameId - 1
/*
[WARNING]
If "pR.InputsBufferLock" was previously held by "battleMainLoop -> applyInputFrameDownsyncDynamics", then this value would be just (pR.LastAllConfirmedInputFrameId - newAllConfirmedCount).
If "pR.InputsBufferLock" was previously held by "doBattleMainLoopPerTickBackendDynamicsWithProperLocking", then this value would be just (pR.LastAllConfirmedInputFrameId - newAllConfirmedCount).
However if "pR.InputsBufferLock" was previously held by another "OnBattleCmdReceived -> markConfirmationIfApplicable", this value might be smaller than (pR.LastAllConfirmedInputFrameId - newAllConfirmedCount)!
However if "pR.InputsBufferLock" was previously held by another "OnBattleCmdReceived", this value might be smaller than (pR.LastAllConfirmedInputFrameId - newAllConfirmedCount)!
*/
snapshotStFrameId := pR.ConvertToInputFrameId(refRenderFrameIdIfNeeded, pR.InputDelayFrames)
// Duplicate downsynced inputFrameIds will be filtered out by frontend.
inputsBufferSnapshot = pR.createInputsBufferSnapshot(snapshotStFrameId, pR.LastAllConfirmedInputFrameId+1)
toSendInputFrameDownsyncs := pR.cloneInputsBuffer(snapshotStFrameId, pR.LastAllConfirmedInputFrameId+1)
Logger.Debug(fmt.Sprintf("markConfirmationIfApplicable for roomId=%v returning newAllConfirmedCount=%d: InputsBuffer=%v", pR.Id, newAllConfirmedCount, pR.InputsBufferString(false)))
return &InputsBufferSnapshot{
RefRenderFrameId: refRenderFrameIdIfNeeded,
UnconfirmedMask: uint64(0),
ToSendInputFrameDownsyncs: toSendInputFrameDownsyncs,
}
} else {
return nil
}
Logger.Debug(fmt.Sprintf("markConfirmationIfApplicable for roomId=%v returning newAllConfirmedCount=%d: InputsBuffer=%v", pR.Id, newAllConfirmedCount, pR.InputsBufferString(false)))
return newAllConfirmedCount, refRenderFrameIdIfNeeded, inputsBufferSnapshot
}
func (pR *Room) forceConfirmationIfApplicable(prevRenderFrameId int32) (uint64, int32, []*InputFrameDownsync) {
func (pR *Room) forceConfirmationIfApplicable(prevRenderFrameId int32) *InputsBufferSnapshot {
// [WARNING] This function MUST BE called while "pR.InputsBufferLock" is locked!
// Force confirmation of non-all-confirmed inputFrame EXACTLY ONE AT A TIME, returns the non-confirmed mask of players, e.g. in a 4-player-battle returning 1001 means that players with JoinIndex=1 and JoinIndex=4 are non-confirmed for inputFrameId2
/*
Upon resynced on frontend, "refRenderFrameId" is now set to as advanced as possible, and it's the frontend's responsibility now to pave way for the "gap inputFrames"
If "NstDelayFrames" becomes larger, "pR.RenderFrameId - refRenderFrameId" possibly becomes larger because the force confirmation is delayed more.
Upon resync, it's still possible that "refRenderFrameId < frontend.chaserRenderFrameId" -- and this is allowed.
*/
refRenderFrameIdIfNeeded := pR.CurDynamicsRenderFrameId - 1
if 0 > refRenderFrameIdIfNeeded {
// Without a "refRenderFrame", there's no point to force confirmation, i.e. nothing to downsync to the "ACTIVE but slowly ticking frontend(s)"
return 0, -1, nil
}
renderFrameId1 := (pR.RenderFrameId - pR.NstDelayFrames) // the renderFrameId which should've been rendered on frontend
if 0 > renderFrameId1 {
return 0, -1, nil
return nil
}
ok := false
renderFrameId2 := int32(-1)
@ -1149,14 +1177,14 @@ func (pR *Room) forceConfirmationIfApplicable(prevRenderFrameId int32) (uint64,
It's also important that "forceConfirmationIfApplicable" is NOT EXECUTED for every renderFrame, such that when a player is forced to resync, it has some time, i.e. (1 << InputScaleFrames) renderFrames, to upsync again.
*/
return 0, -1, nil
return nil
}
inputFrameId2 := pR.ConvertToInputFrameId(renderFrameId2, 0) // The inputFrame to force confirmation (if necessary)
if inputFrameId2 < pR.LastAllConfirmedInputFrameId {
// No need to force confirmation, the inputFrames already arrived
Logger.Debug(fmt.Sprintf("inputFrameId2=%v is already all-confirmed for roomId=%v[type#1], no need to force confirmation of it", inputFrameId2, pR.Id))
return 0, -1, nil
return nil
}
tmp := pR.InputsBuffer.GetByFrameId(inputFrameId2)
@ -1174,14 +1202,31 @@ func (pR *Room) forceConfirmationIfApplicable(prevRenderFrameId int32) (uint64,
inputFrame2.ConfirmedList = allConfirmedMask
pR.onInputFrameDownsyncAllConfirmed(inputFrame2, -1)
var inputsBufferSnapshot []*InputFrameDownsync = nil
if 0 < unconfirmedMask {
// This condition should be rarely met!
snapshotStFrameId := pR.ConvertToInputFrameId(refRenderFrameIdIfNeeded, pR.InputDelayFrames)
inputsBufferSnapshot = pR.createInputsBufferSnapshot(snapshotStFrameId, pR.LastAllConfirmedInputFrameId+1)
}
nextDynamicsRenderFrameId := pR.ConvertToLastUsedRenderFrameId(pR.LastAllConfirmedInputFrameId, pR.InputDelayFrames)
/*
Upon resynced on frontend, "refRenderFrameId" is now set to as advanced as possible, and it's the frontend's responsibility now to pave way for the "gap inputFrames"
return unconfirmedMask, refRenderFrameIdIfNeeded, inputsBufferSnapshot
If "NstDelayFrames" becomes larger, "pR.RenderFrameId - refRenderFrameId" possibly becomes larger because the force confirmation is delayed more.
Upon resync, it's still possible that "refRenderFrameId < frontend.chaserRenderFrameId" -- and this is allowed.
*/
refRenderFrameIdIfNeeded := nextDynamicsRenderFrameId - 1
if 0 > refRenderFrameIdIfNeeded {
// Without a "refRenderFrame", there's no point to force confirmation, i.e. nothing to downsync to the "ACTIVE but slowly ticking frontend(s)"
return nil
}
snapshotStFrameId := pR.ConvertToInputFrameId(refRenderFrameIdIfNeeded, pR.InputDelayFrames)
toSendInputFrameDownsyncs := pR.cloneInputsBuffer(snapshotStFrameId, pR.LastAllConfirmedInputFrameId+1)
return &InputsBufferSnapshot{
RefRenderFrameId: refRenderFrameIdIfNeeded,
UnconfirmedMask: unconfirmedMask,
ToSendInputFrameDownsyncs: toSendInputFrameDownsyncs,
}
} else {
return nil
}
}
func (pR *Room) applyInputFrameDownsyncDynamics(fromRenderFrameId int32, toRenderFrameId int32, spaceOffsetX, spaceOffsetY float64) {
@ -1498,26 +1543,25 @@ 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) doBattleMainLoopPerTickBackendDynamicsWithProperLocking(prevRenderFrameId int32, pDynamicsDuration *int64) (uint64, int32, []*InputFrameDownsync) {
func (pR *Room) doBattleMainLoopPerTickBackendDynamicsWithProperLocking(prevRenderFrameId int32, pDynamicsDuration *int64) {
Logger.Debug(fmt.Sprintf("doBattleMainLoopPerTickBackendDynamicsWithProperLocking-InputsBufferLock to about lock: roomId=%v", pR.Id))
pR.InputsBufferLock.Lock()
Logger.Debug(fmt.Sprintf("doBattleMainLoopPerTickBackendDynamicsWithProperLocking-InputsBufferLock locked: roomId=%v", pR.Id))
defer func() {
// [WARNING] Unlock before calling "downsyncToAllPlayers -> downsyncToSinglePlayer" to avoid unlocking lags due to blocking network I/O
pR.InputsBufferLock.Unlock()
Logger.Debug(fmt.Sprintf("doBattleMainLoopPerTickBackendDynamicsWithProperLocking-InputsBufferLock unlocked: roomId=%v", pR.Id))
}()
if ok, inputFrameGeneratingRenderFrameId := pR.shouldPrefabInputFrameDownsync(prevRenderFrameId, pR.RenderFrameId); ok {
noDelayInputFrameId := pR.ConvertToInputFrameId(inputFrameGeneratingRenderFrameId, 0)
if ok, thatRenderFrameId := pR.shouldPrefabInputFrameDownsync(prevRenderFrameId, pR.RenderFrameId); ok {
noDelayInputFrameId := pR.ConvertToInputFrameId(thatRenderFrameId, 0)
if existingInputFrame := pR.InputsBuffer.GetByFrameId(noDelayInputFrameId); nil == existingInputFrame {
pR.prefabInputFrameDownsync(noDelayInputFrameId)
}
}
// Force setting all-confirmed of buffered inputFrames periodically, kindly note that if "pR.BackendDynamicsEnabled", what we want to achieve is "recovery upon reconnection", which certainly requires "forceConfirmationIfApplicable" to move "pR.LastAllConfirmedInputFrameId" forward as much as possible
unconfirmedMask, refRenderFrameId, inputsBufferSnapshot := pR.forceConfirmationIfApplicable(prevRenderFrameId)
inputsBufferSnapshot := pR.forceConfirmationIfApplicable(prevRenderFrameId)
if 0 <= pR.LastAllConfirmedInputFrameId {
dynamicsStartedAt := utils.UnixtimeNano()
@ -1528,16 +1572,24 @@ func (pR *Room) doBattleMainLoopPerTickBackendDynamicsWithProperLocking(prevRend
*pDynamicsDuration = utils.UnixtimeNano() - dynamicsStartedAt
}
return unconfirmedMask, refRenderFrameId, inputsBufferSnapshot
if nil != inputsBufferSnapshot {
Logger.Warn(fmt.Sprintf("roomId=%v, room.RenderFrameId=%v, room.CurDynamicsRenderFrameId=%v, room.LastAllConfirmedInputFrameId=%v, unconfirmedMask=%v", pR.Id, pR.RenderFrameId, pR.CurDynamicsRenderFrameId, pR.LastAllConfirmedInputFrameId, inputsBufferSnapshot.UnconfirmedMask))
pR.downsyncToAllPlayers(inputsBufferSnapshot)
}
}
func (pR *Room) downsyncToAllPlayers(refRenderFrameId int32, unconfirmedMask uint64, inputsBufferSnapshot []*InputFrameDownsync) {
func (pR *Room) downsyncToAllPlayers(inputsBufferSnapshot *InputsBufferSnapshot) {
/*
[WARNING] This function MUST BE called while "pR.InputsBufferLock" is locked for preserving the order of generation of "inputsBufferSnapshot" -- see comments in "OnBattleCmdReceived" and [this issue](https://github.com/genxium/DelayNoMore/issues/12).
Actually if each player session were both intrinsically thread-safe & non-blocking for writing (like Java NIO), I could've just called "playerSession.WriteMessage" while holding "pR.InputsBufferLock" -- but the ws session provided by Gorilla library is neither thread-safe nor non-blocking for writing, which is fine because it creates a chance for the users to solve an interesting problem :)
*/
/*
[WARNING] This function MUST BE called while "pR.InputsBufferLock" is unlocked -- otherwise the blocking "sendSafely" might cause significant lag!
Moreover, we're downsyncing a same "inputsBufferSnapshot" for all players in the same battle and this is by design, i.e. not respecting "player.LastSentInputFrameId" because "new all-confirmed inputFrameDownsyncs" are the same for all players and ws is TCP-based (no loss of consecutive packets except for reconnection -- which is already handled by READDED_BATTLE_COLLIDER_ACKED)
*/
for _, player := range pR.PlayersArr {
pR.downsyncToSinglePlayer(player.Id, player, refRenderFrameId, unconfirmedMask, inputsBufferSnapshot)
for playerId, playerDownsyncChan := range pR.PlayerDownsyncChanDict {
playerDownsyncChan <- (*inputsBufferSnapshot)
Logger.Debug(fmt.Sprintf("Sent inputsBufferSnapshot(refRenderFrameId:%d, unconfirmedMask:%v) to for (roomId: %d, playerId:%d, playerDownsyncChan:%p)#1", inputsBufferSnapshot.RefRenderFrameId, inputsBufferSnapshot.UnconfirmedMask, pR.Id, playerId, playerDownsyncChan))
}
}
@ -1548,14 +1600,6 @@ func (pR *Room) downsyncToSinglePlayer(playerId int32, player *Player, refRender
*/
playerJoinIndex := player.JoinIndex - 1
Logger.Debug(fmt.Sprintf("downsyncToSinglePlayer-SessionLock about to lock: roomId=%v, playerId=%v", pR.Id, playerId))
pR.PlayerDownsyncSessionLock[playerId].Lock()
Logger.Debug(fmt.Sprintf("downsyncToSinglePlayer-SessionLock locked: roomId=%v, playerId=%v", pR.Id, playerId))
defer func() {
pR.PlayerDownsyncSessionLock[playerId].Unlock()
Logger.Debug(fmt.Sprintf("downsyncToSinglePlayer-SessionLock unlocked: roomId=%v, playerId=%v", pR.Id, playerId))
}()
playerBattleState := atomic.LoadInt32(&(player.BattleState))
switch playerBattleState {
case PlayerBattleStateIns.DISCONNECTED:
@ -1567,7 +1611,7 @@ func (pR *Room) downsyncToSinglePlayer(playerId int32, player *Player, refRender
return
}
shouldResync1 := (PlayerBattleStateIns.READDED_BATTLE_COLLIDER_ACKED == playerBattleState) // i.e. implies that "MAGIC_LAST_SENT_INPUT_FRAME_ID_READDED == player.LastSentInputFrameId", kindly note that this check as well as the re-assignment at the bottom of this function are both guarded by "pR.PlayerDownsyncSessionLock[playerId]"
shouldResync1 := (PlayerBattleStateIns.READDED_BATTLE_COLLIDER_ACKED == playerBattleState) // i.e. implies that "MAGIC_LAST_SENT_INPUT_FRAME_ID_READDED == player.LastSentInputFrameId"
shouldResync2 := (0 < (unconfirmedMask & uint64(1<<uint32(playerJoinIndex)))) // This condition is critical, if we don't send resync upon this condition, the "reconnected or slowly-clocking player" might never get its input synced
// shouldResync2 := (0 < unconfirmedMask) // An easier version of the above, might keep sending "refRenderFrame"s to still connected players when any player is disconnected
shouldResyncOverall := (shouldResync1 || shouldResync2)
@ -1606,9 +1650,9 @@ func (pR *Room) downsyncToSinglePlayer(playerId int32, player *Player, refRender
}
}
func (pR *Room) createInputsBufferSnapshot(stFrameId, edFrameId int32) []*InputFrameDownsync {
func (pR *Room) cloneInputsBuffer(stFrameId, edFrameId int32) []*InputFrameDownsync {
// [WARNING] This function MUST BE called while "pR.InputsBufferLock" is locked!
snapshot := make([]*InputFrameDownsync, 0, edFrameId-stFrameId)
cloned := make([]*InputFrameDownsync, 0, edFrameId-stFrameId)
prevFrameFound := false
j := stFrameId
for j < edFrameId {
@ -1632,9 +1676,9 @@ func (pR *Room) createInputsBufferSnapshot(stFrameId, edFrameId int32) []*InputF
for i, input := range foo.InputList {
bar.InputList[i] = input
}
snapshot = append(snapshot, bar)
cloned = append(cloned, bar)
j++
}
return snapshot
return cloned
}

View File

@ -630,6 +630,69 @@ func (x *WsResp) GetBciFrame() *BattleColliderInfo {
return nil
}
type InputsBufferSnapshot struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
RefRenderFrameId int32 `protobuf:"varint,1,opt,name=refRenderFrameId,proto3" json:"refRenderFrameId,omitempty"`
UnconfirmedMask uint64 `protobuf:"varint,2,opt,name=unconfirmedMask,proto3" json:"unconfirmedMask,omitempty"`
ToSendInputFrameDownsyncs []*InputFrameDownsync `protobuf:"bytes,3,rep,name=toSendInputFrameDownsyncs,proto3" json:"toSendInputFrameDownsyncs,omitempty"`
}
func (x *InputsBufferSnapshot) Reset() {
*x = InputsBufferSnapshot{}
if protoimpl.UnsafeEnabled {
mi := &file_room_downsync_frame_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *InputsBufferSnapshot) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*InputsBufferSnapshot) ProtoMessage() {}
func (x *InputsBufferSnapshot) ProtoReflect() protoreflect.Message {
mi := &file_room_downsync_frame_proto_msgTypes[7]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use InputsBufferSnapshot.ProtoReflect.Descriptor instead.
func (*InputsBufferSnapshot) Descriptor() ([]byte, []int) {
return file_room_downsync_frame_proto_rawDescGZIP(), []int{7}
}
func (x *InputsBufferSnapshot) GetRefRenderFrameId() int32 {
if x != nil {
return x.RefRenderFrameId
}
return 0
}
func (x *InputsBufferSnapshot) GetUnconfirmedMask() uint64 {
if x != nil {
return x.UnconfirmedMask
}
return 0
}
func (x *InputsBufferSnapshot) GetToSendInputFrameDownsyncs() []*InputFrameDownsync {
if x != nil {
return x.ToSendInputFrameDownsyncs
}
return nil
}
type MeleeBullet struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@ -659,7 +722,7 @@ type MeleeBullet struct {
func (x *MeleeBullet) Reset() {
*x = MeleeBullet{}
if protoimpl.UnsafeEnabled {
mi := &file_room_downsync_frame_proto_msgTypes[7]
mi := &file_room_downsync_frame_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@ -672,7 +735,7 @@ func (x *MeleeBullet) String() string {
func (*MeleeBullet) ProtoMessage() {}
func (x *MeleeBullet) ProtoReflect() protoreflect.Message {
mi := &file_room_downsync_frame_proto_msgTypes[7]
mi := &file_room_downsync_frame_proto_msgTypes[8]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@ -685,7 +748,7 @@ func (x *MeleeBullet) ProtoReflect() protoreflect.Message {
// Deprecated: Use MeleeBullet.ProtoReflect.Descriptor instead.
func (*MeleeBullet) Descriptor() ([]byte, []int) {
return file_room_downsync_frame_proto_rawDescGZIP(), []int{7}
return file_room_downsync_frame_proto_rawDescGZIP(), []int{8}
}
func (x *MeleeBullet) GetBattleLocalId() int32 {
@ -843,7 +906,7 @@ type BattleColliderInfo struct {
func (x *BattleColliderInfo) Reset() {
*x = BattleColliderInfo{}
if protoimpl.UnsafeEnabled {
mi := &file_room_downsync_frame_proto_msgTypes[8]
mi := &file_room_downsync_frame_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@ -856,7 +919,7 @@ func (x *BattleColliderInfo) String() string {
func (*BattleColliderInfo) ProtoMessage() {}
func (x *BattleColliderInfo) ProtoReflect() protoreflect.Message {
mi := &file_room_downsync_frame_proto_msgTypes[8]
mi := &file_room_downsync_frame_proto_msgTypes[9]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@ -869,7 +932,7 @@ func (x *BattleColliderInfo) ProtoReflect() protoreflect.Message {
// Deprecated: Use BattleColliderInfo.ProtoReflect.Descriptor instead.
func (*BattleColliderInfo) Descriptor() ([]byte, []int) {
return file_room_downsync_frame_proto_rawDescGZIP(), []int{8}
return file_room_downsync_frame_proto_rawDescGZIP(), []int{9}
}
func (x *BattleColliderInfo) GetStageName() string {
@ -1069,7 +1132,7 @@ type RoomDownsyncFrame struct {
func (x *RoomDownsyncFrame) Reset() {
*x = RoomDownsyncFrame{}
if protoimpl.UnsafeEnabled {
mi := &file_room_downsync_frame_proto_msgTypes[9]
mi := &file_room_downsync_frame_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@ -1082,7 +1145,7 @@ func (x *RoomDownsyncFrame) String() string {
func (*RoomDownsyncFrame) ProtoMessage() {}
func (x *RoomDownsyncFrame) ProtoReflect() protoreflect.Message {
mi := &file_room_downsync_frame_proto_msgTypes[9]
mi := &file_room_downsync_frame_proto_msgTypes[10]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@ -1095,7 +1158,7 @@ func (x *RoomDownsyncFrame) ProtoReflect() protoreflect.Message {
// Deprecated: Use RoomDownsyncFrame.ProtoReflect.Descriptor instead.
func (*RoomDownsyncFrame) Descriptor() ([]byte, []int) {
return file_room_downsync_frame_proto_rawDescGZIP(), []int{9}
return file_room_downsync_frame_proto_rawDescGZIP(), []int{10}
}
func (x *RoomDownsyncFrame) GetId() int32 {
@ -1233,182 +1296,194 @@ var file_room_downsync_frame_proto_rawDesc = []byte{
0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x73, 0x2e, 0x42, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x6c, 0x69, 0x64, 0x65,
0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x62, 0x63, 0x69, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x22,
0xe5, 0x05, 0x0a, 0x0b, 0x4d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x12,
0x24, 0x0a, 0x0d, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64,
0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x4c, 0x6f,
0x63, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70,
0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x73, 0x74,
0x61, 0x72, 0x74, 0x75, 0x70, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x61,
0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28,
0x05, 0x52, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12,
0x26, 0x0a, 0x0e, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x46, 0x72, 0x61, 0x6d, 0x65,
0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72,
0x79, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x34, 0x0a, 0x15, 0x72, 0x65, 0x63, 0x6f, 0x76,
0x65, 0x72, 0x79, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x4f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b,
0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x15, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79,
0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x4f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x30, 0x0a,
0x13, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x4f,
0x6e, 0x48, 0x69, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x13, 0x72, 0x65, 0x63, 0x6f,
0x76, 0x65, 0x72, 0x79, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x4f, 0x6e, 0x48, 0x69, 0x74, 0x12,
0x35, 0x0a, 0x0b, 0x6d, 0x6f, 0x76, 0x65, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x18, 0x07,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x73, 0x2e, 0x56, 0x65, 0x63, 0x32, 0x44, 0x52, 0x0b, 0x6d, 0x6f, 0x76, 0x65, 0x66,
0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78,
0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0c, 0x68, 0x69,
0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x33, 0x0a, 0x0a, 0x68, 0x69,
0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13,
0x2e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x56, 0x65,
0x63, 0x32, 0x44, 0x52, 0x0a, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x12,
0x38, 0x0a, 0x17, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x6e,
0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05,
0x52, 0x17, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x6e, 0x64,
0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74,
0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05,
0x52, 0x0d, 0x68, 0x69, 0x74, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12,
0x28, 0x0a, 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d,
0x65, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53,
0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x75, 0x73,
0x68, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x01, 0x52, 0x08, 0x70, 0x75, 0x73,
0x68, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x2e, 0x0a, 0x12, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65,
0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28,
0x05, 0x52, 0x12, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65,
0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x61, 0x6d, 0x61, 0x67, 0x65, 0x18,
0x0f, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x64, 0x61, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x2c, 0x0a,
0x11, 0x6f, 0x66, 0x66, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64,
0x65, 0x78, 0x18, 0x10, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x6f, 0x66, 0x66, 0x65, 0x6e, 0x64,
0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x2a, 0x0a, 0x10, 0x6f,
0x66, 0x66, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x18,
0x11, 0x20, 0x01, 0x28, 0x05, 0x52, 0x10, 0x6f, 0x66, 0x66, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x50,
0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x22, 0x98, 0x0d, 0x0a, 0x12, 0x42, 0x61, 0x74, 0x74,
0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x6c, 0x69, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1c,
0x0a, 0x09, 0x73, 0x74, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x52, 0x09, 0x73, 0x74, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x5f, 0x0a, 0x11,
0x73, 0x74, 0x72, 0x54, 0x6f, 0x56, 0x65, 0x63, 0x32, 0x44, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61,
0x70, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73,
0x2e, 0x42, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x6c, 0x69, 0x64, 0x65, 0x72, 0x49,
0x6e, 0x66, 0x6f, 0x2e, 0x53, 0x74, 0x72, 0x54, 0x6f, 0x56, 0x65, 0x63, 0x32, 0x44, 0x4c, 0x69,
0x73, 0x74, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x11, 0x73, 0x74, 0x72, 0x54,
0x6f, 0x56, 0x65, 0x63, 0x32, 0x44, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x12, 0x6b, 0x0a,
0x15, 0x73, 0x74, 0x72, 0x54, 0x6f, 0x50, 0x6f, 0x6c, 0x79, 0x67, 0x6f, 0x6e, 0x32, 0x44, 0x4c,
0x69, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x42, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x6c,
0x69, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x53, 0x74, 0x72, 0x54, 0x6f, 0x50, 0x6f,
0x6c, 0x79, 0x67, 0x6f, 0x6e, 0x32, 0x44, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x45, 0x6e,
0x74, 0x72, 0x79, 0x52, 0x15, 0x73, 0x74, 0x72, 0x54, 0x6f, 0x50, 0x6f, 0x6c, 0x79, 0x67, 0x6f,
0x6e, 0x32, 0x44, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x12, 0x26, 0x0a, 0x0e, 0x73, 0x74,
0x61, 0x67, 0x65, 0x44, 0x69, 0x73, 0x63, 0x72, 0x65, 0x74, 0x65, 0x57, 0x18, 0x04, 0x20, 0x01,
0x28, 0x05, 0x52, 0x0e, 0x73, 0x74, 0x61, 0x67, 0x65, 0x44, 0x69, 0x73, 0x63, 0x72, 0x65, 0x74,
0x65, 0x57, 0x12, 0x26, 0x0a, 0x0e, 0x73, 0x74, 0x61, 0x67, 0x65, 0x44, 0x69, 0x73, 0x63, 0x72,
0x65, 0x74, 0x65, 0x48, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x73, 0x74, 0x61, 0x67,
0x65, 0x44, 0x69, 0x73, 0x63, 0x72, 0x65, 0x74, 0x65, 0x48, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x74,
0x61, 0x67, 0x65, 0x54, 0x69, 0x6c, 0x65, 0x57, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a,
0x73, 0x74, 0x61, 0x67, 0x65, 0x54, 0x69, 0x6c, 0x65, 0x57, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x74,
0x61, 0x67, 0x65, 0x54, 0x69, 0x6c, 0x65, 0x48, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a,
0x73, 0x74, 0x61, 0x67, 0x65, 0x54, 0x69, 0x6c, 0x65, 0x48, 0x12, 0x26, 0x0a, 0x0e, 0x69, 0x6e,
0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x54, 0x6f, 0x50, 0x69, 0x6e, 0x67, 0x18, 0x08, 0x20, 0x01,
0x28, 0x05, 0x52, 0x0e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x54, 0x6f, 0x50, 0x69,
0x6e, 0x67, 0x12, 0x34, 0x0a, 0x15, 0x77, 0x69, 0x6c, 0x6c, 0x4b, 0x69, 0x63, 0x6b, 0x49, 0x66,
0x49, 0x6e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x6f, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28,
0x05, 0x52, 0x15, 0x77, 0x69, 0x6c, 0x6c, 0x4b, 0x69, 0x63, 0x6b, 0x49, 0x66, 0x49, 0x6e, 0x61,
0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x6f, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x6f, 0x75, 0x6e,
0x64, 0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x62,
0x6f, 0x75, 0x6e, 0x64, 0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x12, 0x32, 0x0a, 0x14, 0x62, 0x61,
0x74, 0x74, 0x6c, 0x65, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x72, 0x61, 0x6d,
0x65, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x05, 0x52, 0x14, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65,
0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x30,
0x0a, 0x13, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x03, 0x52, 0x13, 0x62, 0x61, 0x74,
0x74, 0x6c, 0x65, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73,
0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x46, 0x70, 0x73, 0x18, 0x0e, 0x20,
0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x46, 0x70, 0x73, 0x12, 0x2a,
0x0a, 0x10, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x46, 0x72, 0x61, 0x6d,
0x65, 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x05, 0x52, 0x10, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x44,
0x65, 0x6c, 0x61, 0x79, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x69, 0x6e,
0x70, 0x75, 0x74, 0x53, 0x63, 0x61, 0x6c, 0x65, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x10,
0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x53, 0x63, 0x61, 0x6c, 0x65,
0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x26, 0x0a, 0x0e, 0x6e, 0x73, 0x74, 0x44, 0x65, 0x6c,
0x61, 0x79, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x11, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e,
0x6e, 0x73, 0x74, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x46,
0x0a, 0x1e, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x73, 0x79,
0x6e, 0x63, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x54, 0x6f, 0x6c, 0x65, 0x72, 0x61, 0x6e, 0x63, 0x65,
0x18, 0x12, 0x20, 0x01, 0x28, 0x05, 0x52, 0x1e, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61,
0x6d, 0x65, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x54, 0x6f, 0x6c,
0x65, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x48, 0x0a, 0x1f, 0x6d, 0x61, 0x78, 0x43, 0x68, 0x61,
0x73, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73,
0x50, 0x65, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x13, 0x20, 0x01, 0x28, 0x05, 0x52,
0x1f, 0x6d, 0x61, 0x78, 0x43, 0x68, 0x61, 0x73, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x6e, 0x64, 0x65,
0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x50, 0x65, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65,
0x12, 0x2c, 0x0a, 0x11, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x42, 0x61, 0x74, 0x74, 0x6c, 0x65,
0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x14, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x70, 0x6c, 0x61,
0x79, 0x65, 0x72, 0x42, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x3c,
0x0a, 0x19, 0x72, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61,
0x74, 0x65, 0x64, 0x44, 0x74, 0x4d, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x18, 0x15, 0x20, 0x01, 0x28,
0x01, 0x52, 0x19, 0x72, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x45, 0x73, 0x74, 0x69, 0x6d,
0x61, 0x74, 0x65, 0x64, 0x44, 0x74, 0x4d, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x12, 0x3a, 0x0a, 0x18,
0x72, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65,
0x64, 0x44, 0x74, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x18, 0x16, 0x20, 0x01, 0x28, 0x03, 0x52, 0x18,
0x72, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65,
0x64, 0x44, 0x74, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x12, 0x38, 0x0a, 0x17, 0x77, 0x6f, 0x72, 0x6c,
0x64, 0x54, 0x6f, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x52, 0x61,
0x74, 0x69, 0x6f, 0x18, 0x17, 0x20, 0x01, 0x28, 0x01, 0x52, 0x17, 0x77, 0x6f, 0x72, 0x6c, 0x64,
0x54, 0x6f, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x52, 0x61, 0x74,
0x69, 0x6f, 0x12, 0x38, 0x0a, 0x17, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x47, 0x72, 0x69,
0x64, 0x54, 0x6f, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x52, 0x61, 0x74, 0x69, 0x6f, 0x18, 0x18, 0x20,
0x01, 0x28, 0x01, 0x52, 0x17, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x47, 0x72, 0x69, 0x64,
0x54, 0x6f, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x52, 0x61, 0x74, 0x69, 0x6f, 0x12, 0x2c, 0x0a, 0x11,
0x73, 0x70, 0x41, 0x74, 0x6b, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x46, 0x72, 0x61, 0x6d, 0x65,
0x73, 0x18, 0x19, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x73, 0x70, 0x41, 0x74, 0x6b, 0x4c, 0x6f,
0x6f, 0x6b, 0x75, 0x70, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x28, 0x0a, 0x0f, 0x72, 0x65,
0x6e, 0x64, 0x65, 0x72, 0x43, 0x61, 0x63, 0x68, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x1a, 0x20,
0x01, 0x28, 0x05, 0x52, 0x0f, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x43, 0x61, 0x63, 0x68, 0x65,
0x53, 0x69, 0x7a, 0x65, 0x12, 0x5c, 0x0a, 0x10, 0x6d, 0x65, 0x6c, 0x65, 0x65, 0x53, 0x6b, 0x69,
0x6c, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x1b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x30,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x42, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x43, 0x6f,
0x6c, 0x6c, 0x69, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x4d, 0x65, 0x6c, 0x65, 0x65,
0x53, 0x6b, 0x69, 0x6c, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79,
0x52, 0x10, 0x6d, 0x65, 0x6c, 0x65, 0x65, 0x53, 0x6b, 0x69, 0x6c, 0x6c, 0x43, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x1a, 0x5d, 0x0a, 0x16, 0x53, 0x74, 0x72, 0x54, 0x6f, 0x56, 0x65, 0x63, 0x32, 0x44,
0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03,
0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2d,
0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e,
0xc6, 0x01, 0x0a, 0x14, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72,
0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x2a, 0x0a, 0x10, 0x72, 0x65, 0x66, 0x52,
0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01,
0x28, 0x05, 0x52, 0x10, 0x72, 0x65, 0x66, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61,
0x6d, 0x65, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x0f, 0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72,
0x6d, 0x65, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x75,
0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x12, 0x58,
0x0a, 0x19, 0x74, 0x6f, 0x53, 0x65, 0x6e, 0x64, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61,
0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74,
0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x52, 0x19, 0x74,
0x6f, 0x53, 0x65, 0x6e, 0x64, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44,
0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x73, 0x22, 0xe5, 0x05, 0x0a, 0x0b, 0x4d, 0x65, 0x6c,
0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x62, 0x61, 0x74, 0x74,
0x6c, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52,
0x0d, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x24,
0x0a, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18,
0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x46, 0x72,
0x61, 0x6d, 0x65, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x72,
0x61, 0x6d, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x61, 0x63, 0x74, 0x69,
0x76, 0x65, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x26, 0x0a, 0x0e, 0x72, 0x65, 0x63, 0x6f,
0x76, 0x65, 0x72, 0x79, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05,
0x52, 0x0e, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73,
0x12, 0x34, 0x0a, 0x15, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x46, 0x72, 0x61, 0x6d,
0x65, 0x73, 0x4f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52,
0x15, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x4f,
0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x30, 0x0a, 0x13, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65,
0x72, 0x79, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x4f, 0x6e, 0x48, 0x69, 0x74, 0x18, 0x06, 0x20,
0x01, 0x28, 0x05, 0x52, 0x13, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x46, 0x72, 0x61,
0x6d, 0x65, 0x73, 0x4f, 0x6e, 0x48, 0x69, 0x74, 0x12, 0x35, 0x0a, 0x0b, 0x6d, 0x6f, 0x76, 0x65,
0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e,
0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x56, 0x65, 0x63,
0x32, 0x44, 0x52, 0x0b, 0x6d, 0x6f, 0x76, 0x65, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x12,
0x22, 0x0a, 0x0c, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18,
0x08, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0c, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66,
0x73, 0x65, 0x74, 0x12, 0x33, 0x0a, 0x0a, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a,
0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x56, 0x65, 0x63, 0x32, 0x44, 0x52, 0x0a, 0x68, 0x69,
0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x38, 0x0a, 0x17, 0x6f, 0x72, 0x69, 0x67,
0x69, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d,
0x65, 0x49, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x17, 0x6f, 0x72, 0x69, 0x67, 0x69,
0x6e, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65,
0x49, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61,
0x6d, 0x65, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x68, 0x69, 0x74, 0x53, 0x74,
0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x28, 0x0a, 0x0f, 0x62, 0x6c, 0x6f, 0x63,
0x6b, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28,
0x05, 0x52, 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d,
0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x0d,
0x20, 0x01, 0x28, 0x01, 0x52, 0x08, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x2e,
0x0a, 0x12, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72,
0x54, 0x79, 0x70, 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x72, 0x65, 0x6c, 0x65,
0x61, 0x73, 0x65, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16,
0x0a, 0x06, 0x64, 0x61, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06,
0x64, 0x61, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x2c, 0x0a, 0x11, 0x6f, 0x66, 0x66, 0x65, 0x6e, 0x64,
0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x10, 0x20, 0x01, 0x28,
0x05, 0x52, 0x11, 0x6f, 0x66, 0x66, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49,
0x6e, 0x64, 0x65, 0x78, 0x12, 0x2a, 0x0a, 0x10, 0x6f, 0x66, 0x66, 0x65, 0x6e, 0x64, 0x65, 0x72,
0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x18, 0x11, 0x20, 0x01, 0x28, 0x05, 0x52, 0x10,
0x6f, 0x66, 0x66, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x64,
0x22, 0x98, 0x0d, 0x0a, 0x12, 0x42, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x6c, 0x69,
0x64, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x67, 0x65,
0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x61, 0x67,
0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x5f, 0x0a, 0x11, 0x73, 0x74, 0x72, 0x54, 0x6f, 0x56, 0x65,
0x63, 0x32, 0x44, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b,
0x32, 0x31, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x42, 0x61, 0x74, 0x74, 0x6c, 0x65,
0x43, 0x6f, 0x6c, 0x6c, 0x69, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x53, 0x74, 0x72,
0x54, 0x6f, 0x56, 0x65, 0x63, 0x32, 0x44, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x45, 0x6e,
0x74, 0x72, 0x79, 0x52, 0x11, 0x73, 0x74, 0x72, 0x54, 0x6f, 0x56, 0x65, 0x63, 0x32, 0x44, 0x4c,
0x69, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x12, 0x6b, 0x0a, 0x15, 0x73, 0x74, 0x72, 0x54, 0x6f, 0x50,
0x6f, 0x6c, 0x79, 0x67, 0x6f, 0x6e, 0x32, 0x44, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x18,
0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x42,
0x61, 0x74, 0x74, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x6c, 0x69, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x66,
0x6f, 0x2e, 0x53, 0x74, 0x72, 0x54, 0x6f, 0x50, 0x6f, 0x6c, 0x79, 0x67, 0x6f, 0x6e, 0x32, 0x44,
0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x15, 0x73, 0x74,
0x72, 0x54, 0x6f, 0x50, 0x6f, 0x6c, 0x79, 0x67, 0x6f, 0x6e, 0x32, 0x44, 0x4c, 0x69, 0x73, 0x74,
0x4d, 0x61, 0x70, 0x12, 0x26, 0x0a, 0x0e, 0x73, 0x74, 0x61, 0x67, 0x65, 0x44, 0x69, 0x73, 0x63,
0x72, 0x65, 0x74, 0x65, 0x57, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x73, 0x74, 0x61,
0x67, 0x65, 0x44, 0x69, 0x73, 0x63, 0x72, 0x65, 0x74, 0x65, 0x57, 0x12, 0x26, 0x0a, 0x0e, 0x73,
0x74, 0x61, 0x67, 0x65, 0x44, 0x69, 0x73, 0x63, 0x72, 0x65, 0x74, 0x65, 0x48, 0x18, 0x05, 0x20,
0x01, 0x28, 0x05, 0x52, 0x0e, 0x73, 0x74, 0x61, 0x67, 0x65, 0x44, 0x69, 0x73, 0x63, 0x72, 0x65,
0x74, 0x65, 0x48, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x67, 0x65, 0x54, 0x69, 0x6c, 0x65,
0x57, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x67, 0x65, 0x54, 0x69,
0x6c, 0x65, 0x57, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x67, 0x65, 0x54, 0x69, 0x6c, 0x65,
0x48, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x67, 0x65, 0x54, 0x69,
0x6c, 0x65, 0x48, 0x12, 0x26, 0x0a, 0x0e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x54,
0x6f, 0x50, 0x69, 0x6e, 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x69, 0x6e, 0x74,
0x65, 0x72, 0x76, 0x61, 0x6c, 0x54, 0x6f, 0x50, 0x69, 0x6e, 0x67, 0x12, 0x34, 0x0a, 0x15, 0x77,
0x69, 0x6c, 0x6c, 0x4b, 0x69, 0x63, 0x6b, 0x49, 0x66, 0x49, 0x6e, 0x61, 0x63, 0x74, 0x69, 0x76,
0x65, 0x46, 0x6f, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x15, 0x77, 0x69, 0x6c, 0x6c,
0x4b, 0x69, 0x63, 0x6b, 0x49, 0x66, 0x49, 0x6e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x6f,
0x72, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x64,
0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x6f, 0x6f,
0x6d, 0x49, 0x64, 0x12, 0x32, 0x0a, 0x14, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x44, 0x75, 0x72,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28,
0x05, 0x52, 0x14, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x30, 0x0a, 0x13, 0x62, 0x61, 0x74, 0x74, 0x6c,
0x65, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x18, 0x0d,
0x20, 0x01, 0x28, 0x03, 0x52, 0x13, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x44, 0x75, 0x72, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x72,
0x76, 0x65, 0x72, 0x46, 0x70, 0x73, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x65,
0x72, 0x76, 0x65, 0x72, 0x46, 0x70, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x69, 0x6e, 0x70, 0x75, 0x74,
0x44, 0x65, 0x6c, 0x61, 0x79, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28,
0x05, 0x52, 0x10, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x46, 0x72, 0x61,
0x6d, 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x53, 0x63, 0x61, 0x6c,
0x65, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, 0x69,
0x6e, 0x70, 0x75, 0x74, 0x53, 0x63, 0x61, 0x6c, 0x65, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12,
0x26, 0x0a, 0x0e, 0x6e, 0x73, 0x74, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x46, 0x72, 0x61, 0x6d, 0x65,
0x73, 0x18, 0x11, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x6e, 0x73, 0x74, 0x44, 0x65, 0x6c, 0x61,
0x79, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x46, 0x0a, 0x1e, 0x69, 0x6e, 0x70, 0x75, 0x74,
0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x44, 0x65, 0x6c, 0x61, 0x79,
0x54, 0x6f, 0x6c, 0x65, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x05, 0x52,
0x1e, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x73, 0x79, 0x6e,
0x63, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x54, 0x6f, 0x6c, 0x65, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x12,
0x48, 0x0a, 0x1f, 0x6d, 0x61, 0x78, 0x43, 0x68, 0x61, 0x73, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x6e,
0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x50, 0x65, 0x72, 0x55, 0x70, 0x64, 0x61,
0x74, 0x65, 0x18, 0x13, 0x20, 0x01, 0x28, 0x05, 0x52, 0x1f, 0x6d, 0x61, 0x78, 0x43, 0x68, 0x61,
0x73, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73,
0x50, 0x65, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x2c, 0x0a, 0x11, 0x70, 0x6c, 0x61,
0x79, 0x65, 0x72, 0x42, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x14,
0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x42, 0x61, 0x74, 0x74,
0x6c, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x3c, 0x0a, 0x19, 0x72, 0x6f, 0x6c, 0x6c, 0x62,
0x61, 0x63, 0x6b, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x64, 0x44, 0x74, 0x4d, 0x69,
0x6c, 0x6c, 0x69, 0x73, 0x18, 0x15, 0x20, 0x01, 0x28, 0x01, 0x52, 0x19, 0x72, 0x6f, 0x6c, 0x6c,
0x62, 0x61, 0x63, 0x6b, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x64, 0x44, 0x74, 0x4d,
0x69, 0x6c, 0x6c, 0x69, 0x73, 0x12, 0x3a, 0x0a, 0x18, 0x72, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63,
0x6b, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x64, 0x44, 0x74, 0x4e, 0x61, 0x6e, 0x6f,
0x73, 0x18, 0x16, 0x20, 0x01, 0x28, 0x03, 0x52, 0x18, 0x72, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63,
0x6b, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x64, 0x44, 0x74, 0x4e, 0x61, 0x6e, 0x6f,
0x73, 0x12, 0x38, 0x0a, 0x17, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x54, 0x6f, 0x56, 0x69, 0x72, 0x74,
0x75, 0x61, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x52, 0x61, 0x74, 0x69, 0x6f, 0x18, 0x17, 0x20, 0x01,
0x28, 0x01, 0x52, 0x17, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x54, 0x6f, 0x56, 0x69, 0x72, 0x74, 0x75,
0x61, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x52, 0x61, 0x74, 0x69, 0x6f, 0x12, 0x38, 0x0a, 0x17, 0x76,
0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x54, 0x6f, 0x57, 0x6f, 0x72, 0x6c,
0x64, 0x52, 0x61, 0x74, 0x69, 0x6f, 0x18, 0x18, 0x20, 0x01, 0x28, 0x01, 0x52, 0x17, 0x76, 0x69,
0x72, 0x74, 0x75, 0x61, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x54, 0x6f, 0x57, 0x6f, 0x72, 0x6c, 0x64,
0x52, 0x61, 0x74, 0x69, 0x6f, 0x12, 0x2c, 0x0a, 0x11, 0x73, 0x70, 0x41, 0x74, 0x6b, 0x4c, 0x6f,
0x6f, 0x6b, 0x75, 0x70, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x19, 0x20, 0x01, 0x28, 0x05,
0x52, 0x11, 0x73, 0x70, 0x41, 0x74, 0x6b, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x46, 0x72, 0x61,
0x6d, 0x65, 0x73, 0x12, 0x28, 0x0a, 0x0f, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x43, 0x61, 0x63,
0x68, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x72, 0x65,
0x6e, 0x64, 0x65, 0x72, 0x43, 0x61, 0x63, 0x68, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x5c, 0x0a,
0x10, 0x6d, 0x65, 0x6c, 0x65, 0x65, 0x53, 0x6b, 0x69, 0x6c, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x18, 0x1b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73,
0x2e, 0x42, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x6c, 0x69, 0x64, 0x65, 0x72, 0x49,
0x6e, 0x66, 0x6f, 0x2e, 0x4d, 0x65, 0x6c, 0x65, 0x65, 0x53, 0x6b, 0x69, 0x6c, 0x6c, 0x43, 0x6f,
0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x10, 0x6d, 0x65, 0x6c, 0x65, 0x65,
0x53, 0x6b, 0x69, 0x6c, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x5d, 0x0a, 0x16, 0x53,
0x74, 0x72, 0x54, 0x6f, 0x56, 0x65, 0x63, 0x32, 0x44, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x70,
0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2d, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x56, 0x65, 0x63, 0x32, 0x44, 0x4c, 0x69, 0x73, 0x74, 0x52,
0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x65, 0x0a, 0x1a, 0x53, 0x74,
0x72, 0x54, 0x6f, 0x50, 0x6f, 0x6c, 0x79, 0x67, 0x6f, 0x6e, 0x32, 0x44, 0x4c, 0x69, 0x73, 0x74,
0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x31, 0x0a, 0x05, 0x76, 0x61,
0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x73, 0x68, 0x61, 0x72,
0x65, 0x64, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x50, 0x6f, 0x6c, 0x79, 0x67, 0x6f, 0x6e,
0x32, 0x44, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
0x01, 0x1a, 0x65, 0x0a, 0x1a, 0x53, 0x74, 0x72, 0x54, 0x6f, 0x50, 0x6f, 0x6c, 0x79, 0x67, 0x6f,
0x6e, 0x32, 0x44, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12,
0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65,
0x79, 0x12, 0x31, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x1b, 0x2e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e,
0x50, 0x6f, 0x6c, 0x79, 0x67, 0x6f, 0x6e, 0x32, 0x44, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x05, 0x76,
0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x58, 0x0a, 0x15, 0x4d, 0x65, 0x6c, 0x65,
0x65, 0x53, 0x6b, 0x69, 0x6c, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72,
0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03,
0x6b, 0x65, 0x79, 0x12, 0x29, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x4d, 0x65, 0x6c, 0x65,
0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02,
0x38, 0x01, 0x22, 0xd2, 0x02, 0x0a, 0x11, 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, 0x64, 0x12, 0x40, 0x0a, 0x07, 0x70, 0x6c, 0x61, 0x79,
0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x73, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x46,
0x72, 0x61, 0x6d, 0x65, 0x2e, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72,
0x79, 0x52, 0x07, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x6f,
0x75, 0x6e, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01,
0x28, 0x03, 0x52, 0x0e, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x4e, 0x61, 0x6e,
0x6f, 0x73, 0x12, 0x37, 0x0a, 0x0c, 0x6d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65,
0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x73, 0x2e, 0x4d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x52, 0x0c, 0x6d,
0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x12, 0x36, 0x0a, 0x16, 0x62,
0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65,
0x64, 0x4d, 0x61, 0x73, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x16, 0x62, 0x61, 0x63,
0x6b, 0x65, 0x6e, 0x64, 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4d,
0x61, 0x73, 0x6b, 0x1a, 0x52, 0x0a, 0x0c, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x45, 0x6e,
0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05,
0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x50, 0x6c,
0x61, 0x79, 0x65, 0x72, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x52, 0x05, 0x76, 0x61,
0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 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,
0x01, 0x1a, 0x58, 0x0a, 0x15, 0x4d, 0x65, 0x6c, 0x65, 0x65, 0x53, 0x6b, 0x69, 0x6c, 0x6c, 0x43,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x29, 0x0a, 0x05,
0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x4d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74,
0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xd2, 0x02, 0x0a, 0x11,
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,
0x64, 0x12, 0x40, 0x0a, 0x07, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03,
0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x52, 0x6f, 0x6f, 0x6d,
0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x2e, 0x50, 0x6c,
0x61, 0x79, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x70, 0x6c, 0x61, 0x79,
0x65, 0x72, 0x73, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x64, 0x6f, 0x77, 0x6e,
0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x63, 0x6f, 0x75,
0x6e, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x12, 0x37, 0x0a, 0x0c, 0x6d,
0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x4d, 0x65, 0x6c, 0x65, 0x65,
0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x52, 0x0c, 0x6d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c,
0x6c, 0x65, 0x74, 0x73, 0x12, 0x36, 0x0a, 0x16, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x55,
0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x18, 0x05,
0x20, 0x01, 0x28, 0x04, 0x52, 0x16, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x55, 0x6e, 0x63,
0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x1a, 0x52, 0x0a, 0x0c,
0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03,
0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2c,
0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x44, 0x6f, 0x77,
0x6e, 0x73, 0x79, 0x6e, 0x63, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01,
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 (
@ -1423,7 +1498,7 @@ func file_room_downsync_frame_proto_rawDescGZIP() []byte {
return file_room_downsync_frame_proto_rawDescData
}
var file_room_downsync_frame_proto_msgTypes = make([]protoimpl.MessageInfo, 14)
var file_room_downsync_frame_proto_msgTypes = make([]protoimpl.MessageInfo, 15)
var file_room_downsync_frame_proto_goTypes = []interface{}{
(*PlayerDownsync)(nil), // 0: protos.PlayerDownsync
(*InputFrameDecoded)(nil), // 1: protos.InputFrameDecoded
@ -1432,39 +1507,41 @@ var file_room_downsync_frame_proto_goTypes = []interface{}{
(*HeartbeatUpsync)(nil), // 4: protos.HeartbeatUpsync
(*WsReq)(nil), // 5: protos.WsReq
(*WsResp)(nil), // 6: protos.WsResp
(*MeleeBullet)(nil), // 7: protos.MeleeBullet
(*BattleColliderInfo)(nil), // 8: protos.BattleColliderInfo
(*RoomDownsyncFrame)(nil), // 9: protos.RoomDownsyncFrame
nil, // 10: protos.BattleColliderInfo.StrToVec2DListMapEntry
nil, // 11: protos.BattleColliderInfo.StrToPolygon2DListMapEntry
nil, // 12: protos.BattleColliderInfo.MeleeSkillConfigEntry
nil, // 13: protos.RoomDownsyncFrame.PlayersEntry
(*sharedprotos.Vec2D)(nil), // 14: sharedprotos.Vec2D
(*sharedprotos.Vec2DList)(nil), // 15: sharedprotos.Vec2DList
(*sharedprotos.Polygon2DList)(nil), // 16: sharedprotos.Polygon2DList
(*InputsBufferSnapshot)(nil), // 7: protos.InputsBufferSnapshot
(*MeleeBullet)(nil), // 8: protos.MeleeBullet
(*BattleColliderInfo)(nil), // 9: protos.BattleColliderInfo
(*RoomDownsyncFrame)(nil), // 10: protos.RoomDownsyncFrame
nil, // 11: protos.BattleColliderInfo.StrToVec2DListMapEntry
nil, // 12: protos.BattleColliderInfo.StrToPolygon2DListMapEntry
nil, // 13: protos.BattleColliderInfo.MeleeSkillConfigEntry
nil, // 14: protos.RoomDownsyncFrame.PlayersEntry
(*sharedprotos.Vec2D)(nil), // 15: sharedprotos.Vec2D
(*sharedprotos.Vec2DList)(nil), // 16: sharedprotos.Vec2DList
(*sharedprotos.Polygon2DList)(nil), // 17: sharedprotos.Polygon2DList
}
var file_room_downsync_frame_proto_depIdxs = []int32{
2, // 0: protos.WsReq.inputFrameUpsyncBatch:type_name -> protos.InputFrameUpsync
4, // 1: protos.WsReq.hb:type_name -> protos.HeartbeatUpsync
9, // 2: protos.WsResp.rdf:type_name -> protos.RoomDownsyncFrame
10, // 2: protos.WsResp.rdf:type_name -> protos.RoomDownsyncFrame
3, // 3: protos.WsResp.inputFrameDownsyncBatch:type_name -> protos.InputFrameDownsync
8, // 4: protos.WsResp.bciFrame:type_name -> protos.BattleColliderInfo
14, // 5: protos.MeleeBullet.moveforward:type_name -> sharedprotos.Vec2D
14, // 6: protos.MeleeBullet.hitboxSize:type_name -> sharedprotos.Vec2D
10, // 7: protos.BattleColliderInfo.strToVec2DListMap:type_name -> protos.BattleColliderInfo.StrToVec2DListMapEntry
11, // 8: protos.BattleColliderInfo.strToPolygon2DListMap:type_name -> protos.BattleColliderInfo.StrToPolygon2DListMapEntry
12, // 9: protos.BattleColliderInfo.meleeSkillConfig:type_name -> protos.BattleColliderInfo.MeleeSkillConfigEntry
13, // 10: protos.RoomDownsyncFrame.players:type_name -> protos.RoomDownsyncFrame.PlayersEntry
7, // 11: protos.RoomDownsyncFrame.meleeBullets:type_name -> protos.MeleeBullet
15, // 12: protos.BattleColliderInfo.StrToVec2DListMapEntry.value:type_name -> sharedprotos.Vec2DList
16, // 13: protos.BattleColliderInfo.StrToPolygon2DListMapEntry.value:type_name -> sharedprotos.Polygon2DList
7, // 14: protos.BattleColliderInfo.MeleeSkillConfigEntry.value:type_name -> protos.MeleeBullet
0, // 15: protos.RoomDownsyncFrame.PlayersEntry.value:type_name -> protos.PlayerDownsync
16, // [16:16] is the sub-list for method output_type
16, // [16:16] is the sub-list for method input_type
16, // [16:16] is the sub-list for extension type_name
16, // [16:16] is the sub-list for extension extendee
0, // [0:16] is the sub-list for field type_name
9, // 4: protos.WsResp.bciFrame:type_name -> protos.BattleColliderInfo
3, // 5: protos.InputsBufferSnapshot.toSendInputFrameDownsyncs:type_name -> protos.InputFrameDownsync
15, // 6: protos.MeleeBullet.moveforward:type_name -> sharedprotos.Vec2D
15, // 7: protos.MeleeBullet.hitboxSize:type_name -> sharedprotos.Vec2D
11, // 8: protos.BattleColliderInfo.strToVec2DListMap:type_name -> protos.BattleColliderInfo.StrToVec2DListMapEntry
12, // 9: protos.BattleColliderInfo.strToPolygon2DListMap:type_name -> protos.BattleColliderInfo.StrToPolygon2DListMapEntry
13, // 10: protos.BattleColliderInfo.meleeSkillConfig:type_name -> protos.BattleColliderInfo.MeleeSkillConfigEntry
14, // 11: protos.RoomDownsyncFrame.players:type_name -> protos.RoomDownsyncFrame.PlayersEntry
8, // 12: protos.RoomDownsyncFrame.meleeBullets:type_name -> protos.MeleeBullet
16, // 13: protos.BattleColliderInfo.StrToVec2DListMapEntry.value:type_name -> sharedprotos.Vec2DList
17, // 14: protos.BattleColliderInfo.StrToPolygon2DListMapEntry.value:type_name -> sharedprotos.Polygon2DList
8, // 15: protos.BattleColliderInfo.MeleeSkillConfigEntry.value:type_name -> protos.MeleeBullet
0, // 16: protos.RoomDownsyncFrame.PlayersEntry.value:type_name -> protos.PlayerDownsync
17, // [17:17] is the sub-list for method output_type
17, // [17:17] is the sub-list for method input_type
17, // [17:17] is the sub-list for extension type_name
17, // [17:17] is the sub-list for extension extendee
0, // [0:17] is the sub-list for field type_name
}
func init() { file_room_downsync_frame_proto_init() }
@ -1558,7 +1635,7 @@ func file_room_downsync_frame_proto_init() {
}
}
file_room_downsync_frame_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*MeleeBullet); i {
switch v := v.(*InputsBufferSnapshot); i {
case 0:
return &v.state
case 1:
@ -1570,7 +1647,7 @@ func file_room_downsync_frame_proto_init() {
}
}
file_room_downsync_frame_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*BattleColliderInfo); i {
switch v := v.(*MeleeBullet); i {
case 0:
return &v.state
case 1:
@ -1582,6 +1659,18 @@ func file_room_downsync_frame_proto_init() {
}
}
file_room_downsync_frame_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*BattleColliderInfo); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_room_downsync_frame_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RoomDownsyncFrame); i {
case 0:
return &v.state
@ -1600,7 +1689,7 @@ func file_room_downsync_frame_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_room_downsync_frame_proto_rawDesc,
NumEnums: 0,
NumMessages: 14,
NumMessages: 15,
NumExtensions: 0,
NumServices: 0,
},

View File

@ -68,6 +68,12 @@ message WsResp {
BattleColliderInfo bciFrame = 6;
}
message InputsBufferSnapshot {
int32 refRenderFrameId = 1;
uint64 unconfirmedMask = 2;
repeated InputFrameDownsync toSendInputFrameDownsyncs = 3;
}
message MeleeBullet {
// Jargon reference https://www.thegamer.com/fighting-games-frame-data-explained/
// ALL lengths are in world coordinate

View File

@ -440,7 +440,7 @@
"array": [
0,
0,
210.43753679824133,
210.14647688706773,
0,
0,
0,

View File

@ -3553,6 +3553,292 @@ $root.protos = (function() {
return WsResp;
})();
protos.InputsBufferSnapshot = (function() {
/**
* Properties of an InputsBufferSnapshot.
* @memberof protos
* @interface IInputsBufferSnapshot
* @property {number|null} [refRenderFrameId] InputsBufferSnapshot refRenderFrameId
* @property {number|Long|null} [unconfirmedMask] InputsBufferSnapshot unconfirmedMask
* @property {Array.<protos.InputFrameDownsync>|null} [toSendInputFrameDownsyncs] InputsBufferSnapshot toSendInputFrameDownsyncs
*/
/**
* Constructs a new InputsBufferSnapshot.
* @memberof protos
* @classdesc Represents an InputsBufferSnapshot.
* @implements IInputsBufferSnapshot
* @constructor
* @param {protos.IInputsBufferSnapshot=} [properties] Properties to set
*/
function InputsBufferSnapshot(properties) {
this.toSendInputFrameDownsyncs = [];
if (properties)
for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
if (properties[keys[i]] != null)
this[keys[i]] = properties[keys[i]];
}
/**
* InputsBufferSnapshot refRenderFrameId.
* @member {number} refRenderFrameId
* @memberof protos.InputsBufferSnapshot
* @instance
*/
InputsBufferSnapshot.prototype.refRenderFrameId = 0;
/**
* InputsBufferSnapshot unconfirmedMask.
* @member {number|Long} unconfirmedMask
* @memberof protos.InputsBufferSnapshot
* @instance
*/
InputsBufferSnapshot.prototype.unconfirmedMask = $util.Long ? $util.Long.fromBits(0,0,true) : 0;
/**
* InputsBufferSnapshot toSendInputFrameDownsyncs.
* @member {Array.<protos.InputFrameDownsync>} toSendInputFrameDownsyncs
* @memberof protos.InputsBufferSnapshot
* @instance
*/
InputsBufferSnapshot.prototype.toSendInputFrameDownsyncs = $util.emptyArray;
/**
* Creates a new InputsBufferSnapshot instance using the specified properties.
* @function create
* @memberof protos.InputsBufferSnapshot
* @static
* @param {protos.IInputsBufferSnapshot=} [properties] Properties to set
* @returns {protos.InputsBufferSnapshot} InputsBufferSnapshot instance
*/
InputsBufferSnapshot.create = function create(properties) {
return new InputsBufferSnapshot(properties);
};
/**
* Encodes the specified InputsBufferSnapshot message. Does not implicitly {@link protos.InputsBufferSnapshot.verify|verify} messages.
* @function encode
* @memberof protos.InputsBufferSnapshot
* @static
* @param {protos.InputsBufferSnapshot} message InputsBufferSnapshot message or plain object to encode
* @param {$protobuf.Writer} [writer] Writer to encode to
* @returns {$protobuf.Writer} Writer
*/
InputsBufferSnapshot.encode = function encode(message, writer) {
if (!writer)
writer = $Writer.create();
if (message.refRenderFrameId != null && Object.hasOwnProperty.call(message, "refRenderFrameId"))
writer.uint32(/* id 1, wireType 0 =*/8).int32(message.refRenderFrameId);
if (message.unconfirmedMask != null && Object.hasOwnProperty.call(message, "unconfirmedMask"))
writer.uint32(/* id 2, wireType 0 =*/16).uint64(message.unconfirmedMask);
if (message.toSendInputFrameDownsyncs != null && message.toSendInputFrameDownsyncs.length)
for (var i = 0; i < message.toSendInputFrameDownsyncs.length; ++i)
$root.protos.InputFrameDownsync.encode(message.toSendInputFrameDownsyncs[i], writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim();
return writer;
};
/**
* Encodes the specified InputsBufferSnapshot message, length delimited. Does not implicitly {@link protos.InputsBufferSnapshot.verify|verify} messages.
* @function encodeDelimited
* @memberof protos.InputsBufferSnapshot
* @static
* @param {protos.InputsBufferSnapshot} message InputsBufferSnapshot message or plain object to encode
* @param {$protobuf.Writer} [writer] Writer to encode to
* @returns {$protobuf.Writer} Writer
*/
InputsBufferSnapshot.encodeDelimited = function encodeDelimited(message, writer) {
return this.encode(message, writer).ldelim();
};
/**
* Decodes an InputsBufferSnapshot message from the specified reader or buffer.
* @function decode
* @memberof protos.InputsBufferSnapshot
* @static
* @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
* @param {number} [length] Message length if known beforehand
* @returns {protos.InputsBufferSnapshot} InputsBufferSnapshot
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
InputsBufferSnapshot.decode = function decode(reader, length) {
if (!(reader instanceof $Reader))
reader = $Reader.create(reader);
var end = length === undefined ? reader.len : reader.pos + length, message = new $root.protos.InputsBufferSnapshot();
while (reader.pos < end) {
var tag = reader.uint32();
switch (tag >>> 3) {
case 1: {
message.refRenderFrameId = reader.int32();
break;
}
case 2: {
message.unconfirmedMask = reader.uint64();
break;
}
case 3: {
if (!(message.toSendInputFrameDownsyncs && message.toSendInputFrameDownsyncs.length))
message.toSendInputFrameDownsyncs = [];
message.toSendInputFrameDownsyncs.push($root.protos.InputFrameDownsync.decode(reader, reader.uint32()));
break;
}
default:
reader.skipType(tag & 7);
break;
}
}
return message;
};
/**
* Decodes an InputsBufferSnapshot message from the specified reader or buffer, length delimited.
* @function decodeDelimited
* @memberof protos.InputsBufferSnapshot
* @static
* @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
* @returns {protos.InputsBufferSnapshot} InputsBufferSnapshot
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
InputsBufferSnapshot.decodeDelimited = function decodeDelimited(reader) {
if (!(reader instanceof $Reader))
reader = new $Reader(reader);
return this.decode(reader, reader.uint32());
};
/**
* Verifies an InputsBufferSnapshot message.
* @function verify
* @memberof protos.InputsBufferSnapshot
* @static
* @param {Object.<string,*>} message Plain object to verify
* @returns {string|null} `null` if valid, otherwise the reason why it is not
*/
InputsBufferSnapshot.verify = function verify(message) {
if (typeof message !== "object" || message === null)
return "object expected";
if (message.refRenderFrameId != null && message.hasOwnProperty("refRenderFrameId"))
if (!$util.isInteger(message.refRenderFrameId))
return "refRenderFrameId: integer expected";
if (message.unconfirmedMask != null && message.hasOwnProperty("unconfirmedMask"))
if (!$util.isInteger(message.unconfirmedMask) && !(message.unconfirmedMask && $util.isInteger(message.unconfirmedMask.low) && $util.isInteger(message.unconfirmedMask.high)))
return "unconfirmedMask: integer|Long expected";
if (message.toSendInputFrameDownsyncs != null && message.hasOwnProperty("toSendInputFrameDownsyncs")) {
if (!Array.isArray(message.toSendInputFrameDownsyncs))
return "toSendInputFrameDownsyncs: array expected";
for (var i = 0; i < message.toSendInputFrameDownsyncs.length; ++i) {
var error = $root.protos.InputFrameDownsync.verify(message.toSendInputFrameDownsyncs[i]);
if (error)
return "toSendInputFrameDownsyncs." + error;
}
}
return null;
};
/**
* Creates an InputsBufferSnapshot message from a plain object. Also converts values to their respective internal types.
* @function fromObject
* @memberof protos.InputsBufferSnapshot
* @static
* @param {Object.<string,*>} object Plain object
* @returns {protos.InputsBufferSnapshot} InputsBufferSnapshot
*/
InputsBufferSnapshot.fromObject = function fromObject(object) {
if (object instanceof $root.protos.InputsBufferSnapshot)
return object;
var message = new $root.protos.InputsBufferSnapshot();
if (object.refRenderFrameId != null)
message.refRenderFrameId = object.refRenderFrameId | 0;
if (object.unconfirmedMask != null)
if ($util.Long)
(message.unconfirmedMask = $util.Long.fromValue(object.unconfirmedMask)).unsigned = true;
else if (typeof object.unconfirmedMask === "string")
message.unconfirmedMask = parseInt(object.unconfirmedMask, 10);
else if (typeof object.unconfirmedMask === "number")
message.unconfirmedMask = object.unconfirmedMask;
else if (typeof object.unconfirmedMask === "object")
message.unconfirmedMask = new $util.LongBits(object.unconfirmedMask.low >>> 0, object.unconfirmedMask.high >>> 0).toNumber(true);
if (object.toSendInputFrameDownsyncs) {
if (!Array.isArray(object.toSendInputFrameDownsyncs))
throw TypeError(".protos.InputsBufferSnapshot.toSendInputFrameDownsyncs: array expected");
message.toSendInputFrameDownsyncs = [];
for (var i = 0; i < object.toSendInputFrameDownsyncs.length; ++i) {
if (typeof object.toSendInputFrameDownsyncs[i] !== "object")
throw TypeError(".protos.InputsBufferSnapshot.toSendInputFrameDownsyncs: object expected");
message.toSendInputFrameDownsyncs[i] = $root.protos.InputFrameDownsync.fromObject(object.toSendInputFrameDownsyncs[i]);
}
}
return message;
};
/**
* Creates a plain object from an InputsBufferSnapshot message. Also converts values to other types if specified.
* @function toObject
* @memberof protos.InputsBufferSnapshot
* @static
* @param {protos.InputsBufferSnapshot} message InputsBufferSnapshot
* @param {$protobuf.IConversionOptions} [options] Conversion options
* @returns {Object.<string,*>} Plain object
*/
InputsBufferSnapshot.toObject = function toObject(message, options) {
if (!options)
options = {};
var object = {};
if (options.arrays || options.defaults)
object.toSendInputFrameDownsyncs = [];
if (options.defaults) {
object.refRenderFrameId = 0;
if ($util.Long) {
var long = new $util.Long(0, 0, true);
object.unconfirmedMask = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long;
} else
object.unconfirmedMask = options.longs === String ? "0" : 0;
}
if (message.refRenderFrameId != null && message.hasOwnProperty("refRenderFrameId"))
object.refRenderFrameId = message.refRenderFrameId;
if (message.unconfirmedMask != null && message.hasOwnProperty("unconfirmedMask"))
if (typeof message.unconfirmedMask === "number")
object.unconfirmedMask = options.longs === String ? String(message.unconfirmedMask) : message.unconfirmedMask;
else
object.unconfirmedMask = options.longs === String ? $util.Long.prototype.toString.call(message.unconfirmedMask) : options.longs === Number ? new $util.LongBits(message.unconfirmedMask.low >>> 0, message.unconfirmedMask.high >>> 0).toNumber(true) : message.unconfirmedMask;
if (message.toSendInputFrameDownsyncs && message.toSendInputFrameDownsyncs.length) {
object.toSendInputFrameDownsyncs = [];
for (var j = 0; j < message.toSendInputFrameDownsyncs.length; ++j)
object.toSendInputFrameDownsyncs[j] = $root.protos.InputFrameDownsync.toObject(message.toSendInputFrameDownsyncs[j], options);
}
return object;
};
/**
* Converts this InputsBufferSnapshot to JSON.
* @function toJSON
* @memberof protos.InputsBufferSnapshot
* @instance
* @returns {Object.<string,*>} JSON object
*/
InputsBufferSnapshot.prototype.toJSON = function toJSON() {
return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
};
/**
* Gets the default type url for InputsBufferSnapshot
* @function getTypeUrl
* @memberof protos.InputsBufferSnapshot
* @static
* @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
* @returns {string} The default type url
*/
InputsBufferSnapshot.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
if (typeUrlPrefix === undefined) {
typeUrlPrefix = "type.googleapis.com";
}
return typeUrlPrefix + "/protos.InputsBufferSnapshot";
};
return InputsBufferSnapshot;
})();
protos.MeleeBullet = (function() {
/**