mirror of
https://github.com/genxium/DelayNoMore
synced 2025-10-17 12:36:46 +00:00
Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
858eba5243 | ||
|
d113cffc7d | ||
|
6af9a14be5 | ||
|
e3fe773634 | ||
|
17cac19c62 | ||
|
26bdd41285 | ||
|
6bf70463fa | ||
|
e3d844abad |
@@ -13,6 +13,7 @@ import (
|
|||||||
type PlayerBattleState struct {
|
type PlayerBattleState struct {
|
||||||
ADDED_PENDING_BATTLE_COLLIDER_ACK int32
|
ADDED_PENDING_BATTLE_COLLIDER_ACK int32
|
||||||
READDED_PENDING_BATTLE_COLLIDER_ACK int32
|
READDED_PENDING_BATTLE_COLLIDER_ACK int32
|
||||||
|
READDED_BATTLE_COLLIDER_ACKED int32
|
||||||
ACTIVE int32
|
ACTIVE int32
|
||||||
DISCONNECTED int32
|
DISCONNECTED int32
|
||||||
LOST int32
|
LOST int32
|
||||||
@@ -26,11 +27,12 @@ func InitPlayerBattleStateIns() {
|
|||||||
PlayerBattleStateIns = PlayerBattleState{
|
PlayerBattleStateIns = PlayerBattleState{
|
||||||
ADDED_PENDING_BATTLE_COLLIDER_ACK: 0,
|
ADDED_PENDING_BATTLE_COLLIDER_ACK: 0,
|
||||||
READDED_PENDING_BATTLE_COLLIDER_ACK: 1,
|
READDED_PENDING_BATTLE_COLLIDER_ACK: 1,
|
||||||
ACTIVE: 2,
|
READDED_BATTLE_COLLIDER_ACKED: 2,
|
||||||
DISCONNECTED: 3,
|
ACTIVE: 3,
|
||||||
LOST: 4,
|
DISCONNECTED: 4,
|
||||||
EXPELLED_DURING_GAME: 5,
|
LOST: 5,
|
||||||
EXPELLED_IN_DISMISSAL: 6,
|
EXPELLED_DURING_GAME: 6,
|
||||||
|
EXPELLED_IN_DISMISSAL: 7,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,10 +1,5 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
|
||||||
. "battle_srv/protos"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
type RingBuffer struct {
|
type RingBuffer struct {
|
||||||
Ed int32 // write index, open index
|
Ed int32 // write index, open index
|
||||||
St int32 // read index, closed index
|
St int32 // read index, closed index
|
||||||
@@ -83,42 +78,3 @@ func (rb *RingBuffer) GetByFrameId(frameId int32) interface{} {
|
|||||||
}
|
}
|
||||||
return rb.GetByOffset(frameId - rb.StFrameId)
|
return rb.GetByOffset(frameId - rb.StFrameId)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rb *RingBuffer) cloneInputFrameDownsyncsByFrameIdRange(stFrameId, edFrameId int32, mux *sync.Mutex) (int32, []*InputFrameDownsync) {
|
|
||||||
dst := make([]*InputFrameDownsync, 0, rb.Cnt)
|
|
||||||
if nil != mux {
|
|
||||||
mux.Lock()
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
mux.Unlock()
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
prevFrameFound := true
|
|
||||||
j := stFrameId
|
|
||||||
for j < edFrameId {
|
|
||||||
tmp := rb.GetByFrameId(j)
|
|
||||||
if nil == tmp {
|
|
||||||
if false == prevFrameFound {
|
|
||||||
// The "id"s are always consecutive
|
|
||||||
break
|
|
||||||
} else {
|
|
||||||
prevFrameFound = false
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
foo := tmp.(*InputFrameDownsync)
|
|
||||||
bar := &InputFrameDownsync{
|
|
||||||
InputFrameId: foo.InputFrameId,
|
|
||||||
InputList: make([]uint64, len(foo.InputList)),
|
|
||||||
ConfirmedList: foo.ConfirmedList,
|
|
||||||
}
|
|
||||||
for i, input := range foo.InputList {
|
|
||||||
bar.InputList[i] = input
|
|
||||||
}
|
|
||||||
dst = append(dst, bar)
|
|
||||||
j++
|
|
||||||
}
|
|
||||||
|
|
||||||
return j, dst
|
|
||||||
}
|
|
||||||
|
@@ -147,6 +147,7 @@ type Room struct {
|
|||||||
* Moreover, during the invocation of `PlayerSignalToCloseDict`, the `Player` instance is supposed to be deallocated (though not synchronously).
|
* Moreover, during the invocation of `PlayerSignalToCloseDict`, the `Player` instance is supposed to be deallocated (though not synchronously).
|
||||||
*/
|
*/
|
||||||
PlayerDownsyncSessionDict map[int32]*websocket.Conn
|
PlayerDownsyncSessionDict map[int32]*websocket.Conn
|
||||||
|
PlayerDownsyncChanDict map[int32](chan InputsBufferSnapshot)
|
||||||
PlayerSignalToCloseDict map[int32]SignalToCloseConnCbType
|
PlayerSignalToCloseDict map[int32]SignalToCloseConnCbType
|
||||||
Score float32
|
Score float32
|
||||||
State int32
|
State int32
|
||||||
@@ -157,8 +158,8 @@ type Room struct {
|
|||||||
DismissalWaitGroup sync.WaitGroup
|
DismissalWaitGroup sync.WaitGroup
|
||||||
Barriers map[int32]*Barrier
|
Barriers map[int32]*Barrier
|
||||||
InputsBuffer *RingBuffer // Indices are STRICTLY consecutive
|
InputsBuffer *RingBuffer // Indices are STRICTLY consecutive
|
||||||
InputsBufferLock sync.Mutex
|
InputsBufferLock sync.Mutex // Guards [InputsBuffer, LastAllConfirmedInputFrameId, LastAllConfirmedInputList, LastAllConfirmedInputFrameIdWithChange]
|
||||||
RenderFrameBuffer *RingBuffer
|
RenderFrameBuffer *RingBuffer // Indices are STRICTLY consecutive
|
||||||
LastAllConfirmedInputFrameId int32
|
LastAllConfirmedInputFrameId int32
|
||||||
LastAllConfirmedInputFrameIdWithChange int32
|
LastAllConfirmedInputFrameIdWithChange int32
|
||||||
LastAllConfirmedInputList []uint64
|
LastAllConfirmedInputList []uint64
|
||||||
@@ -325,7 +326,9 @@ func (pR *Room) ChooseStage() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (pR *Room) ConvertToInputFrameId(renderFrameId int32, inputDelayFrames int32) int32 {
|
func (pR *Room) ConvertToInputFrameId(renderFrameId int32, inputDelayFrames int32) int32 {
|
||||||
// Specifically when "renderFrameId < inputDelayFrames", the result is 0.
|
if renderFrameId < inputDelayFrames {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
return ((renderFrameId - inputDelayFrames) >> pR.InputScaleFrames)
|
return ((renderFrameId - inputDelayFrames) >> pR.InputScaleFrames)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,7 +345,7 @@ func (pR *Room) ConvertToLastUsedRenderFrameId(inputFrameId int32, inputDelayFra
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (pR *Room) RenderFrameBufferString() string {
|
func (pR *Room) RenderFrameBufferString() string {
|
||||||
return fmt.Sprintf("{renderFrameId: %d, stRenderFrameId: %d, edRenderFrameId: %d, lastAllConfirmedRenderFrameId: %d}", pR.RenderFrameId, pR.RenderFrameBuffer.StFrameId, pR.RenderFrameBuffer.EdFrameId, pR.CurDynamicsRenderFrameId)
|
return fmt.Sprintf("{renderFrameId: %d, stRenderFrameId: %d, edRenderFrameId: %d, curDynamicsRenderFrameId: %d}", pR.RenderFrameId, pR.RenderFrameBuffer.StFrameId, pR.RenderFrameBuffer.EdFrameId, pR.CurDynamicsRenderFrameId)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pR *Room) InputsBufferString(allDetails bool) string {
|
func (pR *Room) InputsBufferString(allDetails bool) string {
|
||||||
@@ -350,7 +353,7 @@ func (pR *Room) InputsBufferString(allDetails bool) string {
|
|||||||
// Appending of the array of strings can be very SLOW due to on-demand heap allocation! Use this printing with caution.
|
// Appending of the array of strings can be very SLOW due to on-demand heap allocation! Use this printing with caution.
|
||||||
s := make([]string, 0)
|
s := make([]string, 0)
|
||||||
s = append(s, fmt.Sprintf("{renderFrameId: %v, stInputFrameId: %v, edInputFrameId: %v, lastAllConfirmedInputFrameIdWithChange: %v, lastAllConfirmedInputFrameId: %v}", pR.RenderFrameId, pR.InputsBuffer.StFrameId, pR.InputsBuffer.EdFrameId, pR.LastAllConfirmedInputFrameIdWithChange, pR.LastAllConfirmedInputFrameId))
|
s = append(s, fmt.Sprintf("{renderFrameId: %v, stInputFrameId: %v, edInputFrameId: %v, lastAllConfirmedInputFrameIdWithChange: %v, lastAllConfirmedInputFrameId: %v}", pR.RenderFrameId, pR.InputsBuffer.StFrameId, pR.InputsBuffer.EdFrameId, pR.LastAllConfirmedInputFrameIdWithChange, pR.LastAllConfirmedInputFrameId))
|
||||||
for playerId, player := range pR.Players {
|
for playerId, player := range pR.PlayersArr {
|
||||||
s = append(s, fmt.Sprintf("{playerId: %v, ackingFrameId: %v, ackingInputFrameId: %v, lastSentInputFrameId: %v}", playerId, player.AckingFrameId, player.AckingInputFrameId, player.LastSentInputFrameId))
|
s = append(s, fmt.Sprintf("{playerId: %v, ackingFrameId: %v, ackingInputFrameId: %v, lastSentInputFrameId: %v}", playerId, player.AckingFrameId, player.AckingInputFrameId, player.LastSentInputFrameId))
|
||||||
}
|
}
|
||||||
for i := pR.InputsBuffer.StFrameId; i < pR.InputsBuffer.EdFrameId; i++ {
|
for i := pR.InputsBuffer.StFrameId; i < pR.InputsBuffer.EdFrameId; i++ {
|
||||||
@@ -410,13 +413,13 @@ func (pR *Room) StartBattle() {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
pR.LastRenderFrameIdTriggeredAt = utils.UnixtimeNano()
|
pR.LastRenderFrameIdTriggeredAt = utils.UnixtimeNano()
|
||||||
|
battleStartedAt := utils.UnixtimeNano()
|
||||||
Logger.Info("The `battleMainLoop` is started for:", zap.Any("roomId", pR.Id))
|
Logger.Info("The `battleMainLoop` is started for:", zap.Any("roomId", pR.Id))
|
||||||
for {
|
for {
|
||||||
stCalculation := utils.UnixtimeNano()
|
stCalculation := utils.UnixtimeNano()
|
||||||
elapsedNanosSinceLastFrameIdTriggered := stCalculation - pR.LastRenderFrameIdTriggeredAt
|
elapsedNanosSinceLastFrameIdTriggered := stCalculation - pR.LastRenderFrameIdTriggeredAt
|
||||||
if elapsedNanosSinceLastFrameIdTriggered < pR.RollbackEstimatedDtNanos {
|
if elapsedNanosSinceLastFrameIdTriggered < pR.RollbackEstimatedDtNanos {
|
||||||
Logger.Debug(fmt.Sprintf("renderFrameId=%v@roomId=%v: Is backend running too fast? elapsedNanosSinceLastFrameIdTriggered=%v", pR.RenderFrameId, pR.Id, elapsedNanosSinceLastFrameIdTriggered))
|
Logger.Warn(fmt.Sprintf("renderFrameId=%v@roomId=%v: Is backend running too fast? elapsedNanosSinceLastFrameIdTriggered=%v", pR.RenderFrameId, pR.Id, elapsedNanosSinceLastFrameIdTriggered))
|
||||||
}
|
}
|
||||||
|
|
||||||
if pR.RenderFrameId > pR.BattleDurationFrames {
|
if pR.RenderFrameId > pR.BattleDurationFrames {
|
||||||
@@ -428,7 +431,8 @@ func (pR *Room) StartBattle() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if 0 == pR.RenderFrameId {
|
if 0 == pR.RenderFrameId {
|
||||||
for playerId, player := range pR.Players {
|
for _, player := range pR.PlayersArr {
|
||||||
|
playerId := player.Id
|
||||||
thatPlayerBattleState := atomic.LoadInt32(&(player.BattleState)) // Might be changed in "OnPlayerDisconnected/OnPlayerLost" from other threads
|
thatPlayerBattleState := atomic.LoadInt32(&(player.BattleState)) // Might be changed in "OnPlayerDisconnected/OnPlayerLost" from other threads
|
||||||
// [WARNING] DON'T try to send any message to an inactive player!
|
// [WARNING] DON'T try to send any message to an inactive player!
|
||||||
switch thatPlayerBattleState {
|
switch thatPlayerBattleState {
|
||||||
@@ -439,51 +443,83 @@ func (pR *Room) StartBattle() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
kickoffFrame := pR.RenderFrameBuffer.GetByFrameId(0).(*RoomDownsyncFrame)
|
kickoffFrame := pR.RenderFrameBuffer.GetByFrameId(0).(*RoomDownsyncFrame)
|
||||||
pR.sendSafely(kickoffFrame, nil, DOWNSYNC_MSG_ACT_BATTLE_START, playerId)
|
pR.sendSafely(kickoffFrame, nil, DOWNSYNC_MSG_ACT_BATTLE_START, playerId, true)
|
||||||
}
|
}
|
||||||
Logger.Info(fmt.Sprintf("In `battleMainLoop` for roomId=%v sent out kickoffFrame", pR.Id))
|
Logger.Info(fmt.Sprintf("In `battleMainLoop` for roomId=%v sent out kickoffFrame", pR.Id))
|
||||||
}
|
}
|
||||||
|
|
||||||
dynamicsDuration := int64(0)
|
/*
|
||||||
unconfirmedMask := uint64(0)
|
[WARNING]
|
||||||
|
Golang "time.Sleep" is known to be taking longer than specified time to wake up at millisecond granularity, as discussed in https://github.com/golang/go/issues/44343
|
||||||
|
However, we assume that while "time.Sleep(16.67 ms)" might wake up after ~30ms, it still only covers at most 1 inputFrame generation.
|
||||||
|
*/
|
||||||
|
totalElapsedNanos := utils.UnixtimeNano() - battleStartedAt
|
||||||
|
nextRenderFrameId := int32((totalElapsedNanos + pR.dilutedRollbackEstimatedDtNanos - 1) / pR.dilutedRollbackEstimatedDtNanos) // fast ceiling
|
||||||
|
toSleepNanos := int64(0)
|
||||||
|
if nextRenderFrameId > pR.RenderFrameId {
|
||||||
|
prevRenderFrameId := pR.RenderFrameId
|
||||||
|
pR.RenderFrameId = nextRenderFrameId
|
||||||
|
|
||||||
// Prefab and buffer backend inputFrameDownsync
|
dynamicsDuration := int64(0)
|
||||||
if pR.BackendDynamicsEnabled {
|
|
||||||
if pR.shouldPrefabInputFrameDownsync(pR.RenderFrameId) {
|
// Prefab and buffer backend inputFrameDownsync
|
||||||
noDelayInputFrameId := pR.ConvertToInputFrameId(pR.RenderFrameId, 0)
|
if pR.BackendDynamicsEnabled {
|
||||||
if existingInputFrame := pR.InputsBuffer.GetByFrameId(noDelayInputFrameId); nil == existingInputFrame {
|
pR.doBattleMainLoopPerTickBackendDynamicsWithProperLocking(prevRenderFrameId, &dynamicsDuration)
|
||||||
pR.prefabInputFrameDownsync(noDelayInputFrameId, true)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
pR.LastRenderFrameIdTriggeredAt = utils.UnixtimeNano()
|
||||||
unconfirmedMask = pR.forceConfirmationIfApplicable()
|
|
||||||
|
|
||||||
if 0 <= pR.LastAllConfirmedInputFrameId {
|
elapsedInCalculation := (utils.UnixtimeNano() - stCalculation)
|
||||||
dynamicsStartedAt := utils.UnixtimeNano()
|
toSleepNanos = pR.dilutedRollbackEstimatedDtNanos - elapsedInCalculation // don't sleep if "nextRenderFrame == pR.RenderFrameId"
|
||||||
// Apply "all-confirmed inputFrames" to move forward "pR.CurDynamicsRenderFrameId"
|
if elapsedInCalculation > pR.RollbackEstimatedDtNanos {
|
||||||
nextDynamicsRenderFrameId := pR.ConvertToLastUsedRenderFrameId(pR.LastAllConfirmedInputFrameId, pR.InputDelayFrames)
|
Logger.Warn(fmt.Sprintf("SLOW FRAME! Elapsed time statistics: roomId=%v, room.RenderFrameId=%v, elapsedInCalculation=%v ns, dynamicsDuration=%v ns, RollbackEstimatedDtNanos=%v, dilutedRollbackEstimatedDtNanos=%v", pR.Id, pR.RenderFrameId, elapsedInCalculation, dynamicsDuration, pR.RollbackEstimatedDtNanos, pR.dilutedRollbackEstimatedDtNanos))
|
||||||
Logger.Debug(fmt.Sprintf("roomId=%v, room.RenderFrameId=%v, room.CurDynamicsRenderFrameId=%v, LastAllConfirmedInputFrameId=%v, InputDelayFrames=%v, nextDynamicsRenderFrameId=%v", pR.Id, pR.RenderFrameId, pR.CurDynamicsRenderFrameId, pR.LastAllConfirmedInputFrameId, pR.InputDelayFrames, nextDynamicsRenderFrameId))
|
|
||||||
pR.applyInputFrameDownsyncDynamics(pR.CurDynamicsRenderFrameId, nextDynamicsRenderFrameId, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY)
|
|
||||||
dynamicsDuration = utils.UnixtimeNano() - dynamicsStartedAt
|
|
||||||
}
|
|
||||||
if 0 < unconfirmedMask {
|
|
||||||
Logger.Debug(fmt.Sprintf("roomId=%v, room.RenderFrameId=%v, room.CurDynamicsRenderFrameId=%v, room.LastAllConfirmedInputFrameId=%v, unconfirmedMask=%v", pR.Id, pR.RenderFrameId, pR.CurDynamicsRenderFrameId, pR.LastAllConfirmedInputFrameId, unconfirmedMask))
|
|
||||||
// Otherwise no need to downsync immediately
|
|
||||||
pR.downsyncToAllPlayers(pR.LastAllConfirmedInputFrameId, unconfirmedMask, false)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pR.RenderFrameId++
|
time.Sleep(time.Duration(toSleepNanos))
|
||||||
pR.LastRenderFrameIdTriggeredAt = utils.UnixtimeNano()
|
|
||||||
elapsedInCalculation := (pR.LastRenderFrameIdTriggeredAt - stCalculation)
|
|
||||||
if elapsedInCalculation > pR.RollbackEstimatedDtNanos {
|
|
||||||
Logger.Warn(fmt.Sprintf("SLOW FRAME! Elapsed time statistics: roomId=%v, room.RenderFrameId=%v, elapsedInCalculation=%v ns, dynamicsDuration=%v ns, RollbackEstimatedDtNanos=%v", pR.Id, pR.RenderFrameId, elapsedInCalculation, dynamicsDuration, pR.RollbackEstimatedDtNanos))
|
|
||||||
}
|
|
||||||
time.Sleep(time.Duration(pR.dilutedRollbackEstimatedDtNanos - elapsedInCalculation))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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.onBattlePrepare(func() {
|
||||||
pR.onBattleStarted() // NOTE: Deliberately not using `defer`.
|
pR.onBattleStarted() // NOTE: Deliberately not using `defer`.
|
||||||
go battleMainLoop()
|
go battleMainLoop()
|
||||||
@@ -495,7 +531,19 @@ func (pR *Room) toDiscreteInputsBufferIndex(inputFrameId int32, joinIndex int32)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (pR *Room) OnBattleCmdReceived(pReq *WsReq) {
|
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 {
|
if swapped := atomic.CompareAndSwapInt32(&pR.State, RoomBattleStateIns.IN_BATTLE, RoomBattleStateIns.IN_BATTLE); !swapped {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -515,44 +563,22 @@ func (pR *Room) OnBattleCmdReceived(pReq *WsReq) {
|
|||||||
atomic.StoreInt32(&(player.AckingFrameId), ackingFrameId)
|
atomic.StoreInt32(&(player.AckingFrameId), ackingFrameId)
|
||||||
atomic.StoreInt32(&(player.AckingInputFrameId), ackingInputFrameId)
|
atomic.StoreInt32(&(player.AckingInputFrameId), ackingInputFrameId)
|
||||||
|
|
||||||
Logger.Debug(fmt.Sprintf("InputsBufferLock about to lock: roomId=%v", pR.Id))
|
Logger.Debug(fmt.Sprintf("OnBattleCmdReceived-InputsBufferLock about to lock: roomId=%v, fromPlayerId=%v", pR.Id, playerId))
|
||||||
pR.InputsBufferLock.Lock()
|
pR.InputsBufferLock.Lock()
|
||||||
Logger.Debug(fmt.Sprintf("InputsBufferLock locked: roomId=%v", pR.Id))
|
Logger.Debug(fmt.Sprintf("OnBattleCmdReceived-InputsBufferLock locked: roomId=%v, fromPlayerId=%v", pR.Id, playerId))
|
||||||
defer func() {
|
defer func() {
|
||||||
pR.InputsBufferLock.Unlock()
|
pR.InputsBufferLock.Unlock()
|
||||||
Logger.Debug(fmt.Sprintf("InputsBufferLock unlocked: roomId=%v", pR.Id))
|
Logger.Debug(fmt.Sprintf("OnBattleCmdReceived-InputsBufferLock unlocked: roomId=%v, fromPlayerId=%v", pR.Id, playerId))
|
||||||
}()
|
}()
|
||||||
for _, inputFrameUpsync := range inputFrameUpsyncBatch {
|
|
||||||
clientInputFrameId := inputFrameUpsync.InputFrameId
|
inputsBufferSnapshot := pR.markConfirmationIfApplicable(inputFrameUpsyncBatch, playerId, player)
|
||||||
if clientInputFrameId < pR.InputsBuffer.StFrameId {
|
if nil != inputsBufferSnapshot {
|
||||||
// The updates to "pR.InputsBuffer.StFrameId" is monotonically increasing, thus if "clientInputFrameId < pR.InputsBuffer.StFrameId" at any moment of time, it is obsolete in the future.
|
pR.downsyncToAllPlayers(inputsBufferSnapshot)
|
||||||
Logger.Warn(fmt.Sprintf("Omitting obsolete inputFrameUpsync: roomId=%v, playerId=%v, clientInputFrameId=%v, InputsBuffer=%v", pR.Id, playerId, clientInputFrameId, pR.InputsBufferString(false)))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if clientInputFrameId > pR.InputsBuffer.EdFrameId {
|
|
||||||
Logger.Warn(fmt.Sprintf("Dropping too advanced inputFrameUpsync: roomId=%v, playerId=%v, clientInputFrameId=%v, InputsBuffer=%v; is this player cheating?", pR.Id, playerId, clientInputFrameId, pR.InputsBufferString(false)))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
var targetInputFrameDownsync *InputFrameDownsync = nil
|
|
||||||
if clientInputFrameId == pR.InputsBuffer.EdFrameId {
|
|
||||||
targetInputFrameDownsync = pR.prefabInputFrameDownsync(clientInputFrameId, false)
|
|
||||||
Logger.Debug(fmt.Sprintf("OnBattleCmdReceived-Prefabbed new inputFrameDownsync from inputFrameUpsync: roomId=%v, playerId=%v, clientInputFrameId=%v, InputsBuffer=%v", pR.Id, playerId, clientInputFrameId, pR.InputsBufferString(false)))
|
|
||||||
} else {
|
|
||||||
targetInputFrameDownsync = pR.InputsBuffer.GetByFrameId(clientInputFrameId).(*InputFrameDownsync)
|
|
||||||
Logger.Debug(fmt.Sprintf("OnBattleCmdReceived-stuffing inputFrameDownsync from inputFrameUpsync: roomId=%v, playerId=%v, clientInputFrameId=%v, InputsBuffer=%v", pR.Id, playerId, clientInputFrameId, pR.InputsBufferString(false)))
|
|
||||||
}
|
|
||||||
targetInputFrameDownsync.InputList[player.JoinIndex-1] = inputFrameUpsync.Encoded
|
|
||||||
targetInputFrameDownsync.ConfirmedList |= uint64(1 << uint32(player.JoinIndex-1))
|
|
||||||
}
|
|
||||||
newAllConfirmedCount := pR.markConfirmationIfApplicable()
|
|
||||||
if 0 < newAllConfirmedCount {
|
|
||||||
// Downsync new all-confirmed inputFrames asap
|
|
||||||
unconfirmedMask := uint64(0)
|
|
||||||
pR.downsyncToAllPlayers(pR.LastAllConfirmedInputFrameId, unconfirmedMask, true)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pR *Room) onInputFrameDownsyncAllConfirmed(inputFrameDownsync *InputFrameDownsync, playerId int32) {
|
func (pR *Room) onInputFrameDownsyncAllConfirmed(inputFrameDownsync *InputFrameDownsync, playerId int32) {
|
||||||
|
// [WARNING] This function MUST BE called while "pR.InputsBufferLock" is locked!
|
||||||
inputFrameId := inputFrameDownsync.InputFrameId
|
inputFrameId := inputFrameDownsync.InputFrameId
|
||||||
if -1 == pR.LastAllConfirmedInputFrameIdWithChange || false == pR.equalInputLists(inputFrameDownsync.InputList, pR.LastAllConfirmedInputList) {
|
if -1 == pR.LastAllConfirmedInputFrameIdWithChange || false == pR.equalInputLists(inputFrameDownsync.InputList, pR.LastAllConfirmedInputList) {
|
||||||
if -1 == playerId {
|
if -1 == playerId {
|
||||||
@@ -560,9 +586,9 @@ func (pR *Room) onInputFrameDownsyncAllConfirmed(inputFrameDownsync *InputFrameD
|
|||||||
} else {
|
} else {
|
||||||
Logger.Debug(fmt.Sprintf("Key inputFrame change: roomId=%v, playerId=%v, newInputFrameId=%v, lastInputFrameId=%v, newInputList=%v, lastInputList=%v, InputsBuffer=%v", pR.Id, playerId, inputFrameId, pR.LastAllConfirmedInputFrameId, inputFrameDownsync.InputList, pR.LastAllConfirmedInputList, pR.InputsBufferString(false)))
|
Logger.Debug(fmt.Sprintf("Key inputFrame change: roomId=%v, playerId=%v, newInputFrameId=%v, lastInputFrameId=%v, newInputList=%v, lastInputList=%v, InputsBuffer=%v", pR.Id, playerId, inputFrameId, pR.LastAllConfirmedInputFrameId, inputFrameDownsync.InputList, pR.LastAllConfirmedInputList, pR.InputsBufferString(false)))
|
||||||
}
|
}
|
||||||
atomic.StoreInt32(&(pR.LastAllConfirmedInputFrameIdWithChange), inputFrameId)
|
pR.LastAllConfirmedInputFrameIdWithChange = inputFrameId
|
||||||
}
|
}
|
||||||
atomic.StoreInt32(&(pR.LastAllConfirmedInputFrameId), inputFrameId) // [WARNING] It's IMPORTANT that "pR.LastAllConfirmedInputFrameId" is NOT NECESSARILY CONSECUTIVE, i.e. if one of the players disconnects and reconnects within a considerable amount of frame delays!
|
pR.LastAllConfirmedInputFrameId = inputFrameId
|
||||||
for i, v := range inputFrameDownsync.InputList {
|
for i, v := range inputFrameDownsync.InputList {
|
||||||
// To avoid potential misuse of pointers
|
// To avoid potential misuse of pointers
|
||||||
pR.LastAllConfirmedInputList[i] = v
|
pR.LastAllConfirmedInputList[i] = v
|
||||||
@@ -599,7 +625,7 @@ func (pR *Room) StopBattleForSettlement() {
|
|||||||
Players: toPbPlayers(pR.Players, false),
|
Players: toPbPlayers(pR.Players, false),
|
||||||
CountdownNanos: -1, // TODO: Replace this magic constant!
|
CountdownNanos: -1, // TODO: Replace this magic constant!
|
||||||
}
|
}
|
||||||
pR.sendSafely(&assembledFrame, nil, DOWNSYNC_MSG_ACT_BATTLE_STOPPED, playerId)
|
pR.sendSafely(&assembledFrame, nil, DOWNSYNC_MSG_ACT_BATTLE_STOPPED, playerId, true)
|
||||||
}
|
}
|
||||||
// Note that `pR.onBattleStoppedForSettlement` will be called by `battleMainLoop`.
|
// Note that `pR.onBattleStoppedForSettlement` will be called by `battleMainLoop`.
|
||||||
}
|
}
|
||||||
@@ -628,7 +654,7 @@ func (pR *Room) onBattlePrepare(cb BattleStartCbType) {
|
|||||||
|
|
||||||
Logger.Info("Sending out frame for RoomBattleState.PREPARE:", zap.Any("battleReadyToStartFrame", battleReadyToStartFrame))
|
Logger.Info("Sending out frame for RoomBattleState.PREPARE:", zap.Any("battleReadyToStartFrame", battleReadyToStartFrame))
|
||||||
for _, player := range pR.Players {
|
for _, player := range pR.Players {
|
||||||
pR.sendSafely(battleReadyToStartFrame, nil, DOWNSYNC_MSG_ACT_BATTLE_READY_TO_START, player.Id)
|
pR.sendSafely(battleReadyToStartFrame, nil, DOWNSYNC_MSG_ACT_BATTLE_READY_TO_START, player.Id, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
battlePreparationNanos := int64(6000000000)
|
battlePreparationNanos := int64(6000000000)
|
||||||
@@ -698,6 +724,10 @@ func (pR *Room) OnDismissed() {
|
|||||||
pR.PlayersArr = make([]*Player, pR.Capacity)
|
pR.PlayersArr = make([]*Player, pR.Capacity)
|
||||||
pR.CollisionSysMap = make(map[int32]*resolv.Object)
|
pR.CollisionSysMap = make(map[int32]*resolv.Object)
|
||||||
pR.PlayerDownsyncSessionDict = make(map[int32]*websocket.Conn)
|
pR.PlayerDownsyncSessionDict = make(map[int32]*websocket.Conn)
|
||||||
|
for _, oldChan := range pR.PlayerDownsyncChanDict {
|
||||||
|
close(oldChan)
|
||||||
|
}
|
||||||
|
pR.PlayerDownsyncChanDict = make(map[int32](chan InputsBufferSnapshot))
|
||||||
pR.PlayerSignalToCloseDict = make(map[int32]SignalToCloseConnCbType)
|
pR.PlayerSignalToCloseDict = make(map[int32]SignalToCloseConnCbType)
|
||||||
pR.JoinIndexBooleanArr = make([]bool, pR.Capacity)
|
pR.JoinIndexBooleanArr = make([]bool, pR.Capacity)
|
||||||
pR.Barriers = make(map[int32]*Barrier)
|
pR.Barriers = make(map[int32]*Barrier)
|
||||||
@@ -712,13 +742,13 @@ func (pR *Room) OnDismissed() {
|
|||||||
pR.RenderFrameId = 0
|
pR.RenderFrameId = 0
|
||||||
pR.CurDynamicsRenderFrameId = 0
|
pR.CurDynamicsRenderFrameId = 0
|
||||||
pR.InputDelayFrames = 8
|
pR.InputDelayFrames = 8
|
||||||
pR.NstDelayFrames = 4
|
pR.NstDelayFrames = 8
|
||||||
pR.InputScaleFrames = uint32(2)
|
pR.InputScaleFrames = uint32(2)
|
||||||
pR.ServerFps = 60
|
pR.ServerFps = 60
|
||||||
pR.RollbackEstimatedDtMillis = 16.667 // Use fixed-and-low-precision to mitigate the inconsistent floating-point-number issue between Golang and JavaScript
|
pR.RollbackEstimatedDtMillis = 16.667 // Use fixed-and-low-precision to mitigate the inconsistent floating-point-number issue between Golang and JavaScript
|
||||||
pR.RollbackEstimatedDtNanos = 16666666 // A little smaller than the actual per frame time, just for logging FAST FRAME
|
pR.RollbackEstimatedDtNanos = 16666666 // A little smaller than the actual per frame time, just for logging FAST FRAME
|
||||||
dilutedServerFps := int64(58)
|
dilutedServerFps := float64(55.0)
|
||||||
pR.dilutedRollbackEstimatedDtNanos = pR.RollbackEstimatedDtNanos * (int64(pR.ServerFps) / dilutedServerFps)
|
pR.dilutedRollbackEstimatedDtNanos = int64(float64(pR.RollbackEstimatedDtNanos) * float64(pR.ServerFps) / dilutedServerFps)
|
||||||
pR.BattleDurationFrames = 30 * pR.ServerFps
|
pR.BattleDurationFrames = 30 * pR.ServerFps
|
||||||
pR.BattleDurationNanos = int64(pR.BattleDurationFrames) * (pR.RollbackEstimatedDtNanos + 1)
|
pR.BattleDurationNanos = int64(pR.BattleDurationFrames) * (pR.RollbackEstimatedDtNanos + 1)
|
||||||
pR.InputFrameUpsyncDelayTolerance = 2
|
pR.InputFrameUpsyncDelayTolerance = 2
|
||||||
@@ -759,7 +789,7 @@ func (pR *Room) OnDismissed() {
|
|||||||
pR.State = RoomBattleStateIns.IDLE
|
pR.State = RoomBattleStateIns.IDLE
|
||||||
pR.updateScore()
|
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) {
|
func (pR *Room) expelPlayerDuringGame(playerId int32) {
|
||||||
@@ -850,6 +880,7 @@ func (pR *Room) onPlayerLost(playerId int32) {
|
|||||||
func (pR *Room) clearPlayerNetworkSession(playerId int32) {
|
func (pR *Room) clearPlayerNetworkSession(playerId int32) {
|
||||||
if _, y := pR.PlayerDownsyncSessionDict[playerId]; y {
|
if _, y := pR.PlayerDownsyncSessionDict[playerId]; y {
|
||||||
Logger.Debug("clearPlayerNetworkSession:", zap.Any("roomId", pR.Id), zap.Any("playerId", playerId))
|
Logger.Debug("clearPlayerNetworkSession:", zap.Any("roomId", pR.Id), zap.Any("playerId", playerId))
|
||||||
|
// [WARNING] No need to close "pR.PlayerDownsyncChanDict[playerId]" immediately!
|
||||||
delete(pR.PlayerDownsyncSessionDict, playerId)
|
delete(pR.PlayerDownsyncSessionDict, playerId)
|
||||||
delete(pR.PlayerSignalToCloseDict, playerId)
|
delete(pR.PlayerSignalToCloseDict, playerId)
|
||||||
}
|
}
|
||||||
@@ -913,8 +944,10 @@ func (pR *Room) OnPlayerBattleColliderAcked(playerId int32) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shouldTryToStartBattle := true
|
||||||
Logger.Debug(fmt.Sprintf("OnPlayerBattleColliderAcked-before: roomId=%v, roomState=%v, targetPlayerId=%v, targetPlayerBattleState=%v, capacity=%v, EffectivePlayerCount=%v", pR.Id, pR.State, targetPlayer.Id, targetPlayer.BattleState, pR.Capacity, pR.EffectivePlayerCount))
|
Logger.Debug(fmt.Sprintf("OnPlayerBattleColliderAcked-before: roomId=%v, roomState=%v, targetPlayerId=%v, targetPlayerBattleState=%v, capacity=%v, EffectivePlayerCount=%v", pR.Id, pR.State, targetPlayer.Id, targetPlayer.BattleState, pR.Capacity, pR.EffectivePlayerCount))
|
||||||
switch targetPlayer.BattleState {
|
targetPlayerBattleState := atomic.LoadInt32(&(targetPlayer.BattleState))
|
||||||
|
switch targetPlayerBattleState {
|
||||||
case PlayerBattleStateIns.ADDED_PENDING_BATTLE_COLLIDER_ACK:
|
case PlayerBattleStateIns.ADDED_PENDING_BATTLE_COLLIDER_ACK:
|
||||||
playerAckedFrame := &RoomDownsyncFrame{
|
playerAckedFrame := &RoomDownsyncFrame{
|
||||||
Id: pR.RenderFrameId,
|
Id: pR.RenderFrameId,
|
||||||
@@ -922,7 +955,7 @@ func (pR *Room) OnPlayerBattleColliderAcked(playerId int32) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Broadcast normally added player info to all players in the same room
|
// Broadcast normally added player info to all players in the same room
|
||||||
for thatPlayerId, thatPlayer := range pR.Players {
|
for _, thatPlayer := range pR.Players {
|
||||||
/*
|
/*
|
||||||
[WARNING]
|
[WARNING]
|
||||||
This `playerAckedFrame` is the first ever "RoomDownsyncFrame" for every "PersistentSessionClient on the frontend", and it goes right after each "BattleColliderInfo".
|
This `playerAckedFrame` is the first ever "RoomDownsyncFrame" for every "PersistentSessionClient on the frontend", and it goes right after each "BattleColliderInfo".
|
||||||
@@ -931,42 +964,44 @@ func (pR *Room) OnPlayerBattleColliderAcked(playerId int32) bool {
|
|||||||
|
|
||||||
This function is triggered by an upsync message via WebSocket, thus downsync sending is also available by now.
|
This function is triggered by an upsync message via WebSocket, thus downsync sending is also available by now.
|
||||||
*/
|
*/
|
||||||
|
thatPlayerId := thatPlayer.Id
|
||||||
thatPlayerBattleState := atomic.LoadInt32(&(thatPlayer.BattleState))
|
thatPlayerBattleState := atomic.LoadInt32(&(thatPlayer.BattleState))
|
||||||
Logger.Debug(fmt.Sprintf("OnPlayerBattleColliderAcked-middle: roomId=%v, roomState=%v, targetPlayerId=%v, targetPlayerBattleState=%v, thatPlayerId=%v, thatPlayerBattleState=%v", pR.Id, pR.State, targetPlayer.Id, targetPlayer.BattleState, thatPlayer.Id, thatPlayerBattleState))
|
Logger.Debug(fmt.Sprintf("OnPlayerBattleColliderAcked-middle: roomId=%v, roomState=%v, targetPlayerId=%v, targetPlayerBattleState=%v, thatPlayerId=%v, thatPlayerBattleState=%v", pR.Id, pR.State, targetPlayer.Id, targetPlayer.BattleState, thatPlayer.Id, thatPlayerBattleState))
|
||||||
if thatPlayerId == targetPlayer.Id || (PlayerBattleStateIns.ADDED_PENDING_BATTLE_COLLIDER_ACK == thatPlayerBattleState || PlayerBattleStateIns.ACTIVE == thatPlayerBattleState) {
|
if thatPlayerId == targetPlayer.Id || (PlayerBattleStateIns.ADDED_PENDING_BATTLE_COLLIDER_ACK == thatPlayerBattleState || PlayerBattleStateIns.ACTIVE == thatPlayerBattleState) {
|
||||||
Logger.Debug(fmt.Sprintf("OnPlayerBattleColliderAcked-sending DOWNSYNC_MSG_ACT_PLAYER_ADDED_AND_ACKED: roomId=%v, roomState=%v, targetPlayerId=%v, targetPlayerBattleState=%v, capacity=%v, EffectivePlayerCount=%v", pR.Id, pR.State, targetPlayer.Id, targetPlayer.BattleState, pR.Capacity, pR.EffectivePlayerCount))
|
Logger.Debug(fmt.Sprintf("OnPlayerBattleColliderAcked-sending DOWNSYNC_MSG_ACT_PLAYER_ADDED_AND_ACKED: roomId=%v, roomState=%v, targetPlayerId=%v, targetPlayerBattleState=%v, capacity=%v, EffectivePlayerCount=%v", pR.Id, pR.State, targetPlayer.Id, targetPlayer.BattleState, pR.Capacity, pR.EffectivePlayerCount))
|
||||||
pR.sendSafely(playerAckedFrame, nil, DOWNSYNC_MSG_ACT_PLAYER_ADDED_AND_ACKED, thatPlayer.Id)
|
pR.sendSafely(playerAckedFrame, nil, DOWNSYNC_MSG_ACT_PLAYER_ADDED_AND_ACKED, thatPlayer.Id, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
atomic.StoreInt32(&(targetPlayer.BattleState), PlayerBattleStateIns.ACTIVE)
|
||||||
case PlayerBattleStateIns.READDED_PENDING_BATTLE_COLLIDER_ACK:
|
case PlayerBattleStateIns.READDED_PENDING_BATTLE_COLLIDER_ACK:
|
||||||
// only send resync info to the targetPlayer
|
shouldTryToStartBattle = false
|
||||||
// i.e. implies that "targetPlayer.LastSentInputFrameId == MAGIC_LAST_SENT_INPUT_FRAME_ID_READDED"
|
atomic.StoreInt32(&(targetPlayer.BattleState), PlayerBattleStateIns.READDED_BATTLE_COLLIDER_ACKED)
|
||||||
pR.downsyncToSinglePlayer(playerId, targetPlayer, pR.LastAllConfirmedInputFrameId, uint64(0), false)
|
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
targetPlayer.BattleState = PlayerBattleStateIns.ACTIVE
|
|
||||||
Logger.Debug(fmt.Sprintf("OnPlayerBattleColliderAcked-post-downsync: roomId=%v, roomState=%v, targetPlayerId=%v, targetPlayerBattleState=%v, capacity=%v, EffectivePlayerCount=%v", pR.Id, pR.State, targetPlayer.Id, targetPlayer.BattleState, pR.Capacity, pR.EffectivePlayerCount))
|
Logger.Debug(fmt.Sprintf("OnPlayerBattleColliderAcked-post-downsync: roomId=%v, roomState=%v, targetPlayerId=%v, targetPlayerBattleState=%v, capacity=%v, EffectivePlayerCount=%v", pR.Id, pR.State, targetPlayer.Id, targetPlayer.BattleState, pR.Capacity, pR.EffectivePlayerCount))
|
||||||
|
|
||||||
if pR.Capacity == int(pR.EffectivePlayerCount) {
|
if shouldTryToStartBattle {
|
||||||
allAcked := true
|
if pR.Capacity == int(pR.EffectivePlayerCount) {
|
||||||
for _, p := range pR.Players {
|
allAcked := true
|
||||||
if PlayerBattleStateIns.ACTIVE != p.BattleState {
|
for _, p := range pR.Players {
|
||||||
Logger.Warn("unexpectedly got an inactive player", zap.Any("roomId", pR.Id), zap.Any("playerId", p.Id), zap.Any("battleState", p.BattleState))
|
if PlayerBattleStateIns.ACTIVE != p.BattleState {
|
||||||
allAcked = false
|
Logger.Warn("Unexpectedly got an inactive player", zap.Any("roomId", pR.Id), zap.Any("playerId", p.Id), zap.Any("battleState", p.BattleState))
|
||||||
break
|
allAcked = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if true == allAcked {
|
||||||
|
pR.StartBattle() // WON'T run if the battle state is not in WAITING.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if true == allAcked {
|
|
||||||
pR.StartBattle() // WON'T run if the battle state is not in WAITING.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pR.updateScore()
|
pR.updateScore()
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pR *Room) sendSafely(roomDownsyncFrame *RoomDownsyncFrame, toSendInputFrameDownsyncs []*InputFrameDownsync, act int32, playerId int32) {
|
func (pR *Room) sendSafely(roomDownsyncFrame *RoomDownsyncFrame, toSendInputFrameDownsyncs []*InputFrameDownsync, act int32, playerId int32, needLockExplicitly bool) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
Logger.Error("sendSafely, recovered from: ", zap.Any("roomId", pR.Id), zap.Any("playerId", playerId), zap.Any("panic", r))
|
Logger.Error("sendSafely, recovered from: ", zap.Any("roomId", pR.Id), zap.Any("playerId", playerId), zap.Any("panic", r))
|
||||||
@@ -992,59 +1027,82 @@ func (pR *Room) sendSafely(roomDownsyncFrame *RoomDownsyncFrame, toSendInputFram
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pR *Room) shouldPrefabInputFrameDownsync(renderFrameId int32) bool {
|
func (pR *Room) shouldPrefabInputFrameDownsync(prevRenderFrameId int32, renderFrameId int32) (bool, int32) {
|
||||||
return ((renderFrameId & ((1 << pR.InputScaleFrames) - 1)) == 0)
|
for i := prevRenderFrameId + 1; i <= renderFrameId; i++ {
|
||||||
|
if (0 <= i) && (0 == (i & ((1 << pR.InputScaleFrames) - 1))) {
|
||||||
|
return true, i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, -1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pR *Room) prefabInputFrameDownsync(inputFrameId int32, lockInputsBuffer bool) *InputFrameDownsync {
|
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,
|
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,
|
- EITHER it's due to local lag and bad network,
|
||||||
- OR there's no change w.r.t. to its prev cmd.
|
- OR there's no change w.r.t. to its prev cmd.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if lockInputsBuffer {
|
|
||||||
Logger.Debug(fmt.Sprintf("prefabInputFrameDownsync-InputsBufferLock to about lock: roomId=%v", pR.Id))
|
|
||||||
pR.InputsBufferLock.Lock()
|
|
||||||
Logger.Debug(fmt.Sprintf("prefabInputFrameDownsync-InputsBufferLock locked: roomId=%v", pR.Id))
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
pR.InputsBufferLock.Unlock()
|
|
||||||
Logger.Debug(fmt.Sprintf("prefabInputFrameDownsync-InputsBufferLock unlocked: roomId=%v", pR.Id))
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
var currInputFrameDownsync *InputFrameDownsync = nil
|
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 {
|
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
|
||||||
currInputFrameDownsync = &InputFrameDownsync{
|
if nil != tmp2 {
|
||||||
InputFrameId: 0,
|
prevInputFrameDownsync := tmp2.(*InputFrameDownsync)
|
||||||
InputList: make([]uint64, pR.Capacity),
|
for i, _ := range currInputFrameDownsync.InputList {
|
||||||
ConfirmedList: uint64(0),
|
currInputFrameDownsync.InputList[i] = (prevInputFrameDownsync.InputList[i] & uint64(15)) // Don't predict attack input!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pR.InputsBuffer.Put(currInputFrameDownsync)
|
||||||
}
|
}
|
||||||
} else {
|
} 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
|
currInputFrameDownsync = tmp1.(*InputFrameDownsync)
|
||||||
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),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pR.InputsBuffer.Put(currInputFrameDownsync)
|
|
||||||
return currInputFrameDownsync
|
return currInputFrameDownsync
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pR *Room) markConfirmationIfApplicable() int {
|
func (pR *Room) markConfirmationIfApplicable(inputFrameUpsyncBatch []*InputFrameUpsync, playerId int32, player *Player) *InputsBufferSnapshot {
|
||||||
newAllConfirmedCount := 0
|
// [WARNING] This function MUST BE called while "pR.InputsBufferLock" is locked!
|
||||||
|
for _, inputFrameUpsync := range inputFrameUpsyncBatch {
|
||||||
|
clientInputFrameId := inputFrameUpsync.InputFrameId
|
||||||
|
if clientInputFrameId < pR.InputsBuffer.StFrameId {
|
||||||
|
// The updates to "pR.InputsBuffer.StFrameId" is monotonically increasing, thus if "clientInputFrameId < pR.InputsBuffer.StFrameId" at any moment of time, it is obsolete in the future.
|
||||||
|
Logger.Debug(fmt.Sprintf("Omitting obsolete inputFrameUpsync#1: roomId=%v, playerId=%v, clientInputFrameId=%v, InputsBuffer=%v", pR.Id, playerId, clientInputFrameId, pR.InputsBufferString(false)))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if clientInputFrameId < pR.LastAllConfirmedInputFrameId {
|
||||||
|
Logger.Info(fmt.Sprintf("Omitting obsolete inputFrameUpsync#2: roomId=%v, playerId=%v, clientInputFrameId=%v, InputsBuffer=%v", pR.Id, playerId, clientInputFrameId, pR.InputsBufferString(false)))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if clientInputFrameId > pR.InputsBuffer.EdFrameId {
|
||||||
|
Logger.Warn(fmt.Sprintf("Dropping too advanced inputFrameUpsync: roomId=%v, playerId=%v, clientInputFrameId=%v, InputsBuffer=%v; is this player cheating?", pR.Id, playerId, clientInputFrameId, pR.InputsBufferString(false)))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var targetInputFrameDownsync *InputFrameDownsync = nil
|
||||||
|
if clientInputFrameId == pR.InputsBuffer.EdFrameId {
|
||||||
|
targetInputFrameDownsync = pR.prefabInputFrameDownsync(clientInputFrameId)
|
||||||
|
Logger.Debug(fmt.Sprintf("OnBattleCmdReceived-Prefabbed new inputFrameDownsync from inputFrameUpsync: roomId=%v, playerId=%v, clientInputFrameId=%v, InputsBuffer=%v", pR.Id, playerId, clientInputFrameId, pR.InputsBufferString(false)))
|
||||||
|
} else {
|
||||||
|
targetInputFrameDownsync = pR.InputsBuffer.GetByFrameId(clientInputFrameId).(*InputFrameDownsync)
|
||||||
|
Logger.Debug(fmt.Sprintf("OnBattleCmdReceived-stuffing inputFrameDownsync from inputFrameUpsync: roomId=%v, playerId=%v, clientInputFrameId=%v, InputsBuffer=%v", pR.Id, playerId, clientInputFrameId, pR.InputsBufferString(false)))
|
||||||
|
}
|
||||||
|
targetInputFrameDownsync.InputList[player.JoinIndex-1] = inputFrameUpsync.Encoded
|
||||||
|
targetInputFrameDownsync.ConfirmedList |= uint64(1 << uint32(player.JoinIndex-1))
|
||||||
|
}
|
||||||
|
|
||||||
|
newAllConfirmedCount := int32(0)
|
||||||
inputFrameId1 := pR.LastAllConfirmedInputFrameId + 1
|
inputFrameId1 := pR.LastAllConfirmedInputFrameId + 1
|
||||||
totPlayerCnt := uint32(pR.Capacity)
|
totPlayerCnt := uint32(pR.Capacity)
|
||||||
allConfirmedMask := uint64((1 << totPlayerCnt) - 1)
|
allConfirmedMask := uint64((1 << totPlayerCnt) - 1)
|
||||||
@@ -1058,7 +1116,7 @@ func (pR *Room) markConfirmationIfApplicable() int {
|
|||||||
inputFrameDownsync := tmp.(*InputFrameDownsync)
|
inputFrameDownsync := tmp.(*InputFrameDownsync)
|
||||||
|
|
||||||
if allConfirmedMask != inputFrameDownsync.ConfirmedList {
|
if allConfirmedMask != inputFrameDownsync.ConfirmedList {
|
||||||
for _, player := range pR.Players {
|
for _, player := range pR.PlayersArr {
|
||||||
thatPlayerBattleState := atomic.LoadInt32(&(player.BattleState))
|
thatPlayerBattleState := atomic.LoadInt32(&(player.BattleState))
|
||||||
thatPlayerJoinMask := uint64(1 << uint32(player.JoinIndex-1))
|
thatPlayerJoinMask := uint64(1 << uint32(player.JoinIndex-1))
|
||||||
if 0 == (inputFrameDownsync.ConfirmedList & thatPlayerJoinMask) {
|
if 0 == (inputFrameDownsync.ConfirmedList & thatPlayerJoinMask) {
|
||||||
@@ -1080,37 +1138,55 @@ func (pR *Room) markConfirmationIfApplicable() int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.Debug(fmt.Sprintf("markConfirmationIfApplicable checking inputFrameId=[%v, %v) for roomId=%v, newAllConfirmedCount=%d: InputsBuffer=%v", inputFrameId1, pR.InputsBuffer.EdFrameId, pR.Id, newAllConfirmedCount, pR.InputsBufferString(false)))
|
if 0 < newAllConfirmedCount {
|
||||||
return newAllConfirmedCount
|
refRenderFrameIdIfNeeded := pR.CurDynamicsRenderFrameId - 1
|
||||||
|
/*
|
||||||
|
[WARNING]
|
||||||
|
|
||||||
|
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", this value might be smaller than (pR.LastAllConfirmedInputFrameId - newAllConfirmedCount)!
|
||||||
|
*/
|
||||||
|
snapshotStFrameId := pR.ConvertToInputFrameId(refRenderFrameIdIfNeeded, pR.InputDelayFrames)
|
||||||
|
// Duplicate downsynced inputFrameIds will be filtered out by frontend.
|
||||||
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pR *Room) forceConfirmationIfApplicable() uint64 {
|
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
|
// 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
|
||||||
|
|
||||||
renderFrameId1 := (pR.RenderFrameId - pR.NstDelayFrames) // the renderFrameId which should've been rendered on frontend
|
renderFrameId1 := (pR.RenderFrameId - pR.NstDelayFrames) // the renderFrameId which should've been rendered on frontend
|
||||||
if 0 > renderFrameId1 || !pR.shouldPrefabInputFrameDownsync(renderFrameId1) {
|
if 0 > renderFrameId1 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
ok := false
|
||||||
|
renderFrameId2 := int32(-1)
|
||||||
|
if ok, renderFrameId2 = pR.shouldPrefabInputFrameDownsync(prevRenderFrameId-pR.NstDelayFrames, renderFrameId1); !ok {
|
||||||
/*
|
/*
|
||||||
The backend "shouldPrefabInputFrameDownsync" shares the same rule as frontend "shouldGenerateInputFrameUpsync".
|
The backend "shouldPrefabInputFrameDownsync" shares the same rule as frontend "shouldGenerateInputFrameUpsync".
|
||||||
|
|
||||||
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.
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
inputFrameId2 := pR.ConvertToInputFrameId(renderFrameId1, 0) // The inputFrame to force confirmation (if necessary)
|
inputFrameId2 := pR.ConvertToInputFrameId(renderFrameId2, 0) // The inputFrame to force confirmation (if necessary)
|
||||||
if inputFrameId2 < pR.LastAllConfirmedInputFrameId {
|
if inputFrameId2 < pR.LastAllConfirmedInputFrameId {
|
||||||
// No need to force confirmation, the inputFrames already arrived
|
// 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))
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.Debug(fmt.Sprintf("forceConfirmation-InputsBufferLock about to lock: roomId=%v", pR.Id))
|
|
||||||
pR.InputsBufferLock.Lock()
|
|
||||||
Logger.Debug(fmt.Sprintf("forceConfirmation-InputsBufferLock locked: roomId=%v", pR.Id))
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
pR.InputsBufferLock.Unlock()
|
|
||||||
Logger.Debug(fmt.Sprintf("forceConfirmation-InputsBufferLock unlocked: roomId=%v", pR.Id))
|
|
||||||
}()
|
|
||||||
tmp := pR.InputsBuffer.GetByFrameId(inputFrameId2)
|
tmp := pR.InputsBuffer.GetByFrameId(inputFrameId2)
|
||||||
if nil == tmp {
|
if nil == tmp {
|
||||||
panic(fmt.Sprintf("inputFrameId2=%v doesn't exist for roomId=%v, this is abnormal because the server should prefab inputFrameDownsync in a most advanced pace, check the prefab logic! InputsBuffer=%v", inputFrameId2, pR.Id, pR.InputsBufferString(false)))
|
panic(fmt.Sprintf("inputFrameId2=%v doesn't exist for roomId=%v, this is abnormal because the server should prefab inputFrameDownsync in a most advanced pace, check the prefab logic! InputsBuffer=%v", inputFrameId2, pR.Id, pR.InputsBufferString(false)))
|
||||||
@@ -1126,10 +1202,35 @@ func (pR *Room) forceConfirmationIfApplicable() uint64 {
|
|||||||
inputFrame2.ConfirmedList = allConfirmedMask
|
inputFrame2.ConfirmedList = allConfirmedMask
|
||||||
pR.onInputFrameDownsyncAllConfirmed(inputFrame2, -1)
|
pR.onInputFrameDownsyncAllConfirmed(inputFrame2, -1)
|
||||||
|
|
||||||
return unconfirmedMask
|
if 0 < unconfirmedMask {
|
||||||
|
// This condition should be rarely met!
|
||||||
|
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"
|
||||||
|
|
||||||
|
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) {
|
func (pR *Room) applyInputFrameDownsyncDynamics(fromRenderFrameId int32, toRenderFrameId int32, spaceOffsetX, spaceOffsetY float64) {
|
||||||
|
// [WARNING] This function MUST BE called while "pR.InputsBufferLock" is locked!
|
||||||
if fromRenderFrameId >= toRenderFrameId {
|
if fromRenderFrameId >= toRenderFrameId {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -1138,14 +1239,6 @@ func (pR *Room) applyInputFrameDownsyncDynamics(fromRenderFrameId int32, toRende
|
|||||||
totPlayerCnt := uint32(pR.Capacity)
|
totPlayerCnt := uint32(pR.Capacity)
|
||||||
allConfirmedMask := uint64((1 << totPlayerCnt) - 1)
|
allConfirmedMask := uint64((1 << totPlayerCnt) - 1)
|
||||||
|
|
||||||
Logger.Debug(fmt.Sprintf("applyInputFrameDownsyncDynamics-InputsBufferLock about to lock: roomId=%v", pR.Id))
|
|
||||||
pR.InputsBufferLock.Lock()
|
|
||||||
Logger.Debug(fmt.Sprintf("applyInputFrameDownsyncDynamics-InputsBufferLock locked: roomId=%v", pR.Id))
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
pR.InputsBufferLock.Unlock()
|
|
||||||
Logger.Debug(fmt.Sprintf("applyInputFrameDownsyncDynamics-InputsBufferLock unlocked: roomId=%v", pR.Id))
|
|
||||||
}()
|
|
||||||
for collisionSysRenderFrameId := fromRenderFrameId; collisionSysRenderFrameId < toRenderFrameId; collisionSysRenderFrameId++ {
|
for collisionSysRenderFrameId := fromRenderFrameId; collisionSysRenderFrameId < toRenderFrameId; collisionSysRenderFrameId++ {
|
||||||
currRenderFrameTmp := pR.RenderFrameBuffer.GetByFrameId(collisionSysRenderFrameId)
|
currRenderFrameTmp := pR.RenderFrameBuffer.GetByFrameId(collisionSysRenderFrameId)
|
||||||
if nil == currRenderFrameTmp {
|
if nil == currRenderFrameTmp {
|
||||||
@@ -1164,7 +1257,7 @@ func (pR *Room) applyInputFrameDownsyncDynamics(fromRenderFrameId int32, toRende
|
|||||||
}
|
}
|
||||||
delayedInputFrame = tmp.(*InputFrameDownsync)
|
delayedInputFrame = tmp.(*InputFrameDownsync)
|
||||||
// [WARNING] It's possible that by now "allConfirmedMask != delayedInputFrame.ConfirmedList && delayedInputFrameId <= pR.LastAllConfirmedInputFrameId", we trust "pR.LastAllConfirmedInputFrameId" as the TOP AUTHORITY.
|
// [WARNING] It's possible that by now "allConfirmedMask != delayedInputFrame.ConfirmedList && delayedInputFrameId <= pR.LastAllConfirmedInputFrameId", we trust "pR.LastAllConfirmedInputFrameId" as the TOP AUTHORITY.
|
||||||
atomic.StoreUint64(&(delayedInputFrame.ConfirmedList), allConfirmedMask)
|
delayedInputFrame.ConfirmedList = allConfirmedMask
|
||||||
}
|
}
|
||||||
|
|
||||||
nextRenderFrame := pR.applyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputFrame, currRenderFrame, pR.CollisionSysMap)
|
nextRenderFrame := pR.applyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputFrame, currRenderFrame, pR.CollisionSysMap)
|
||||||
@@ -1175,7 +1268,7 @@ func (pR *Room) applyInputFrameDownsyncDynamics(fromRenderFrameId int32, toRende
|
|||||||
|
|
||||||
// TODO: Write unit-test for this function to compare with its frontend counter part
|
// TODO: Write unit-test for this function to compare with its frontend counter part
|
||||||
func (pR *Room) applyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputFrame *InputFrameDownsync, currRenderFrame *RoomDownsyncFrame, collisionSysMap map[int32]*resolv.Object) *RoomDownsyncFrame {
|
func (pR *Room) applyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputFrame *InputFrameDownsync, currRenderFrame *RoomDownsyncFrame, collisionSysMap map[int32]*resolv.Object) *RoomDownsyncFrame {
|
||||||
// TODO: Derive "nextRenderFramePlayers[*].CharacterState" as the frontend counter-part!
|
// [WARNING] This function MUST BE called while "pR.InputsBufferLock" is locked!
|
||||||
nextRenderFramePlayers := make(map[int32]*PlayerDownsync, pR.Capacity)
|
nextRenderFramePlayers := make(map[int32]*PlayerDownsync, pR.Capacity)
|
||||||
// Make a copy first
|
// Make a copy first
|
||||||
for playerId, currPlayerDownsync := range currRenderFrame.Players {
|
for playerId, currPlayerDownsync := range currRenderFrame.Players {
|
||||||
@@ -1211,7 +1304,8 @@ func (pR *Room) applyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputF
|
|||||||
effPushbacks := make([]Vec2D, pR.Capacity) // Guaranteed determinism regardless of traversal order
|
effPushbacks := make([]Vec2D, pR.Capacity) // Guaranteed determinism regardless of traversal order
|
||||||
|
|
||||||
// Reset playerCollider position from the "virtual grid position"
|
// Reset playerCollider position from the "virtual grid position"
|
||||||
for playerId, player := range pR.Players {
|
for _, player := range pR.PlayersArr {
|
||||||
|
playerId := player.Id
|
||||||
joinIndex := player.JoinIndex
|
joinIndex := player.JoinIndex
|
||||||
bulletPushbacks[joinIndex-1].X, bulletPushbacks[joinIndex-1].Y = float64(0), float64(0)
|
bulletPushbacks[joinIndex-1].X, bulletPushbacks[joinIndex-1].Y = float64(0), float64(0)
|
||||||
effPushbacks[joinIndex-1].X, effPushbacks[joinIndex-1].Y = float64(0), float64(0)
|
effPushbacks[joinIndex-1].X, effPushbacks[joinIndex-1].Y = float64(0), float64(0)
|
||||||
@@ -1306,7 +1400,8 @@ func (pR *Room) applyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputF
|
|||||||
}
|
}
|
||||||
inputList := delayedInputFrame.InputList
|
inputList := delayedInputFrame.InputList
|
||||||
// Process player inputs
|
// Process player inputs
|
||||||
for playerId, player := range pR.Players {
|
for _, player := range pR.PlayersArr {
|
||||||
|
playerId := player.Id
|
||||||
joinIndex := player.JoinIndex
|
joinIndex := player.JoinIndex
|
||||||
collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex
|
collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex
|
||||||
playerCollider := collisionSysMap[collisionPlayerIndex]
|
playerCollider := collisionSysMap[collisionPlayerIndex]
|
||||||
@@ -1368,7 +1463,7 @@ func (pR *Room) applyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputF
|
|||||||
}
|
}
|
||||||
|
|
||||||
// handle pushbacks upon collision after all movements treated as simultaneous
|
// handle pushbacks upon collision after all movements treated as simultaneous
|
||||||
for _, player := range pR.Players {
|
for _, player := range pR.PlayersArr {
|
||||||
joinIndex := player.JoinIndex
|
joinIndex := player.JoinIndex
|
||||||
collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex
|
collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex
|
||||||
playerCollider := collisionSysMap[collisionPlayerIndex]
|
playerCollider := collisionSysMap[collisionPlayerIndex]
|
||||||
@@ -1387,7 +1482,8 @@ func (pR *Room) applyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputF
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for playerId, player := range pR.Players {
|
for _, player := range pR.PlayersArr {
|
||||||
|
playerId := player.Id
|
||||||
joinIndex := player.JoinIndex
|
joinIndex := player.JoinIndex
|
||||||
collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex
|
collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex
|
||||||
playerCollider := collisionSysMap[collisionPlayerIndex]
|
playerCollider := collisionSysMap[collisionPlayerIndex]
|
||||||
@@ -1447,64 +1543,88 @@ 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))
|
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) downsyncToAllPlayers(upperToSendInputFrameId int32, unconfirmedMask uint64, prohibitsInputsBufferLock bool) {
|
func (pR *Room) doBattleMainLoopPerTickBackendDynamicsWithProperLocking(prevRenderFrameId int32, pDynamicsDuration *int64) {
|
||||||
for playerId, player := range pR.Players {
|
Logger.Debug(fmt.Sprintf("doBattleMainLoopPerTickBackendDynamicsWithProperLocking-InputsBufferLock to about lock: roomId=%v", pR.Id))
|
||||||
thatPlayerBattleState := atomic.LoadInt32(&(player.BattleState))
|
pR.InputsBufferLock.Lock()
|
||||||
switch thatPlayerBattleState {
|
Logger.Debug(fmt.Sprintf("doBattleMainLoopPerTickBackendDynamicsWithProperLocking-InputsBufferLock locked: roomId=%v", pR.Id))
|
||||||
case PlayerBattleStateIns.DISCONNECTED:
|
|
||||||
case PlayerBattleStateIns.LOST:
|
defer func() {
|
||||||
case PlayerBattleStateIns.EXPELLED_DURING_GAME:
|
pR.InputsBufferLock.Unlock()
|
||||||
case PlayerBattleStateIns.EXPELLED_IN_DISMISSAL:
|
Logger.Debug(fmt.Sprintf("doBattleMainLoopPerTickBackendDynamicsWithProperLocking-InputsBufferLock unlocked: roomId=%v", pR.Id))
|
||||||
case PlayerBattleStateIns.READDED_PENDING_BATTLE_COLLIDER_ACK: // This is the reason why battleState filter is put at "downsyncToAllPlayers" instead of "downsyncToSinglePlayer"
|
}()
|
||||||
continue
|
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
pR.downsyncToSinglePlayer(playerId, player, pR.LastAllConfirmedInputFrameId, unconfirmedMask, prohibitsInputsBufferLock)
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
inputsBufferSnapshot := pR.forceConfirmationIfApplicable(prevRenderFrameId)
|
||||||
|
|
||||||
|
if 0 <= pR.LastAllConfirmedInputFrameId {
|
||||||
|
dynamicsStartedAt := utils.UnixtimeNano()
|
||||||
|
// Apply "all-confirmed inputFrames" to move forward "pR.CurDynamicsRenderFrameId"
|
||||||
|
nextDynamicsRenderFrameId := pR.ConvertToLastUsedRenderFrameId(pR.LastAllConfirmedInputFrameId, pR.InputDelayFrames)
|
||||||
|
Logger.Debug(fmt.Sprintf("roomId=%v, room.RenderFrameId=%v, room.CurDynamicsRenderFrameId=%v, LastAllConfirmedInputFrameId=%v, InputDelayFrames=%v, nextDynamicsRenderFrameId=%v", pR.Id, pR.RenderFrameId, pR.CurDynamicsRenderFrameId, pR.LastAllConfirmedInputFrameId, pR.InputDelayFrames, nextDynamicsRenderFrameId))
|
||||||
|
pR.applyInputFrameDownsyncDynamics(pR.CurDynamicsRenderFrameId, nextDynamicsRenderFrameId, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY)
|
||||||
|
*pDynamicsDuration = utils.UnixtimeNano() - dynamicsStartedAt
|
||||||
|
}
|
||||||
|
|
||||||
|
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) downsyncToSinglePlayer(playerId int32, player *Player, upperToSendInputFrameId int32, unconfirmedMask uint64, prohibitsInputsBufferLock bool) {
|
func (pR *Room) downsyncToAllPlayers(inputsBufferSnapshot *InputsBufferSnapshot) {
|
||||||
// TODO: DON'T try to send any message to an inactive player! However, note that player.BattleState could be modified from different threads and needs to be synced!
|
|
||||||
// [WARNING] Websocket is TCP-based, thus no need to re-send a previously sent inputFrame to a same player!
|
|
||||||
lowerToSentInputFrameId := player.LastSentInputFrameId + 1
|
|
||||||
/*
|
/*
|
||||||
[WARNING]
|
[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).
|
||||||
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.
|
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 :)
|
||||||
|
|
||||||
Upon resync, it's still possible that "refRenderFrameId < frontend.chaserRenderFrameId" -- and this is allowed.
|
|
||||||
*/
|
*/
|
||||||
refRenderFrameId := pR.CurDynamicsRenderFrameId - 1
|
/*
|
||||||
|
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 playerId, playerDownsyncChan := range pR.PlayerDownsyncChanDict {
|
||||||
|
/*
|
||||||
|
[WARNING] While the order of generation of "inputsBufferSnapshot" is preserved for sending, the underlying network I/O blocking action is dispatched to "downsyncLoop of each player" such that "markConfirmationIfApplicable & forceConfirmationIfApplicable" can re-hold "pR.InputsBufferLock" asap and proceed with more inputFrameUpsyncs.
|
||||||
|
|
||||||
shouldResync1 := (MAGIC_LAST_SENT_INPUT_FRAME_ID_READDED == player.LastSentInputFrameId)
|
The use of "downsyncLoop of each player" also waives the need of guarding each "pR.PlayerDownsyncSessionDict[playerId]" from multithread-access (e.g. by a "pR.PlayerDownsyncSessionMutexDict[playerId]"), i.e. Gorilla v1.2.0 "conn.WriteMessage" isn't thread-safe https://github.com/gorilla/websocket/blob/v1.2.0/conn.go#L585.
|
||||||
shouldResync2 := (0 < (unconfirmedMask & uint64(1<<uint32(player.JoinIndex-1)))) // 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
|
*/
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pR *Room) downsyncToSinglePlayer(playerId int32, player *Player, refRenderFrameId int32, unconfirmedMask uint64, toSendInputFrameDownsyncsSnapshot []*InputFrameDownsync) {
|
||||||
|
/*
|
||||||
|
[WARNING] This function MUST BE called while "pR.InputsBufferLock" is unlocked -- otherwise the network I/O blocking of "sendSafely" might cause significant lag for "markConfirmationIfApplicable & forceConfirmationIfApplicable"!
|
||||||
|
|
||||||
|
We hereby assume that Golang runtime allocates & frees small amount of RAM quickly enough compared to either network I/O blocking in worst cases or the high frequency "per inputFrameDownsync*player" locking (though "OnBattleCmdReceived" locks at the same frequency but it's inevitable).
|
||||||
|
*/
|
||||||
|
|
||||||
|
playerJoinIndex := player.JoinIndex - 1
|
||||||
|
playerBattleState := atomic.LoadInt32(&(player.BattleState))
|
||||||
|
switch playerBattleState {
|
||||||
|
case PlayerBattleStateIns.DISCONNECTED:
|
||||||
|
case PlayerBattleStateIns.LOST:
|
||||||
|
case PlayerBattleStateIns.EXPELLED_DURING_GAME:
|
||||||
|
case PlayerBattleStateIns.EXPELLED_IN_DISMISSAL:
|
||||||
|
case PlayerBattleStateIns.ADDED_PENDING_BATTLE_COLLIDER_ACK:
|
||||||
|
case PlayerBattleStateIns.READDED_PENDING_BATTLE_COLLIDER_ACK:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
// 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)
|
shouldResyncOverall := (shouldResync1 || shouldResync2)
|
||||||
|
|
||||||
if shouldResyncOverall {
|
if shouldResyncOverall {
|
||||||
// A rejoined player, should guarantee that when it resyncs to "refRenderFrameId" a matching inputFrame to apply exists
|
// A rejoined player, should guarantee that when it resyncs to "refRenderFrameId" a matching inputFrame to apply exists
|
||||||
lowerToSentInputFrameId = pR.ConvertToInputFrameId(refRenderFrameId, pR.InputDelayFrames)
|
Logger.Debug(fmt.Sprintf("Resyncing player: roomId=%v, playerId=%v, playerJoinIndex=%v, renderFrameId=%v, curDynamicsRenderFrameId=%v, playerLastSentInputFrameId=%v, refRenderFrameId=%v", pR.Id, playerId, player.JoinIndex, pR.RenderFrameId, pR.CurDynamicsRenderFrameId, player.LastSentInputFrameId, refRenderFrameId))
|
||||||
Logger.Info(fmt.Sprintf("Resyncing player: roomId=%v, playerId=%v, playerJoinIndex=%v, renderFrameId=%v, curDynamicsRenderFrameId=%v, playerLastSentInputFrameId=%v, refRenderFrameId=%v, lowerToSentInputFrameId=%v, upperToSendInputFrameId=%v", pR.Id, playerId, player.JoinIndex, pR.RenderFrameId, pR.CurDynamicsRenderFrameId, player.LastSentInputFrameId, refRenderFrameId, lowerToSentInputFrameId, upperToSendInputFrameId))
|
|
||||||
// TODO: What if "lowerToSentInputFrameId > pR.InputsBuffer.StFrameId" now?
|
|
||||||
}
|
|
||||||
|
|
||||||
if lowerToSentInputFrameId > upperToSendInputFrameId {
|
|
||||||
Logger.Debug(fmt.Sprintf("Not sending due to potentially empty toSendInputFrameDownsyncs: roomId=%v, playerId=%v, playerLastSentInputFrameId=%v, refRenderFrameId=%v, lowerToSentInputFrameId=%v, upperToSendInputFrameId=%v, lastSentInputFrameId=%v, playerAckingInputFrameId=%v", pR.Id, playerId, player.LastSentInputFrameId, refRenderFrameId, lowerToSentInputFrameId, upperToSendInputFrameId, player.LastSentInputFrameId, player.AckingInputFrameId))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// [WARNING] EDGE CASE HERE: Upon initialization, all of "lastAllConfirmedInputFrameId", "lastAllConfirmedInputFrameIdWithChange" and "anchorInputFrameId" are "-1", thus "j" starts with "0", however "inputFrameId: 0" might not have been all confirmed!
|
|
||||||
var theInputsBufferLockToUse *sync.Mutex = &pR.InputsBufferLock
|
|
||||||
if prohibitsInputsBufferLock {
|
|
||||||
// Already locked in caller function
|
|
||||||
theInputsBufferLockToUse = nil
|
|
||||||
}
|
|
||||||
// [WARNING] Clone to deliberately avoid holding "pR.InputsBufferLock" while using network I/O
|
|
||||||
j, toSendInputFrameDownsyncs := pR.InputsBuffer.cloneInputFrameDownsyncsByFrameIdRange(lowerToSentInputFrameId, upperToSendInputFrameId+1, theInputsBufferLockToUse)
|
|
||||||
|
|
||||||
if 0 >= len(toSendInputFrameDownsyncs) {
|
|
||||||
Logger.Debug(fmt.Sprintf("Not sending due to actually empty toSendInputFrameDownsyncs: roomId=%v, playerId=%v, playerLastSentInputFrameId=%v, refRenderFrameId=%v, lowerToSentInputFrameId=%v, upperToSendInputFrameId=%v, j=%v, lastSentInputFrameId=%v, playerAckingInputFrameId=%v", pR.Id, playerId, player.LastSentInputFrameId, refRenderFrameId, lowerToSentInputFrameId, upperToSendInputFrameId, j, player.LastSentInputFrameId, player.AckingInputFrameId))
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1512,21 +1632,59 @@ func (pR *Room) downsyncToSinglePlayer(playerId int32, player *Player, upperToSe
|
|||||||
1. when player with a slower frontend clock lags significantly behind and thus wouldn't get its inputUpsync recognized due to faster "forceConfirmation"
|
1. when player with a slower frontend clock lags significantly behind and thus wouldn't get its inputUpsync recognized due to faster "forceConfirmation"
|
||||||
2. reconnection
|
2. reconnection
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
toSendInputFrameIdSt, toSendInputFrameIdEd := toSendInputFrameDownsyncsSnapshot[0].InputFrameId, toSendInputFrameDownsyncsSnapshot[len(toSendInputFrameDownsyncsSnapshot)-1].InputFrameId+1
|
||||||
if pR.BackendDynamicsEnabled && shouldResyncOverall {
|
if pR.BackendDynamicsEnabled && shouldResyncOverall {
|
||||||
tmp := pR.RenderFrameBuffer.GetByFrameId(refRenderFrameId)
|
tmp := pR.RenderFrameBuffer.GetByFrameId(refRenderFrameId)
|
||||||
if nil == tmp {
|
if nil == tmp {
|
||||||
panic(fmt.Sprintf("Required refRenderFrameId=%v for roomId=%v, renderFrameId=%v, playerId=%v, playerLastSentInputFrameId=%v, j=%v doesn't exist! InputsBuffer=%v, RenderFrameBuffer=%v", refRenderFrameId, pR.Id, pR.RenderFrameId, playerId, player.LastSentInputFrameId, j, pR.InputsBufferString(false), pR.RenderFrameBufferString()))
|
panic(fmt.Sprintf("Required refRenderFrameId=%v for (roomId=%v, renderFrameId=%v, playerId=%v, playerLastSentInputFrameId=%v) doesn't exist! InputsBuffer=%v, RenderFrameBuffer=%v", refRenderFrameId, pR.Id, pR.RenderFrameId, playerId, player.LastSentInputFrameId, pR.InputsBufferString(false), pR.RenderFrameBufferString()))
|
||||||
}
|
}
|
||||||
|
|
||||||
refRenderFrame := tmp.(*RoomDownsyncFrame)
|
refRenderFrame := tmp.(*RoomDownsyncFrame)
|
||||||
for playerId, player := range pR.Players {
|
for _, player := range pR.PlayersArr {
|
||||||
refRenderFrame.Players[playerId].ColliderRadius = player.ColliderRadius // hardcoded for now
|
refRenderFrame.Players[player.Id].ColliderRadius = player.ColliderRadius // hardcoded for now
|
||||||
}
|
}
|
||||||
refRenderFrame.BackendUnconfirmedMask = unconfirmedMask
|
refRenderFrame.BackendUnconfirmedMask = unconfirmedMask
|
||||||
Logger.Warn(fmt.Sprintf("Sending refRenderFrameId=%v for roomId=%v, , playerId=%v, playerJoinIndex=%v, renderFrameId=%v, curDynamicsRenderFrameId=%v, playerLastSentInputFrameId=%v, lowerToSentInputFrameId=%v, upperToSendInputFrameId=%v, j=%v: InputsBuffer=%v", refRenderFrameId, pR.Id, playerId, player.JoinIndex, pR.RenderFrameId, pR.CurDynamicsRenderFrameId, player.LastSentInputFrameId, lowerToSentInputFrameId, upperToSendInputFrameId, j, pR.InputsBufferString(false)))
|
pR.sendSafely(refRenderFrame, toSendInputFrameDownsyncsSnapshot, DOWNSYNC_MSG_ACT_FORCED_RESYNC, playerId, false)
|
||||||
pR.sendSafely(refRenderFrame, toSendInputFrameDownsyncs, DOWNSYNC_MSG_ACT_FORCED_RESYNC, playerId)
|
Logger.Warn(fmt.Sprintf("Sent refRenderFrameId=%v & inputFrameIds [%d, %d), for roomId=%v, playerId=%d, playerJoinIndex=%d, renderFrameId=%d, curDynamicsRenderFrameId=%d, playerLastSentInputFrameId=%d: InputsBuffer=%v", refRenderFrameId, toSendInputFrameIdSt, toSendInputFrameIdEd, pR.Id, playerId, player.JoinIndex, pR.RenderFrameId, pR.CurDynamicsRenderFrameId, player.LastSentInputFrameId, pR.InputsBufferString(false)))
|
||||||
} else {
|
} else {
|
||||||
pR.sendSafely(nil, toSendInputFrameDownsyncs, DOWNSYNC_MSG_ACT_INPUT_BATCH, playerId)
|
pR.sendSafely(nil, toSendInputFrameDownsyncsSnapshot, DOWNSYNC_MSG_ACT_INPUT_BATCH, playerId, false)
|
||||||
|
}
|
||||||
|
player.LastSentInputFrameId = toSendInputFrameIdEd - 1
|
||||||
|
if shouldResync1 {
|
||||||
|
atomic.StoreInt32(&(player.BattleState), PlayerBattleStateIns.ACTIVE)
|
||||||
}
|
}
|
||||||
player.LastSentInputFrameId = j - 1
|
}
|
||||||
|
|
||||||
|
func (pR *Room) cloneInputsBuffer(stFrameId, edFrameId int32) []*InputFrameDownsync {
|
||||||
|
// [WARNING] This function MUST BE called while "pR.InputsBufferLock" is locked!
|
||||||
|
cloned := make([]*InputFrameDownsync, 0, edFrameId-stFrameId)
|
||||||
|
prevFrameFound := false
|
||||||
|
j := stFrameId
|
||||||
|
for j < edFrameId {
|
||||||
|
tmp := pR.InputsBuffer.GetByFrameId(j)
|
||||||
|
if nil == tmp {
|
||||||
|
if false == prevFrameFound {
|
||||||
|
j++
|
||||||
|
continue // allowed to keep not finding the requested inputFrames at the beginning
|
||||||
|
} else {
|
||||||
|
break // The "id"s are always consecutive
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prevFrameFound = true
|
||||||
|
foo := tmp.(*InputFrameDownsync)
|
||||||
|
|
||||||
|
bar := &InputFrameDownsync{
|
||||||
|
InputFrameId: foo.InputFrameId,
|
||||||
|
InputList: make([]uint64, len(foo.InputList)),
|
||||||
|
ConfirmedList: foo.ConfirmedList,
|
||||||
|
}
|
||||||
|
for i, input := range foo.InputList {
|
||||||
|
bar.InputList[i] = input
|
||||||
|
}
|
||||||
|
cloned = append(cloned, bar)
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
|
||||||
|
return cloned
|
||||||
}
|
}
|
||||||
|
@@ -630,6 +630,69 @@ func (x *WsResp) GetBciFrame() *BattleColliderInfo {
|
|||||||
return nil
|
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 {
|
type MeleeBullet struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
@@ -659,7 +722,7 @@ type MeleeBullet struct {
|
|||||||
func (x *MeleeBullet) Reset() {
|
func (x *MeleeBullet) Reset() {
|
||||||
*x = MeleeBullet{}
|
*x = MeleeBullet{}
|
||||||
if protoimpl.UnsafeEnabled {
|
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 := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -672,7 +735,7 @@ func (x *MeleeBullet) String() string {
|
|||||||
func (*MeleeBullet) ProtoMessage() {}
|
func (*MeleeBullet) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *MeleeBullet) ProtoReflect() protoreflect.Message {
|
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 {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -685,7 +748,7 @@ func (x *MeleeBullet) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use MeleeBullet.ProtoReflect.Descriptor instead.
|
// Deprecated: Use MeleeBullet.ProtoReflect.Descriptor instead.
|
||||||
func (*MeleeBullet) Descriptor() ([]byte, []int) {
|
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 {
|
func (x *MeleeBullet) GetBattleLocalId() int32 {
|
||||||
@@ -843,7 +906,7 @@ type BattleColliderInfo struct {
|
|||||||
func (x *BattleColliderInfo) Reset() {
|
func (x *BattleColliderInfo) Reset() {
|
||||||
*x = BattleColliderInfo{}
|
*x = BattleColliderInfo{}
|
||||||
if protoimpl.UnsafeEnabled {
|
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 := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -856,7 +919,7 @@ func (x *BattleColliderInfo) String() string {
|
|||||||
func (*BattleColliderInfo) ProtoMessage() {}
|
func (*BattleColliderInfo) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *BattleColliderInfo) ProtoReflect() protoreflect.Message {
|
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 {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -869,7 +932,7 @@ func (x *BattleColliderInfo) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use BattleColliderInfo.ProtoReflect.Descriptor instead.
|
// Deprecated: Use BattleColliderInfo.ProtoReflect.Descriptor instead.
|
||||||
func (*BattleColliderInfo) Descriptor() ([]byte, []int) {
|
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 {
|
func (x *BattleColliderInfo) GetStageName() string {
|
||||||
@@ -1069,7 +1132,7 @@ type RoomDownsyncFrame struct {
|
|||||||
func (x *RoomDownsyncFrame) Reset() {
|
func (x *RoomDownsyncFrame) Reset() {
|
||||||
*x = RoomDownsyncFrame{}
|
*x = RoomDownsyncFrame{}
|
||||||
if protoimpl.UnsafeEnabled {
|
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 := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -1082,7 +1145,7 @@ func (x *RoomDownsyncFrame) String() string {
|
|||||||
func (*RoomDownsyncFrame) ProtoMessage() {}
|
func (*RoomDownsyncFrame) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *RoomDownsyncFrame) ProtoReflect() protoreflect.Message {
|
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 {
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -1095,7 +1158,7 @@ func (x *RoomDownsyncFrame) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use RoomDownsyncFrame.ProtoReflect.Descriptor instead.
|
// Deprecated: Use RoomDownsyncFrame.ProtoReflect.Descriptor instead.
|
||||||
func (*RoomDownsyncFrame) Descriptor() ([]byte, []int) {
|
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 {
|
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,
|
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,
|
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,
|
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,
|
0xc6, 0x01, 0x0a, 0x14, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72,
|
||||||
0x24, 0x0a, 0x0d, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64,
|
0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x2a, 0x0a, 0x10, 0x72, 0x65, 0x66, 0x52,
|
||||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x4c, 0x6f,
|
0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01,
|
||||||
0x63, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70,
|
0x28, 0x05, 0x52, 0x10, 0x72, 0x65, 0x66, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61,
|
||||||
0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x73, 0x74,
|
0x6d, 0x65, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x0f, 0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72,
|
||||||
0x61, 0x72, 0x74, 0x75, 0x70, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x61,
|
0x6d, 0x65, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x75,
|
||||||
0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28,
|
0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x12, 0x58,
|
||||||
0x05, 0x52, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12,
|
0x0a, 0x19, 0x74, 0x6f, 0x53, 0x65, 0x6e, 0x64, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61,
|
||||||
0x26, 0x0a, 0x0e, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x46, 0x72, 0x61, 0x6d, 0x65,
|
0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28,
|
||||||
0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72,
|
0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74,
|
||||||
0x79, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x34, 0x0a, 0x15, 0x72, 0x65, 0x63, 0x6f, 0x76,
|
0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x52, 0x19, 0x74,
|
||||||
0x65, 0x72, 0x79, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x4f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b,
|
0x6f, 0x53, 0x65, 0x6e, 0x64, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44,
|
||||||
0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x15, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79,
|
0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x73, 0x22, 0xe5, 0x05, 0x0a, 0x0b, 0x4d, 0x65, 0x6c,
|
||||||
0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x4f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x30, 0x0a,
|
0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x62, 0x61, 0x74, 0x74,
|
||||||
0x13, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x4f,
|
0x6c, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52,
|
||||||
0x6e, 0x48, 0x69, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x13, 0x72, 0x65, 0x63, 0x6f,
|
0x0d, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x24,
|
||||||
0x76, 0x65, 0x72, 0x79, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x4f, 0x6e, 0x48, 0x69, 0x74, 0x12,
|
0x0a, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18,
|
||||||
0x35, 0x0a, 0x0b, 0x6d, 0x6f, 0x76, 0x65, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x18, 0x07,
|
0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x46, 0x72,
|
||||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x70, 0x72, 0x6f,
|
0x61, 0x6d, 0x65, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x72,
|
||||||
0x74, 0x6f, 0x73, 0x2e, 0x56, 0x65, 0x63, 0x32, 0x44, 0x52, 0x0b, 0x6d, 0x6f, 0x76, 0x65, 0x66,
|
0x61, 0x6d, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x61, 0x63, 0x74, 0x69,
|
||||||
0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78,
|
0x76, 0x65, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x26, 0x0a, 0x0e, 0x72, 0x65, 0x63, 0x6f,
|
||||||
0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0c, 0x68, 0x69,
|
0x76, 0x65, 0x72, 0x79, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05,
|
||||||
0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x33, 0x0a, 0x0a, 0x68, 0x69,
|
0x52, 0x0e, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73,
|
||||||
0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13,
|
0x12, 0x34, 0x0a, 0x15, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x46, 0x72, 0x61, 0x6d,
|
||||||
0x2e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x56, 0x65,
|
0x65, 0x73, 0x4f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52,
|
||||||
0x63, 0x32, 0x44, 0x52, 0x0a, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x12,
|
0x15, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x4f,
|
||||||
0x38, 0x0a, 0x17, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x6e,
|
0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x30, 0x0a, 0x13, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65,
|
||||||
0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05,
|
0x72, 0x79, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x4f, 0x6e, 0x48, 0x69, 0x74, 0x18, 0x06, 0x20,
|
||||||
0x52, 0x17, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x6e, 0x64,
|
0x01, 0x28, 0x05, 0x52, 0x13, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x46, 0x72, 0x61,
|
||||||
0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74,
|
0x6d, 0x65, 0x73, 0x4f, 0x6e, 0x48, 0x69, 0x74, 0x12, 0x35, 0x0a, 0x0b, 0x6d, 0x6f, 0x76, 0x65,
|
||||||
0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05,
|
0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e,
|
||||||
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,
|
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,
|
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,
|
0x01, 0x1a, 0x58, 0x0a, 0x15, 0x4d, 0x65, 0x6c, 0x65, 0x65, 0x53, 0x6b, 0x69, 0x6c, 0x6c, 0x43,
|
||||||
0x6e, 0x32, 0x44, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12,
|
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
|
||||||
0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65,
|
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x29, 0x0a, 0x05,
|
||||||
0x79, 0x12, 0x31, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
|
0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72,
|
||||||
0x32, 0x1b, 0x2e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e,
|
0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x4d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74,
|
||||||
0x50, 0x6f, 0x6c, 0x79, 0x67, 0x6f, 0x6e, 0x32, 0x44, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x05, 0x76,
|
0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xd2, 0x02, 0x0a, 0x11,
|
||||||
0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x58, 0x0a, 0x15, 0x4d, 0x65, 0x6c, 0x65,
|
0x52, 0x6f, 0x6f, 0x6d, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x46, 0x72, 0x61, 0x6d,
|
||||||
0x65, 0x53, 0x6b, 0x69, 0x6c, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72,
|
0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69,
|
||||||
0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03,
|
0x64, 0x12, 0x40, 0x0a, 0x07, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03,
|
||||||
0x6b, 0x65, 0x79, 0x12, 0x29, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
|
0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x52, 0x6f, 0x6f, 0x6d,
|
||||||
0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x4d, 0x65, 0x6c, 0x65,
|
0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x2e, 0x50, 0x6c,
|
||||||
0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02,
|
0x61, 0x79, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x70, 0x6c, 0x61, 0x79,
|
||||||
0x38, 0x01, 0x22, 0xd2, 0x02, 0x0a, 0x11, 0x52, 0x6f, 0x6f, 0x6d, 0x44, 0x6f, 0x77, 0x6e, 0x73,
|
0x65, 0x72, 0x73, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x64, 0x6f, 0x77, 0x6e,
|
||||||
0x79, 0x6e, 0x63, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01,
|
0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x63, 0x6f, 0x75,
|
||||||
0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x40, 0x0a, 0x07, 0x70, 0x6c, 0x61, 0x79,
|
0x6e, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x12, 0x37, 0x0a, 0x0c, 0x6d,
|
||||||
0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28,
|
||||||
0x6f, 0x73, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x46,
|
0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x4d, 0x65, 0x6c, 0x65, 0x65,
|
||||||
0x72, 0x61, 0x6d, 0x65, 0x2e, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72,
|
0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x52, 0x0c, 0x6d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c,
|
||||||
0x79, 0x52, 0x07, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x6f,
|
0x6c, 0x65, 0x74, 0x73, 0x12, 0x36, 0x0a, 0x16, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x55,
|
||||||
0x75, 0x6e, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01,
|
0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x18, 0x05,
|
||||||
0x28, 0x03, 0x52, 0x0e, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x4e, 0x61, 0x6e,
|
0x20, 0x01, 0x28, 0x04, 0x52, 0x16, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x55, 0x6e, 0x63,
|
||||||
0x6f, 0x73, 0x12, 0x37, 0x0a, 0x0c, 0x6d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65,
|
0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x1a, 0x52, 0x0a, 0x0c,
|
||||||
0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03,
|
||||||
0x73, 0x2e, 0x4d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x52, 0x0c, 0x6d,
|
0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2c,
|
||||||
0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x12, 0x36, 0x0a, 0x16, 0x62,
|
0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e,
|
||||||
0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65,
|
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x44, 0x6f, 0x77,
|
||||||
0x64, 0x4d, 0x61, 0x73, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x16, 0x62, 0x61, 0x63,
|
0x6e, 0x73, 0x79, 0x6e, 0x63, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01,
|
||||||
0x6b, 0x65, 0x6e, 0x64, 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4d,
|
0x42, 0x13, 0x5a, 0x11, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x5f, 0x73, 0x72, 0x76, 0x2f, 0x70,
|
||||||
0x61, 0x73, 0x6b, 0x1a, 0x52, 0x0a, 0x0c, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x45, 0x6e,
|
0x72, 0x6f, 0x74, 0x6f, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
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 (
|
var (
|
||||||
@@ -1423,7 +1498,7 @@ func file_room_downsync_frame_proto_rawDescGZIP() []byte {
|
|||||||
return file_room_downsync_frame_proto_rawDescData
|
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{}{
|
var file_room_downsync_frame_proto_goTypes = []interface{}{
|
||||||
(*PlayerDownsync)(nil), // 0: protos.PlayerDownsync
|
(*PlayerDownsync)(nil), // 0: protos.PlayerDownsync
|
||||||
(*InputFrameDecoded)(nil), // 1: protos.InputFrameDecoded
|
(*InputFrameDecoded)(nil), // 1: protos.InputFrameDecoded
|
||||||
@@ -1432,39 +1507,41 @@ var file_room_downsync_frame_proto_goTypes = []interface{}{
|
|||||||
(*HeartbeatUpsync)(nil), // 4: protos.HeartbeatUpsync
|
(*HeartbeatUpsync)(nil), // 4: protos.HeartbeatUpsync
|
||||||
(*WsReq)(nil), // 5: protos.WsReq
|
(*WsReq)(nil), // 5: protos.WsReq
|
||||||
(*WsResp)(nil), // 6: protos.WsResp
|
(*WsResp)(nil), // 6: protos.WsResp
|
||||||
(*MeleeBullet)(nil), // 7: protos.MeleeBullet
|
(*InputsBufferSnapshot)(nil), // 7: protos.InputsBufferSnapshot
|
||||||
(*BattleColliderInfo)(nil), // 8: protos.BattleColliderInfo
|
(*MeleeBullet)(nil), // 8: protos.MeleeBullet
|
||||||
(*RoomDownsyncFrame)(nil), // 9: protos.RoomDownsyncFrame
|
(*BattleColliderInfo)(nil), // 9: protos.BattleColliderInfo
|
||||||
nil, // 10: protos.BattleColliderInfo.StrToVec2DListMapEntry
|
(*RoomDownsyncFrame)(nil), // 10: protos.RoomDownsyncFrame
|
||||||
nil, // 11: protos.BattleColliderInfo.StrToPolygon2DListMapEntry
|
nil, // 11: protos.BattleColliderInfo.StrToVec2DListMapEntry
|
||||||
nil, // 12: protos.BattleColliderInfo.MeleeSkillConfigEntry
|
nil, // 12: protos.BattleColliderInfo.StrToPolygon2DListMapEntry
|
||||||
nil, // 13: protos.RoomDownsyncFrame.PlayersEntry
|
nil, // 13: protos.BattleColliderInfo.MeleeSkillConfigEntry
|
||||||
(*sharedprotos.Vec2D)(nil), // 14: sharedprotos.Vec2D
|
nil, // 14: protos.RoomDownsyncFrame.PlayersEntry
|
||||||
(*sharedprotos.Vec2DList)(nil), // 15: sharedprotos.Vec2DList
|
(*sharedprotos.Vec2D)(nil), // 15: sharedprotos.Vec2D
|
||||||
(*sharedprotos.Polygon2DList)(nil), // 16: sharedprotos.Polygon2DList
|
(*sharedprotos.Vec2DList)(nil), // 16: sharedprotos.Vec2DList
|
||||||
|
(*sharedprotos.Polygon2DList)(nil), // 17: sharedprotos.Polygon2DList
|
||||||
}
|
}
|
||||||
var file_room_downsync_frame_proto_depIdxs = []int32{
|
var file_room_downsync_frame_proto_depIdxs = []int32{
|
||||||
2, // 0: protos.WsReq.inputFrameUpsyncBatch:type_name -> protos.InputFrameUpsync
|
2, // 0: protos.WsReq.inputFrameUpsyncBatch:type_name -> protos.InputFrameUpsync
|
||||||
4, // 1: protos.WsReq.hb:type_name -> protos.HeartbeatUpsync
|
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
|
3, // 3: protos.WsResp.inputFrameDownsyncBatch:type_name -> protos.InputFrameDownsync
|
||||||
8, // 4: protos.WsResp.bciFrame:type_name -> protos.BattleColliderInfo
|
9, // 4: protos.WsResp.bciFrame:type_name -> protos.BattleColliderInfo
|
||||||
14, // 5: protos.MeleeBullet.moveforward:type_name -> sharedprotos.Vec2D
|
3, // 5: protos.InputsBufferSnapshot.toSendInputFrameDownsyncs:type_name -> protos.InputFrameDownsync
|
||||||
14, // 6: protos.MeleeBullet.hitboxSize:type_name -> sharedprotos.Vec2D
|
15, // 6: protos.MeleeBullet.moveforward:type_name -> sharedprotos.Vec2D
|
||||||
10, // 7: protos.BattleColliderInfo.strToVec2DListMap:type_name -> protos.BattleColliderInfo.StrToVec2DListMapEntry
|
15, // 7: protos.MeleeBullet.hitboxSize:type_name -> sharedprotos.Vec2D
|
||||||
11, // 8: protos.BattleColliderInfo.strToPolygon2DListMap:type_name -> protos.BattleColliderInfo.StrToPolygon2DListMapEntry
|
11, // 8: protos.BattleColliderInfo.strToVec2DListMap:type_name -> protos.BattleColliderInfo.StrToVec2DListMapEntry
|
||||||
12, // 9: protos.BattleColliderInfo.meleeSkillConfig:type_name -> protos.BattleColliderInfo.MeleeSkillConfigEntry
|
12, // 9: protos.BattleColliderInfo.strToPolygon2DListMap:type_name -> protos.BattleColliderInfo.StrToPolygon2DListMapEntry
|
||||||
13, // 10: protos.RoomDownsyncFrame.players:type_name -> protos.RoomDownsyncFrame.PlayersEntry
|
13, // 10: protos.BattleColliderInfo.meleeSkillConfig:type_name -> protos.BattleColliderInfo.MeleeSkillConfigEntry
|
||||||
7, // 11: protos.RoomDownsyncFrame.meleeBullets:type_name -> protos.MeleeBullet
|
14, // 11: protos.RoomDownsyncFrame.players:type_name -> protos.RoomDownsyncFrame.PlayersEntry
|
||||||
15, // 12: protos.BattleColliderInfo.StrToVec2DListMapEntry.value:type_name -> sharedprotos.Vec2DList
|
8, // 12: protos.RoomDownsyncFrame.meleeBullets:type_name -> protos.MeleeBullet
|
||||||
16, // 13: protos.BattleColliderInfo.StrToPolygon2DListMapEntry.value:type_name -> sharedprotos.Polygon2DList
|
16, // 13: protos.BattleColliderInfo.StrToVec2DListMapEntry.value:type_name -> sharedprotos.Vec2DList
|
||||||
7, // 14: protos.BattleColliderInfo.MeleeSkillConfigEntry.value:type_name -> protos.MeleeBullet
|
17, // 14: protos.BattleColliderInfo.StrToPolygon2DListMapEntry.value:type_name -> sharedprotos.Polygon2DList
|
||||||
0, // 15: protos.RoomDownsyncFrame.PlayersEntry.value:type_name -> protos.PlayerDownsync
|
8, // 15: protos.BattleColliderInfo.MeleeSkillConfigEntry.value:type_name -> protos.MeleeBullet
|
||||||
16, // [16:16] is the sub-list for method output_type
|
0, // 16: protos.RoomDownsyncFrame.PlayersEntry.value:type_name -> protos.PlayerDownsync
|
||||||
16, // [16:16] is the sub-list for method input_type
|
17, // [17:17] is the sub-list for method output_type
|
||||||
16, // [16:16] is the sub-list for extension type_name
|
17, // [17:17] is the sub-list for method input_type
|
||||||
16, // [16:16] is the sub-list for extension extendee
|
17, // [17:17] is the sub-list for extension type_name
|
||||||
0, // [0:16] is the sub-list for field 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() }
|
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{} {
|
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:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
case 1:
|
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{} {
|
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:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
case 1:
|
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{} {
|
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 {
|
switch v := v.(*RoomDownsyncFrame); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
@@ -1600,7 +1689,7 @@ func file_room_downsync_frame_proto_init() {
|
|||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: file_room_downsync_frame_proto_rawDesc,
|
RawDescriptor: file_room_downsync_frame_proto_rawDesc,
|
||||||
NumEnums: 0,
|
NumEnums: 0,
|
||||||
NumMessages: 14,
|
NumMessages: 15,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 0,
|
NumServices: 0,
|
||||||
},
|
},
|
||||||
|
@@ -68,6 +68,12 @@ message WsResp {
|
|||||||
BattleColliderInfo bciFrame = 6;
|
BattleColliderInfo bciFrame = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message InputsBufferSnapshot {
|
||||||
|
int32 refRenderFrameId = 1;
|
||||||
|
uint64 unconfirmedMask = 2;
|
||||||
|
repeated InputFrameDownsync toSendInputFrameDownsyncs = 3;
|
||||||
|
}
|
||||||
|
|
||||||
message MeleeBullet {
|
message MeleeBullet {
|
||||||
// Jargon reference https://www.thegamer.com/fighting-games-frame-data-explained/
|
// Jargon reference https://www.thegamer.com/fighting-games-frame-data-explained/
|
||||||
// ALL lengths are in world coordinate
|
// ALL lengths are in world coordinate
|
||||||
|
@@ -440,7 +440,7 @@
|
|||||||
"array": [
|
"array": [
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
210.4441731196186,
|
210.54381524704266,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
|
@@ -3553,6 +3553,292 @@ $root.protos = (function() {
|
|||||||
return WsResp;
|
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() {
|
protos.MeleeBullet = (function() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user