mirror of
				https://github.com/genxium/DelayNoMore
				synced 2025-11-03 21:06:35 +00:00 
			
		
		
		
	Drafted peer inputFrameUpsync broadcasting mechanism.
This commit is contained in:
		@@ -89,6 +89,7 @@ func setRouter(router *gin.Engine) {
 | 
			
		||||
	router.StaticFS("/asset", http.Dir(filepath.Join(Conf.General.AppRoot, "asset")))
 | 
			
		||||
	router.GET("/ping", f)
 | 
			
		||||
	router.GET("/tsrht", ws.Serve)
 | 
			
		||||
	router.GET("/tsrhtSecondary", ws.HandleSecondaryWsSessionForPlayer)
 | 
			
		||||
 | 
			
		||||
	apiRouter := router.Group("/api")
 | 
			
		||||
	{
 | 
			
		||||
 
 | 
			
		||||
@@ -27,10 +27,11 @@ const (
 | 
			
		||||
	UPSYNC_MSG_ACT_PLAYER_CMD          = int32(2)
 | 
			
		||||
	UPSYNC_MSG_ACT_PLAYER_COLLIDER_ACK = int32(3)
 | 
			
		||||
 | 
			
		||||
	DOWNSYNC_MSG_ACT_HB_REQ         = int32(1)
 | 
			
		||||
	DOWNSYNC_MSG_ACT_INPUT_BATCH    = int32(2)
 | 
			
		||||
	DOWNSYNC_MSG_ACT_BATTLE_STOPPED = int32(3)
 | 
			
		||||
	DOWNSYNC_MSG_ACT_FORCED_RESYNC  = int32(4)
 | 
			
		||||
	DOWNSYNC_MSG_ACT_HB_REQ           = int32(1)
 | 
			
		||||
	DOWNSYNC_MSG_ACT_INPUT_BATCH      = int32(2)
 | 
			
		||||
	DOWNSYNC_MSG_ACT_BATTLE_STOPPED   = int32(3)
 | 
			
		||||
	DOWNSYNC_MSG_ACT_FORCED_RESYNC    = int32(4)
 | 
			
		||||
	DOWNSYNC_MSG_ACT_PEER_INPUT_BATCH = int32(5)
 | 
			
		||||
 | 
			
		||||
	DOWNSYNC_MSG_ACT_BATTLE_READY_TO_START = int32(-1)
 | 
			
		||||
	DOWNSYNC_MSG_ACT_BATTLE_START          = int32(0)
 | 
			
		||||
@@ -116,10 +117,15 @@ type Room struct {
 | 
			
		||||
	     *
 | 
			
		||||
	     * Moreover, during the invocation of `PlayerSignalToCloseDict`, the `Player` instance is supposed to be deallocated (though not synchronously).
 | 
			
		||||
	*/
 | 
			
		||||
	PlayerDownsyncSessionDict              map[int32]*websocket.Conn
 | 
			
		||||
	PlayerDownsyncChanDict                 map[int32](chan pb.InputsBufferSnapshot)
 | 
			
		||||
	PlayerDownsyncSessionDict map[int32]*websocket.Conn
 | 
			
		||||
	PlayerSignalToCloseDict   map[int32]SignalToCloseConnCbType
 | 
			
		||||
	PlayerDownsyncChanDict    map[int32](chan pb.InputsBufferSnapshot)
 | 
			
		||||
 | 
			
		||||
	PlayerSecondaryDownsyncSessionDict map[int32]*websocket.Conn
 | 
			
		||||
	PlayerSecondarySignalToCloseDict   map[int32]SignalToCloseConnCbType
 | 
			
		||||
	PlayerSecondaryDownsyncChanDict    map[int32](chan pb.InputsBufferSnapshot)
 | 
			
		||||
 | 
			
		||||
	PlayerActiveWatchdogDict               map[int32](*Watchdog)
 | 
			
		||||
	PlayerSignalToCloseDict                map[int32]SignalToCloseConnCbType
 | 
			
		||||
	Score                                  float32
 | 
			
		||||
	State                                  int32
 | 
			
		||||
	Index                                  int
 | 
			
		||||
@@ -184,7 +190,7 @@ func (pR *Room) AddPlayerIfPossible(pPlayerFromDbInit *Player, session *websocke
 | 
			
		||||
	pR.PlayerSignalToCloseDict[playerId] = signalToCloseConnOfThisPlayer
 | 
			
		||||
	newWatchdog := NewWatchdog(ConstVals.Ws.WillKickIfInactiveFor, func() {
 | 
			
		||||
		Logger.Warn("Conn inactive watchdog triggered#1:", zap.Any("playerId", playerId), zap.Any("roomId", pR.Id), zap.Any("roomState", pR.State), zap.Any("roomEffectivePlayerCount", pR.EffectivePlayerCount))
 | 
			
		||||
		signalToCloseConnOfThisPlayer(Constants.RetCode.ActiveWatchdog, "")
 | 
			
		||||
		pR.signalToCloseAllSessionsOfPlayer(playerId, Constants.RetCode.ActiveWatchdog)
 | 
			
		||||
	})
 | 
			
		||||
	newWatchdog.Stop()
 | 
			
		||||
	pR.PlayerActiveWatchdogDict[playerId] = newWatchdog
 | 
			
		||||
@@ -221,7 +227,7 @@ func (pR *Room) ReAddPlayerIfPossible(pTmpPlayerInstance *Player, session *webso
 | 
			
		||||
	pR.PlayerSignalToCloseDict[playerId] = signalToCloseConnOfThisPlayer
 | 
			
		||||
	pR.PlayerActiveWatchdogDict[playerId] = NewWatchdog(ConstVals.Ws.WillKickIfInactiveFor, func() {
 | 
			
		||||
		Logger.Warn("Conn inactive watchdog triggered#2:", zap.Any("playerId", playerId), zap.Any("roomId", pR.Id), zap.Any("roomState", pR.State), zap.Any("roomEffectivePlayerCount", pR.EffectivePlayerCount))
 | 
			
		||||
		signalToCloseConnOfThisPlayer(Constants.RetCode.ActiveWatchdog, "")
 | 
			
		||||
		pR.signalToCloseAllSessionsOfPlayer(playerId, Constants.RetCode.ActiveWatchdog)
 | 
			
		||||
	}) // For ReAdded player the new watchdog starts immediately
 | 
			
		||||
 | 
			
		||||
	Logger.Warn("ReAddPlayerIfPossible finished.", zap.Any("roomId", pR.Id), zap.Any("playerId", playerId), zap.Any("joinIndex", pEffectiveInRoomPlayerInstance.JoinIndex), zap.Any("playerBattleState", pEffectiveInRoomPlayerInstance.BattleState), zap.Any("roomState", pR.State), zap.Any("roomEffectivePlayerCount", pR.EffectivePlayerCount), zap.Any("AckingFrameId", pEffectiveInRoomPlayerInstance.AckingFrameId), zap.Any("AckingInputFrameId", pEffectiveInRoomPlayerInstance.AckingInputFrameId), zap.Any("LastSentInputFrameId", pEffectiveInRoomPlayerInstance.LastSentInputFrameId))
 | 
			
		||||
@@ -482,7 +488,7 @@ func (pR *Room) StartBattle() {
 | 
			
		||||
						kickoffFrameJs := pR.RenderFrameBuffer.GetByFrameId(0).(*battle.RoomDownsyncFrame)
 | 
			
		||||
						pbKickOffRenderFrame := toPbRoomDownsyncFrame(kickoffFrameJs)
 | 
			
		||||
						pbKickOffRenderFrame.SpeciesIdList = pR.SpeciesIdList
 | 
			
		||||
						pR.sendSafely(pbKickOffRenderFrame, nil, DOWNSYNC_MSG_ACT_BATTLE_START, playerId, true)
 | 
			
		||||
						pR.sendSafely(pbKickOffRenderFrame, nil, DOWNSYNC_MSG_ACT_BATTLE_START, playerId, true, MAGIC_JOIN_INDEX_DEFAULT)
 | 
			
		||||
					}
 | 
			
		||||
					Logger.Info(fmt.Sprintf("In `battleMainLoop` for roomId=%v sent out kickoffFrame", pR.Id))
 | 
			
		||||
				}
 | 
			
		||||
@@ -509,7 +515,7 @@ func (pR *Room) StartBattle() {
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	downsyncLoop := func(playerId int32, player *Player, playerDownsyncChan chan pb.InputsBufferSnapshot) {
 | 
			
		||||
	downsyncLoop := func(playerId int32, player *Player, playerDownsyncChan chan pb.InputsBufferSnapshot, playerSecondaryDownsyncChan chan pb.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))
 | 
			
		||||
@@ -517,19 +523,23 @@ func (pR *Room) StartBattle() {
 | 
			
		||||
			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))
 | 
			
		||||
		//Logger.Info(fmt.Sprintf("Started downsyncLoop for (roomId: %d, playerId:%d, playerDownsyncChan:%p)", pR.Id, playerId, playerDownsyncChan))
 | 
			
		||||
 | 
			
		||||
		for {
 | 
			
		||||
			nowBattleState := atomic.LoadInt32(&pR.State)
 | 
			
		||||
			switch nowBattleState {
 | 
			
		||||
			case RoomBattleStateIns.IDLE, RoomBattleStateIns.STOPPING_BATTLE_FOR_SETTLEMENT, RoomBattleStateIns.IN_SETTLEMENT, RoomBattleStateIns.IN_DISMISSAL:
 | 
			
		||||
				Logger.Warn(fmt.Sprintf("Battle is not waiting/preparing/active for playerDownsyncChan for (roomId: %d, playerId:%d)", pR.Id, playerId))
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			select {
 | 
			
		||||
			case inputsBufferSnapshot := <-playerDownsyncChan:
 | 
			
		||||
				nowBattleState := atomic.LoadInt32(&pR.State)
 | 
			
		||||
				switch nowBattleState {
 | 
			
		||||
				case RoomBattleStateIns.IDLE, RoomBattleStateIns.STOPPING_BATTLE_FOR_SETTLEMENT, RoomBattleStateIns.IN_SETTLEMENT, 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, inputsBufferSnapshot.ShouldForceResync)
 | 
			
		||||
				//Logger.Info(fmt.Sprintf("Sent inputsBufferSnapshot(refRenderFrameId:%d, unconfirmedMask:%v) to for (roomId: %d, playerId:%d)#2", inputsBufferSnapshot.RefRenderFrameId, inputsBufferSnapshot.UnconfirmedMask, pR.Id, playerId))
 | 
			
		||||
			case inputsBufferSnapshot2 := <-playerSecondaryDownsyncChan:
 | 
			
		||||
				pR.downsyncPeerInputFrameUpsyncToSinglePlayer(playerId, player, inputsBufferSnapshot2.ToSendInputFrameDownsyncs, inputsBufferSnapshot2.PeerJoinIndex)
 | 
			
		||||
				//Logger.Info(fmt.Sprintf("Sent secondary inputsBufferSnapshot to for (roomId: %d, playerId:%d)#2", pR.Id, playerId))
 | 
			
		||||
			default:
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
@@ -542,7 +552,8 @@ func (pR *Room) StartBattle() {
 | 
			
		||||
		   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 pb.InputsBufferSnapshot, pR.InputsBuffer.N)
 | 
			
		||||
		go downsyncLoop(playerId, player, pR.PlayerDownsyncChanDict[playerId])
 | 
			
		||||
		pR.PlayerSecondaryDownsyncChanDict[playerId] = make(chan pb.InputsBufferSnapshot, pR.InputsBuffer.N)
 | 
			
		||||
		go downsyncLoop(playerId, player, pR.PlayerDownsyncChanDict[playerId], pR.PlayerSecondaryDownsyncChanDict[playerId])
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pR.onBattlePrepare(func() {
 | 
			
		||||
@@ -599,6 +610,16 @@ func (pR *Room) OnBattleCmdReceived(pReq *pb.WsReq) {
 | 
			
		||||
	inputsBufferSnapshot := pR.markConfirmationIfApplicable(inputFrameUpsyncBatch, playerId, player)
 | 
			
		||||
	if nil != inputsBufferSnapshot {
 | 
			
		||||
		pR.downsyncToAllPlayers(inputsBufferSnapshot)
 | 
			
		||||
	} else {
 | 
			
		||||
		// no new all-confirmed
 | 
			
		||||
		toSendInputFrameDownsyncs := pR.cloneInputsBuffer(inputFrameUpsyncBatch[0].InputFrameId, inputFrameUpsyncBatch[len(inputFrameUpsyncBatch)-1].InputFrameId+1)
 | 
			
		||||
 | 
			
		||||
		inputsBufferSnapshot = &pb.InputsBufferSnapshot{
 | 
			
		||||
			ToSendInputFrameDownsyncs: toSendInputFrameDownsyncs,
 | 
			
		||||
			PeerJoinIndex:             player.JoinIndex,
 | 
			
		||||
		}
 | 
			
		||||
		//Logger.Info(fmt.Sprintf("OnBattleCmdReceived no new all-confirmed: roomId=%v, fromPlayerId=%v, forming peer broadcasting snapshot=%v", pR.Id, playerId, inputsBufferSnapshot))
 | 
			
		||||
		pR.broadcastPeerUpsyncForBetterPrediction(inputsBufferSnapshot)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -650,7 +671,7 @@ func (pR *Room) StopBattleForSettlement() {
 | 
			
		||||
			PlayersArr:     toPbPlayers(pR.Players, false),
 | 
			
		||||
			CountdownNanos: -1, // TODO: Replace this magic constant!
 | 
			
		||||
		}
 | 
			
		||||
		pR.sendSafely(&assembledFrame, nil, DOWNSYNC_MSG_ACT_BATTLE_STOPPED, playerId, true)
 | 
			
		||||
		pR.sendSafely(&assembledFrame, nil, DOWNSYNC_MSG_ACT_BATTLE_STOPPED, playerId, true, MAGIC_JOIN_INDEX_DEFAULT)
 | 
			
		||||
	}
 | 
			
		||||
	// Note that `pR.onBattleStoppedForSettlement` will be called by `battleMainLoop`.
 | 
			
		||||
}
 | 
			
		||||
@@ -679,7 +700,7 @@ func (pR *Room) onBattlePrepare(cb BattleStartCbType) {
 | 
			
		||||
 | 
			
		||||
	Logger.Info("Sending out frame for RoomBattleState.PREPARE:", zap.Any("battleReadyToStartFrame", battleReadyToStartFrame))
 | 
			
		||||
	for _, player := range pR.Players {
 | 
			
		||||
		pR.sendSafely(battleReadyToStartFrame, nil, DOWNSYNC_MSG_ACT_BATTLE_READY_TO_START, player.Id, true)
 | 
			
		||||
		pR.sendSafely(battleReadyToStartFrame, nil, DOWNSYNC_MSG_ACT_BATTLE_READY_TO_START, player.Id, true, MAGIC_JOIN_INDEX_DEFAULT)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	battlePreparationNanos := int64(6000000000)
 | 
			
		||||
@@ -748,6 +769,7 @@ func (pR *Room) OnDismissed() {
 | 
			
		||||
	pR.CharacterConfigsArr = make([]*battle.CharacterConfig, pR.Capacity)
 | 
			
		||||
	pR.CollisionSysMap = make(map[int32]*resolv.Object)
 | 
			
		||||
	pR.PlayerDownsyncSessionDict = make(map[int32]*websocket.Conn)
 | 
			
		||||
	pR.PlayerSecondaryDownsyncSessionDict = make(map[int32]*websocket.Conn)
 | 
			
		||||
	for _, oldWatchdog := range pR.PlayerActiveWatchdogDict {
 | 
			
		||||
		oldWatchdog.Stop()
 | 
			
		||||
	}
 | 
			
		||||
@@ -756,7 +778,12 @@ func (pR *Room) OnDismissed() {
 | 
			
		||||
		close(oldChan)
 | 
			
		||||
	}
 | 
			
		||||
	pR.PlayerDownsyncChanDict = make(map[int32](chan pb.InputsBufferSnapshot))
 | 
			
		||||
	for _, oldChan := range pR.PlayerSecondaryDownsyncChanDict {
 | 
			
		||||
		close(oldChan)
 | 
			
		||||
	}
 | 
			
		||||
	pR.PlayerSecondaryDownsyncChanDict = make(map[int32](chan pb.InputsBufferSnapshot))
 | 
			
		||||
	pR.PlayerSignalToCloseDict = make(map[int32]SignalToCloseConnCbType)
 | 
			
		||||
	pR.PlayerSecondarySignalToCloseDict = make(map[int32]SignalToCloseConnCbType)
 | 
			
		||||
	pR.JoinIndexBooleanArr = make([]bool, pR.Capacity)
 | 
			
		||||
	pR.RenderCacheSize = 1024
 | 
			
		||||
	pR.RenderFrameBuffer = battle.NewRingBuffer(pR.RenderCacheSize)
 | 
			
		||||
@@ -799,19 +826,24 @@ func (pR *Room) OnDismissed() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (pR *Room) expelPlayerDuringGame(playerId int32) {
 | 
			
		||||
	if signalToCloseConnOfThisPlayer, existent := pR.PlayerSignalToCloseDict[playerId]; existent {
 | 
			
		||||
		signalToCloseConnOfThisPlayer(Constants.RetCode.UnknownError, "") // TODO: Specify an error code
 | 
			
		||||
	}
 | 
			
		||||
	pR.signalToCloseAllSessionsOfPlayer(playerId, Constants.RetCode.UnknownError)
 | 
			
		||||
	pR.onPlayerExpelledDuringGame(playerId)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (pR *Room) expelPlayerForDismissal(playerId int32) {
 | 
			
		||||
	if signalToCloseConnOfThisPlayer, existent := pR.PlayerSignalToCloseDict[playerId]; existent {
 | 
			
		||||
		signalToCloseConnOfThisPlayer(Constants.RetCode.UnknownError, "") // TODO: Specify an error code
 | 
			
		||||
	}
 | 
			
		||||
	pR.signalToCloseAllSessionsOfPlayer(playerId, Constants.RetCode.UnknownError)
 | 
			
		||||
	pR.onPlayerExpelledForDismissal(playerId)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (pR *Room) signalToCloseAllSessionsOfPlayer(playerId int32, retCode int) {
 | 
			
		||||
	if signalToCloseConnOfThisPlayer, existent := pR.PlayerSignalToCloseDict[playerId]; existent {
 | 
			
		||||
		signalToCloseConnOfThisPlayer(retCode, "") // TODO: Specify an error code
 | 
			
		||||
	}
 | 
			
		||||
	if signalToCloseConnOfThisPlayer2, existent2 := pR.PlayerSecondarySignalToCloseDict[playerId]; existent2 {
 | 
			
		||||
		signalToCloseConnOfThisPlayer2(retCode, "") // TODO: Specify an error code
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (pR *Room) onPlayerExpelledDuringGame(playerId int32) {
 | 
			
		||||
	pR.onPlayerLost(playerId)
 | 
			
		||||
}
 | 
			
		||||
@@ -829,6 +861,10 @@ func (pR *Room) OnPlayerDisconnected(playerId int32) {
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	if signalToCloseConnOfThisPlayer2, existent2 := pR.PlayerSecondarySignalToCloseDict[playerId]; existent2 {
 | 
			
		||||
		signalToCloseConnOfThisPlayer2(Constants.RetCode.UnknownError, "") // TODO: Specify an error code
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if player, existent := pR.Players[playerId]; existent {
 | 
			
		||||
		thatPlayerBattleState := atomic.LoadInt32(&(player.BattleState))
 | 
			
		||||
		switch thatPlayerBattleState {
 | 
			
		||||
@@ -888,6 +924,8 @@ func (pR *Room) clearPlayerNetworkSession(playerId int32) {
 | 
			
		||||
		delete(pR.PlayerActiveWatchdogDict, playerId)
 | 
			
		||||
		delete(pR.PlayerDownsyncSessionDict, playerId)
 | 
			
		||||
		delete(pR.PlayerSignalToCloseDict, playerId)
 | 
			
		||||
		delete(pR.PlayerSecondaryDownsyncSessionDict, playerId)
 | 
			
		||||
		delete(pR.PlayerSecondarySignalToCloseDict, playerId)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -977,7 +1015,7 @@ func (pR *Room) OnPlayerBattleColliderAcked(playerId int32) bool {
 | 
			
		||||
			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) {
 | 
			
		||||
				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, true)
 | 
			
		||||
				pR.sendSafely(playerAckedFrame, nil, DOWNSYNC_MSG_ACT_PLAYER_ADDED_AND_ACKED, thatPlayer.Id, true, MAGIC_JOIN_INDEX_DEFAULT)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		atomic.StoreInt32(&(targetPlayer.BattleState), PlayerBattleStateIns.ACTIVE)
 | 
			
		||||
@@ -1010,28 +1048,43 @@ func (pR *Room) OnPlayerBattleColliderAcked(playerId int32) bool {
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (pR *Room) sendSafely(roomDownsyncFrame *pb.RoomDownsyncFrame, toSendInputFrameDownsyncs []*pb.InputFrameDownsync, act int32, playerId int32, needLockExplicitly bool) {
 | 
			
		||||
func (pR *Room) sendSafely(roomDownsyncFrame *pb.RoomDownsyncFrame, toSendInputFrameDownsyncs []*pb.InputFrameDownsync, act int32, playerId int32, needLockExplicitly bool, peerJoinIndex int32) {
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if r := recover(); r != nil {
 | 
			
		||||
			Logger.Error("sendSafely, recovered from: ", zap.Any("roomId", pR.Id), zap.Any("playerId", playerId), zap.Any("panic", r))
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	if playerDownsyncSession, existent := pR.PlayerDownsyncSessionDict[playerId]; existent {
 | 
			
		||||
		pResp := &pb.WsResp{
 | 
			
		||||
			Ret:                     int32(Constants.RetCode.Ok),
 | 
			
		||||
			Act:                     act,
 | 
			
		||||
			Rdf:                     roomDownsyncFrame,
 | 
			
		||||
			InputFrameDownsyncBatch: toSendInputFrameDownsyncs,
 | 
			
		||||
		}
 | 
			
		||||
	pResp := &pb.WsResp{
 | 
			
		||||
		Ret:                     int32(Constants.RetCode.Ok),
 | 
			
		||||
		Act:                     act,
 | 
			
		||||
		Rdf:                     roomDownsyncFrame,
 | 
			
		||||
		InputFrameDownsyncBatch: toSendInputFrameDownsyncs,
 | 
			
		||||
		PeerJoinIndex:           peerJoinIndex,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
		theBytes, marshalErr := proto.Marshal(pResp)
 | 
			
		||||
		if nil != marshalErr {
 | 
			
		||||
			panic(fmt.Sprintf("Error marshaling downsync message: roomId=%v, playerId=%v, roomState=%v, roomEffectivePlayerCount=%v", pR.Id, playerId, pR.State, pR.EffectivePlayerCount))
 | 
			
		||||
		}
 | 
			
		||||
	theBytes, marshalErr := proto.Marshal(pResp)
 | 
			
		||||
	if nil != marshalErr {
 | 
			
		||||
		panic(fmt.Sprintf("Error marshaling downsync message: roomId=%v, playerId=%v, roomState=%v, roomEffectivePlayerCount=%v", pR.Id, playerId, pR.State, pR.EffectivePlayerCount))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
		if err := playerDownsyncSession.WriteMessage(websocket.BinaryMessage, theBytes); nil != err {
 | 
			
		||||
			panic(fmt.Sprintf("Error sending downsync message: roomId=%v, playerId=%v, roomState=%v, roomEffectivePlayerCount=%v, err=%v", pR.Id, playerId, pR.State, pR.EffectivePlayerCount, err))
 | 
			
		||||
	if MAGIC_JOIN_INDEX_DEFAULT == peerJoinIndex {
 | 
			
		||||
		if playerDownsyncSession, existent := pR.PlayerDownsyncSessionDict[playerId]; existent {
 | 
			
		||||
			if err := playerDownsyncSession.WriteMessage(websocket.BinaryMessage, theBytes); nil != err {
 | 
			
		||||
				panic(fmt.Sprintf("Error sending primary downsync message: roomId=%v, playerId=%v, roomState=%v, roomEffectivePlayerCount=%v, err=%v", pR.Id, playerId, pR.State, pR.EffectivePlayerCount, err))
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		/*
 | 
			
		||||
		   [FIXME]
 | 
			
		||||
		   This branch is preferred to use an additional session of each player for sending, and the session is preferrably UDP instead of any TCP-based protocol, but I'm being lazy here.
 | 
			
		||||
 | 
			
		||||
		   See `<proj-root>/ConcerningEdgeCases.md` for the advantage of using UDP as a supplement.
 | 
			
		||||
		*/
 | 
			
		||||
		if playerSecondaryDownsyncSession, existent := pR.PlayerSecondaryDownsyncSessionDict[playerId]; existent {
 | 
			
		||||
			if err := playerSecondaryDownsyncSession.WriteMessage(websocket.BinaryMessage, theBytes); nil != err {
 | 
			
		||||
				panic(fmt.Sprintf("Error sending secondary downsync message: roomId=%v, playerId=%v, roomState=%v, roomEffectivePlayerCount=%v, err=%v", pR.Id, playerId, pR.State, pR.EffectivePlayerCount, err))
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -1347,6 +1400,30 @@ func (pR *Room) doBattleMainLoopPerTickBackendDynamicsWithProperLocking(prevRend
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (pR *Room) broadcastPeerUpsyncForBetterPrediction(inputsBufferSnapshot *pb.InputsBufferSnapshot) {
 | 
			
		||||
	// See `<proj-root>/ConcerningEdgeCases.md` for why this method exists.
 | 
			
		||||
	for _, player := range pR.PlayersArr {
 | 
			
		||||
		playerBattleState := atomic.LoadInt32(&(player.BattleState))
 | 
			
		||||
		switch playerBattleState {
 | 
			
		||||
		case PlayerBattleStateIns.DISCONNECTED, PlayerBattleStateIns.LOST, PlayerBattleStateIns.EXPELLED_DURING_GAME, PlayerBattleStateIns.EXPELLED_IN_DISMISSAL, PlayerBattleStateIns.ADDED_PENDING_BATTLE_COLLIDER_ACK, PlayerBattleStateIns.READDED_PENDING_BATTLE_COLLIDER_ACK:
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if player.JoinIndex == inputsBufferSnapshot.PeerJoinIndex {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if playerSecondaryDownsyncChan, existent := pR.PlayerSecondaryDownsyncChanDict[player.Id]; existent {
 | 
			
		||||
			/*
 | 
			
		||||
			   [FIXME]
 | 
			
		||||
			   This function is preferred to use an additional go-channel of each player for sending, see "downsyncLoop" & "Room.sendSafely" for more information!
 | 
			
		||||
			*/
 | 
			
		||||
			playerSecondaryDownsyncChan <- (*inputsBufferSnapshot)
 | 
			
		||||
		} else {
 | 
			
		||||
			Logger.Warn(fmt.Sprintf("playerDownsyncChan for (roomId: %d, playerId:%d) is gone", pR.Id, player.Id))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (pR *Room) downsyncToAllPlayers(inputsBufferSnapshot *pb.InputsBufferSnapshot) {
 | 
			
		||||
	/*
 | 
			
		||||
		       [WARNING] This function MUST BE called while "pR.InputsBufferLock" is LOCKED to **preserve the order of generation of "inputsBufferSnapshot" for sending** -- see comments in "OnBattleCmdReceived" and [this issue](https://github.com/genxium/DelayNoMore/issues/12).
 | 
			
		||||
@@ -1423,14 +1500,14 @@ func (pR *Room) downsyncToSinglePlayer(playerId int32, player *Player, refRender
 | 
			
		||||
	   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
 | 
			
		||||
	playerJoinIndexInBooleanArr := player.JoinIndex - 1
 | 
			
		||||
	playerBattleState := atomic.LoadInt32(&(player.BattleState))
 | 
			
		||||
	switch playerBattleState {
 | 
			
		||||
	case PlayerBattleStateIns.DISCONNECTED, PlayerBattleStateIns.LOST, PlayerBattleStateIns.EXPELLED_DURING_GAME, PlayerBattleStateIns.EXPELLED_IN_DISMISSAL, PlayerBattleStateIns.ADDED_PENDING_BATTLE_COLLIDER_ACK, PlayerBattleStateIns.READDED_PENDING_BATTLE_COLLIDER_ACK:
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	isSlowTicker := (0 < (unconfirmedMask & uint64(1<<uint32(playerJoinIndex))))
 | 
			
		||||
	isSlowTicker := (0 < (unconfirmedMask & uint64(1<<uint32(playerJoinIndexInBooleanArr))))
 | 
			
		||||
	shouldResync1 := (PlayerBattleStateIns.READDED_BATTLE_COLLIDER_ACKED == playerBattleState) // i.e. implies that "MAGIC_LAST_SENT_INPUT_FRAME_ID_READDED == player.LastSentInputFrameId"
 | 
			
		||||
	shouldResync2 := isSlowTicker                                                              // 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
 | 
			
		||||
	shouldResync3 := shouldForceResync
 | 
			
		||||
@@ -1455,13 +1532,13 @@ func (pR *Room) downsyncToSinglePlayer(playerId int32, player *Player, refRender
 | 
			
		||||
		refRenderFrame.BackendUnconfirmedMask = unconfirmedMask
 | 
			
		||||
		pbRefRenderFrame := toPbRoomDownsyncFrame(refRenderFrame)
 | 
			
		||||
		pbRefRenderFrame.SpeciesIdList = pR.SpeciesIdList
 | 
			
		||||
		pR.sendSafely(pbRefRenderFrame, toSendInputFrameDownsyncsSnapshot, DOWNSYNC_MSG_ACT_FORCED_RESYNC, playerId, false)
 | 
			
		||||
		pR.sendSafely(pbRefRenderFrame, toSendInputFrameDownsyncsSnapshot, DOWNSYNC_MSG_ACT_FORCED_RESYNC, playerId, false, MAGIC_JOIN_INDEX_DEFAULT)
 | 
			
		||||
		//Logger.Warn(fmt.Sprintf("Sent refRenderFrameId=%v & inputFrameIds [%d, %d), for roomId=%v, playerId=%d, playerJoinIndex=%d, renderFrameId=%d, curDynamicsRenderFrameId=%d, playerLastSentInputFrameId=%d: InputsBuffer=%v", refRenderFrameId, toSendInputFrameIdSt, toSendInputFrameIdEd, pR.Id, playerId, player.JoinIndex, pR.RenderFrameId, pR.CurDynamicsRenderFrameId, player.LastSentInputFrameId, pR.InputsBufferString(false)))
 | 
			
		||||
		if shouldResync1 || shouldResync3 {
 | 
			
		||||
			Logger.Debug(fmt.Sprintf("Sent refRenderFrameId=%v & inputFrameIds [%d, %d), for roomId=%v, playerId=%d, playerJoinIndex=%d, renderFrameId=%d, curDynamicsRenderFrameId=%d, playerLastSentInputFrameId=%d: shouldResync1=%v, shouldResync2=%v, shouldResync3=%v, playerBattleState=%d", refRenderFrameId, toSendInputFrameIdSt, toSendInputFrameIdEd, pR.Id, playerId, player.JoinIndex, pR.RenderFrameId, pR.CurDynamicsRenderFrameId, player.LastSentInputFrameId, shouldResync1, shouldResync2, shouldResync3, playerBattleState))
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		pR.sendSafely(nil, toSendInputFrameDownsyncsSnapshot, DOWNSYNC_MSG_ACT_INPUT_BATCH, playerId, false)
 | 
			
		||||
		pR.sendSafely(nil, toSendInputFrameDownsyncsSnapshot, DOWNSYNC_MSG_ACT_INPUT_BATCH, playerId, false, MAGIC_JOIN_INDEX_DEFAULT)
 | 
			
		||||
	}
 | 
			
		||||
	player.LastSentInputFrameId = toSendInputFrameIdEd - 1
 | 
			
		||||
	if shouldResync1 {
 | 
			
		||||
@@ -1469,6 +1546,16 @@ func (pR *Room) downsyncToSinglePlayer(playerId int32, player *Player, refRender
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (pR *Room) downsyncPeerInputFrameUpsyncToSinglePlayer(playerId int32, player *Player, toSendInputFrameDownsyncsSnapshot []*pb.InputFrameDownsync, peerJoinIndex int32) {
 | 
			
		||||
	playerBattleState := atomic.LoadInt32(&(player.BattleState))
 | 
			
		||||
	switch playerBattleState {
 | 
			
		||||
	case PlayerBattleStateIns.DISCONNECTED, PlayerBattleStateIns.LOST, PlayerBattleStateIns.EXPELLED_DURING_GAME, PlayerBattleStateIns.EXPELLED_IN_DISMISSAL, PlayerBattleStateIns.ADDED_PENDING_BATTLE_COLLIDER_ACK, PlayerBattleStateIns.READDED_PENDING_BATTLE_COLLIDER_ACK:
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pR.sendSafely(nil, toSendInputFrameDownsyncsSnapshot, DOWNSYNC_MSG_ACT_PEER_INPUT_BATCH, playerId, false, peerJoinIndex)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (pR *Room) cloneInputsBuffer(stFrameId, edFrameId int32) []*pb.InputFrameDownsync {
 | 
			
		||||
	// [WARNING] This function MUST BE called while "pR.InputsBufferLock" is locked!
 | 
			
		||||
	cloned := make([]*pb.InputFrameDownsync, 0, edFrameId-stFrameId)
 | 
			
		||||
@@ -1501,3 +1588,22 @@ func (pR *Room) cloneInputsBuffer(stFrameId, edFrameId int32) []*pb.InputFrameDo
 | 
			
		||||
 | 
			
		||||
	return cloned
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (pR *Room) SetSecondarySession(playerId int32, session *websocket.Conn, signalToCloseConnOfThisPlayer SignalToCloseConnCbType) {
 | 
			
		||||
	// TODO: Use a dedicated lock
 | 
			
		||||
	if player, ok := pR.Players[playerId]; ok {
 | 
			
		||||
		playerBattleState := atomic.LoadInt32(&(player.BattleState))
 | 
			
		||||
		switch playerBattleState {
 | 
			
		||||
		case PlayerBattleStateIns.DISCONNECTED, PlayerBattleStateIns.LOST, PlayerBattleStateIns.EXPELLED_DURING_GAME, PlayerBattleStateIns.EXPELLED_IN_DISMISSAL:
 | 
			
		||||
			// Kindly note that "PlayerBattleStateIns.ADDED_PENDING_BATTLE_COLLIDER_ACK, PlayerBattleStateIns.READDED_PENDING_BATTLE_COLLIDER_ACK" are allowed
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		if _, existent := pR.PlayerDownsyncSessionDict[playerId]; existent {
 | 
			
		||||
			if _, existent2 := pR.PlayerSecondaryDownsyncSessionDict[playerId]; !existent2 {
 | 
			
		||||
				Logger.Info(fmt.Sprintf("SetSecondarySession for roomId=%v, playerId=%d, pR.Players=%v", pR.Id, playerId, pR.Players))
 | 
			
		||||
				pR.PlayerSecondaryDownsyncSessionDict[playerId] = session
 | 
			
		||||
				pR.PlayerSecondarySignalToCloseDict[playerId] = signalToCloseConnOfThisPlayer
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -386,6 +386,7 @@ type InputFrameUpsync struct {
 | 
			
		||||
 | 
			
		||||
	InputFrameId int32  `protobuf:"varint,1,opt,name=inputFrameId,proto3" json:"inputFrameId,omitempty"`
 | 
			
		||||
	Encoded      uint64 `protobuf:"varint,2,opt,name=encoded,proto3" json:"encoded,omitempty"`
 | 
			
		||||
	JoinIndex    int32  `protobuf:"varint,3,opt,name=joinIndex,proto3" json:"joinIndex,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *InputFrameUpsync) Reset() {
 | 
			
		||||
@@ -434,6 +435,13 @@ func (x *InputFrameUpsync) GetEncoded() uint64 {
 | 
			
		||||
	return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *InputFrameUpsync) GetJoinIndex() int32 {
 | 
			
		||||
	if x != nil {
 | 
			
		||||
		return x.JoinIndex
 | 
			
		||||
	}
 | 
			
		||||
	return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type InputFrameDownsync struct {
 | 
			
		||||
	state         protoimpl.MessageState
 | 
			
		||||
	sizeCache     protoimpl.SizeCache
 | 
			
		||||
@@ -658,6 +666,7 @@ type WsResp struct {
 | 
			
		||||
	Rdf                     *RoomDownsyncFrame    `protobuf:"bytes,4,opt,name=rdf,proto3" json:"rdf,omitempty"`
 | 
			
		||||
	InputFrameDownsyncBatch []*InputFrameDownsync `protobuf:"bytes,5,rep,name=inputFrameDownsyncBatch,proto3" json:"inputFrameDownsyncBatch,omitempty"`
 | 
			
		||||
	BciFrame                *BattleColliderInfo   `protobuf:"bytes,6,opt,name=bciFrame,proto3" json:"bciFrame,omitempty"`
 | 
			
		||||
	PeerJoinIndex           int32                 `protobuf:"varint,7,opt,name=peerJoinIndex,proto3" json:"peerJoinIndex,omitempty"` // Only used when "InputsBufferSnapshot.peerJoinIndex" is used.
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *WsResp) Reset() {
 | 
			
		||||
@@ -734,6 +743,13 @@ func (x *WsResp) GetBciFrame() *BattleColliderInfo {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *WsResp) GetPeerJoinIndex() int32 {
 | 
			
		||||
	if x != nil {
 | 
			
		||||
		return x.PeerJoinIndex
 | 
			
		||||
	}
 | 
			
		||||
	return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type InputsBufferSnapshot struct {
 | 
			
		||||
	state         protoimpl.MessageState
 | 
			
		||||
	sizeCache     protoimpl.SizeCache
 | 
			
		||||
@@ -743,6 +759,7 @@ type InputsBufferSnapshot struct {
 | 
			
		||||
	UnconfirmedMask           uint64                `protobuf:"varint,2,opt,name=unconfirmedMask,proto3" json:"unconfirmedMask,omitempty"`
 | 
			
		||||
	ToSendInputFrameDownsyncs []*InputFrameDownsync `protobuf:"bytes,3,rep,name=toSendInputFrameDownsyncs,proto3" json:"toSendInputFrameDownsyncs,omitempty"`
 | 
			
		||||
	ShouldForceResync         bool                  `protobuf:"varint,4,opt,name=shouldForceResync,proto3" json:"shouldForceResync,omitempty"`
 | 
			
		||||
	PeerJoinIndex             int32                 `protobuf:"varint,5,opt,name=peerJoinIndex,proto3" json:"peerJoinIndex,omitempty"` // Only used when "WsResp.peerJoinIndex" is used.
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *InputsBufferSnapshot) Reset() {
 | 
			
		||||
@@ -805,6 +822,13 @@ func (x *InputsBufferSnapshot) GetShouldForceResync() bool {
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *InputsBufferSnapshot) GetPeerJoinIndex() int32 {
 | 
			
		||||
	if x != nil {
 | 
			
		||||
		return x.PeerJoinIndex
 | 
			
		||||
	}
 | 
			
		||||
	return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type MeleeBullet struct {
 | 
			
		||||
	state         protoimpl.MessageState
 | 
			
		||||
	sizeCache     protoimpl.SizeCache
 | 
			
		||||
@@ -1659,276 +1683,282 @@ var file_room_downsync_frame_proto_rawDesc = []byte{
 | 
			
		||||
	0x12, 0x1c, 0x0a, 0x09, 0x62, 0x74, 0x6e, 0x41, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x03, 0x20,
 | 
			
		||||
	0x01, 0x28, 0x05, 0x52, 0x09, 0x62, 0x74, 0x6e, 0x41, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x1c,
 | 
			
		||||
	0x0a, 0x09, 0x62, 0x74, 0x6e, 0x42, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28,
 | 
			
		||||
	0x05, 0x52, 0x09, 0x62, 0x74, 0x6e, 0x42, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0x50, 0x0a, 0x10,
 | 
			
		||||
	0x05, 0x52, 0x09, 0x62, 0x74, 0x6e, 0x42, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0x6e, 0x0a, 0x10,
 | 
			
		||||
	0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63,
 | 
			
		||||
	0x12, 0x22, 0x0a, 0x0c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64,
 | 
			
		||||
	0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61,
 | 
			
		||||
	0x6d, 0x65, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x18,
 | 
			
		||||
	0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x22, 0x7c,
 | 
			
		||||
	0x0a, 0x12, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e,
 | 
			
		||||
	0x73, 0x79, 0x6e, 0x63, 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61,
 | 
			
		||||
	0x6d, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x69, 0x6e, 0x70, 0x75,
 | 
			
		||||
	0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x70, 0x75,
 | 
			
		||||
	0x74, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x04, 0x52, 0x09, 0x69, 0x6e, 0x70,
 | 
			
		||||
	0x75, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72,
 | 
			
		||||
	0x6d, 0x65, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x63,
 | 
			
		||||
	0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x3b, 0x0a, 0x0f,
 | 
			
		||||
	0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x12,
 | 
			
		||||
	0x28, 0x0a, 0x0f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
 | 
			
		||||
	0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74,
 | 
			
		||||
	0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0xb8, 0x02, 0x0a, 0x05, 0x57, 0x73,
 | 
			
		||||
	0x52, 0x65, 0x71, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x73, 0x67, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01,
 | 
			
		||||
	0x28, 0x05, 0x52, 0x05, 0x6d, 0x73, 0x67, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61,
 | 
			
		||||
	0x79, 0x65, 0x72, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x6c, 0x61,
 | 
			
		||||
	0x79, 0x65, 0x72, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01,
 | 
			
		||||
	0x28, 0x05, 0x52, 0x03, 0x61, 0x63, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6a, 0x6f, 0x69, 0x6e, 0x49,
 | 
			
		||||
	0x6e, 0x64, 0x65, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x6a, 0x6f, 0x69, 0x6e,
 | 
			
		||||
	0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x24, 0x0a, 0x0d, 0x61, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x46,
 | 
			
		||||
	0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x61, 0x63,
 | 
			
		||||
	0x6b, 0x69, 0x6e, 0x67, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x12, 0x61,
 | 
			
		||||
	0x63, 0x6b, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49,
 | 
			
		||||
	0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x61, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x49,
 | 
			
		||||
	0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x4e, 0x0a, 0x15, 0x69,
 | 
			
		||||
	0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x42,
 | 
			
		||||
	0x61, 0x74, 0x63, 0x68, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f,
 | 
			
		||||
	0x74, 0x6f, 0x73, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70,
 | 
			
		||||
	0x73, 0x79, 0x6e, 0x63, 0x52, 0x15, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65,
 | 
			
		||||
	0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x42, 0x61, 0x74, 0x63, 0x68, 0x12, 0x27, 0x0a, 0x02, 0x68,
 | 
			
		||||
	0x62, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73,
 | 
			
		||||
	0x2e, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63,
 | 
			
		||||
	0x52, 0x02, 0x68, 0x62, 0x22, 0x89, 0x02, 0x0a, 0x06, 0x57, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12,
 | 
			
		||||
	0x10, 0x0a, 0x03, 0x72, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x72, 0x65,
 | 
			
		||||
	0x74, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x63, 0x68, 0x6f, 0x65, 0x64, 0x4d, 0x73, 0x67, 0x49, 0x64,
 | 
			
		||||
	0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x65, 0x63, 0x68, 0x6f, 0x65, 0x64, 0x4d, 0x73,
 | 
			
		||||
	0x67, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05,
 | 
			
		||||
	0x52, 0x03, 0x61, 0x63, 0x74, 0x12, 0x2b, 0x0a, 0x03, 0x72, 0x64, 0x66, 0x18, 0x04, 0x20, 0x01,
 | 
			
		||||
	0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x52, 0x6f, 0x6f, 0x6d,
 | 
			
		||||
	0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x03, 0x72,
 | 
			
		||||
	0x64, 0x66, 0x12, 0x54, 0x0a, 0x17, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65,
 | 
			
		||||
	0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x42, 0x61, 0x74, 0x63, 0x68, 0x18, 0x05, 0x20,
 | 
			
		||||
	0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x49, 0x6e, 0x70,
 | 
			
		||||
	0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x52,
 | 
			
		||||
	0x17, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73,
 | 
			
		||||
	0x79, 0x6e, 0x63, 0x42, 0x61, 0x74, 0x63, 0x68, 0x12, 0x36, 0x0a, 0x08, 0x62, 0x63, 0x69, 0x46,
 | 
			
		||||
	0x72, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f,
 | 
			
		||||
	0x74, 0x6f, 0x73, 0x2e, 0x42, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x6c, 0x69, 0x64,
 | 
			
		||||
	0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x62, 0x63, 0x69, 0x46, 0x72, 0x61, 0x6d, 0x65,
 | 
			
		||||
	0x22, 0xf4, 0x01, 0x0a, 0x14, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x42, 0x75, 0x66, 0x66, 0x65,
 | 
			
		||||
	0x72, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x2a, 0x0a, 0x10, 0x72, 0x65, 0x66,
 | 
			
		||||
	0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20,
 | 
			
		||||
	0x01, 0x28, 0x05, 0x52, 0x10, 0x72, 0x65, 0x66, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72,
 | 
			
		||||
	0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x0f, 0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69,
 | 
			
		||||
	0x72, 0x6d, 0x65, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f,
 | 
			
		||||
	0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x12,
 | 
			
		||||
	0x58, 0x0a, 0x19, 0x74, 0x6f, 0x53, 0x65, 0x6e, 0x64, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72,
 | 
			
		||||
	0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x73, 0x18, 0x03, 0x20, 0x03,
 | 
			
		||||
	0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x49, 0x6e, 0x70, 0x75,
 | 
			
		||||
	0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x52, 0x19,
 | 
			
		||||
	0x74, 0x6f, 0x53, 0x65, 0x6e, 0x64, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65,
 | 
			
		||||
	0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x73, 0x12, 0x2c, 0x0a, 0x11, 0x73, 0x68, 0x6f,
 | 
			
		||||
	0x75, 0x6c, 0x64, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x04,
 | 
			
		||||
	0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x46, 0x6f, 0x72, 0x63,
 | 
			
		||||
	0x65, 0x52, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x22, 0x89, 0x07, 0x0a, 0x0b, 0x4d, 0x65, 0x6c, 0x65,
 | 
			
		||||
	0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 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, 0x01, 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, 0x2c, 0x0a, 0x11, 0x6f, 0x66, 0x66, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4a, 0x6f, 0x69,
 | 
			
		||||
	0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x6f, 0x66,
 | 
			
		||||
	0x66, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12,
 | 
			
		||||
	0x24, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73,
 | 
			
		||||
	0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x46,
 | 
			
		||||
	0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x2e, 0x0a, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c,
 | 
			
		||||
	0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28,
 | 
			
		||||
	0x05, 0x52, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74,
 | 
			
		||||
	0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c,
 | 
			
		||||
	0x61, 0x62, 0x6c, 0x65, 0x45, 0x64, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28,
 | 
			
		||||
	0x05, 0x52, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x64,
 | 
			
		||||
	0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46,
 | 
			
		||||
	0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x61, 0x63, 0x74,
 | 
			
		||||
	0x69, 0x76, 0x65, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74,
 | 
			
		||||
	0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x07, 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, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53,
 | 
			
		||||
	0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x75, 0x73,
 | 
			
		||||
	0x68, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52,
 | 
			
		||||
	0x0c, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58, 0x12, 0x22, 0x0a,
 | 
			
		||||
	0x0c, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x59, 0x18, 0x0a, 0x20,
 | 
			
		||||
	0x01, 0x28, 0x05, 0x52, 0x0c, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c,
 | 
			
		||||
	0x59, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x61, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28,
 | 
			
		||||
	0x05, 0x52, 0x06, 0x64, 0x61, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x65, 0x6c,
 | 
			
		||||
	0x66, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x05, 0x52,
 | 
			
		||||
	0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58, 0x12, 0x22, 0x0a,
 | 
			
		||||
	0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x59, 0x18, 0x0d, 0x20,
 | 
			
		||||
	0x01, 0x28, 0x05, 0x52, 0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c,
 | 
			
		||||
	0x59, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65,
 | 
			
		||||
	0x74, 0x58, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78,
 | 
			
		||||
	0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x58, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f,
 | 
			
		||||
	0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x59, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d,
 | 
			
		||||
	0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x59, 0x12, 0x20, 0x0a,
 | 
			
		||||
	0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x58, 0x18, 0x10, 0x20, 0x01,
 | 
			
		||||
	0x28, 0x05, 0x52, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x58, 0x12,
 | 
			
		||||
	0x20, 0x0a, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x59, 0x18, 0x11,
 | 
			
		||||
	0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65,
 | 
			
		||||
	0x59, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x6c, 0x6f, 0x77, 0x55, 0x70, 0x18, 0x12, 0x20, 0x01, 0x28,
 | 
			
		||||
	0x08, 0x52, 0x06, 0x62, 0x6c, 0x6f, 0x77, 0x55, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x65, 0x61,
 | 
			
		||||
	0x6d, 0x49, 0x64, 0x18, 0x13, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x74, 0x65, 0x61, 0x6d, 0x49,
 | 
			
		||||
	0x64, 0x12, 0x24, 0x0a, 0x0d, 0x62, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x6c,
 | 
			
		||||
	0x49, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x62, 0x75, 0x6c, 0x6c, 0x65, 0x74,
 | 
			
		||||
	0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x70, 0x65, 0x63, 0x69,
 | 
			
		||||
	0x65, 0x73, 0x49, 0x64, 0x18, 0x15, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x70, 0x65, 0x63,
 | 
			
		||||
	0x69, 0x65, 0x73, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x0f, 0x65, 0x78, 0x70, 0x6c, 0x6f, 0x73, 0x69,
 | 
			
		||||
	0x6f, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x16, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f,
 | 
			
		||||
	0x65, 0x78, 0x70, 0x6c, 0x6f, 0x73, 0x69, 0x6f, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12,
 | 
			
		||||
	0x18, 0x0a, 0x07, 0x62, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x17, 0x20, 0x01, 0x28, 0x05,
 | 
			
		||||
	0x52, 0x07, 0x62, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x66, 0x72, 0x61,
 | 
			
		||||
	0x6d, 0x65, 0x73, 0x49, 0x6e, 0x42, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x18, 0x20, 0x01,
 | 
			
		||||
	0x28, 0x05, 0x52, 0x0f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x49, 0x6e, 0x42, 0x6c, 0x53, 0x74,
 | 
			
		||||
	0x61, 0x74, 0x65, 0x22, 0xc1, 0x08, 0x0a, 0x0e, 0x46, 0x69, 0x72, 0x65, 0x62, 0x61, 0x6c, 0x6c,
 | 
			
		||||
	0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 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, 0x01, 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, 0x2c, 0x0a, 0x11, 0x6f, 0x66, 0x66, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e,
 | 
			
		||||
	0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x6f, 0x66, 0x66,
 | 
			
		||||
	0x65, 0x6e, 0x64, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x24,
 | 
			
		||||
	0x0a, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18,
 | 
			
		||||
	0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x46, 0x72,
 | 
			
		||||
	0x61, 0x6d, 0x65, 0x73, 0x12, 0x2e, 0x0a, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61,
 | 
			
		||||
	0x62, 0x6c, 0x65, 0x53, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05,
 | 
			
		||||
	0x52, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x46,
 | 
			
		||||
	0x72, 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61,
 | 
			
		||||
	0x62, 0x6c, 0x65, 0x45, 0x64, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05,
 | 
			
		||||
	0x52, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x64, 0x46,
 | 
			
		||||
	0x72, 0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x72,
 | 
			
		||||
	0x61, 0x6d, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x61, 0x63, 0x74, 0x69,
 | 
			
		||||
	0x76, 0x65, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74, 0x53,
 | 
			
		||||
	0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x07, 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, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x74,
 | 
			
		||||
	0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x75, 0x73, 0x68,
 | 
			
		||||
	0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c,
 | 
			
		||||
	0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58, 0x12, 0x22, 0x0a, 0x0c,
 | 
			
		||||
	0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x59, 0x18, 0x0a, 0x20, 0x01,
 | 
			
		||||
	0x28, 0x05, 0x52, 0x0c, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x59,
 | 
			
		||||
	0x12, 0x16, 0x0a, 0x06, 0x64, 0x61, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05,
 | 
			
		||||
	0x52, 0x06, 0x64, 0x61, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x65, 0x6c, 0x66,
 | 
			
		||||
	0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c,
 | 
			
		||||
	0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58, 0x12, 0x22, 0x0a, 0x0c,
 | 
			
		||||
	0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x59, 0x18, 0x0d, 0x20, 0x01,
 | 
			
		||||
	0x28, 0x05, 0x52, 0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x59,
 | 
			
		||||
	0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74,
 | 
			
		||||
	0x58, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f,
 | 
			
		||||
	0x66, 0x66, 0x73, 0x65, 0x74, 0x58, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78,
 | 
			
		||||
	0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x59, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x68,
 | 
			
		||||
	0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x59, 0x12, 0x20, 0x0a, 0x0b,
 | 
			
		||||
	0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x58, 0x18, 0x10, 0x20, 0x01, 0x28,
 | 
			
		||||
	0x05, 0x52, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x58, 0x12, 0x20,
 | 
			
		||||
	0x0a, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x59, 0x18, 0x11, 0x20,
 | 
			
		||||
	0x01, 0x28, 0x05, 0x52, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x59,
 | 
			
		||||
	0x12, 0x16, 0x0a, 0x06, 0x62, 0x6c, 0x6f, 0x77, 0x55, 0x70, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08,
 | 
			
		||||
	0x52, 0x06, 0x62, 0x6c, 0x6f, 0x77, 0x55, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x65, 0x61, 0x6d,
 | 
			
		||||
	0x49, 0x64, 0x18, 0x13, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x74, 0x65, 0x61, 0x6d, 0x49, 0x64,
 | 
			
		||||
	0x12, 0x24, 0x0a, 0x0d, 0x62, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49,
 | 
			
		||||
	0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x62, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x4c,
 | 
			
		||||
	0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x70, 0x65, 0x63, 0x69, 0x65,
 | 
			
		||||
	0x73, 0x49, 0x64, 0x18, 0x15, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x70, 0x65, 0x63, 0x69,
 | 
			
		||||
	0x65, 0x73, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x0f, 0x65, 0x78, 0x70, 0x6c, 0x6f, 0x73, 0x69, 0x6f,
 | 
			
		||||
	0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x16, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x65,
 | 
			
		||||
	0x78, 0x70, 0x6c, 0x6f, 0x73, 0x69, 0x6f, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x18,
 | 
			
		||||
	0x0a, 0x07, 0x62, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x17, 0x20, 0x01, 0x28, 0x05, 0x52,
 | 
			
		||||
	0x07, 0x62, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x66, 0x72, 0x61, 0x6d,
 | 
			
		||||
	0x65, 0x73, 0x49, 0x6e, 0x42, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x18, 0x20, 0x01, 0x28,
 | 
			
		||||
	0x05, 0x52, 0x0f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x49, 0x6e, 0x42, 0x6c, 0x53, 0x74, 0x61,
 | 
			
		||||
	0x74, 0x65, 0x12, 0x23, 0x0a, 0x0c, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x47, 0x72, 0x69,
 | 
			
		||||
	0x64, 0x58, 0x18, 0xe7, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x76, 0x69, 0x72, 0x74, 0x75,
 | 
			
		||||
	0x61, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x58, 0x12, 0x23, 0x0a, 0x0c, 0x76, 0x69, 0x72, 0x74, 0x75,
 | 
			
		||||
	0x61, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x59, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c,
 | 
			
		||||
	0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x59, 0x12, 0x13, 0x0a, 0x04,
 | 
			
		||||
	0x64, 0x69, 0x72, 0x58, 0x18, 0xe9, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x64, 0x69, 0x72,
 | 
			
		||||
	0x58, 0x12, 0x13, 0x0a, 0x04, 0x64, 0x69, 0x72, 0x59, 0x18, 0xea, 0x07, 0x20, 0x01, 0x28, 0x05,
 | 
			
		||||
	0x52, 0x04, 0x64, 0x69, 0x72, 0x59, 0x12, 0x13, 0x0a, 0x04, 0x76, 0x65, 0x6c, 0x58, 0x18, 0xeb,
 | 
			
		||||
	0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x76, 0x65, 0x6c, 0x58, 0x12, 0x13, 0x0a, 0x04, 0x76,
 | 
			
		||||
	0x65, 0x6c, 0x59, 0x18, 0xec, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x76, 0x65, 0x6c, 0x59,
 | 
			
		||||
	0x12, 0x15, 0x0a, 0x05, 0x73, 0x70, 0x65, 0x65, 0x64, 0x18, 0xed, 0x07, 0x20, 0x01, 0x28, 0x05,
 | 
			
		||||
	0x52, 0x05, 0x73, 0x70, 0x65, 0x65, 0x64, 0x22, 0xc9, 0x05, 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, 0x26, 0x0a, 0x0e,
 | 
			
		||||
	0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x54, 0x6f, 0x50, 0x69, 0x6e, 0x67, 0x18, 0x02,
 | 
			
		||||
	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, 0x03, 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, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52,
 | 
			
		||||
	0x0b, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x13,
 | 
			
		||||
	0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61,
 | 
			
		||||
	0x6e, 0x6f, 0x73, 0x18, 0x05, 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, 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, 0x06, 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, 0x07, 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, 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, 0x08, 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, 0x09, 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, 0x28, 0x0a, 0x0f, 0x72, 0x65,
 | 
			
		||||
	0x6e, 0x64, 0x65, 0x72, 0x43, 0x61, 0x63, 0x68, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x0a, 0x20,
 | 
			
		||||
	0x01, 0x28, 0x05, 0x52, 0x0f, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x43, 0x61, 0x63, 0x68, 0x65,
 | 
			
		||||
	0x53, 0x69, 0x7a, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x66, 0x66,
 | 
			
		||||
	0x73, 0x65, 0x74, 0x58, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0c, 0x73, 0x70, 0x61, 0x63,
 | 
			
		||||
	0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x58, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x70, 0x61, 0x63,
 | 
			
		||||
	0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x59, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0c,
 | 
			
		||||
	0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x59, 0x12, 0x2a, 0x0a, 0x10,
 | 
			
		||||
	0x63, 0x6f, 0x6c, 0x6c, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x69, 0x6e, 0x53, 0x74, 0x65, 0x70,
 | 
			
		||||
	0x18, 0x0d, 0x20, 0x01, 0x28, 0x05, 0x52, 0x10, 0x63, 0x6f, 0x6c, 0x6c, 0x69, 0x73, 0x69, 0x6f,
 | 
			
		||||
	0x6e, 0x4d, 0x69, 0x6e, 0x53, 0x74, 0x65, 0x70, 0x12, 0x39, 0x0a, 0x17, 0x66, 0x72, 0x61, 0x6d,
 | 
			
		||||
	0x65, 0x44, 0x61, 0x74, 0x61, 0x4c, 0x6f, 0x67, 0x67, 0x69, 0x6e, 0x67, 0x45, 0x6e, 0x61, 0x62,
 | 
			
		||||
	0x6c, 0x65, 0x64, 0x18, 0x80, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x17, 0x66, 0x72, 0x61, 0x6d,
 | 
			
		||||
	0x65, 0x44, 0x61, 0x74, 0x61, 0x4c, 0x6f, 0x67, 0x67, 0x69, 0x6e, 0x67, 0x45, 0x6e, 0x61, 0x62,
 | 
			
		||||
	0x6c, 0x65, 0x64, 0x22, 0xc2, 0x03, 0x0a, 0x11, 0x52, 0x6f, 0x6f, 0x6d, 0x44, 0x6f, 0x77, 0x6e,
 | 
			
		||||
	0x73, 0x79, 0x6e, 0x63, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18,
 | 
			
		||||
	0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x36, 0x0a, 0x0a, 0x70, 0x6c, 0x61,
 | 
			
		||||
	0x79, 0x65, 0x72, 0x73, 0x41, 0x72, 0x72, 0x18, 0x02, 0x20, 0x03, 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, 0x0a, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x41, 0x72,
 | 
			
		||||
	0x72, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x4e, 0x61,
 | 
			
		||||
	0x6e, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x63, 0x6f, 0x75, 0x6e, 0x74,
 | 
			
		||||
	0x64, 0x6f, 0x77, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x12, 0x37, 0x0a, 0x0c, 0x6d, 0x65, 0x6c,
 | 
			
		||||
	0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32,
 | 
			
		||||
	0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x4d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75,
 | 
			
		||||
	0x6c, 0x6c, 0x65, 0x74, 0x52, 0x0c, 0x6d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65,
 | 
			
		||||
	0x74, 0x73, 0x12, 0x40, 0x0a, 0x0f, 0x66, 0x69, 0x72, 0x65, 0x62, 0x61, 0x6c, 0x6c, 0x42, 0x75,
 | 
			
		||||
	0x6c, 0x6c, 0x65, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72,
 | 
			
		||||
	0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x46, 0x69, 0x72, 0x65, 0x62, 0x61, 0x6c, 0x6c, 0x42, 0x75, 0x6c,
 | 
			
		||||
	0x6c, 0x65, 0x74, 0x52, 0x0f, 0x66, 0x69, 0x72, 0x65, 0x62, 0x61, 0x6c, 0x6c, 0x42, 0x75, 0x6c,
 | 
			
		||||
	0x6c, 0x65, 0x74, 0x73, 0x12, 0x37, 0x0a, 0x16, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x55,
 | 
			
		||||
	0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x18, 0x80,
 | 
			
		||||
	0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x16, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x55, 0x6e,
 | 
			
		||||
	0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x12, 0x2d, 0x0a,
 | 
			
		||||
	0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x12, 0x1c,
 | 
			
		||||
	0x0a, 0x09, 0x6a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28,
 | 
			
		||||
	0x05, 0x52, 0x09, 0x6a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x7c, 0x0a, 0x12,
 | 
			
		||||
	0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79,
 | 
			
		||||
	0x6e, 0x63, 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65,
 | 
			
		||||
	0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46,
 | 
			
		||||
	0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x4c,
 | 
			
		||||
	0x69, 0x73, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x04, 0x52, 0x09, 0x69, 0x6e, 0x70, 0x75, 0x74,
 | 
			
		||||
	0x4c, 0x69, 0x73, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65,
 | 
			
		||||
	0x64, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x63, 0x6f, 0x6e,
 | 
			
		||||
	0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x3b, 0x0a, 0x0f, 0x48, 0x65,
 | 
			
		||||
	0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x28, 0x0a,
 | 
			
		||||
	0x0f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
 | 
			
		||||
	0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x69,
 | 
			
		||||
	0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0xb8, 0x02, 0x0a, 0x05, 0x57, 0x73, 0x52, 0x65,
 | 
			
		||||
	0x71, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x73, 0x67, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05,
 | 
			
		||||
	0x52, 0x05, 0x6d, 0x73, 0x67, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x79, 0x65,
 | 
			
		||||
	0x72, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x79, 0x65,
 | 
			
		||||
	0x72, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05,
 | 
			
		||||
	0x52, 0x03, 0x61, 0x63, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64,
 | 
			
		||||
	0x65, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x6a, 0x6f, 0x69, 0x6e, 0x49, 0x6e,
 | 
			
		||||
	0x64, 0x65, 0x78, 0x12, 0x24, 0x0a, 0x0d, 0x61, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x46, 0x72, 0x61,
 | 
			
		||||
	0x6d, 0x65, 0x49, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x61, 0x63, 0x6b, 0x69,
 | 
			
		||||
	0x6e, 0x67, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x12, 0x61, 0x63, 0x6b,
 | 
			
		||||
	0x69, 0x6e, 0x67, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x18,
 | 
			
		||||
	0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x61, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x70,
 | 
			
		||||
	0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x4e, 0x0a, 0x15, 0x69, 0x6e, 0x70,
 | 
			
		||||
	0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x42, 0x61, 0x74,
 | 
			
		||||
	0x63, 0x68, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
 | 
			
		||||
	0x73, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x73, 0x79,
 | 
			
		||||
	0x6e, 0x63, 0x52, 0x15, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70,
 | 
			
		||||
	0x73, 0x79, 0x6e, 0x63, 0x42, 0x61, 0x74, 0x63, 0x68, 0x12, 0x27, 0x0a, 0x02, 0x68, 0x62, 0x18,
 | 
			
		||||
	0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x48,
 | 
			
		||||
	0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x52, 0x02,
 | 
			
		||||
	0x68, 0x62, 0x22, 0xaf, 0x02, 0x0a, 0x06, 0x57, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x10, 0x0a,
 | 
			
		||||
	0x03, 0x72, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x72, 0x65, 0x74, 0x12,
 | 
			
		||||
	0x20, 0x0a, 0x0b, 0x65, 0x63, 0x68, 0x6f, 0x65, 0x64, 0x4d, 0x73, 0x67, 0x49, 0x64, 0x18, 0x02,
 | 
			
		||||
	0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x65, 0x63, 0x68, 0x6f, 0x65, 0x64, 0x4d, 0x73, 0x67, 0x49,
 | 
			
		||||
	0x64, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03,
 | 
			
		||||
	0x61, 0x63, 0x74, 0x12, 0x2b, 0x0a, 0x03, 0x72, 0x64, 0x66, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b,
 | 
			
		||||
	0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x44, 0x6f,
 | 
			
		||||
	0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x03, 0x72, 0x64, 0x66,
 | 
			
		||||
	0x12, 0x54, 0x0a, 0x17, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f,
 | 
			
		||||
	0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x42, 0x61, 0x74, 0x63, 0x68, 0x18, 0x05, 0x20, 0x03, 0x28,
 | 
			
		||||
	0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74,
 | 
			
		||||
	0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x52, 0x17, 0x69,
 | 
			
		||||
	0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e,
 | 
			
		||||
	0x63, 0x42, 0x61, 0x74, 0x63, 0x68, 0x12, 0x36, 0x0a, 0x08, 0x62, 0x63, 0x69, 0x46, 0x72, 0x61,
 | 
			
		||||
	0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
 | 
			
		||||
	0x73, 0x2e, 0x42, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x6c, 0x69, 0x64, 0x65, 0x72,
 | 
			
		||||
	0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x62, 0x63, 0x69, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x24,
 | 
			
		||||
	0x0a, 0x0d, 0x70, 0x65, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18,
 | 
			
		||||
	0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x70, 0x65, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49,
 | 
			
		||||
	0x6e, 0x64, 0x65, 0x78, 0x22, 0x9a, 0x02, 0x0a, 0x14, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x42,
 | 
			
		||||
	0x75, 0x66, 0x66, 0x65, 0x72, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x2a, 0x0a,
 | 
			
		||||
	0x10, 0x72, 0x65, 0x66, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49,
 | 
			
		||||
	0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x10, 0x72, 0x65, 0x66, 0x52, 0x65, 0x6e, 0x64,
 | 
			
		||||
	0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x0f, 0x75, 0x6e, 0x63,
 | 
			
		||||
	0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01,
 | 
			
		||||
	0x28, 0x04, 0x52, 0x0f, 0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4d,
 | 
			
		||||
	0x61, 0x73, 0x6b, 0x12, 0x58, 0x0a, 0x19, 0x74, 0x6f, 0x53, 0x65, 0x6e, 0x64, 0x49, 0x6e, 0x70,
 | 
			
		||||
	0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x73,
 | 
			
		||||
	0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e,
 | 
			
		||||
	0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79,
 | 
			
		||||
	0x6e, 0x63, 0x52, 0x19, 0x74, 0x6f, 0x53, 0x65, 0x6e, 0x64, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46,
 | 
			
		||||
	0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x73, 0x12, 0x2c, 0x0a,
 | 
			
		||||
	0x11, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x79,
 | 
			
		||||
	0x6e, 0x63, 0x18, 0x81, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x73, 0x68, 0x6f, 0x75, 0x6c,
 | 
			
		||||
	0x64, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x25, 0x0a, 0x0d,
 | 
			
		||||
	0x73, 0x70, 0x65, 0x63, 0x69, 0x65, 0x73, 0x49, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x82, 0x08,
 | 
			
		||||
	0x20, 0x03, 0x28, 0x05, 0x52, 0x0d, 0x73, 0x70, 0x65, 0x63, 0x69, 0x65, 0x73, 0x49, 0x64, 0x4c,
 | 
			
		||||
	0x69, 0x73, 0x74, 0x12, 0x33, 0x0a, 0x14, 0x62, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x4c, 0x6f, 0x63,
 | 
			
		||||
	0x61, 0x6c, 0x49, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x83, 0x08, 0x20, 0x01,
 | 
			
		||||
	0x28, 0x05, 0x52, 0x14, 0x62, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49,
 | 
			
		||||
	0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 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,
 | 
			
		||||
	0x6e, 0x63, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64,
 | 
			
		||||
	0x46, 0x6f, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x24, 0x0a, 0x0d, 0x70,
 | 
			
		||||
	0x65, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x05, 0x20, 0x01,
 | 
			
		||||
	0x28, 0x05, 0x52, 0x0d, 0x70, 0x65, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65,
 | 
			
		||||
	0x78, 0x22, 0x89, 0x07, 0x0a, 0x0b, 0x4d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65,
 | 
			
		||||
	0x74, 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, 0x01, 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, 0x2c, 0x0a, 0x11, 0x6f,
 | 
			
		||||
	0x66, 0x66, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78,
 | 
			
		||||
	0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x6f, 0x66, 0x66, 0x65, 0x6e, 0x64, 0x65, 0x72,
 | 
			
		||||
	0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x24, 0x0a, 0x0d, 0x73, 0x74, 0x61,
 | 
			
		||||
	0x72, 0x74, 0x75, 0x70, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05,
 | 
			
		||||
	0x52, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12,
 | 
			
		||||
	0x2e, 0x0a, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74,
 | 
			
		||||
	0x46, 0x72, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x63, 0x61, 0x6e,
 | 
			
		||||
	0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12,
 | 
			
		||||
	0x2e, 0x0a, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x64,
 | 
			
		||||
	0x46, 0x72, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x63, 0x61, 0x6e,
 | 
			
		||||
	0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x64, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12,
 | 
			
		||||
	0x22, 0x0a, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18,
 | 
			
		||||
	0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x72, 0x61,
 | 
			
		||||
	0x6d, 0x65, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72,
 | 
			
		||||
	0x61, 0x6d, 0x65, 0x73, 0x18, 0x07, 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, 0x08, 0x20, 0x01,
 | 
			
		||||
	0x28, 0x05, 0x52, 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61,
 | 
			
		||||
	0x6d, 0x65, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b, 0x56,
 | 
			
		||||
	0x65, 0x6c, 0x58, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x70, 0x75, 0x73, 0x68, 0x62,
 | 
			
		||||
	0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x75, 0x73, 0x68, 0x62,
 | 
			
		||||
	0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x59, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x70,
 | 
			
		||||
	0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x59, 0x12, 0x16, 0x0a, 0x06, 0x64,
 | 
			
		||||
	0x61, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x64, 0x61, 0x6d,
 | 
			
		||||
	0x61, 0x67, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b, 0x56,
 | 
			
		||||
	0x65, 0x6c, 0x58, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c,
 | 
			
		||||
	0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c,
 | 
			
		||||
	0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x59, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x73,
 | 
			
		||||
	0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x59, 0x12, 0x24, 0x0a, 0x0d, 0x68,
 | 
			
		||||
	0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x58, 0x18, 0x0e, 0x20, 0x01,
 | 
			
		||||
	0x28, 0x05, 0x52, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74,
 | 
			
		||||
	0x58, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65,
 | 
			
		||||
	0x74, 0x59, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78,
 | 
			
		||||
	0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x59, 0x12, 0x20, 0x0a, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f,
 | 
			
		||||
	0x78, 0x53, 0x69, 0x7a, 0x65, 0x58, 0x18, 0x10, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x68, 0x69,
 | 
			
		||||
	0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x58, 0x12, 0x20, 0x0a, 0x0b, 0x68, 0x69, 0x74,
 | 
			
		||||
	0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x59, 0x18, 0x11, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b,
 | 
			
		||||
	0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x59, 0x12, 0x16, 0x0a, 0x06, 0x62,
 | 
			
		||||
	0x6c, 0x6f, 0x77, 0x55, 0x70, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x62, 0x6c, 0x6f,
 | 
			
		||||
	0x77, 0x55, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x18, 0x13, 0x20,
 | 
			
		||||
	0x01, 0x28, 0x05, 0x52, 0x06, 0x74, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x62,
 | 
			
		||||
	0x75, 0x6c, 0x6c, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x18, 0x14, 0x20, 0x01,
 | 
			
		||||
	0x28, 0x05, 0x52, 0x0d, 0x62, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49,
 | 
			
		||||
	0x64, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x70, 0x65, 0x63, 0x69, 0x65, 0x73, 0x49, 0x64, 0x18, 0x15,
 | 
			
		||||
	0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x70, 0x65, 0x63, 0x69, 0x65, 0x73, 0x49, 0x64, 0x12,
 | 
			
		||||
	0x28, 0x0a, 0x0f, 0x65, 0x78, 0x70, 0x6c, 0x6f, 0x73, 0x69, 0x6f, 0x6e, 0x46, 0x72, 0x61, 0x6d,
 | 
			
		||||
	0x65, 0x73, 0x18, 0x16, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x65, 0x78, 0x70, 0x6c, 0x6f, 0x73,
 | 
			
		||||
	0x69, 0x6f, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x6c, 0x53,
 | 
			
		||||
	0x74, 0x61, 0x74, 0x65, 0x18, 0x17, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x62, 0x6c, 0x53, 0x74,
 | 
			
		||||
	0x61, 0x74, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x49, 0x6e, 0x42,
 | 
			
		||||
	0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x18, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x66, 0x72,
 | 
			
		||||
	0x61, 0x6d, 0x65, 0x73, 0x49, 0x6e, 0x42, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0xc1, 0x08,
 | 
			
		||||
	0x0a, 0x0e, 0x46, 0x69, 0x72, 0x65, 0x62, 0x61, 0x6c, 0x6c, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74,
 | 
			
		||||
	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, 0x01, 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, 0x2c, 0x0a, 0x11, 0x6f, 0x66,
 | 
			
		||||
	0x66, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18,
 | 
			
		||||
	0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x6f, 0x66, 0x66, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4a,
 | 
			
		||||
	0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x24, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x72,
 | 
			
		||||
	0x74, 0x75, 0x70, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52,
 | 
			
		||||
	0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x2e,
 | 
			
		||||
	0x0a, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x46,
 | 
			
		||||
	0x72, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x63, 0x61, 0x6e, 0x63,
 | 
			
		||||
	0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x2e,
 | 
			
		||||
	0x0a, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x64, 0x46,
 | 
			
		||||
	0x72, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x63, 0x61, 0x6e, 0x63,
 | 
			
		||||
	0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x64, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x22,
 | 
			
		||||
	0x0a, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x06,
 | 
			
		||||
	0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x72, 0x61, 0x6d,
 | 
			
		||||
	0x65, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61,
 | 
			
		||||
	0x6d, 0x65, 0x73, 0x18, 0x07, 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, 0x08, 0x20, 0x01, 0x28,
 | 
			
		||||
	0x05, 0x52, 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d,
 | 
			
		||||
	0x65, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65,
 | 
			
		||||
	0x6c, 0x58, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61,
 | 
			
		||||
	0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61,
 | 
			
		||||
	0x63, 0x6b, 0x56, 0x65, 0x6c, 0x59, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x70, 0x75,
 | 
			
		||||
	0x73, 0x68, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x59, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x61,
 | 
			
		||||
	0x6d, 0x61, 0x67, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x64, 0x61, 0x6d, 0x61,
 | 
			
		||||
	0x67, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65,
 | 
			
		||||
	0x6c, 0x58, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f,
 | 
			
		||||
	0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f,
 | 
			
		||||
	0x63, 0x6b, 0x56, 0x65, 0x6c, 0x59, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x73, 0x65,
 | 
			
		||||
	0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x59, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69,
 | 
			
		||||
	0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x58, 0x18, 0x0e, 0x20, 0x01, 0x28,
 | 
			
		||||
	0x05, 0x52, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x58,
 | 
			
		||||
	0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74,
 | 
			
		||||
	0x59, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f,
 | 
			
		||||
	0x66, 0x66, 0x73, 0x65, 0x74, 0x59, 0x12, 0x20, 0x0a, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78,
 | 
			
		||||
	0x53, 0x69, 0x7a, 0x65, 0x58, 0x18, 0x10, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x68, 0x69, 0x74,
 | 
			
		||||
	0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x58, 0x12, 0x20, 0x0a, 0x0b, 0x68, 0x69, 0x74, 0x62,
 | 
			
		||||
	0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x59, 0x18, 0x11, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x68,
 | 
			
		||||
	0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x59, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x6c,
 | 
			
		||||
	0x6f, 0x77, 0x55, 0x70, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x62, 0x6c, 0x6f, 0x77,
 | 
			
		||||
	0x55, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x18, 0x13, 0x20, 0x01,
 | 
			
		||||
	0x28, 0x05, 0x52, 0x06, 0x74, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x62, 0x75,
 | 
			
		||||
	0x6c, 0x6c, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28,
 | 
			
		||||
	0x05, 0x52, 0x0d, 0x62, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64,
 | 
			
		||||
	0x12, 0x1c, 0x0a, 0x09, 0x73, 0x70, 0x65, 0x63, 0x69, 0x65, 0x73, 0x49, 0x64, 0x18, 0x15, 0x20,
 | 
			
		||||
	0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x70, 0x65, 0x63, 0x69, 0x65, 0x73, 0x49, 0x64, 0x12, 0x28,
 | 
			
		||||
	0x0a, 0x0f, 0x65, 0x78, 0x70, 0x6c, 0x6f, 0x73, 0x69, 0x6f, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65,
 | 
			
		||||
	0x73, 0x18, 0x16, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x65, 0x78, 0x70, 0x6c, 0x6f, 0x73, 0x69,
 | 
			
		||||
	0x6f, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x6c, 0x53, 0x74,
 | 
			
		||||
	0x61, 0x74, 0x65, 0x18, 0x17, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x62, 0x6c, 0x53, 0x74, 0x61,
 | 
			
		||||
	0x74, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x49, 0x6e, 0x42, 0x6c,
 | 
			
		||||
	0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x18, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x66, 0x72, 0x61,
 | 
			
		||||
	0x6d, 0x65, 0x73, 0x49, 0x6e, 0x42, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x23, 0x0a, 0x0c,
 | 
			
		||||
	0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x58, 0x18, 0xe7, 0x07, 0x20,
 | 
			
		||||
	0x01, 0x28, 0x05, 0x52, 0x0c, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x47, 0x72, 0x69, 0x64,
 | 
			
		||||
	0x58, 0x12, 0x23, 0x0a, 0x0c, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x47, 0x72, 0x69, 0x64,
 | 
			
		||||
	0x59, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61,
 | 
			
		||||
	0x6c, 0x47, 0x72, 0x69, 0x64, 0x59, 0x12, 0x13, 0x0a, 0x04, 0x64, 0x69, 0x72, 0x58, 0x18, 0xe9,
 | 
			
		||||
	0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x64, 0x69, 0x72, 0x58, 0x12, 0x13, 0x0a, 0x04, 0x64,
 | 
			
		||||
	0x69, 0x72, 0x59, 0x18, 0xea, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x64, 0x69, 0x72, 0x59,
 | 
			
		||||
	0x12, 0x13, 0x0a, 0x04, 0x76, 0x65, 0x6c, 0x58, 0x18, 0xeb, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52,
 | 
			
		||||
	0x04, 0x76, 0x65, 0x6c, 0x58, 0x12, 0x13, 0x0a, 0x04, 0x76, 0x65, 0x6c, 0x59, 0x18, 0xec, 0x07,
 | 
			
		||||
	0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x76, 0x65, 0x6c, 0x59, 0x12, 0x15, 0x0a, 0x05, 0x73, 0x70,
 | 
			
		||||
	0x65, 0x65, 0x64, 0x18, 0xed, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x73, 0x70, 0x65, 0x65,
 | 
			
		||||
	0x64, 0x22, 0xc9, 0x05, 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, 0x26, 0x0a, 0x0e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76,
 | 
			
		||||
	0x61, 0x6c, 0x54, 0x6f, 0x50, 0x69, 0x6e, 0x67, 0x18, 0x02, 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, 0x03, 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, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x62, 0x6f, 0x75, 0x6e, 0x64,
 | 
			
		||||
	0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x13, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65,
 | 
			
		||||
	0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x18, 0x05, 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, 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, 0x06, 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, 0x07, 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, 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, 0x08, 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, 0x09, 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, 0x28, 0x0a, 0x0f, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x43, 0x61,
 | 
			
		||||
	0x63, 0x68, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x72,
 | 
			
		||||
	0x65, 0x6e, 0x64, 0x65, 0x72, 0x43, 0x61, 0x63, 0x68, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x22,
 | 
			
		||||
	0x0a, 0x0c, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x58, 0x18, 0x0b,
 | 
			
		||||
	0x20, 0x01, 0x28, 0x01, 0x52, 0x0c, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65,
 | 
			
		||||
	0x74, 0x58, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65,
 | 
			
		||||
	0x74, 0x59, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0c, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f,
 | 
			
		||||
	0x66, 0x66, 0x73, 0x65, 0x74, 0x59, 0x12, 0x2a, 0x0a, 0x10, 0x63, 0x6f, 0x6c, 0x6c, 0x69, 0x73,
 | 
			
		||||
	0x69, 0x6f, 0x6e, 0x4d, 0x69, 0x6e, 0x53, 0x74, 0x65, 0x70, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x05,
 | 
			
		||||
	0x52, 0x10, 0x63, 0x6f, 0x6c, 0x6c, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x69, 0x6e, 0x53, 0x74,
 | 
			
		||||
	0x65, 0x70, 0x12, 0x39, 0x0a, 0x17, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x61, 0x74, 0x61, 0x4c,
 | 
			
		||||
	0x6f, 0x67, 0x67, 0x69, 0x6e, 0x67, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x80, 0x08,
 | 
			
		||||
	0x20, 0x01, 0x28, 0x08, 0x52, 0x17, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x61, 0x74, 0x61, 0x4c,
 | 
			
		||||
	0x6f, 0x67, 0x67, 0x69, 0x6e, 0x67, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0xc2, 0x03,
 | 
			
		||||
	0x0a, 0x11, 0x52, 0x6f, 0x6f, 0x6d, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x46, 0x72,
 | 
			
		||||
	0x61, 0x6d, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52,
 | 
			
		||||
	0x02, 0x69, 0x64, 0x12, 0x36, 0x0a, 0x0a, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x41, 0x72,
 | 
			
		||||
	0x72, 0x18, 0x02, 0x20, 0x03, 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,
 | 
			
		||||
	0x0a, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x41, 0x72, 0x72, 0x12, 0x26, 0x0a, 0x0e, 0x63,
 | 
			
		||||
	0x6f, 0x75, 0x6e, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x18, 0x03, 0x20,
 | 
			
		||||
	0x01, 0x28, 0x03, 0x52, 0x0e, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x4e, 0x61,
 | 
			
		||||
	0x6e, 0x6f, 0x73, 0x12, 0x37, 0x0a, 0x0c, 0x6d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c,
 | 
			
		||||
	0x65, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74,
 | 
			
		||||
	0x6f, 0x73, 0x2e, 0x4d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x52, 0x0c,
 | 
			
		||||
	0x6d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x12, 0x40, 0x0a, 0x0f,
 | 
			
		||||
	0x66, 0x69, 0x72, 0x65, 0x62, 0x61, 0x6c, 0x6c, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x18,
 | 
			
		||||
	0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x46,
 | 
			
		||||
	0x69, 0x72, 0x65, 0x62, 0x61, 0x6c, 0x6c, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x52, 0x0f, 0x66,
 | 
			
		||||
	0x69, 0x72, 0x65, 0x62, 0x61, 0x6c, 0x6c, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x12, 0x37,
 | 
			
		||||
	0x0a, 0x16, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69,
 | 
			
		||||
	0x72, 0x6d, 0x65, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x18, 0x80, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52,
 | 
			
		||||
	0x16, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72,
 | 
			
		||||
	0x6d, 0x65, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x12, 0x2d, 0x0a, 0x11, 0x73, 0x68, 0x6f, 0x75, 0x6c,
 | 
			
		||||
	0x64, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x81, 0x08, 0x20,
 | 
			
		||||
	0x01, 0x28, 0x08, 0x52, 0x11, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x46, 0x6f, 0x72, 0x63, 0x65,
 | 
			
		||||
	0x52, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x25, 0x0a, 0x0d, 0x73, 0x70, 0x65, 0x63, 0x69, 0x65,
 | 
			
		||||
	0x73, 0x49, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x82, 0x08, 0x20, 0x03, 0x28, 0x05, 0x52, 0x0d,
 | 
			
		||||
	0x73, 0x70, 0x65, 0x63, 0x69, 0x65, 0x73, 0x49, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x33, 0x0a,
 | 
			
		||||
	0x14, 0x62, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x43, 0x6f,
 | 
			
		||||
	0x75, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x83, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x14, 0x62, 0x75,
 | 
			
		||||
	0x6c, 0x6c, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74,
 | 
			
		||||
	0x65, 0x72, 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 (
 | 
			
		||||
 
 | 
			
		||||
@@ -46,6 +46,7 @@ func Serve(c *gin.Context) {
 | 
			
		||||
		c.AbortWithStatus(http.StatusBadRequest)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	boundRoomId := 0
 | 
			
		||||
	expectedRoomId := 0
 | 
			
		||||
	var err error
 | 
			
		||||
@@ -395,3 +396,89 @@ func Serve(c *gin.Context) {
 | 
			
		||||
	startOrFeedHeartbeatWatchdog(conn)
 | 
			
		||||
	go receivingLoopAgainstPlayer()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func HandleSecondaryWsSessionForPlayer(c *gin.Context) {
 | 
			
		||||
	token, ok := c.GetQuery("intAuthToken")
 | 
			
		||||
	if !ok {
 | 
			
		||||
		Logger.Warn("Secondary ws session req must have intAuthToken param!")
 | 
			
		||||
		c.AbortWithStatus(http.StatusBadRequest)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	boundRoomId := 0
 | 
			
		||||
	var err error = nil
 | 
			
		||||
	if boundRoomIdStr, hasBoundRoomId := c.GetQuery("boundRoomId"); hasBoundRoomId {
 | 
			
		||||
		boundRoomId, err = strconv.Atoi(boundRoomIdStr)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			c.AbortWithStatus(http.StatusBadRequest)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		Logger.Warn("Secondary ws session req must have boundRoomId param:", zap.Any("intAuthToken", token))
 | 
			
		||||
		c.AbortWithStatus(http.StatusBadRequest)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var pRoom *models.Room = nil
 | 
			
		||||
	// Deliberately querying playerId after querying room, because the former is against persistent storage and could be slow!
 | 
			
		||||
	if tmpPRoom, existent := (*models.RoomMapManagerIns)[int32(boundRoomId)]; !existent {
 | 
			
		||||
		Logger.Warn("Secondary ws session failed to get:\n", zap.Any("intAuthToken", token), zap.Any("forBoundRoomId", boundRoomId))
 | 
			
		||||
		c.AbortWithStatus(http.StatusBadRequest)
 | 
			
		||||
	} else {
 | 
			
		||||
		pRoom = tmpPRoom
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO: Wrap the following 2 stmts by sql transaction!
 | 
			
		||||
	playerId, err := models.GetPlayerIdByToken(token)
 | 
			
		||||
	if err != nil || playerId == 0 {
 | 
			
		||||
		// TODO: Abort with specific message.
 | 
			
		||||
		Logger.Warn("Secondary ws session playerLogin record not found for ws authentication:", zap.Any("intAuthToken", token))
 | 
			
		||||
		c.AbortWithStatus(http.StatusBadRequest)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Logger.Info("Secondary ws session playerLogin record has been found for ws authentication:", zap.Any("playerId", playerId), zap.Any("intAuthToken", token), zap.Any("boundRoomId", boundRoomId))
 | 
			
		||||
 | 
			
		||||
	conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		Logger.Error("Secondary ws session upgrade:", zap.Error(err), zap.Any("playerId", playerId))
 | 
			
		||||
		c.AbortWithStatus(http.StatusBadRequest)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	connHasBeenSignaledToClose := int32(0)
 | 
			
		||||
	pConnHasBeenSignaledToClose := &connHasBeenSignaledToClose
 | 
			
		||||
 | 
			
		||||
	signalToCloseConnOfThisPlayer := func(customRetCode int, customRetMsg string) {
 | 
			
		||||
		if swapped := atomic.CompareAndSwapInt32(pConnHasBeenSignaledToClose, 0, 1); !swapped {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		Logger.Warn("Secondary ws session signalToCloseConnOfThisPlayer:", zap.Any("playerId", playerId), zap.Any("customRetCode", customRetCode), zap.Any("customRetMsg", customRetMsg))
 | 
			
		||||
		defer func() {
 | 
			
		||||
			if r := recover(); r != nil {
 | 
			
		||||
				Logger.Error("Secondary ws session recovered from: ", zap.Any("panic", r))
 | 
			
		||||
			}
 | 
			
		||||
		}()
 | 
			
		||||
 | 
			
		||||
		closeMessage := websocket.FormatCloseMessage(customRetCode, customRetMsg)
 | 
			
		||||
		err := conn.WriteControl(websocket.CloseMessage, closeMessage, time.Now().Add(time.Millisecond*(ConstVals.Ws.WillKickIfInactiveFor)))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			Logger.Error("Secondary ws session unable to send the CloseFrame control message to player(client-side):", zap.Any("playerId", playerId), zap.Error(err))
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		time.AfterFunc(3*time.Second, func() {
 | 
			
		||||
			// To actually terminates the underlying TCP connection which might be in `CLOSE_WAIT` state if inspected by `netstat`.
 | 
			
		||||
			conn.Close()
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	onReceivedCloseMessageFromClient := func(code int, text string) error {
 | 
			
		||||
		Logger.Warn("Secondary ws session triggered `onReceivedCloseMessageFromClient`:", zap.Any("code", code), zap.Any("playerId", playerId), zap.Any("message", text))
 | 
			
		||||
		signalToCloseConnOfThisPlayer(code, text)
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	conn.SetCloseHandler(onReceivedCloseMessageFromClient)
 | 
			
		||||
 | 
			
		||||
	pRoom.SetSecondarySession(int32(playerId), conn, signalToCloseConnOfThisPlayer)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -51,6 +51,7 @@ message InputFrameDecoded {
 | 
			
		||||
message InputFrameUpsync {
 | 
			
		||||
  int32 inputFrameId = 1;
 | 
			
		||||
  uint64 encoded = 2;
 | 
			
		||||
  int32 joinIndex = 3;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message InputFrameDownsync {
 | 
			
		||||
@@ -81,6 +82,7 @@ message WsResp {
 | 
			
		||||
  RoomDownsyncFrame rdf = 4;
 | 
			
		||||
  repeated InputFrameDownsync inputFrameDownsyncBatch = 5;
 | 
			
		||||
  BattleColliderInfo bciFrame = 6;
 | 
			
		||||
  int32 peerJoinIndex = 7; // Only used when "InputsBufferSnapshot.peerJoinIndex" is used.
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message InputsBufferSnapshot {
 | 
			
		||||
@@ -88,6 +90,7 @@ message InputsBufferSnapshot {
 | 
			
		||||
  uint64 unconfirmedMask = 2;
 | 
			
		||||
  repeated InputFrameDownsync toSendInputFrameDownsyncs = 3;
 | 
			
		||||
  bool shouldForceResync = 4;
 | 
			
		||||
  int32 peerJoinIndex = 5; // Only used when "WsResp.peerJoinIndex" is used.
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message MeleeBullet {
 | 
			
		||||
 
 | 
			
		||||
@@ -362,7 +362,7 @@
 | 
			
		||||
      "array": [
 | 
			
		||||
        0,
 | 
			
		||||
        0,
 | 
			
		||||
        209.57814771583418,
 | 
			
		||||
        210.4394431281402,
 | 
			
		||||
        0,
 | 
			
		||||
        0,
 | 
			
		||||
        0,
 | 
			
		||||
 
 | 
			
		||||
@@ -846,6 +846,33 @@ batchInputFrameIdRange=[${batch[0].inputFrameId}, ${batch[batch.length - 1].inpu
 | 
			
		||||
    self.chaserRenderFrameId = renderFrameId1;
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onPeerInputFrameUpsync(peerJoinIndex, batch /* []*pb.InputFrameDownsync */ ) {
 | 
			
		||||
    // TODO: find some kind of synchronization mechanism against "getOrPrefabInputFrameUpsync"!
 | 
			
		||||
    // See `<proj-root>/ConcerningEdgeCases.md` for why this method exists.
 | 
			
		||||
    if (null == batch) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    const self = this;
 | 
			
		||||
    if (!self.recentInputCache) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    if (ALL_BATTLE_STATES.IN_SETTLEMENT == self.battleState) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (let k in batch) {
 | 
			
		||||
      const inputFrameDownsync = batch[k];
 | 
			
		||||
      const inputFrameDownsyncId = inputFrameDownsync.inputFrameId;
 | 
			
		||||
      if (inputFrameDownsyncId <= self.lastAllConfirmedInputFrameId) {
 | 
			
		||||
        continue;
 | 
			
		||||
      }
 | 
			
		||||
      self.getOrPrefabInputFrameUpsync(inputFrameDownsyncId); // Make sure that inputFrame exists locally
 | 
			
		||||
      const existingInputFrame = self.recentInputCache.GetByFrameId(inputFrameDownsyncId);
 | 
			
		||||
      existingInputFrame.InputList[peerJoinIndex - 1] = inputFrameDownsync.inputList[peerJoinIndex - 1]; // No need to change "confirmedList", leave it to "onInputFrameDownsyncBatch" -- we're just helping prediction here
 | 
			
		||||
      self.recentInputCache.SetByFrameId(existingInputFrame, inputFrameDownsyncId);
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onPlayerAdded(rdf /* pb.RoomDownsyncFrame */ ) {
 | 
			
		||||
    const self = this;
 | 
			
		||||
    // Update the "finding player" GUI and show it if not previously present
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,7 @@ window.DOWNSYNC_MSG_ACT_HB_REQ = 1;
 | 
			
		||||
window.DOWNSYNC_MSG_ACT_INPUT_BATCH = 2;
 | 
			
		||||
window.DOWNSYNC_MSG_ACT_BATTLE_STOPPED = 3;
 | 
			
		||||
window.DOWNSYNC_MSG_ACT_FORCED_RESYNC = 4;
 | 
			
		||||
window.DOWNSYNC_MSG_ACT_PEER_INPUT_BATCH = 5;
 | 
			
		||||
 | 
			
		||||
window.sendSafely = function(msgStr) {
 | 
			
		||||
  /**
 | 
			
		||||
@@ -65,6 +66,7 @@ window.handleHbRequirements = function(resp) {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (window.handleBattleColliderInfo) {
 | 
			
		||||
    window.initSecondarySession(null, window.boundRoomId);
 | 
			
		||||
    window.handleBattleColliderInfo(resp.bciFrame);
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
@@ -130,8 +132,6 @@ window.initPersistentSessionClient = function(onopenCb, expectedRoomId) {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const currentHistoryState = window.history && window.history.state ? window.history.state : {};
 | 
			
		||||
 | 
			
		||||
  const clientSession = new WebSocket(urlToConnect);
 | 
			
		||||
  clientSession.binaryType = 'arraybuffer'; // Make 'event.data' of 'onmessage' an "ArrayBuffer" instead of a "Blob"
 | 
			
		||||
 | 
			
		||||
@@ -240,3 +240,56 @@ window.clearLocalStorageAndBackToLoginScene = function(shouldRetainBoundRoomIdIn
 | 
			
		||||
  cc.director.loadScene('login');
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// For secondary ws session
 | 
			
		||||
window.initSecondarySession = function(onopenCb, boundRoomId) {
 | 
			
		||||
  if (window.secondarySession && window.secondarySession.readyState == WebSocket.OPEN) {
 | 
			
		||||
    if (null != onopenCb) {
 | 
			
		||||
      onopenCb();
 | 
			
		||||
    }
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const selfPlayerStr = cc.sys.localStorage.getItem("selfPlayer");
 | 
			
		||||
  const selfPlayer = null == selfPlayerStr ? null : JSON.parse(selfPlayerStr);
 | 
			
		||||
  const intAuthToken = null == selfPlayer ? "" : selfPlayer.intAuthToken;
 | 
			
		||||
 | 
			
		||||
  let urlToConnect = backendAddress.PROTOCOL.replace('http', 'ws') + '://' + backendAddress.HOST + ":" + backendAddress.PORT + "/tsrhtSecondary?isSecondary=true&intAuthToken=" + intAuthToken + "&boundRoomId=" + boundRoomId;
 | 
			
		||||
 | 
			
		||||
  const clientSession = new WebSocket(urlToConnect);
 | 
			
		||||
  clientSession.binaryType = 'arraybuffer'; // Make 'event.data' of 'onmessage' an "ArrayBuffer" instead of a "Blob"
 | 
			
		||||
 | 
			
		||||
  clientSession.onopen = function(evt) {
 | 
			
		||||
    console.warn("The secondary WS clientSession is opened.");
 | 
			
		||||
    window.secondarySession = clientSession;
 | 
			
		||||
    if (null == onopenCb) return;
 | 
			
		||||
    onopenCb();
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  clientSession.onmessage = function(evt) {
 | 
			
		||||
    if (null == evt || null == evt.data) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    try {
 | 
			
		||||
      const resp = window.pb.protos.WsResp.decode(new Uint8Array(evt.data));
 | 
			
		||||
      //console.log(`Got non-empty onmessage decoded: resp.act=${resp.act}`);
 | 
			
		||||
      switch (resp.act) {
 | 
			
		||||
        case window.DOWNSYNC_MSG_ACT_PEER_INPUT_BATCH:
 | 
			
		||||
          mapIns.onPeerInputFrameUpsync(resp.peerJoinIndex, resp.inputFrameDownsyncBatch);
 | 
			
		||||
          break;
 | 
			
		||||
        default:
 | 
			
		||||
          break;
 | 
			
		||||
      }
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      console.error("Secondary ws session, unexpected error when parsing data of:", evt.data, e);
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  clientSession.onerror = function(evt) {
 | 
			
		||||
    console.error("Secondary ws session, error caught on the WS clientSession: ", evt);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  clientSession.onclose = function(evt) {
 | 
			
		||||
    // [WARNING] The callback "onclose" might be called AFTER the webpage is refreshed with "1001 == evt.code".
 | 
			
		||||
    console.warn(`Secondary ws session is closed: evt=${JSON.stringify(evt)}, evt.code=${evt.code}`);
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -2360,6 +2360,7 @@ $root.protos = (function() {
 | 
			
		||||
         * @interface IInputFrameUpsync
 | 
			
		||||
         * @property {number|null} [inputFrameId] InputFrameUpsync inputFrameId
 | 
			
		||||
         * @property {number|Long|null} [encoded] InputFrameUpsync encoded
 | 
			
		||||
         * @property {number|null} [joinIndex] InputFrameUpsync joinIndex
 | 
			
		||||
         */
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
@@ -2393,6 +2394,14 @@ $root.protos = (function() {
 | 
			
		||||
         */
 | 
			
		||||
        InputFrameUpsync.prototype.encoded = $util.Long ? $util.Long.fromBits(0,0,true) : 0;
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * InputFrameUpsync joinIndex.
 | 
			
		||||
         * @member {number} joinIndex
 | 
			
		||||
         * @memberof protos.InputFrameUpsync
 | 
			
		||||
         * @instance
 | 
			
		||||
         */
 | 
			
		||||
        InputFrameUpsync.prototype.joinIndex = 0;
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Creates a new InputFrameUpsync instance using the specified properties.
 | 
			
		||||
         * @function create
 | 
			
		||||
@@ -2421,6 +2430,8 @@ $root.protos = (function() {
 | 
			
		||||
                writer.uint32(/* id 1, wireType 0 =*/8).int32(message.inputFrameId);
 | 
			
		||||
            if (message.encoded != null && Object.hasOwnProperty.call(message, "encoded"))
 | 
			
		||||
                writer.uint32(/* id 2, wireType 0 =*/16).uint64(message.encoded);
 | 
			
		||||
            if (message.joinIndex != null && Object.hasOwnProperty.call(message, "joinIndex"))
 | 
			
		||||
                writer.uint32(/* id 3, wireType 0 =*/24).int32(message.joinIndex);
 | 
			
		||||
            return writer;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
@@ -2463,6 +2474,10 @@ $root.protos = (function() {
 | 
			
		||||
                        message.encoded = reader.uint64();
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                case 3: {
 | 
			
		||||
                        message.joinIndex = reader.int32();
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                default:
 | 
			
		||||
                    reader.skipType(tag & 7);
 | 
			
		||||
                    break;
 | 
			
		||||
@@ -2504,6 +2519,9 @@ $root.protos = (function() {
 | 
			
		||||
            if (message.encoded != null && message.hasOwnProperty("encoded"))
 | 
			
		||||
                if (!$util.isInteger(message.encoded) && !(message.encoded && $util.isInteger(message.encoded.low) && $util.isInteger(message.encoded.high)))
 | 
			
		||||
                    return "encoded: integer|Long expected";
 | 
			
		||||
            if (message.joinIndex != null && message.hasOwnProperty("joinIndex"))
 | 
			
		||||
                if (!$util.isInteger(message.joinIndex))
 | 
			
		||||
                    return "joinIndex: integer expected";
 | 
			
		||||
            return null;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
@@ -2530,6 +2548,8 @@ $root.protos = (function() {
 | 
			
		||||
                    message.encoded = object.encoded;
 | 
			
		||||
                else if (typeof object.encoded === "object")
 | 
			
		||||
                    message.encoded = new $util.LongBits(object.encoded.low >>> 0, object.encoded.high >>> 0).toNumber(true);
 | 
			
		||||
            if (object.joinIndex != null)
 | 
			
		||||
                message.joinIndex = object.joinIndex | 0;
 | 
			
		||||
            return message;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
@@ -2553,6 +2573,7 @@ $root.protos = (function() {
 | 
			
		||||
                    object.encoded = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long;
 | 
			
		||||
                } else
 | 
			
		||||
                    object.encoded = options.longs === String ? "0" : 0;
 | 
			
		||||
                object.joinIndex = 0;
 | 
			
		||||
            }
 | 
			
		||||
            if (message.inputFrameId != null && message.hasOwnProperty("inputFrameId"))
 | 
			
		||||
                object.inputFrameId = message.inputFrameId;
 | 
			
		||||
@@ -2561,6 +2582,8 @@ $root.protos = (function() {
 | 
			
		||||
                    object.encoded = options.longs === String ? String(message.encoded) : message.encoded;
 | 
			
		||||
                else
 | 
			
		||||
                    object.encoded = options.longs === String ? $util.Long.prototype.toString.call(message.encoded) : options.longs === Number ? new $util.LongBits(message.encoded.low >>> 0, message.encoded.high >>> 0).toNumber(true) : message.encoded;
 | 
			
		||||
            if (message.joinIndex != null && message.hasOwnProperty("joinIndex"))
 | 
			
		||||
                object.joinIndex = message.joinIndex;
 | 
			
		||||
            return object;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
@@ -3513,6 +3536,7 @@ $root.protos = (function() {
 | 
			
		||||
         * @property {protos.RoomDownsyncFrame|null} [rdf] WsResp rdf
 | 
			
		||||
         * @property {Array.<protos.InputFrameDownsync>|null} [inputFrameDownsyncBatch] WsResp inputFrameDownsyncBatch
 | 
			
		||||
         * @property {protos.BattleColliderInfo|null} [bciFrame] WsResp bciFrame
 | 
			
		||||
         * @property {number|null} [peerJoinIndex] WsResp peerJoinIndex
 | 
			
		||||
         */
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
@@ -3579,6 +3603,14 @@ $root.protos = (function() {
 | 
			
		||||
         */
 | 
			
		||||
        WsResp.prototype.bciFrame = null;
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * WsResp peerJoinIndex.
 | 
			
		||||
         * @member {number} peerJoinIndex
 | 
			
		||||
         * @memberof protos.WsResp
 | 
			
		||||
         * @instance
 | 
			
		||||
         */
 | 
			
		||||
        WsResp.prototype.peerJoinIndex = 0;
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Creates a new WsResp instance using the specified properties.
 | 
			
		||||
         * @function create
 | 
			
		||||
@@ -3616,6 +3648,8 @@ $root.protos = (function() {
 | 
			
		||||
                    $root.protos.InputFrameDownsync.encode(message.inputFrameDownsyncBatch[i], writer.uint32(/* id 5, wireType 2 =*/42).fork()).ldelim();
 | 
			
		||||
            if (message.bciFrame != null && Object.hasOwnProperty.call(message, "bciFrame"))
 | 
			
		||||
                $root.protos.BattleColliderInfo.encode(message.bciFrame, writer.uint32(/* id 6, wireType 2 =*/50).fork()).ldelim();
 | 
			
		||||
            if (message.peerJoinIndex != null && Object.hasOwnProperty.call(message, "peerJoinIndex"))
 | 
			
		||||
                writer.uint32(/* id 7, wireType 0 =*/56).int32(message.peerJoinIndex);
 | 
			
		||||
            return writer;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
@@ -3676,6 +3710,10 @@ $root.protos = (function() {
 | 
			
		||||
                        message.bciFrame = $root.protos.BattleColliderInfo.decode(reader, reader.uint32());
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                case 7: {
 | 
			
		||||
                        message.peerJoinIndex = reader.int32();
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                default:
 | 
			
		||||
                    reader.skipType(tag & 7);
 | 
			
		||||
                    break;
 | 
			
		||||
@@ -3739,6 +3777,9 @@ $root.protos = (function() {
 | 
			
		||||
                if (error)
 | 
			
		||||
                    return "bciFrame." + error;
 | 
			
		||||
            }
 | 
			
		||||
            if (message.peerJoinIndex != null && message.hasOwnProperty("peerJoinIndex"))
 | 
			
		||||
                if (!$util.isInteger(message.peerJoinIndex))
 | 
			
		||||
                    return "peerJoinIndex: integer expected";
 | 
			
		||||
            return null;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
@@ -3780,6 +3821,8 @@ $root.protos = (function() {
 | 
			
		||||
                    throw TypeError(".protos.WsResp.bciFrame: object expected");
 | 
			
		||||
                message.bciFrame = $root.protos.BattleColliderInfo.fromObject(object.bciFrame);
 | 
			
		||||
            }
 | 
			
		||||
            if (object.peerJoinIndex != null)
 | 
			
		||||
                message.peerJoinIndex = object.peerJoinIndex | 0;
 | 
			
		||||
            return message;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
@@ -3804,6 +3847,7 @@ $root.protos = (function() {
 | 
			
		||||
                object.act = 0;
 | 
			
		||||
                object.rdf = null;
 | 
			
		||||
                object.bciFrame = null;
 | 
			
		||||
                object.peerJoinIndex = 0;
 | 
			
		||||
            }
 | 
			
		||||
            if (message.ret != null && message.hasOwnProperty("ret"))
 | 
			
		||||
                object.ret = message.ret;
 | 
			
		||||
@@ -3820,6 +3864,8 @@ $root.protos = (function() {
 | 
			
		||||
            }
 | 
			
		||||
            if (message.bciFrame != null && message.hasOwnProperty("bciFrame"))
 | 
			
		||||
                object.bciFrame = $root.protos.BattleColliderInfo.toObject(message.bciFrame, options);
 | 
			
		||||
            if (message.peerJoinIndex != null && message.hasOwnProperty("peerJoinIndex"))
 | 
			
		||||
                object.peerJoinIndex = message.peerJoinIndex;
 | 
			
		||||
            return object;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
@@ -3862,6 +3908,7 @@ $root.protos = (function() {
 | 
			
		||||
         * @property {number|Long|null} [unconfirmedMask] InputsBufferSnapshot unconfirmedMask
 | 
			
		||||
         * @property {Array.<protos.InputFrameDownsync>|null} [toSendInputFrameDownsyncs] InputsBufferSnapshot toSendInputFrameDownsyncs
 | 
			
		||||
         * @property {boolean|null} [shouldForceResync] InputsBufferSnapshot shouldForceResync
 | 
			
		||||
         * @property {number|null} [peerJoinIndex] InputsBufferSnapshot peerJoinIndex
 | 
			
		||||
         */
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
@@ -3912,6 +3959,14 @@ $root.protos = (function() {
 | 
			
		||||
         */
 | 
			
		||||
        InputsBufferSnapshot.prototype.shouldForceResync = false;
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * InputsBufferSnapshot peerJoinIndex.
 | 
			
		||||
         * @member {number} peerJoinIndex
 | 
			
		||||
         * @memberof protos.InputsBufferSnapshot
 | 
			
		||||
         * @instance
 | 
			
		||||
         */
 | 
			
		||||
        InputsBufferSnapshot.prototype.peerJoinIndex = 0;
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Creates a new InputsBufferSnapshot instance using the specified properties.
 | 
			
		||||
         * @function create
 | 
			
		||||
@@ -3945,6 +4000,8 @@ $root.protos = (function() {
 | 
			
		||||
                    $root.protos.InputFrameDownsync.encode(message.toSendInputFrameDownsyncs[i], writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim();
 | 
			
		||||
            if (message.shouldForceResync != null && Object.hasOwnProperty.call(message, "shouldForceResync"))
 | 
			
		||||
                writer.uint32(/* id 4, wireType 0 =*/32).bool(message.shouldForceResync);
 | 
			
		||||
            if (message.peerJoinIndex != null && Object.hasOwnProperty.call(message, "peerJoinIndex"))
 | 
			
		||||
                writer.uint32(/* id 5, wireType 0 =*/40).int32(message.peerJoinIndex);
 | 
			
		||||
            return writer;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
@@ -3997,6 +4054,10 @@ $root.protos = (function() {
 | 
			
		||||
                        message.shouldForceResync = reader.bool();
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                case 5: {
 | 
			
		||||
                        message.peerJoinIndex = reader.int32();
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                default:
 | 
			
		||||
                    reader.skipType(tag & 7);
 | 
			
		||||
                    break;
 | 
			
		||||
@@ -4050,6 +4111,9 @@ $root.protos = (function() {
 | 
			
		||||
            if (message.shouldForceResync != null && message.hasOwnProperty("shouldForceResync"))
 | 
			
		||||
                if (typeof message.shouldForceResync !== "boolean")
 | 
			
		||||
                    return "shouldForceResync: boolean expected";
 | 
			
		||||
            if (message.peerJoinIndex != null && message.hasOwnProperty("peerJoinIndex"))
 | 
			
		||||
                if (!$util.isInteger(message.peerJoinIndex))
 | 
			
		||||
                    return "peerJoinIndex: integer expected";
 | 
			
		||||
            return null;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
@@ -4088,6 +4152,8 @@ $root.protos = (function() {
 | 
			
		||||
            }
 | 
			
		||||
            if (object.shouldForceResync != null)
 | 
			
		||||
                message.shouldForceResync = Boolean(object.shouldForceResync);
 | 
			
		||||
            if (object.peerJoinIndex != null)
 | 
			
		||||
                message.peerJoinIndex = object.peerJoinIndex | 0;
 | 
			
		||||
            return message;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
@@ -4114,6 +4180,7 @@ $root.protos = (function() {
 | 
			
		||||
                } else
 | 
			
		||||
                    object.unconfirmedMask = options.longs === String ? "0" : 0;
 | 
			
		||||
                object.shouldForceResync = false;
 | 
			
		||||
                object.peerJoinIndex = 0;
 | 
			
		||||
            }
 | 
			
		||||
            if (message.refRenderFrameId != null && message.hasOwnProperty("refRenderFrameId"))
 | 
			
		||||
                object.refRenderFrameId = message.refRenderFrameId;
 | 
			
		||||
@@ -4129,6 +4196,8 @@ $root.protos = (function() {
 | 
			
		||||
            }
 | 
			
		||||
            if (message.shouldForceResync != null && message.hasOwnProperty("shouldForceResync"))
 | 
			
		||||
                object.shouldForceResync = message.shouldForceResync;
 | 
			
		||||
            if (message.peerJoinIndex != null && message.hasOwnProperty("peerJoinIndex"))
 | 
			
		||||
                object.peerJoinIndex = message.peerJoinIndex;
 | 
			
		||||
            return object;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user