Compare commits

...

22 Commits

Author SHA1 Message Date
genxium
b5b43bb596 Minor update. 2023-01-22 14:32:32 +08:00
genxium
59767c1ed5 Added network doctor stats. 2023-01-22 11:39:27 +08:00
genxium
1c6ad5c8f8 Minor fix. 2023-01-21 23:03:55 +08:00
genxium
34e0893eb8 Added network doctor for frontend. 2023-01-21 22:53:41 +08:00
genxium
cc7524becd Updated README. 2023-01-21 11:59:01 +08:00
genxium
d06cb18a08 Fixed inertia on jumping. 2023-01-21 11:11:48 +08:00
genxium
00816fb636 Minor update. 2023-01-21 10:41:38 +08:00
genxium
ff24bea055 Fixed fireball trigger. 2023-01-21 10:40:13 +08:00
genxium
56d66a128a Minor updates. 2023-01-20 23:44:26 +08:00
genxium
2f097dfec5 Added turn-around and dashing actual triggers. 2023-01-20 23:22:02 +08:00
genxium
ff48b47ecc Updated documentation for the plan of UDP secondary session. 2023-01-20 20:49:26 +08:00
genxium
7a0127b17d Updated README. 2023-01-20 14:32:38 +08:00
genxium
59c8427c70 Enhanced turn-around performance. 2023-01-20 11:29:27 +08:00
genxium
c357ebad3b Updated README again. 2023-01-19 22:19:40 +08:00
genxium
b2e1f7c2a6 Updated README. 2023-01-19 10:45:48 +08:00
genxium
9a8c32197e Added TurnAroundFramesToRecover. 2023-01-19 09:20:52 +08:00
genxium
a82a238ce9 Added frontend log for inspection of "onPeerInputFrameUpsync". 2023-01-18 22:43:10 +08:00
genxium
5b76c5bbfb Minor fix. 2023-01-18 18:03:54 +08:00
genxium
b81c470135 Drafted peer inputFrameUpsync broadcasting mechanism. 2023-01-18 17:53:58 +08:00
genxium
48074d48af Misc fixes for UI alignments. 2023-01-18 12:22:12 +08:00
genxium
342efc623c Made frontend landscape. 2023-01-17 23:35:23 +08:00
genxium
b8e757064d Further enhanced frontend input processing and fixed frame data logging. 2023-01-17 17:38:18 +08:00
67 changed files with 7848 additions and 6070 deletions

View File

@@ -67,3 +67,12 @@ To summarize, if UDP is used we need
## Additional hassles to care about using UDP ## Additional hassles to care about using UDP
When using UDP, it's also necessary to verify authorization of each incoming packet, e.g. by simple time limited symmetric key, due to being connectionless. When using UDP, it's also necessary to verify authorization of each incoming packet, e.g. by simple time limited symmetric key, due to being connectionless.
## Why not hybrid?
Instead of replacing all use of TCP by UDP, it's more reasonable to keep using TCP for login and the "all-confirmed downsync inputFrames" from server to players (and possibly "upsync inputFrames" from player to server, but tradeoff on that remains to be discussed), while using a `UDP secondary session` for broadcasting inputFrames of each individual player asap (either using p2p or not) just for **better prediction performance**!
## How do you actually implement the `UDP secondary session`?
It's not a global consensus, but in practice many UDP communications are platform specific due to their paired asynchronous I/O choices, e.g. epoll in Linux and kqueue in BSD-ish. Of course there're many 3rd party higher level encapsulated tools for cross-platform use but that introduces extra debugging when things go wrong.
Therefore, the following plan doesn't assume use of any specific 3rd party encapsulation of UDP communication.
![UDP_secondary_session](./charts/UDPEssentials.jpg)

View File

@@ -2,13 +2,15 @@
This project is a demo for a websocket-based rollback netcode inspired by [GGPO](https://github.com/pond3r/ggpo/blob/master/doc/README.md). As lots of feedbacks ask for a discussion on using UDP instead, I tried to summarize my personal opinion about it in [ConcerningEdgeCases](./ConcerningEdgeCases.md) -- not necessarily correct but that's indeed a question to face :) This project is a demo for a websocket-based rollback netcode inspired by [GGPO](https://github.com/pond3r/ggpo/blob/master/doc/README.md). As lots of feedbacks ask for a discussion on using UDP instead, I tried to summarize my personal opinion about it in [ConcerningEdgeCases](./ConcerningEdgeCases.md) -- not necessarily correct but that's indeed a question to face :)
The following video is recorded over INTERNET using an input delay of 4 frames and it feels SMOOTH when playing! Please also checkout [this demo video](https://pan.baidu.com/s/1ML6hNupaPHPJRd5rcTvQvw?pwd=8ruc) to see how this demo carries out a full 60fps synchronization with the help of _batched input upsync/downsync_ for satisfying network I/O performance. The following video is recorded over INTERNET using an input delay of 4 frames and it feels SMOOTH when playing! Please also checkout these demo videos
- [source video of the first gif (earlier version)](https://pan.baidu.com/s/1ML6hNupaPHPJRd5rcTvQvw?pwd=8ruc)
- [source video of the second gif (added turn-around optimization & dashing)](https://pan.baidu.com/s/1isMcLvxax4NNkDgitV_FDg?pwd=s1i6)
to see how this demo carries out a full 60fps synchronization with the help of _batched input upsync/downsync_ for satisfying network I/O performance.
![gif_demo_1](./charts/internet_fireball_explosion_wallmove_spedup.gif) ![gif_demo_1](./charts/internet_fireball_explosion_wallmove_spedup.gif)
![gif_demo_2](./charts/jump_sync_spedup.gif) ![gif_demo_2](./charts/internet_dash_turnaround_cut_spedup.gif)
All gifs are sped up to ~1.5x for file size reduction, kindly note that animations are resumed from a partial progress!
# Notable Features # Notable Features
- Backend dynamics toggle via [Room.BackendDynamicsEnabled](https://github.com/genxium/DelayNoMore/blob/v0.9.14/battle_srv/models/room.go#L786) - Backend dynamics toggle via [Room.BackendDynamicsEnabled](https://github.com/genxium/DelayNoMore/blob/v0.9.14/battle_srv/models/room.go#L786)
@@ -67,7 +69,7 @@ user@proj-root/battle_srv/configs> cp -r ./configs.template ./configs
user@proj-root/frontend/assets/plugin_scripts> cp ./conf.js.template ./conf.js user@proj-root/frontend/assets/plugin_scripts> cp ./conf.js.template ./conf.js
``` ```
## 1.2 Actual building & running ## 1.3 Actual building & running
### Backend ### Backend
``` ```
### The following command runs mysql-server in foreground, it's almost NEVER run in such a way, please find a proper way to run it for yourself ### The following command runs mysql-server in foreground, it's almost NEVER run in such a way, please find a proper way to run it for yourself
@@ -96,3 +98,14 @@ ErrFatal {"err": "MISCONF Redis is configured to save RDB snapshots, but
``` ```
Just restart your `redis-server` process. Just restart your `redis-server` process.
### 2.2 Why not show "PING value" on frontend display?
The most important reason for not showing "PING value" is simple: in most games the "PING value" is collected by a dedicated kernel thread which doesn't interfere the UI thread or the primary networking thread. As this demo primarily runs on browser by far, I don't have this capability easily.
Moreover, in practice I found that to spot sync anomalies, the following tools are much more useful than the "PING VALUE".
- Detection of [prediction mismatch on the frontend](https://github.com/genxium/DelayNoMore/blob/v0.9.19/frontend/assets/scripts/Map.js#L842).
- Detection of [type#1 forceConfirmation on the backend](https://github.com/genxium/DelayNoMore/blob/v0.9.19/battle_srv/models/room.go#L1246).
- Detection of [type#2 forceConfirmation on the backend](https://github.com/genxium/DelayNoMore/blob/v0.9.19/battle_srv/models/room.go#L1259).
There's also some useful information displayed on the frontend when `true == Map.showNetworkDoctorInfo`.
![networkstats](./charts/networkstats.png)

View File

@@ -89,6 +89,7 @@ func setRouter(router *gin.Engine) {
router.StaticFS("/asset", http.Dir(filepath.Join(Conf.General.AppRoot, "asset"))) router.StaticFS("/asset", http.Dir(filepath.Join(Conf.General.AppRoot, "asset")))
router.GET("/ping", f) router.GET("/ping", f)
router.GET("/tsrht", ws.Serve) router.GET("/tsrht", ws.Serve)
router.GET("/tsrhtSecondary", ws.HandleSecondaryWsSessionForPlayer)
apiRouter := router.Group("/api") apiRouter := router.Group("/api")
{ {

View File

@@ -41,6 +41,7 @@ func toPbRoomDownsyncFrame(rdf *battle.RoomDownsyncFrame) *pb.RoomDownsyncFrame
OnWall: last.OnWall, OnWall: last.OnWall,
OnWallNormX: last.OnWallNormX, OnWallNormX: last.OnWallNormX,
OnWallNormY: last.OnWallNormY, OnWallNormY: last.OnWallNormY,
CapturedByInertia: last.CapturedByInertia,
JoinIndex: last.JoinIndex, JoinIndex: last.JoinIndex,
BulletTeamId: last.BulletTeamId, BulletTeamId: last.BulletTeamId,
ChCollisionTeamId: last.ChCollisionTeamId, ChCollisionTeamId: last.ChCollisionTeamId,
@@ -165,6 +166,7 @@ func toPbPlayers(modelInstances map[int32]*Player, withMetaInfo bool) []*pb.Play
OnWall: last.OnWall, OnWall: last.OnWall,
OnWallNormX: last.OnWallNormX, OnWallNormX: last.OnWallNormX,
OnWallNormY: last.OnWallNormY, OnWallNormY: last.OnWallNormY,
CapturedByInertia: last.CapturedByInertia,
JoinIndex: last.JoinIndex, JoinIndex: last.JoinIndex,
BulletTeamId: last.BulletTeamId, BulletTeamId: last.BulletTeamId,
ChCollisionTeamId: last.ChCollisionTeamId, ChCollisionTeamId: last.ChCollisionTeamId,
@@ -216,6 +218,7 @@ func toJsPlayers(modelInstances map[int32]*Player) []*battle.PlayerDownsync {
OnWall: last.OnWall, OnWall: last.OnWall,
OnWallNormX: last.OnWallNormX, OnWallNormX: last.OnWallNormX,
OnWallNormY: last.OnWallNormY, OnWallNormY: last.OnWallNormY,
CapturedByInertia: last.CapturedByInertia,
Score: last.Score, Score: last.Score,
Removed: last.Removed, Removed: last.Removed,
} }

View File

@@ -31,6 +31,7 @@ const (
DOWNSYNC_MSG_ACT_INPUT_BATCH = int32(2) DOWNSYNC_MSG_ACT_INPUT_BATCH = int32(2)
DOWNSYNC_MSG_ACT_BATTLE_STOPPED = int32(3) DOWNSYNC_MSG_ACT_BATTLE_STOPPED = int32(3)
DOWNSYNC_MSG_ACT_FORCED_RESYNC = int32(4) 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_READY_TO_START = int32(-1)
DOWNSYNC_MSG_ACT_BATTLE_START = int32(0) DOWNSYNC_MSG_ACT_BATTLE_START = int32(0)
@@ -117,9 +118,14 @@ type Room struct {
* Moreover, during the invocation of `PlayerSignalToCloseDict`, the `Player` instance is supposed to be deallocated (though not synchronously). * Moreover, during the invocation of `PlayerSignalToCloseDict`, the `Player` instance is supposed to be deallocated (though not synchronously).
*/ */
PlayerDownsyncSessionDict map[int32]*websocket.Conn PlayerDownsyncSessionDict map[int32]*websocket.Conn
PlayerDownsyncChanDict map[int32](chan pb.InputsBufferSnapshot)
PlayerActiveWatchdogDict map[int32](*Watchdog)
PlayerSignalToCloseDict map[int32]SignalToCloseConnCbType 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)
Score float32 Score float32
State int32 State int32
Index int Index int
@@ -184,7 +190,7 @@ func (pR *Room) AddPlayerIfPossible(pPlayerFromDbInit *Player, session *websocke
pR.PlayerSignalToCloseDict[playerId] = signalToCloseConnOfThisPlayer pR.PlayerSignalToCloseDict[playerId] = signalToCloseConnOfThisPlayer
newWatchdog := NewWatchdog(ConstVals.Ws.WillKickIfInactiveFor, func() { 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)) 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() newWatchdog.Stop()
pR.PlayerActiveWatchdogDict[playerId] = newWatchdog pR.PlayerActiveWatchdogDict[playerId] = newWatchdog
@@ -221,7 +227,7 @@ func (pR *Room) ReAddPlayerIfPossible(pTmpPlayerInstance *Player, session *webso
pR.PlayerSignalToCloseDict[playerId] = signalToCloseConnOfThisPlayer pR.PlayerSignalToCloseDict[playerId] = signalToCloseConnOfThisPlayer
pR.PlayerActiveWatchdogDict[playerId] = NewWatchdog(ConstVals.Ws.WillKickIfInactiveFor, func() { 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)) 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 }) // 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)) 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) kickoffFrameJs := pR.RenderFrameBuffer.GetByFrameId(0).(*battle.RoomDownsyncFrame)
pbKickOffRenderFrame := toPbRoomDownsyncFrame(kickoffFrameJs) pbKickOffRenderFrame := toPbRoomDownsyncFrame(kickoffFrameJs)
pbKickOffRenderFrame.SpeciesIdList = pR.SpeciesIdList 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)) 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() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
Logger.Error("downsyncLoop, recovery spot#1, recovered from: ", zap.Any("roomId", pR.Id), zap.Any("playerId", playerId), zap.Any("panic", r)) Logger.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.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 { for {
select {
case inputsBufferSnapshot := <-playerDownsyncChan:
nowBattleState := atomic.LoadInt32(&pR.State) nowBattleState := atomic.LoadInt32(&pR.State)
switch nowBattleState { switch nowBattleState {
case RoomBattleStateIns.IDLE, RoomBattleStateIns.STOPPING_BATTLE_FOR_SETTLEMENT, RoomBattleStateIns.IN_SETTLEMENT, RoomBattleStateIns.IN_DISMISSAL: 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)) Logger.Warn(fmt.Sprintf("Battle is not waiting/preparing/active for playerDownsyncChan for (roomId: %d, playerId:%d)", pR.Id, playerId))
return return
} }
select {
case inputsBufferSnapshot := <-playerDownsyncChan:
pR.downsyncToSinglePlayer(playerId, player, inputsBufferSnapshot.RefRenderFrameId, inputsBufferSnapshot.UnconfirmedMask, inputsBufferSnapshot.ToSendInputFrameDownsyncs, inputsBufferSnapshot.ShouldForceResync) 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)) //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: 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. 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) 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() { pR.onBattlePrepare(func() {
@@ -599,6 +610,16 @@ func (pR *Room) OnBattleCmdReceived(pReq *pb.WsReq) {
inputsBufferSnapshot := pR.markConfirmationIfApplicable(inputFrameUpsyncBatch, playerId, player) inputsBufferSnapshot := pR.markConfirmationIfApplicable(inputFrameUpsyncBatch, playerId, player)
if nil != inputsBufferSnapshot { if nil != inputsBufferSnapshot {
pR.downsyncToAllPlayers(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), PlayersArr: toPbPlayers(pR.Players, false),
CountdownNanos: -1, // TODO: Replace this magic constant! CountdownNanos: -1, // TODO: Replace this magic constant!
} }
pR.sendSafely(&assembledFrame, nil, DOWNSYNC_MSG_ACT_BATTLE_STOPPED, playerId, 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`. // 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)) Logger.Info("Sending out frame for RoomBattleState.PREPARE:", zap.Any("battleReadyToStartFrame", battleReadyToStartFrame))
for _, player := range pR.Players { for _, player := range pR.Players {
pR.sendSafely(battleReadyToStartFrame, nil, DOWNSYNC_MSG_ACT_BATTLE_READY_TO_START, player.Id, true) pR.sendSafely(battleReadyToStartFrame, nil, DOWNSYNC_MSG_ACT_BATTLE_READY_TO_START, player.Id, true, MAGIC_JOIN_INDEX_DEFAULT)
} }
battlePreparationNanos := int64(6000000000) battlePreparationNanos := int64(6000000000)
@@ -748,6 +769,7 @@ func (pR *Room) OnDismissed() {
pR.CharacterConfigsArr = make([]*battle.CharacterConfig, pR.Capacity) pR.CharacterConfigsArr = make([]*battle.CharacterConfig, pR.Capacity)
pR.CollisionSysMap = make(map[int32]*resolv.Object) pR.CollisionSysMap = make(map[int32]*resolv.Object)
pR.PlayerDownsyncSessionDict = make(map[int32]*websocket.Conn) pR.PlayerDownsyncSessionDict = make(map[int32]*websocket.Conn)
pR.PlayerSecondaryDownsyncSessionDict = make(map[int32]*websocket.Conn)
for _, oldWatchdog := range pR.PlayerActiveWatchdogDict { for _, oldWatchdog := range pR.PlayerActiveWatchdogDict {
oldWatchdog.Stop() oldWatchdog.Stop()
} }
@@ -756,7 +778,12 @@ func (pR *Room) OnDismissed() {
close(oldChan) close(oldChan)
} }
pR.PlayerDownsyncChanDict = make(map[int32](chan pb.InputsBufferSnapshot)) 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.PlayerSignalToCloseDict = make(map[int32]SignalToCloseConnCbType)
pR.PlayerSecondarySignalToCloseDict = make(map[int32]SignalToCloseConnCbType)
pR.JoinIndexBooleanArr = make([]bool, pR.Capacity) pR.JoinIndexBooleanArr = make([]bool, pR.Capacity)
pR.RenderCacheSize = 1024 pR.RenderCacheSize = 1024
pR.RenderFrameBuffer = battle.NewRingBuffer(pR.RenderCacheSize) pR.RenderFrameBuffer = battle.NewRingBuffer(pR.RenderCacheSize)
@@ -781,7 +808,7 @@ func (pR *Room) OnDismissed() {
pR.BattleDurationFrames = int32(60 * serverFps) pR.BattleDurationFrames = int32(60 * serverFps)
pR.BattleDurationNanos = int64(pR.BattleDurationFrames) * (pR.RollbackEstimatedDtNanos + 1) pR.BattleDurationNanos = int64(pR.BattleDurationFrames) * (pR.RollbackEstimatedDtNanos + 1)
pR.InputFrameUpsyncDelayTolerance = battle.ConvertToNoDelayInputFrameId(pR.NstDelayFrames) - 1 // this value should be strictly smaller than (NstDelayFrames >> InputScaleFrames), otherwise "type#1 forceConfirmation" might become a lag avalanche pR.InputFrameUpsyncDelayTolerance = battle.ConvertToNoDelayInputFrameId(pR.NstDelayFrames) - 1 // this value should be strictly smaller than (NstDelayFrames >> InputScaleFrames), otherwise "type#1 forceConfirmation" might become a lag avalanche
pR.MaxChasingRenderFramesPerUpdate = 12 // Don't set this value too high to avoid exhausting frontend CPU within a single frame pR.MaxChasingRenderFramesPerUpdate = 4 // Don't set this value too high to avoid exhausting frontend CPU within a single frame
pR.BackendDynamicsEnabled = true // [WARNING] When "false", recovery upon reconnection wouldn't work! pR.BackendDynamicsEnabled = true // [WARNING] When "false", recovery upon reconnection wouldn't work!
pR.ForceAllResyncOnAnyActiveSlowTicker = true // See tradeoff discussion in "downsyncToAllPlayers" pR.ForceAllResyncOnAnyActiveSlowTicker = true // See tradeoff discussion in "downsyncToAllPlayers"
@@ -799,19 +826,24 @@ func (pR *Room) OnDismissed() {
} }
func (pR *Room) expelPlayerDuringGame(playerId int32) { func (pR *Room) expelPlayerDuringGame(playerId int32) {
if signalToCloseConnOfThisPlayer, existent := pR.PlayerSignalToCloseDict[playerId]; existent { pR.signalToCloseAllSessionsOfPlayer(playerId, Constants.RetCode.UnknownError)
signalToCloseConnOfThisPlayer(Constants.RetCode.UnknownError, "") // TODO: Specify an error code
}
pR.onPlayerExpelledDuringGame(playerId) pR.onPlayerExpelledDuringGame(playerId)
} }
func (pR *Room) expelPlayerForDismissal(playerId int32) { func (pR *Room) expelPlayerForDismissal(playerId int32) {
if signalToCloseConnOfThisPlayer, existent := pR.PlayerSignalToCloseDict[playerId]; existent { pR.signalToCloseAllSessionsOfPlayer(playerId, Constants.RetCode.UnknownError)
signalToCloseConnOfThisPlayer(Constants.RetCode.UnknownError, "") // TODO: Specify an error code
}
pR.onPlayerExpelledForDismissal(playerId) 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) { func (pR *Room) onPlayerExpelledDuringGame(playerId int32) {
pR.onPlayerLost(playerId) 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 { if player, existent := pR.Players[playerId]; existent {
thatPlayerBattleState := atomic.LoadInt32(&(player.BattleState)) thatPlayerBattleState := atomic.LoadInt32(&(player.BattleState))
switch thatPlayerBattleState { switch thatPlayerBattleState {
@@ -888,6 +924,8 @@ func (pR *Room) clearPlayerNetworkSession(playerId int32) {
delete(pR.PlayerActiveWatchdogDict, playerId) delete(pR.PlayerActiveWatchdogDict, playerId)
delete(pR.PlayerDownsyncSessionDict, playerId) delete(pR.PlayerDownsyncSessionDict, playerId)
delete(pR.PlayerSignalToCloseDict, 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)) Logger.Debug(fmt.Sprintf("OnPlayerBattleColliderAcked-middle: roomId=%v, roomState=%v, targetPlayerId=%v, targetPlayerBattleState=%v, thatPlayerId=%v, thatPlayerBattleState=%v", pR.Id, pR.State, targetPlayer.Id, targetPlayer.BattleState, thatPlayer.Id, thatPlayerBattleState))
if thatPlayerId == targetPlayer.Id || (PlayerBattleStateIns.ADDED_PENDING_BATTLE_COLLIDER_ACK == thatPlayerBattleState || PlayerBattleStateIns.ACTIVE == thatPlayerBattleState) { if thatPlayerId == targetPlayer.Id || (PlayerBattleStateIns.ADDED_PENDING_BATTLE_COLLIDER_ACK == thatPlayerBattleState || PlayerBattleStateIns.ACTIVE == thatPlayerBattleState) {
Logger.Debug(fmt.Sprintf("OnPlayerBattleColliderAcked-sending DOWNSYNC_MSG_ACT_PLAYER_ADDED_AND_ACKED: roomId=%v, roomState=%v, targetPlayerId=%v, targetPlayerBattleState=%v, capacity=%v, EffectivePlayerCount=%v", pR.Id, pR.State, targetPlayer.Id, targetPlayer.BattleState, pR.Capacity, pR.EffectivePlayerCount)) Logger.Debug(fmt.Sprintf("OnPlayerBattleColliderAcked-sending DOWNSYNC_MSG_ACT_PLAYER_ADDED_AND_ACKED: roomId=%v, roomState=%v, targetPlayerId=%v, targetPlayerBattleState=%v, capacity=%v, EffectivePlayerCount=%v", pR.Id, pR.State, targetPlayer.Id, targetPlayer.BattleState, pR.Capacity, pR.EffectivePlayerCount))
pR.sendSafely(playerAckedFrame, nil, DOWNSYNC_MSG_ACT_PLAYER_ADDED_AND_ACKED, thatPlayer.Id, 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) atomic.StoreInt32(&(targetPlayer.BattleState), PlayerBattleStateIns.ACTIVE)
@@ -1010,19 +1048,19 @@ func (pR *Room) OnPlayerBattleColliderAcked(playerId int32) bool {
return true 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() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
Logger.Error("sendSafely, recovered from: ", zap.Any("roomId", pR.Id), zap.Any("playerId", playerId), zap.Any("panic", r)) Logger.Error("sendSafely, recovered from: ", zap.Any("roomId", pR.Id), zap.Any("playerId", playerId), zap.Any("panic", r))
} }
}() }()
if playerDownsyncSession, existent := pR.PlayerDownsyncSessionDict[playerId]; existent {
pResp := &pb.WsResp{ pResp := &pb.WsResp{
Ret: int32(Constants.RetCode.Ok), Ret: int32(Constants.RetCode.Ok),
Act: act, Act: act,
Rdf: roomDownsyncFrame, Rdf: roomDownsyncFrame,
InputFrameDownsyncBatch: toSendInputFrameDownsyncs, InputFrameDownsyncBatch: toSendInputFrameDownsyncs,
PeerJoinIndex: peerJoinIndex,
} }
theBytes, marshalErr := proto.Marshal(pResp) theBytes, marshalErr := proto.Marshal(pResp)
@@ -1030,8 +1068,23 @@ func (pR *Room) sendSafely(roomDownsyncFrame *pb.RoomDownsyncFrame, toSendInputF
panic(fmt.Sprintf("Error marshaling downsync message: roomId=%v, playerId=%v, roomState=%v, roomEffectivePlayerCount=%v", pR.Id, playerId, pR.State, pR.EffectivePlayerCount)) panic(fmt.Sprintf("Error marshaling downsync message: roomId=%v, playerId=%v, roomState=%v, roomEffectivePlayerCount=%v", pR.Id, playerId, pR.State, pR.EffectivePlayerCount))
} }
if MAGIC_JOIN_INDEX_DEFAULT == peerJoinIndex {
if playerDownsyncSession, existent := pR.PlayerDownsyncSessionDict[playerId]; existent {
if err := playerDownsyncSession.WriteMessage(websocket.BinaryMessage, theBytes); nil != err { 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)) 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) { 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). [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). 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)) playerBattleState := atomic.LoadInt32(&(player.BattleState))
switch playerBattleState { 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: 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 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" 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 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 shouldResync3 := shouldForceResync
@@ -1455,13 +1532,13 @@ func (pR *Room) downsyncToSinglePlayer(playerId int32, player *Player, refRender
refRenderFrame.BackendUnconfirmedMask = unconfirmedMask refRenderFrame.BackendUnconfirmedMask = unconfirmedMask
pbRefRenderFrame := toPbRoomDownsyncFrame(refRenderFrame) pbRefRenderFrame := toPbRoomDownsyncFrame(refRenderFrame)
pbRefRenderFrame.SpeciesIdList = pR.SpeciesIdList 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))) //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 { 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)) 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 { } 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 player.LastSentInputFrameId = toSendInputFrameIdEd - 1
if shouldResync1 { 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 { func (pR *Room) cloneInputsBuffer(stFrameId, edFrameId int32) []*pb.InputFrameDownsync {
// [WARNING] This function MUST BE called while "pR.InputsBufferLock" is locked! // [WARNING] This function MUST BE called while "pR.InputsBufferLock" is locked!
cloned := make([]*pb.InputFrameDownsync, 0, edFrameId-stFrameId) cloned := make([]*pb.InputFrameDownsync, 0, edFrameId-stFrameId)
@@ -1501,3 +1588,22 @@ func (pR *Room) cloneInputsBuffer(stFrameId, edFrameId int32) []*pb.InputFrameDo
return cloned 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
}
}
}
}

View File

@@ -30,9 +30,9 @@ type PlayerDownsync struct {
VirtualGridX int32 `protobuf:"varint,2,opt,name=virtualGridX,proto3" json:"virtualGridX,omitempty"` VirtualGridX int32 `protobuf:"varint,2,opt,name=virtualGridX,proto3" json:"virtualGridX,omitempty"`
VirtualGridY int32 `protobuf:"varint,3,opt,name=virtualGridY,proto3" json:"virtualGridY,omitempty"` VirtualGridY int32 `protobuf:"varint,3,opt,name=virtualGridY,proto3" json:"virtualGridY,omitempty"`
DirX int32 `protobuf:"varint,4,opt,name=dirX,proto3" json:"dirX,omitempty"` DirX int32 `protobuf:"varint,4,opt,name=dirX,proto3" json:"dirX,omitempty"`
DirY int32 `protobuf:"varint,5,opt,name=dirY,proto3" json:"dirY,omitempty"` // "dirX" and "dirY" determines character facing DirY int32 `protobuf:"varint,5,opt,name=dirY,proto3" json:"dirY,omitempty"`
VelX int32 `protobuf:"varint,6,opt,name=velX,proto3" json:"velX,omitempty"` VelX int32 `protobuf:"varint,6,opt,name=velX,proto3" json:"velX,omitempty"`
VelY int32 `protobuf:"varint,7,opt,name=velY,proto3" json:"velY,omitempty"` // "velX" and "velY" is used to record the accumulated effect by accelerations (including gravity) VelY int32 `protobuf:"varint,7,opt,name=velY,proto3" json:"velY,omitempty"` // "velX" and "velY" is used to record the accumulated effect by inertia and accelerations (including gravity)
Speed int32 `protobuf:"varint,8,opt,name=speed,proto3" json:"speed,omitempty"` // this is the instantaneous scalar attribute of a character, different from but will be accounted in "velX" and "velY" Speed int32 `protobuf:"varint,8,opt,name=speed,proto3" json:"speed,omitempty"` // this is the instantaneous scalar attribute of a character, different from but will be accounted in "velX" and "velY"
BattleState int32 `protobuf:"varint,9,opt,name=battleState,proto3" json:"battleState,omitempty"` BattleState int32 `protobuf:"varint,9,opt,name=battleState,proto3" json:"battleState,omitempty"`
JoinIndex int32 `protobuf:"varint,10,opt,name=joinIndex,proto3" json:"joinIndex,omitempty"` JoinIndex int32 `protobuf:"varint,10,opt,name=joinIndex,proto3" json:"joinIndex,omitempty"`
@@ -54,6 +54,7 @@ type PlayerDownsync struct {
OnWall bool `protobuf:"varint,26,opt,name=onWall,proto3" json:"onWall,omitempty"` // like "inAir", its by design a standalone field only inferred by the collision result of "applyInputFrameDownsyncDynamicsOnSingleRenderFrame" instead of "characterState", because we need check the transition for "characterState" from this field, i.e. "onWall (prev -> curr)" OnWall bool `protobuf:"varint,26,opt,name=onWall,proto3" json:"onWall,omitempty"` // like "inAir", its by design a standalone field only inferred by the collision result of "applyInputFrameDownsyncDynamicsOnSingleRenderFrame" instead of "characterState", because we need check the transition for "characterState" from this field, i.e. "onWall (prev -> curr)"
OnWallNormX int32 `protobuf:"varint,27,opt,name=onWallNormX,proto3" json:"onWallNormX,omitempty"` OnWallNormX int32 `protobuf:"varint,27,opt,name=onWallNormX,proto3" json:"onWallNormX,omitempty"`
OnWallNormY int32 `protobuf:"varint,28,opt,name=onWallNormY,proto3" json:"onWallNormY,omitempty"` OnWallNormY int32 `protobuf:"varint,28,opt,name=onWallNormY,proto3" json:"onWallNormY,omitempty"`
CapturedByInertia bool `protobuf:"varint,29,opt,name=capturedByInertia,proto3" json:"capturedByInertia,omitempty"` // like "inAir", its by design a standalone field only inferred by the calc result of "applyInputFrameDownsyncDynamicsOnSingleRenderFrame" instead of "characterState"
Name string `protobuf:"bytes,997,opt,name=name,proto3" json:"name,omitempty"` Name string `protobuf:"bytes,997,opt,name=name,proto3" json:"name,omitempty"`
DisplayName string `protobuf:"bytes,998,opt,name=displayName,proto3" json:"displayName,omitempty"` DisplayName string `protobuf:"bytes,998,opt,name=displayName,proto3" json:"displayName,omitempty"`
Avatar string `protobuf:"bytes,999,opt,name=avatar,proto3" json:"avatar,omitempty"` Avatar string `protobuf:"bytes,999,opt,name=avatar,proto3" json:"avatar,omitempty"`
@@ -287,6 +288,13 @@ func (x *PlayerDownsync) GetOnWallNormY() int32 {
return 0 return 0
} }
func (x *PlayerDownsync) GetCapturedByInertia() bool {
if x != nil {
return x.CapturedByInertia
}
return false
}
func (x *PlayerDownsync) GetName() string { func (x *PlayerDownsync) GetName() string {
if x != nil { if x != nil {
return x.Name return x.Name
@@ -386,6 +394,7 @@ type InputFrameUpsync struct {
InputFrameId int32 `protobuf:"varint,1,opt,name=inputFrameId,proto3" json:"inputFrameId,omitempty"` InputFrameId int32 `protobuf:"varint,1,opt,name=inputFrameId,proto3" json:"inputFrameId,omitempty"`
Encoded uint64 `protobuf:"varint,2,opt,name=encoded,proto3" json:"encoded,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() { func (x *InputFrameUpsync) Reset() {
@@ -434,6 +443,13 @@ func (x *InputFrameUpsync) GetEncoded() uint64 {
return 0 return 0
} }
func (x *InputFrameUpsync) GetJoinIndex() int32 {
if x != nil {
return x.JoinIndex
}
return 0
}
type InputFrameDownsync struct { type InputFrameDownsync struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@@ -658,6 +674,7 @@ type WsResp struct {
Rdf *RoomDownsyncFrame `protobuf:"bytes,4,opt,name=rdf,proto3" json:"rdf,omitempty"` Rdf *RoomDownsyncFrame `protobuf:"bytes,4,opt,name=rdf,proto3" json:"rdf,omitempty"`
InputFrameDownsyncBatch []*InputFrameDownsync `protobuf:"bytes,5,rep,name=inputFrameDownsyncBatch,proto3" json:"inputFrameDownsyncBatch,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"` 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() { func (x *WsResp) Reset() {
@@ -734,6 +751,13 @@ func (x *WsResp) GetBciFrame() *BattleColliderInfo {
return nil return nil
} }
func (x *WsResp) GetPeerJoinIndex() int32 {
if x != nil {
return x.PeerJoinIndex
}
return 0
}
type InputsBufferSnapshot struct { type InputsBufferSnapshot struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@@ -743,6 +767,7 @@ type InputsBufferSnapshot struct {
UnconfirmedMask uint64 `protobuf:"varint,2,opt,name=unconfirmedMask,proto3" json:"unconfirmedMask,omitempty"` UnconfirmedMask uint64 `protobuf:"varint,2,opt,name=unconfirmedMask,proto3" json:"unconfirmedMask,omitempty"`
ToSendInputFrameDownsyncs []*InputFrameDownsync `protobuf:"bytes,3,rep,name=toSendInputFrameDownsyncs,proto3" json:"toSendInputFrameDownsyncs,omitempty"` ToSendInputFrameDownsyncs []*InputFrameDownsync `protobuf:"bytes,3,rep,name=toSendInputFrameDownsyncs,proto3" json:"toSendInputFrameDownsyncs,omitempty"`
ShouldForceResync bool `protobuf:"varint,4,opt,name=shouldForceResync,proto3" json:"shouldForceResync,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() { func (x *InputsBufferSnapshot) Reset() {
@@ -805,6 +830,13 @@ func (x *InputsBufferSnapshot) GetShouldForceResync() bool {
return false return false
} }
func (x *InputsBufferSnapshot) GetPeerJoinIndex() int32 {
if x != nil {
return x.PeerJoinIndex
}
return 0
}
type MeleeBullet struct { type MeleeBullet struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@@ -1592,7 +1624,7 @@ var file_room_downsync_frame_proto_rawDesc = []byte{
0x0a, 0x19, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x0a, 0x19, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x5f,
0x66, 0x72, 0x61, 0x6d, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06, 0x70, 0x72, 0x6f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x73, 0x1a, 0x0e, 0x67, 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x74, 0x6f, 0x73, 0x1a, 0x0e, 0x67, 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x22, 0xc5, 0x07, 0x0a, 0x0e, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x44, 0x6f, 0x6f, 0x74, 0x6f, 0x22, 0xf3, 0x07, 0x0a, 0x0e, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x44, 0x6f,
0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61,
0x6c, 0x47, 0x72, 0x69, 0x64, 0x58, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x76, 0x69, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x58, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x76, 0x69,
@@ -1647,288 +1679,297 @@ var file_room_downsync_frame_proto_rawDesc = []byte{
0x4e, 0x6f, 0x72, 0x6d, 0x58, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x6f, 0x6e, 0x57, 0x4e, 0x6f, 0x72, 0x6d, 0x58, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x6f, 0x6e, 0x57,
0x61, 0x6c, 0x6c, 0x4e, 0x6f, 0x72, 0x6d, 0x58, 0x12, 0x20, 0x0a, 0x0b, 0x6f, 0x6e, 0x57, 0x61, 0x61, 0x6c, 0x6c, 0x4e, 0x6f, 0x72, 0x6d, 0x58, 0x12, 0x20, 0x0a, 0x0b, 0x6f, 0x6e, 0x57, 0x61,
0x6c, 0x6c, 0x4e, 0x6f, 0x72, 0x6d, 0x59, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x6f, 0x6c, 0x6c, 0x4e, 0x6f, 0x72, 0x6d, 0x59, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x6f,
0x6e, 0x57, 0x61, 0x6c, 0x6c, 0x4e, 0x6f, 0x72, 0x6d, 0x59, 0x12, 0x13, 0x0a, 0x04, 0x6e, 0x61, 0x6e, 0x57, 0x61, 0x6c, 0x6c, 0x4e, 0x6f, 0x72, 0x6d, 0x59, 0x12, 0x2c, 0x0a, 0x11, 0x63, 0x61,
0x6d, 0x65, 0x18, 0xe5, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x70, 0x74, 0x75, 0x72, 0x65, 0x64, 0x42, 0x79, 0x49, 0x6e, 0x65, 0x72, 0x74, 0x69, 0x61, 0x18,
0x21, 0x0a, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0xe6, 0x1d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x63, 0x61, 0x70, 0x74, 0x75, 0x72, 0x65, 0x64, 0x42,
0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x79, 0x49, 0x6e, 0x65, 0x72, 0x74, 0x69, 0x61, 0x12, 0x13, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65,
0x6d, 0x65, 0x12, 0x17, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0xe7, 0x07, 0x20, 0x18, 0xe5, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a,
0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x22, 0x6f, 0x0a, 0x11, 0x49, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0xe6, 0x07, 0x20,
0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65,
0x12, 0x0e, 0x0a, 0x02, 0x64, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x64, 0x78, 0x12, 0x17, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0xe7, 0x07, 0x20, 0x01, 0x28,
0x12, 0x0e, 0x0a, 0x02, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x64, 0x79, 0x09, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x22, 0x6f, 0x0a, 0x11, 0x49, 0x6e, 0x70,
0x12, 0x1c, 0x0a, 0x09, 0x62, 0x74, 0x6e, 0x41, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x12, 0x0e,
0x01, 0x28, 0x05, 0x52, 0x09, 0x62, 0x74, 0x6e, 0x41, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x1c, 0x0a, 0x02, 0x64, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x64, 0x78, 0x12, 0x0e,
0x0a, 0x09, 0x62, 0x74, 0x6e, 0x42, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0a, 0x02, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x64, 0x79, 0x12, 0x1c,
0x05, 0x52, 0x09, 0x62, 0x74, 0x6e, 0x42, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0x50, 0x0a, 0x10, 0x0a, 0x09, 0x62, 0x74, 0x6e, 0x41, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28,
0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 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, 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, 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, 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, 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, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x4c, 0x69, 0x73,
0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x22, 0x7c, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x04, 0x52, 0x09, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x4c, 0x69,
0x0a, 0x12, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4c,
0x73, 0x79, 0x6e, 0x63, 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x69, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x66, 0x69,
0x6d, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x69, 0x6e, 0x70, 0x75, 0x72, 0x6d, 0x65, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x3b, 0x0a, 0x0f, 0x48, 0x65, 0x61, 0x72,
0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x62, 0x65, 0x61, 0x74, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x28, 0x0a, 0x0f, 0x63,
0x74, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x04, 0x52, 0x09, 0x69, 0x6e, 0x70, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01,
0x75, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65,
0x6d, 0x65, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x63, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0xb8, 0x02, 0x0a, 0x05, 0x57, 0x73, 0x52, 0x65, 0x71, 0x12,
0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x3b, 0x0a, 0x0f, 0x14, 0x0a, 0x05, 0x6d, 0x73, 0x67, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05,
0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x6d, 0x73, 0x67, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49,
0x28, 0x0a, 0x0f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49,
0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03,
0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0xb8, 0x02, 0x0a, 0x05, 0x57, 0x73, 0x61, 0x63, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78,
0x52, 0x65, 0x71, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x73, 0x67, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x6a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65,
0x28, 0x05, 0x52, 0x05, 0x6d, 0x73, 0x67, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x78, 0x12, 0x24, 0x0a, 0x0d, 0x61, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x46, 0x72, 0x61, 0x6d, 0x65,
0x79, 0x65, 0x72, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x49, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x61, 0x63, 0x6b, 0x69, 0x6e, 0x67,
0x79, 0x65, 0x72, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x12, 0x61, 0x63, 0x6b, 0x69, 0x6e,
0x28, 0x05, 0x52, 0x03, 0x61, 0x63, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6a, 0x6f, 0x69, 0x6e, 0x49, 0x67, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x18, 0x06, 0x20,
0x6e, 0x64, 0x65, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x6a, 0x6f, 0x69, 0x6e, 0x01, 0x28, 0x05, 0x52, 0x12, 0x61, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x70, 0x75, 0x74,
0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x24, 0x0a, 0x0d, 0x61, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x46, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x4e, 0x0a, 0x15, 0x69, 0x6e, 0x70, 0x75, 0x74,
0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x61, 0x63, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x42, 0x61, 0x74, 0x63, 0x68,
0x6b, 0x69, 0x6e, 0x67, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x12, 0x61, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e,
0x63, 0x6b, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63,
0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x61, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x49, 0x52, 0x15, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x73, 0x79,
0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x4e, 0x0a, 0x15, 0x69, 0x6e, 0x63, 0x42, 0x61, 0x74, 0x63, 0x68, 0x12, 0x27, 0x0a, 0x02, 0x68, 0x62, 0x18, 0x08, 0x20,
0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x42, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x48, 0x65, 0x61,
0x61, 0x74, 0x63, 0x68, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x52, 0x02, 0x68, 0x62,
0x74, 0x6f, 0x73, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x22, 0xaf, 0x02, 0x0a, 0x06, 0x57, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x10, 0x0a, 0x03, 0x72,
0x73, 0x79, 0x6e, 0x63, 0x52, 0x15, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x72, 0x65, 0x74, 0x12, 0x20, 0x0a,
0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x42, 0x61, 0x74, 0x63, 0x68, 0x12, 0x27, 0x0a, 0x02, 0x68, 0x0b, 0x65, 0x63, 0x68, 0x6f, 0x65, 0x64, 0x4d, 0x73, 0x67, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01,
0x62, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x28, 0x05, 0x52, 0x0b, 0x65, 0x63, 0x68, 0x6f, 0x65, 0x64, 0x4d, 0x73, 0x67, 0x49, 0x64, 0x12,
0x2e, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x10, 0x0a, 0x03, 0x61, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x61, 0x63,
0x52, 0x02, 0x68, 0x62, 0x22, 0x89, 0x02, 0x0a, 0x06, 0x57, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x74, 0x12, 0x2b, 0x0a, 0x03, 0x72, 0x64, 0x66, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19,
0x10, 0x0a, 0x03, 0x72, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x44, 0x6f, 0x77, 0x6e,
0x74, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x63, 0x68, 0x6f, 0x65, 0x64, 0x4d, 0x73, 0x67, 0x49, 0x64, 0x73, 0x79, 0x6e, 0x63, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x03, 0x72, 0x64, 0x66, 0x12, 0x54,
0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x65, 0x63, 0x68, 0x6f, 0x65, 0x64, 0x4d, 0x73, 0x0a, 0x17, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e,
0x67, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x73, 0x79, 0x6e, 0x63, 0x42, 0x61, 0x74, 0x63, 0x68, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32,
0x52, 0x03, 0x61, 0x63, 0x74, 0x12, 0x2b, 0x0a, 0x03, 0x72, 0x64, 0x66, 0x18, 0x04, 0x20, 0x01, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72,
0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x52, 0x17, 0x69, 0x6e, 0x70,
0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x03, 0x72, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x42,
0x64, 0x66, 0x12, 0x54, 0x0a, 0x17, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x61, 0x74, 0x63, 0x68, 0x12, 0x36, 0x0a, 0x08, 0x62, 0x63, 0x69, 0x46, 0x72, 0x61, 0x6d, 0x65,
0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x42, 0x61, 0x74, 0x63, 0x68, 0x18, 0x05, 0x20, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e,
0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x49, 0x6e, 0x70, 0x42, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x6c, 0x69, 0x64, 0x65, 0x72, 0x49, 0x6e,
0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x52, 0x66, 0x6f, 0x52, 0x08, 0x62, 0x63, 0x69, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x0d,
0x17, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x70, 0x65, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x07, 0x20,
0x79, 0x6e, 0x63, 0x42, 0x61, 0x74, 0x63, 0x68, 0x12, 0x36, 0x0a, 0x08, 0x62, 0x63, 0x69, 0x46, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x70, 0x65, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64,
0x72, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x65, 0x78, 0x22, 0x9a, 0x02, 0x0a, 0x14, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x42, 0x75, 0x66,
0x74, 0x6f, 0x73, 0x2e, 0x42, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x6c, 0x69, 0x64, 0x66, 0x65, 0x72, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x2a, 0x0a, 0x10, 0x72,
0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x62, 0x63, 0x69, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x65, 0x66, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x18,
0x22, 0xf4, 0x01, 0x0a, 0x14, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x42, 0x75, 0x66, 0x66, 0x65, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x10, 0x72, 0x65, 0x66, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72,
0x72, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x2a, 0x0a, 0x10, 0x72, 0x65, 0x66, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x0f, 0x75, 0x6e, 0x63, 0x6f, 0x6e,
0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04,
0x01, 0x28, 0x05, 0x52, 0x10, 0x72, 0x65, 0x66, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x52, 0x0f, 0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4d, 0x61, 0x73,
0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x0f, 0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x6b, 0x12, 0x58, 0x0a, 0x19, 0x74, 0x6f, 0x53, 0x65, 0x6e, 0x64, 0x49, 0x6e, 0x70, 0x75, 0x74,
0x72, 0x6d, 0x65, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x73, 0x18, 0x03,
0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x12, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x49, 0x6e,
0x58, 0x0a, 0x19, 0x74, 0x6f, 0x53, 0x65, 0x6e, 0x64, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63,
0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x73, 0x18, 0x03, 0x20, 0x03, 0x52, 0x19, 0x74, 0x6f, 0x53, 0x65, 0x6e, 0x64, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61,
0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x73, 0x12, 0x2c, 0x0a, 0x11, 0x73,
0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x52, 0x19, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x79, 0x6e, 0x63,
0x74, 0x6f, 0x53, 0x65, 0x6e, 0x64, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x46, 0x6f,
0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x73, 0x12, 0x2c, 0x0a, 0x11, 0x73, 0x68, 0x6f, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x24, 0x0a, 0x0d, 0x70, 0x65, 0x65,
0x75, 0x6c, 0x64, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x04, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05,
0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x46, 0x6f, 0x72, 0x63, 0x52, 0x0d, 0x70, 0x65, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22,
0x65, 0x52, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x22, 0x89, 0x07, 0x0a, 0x0b, 0x4d, 0x65, 0x6c, 0x65, 0x89, 0x07, 0x0a, 0x0b, 0x4d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x12,
0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x12, 0x38, 0x0a, 0x17, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x38, 0x0a, 0x17, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x6e,
0x6e, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05,
0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x17, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x52, 0x17, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x6e, 0x64,
0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x2c, 0x0a, 0x11, 0x6f, 0x66, 0x66,
0x64, 0x12, 0x2c, 0x0a, 0x11, 0x6f, 0x66, 0x66, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02,
0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x6f, 0x66, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x6f, 0x66, 0x66, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4a, 0x6f,
0x66, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x24, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74,
0x24, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x75, 0x70, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d,
0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x46, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x2e, 0x0a,
0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x2e, 0x0a, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x46, 0x72,
0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65,
0x05, 0x52, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a,
0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x64, 0x46, 0x72,
0x61, 0x62, 0x6c, 0x65, 0x45, 0x64, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65,
0x05, 0x52, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x64, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x64, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a,
0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x06, 0x20,
0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x61, 0x63, 0x74, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x72, 0x61, 0x6d, 0x65,
0x69, 0x76, 0x65, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d,
0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x65, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x68, 0x69, 0x74, 0x53, 0x74, 0x75,
0x52, 0x0d, 0x68, 0x69, 0x74, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x28, 0x0a, 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
0x28, 0x0a, 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x05,
0x65, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x52, 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65,
0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x75, 0x73, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c,
0x68, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x58, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63,
0x0c, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58, 0x12, 0x22, 0x0a, 0x6b, 0x56, 0x65, 0x6c, 0x58, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63,
0x0c, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x59, 0x18, 0x0a, 0x20, 0x6b, 0x56, 0x65, 0x6c, 0x59, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x70, 0x75, 0x73,
0x01, 0x28, 0x05, 0x52, 0x0c, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x68, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x59, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x61, 0x6d,
0x59, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x61, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x61, 0x67, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x64, 0x61, 0x6d, 0x61, 0x67,
0x05, 0x52, 0x06, 0x64, 0x61, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x65, 0x6c, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c,
0x66, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x05, 0x52, 0x58, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63,
0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58, 0x12, 0x22, 0x0a, 0x6b, 0x56, 0x65, 0x6c, 0x58, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63,
0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x59, 0x18, 0x0d, 0x20, 0x6b, 0x56, 0x65, 0x6c, 0x59, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x73, 0x65, 0x6c,
0x01, 0x28, 0x05, 0x52, 0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x59, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74,
0x59, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x58, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x05,
0x74, 0x58, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x52, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x58, 0x12,
0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x58, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x59,
0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x59, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66,
0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x59, 0x12, 0x20, 0x0a, 0x66, 0x73, 0x65, 0x74, 0x59, 0x12, 0x20, 0x0a, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53,
0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x58, 0x18, 0x10, 0x20, 0x01, 0x69, 0x7a, 0x65, 0x58, 0x18, 0x10, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x68, 0x69, 0x74, 0x62,
0x28, 0x05, 0x52, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x58, 0x12, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x58, 0x12, 0x20, 0x0a, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f,
0x20, 0x0a, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x59, 0x18, 0x11, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x59, 0x18, 0x11, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x68, 0x69,
0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x59, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x6c, 0x6f,
0x59, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x6c, 0x6f, 0x77, 0x55, 0x70, 0x18, 0x12, 0x20, 0x01, 0x28, 0x77, 0x55, 0x70, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x62, 0x6c, 0x6f, 0x77, 0x55,
0x08, 0x52, 0x06, 0x62, 0x6c, 0x6f, 0x77, 0x55, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x65, 0x61, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x18, 0x13, 0x20, 0x01, 0x28,
0x6d, 0x49, 0x64, 0x18, 0x13, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x74, 0x65, 0x61, 0x6d, 0x49, 0x05, 0x52, 0x06, 0x74, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x62, 0x75, 0x6c,
0x64, 0x12, 0x24, 0x0a, 0x0d, 0x62, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x05,
0x49, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x62, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x52, 0x0d, 0x62, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x12,
0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x70, 0x65, 0x63, 0x69, 0x1c, 0x0a, 0x09, 0x73, 0x70, 0x65, 0x63, 0x69, 0x65, 0x73, 0x49, 0x64, 0x18, 0x15, 0x20, 0x01,
0x65, 0x73, 0x49, 0x64, 0x18, 0x15, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x70, 0x65, 0x63, 0x28, 0x05, 0x52, 0x09, 0x73, 0x70, 0x65, 0x63, 0x69, 0x65, 0x73, 0x49, 0x64, 0x12, 0x28, 0x0a,
0x69, 0x65, 0x73, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x0f, 0x65, 0x78, 0x70, 0x6c, 0x6f, 0x73, 0x69, 0x0f, 0x65, 0x78, 0x70, 0x6c, 0x6f, 0x73, 0x69, 0x6f, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73,
0x6f, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x16, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x18, 0x16, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x65, 0x78, 0x70, 0x6c, 0x6f, 0x73, 0x69, 0x6f,
0x65, 0x78, 0x70, 0x6c, 0x6f, 0x73, 0x69, 0x6f, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x6c, 0x53, 0x74, 0x61,
0x18, 0x0a, 0x07, 0x62, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x17, 0x20, 0x01, 0x28, 0x05, 0x74, 0x65, 0x18, 0x17, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x62, 0x6c, 0x53, 0x74, 0x61, 0x74,
0x52, 0x07, 0x62, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x66, 0x72, 0x61, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x49, 0x6e, 0x42, 0x6c, 0x53,
0x6d, 0x65, 0x73, 0x49, 0x6e, 0x42, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x18, 0x20, 0x01, 0x74, 0x61, 0x74, 0x65, 0x18, 0x18, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x66, 0x72, 0x61, 0x6d,
0x28, 0x05, 0x52, 0x0f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x49, 0x6e, 0x42, 0x6c, 0x53, 0x74, 0x65, 0x73, 0x49, 0x6e, 0x42, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0xc1, 0x08, 0x0a, 0x0e,
0x61, 0x74, 0x65, 0x22, 0xc1, 0x08, 0x0a, 0x0e, 0x46, 0x69, 0x72, 0x65, 0x62, 0x61, 0x6c, 0x6c, 0x46, 0x69, 0x72, 0x65, 0x62, 0x61, 0x6c, 0x6c, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x12, 0x38,
0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x12, 0x38, 0x0a, 0x17, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x0a, 0x17, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x6e, 0x64,
0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52,
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x17, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x17, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x6e, 0x64, 0x65,
0x74, 0x65, 0x64, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x2c, 0x0a, 0x11, 0x6f, 0x66, 0x66, 0x65,
0x12, 0x2c, 0x0a, 0x11, 0x6f, 0x66, 0x66, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x6e, 0x64, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20,
0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x6f, 0x66, 0x66, 0x01, 0x28, 0x05, 0x52, 0x11, 0x6f, 0x66, 0x66, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4a, 0x6f, 0x69,
0x65, 0x6e, 0x64, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x24, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x24, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75,
0x0a, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x70, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x73,
0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x46, 0x72, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x2e, 0x0a, 0x12,
0x61, 0x6d, 0x65, 0x73, 0x12, 0x2e, 0x0a, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x46, 0x72, 0x61,
0x62, 0x6c, 0x65, 0x53, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c,
0x52, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x46, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x12,
0x72, 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x64, 0x46, 0x72, 0x61,
0x62, 0x6c, 0x65, 0x45, 0x64, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c,
0x52, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x64, 0x46, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x64, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0c,
0x72, 0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x72, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01,
0x61, 0x6d, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x28, 0x05, 0x52, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73,
0x76, 0x65, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74, 0x53, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65,
0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x68, 0x69, 0x74, 0x53, 0x74, 0x75, 0x6e,
0x0d, 0x68, 0x69, 0x74, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x28, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x28, 0x0a, 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53,
0x0a, 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52,
0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x74, 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73,
0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x75, 0x73, 0x68, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58,
0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b,
0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58, 0x12, 0x22, 0x0a, 0x0c, 0x56, 0x65, 0x6c, 0x58, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b,
0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x59, 0x18, 0x0a, 0x20, 0x01, 0x56, 0x65, 0x6c, 0x59, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x70, 0x75, 0x73, 0x68,
0x28, 0x05, 0x52, 0x0c, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x59, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x59, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x61, 0x6d, 0x61,
0x12, 0x16, 0x0a, 0x06, 0x64, 0x61, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x67, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x64, 0x61, 0x6d, 0x61, 0x67, 0x65,
0x52, 0x06, 0x64, 0x61, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x65, 0x6c, 0x66, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58,
0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b,
0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58, 0x12, 0x22, 0x0a, 0x0c, 0x56, 0x65, 0x6c, 0x58, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b,
0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x59, 0x18, 0x0d, 0x20, 0x01, 0x56, 0x65, 0x6c, 0x59, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x73, 0x65, 0x6c, 0x66,
0x28, 0x05, 0x52, 0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x59, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x59, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74, 0x62,
0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x58, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x05, 0x52,
0x58, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x58, 0x12, 0x24,
0x66, 0x66, 0x73, 0x65, 0x74, 0x58, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x0a, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x59, 0x18,
0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x59, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x68, 0x0f, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66,
0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x59, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x65, 0x74, 0x59, 0x12, 0x20, 0x0a, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69,
0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x58, 0x18, 0x10, 0x20, 0x01, 0x28, 0x7a, 0x65, 0x58, 0x18, 0x10, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f,
0x05, 0x52, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x58, 0x12, 0x20, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x58, 0x12, 0x20, 0x0a, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78,
0x0a, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x59, 0x18, 0x11, 0x20, 0x53, 0x69, 0x7a, 0x65, 0x59, 0x18, 0x11, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x68, 0x69, 0x74,
0x01, 0x28, 0x05, 0x52, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x59, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x59, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x6c, 0x6f, 0x77,
0x12, 0x16, 0x0a, 0x06, 0x62, 0x6c, 0x6f, 0x77, 0x55, 0x70, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, 0x55, 0x70, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x62, 0x6c, 0x6f, 0x77, 0x55, 0x70,
0x52, 0x06, 0x62, 0x6c, 0x6f, 0x77, 0x55, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x65, 0x61, 0x6d, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x18, 0x13, 0x20, 0x01, 0x28, 0x05,
0x49, 0x64, 0x18, 0x13, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x74, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x52, 0x06, 0x74, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x62, 0x75, 0x6c, 0x6c,
0x12, 0x24, 0x0a, 0x0d, 0x62, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x05, 0x52,
0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x62, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x4c, 0x0d, 0x62, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x1c,
0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x70, 0x65, 0x63, 0x69, 0x65, 0x0a, 0x09, 0x73, 0x70, 0x65, 0x63, 0x69, 0x65, 0x73, 0x49, 0x64, 0x18, 0x15, 0x20, 0x01, 0x28,
0x73, 0x49, 0x64, 0x18, 0x15, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x70, 0x65, 0x63, 0x69, 0x05, 0x52, 0x09, 0x73, 0x70, 0x65, 0x63, 0x69, 0x65, 0x73, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x0f,
0x65, 0x73, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x0f, 0x65, 0x78, 0x70, 0x6c, 0x6f, 0x73, 0x69, 0x6f, 0x65, 0x78, 0x70, 0x6c, 0x6f, 0x73, 0x69, 0x6f, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18,
0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x16, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x65, 0x16, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x65, 0x78, 0x70, 0x6c, 0x6f, 0x73, 0x69, 0x6f, 0x6e,
0x78, 0x70, 0x6c, 0x6f, 0x73, 0x69, 0x6f, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x18, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x6c, 0x53, 0x74, 0x61, 0x74,
0x0a, 0x07, 0x62, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x17, 0x20, 0x01, 0x28, 0x05, 0x52, 0x65, 0x18, 0x17, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x62, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65,
0x07, 0x62, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x66, 0x72, 0x61, 0x6d, 0x12, 0x28, 0x0a, 0x0f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x49, 0x6e, 0x42, 0x6c, 0x53, 0x74,
0x65, 0x73, 0x49, 0x6e, 0x42, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x18, 0x20, 0x01, 0x28, 0x61, 0x74, 0x65, 0x18, 0x18, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x66, 0x72, 0x61, 0x6d, 0x65,
0x05, 0x52, 0x0f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x49, 0x6e, 0x42, 0x6c, 0x53, 0x74, 0x61, 0x73, 0x49, 0x6e, 0x42, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x23, 0x0a, 0x0c, 0x76, 0x69,
0x74, 0x65, 0x12, 0x23, 0x0a, 0x0c, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x47, 0x72, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x58, 0x18, 0xe7, 0x07, 0x20, 0x01, 0x28,
0x64, 0x58, 0x18, 0xe7, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x76, 0x69, 0x72, 0x74, 0x75, 0x05, 0x52, 0x0c, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x58, 0x12,
0x61, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x58, 0x12, 0x23, 0x0a, 0x0c, 0x76, 0x69, 0x72, 0x74, 0x75, 0x23, 0x0a, 0x0c, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x59, 0x18,
0x61, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x59, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x47,
0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x59, 0x12, 0x13, 0x0a, 0x04, 0x72, 0x69, 0x64, 0x59, 0x12, 0x13, 0x0a, 0x04, 0x64, 0x69, 0x72, 0x58, 0x18, 0xe9, 0x07, 0x20,
0x64, 0x69, 0x72, 0x58, 0x18, 0xe9, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x64, 0x69, 0x72, 0x01, 0x28, 0x05, 0x52, 0x04, 0x64, 0x69, 0x72, 0x58, 0x12, 0x13, 0x0a, 0x04, 0x64, 0x69, 0x72,
0x58, 0x12, 0x13, 0x0a, 0x04, 0x64, 0x69, 0x72, 0x59, 0x18, 0xea, 0x07, 0x20, 0x01, 0x28, 0x05, 0x59, 0x18, 0xea, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x64, 0x69, 0x72, 0x59, 0x12, 0x13,
0x52, 0x04, 0x64, 0x69, 0x72, 0x59, 0x12, 0x13, 0x0a, 0x04, 0x76, 0x65, 0x6c, 0x58, 0x18, 0xeb, 0x0a, 0x04, 0x76, 0x65, 0x6c, 0x58, 0x18, 0xeb, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x76,
0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x76, 0x65, 0x6c, 0x58, 0x12, 0x13, 0x0a, 0x04, 0x76, 0x65, 0x6c, 0x58, 0x12, 0x13, 0x0a, 0x04, 0x76, 0x65, 0x6c, 0x59, 0x18, 0xec, 0x07, 0x20, 0x01,
0x65, 0x6c, 0x59, 0x18, 0xec, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x76, 0x65, 0x6c, 0x59, 0x28, 0x05, 0x52, 0x04, 0x76, 0x65, 0x6c, 0x59, 0x12, 0x15, 0x0a, 0x05, 0x73, 0x70, 0x65, 0x65,
0x12, 0x15, 0x0a, 0x05, 0x73, 0x70, 0x65, 0x65, 0x64, 0x18, 0xed, 0x07, 0x20, 0x01, 0x28, 0x05, 0x64, 0x18, 0xed, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x73, 0x70, 0x65, 0x65, 0x64, 0x22,
0x52, 0x05, 0x73, 0x70, 0x65, 0x65, 0x64, 0x22, 0xc9, 0x05, 0x0a, 0x12, 0x42, 0x61, 0x74, 0x74, 0xc9, 0x05, 0x0a, 0x12, 0x42, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x6c, 0x69, 0x64,
0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x6c, 0x69, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1c, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x67, 0x65, 0x4e,
0x0a, 0x09, 0x73, 0x74, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x61, 0x67, 0x65,
0x09, 0x52, 0x09, 0x73, 0x74, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c,
0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x54, 0x6f, 0x50, 0x69, 0x6e, 0x67, 0x18, 0x02, 0x54, 0x6f, 0x50, 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x69, 0x6e,
0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x54, 0x6f, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x54, 0x6f, 0x50, 0x69, 0x6e, 0x67, 0x12, 0x34, 0x0a, 0x15,
0x50, 0x69, 0x6e, 0x67, 0x12, 0x34, 0x0a, 0x15, 0x77, 0x69, 0x6c, 0x6c, 0x4b, 0x69, 0x63, 0x6b, 0x77, 0x69, 0x6c, 0x6c, 0x4b, 0x69, 0x63, 0x6b, 0x49, 0x66, 0x49, 0x6e, 0x61, 0x63, 0x74, 0x69,
0x49, 0x66, 0x49, 0x6e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x76, 0x65, 0x46, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x15, 0x77, 0x69, 0x6c,
0x01, 0x28, 0x05, 0x52, 0x15, 0x77, 0x69, 0x6c, 0x6c, 0x4b, 0x69, 0x63, 0x6b, 0x49, 0x66, 0x49, 0x6c, 0x4b, 0x69, 0x63, 0x6b, 0x49, 0x66, 0x49, 0x6e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46,
0x6e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x6f, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x6f, 0x6f, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x6f, 0x6f, 0x6d, 0x49,
0x75, 0x6e, 0x64, 0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x6f,
0x0b, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x13, 0x6f, 0x6d, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x13, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x44, 0x75,
0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28,
0x6e, 0x6f, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x13, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x03, 0x52, 0x13, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f,
0x65, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x12, 0x46, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x12, 0x46, 0x0a, 0x1e, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46,
0x0a, 0x1e, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x73, 0x79, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x54,
0x6e, 0x63, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x54, 0x6f, 0x6c, 0x65, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x6f, 0x6c, 0x65, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x1e,
0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x1e, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63,
0x6d, 0x65, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x54, 0x6f, 0x6c, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x54, 0x6f, 0x6c, 0x65, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x48,
0x65, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x48, 0x0a, 0x1f, 0x6d, 0x61, 0x78, 0x43, 0x68, 0x61, 0x0a, 0x1f, 0x6d, 0x61, 0x78, 0x43, 0x68, 0x61, 0x73, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x6e, 0x64,
0x73, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x50, 0x65, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74,
0x50, 0x65, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x1f, 0x6d, 0x61, 0x78, 0x43, 0x68, 0x61, 0x73,
0x1f, 0x6d, 0x61, 0x78, 0x43, 0x68, 0x61, 0x73, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x50,
0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x50, 0x65, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x65, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x3c, 0x0a, 0x19, 0x72, 0x6f, 0x6c, 0x6c,
0x12, 0x3c, 0x0a, 0x19, 0x72, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x45, 0x73, 0x74, 0x69, 0x62, 0x61, 0x63, 0x6b, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x64, 0x44, 0x74, 0x4d,
0x6d, 0x61, 0x74, 0x65, 0x64, 0x44, 0x74, 0x4d, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x18, 0x08, 0x20, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x01, 0x52, 0x19, 0x72, 0x6f, 0x6c,
0x01, 0x28, 0x01, 0x52, 0x19, 0x72, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x45, 0x73, 0x74, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x64, 0x44, 0x74,
0x69, 0x6d, 0x61, 0x74, 0x65, 0x64, 0x44, 0x74, 0x4d, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x12, 0x3a, 0x4d, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x12, 0x3a, 0x0a, 0x18, 0x72, 0x6f, 0x6c, 0x6c, 0x62, 0x61,
0x0a, 0x18, 0x72, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x63, 0x6b, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x64, 0x44, 0x74, 0x4e, 0x61, 0x6e,
0x74, 0x65, 0x64, 0x44, 0x74, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x6f, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x18, 0x72, 0x6f, 0x6c, 0x6c, 0x62, 0x61,
0x52, 0x18, 0x72, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x63, 0x6b, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x64, 0x44, 0x74, 0x4e, 0x61, 0x6e,
0x74, 0x65, 0x64, 0x44, 0x74, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x12, 0x28, 0x0a, 0x0f, 0x72, 0x65, 0x6f, 0x73, 0x12, 0x28, 0x0a, 0x0f, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x43, 0x61, 0x63, 0x68,
0x6e, 0x64, 0x65, 0x72, 0x43, 0x61, 0x63, 0x68, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x0a, 0x20, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x72, 0x65, 0x6e,
0x01, 0x28, 0x05, 0x52, 0x0f, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x43, 0x61, 0x63, 0x68, 0x65, 0x64, 0x65, 0x72, 0x43, 0x61, 0x63, 0x68, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x22, 0x0a, 0x0c,
0x53, 0x69, 0x7a, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x58, 0x18, 0x0b, 0x20, 0x01,
0x73, 0x65, 0x74, 0x58, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0c, 0x73, 0x70, 0x61, 0x63, 0x28, 0x01, 0x52, 0x0c, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x58,
0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x58, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x70, 0x61, 0x63, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x59,
0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x59, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0c, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0c, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x66, 0x66,
0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x59, 0x12, 0x2a, 0x0a, 0x10, 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, 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, 0x12, 0x39, 0x0a, 0x17, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x61, 0x74, 0x61, 0x4c, 0x6f, 0x67,
0x6e, 0x4d, 0x69, 0x6e, 0x53, 0x74, 0x65, 0x70, 0x12, 0x39, 0x0a, 0x17, 0x66, 0x72, 0x61, 0x6d, 0x67, 0x69, 0x6e, 0x67, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x80, 0x08, 0x20, 0x01,
0x65, 0x44, 0x61, 0x74, 0x61, 0x4c, 0x6f, 0x67, 0x67, 0x69, 0x6e, 0x67, 0x45, 0x6e, 0x61, 0x62, 0x28, 0x08, 0x52, 0x17, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x61, 0x74, 0x61, 0x4c, 0x6f, 0x67,
0x6c, 0x65, 0x64, 0x18, 0x80, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x17, 0x66, 0x72, 0x61, 0x6d, 0x67, 0x69, 0x6e, 0x67, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0xc2, 0x03, 0x0a, 0x11,
0x65, 0x44, 0x61, 0x74, 0x61, 0x4c, 0x6f, 0x67, 0x67, 0x69, 0x6e, 0x67, 0x45, 0x6e, 0x61, 0x62, 0x52, 0x6f, 0x6f, 0x6d, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x46, 0x72, 0x61, 0x6d,
0x6c, 0x65, 0x64, 0x22, 0xc2, 0x03, 0x0a, 0x11, 0x52, 0x6f, 0x6f, 0x6d, 0x44, 0x6f, 0x77, 0x6e, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69,
0x73, 0x79, 0x6e, 0x63, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x64, 0x12, 0x36, 0x0a, 0x0a, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x41, 0x72, 0x72, 0x18,
0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x36, 0x0a, 0x0a, 0x70, 0x6c, 0x61, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x50,
0x79, 0x65, 0x72, 0x73, 0x41, 0x72, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x52, 0x0a, 0x70,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x44, 0x6f, 0x77, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x41, 0x72, 0x72, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x6f, 0x75,
0x6e, 0x73, 0x79, 0x6e, 0x63, 0x52, 0x0a, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x41, 0x72, 0x6e, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28,
0x72, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x4e, 0x61, 0x03, 0x52, 0x0e, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x4e, 0x61, 0x6e, 0x6f,
0x6e, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x12, 0x37, 0x0a, 0x0c, 0x6d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74,
0x64, 0x6f, 0x77, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x12, 0x37, 0x0a, 0x0c, 0x6d, 0x65, 0x6c, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73,
0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x4d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x52, 0x0c, 0x6d, 0x65,
0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x4d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x12, 0x40, 0x0a, 0x0f, 0x66, 0x69,
0x6c, 0x6c, 0x65, 0x74, 0x52, 0x0c, 0x6d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x72, 0x65, 0x62, 0x61, 0x6c, 0x6c, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x18, 0x05, 0x20,
0x74, 0x73, 0x12, 0x40, 0x0a, 0x0f, 0x66, 0x69, 0x72, 0x65, 0x62, 0x61, 0x6c, 0x6c, 0x42, 0x75, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x46, 0x69, 0x72,
0x6c, 0x6c, 0x65, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x65, 0x62, 0x61, 0x6c, 0x6c, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x52, 0x0f, 0x66, 0x69, 0x72,
0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x46, 0x69, 0x72, 0x65, 0x62, 0x61, 0x6c, 0x6c, 0x42, 0x75, 0x6c, 0x65, 0x62, 0x61, 0x6c, 0x6c, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x12, 0x37, 0x0a, 0x16,
0x6c, 0x65, 0x74, 0x52, 0x0f, 0x66, 0x69, 0x72, 0x65, 0x62, 0x61, 0x6c, 0x6c, 0x42, 0x75, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d,
0x6c, 0x65, 0x74, 0x73, 0x12, 0x37, 0x0a, 0x16, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x55, 0x65, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x18, 0x80, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x16, 0x62,
0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x18, 0x80, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65,
0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x16, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x55, 0x6e, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x12, 0x2d, 0x0a, 0x11, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x46,
0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x12, 0x2d, 0x0a, 0x6f, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x81, 0x08, 0x20, 0x01, 0x28,
0x11, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x79, 0x08, 0x52, 0x11, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x52, 0x65,
0x6e, 0x63, 0x18, 0x81, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x25, 0x0a, 0x0d, 0x73, 0x70, 0x65, 0x63, 0x69, 0x65, 0x73, 0x49,
0x64, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x25, 0x0a, 0x0d, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x82, 0x08, 0x20, 0x03, 0x28, 0x05, 0x52, 0x0d, 0x73, 0x70,
0x73, 0x70, 0x65, 0x63, 0x69, 0x65, 0x73, 0x49, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x82, 0x08, 0x65, 0x63, 0x69, 0x65, 0x73, 0x49, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x33, 0x0a, 0x14, 0x62,
0x20, 0x03, 0x28, 0x05, 0x52, 0x0d, 0x73, 0x70, 0x65, 0x63, 0x69, 0x65, 0x73, 0x49, 0x64, 0x4c, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x43, 0x6f, 0x75, 0x6e,
0x69, 0x73, 0x74, 0x12, 0x33, 0x0a, 0x14, 0x62, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x74, 0x65, 0x72, 0x18, 0x83, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x14, 0x62, 0x75, 0x6c, 0x6c,
0x61, 0x6c, 0x49, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x83, 0x08, 0x20, 0x01, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72,
0x28, 0x05, 0x52, 0x14, 0x62, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x42, 0x13, 0x5a, 0x11, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x5f, 0x73, 0x72, 0x76, 0x2f, 0x70,
0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x42, 0x13, 0x5a, 0x11, 0x62, 0x61, 0x74, 0x74, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x6c, 0x65, 0x5f, 0x73, 0x72, 0x76, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x62, 0x06, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (

View File

@@ -46,6 +46,7 @@ func Serve(c *gin.Context) {
c.AbortWithStatus(http.StatusBadRequest) c.AbortWithStatus(http.StatusBadRequest)
return return
} }
boundRoomId := 0 boundRoomId := 0
expectedRoomId := 0 expectedRoomId := 0
var err error var err error
@@ -395,3 +396,89 @@ func Serve(c *gin.Context) {
startOrFeedHeartbeatWatchdog(conn) startOrFeedHeartbeatWatchdog(conn)
go receivingLoopAgainstPlayer() 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)
}

File diff suppressed because one or more lines are too long

BIN
charts/UDPEssentials.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 417 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 MiB

BIN
charts/networkstats.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

View File

@@ -1,66 +0,0 @@
function NetworkDoctor(serverFps, clientUpsyncFps) {
this.serverFps = serverFps;
this.clientUpsyncFps = clientUpsyncFps;
this.millisPerServerFrame = parseInt(1000 / this.serverFps);
this._tooLongSinceLastFrameDiffReceivedThreshold = (this.millisPerServerFrame << 6);
this.setupFps = function(fps) {
this.serverFps = this.clientUpsyncFps = fps;
this.millisPerServerFrame = parseInt(1000 / this.serverFps);
this._tooLongSinceLastFrameDiffReceivedThreshold = (this.millisPerServerFrame << 6);
}
this._lastFrameDiffRecvTime = null;
this._tooLongSinceLastFrameDiffReceived = function() {
if (undefined === this._lastFrameDiffRecvTime || null === this._lastFrameDiffRecvTime) return false;
return (this._tooLongSinceLastFrameDiffReceivedThreshold <= (Date.now() - this._lastFrameDiffRecvTime));
};
this._consecutiveALittleLongFrameDiffReceivedIntervalCount = 0;
this._consecutiveALittleLongFrameDiffReceivedIntervalCountThreshold = 120;
this.onNewFrameDiffReceived = function(frameDiff) {
var now = Date.now();
if (undefined !== this._lastFrameDiffRecvTime && null !== this._lastFrameDiffRecvTime) {
var intervalFromLastFrameDiff = (now - this._lastFrameDiffRecvTime);
if ((this.millisPerServerFrame << 5) < intervalFromLastFrameDiff) {
++this._consecutiveALittleLongFrameDiffReceivedIntervalCount;
console.log('Medium delay, intervalFromLastFrameDiff is', intervalFromLastFrameDiff);
} else {
this._consecutiveALittleLongFrameDiffReceivedIntervalCount = 0;
}
}
this._lastFrameDiffRecvTime = now;
};
this._networkComplaintPrefix = "\nNetwork is not good >_<\n";
this.generateNetworkComplaint = function(excludeTypeConstantALittleLongFrameDiffReceivedInterval, excludeTypeTooLongSinceLastFrameDiffReceived) {
if (this.hasBattleStopped) return null;
var shouldComplain = false;
var ret = this._networkComplaintPrefix;
if (true != excludeTypeConstantALittleLongFrameDiffReceivedInterval && this._consecutiveALittleLongFrameDiffReceivedIntervalCountThreshold <= this._consecutiveALittleLongFrameDiffReceivedIntervalCount) {
this._consecutiveALittleLongFrameDiffReceivedIntervalCount = 0;
ret += "\nConstantly having a little long recv interval.\n";
shouldComplain = true;
}
if (true != excludeTypeTooLongSinceLastFrameDiffReceived && this._tooLongSinceLastFrameDiffReceived()) {
ret += "\nToo long since last received frameDiff.\n";
shouldComplain = true;
}
return (shouldComplain ? ret : null);
};
this.hasBattleStopped = false;
this.onBattleStopped = function() {
this.hasBattleStopped = true;
};
this.isClientSessionConnected = function() {
if (!window.game) return false;
if (!window.game.clientSession) return false;
return window.game.clientSession.connected;
};
}
window.NetworkDoctor = NetworkDoctor;

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,6 @@
{ {
"ver": "1.0.5", "ver": "1.0.5",
"uuid": "d41313ca-b2c3-4436-a05f-7e0eb290b1e6", "uuid": "40edd08e-316c-44b8-a50f-bd173554c554",
"isPlugin": true, "isPlugin": true,
"loadPluginInWeb": true, "loadPluginInWeb": true,
"loadPluginInNative": true, "loadPluginInNative": true,

View File

@@ -18,61 +18,43 @@
} }
}, },
{ {
"frame": 0.06666666666666667, "frame": 0.05,
"value": { "value": {
"__uuid__": "dd9a00aa-ddbc-4b01-a7cb-3c43c3a655b6" "__uuid__": "dd9a00aa-ddbc-4b01-a7cb-3c43c3a655b6"
} }
}, },
{ {
"frame": 0.11666666666666667, "frame": 0.08333333333333333,
"value": {
"__uuid__": "f66e83bd-1afc-4957-bb16-488d70566ed1"
}
},
{
"frame": 0.16666666666666666,
"value": {
"__uuid__": "bd682c41-dc62-49ff-a96a-18b33e50a6de"
}
},
{
"frame": 0.23333333333333334,
"value": {
"__uuid__": "94ccab85-e32f-4e13-b0e5-72c798f78ad1"
}
},
{
"frame": 0.3,
"value": { "value": {
"__uuid__": "e80d3a01-5048-42b7-a280-cb6aa01602c2" "__uuid__": "e80d3a01-5048-42b7-a280-cb6aa01602c2"
} }
}, },
{ {
"frame": 0.36666666666666664, "frame": 0.11666666666666667,
"value": { "value": {
"__uuid__": "d899088c-be62-47b4-9ebf-0a89a2261565" "__uuid__": "d899088c-be62-47b4-9ebf-0a89a2261565"
} }
}, },
{ {
"frame": 0.4166666666666667, "frame": 0.15,
"value": { "value": {
"__uuid__": "5b1e5aa7-fd82-47ae-a5b2-6d4983d848ed" "__uuid__": "5b1e5aa7-fd82-47ae-a5b2-6d4983d848ed"
} }
}, },
{ {
"frame": 0.48333333333333334, "frame": 0.18333333333333332,
"value": { "value": {
"__uuid__": "c2945988-b4bb-4583-a5ef-2fa02b23a347" "__uuid__": "c2945988-b4bb-4583-a5ef-2fa02b23a347"
} }
}, },
{ {
"frame": 0.5666666666666667, "frame": 0.23333333333333334,
"value": { "value": {
"__uuid__": "070ea1e3-9c07-4735-8b94-515ef70216ad" "__uuid__": "070ea1e3-9c07-4735-8b94-515ef70216ad"
} }
}, },
{ {
"frame": 0.6666666666666666, "frame": 0.2833333333333333,
"value": { "value": {
"__uuid__": "3b8bc5c0-26df-4218-b7dc-134a36080a35" "__uuid__": "3b8bc5c0-26df-4218-b7dc-134a36080a35"
} }

View File

@@ -15,7 +15,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{112,128}</string> <string>{112,128}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{806,750},{112,128}}</string> <string>{{384,989},{112,128}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -30,7 +30,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{112,128}</string> <string>{112,128}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{0,1076},{112,128}}</string> <string>{{256,990},{112,128}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -60,7 +60,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{80,128}</string> <string>{80,128}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{528,515},{80,128}}</string> <string>{{940,0},{80,128}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -75,7 +75,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{80,128}</string> <string>{80,128}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{934,640},{80,128}}</string> <string>{{940,128},{80,128}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -90,7 +90,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{112,128}</string> <string>{112,128}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{128,1076},{112,128}}</string> <string>{{128,1082},{112,128}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -105,7 +105,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{112,128}</string> <string>{112,128}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{678,862},{112,128}}</string> <string>{{0,1188},{112,128}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -150,7 +150,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{80,128}</string> <string>{80,128}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{934,768},{80,128}}</string> <string>{{940,256},{80,128}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -165,7 +165,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{80,128}</string> <string>{80,128}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{934,896},{80,128}}</string> <string>{{937,384},{80,128}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -180,9 +180,9 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{80,128}</string> <string>{80,128}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{806,958},{80,128}}</string> <string>{{528,515},{80,128}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <false/>
</dict> </dict>
<key>Atk2_0.png</key> <key>Atk2_0.png</key>
<dict> <dict>
@@ -195,7 +195,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{80,128}</string> <string>{80,128}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{934,1024},{80,128}}</string> <string>{{936,512},{80,128}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -225,7 +225,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{128,112}</string> <string>{128,112}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{128,964},{128,112}}</string> <string>{{0,1076},{128,112}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -240,7 +240,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{96,96}</string> <string>{96,96}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{912,1152},{96,96}}</string> <string>{{688,1357},{96,96}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -255,7 +255,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{96,112}</string> <string>{96,112}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{340,1197},{96,112}}</string> <string>{{240,1360},{96,112}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -270,7 +270,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{96,112}</string> <string>{96,112}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{452,1196},{96,112}}</string> <string>{{352,1358},{96,112}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -285,7 +285,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{96,112}</string> <string>{96,112}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{564,1155},{96,112}}</string> <string>{{920,1072},{96,112}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -300,7 +300,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{96,112}</string> <string>{96,112}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{608,1043},{96,112}}</string> <string>{{914,1184},{96,112}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -330,7 +330,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{128,112}</string> <string>{128,112}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{678,750},{128,112}}</string> <string>{{806,631},{128,112}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -540,7 +540,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{112,112}</string> <string>{112,112}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{448,1293},{112,112}}</string> <string>{{802,1149},{112,112}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -555,9 +555,9 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{96,112}</string> <string>{96,112}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{660,1155},{96,112}}</string> <string>{{800,1261},{96,112}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <true/>
</dict> </dict>
<key>Atked1_3.png</key> <key>Atked1_3.png</key>
<dict> <dict>
@@ -570,7 +570,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{128,112}</string> <string>{128,112}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{384,988},{128,112}}</string> <string>{{806,743},{128,112}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -645,7 +645,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{114,112}</string> <string>{114,112}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{0,1188},{114,112}}</string> <string>{{806,1037},{114,112}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -660,9 +660,9 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{114,112}</string> <string>{114,112}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{114,1188},{114,112}}</string> <string>{{384,1213},{114,112}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <true/>
</dict> </dict>
<key>Dashing_3.png</key> <key>Dashing_3.png</key>
<dict> <dict>
@@ -675,7 +675,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{114,112}</string> <string>{114,112}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{0,1300},{114,112}}</string> <string>{{464,1327},{114,112}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -690,7 +690,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{114,112}</string> <string>{114,112}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{112,1300},{114,112}}</string> <string>{{496,1213},{114,112}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -705,7 +705,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{114,112}</string> <string>{114,112}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{0,1300},{114,112}}</string> <string>{{464,1327},{114,112}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -720,7 +720,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{114,112}</string> <string>{114,112}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{224,1300},{114,112}}</string> <string>{{576,1327},{114,112}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -735,56 +735,11 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{114,112}</string> <string>{114,112}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{336,1293},{114,112}}</string> <string>{{688,1043},{114,112}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <false/>
</dict> </dict>
<key>GetUp1_1.png</key> <key>GetUp1_1.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{128,118}</string>
<key>spriteSourceSize</key>
<string>{128,118}</string>
<key>textureRect</key>
<string>{{384,634},{128,118}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>GetUp1_2.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{128,118}</string>
<key>spriteSourceSize</key>
<string>{128,118}</string>
<key>textureRect</key>
<string>{{384,752},{128,118}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>GetUp1_3.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{128,118}</string>
<key>spriteSourceSize</key>
<string>{128,118}</string>
<key>textureRect</key>
<string>{{256,753},{128,118}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>GetUp1_4.png</key>
<dict> <dict>
<key>aliases</key> <key>aliases</key>
<array/> <array/>
@@ -799,7 +754,7 @@
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
<key>GetUp1_5.png</key> <key>GetUp1_2.png</key>
<dict> <dict>
<key>aliases</key> <key>aliases</key>
<array/> <array/>
@@ -814,6 +769,51 @@
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
<key>GetUp1_3.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{128,118}</string>
<key>spriteSourceSize</key>
<string>{128,118}</string>
<key>textureRect</key>
<string>{{384,753},{128,118}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>GetUp1_4.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{128,118}</string>
<key>spriteSourceSize</key>
<string>{128,118}</string>
<key>textureRect</key>
<string>{{678,631},{128,118}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>GetUp1_5.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{128,118}</string>
<key>spriteSourceSize</key>
<string>{128,118}</string>
<key>textureRect</key>
<string>{{384,871},{128,118}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>GetUp1_6.png</key> <key>GetUp1_6.png</key>
<dict> <dict>
<key>aliases</key> <key>aliases</key>
@@ -825,7 +825,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{128,118}</string> <string>{128,118}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{384,870},{128,118}}</string> <string>{{256,872},{128,118}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -840,7 +840,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{128,118}</string> <string>{128,118}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{256,871},{128,118}}</string> <string>{{128,964},{128,118}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -855,7 +855,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{70,128}</string> <string>{70,128}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{940,0},{70,128}}</string> <string>{{608,531},{70,128}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -870,7 +870,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{70,128}</string> <string>{70,128}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{940,128},{70,128}}</string> <string>{{608,659},{70,128}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -885,7 +885,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{70,128}</string> <string>{70,128}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{940,256},{70,128}}</string> <string>{{608,787},{70,128}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -900,7 +900,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{70,128}</string> <string>{70,128}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{937,384},{70,128}}</string> <string>{{608,915},{70,128}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -915,9 +915,9 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{70,128}</string> <string>{70,128}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{936,512},{70,128}}</string> <string>{{128,1290},{70,128}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <true/>
</dict> </dict>
<key>Idle1_14.png</key> <key>Idle1_14.png</key>
<dict> <dict>
@@ -930,9 +930,9 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{70,128}</string> <string>{70,128}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{608,531},{70,128}}</string> <string>{{0,1300},{70,128}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <true/>
</dict> </dict>
<key>Idle1_15.png</key> <key>Idle1_15.png</key>
<dict> <dict>
@@ -945,9 +945,9 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{70,128}</string> <string>{70,128}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{608,659},{70,128}}</string> <string>{{0,1370},{70,128}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <true/>
</dict> </dict>
<key>Idle1_2.png</key> <key>Idle1_2.png</key>
<dict> <dict>
@@ -960,9 +960,9 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{70,128}</string> <string>{70,128}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{608,659},{70,128}}</string> <string>{{0,1370},{70,128}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <true/>
</dict> </dict>
<key>Idle1_3.png</key> <key>Idle1_3.png</key>
<dict> <dict>
@@ -975,9 +975,9 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{70,128}</string> <string>{70,128}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{608,531},{70,128}}</string> <string>{{0,1300},{70,128}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <true/>
</dict> </dict>
<key>Idle1_4.png</key> <key>Idle1_4.png</key>
<dict> <dict>
@@ -990,71 +990,11 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{70,128}</string> <string>{70,128}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{936,512},{70,128}}</string> <string>{{128,1290},{70,128}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <true/>
</dict> </dict>
<key>Idle1_5.png</key> <key>Idle1_5.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{70,128}</string>
<key>spriteSourceSize</key>
<string>{70,128}</string>
<key>textureRect</key>
<string>{{937,384},{70,128}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>Idle1_6.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{70,128}</string>
<key>spriteSourceSize</key>
<string>{70,128}</string>
<key>textureRect</key>
<string>{{940,256},{70,128}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>Idle1_7.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{70,128}</string>
<key>spriteSourceSize</key>
<string>{70,128}</string>
<key>textureRect</key>
<string>{{940,128},{70,128}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>Idle1_8.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{70,128}</string>
<key>spriteSourceSize</key>
<string>{70,128}</string>
<key>textureRect</key>
<string>{{608,787},{70,128}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>Idle1_9.png</key>
<dict> <dict>
<key>aliases</key> <key>aliases</key>
<array/> <array/>
@@ -1069,6 +1009,66 @@
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
<key>Idle1_6.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{70,128}</string>
<key>spriteSourceSize</key>
<string>{70,128}</string>
<key>textureRect</key>
<string>{{608,787},{70,128}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>Idle1_7.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{70,128}</string>
<key>spriteSourceSize</key>
<string>{70,128}</string>
<key>textureRect</key>
<string>{{608,659},{70,128}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>Idle1_8.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{70,128}</string>
<key>spriteSourceSize</key>
<string>{70,128}</string>
<key>textureRect</key>
<string>{{806,967},{70,128}}</string>
<key>textureRotated</key>
<true/>
</dict>
<key>Idle1_9.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{70,128}</string>
<key>spriteSourceSize</key>
<string>{70,128}</string>
<key>textureRect</key>
<string>{{678,973},{70,128}}</string>
<key>textureRotated</key>
<true/>
</dict>
<key>InAirAtk1_0.png</key> <key>InAirAtk1_0.png</key>
<dict> <dict>
<key>aliases</key> <key>aliases</key>
@@ -1080,7 +1080,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{112,96}</string> <string>{112,96}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{228,1197},{112,96}}</string> <string>{{128,1360},{112,96}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -1125,7 +1125,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{128,112}</string> <string>{128,112}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{256,989},{128,112}}</string> <string>{{678,749},{128,112}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -1140,7 +1140,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{96,96}</string> <string>{96,96}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{672,1363},{96,96}}</string> <string>{{784,1357},{96,96}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -1155,7 +1155,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{80,96}</string> <string>{80,96}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{672,1267},{80,96}}</string> <string>{{934,976},{80,96}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -1170,7 +1170,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{112,112}</string> <string>{112,112}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{560,1292},{112,112}}</string> <string>{{688,1155},{112,112}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -1185,7 +1185,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{128,96}</string> <string>{128,96}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{384,1100},{128,96}}</string> <string>{{256,1102},{128,96}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -1200,9 +1200,9 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{80,112}</string> <string>{80,112}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{800,1038},{80,112}}</string> <string>{{934,640},{80,112}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <false/>
</dict> </dict>
<key>InAirIdle1_1.png</key> <key>InAirIdle1_1.png</key>
<dict> <dict>
@@ -1215,9 +1215,9 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{80,112}</string> <string>{80,112}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{800,1118},{80,112}}</string> <string>{{934,752},{80,112}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <false/>
</dict> </dict>
<key>InAirIdle1_2.png</key> <key>InAirIdle1_2.png</key>
<dict> <dict>
@@ -1230,7 +1230,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{64,128}</string> <string>{64,128}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{678,974},{64,128}}</string> <string>{{256,1294},{64,128}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -1245,9 +1245,9 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{80,112}</string> <string>{80,112}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{756,1198},{80,112}}</string> <string>{{934,864},{80,112}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <false/>
</dict> </dict>
<key>InAirIdle1_4.png</key> <key>InAirIdle1_4.png</key>
<dict> <dict>
@@ -1260,9 +1260,9 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{80,96}</string> <string>{80,96}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{752,1278},{80,96}}</string> <string>{{608,1043},{80,96}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <false/>
</dict> </dict>
<key>InAirIdle1_5.png</key> <key>InAirIdle1_5.png</key>
<dict> <dict>
@@ -1275,7 +1275,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{80,96}</string> <string>{80,96}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{768,1358},{80,96}}</string> <string>{{608,1139},{80,96}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -1290,7 +1290,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{80,96}</string> <string>{80,96}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{868,1248},{80,96}}</string> <string>{{688,1267},{80,96}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -1305,9 +1305,9 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{96,112}</string> <string>{96,112}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{704,1038},{96,112}}</string> <string>{{912,1296},{96,112}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <true/>
</dict> </dict>
<key>InAirIdle1_8.png</key> <key>InAirIdle1_8.png</key>
<dict> <dict>
@@ -1320,7 +1320,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{96,128}</string> <string>{96,128}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{256,1101},{96,128}}</string> <string>{{128,1194},{96,128}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -1335,7 +1335,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{96,128}</string> <string>{96,128}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{806,862},{96,128}}</string> <string>{{256,1198},{96,128}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -1414,6 +1414,51 @@
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
<key>TurnAround1_1.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{112,128}</string>
<key>spriteSourceSize</key>
<string>{112,128}</string>
<key>textureRect</key>
<string>{{806,855},{112,128}}</string>
<key>textureRotated</key>
<true/>
</dict>
<key>TurnAround1_2.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{112,128}</string>
<key>spriteSourceSize</key>
<string>{112,128}</string>
<key>textureRect</key>
<string>{{678,861},{112,128}}</string>
<key>textureRotated</key>
<true/>
</dict>
<key>TurnAround1_3.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{112,128}</string>
<key>spriteSourceSize</key>
<string>{112,128}</string>
<key>textureRect</key>
<string>{{384,1101},{112,128}}</string>
<key>textureRotated</key>
<true/>
</dict>
<key>Walking_1.png</key> <key>Walking_1.png</key>
<dict> <dict>
<key>aliases</key> <key>aliases</key>
@@ -1455,7 +1500,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{119,128}</string> <string>{119,128}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{680,512},{119,128}}</string> <string>{{272,515},{119,128}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -1470,7 +1515,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{119,128}</string> <string>{119,128}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{808,512},{119,128}}</string> <string>{{128,608},{119,128}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -1485,7 +1530,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{119,128}</string> <string>{119,128}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{272,515},{119,128}}</string> <string>{{0,720},{119,128}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -1500,7 +1545,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{119,128}</string> <string>{119,128}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{128,608},{119,128}}</string> <string>{{400,515},{119,128}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -1515,7 +1560,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{119,128}</string> <string>{119,128}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{0,720},{119,128}}</string> <string>{{256,634},{119,128}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -1530,7 +1575,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{119,128}</string> <string>{119,128}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{400,515},{119,128}}</string> <string>{{128,727},{119,128}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -1545,7 +1590,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{119,128}</string> <string>{119,128}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{678,631},{119,128}}</string> <string>{{0,839},{119,128}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -1560,7 +1605,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{119,128}</string> <string>{119,128}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{806,631},{119,128}}</string> <string>{{384,634},{119,128}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -1575,7 +1620,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{119,128}</string> <string>{119,128}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{256,634},{119,128}}</string> <string>{{680,512},{119,128}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -1590,7 +1635,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{119,128}</string> <string>{119,128}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{128,727},{119,128}}</string> <string>{{808,512},{119,128}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -1605,7 +1650,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{119,128}</string> <string>{119,128}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{0,839},{119,128}}</string> <string>{{256,753},{119,128}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -1621,9 +1666,9 @@
<key>realTextureFileName</key> <key>realTextureFileName</key>
<string>KnifeGirl.png</string> <string>KnifeGirl.png</string>
<key>size</key> <key>size</key>
<string>{1014,1459}</string> <string>{1024,1456}</string>
<key>smartupdate</key> <key>smartupdate</key>
<string>$TexturePacker:SmartUpdate:4ca72309f7dc04bba6be361462471d91:9a48d10caa37a76ff8c43fb72bce6103:1ae107e0c6667a1ecb5ed98687517e0e$</string> <string>$TexturePacker:SmartUpdate:8fd7507b5e24a1de6da5e4a6c568fcd3:d861e924a13180a640774a9c85662e57:1ae107e0c6667a1ecb5ed98687517e0e$</string>
<key>textureFileName</key> <key>textureFileName</key>
<string>KnifeGirl.png</string> <string>KnifeGirl.png</string>
</dict> </dict>

View File

@@ -3,8 +3,8 @@
"uuid": "579bc0c1-f5e2-4a5d-889b-9d567e53b0e6", "uuid": "579bc0c1-f5e2-4a5d-889b-9d567e53b0e6",
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a", "rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"size": { "size": {
"width": 1014, "width": 1024,
"height": 1459 "height": 1456
}, },
"type": "Texture Packer", "type": "Texture Packer",
"subMetas": { "subMetas": {
@@ -17,8 +17,8 @@
"rotated": true, "rotated": true,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 806, "trimX": 384,
"trimY": 750, "trimY": 989,
"width": 112, "width": 112,
"height": 128, "height": 128,
"rawWidth": 112, "rawWidth": 112,
@@ -39,8 +39,8 @@
"rotated": true, "rotated": true,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 0, "trimX": 256,
"trimY": 1076, "trimY": 990,
"width": 112, "width": 112,
"height": 128, "height": 128,
"rawWidth": 112, "rawWidth": 112,
@@ -83,8 +83,8 @@
"rotated": false, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 528, "trimX": 940,
"trimY": 515, "trimY": 0,
"width": 80, "width": 80,
"height": 128, "height": 128,
"rawWidth": 80, "rawWidth": 80,
@@ -105,8 +105,8 @@
"rotated": false, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 934, "trimX": 940,
"trimY": 640, "trimY": 128,
"width": 80, "width": 80,
"height": 128, "height": 128,
"rawWidth": 80, "rawWidth": 80,
@@ -128,7 +128,7 @@
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 128, "trimX": 128,
"trimY": 1076, "trimY": 1082,
"width": 112, "width": 112,
"height": 128, "height": 128,
"rawWidth": 112, "rawWidth": 112,
@@ -149,8 +149,8 @@
"rotated": true, "rotated": true,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 678, "trimX": 0,
"trimY": 862, "trimY": 1188,
"width": 112, "width": 112,
"height": 128, "height": 128,
"rawWidth": 112, "rawWidth": 112,
@@ -215,8 +215,8 @@
"rotated": false, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 934, "trimX": 940,
"trimY": 768, "trimY": 256,
"width": 80, "width": 80,
"height": 128, "height": 128,
"rawWidth": 80, "rawWidth": 80,
@@ -237,8 +237,8 @@
"rotated": false, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 934, "trimX": 937,
"trimY": 896, "trimY": 384,
"width": 80, "width": 80,
"height": 128, "height": 128,
"rawWidth": 80, "rawWidth": 80,
@@ -256,11 +256,11 @@
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a", "rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"trimType": "auto", "trimType": "auto",
"trimThreshold": 1, "trimThreshold": 1,
"rotated": true, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 806, "trimX": 528,
"trimY": 958, "trimY": 515,
"width": 80, "width": 80,
"height": 128, "height": 128,
"rawWidth": 80, "rawWidth": 80,
@@ -281,8 +281,8 @@
"rotated": false, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 934, "trimX": 936,
"trimY": 1024, "trimY": 512,
"width": 80, "width": 80,
"height": 128, "height": 128,
"rawWidth": 80, "rawWidth": 80,
@@ -325,8 +325,8 @@
"rotated": false, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 128, "trimX": 0,
"trimY": 964, "trimY": 1076,
"width": 128, "width": 128,
"height": 112, "height": 112,
"rawWidth": 128, "rawWidth": 128,
@@ -347,8 +347,8 @@
"rotated": false, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 912, "trimX": 688,
"trimY": 1152, "trimY": 1357,
"width": 96, "width": 96,
"height": 96, "height": 96,
"rawWidth": 96, "rawWidth": 96,
@@ -369,8 +369,8 @@
"rotated": true, "rotated": true,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 340, "trimX": 240,
"trimY": 1197, "trimY": 1360,
"width": 96, "width": 96,
"height": 112, "height": 112,
"rawWidth": 96, "rawWidth": 96,
@@ -391,8 +391,8 @@
"rotated": true, "rotated": true,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 452, "trimX": 352,
"trimY": 1196, "trimY": 1358,
"width": 96, "width": 96,
"height": 112, "height": 112,
"rawWidth": 96, "rawWidth": 96,
@@ -413,8 +413,8 @@
"rotated": false, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 564, "trimX": 920,
"trimY": 1155, "trimY": 1072,
"width": 96, "width": 96,
"height": 112, "height": 112,
"rawWidth": 96, "rawWidth": 96,
@@ -435,8 +435,8 @@
"rotated": false, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 608, "trimX": 914,
"trimY": 1043, "trimY": 1184,
"width": 96, "width": 96,
"height": 112, "height": 112,
"rawWidth": 96, "rawWidth": 96,
@@ -479,8 +479,8 @@
"rotated": false, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 678, "trimX": 806,
"trimY": 750, "trimY": 631,
"width": 128, "width": 128,
"height": 112, "height": 112,
"rawWidth": 128, "rawWidth": 128,
@@ -787,8 +787,8 @@
"rotated": false, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 448, "trimX": 802,
"trimY": 1293, "trimY": 1149,
"width": 112, "width": 112,
"height": 112, "height": 112,
"rawWidth": 112, "rawWidth": 112,
@@ -806,11 +806,11 @@
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a", "rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"trimType": "auto", "trimType": "auto",
"trimThreshold": 1, "trimThreshold": 1,
"rotated": false, "rotated": true,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 660, "trimX": 800,
"trimY": 1155, "trimY": 1261,
"width": 96, "width": 96,
"height": 112, "height": 112,
"rawWidth": 96, "rawWidth": 96,
@@ -831,8 +831,8 @@
"rotated": false, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 384, "trimX": 806,
"trimY": 988, "trimY": 743,
"width": 128, "width": 128,
"height": 112, "height": 112,
"rawWidth": 128, "rawWidth": 128,
@@ -941,8 +941,8 @@
"rotated": false, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 0, "trimX": 806,
"trimY": 1188, "trimY": 1037,
"width": 114, "width": 114,
"height": 112, "height": 112,
"rawWidth": 114, "rawWidth": 114,
@@ -960,11 +960,11 @@
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a", "rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"trimType": "auto", "trimType": "auto",
"trimThreshold": 1, "trimThreshold": 1,
"rotated": false, "rotated": true,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 114, "trimX": 384,
"trimY": 1188, "trimY": 1213,
"width": 114, "width": 114,
"height": 112, "height": 112,
"rawWidth": 114, "rawWidth": 114,
@@ -985,8 +985,8 @@
"rotated": true, "rotated": true,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 0, "trimX": 464,
"trimY": 1300, "trimY": 1327,
"width": 114, "width": 114,
"height": 112, "height": 112,
"rawWidth": 114, "rawWidth": 114,
@@ -1007,8 +1007,8 @@
"rotated": true, "rotated": true,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 112, "trimX": 496,
"trimY": 1300, "trimY": 1213,
"width": 114, "width": 114,
"height": 112, "height": 112,
"rawWidth": 114, "rawWidth": 114,
@@ -1029,8 +1029,8 @@
"rotated": true, "rotated": true,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 0, "trimX": 464,
"trimY": 1300, "trimY": 1327,
"width": 114, "width": 114,
"height": 112, "height": 112,
"rawWidth": 114, "rawWidth": 114,
@@ -1051,8 +1051,8 @@
"rotated": true, "rotated": true,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 224, "trimX": 576,
"trimY": 1300, "trimY": 1327,
"width": 114, "width": 114,
"height": 112, "height": 112,
"rawWidth": 114, "rawWidth": 114,
@@ -1070,11 +1070,11 @@
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a", "rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"trimType": "auto", "trimType": "auto",
"trimThreshold": 1, "trimThreshold": 1,
"rotated": true, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 336, "trimX": 688,
"trimY": 1293, "trimY": 1043,
"width": 114, "width": 114,
"height": 112, "height": 112,
"rawWidth": 114, "rawWidth": 114,
@@ -1095,8 +1095,8 @@
"rotated": false, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 384, "trimX": 128,
"trimY": 634, "trimY": 846,
"width": 128, "width": 128,
"height": 118, "height": 118,
"rawWidth": 128, "rawWidth": 128,
@@ -1117,8 +1117,8 @@
"rotated": false, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 384, "trimX": 0,
"trimY": 752, "trimY": 958,
"width": 128, "width": 128,
"height": 118, "height": 118,
"rawWidth": 128, "rawWidth": 128,
@@ -1139,7 +1139,7 @@
"rotated": false, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 256, "trimX": 384,
"trimY": 753, "trimY": 753,
"width": 128, "width": 128,
"height": 118, "height": 118,
@@ -1161,8 +1161,8 @@
"rotated": false, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 128, "trimX": 678,
"trimY": 846, "trimY": 631,
"width": 128, "width": 128,
"height": 118, "height": 118,
"rawWidth": 128, "rawWidth": 128,
@@ -1183,8 +1183,8 @@
"rotated": false, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 0, "trimX": 384,
"trimY": 958, "trimY": 871,
"width": 128, "width": 128,
"height": 118, "height": 118,
"rawWidth": 128, "rawWidth": 128,
@@ -1205,8 +1205,8 @@
"rotated": false, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 384, "trimX": 256,
"trimY": 870, "trimY": 872,
"width": 128, "width": 128,
"height": 118, "height": 118,
"rawWidth": 128, "rawWidth": 128,
@@ -1227,8 +1227,8 @@
"rotated": false, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 256, "trimX": 128,
"trimY": 871, "trimY": 964,
"width": 128, "width": 128,
"height": 118, "height": 118,
"rawWidth": 128, "rawWidth": 128,
@@ -1249,8 +1249,8 @@
"rotated": false, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 940, "trimX": 608,
"trimY": 0, "trimY": 531,
"width": 70, "width": 70,
"height": 128, "height": 128,
"rawWidth": 70, "rawWidth": 70,
@@ -1271,8 +1271,8 @@
"rotated": false, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 940, "trimX": 608,
"trimY": 128, "trimY": 659,
"width": 70, "width": 70,
"height": 128, "height": 128,
"rawWidth": 70, "rawWidth": 70,
@@ -1293,8 +1293,8 @@
"rotated": false, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 940, "trimX": 608,
"trimY": 256, "trimY": 787,
"width": 70, "width": 70,
"height": 128, "height": 128,
"rawWidth": 70, "rawWidth": 70,
@@ -1315,8 +1315,8 @@
"rotated": false, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 937, "trimX": 608,
"trimY": 384, "trimY": 915,
"width": 70, "width": 70,
"height": 128, "height": 128,
"rawWidth": 70, "rawWidth": 70,
@@ -1334,11 +1334,11 @@
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a", "rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"trimType": "auto", "trimType": "auto",
"trimThreshold": 1, "trimThreshold": 1,
"rotated": false, "rotated": true,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 936, "trimX": 128,
"trimY": 512, "trimY": 1290,
"width": 70, "width": 70,
"height": 128, "height": 128,
"rawWidth": 70, "rawWidth": 70,
@@ -1356,11 +1356,11 @@
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a", "rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"trimType": "auto", "trimType": "auto",
"trimThreshold": 1, "trimThreshold": 1,
"rotated": false, "rotated": true,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 608, "trimX": 0,
"trimY": 531, "trimY": 1300,
"width": 70, "width": 70,
"height": 128, "height": 128,
"rawWidth": 70, "rawWidth": 70,
@@ -1378,11 +1378,11 @@
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a", "rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"trimType": "auto", "trimType": "auto",
"trimThreshold": 1, "trimThreshold": 1,
"rotated": false, "rotated": true,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 608, "trimX": 0,
"trimY": 659, "trimY": 1370,
"width": 70, "width": 70,
"height": 128, "height": 128,
"rawWidth": 70, "rawWidth": 70,
@@ -1400,11 +1400,11 @@
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a", "rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"trimType": "auto", "trimType": "auto",
"trimThreshold": 1, "trimThreshold": 1,
"rotated": false, "rotated": true,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 608, "trimX": 0,
"trimY": 659, "trimY": 1370,
"width": 70, "width": 70,
"height": 128, "height": 128,
"rawWidth": 70, "rawWidth": 70,
@@ -1422,11 +1422,11 @@
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a", "rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"trimType": "auto", "trimType": "auto",
"trimThreshold": 1, "trimThreshold": 1,
"rotated": false, "rotated": true,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 608, "trimX": 0,
"trimY": 531, "trimY": 1300,
"width": 70, "width": 70,
"height": 128, "height": 128,
"rawWidth": 70, "rawWidth": 70,
@@ -1444,11 +1444,11 @@
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a", "rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"trimType": "auto", "trimType": "auto",
"trimThreshold": 1, "trimThreshold": 1,
"rotated": false, "rotated": true,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 936, "trimX": 128,
"trimY": 512, "trimY": 1290,
"width": 70, "width": 70,
"height": 128, "height": 128,
"rawWidth": 70, "rawWidth": 70,
@@ -1469,8 +1469,8 @@
"rotated": false, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 937, "trimX": 608,
"trimY": 384, "trimY": 915,
"width": 70, "width": 70,
"height": 128, "height": 128,
"rawWidth": 70, "rawWidth": 70,
@@ -1491,8 +1491,8 @@
"rotated": false, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 940, "trimX": 608,
"trimY": 256, "trimY": 787,
"width": 70, "width": 70,
"height": 128, "height": 128,
"rawWidth": 70, "rawWidth": 70,
@@ -1513,8 +1513,8 @@
"rotated": false, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 940, "trimX": 608,
"trimY": 128, "trimY": 659,
"width": 70, "width": 70,
"height": 128, "height": 128,
"rawWidth": 70, "rawWidth": 70,
@@ -1532,11 +1532,11 @@
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a", "rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"trimType": "auto", "trimType": "auto",
"trimThreshold": 1, "trimThreshold": 1,
"rotated": false, "rotated": true,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 608, "trimX": 806,
"trimY": 787, "trimY": 967,
"width": 70, "width": 70,
"height": 128, "height": 128,
"rawWidth": 70, "rawWidth": 70,
@@ -1554,11 +1554,11 @@
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a", "rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"trimType": "auto", "trimType": "auto",
"trimThreshold": 1, "trimThreshold": 1,
"rotated": false, "rotated": true,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 608, "trimX": 678,
"trimY": 915, "trimY": 973,
"width": 70, "width": 70,
"height": 128, "height": 128,
"rawWidth": 70, "rawWidth": 70,
@@ -1579,8 +1579,8 @@
"rotated": false, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 228, "trimX": 128,
"trimY": 1197, "trimY": 1360,
"width": 112, "width": 112,
"height": 96, "height": 96,
"rawWidth": 112, "rawWidth": 112,
@@ -1645,8 +1645,8 @@
"rotated": false, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 256, "trimX": 678,
"trimY": 989, "trimY": 749,
"width": 128, "width": 128,
"height": 112, "height": 112,
"rawWidth": 128, "rawWidth": 128,
@@ -1667,8 +1667,8 @@
"rotated": false, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 672, "trimX": 784,
"trimY": 1363, "trimY": 1357,
"width": 96, "width": 96,
"height": 96, "height": 96,
"rawWidth": 96, "rawWidth": 96,
@@ -1689,8 +1689,8 @@
"rotated": false, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 672, "trimX": 934,
"trimY": 1267, "trimY": 976,
"width": 80, "width": 80,
"height": 96, "height": 96,
"rawWidth": 80, "rawWidth": 80,
@@ -1711,8 +1711,8 @@
"rotated": false, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 560, "trimX": 688,
"trimY": 1292, "trimY": 1155,
"width": 112, "width": 112,
"height": 112, "height": 112,
"rawWidth": 112, "rawWidth": 112,
@@ -1733,8 +1733,8 @@
"rotated": false, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 384, "trimX": 256,
"trimY": 1100, "trimY": 1102,
"width": 128, "width": 128,
"height": 96, "height": 96,
"rawWidth": 128, "rawWidth": 128,
@@ -1752,11 +1752,11 @@
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a", "rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"trimType": "auto", "trimType": "auto",
"trimThreshold": 1, "trimThreshold": 1,
"rotated": true, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 800, "trimX": 934,
"trimY": 1038, "trimY": 640,
"width": 80, "width": 80,
"height": 112, "height": 112,
"rawWidth": 80, "rawWidth": 80,
@@ -1774,11 +1774,11 @@
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a", "rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"trimType": "auto", "trimType": "auto",
"trimThreshold": 1, "trimThreshold": 1,
"rotated": true, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 800, "trimX": 934,
"trimY": 1118, "trimY": 752,
"width": 80, "width": 80,
"height": 112, "height": 112,
"rawWidth": 80, "rawWidth": 80,
@@ -1799,8 +1799,8 @@
"rotated": true, "rotated": true,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 678, "trimX": 256,
"trimY": 974, "trimY": 1294,
"width": 64, "width": 64,
"height": 128, "height": 128,
"rawWidth": 64, "rawWidth": 64,
@@ -1818,11 +1818,11 @@
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a", "rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"trimType": "auto", "trimType": "auto",
"trimThreshold": 1, "trimThreshold": 1,
"rotated": true, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 756, "trimX": 934,
"trimY": 1198, "trimY": 864,
"width": 80, "width": 80,
"height": 112, "height": 112,
"rawWidth": 80, "rawWidth": 80,
@@ -1840,11 +1840,11 @@
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a", "rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"trimType": "auto", "trimType": "auto",
"trimThreshold": 1, "trimThreshold": 1,
"rotated": true, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 752, "trimX": 608,
"trimY": 1278, "trimY": 1043,
"width": 80, "width": 80,
"height": 96, "height": 96,
"rawWidth": 80, "rawWidth": 80,
@@ -1865,8 +1865,8 @@
"rotated": false, "rotated": false,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 768, "trimX": 608,
"trimY": 1358, "trimY": 1139,
"width": 80, "width": 80,
"height": 96, "height": 96,
"rawWidth": 80, "rawWidth": 80,
@@ -1887,8 +1887,8 @@
"rotated": true, "rotated": true,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 868, "trimX": 688,
"trimY": 1248, "trimY": 1267,
"width": 80, "width": 80,
"height": 96, "height": 96,
"rawWidth": 80, "rawWidth": 80,
@@ -1906,11 +1906,11 @@
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a", "rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"trimType": "auto", "trimType": "auto",
"trimThreshold": 1, "trimThreshold": 1,
"rotated": false, "rotated": true,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 704, "trimX": 912,
"trimY": 1038, "trimY": 1296,
"width": 96, "width": 96,
"height": 112, "height": 112,
"rawWidth": 96, "rawWidth": 96,
@@ -1931,8 +1931,8 @@
"rotated": true, "rotated": true,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 256, "trimX": 128,
"trimY": 1101, "trimY": 1194,
"width": 96, "width": 96,
"height": 128, "height": 128,
"rawWidth": 96, "rawWidth": 96,
@@ -1953,8 +1953,8 @@
"rotated": true, "rotated": true,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 806, "trimX": 256,
"trimY": 862, "trimY": 1198,
"width": 96, "width": 96,
"height": 128, "height": 128,
"rawWidth": 96, "rawWidth": 96,
@@ -2076,6 +2076,72 @@
"spriteType": "normal", "spriteType": "normal",
"subMetas": {} "subMetas": {}
}, },
"TurnAround1_1.png": {
"ver": "1.0.4",
"uuid": "28ee1f29-e538-4d36-bb5c-275f9e3b392b",
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 806,
"trimY": 855,
"width": 112,
"height": 128,
"rawWidth": 112,
"rawHeight": 128,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"TurnAround1_2.png": {
"ver": "1.0.4",
"uuid": "211a73bb-31d7-4e6c-901e-f6939d9214e0",
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 678,
"trimY": 861,
"width": 112,
"height": 128,
"rawWidth": 112,
"rawHeight": 128,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"TurnAround1_3.png": {
"ver": "1.0.4",
"uuid": "048c41dc-fc00-4bc4-8041-6003e7c2b6e4",
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 384,
"trimY": 1101,
"width": 112,
"height": 128,
"rawWidth": 112,
"rawHeight": 128,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Walking_1.png": { "Walking_1.png": {
"ver": "1.0.4", "ver": "1.0.4",
"uuid": "9435195e-4560-495e-b1ae-083c0c87e8a0", "uuid": "9435195e-4560-495e-b1ae-083c0c87e8a0",
@@ -2129,8 +2195,8 @@
"rotated": true, "rotated": true,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 680, "trimX": 272,
"trimY": 512, "trimY": 515,
"width": 119, "width": 119,
"height": 128, "height": 128,
"rawWidth": 119, "rawWidth": 119,
@@ -2151,8 +2217,8 @@
"rotated": true, "rotated": true,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 808, "trimX": 128,
"trimY": 512, "trimY": 608,
"width": 119, "width": 119,
"height": 128, "height": 128,
"rawWidth": 119, "rawWidth": 119,
@@ -2173,8 +2239,8 @@
"rotated": true, "rotated": true,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 272, "trimX": 0,
"trimY": 515, "trimY": 720,
"width": 119, "width": 119,
"height": 128, "height": 128,
"rawWidth": 119, "rawWidth": 119,
@@ -2195,8 +2261,8 @@
"rotated": true, "rotated": true,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 128, "trimX": 400,
"trimY": 608, "trimY": 515,
"width": 119, "width": 119,
"height": 128, "height": 128,
"rawWidth": 119, "rawWidth": 119,
@@ -2217,8 +2283,8 @@
"rotated": true, "rotated": true,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 0, "trimX": 256,
"trimY": 720, "trimY": 634,
"width": 119, "width": 119,
"height": 128, "height": 128,
"rawWidth": 119, "rawWidth": 119,
@@ -2239,8 +2305,8 @@
"rotated": true, "rotated": true,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 400, "trimX": 128,
"trimY": 515, "trimY": 727,
"width": 119, "width": 119,
"height": 128, "height": 128,
"rawWidth": 119, "rawWidth": 119,
@@ -2261,8 +2327,8 @@
"rotated": true, "rotated": true,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 678, "trimX": 0,
"trimY": 631, "trimY": 839,
"width": 119, "width": 119,
"height": 128, "height": 128,
"rawWidth": 119, "rawWidth": 119,
@@ -2283,8 +2349,8 @@
"rotated": true, "rotated": true,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 806, "trimX": 384,
"trimY": 631, "trimY": 634,
"width": 119, "width": 119,
"height": 128, "height": 128,
"rawWidth": 119, "rawWidth": 119,
@@ -2305,8 +2371,8 @@
"rotated": true, "rotated": true,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 256, "trimX": 680,
"trimY": 634, "trimY": 512,
"width": 119, "width": 119,
"height": 128, "height": 128,
"rawWidth": 119, "rawWidth": 119,
@@ -2327,8 +2393,8 @@
"rotated": true, "rotated": true,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 128, "trimX": 808,
"trimY": 727, "trimY": 512,
"width": 119, "width": 119,
"height": 128, "height": 128,
"rawWidth": 119, "rawWidth": 119,
@@ -2349,8 +2415,8 @@
"rotated": true, "rotated": true,
"offsetX": 0, "offsetX": 0,
"offsetY": 0, "offsetY": 0,
"trimX": 0, "trimX": 256,
"trimY": 839, "trimY": 753,
"width": 119, "width": 119,
"height": 128, "height": 128,
"rawWidth": 119, "rawWidth": 119,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 KiB

After

Width:  |  Height:  |  Size: 119 KiB

View File

@@ -0,0 +1,43 @@
{
"__type__": "cc.AnimationClip",
"_name": "TurnAround1",
"_objFlags": 0,
"_native": "",
"_duration": 0.15,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "28ee1f29-e538-4d36-bb5c-275f9e3b392b"
}
},
{
"frame": 0.03333333333333333,
"value": {
"__uuid__": "211a73bb-31d7-4e6c-901e-f6939d9214e0"
}
},
{
"frame": 0.08333333333333333,
"value": {
"__uuid__": "048c41dc-fc00-4bc4-8041-6003e7c2b6e4"
}
},
{
"frame": 0.13333333333333333,
"value": {
"__uuid__": "9435195e-4560-495e-b1ae-083c0c87e8a0"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "e906322d-a08b-4477-a2e9-98acd42fa034",
"subMetas": {}
}

View File

@@ -3,7 +3,7 @@
"_name": "Walking", "_name": "Walking",
"_objFlags": 0, "_objFlags": 0,
"_native": "", "_native": "",
"_duration": 1.5166666666666666, "_duration": 0.6333333333333333,
"sample": 60, "sample": 60,
"speed": 1.2, "speed": 1.2,
"wrapMode": 2, "wrapMode": 2,
@@ -13,78 +13,78 @@
"spriteFrame": [ "spriteFrame": [
{ {
"frame": 0, "frame": 0,
"value": {
"__uuid__": "c3b14ecc-a6d9-4cb3-8637-ca7b407a0f5c"
}
},
{
"frame": 0.08333333333333333,
"value": { "value": {
"__uuid__": "9435195e-4560-495e-b1ae-083c0c87e8a0" "__uuid__": "9435195e-4560-495e-b1ae-083c0c87e8a0"
} }
}, },
{ {
"frame": 0.18333333333333332, "frame": 0.06666666666666667,
"value": { "value": {
"__uuid__": "ec048360-7a17-4f22-ba52-eb86ec1acae8" "__uuid__": "ec048360-7a17-4f22-ba52-eb86ec1acae8"
} }
}, },
{ {
"frame": 0.2833333333333333, "frame": 0.11666666666666667,
"value": { "value": {
"__uuid__": "82bb81e3-667c-4280-8710-211f4904ef2f" "__uuid__": "82bb81e3-667c-4280-8710-211f4904ef2f"
} }
}, },
{ {
"frame": 0.4, "frame": 0.16666666666666666,
"value": {
"__uuid__": "c3b14ecc-a6d9-4cb3-8637-ca7b407a0f5c"
}
},
{
"frame": 0.21666666666666667,
"value": { "value": {
"__uuid__": "f958fb7f-ef5a-4918-81f3-564004572f45" "__uuid__": "f958fb7f-ef5a-4918-81f3-564004572f45"
} }
}, },
{ {
"frame": 0.5333333333333333, "frame": 0.26666666666666666,
"value": { "value": {
"__uuid__": "8a0ecf92-db26-4206-9a80-20e749055def" "__uuid__": "8a0ecf92-db26-4206-9a80-20e749055def"
} }
}, },
{ {
"frame": 0.65, "frame": 0.31666666666666665,
"value": { "value": {
"__uuid__": "942f2e02-a700-4fbf-877e-08c93e4d4010" "__uuid__": "942f2e02-a700-4fbf-877e-08c93e4d4010"
} }
}, },
{ {
"frame": 0.7666666666666667, "frame": 0.36666666666666664,
"value": { "value": {
"__uuid__": "30546064-1a11-499e-8523-a82c83951c73" "__uuid__": "30546064-1a11-499e-8523-a82c83951c73"
} }
}, },
{ {
"frame": 0.9, "frame": 0.4166666666666667,
"value": { "value": {
"__uuid__": "515bb75f-7a1f-4500-8aa9-c895915ce19f" "__uuid__": "515bb75f-7a1f-4500-8aa9-c895915ce19f"
} }
}, },
{ {
"frame": 1.0333333333333334, "frame": 0.4666666666666667,
"value": { "value": {
"__uuid__": "9100da6b-7582-4afb-9698-3d67d3b2012d" "__uuid__": "9100da6b-7582-4afb-9698-3d67d3b2012d"
} }
}, },
{ {
"frame": 1.2166666666666666, "frame": 0.5166666666666667,
"value": { "value": {
"__uuid__": "1257f72d-0cb3-4750-ae70-13c2d8eb2269" "__uuid__": "1257f72d-0cb3-4750-ae70-13c2d8eb2269"
} }
}, },
{ {
"frame": 1.3833333333333333, "frame": 0.5666666666666667,
"value": { "value": {
"__uuid__": "1d34b6db-27ba-4e26-864d-0f00d501765e" "__uuid__": "1d34b6db-27ba-4e26-864d-0f00d501765e"
} }
}, },
{ {
"frame": 1.5, "frame": 0.6166666666666667,
"value": { "value": {
"__uuid__": "c317a75a-52c0-4c38-9300-a064cbf4efb3" "__uuid__": "c317a75a-52c0-4c38-9300-a064cbf4efb3"
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 259 KiB

After

Width:  |  Height:  |  Size: 269 KiB

View File

@@ -0,0 +1,43 @@
{
"__type__": "cc.AnimationClip",
"_name": "TurnAround1",
"_objFlags": 0,
"_native": "",
"_duration": 0.15,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "ee5e05fa-b515-470f-bc3c-43544f02cb92"
}
},
{
"frame": 0.03333333333333333,
"value": {
"__uuid__": "ffa521b6-118e-46e8-be1c-51cc54381ec8"
}
},
{
"frame": 0.08333333333333333,
"value": {
"__uuid__": "0b27d2c9-c5a3-4020-adbe-0297c1ba3aeb"
}
},
{
"frame": 0.13333333333333333,
"value": {
"__uuid__": "a47f518e-62fb-4549-8897-4f2d387bd145"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "edd23b2f-1caa-4836-88a7-e4af1f26743e",
"subMetas": {}
}

View File

@@ -15,7 +15,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{62,92}</string> <string>{62,92}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{1277,188},{62,92}}</string> <string>{{1307,188},{62,92}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -30,7 +30,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{77,99}</string> <string>{77,99}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{748,0},{77,99}}</string> <string>{{782,101},{77,99}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -45,7 +45,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{112,99}</string> <string>{112,99}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{408,348},{112,99}}</string> <string>{{381,360},{112,99}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -60,7 +60,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{96,100}</string> <string>{96,100}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{664,315},{96,100}}</string> <string>{{704,312},{96,100}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -75,7 +75,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{62,92}</string> <string>{62,92}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{1277,188},{62,92}}</string> <string>{{1307,188},{62,92}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -90,7 +90,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{58,97}</string> <string>{58,97}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{1023,194},{58,97}}</string> <string>{{983,388},{58,97}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -105,9 +105,9 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{60,90}</string> <string>{60,90}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{1393,141},{60,90}}</string> <string>{{1424,0},{60,90}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <false/>
</dict> </dict>
<key>Atk2_2.png</key> <key>Atk2_2.png</key>
<dict> <dict>
@@ -120,7 +120,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{84,96}</string> <string>{84,96}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{1087,97},{84,96}}</string> <string>{{1082,291},{84,96}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -135,7 +135,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{55,100}</string> <string>{55,100}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{731,101},{55,100}}</string> <string>{{738,206},{55,100}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -150,9 +150,9 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{63,100}</string> <string>{63,100}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{717,206},{63,100}}</string> <string>{{0,437},{63,100}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <true/>
</dict> </dict>
<key>Atk2_5.png</key> <key>Atk2_5.png</key>
<dict> <dict>
@@ -165,7 +165,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{66,101}</string> <string>{66,101}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{682,0},{66,101}}</string> <string>{{755,0},{66,101}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -180,7 +180,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{80,95}</string> <string>{80,95}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{1126,0},{80,95}}</string> <string>{{1099,387},{80,95}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -195,7 +195,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{116,109}</string> <string>{116,109}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{315,119},{116,109}}</string> <string>{{336,244},{116,109}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -210,7 +210,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{102,96}</string> <string>{102,96}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{621,213},{102,96}}</string> <string>{{608,325},{102,96}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -225,9 +225,9 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{75,102}</string> <string>{75,102}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{139,421},{75,102}}</string> <string>{{663,210},{75,102}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <false/>
</dict> </dict>
<key>Atk3_0.png</key> <key>Atk3_0.png</key>
<dict> <dict>
@@ -240,7 +240,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{66,109}</string> <string>{66,109}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{469,110},{66,109}}</string> <string>{{480,339},{66,109}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -255,7 +255,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{66,113}</string> <string>{66,113}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{355,235},{66,113}}</string> <string>{{403,114},{66,113}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -330,7 +330,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{78,131}</string> <string>{78,131}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{137,290},{78,131}}</string> <string>{{78,0},{78,131}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -345,9 +345,9 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{59,139}</string> <string>{59,139}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{0,437},{59,139}}</string> <string>{{78,290},{59,139}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <false/>
</dict> </dict>
<key>Atk3_8.png</key> <key>Atk3_8.png</key>
<dict> <dict>
@@ -360,7 +360,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{59,139}</string> <string>{59,139}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{78,290},{59,139}}</string> <string>{{137,290},{59,139}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -375,9 +375,9 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{62,97}</string> <string>{62,97}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{507,434},{62,97}}</string> <string>{{962,291},{62,97}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <false/>
</dict> </dict>
<key>Atked1_1.png</key> <key>Atked1_1.png</key>
<dict> <dict>
@@ -390,9 +390,9 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{73,95}</string> <string>{73,95}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{1171,95},{73,95}}</string> <string>{{641,427},{73,95}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <true/>
</dict> </dict>
<key>Atked1_2.png</key> <key>Atked1_2.png</key>
<dict> <dict>
@@ -405,7 +405,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{90,89}</string> <string>{90,89}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{1324,0},{90,89}}</string> <string>{{1335,0},{90,89}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -420,7 +420,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{95,80}</string> <string>{95,80}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{1084,291},{95,80}}</string> <string>{{1168,193},{95,80}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -435,7 +435,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{80,95}</string> <string>{80,95}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{1010,388},{80,95}}</string> <string>{{1166,290},{80,95}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -450,7 +450,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{83,92}</string> <string>{83,92}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{1208,382},{83,92}}</string> <string>{{1299,382},{83,92}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -465,7 +465,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{92,83}</string> <string>{92,83}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{1224,284},{92,83}}</string> <string>{{1306,284},{92,83}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -480,7 +480,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{112,45}</string> <string>{112,45}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{424,115},{112,45}}</string> <string>{{469,112},{112,45}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -495,7 +495,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{88,69}</string> <string>{88,69}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{604,427},{88,69}}</string> <string>{{1443,222},{88,69}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -510,7 +510,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{91,90}</string> <string>{91,90}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{1303,93},{91,90}}</string> <string>{{1313,93},{91,90}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -525,7 +525,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{120,93}</string> <string>{120,93}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{222,123},{120,93}}</string> <string>{{254,124},{120,93}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -540,9 +540,9 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{100,112}</string> <string>{100,112}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{241,396},{100,112}}</string> <string>{{408,0},{100,112}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <false/>
</dict> </dict>
<key>GetUp1_5.png</key> <key>GetUp1_5.png</key>
<dict> <dict>
@@ -555,7 +555,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{106,93}</string> <string>{106,93}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{507,328},{106,93}}</string> <string>{{570,219},{106,93}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -570,7 +570,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{106,79}</string> <string>{106,79}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{542,217},{106,79}}</string> <string>{{571,108},{106,79}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -585,7 +585,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{73,87}</string> <string>{73,87}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{1307,280},{73,87}}</string> <string>{{1382,376},{73,87}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -600,9 +600,9 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{67,90}</string> <string>{67,90}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{1413,74},{67,90}}</string> <string>{{1403,90},{67,90}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <false/>
</dict> </dict>
<key>GetUp1_9.png</key> <key>GetUp1_9.png</key>
<dict> <dict>
@@ -615,7 +615,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{58,97}</string> <string>{58,97}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{1023,194},{58,97}}</string> <string>{{983,388},{58,97}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -630,7 +630,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{58,95}</string> <string>{58,95}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{1090,386},{58,95}}</string> <string>{{1219,0},{58,95}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -645,7 +645,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{58,97}</string> <string>{58,97}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{1029,97},{58,97}}</string> <string>{{1024,291},{58,97}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -660,7 +660,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{60,94}</string> <string>{60,94}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{1148,386},{60,94}}</string> <string>{{1179,385},{60,94}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -675,7 +675,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{58,97}</string> <string>{58,97}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{1081,194},{58,97}}</string> <string>{{1036,194},{58,97}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -690,7 +690,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{58,97}</string> <string>{58,97}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{1068,0},{58,97}}</string> <string>{{1041,388},{58,97}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -705,9 +705,9 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{60,95}</string> <string>{60,95}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{1206,0},{60,95}}</string> <string>{{546,440},{60,95}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <true/>
</dict> </dict>
<key>Idle1_5.png</key> <key>Idle1_5.png</key>
<dict> <dict>
@@ -720,7 +720,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{60,94}</string> <string>{60,94}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{1164,288},{60,94}}</string> <string>{{1239,385},{60,94}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -735,7 +735,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{59,93}</string> <string>{59,93}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{789,403},{59,93}}</string> <string>{{1248,191},{59,93}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -750,7 +750,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{58,93}</string> <string>{58,93}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{1266,0},{58,93}}</string> <string>{{1277,0},{58,93}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -765,7 +765,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{59,93}</string> <string>{59,93}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{1244,95},{59,93}}</string> <string>{{1254,95},{59,93}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -780,7 +780,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{60,94}</string> <string>{60,94}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{1217,190},{60,94}}</string> <string>{{1246,288},{60,94}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -795,7 +795,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{77,68}</string> <string>{77,68}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{1437,417},{77,68}}</string> <string>{{1473,291},{77,68}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -810,7 +810,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{118,76}</string> <string>{118,76}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{215,278},{118,76}}</string> <string>{{196,284},{118,76}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -825,7 +825,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{104,65}</string> <string>{104,65}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{617,0},{104,65}}</string> <string>{{650,106},{104,65}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -840,9 +840,9 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{80,66}</string> <string>{80,66}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{1380,285},{80,66}}</string> <string>{{1473,368},{80,66}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <true/>
</dict> </dict>
<key>InAirAtk1_12.png</key> <key>InAirAtk1_12.png</key>
<dict> <dict>
@@ -855,7 +855,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{102,67}</string> <string>{102,67}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{664,104},{102,67}}</string> <string>{{715,104},{102,67}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -870,9 +870,9 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{79,66}</string> <string>{79,66}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{1339,201},{79,66}}</string> <string>{{1470,90},{79,66}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <false/>
</dict> </dict>
<key>InAirAtk1_3.png</key> <key>InAirAtk1_3.png</key>
<dict> <dict>
@@ -885,7 +885,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{124,64}</string> <string>{124,64}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{78,0},{124,64}}</string> <string>{{156,0},{124,64}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -900,7 +900,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{104,64}</string> <string>{104,64}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{600,323},{104,64}}</string> <string>{{691,0},{104,64}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -915,7 +915,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{79,61}</string> <string>{79,61}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{1376,417},{79,61}}</string> <string>{{1484,0},{79,61}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -930,7 +930,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{124,64}</string> <string>{124,64}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{142,0},{124,64}}</string> <string>{{160,124},{124,64}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -945,7 +945,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{106,67}</string> <string>{106,67}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{597,107},{106,67}}</string> <string>{{624,0},{106,67}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -960,7 +960,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{79,66}</string> <string>{79,66}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{1380,351},{79,66}}</string> <string>{{1470,156},{79,66}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -975,7 +975,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{118,64}</string> <string>{118,64}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{291,243},{118,64}}</string> <string>{{272,284},{118,64}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -990,9 +990,9 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{71,119}</string> <string>{71,119}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{242,0},{71,119}}</string> <string>{{100,429},{71,119}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <true/>
</dict> </dict>
<key>InAirIdle1_1.png</key> <key>InAirIdle1_1.png</key>
<dict> <dict>
@@ -1005,7 +1005,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{71,119}</string> <string>{71,119}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{313,0},{71,119}}</string> <string>{{282,0},{71,119}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -1020,7 +1020,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{55,114}</string> <string>{55,114}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{353,361},{55,114}}</string> <string>{{353,0},{55,114}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -1035,7 +1035,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{62,124}</string> <string>{62,124}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{160,124},{62,124}}</string> <string>{{220,0},{62,124}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -1050,9 +1050,9 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{74,90}</string> <string>{74,90}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{1413,0},{74,90}}</string> <string>{{1369,184},{74,90}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <false/>
</dict> </dict>
<key>InAirIdle1_3.png</key> <key>InAirIdle1_3.png</key>
<dict> <dict>
@@ -1065,7 +1065,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{110,54}</string> <string>{110,54}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{440,0},{110,54}}</string> <string>{{508,0},{110,54}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -1080,7 +1080,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{85,88}</string> <string>{85,88}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{1291,376},{85,88}}</string> <string>{{736,412},{85,88}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -1095,7 +1095,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{64,112}</string> <string>{64,112}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{421,235},{64,112}}</string> <string>{{445,227},{64,112}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -1110,7 +1110,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{62,107}</string> <string>{62,107}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{555,0},{62,107}}</string> <string>{{546,333},{62,107}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -1125,9 +1125,9 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{85,84}</string> <string>{85,84}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{1405,201},{85,84}}</string> <string>{{1389,291},{85,84}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <true/>
</dict> </dict>
<key>InAirIdle1_8.png</key> <key>InAirIdle1_8.png</key>
<dict> <dict>
@@ -1140,7 +1140,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{109,61}</string> <string>{109,61}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{494,0},{109,61}}</string> <string>{{509,224},{109,61}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -1155,7 +1155,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{78,95}</string> <string>{78,95}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{1139,193},{78,95}}</string> <string>{{1176,96},{78,95}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -1170,7 +1170,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{115,56}</string> <string>{115,56}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{384,0},{115,56}}</string> <string>{{347,119},{115,56}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -1185,7 +1185,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{109,57}</string> <string>{109,57}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{485,219},{109,57}}</string> <string>{{514,110},{109,57}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -1200,7 +1200,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{108,62}</string> <string>{108,62}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{535,109},{108,62}}</string> <string>{{562,0},{108,62}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <true/>
</dict> </dict>
@@ -1215,9 +1215,9 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{123,36}</string> <string>{123,36}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{206,0},{123,36}}</string> <string>{{160,248},{123,36}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <false/>
</dict> </dict>
<key>LayDown1_4.png</key> <key>LayDown1_4.png</key>
<dict> <dict>
@@ -1230,7 +1230,52 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{123,30}</string> <string>{123,30}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{160,248},{123,30}}</string> <string>{{224,124},{123,30}}</string>
<key>textureRotated</key>
<true/>
</dict>
<key>TurnAround1_1.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{74,96}</string>
<key>spriteSourceSize</key>
<string>{74,96}</string>
<key>textureRect</key>
<string>{{1094,194},{74,96}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>TurnAround1_2.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{74,96}</string>
<key>spriteSourceSize</key>
<string>{74,96}</string>
<key>textureRect</key>
<string>{{1102,97},{74,96}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>TurnAround1_3.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{74,96}</string>
<key>spriteSourceSize</key>
<string>{74,96}</string>
<key>textureRect</key>
<string>{{1145,0},{74,96}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -1245,9 +1290,9 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{81,97}</string> <string>{81,97}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{692,415},{81,97}}</string> <string>{{219,402},{81,97}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<true/> <false/>
</dict> </dict>
<key>Walking_10.png</key> <key>Walking_10.png</key>
<dict> <dict>
@@ -1260,7 +1305,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{81,97}</string> <string>{81,97}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{760,306},{81,97}}</string> <string>{{300,402},{81,97}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -1275,7 +1320,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{81,97}</string> <string>{81,97}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{780,201},{81,97}}</string> <string>{{821,0},{81,97}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -1290,7 +1335,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{81,97}</string> <string>{81,97}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{786,99},{81,97}}</string> <string>{{793,200},{81,97}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -1305,7 +1350,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{81,97}</string> <string>{81,97}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{825,0},{81,97}}</string> <string>{{859,97},{81,97}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -1320,7 +1365,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{81,97}</string> <string>{81,97}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{841,298},{81,97}}</string> <string>{{902,0},{81,97}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -1335,7 +1380,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{81,97}</string> <string>{81,97}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{848,395},{81,97}}</string> <string>{{800,297},{81,97}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -1350,7 +1395,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{81,97}</string> <string>{81,97}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{861,196},{81,97}}</string> <string>{{874,194},{81,97}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -1365,7 +1410,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{81,97}</string> <string>{81,97}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{867,97},{81,97}}</string> <string>{{940,97},{81,97}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -1380,7 +1425,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{81,97}</string> <string>{81,97}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{906,0},{81,97}}</string> <string>{{983,0},{81,97}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -1395,7 +1440,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{81,97}</string> <string>{81,97}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{922,293},{81,97}}</string> <string>{{821,394},{81,97}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -1410,7 +1455,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{81,97}</string> <string>{81,97}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{942,194},{81,97}}</string> <string>{{881,291},{81,97}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -1425,7 +1470,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{81,97}</string> <string>{81,97}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{948,97},{81,97}}</string> <string>{{955,194},{81,97}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -1440,7 +1485,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{81,97}</string> <string>{81,97}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{987,0},{81,97}}</string> <string>{{1021,97},{81,97}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -1455,7 +1500,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{81,97}</string> <string>{81,97}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{929,390},{81,97}}</string> <string>{{1064,0},{81,97}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -1470,7 +1515,7 @@
<key>spriteSourceSize</key> <key>spriteSourceSize</key>
<string>{81,97}</string> <string>{81,97}</string>
<key>textureRect</key> <key>textureRect</key>
<string>{{1003,291},{81,97}}</string> <string>{{902,388},{81,97}}</string>
<key>textureRotated</key> <key>textureRotated</key>
<false/> <false/>
</dict> </dict>
@@ -1486,9 +1531,9 @@
<key>realTextureFileName</key> <key>realTextureFileName</key>
<string>MonkGirl.png</string> <string>MonkGirl.png</string>
<key>size</key> <key>size</key>
<string>{1505,496}</string> <string>{1549,500}</string>
<key>smartupdate</key> <key>smartupdate</key>
<string>$TexturePacker:SmartUpdate:8383576ddc6ed0fb9e6adcbc98ec9c07:b0caf27c9f592741053365a3d87b3473:7b088363a1f16e4f4ff313aecc52227b$</string> <string>$TexturePacker:SmartUpdate:f2fd96a7a4bba5a2e1c4622dcb63e1f2:17c698372c46bf0be82704dd808cd6f4:7b088363a1f16e4f4ff313aecc52227b$</string>
<key>textureFileName</key> <key>textureFileName</key>
<string>MonkGirl.png</string> <string>MonkGirl.png</string>
</dict> </dict>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 98 KiB

View File

@@ -0,0 +1,43 @@
{
"__type__": "cc.AnimationClip",
"_name": "TurnAround1",
"_objFlags": 0,
"_native": "",
"_duration": 0.15,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "c1a00209-f74d-41b5-a5da-df5720ac34b4"
}
},
{
"frame": 0.03333333333333333,
"value": {
"__uuid__": "2b52c0f1-2360-4a2b-9233-bf5662de09a5"
}
},
{
"frame": 0.08333333333333333,
"value": {
"__uuid__": "e3f9dfe7-ed91-4dc3-b68b-a3a3c2637074"
}
},
{
"frame": 0.13333333333333333,
"value": {
"__uuid__": "7515ef50-3a14-4e58-8811-a0c890fc40f3"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "6e1139d4-03dd-4bd4-9510-606e94f629fe",
"subMetas": {}
}

View File

@@ -1,18 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<map version="1.2" tiledversion="1.2.3" orientation="orthogonal" renderorder="right-down" width="128" height="64" tilewidth="16" tileheight="16" infinite="0" nextlayerid="7" nextobjectid="135"> <map version="1.2" tiledversion="1.2.3" orientation="orthogonal" renderorder="right-down" width="128" height="64" tilewidth="16" tileheight="16" infinite="0" nextlayerid="7" nextobjectid="137">
<tileset firstgid="1" source="tiles0.tsx"/> <tileset firstgid="1" source="tiles0.tsx"/>
<tileset firstgid="65" source="tiles1.tsx"/> <tileset firstgid="65" source="tiles1.tsx"/>
<tileset firstgid="129" source="tiles2.tsx"/> <tileset firstgid="129" source="tiles2.tsx"/>
<layer id="6" name="Ground" width="128" height="64"> <layer id="6" name="Ground" width="128" height="64">
<data encoding="base64" compression="zlib"> <data encoding="base64" compression="zlib">
eJzt2ztuAjEURmELlIYuiKRHyk4iGjo2wP6XkRDGUmThxwx3fC3+U3wNw8v3eEyabEMIWwAAAAAAAAAAAADo4IQ/3h08+3t/B2/KM1BeOzPQXjsz0F47M6iv/c3oc6zeh/7+/Q+NHr1P6z7YGz2H/svWXur1TP/SvqL/OP1LnSz6t7Qt9a1dp//4/VvOgJJeM3hlLf2tzNljI83glY2+9vcMpRko9E/PgFz3NfbBKDNQ7r+kvdU+GHEGHv2/Gl9zNHrOKOh/t5vQX8dt7d+JeC19PDo2yr1+NHEG3i28+m8m8f6//jpnbAzkfsNr15eqfR/1+z/tfxP/Fvj/mFX/0dD/7pz0fsR69p8rmHv20D9vl5mZ1flb67VkP81pT/8QPialmT1z/5f2QK/7v7Q/6Z/vb6F0DvToXzuf1PvDv4Nn/4s4+mujvzb6a6O/Nvpro782+mujvzb6a6O/Nvpro782+mujvzb6a6O/Nvpro782+mujvzb6a6O/tvg/UN4t6E9/+tO/d3+s1/8HUhSy6A== eJzt201uwjAQhuEIxCY7KugeqTepumHXC/T+xyCqYimy4sQ4E2bE9y6eDf+e1w4bOHZddwQAAAAAAAAAAACAF/jBP+8Onv29P4M35Rkor50ZaK+dGWivnRlor50ZtK39UmnL5/owegz94/X/on8Ykfsv9V27n/72a0/drPqfBucZeeMSjxm8m5b+W1m9Dv3fv//c9eG88f3p397fytr1vNR9j31A/1hq21vtg4gziNz/ZvQY+vubrr0fefdv3QOt+0O9/3cm3ZffntwqlZ4fTZqBdwuv/odROv9/g3vBwUDpjFq8dst7q5//vP/0O2B6m1V/T/Qv979nvedY9/jcwTPXHPov9+lXZldjrb/1fqL/c/2vo6W5bTn/S3tg7/Nfsz/pX+5v+Z1L/3i8f3cdhXcHz/6/4uivjf7a6K+N/tror43+2uivjf7a6K+N/tror43+2uivjf7a6K+N/tror43+2uivjf7a6K+N/trSf6C8W9Cf/vSn/6v7Y7/+Dyz1uAA=
</data> </data>
</layer> </layer>
<objectgroup id="1" name="PlayerStartingPos"> <objectgroup id="1" name="PlayerStartingPos">
<object id="135" x="840" y="530"> <object id="135" x="1400" y="580">
<point/> <point/>
</object> </object>
<object id="137" x="959" y="532"> <object id="137" x="1500" y="580">
<point/> <point/>
</object> </object>
</objectgroup> </objectgroup>
@@ -64,7 +64,7 @@
<property name="boundary_type" value="barrier"/> <property name="boundary_type" value="barrier"/>
</properties> </properties>
</object> </object>
<object id="60" x="1232" y="432" width="208" height="16"> <object id="60" x="1232" y="448" width="208" height="16">
<properties> <properties>
<property name="boundary_type" value="barrier"/> <property name="boundary_type" value="barrier"/>
</properties> </properties>
@@ -99,7 +99,7 @@
<property name="boundary_type" value="barrier"/> <property name="boundary_type" value="barrier"/>
</properties> </properties>
</object> </object>
<object id="90" x="1232" y="496" width="320" height="16"> <object id="90" x="1248" y="464" width="320" height="16">
<properties> <properties>
<property name="boundary_type" value="barrier"/> <property name="boundary_type" value="barrier"/>
</properties> </properties>
@@ -114,37 +114,37 @@
<property name="boundary_type" value="barrier"/> <property name="boundary_type" value="barrier"/>
</properties> </properties>
</object> </object>
<object id="100" x="1552" y="576" width="128" height="16"> <object id="100" x="1538" y="560" width="144" height="32">
<properties> <properties>
<property name="boundary_type" value="barrier"/> <property name="boundary_type" value="barrier"/>
</properties> </properties>
</object> </object>
<object id="101" x="1568" y="560" width="112" height="16"> <object id="101" x="1568" y="528" width="112" height="32">
<properties> <properties>
<property name="boundary_type" value="barrier"/> <property name="boundary_type" value="barrier"/>
</properties> </properties>
</object> </object>
<object id="102" x="1584" y="544" width="96" height="16"> <object id="102" x="1136" y="368" width="96" height="16">
<properties> <properties>
<property name="boundary_type" value="barrier"/> <property name="boundary_type" value="barrier"/>
</properties> </properties>
</object> </object>
<object id="103" x="1600" y="528" width="80" height="16"> <object id="103" x="1600" y="496" width="80" height="32">
<properties> <properties>
<property name="boundary_type" value="barrier"/> <property name="boundary_type" value="barrier"/>
</properties> </properties>
</object> </object>
<object id="104" x="768" y="382" width="304" height="16"> <object id="104" x="816" y="414" width="304" height="16">
<properties> <properties>
<property name="boundary_type" value="barrier"/> <property name="boundary_type" value="barrier"/>
</properties> </properties>
</object> </object>
<object id="105" x="768" y="302" width="16" height="96"> <object id="105" x="816" y="366" width="16" height="64">
<properties> <properties>
<property name="boundary_type" value="barrier"/> <property name="boundary_type" value="barrier"/>
</properties> </properties>
</object> </object>
<object id="106" x="1056" y="302" width="16" height="96"> <object id="106" x="1104" y="334" width="16" height="96">
<properties> <properties>
<property name="boundary_type" value="barrier"/> <property name="boundary_type" value="barrier"/>
</properties> </properties>
@@ -164,42 +164,7 @@
<property name="boundary_type" value="barrier"/> <property name="boundary_type" value="barrier"/>
</properties> </properties>
</object> </object>
<object id="120" x="736" y="512" width="16" height="16"> <object id="136" x="1232" y="432" width="208" height="16">
<properties>
<property name="boundary_type" value="barrier"/>
</properties>
</object>
<object id="121" x="736" y="336" width="16" height="16">
<properties>
<property name="boundary_type" value="barrier"/>
</properties>
</object>
<object id="125" x="688" y="448" width="16" height="16">
<properties>
<property name="boundary_type" value="barrier"/>
</properties>
</object>
<object id="127" x="1088" y="320" width="16" height="16">
<properties>
<property name="boundary_type" value="barrier"/>
</properties>
</object>
<object id="128" x="1120" y="336" width="16" height="16">
<properties>
<property name="boundary_type" value="barrier"/>
</properties>
</object>
<object id="129" x="1136" y="368" width="16" height="16">
<properties>
<property name="boundary_type" value="barrier"/>
</properties>
</object>
<object id="130" x="1168" y="384" width="16" height="16">
<properties>
<property name="boundary_type" value="barrier"/>
</properties>
</object>
<object id="132" x="1184" y="416" width="16" height="16">
<properties> <properties>
<property name="boundary_type" value="barrier"/> <property name="boundary_type" value="barrier"/>
</properties> </properties>

View File

@@ -9,9 +9,9 @@ message PlayerDownsync {
int32 virtualGridX = 2; int32 virtualGridX = 2;
int32 virtualGridY = 3; int32 virtualGridY = 3;
int32 dirX = 4; int32 dirX = 4;
int32 dirY = 5; // "dirX" and "dirY" determines character facing int32 dirY = 5;
int32 velX = 6; int32 velX = 6;
int32 velY = 7; // "velX" and "velY" is used to record the accumulated effect by accelerations (including gravity) int32 velY = 7; // "velX" and "velY" is used to record the accumulated effect by inertia and accelerations (including gravity)
int32 speed = 8; // this is the instantaneous scalar attribute of a character, different from but will be accounted in "velX" and "velY" int32 speed = 8; // this is the instantaneous scalar attribute of a character, different from but will be accounted in "velX" and "velY"
int32 battleState = 9; int32 battleState = 9;
int32 joinIndex = 10; int32 joinIndex = 10;
@@ -36,6 +36,8 @@ message PlayerDownsync {
int32 onWallNormX = 27; int32 onWallNormX = 27;
int32 onWallNormY = 28; int32 onWallNormY = 28;
bool capturedByInertia = 29; // like "inAir", its by design a standalone field only inferred by the calc result of "applyInputFrameDownsyncDynamicsOnSingleRenderFrame" instead of "characterState"
string name = 997; string name = 997;
string displayName = 998; string displayName = 998;
string avatar = 999; string avatar = 999;
@@ -51,6 +53,7 @@ message InputFrameDecoded {
message InputFrameUpsync { message InputFrameUpsync {
int32 inputFrameId = 1; int32 inputFrameId = 1;
uint64 encoded = 2; uint64 encoded = 2;
int32 joinIndex = 3;
} }
message InputFrameDownsync { message InputFrameDownsync {
@@ -81,6 +84,7 @@ message WsResp {
RoomDownsyncFrame rdf = 4; RoomDownsyncFrame rdf = 4;
repeated InputFrameDownsync inputFrameDownsyncBatch = 5; repeated InputFrameDownsync inputFrameDownsyncBatch = 5;
BattleColliderInfo bciFrame = 6; BattleColliderInfo bciFrame = 6;
int32 peerJoinIndex = 7; // Only used when "InputsBufferSnapshot.peerJoinIndex" is used.
} }
message InputsBufferSnapshot { message InputsBufferSnapshot {
@@ -88,6 +92,7 @@ message InputsBufferSnapshot {
uint64 unconfirmedMask = 2; uint64 unconfirmedMask = 2;
repeated InputFrameDownsync toSendInputFrameDownsyncs = 3; repeated InputFrameDownsync toSendInputFrameDownsyncs = 3;
bool shouldForceResync = 4; bool shouldForceResync = 4;
int32 peerJoinIndex = 5; // Only used when "WsResp.peerJoinIndex" is used.
} }
message MeleeBullet { message MeleeBullet {

View File

@@ -482,6 +482,13 @@
}, },
{ {
"__uuid__": "e8247e2a-1b5b-4618-86f8-224b25246b55" "__uuid__": "e8247e2a-1b5b-4618-86f8-224b25246b55"
},
null,
null,
null,
null,
{
"__uuid__": "6e1139d4-03dd-4bd4-9510-606e94f629fe"
} }
], ],
"playOnLoad": false, "playOnLoad": false,
@@ -653,6 +660,9 @@
}, },
{ {
"__uuid__": "411f964a-4dd8-424c-b2e2-d92b10474ce2" "__uuid__": "411f964a-4dd8-424c-b2e2-d92b10474ce2"
},
{
"__uuid__": "e906322d-a08b-4477-a2e9-98acd42fa034"
} }
], ],
"playOnLoad": false, "playOnLoad": false,
@@ -822,6 +832,11 @@
}, },
{ {
"__uuid__": "0abbd156-980e-475e-9994-3c958bd913fc" "__uuid__": "0abbd156-980e-475e-9994-3c958bd913fc"
},
null,
null,
{
"__uuid__": "edd23b2f-1caa-4836-88a7-e4af1f26743e"
} }
], ],
"playOnLoad": false, "playOnLoad": false,

View File

@@ -8,7 +8,8 @@
"__id__": 1 "__id__": 1
}, },
"optimizationPolicy": 0, "optimizationPolicy": 0,
"asyncLoadAssets": false "asyncLoadAssets": false,
"readonly": false
}, },
{ {
"__type__": "cc.Node", "__type__": "cc.Node",
@@ -27,20 +28,19 @@
}, },
{ {
"__id__": 11 "__id__": 11
},
{
"__id__": 14
} }
], ],
"_active": true, "_active": true,
"_level": 1,
"_components": [ "_components": [
{ {
"__id__": 14 "__id__": 17
},
{
"__id__": 15
} }
], ],
"_prefab": { "_prefab": {
"__id__": 16 "__id__": 18
}, },
"_opacity": 255, "_opacity": 255,
"_color": { "_color": {
@@ -52,25 +52,14 @@
}, },
"_contentSize": { "_contentSize": {
"__type__": "cc.Size", "__type__": "cc.Size",
"width": 1024, "width": 960,
"height": 1920 "height": 640
}, },
"_anchorPoint": { "_anchorPoint": {
"__type__": "cc.Vec2", "__type__": "cc.Vec2",
"x": 0.5, "x": 0.5,
"y": 0.5 "y": 0.5
}, },
"_quat": {
"__type__": "cc.Quat",
"x": 0,
"y": 0,
"z": 0,
"w": 1
},
"_skewX": 0,
"_skewY": 0,
"groupIndex": 0,
"_id": "",
"_trs": { "_trs": {
"__type__": "TypedArray", "__type__": "TypedArray",
"ctor": "Float64Array", "ctor": "Float64Array",
@@ -86,18 +75,29 @@
1, 1,
1 1
] ]
} },
"_eulerAngles": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_skewX": 0,
"_skewY": 0,
"_is3DNode": false,
"_groupIndex": 0,
"groupIndex": 0,
"_id": ""
}, },
{ {
"__type__": "cc.Node", "__type__": "cc.Node",
"_name": "WhiteStars", "_name": "Background",
"_objFlags": 0, "_objFlags": 0,
"_parent": { "_parent": {
"__id__": 1 "__id__": 1
}, },
"_children": [], "_children": [],
"_active": true, "_active": true,
"_level": 2,
"_components": [ "_components": [
{ {
"__id__": 3 "__id__": 3
@@ -109,37 +109,26 @@
"_opacity": 255, "_opacity": 255,
"_color": { "_color": {
"__type__": "cc.Color", "__type__": "cc.Color",
"r": 255, "r": 0,
"g": 255, "g": 163,
"b": 255, "b": 255,
"a": 255 "a": 255
}, },
"_contentSize": { "_contentSize": {
"__type__": "cc.Size", "__type__": "cc.Size",
"width": 268, "width": 1920,
"height": 112 "height": 1280
}, },
"_anchorPoint": { "_anchorPoint": {
"__type__": "cc.Vec2", "__type__": "cc.Vec2",
"x": 0.5, "x": 0.5,
"y": 0.5 "y": 0.5
}, },
"_quat": {
"__type__": "cc.Quat",
"x": 0,
"y": 0,
"z": 0,
"w": 1
},
"_skewX": 0,
"_skewY": 0,
"groupIndex": 0,
"_id": "",
"_trs": { "_trs": {
"__type__": "TypedArray", "__type__": "TypedArray",
"ctor": "Float64Array", "ctor": "Float64Array",
"array": [ "array": [
-16, 0,
0, 0,
0, 0,
0, 0,
@@ -150,7 +139,19 @@
1, 1,
1 1
] ]
} },
"_eulerAngles": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_skewX": 0,
"_skewY": 0,
"_is3DNode": false,
"_groupIndex": 0,
"groupIndex": 0,
"_id": ""
}, },
{ {
"__type__": "cc.Sprite", "__type__": "cc.Sprite",
@@ -160,11 +161,18 @@
"__id__": 2 "__id__": 2
}, },
"_enabled": true, "_enabled": true,
"_materials": [
{
"__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432"
}
],
"_srcBlendFactor": 770,
"_dstBlendFactor": 771,
"_spriteFrame": { "_spriteFrame": {
"__uuid__": "1a2d934e-9d6d-45bf-83c6-564586cc8400" "__uuid__": "637f31c2-c53e-4dec-ae11-d56c0c6177ad"
}, },
"_type": 0, "_type": 0,
"_sizeMode": 1, "_sizeMode": 0,
"_fillType": 0, "_fillType": 0,
"_fillCenter": { "_fillCenter": {
"__type__": "cc.Vec2", "__type__": "cc.Vec2",
@@ -174,12 +182,9 @@
"_fillStart": 0, "_fillStart": 0,
"_fillRange": 0, "_fillRange": 0,
"_isTrimmedMode": true, "_isTrimmedMode": true,
"_state": 0,
"_atlas": { "_atlas": {
"__uuid__": "030d9286-e8a2-40cf-98f8-baf713f0b8c4" "__uuid__": "030d9286-e8a2-40cf-98f8-baf713f0b8c4"
}, },
"_srcBlendFactor": 770,
"_dstBlendFactor": 771,
"_id": "" "_id": ""
}, },
{ {
@@ -190,7 +195,7 @@
"asset": { "asset": {
"__uuid__": "230eeb1f-e0f9-4a41-ab6c-05b3771cbf3e" "__uuid__": "230eeb1f-e0f9-4a41-ab6c-05b3771cbf3e"
}, },
"fileId": "50Mjaee6xFXLrZ/mSBD3P5", "fileId": "83iQr+5XNNF5E2qjV+WUp0",
"sync": false "sync": false
}, },
{ {
@@ -202,7 +207,6 @@
}, },
"_children": [], "_children": [],
"_active": true, "_active": true,
"_level": 3,
"_components": [ "_components": [
{ {
"__id__": 6 "__id__": 6
@@ -229,17 +233,6 @@
"x": 0.5, "x": 0.5,
"y": 0.5 "y": 0.5
}, },
"_quat": {
"__type__": "cc.Quat",
"x": 0,
"y": 0,
"z": 0,
"w": 1
},
"_skewX": 0,
"_skewY": 0,
"groupIndex": 0,
"_id": "",
"_trs": { "_trs": {
"__type__": "TypedArray", "__type__": "TypedArray",
"ctor": "Float64Array", "ctor": "Float64Array",
@@ -255,7 +248,19 @@
1, 1,
1 1
] ]
} },
"_eulerAngles": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_skewX": 0,
"_skewY": 0,
"_is3DNode": false,
"_groupIndex": 0,
"groupIndex": 0,
"_id": ""
}, },
{ {
"__type__": "cc.Sprite", "__type__": "cc.Sprite",
@@ -265,6 +270,13 @@
"__id__": 5 "__id__": 5
}, },
"_enabled": true, "_enabled": true,
"_materials": [
{
"__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432"
}
],
"_srcBlendFactor": 770,
"_dstBlendFactor": 771,
"_spriteFrame": { "_spriteFrame": {
"__uuid__": "75a2c1e3-2c22-480c-9572-eb65f4a554e1" "__uuid__": "75a2c1e3-2c22-480c-9572-eb65f4a554e1"
}, },
@@ -279,12 +291,9 @@
"_fillStart": 0, "_fillStart": 0,
"_fillRange": 0, "_fillRange": 0,
"_isTrimmedMode": true, "_isTrimmedMode": true,
"_state": 0,
"_atlas": { "_atlas": {
"__uuid__": "030d9286-e8a2-40cf-98f8-baf713f0b8c4" "__uuid__": "030d9286-e8a2-40cf-98f8-baf713f0b8c4"
}, },
"_srcBlendFactor": 770,
"_dstBlendFactor": 771,
"_id": "" "_id": ""
}, },
{ {
@@ -307,7 +316,6 @@
}, },
"_children": [], "_children": [],
"_active": true, "_active": true,
"_level": 2,
"_components": [ "_components": [
{ {
"__id__": 9 "__id__": 9
@@ -327,24 +335,13 @@
"_contentSize": { "_contentSize": {
"__type__": "cc.Size", "__type__": "cc.Size",
"width": 111.23, "width": 111.23,
"height": 200 "height": 252
}, },
"_anchorPoint": { "_anchorPoint": {
"__type__": "cc.Vec2", "__type__": "cc.Vec2",
"x": 0.5, "x": 0.5,
"y": 0.5 "y": 0.5
}, },
"_quat": {
"__type__": "cc.Quat",
"x": 0,
"y": 0,
"z": 0,
"w": 1
},
"_skewX": 0,
"_skewY": 0,
"groupIndex": 0,
"_id": "",
"_trs": { "_trs": {
"__type__": "TypedArray", "__type__": "TypedArray",
"ctor": "Float64Array", "ctor": "Float64Array",
@@ -360,7 +357,19 @@
0.66667, 0.66667,
0.66667 0.66667
] ]
} },
"_eulerAngles": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_skewX": 0,
"_skewY": 0,
"_is3DNode": false,
"_groupIndex": 0,
"groupIndex": 0,
"_id": ""
}, },
{ {
"__type__": "cc.Label", "__type__": "cc.Label",
@@ -370,6 +379,11 @@
"__id__": 8 "__id__": 8
}, },
"_enabled": true, "_enabled": true,
"_materials": [
{
"__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432"
}
],
"_useOriginalSize": false, "_useOriginalSize": false,
"_string": "3", "_string": "3",
"_N$string": "3", "_N$string": "3",
@@ -407,7 +421,6 @@
}, },
"_children": [], "_children": [],
"_active": true, "_active": true,
"_level": 2,
"_components": [ "_components": [
{ {
"__id__": 12 "__id__": 12
@@ -434,17 +447,6 @@
"x": 0.5, "x": 0.5,
"y": 0.5 "y": 0.5
}, },
"_quat": {
"__type__": "cc.Quat",
"x": 0,
"y": 0,
"z": 0,
"w": 1
},
"_skewX": 0,
"_skewY": 0,
"groupIndex": 0,
"_id": "",
"_trs": { "_trs": {
"__type__": "TypedArray", "__type__": "TypedArray",
"ctor": "Float64Array", "ctor": "Float64Array",
@@ -460,7 +462,19 @@
1, 1,
1 1
] ]
} },
"_eulerAngles": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_skewX": 0,
"_skewY": 0,
"_is3DNode": false,
"_groupIndex": 0,
"groupIndex": 0,
"_id": ""
}, },
{ {
"__type__": "cc.Sprite", "__type__": "cc.Sprite",
@@ -470,6 +484,13 @@
"__id__": 11 "__id__": 11
}, },
"_enabled": true, "_enabled": true,
"_materials": [
{
"__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432"
}
],
"_srcBlendFactor": 770,
"_dstBlendFactor": 771,
"_spriteFrame": { "_spriteFrame": {
"__uuid__": "637f31c2-c53e-4dec-ae11-d56c0c6177ad" "__uuid__": "637f31c2-c53e-4dec-ae11-d56c0c6177ad"
}, },
@@ -484,12 +505,9 @@
"_fillStart": 0, "_fillStart": 0,
"_fillRange": 0, "_fillRange": 0,
"_isTrimmedMode": true, "_isTrimmedMode": true,
"_state": 0,
"_atlas": { "_atlas": {
"__uuid__": "030d9286-e8a2-40cf-98f8-baf713f0b8c4" "__uuid__": "030d9286-e8a2-40cf-98f8-baf713f0b8c4"
}, },
"_srcBlendFactor": 770,
"_dstBlendFactor": 771,
"_id": "" "_id": ""
}, },
{ {
@@ -503,6 +521,115 @@
"fileId": "21dxpL7zlKIIDhUt+GIMbg", "fileId": "21dxpL7zlKIIDhUt+GIMbg",
"sync": false "sync": false
}, },
{
"__type__": "cc.Node",
"_name": "WhiteStars",
"_objFlags": 0,
"_parent": {
"__id__": 1
},
"_children": [],
"_active": true,
"_components": [
{
"__id__": 15
}
],
"_prefab": {
"__id__": 16
},
"_opacity": 255,
"_color": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_contentSize": {
"__type__": "cc.Size",
"width": 268,
"height": 112
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_trs": {
"__type__": "TypedArray",
"ctor": "Float64Array",
"array": [
-16,
0,
0,
0,
0,
0,
1,
1,
1,
1
]
},
"_eulerAngles": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_skewX": 0,
"_skewY": 0,
"_is3DNode": false,
"_groupIndex": 0,
"groupIndex": 0,
"_id": ""
},
{
"__type__": "cc.Sprite",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 14
},
"_enabled": true,
"_materials": [
{
"__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432"
}
],
"_srcBlendFactor": 770,
"_dstBlendFactor": 771,
"_spriteFrame": {
"__uuid__": "1a2d934e-9d6d-45bf-83c6-564586cc8400"
},
"_type": 0,
"_sizeMode": 1,
"_fillType": 0,
"_fillCenter": {
"__type__": "cc.Vec2",
"x": 0,
"y": 0
},
"_fillStart": 0,
"_fillRange": 0,
"_isTrimmedMode": true,
"_atlas": {
"__uuid__": "030d9286-e8a2-40cf-98f8-baf713f0b8c4"
},
"_id": ""
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__uuid__": "230eeb1f-e0f9-4a41-ab6c-05b3771cbf3e"
},
"fileId": "50Mjaee6xFXLrZ/mSBD3P5",
"sync": false
},
{ {
"__type__": "6a3d6Y6Ki1BiqAVSKIRdwRl", "__type__": "6a3d6Y6Ki1BiqAVSKIRdwRl",
"_name": "", "_name": "",
@@ -516,34 +643,6 @@
}, },
"_id": "" "_id": ""
}, },
{
"__type__": "cc.Sprite",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 1
},
"_enabled": true,
"_spriteFrame": {
"__uuid__": "334d4f93-b007-49e8-9268-35891d4f4ebb"
},
"_type": 0,
"_sizeMode": 1,
"_fillType": 0,
"_fillCenter": {
"__type__": "cc.Vec2",
"x": 0,
"y": 0
},
"_fillStart": 0,
"_fillRange": 0,
"_isTrimmedMode": true,
"_state": 0,
"_atlas": null,
"_srcBlendFactor": 770,
"_dstBlendFactor": 771,
"_id": ""
},
{ {
"__type__": "cc.PrefabInfo", "__type__": "cc.PrefabInfo",
"root": { "root": {

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{ {
"ver": "1.2.5", "ver": "1.2.5",
"uuid": "3ed4c7bc-79d0-4075-a563-d5a58ae798f9", "uuid": "dc804c5c-ff76-445e-ac69-52269055c3c5",
"optimizationPolicy": "AUTO", "optimizationPolicy": "AUTO",
"asyncLoadAssets": false, "asyncLoadAssets": false,
"readonly": false, "readonly": false,

View File

@@ -21,20 +21,20 @@
"__id__": 2 "__id__": 2
}, },
{ {
"__id__": 10 "__id__": 5
} }
], ],
"_active": true, "_active": true,
"_components": [ "_components": [
{ {
"__id__": 13 "__id__": 12
}, },
{ {
"__id__": 14 "__id__": 13
} }
], ],
"_prefab": { "_prefab": {
"__id__": 15 "__id__": 14
}, },
"_opacity": 255, "_opacity": 255,
"_color": { "_color": {
@@ -46,8 +46,72 @@
}, },
"_contentSize": { "_contentSize": {
"__type__": "cc.Size", "__type__": "cc.Size",
"width": 1024, "width": 960,
"height": 1920 "height": 640
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_trs": {
"__type__": "TypedArray",
"ctor": "Float64Array",
"array": [
480,
320,
0,
0,
0,
0,
1,
1,
1,
1
]
},
"_eulerAngles": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_skewX": 0,
"_skewY": 0,
"_is3DNode": false,
"_groupIndex": 0,
"groupIndex": 0,
"_id": ""
},
{
"__type__": "cc.Node",
"_name": "Background",
"_objFlags": 0,
"_parent": {
"__id__": 1
},
"_children": [],
"_active": true,
"_components": [
{
"__id__": 3
}
],
"_prefab": {
"__id__": 4
},
"_opacity": 255,
"_color": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_contentSize": {
"__type__": "cc.Size",
"width": 1920,
"height": 1280
}, },
"_anchorPoint": { "_anchorPoint": {
"__type__": "cc.Vec2", "__type__": "cc.Vec2",
@@ -83,6 +147,51 @@
"groupIndex": 0, "groupIndex": 0,
"_id": "" "_id": ""
}, },
{
"__type__": "cc.Sprite",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 2
},
"_enabled": true,
"_materials": [
{
"__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432"
}
],
"_srcBlendFactor": 770,
"_dstBlendFactor": 771,
"_spriteFrame": {
"__uuid__": "637f31c2-c53e-4dec-ae11-d56c0c6177ad"
},
"_type": 0,
"_sizeMode": 0,
"_fillType": 0,
"_fillCenter": {
"__type__": "cc.Vec2",
"x": 0,
"y": 0
},
"_fillStart": 0,
"_fillRange": 0,
"_isTrimmedMode": true,
"_atlas": {
"__uuid__": "030d9286-e8a2-40cf-98f8-baf713f0b8c4"
},
"_id": ""
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__uuid__": "32b8e752-8362-4783-a4a6-1160af8b7109"
},
"fileId": "a7oR1cZvVO/pp9QJgLnJyt",
"sync": false
},
{ {
"__type__": "cc.Node", "__type__": "cc.Node",
"_name": "modeButton", "_name": "modeButton",
@@ -92,20 +201,20 @@
}, },
"_children": [ "_children": [
{ {
"__id__": 3 "__id__": 6
} }
], ],
"_active": true, "_active": true,
"_components": [ "_components": [
{ {
"__id__": 7 "__id__": 9
}, },
{ {
"__id__": 8 "__id__": 10
} }
], ],
"_prefab": { "_prefab": {
"__id__": 9 "__id__": 11
}, },
"_opacity": 255, "_opacity": 255,
"_color": { "_color": {
@@ -117,8 +226,8 @@
}, },
"_contentSize": { "_contentSize": {
"__type__": "cc.Size", "__type__": "cc.Size",
"width": 280, "width": 240,
"height": 130 "height": 100
}, },
"_anchorPoint": { "_anchorPoint": {
"__type__": "cc.Vec2", "__type__": "cc.Vec2",
@@ -130,7 +239,7 @@
"ctor": "Float64Array", "ctor": "Float64Array",
"array": [ "array": [
0, 0,
-564, -90.495,
0, 0,
0, 0,
0, 0,
@@ -159,20 +268,17 @@
"_name": "Label", "_name": "Label",
"_objFlags": 0, "_objFlags": 0,
"_parent": { "_parent": {
"__id__": 2 "__id__": 5
}, },
"_children": [], "_children": [],
"_active": true, "_active": true,
"_components": [ "_components": [
{ {
"__id__": 4 "__id__": 7
},
{
"__id__": 5
} }
], ],
"_prefab": { "_prefab": {
"__id__": 6 "__id__": 8
}, },
"_opacity": 255, "_opacity": 255,
"_color": { "_color": {
@@ -226,7 +332,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 3 "__id__": 6
}, },
"_enabled": true, "_enabled": true,
"_materials": [ "_materials": [
@@ -235,8 +341,8 @@
} }
], ],
"_useOriginalSize": false, "_useOriginalSize": false,
"_string": "gameRule.mode", "_string": "1 v 1",
"_N$string": "gameRule.mode", "_N$string": "1 v 1",
"_fontSize": 55, "_fontSize": 55,
"_lineHeight": 50, "_lineHeight": 50,
"_enableWrapText": false, "_enableWrapText": false,
@@ -251,17 +357,6 @@
"_N$cacheMode": 0, "_N$cacheMode": 0,
"_id": "" "_id": ""
}, },
{
"__type__": "744dcs4DCdNprNhG0xwq6FK",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 3
},
"_enabled": true,
"_dataID": "gameRule.mode",
"_id": ""
},
{ {
"__type__": "cc.PrefabInfo", "__type__": "cc.PrefabInfo",
"root": { "root": {
@@ -278,7 +373,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 2 "__id__": 5
}, },
"_enabled": true, "_enabled": true,
"_materials": [ "_materials": [
@@ -312,7 +407,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 2 "__id__": 5
}, },
"_enabled": true, "_enabled": true,
"_normalMaterial": null, "_normalMaterial": null,
@@ -375,7 +470,7 @@
"hoverSprite": null, "hoverSprite": null,
"_N$disabledSprite": null, "_N$disabledSprite": null,
"_N$target": { "_N$target": {
"__id__": 2 "__id__": 5
}, },
"_id": "" "_id": ""
}, },
@@ -390,115 +485,6 @@
"fileId": "c54lqSflFD8ogSYAhsAkKh", "fileId": "c54lqSflFD8ogSYAhsAkKh",
"sync": false "sync": false
}, },
{
"__type__": "cc.Node",
"_name": "decoration",
"_objFlags": 0,
"_parent": {
"__id__": 1
},
"_children": [],
"_active": true,
"_components": [
{
"__id__": 11
}
],
"_prefab": {
"__id__": 12
},
"_opacity": 255,
"_color": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_contentSize": {
"__type__": "cc.Size",
"width": 543,
"height": 117
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_trs": {
"__type__": "TypedArray",
"ctor": "Float64Array",
"array": [
0,
-312,
0,
0,
0,
0,
1,
1,
1,
1
]
},
"_eulerAngles": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_skewX": 0,
"_skewY": 0,
"_is3DNode": false,
"_groupIndex": 0,
"groupIndex": 0,
"_id": ""
},
{
"__type__": "cc.Sprite",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 10
},
"_enabled": true,
"_materials": [
{
"__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432"
}
],
"_srcBlendFactor": 770,
"_dstBlendFactor": 771,
"_spriteFrame": {
"__uuid__": "153d890a-fc37-4d59-8779-93a8fb19fa85"
},
"_type": 0,
"_sizeMode": 1,
"_fillType": 0,
"_fillCenter": {
"__type__": "cc.Vec2",
"x": 0,
"y": 0
},
"_fillStart": 0,
"_fillRange": 0,
"_isTrimmedMode": true,
"_atlas": {
"__uuid__": "030d9286-e8a2-40cf-98f8-baf713f0b8c4"
},
"_id": ""
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__uuid__": "32b8e752-8362-4783-a4a6-1160af8b7109"
},
"fileId": "1bbMLAzntHZpEudL8lM/Lx",
"sync": false
},
{ {
"__type__": "dd92bKVy8FJY7uq3ieoNZCZ", "__type__": "dd92bKVy8FJY7uq3ieoNZCZ",
"_name": "", "_name": "",
@@ -508,41 +494,36 @@
}, },
"_enabled": true, "_enabled": true,
"modeButton": { "modeButton": {
"__id__": 8 "__id__": 10
}, },
"mapNode": null, "mapNode": null,
"_id": "" "_id": ""
}, },
{ {
"__type__": "cc.Sprite", "__type__": "cc.Widget",
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 1 "__id__": 1
}, },
"_enabled": true, "_enabled": true,
"_materials": [ "alignMode": 1,
{ "_target": null,
"__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432" "_alignFlags": 18,
} "_left": 0,
], "_right": 0,
"_srcBlendFactor": 770, "_top": 0,
"_dstBlendFactor": 771, "_bottom": 0,
"_spriteFrame": { "_verticalCenter": 0,
"__uuid__": "7838f276-ab48-445a-b858-937dd27d9520" "_horizontalCenter": 0,
}, "_isAbsLeft": true,
"_type": 0, "_isAbsRight": true,
"_sizeMode": 0, "_isAbsTop": true,
"_fillType": 0, "_isAbsBottom": true,
"_fillCenter": { "_isAbsHorizontalCenter": true,
"__type__": "cc.Vec2", "_isAbsVerticalCenter": true,
"x": 0, "_originalWidth": 0,
"y": 0 "_originalHeight": 0,
},
"_fillStart": 0,
"_fillRange": 0,
"_isTrimmedMode": true,
"_atlas": null,
"_id": "" "_id": ""
}, },
{ {

View File

@@ -8,7 +8,8 @@
"__id__": 1 "__id__": 1
}, },
"optimizationPolicy": 0, "optimizationPolicy": 0,
"asyncLoadAssets": false "asyncLoadAssets": false,
"readonly": false
}, },
{ {
"__type__": "cc.Node", "__type__": "cc.Node",
@@ -20,18 +21,17 @@
"__id__": 2 "__id__": 2
}, },
{ {
"__id__": 6 "__id__": 5
} }
], ],
"_active": true, "_active": true,
"_level": 1,
"_components": [ "_components": [
{ {
"__id__": 9 "__id__": 8
} }
], ],
"_prefab": { "_prefab": {
"__id__": 10 "__id__": 9
}, },
"_opacity": 255, "_opacity": 255,
"_color": { "_color": {
@@ -51,24 +51,12 @@
"x": 0.5, "x": 0.5,
"y": 0.5 "y": 0.5
}, },
"_quat": {
"__type__": "cc.Quat",
"x": 0,
"y": 0,
"z": 0,
"w": 1
},
"_skewX": 0,
"_skewY": 0,
"_zIndex": 0,
"groupIndex": 0,
"_id": "",
"_trs": { "_trs": {
"__type__": "TypedArray", "__type__": "TypedArray",
"ctor": "Float64Array", "ctor": "Float64Array",
"array": [ "array": [
512, 480,
0, 480,
0, 0,
0, 0,
0, 0,
@@ -78,7 +66,19 @@
1, 1,
1 1
] ]
} },
"_eulerAngles": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_skewX": 0,
"_skewY": 0,
"_is3DNode": false,
"_groupIndex": 0,
"groupIndex": 0,
"_id": ""
}, },
{ {
"__type__": "cc.Node", "__type__": "cc.Node",
@@ -89,17 +89,13 @@
}, },
"_children": [], "_children": [],
"_active": true, "_active": true,
"_level": 0,
"_components": [ "_components": [
{ {
"__id__": 3 "__id__": 3
},
{
"__id__": 4
} }
], ],
"_prefab": { "_prefab": {
"__id__": 5 "__id__": 4
}, },
"_opacity": 255, "_opacity": 255,
"_color": { "_color": {
@@ -111,32 +107,20 @@
}, },
"_contentSize": { "_contentSize": {
"__type__": "cc.Size", "__type__": "cc.Size",
"width": 303.5, "width": 805.7,
"height": 30 "height": 35.28
}, },
"_anchorPoint": { "_anchorPoint": {
"__type__": "cc.Vec2", "__type__": "cc.Vec2",
"x": 0.5, "x": 0.5,
"y": 0.5 "y": 0.5
}, },
"_quat": {
"__type__": "cc.Quat",
"x": 0,
"y": 0,
"z": 0,
"w": 1
},
"_skewX": 0,
"_skewY": 0,
"_zIndex": 0,
"groupIndex": 0,
"_id": "",
"_trs": { "_trs": {
"__type__": "TypedArray", "__type__": "TypedArray",
"ctor": "Float64Array", "ctor": "Float64Array",
"array": [ "array": [
0, 0,
210, -150,
0, 0,
0, 0,
0, 0,
@@ -146,7 +130,19 @@
1, 1,
1 1
] ]
} },
"_eulerAngles": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_skewX": 0,
"_skewY": 0,
"_is3DNode": false,
"_groupIndex": 0,
"groupIndex": 0,
"_id": ""
}, },
{ {
"__type__": "cc.Label", "__type__": "cc.Label",
@@ -156,32 +152,26 @@
"__id__": 2 "__id__": 2
}, },
"_enabled": true, "_enabled": true,
"_srcBlendFactor": 1, "_materials": [
"_dstBlendFactor": 771, {
"__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432"
}
],
"_useOriginalSize": false, "_useOriginalSize": false,
"_string": "login.tips.loginSuccess", "_string": "Logged in successfully, loading game resources...",
"_N$string": "login.tips.loginSuccess", "_N$string": "Logged in successfully, loading game resources...",
"_fontSize": 30, "_fontSize": 28,
"_lineHeight": 30, "_lineHeight": 28,
"_enableWrapText": true, "_enableWrapText": true,
"_N$file": null, "_N$file": null,
"_isSystemFontUsed": true, "_isSystemFontUsed": true,
"_spacingX": 0, "_spacingX": 0,
"_batchAsBitmap": false,
"_N$horizontalAlign": 1, "_N$horizontalAlign": 1,
"_N$verticalAlign": 1, "_N$verticalAlign": 1,
"_N$fontFamily": "Arial", "_N$fontFamily": "Arial",
"_N$overflow": 0, "_N$overflow": 3,
"_id": "" "_N$cacheMode": 0,
},
{
"__type__": "744dcs4DCdNprNhG0xwq6FK",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 2
},
"_enabled": true,
"_dataID": "login.tips.loginSuccess",
"_id": "" "_id": ""
}, },
{ {
@@ -204,14 +194,13 @@
}, },
"_children": [], "_children": [],
"_active": true, "_active": true,
"_level": 0,
"_components": [ "_components": [
{ {
"__id__": 7 "__id__": 6
} }
], ],
"_prefab": { "_prefab": {
"__id__": 8 "__id__": 7
}, },
"_opacity": 255, "_opacity": 255,
"_color": { "_color": {
@@ -231,24 +220,12 @@
"x": 0.5, "x": 0.5,
"y": 0.5 "y": 0.5
}, },
"_quat": {
"__type__": "cc.Quat",
"x": 0,
"y": 0,
"z": 0,
"w": 1
},
"_skewX": 0,
"_skewY": 0,
"_zIndex": 0,
"groupIndex": 0,
"_id": "",
"_trs": { "_trs": {
"__type__": "TypedArray", "__type__": "TypedArray",
"ctor": "Float64Array", "ctor": "Float64Array",
"array": [ "array": [
0, 0,
333, 0,
0, 0,
0, 0,
0, 0,
@@ -258,16 +235,29 @@
1, 1,
1 1
] ]
} },
"_eulerAngles": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_skewX": 0,
"_skewY": 0,
"_is3DNode": false,
"_groupIndex": 0,
"groupIndex": 0,
"_id": ""
}, },
{ {
"__type__": "cc.Sprite", "__type__": "cc.Sprite",
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 6 "__id__": 5
}, },
"_enabled": true, "_enabled": true,
"_materials": [],
"_srcBlendFactor": 770, "_srcBlendFactor": 770,
"_dstBlendFactor": 771, "_dstBlendFactor": 771,
"_spriteFrame": null, "_spriteFrame": null,
@@ -282,7 +272,6 @@
"_fillStart": 0, "_fillStart": 0,
"_fillRange": 0, "_fillRange": 0,
"_isTrimmedMode": true, "_isTrimmedMode": true,
"_state": 0,
"_atlas": null, "_atlas": null,
"_id": "" "_id": ""
}, },
@@ -307,7 +296,7 @@
"_enabled": true, "_enabled": true,
"alignMode": 0, "alignMode": 0,
"_target": null, "_target": null,
"_alignFlags": 20, "_alignFlags": 18,
"_left": 0, "_left": 0,
"_right": 0, "_right": 0,
"_top": 0, "_top": 0,

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 121 KiB

View File

@@ -1,34 +0,0 @@
{
"ver": "2.3.3",
"uuid": "825df908-a4cb-449d-9731-8ef53f3fd44f",
"type": "sprite",
"wrapMode": "clamp",
"filterMode": "bilinear",
"premultiplyAlpha": false,
"genMipmaps": false,
"packable": true,
"platformSettings": {},
"subMetas": {
"MiniGame_Background": {
"ver": "1.0.4",
"uuid": "7838f276-ab48-445a-b858-937dd27d9520",
"rawTextureUuid": "825df908-a4cb-449d-9731-8ef53f3fd44f",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 0,
"trimY": 0,
"width": 750,
"height": 1624,
"rawWidth": 750,
"rawHeight": 1624,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"subMetas": {}
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

View File

@@ -1,34 +0,0 @@
{
"ver": "2.3.3",
"uuid": "94b8bb09-e8ac-4402-a933-b79f01b5a813",
"type": "sprite",
"wrapMode": "clamp",
"filterMode": "bilinear",
"premultiplyAlpha": false,
"genMipmaps": false,
"packable": true,
"platformSettings": {},
"subMetas": {
"MiniGame_Blackboard": {
"ver": "1.0.4",
"uuid": "334d4f93-b007-49e8-9268-35891d4f4ebb",
"rawTextureUuid": "94b8bb09-e8ac-4402-a933-b79f01b5a813",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 0,
"trimY": 0,
"width": 1024,
"height": 1920,
"rawWidth": 1024,
"rawHeight": 1920,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"subMetas": {}
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -18,6 +18,7 @@ window.ATK_CHARACTER_STATE = {
Atk5: [14, "Atk5"], Atk5: [14, "Atk5"],
Dashing: [15, "Dashing"], Dashing: [15, "Dashing"],
OnWall: [16, "OnWall"], OnWall: [16, "OnWall"],
TurnAround1: [17, "TurnAround1"],
}; };
window.ATK_CHARACTER_STATE_ARR = []; window.ATK_CHARACTER_STATE_ARR = [];
@@ -93,7 +94,7 @@ cc.Class({
} else if (0 < rdfPlayer.DirX) { } else if (0 < rdfPlayer.DirX) {
this.animNode.scaleX = (+1.0); this.animNode.scaleX = (+1.0);
} }
if (ATK_CHARACTER_STATE.OnWall[0] == newCharacterState) { if (ATK_CHARACTER_STATE.OnWall[0] == newCharacterState || ATK_CHARACTER_STATE.TurnAround1[0] == newCharacterState) {
if (0 < rdfPlayer.OnWallNormX) { if (0 < rdfPlayer.OnWallNormX) {
this.animNode.scaleX = (-1.0); this.animNode.scaleX = (-1.0);
} else { } else {

View File

@@ -14,10 +14,6 @@ cc.Class({
type: cc.Node, type: cc.Node,
default: null default: null
}, },
myAvatarNode: {
type: cc.Node,
default: null
},
exitBtnNode: { exitBtnNode: {
type: cc.Node, type: cc.Node,
default: null default: null
@@ -25,8 +21,7 @@ cc.Class({
}, },
// LIFE-CYCLE CALLBACKS: // LIFE-CYCLE CALLBACKS:
onLoad() { onLoad() {},
},
init() { init() {
if (null != this.firstPlayerInfoNode) { if (null != this.firstPlayerInfoNode) {
@@ -79,20 +74,11 @@ cc.Class({
} }
} }
//显示自己的头像名称以及他人的头像名称
for (let i in playerMetas) { for (let i in playerMetas) {
const playerMeta = playerMetas[i]; const playerMeta = playerMetas[i];
console.log("Showing playerMeta:", playerMeta); console.log("Showing playerMeta:", playerMeta);
const playerInfoNode = this.playersInfoNode[playerMeta.joinIndex]; const playerInfoNode = this.playersInfoNode[playerMeta.joinIndex];
(() => { //远程加载头像
let remoteUrl = playerMeta.avatar;
if (remoteUrl == null || remoteUrl == '') {
cc.log(`No avatar to show for :`);
cc.log(playerMeta);
}
})();
function isEmptyString(str) { function isEmptyString(str) {
return str == null || str == '' return str == null || str == ''
} }

View File

@@ -68,6 +68,8 @@ cc.Class({
// LIFE-CYCLE CALLBACKS: // LIFE-CYCLE CALLBACKS:
onLoad() { onLoad() {
cc.view.setOrientation(cc.macro.ORIENTATION_AUTO);
cc.view.enableAutoFullScreen(true);
window.atFirstLocationHref = window.location.href.split('#')[0]; window.atFirstLocationHref = window.location.href.split('#')[0];
const self = this; const self = this;

View File

@@ -2,6 +2,7 @@ const i18n = require('LanguageData');
i18n.init(window.language); // languageID should be equal to the one we input in New Language ID input field i18n.init(window.language); // languageID should be equal to the one we input in New Language ID input field
const RingBuffer = require('./RingBuffer'); const RingBuffer = require('./RingBuffer');
const NetworkDoctor = require('./NetworkDoctor');
const PriorityQueue = require("./PriorityQueue"); const PriorityQueue = require("./PriorityQueue");
window.ALL_MAP_STATES = { window.ALL_MAP_STATES = {
@@ -96,16 +97,26 @@ cc.Class({
type: cc.Integer, type: cc.Integer,
default: 4 // implies (renderFrameIdLagTolerance >> inputScaleFrames) count of inputFrameIds default: 4 // implies (renderFrameIdLagTolerance >> inputScaleFrames) count of inputFrameIds
}, },
jigglingEps1D: { sendingQLabel: {
type: cc.Float, type: cc.Label,
default: 1e-3 default: null
}, },
bulletTriggerEnabled: { inputFrameDownsyncQLabel: {
default: false type: cc.Label,
default: null
}, },
closeOnForcedtoResyncNotSelf: { peerInputFrameUpsyncQLabel: {
default: true type: cc.Label,
default: null
}, },
rollbackFramesLabel: {
type: cc.Label,
default: null
},
skippedRenderFrameCntLabel: {
type: cc.Label,
default: null
}
}, },
_inputFrameIdDebuggable(inputFrameId) { _inputFrameIdDebuggable(inputFrameId) {
@@ -152,7 +163,6 @@ cc.Class({
prefabbedInputList[k] = (prefabbedInputList[k] & 15); prefabbedInputList[k] = (prefabbedInputList[k] & 15);
} }
currSelfInput = self.ctrl.getEncodedInput(); // When "null == existingInputFrame", it'd be safe to say that the realtime "self.ctrl.getEncodedInput()" is for the requested "inputFrameId" currSelfInput = self.ctrl.getEncodedInput(); // When "null == existingInputFrame", it'd be safe to say that the realtime "self.ctrl.getEncodedInput()" is for the requested "inputFrameId"
//console.log(`@rdf.Id=${self.renderFrameId}, currSelfInput=${currSelfInput}`);
prefabbedInputList[(joinIndex - 1)] = currSelfInput; prefabbedInputList[(joinIndex - 1)] = currSelfInput;
while (self.recentInputCache.EdFrameId <= inputFrameId) { while (self.recentInputCache.EdFrameId <= inputFrameId) {
// Fill the gap // Fill the gap
@@ -185,6 +195,7 @@ cc.Class({
// Upon resync, "self.lastUpsyncInputFrameId" might not have been updated properly. // Upon resync, "self.lastUpsyncInputFrameId" might not have been updated properly.
batchInputFrameIdSt = self.recentInputCache.StFrameId; batchInputFrameIdSt = self.recentInputCache.StFrameId;
} }
self.networkDoctor.logSending(batchInputFrameIdSt, latestLocalInputFrameId);
for (let i = batchInputFrameIdSt; i <= latestLocalInputFrameId; ++i) { for (let i = batchInputFrameIdSt; i <= latestLocalInputFrameId; ++i) {
const inputFrameDownsync = self.recentInputCache.GetByFrameId(i); const inputFrameDownsync = self.recentInputCache.GetByFrameId(i);
if (null == inputFrameDownsync) { if (null == inputFrameDownsync) {
@@ -309,7 +320,7 @@ cc.Class({
const newFireball = newFireballNode.getComponent("Fireball"); const newFireball = newFireballNode.getComponent("Fireball");
newFireballNode.setPosition(cc.v2(Number.MAX_VALUE, Number.MAX_VALUE)); newFireballNode.setPosition(cc.v2(Number.MAX_VALUE, Number.MAX_VALUE));
safelyAddChild(self.node, newFireballNode); safelyAddChild(self.node, newFireballNode);
setLocalZOrder(newFireballNode, 5); setLocalZOrder(newFireballNode, 10);
newFireball.lastUsed = -1; newFireball.lastUsed = -1;
newFireball.bulletLocalId = -1; newFireball.bulletLocalId = -1;
const initLookupKey = -(k + 1); // there's definitely no suck "bulletLocalId" const initLookupKey = -(k + 1); // there's definitely no suck "bulletLocalId"
@@ -343,6 +354,9 @@ cc.Class({
self.othersForcedDownsyncRenderFrameDict = new Map(); self.othersForcedDownsyncRenderFrameDict = new Map();
self.rdfIdToActuallyUsedInput = new Map(); self.rdfIdToActuallyUsedInput = new Map();
self.networkDoctor = new NetworkDoctor(20);
self.skipRenderFrameFlag = false;
self.countdownNanos = null; self.countdownNanos = null;
if (self.countdownLabel) { if (self.countdownLabel) {
self.countdownLabel.string = ""; self.countdownLabel.string = "";
@@ -410,11 +424,16 @@ cc.Class({
}, },
onLoad() { onLoad() {
cc.game.setFrameRate(60);
cc.view.setOrientation(cc.macro.ORIENTATION_LANDSCAPE);
cc.view.enableAutoFullScreen(true);
const self = this; const self = this;
window.mapIns = self; window.mapIns = self;
window.forceBigEndianFloatingNumDecoding = self.forceBigEndianFloatingNumDecoding; window.forceBigEndianFloatingNumDecoding = self.forceBigEndianFloatingNumDecoding;
self.showCriticalCoordinateLabels = false; self.showCriticalCoordinateLabels = false;
self.showNetworkDoctorInfo = true;
console.warn("+++++++ Map onLoad()"); console.warn("+++++++ Map onLoad()");
@@ -474,7 +493,6 @@ cc.Class({
console.log(`Received parsedBattleColliderInfo via ws`); console.log(`Received parsedBattleColliderInfo via ws`);
// TODO: Upon reconnection, the backend might have already been sending down data that'd trigger "onRoomDownsyncFrame & onInputFrameDownsyncBatch", but frontend could reject those data due to "battleState != PlayerBattleState.ACTIVE". // TODO: Upon reconnection, the backend might have already been sending down data that'd trigger "onRoomDownsyncFrame & onInputFrameDownsyncBatch", but frontend could reject those data due to "battleState != PlayerBattleState.ACTIVE".
Object.assign(self, parsedBattleColliderInfo); Object.assign(self, parsedBattleColliderInfo);
self.tooFastDtIntervalMillis = 0.5 * self.rollbackEstimatedDtMillis;
const tiledMapIns = self.node.getComponent(cc.TiledMap); const tiledMapIns = self.node.getComponent(cc.TiledMap);
@@ -608,7 +626,7 @@ cc.Class({
const jsPlayersArr = new Array(pbRdf.playersArr.length).fill(null); const jsPlayersArr = new Array(pbRdf.playersArr.length).fill(null);
for (let k = 0; k < pbRdf.playersArr.length; ++k) { for (let k = 0; k < pbRdf.playersArr.length; ++k) {
const pbPlayer = pbRdf.playersArr[k]; const pbPlayer = pbRdf.playersArr[k];
const jsPlayer = gopkgs.NewPlayerDownsyncJs(pbPlayer.id, pbPlayer.virtualGridX, pbPlayer.virtualGridY, pbPlayer.dirX, pbPlayer.dirY, pbPlayer.velX, pbPlayer.velY, pbPlayer.framesToRecover, pbPlayer.framesInChState, pbPlayer.activeSkillId, pbPlayer.activeSkillHit, pbPlayer.framesInvinsible, pbPlayer.speed, pbPlayer.battleState, pbPlayer.characterState, pbPlayer.joinIndex, pbPlayer.hp, pbPlayer.maxHp, pbPlayer.colliderRadius, pbPlayer.inAir, pbPlayer.onWall, pbPlayer.onWallNormX, pbPlayer.onWallNormY, pbPlayer.bulletTeamId, pbPlayer.chCollisionTeamId); const jsPlayer = gopkgs.NewPlayerDownsyncJs(pbPlayer.id, pbPlayer.virtualGridX, pbPlayer.virtualGridY, pbPlayer.dirX, pbPlayer.dirY, pbPlayer.velX, pbPlayer.velY, pbPlayer.framesToRecover, pbPlayer.framesInChState, pbPlayer.activeSkillId, pbPlayer.activeSkillHit, pbPlayer.framesInvinsible, pbPlayer.speed, pbPlayer.battleState, pbPlayer.characterState, pbPlayer.joinIndex, pbPlayer.hp, pbPlayer.maxHp, pbPlayer.colliderRadius, pbPlayer.inAir, pbPlayer.onWall, pbPlayer.onWallNormX, pbPlayer.onWallNormY, pbPlayer.capturedByInertia, pbPlayer.bulletTeamId, pbPlayer.chCollisionTeamId);
jsPlayersArr[k] = jsPlayer; jsPlayersArr[k] = jsPlayer;
} }
const jsMeleeBulletsArr = new Array(pbRdf.meleeBullets.length).fill(null); const jsMeleeBulletsArr = new Array(pbRdf.meleeBullets.length).fill(null);
@@ -689,6 +707,7 @@ cc.Class({
self.lastRenderFrameIdTriggeredAt = performance.now(); self.lastRenderFrameIdTriggeredAt = performance.now();
// In this case it must be true that "rdf.id > chaserRenderFrameId". // In this case it must be true that "rdf.id > chaserRenderFrameId".
self.chaserRenderFrameId = rdf.Id; self.chaserRenderFrameId = rdf.Id;
self.networkDoctor.logRollbackFrames(0);
const canvasNode = self.canvasNode; const canvasNode = self.canvasNode;
self.ctrl = canvasNode.getComponent("TouchEventsManager"); self.ctrl = canvasNode.getComponent("TouchEventsManager");
@@ -795,6 +814,7 @@ cc.Class({
return; return;
} }
self.networkDoctor.logInputFrameDownsync(batch[0].inputFrameId, batch[batch.length - 1].inputFrameId);
let firstPredictedYetIncorrectInputFrameId = null; let firstPredictedYetIncorrectInputFrameId = null;
for (let k in batch) { for (let k in batch) {
const inputFrameDownsync = batch[k]; const inputFrameDownsync = batch[k];
@@ -838,11 +858,45 @@ cc.Class({
-------------------------------------------------------- --------------------------------------------------------
*/ */
// The actual rollback-and-chase would later be executed in update(dt). // The actual rollback-and-chase would later be executed in update(dt).
console.warn(`Mismatched input detected, resetting chaserRenderFrameId: ${self.chaserRenderFrameId}->${renderFrameId1} by firstPredictedYetIncorrectInputFrameId: ${firstPredictedYetIncorrectInputFrameId} console.log(`Mismatched input detected, resetting chaserRenderFrameId: ${self.chaserRenderFrameId}->${renderFrameId1} by firstPredictedYetIncorrectInputFrameId: ${firstPredictedYetIncorrectInputFrameId}
lastAllConfirmedInputFrameId=${self.lastAllConfirmedInputFrameId} lastAllConfirmedInputFrameId=${self.lastAllConfirmedInputFrameId}
recentInputCache=${self._stringifyRecentInputCache(false)} recentInputCache=${self._stringifyRecentInputCache(false)}
batchInputFrameIdRange=[${batch[0].inputFrameId}, ${batch[batch.length - 1].inputFrameId}]`); batchInputFrameIdRange=[${batch[0].inputFrameId}, ${batch[batch.length - 1].inputFrameId}]`);
self.chaserRenderFrameId = renderFrameId1; self.chaserRenderFrameId = renderFrameId1;
self.networkDoctor.logRollbackFrames(self.renderFrameId - self.chaserRenderFrameId);
},
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;
}
let effCnt = 0;
//console.log(`Received peer inputFrameUpsync batch w/ inputFrameId in [${batch[0].inputFrameId}, ${batch[batch.length - 1].inputFrameId}] for prediction assistance`);
for (let k in batch) {
const inputFrameDownsync = batch[k];
const inputFrameDownsyncId = inputFrameDownsync.inputFrameId;
if (inputFrameDownsyncId <= self.lastAllConfirmedInputFrameId) {
continue;
}
effCnt += 1;
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);
}
if (0 < effCnt) {
self.networkDoctor.logPeerInputFrameUpsync(batch[0].inputFrameId, batch[batch.length - 1].inputFrameId);
}
}, },
onPlayerAdded(rdf /* pb.RoomDownsyncFrame */ ) { onPlayerAdded(rdf /* pb.RoomDownsyncFrame */ ) {
@@ -909,10 +963,16 @@ batchInputFrameIdRange=[${batch[0].inputFrameId}, ${batch[batch.length - 1].inpu
update(dt) { update(dt) {
const self = this; const self = this;
if (ALL_BATTLE_STATES.IN_BATTLE == self.battleState) { if (ALL_BATTLE_STATES.IN_BATTLE == self.battleState) {
const elapsedMillisSinceLastFrameIdTriggered = performance.now() - self.lastRenderFrameIdTriggeredAt; /*
if (elapsedMillisSinceLastFrameIdTriggered < self.tooFastDtIntervalMillis) { [WARNING] Different devices might differ in the rate of calling "update(dt)", and the game engine is responsible of keeping this rate statistically constant.
// [WARNING] We should avoid a frontend ticking too fast to prevent cheating, as well as ticking too slow to cause a "resync avalanche" that impacts user experience!
// console.debug("Avoiding too fast frame@renderFrameId=", self.renderFrameId, ": elapsedMillisSinceLastFrameIdTriggered=", elapsedMillisSinceLastFrameIdTriggered); Significantly different rates of calling "update(dt)" among players in a same battle would result in frequent [type#1 forceConfirmation], if you have any doubt on troubles caused by this, sample the FPS curve from all players in that battle.
Kindly note that Significantly different network bandwidths or delay fluctuations would result in frequent [type#1 forceConfirmation] too, but CAUSE FROM DIFFERENT LOCAL "update(dt)" RATE SHOULD BE THE FIRST TO INVESTIGATE AND ELIMINATE -- because we have control on it, but no one has control on the internet.
*/
if (self.skipRenderFrameFlag) {
self.networkDoctor.logSkippedRenderFrameCnt();
self.skipRenderFrameFlag = false;
return; return;
} }
try { try {
@@ -924,6 +984,12 @@ batchInputFrameIdRange=[${batch[0].inputFrameId}, ${batch[batch.length - 1].inpu
[prevSelfInput, currSelfInput] = self.getOrPrefabInputFrameUpsync(noDelayInputFrameId); [prevSelfInput, currSelfInput] = self.getOrPrefabInputFrameUpsync(noDelayInputFrameId);
} }
const delayedInputFrameId = gopkgs.ConvertToDelayedInputFrameId(self.renderFrameId);
if (null == self.recentInputCache.GetByFrameId(delayedInputFrameId)) {
// Possible edge case after resync, kindly note that it's OK to prefab a "future inputFrame" here, because "sendInputFrameUpsyncBatch" would be capped by "noDelayInputFrameId from self.renderFrameId".
self.getOrPrefabInputFrameUpsync(delayedInputFrameId);
}
let t0 = performance.now(); let t0 = performance.now();
if (self.shouldSendInputFrameUpsyncBatch(prevSelfInput, currSelfInput, self.lastUpsyncInputFrameId, noDelayInputFrameId)) { if (self.shouldSendInputFrameUpsyncBatch(prevSelfInput, currSelfInput, self.lastUpsyncInputFrameId, noDelayInputFrameId)) {
// TODO: Is the following statement run asynchronously in an implicit manner? Should I explicitly run it asynchronously? // TODO: Is the following statement run asynchronously in an implicit manner? Should I explicitly run it asynchronously?
@@ -945,6 +1011,7 @@ batchInputFrameIdRange=[${batch[0].inputFrameId}, ${batch[batch.length - 1].inpu
// Inside the following "self.rollbackAndChase" actually ROLLS FORWARD w.r.t. the corresponding delayedInputFrame, REGARDLESS OF whether or not "self.chaserRenderFrameId == self.renderFrameId" now. // Inside the following "self.rollbackAndChase" actually ROLLS FORWARD w.r.t. the corresponding delayedInputFrame, REGARDLESS OF whether or not "self.chaserRenderFrameId == self.renderFrameId" now.
const latestRdfResults = self.rollbackAndChase(self.renderFrameId, self.renderFrameId + 1, self.gopkgsCollisionSys, self.gopkgsCollisionSysMap, false); const latestRdfResults = self.rollbackAndChase(self.renderFrameId, self.renderFrameId + 1, self.gopkgsCollisionSys, self.gopkgsCollisionSysMap, false);
self.networkDoctor.logRollbackFrames(self.renderFrameId - self.chaserRenderFrameId);
let prevRdf = latestRdfResults[0], let prevRdf = latestRdfResults[0],
rdf = latestRdfResults[1]; rdf = latestRdfResults[1];
/* /*
@@ -969,9 +1036,13 @@ othersForcedDownsyncRenderFrame=${JSON.stringify(othersForcedDownsyncRenderFrame
} }
self.applyRoomDownsyncFrameDynamics(rdf, prevRdf); self.applyRoomDownsyncFrameDynamics(rdf, prevRdf);
self.showDebugBoundaries(rdf); self.showDebugBoundaries(rdf);
if (self.showNetworkDoctorInfo) {
self.showNetworkDoctorLabels();
}
++self.renderFrameId; // [WARNING] It's important to increment the renderFrameId AFTER all the operations above!!! ++self.renderFrameId; // [WARNING] It's important to increment the renderFrameId AFTER all the operations above!!!
self.lastRenderFrameIdTriggeredAt = performance.now(); self.lastRenderFrameIdTriggeredAt = performance.now();
let t3 = performance.now(); let t3 = performance.now();
self.skipRenderFrameFlag = self.networkDoctor.isTooFast();
} catch (err) { } catch (err) {
console.error("Error during Map.update", err); console.error("Error during Map.update", err);
self.onBattleStopped(); // TODO: Popup to ask player to refresh browser self.onBattleStopped(); // TODO: Popup to ask player to refresh browser
@@ -1196,7 +1267,25 @@ othersForcedDownsyncRenderFrame=${JSON.stringify(othersForcedDownsyncRenderFrame
throw `Couldn't find renderFrame for i=${i} to rollback (are you using Firefox?), self.renderFrameId=${self.renderFrameId}, lastAllConfirmedInputFrameId=${self.lastAllConfirmedInputFrameId}, might've been interruptted by onRoomDownsyncFrame`; throw `Couldn't find renderFrame for i=${i} to rollback (are you using Firefox?), self.renderFrameId=${self.renderFrameId}, lastAllConfirmedInputFrameId=${self.lastAllConfirmedInputFrameId}, might've been interruptted by onRoomDownsyncFrame`;
} }
const j = gopkgs.ConvertToDelayedInputFrameId(i); const j = gopkgs.ConvertToDelayedInputFrameId(i);
const delayedInputFrame = self.getOrPrefabInputFrameUpsync(j); const delayedInputFrame = self.recentInputCache.GetByFrameId(j);
/*
const prevJ = gopkgs.ConvertToDelayedInputFrameId(i - 1);
const prevDelayedInputFrame = self.recentInputCache.GetByFrameId(prevJ);
const prevBtnALevel = (null == prevDelayedInputFrame ? 0 : ((prevDelayedInputFrame.InputList[self.selfPlayerInfo.JoinIndex - 1] >> 4) & 1));
const btnALevel = ((delayedInputFrame.InputList[self.selfPlayerInfo.JoinIndex - 1] >> 4) & 1);
if (
ATK_CHARACTER_STATE.Atk1[0] == currRdf.PlayersArr[self.selfPlayerInfo.JoinIndex - 1].CharacterState
||
ATK_CHARACTER_STATE.Atk2[0] == currRdf.PlayersArr[self.selfPlayerInfo.JoinIndex - 1].CharacterState
) {
console.log(`rdf.Id=${i}, (btnALevel,j)=(${btnALevel},${j}), (prevBtnALevel,prevJ) is (${prevBtnALevel},${prevJ}), in cancellable atk!`);
}
if (btnALevel > 0) {
if (btnALevel > prevBtnALevel) {
console.log(`rdf.Id=${i}, rising edge of btnA triggered`);
}
}
*/
if (self.frameDataLoggingEnabled) { if (self.frameDataLoggingEnabled) {
const actuallyUsedInputClone = delayedInputFrame.InputList.slice(); const actuallyUsedInputClone = delayedInputFrame.InputList.slice();
@@ -1445,4 +1534,44 @@ actuallyUsedinputList:{${self.inputFrameDownsyncStr(actuallyUsedInputClone)}}`);
} }
} }
}, },
showNetworkDoctorLabels() {
const self = this;
const [sendingFps, srvDownsyncFps, peerUpsyncFps, rollbackFrames, skippedRenderFrameCnt] = self.networkDoctor.stats();
if (self.sendingQLabel) {
self.sendingQLabel.string = `${sendingFps} fps sending`;
if (sendingFps < self.networkDoctor.inputRateThreshold) {
self.sendingQLabel.node.color = cc.Color.RED;
} else {
self.sendingQLabel.node.color = cc.Color.WHITE;
}
}
if (self.inputFrameDownsyncQLabel) {
self.inputFrameDownsyncQLabel.string = `${srvDownsyncFps} fps srv-downsync`;
if (srvDownsyncFps < self.networkDoctor.inputRateThreshold) {
self.inputFrameDownsyncQLabel.node.color = cc.Color.RED;
} else {
self.inputFrameDownsyncQLabel.node.color = cc.Color.WHITE;
}
}
if (self.peerInputFrameUpsyncQLabel) {
self.peerInputFrameUpsyncQLabel.string = `${peerUpsyncFps} fps peer-upsync`;
if (peerUpsyncFps > self.networkDoctor.peerUpsyncFps) {
self.peerInputFrameUpsyncQLabel.node.color = cc.Color.RED;
} else {
self.peerInputFrameUpsyncQLabel.node.color = cc.Color.WHITE;
}
}
if (self.rollbackFramesLabel) {
self.rollbackFramesLabel.string = `rollbackFrames: ${rollbackFrames}`
if (rollbackFrames > self.networkDoctor.rollbackFramesThreshold) {
self.rollbackFramesLabel.node.color = cc.Color.RED;
} else {
self.rollbackFramesLabel.node.color = cc.Color.WHITE;
}
}
if (self.skippedRenderFrameCntLabel) {
self.skippedRenderFrameCntLabel.string = `${skippedRenderFrameCnt} frames skipped`
}
},
}); });

View File

@@ -0,0 +1,94 @@
const RingBuffer = require('./RingBuffer');
var NetworkDoctor = function(capacity) {
this.reset(capacity);
};
NetworkDoctor.prototype.reset = function(capacity) {
this.sendingQ = new RingBuffer(capacity);
this.inputFrameDownsyncQ = new RingBuffer(capacity);
this.peerInputFrameUpsyncQ = new RingBuffer(capacity);
this.peerInputFrameUpsyncCnt = 0;
this.immediateRollbackFrames = 0;
this.skippedRenderFrameCnt = 0;
this.inputRateThreshold = gopkgs.ConvertToNoDelayInputFrameId(60);
this.peerUpsyncThreshold = 8;
this.rollbackFramesThreshold = 4; // Slightly smaller than the minimum "TurnAroundFramesToRecover".
};
NetworkDoctor.prototype.logSending = function(stFrameId, edFrameId) {
this.sendingQ.put({
i: stFrameId,
j: edFrameId,
t: Date.now()
});
};
NetworkDoctor.prototype.logInputFrameDownsync = function(stFrameId, edFrameId) {
this.inputFrameDownsyncQ.put({
i: stFrameId,
j: edFrameId,
t: Date.now()
});
};
NetworkDoctor.prototype.logPeerInputFrameUpsync = function(stFrameId, edFrameId) {
const firstPopped = this.peerInputFrameUpsyncQ.put({
i: stFrameId,
j: edFrameId,
t: Date.now()
});
if (null != firstPopped) {
this.peerInputFrameUpsyncCnt -= (firstPopped.j - firstPopped.i + 1);
}
this.peerInputFrameUpsyncCnt += (edFrameId - stFrameId + 1);
};
NetworkDoctor.prototype.logRollbackFrames = function(x) {
this.immediateRollbackFrames = x;
};
NetworkDoctor.prototype.stats = function() {
let sendingFps = 0,
srvDownsyncFps = 0,
peerUpsyncFps = 0,
rollbackFrames = this.immediateRollbackFrames;
if (1 < this.sendingQ.cnt) {
const st = this.sendingQ.getByFrameId(this.sendingQ.stFrameId);
const ed = this.sendingQ.getByFrameId(this.sendingQ.edFrameId - 1);
const elapsedMillis = ed.t - st.t;
sendingFps = Math.round((ed.j - st.i) * 1000 / elapsedMillis);
}
if (1 < this.inputFrameDownsyncQ.cnt) {
const st = this.inputFrameDownsyncQ.getByFrameId(this.inputFrameDownsyncQ.stFrameId);
const ed = this.inputFrameDownsyncQ.getByFrameId(this.inputFrameDownsyncQ.edFrameId - 1);
const elapsedMillis = ed.t - st.t;
srvDownsyncFps = Math.round((ed.j - st.i) * 1000 / elapsedMillis);
}
if (1 < this.peerInputFrameUpsyncQ.cnt) {
const st = this.peerInputFrameUpsyncQ.getByFrameId(this.peerInputFrameUpsyncQ.stFrameId);
const ed = this.peerInputFrameUpsyncQ.getByFrameId(this.peerInputFrameUpsyncQ.edFrameId - 1);
const elapsedMillis = ed.t - st.t;
peerUpsyncFps = Math.round(this.peerInputFrameUpsyncCnt * 1000 / elapsedMillis);
}
return [sendingFps, srvDownsyncFps, peerUpsyncFps, rollbackFrames, this.skippedRenderFrameCnt];
};
NetworkDoctor.prototype.logSkippedRenderFrameCnt = function() {
this.skippedRenderFrameCnt += 1;
}
NetworkDoctor.prototype.isTooFast = function() {
const [sendingFps, srvDownsyncFps, peerUpsyncFps, rollbackFrames, skippedRenderFrameCnt] = this.stats();
if (sendingFps >= this.inputRateThreshold && srvDownsyncFps >= this.inputRateThreshold) {
// At least my network is OK for both TX & RX directions.
if (rollbackFrames >= this.rollbackFramesThreshold) {
// I got many frames rolled back while none of my peers effectively helped my preciction. Deliberately not using "peerUpsyncThreshold" here because when using UDP p2p upsync broadcasting, we expect to receive effective p2p upsyncs from every other player.
return true;
}
}
return false;
};
module.exports = NetworkDoctor;

View File

@@ -1,6 +1,6 @@
{ {
"ver": "1.0.5", "ver": "1.0.5",
"uuid": "477c07c3-0d50-4d55-96f0-6eaf9f25e2da", "uuid": "affd726a-02f0-4079-aace-39fe525d7478",
"isPlugin": false, "isPlugin": false,
"loadPluginInWeb": true, "loadPluginInWeb": true,
"loadPluginInNative": true, "loadPluginInNative": true,

View File

@@ -11,9 +11,13 @@ cc.Class({
}, },
onLoad() { onLoad() {
cc.game.setFrameRate(60);
cc.view.setOrientation(cc.macro.ORIENTATION_LANDSCAPE);
cc.view.enableAutoFullScreen(true);
const self = this; const self = this;
window.mapIns = self; window.mapIns = self;
self.showCriticalCoordinateLabels = false; self.showCriticalCoordinateLabels = false;
self.showNetworkDoctorInfo = true;
const mapNode = self.node; const mapNode = self.node;
const canvasNode = mapNode.parent; const canvasNode = mapNode.parent;
@@ -94,7 +98,7 @@ cc.Class({
const p2Vpos = gopkgs.WorldToVirtualGridPos(boundaryObjs.playerStartingPositions[1].x, boundaryObjs.playerStartingPositions[1].y); const p2Vpos = gopkgs.WorldToVirtualGridPos(boundaryObjs.playerStartingPositions[1].x, boundaryObjs.playerStartingPositions[1].y);
const colliderRadiusV = gopkgs.WorldToVirtualGridPos(12.0, 0); const colliderRadiusV = gopkgs.WorldToVirtualGridPos(12.0, 0);
const speciesIdList = [4096, 1]; const speciesIdList = [1, 4096];
const chConfigsOrderedByJoinIndex = gopkgs.GetCharacterConfigsOrderedByJoinIndex(speciesIdList); const chConfigsOrderedByJoinIndex = gopkgs.GetCharacterConfigsOrderedByJoinIndex(speciesIdList);
const startRdf = window.pb.protos.RoomDownsyncFrame.create({ const startRdf = window.pb.protos.RoomDownsyncFrame.create({
@@ -154,7 +158,7 @@ cc.Class({
if (elapsedMillisSinceLastFrameIdTriggered < self.tooFastDtIntervalMillis) { if (elapsedMillisSinceLastFrameIdTriggered < self.tooFastDtIntervalMillis) {
// [WARNING] We should avoid a frontend ticking too fast to prevent cheating, as well as ticking too slow to cause a "resync avalanche" that impacts user experience! // [WARNING] We should avoid a frontend ticking too fast to prevent cheating, as well as ticking too slow to cause a "resync avalanche" that impacts user experience!
// console.debug("Avoiding too fast frame@renderFrameId=", self.renderFrameId, ": elapsedMillisSinceLastFrameIdTriggered=", elapsedMillisSinceLastFrameIdTriggered); // console.debug("Avoiding too fast frame@renderFrameId=", self.renderFrameId, ": elapsedMillisSinceLastFrameIdTriggered=", elapsedMillisSinceLastFrameIdTriggered);
return; //return;
} }
try { try {
let st = performance.now(); let st = performance.now();

View File

@@ -11,14 +11,6 @@ cc.Class({
type: cc.Object, type: cc.Object,
default: null default: null
}, },
myAvatarNode: {
type: cc.Node,
default: null,
},
myNameNode: {
type: cc.Node,
default: null,
},
rankingNodes: { rankingNodes: {
type: [cc.Node], type: [cc.Node],
default: [], default: [],
@@ -46,22 +38,6 @@ cc.Class({
showPlayerInfo(playerRichInfoDict) { showPlayerInfo(playerRichInfoDict) {
this.showRanking(playerRichInfoDict); this.showRanking(playerRichInfoDict);
this.showMyAvatar();
this.showMyName();
},
showMyName() {
const selfPlayerInfo = JSON.parse(cc.sys.localStorage.getItem('selfPlayer'));
let name = 'No name';
if (null == selfPlayerInfo.displayName || "" == selfPlayerInfo.displayName) {
name = selfPlayerInfo.name;
} else {
name = selfPlayerInfo.displayName;
}
if (!this.myNameNode) return;
const myNameNodeLabel = this.myNameNode.getComponent(cc.Label);
if (!myNameNodeLabel || null == name) return;
myNameNodeLabel.string = name;
}, },
showRanking(playerRichInfoDict) { showRanking(playerRichInfoDict) {
@@ -115,42 +91,6 @@ cc.Class({
} }
}, },
showMyAvatar() {
const self = this;
const selfPlayerInfo = JSON.parse(cc.sys.localStorage.getItem('selfPlayer'));
let remoteUrl = selfPlayerInfo.avatar;
if (remoteUrl == null || remoteUrl == '') {
cc.log(`No avatar to show for myself, check storage.`);
return;
} else {
cc.loader.load({
url: remoteUrl,
type: 'jpg'
}, function(err, texture) {
if (err != null || texture == null) {
console.log(err);
} else {
const sf = new cc.SpriteFrame();
sf.setTexture(texture);
self.myAvatarNode.getComponent(cc.Sprite).spriteFrame = sf;
}
});
}
},
showRibbon(winnerInfo, ribbonNode) {
const selfPlayerInfo = JSON.parse(cc.sys.localStorage.getItem('selfPlayer'));
const texture = (selfPlayerInfo.playerId == winnerInfo.id) ? "textures/resultPanel/WinRibbon" : "textures/resultPanel/loseRibbon";
cc.loader.loadRes(texture, cc.SpriteFrame, function(err, spriteFrame) {
if (err) {
console.log(err);
return;
}
ribbonNode.getComponent(cc.Sprite).spriteFrame = spriteFrame;
});
},
onClose(evt) { onClose(evt) {
if (this.node.parent) { if (this.node.parent) {
this.node.parent.removeChild(this.node); this.node.parent.removeChild(this.node);

View File

@@ -13,9 +13,12 @@ var RingBuffer = function(capacity) {
}; };
RingBuffer.prototype.put = function(item) { RingBuffer.prototype.put = function(item) {
let firstPopped = null;
while (0 < this.cnt && this.cnt >= this.n) { while (0 < this.cnt && this.cnt >= this.n) {
// Make room for the new element // Make room for the new element
this.pop(); const popped = this.pop();
if (null == firstPopped)
firstPopped = popped;
} }
this.eles[this.ed] = item this.eles[this.ed] = item
this.edFrameId++; this.edFrameId++;
@@ -24,6 +27,7 @@ RingBuffer.prototype.put = function(item) {
if (this.ed >= this.n) { if (this.ed >= this.n) {
this.ed -= this.n; // Deliberately not using "%" operator for performance concern this.ed -= this.n; // Deliberately not using "%" operator for performance concern
} }
return firstPopped;
}; };
RingBuffer.prototype.pop = function() { RingBuffer.prototype.pop = function() {

View File

@@ -169,30 +169,24 @@ cc.Class({
if (self.btnA) { if (self.btnA) {
self.btnA.on(cc.Node.EventType.TOUCH_START, function(evt) { self.btnA.on(cc.Node.EventType.TOUCH_START, function(evt) {
self._triggerEdgeBtnA(true); self._triggerEdgeBtnA(true);
evt.target.runAction(cc.scaleTo(0.1, 0.3));
}); });
self.btnA.on(cc.Node.EventType.TOUCH_END, function(evt) { self.btnA.on(cc.Node.EventType.TOUCH_END, function(evt) {
self._triggerEdgeBtnA(false); self._triggerEdgeBtnA(false);
evt.target.runAction(cc.scaleTo(0.1, 1.0));
}); });
self.btnA.on(cc.Node.EventType.TOUCH_CANCEL, function(evt) { self.btnA.on(cc.Node.EventType.TOUCH_CANCEL, function(evt) {
self._triggerEdgeBtnA(false); self._triggerEdgeBtnA(false);
evt.target.runAction(cc.scaleTo(0.1, 1.0));
}); });
} }
if (self.btnB) { if (self.btnB) {
self.btnB.on(cc.Node.EventType.TOUCH_START, function(evt) { self.btnB.on(cc.Node.EventType.TOUCH_START, function(evt) {
self._triggerEdgeBtnB(true); self._triggerEdgeBtnB(true);
evt.target.runAction(cc.scaleTo(0.1, 0.3));
}); });
self.btnB.on(cc.Node.EventType.TOUCH_END, function(evt) { self.btnB.on(cc.Node.EventType.TOUCH_END, function(evt) {
self._triggerEdgeBtnB(false); self._triggerEdgeBtnB(false);
evt.target.runAction(cc.scaleTo(0.1, 1.0));
}); });
self.btnB.on(cc.Node.EventType.TOUCH_CANCEL, function(evt) { self.btnB.on(cc.Node.EventType.TOUCH_CANCEL, function(evt) {
self._triggerEdgeBtnB(false); self._triggerEdgeBtnB(false);
evt.target.runAction(cc.scaleTo(0.1, 1.0));
}); });
} }
@@ -500,13 +494,23 @@ cc.Class({
this.cachedBtnALevel = this.realtimeBtnALevel; this.cachedBtnALevel = this.realtimeBtnALevel;
this.btnAEdgeTriggerLock = true; this.btnAEdgeTriggerLock = true;
} }
if (rising) {
this.btnA.runAction(cc.scaleTo(0.1, 0.3));
} else {
this.btnA.runAction(cc.scaleTo(0.1, 0.5));
}
}, },
_triggerEdgeBtnB(rising) { _triggerEdgeBtnB(rising, evt) {
this.realtimeBtnBLevel = (rising ? 1 : 0); this.realtimeBtnBLevel = (rising ? 1 : 0);
if (!this.btnBEdgeTriggerLock && (1 - this.realtimeBtnBLevel) == this.cachedBtnBLevel) { if (!this.btnBEdgeTriggerLock && (1 - this.realtimeBtnBLevel) == this.cachedBtnBLevel) {
this.cachedBtnBLevel = this.realtimeBtnBLevel; this.cachedBtnBLevel = this.realtimeBtnBLevel;
this.btnBEdgeTriggerLock = true; this.btnBEdgeTriggerLock = true;
} }
if (rising) {
this.btnB.runAction(cc.scaleTo(0.1, 0.3));
} else {
this.btnB.runAction(cc.scaleTo(0.1, 0.5));
}
}, },
}); });

View File

@@ -11,6 +11,7 @@ window.DOWNSYNC_MSG_ACT_HB_REQ = 1;
window.DOWNSYNC_MSG_ACT_INPUT_BATCH = 2; window.DOWNSYNC_MSG_ACT_INPUT_BATCH = 2;
window.DOWNSYNC_MSG_ACT_BATTLE_STOPPED = 3; window.DOWNSYNC_MSG_ACT_BATTLE_STOPPED = 3;
window.DOWNSYNC_MSG_ACT_FORCED_RESYNC = 4; window.DOWNSYNC_MSG_ACT_FORCED_RESYNC = 4;
window.DOWNSYNC_MSG_ACT_PEER_INPUT_BATCH = 5;
window.sendSafely = function(msgStr) { window.sendSafely = function(msgStr) {
/** /**
@@ -65,6 +66,7 @@ window.handleHbRequirements = function(resp) {
} }
if (window.handleBattleColliderInfo) { if (window.handleBattleColliderInfo) {
window.initSecondarySession(null, window.boundRoomId);
window.handleBattleColliderInfo(resp.bciFrame); 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); const clientSession = new WebSocket(urlToConnect);
clientSession.binaryType = 'arraybuffer'; // Make 'event.data' of 'onmessage' an "ArrayBuffer" instead of a "Blob" 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'); 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}`);
};
};

View File

@@ -1219,6 +1219,7 @@ $root.protos = (function() {
* @property {boolean|null} [onWall] PlayerDownsync onWall * @property {boolean|null} [onWall] PlayerDownsync onWall
* @property {number|null} [onWallNormX] PlayerDownsync onWallNormX * @property {number|null} [onWallNormX] PlayerDownsync onWallNormX
* @property {number|null} [onWallNormY] PlayerDownsync onWallNormY * @property {number|null} [onWallNormY] PlayerDownsync onWallNormY
* @property {boolean|null} [capturedByInertia] PlayerDownsync capturedByInertia
* @property {string|null} [name] PlayerDownsync name * @property {string|null} [name] PlayerDownsync name
* @property {string|null} [displayName] PlayerDownsync displayName * @property {string|null} [displayName] PlayerDownsync displayName
* @property {string|null} [avatar] PlayerDownsync avatar * @property {string|null} [avatar] PlayerDownsync avatar
@@ -1463,6 +1464,14 @@ $root.protos = (function() {
*/ */
PlayerDownsync.prototype.onWallNormY = 0; PlayerDownsync.prototype.onWallNormY = 0;
/**
* PlayerDownsync capturedByInertia.
* @member {boolean} capturedByInertia
* @memberof protos.PlayerDownsync
* @instance
*/
PlayerDownsync.prototype.capturedByInertia = false;
/** /**
* PlayerDownsync name. * PlayerDownsync name.
* @member {string} name * @member {string} name
@@ -1567,6 +1576,8 @@ $root.protos = (function() {
writer.uint32(/* id 27, wireType 0 =*/216).int32(message.onWallNormX); writer.uint32(/* id 27, wireType 0 =*/216).int32(message.onWallNormX);
if (message.onWallNormY != null && Object.hasOwnProperty.call(message, "onWallNormY")) if (message.onWallNormY != null && Object.hasOwnProperty.call(message, "onWallNormY"))
writer.uint32(/* id 28, wireType 0 =*/224).int32(message.onWallNormY); writer.uint32(/* id 28, wireType 0 =*/224).int32(message.onWallNormY);
if (message.capturedByInertia != null && Object.hasOwnProperty.call(message, "capturedByInertia"))
writer.uint32(/* id 29, wireType 0 =*/232).bool(message.capturedByInertia);
if (message.name != null && Object.hasOwnProperty.call(message, "name")) if (message.name != null && Object.hasOwnProperty.call(message, "name"))
writer.uint32(/* id 997, wireType 2 =*/7978).string(message.name); writer.uint32(/* id 997, wireType 2 =*/7978).string(message.name);
if (message.displayName != null && Object.hasOwnProperty.call(message, "displayName")) if (message.displayName != null && Object.hasOwnProperty.call(message, "displayName"))
@@ -1719,6 +1730,10 @@ $root.protos = (function() {
message.onWallNormY = reader.int32(); message.onWallNormY = reader.int32();
break; break;
} }
case 29: {
message.capturedByInertia = reader.bool();
break;
}
case 997: { case 997: {
message.name = reader.string(); message.name = reader.string();
break; break;
@@ -1850,6 +1865,9 @@ $root.protos = (function() {
if (message.onWallNormY != null && message.hasOwnProperty("onWallNormY")) if (message.onWallNormY != null && message.hasOwnProperty("onWallNormY"))
if (!$util.isInteger(message.onWallNormY)) if (!$util.isInteger(message.onWallNormY))
return "onWallNormY: integer expected"; return "onWallNormY: integer expected";
if (message.capturedByInertia != null && message.hasOwnProperty("capturedByInertia"))
if (typeof message.capturedByInertia !== "boolean")
return "capturedByInertia: boolean expected";
if (message.name != null && message.hasOwnProperty("name")) if (message.name != null && message.hasOwnProperty("name"))
if (!$util.isString(message.name)) if (!$util.isString(message.name))
return "name: string expected"; return "name: string expected";
@@ -1930,6 +1948,8 @@ $root.protos = (function() {
message.onWallNormX = object.onWallNormX | 0; message.onWallNormX = object.onWallNormX | 0;
if (object.onWallNormY != null) if (object.onWallNormY != null)
message.onWallNormY = object.onWallNormY | 0; message.onWallNormY = object.onWallNormY | 0;
if (object.capturedByInertia != null)
message.capturedByInertia = Boolean(object.capturedByInertia);
if (object.name != null) if (object.name != null)
message.name = String(object.name); message.name = String(object.name);
if (object.displayName != null) if (object.displayName != null)
@@ -1981,6 +2001,7 @@ $root.protos = (function() {
object.onWall = false; object.onWall = false;
object.onWallNormX = 0; object.onWallNormX = 0;
object.onWallNormY = 0; object.onWallNormY = 0;
object.capturedByInertia = false;
object.name = ""; object.name = "";
object.displayName = ""; object.displayName = "";
object.avatar = ""; object.avatar = "";
@@ -2041,6 +2062,8 @@ $root.protos = (function() {
object.onWallNormX = message.onWallNormX; object.onWallNormX = message.onWallNormX;
if (message.onWallNormY != null && message.hasOwnProperty("onWallNormY")) if (message.onWallNormY != null && message.hasOwnProperty("onWallNormY"))
object.onWallNormY = message.onWallNormY; object.onWallNormY = message.onWallNormY;
if (message.capturedByInertia != null && message.hasOwnProperty("capturedByInertia"))
object.capturedByInertia = message.capturedByInertia;
if (message.name != null && message.hasOwnProperty("name")) if (message.name != null && message.hasOwnProperty("name"))
object.name = message.name; object.name = message.name;
if (message.displayName != null && message.hasOwnProperty("displayName")) if (message.displayName != null && message.hasOwnProperty("displayName"))
@@ -2360,6 +2383,7 @@ $root.protos = (function() {
* @interface IInputFrameUpsync * @interface IInputFrameUpsync
* @property {number|null} [inputFrameId] InputFrameUpsync inputFrameId * @property {number|null} [inputFrameId] InputFrameUpsync inputFrameId
* @property {number|Long|null} [encoded] InputFrameUpsync encoded * @property {number|Long|null} [encoded] InputFrameUpsync encoded
* @property {number|null} [joinIndex] InputFrameUpsync joinIndex
*/ */
/** /**
@@ -2393,6 +2417,14 @@ $root.protos = (function() {
*/ */
InputFrameUpsync.prototype.encoded = $util.Long ? $util.Long.fromBits(0,0,true) : 0; 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. * Creates a new InputFrameUpsync instance using the specified properties.
* @function create * @function create
@@ -2421,6 +2453,8 @@ $root.protos = (function() {
writer.uint32(/* id 1, wireType 0 =*/8).int32(message.inputFrameId); writer.uint32(/* id 1, wireType 0 =*/8).int32(message.inputFrameId);
if (message.encoded != null && Object.hasOwnProperty.call(message, "encoded")) if (message.encoded != null && Object.hasOwnProperty.call(message, "encoded"))
writer.uint32(/* id 2, wireType 0 =*/16).uint64(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; return writer;
}; };
@@ -2463,6 +2497,10 @@ $root.protos = (function() {
message.encoded = reader.uint64(); message.encoded = reader.uint64();
break; break;
} }
case 3: {
message.joinIndex = reader.int32();
break;
}
default: default:
reader.skipType(tag & 7); reader.skipType(tag & 7);
break; break;
@@ -2504,6 +2542,9 @@ $root.protos = (function() {
if (message.encoded != null && message.hasOwnProperty("encoded")) if (message.encoded != null && message.hasOwnProperty("encoded"))
if (!$util.isInteger(message.encoded) && !(message.encoded && $util.isInteger(message.encoded.low) && $util.isInteger(message.encoded.high))) if (!$util.isInteger(message.encoded) && !(message.encoded && $util.isInteger(message.encoded.low) && $util.isInteger(message.encoded.high)))
return "encoded: integer|Long expected"; return "encoded: integer|Long expected";
if (message.joinIndex != null && message.hasOwnProperty("joinIndex"))
if (!$util.isInteger(message.joinIndex))
return "joinIndex: integer expected";
return null; return null;
}; };
@@ -2530,6 +2571,8 @@ $root.protos = (function() {
message.encoded = object.encoded; message.encoded = object.encoded;
else if (typeof object.encoded === "object") else if (typeof object.encoded === "object")
message.encoded = new $util.LongBits(object.encoded.low >>> 0, object.encoded.high >>> 0).toNumber(true); 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; return message;
}; };
@@ -2553,6 +2596,7 @@ $root.protos = (function() {
object.encoded = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long; object.encoded = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long;
} else } else
object.encoded = options.longs === String ? "0" : 0; object.encoded = options.longs === String ? "0" : 0;
object.joinIndex = 0;
} }
if (message.inputFrameId != null && message.hasOwnProperty("inputFrameId")) if (message.inputFrameId != null && message.hasOwnProperty("inputFrameId"))
object.inputFrameId = message.inputFrameId; object.inputFrameId = message.inputFrameId;
@@ -2561,6 +2605,8 @@ $root.protos = (function() {
object.encoded = options.longs === String ? String(message.encoded) : message.encoded; object.encoded = options.longs === String ? String(message.encoded) : message.encoded;
else 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; 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; return object;
}; };
@@ -3513,6 +3559,7 @@ $root.protos = (function() {
* @property {protos.RoomDownsyncFrame|null} [rdf] WsResp rdf * @property {protos.RoomDownsyncFrame|null} [rdf] WsResp rdf
* @property {Array.<protos.InputFrameDownsync>|null} [inputFrameDownsyncBatch] WsResp inputFrameDownsyncBatch * @property {Array.<protos.InputFrameDownsync>|null} [inputFrameDownsyncBatch] WsResp inputFrameDownsyncBatch
* @property {protos.BattleColliderInfo|null} [bciFrame] WsResp bciFrame * @property {protos.BattleColliderInfo|null} [bciFrame] WsResp bciFrame
* @property {number|null} [peerJoinIndex] WsResp peerJoinIndex
*/ */
/** /**
@@ -3579,6 +3626,14 @@ $root.protos = (function() {
*/ */
WsResp.prototype.bciFrame = null; 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. * Creates a new WsResp instance using the specified properties.
* @function create * @function create
@@ -3616,6 +3671,8 @@ $root.protos = (function() {
$root.protos.InputFrameDownsync.encode(message.inputFrameDownsyncBatch[i], writer.uint32(/* id 5, wireType 2 =*/42).fork()).ldelim(); $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")) if (message.bciFrame != null && Object.hasOwnProperty.call(message, "bciFrame"))
$root.protos.BattleColliderInfo.encode(message.bciFrame, writer.uint32(/* id 6, wireType 2 =*/50).fork()).ldelim(); $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; return writer;
}; };
@@ -3676,6 +3733,10 @@ $root.protos = (function() {
message.bciFrame = $root.protos.BattleColliderInfo.decode(reader, reader.uint32()); message.bciFrame = $root.protos.BattleColliderInfo.decode(reader, reader.uint32());
break; break;
} }
case 7: {
message.peerJoinIndex = reader.int32();
break;
}
default: default:
reader.skipType(tag & 7); reader.skipType(tag & 7);
break; break;
@@ -3739,6 +3800,9 @@ $root.protos = (function() {
if (error) if (error)
return "bciFrame." + error; return "bciFrame." + error;
} }
if (message.peerJoinIndex != null && message.hasOwnProperty("peerJoinIndex"))
if (!$util.isInteger(message.peerJoinIndex))
return "peerJoinIndex: integer expected";
return null; return null;
}; };
@@ -3780,6 +3844,8 @@ $root.protos = (function() {
throw TypeError(".protos.WsResp.bciFrame: object expected"); throw TypeError(".protos.WsResp.bciFrame: object expected");
message.bciFrame = $root.protos.BattleColliderInfo.fromObject(object.bciFrame); message.bciFrame = $root.protos.BattleColliderInfo.fromObject(object.bciFrame);
} }
if (object.peerJoinIndex != null)
message.peerJoinIndex = object.peerJoinIndex | 0;
return message; return message;
}; };
@@ -3804,6 +3870,7 @@ $root.protos = (function() {
object.act = 0; object.act = 0;
object.rdf = null; object.rdf = null;
object.bciFrame = null; object.bciFrame = null;
object.peerJoinIndex = 0;
} }
if (message.ret != null && message.hasOwnProperty("ret")) if (message.ret != null && message.hasOwnProperty("ret"))
object.ret = message.ret; object.ret = message.ret;
@@ -3820,6 +3887,8 @@ $root.protos = (function() {
} }
if (message.bciFrame != null && message.hasOwnProperty("bciFrame")) if (message.bciFrame != null && message.hasOwnProperty("bciFrame"))
object.bciFrame = $root.protos.BattleColliderInfo.toObject(message.bciFrame, options); object.bciFrame = $root.protos.BattleColliderInfo.toObject(message.bciFrame, options);
if (message.peerJoinIndex != null && message.hasOwnProperty("peerJoinIndex"))
object.peerJoinIndex = message.peerJoinIndex;
return object; return object;
}; };
@@ -3862,6 +3931,7 @@ $root.protos = (function() {
* @property {number|Long|null} [unconfirmedMask] InputsBufferSnapshot unconfirmedMask * @property {number|Long|null} [unconfirmedMask] InputsBufferSnapshot unconfirmedMask
* @property {Array.<protos.InputFrameDownsync>|null} [toSendInputFrameDownsyncs] InputsBufferSnapshot toSendInputFrameDownsyncs * @property {Array.<protos.InputFrameDownsync>|null} [toSendInputFrameDownsyncs] InputsBufferSnapshot toSendInputFrameDownsyncs
* @property {boolean|null} [shouldForceResync] InputsBufferSnapshot shouldForceResync * @property {boolean|null} [shouldForceResync] InputsBufferSnapshot shouldForceResync
* @property {number|null} [peerJoinIndex] InputsBufferSnapshot peerJoinIndex
*/ */
/** /**
@@ -3912,6 +3982,14 @@ $root.protos = (function() {
*/ */
InputsBufferSnapshot.prototype.shouldForceResync = false; 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. * Creates a new InputsBufferSnapshot instance using the specified properties.
* @function create * @function create
@@ -3945,6 +4023,8 @@ $root.protos = (function() {
$root.protos.InputFrameDownsync.encode(message.toSendInputFrameDownsyncs[i], writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim(); $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")) if (message.shouldForceResync != null && Object.hasOwnProperty.call(message, "shouldForceResync"))
writer.uint32(/* id 4, wireType 0 =*/32).bool(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; return writer;
}; };
@@ -3997,6 +4077,10 @@ $root.protos = (function() {
message.shouldForceResync = reader.bool(); message.shouldForceResync = reader.bool();
break; break;
} }
case 5: {
message.peerJoinIndex = reader.int32();
break;
}
default: default:
reader.skipType(tag & 7); reader.skipType(tag & 7);
break; break;
@@ -4050,6 +4134,9 @@ $root.protos = (function() {
if (message.shouldForceResync != null && message.hasOwnProperty("shouldForceResync")) if (message.shouldForceResync != null && message.hasOwnProperty("shouldForceResync"))
if (typeof message.shouldForceResync !== "boolean") if (typeof message.shouldForceResync !== "boolean")
return "shouldForceResync: boolean expected"; return "shouldForceResync: boolean expected";
if (message.peerJoinIndex != null && message.hasOwnProperty("peerJoinIndex"))
if (!$util.isInteger(message.peerJoinIndex))
return "peerJoinIndex: integer expected";
return null; return null;
}; };
@@ -4088,6 +4175,8 @@ $root.protos = (function() {
} }
if (object.shouldForceResync != null) if (object.shouldForceResync != null)
message.shouldForceResync = Boolean(object.shouldForceResync); message.shouldForceResync = Boolean(object.shouldForceResync);
if (object.peerJoinIndex != null)
message.peerJoinIndex = object.peerJoinIndex | 0;
return message; return message;
}; };
@@ -4114,6 +4203,7 @@ $root.protos = (function() {
} else } else
object.unconfirmedMask = options.longs === String ? "0" : 0; object.unconfirmedMask = options.longs === String ? "0" : 0;
object.shouldForceResync = false; object.shouldForceResync = false;
object.peerJoinIndex = 0;
} }
if (message.refRenderFrameId != null && message.hasOwnProperty("refRenderFrameId")) if (message.refRenderFrameId != null && message.hasOwnProperty("refRenderFrameId"))
object.refRenderFrameId = message.refRenderFrameId; object.refRenderFrameId = message.refRenderFrameId;
@@ -4129,6 +4219,8 @@ $root.protos = (function() {
} }
if (message.shouldForceResync != null && message.hasOwnProperty("shouldForceResync")) if (message.shouldForceResync != null && message.hasOwnProperty("shouldForceResync"))
object.shouldForceResync = message.shouldForceResync; object.shouldForceResync = message.shouldForceResync;
if (message.peerJoinIndex != null && message.hasOwnProperty("peerJoinIndex"))
object.peerJoinIndex = message.peerJoinIndex;
return object; return object;
}; };

View File

@@ -38,7 +38,7 @@
"orientation": "portrait" "orientation": "portrait"
}, },
"startScene": "2ff474d9-0c9e-4fe3-87ec-fbff7cae85b4", "startScene": "2ff474d9-0c9e-4fe3-87ec-fbff7cae85b4",
"title": "TreasureHunterX", "title": "DelayNoMore",
"webOrientation": "portrait", "webOrientation": "portrait",
"wechatgame": { "wechatgame": {
"REMOTE_SERVER_ROOT": "https://bgmoba.lokcol.com/static/", "REMOTE_SERVER_ROOT": "https://bgmoba.lokcol.com/static/",

View File

@@ -6,16 +6,22 @@ all: help
GOPROXY=https://goproxy.io GOPROXY=https://goproxy.io
serve: serve:
gopherjs clean
gopherjs serve $(PROJECTNAME) gopherjs serve $(PROJECTNAME)
build: clean:
gopherjs build $(PROJECTNAME) gopherjs clean
rm ../frontend/assets/plugin_scripts/jsexport.js && mv ./jsexport.js ../frontend/assets/plugin_scripts/jsexport.js rm -f ../frontend/assets/plugin_scripts/jsexport.js
#rm -f ../frontend/assets/plugin_scripts/jsexport.js.map
build-min: build: clean
gopherjs build $(PROJECTNAME)
mv ./jsexport.js ../frontend/assets/plugin_scripts/
#mv ./jsexport.js.map ../frontend/assets/plugin_scripts/
build-min: clean
gopherjs build -m $(PROJECTNAME) gopherjs build -m $(PROJECTNAME)
rm ../frontend/assets/plugin_scripts/jsexport.js && mv ./jsexport.js ../frontend/assets/plugin_scripts/jsexport.js mv ./jsexport.js ../frontend/assets/plugin_scripts/
#mv ./jsexport.js.map ../frontend/assets/plugin_scripts/
.PHONY: help .PHONY: help

View File

@@ -16,14 +16,14 @@ const (
PATTERN_ID_UNABLE_TO_OP = -2 PATTERN_ID_UNABLE_TO_OP = -2
PATTERN_ID_NO_OP = -1 PATTERN_ID_NO_OP = -1
WORLD_TO_VIRTUAL_GRID_RATIO = float64(100) WORLD_TO_VIRTUAL_GRID_RATIO = float64(100.0)
VIRTUAL_GRID_TO_WORLD_RATIO = float64(1.0) / WORLD_TO_VIRTUAL_GRID_RATIO VIRTUAL_GRID_TO_WORLD_RATIO = float64(1.0) / WORLD_TO_VIRTUAL_GRID_RATIO
GRAVITY_X = int32(0) GRAVITY_X = int32(0)
GRAVITY_Y = -int32(float64(0.5) * WORLD_TO_VIRTUAL_GRID_RATIO) // makes all "playerCollider.Y" a multiple of 0.5 in all cases GRAVITY_Y = -int32(float64(0.5) * WORLD_TO_VIRTUAL_GRID_RATIO) // makes all "playerCollider.Y" a multiple of 0.5 in all cases
INPUT_DELAY_FRAMES = int32(4) // in the count of render frames INPUT_DELAY_FRAMES = int32(4) // in the count of render frames
INPUT_SCALE_FRAMES = uint32(3) // inputDelayedAndScaledFrameId = ((originalFrameId - InputDelayFrames) >> InputScaleFrames) INPUT_SCALE_FRAMES = uint32(2) // inputDelayedAndScaledFrameId = ((originalFrameId - InputDelayFrames) >> InputScaleFrames)
NST_DELAY_FRAMES = int32(16) // network-single-trip delay in the count of render frames, proposed to be (InputDelayFrames >> 1) because we expect a round-trip delay to be exactly "InputDelayFrames" NST_DELAY_FRAMES = int32(16) // network-single-trip delay in the count of render frames, proposed to be (InputDelayFrames >> 1) because we expect a round-trip delay to be exactly "InputDelayFrames"
SP_ATK_LOOKUP_FRAMES = int32(5) SP_ATK_LOOKUP_FRAMES = int32(5)
@@ -77,6 +77,8 @@ const (
ATK_CHARACTER_STATE_DASHING = int32(15) ATK_CHARACTER_STATE_DASHING = int32(15)
ATK_CHARACTER_STATE_ONWALL = int32(16) ATK_CHARACTER_STATE_ONWALL = int32(16)
ATK_CHARACTER_STATE_TURNAROUND = int32(17)
) )
var inAirSet = map[int32]bool{ var inAirSet = map[int32]bool{
@@ -446,7 +448,7 @@ func calcHardPushbacksNorms(joinIndex int32, currPlayerDownsync, thatPlayerInNex
return &ret return &ret
} }
func deriveOpPattern(currPlayerDownsync, thatPlayerInNextFrame *PlayerDownsync, currRenderFrame *RoomDownsyncFrame, inputsBuffer *RingBuffer) (int, bool, int32, int32) { func deriveOpPattern(currPlayerDownsync, thatPlayerInNextFrame *PlayerDownsync, currRenderFrame *RoomDownsyncFrame, chConfig *CharacterConfig, inputsBuffer *RingBuffer) (int, bool, int32, int32) {
// returns (patternId, jumpedOrNot, effectiveDx, effectiveDy) // returns (patternId, jumpedOrNot, effectiveDx, effectiveDy)
delayedInputFrameId := ConvertToDelayedInputFrameId(currRenderFrame.Id) delayedInputFrameId := ConvertToDelayedInputFrameId(currRenderFrame.Id)
delayedInputFrameIdForPrevRdf := ConvertToDelayedInputFrameId(currRenderFrame.Id - 1) delayedInputFrameIdForPrevRdf := ConvertToDelayedInputFrameId(currRenderFrame.Id - 1)
@@ -476,11 +478,19 @@ func deriveOpPattern(currPlayerDownsync, thatPlayerInNextFrame *PlayerDownsync,
prevBtnBLevel = prevDecodedInput.BtnBLevel prevBtnBLevel = prevDecodedInput.BtnBLevel
} }
// Jumping is partially allowed within "CapturedByInertia", but moving is only allowed when "0 == FramesToRecover" (constrained later in "ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame")
if 0 == currPlayerDownsync.FramesToRecover { if 0 == currPlayerDownsync.FramesToRecover {
// Jumping and moving are only allowed here
effDx, effDy = decodedInput.Dx, decodedInput.Dy effDx, effDy = decodedInput.Dx, decodedInput.Dy
}
patternId := PATTERN_ID_NO_OP
canJumpWithinInertia := currPlayerDownsync.CapturedByInertia && ((chConfig.InertiaFramesToRecover >> 1) > currPlayerDownsync.FramesToRecover)
if 0 == currPlayerDownsync.FramesToRecover || canJumpWithinInertia {
if decodedInput.BtnBLevel > prevBtnBLevel { if decodedInput.BtnBLevel > prevBtnBLevel {
if _, existent := inAirSet[currPlayerDownsync.CharacterState]; !existent { if chConfig.DashingEnabled && 0 > decodedInput.Dy {
// Checking "DashingEnabled" here to allow jumping when dashing-disabled players pressed "DOWN + BtnB"
patternId = 5
} else if _, existent := inAirSet[currPlayerDownsync.CharacterState]; !existent {
jumpedOrNot = true jumpedOrNot = true
} else if ATK_CHARACTER_STATE_ONWALL == currPlayerDownsync.CharacterState { } else if ATK_CHARACTER_STATE_ONWALL == currPlayerDownsync.CharacterState {
jumpedOrNot = true jumpedOrNot = true
@@ -488,15 +498,20 @@ func deriveOpPattern(currPlayerDownsync, thatPlayerInNextFrame *PlayerDownsync,
} }
} }
patternId := PATTERN_ID_NO_OP if PATTERN_ID_NO_OP == patternId {
if 0 < decodedInput.BtnALevel {
if decodedInput.BtnALevel > prevBtnALevel { if decodedInput.BtnALevel > prevBtnALevel {
if 0 > effDy { if 0 > decodedInput.Dy {
patternId = 3 patternId = 3
} else if 0 < effDy { } else if 0 < decodedInput.Dy {
patternId = 2 patternId = 2
} else { } else {
patternId = 1 patternId = 1
} }
} else {
patternId = 4 // Holding
}
}
} }
return patternId, jumpedOrNot, effDx, effDy return patternId, jumpedOrNot, effDx, effDy
@@ -535,6 +550,7 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
ColliderRadius: currPlayerDownsync.ColliderRadius, ColliderRadius: currPlayerDownsync.ColliderRadius,
OnWallNormX: currPlayerDownsync.OnWallNormX, OnWallNormX: currPlayerDownsync.OnWallNormX,
OnWallNormY: currPlayerDownsync.OnWallNormY, OnWallNormY: currPlayerDownsync.OnWallNormY,
CapturedByInertia: currPlayerDownsync.CapturedByInertia,
} }
if nextRenderFramePlayers[i].FramesToRecover < 0 { if nextRenderFramePlayers[i].FramesToRecover < 0 {
nextRenderFramePlayers[i].FramesToRecover = 0 nextRenderFramePlayers[i].FramesToRecover = 0
@@ -555,7 +571,7 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
for i, currPlayerDownsync := range currRenderFrame.PlayersArr { for i, currPlayerDownsync := range currRenderFrame.PlayersArr {
chConfig := chConfigsOrderedByJoinIndex[i] chConfig := chConfigsOrderedByJoinIndex[i]
thatPlayerInNextFrame := nextRenderFramePlayers[i] thatPlayerInNextFrame := nextRenderFramePlayers[i]
patternId, jumpedOrNot, effDx, effDy := deriveOpPattern(currPlayerDownsync, thatPlayerInNextFrame, currRenderFrame, inputsBuffer) patternId, jumpedOrNot, effDx, effDy := deriveOpPattern(currPlayerDownsync, thatPlayerInNextFrame, currRenderFrame, chConfig, inputsBuffer)
jumpedOrNotList[i] = jumpedOrNot jumpedOrNotList[i] = jumpedOrNot
joinIndex := currPlayerDownsync.JoinIndex joinIndex := currPlayerDownsync.JoinIndex
@@ -627,6 +643,38 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
} }
if 0 == currPlayerDownsync.FramesToRecover { if 0 == currPlayerDownsync.FramesToRecover {
prevCapturedByInertia := currPlayerDownsync.CapturedByInertia
isWallJumping := (chConfig.OnWallEnabled && chConfig.WallJumpingInitVelX == intAbs(currPlayerDownsync.VelX))
/*
if isWallJumping {
fmt.Printf("joinIndex=%d is wall jumping\n{renderFrame.id: %d, currPlayerDownsync.Speed: %d, currPlayerDownsync.VelX: %d}\n", currPlayerDownsync.JoinIndex, currRenderFrame.Id, currPlayerDownsync.Speed, currPlayerDownsync.VelX)
}
*/
alignedWithInertia := true
exactTurningAround := false
if 0 == effDx && 0 != thatPlayerInNextFrame.VelX {
alignedWithInertia = false
} else if 0 != effDx && 0 == thatPlayerInNextFrame.VelX {
alignedWithInertia = false
} else if 0 > effDx*thatPlayerInNextFrame.VelX {
alignedWithInertia = false
exactTurningAround = true
}
if !jumpedOrNot && !isWallJumping && !prevCapturedByInertia && !alignedWithInertia {
/*
[WARNING] A "turn-around", or in more generic direction schema a "change in direction" is a hurdle for our current "prediction+rollback" approach, yet applying a "FramesToRecover" for "turn-around" can alleviate the graphical inconsistence to a huge extent! For better operational experience, this is intentionally NOT APPLIED TO WALL JUMPING!
When "false == alignedWithInertia", we're GUARANTEED TO BE WRONG AT INPUT PREDICTION ON THE FRONTEND, but we COULD STILL BE RIGHT AT POSITION PREDICTION WITHIN "InertiaFramesToRecover" -- which together with "INPUT_DELAY_FRAMES" grants the frontend a big chance to be graphically consistent even upon wrong prediction!
*/
//fmt.Printf("joinIndex=%d is not wall jumping and not aligned w/ inertia\n{renderFrame.id: %d, effDx: %d, thatPlayerInNextFrame.VelX: %d}\n", currPlayerDownsync.JoinIndex, currRenderFrame.Id, effDx, thatPlayerInNextFrame.VelX)
thatPlayerInNextFrame.CapturedByInertia = true
thatPlayerInNextFrame.FramesToRecover = chConfig.InertiaFramesToRecover
if exactTurningAround {
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_TURNAROUND
}
} else {
thatPlayerInNextFrame.CapturedByInertia = false
if 0 != effDx { if 0 != effDx {
xfac := int32(1) xfac := int32(1)
if 0 > effDx { if 0 > effDx {
@@ -635,10 +683,11 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
thatPlayerInNextFrame.DirX = effDx thatPlayerInNextFrame.DirX = effDx
thatPlayerInNextFrame.DirY = effDy thatPlayerInNextFrame.DirY = effDy
thatPlayerInNextFrame.VelX = xfac * currPlayerDownsync.Speed if isWallJumping {
if intAbs(thatPlayerInNextFrame.VelX) < intAbs(currPlayerDownsync.VelX) { //fmt.Printf("joinIndex=%d is controlling while wall jumping\n{renderFrame.id: %d, currPlayerDownsync.Speed: %d, currPlayerDownsync.VelX: %d, effDx: %d}\n", currPlayerDownsync.JoinIndex, currRenderFrame.Id, currPlayerDownsync.Speed, currPlayerDownsync.VelX, effDx)
// Wall jumping
thatPlayerInNextFrame.VelX = xfac * intAbs(currPlayerDownsync.VelX) thatPlayerInNextFrame.VelX = xfac * intAbs(currPlayerDownsync.VelX)
} else {
thatPlayerInNextFrame.VelX = xfac * currPlayerDownsync.Speed
} }
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_WALKING thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_WALKING
} else { } else {
@@ -646,6 +695,8 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
thatPlayerInNextFrame.VelX = 0 thatPlayerInNextFrame.VelX = 0
} }
} }
}
} }
// 2. Process player movement // 2. Process player movement
@@ -701,6 +752,8 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
if ATK_CHARACTER_STATE_ONWALL == currPlayerDownsync.CharacterState && !jumpedOrNotList[i] { if ATK_CHARACTER_STATE_ONWALL == currPlayerDownsync.CharacterState && !jumpedOrNotList[i] {
thatPlayerInNextFrame.VelX += GRAVITY_X thatPlayerInNextFrame.VelX += GRAVITY_X
thatPlayerInNextFrame.VelY = chConfig.WallSlidingVelY thatPlayerInNextFrame.VelY = chConfig.WallSlidingVelY
} else if ATK_CHARACTER_STATE_DASHING == currPlayerDownsync.CharacterState {
thatPlayerInNextFrame.VelX += GRAVITY_X
} else { } else {
thatPlayerInNextFrame.VelX += GRAVITY_X thatPlayerInNextFrame.VelX += GRAVITY_X
thatPlayerInNextFrame.VelY += GRAVITY_Y thatPlayerInNextFrame.VelY += GRAVITY_Y
@@ -1016,7 +1069,7 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
if thatPlayerInNextFrame.InAir { if thatPlayerInNextFrame.InAir {
oldNextCharacterState := thatPlayerInNextFrame.CharacterState oldNextCharacterState := thatPlayerInNextFrame.CharacterState
switch oldNextCharacterState { switch oldNextCharacterState {
case ATK_CHARACTER_STATE_IDLE1, ATK_CHARACTER_STATE_WALKING: case ATK_CHARACTER_STATE_IDLE1, ATK_CHARACTER_STATE_WALKING, ATK_CHARACTER_STATE_TURNAROUND:
if thatPlayerInNextFrame.OnWall { if thatPlayerInNextFrame.OnWall {
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_ONWALL thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_ONWALL
} else if jumpedOrNotList[i] || ATK_CHARACTER_STATE_INAIR_IDLE1_BY_JUMP == currPlayerDownsync.CharacterState { } else if jumpedOrNotList[i] || ATK_CHARACTER_STATE_INAIR_IDLE1_BY_JUMP == currPlayerDownsync.CharacterState {

View File

@@ -17,6 +17,7 @@ type CharacterConfig struct {
Speed int32 Speed int32
JumpingInitVelY int32 JumpingInitVelY int32
JumpingFramesToRecover int32 // Not used yet
DashingEnabled bool DashingEnabled bool
OnWallEnabled bool OnWallEnabled bool
@@ -25,6 +26,8 @@ type CharacterConfig struct {
WallJumpingInitVelY int32 WallJumpingInitVelY int32
WallSlidingVelY int32 WallSlidingVelY int32
InertiaFramesToRecover int32
SkillMapper SkillMapperType SkillMapper SkillMapperType
} }
@@ -42,8 +45,11 @@ var Characters = map[int]*CharacterConfig{
GetUpInvinsibleFrames: int32(10), GetUpInvinsibleFrames: int32(10),
GetUpFramesToRecover: int32(27), GetUpFramesToRecover: int32(27),
Speed: int32(float64(3.0) * WORLD_TO_VIRTUAL_GRID_RATIO), Speed: int32(float64(2.1) * WORLD_TO_VIRTUAL_GRID_RATIO),
JumpingInitVelY: int32(float64(8) * WORLD_TO_VIRTUAL_GRID_RATIO), JumpingInitVelY: int32(float64(8) * WORLD_TO_VIRTUAL_GRID_RATIO),
JumpingFramesToRecover: int32(2),
InertiaFramesToRecover: int32(9),
DashingEnabled: false, DashingEnabled: false,
OnWallEnabled: false, OnWallEnabled: false,
@@ -88,13 +94,16 @@ var Characters = map[int]*CharacterConfig{
GetUpInvinsibleFrames: int32(10), GetUpInvinsibleFrames: int32(10),
GetUpFramesToRecover: int32(27), GetUpFramesToRecover: int32(27),
Speed: int32(float64(4.0) * WORLD_TO_VIRTUAL_GRID_RATIO), Speed: int32(float64(2.19) * WORLD_TO_VIRTUAL_GRID_RATIO), // I don't know why "2.2" is so special that it throws a compile error
JumpingInitVelY: int32(float64(7.5) * WORLD_TO_VIRTUAL_GRID_RATIO), JumpingInitVelY: int32(float64(7.5) * WORLD_TO_VIRTUAL_GRID_RATIO),
JumpingFramesToRecover: int32(2),
InertiaFramesToRecover: int32(9),
DashingEnabled: true, DashingEnabled: true,
OnWallEnabled: true, OnWallEnabled: true,
WallJumpingFramesToRecover: int32(9), // 8 would be the minimum for an avg human WallJumpingFramesToRecover: int32(8), // 8 would be the minimum for an avg human
WallJumpingInitVelX: int32(float64(2.5) * WORLD_TO_VIRTUAL_GRID_RATIO), // Default is "appeared facing right", but actually holding ctrl against left WallJumpingInitVelX: int32(float64(2.8) * WORLD_TO_VIRTUAL_GRID_RATIO), // Default is "appeared facing right", but actually holding ctrl against left
WallJumpingInitVelY: int32(float64(7) * WORLD_TO_VIRTUAL_GRID_RATIO), WallJumpingInitVelY: int32(float64(7) * WORLD_TO_VIRTUAL_GRID_RATIO),
WallSlidingVelY: int32(float64(-1) * WORLD_TO_VIRTUAL_GRID_RATIO), WallSlidingVelY: int32(float64(-1) * WORLD_TO_VIRTUAL_GRID_RATIO),
@@ -119,6 +128,9 @@ var Characters = map[int]*CharacterConfig{
} }
} }
} }
} else if 5 == patternId {
// Dashing is already constrained by "FramesToRecover & CapturedByInertia" in "deriveOpPattern"
return 12
} }
// By default no skill can be fired // By default no skill can be fired
@@ -138,8 +150,11 @@ var Characters = map[int]*CharacterConfig{
GetUpInvinsibleFrames: int32(8), GetUpInvinsibleFrames: int32(8),
GetUpFramesToRecover: int32(30), GetUpFramesToRecover: int32(30),
Speed: int32(float64(3.0) * WORLD_TO_VIRTUAL_GRID_RATIO), Speed: int32(float64(1.8) * WORLD_TO_VIRTUAL_GRID_RATIO),
JumpingInitVelY: int32(float64(7.5) * WORLD_TO_VIRTUAL_GRID_RATIO), JumpingInitVelY: int32(float64(7.8) * WORLD_TO_VIRTUAL_GRID_RATIO),
JumpingFramesToRecover: int32(2),
InertiaFramesToRecover: int32(9),
DashingEnabled: false, DashingEnabled: false,
OnWallEnabled: false, OnWallEnabled: false,
@@ -166,11 +181,11 @@ var Characters = map[int]*CharacterConfig{
} }
} }
} else if 2 == patternId { } else if 2 == patternId {
if !currPlayerDownsync.InAir { if 0 == currPlayerDownsync.FramesToRecover && !currPlayerDownsync.InAir {
return 11 return 11
} }
} else if 3 == patternId { } else if 3 == patternId {
if !currPlayerDownsync.InAir { if 0 == currPlayerDownsync.FramesToRecover && !currPlayerDownsync.InAir {
return 10 return 10
} }
} }
@@ -302,7 +317,7 @@ var skills = map[int]*Skill{
HitboxOffsetY: int32(0), HitboxOffsetY: int32(0),
HitboxSizeX: int32(float64(24) * WORLD_TO_VIRTUAL_GRID_RATIO), HitboxSizeX: int32(float64(24) * WORLD_TO_VIRTUAL_GRID_RATIO),
HitboxSizeY: int32(float64(32) * WORLD_TO_VIRTUAL_GRID_RATIO), HitboxSizeY: int32(float64(32) * WORLD_TO_VIRTUAL_GRID_RATIO),
CancellableStFrame: int32(8), CancellableStFrame: int32(13),
CancellableEdFrame: int32(30), CancellableEdFrame: int32(30),
CancelTransit: map[int]int{ CancelTransit: map[int]int{
@@ -337,7 +352,7 @@ var skills = map[int]*Skill{
HitboxOffsetY: int32(0), HitboxOffsetY: int32(0),
HitboxSizeX: int32(float64(24) * WORLD_TO_VIRTUAL_GRID_RATIO), HitboxSizeX: int32(float64(24) * WORLD_TO_VIRTUAL_GRID_RATIO),
HitboxSizeY: int32(float64(32) * WORLD_TO_VIRTUAL_GRID_RATIO), HitboxSizeY: int32(float64(32) * WORLD_TO_VIRTUAL_GRID_RATIO),
CancellableStFrame: int32(19), CancellableStFrame: int32(23),
CancellableEdFrame: int32(36), CancellableEdFrame: int32(36),
CancelTransit: map[int]int{ CancelTransit: map[int]int{
1: 6, 1: 6,
@@ -496,7 +511,7 @@ var skills = map[int]*Skill{
PushbackVelX: int32(float64(2) * WORLD_TO_VIRTUAL_GRID_RATIO), PushbackVelX: int32(float64(2) * WORLD_TO_VIRTUAL_GRID_RATIO),
PushbackVelY: int32(0), PushbackVelY: int32(0),
HitboxOffsetX: int32(float64(24) * WORLD_TO_VIRTUAL_GRID_RATIO), HitboxOffsetX: int32(float64(24) * WORLD_TO_VIRTUAL_GRID_RATIO),
HitboxOffsetY: int32(float64(5) * WORLD_TO_VIRTUAL_GRID_RATIO), HitboxOffsetY: int32(float64(8) * WORLD_TO_VIRTUAL_GRID_RATIO),
HitboxSizeX: int32(float64(48) * WORLD_TO_VIRTUAL_GRID_RATIO), HitboxSizeX: int32(float64(48) * WORLD_TO_VIRTUAL_GRID_RATIO),
HitboxSizeY: int32(float64(32) * WORLD_TO_VIRTUAL_GRID_RATIO), HitboxSizeY: int32(float64(32) * WORLD_TO_VIRTUAL_GRID_RATIO),
BlowUp: false, BlowUp: false,
@@ -535,6 +550,33 @@ var skills = map[int]*Skill{
}, },
}, },
}, },
12: &Skill{
RecoveryFrames: int32(12),
RecoveryFramesOnBlock: int32(12),
RecoveryFramesOnHit: int32(12),
ReleaseTriggerType: int32(1),
BoundChState: ATK_CHARACTER_STATE_DASHING,
Hits: []interface{}{
&MeleeBullet{
Bullet: &BulletConfig{
StartupFrames: int32(0),
ActiveFrames: int32(0),
HitStunFrames: MAX_INT32,
BlockStunFrames: int32(0),
Damage: int32(0),
SelfLockVelX: int32(float64(9) * WORLD_TO_VIRTUAL_GRID_RATIO),
SelfLockVelY: int32(0),
PushbackVelX: NO_LOCK_VEL,
PushbackVelY: NO_LOCK_VEL,
HitboxOffsetX: int32(0),
HitboxOffsetY: int32(0),
HitboxSizeX: int32(0),
HitboxSizeY: int32(0),
BlowUp: false,
},
},
},
},
255: &Skill{ 255: &Skill{
RecoveryFrames: int32(30), RecoveryFrames: int32(30),
RecoveryFramesOnBlock: int32(30), RecoveryFramesOnBlock: int32(30),

View File

@@ -37,6 +37,8 @@ type PlayerDownsync struct {
OnWallNormX int32 OnWallNormX int32
OnWallNormY int32 OnWallNormY int32
CapturedByInertia bool
ActiveSkillId int32 ActiveSkillId int32
ActiveSkillHit int32 ActiveSkillHit int32

View File

@@ -42,7 +42,7 @@ func NewBarrierJs(boundary *Polygon2D) *js.Object {
}) })
} }
func NewPlayerDownsyncJs(id, virtualGridX, virtualGridY, dirX, dirY, velX, velY, framesToRecover, framesInChState, activeSkillId, activeSkillHit, framesInvinsible, speed, battleState, characterState, joinIndex, hp, maxHp, colliderRadius int32, inAir, onWall bool, onWallNormX, onWallNormY, bulletTeamId, chCollisionTeamId int32) *js.Object { func NewPlayerDownsyncJs(id, virtualGridX, virtualGridY, dirX, dirY, velX, velY, framesToRecover, framesInChState, activeSkillId, activeSkillHit, framesInvinsible, speed, battleState, characterState, joinIndex, hp, maxHp, colliderRadius int32, inAir, onWall bool, onWallNormX, onWallNormY int32, capturedByInertia bool, bulletTeamId, chCollisionTeamId int32) *js.Object {
return js.MakeWrapper(&PlayerDownsync{ return js.MakeWrapper(&PlayerDownsync{
Id: id, Id: id,
VirtualGridX: virtualGridX, VirtualGridX: virtualGridX,
@@ -67,6 +67,7 @@ func NewPlayerDownsyncJs(id, virtualGridX, virtualGridY, dirX, dirY, velX, velY,
OnWall: onWall, OnWall: onWall,
OnWallNormX: onWallNormX, OnWallNormX: onWallNormX,
OnWallNormY: onWallNormY, OnWallNormY: onWallNormY,
CapturedByInertia: capturedByInertia,
BulletTeamId: bulletTeamId, BulletTeamId: bulletTeamId,
ChCollisionTeamId: chCollisionTeamId, ChCollisionTeamId: chCollisionTeamId,
}) })

View File

@@ -66,4 +66,21 @@ hp application/json application/javascript;
proxy_pass http://tsrht_cluster/tsrht$is_args$args; proxy_pass http://tsrht_cluster/tsrht$is_args$args;
} }
location ~^/tsrhtSecondary$ {
# Reference http://www.tornadoweb.org/en/stable/guide/running.html
proxy_pass_header Server;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Scheme $scheme;
# Reverse-proxy for ws connection.
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://tsrht_cluster/tsrhtSecondary$is_args$args;
}
} }