Compare commits

...

32 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
genxium
71b9e72592 Minor fix. 2023-01-17 15:16:31 +08:00
genxium
21b48b7c0d Updated frontend input generation. 2023-01-17 13:07:26 +08:00
genxium
fbfca965e6 Minor update. 2023-01-17 12:49:49 +08:00
genxium
b27b567c77 Fixed frontend action triggers. 2023-01-17 12:48:51 +08:00
genxium
e9119530f1 Updated README for UDP discussion. 2023-01-16 23:25:40 +08:00
genxium
e6a4295773 Updated charts in README. 2023-01-15 17:43:02 +08:00
Wing
aa14529bf8 Merge pull request #19 from genxium/explosion
Drafted bullet explosion data structure.
2023-01-15 17:23:52 +08:00
genxium
84af0d1572 Drafted bullet explosion data structure. 2023-01-15 17:21:34 +08:00
genxium
16fb23c376 Updated charts and refs in README. 2023-01-14 23:06:45 +08:00
genxium
d1f8a58154 Updated README. 2023-01-14 09:35:56 +08:00
88 changed files with 10105 additions and 6252 deletions

View File

@@ -47,3 +47,32 @@ renderFrameId | toApplyInputFrameId
..., ..., ..., 368 | 90
369, 370, 371, 372 | 91
373, 374, 375, ... | 92
# Would using UDP instead of TCP yield better synchronization performance?
Yes, but with non-trivial efforts.
## Neat advantage using UDP
Let's check an actual use case. As soon as an inputFrame becomes all-confirmed, the server should downsync it to all active players -- and upon reception loss of the packet containing this "all-confirmed downsync inputFrame" to a certain player, the server MUST retransmit another packet containing the same inputFrame to that player.
To apply UDP on this use case, additional `ack & retransmission mechanism` would be required, which is a moderately difficult task -- don't just pick a 3rd party lib using TCP flow-control alike `sliding window mechanism`, e.g. [RUDP](https://www.geeksforgeeks.org/reliable-user-datagram-protocol-rudp/)! Here's why.
Assume that the server is downsyncing `sequence of packets[#1, #2, #3, #4, #5, #6, #7, #8, #9, #10]`, when using TCP we get the advantage that each active player is guaranteed to receive that same sequence in the same order -- however in a bad, lossy network when `packet#2` got lost several times for a certain player whose reception window size is just 5, it has to wait for the arrival of `packet#2` at `[_, #3, #4, #5, #6]`, thus unable to process `[#7, #8, #9, #10]` which could contain `unpredictable inputFrame` while `#2` being `correct prediction` for that player.
That's so neat but still an advantage for using UDP! Yet if the TCP flow-control alike `sliding window mechanism` is employed on UDP, such advantage'd be compromised.
To summarize, if UDP is used we need
- an `ack & retransmission mechanism` built on top of it to guarantee reception of critical packets for active players, and
- reception order is not necessary to be reserved (mimic [markConfirmationIfApplicable](https://github.com/genxium/DelayNoMore/blob/v0.9.14/battle_srv/models/room.go#L1085) to maintain `lastAllConfirmedInputFrameId`), but
- TCP flow-control alike `sliding window mechanism` should be avoided to gain advantage over TCP.
## 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.
## 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

@@ -1,27 +1,33 @@
# Preface
This project is a demo for a websocket-based rollback netcode inspired by [GGPO](https://github.com/pond3r/ggpo/blob/master/doc/README.md).
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 gifs are sped up to ~1.5x for file size reduction, kindly note that animations are resumed from a partial progress)_
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)
![gif_demo](./charts/internet_fireball_wallmoveset_spedup.gif)
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](./charts/jump_sync_spedup.gif)
![gif_demo_1](./charts/internet_fireball_explosion_wallmove_spedup.gif)
Please also checkout [this demo video](https://pan.baidu.com/s/1_DAEuE66s5Obf2GwtVul4Q?pwd=mfpq) 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_2](./charts/internet_dash_turnaround_cut_spedup.gif)
The video mainly shows the following features.
- The backend receives inputs from frontend peers and broadcasts back for synchronization.
- The game is recovered for a player upon reconnection.
- Both backend(Golang) and frontend(JavaScript) execute collision detection and handle collision contacts by the same algorithm. The backend dynamics is togglable by [Room.BackendDynamicsEnabled](https://github.com/genxium/DelayNoMore/blob/v0.5.2/battle_srv/models/room.go#L813), but **when turned off the game couldn't support recovery upon reconnection**.
# Notable Features
- Backend dynamics toggle via [Room.BackendDynamicsEnabled](https://github.com/genxium/DelayNoMore/blob/v0.9.14/battle_srv/models/room.go#L786)
- Recovery upon reconnection (only if backend dynamics is ON)
- Automatically correction for "slow ticker", especially "active slow ticker" which is well-known to be a headache for input synchronization
- Frame data logging toggle for both frontend & backend, useful for debugging out of sync entities when developing new features
_(how input delay roughly works)_
![input_delay_intro](./charts/InputDelayIntro.jpg)
_(how rollback-and-chase in this project roughly works)_
_(how rollback-and-chase in this project roughly works, kindly note that by the current implementation, each frontend only maintains a `lastAllConfirmedInputFrameId` for all the other peers, because the backend only downsyncs all-confirmed inputFrames, see [markConfirmationIfApplicable](https://github.com/genxium/DelayNoMore/blob/v0.9.14/battle_srv/models/room.go#L1085) for more information -- if a serverless peer-to-peer communication is seriously needed here, consider porting [markConfirmationIfApplicable](https://github.com/genxium/DelayNoMore/blob/v0.9.14/battle_srv/models/room.go#L1085) into frontend for maintaining `lastAllConfirmedInputFrameId` under chaotic reception order of inputFrames from peers)_
![server_clients](./charts/ServerClients.jpg)
![rollback_and_chase_intro](./charts/RollbackAndChase.jpg)
(By use of [GopherJs](https://github.com/gopherjs/gopherjs), the frontend codes for dynamics are now automatically generated)
![floating_point_accumulation_err](./charts/AvoidingFloatingPointAccumulationErr.jpg)
# 1. Building & running
@@ -63,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
```
## 1.2 Actual building & running
## 1.3 Actual building & running
### 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
@@ -92,3 +98,14 @@ ErrFatal {"err": "MISCONF Redis is configured to save RDB snapshots, but
```
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.GET("/ping", f)
router.GET("/tsrht", ws.Serve)
router.GET("/tsrhtSecondary", ws.HandleSecondaryWsSessionForPlayer)
apiRouter := router.Group("/api")
{

View File

@@ -41,6 +41,7 @@ func toPbRoomDownsyncFrame(rdf *battle.RoomDownsyncFrame) *pb.RoomDownsyncFrame
OnWall: last.OnWall,
OnWallNormX: last.OnWallNormX,
OnWallNormY: last.OnWallNormY,
CapturedByInertia: last.CapturedByInertia,
JoinIndex: last.JoinIndex,
BulletTeamId: last.BulletTeamId,
ChCollisionTeamId: last.ChCollisionTeamId,
@@ -58,7 +59,7 @@ func toPbRoomDownsyncFrame(rdf *battle.RoomDownsyncFrame) *pb.RoomDownsyncFrame
BulletLocalId: last.BattleAttr.BulletLocalId,
OriginatedRenderFrameId: last.BattleAttr.OriginatedRenderFrameId,
OffenderJoinIndex: last.BattleAttr.OffenderJoinIndex,
TeamId: last.BattleAttr.TeamId,
TeamId: last.BattleAttr.TeamId,
StartupFrames: last.Bullet.StartupFrames,
CancellableStFrame: last.Bullet.CancellableStFrame,
@@ -80,6 +81,12 @@ func toPbRoomDownsyncFrame(rdf *battle.RoomDownsyncFrame) *pb.RoomDownsyncFrame
HitboxSizeY: last.Bullet.HitboxSizeY,
BlowUp: last.Bullet.BlowUp,
SpeciesId: last.Bullet.SpeciesId,
ExplosionFrames: last.Bullet.ExplosionFrames,
BlState: last.BlState,
FramesInBlState: last.FramesInBlState,
}
ret.MeleeBullets[i] = pbBullet
}
@@ -89,7 +96,7 @@ func toPbRoomDownsyncFrame(rdf *battle.RoomDownsyncFrame) *pb.RoomDownsyncFrame
BulletLocalId: last.BattleAttr.BulletLocalId,
OriginatedRenderFrameId: last.BattleAttr.OriginatedRenderFrameId,
OffenderJoinIndex: last.BattleAttr.OffenderJoinIndex,
TeamId: last.BattleAttr.TeamId,
TeamId: last.BattleAttr.TeamId,
StartupFrames: last.Bullet.StartupFrames,
CancellableStFrame: last.Bullet.CancellableStFrame,
@@ -112,6 +119,12 @@ func toPbRoomDownsyncFrame(rdf *battle.RoomDownsyncFrame) *pb.RoomDownsyncFrame
BlowUp: last.Bullet.BlowUp,
SpeciesId: last.Bullet.SpeciesId,
ExplosionFrames: last.Bullet.ExplosionFrames,
BlState: last.BlState,
FramesInBlState: last.FramesInBlState,
VirtualGridX: last.VirtualGridX,
VirtualGridY: last.VirtualGridY,
DirX: last.DirX,
@@ -119,7 +132,6 @@ func toPbRoomDownsyncFrame(rdf *battle.RoomDownsyncFrame) *pb.RoomDownsyncFrame
VelX: last.VelX,
VelY: last.VelY,
Speed: last.Speed,
SpeciesId: last.SpeciesId,
}
ret.FireballBullets[i] = pbBullet
}
@@ -154,6 +166,7 @@ func toPbPlayers(modelInstances map[int32]*Player, withMetaInfo bool) []*pb.Play
OnWall: last.OnWall,
OnWallNormX: last.OnWallNormX,
OnWallNormY: last.OnWallNormY,
CapturedByInertia: last.CapturedByInertia,
JoinIndex: last.JoinIndex,
BulletTeamId: last.BulletTeamId,
ChCollisionTeamId: last.ChCollisionTeamId,
@@ -205,6 +218,7 @@ func toJsPlayers(modelInstances map[int32]*Player) []*battle.PlayerDownsync {
OnWall: last.OnWall,
OnWallNormX: last.OnWallNormX,
OnWallNormY: last.OnWallNormY,
CapturedByInertia: last.CapturedByInertia,
Score: last.Score,
Removed: last.Removed,
}

View File

@@ -27,10 +27,11 @@ const (
UPSYNC_MSG_ACT_PLAYER_CMD = int32(2)
UPSYNC_MSG_ACT_PLAYER_COLLIDER_ACK = int32(3)
DOWNSYNC_MSG_ACT_HB_REQ = int32(1)
DOWNSYNC_MSG_ACT_INPUT_BATCH = int32(2)
DOWNSYNC_MSG_ACT_BATTLE_STOPPED = int32(3)
DOWNSYNC_MSG_ACT_FORCED_RESYNC = int32(4)
DOWNSYNC_MSG_ACT_HB_REQ = int32(1)
DOWNSYNC_MSG_ACT_INPUT_BATCH = int32(2)
DOWNSYNC_MSG_ACT_BATTLE_STOPPED = int32(3)
DOWNSYNC_MSG_ACT_FORCED_RESYNC = int32(4)
DOWNSYNC_MSG_ACT_PEER_INPUT_BATCH = int32(5)
DOWNSYNC_MSG_ACT_BATTLE_READY_TO_START = int32(-1)
DOWNSYNC_MSG_ACT_BATTLE_START = int32(0)
@@ -116,10 +117,15 @@ type Room struct {
*
* Moreover, during the invocation of `PlayerSignalToCloseDict`, the `Player` instance is supposed to be deallocated (though not synchronously).
*/
PlayerDownsyncSessionDict map[int32]*websocket.Conn
PlayerDownsyncChanDict map[int32](chan pb.InputsBufferSnapshot)
PlayerDownsyncSessionDict map[int32]*websocket.Conn
PlayerSignalToCloseDict map[int32]SignalToCloseConnCbType
PlayerDownsyncChanDict map[int32](chan pb.InputsBufferSnapshot)
PlayerSecondaryDownsyncSessionDict map[int32]*websocket.Conn
PlayerSecondarySignalToCloseDict map[int32]SignalToCloseConnCbType
PlayerSecondaryDownsyncChanDict map[int32](chan pb.InputsBufferSnapshot)
PlayerActiveWatchdogDict map[int32](*Watchdog)
PlayerSignalToCloseDict map[int32]SignalToCloseConnCbType
Score float32
State int32
Index int
@@ -184,7 +190,7 @@ func (pR *Room) AddPlayerIfPossible(pPlayerFromDbInit *Player, session *websocke
pR.PlayerSignalToCloseDict[playerId] = signalToCloseConnOfThisPlayer
newWatchdog := NewWatchdog(ConstVals.Ws.WillKickIfInactiveFor, func() {
Logger.Warn("Conn inactive watchdog triggered#1:", zap.Any("playerId", playerId), zap.Any("roomId", pR.Id), zap.Any("roomState", pR.State), zap.Any("roomEffectivePlayerCount", pR.EffectivePlayerCount))
signalToCloseConnOfThisPlayer(Constants.RetCode.ActiveWatchdog, "")
pR.signalToCloseAllSessionsOfPlayer(playerId, Constants.RetCode.ActiveWatchdog)
})
newWatchdog.Stop()
pR.PlayerActiveWatchdogDict[playerId] = newWatchdog
@@ -221,7 +227,7 @@ func (pR *Room) ReAddPlayerIfPossible(pTmpPlayerInstance *Player, session *webso
pR.PlayerSignalToCloseDict[playerId] = signalToCloseConnOfThisPlayer
pR.PlayerActiveWatchdogDict[playerId] = NewWatchdog(ConstVals.Ws.WillKickIfInactiveFor, func() {
Logger.Warn("Conn inactive watchdog triggered#2:", zap.Any("playerId", playerId), zap.Any("roomId", pR.Id), zap.Any("roomState", pR.State), zap.Any("roomEffectivePlayerCount", pR.EffectivePlayerCount))
signalToCloseConnOfThisPlayer(Constants.RetCode.ActiveWatchdog, "")
pR.signalToCloseAllSessionsOfPlayer(playerId, Constants.RetCode.ActiveWatchdog)
}) // For ReAdded player the new watchdog starts immediately
Logger.Warn("ReAddPlayerIfPossible finished.", zap.Any("roomId", pR.Id), zap.Any("playerId", playerId), zap.Any("joinIndex", pEffectiveInRoomPlayerInstance.JoinIndex), zap.Any("playerBattleState", pEffectiveInRoomPlayerInstance.BattleState), zap.Any("roomState", pR.State), zap.Any("roomEffectivePlayerCount", pR.EffectivePlayerCount), zap.Any("AckingFrameId", pEffectiveInRoomPlayerInstance.AckingFrameId), zap.Any("AckingInputFrameId", pEffectiveInRoomPlayerInstance.AckingInputFrameId), zap.Any("LastSentInputFrameId", pEffectiveInRoomPlayerInstance.LastSentInputFrameId))
@@ -482,7 +488,7 @@ func (pR *Room) StartBattle() {
kickoffFrameJs := pR.RenderFrameBuffer.GetByFrameId(0).(*battle.RoomDownsyncFrame)
pbKickOffRenderFrame := toPbRoomDownsyncFrame(kickoffFrameJs)
pbKickOffRenderFrame.SpeciesIdList = pR.SpeciesIdList
pR.sendSafely(pbKickOffRenderFrame, nil, DOWNSYNC_MSG_ACT_BATTLE_START, playerId, true)
pR.sendSafely(pbKickOffRenderFrame, nil, DOWNSYNC_MSG_ACT_BATTLE_START, playerId, true, MAGIC_JOIN_INDEX_DEFAULT)
}
Logger.Info(fmt.Sprintf("In `battleMainLoop` for roomId=%v sent out kickoffFrame", pR.Id))
}
@@ -509,7 +515,7 @@ func (pR *Room) StartBattle() {
}
}
downsyncLoop := func(playerId int32, player *Player, playerDownsyncChan chan pb.InputsBufferSnapshot) {
downsyncLoop := func(playerId int32, player *Player, playerDownsyncChan chan pb.InputsBufferSnapshot, playerSecondaryDownsyncChan chan pb.InputsBufferSnapshot) {
defer func() {
if r := recover(); r != nil {
Logger.Error("downsyncLoop, recovery spot#1, recovered from: ", zap.Any("roomId", pR.Id), zap.Any("playerId", playerId), zap.Any("panic", r))
@@ -517,19 +523,23 @@ func (pR *Room) StartBattle() {
Logger.Info(fmt.Sprintf("The `downsyncLoop` for (roomId=%v, playerId=%v) is stopped@renderFrameId=%v", pR.Id, playerId, pR.RenderFrameId))
}()
Logger.Debug(fmt.Sprintf("Started downsyncLoop for (roomId: %d, playerId:%d, playerDownsyncChan:%p)", pR.Id, playerId, playerDownsyncChan))
//Logger.Info(fmt.Sprintf("Started downsyncLoop for (roomId: %d, playerId:%d, playerDownsyncChan:%p)", pR.Id, playerId, playerDownsyncChan))
for {
nowBattleState := atomic.LoadInt32(&pR.State)
switch nowBattleState {
case RoomBattleStateIns.IDLE, RoomBattleStateIns.STOPPING_BATTLE_FOR_SETTLEMENT, RoomBattleStateIns.IN_SETTLEMENT, RoomBattleStateIns.IN_DISMISSAL:
Logger.Warn(fmt.Sprintf("Battle is not waiting/preparing/active for playerDownsyncChan for (roomId: %d, playerId:%d)", pR.Id, playerId))
return
}
select {
case inputsBufferSnapshot := <-playerDownsyncChan:
nowBattleState := atomic.LoadInt32(&pR.State)
switch nowBattleState {
case RoomBattleStateIns.IDLE, RoomBattleStateIns.STOPPING_BATTLE_FOR_SETTLEMENT, RoomBattleStateIns.IN_SETTLEMENT, RoomBattleStateIns.IN_DISMISSAL:
Logger.Warn(fmt.Sprintf("Battle is not waiting/preparing/active for playerDownsyncChan for (roomId: %d, playerId:%d)", pR.Id, playerId))
return
}
pR.downsyncToSinglePlayer(playerId, player, inputsBufferSnapshot.RefRenderFrameId, inputsBufferSnapshot.UnconfirmedMask, inputsBufferSnapshot.ToSendInputFrameDownsyncs, inputsBufferSnapshot.ShouldForceResync)
//Logger.Info(fmt.Sprintf("Sent inputsBufferSnapshot(refRenderFrameId:%d, unconfirmedMask:%v) to for (roomId: %d, playerId:%d)#2", inputsBufferSnapshot.RefRenderFrameId, inputsBufferSnapshot.UnconfirmedMask, pR.Id, playerId))
case inputsBufferSnapshot2 := <-playerSecondaryDownsyncChan:
pR.downsyncPeerInputFrameUpsyncToSinglePlayer(playerId, player, inputsBufferSnapshot2.ToSendInputFrameDownsyncs, inputsBufferSnapshot2.PeerJoinIndex)
//Logger.Info(fmt.Sprintf("Sent secondary inputsBufferSnapshot to for (roomId: %d, playerId:%d)#2", pR.Id, playerId))
default:
}
}
@@ -542,7 +552,8 @@ func (pR *Room) StartBattle() {
Each "playerDownsyncChan" stays alive through out the lifecycle of room instead of each "playerDownsyncSession", i.e. not closed or dereferenced upon disconnection.
*/
pR.PlayerDownsyncChanDict[playerId] = make(chan pb.InputsBufferSnapshot, pR.InputsBuffer.N)
go downsyncLoop(playerId, player, pR.PlayerDownsyncChanDict[playerId])
pR.PlayerSecondaryDownsyncChanDict[playerId] = make(chan pb.InputsBufferSnapshot, pR.InputsBuffer.N)
go downsyncLoop(playerId, player, pR.PlayerDownsyncChanDict[playerId], pR.PlayerSecondaryDownsyncChanDict[playerId])
}
pR.onBattlePrepare(func() {
@@ -599,6 +610,16 @@ func (pR *Room) OnBattleCmdReceived(pReq *pb.WsReq) {
inputsBufferSnapshot := pR.markConfirmationIfApplicable(inputFrameUpsyncBatch, playerId, player)
if nil != inputsBufferSnapshot {
pR.downsyncToAllPlayers(inputsBufferSnapshot)
} else {
// no new all-confirmed
toSendInputFrameDownsyncs := pR.cloneInputsBuffer(inputFrameUpsyncBatch[0].InputFrameId, inputFrameUpsyncBatch[len(inputFrameUpsyncBatch)-1].InputFrameId+1)
inputsBufferSnapshot = &pb.InputsBufferSnapshot{
ToSendInputFrameDownsyncs: toSendInputFrameDownsyncs,
PeerJoinIndex: player.JoinIndex,
}
//Logger.Info(fmt.Sprintf("OnBattleCmdReceived no new all-confirmed: roomId=%v, fromPlayerId=%v, forming peer broadcasting snapshot=%v", pR.Id, playerId, inputsBufferSnapshot))
pR.broadcastPeerUpsyncForBetterPrediction(inputsBufferSnapshot)
}
}
@@ -650,7 +671,7 @@ func (pR *Room) StopBattleForSettlement() {
PlayersArr: toPbPlayers(pR.Players, false),
CountdownNanos: -1, // TODO: Replace this magic constant!
}
pR.sendSafely(&assembledFrame, nil, DOWNSYNC_MSG_ACT_BATTLE_STOPPED, playerId, true)
pR.sendSafely(&assembledFrame, nil, DOWNSYNC_MSG_ACT_BATTLE_STOPPED, playerId, true, MAGIC_JOIN_INDEX_DEFAULT)
}
// Note that `pR.onBattleStoppedForSettlement` will be called by `battleMainLoop`.
}
@@ -679,7 +700,7 @@ func (pR *Room) onBattlePrepare(cb BattleStartCbType) {
Logger.Info("Sending out frame for RoomBattleState.PREPARE:", zap.Any("battleReadyToStartFrame", battleReadyToStartFrame))
for _, player := range pR.Players {
pR.sendSafely(battleReadyToStartFrame, nil, DOWNSYNC_MSG_ACT_BATTLE_READY_TO_START, player.Id, true)
pR.sendSafely(battleReadyToStartFrame, nil, DOWNSYNC_MSG_ACT_BATTLE_READY_TO_START, player.Id, true, MAGIC_JOIN_INDEX_DEFAULT)
}
battlePreparationNanos := int64(6000000000)
@@ -748,6 +769,7 @@ func (pR *Room) OnDismissed() {
pR.CharacterConfigsArr = make([]*battle.CharacterConfig, pR.Capacity)
pR.CollisionSysMap = make(map[int32]*resolv.Object)
pR.PlayerDownsyncSessionDict = make(map[int32]*websocket.Conn)
pR.PlayerSecondaryDownsyncSessionDict = make(map[int32]*websocket.Conn)
for _, oldWatchdog := range pR.PlayerActiveWatchdogDict {
oldWatchdog.Stop()
}
@@ -756,7 +778,12 @@ func (pR *Room) OnDismissed() {
close(oldChan)
}
pR.PlayerDownsyncChanDict = make(map[int32](chan pb.InputsBufferSnapshot))
for _, oldChan := range pR.PlayerSecondaryDownsyncChanDict {
close(oldChan)
}
pR.PlayerSecondaryDownsyncChanDict = make(map[int32](chan pb.InputsBufferSnapshot))
pR.PlayerSignalToCloseDict = make(map[int32]SignalToCloseConnCbType)
pR.PlayerSecondarySignalToCloseDict = make(map[int32]SignalToCloseConnCbType)
pR.JoinIndexBooleanArr = make([]bool, pR.Capacity)
pR.RenderCacheSize = 1024
pR.RenderFrameBuffer = battle.NewRingBuffer(pR.RenderCacheSize)
@@ -781,7 +808,7 @@ func (pR *Room) OnDismissed() {
pR.BattleDurationFrames = int32(60 * serverFps)
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.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.ForceAllResyncOnAnyActiveSlowTicker = true // See tradeoff discussion in "downsyncToAllPlayers"
@@ -799,19 +826,24 @@ func (pR *Room) OnDismissed() {
}
func (pR *Room) expelPlayerDuringGame(playerId int32) {
if signalToCloseConnOfThisPlayer, existent := pR.PlayerSignalToCloseDict[playerId]; existent {
signalToCloseConnOfThisPlayer(Constants.RetCode.UnknownError, "") // TODO: Specify an error code
}
pR.signalToCloseAllSessionsOfPlayer(playerId, Constants.RetCode.UnknownError)
pR.onPlayerExpelledDuringGame(playerId)
}
func (pR *Room) expelPlayerForDismissal(playerId int32) {
if signalToCloseConnOfThisPlayer, existent := pR.PlayerSignalToCloseDict[playerId]; existent {
signalToCloseConnOfThisPlayer(Constants.RetCode.UnknownError, "") // TODO: Specify an error code
}
pR.signalToCloseAllSessionsOfPlayer(playerId, Constants.RetCode.UnknownError)
pR.onPlayerExpelledForDismissal(playerId)
}
func (pR *Room) signalToCloseAllSessionsOfPlayer(playerId int32, retCode int) {
if signalToCloseConnOfThisPlayer, existent := pR.PlayerSignalToCloseDict[playerId]; existent {
signalToCloseConnOfThisPlayer(retCode, "") // TODO: Specify an error code
}
if signalToCloseConnOfThisPlayer2, existent2 := pR.PlayerSecondarySignalToCloseDict[playerId]; existent2 {
signalToCloseConnOfThisPlayer2(retCode, "") // TODO: Specify an error code
}
}
func (pR *Room) onPlayerExpelledDuringGame(playerId int32) {
pR.onPlayerLost(playerId)
}
@@ -829,6 +861,10 @@ func (pR *Room) OnPlayerDisconnected(playerId int32) {
}
}()
if signalToCloseConnOfThisPlayer2, existent2 := pR.PlayerSecondarySignalToCloseDict[playerId]; existent2 {
signalToCloseConnOfThisPlayer2(Constants.RetCode.UnknownError, "") // TODO: Specify an error code
}
if player, existent := pR.Players[playerId]; existent {
thatPlayerBattleState := atomic.LoadInt32(&(player.BattleState))
switch thatPlayerBattleState {
@@ -888,6 +924,8 @@ func (pR *Room) clearPlayerNetworkSession(playerId int32) {
delete(pR.PlayerActiveWatchdogDict, playerId)
delete(pR.PlayerDownsyncSessionDict, playerId)
delete(pR.PlayerSignalToCloseDict, playerId)
delete(pR.PlayerSecondaryDownsyncSessionDict, playerId)
delete(pR.PlayerSecondarySignalToCloseDict, playerId)
}
}
@@ -977,7 +1015,7 @@ func (pR *Room) OnPlayerBattleColliderAcked(playerId int32) bool {
Logger.Debug(fmt.Sprintf("OnPlayerBattleColliderAcked-middle: roomId=%v, roomState=%v, targetPlayerId=%v, targetPlayerBattleState=%v, thatPlayerId=%v, thatPlayerBattleState=%v", pR.Id, pR.State, targetPlayer.Id, targetPlayer.BattleState, thatPlayer.Id, thatPlayerBattleState))
if thatPlayerId == targetPlayer.Id || (PlayerBattleStateIns.ADDED_PENDING_BATTLE_COLLIDER_ACK == thatPlayerBattleState || PlayerBattleStateIns.ACTIVE == thatPlayerBattleState) {
Logger.Debug(fmt.Sprintf("OnPlayerBattleColliderAcked-sending DOWNSYNC_MSG_ACT_PLAYER_ADDED_AND_ACKED: roomId=%v, roomState=%v, targetPlayerId=%v, targetPlayerBattleState=%v, capacity=%v, EffectivePlayerCount=%v", pR.Id, pR.State, targetPlayer.Id, targetPlayer.BattleState, pR.Capacity, pR.EffectivePlayerCount))
pR.sendSafely(playerAckedFrame, nil, DOWNSYNC_MSG_ACT_PLAYER_ADDED_AND_ACKED, thatPlayer.Id, true)
pR.sendSafely(playerAckedFrame, nil, DOWNSYNC_MSG_ACT_PLAYER_ADDED_AND_ACKED, thatPlayer.Id, true, MAGIC_JOIN_INDEX_DEFAULT)
}
}
atomic.StoreInt32(&(targetPlayer.BattleState), PlayerBattleStateIns.ACTIVE)
@@ -1010,28 +1048,43 @@ func (pR *Room) OnPlayerBattleColliderAcked(playerId int32) bool {
return true
}
func (pR *Room) sendSafely(roomDownsyncFrame *pb.RoomDownsyncFrame, toSendInputFrameDownsyncs []*pb.InputFrameDownsync, act int32, playerId int32, needLockExplicitly bool) {
func (pR *Room) sendSafely(roomDownsyncFrame *pb.RoomDownsyncFrame, toSendInputFrameDownsyncs []*pb.InputFrameDownsync, act int32, playerId int32, needLockExplicitly bool, peerJoinIndex int32) {
defer func() {
if r := recover(); r != nil {
Logger.Error("sendSafely, recovered from: ", zap.Any("roomId", pR.Id), zap.Any("playerId", playerId), zap.Any("panic", r))
}
}()
if playerDownsyncSession, existent := pR.PlayerDownsyncSessionDict[playerId]; existent {
pResp := &pb.WsResp{
Ret: int32(Constants.RetCode.Ok),
Act: act,
Rdf: roomDownsyncFrame,
InputFrameDownsyncBatch: toSendInputFrameDownsyncs,
}
pResp := &pb.WsResp{
Ret: int32(Constants.RetCode.Ok),
Act: act,
Rdf: roomDownsyncFrame,
InputFrameDownsyncBatch: toSendInputFrameDownsyncs,
PeerJoinIndex: peerJoinIndex,
}
theBytes, marshalErr := proto.Marshal(pResp)
if nil != marshalErr {
panic(fmt.Sprintf("Error marshaling downsync message: roomId=%v, playerId=%v, roomState=%v, roomEffectivePlayerCount=%v", pR.Id, playerId, pR.State, pR.EffectivePlayerCount))
}
theBytes, marshalErr := proto.Marshal(pResp)
if nil != marshalErr {
panic(fmt.Sprintf("Error marshaling downsync message: roomId=%v, playerId=%v, roomState=%v, roomEffectivePlayerCount=%v", pR.Id, playerId, pR.State, pR.EffectivePlayerCount))
}
if err := playerDownsyncSession.WriteMessage(websocket.BinaryMessage, theBytes); nil != err {
panic(fmt.Sprintf("Error sending downsync message: roomId=%v, playerId=%v, roomState=%v, roomEffectivePlayerCount=%v, err=%v", pR.Id, playerId, pR.State, pR.EffectivePlayerCount, err))
if MAGIC_JOIN_INDEX_DEFAULT == peerJoinIndex {
if playerDownsyncSession, existent := pR.PlayerDownsyncSessionDict[playerId]; existent {
if err := playerDownsyncSession.WriteMessage(websocket.BinaryMessage, theBytes); nil != err {
panic(fmt.Sprintf("Error sending primary downsync message: roomId=%v, playerId=%v, roomState=%v, roomEffectivePlayerCount=%v, err=%v", pR.Id, playerId, pR.State, pR.EffectivePlayerCount, err))
}
}
} else {
/*
[FIXME]
This branch is preferred to use an additional session of each player for sending, and the session is preferrably UDP instead of any TCP-based protocol, but I'm being lazy here.
See `<proj-root>/ConcerningEdgeCases.md` for the advantage of using UDP as a supplement.
*/
if playerSecondaryDownsyncSession, existent := pR.PlayerSecondaryDownsyncSessionDict[playerId]; existent {
if err := playerSecondaryDownsyncSession.WriteMessage(websocket.BinaryMessage, theBytes); nil != err {
panic(fmt.Sprintf("Error sending secondary downsync message: roomId=%v, playerId=%v, roomState=%v, roomEffectivePlayerCount=%v, err=%v", pR.Id, playerId, pR.State, pR.EffectivePlayerCount, err))
}
}
}
}
@@ -1342,11 +1395,35 @@ func (pR *Room) doBattleMainLoopPerTickBackendDynamicsWithProperLocking(prevRend
snapshotStFrameId = refSnapshotStFrameId
}
inputsBufferSnapshot := pR.produceInputsBufferSnapshotWithCurDynamicsRenderFrameAsRef(unconfirmedMask, snapshotStFrameId, pR.LastAllConfirmedInputFrameId+1)
Logger.Debug(fmt.Sprintf("[forceConfirmation] roomId=%v, room.RenderFrameId=%v, room.CurDynamicsRenderFrameId=%v, room.LastAllConfirmedInputFrameId=%v, unconfirmedMask=%v", pR.Id, pR.RenderFrameId, pR.CurDynamicsRenderFrameId, pR.LastAllConfirmedInputFrameId, unconfirmedMask))
//Logger.Warn(fmt.Sprintf("[forceConfirmation] roomId=%v, room.RenderFrameId=%v, room.CurDynamicsRenderFrameId=%v, room.LastAllConfirmedInputFrameId=%v, unconfirmedMask=%v", pR.Id, pR.RenderFrameId, pR.CurDynamicsRenderFrameId, pR.LastAllConfirmedInputFrameId, unconfirmedMask))
pR.downsyncToAllPlayers(inputsBufferSnapshot)
}
}
func (pR *Room) broadcastPeerUpsyncForBetterPrediction(inputsBufferSnapshot *pb.InputsBufferSnapshot) {
// See `<proj-root>/ConcerningEdgeCases.md` for why this method exists.
for _, player := range pR.PlayersArr {
playerBattleState := atomic.LoadInt32(&(player.BattleState))
switch playerBattleState {
case PlayerBattleStateIns.DISCONNECTED, PlayerBattleStateIns.LOST, PlayerBattleStateIns.EXPELLED_DURING_GAME, PlayerBattleStateIns.EXPELLED_IN_DISMISSAL, PlayerBattleStateIns.ADDED_PENDING_BATTLE_COLLIDER_ACK, PlayerBattleStateIns.READDED_PENDING_BATTLE_COLLIDER_ACK:
continue
}
if player.JoinIndex == inputsBufferSnapshot.PeerJoinIndex {
continue
}
if playerSecondaryDownsyncChan, existent := pR.PlayerSecondaryDownsyncChanDict[player.Id]; existent {
/*
[FIXME]
This function is preferred to use an additional go-channel of each player for sending, see "downsyncLoop" & "Room.sendSafely" for more information!
*/
playerSecondaryDownsyncChan <- (*inputsBufferSnapshot)
} else {
Logger.Warn(fmt.Sprintf("playerDownsyncChan for (roomId: %d, playerId:%d) is gone", pR.Id, player.Id))
}
}
}
func (pR *Room) downsyncToAllPlayers(inputsBufferSnapshot *pb.InputsBufferSnapshot) {
/*
[WARNING] This function MUST BE called while "pR.InputsBufferLock" is LOCKED to **preserve the order of generation of "inputsBufferSnapshot" for sending** -- see comments in "OnBattleCmdReceived" and [this issue](https://github.com/genxium/DelayNoMore/issues/12).
@@ -1423,14 +1500,14 @@ func (pR *Room) downsyncToSinglePlayer(playerId int32, player *Player, refRender
We hereby assume that Golang runtime allocates & frees small amount of RAM quickly enough compared to either network I/O blocking in worst cases or the high frequency "per inputFrameDownsync*player" locking (though "OnBattleCmdReceived" locks at the same frequency but it's inevitable).
*/
playerJoinIndex := player.JoinIndex - 1
playerJoinIndexInBooleanArr := player.JoinIndex - 1
playerBattleState := atomic.LoadInt32(&(player.BattleState))
switch playerBattleState {
case PlayerBattleStateIns.DISCONNECTED, PlayerBattleStateIns.LOST, PlayerBattleStateIns.EXPELLED_DURING_GAME, PlayerBattleStateIns.EXPELLED_IN_DISMISSAL, PlayerBattleStateIns.ADDED_PENDING_BATTLE_COLLIDER_ACK, PlayerBattleStateIns.READDED_PENDING_BATTLE_COLLIDER_ACK:
return
}
isSlowTicker := (0 < (unconfirmedMask & uint64(1<<uint32(playerJoinIndex))))
isSlowTicker := (0 < (unconfirmedMask & uint64(1<<uint32(playerJoinIndexInBooleanArr))))
shouldResync1 := (PlayerBattleStateIns.READDED_BATTLE_COLLIDER_ACKED == playerBattleState) // i.e. implies that "MAGIC_LAST_SENT_INPUT_FRAME_ID_READDED == player.LastSentInputFrameId"
shouldResync2 := isSlowTicker // This condition is critical, if we don't send resync upon this condition, the "reconnected or slowly-clocking player" might never get its input synced
shouldResync3 := shouldForceResync
@@ -1455,13 +1532,13 @@ func (pR *Room) downsyncToSinglePlayer(playerId int32, player *Player, refRender
refRenderFrame.BackendUnconfirmedMask = unconfirmedMask
pbRefRenderFrame := toPbRoomDownsyncFrame(refRenderFrame)
pbRefRenderFrame.SpeciesIdList = pR.SpeciesIdList
pR.sendSafely(pbRefRenderFrame, toSendInputFrameDownsyncsSnapshot, DOWNSYNC_MSG_ACT_FORCED_RESYNC, playerId, false)
pR.sendSafely(pbRefRenderFrame, toSendInputFrameDownsyncsSnapshot, DOWNSYNC_MSG_ACT_FORCED_RESYNC, playerId, false, MAGIC_JOIN_INDEX_DEFAULT)
//Logger.Warn(fmt.Sprintf("Sent refRenderFrameId=%v & inputFrameIds [%d, %d), for roomId=%v, playerId=%d, playerJoinIndex=%d, renderFrameId=%d, curDynamicsRenderFrameId=%d, playerLastSentInputFrameId=%d: InputsBuffer=%v", refRenderFrameId, toSendInputFrameIdSt, toSendInputFrameIdEd, pR.Id, playerId, player.JoinIndex, pR.RenderFrameId, pR.CurDynamicsRenderFrameId, player.LastSentInputFrameId, pR.InputsBufferString(false)))
if shouldResync1 {
Logger.Warn(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))
if shouldResync1 || shouldResync3 {
Logger.Debug(fmt.Sprintf("Sent refRenderFrameId=%v & inputFrameIds [%d, %d), for roomId=%v, playerId=%d, playerJoinIndex=%d, renderFrameId=%d, curDynamicsRenderFrameId=%d, playerLastSentInputFrameId=%d: shouldResync1=%v, shouldResync2=%v, shouldResync3=%v, playerBattleState=%d", refRenderFrameId, toSendInputFrameIdSt, toSendInputFrameIdEd, pR.Id, playerId, player.JoinIndex, pR.RenderFrameId, pR.CurDynamicsRenderFrameId, player.LastSentInputFrameId, shouldResync1, shouldResync2, shouldResync3, playerBattleState))
}
} else {
pR.sendSafely(nil, toSendInputFrameDownsyncsSnapshot, DOWNSYNC_MSG_ACT_INPUT_BATCH, playerId, false)
pR.sendSafely(nil, toSendInputFrameDownsyncsSnapshot, DOWNSYNC_MSG_ACT_INPUT_BATCH, playerId, false, MAGIC_JOIN_INDEX_DEFAULT)
}
player.LastSentInputFrameId = toSendInputFrameIdEd - 1
if shouldResync1 {
@@ -1469,6 +1546,16 @@ func (pR *Room) downsyncToSinglePlayer(playerId int32, player *Player, refRender
}
}
func (pR *Room) downsyncPeerInputFrameUpsyncToSinglePlayer(playerId int32, player *Player, toSendInputFrameDownsyncsSnapshot []*pb.InputFrameDownsync, peerJoinIndex int32) {
playerBattleState := atomic.LoadInt32(&(player.BattleState))
switch playerBattleState {
case PlayerBattleStateIns.DISCONNECTED, PlayerBattleStateIns.LOST, PlayerBattleStateIns.EXPELLED_DURING_GAME, PlayerBattleStateIns.EXPELLED_IN_DISMISSAL, PlayerBattleStateIns.ADDED_PENDING_BATTLE_COLLIDER_ACK, PlayerBattleStateIns.READDED_PENDING_BATTLE_COLLIDER_ACK:
return
}
pR.sendSafely(nil, toSendInputFrameDownsyncsSnapshot, DOWNSYNC_MSG_ACT_PEER_INPUT_BATCH, playerId, false, peerJoinIndex)
}
func (pR *Room) cloneInputsBuffer(stFrameId, edFrameId int32) []*pb.InputFrameDownsync {
// [WARNING] This function MUST BE called while "pR.InputsBufferLock" is locked!
cloned := make([]*pb.InputFrameDownsync, 0, edFrameId-stFrameId)
@@ -1501,3 +1588,22 @@ func (pR *Room) cloneInputsBuffer(stFrameId, edFrameId int32) []*pb.InputFrameDo
return cloned
}
func (pR *Room) SetSecondarySession(playerId int32, session *websocket.Conn, signalToCloseConnOfThisPlayer SignalToCloseConnCbType) {
// TODO: Use a dedicated lock
if player, ok := pR.Players[playerId]; ok {
playerBattleState := atomic.LoadInt32(&(player.BattleState))
switch playerBattleState {
case PlayerBattleStateIns.DISCONNECTED, PlayerBattleStateIns.LOST, PlayerBattleStateIns.EXPELLED_DURING_GAME, PlayerBattleStateIns.EXPELLED_IN_DISMISSAL:
// Kindly note that "PlayerBattleStateIns.ADDED_PENDING_BATTLE_COLLIDER_ACK, PlayerBattleStateIns.READDED_PENDING_BATTLE_COLLIDER_ACK" are allowed
return
}
if _, existent := pR.PlayerDownsyncSessionDict[playerId]; existent {
if _, existent2 := pR.PlayerSecondaryDownsyncSessionDict[playerId]; !existent2 {
Logger.Info(fmt.Sprintf("SetSecondarySession for roomId=%v, playerId=%d, pR.Players=%v", pR.Id, playerId, pR.Players))
pR.PlayerSecondaryDownsyncSessionDict[playerId] = session
pR.PlayerSecondarySignalToCloseDict[playerId] = signalToCloseConnOfThisPlayer
}
}
}
}

View File

@@ -30,9 +30,9 @@ type PlayerDownsync struct {
VirtualGridX int32 `protobuf:"varint,2,opt,name=virtualGridX,proto3" json:"virtualGridX,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"`
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"`
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"
BattleState int32 `protobuf:"varint,9,opt,name=battleState,proto3" json:"battleState,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)"
OnWallNormX int32 `protobuf:"varint,27,opt,name=onWallNormX,proto3" json:"onWallNormX,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"`
DisplayName string `protobuf:"bytes,998,opt,name=displayName,proto3" json:"displayName,omitempty"`
Avatar string `protobuf:"bytes,999,opt,name=avatar,proto3" json:"avatar,omitempty"`
@@ -287,6 +288,13 @@ func (x *PlayerDownsync) GetOnWallNormY() int32 {
return 0
}
func (x *PlayerDownsync) GetCapturedByInertia() bool {
if x != nil {
return x.CapturedByInertia
}
return false
}
func (x *PlayerDownsync) GetName() string {
if x != nil {
return x.Name
@@ -386,6 +394,7 @@ type InputFrameUpsync struct {
InputFrameId int32 `protobuf:"varint,1,opt,name=inputFrameId,proto3" json:"inputFrameId,omitempty"`
Encoded uint64 `protobuf:"varint,2,opt,name=encoded,proto3" json:"encoded,omitempty"`
JoinIndex int32 `protobuf:"varint,3,opt,name=joinIndex,proto3" json:"joinIndex,omitempty"`
}
func (x *InputFrameUpsync) Reset() {
@@ -434,6 +443,13 @@ func (x *InputFrameUpsync) GetEncoded() uint64 {
return 0
}
func (x *InputFrameUpsync) GetJoinIndex() int32 {
if x != nil {
return x.JoinIndex
}
return 0
}
type InputFrameDownsync struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -658,6 +674,7 @@ type WsResp struct {
Rdf *RoomDownsyncFrame `protobuf:"bytes,4,opt,name=rdf,proto3" json:"rdf,omitempty"`
InputFrameDownsyncBatch []*InputFrameDownsync `protobuf:"bytes,5,rep,name=inputFrameDownsyncBatch,proto3" json:"inputFrameDownsyncBatch,omitempty"`
BciFrame *BattleColliderInfo `protobuf:"bytes,6,opt,name=bciFrame,proto3" json:"bciFrame,omitempty"`
PeerJoinIndex int32 `protobuf:"varint,7,opt,name=peerJoinIndex,proto3" json:"peerJoinIndex,omitempty"` // Only used when "InputsBufferSnapshot.peerJoinIndex" is used.
}
func (x *WsResp) Reset() {
@@ -734,6 +751,13 @@ func (x *WsResp) GetBciFrame() *BattleColliderInfo {
return nil
}
func (x *WsResp) GetPeerJoinIndex() int32 {
if x != nil {
return x.PeerJoinIndex
}
return 0
}
type InputsBufferSnapshot struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -743,6 +767,7 @@ type InputsBufferSnapshot struct {
UnconfirmedMask uint64 `protobuf:"varint,2,opt,name=unconfirmedMask,proto3" json:"unconfirmedMask,omitempty"`
ToSendInputFrameDownsyncs []*InputFrameDownsync `protobuf:"bytes,3,rep,name=toSendInputFrameDownsyncs,proto3" json:"toSendInputFrameDownsyncs,omitempty"`
ShouldForceResync bool `protobuf:"varint,4,opt,name=shouldForceResync,proto3" json:"shouldForceResync,omitempty"`
PeerJoinIndex int32 `protobuf:"varint,5,opt,name=peerJoinIndex,proto3" json:"peerJoinIndex,omitempty"` // Only used when "WsResp.peerJoinIndex" is used.
}
func (x *InputsBufferSnapshot) Reset() {
@@ -805,6 +830,13 @@ func (x *InputsBufferSnapshot) GetShouldForceResync() bool {
return false
}
func (x *InputsBufferSnapshot) GetPeerJoinIndex() int32 {
if x != nil {
return x.PeerJoinIndex
}
return 0
}
type MeleeBullet struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -831,6 +863,10 @@ type MeleeBullet struct {
BlowUp bool `protobuf:"varint,18,opt,name=blowUp,proto3" json:"blowUp,omitempty"`
TeamId int32 `protobuf:"varint,19,opt,name=teamId,proto3" json:"teamId,omitempty"`
BulletLocalId int32 `protobuf:"varint,20,opt,name=bulletLocalId,proto3" json:"bulletLocalId,omitempty"`
SpeciesId int32 `protobuf:"varint,21,opt,name=speciesId,proto3" json:"speciesId,omitempty"`
ExplosionFrames int32 `protobuf:"varint,22,opt,name=explosionFrames,proto3" json:"explosionFrames,omitempty"`
BlState int32 `protobuf:"varint,23,opt,name=blState,proto3" json:"blState,omitempty"`
FramesInBlState int32 `protobuf:"varint,24,opt,name=framesInBlState,proto3" json:"framesInBlState,omitempty"`
}
func (x *MeleeBullet) Reset() {
@@ -1005,6 +1041,34 @@ func (x *MeleeBullet) GetBulletLocalId() int32 {
return 0
}
func (x *MeleeBullet) GetSpeciesId() int32 {
if x != nil {
return x.SpeciesId
}
return 0
}
func (x *MeleeBullet) GetExplosionFrames() int32 {
if x != nil {
return x.ExplosionFrames
}
return 0
}
func (x *MeleeBullet) GetBlState() int32 {
if x != nil {
return x.BlState
}
return 0
}
func (x *MeleeBullet) GetFramesInBlState() int32 {
if x != nil {
return x.FramesInBlState
}
return 0
}
type FireballBullet struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -1031,6 +1095,9 @@ type FireballBullet struct {
TeamId int32 `protobuf:"varint,19,opt,name=teamId,proto3" json:"teamId,omitempty"`
BulletLocalId int32 `protobuf:"varint,20,opt,name=bulletLocalId,proto3" json:"bulletLocalId,omitempty"`
SpeciesId int32 `protobuf:"varint,21,opt,name=speciesId,proto3" json:"speciesId,omitempty"`
ExplosionFrames int32 `protobuf:"varint,22,opt,name=explosionFrames,proto3" json:"explosionFrames,omitempty"`
BlState int32 `protobuf:"varint,23,opt,name=blState,proto3" json:"blState,omitempty"`
FramesInBlState int32 `protobuf:"varint,24,opt,name=framesInBlState,proto3" json:"framesInBlState,omitempty"`
VirtualGridX int32 `protobuf:"varint,999,opt,name=virtualGridX,proto3" json:"virtualGridX,omitempty"`
VirtualGridY int32 `protobuf:"varint,1000,opt,name=virtualGridY,proto3" json:"virtualGridY,omitempty"`
DirX int32 `protobuf:"varint,1001,opt,name=dirX,proto3" json:"dirX,omitempty"`
@@ -1219,6 +1286,27 @@ func (x *FireballBullet) GetSpeciesId() int32 {
return 0
}
func (x *FireballBullet) GetExplosionFrames() int32 {
if x != nil {
return x.ExplosionFrames
}
return 0
}
func (x *FireballBullet) GetBlState() int32 {
if x != nil {
return x.BlState
}
return 0
}
func (x *FireballBullet) GetFramesInBlState() int32 {
if x != nil {
return x.FramesInBlState
}
return 0
}
func (x *FireballBullet) GetVirtualGridX() int32 {
if x != nil {
return x.VirtualGridX
@@ -1536,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,
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,
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,
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,
@@ -1591,272 +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,
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,
0x6e, 0x57, 0x61, 0x6c, 0x6c, 0x4e, 0x6f, 0x72, 0x6d, 0x59, 0x12, 0x13, 0x0a, 0x04, 0x6e, 0x61,
0x6d, 0x65, 0x18, 0xe5, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12,
0x21, 0x0a, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0xe6,
0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61,
0x6d, 0x65, 0x12, 0x17, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0xe7, 0x07, 0x20,
0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x22, 0x6f, 0x0a, 0x11, 0x49,
0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x64,
0x12, 0x0e, 0x0a, 0x02, 0x64, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x64, 0x78,
0x12, 0x0e, 0x0a, 0x02, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x64, 0x79,
0x12, 0x1c, 0x0a, 0x09, 0x62, 0x74, 0x6e, 0x41, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x03, 0x20,
0x01, 0x28, 0x05, 0x52, 0x09, 0x62, 0x74, 0x6e, 0x41, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x1c,
0x0a, 0x09, 0x62, 0x74, 0x6e, 0x42, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28,
0x05, 0x52, 0x09, 0x62, 0x74, 0x6e, 0x42, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0x50, 0x0a, 0x10,
0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63,
0x6e, 0x57, 0x61, 0x6c, 0x6c, 0x4e, 0x6f, 0x72, 0x6d, 0x59, 0x12, 0x2c, 0x0a, 0x11, 0x63, 0x61,
0x70, 0x74, 0x75, 0x72, 0x65, 0x64, 0x42, 0x79, 0x49, 0x6e, 0x65, 0x72, 0x74, 0x69, 0x61, 0x18,
0x1d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x63, 0x61, 0x70, 0x74, 0x75, 0x72, 0x65, 0x64, 0x42,
0x79, 0x49, 0x6e, 0x65, 0x72, 0x74, 0x69, 0x61, 0x12, 0x13, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65,
0x18, 0xe5, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a,
0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0xe6, 0x07, 0x20,
0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65,
0x12, 0x17, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0xe7, 0x07, 0x20, 0x01, 0x28,
0x09, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x22, 0x6f, 0x0a, 0x11, 0x49, 0x6e, 0x70,
0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x12, 0x0e,
0x0a, 0x02, 0x64, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x64, 0x78, 0x12, 0x0e,
0x0a, 0x02, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x64, 0x79, 0x12, 0x1c,
0x0a, 0x09, 0x62, 0x74, 0x6e, 0x41, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28,
0x05, 0x52, 0x09, 0x62, 0x74, 0x6e, 0x41, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x1c, 0x0a, 0x09,
0x62, 0x74, 0x6e, 0x42, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52,
0x09, 0x62, 0x74, 0x6e, 0x42, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x22, 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,
0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61,
0x6d, 0x65, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x18,
0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x22, 0x7c,
0x0a, 0x12, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e,
0x73, 0x79, 0x6e, 0x63, 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61,
0x6d, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x69, 0x6e, 0x70, 0x75,
0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x70, 0x75,
0x74, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x04, 0x52, 0x09, 0x69, 0x6e, 0x70,
0x75, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72,
0x6d, 0x65, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x63,
0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x3b, 0x0a, 0x0f,
0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x12,
0x28, 0x0a, 0x0f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74,
0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0xb8, 0x02, 0x0a, 0x05, 0x57, 0x73,
0x52, 0x65, 0x71, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x73, 0x67, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01,
0x28, 0x05, 0x52, 0x05, 0x6d, 0x73, 0x67, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61,
0x79, 0x65, 0x72, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x6c, 0x61,
0x79, 0x65, 0x72, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01,
0x28, 0x05, 0x52, 0x03, 0x61, 0x63, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6a, 0x6f, 0x69, 0x6e, 0x49,
0x6e, 0x64, 0x65, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x6a, 0x6f, 0x69, 0x6e,
0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x24, 0x0a, 0x0d, 0x61, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x46,
0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x61, 0x63,
0x6b, 0x69, 0x6e, 0x67, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x12, 0x61,
0x63, 0x6b, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49,
0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x61, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x49,
0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x4e, 0x0a, 0x15, 0x69,
0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x42,
0x61, 0x74, 0x63, 0x68, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x73, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70,
0x73, 0x79, 0x6e, 0x63, 0x52, 0x15, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65,
0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x42, 0x61, 0x74, 0x63, 0x68, 0x12, 0x27, 0x0a, 0x02, 0x68,
0x62, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73,
0x2e, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63,
0x52, 0x02, 0x68, 0x62, 0x22, 0x89, 0x02, 0x0a, 0x06, 0x57, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12,
0x10, 0x0a, 0x03, 0x72, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x72, 0x65,
0x74, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x63, 0x68, 0x6f, 0x65, 0x64, 0x4d, 0x73, 0x67, 0x49, 0x64,
0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x65, 0x63, 0x68, 0x6f, 0x65, 0x64, 0x4d, 0x73,
0x67, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05,
0x52, 0x03, 0x61, 0x63, 0x74, 0x12, 0x2b, 0x0a, 0x03, 0x72, 0x64, 0x66, 0x18, 0x04, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x52, 0x6f, 0x6f, 0x6d,
0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x03, 0x72,
0x64, 0x66, 0x12, 0x54, 0x0a, 0x17, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65,
0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x42, 0x61, 0x74, 0x63, 0x68, 0x18, 0x05, 0x20,
0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x49, 0x6e, 0x70,
0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x52,
0x17, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73,
0x79, 0x6e, 0x63, 0x42, 0x61, 0x74, 0x63, 0x68, 0x12, 0x36, 0x0a, 0x08, 0x62, 0x63, 0x69, 0x46,
0x72, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x73, 0x2e, 0x42, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x6c, 0x69, 0x64,
0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x62, 0x63, 0x69, 0x46, 0x72, 0x61, 0x6d, 0x65,
0x22, 0xf4, 0x01, 0x0a, 0x14, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x42, 0x75, 0x66, 0x66, 0x65,
0x72, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x2a, 0x0a, 0x10, 0x72, 0x65, 0x66,
0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20,
0x01, 0x28, 0x05, 0x52, 0x10, 0x72, 0x65, 0x66, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72,
0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x0f, 0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69,
0x72, 0x6d, 0x65, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f,
0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x12,
0x58, 0x0a, 0x19, 0x74, 0x6f, 0x53, 0x65, 0x6e, 0x64, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72,
0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x73, 0x18, 0x03, 0x20, 0x03,
0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x49, 0x6e, 0x70, 0x75,
0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x52, 0x19,
0x74, 0x6f, 0x53, 0x65, 0x6e, 0x64, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65,
0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x73, 0x12, 0x2c, 0x0a, 0x11, 0x73, 0x68, 0x6f,
0x75, 0x6c, 0x64, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x04,
0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x46, 0x6f, 0x72, 0x63,
0x65, 0x52, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x22, 0xfd, 0x05, 0x0a, 0x0b, 0x4d, 0x65, 0x6c, 0x65,
0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x12, 0x38, 0x0a, 0x17, 0x6f, 0x72, 0x69, 0x67, 0x69,
0x6e, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65,
0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x17, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e,
0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49,
0x64, 0x12, 0x2c, 0x0a, 0x11, 0x6f, 0x66, 0x66, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4a, 0x6f, 0x69,
0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x6f, 0x66,
0x66, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12,
0x24, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73,
0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x46,
0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x2e, 0x0a, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c,
0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28,
0x05, 0x52, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74,
0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c,
0x61, 0x62, 0x6c, 0x65, 0x45, 0x64, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28,
0x05, 0x52, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x64,
0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46,
0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x61, 0x63, 0x74,
0x69, 0x76, 0x65, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74,
0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05,
0x52, 0x0d, 0x68, 0x69, 0x74, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12,
0x28, 0x0a, 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d,
0x65, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53,
0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x75, 0x73,
0x68, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52,
0x0c, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58, 0x12, 0x22, 0x0a,
0x0c, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x59, 0x18, 0x0a, 0x20,
0x01, 0x28, 0x05, 0x52, 0x0c, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c,
0x59, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x61, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28,
0x05, 0x52, 0x06, 0x64, 0x61, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x65, 0x6c,
0x66, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x05, 0x52,
0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58, 0x12, 0x22, 0x0a,
0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x59, 0x18, 0x0d, 0x20,
0x01, 0x28, 0x05, 0x52, 0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c,
0x59, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65,
0x74, 0x58, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78,
0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x58, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f,
0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x59, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d,
0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x59, 0x12, 0x20, 0x0a,
0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x58, 0x18, 0x10, 0x20, 0x01,
0x28, 0x05, 0x52, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x58, 0x12,
0x20, 0x0a, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x59, 0x18, 0x11,
0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65,
0x59, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x6c, 0x6f, 0x77, 0x55, 0x70, 0x18, 0x12, 0x20, 0x01, 0x28,
0x08, 0x52, 0x06, 0x62, 0x6c, 0x6f, 0x77, 0x55, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x65, 0x61,
0x6d, 0x49, 0x64, 0x18, 0x13, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x74, 0x65, 0x61, 0x6d, 0x49,
0x64, 0x12, 0x24, 0x0a, 0x0d, 0x62, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x6c,
0x49, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x62, 0x75, 0x6c, 0x6c, 0x65, 0x74,
0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x22, 0xd3, 0x07, 0x0a, 0x0e, 0x46, 0x69, 0x72, 0x65,
0x62, 0x61, 0x6c, 0x6c, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x12, 0x38, 0x0a, 0x17, 0x6f, 0x72,
0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72,
0x61, 0x6d, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x17, 0x6f, 0x72, 0x69,
0x67, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61,
0x6d, 0x65, 0x49, 0x64, 0x12, 0x2c, 0x0a, 0x11, 0x6f, 0x66, 0x66, 0x65, 0x6e, 0x64, 0x65, 0x72,
0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52,
0x11, 0x6f, 0x66, 0x66, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64,
0x65, 0x78, 0x12, 0x24, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x46, 0x72, 0x61,
0x6d, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74,
0x75, 0x70, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x2e, 0x0a, 0x12, 0x63, 0x61, 0x6e, 0x63,
0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x18, 0x04,
0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c,
0x65, 0x53, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x12, 0x63, 0x61, 0x6e, 0x63,
0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x64, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x18, 0x05,
0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c,
0x65, 0x45, 0x64, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x63, 0x74, 0x69,
0x76, 0x65, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c,
0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x24, 0x0a, 0x0d,
0x68, 0x69, 0x74, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x07, 0x20,
0x01, 0x28, 0x05, 0x52, 0x0d, 0x68, 0x69, 0x74, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d,
0x65, 0x73, 0x12, 0x28, 0x0a, 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x74, 0x75, 0x6e, 0x46,
0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x62, 0x6c, 0x6f,
0x63, 0x6b, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x22, 0x0a, 0x0c,
0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58, 0x18, 0x09, 0x20, 0x01,
0x28, 0x05, 0x52, 0x0c, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58,
0x12, 0x22, 0x0a, 0x0c, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x59,
0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b,
0x56, 0x65, 0x6c, 0x59, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x61, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x0b,
0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x64, 0x61, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x22, 0x0a, 0x0c,
0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58, 0x18, 0x0c, 0x20, 0x01,
0x28, 0x05, 0x52, 0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58,
0x12, 0x22, 0x0a, 0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x59,
0x18, 0x0d, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b,
0x56, 0x65, 0x6c, 0x59, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66,
0x66, 0x73, 0x65, 0x74, 0x58, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x68, 0x69, 0x74,
0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x58, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69,
0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x59, 0x18, 0x0f, 0x20, 0x01, 0x28,
0x05, 0x52, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x59,
0x12, 0x20, 0x0a, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x58, 0x18,
0x10, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a,
0x65, 0x58, 0x12, 0x20, 0x0a, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65,
0x59, 0x18, 0x11, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53,
0x69, 0x7a, 0x65, 0x59, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x6c, 0x6f, 0x77, 0x55, 0x70, 0x18, 0x12,
0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x62, 0x6c, 0x6f, 0x77, 0x55, 0x70, 0x12, 0x16, 0x0a, 0x06,
0x74, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x18, 0x13, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x74, 0x65,
0x61, 0x6d, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x62, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x4c, 0x6f,
0x63, 0x61, 0x6c, 0x49, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x62, 0x75, 0x6c,
0x6c, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x70,
0x65, 0x63, 0x69, 0x65, 0x73, 0x49, 0x64, 0x18, 0x15, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73,
0x70, 0x65, 0x63, 0x69, 0x65, 0x73, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0c, 0x76, 0x69, 0x72, 0x74,
0x75, 0x61, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x58, 0x18, 0xe7, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52,
0x0c, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x58, 0x12, 0x23, 0x0a,
0x0c, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x59, 0x18, 0xe8, 0x07,
0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x47, 0x72, 0x69,
0x64, 0x59, 0x12, 0x13, 0x0a, 0x04, 0x64, 0x69, 0x72, 0x58, 0x18, 0xe9, 0x07, 0x20, 0x01, 0x28,
0x05, 0x52, 0x04, 0x64, 0x69, 0x72, 0x58, 0x12, 0x13, 0x0a, 0x04, 0x64, 0x69, 0x72, 0x59, 0x18,
0xea, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x64, 0x69, 0x72, 0x59, 0x12, 0x13, 0x0a, 0x04,
0x76, 0x65, 0x6c, 0x58, 0x18, 0xeb, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x76, 0x65, 0x6c,
0x58, 0x12, 0x13, 0x0a, 0x04, 0x76, 0x65, 0x6c, 0x59, 0x18, 0xec, 0x07, 0x20, 0x01, 0x28, 0x05,
0x52, 0x04, 0x76, 0x65, 0x6c, 0x59, 0x12, 0x15, 0x0a, 0x05, 0x73, 0x70, 0x65, 0x65, 0x64, 0x18,
0xed, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x73, 0x70, 0x65, 0x65, 0x64, 0x22, 0xc9, 0x05,
0x0a, 0x12, 0x42, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x6c, 0x69, 0x64, 0x65, 0x72,
0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d,
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x61, 0x67, 0x65, 0x4e, 0x61,
0x6d, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x54, 0x6f,
0x50, 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x69, 0x6e, 0x74, 0x65,
0x72, 0x76, 0x61, 0x6c, 0x54, 0x6f, 0x50, 0x69, 0x6e, 0x67, 0x12, 0x34, 0x0a, 0x15, 0x77, 0x69,
0x6c, 0x6c, 0x4b, 0x69, 0x63, 0x6b, 0x49, 0x66, 0x49, 0x6e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65,
0x46, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x15, 0x77, 0x69, 0x6c, 0x6c, 0x4b,
0x69, 0x63, 0x6b, 0x49, 0x66, 0x49, 0x6e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x6f, 0x72,
0x12, 0x20, 0x0a, 0x0b, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x18,
0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x6f, 0x6f, 0x6d,
0x49, 0x64, 0x12, 0x30, 0x0a, 0x13, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x44, 0x75, 0x72, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52,
0x13, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e,
0x61, 0x6e, 0x6f, 0x73, 0x12, 0x46, 0x0a, 0x1e, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61,
0x6d, 0x65, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x54, 0x6f, 0x6c,
0x65, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x1e, 0x69, 0x6e,
0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x44, 0x65,
0x6c, 0x61, 0x79, 0x54, 0x6f, 0x6c, 0x65, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x48, 0x0a, 0x1f,
0x6d, 0x61, 0x78, 0x43, 0x68, 0x61, 0x73, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72,
0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x50, 0x65, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18,
0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x1f, 0x6d, 0x61, 0x78, 0x43, 0x68, 0x61, 0x73, 0x69, 0x6e,
0x67, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x50, 0x65, 0x72,
0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x3c, 0x0a, 0x19, 0x72, 0x6f, 0x6c, 0x6c, 0x62, 0x61,
0x63, 0x6b, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x64, 0x44, 0x74, 0x4d, 0x69, 0x6c,
0x6c, 0x69, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x01, 0x52, 0x19, 0x72, 0x6f, 0x6c, 0x6c, 0x62,
0x61, 0x63, 0x6b, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x64, 0x44, 0x74, 0x4d, 0x69,
0x6c, 0x6c, 0x69, 0x73, 0x12, 0x3a, 0x0a, 0x18, 0x72, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b,
0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x64, 0x44, 0x74, 0x4e, 0x61, 0x6e, 0x6f, 0x73,
0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x18, 0x72, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b,
0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x64, 0x44, 0x74, 0x4e, 0x61, 0x6e, 0x6f, 0x73,
0x12, 0x28, 0x0a, 0x0f, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x43, 0x61, 0x63, 0x68, 0x65, 0x53,
0x69, 0x7a, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x72, 0x65, 0x6e, 0x64, 0x65,
0x72, 0x43, 0x61, 0x63, 0x68, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x70,
0x61, 0x63, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x58, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x01,
0x52, 0x0c, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x58, 0x12, 0x22,
0x0a, 0x0c, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x59, 0x18, 0x0c,
0x20, 0x01, 0x28, 0x01, 0x52, 0x0c, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65,
0x74, 0x59, 0x12, 0x2a, 0x0a, 0x10, 0x63, 0x6f, 0x6c, 0x6c, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x4d,
0x69, 0x6e, 0x53, 0x74, 0x65, 0x70, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x05, 0x52, 0x10, 0x63, 0x6f,
0x6c, 0x6c, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x69, 0x6e, 0x53, 0x74, 0x65, 0x70, 0x12, 0x39,
0x0a, 0x17, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x61, 0x74, 0x61, 0x4c, 0x6f, 0x67, 0x67, 0x69,
0x6e, 0x67, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x80, 0x08, 0x20, 0x01, 0x28, 0x08,
0x52, 0x17, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x61, 0x74, 0x61, 0x4c, 0x6f, 0x67, 0x67, 0x69,
0x6e, 0x67, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0xc2, 0x03, 0x0a, 0x11, 0x52, 0x6f,
0x6f, 0x6d, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12,
0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12,
0x36, 0x0a, 0x0a, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x41, 0x72, 0x72, 0x18, 0x02, 0x20,
0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x50, 0x6c, 0x61,
0x79, 0x65, 0x72, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x52, 0x0a, 0x70, 0x6c, 0x61,
0x79, 0x65, 0x72, 0x73, 0x41, 0x72, 0x72, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x6f, 0x75, 0x6e, 0x74,
0x64, 0x6f, 0x77, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52,
0x0e, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x12,
0x37, 0x0a, 0x0c, 0x6d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x18,
0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x4d,
0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x52, 0x0c, 0x6d, 0x65, 0x6c, 0x65,
0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x12, 0x40, 0x0a, 0x0f, 0x66, 0x69, 0x72, 0x65,
0x62, 0x61, 0x6c, 0x6c, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x46, 0x69, 0x72, 0x65, 0x62,
0x61, 0x6c, 0x6c, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x52, 0x0f, 0x66, 0x69, 0x72, 0x65, 0x62,
0x61, 0x6c, 0x6c, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x12, 0x37, 0x0a, 0x16, 0x62, 0x61,
0x63, 0x6b, 0x65, 0x6e, 0x64, 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64,
0x4d, 0x61, 0x73, 0x6b, 0x18, 0x80, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x16, 0x62, 0x61, 0x63,
0x6b, 0x65, 0x6e, 0x64, 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4d,
0x61, 0x73, 0x6b, 0x12, 0x2d, 0x0a, 0x11, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x46, 0x6f, 0x72,
0x63, 0x65, 0x52, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x81, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52,
0x11, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x79,
0x6e, 0x63, 0x12, 0x25, 0x0a, 0x0d, 0x73, 0x70, 0x65, 0x63, 0x69, 0x65, 0x73, 0x49, 0x64, 0x4c,
0x69, 0x73, 0x74, 0x18, 0x82, 0x08, 0x20, 0x03, 0x28, 0x05, 0x52, 0x0d, 0x73, 0x70, 0x65, 0x63,
0x69, 0x65, 0x73, 0x49, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x33, 0x0a, 0x14, 0x62, 0x75, 0x6c,
0x6c, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65,
0x72, 0x18, 0x83, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x14, 0x62, 0x75, 0x6c, 0x6c, 0x65, 0x74,
0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x42, 0x13,
0x5a, 0x11, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x5f, 0x73, 0x72, 0x76, 0x2f, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x6d, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x4c, 0x69, 0x73,
0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x04, 0x52, 0x09, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x4c, 0x69,
0x73, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4c,
0x69, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x66, 0x69,
0x72, 0x6d, 0x65, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x3b, 0x0a, 0x0f, 0x48, 0x65, 0x61, 0x72,
0x74, 0x62, 0x65, 0x61, 0x74, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x28, 0x0a, 0x0f, 0x63,
0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01,
0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65,
0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0xb8, 0x02, 0x0a, 0x05, 0x57, 0x73, 0x52, 0x65, 0x71, 0x12,
0x14, 0x0a, 0x05, 0x6d, 0x73, 0x67, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05,
0x6d, 0x73, 0x67, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49,
0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49,
0x64, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03,
0x61, 0x63, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78,
0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x6a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65,
0x78, 0x12, 0x24, 0x0a, 0x0d, 0x61, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x46, 0x72, 0x61, 0x6d, 0x65,
0x49, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x61, 0x63, 0x6b, 0x69, 0x6e, 0x67,
0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x12, 0x61, 0x63, 0x6b, 0x69, 0x6e,
0x67, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x18, 0x06, 0x20,
0x01, 0x28, 0x05, 0x52, 0x12, 0x61, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x70, 0x75, 0x74,
0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x4e, 0x0a, 0x15, 0x69, 0x6e, 0x70, 0x75, 0x74,
0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x42, 0x61, 0x74, 0x63, 0x68,
0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e,
0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63,
0x52, 0x15, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x73, 0x79,
0x6e, 0x63, 0x42, 0x61, 0x74, 0x63, 0x68, 0x12, 0x27, 0x0a, 0x02, 0x68, 0x62, 0x18, 0x08, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x48, 0x65, 0x61,
0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x52, 0x02, 0x68, 0x62,
0x22, 0xaf, 0x02, 0x0a, 0x06, 0x57, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x10, 0x0a, 0x03, 0x72,
0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x72, 0x65, 0x74, 0x12, 0x20, 0x0a,
0x0b, 0x65, 0x63, 0x68, 0x6f, 0x65, 0x64, 0x4d, 0x73, 0x67, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01,
0x28, 0x05, 0x52, 0x0b, 0x65, 0x63, 0x68, 0x6f, 0x65, 0x64, 0x4d, 0x73, 0x67, 0x49, 0x64, 0x12,
0x10, 0x0a, 0x03, 0x61, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x61, 0x63,
0x74, 0x12, 0x2b, 0x0a, 0x03, 0x72, 0x64, 0x66, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x44, 0x6f, 0x77, 0x6e,
0x73, 0x79, 0x6e, 0x63, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x03, 0x72, 0x64, 0x66, 0x12, 0x54,
0x0a, 0x17, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e,
0x73, 0x79, 0x6e, 0x63, 0x42, 0x61, 0x74, 0x63, 0x68, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32,
0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72,
0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x52, 0x17, 0x69, 0x6e, 0x70,
0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x42,
0x61, 0x74, 0x63, 0x68, 0x12, 0x36, 0x0a, 0x08, 0x62, 0x63, 0x69, 0x46, 0x72, 0x61, 0x6d, 0x65,
0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e,
0x42, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x6c, 0x69, 0x64, 0x65, 0x72, 0x49, 0x6e,
0x66, 0x6f, 0x52, 0x08, 0x62, 0x63, 0x69, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x0d,
0x70, 0x65, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x07, 0x20,
0x01, 0x28, 0x05, 0x52, 0x0d, 0x70, 0x65, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64,
0x65, 0x78, 0x22, 0x9a, 0x02, 0x0a, 0x14, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x42, 0x75, 0x66,
0x66, 0x65, 0x72, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x2a, 0x0a, 0x10, 0x72,
0x65, 0x66, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x18,
0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x10, 0x72, 0x65, 0x66, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72,
0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x0f, 0x75, 0x6e, 0x63, 0x6f, 0x6e,
0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04,
0x52, 0x0f, 0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4d, 0x61, 0x73,
0x6b, 0x12, 0x58, 0x0a, 0x19, 0x74, 0x6f, 0x53, 0x65, 0x6e, 0x64, 0x49, 0x6e, 0x70, 0x75, 0x74,
0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x73, 0x18, 0x03,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x49, 0x6e,
0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63,
0x52, 0x19, 0x74, 0x6f, 0x53, 0x65, 0x6e, 0x64, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61,
0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x73, 0x12, 0x2c, 0x0a, 0x11, 0x73,
0x68, 0x6f, 0x75, 0x6c, 0x64, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x79, 0x6e, 0x63,
0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x46, 0x6f,
0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x24, 0x0a, 0x0d, 0x70, 0x65, 0x65,
0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05,
0x52, 0x0d, 0x70, 0x65, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22,
0x89, 0x07, 0x0a, 0x0b, 0x4d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x12,
0x38, 0x0a, 0x17, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x6e,
0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05,
0x52, 0x17, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x6e, 0x64,
0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x2c, 0x0a, 0x11, 0x6f, 0x66, 0x66,
0x65, 0x6e, 0x64, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02,
0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x6f, 0x66, 0x66, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4a, 0x6f,
0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x24, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74,
0x75, 0x70, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d,
0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x2e, 0x0a,
0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x46, 0x72,
0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65,
0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a,
0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x64, 0x46, 0x72,
0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65,
0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x64, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a,
0x0c, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x06, 0x20,
0x01, 0x28, 0x05, 0x52, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x72, 0x61, 0x6d, 0x65,
0x73, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d,
0x65, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x68, 0x69, 0x74, 0x53, 0x74, 0x75,
0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x28, 0x0a, 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x05,
0x52, 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65,
0x73, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c,
0x58, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63,
0x6b, 0x56, 0x65, 0x6c, 0x58, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63,
0x6b, 0x56, 0x65, 0x6c, 0x59, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x70, 0x75, 0x73,
0x68, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x59, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x61, 0x6d,
0x61, 0x67, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x64, 0x61, 0x6d, 0x61, 0x67,
0x65, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c,
0x58, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63,
0x6b, 0x56, 0x65, 0x6c, 0x58, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63,
0x6b, 0x56, 0x65, 0x6c, 0x59, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x73, 0x65, 0x6c,
0x66, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x59, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74,
0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x58, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x05,
0x52, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x58, 0x12,
0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x59,
0x18, 0x0f, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66,
0x66, 0x73, 0x65, 0x74, 0x59, 0x12, 0x20, 0x0a, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53,
0x69, 0x7a, 0x65, 0x58, 0x18, 0x10, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x68, 0x69, 0x74, 0x62,
0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x58, 0x12, 0x20, 0x0a, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f,
0x78, 0x53, 0x69, 0x7a, 0x65, 0x59, 0x18, 0x11, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x68, 0x69,
0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x59, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x6c, 0x6f,
0x77, 0x55, 0x70, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x62, 0x6c, 0x6f, 0x77, 0x55,
0x70, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x18, 0x13, 0x20, 0x01, 0x28,
0x05, 0x52, 0x06, 0x74, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x62, 0x75, 0x6c,
0x6c, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x05,
0x52, 0x0d, 0x62, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x12,
0x1c, 0x0a, 0x09, 0x73, 0x70, 0x65, 0x63, 0x69, 0x65, 0x73, 0x49, 0x64, 0x18, 0x15, 0x20, 0x01,
0x28, 0x05, 0x52, 0x09, 0x73, 0x70, 0x65, 0x63, 0x69, 0x65, 0x73, 0x49, 0x64, 0x12, 0x28, 0x0a,
0x0f, 0x65, 0x78, 0x70, 0x6c, 0x6f, 0x73, 0x69, 0x6f, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73,
0x18, 0x16, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x65, 0x78, 0x70, 0x6c, 0x6f, 0x73, 0x69, 0x6f,
0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x6c, 0x53, 0x74, 0x61,
0x74, 0x65, 0x18, 0x17, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x62, 0x6c, 0x53, 0x74, 0x61, 0x74,
0x65, 0x12, 0x28, 0x0a, 0x0f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x49, 0x6e, 0x42, 0x6c, 0x53,
0x74, 0x61, 0x74, 0x65, 0x18, 0x18, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x66, 0x72, 0x61, 0x6d,
0x65, 0x73, 0x49, 0x6e, 0x42, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0xc1, 0x08, 0x0a, 0x0e,
0x46, 0x69, 0x72, 0x65, 0x62, 0x61, 0x6c, 0x6c, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x12, 0x38,
0x0a, 0x17, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x6e, 0x64,
0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52,
0x17, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x6e, 0x64, 0x65,
0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x2c, 0x0a, 0x11, 0x6f, 0x66, 0x66, 0x65,
0x6e, 0x64, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20,
0x01, 0x28, 0x05, 0x52, 0x11, 0x6f, 0x66, 0x66, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4a, 0x6f, 0x69,
0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x24, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75,
0x70, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x73,
0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x2e, 0x0a, 0x12,
0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x46, 0x72, 0x61,
0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c,
0x6c, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x12,
0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x64, 0x46, 0x72, 0x61,
0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c,
0x6c, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x64, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0c,
0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01,
0x28, 0x05, 0x52, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73,
0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65,
0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x68, 0x69, 0x74, 0x53, 0x74, 0x75, 0x6e,
0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x28, 0x0a, 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53,
0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52,
0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73,
0x12, 0x22, 0x0a, 0x0c, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58,
0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b,
0x56, 0x65, 0x6c, 0x58, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b,
0x56, 0x65, 0x6c, 0x59, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x70, 0x75, 0x73, 0x68,
0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x59, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x61, 0x6d, 0x61,
0x67, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x64, 0x61, 0x6d, 0x61, 0x67, 0x65,
0x12, 0x22, 0x0a, 0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58,
0x18, 0x0c, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b,
0x56, 0x65, 0x6c, 0x58, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b,
0x56, 0x65, 0x6c, 0x59, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x73, 0x65, 0x6c, 0x66,
0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x59, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74, 0x62,
0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x58, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x05, 0x52,
0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x58, 0x12, 0x24,
0x0a, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x59, 0x18,
0x0f, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66,
0x73, 0x65, 0x74, 0x59, 0x12, 0x20, 0x0a, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69,
0x7a, 0x65, 0x58, 0x18, 0x10, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f,
0x78, 0x53, 0x69, 0x7a, 0x65, 0x58, 0x12, 0x20, 0x0a, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78,
0x53, 0x69, 0x7a, 0x65, 0x59, 0x18, 0x11, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x68, 0x69, 0x74,
0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x59, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x6c, 0x6f, 0x77,
0x55, 0x70, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x62, 0x6c, 0x6f, 0x77, 0x55, 0x70,
0x12, 0x16, 0x0a, 0x06, 0x74, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x18, 0x13, 0x20, 0x01, 0x28, 0x05,
0x52, 0x06, 0x74, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x62, 0x75, 0x6c, 0x6c,
0x65, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x05, 0x52,
0x0d, 0x62, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x1c,
0x0a, 0x09, 0x73, 0x70, 0x65, 0x63, 0x69, 0x65, 0x73, 0x49, 0x64, 0x18, 0x15, 0x20, 0x01, 0x28,
0x05, 0x52, 0x09, 0x73, 0x70, 0x65, 0x63, 0x69, 0x65, 0x73, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x0f,
0x65, 0x78, 0x70, 0x6c, 0x6f, 0x73, 0x69, 0x6f, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18,
0x16, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x65, 0x78, 0x70, 0x6c, 0x6f, 0x73, 0x69, 0x6f, 0x6e,
0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x6c, 0x53, 0x74, 0x61, 0x74,
0x65, 0x18, 0x17, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x62, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65,
0x12, 0x28, 0x0a, 0x0f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x49, 0x6e, 0x42, 0x6c, 0x53, 0x74,
0x61, 0x74, 0x65, 0x18, 0x18, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x66, 0x72, 0x61, 0x6d, 0x65,
0x73, 0x49, 0x6e, 0x42, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x23, 0x0a, 0x0c, 0x76, 0x69,
0x72, 0x74, 0x75, 0x61, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x58, 0x18, 0xe7, 0x07, 0x20, 0x01, 0x28,
0x05, 0x52, 0x0c, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x58, 0x12,
0x23, 0x0a, 0x0c, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x59, 0x18,
0xe8, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x47,
0x72, 0x69, 0x64, 0x59, 0x12, 0x13, 0x0a, 0x04, 0x64, 0x69, 0x72, 0x58, 0x18, 0xe9, 0x07, 0x20,
0x01, 0x28, 0x05, 0x52, 0x04, 0x64, 0x69, 0x72, 0x58, 0x12, 0x13, 0x0a, 0x04, 0x64, 0x69, 0x72,
0x59, 0x18, 0xea, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x64, 0x69, 0x72, 0x59, 0x12, 0x13,
0x0a, 0x04, 0x76, 0x65, 0x6c, 0x58, 0x18, 0xeb, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x76,
0x65, 0x6c, 0x58, 0x12, 0x13, 0x0a, 0x04, 0x76, 0x65, 0x6c, 0x59, 0x18, 0xec, 0x07, 0x20, 0x01,
0x28, 0x05, 0x52, 0x04, 0x76, 0x65, 0x6c, 0x59, 0x12, 0x15, 0x0a, 0x05, 0x73, 0x70, 0x65, 0x65,
0x64, 0x18, 0xed, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x73, 0x70, 0x65, 0x65, 0x64, 0x22,
0xc9, 0x05, 0x0a, 0x12, 0x42, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x6c, 0x69, 0x64,
0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x67, 0x65, 0x4e,
0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x61, 0x67, 0x65,
0x4e, 0x61, 0x6d, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c,
0x54, 0x6f, 0x50, 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x69, 0x6e,
0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x54, 0x6f, 0x50, 0x69, 0x6e, 0x67, 0x12, 0x34, 0x0a, 0x15,
0x77, 0x69, 0x6c, 0x6c, 0x4b, 0x69, 0x63, 0x6b, 0x49, 0x66, 0x49, 0x6e, 0x61, 0x63, 0x74, 0x69,
0x76, 0x65, 0x46, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x15, 0x77, 0x69, 0x6c,
0x6c, 0x4b, 0x69, 0x63, 0x6b, 0x49, 0x66, 0x49, 0x6e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46,
0x6f, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x6f, 0x6f, 0x6d, 0x49,
0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x6f,
0x6f, 0x6d, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x13, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x44, 0x75,
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28,
0x03, 0x52, 0x13, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x12, 0x46, 0x0a, 0x1e, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46,
0x72, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x54,
0x6f, 0x6c, 0x65, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x1e,
0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63,
0x44, 0x65, 0x6c, 0x61, 0x79, 0x54, 0x6f, 0x6c, 0x65, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x48,
0x0a, 0x1f, 0x6d, 0x61, 0x78, 0x43, 0x68, 0x61, 0x73, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x6e, 0x64,
0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x50, 0x65, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74,
0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x1f, 0x6d, 0x61, 0x78, 0x43, 0x68, 0x61, 0x73,
0x69, 0x6e, 0x67, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x50,
0x65, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x3c, 0x0a, 0x19, 0x72, 0x6f, 0x6c, 0x6c,
0x62, 0x61, 0x63, 0x6b, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x64, 0x44, 0x74, 0x4d,
0x69, 0x6c, 0x6c, 0x69, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x01, 0x52, 0x19, 0x72, 0x6f, 0x6c,
0x6c, 0x62, 0x61, 0x63, 0x6b, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x64, 0x44, 0x74,
0x4d, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x12, 0x3a, 0x0a, 0x18, 0x72, 0x6f, 0x6c, 0x6c, 0x62, 0x61,
0x63, 0x6b, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x64, 0x44, 0x74, 0x4e, 0x61, 0x6e,
0x6f, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x18, 0x72, 0x6f, 0x6c, 0x6c, 0x62, 0x61,
0x63, 0x6b, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x64, 0x44, 0x74, 0x4e, 0x61, 0x6e,
0x6f, 0x73, 0x12, 0x28, 0x0a, 0x0f, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x43, 0x61, 0x63, 0x68,
0x65, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x72, 0x65, 0x6e,
0x64, 0x65, 0x72, 0x43, 0x61, 0x63, 0x68, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x22, 0x0a, 0x0c,
0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x58, 0x18, 0x0b, 0x20, 0x01,
0x28, 0x01, 0x52, 0x0c, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x58,
0x12, 0x22, 0x0a, 0x0c, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x59,
0x18, 0x0c, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0c, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x66, 0x66,
0x73, 0x65, 0x74, 0x59, 0x12, 0x2a, 0x0a, 0x10, 0x63, 0x6f, 0x6c, 0x6c, 0x69, 0x73, 0x69, 0x6f,
0x6e, 0x4d, 0x69, 0x6e, 0x53, 0x74, 0x65, 0x70, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x05, 0x52, 0x10,
0x63, 0x6f, 0x6c, 0x6c, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x69, 0x6e, 0x53, 0x74, 0x65, 0x70,
0x12, 0x39, 0x0a, 0x17, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x61, 0x74, 0x61, 0x4c, 0x6f, 0x67,
0x67, 0x69, 0x6e, 0x67, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x80, 0x08, 0x20, 0x01,
0x28, 0x08, 0x52, 0x17, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x61, 0x74, 0x61, 0x4c, 0x6f, 0x67,
0x67, 0x69, 0x6e, 0x67, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0xc2, 0x03, 0x0a, 0x11,
0x52, 0x6f, 0x6f, 0x6d, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x46, 0x72, 0x61, 0x6d,
0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69,
0x64, 0x12, 0x36, 0x0a, 0x0a, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x41, 0x72, 0x72, 0x18,
0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x50,
0x6c, 0x61, 0x79, 0x65, 0x72, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x52, 0x0a, 0x70,
0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x41, 0x72, 0x72, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x6f, 0x75,
0x6e, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28,
0x03, 0x52, 0x0e, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x4e, 0x61, 0x6e, 0x6f,
0x73, 0x12, 0x37, 0x0a, 0x0c, 0x6d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74,
0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73,
0x2e, 0x4d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x52, 0x0c, 0x6d, 0x65,
0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x12, 0x40, 0x0a, 0x0f, 0x66, 0x69,
0x72, 0x65, 0x62, 0x61, 0x6c, 0x6c, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x18, 0x05, 0x20,
0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x46, 0x69, 0x72,
0x65, 0x62, 0x61, 0x6c, 0x6c, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x52, 0x0f, 0x66, 0x69, 0x72,
0x65, 0x62, 0x61, 0x6c, 0x6c, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x12, 0x37, 0x0a, 0x16,
0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d,
0x65, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x18, 0x80, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x16, 0x62,
0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65,
0x64, 0x4d, 0x61, 0x73, 0x6b, 0x12, 0x2d, 0x0a, 0x11, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x46,
0x6f, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x81, 0x08, 0x20, 0x01, 0x28,
0x08, 0x52, 0x11, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x52, 0x65,
0x73, 0x79, 0x6e, 0x63, 0x12, 0x25, 0x0a, 0x0d, 0x73, 0x70, 0x65, 0x63, 0x69, 0x65, 0x73, 0x49,
0x64, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x82, 0x08, 0x20, 0x03, 0x28, 0x05, 0x52, 0x0d, 0x73, 0x70,
0x65, 0x63, 0x69, 0x65, 0x73, 0x49, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x33, 0x0a, 0x14, 0x62,
0x75, 0x6c, 0x6c, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x43, 0x6f, 0x75, 0x6e,
0x74, 0x65, 0x72, 0x18, 0x83, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x14, 0x62, 0x75, 0x6c, 0x6c,
0x65, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72,
0x42, 0x13, 0x5a, 0x11, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x5f, 0x73, 0x72, 0x76, 0x2f, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (

View File

@@ -46,6 +46,7 @@ func Serve(c *gin.Context) {
c.AbortWithStatus(http.StatusBadRequest)
return
}
boundRoomId := 0
expectedRoomId := 0
var err error
@@ -395,3 +396,89 @@ func Serve(c *gin.Context) {
startOrFeedHeartbeatWatchdog(conn)
go receivingLoopAgainstPlayer()
}
func HandleSecondaryWsSessionForPlayer(c *gin.Context) {
token, ok := c.GetQuery("intAuthToken")
if !ok {
Logger.Warn("Secondary ws session req must have intAuthToken param!")
c.AbortWithStatus(http.StatusBadRequest)
return
}
boundRoomId := 0
var err error = nil
if boundRoomIdStr, hasBoundRoomId := c.GetQuery("boundRoomId"); hasBoundRoomId {
boundRoomId, err = strconv.Atoi(boundRoomIdStr)
if err != nil {
c.AbortWithStatus(http.StatusBadRequest)
return
}
} else {
Logger.Warn("Secondary ws session req must have boundRoomId param:", zap.Any("intAuthToken", token))
c.AbortWithStatus(http.StatusBadRequest)
return
}
var pRoom *models.Room = nil
// Deliberately querying playerId after querying room, because the former is against persistent storage and could be slow!
if tmpPRoom, existent := (*models.RoomMapManagerIns)[int32(boundRoomId)]; !existent {
Logger.Warn("Secondary ws session failed to get:\n", zap.Any("intAuthToken", token), zap.Any("forBoundRoomId", boundRoomId))
c.AbortWithStatus(http.StatusBadRequest)
} else {
pRoom = tmpPRoom
}
// TODO: Wrap the following 2 stmts by sql transaction!
playerId, err := models.GetPlayerIdByToken(token)
if err != nil || playerId == 0 {
// TODO: Abort with specific message.
Logger.Warn("Secondary ws session playerLogin record not found for ws authentication:", zap.Any("intAuthToken", token))
c.AbortWithStatus(http.StatusBadRequest)
return
}
Logger.Info("Secondary ws session playerLogin record has been found for ws authentication:", zap.Any("playerId", playerId), zap.Any("intAuthToken", token), zap.Any("boundRoomId", boundRoomId))
conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
Logger.Error("Secondary ws session upgrade:", zap.Error(err), zap.Any("playerId", playerId))
c.AbortWithStatus(http.StatusBadRequest)
return
}
connHasBeenSignaledToClose := int32(0)
pConnHasBeenSignaledToClose := &connHasBeenSignaledToClose
signalToCloseConnOfThisPlayer := func(customRetCode int, customRetMsg string) {
if swapped := atomic.CompareAndSwapInt32(pConnHasBeenSignaledToClose, 0, 1); !swapped {
return
}
Logger.Warn("Secondary ws session signalToCloseConnOfThisPlayer:", zap.Any("playerId", playerId), zap.Any("customRetCode", customRetCode), zap.Any("customRetMsg", customRetMsg))
defer func() {
if r := recover(); r != nil {
Logger.Error("Secondary ws session recovered from: ", zap.Any("panic", r))
}
}()
closeMessage := websocket.FormatCloseMessage(customRetCode, customRetMsg)
err := conn.WriteControl(websocket.CloseMessage, closeMessage, time.Now().Add(time.Millisecond*(ConstVals.Ws.WillKickIfInactiveFor)))
if err != nil {
Logger.Error("Secondary ws session unable to send the CloseFrame control message to player(client-side):", zap.Any("playerId", playerId), zap.Error(err))
}
time.AfterFunc(3*time.Second, func() {
// To actually terminates the underlying TCP connection which might be in `CLOSE_WAIT` state if inspected by `netstat`.
conn.Close()
})
}
onReceivedCloseMessageFromClient := func(code int, text string) error {
Logger.Warn("Secondary ws session triggered `onReceivedCloseMessageFromClient`:", zap.Any("code", code), zap.Any("playerId", playerId), zap.Any("message", text))
signalToCloseConnOfThisPlayer(code, text)
return nil
}
conn.SetCloseHandler(onReceivedCloseMessageFromClient)
pRoom.SetSecondarySession(int32(playerId), conn, signalToCloseConnOfThisPlayer)
}

File diff suppressed because one or more lines are too long

BIN
charts/ServerClients.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

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.

After

Width:  |  Height:  |  Size: 3.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 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",
"uuid": "d41313ca-b2c3-4436-a05f-7e0eb290b1e6",
"uuid": "40edd08e-316c-44b8-a50f-bd173554c554",
"isPlugin": true,
"loadPluginInWeb": true,
"loadPluginInNative": true,

View File

@@ -0,0 +1,7 @@
{
"ver": "1.0.1",
"uuid": "c7c2ac6e-f1ea-4233-b6a4-aa5b96b61e17",
"isSubpackage": false,
"subpackageName": "",
"subMetas": {}
}

View File

@@ -0,0 +1,55 @@
{
"__type__": "cc.AnimationClip",
"_name": "Fireball1Explosion",
"_objFlags": 0,
"_native": "",
"_duration": 0.26666666666666666,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "f4ad4f9f-4890-450b-9334-68fe6b903893"
}
},
{
"frame": 0.05,
"value": {
"__uuid__": "c6a5994f-251d-4191-a550-dfef979bab59"
}
},
{
"frame": 0.11666666666666667,
"value": {
"__uuid__": "417e58d9-e364-47f7-9364-f31ad3452adc"
}
},
{
"frame": 0.15,
"value": {
"__uuid__": "8b566f26-b34d-4da6-bdaa-078358a5b685"
}
},
{
"frame": 0.2,
"value": {
"__uuid__": "6ec5f75d-307e-4292-b667-cbbb5a52c2f6"
}
},
{
"frame": 0.25,
"value": {
"__uuid__": "d89977f1-d927-4a08-9591-9feb1daf68c8"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "7941215a-2b8c-4798-954b-4f1b16d5f6f5",
"subMetas": {}
}

View File

@@ -0,0 +1,79 @@
{
"__type__": "cc.AnimationClip",
"_name": "MeleeExplosion1",
"_objFlags": 0,
"_native": "",
"_duration": 0.16666666666666666,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "ab4866e8-ce52-4bc1-be19-b03687acf0d6"
}
},
{
"frame": 0.016666666666666666,
"value": {
"__uuid__": "67cc8a51-0ebe-49db-a941-7aabc5655ecf"
}
},
{
"frame": 0.03333333333333333,
"value": {
"__uuid__": "367592d0-3566-4b6a-8707-01d6a8dbe34a"
}
},
{
"frame": 0.05,
"value": {
"__uuid__": "cc336b1e-b5d8-4a89-96fc-7ada0e232389"
}
},
{
"frame": 0.06666666666666667,
"value": {
"__uuid__": "a457cc63-08bd-4cfa-b84a-7287d0343ecf"
}
},
{
"frame": 0.08333333333333333,
"value": {
"__uuid__": "89697d35-cde3-4392-a231-db91d4ede29b"
}
},
{
"frame": 0.1,
"value": {
"__uuid__": "3815bf7a-0a48-40e0-b791-0a0be9ec0da6"
}
},
{
"frame": 0.11666666666666667,
"value": {
"__uuid__": "20e691ee-a0c0-4710-8981-8dee1911e819"
}
},
{
"frame": 0.13333333333333333,
"value": {
"__uuid__": "94e678c5-0780-4f2b-bf3b-86c6c0a75c23"
}
},
{
"frame": 0.15,
"value": {
"__uuid__": "af4f9c62-4c7e-43a4-b9b3-dd3effbbbafb"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "954a2924-89df-4df4-93fc-36d2b22e7619",
"subMetas": {}
}

View File

@@ -0,0 +1,79 @@
{
"__type__": "cc.AnimationClip",
"_name": "MeleeExplosion2",
"_objFlags": 0,
"_native": "",
"_duration": 0.26666666666666666,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "89e54317-7835-4d4c-9c04-579da8b33c54"
}
},
{
"frame": 0.016666666666666666,
"value": {
"__uuid__": "2a186e00-a0c5-4c8a-b0ab-c84d56dcee7c"
}
},
{
"frame": 0.05,
"value": {
"__uuid__": "083168e3-6ccc-4c5b-a800-2554bffc67d4"
}
},
{
"frame": 0.08333333333333333,
"value": {
"__uuid__": "d4b12ec9-6f04-493c-91e5-22b1a212262a"
}
},
{
"frame": 0.13333333333333333,
"value": {
"__uuid__": "13038788-b0f9-4714-960b-c98619a0d0ce"
}
},
{
"frame": 0.16666666666666666,
"value": {
"__uuid__": "94c21ed7-94a2-47a4-9537-fe5d9c51d7b0"
}
},
{
"frame": 0.2,
"value": {
"__uuid__": "d5340298-923c-4bd7-9fd7-7a2e029a2b44"
}
},
{
"frame": 0.21666666666666667,
"value": {
"__uuid__": "c4b145c0-0145-4e09-8559-9ef508d95be8"
}
},
{
"frame": 0.23333333333333334,
"value": {
"__uuid__": "79398d4d-305e-4987-b199-d9d9649cf490"
}
},
{
"frame": 0.25,
"value": {
"__uuid__": "c032eb65-fdf3-41e6-b868-d95df34168df"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "5bd304eb-c8ba-426f-a9ab-5698ac62de85",
"subMetas": {}
}

View File

@@ -0,0 +1,79 @@
{
"__type__": "cc.AnimationClip",
"_name": "MeleeExplosion3",
"_objFlags": 0,
"_native": "",
"_duration": 0.26666666666666666,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "20d9ce6b-d9ab-4402-8c59-770ad0adf570"
}
},
{
"frame": 0.016666666666666666,
"value": {
"__uuid__": "0654601f-6788-4a2c-aed4-8dfbe1c5fdd0"
}
},
{
"frame": 0.03333333333333333,
"value": {
"__uuid__": "0913e11a-c796-4b58-94cf-f70b3869deff"
}
},
{
"frame": 0.06666666666666667,
"value": {
"__uuid__": "d6b58622-2cc3-4ee6-a34f-1a18deb73700"
}
},
{
"frame": 0.08333333333333333,
"value": {
"__uuid__": "b83c6261-b86f-4323-ad11-7375cac02a2b"
}
},
{
"frame": 0.11666666666666667,
"value": {
"__uuid__": "b458c047-b7b5-4476-996e-d4c1ca85ef9c"
}
},
{
"frame": 0.15,
"value": {
"__uuid__": "3971256a-8120-448e-8adf-de8d67dedfd3"
}
},
{
"frame": 0.18333333333333332,
"value": {
"__uuid__": "0e548d92-36c8-4795-b3dc-2bc2cfcd7170"
}
},
{
"frame": 0.21666666666666667,
"value": {
"__uuid__": "25f94245-87b0-4954-abab-c817c80fed37"
}
},
{
"frame": 0.25,
"value": {
"__uuid__": "20d9ce6b-d9ab-4402-8c59-770ad0adf570"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "5054633c-a588-4506-b4ac-eef29b1d8511",
"subMetas": {}
}

View File

@@ -0,0 +1,476 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>frames</key>
<dict>
<key>Explosion1_1.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{71,67}</string>
<key>spriteSourceSize</key>
<string>{71,67}</string>
<key>textureRect</key>
<string>{{0,506},{71,67}}</string>
<key>textureRotated</key>
<true/>
</dict>
<key>Explosion1_10.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{71,67}</string>
<key>spriteSourceSize</key>
<string>{71,67}</string>
<key>textureRect</key>
<string>{{0,577},{71,67}}</string>
<key>textureRotated</key>
<true/>
</dict>
<key>Explosion1_2.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{71,67}</string>
<key>spriteSourceSize</key>
<string>{71,67}</string>
<key>textureRect</key>
<string>{{67,506},{71,67}}</string>
<key>textureRotated</key>
<true/>
</dict>
<key>Explosion1_3.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{71,67}</string>
<key>spriteSourceSize</key>
<string>{71,67}</string>
<key>textureRect</key>
<string>{{67,577},{71,67}}</string>
<key>textureRotated</key>
<true/>
</dict>
<key>Explosion1_4.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{71,67}</string>
<key>spriteSourceSize</key>
<string>{71,67}</string>
<key>textureRect</key>
<string>{{134,506},{71,67}}</string>
<key>textureRotated</key>
<true/>
</dict>
<key>Explosion1_5.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{71,67}</string>
<key>spriteSourceSize</key>
<string>{71,67}</string>
<key>textureRect</key>
<string>{{134,577},{71,67}}</string>
<key>textureRotated</key>
<true/>
</dict>
<key>Explosion1_6.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{71,67}</string>
<key>spriteSourceSize</key>
<string>{71,67}</string>
<key>textureRect</key>
<string>{{355,503},{71,67}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>Explosion1_7.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{71,67}</string>
<key>spriteSourceSize</key>
<string>{71,67}</string>
<key>textureRect</key>
<string>{{426,503},{71,67}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>Explosion1_8.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{71,67}</string>
<key>spriteSourceSize</key>
<string>{71,67}</string>
<key>textureRect</key>
<string>{{355,570},{71,67}}</string>
<key>textureRotated</key>
<true/>
</dict>
<key>Explosion1_9.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{71,67}</string>
<key>spriteSourceSize</key>
<string>{71,67}</string>
<key>textureRect</key>
<string>{{422,570},{71,67}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>Explosion2_1.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{88,45}</string>
<key>spriteSourceSize</key>
<string>{88,45}</string>
<key>textureRect</key>
<string>{{462,0},{88,45}}</string>
<key>textureRotated</key>
<true/>
</dict>
<key>Explosion2_10.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{88,45}</string>
<key>spriteSourceSize</key>
<string>{88,45}</string>
<key>textureRect</key>
<string>{{462,88},{88,45}}</string>
<key>textureRotated</key>
<true/>
</dict>
<key>Explosion2_2.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{88,45}</string>
<key>spriteSourceSize</key>
<string>{88,45}</string>
<key>textureRect</key>
<string>{{462,176},{88,45}}</string>
<key>textureRotated</key>
<true/>
</dict>
<key>Explosion2_3.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{88,45}</string>
<key>spriteSourceSize</key>
<string>{88,45}</string>
<key>textureRect</key>
<string>{{462,264},{88,45}}</string>
<key>textureRotated</key>
<true/>
</dict>
<key>Explosion2_4.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{88,45}</string>
<key>spriteSourceSize</key>
<string>{88,45}</string>
<key>textureRect</key>
<string>{{0,304},{88,45}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>Explosion2_5.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{88,45}</string>
<key>spriteSourceSize</key>
<string>{88,45}</string>
<key>textureRect</key>
<string>{{88,304},{88,45}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>Explosion2_6.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{88,45}</string>
<key>spriteSourceSize</key>
<string>{88,45}</string>
<key>textureRect</key>
<string>{{176,304},{88,45}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>Explosion2_7.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{88,45}</string>
<key>spriteSourceSize</key>
<string>{88,45}</string>
<key>textureRect</key>
<string>{{264,304},{88,45}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>Explosion2_8.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{88,45}</string>
<key>spriteSourceSize</key>
<string>{88,45}</string>
<key>textureRect</key>
<string>{{352,304},{88,45}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>Explosion2_9.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{88,45}</string>
<key>spriteSourceSize</key>
<string>{88,45}</string>
<key>textureRect</key>
<string>{{456,352},{88,45}}</string>
<key>textureRotated</key>
<true/>
</dict>
<key>Explosion3_1.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{154,152}</string>
<key>spriteSourceSize</key>
<string>{154,152}</string>
<key>textureRect</key>
<string>{{0,0},{154,152}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>Explosion3_10.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{154,152}</string>
<key>spriteSourceSize</key>
<string>{154,152}</string>
<key>textureRect</key>
<string>{{154,0},{154,152}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>Explosion3_2.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{154,152}</string>
<key>spriteSourceSize</key>
<string>{154,152}</string>
<key>textureRect</key>
<string>{{308,0},{154,152}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>Explosion3_3.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{154,152}</string>
<key>spriteSourceSize</key>
<string>{154,152}</string>
<key>textureRect</key>
<string>{{0,152},{154,152}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>Explosion3_4.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{154,152}</string>
<key>spriteSourceSize</key>
<string>{154,152}</string>
<key>textureRect</key>
<string>{{154,152},{154,152}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>Explosion3_5.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{154,152}</string>
<key>spriteSourceSize</key>
<string>{154,152}</string>
<key>textureRect</key>
<string>{{308,152},{154,152}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>Explosion3_6.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{154,152}</string>
<key>spriteSourceSize</key>
<string>{154,152}</string>
<key>textureRect</key>
<string>{{0,352},{154,152}}</string>
<key>textureRotated</key>
<true/>
</dict>
<key>Explosion3_7.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{154,152}</string>
<key>spriteSourceSize</key>
<string>{154,152}</string>
<key>textureRect</key>
<string>{{152,349},{154,152}}</string>
<key>textureRotated</key>
<true/>
</dict>
<key>Explosion3_8.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{154,152}</string>
<key>spriteSourceSize</key>
<string>{154,152}</string>
<key>textureRect</key>
<string>{{201,503},{154,152}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>Explosion3_9.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{154,152}</string>
<key>spriteSourceSize</key>
<string>{154,152}</string>
<key>textureRect</key>
<string>{{304,349},{154,152}}</string>
<key>textureRotated</key>
<true/>
</dict>
</dict>
<key>metadata</key>
<dict>
<key>format</key>
<integer>3</integer>
<key>pixelFormat</key>
<string>RGBA8888</string>
<key>premultiplyAlpha</key>
<false/>
<key>realTextureFileName</key>
<string>MeleeExplosions.png</string>
<key>size</key>
<string>{507,655}</string>
<key>smartupdate</key>
<string>$TexturePacker:SmartUpdate:6c1498ee6f30bdad4abeb6a9f6af8367:4c81e1a1720f2ad3535ac93f1b42991f:d9b184ec81b83b14db5cf31d298727df$</string>
<key>textureFileName</key>
<string>MeleeExplosions.png</string>
</dict>
</dict>
</plist>

View File

@@ -0,0 +1,672 @@
{
"ver": "1.2.4",
"uuid": "1c4c1dcb-54af-485b-9119-abd6d6d84526",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"size": {
"width": 507,
"height": 655
},
"type": "Texture Packer",
"subMetas": {
"Explosion1_1.png": {
"ver": "1.0.4",
"uuid": "ab4866e8-ce52-4bc1-be19-b03687acf0d6",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 0,
"trimY": 506,
"width": 71,
"height": 67,
"rawWidth": 71,
"rawHeight": 67,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion1_10.png": {
"ver": "1.0.4",
"uuid": "af4f9c62-4c7e-43a4-b9b3-dd3effbbbafb",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 0,
"trimY": 577,
"width": 71,
"height": 67,
"rawWidth": 71,
"rawHeight": 67,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion1_2.png": {
"ver": "1.0.4",
"uuid": "67cc8a51-0ebe-49db-a941-7aabc5655ecf",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 67,
"trimY": 506,
"width": 71,
"height": 67,
"rawWidth": 71,
"rawHeight": 67,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion1_3.png": {
"ver": "1.0.4",
"uuid": "367592d0-3566-4b6a-8707-01d6a8dbe34a",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 67,
"trimY": 577,
"width": 71,
"height": 67,
"rawWidth": 71,
"rawHeight": 67,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion1_4.png": {
"ver": "1.0.4",
"uuid": "cc336b1e-b5d8-4a89-96fc-7ada0e232389",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 134,
"trimY": 506,
"width": 71,
"height": 67,
"rawWidth": 71,
"rawHeight": 67,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion1_5.png": {
"ver": "1.0.4",
"uuid": "a457cc63-08bd-4cfa-b84a-7287d0343ecf",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 134,
"trimY": 577,
"width": 71,
"height": 67,
"rawWidth": 71,
"rawHeight": 67,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion1_6.png": {
"ver": "1.0.4",
"uuid": "89697d35-cde3-4392-a231-db91d4ede29b",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 355,
"trimY": 503,
"width": 71,
"height": 67,
"rawWidth": 71,
"rawHeight": 67,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion1_7.png": {
"ver": "1.0.4",
"uuid": "3815bf7a-0a48-40e0-b791-0a0be9ec0da6",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 426,
"trimY": 503,
"width": 71,
"height": 67,
"rawWidth": 71,
"rawHeight": 67,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion1_8.png": {
"ver": "1.0.4",
"uuid": "20e691ee-a0c0-4710-8981-8dee1911e819",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 355,
"trimY": 570,
"width": 71,
"height": 67,
"rawWidth": 71,
"rawHeight": 67,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion1_9.png": {
"ver": "1.0.4",
"uuid": "94e678c5-0780-4f2b-bf3b-86c6c0a75c23",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 422,
"trimY": 570,
"width": 71,
"height": 67,
"rawWidth": 71,
"rawHeight": 67,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion2_1.png": {
"ver": "1.0.4",
"uuid": "89e54317-7835-4d4c-9c04-579da8b33c54",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 462,
"trimY": 0,
"width": 88,
"height": 45,
"rawWidth": 88,
"rawHeight": 45,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion2_10.png": {
"ver": "1.0.4",
"uuid": "c032eb65-fdf3-41e6-b868-d95df34168df",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 462,
"trimY": 88,
"width": 88,
"height": 45,
"rawWidth": 88,
"rawHeight": 45,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion2_2.png": {
"ver": "1.0.4",
"uuid": "2a186e00-a0c5-4c8a-b0ab-c84d56dcee7c",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 462,
"trimY": 176,
"width": 88,
"height": 45,
"rawWidth": 88,
"rawHeight": 45,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion2_3.png": {
"ver": "1.0.4",
"uuid": "083168e3-6ccc-4c5b-a800-2554bffc67d4",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 462,
"trimY": 264,
"width": 88,
"height": 45,
"rawWidth": 88,
"rawHeight": 45,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion2_4.png": {
"ver": "1.0.4",
"uuid": "d4b12ec9-6f04-493c-91e5-22b1a212262a",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 0,
"trimY": 304,
"width": 88,
"height": 45,
"rawWidth": 88,
"rawHeight": 45,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion2_5.png": {
"ver": "1.0.4",
"uuid": "13038788-b0f9-4714-960b-c98619a0d0ce",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 88,
"trimY": 304,
"width": 88,
"height": 45,
"rawWidth": 88,
"rawHeight": 45,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion2_6.png": {
"ver": "1.0.4",
"uuid": "94c21ed7-94a2-47a4-9537-fe5d9c51d7b0",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 176,
"trimY": 304,
"width": 88,
"height": 45,
"rawWidth": 88,
"rawHeight": 45,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion2_7.png": {
"ver": "1.0.4",
"uuid": "d5340298-923c-4bd7-9fd7-7a2e029a2b44",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 264,
"trimY": 304,
"width": 88,
"height": 45,
"rawWidth": 88,
"rawHeight": 45,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion2_8.png": {
"ver": "1.0.4",
"uuid": "c4b145c0-0145-4e09-8559-9ef508d95be8",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 352,
"trimY": 304,
"width": 88,
"height": 45,
"rawWidth": 88,
"rawHeight": 45,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion2_9.png": {
"ver": "1.0.4",
"uuid": "79398d4d-305e-4987-b199-d9d9649cf490",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 456,
"trimY": 352,
"width": 88,
"height": 45,
"rawWidth": 88,
"rawHeight": 45,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion3_1.png": {
"ver": "1.0.4",
"uuid": "84e28787-c6cb-435b-8f59-20d9afe6bf3a",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 0,
"trimY": 0,
"width": 154,
"height": 152,
"rawWidth": 154,
"rawHeight": 152,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion3_10.png": {
"ver": "1.0.4",
"uuid": "20d9ce6b-d9ab-4402-8c59-770ad0adf570",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 154,
"trimY": 0,
"width": 154,
"height": 152,
"rawWidth": 154,
"rawHeight": 152,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion3_2.png": {
"ver": "1.0.4",
"uuid": "0654601f-6788-4a2c-aed4-8dfbe1c5fdd0",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 308,
"trimY": 0,
"width": 154,
"height": 152,
"rawWidth": 154,
"rawHeight": 152,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion3_3.png": {
"ver": "1.0.4",
"uuid": "0913e11a-c796-4b58-94cf-f70b3869deff",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 0,
"trimY": 152,
"width": 154,
"height": 152,
"rawWidth": 154,
"rawHeight": 152,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion3_4.png": {
"ver": "1.0.4",
"uuid": "d6b58622-2cc3-4ee6-a34f-1a18deb73700",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 154,
"trimY": 152,
"width": 154,
"height": 152,
"rawWidth": 154,
"rawHeight": 152,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion3_5.png": {
"ver": "1.0.4",
"uuid": "b83c6261-b86f-4323-ad11-7375cac02a2b",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 308,
"trimY": 152,
"width": 154,
"height": 152,
"rawWidth": 154,
"rawHeight": 152,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion3_6.png": {
"ver": "1.0.4",
"uuid": "b458c047-b7b5-4476-996e-d4c1ca85ef9c",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 0,
"trimY": 352,
"width": 154,
"height": 152,
"rawWidth": 154,
"rawHeight": 152,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion3_7.png": {
"ver": "1.0.4",
"uuid": "3971256a-8120-448e-8adf-de8d67dedfd3",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 152,
"trimY": 349,
"width": 154,
"height": 152,
"rawWidth": 154,
"rawHeight": 152,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion3_8.png": {
"ver": "1.0.4",
"uuid": "0e548d92-36c8-4795-b3dc-2bc2cfcd7170",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 201,
"trimY": 503,
"width": 154,
"height": 152,
"rawWidth": 154,
"rawHeight": 152,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion3_9.png": {
"ver": "1.0.4",
"uuid": "25f94245-87b0-4954-abab-c817c80fed37",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 304,
"trimY": 349,
"width": 154,
"height": 152,
"rawWidth": 154,
"rawHeight": 152,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -0,0 +1,12 @@
{
"ver": "2.3.3",
"uuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"type": "raw",
"wrapMode": "clamp",
"filterMode": "bilinear",
"premultiplyAlpha": false,
"genMipmaps": false,
"packable": true,
"platformSettings": {},
"subMetas": {}
}

View File

@@ -18,61 +18,43 @@
}
},
{
"frame": 0.06666666666666667,
"frame": 0.05,
"value": {
"__uuid__": "dd9a00aa-ddbc-4b01-a7cb-3c43c3a655b6"
}
},
{
"frame": 0.11666666666666667,
"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,
"frame": 0.08333333333333333,
"value": {
"__uuid__": "e80d3a01-5048-42b7-a280-cb6aa01602c2"
}
},
{
"frame": 0.36666666666666664,
"frame": 0.11666666666666667,
"value": {
"__uuid__": "d899088c-be62-47b4-9ebf-0a89a2261565"
}
},
{
"frame": 0.4166666666666667,
"frame": 0.15,
"value": {
"__uuid__": "5b1e5aa7-fd82-47ae-a5b2-6d4983d848ed"
}
},
{
"frame": 0.48333333333333334,
"frame": 0.18333333333333332,
"value": {
"__uuid__": "c2945988-b4bb-4583-a5ef-2fa02b23a347"
}
},
{
"frame": 0.5666666666666667,
"frame": 0.23333333333333334,
"value": {
"__uuid__": "070ea1e3-9c07-4735-8b94-515ef70216ad"
}
},
{
"frame": 0.6666666666666666,
"frame": 0.2833333333333333,
"value": {
"__uuid__": "3b8bc5c0-26df-4218-b7dc-134a36080a35"
}

View File

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

View File

@@ -3,8 +3,8 @@
"uuid": "579bc0c1-f5e2-4a5d-889b-9d567e53b0e6",
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"size": {
"width": 1014,
"height": 1459
"width": 1024,
"height": 1456
},
"type": "Texture Packer",
"subMetas": {
@@ -17,8 +17,8 @@
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 806,
"trimY": 750,
"trimX": 384,
"trimY": 989,
"width": 112,
"height": 128,
"rawWidth": 112,
@@ -39,8 +39,8 @@
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 0,
"trimY": 1076,
"trimX": 256,
"trimY": 990,
"width": 112,
"height": 128,
"rawWidth": 112,
@@ -83,8 +83,8 @@
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 528,
"trimY": 515,
"trimX": 940,
"trimY": 0,
"width": 80,
"height": 128,
"rawWidth": 80,
@@ -105,8 +105,8 @@
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 934,
"trimY": 640,
"trimX": 940,
"trimY": 128,
"width": 80,
"height": 128,
"rawWidth": 80,
@@ -128,7 +128,7 @@
"offsetX": 0,
"offsetY": 0,
"trimX": 128,
"trimY": 1076,
"trimY": 1082,
"width": 112,
"height": 128,
"rawWidth": 112,
@@ -149,8 +149,8 @@
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 678,
"trimY": 862,
"trimX": 0,
"trimY": 1188,
"width": 112,
"height": 128,
"rawWidth": 112,
@@ -215,8 +215,8 @@
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 934,
"trimY": 768,
"trimX": 940,
"trimY": 256,
"width": 80,
"height": 128,
"rawWidth": 80,
@@ -237,8 +237,8 @@
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 934,
"trimY": 896,
"trimX": 937,
"trimY": 384,
"width": 80,
"height": 128,
"rawWidth": 80,
@@ -256,11 +256,11 @@
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 806,
"trimY": 958,
"trimX": 528,
"trimY": 515,
"width": 80,
"height": 128,
"rawWidth": 80,
@@ -281,8 +281,8 @@
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 934,
"trimY": 1024,
"trimX": 936,
"trimY": 512,
"width": 80,
"height": 128,
"rawWidth": 80,
@@ -325,8 +325,8 @@
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 128,
"trimY": 964,
"trimX": 0,
"trimY": 1076,
"width": 128,
"height": 112,
"rawWidth": 128,
@@ -347,8 +347,8 @@
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 912,
"trimY": 1152,
"trimX": 688,
"trimY": 1357,
"width": 96,
"height": 96,
"rawWidth": 96,
@@ -369,8 +369,8 @@
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 340,
"trimY": 1197,
"trimX": 240,
"trimY": 1360,
"width": 96,
"height": 112,
"rawWidth": 96,
@@ -391,8 +391,8 @@
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 452,
"trimY": 1196,
"trimX": 352,
"trimY": 1358,
"width": 96,
"height": 112,
"rawWidth": 96,
@@ -413,8 +413,8 @@
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 564,
"trimY": 1155,
"trimX": 920,
"trimY": 1072,
"width": 96,
"height": 112,
"rawWidth": 96,
@@ -435,8 +435,8 @@
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 608,
"trimY": 1043,
"trimX": 914,
"trimY": 1184,
"width": 96,
"height": 112,
"rawWidth": 96,
@@ -479,8 +479,8 @@
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 678,
"trimY": 750,
"trimX": 806,
"trimY": 631,
"width": 128,
"height": 112,
"rawWidth": 128,
@@ -787,8 +787,8 @@
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 448,
"trimY": 1293,
"trimX": 802,
"trimY": 1149,
"width": 112,
"height": 112,
"rawWidth": 112,
@@ -806,11 +806,11 @@
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 660,
"trimY": 1155,
"trimX": 800,
"trimY": 1261,
"width": 96,
"height": 112,
"rawWidth": 96,
@@ -831,8 +831,8 @@
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 384,
"trimY": 988,
"trimX": 806,
"trimY": 743,
"width": 128,
"height": 112,
"rawWidth": 128,
@@ -941,8 +941,8 @@
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 0,
"trimY": 1188,
"trimX": 806,
"trimY": 1037,
"width": 114,
"height": 112,
"rawWidth": 114,
@@ -960,11 +960,11 @@
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 114,
"trimY": 1188,
"trimX": 384,
"trimY": 1213,
"width": 114,
"height": 112,
"rawWidth": 114,
@@ -985,8 +985,8 @@
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 0,
"trimY": 1300,
"trimX": 464,
"trimY": 1327,
"width": 114,
"height": 112,
"rawWidth": 114,
@@ -1007,8 +1007,8 @@
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 112,
"trimY": 1300,
"trimX": 496,
"trimY": 1213,
"width": 114,
"height": 112,
"rawWidth": 114,
@@ -1029,8 +1029,8 @@
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 0,
"trimY": 1300,
"trimX": 464,
"trimY": 1327,
"width": 114,
"height": 112,
"rawWidth": 114,
@@ -1051,8 +1051,8 @@
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 224,
"trimY": 1300,
"trimX": 576,
"trimY": 1327,
"width": 114,
"height": 112,
"rawWidth": 114,
@@ -1070,11 +1070,11 @@
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 336,
"trimY": 1293,
"trimX": 688,
"trimY": 1043,
"width": 114,
"height": 112,
"rawWidth": 114,
@@ -1095,8 +1095,8 @@
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 384,
"trimY": 634,
"trimX": 128,
"trimY": 846,
"width": 128,
"height": 118,
"rawWidth": 128,
@@ -1117,8 +1117,8 @@
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 384,
"trimY": 752,
"trimX": 0,
"trimY": 958,
"width": 128,
"height": 118,
"rawWidth": 128,
@@ -1139,7 +1139,7 @@
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 256,
"trimX": 384,
"trimY": 753,
"width": 128,
"height": 118,
@@ -1161,8 +1161,8 @@
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 128,
"trimY": 846,
"trimX": 678,
"trimY": 631,
"width": 128,
"height": 118,
"rawWidth": 128,
@@ -1183,8 +1183,8 @@
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 0,
"trimY": 958,
"trimX": 384,
"trimY": 871,
"width": 128,
"height": 118,
"rawWidth": 128,
@@ -1205,8 +1205,8 @@
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 384,
"trimY": 870,
"trimX": 256,
"trimY": 872,
"width": 128,
"height": 118,
"rawWidth": 128,
@@ -1227,8 +1227,8 @@
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 256,
"trimY": 871,
"trimX": 128,
"trimY": 964,
"width": 128,
"height": 118,
"rawWidth": 128,
@@ -1249,8 +1249,8 @@
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 940,
"trimY": 0,
"trimX": 608,
"trimY": 531,
"width": 70,
"height": 128,
"rawWidth": 70,
@@ -1271,8 +1271,8 @@
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 940,
"trimY": 128,
"trimX": 608,
"trimY": 659,
"width": 70,
"height": 128,
"rawWidth": 70,
@@ -1293,8 +1293,8 @@
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 940,
"trimY": 256,
"trimX": 608,
"trimY": 787,
"width": 70,
"height": 128,
"rawWidth": 70,
@@ -1315,8 +1315,8 @@
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 937,
"trimY": 384,
"trimX": 608,
"trimY": 915,
"width": 70,
"height": 128,
"rawWidth": 70,
@@ -1334,11 +1334,11 @@
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 936,
"trimY": 512,
"trimX": 128,
"trimY": 1290,
"width": 70,
"height": 128,
"rawWidth": 70,
@@ -1356,11 +1356,11 @@
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 608,
"trimY": 531,
"trimX": 0,
"trimY": 1300,
"width": 70,
"height": 128,
"rawWidth": 70,
@@ -1378,11 +1378,11 @@
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 608,
"trimY": 659,
"trimX": 0,
"trimY": 1370,
"width": 70,
"height": 128,
"rawWidth": 70,
@@ -1400,11 +1400,11 @@
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 608,
"trimY": 659,
"trimX": 0,
"trimY": 1370,
"width": 70,
"height": 128,
"rawWidth": 70,
@@ -1422,11 +1422,11 @@
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 608,
"trimY": 531,
"trimX": 0,
"trimY": 1300,
"width": 70,
"height": 128,
"rawWidth": 70,
@@ -1444,11 +1444,11 @@
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 936,
"trimY": 512,
"trimX": 128,
"trimY": 1290,
"width": 70,
"height": 128,
"rawWidth": 70,
@@ -1469,8 +1469,8 @@
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 937,
"trimY": 384,
"trimX": 608,
"trimY": 915,
"width": 70,
"height": 128,
"rawWidth": 70,
@@ -1491,8 +1491,8 @@
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 940,
"trimY": 256,
"trimX": 608,
"trimY": 787,
"width": 70,
"height": 128,
"rawWidth": 70,
@@ -1513,8 +1513,8 @@
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 940,
"trimY": 128,
"trimX": 608,
"trimY": 659,
"width": 70,
"height": 128,
"rawWidth": 70,
@@ -1532,11 +1532,11 @@
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 608,
"trimY": 787,
"trimX": 806,
"trimY": 967,
"width": 70,
"height": 128,
"rawWidth": 70,
@@ -1554,11 +1554,11 @@
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 608,
"trimY": 915,
"trimX": 678,
"trimY": 973,
"width": 70,
"height": 128,
"rawWidth": 70,
@@ -1579,8 +1579,8 @@
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 228,
"trimY": 1197,
"trimX": 128,
"trimY": 1360,
"width": 112,
"height": 96,
"rawWidth": 112,
@@ -1645,8 +1645,8 @@
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 256,
"trimY": 989,
"trimX": 678,
"trimY": 749,
"width": 128,
"height": 112,
"rawWidth": 128,
@@ -1667,8 +1667,8 @@
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 672,
"trimY": 1363,
"trimX": 784,
"trimY": 1357,
"width": 96,
"height": 96,
"rawWidth": 96,
@@ -1689,8 +1689,8 @@
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 672,
"trimY": 1267,
"trimX": 934,
"trimY": 976,
"width": 80,
"height": 96,
"rawWidth": 80,
@@ -1711,8 +1711,8 @@
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 560,
"trimY": 1292,
"trimX": 688,
"trimY": 1155,
"width": 112,
"height": 112,
"rawWidth": 112,
@@ -1733,8 +1733,8 @@
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 384,
"trimY": 1100,
"trimX": 256,
"trimY": 1102,
"width": 128,
"height": 96,
"rawWidth": 128,
@@ -1752,11 +1752,11 @@
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 800,
"trimY": 1038,
"trimX": 934,
"trimY": 640,
"width": 80,
"height": 112,
"rawWidth": 80,
@@ -1774,11 +1774,11 @@
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 800,
"trimY": 1118,
"trimX": 934,
"trimY": 752,
"width": 80,
"height": 112,
"rawWidth": 80,
@@ -1799,8 +1799,8 @@
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 678,
"trimY": 974,
"trimX": 256,
"trimY": 1294,
"width": 64,
"height": 128,
"rawWidth": 64,
@@ -1818,11 +1818,11 @@
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 756,
"trimY": 1198,
"trimX": 934,
"trimY": 864,
"width": 80,
"height": 112,
"rawWidth": 80,
@@ -1840,11 +1840,11 @@
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 752,
"trimY": 1278,
"trimX": 608,
"trimY": 1043,
"width": 80,
"height": 96,
"rawWidth": 80,
@@ -1865,8 +1865,8 @@
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 768,
"trimY": 1358,
"trimX": 608,
"trimY": 1139,
"width": 80,
"height": 96,
"rawWidth": 80,
@@ -1887,8 +1887,8 @@
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 868,
"trimY": 1248,
"trimX": 688,
"trimY": 1267,
"width": 80,
"height": 96,
"rawWidth": 80,
@@ -1906,11 +1906,11 @@
"rawTextureUuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 704,
"trimY": 1038,
"trimX": 912,
"trimY": 1296,
"width": 96,
"height": 112,
"rawWidth": 96,
@@ -1931,8 +1931,8 @@
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 256,
"trimY": 1101,
"trimX": 128,
"trimY": 1194,
"width": 96,
"height": 128,
"rawWidth": 96,
@@ -1953,8 +1953,8 @@
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 806,
"trimY": 862,
"trimX": 256,
"trimY": 1198,
"width": 96,
"height": 128,
"rawWidth": 96,
@@ -2076,6 +2076,72 @@
"spriteType": "normal",
"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": {
"ver": "1.0.4",
"uuid": "9435195e-4560-495e-b1ae-083c0c87e8a0",
@@ -2129,8 +2195,8 @@
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 680,
"trimY": 512,
"trimX": 272,
"trimY": 515,
"width": 119,
"height": 128,
"rawWidth": 119,
@@ -2151,8 +2217,8 @@
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 808,
"trimY": 512,
"trimX": 128,
"trimY": 608,
"width": 119,
"height": 128,
"rawWidth": 119,
@@ -2173,8 +2239,8 @@
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 272,
"trimY": 515,
"trimX": 0,
"trimY": 720,
"width": 119,
"height": 128,
"rawWidth": 119,
@@ -2195,8 +2261,8 @@
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 128,
"trimY": 608,
"trimX": 400,
"trimY": 515,
"width": 119,
"height": 128,
"rawWidth": 119,
@@ -2217,8 +2283,8 @@
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 0,
"trimY": 720,
"trimX": 256,
"trimY": 634,
"width": 119,
"height": 128,
"rawWidth": 119,
@@ -2239,8 +2305,8 @@
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 400,
"trimY": 515,
"trimX": 128,
"trimY": 727,
"width": 119,
"height": 128,
"rawWidth": 119,
@@ -2261,8 +2327,8 @@
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 678,
"trimY": 631,
"trimX": 0,
"trimY": 839,
"width": 119,
"height": 128,
"rawWidth": 119,
@@ -2283,8 +2349,8 @@
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 806,
"trimY": 631,
"trimX": 384,
"trimY": 634,
"width": 119,
"height": 128,
"rawWidth": 119,
@@ -2305,8 +2371,8 @@
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 256,
"trimY": 634,
"trimX": 680,
"trimY": 512,
"width": 119,
"height": 128,
"rawWidth": 119,
@@ -2327,8 +2393,8 @@
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 128,
"trimY": 727,
"trimX": 808,
"trimY": 512,
"width": 119,
"height": 128,
"rawWidth": 119,
@@ -2349,8 +2415,8 @@
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 0,
"trimY": 839,
"trimX": 256,
"trimY": 753,
"width": 119,
"height": 128,
"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",
"_objFlags": 0,
"_native": "",
"_duration": 1.5166666666666666,
"_duration": 0.6333333333333333,
"sample": 60,
"speed": 1.2,
"wrapMode": 2,
@@ -13,78 +13,78 @@
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "c3b14ecc-a6d9-4cb3-8637-ca7b407a0f5c"
}
},
{
"frame": 0.08333333333333333,
"value": {
"__uuid__": "9435195e-4560-495e-b1ae-083c0c87e8a0"
}
},
{
"frame": 0.18333333333333332,
"frame": 0.06666666666666667,
"value": {
"__uuid__": "ec048360-7a17-4f22-ba52-eb86ec1acae8"
}
},
{
"frame": 0.2833333333333333,
"frame": 0.11666666666666667,
"value": {
"__uuid__": "82bb81e3-667c-4280-8710-211f4904ef2f"
}
},
{
"frame": 0.4,
"frame": 0.16666666666666666,
"value": {
"__uuid__": "c3b14ecc-a6d9-4cb3-8637-ca7b407a0f5c"
}
},
{
"frame": 0.21666666666666667,
"value": {
"__uuid__": "f958fb7f-ef5a-4918-81f3-564004572f45"
}
},
{
"frame": 0.5333333333333333,
"frame": 0.26666666666666666,
"value": {
"__uuid__": "8a0ecf92-db26-4206-9a80-20e749055def"
}
},
{
"frame": 0.65,
"frame": 0.31666666666666665,
"value": {
"__uuid__": "942f2e02-a700-4fbf-877e-08c93e4d4010"
}
},
{
"frame": 0.7666666666666667,
"frame": 0.36666666666666664,
"value": {
"__uuid__": "30546064-1a11-499e-8523-a82c83951c73"
}
},
{
"frame": 0.9,
"frame": 0.4166666666666667,
"value": {
"__uuid__": "515bb75f-7a1f-4500-8aa9-c895915ce19f"
}
},
{
"frame": 1.0333333333333334,
"frame": 0.4666666666666667,
"value": {
"__uuid__": "9100da6b-7582-4afb-9698-3d67d3b2012d"
}
},
{
"frame": 1.2166666666666666,
"frame": 0.5166666666666667,
"value": {
"__uuid__": "1257f72d-0cb3-4750-ae70-13c2d8eb2269"
}
},
{
"frame": 1.3833333333333333,
"frame": 0.5666666666666667,
"value": {
"__uuid__": "1d34b6db-27ba-4e26-864d-0f00d501765e"
}
},
{
"frame": 1.5,
"frame": 0.6166666666666667,
"value": {
"__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>
<string>{62,92}</string>
<key>textureRect</key>
<string>{{1277,188},{62,92}}</string>
<string>{{1307,188},{62,92}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -30,7 +30,7 @@
<key>spriteSourceSize</key>
<string>{77,99}</string>
<key>textureRect</key>
<string>{{748,0},{77,99}}</string>
<string>{{782,101},{77,99}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -45,7 +45,7 @@
<key>spriteSourceSize</key>
<string>{112,99}</string>
<key>textureRect</key>
<string>{{408,348},{112,99}}</string>
<string>{{381,360},{112,99}}</string>
<key>textureRotated</key>
<true/>
</dict>
@@ -60,7 +60,7 @@
<key>spriteSourceSize</key>
<string>{96,100}</string>
<key>textureRect</key>
<string>{{664,315},{96,100}}</string>
<string>{{704,312},{96,100}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -75,7 +75,7 @@
<key>spriteSourceSize</key>
<string>{62,92}</string>
<key>textureRect</key>
<string>{{1277,188},{62,92}}</string>
<string>{{1307,188},{62,92}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -90,7 +90,7 @@
<key>spriteSourceSize</key>
<string>{58,97}</string>
<key>textureRect</key>
<string>{{1023,194},{58,97}}</string>
<string>{{983,388},{58,97}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -105,9 +105,9 @@
<key>spriteSourceSize</key>
<string>{60,90}</string>
<key>textureRect</key>
<string>{{1393,141},{60,90}}</string>
<string>{{1424,0},{60,90}}</string>
<key>textureRotated</key>
<true/>
<false/>
</dict>
<key>Atk2_2.png</key>
<dict>
@@ -120,7 +120,7 @@
<key>spriteSourceSize</key>
<string>{84,96}</string>
<key>textureRect</key>
<string>{{1087,97},{84,96}}</string>
<string>{{1082,291},{84,96}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -135,7 +135,7 @@
<key>spriteSourceSize</key>
<string>{55,100}</string>
<key>textureRect</key>
<string>{{731,101},{55,100}}</string>
<string>{{738,206},{55,100}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -150,9 +150,9 @@
<key>spriteSourceSize</key>
<string>{63,100}</string>
<key>textureRect</key>
<string>{{717,206},{63,100}}</string>
<string>{{0,437},{63,100}}</string>
<key>textureRotated</key>
<false/>
<true/>
</dict>
<key>Atk2_5.png</key>
<dict>
@@ -165,7 +165,7 @@
<key>spriteSourceSize</key>
<string>{66,101}</string>
<key>textureRect</key>
<string>{{682,0},{66,101}}</string>
<string>{{755,0},{66,101}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -180,7 +180,7 @@
<key>spriteSourceSize</key>
<string>{80,95}</string>
<key>textureRect</key>
<string>{{1126,0},{80,95}}</string>
<string>{{1099,387},{80,95}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -195,7 +195,7 @@
<key>spriteSourceSize</key>
<string>{116,109}</string>
<key>textureRect</key>
<string>{{315,119},{116,109}}</string>
<string>{{336,244},{116,109}}</string>
<key>textureRotated</key>
<true/>
</dict>
@@ -210,7 +210,7 @@
<key>spriteSourceSize</key>
<string>{102,96}</string>
<key>textureRect</key>
<string>{{621,213},{102,96}}</string>
<string>{{608,325},{102,96}}</string>
<key>textureRotated</key>
<true/>
</dict>
@@ -225,9 +225,9 @@
<key>spriteSourceSize</key>
<string>{75,102}</string>
<key>textureRect</key>
<string>{{139,421},{75,102}}</string>
<string>{{663,210},{75,102}}</string>
<key>textureRotated</key>
<true/>
<false/>
</dict>
<key>Atk3_0.png</key>
<dict>
@@ -240,7 +240,7 @@
<key>spriteSourceSize</key>
<string>{66,109}</string>
<key>textureRect</key>
<string>{{469,110},{66,109}}</string>
<string>{{480,339},{66,109}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -255,7 +255,7 @@
<key>spriteSourceSize</key>
<string>{66,113}</string>
<key>textureRect</key>
<string>{{355,235},{66,113}}</string>
<string>{{403,114},{66,113}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -330,7 +330,7 @@
<key>spriteSourceSize</key>
<string>{78,131}</string>
<key>textureRect</key>
<string>{{137,290},{78,131}}</string>
<string>{{78,0},{78,131}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -345,9 +345,9 @@
<key>spriteSourceSize</key>
<string>{59,139}</string>
<key>textureRect</key>
<string>{{0,437},{59,139}}</string>
<string>{{78,290},{59,139}}</string>
<key>textureRotated</key>
<true/>
<false/>
</dict>
<key>Atk3_8.png</key>
<dict>
@@ -360,7 +360,7 @@
<key>spriteSourceSize</key>
<string>{59,139}</string>
<key>textureRect</key>
<string>{{78,290},{59,139}}</string>
<string>{{137,290},{59,139}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -375,9 +375,9 @@
<key>spriteSourceSize</key>
<string>{62,97}</string>
<key>textureRect</key>
<string>{{507,434},{62,97}}</string>
<string>{{962,291},{62,97}}</string>
<key>textureRotated</key>
<true/>
<false/>
</dict>
<key>Atked1_1.png</key>
<dict>
@@ -390,9 +390,9 @@
<key>spriteSourceSize</key>
<string>{73,95}</string>
<key>textureRect</key>
<string>{{1171,95},{73,95}}</string>
<string>{{641,427},{73,95}}</string>
<key>textureRotated</key>
<false/>
<true/>
</dict>
<key>Atked1_2.png</key>
<dict>
@@ -405,7 +405,7 @@
<key>spriteSourceSize</key>
<string>{90,89}</string>
<key>textureRect</key>
<string>{{1324,0},{90,89}}</string>
<string>{{1335,0},{90,89}}</string>
<key>textureRotated</key>
<true/>
</dict>
@@ -420,7 +420,7 @@
<key>spriteSourceSize</key>
<string>{95,80}</string>
<key>textureRect</key>
<string>{{1084,291},{95,80}}</string>
<string>{{1168,193},{95,80}}</string>
<key>textureRotated</key>
<true/>
</dict>
@@ -435,7 +435,7 @@
<key>spriteSourceSize</key>
<string>{80,95}</string>
<key>textureRect</key>
<string>{{1010,388},{80,95}}</string>
<string>{{1166,290},{80,95}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -450,7 +450,7 @@
<key>spriteSourceSize</key>
<string>{83,92}</string>
<key>textureRect</key>
<string>{{1208,382},{83,92}}</string>
<string>{{1299,382},{83,92}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -465,7 +465,7 @@
<key>spriteSourceSize</key>
<string>{92,83}</string>
<key>textureRect</key>
<string>{{1224,284},{92,83}}</string>
<string>{{1306,284},{92,83}}</string>
<key>textureRotated</key>
<true/>
</dict>
@@ -480,7 +480,7 @@
<key>spriteSourceSize</key>
<string>{112,45}</string>
<key>textureRect</key>
<string>{{424,115},{112,45}}</string>
<string>{{469,112},{112,45}}</string>
<key>textureRotated</key>
<true/>
</dict>
@@ -495,7 +495,7 @@
<key>spriteSourceSize</key>
<string>{88,69}</string>
<key>textureRect</key>
<string>{{604,427},{88,69}}</string>
<string>{{1443,222},{88,69}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -510,7 +510,7 @@
<key>spriteSourceSize</key>
<string>{91,90}</string>
<key>textureRect</key>
<string>{{1303,93},{91,90}}</string>
<string>{{1313,93},{91,90}}</string>
<key>textureRotated</key>
<true/>
</dict>
@@ -525,7 +525,7 @@
<key>spriteSourceSize</key>
<string>{120,93}</string>
<key>textureRect</key>
<string>{{222,123},{120,93}}</string>
<string>{{254,124},{120,93}}</string>
<key>textureRotated</key>
<true/>
</dict>
@@ -540,9 +540,9 @@
<key>spriteSourceSize</key>
<string>{100,112}</string>
<key>textureRect</key>
<string>{{241,396},{100,112}}</string>
<string>{{408,0},{100,112}}</string>
<key>textureRotated</key>
<true/>
<false/>
</dict>
<key>GetUp1_5.png</key>
<dict>
@@ -555,7 +555,7 @@
<key>spriteSourceSize</key>
<string>{106,93}</string>
<key>textureRect</key>
<string>{{507,328},{106,93}}</string>
<string>{{570,219},{106,93}}</string>
<key>textureRotated</key>
<true/>
</dict>
@@ -570,7 +570,7 @@
<key>spriteSourceSize</key>
<string>{106,79}</string>
<key>textureRect</key>
<string>{{542,217},{106,79}}</string>
<string>{{571,108},{106,79}}</string>
<key>textureRotated</key>
<true/>
</dict>
@@ -585,7 +585,7 @@
<key>spriteSourceSize</key>
<string>{73,87}</string>
<key>textureRect</key>
<string>{{1307,280},{73,87}}</string>
<string>{{1382,376},{73,87}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -600,9 +600,9 @@
<key>spriteSourceSize</key>
<string>{67,90}</string>
<key>textureRect</key>
<string>{{1413,74},{67,90}}</string>
<string>{{1403,90},{67,90}}</string>
<key>textureRotated</key>
<true/>
<false/>
</dict>
<key>GetUp1_9.png</key>
<dict>
@@ -615,7 +615,7 @@
<key>spriteSourceSize</key>
<string>{58,97}</string>
<key>textureRect</key>
<string>{{1023,194},{58,97}}</string>
<string>{{983,388},{58,97}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -630,7 +630,7 @@
<key>spriteSourceSize</key>
<string>{58,95}</string>
<key>textureRect</key>
<string>{{1090,386},{58,95}}</string>
<string>{{1219,0},{58,95}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -645,7 +645,7 @@
<key>spriteSourceSize</key>
<string>{58,97}</string>
<key>textureRect</key>
<string>{{1029,97},{58,97}}</string>
<string>{{1024,291},{58,97}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -660,7 +660,7 @@
<key>spriteSourceSize</key>
<string>{60,94}</string>
<key>textureRect</key>
<string>{{1148,386},{60,94}}</string>
<string>{{1179,385},{60,94}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -675,7 +675,7 @@
<key>spriteSourceSize</key>
<string>{58,97}</string>
<key>textureRect</key>
<string>{{1081,194},{58,97}}</string>
<string>{{1036,194},{58,97}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -690,7 +690,7 @@
<key>spriteSourceSize</key>
<string>{58,97}</string>
<key>textureRect</key>
<string>{{1068,0},{58,97}}</string>
<string>{{1041,388},{58,97}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -705,9 +705,9 @@
<key>spriteSourceSize</key>
<string>{60,95}</string>
<key>textureRect</key>
<string>{{1206,0},{60,95}}</string>
<string>{{546,440},{60,95}}</string>
<key>textureRotated</key>
<false/>
<true/>
</dict>
<key>Idle1_5.png</key>
<dict>
@@ -720,7 +720,7 @@
<key>spriteSourceSize</key>
<string>{60,94}</string>
<key>textureRect</key>
<string>{{1164,288},{60,94}}</string>
<string>{{1239,385},{60,94}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -735,7 +735,7 @@
<key>spriteSourceSize</key>
<string>{59,93}</string>
<key>textureRect</key>
<string>{{789,403},{59,93}}</string>
<string>{{1248,191},{59,93}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -750,7 +750,7 @@
<key>spriteSourceSize</key>
<string>{58,93}</string>
<key>textureRect</key>
<string>{{1266,0},{58,93}}</string>
<string>{{1277,0},{58,93}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -765,7 +765,7 @@
<key>spriteSourceSize</key>
<string>{59,93}</string>
<key>textureRect</key>
<string>{{1244,95},{59,93}}</string>
<string>{{1254,95},{59,93}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -780,7 +780,7 @@
<key>spriteSourceSize</key>
<string>{60,94}</string>
<key>textureRect</key>
<string>{{1217,190},{60,94}}</string>
<string>{{1246,288},{60,94}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -795,7 +795,7 @@
<key>spriteSourceSize</key>
<string>{77,68}</string>
<key>textureRect</key>
<string>{{1437,417},{77,68}}</string>
<string>{{1473,291},{77,68}}</string>
<key>textureRotated</key>
<true/>
</dict>
@@ -810,7 +810,7 @@
<key>spriteSourceSize</key>
<string>{118,76}</string>
<key>textureRect</key>
<string>{{215,278},{118,76}}</string>
<string>{{196,284},{118,76}}</string>
<key>textureRotated</key>
<true/>
</dict>
@@ -825,7 +825,7 @@
<key>spriteSourceSize</key>
<string>{104,65}</string>
<key>textureRect</key>
<string>{{617,0},{104,65}}</string>
<string>{{650,106},{104,65}}</string>
<key>textureRotated</key>
<true/>
</dict>
@@ -840,9 +840,9 @@
<key>spriteSourceSize</key>
<string>{80,66}</string>
<key>textureRect</key>
<string>{{1380,285},{80,66}}</string>
<string>{{1473,368},{80,66}}</string>
<key>textureRotated</key>
<false/>
<true/>
</dict>
<key>InAirAtk1_12.png</key>
<dict>
@@ -855,7 +855,7 @@
<key>spriteSourceSize</key>
<string>{102,67}</string>
<key>textureRect</key>
<string>{{664,104},{102,67}}</string>
<string>{{715,104},{102,67}}</string>
<key>textureRotated</key>
<true/>
</dict>
@@ -870,9 +870,9 @@
<key>spriteSourceSize</key>
<string>{79,66}</string>
<key>textureRect</key>
<string>{{1339,201},{79,66}}</string>
<string>{{1470,90},{79,66}}</string>
<key>textureRotated</key>
<true/>
<false/>
</dict>
<key>InAirAtk1_3.png</key>
<dict>
@@ -885,7 +885,7 @@
<key>spriteSourceSize</key>
<string>{124,64}</string>
<key>textureRect</key>
<string>{{78,0},{124,64}}</string>
<string>{{156,0},{124,64}}</string>
<key>textureRotated</key>
<true/>
</dict>
@@ -900,7 +900,7 @@
<key>spriteSourceSize</key>
<string>{104,64}</string>
<key>textureRect</key>
<string>{{600,323},{104,64}}</string>
<string>{{691,0},{104,64}}</string>
<key>textureRotated</key>
<true/>
</dict>
@@ -915,7 +915,7 @@
<key>spriteSourceSize</key>
<string>{79,61}</string>
<key>textureRect</key>
<string>{{1376,417},{79,61}}</string>
<string>{{1484,0},{79,61}}</string>
<key>textureRotated</key>
<true/>
</dict>
@@ -930,7 +930,7 @@
<key>spriteSourceSize</key>
<string>{124,64}</string>
<key>textureRect</key>
<string>{{142,0},{124,64}}</string>
<string>{{160,124},{124,64}}</string>
<key>textureRotated</key>
<true/>
</dict>
@@ -945,7 +945,7 @@
<key>spriteSourceSize</key>
<string>{106,67}</string>
<key>textureRect</key>
<string>{{597,107},{106,67}}</string>
<string>{{624,0},{106,67}}</string>
<key>textureRotated</key>
<true/>
</dict>
@@ -960,7 +960,7 @@
<key>spriteSourceSize</key>
<string>{79,66}</string>
<key>textureRect</key>
<string>{{1380,351},{79,66}}</string>
<string>{{1470,156},{79,66}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -975,7 +975,7 @@
<key>spriteSourceSize</key>
<string>{118,64}</string>
<key>textureRect</key>
<string>{{291,243},{118,64}}</string>
<string>{{272,284},{118,64}}</string>
<key>textureRotated</key>
<true/>
</dict>
@@ -990,9 +990,9 @@
<key>spriteSourceSize</key>
<string>{71,119}</string>
<key>textureRect</key>
<string>{{242,0},{71,119}}</string>
<string>{{100,429},{71,119}}</string>
<key>textureRotated</key>
<false/>
<true/>
</dict>
<key>InAirIdle1_1.png</key>
<dict>
@@ -1005,7 +1005,7 @@
<key>spriteSourceSize</key>
<string>{71,119}</string>
<key>textureRect</key>
<string>{{313,0},{71,119}}</string>
<string>{{282,0},{71,119}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -1020,7 +1020,7 @@
<key>spriteSourceSize</key>
<string>{55,114}</string>
<key>textureRect</key>
<string>{{353,361},{55,114}}</string>
<string>{{353,0},{55,114}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -1035,7 +1035,7 @@
<key>spriteSourceSize</key>
<string>{62,124}</string>
<key>textureRect</key>
<string>{{160,124},{62,124}}</string>
<string>{{220,0},{62,124}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -1050,9 +1050,9 @@
<key>spriteSourceSize</key>
<string>{74,90}</string>
<key>textureRect</key>
<string>{{1413,0},{74,90}}</string>
<string>{{1369,184},{74,90}}</string>
<key>textureRotated</key>
<true/>
<false/>
</dict>
<key>InAirIdle1_3.png</key>
<dict>
@@ -1065,7 +1065,7 @@
<key>spriteSourceSize</key>
<string>{110,54}</string>
<key>textureRect</key>
<string>{{440,0},{110,54}}</string>
<string>{{508,0},{110,54}}</string>
<key>textureRotated</key>
<true/>
</dict>
@@ -1080,7 +1080,7 @@
<key>spriteSourceSize</key>
<string>{85,88}</string>
<key>textureRect</key>
<string>{{1291,376},{85,88}}</string>
<string>{{736,412},{85,88}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -1095,7 +1095,7 @@
<key>spriteSourceSize</key>
<string>{64,112}</string>
<key>textureRect</key>
<string>{{421,235},{64,112}}</string>
<string>{{445,227},{64,112}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -1110,7 +1110,7 @@
<key>spriteSourceSize</key>
<string>{62,107}</string>
<key>textureRect</key>
<string>{{555,0},{62,107}}</string>
<string>{{546,333},{62,107}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -1125,9 +1125,9 @@
<key>spriteSourceSize</key>
<string>{85,84}</string>
<key>textureRect</key>
<string>{{1405,201},{85,84}}</string>
<string>{{1389,291},{85,84}}</string>
<key>textureRotated</key>
<false/>
<true/>
</dict>
<key>InAirIdle1_8.png</key>
<dict>
@@ -1140,7 +1140,7 @@
<key>spriteSourceSize</key>
<string>{109,61}</string>
<key>textureRect</key>
<string>{{494,0},{109,61}}</string>
<string>{{509,224},{109,61}}</string>
<key>textureRotated</key>
<true/>
</dict>
@@ -1155,7 +1155,7 @@
<key>spriteSourceSize</key>
<string>{78,95}</string>
<key>textureRect</key>
<string>{{1139,193},{78,95}}</string>
<string>{{1176,96},{78,95}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -1170,7 +1170,7 @@
<key>spriteSourceSize</key>
<string>{115,56}</string>
<key>textureRect</key>
<string>{{384,0},{115,56}}</string>
<string>{{347,119},{115,56}}</string>
<key>textureRotated</key>
<true/>
</dict>
@@ -1185,7 +1185,7 @@
<key>spriteSourceSize</key>
<string>{109,57}</string>
<key>textureRect</key>
<string>{{485,219},{109,57}}</string>
<string>{{514,110},{109,57}}</string>
<key>textureRotated</key>
<true/>
</dict>
@@ -1200,7 +1200,7 @@
<key>spriteSourceSize</key>
<string>{108,62}</string>
<key>textureRect</key>
<string>{{535,109},{108,62}}</string>
<string>{{562,0},{108,62}}</string>
<key>textureRotated</key>
<true/>
</dict>
@@ -1215,9 +1215,9 @@
<key>spriteSourceSize</key>
<string>{123,36}</string>
<key>textureRect</key>
<string>{{206,0},{123,36}}</string>
<string>{{160,248},{123,36}}</string>
<key>textureRotated</key>
<true/>
<false/>
</dict>
<key>LayDown1_4.png</key>
<dict>
@@ -1230,7 +1230,52 @@
<key>spriteSourceSize</key>
<string>{123,30}</string>
<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>
<false/>
</dict>
@@ -1245,9 +1290,9 @@
<key>spriteSourceSize</key>
<string>{81,97}</string>
<key>textureRect</key>
<string>{{692,415},{81,97}}</string>
<string>{{219,402},{81,97}}</string>
<key>textureRotated</key>
<true/>
<false/>
</dict>
<key>Walking_10.png</key>
<dict>
@@ -1260,7 +1305,7 @@
<key>spriteSourceSize</key>
<string>{81,97}</string>
<key>textureRect</key>
<string>{{760,306},{81,97}}</string>
<string>{{300,402},{81,97}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -1275,7 +1320,7 @@
<key>spriteSourceSize</key>
<string>{81,97}</string>
<key>textureRect</key>
<string>{{780,201},{81,97}}</string>
<string>{{821,0},{81,97}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -1290,7 +1335,7 @@
<key>spriteSourceSize</key>
<string>{81,97}</string>
<key>textureRect</key>
<string>{{786,99},{81,97}}</string>
<string>{{793,200},{81,97}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -1305,7 +1350,7 @@
<key>spriteSourceSize</key>
<string>{81,97}</string>
<key>textureRect</key>
<string>{{825,0},{81,97}}</string>
<string>{{859,97},{81,97}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -1320,7 +1365,7 @@
<key>spriteSourceSize</key>
<string>{81,97}</string>
<key>textureRect</key>
<string>{{841,298},{81,97}}</string>
<string>{{902,0},{81,97}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -1335,7 +1380,7 @@
<key>spriteSourceSize</key>
<string>{81,97}</string>
<key>textureRect</key>
<string>{{848,395},{81,97}}</string>
<string>{{800,297},{81,97}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -1350,7 +1395,7 @@
<key>spriteSourceSize</key>
<string>{81,97}</string>
<key>textureRect</key>
<string>{{861,196},{81,97}}</string>
<string>{{874,194},{81,97}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -1365,7 +1410,7 @@
<key>spriteSourceSize</key>
<string>{81,97}</string>
<key>textureRect</key>
<string>{{867,97},{81,97}}</string>
<string>{{940,97},{81,97}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -1380,7 +1425,7 @@
<key>spriteSourceSize</key>
<string>{81,97}</string>
<key>textureRect</key>
<string>{{906,0},{81,97}}</string>
<string>{{983,0},{81,97}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -1395,7 +1440,7 @@
<key>spriteSourceSize</key>
<string>{81,97}</string>
<key>textureRect</key>
<string>{{922,293},{81,97}}</string>
<string>{{821,394},{81,97}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -1410,7 +1455,7 @@
<key>spriteSourceSize</key>
<string>{81,97}</string>
<key>textureRect</key>
<string>{{942,194},{81,97}}</string>
<string>{{881,291},{81,97}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -1425,7 +1470,7 @@
<key>spriteSourceSize</key>
<string>{81,97}</string>
<key>textureRect</key>
<string>{{948,97},{81,97}}</string>
<string>{{955,194},{81,97}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -1440,7 +1485,7 @@
<key>spriteSourceSize</key>
<string>{81,97}</string>
<key>textureRect</key>
<string>{{987,0},{81,97}}</string>
<string>{{1021,97},{81,97}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -1455,7 +1500,7 @@
<key>spriteSourceSize</key>
<string>{81,97}</string>
<key>textureRect</key>
<string>{{929,390},{81,97}}</string>
<string>{{1064,0},{81,97}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -1470,7 +1515,7 @@
<key>spriteSourceSize</key>
<string>{81,97}</string>
<key>textureRect</key>
<string>{{1003,291},{81,97}}</string>
<string>{{902,388},{81,97}}</string>
<key>textureRotated</key>
<false/>
</dict>
@@ -1486,9 +1531,9 @@
<key>realTextureFileName</key>
<string>MonkGirl.png</string>
<key>size</key>
<string>{1505,496}</string>
<string>{1549,500}</string>
<key>smartupdate</key>
<string>$TexturePacker:SmartUpdate:8383576ddc6ed0fb9e6adcbc98ec9c07:b0caf27c9f592741053365a3d87b3473:7b088363a1f16e4f4ff313aecc52227b$</string>
<string>$TexturePacker:SmartUpdate:f2fd96a7a4bba5a2e1c4622dcb63e1f2:17c698372c46bf0be82704dd808cd6f4:7b088363a1f16e4f4ff313aecc52227b$</string>
<key>textureFileName</key>
<string>MonkGirl.png</string>
</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"?>
<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="65" source="tiles1.tsx"/>
<tileset firstgid="129" source="tiles2.tsx"/>
<layer id="6" name="Ground" width="128" height="64">
<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>
</layer>
<objectgroup id="1" name="PlayerStartingPos">
<object id="135" x="1140" y="488">
<object id="135" x="1400" y="580">
<point/>
</object>
<object id="137" x="1527" y="488">
<object id="137" x="1500" y="580">
<point/>
</object>
</objectgroup>
@@ -64,7 +64,7 @@
<property name="boundary_type" value="barrier"/>
</properties>
</object>
<object id="60" x="1232" y="432" width="208" height="16">
<object id="60" x="1232" y="448" width="208" height="16">
<properties>
<property name="boundary_type" value="barrier"/>
</properties>
@@ -99,7 +99,7 @@
<property name="boundary_type" value="barrier"/>
</properties>
</object>
<object id="90" x="1232" y="496" width="320" height="16">
<object id="90" x="1248" y="464" width="320" height="16">
<properties>
<property name="boundary_type" value="barrier"/>
</properties>
@@ -114,37 +114,37 @@
<property name="boundary_type" value="barrier"/>
</properties>
</object>
<object id="100" x="1552" y="576" width="128" height="16">
<object id="100" x="1538" y="560" width="144" height="32">
<properties>
<property name="boundary_type" value="barrier"/>
</properties>
</object>
<object id="101" x="1568" y="560" width="112" height="16">
<object id="101" x="1568" y="528" width="112" height="32">
<properties>
<property name="boundary_type" value="barrier"/>
</properties>
</object>
<object id="102" x="1584" y="544" width="96" height="16">
<object id="102" x="1136" y="368" width="96" height="16">
<properties>
<property name="boundary_type" value="barrier"/>
</properties>
</object>
<object id="103" x="1600" y="528" width="80" height="16">
<object id="103" x="1600" y="496" width="80" height="32">
<properties>
<property name="boundary_type" value="barrier"/>
</properties>
</object>
<object id="104" x="768" y="382" width="304" height="16">
<object id="104" x="816" y="414" width="304" height="16">
<properties>
<property name="boundary_type" value="barrier"/>
</properties>
</object>
<object id="105" x="768" y="302" width="16" height="96">
<object id="105" x="816" y="366" width="16" height="64">
<properties>
<property name="boundary_type" value="barrier"/>
</properties>
</object>
<object id="106" x="1056" y="302" width="16" height="96">
<object id="106" x="1104" y="334" width="16" height="96">
<properties>
<property name="boundary_type" value="barrier"/>
</properties>
@@ -164,42 +164,7 @@
<property name="boundary_type" value="barrier"/>
</properties>
</object>
<object id="120" x="736" y="512" width="16" 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">
<object id="136" x="1232" y="432" width="208" height="16">
<properties>
<property name="boundary_type" value="barrier"/>
</properties>

View File

@@ -6,12 +6,12 @@ import "geometry.proto"; // The import path here is only w.r.t. the proto file,
message PlayerDownsync {
int32 id = 1;
int32 virtualGridX = 2;
int32 virtualGridY = 3;
int32 virtualGridX = 2;
int32 virtualGridY = 3;
int32 dirX = 4;
int32 dirY = 5; // "dirX" and "dirY" determines character facing
int32 velX = 6;
int32 velY = 7; // "velX" and "velY" is used to record the accumulated effect by accelerations (including gravity)
int32 dirY = 5;
int32 velX = 6;
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 battleState = 9;
int32 joinIndex = 10;
@@ -36,6 +36,8 @@ message PlayerDownsync {
int32 onWallNormX = 27;
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 displayName = 998;
string avatar = 999;
@@ -51,6 +53,7 @@ message InputFrameDecoded {
message InputFrameUpsync {
int32 inputFrameId = 1;
uint64 encoded = 2;
int32 joinIndex = 3;
}
message InputFrameDownsync {
@@ -60,97 +63,108 @@ message InputFrameDownsync {
}
message HeartbeatUpsync {
int64 clientTimestamp = 1;
int64 clientTimestamp = 1;
}
message WsReq {
int32 msgId = 1;
int32 playerId = 2;
int32 act = 3;
int32 act = 3;
int32 joinIndex = 4;
int32 ackingFrameId = 5;
int32 ackingInputFrameId = 6;
repeated InputFrameUpsync inputFrameUpsyncBatch = 7;
HeartbeatUpsync hb = 8;
repeated InputFrameUpsync inputFrameUpsyncBatch = 7;
HeartbeatUpsync hb = 8;
}
message WsResp {
int32 ret = 1;
int32 echoedMsgId = 2;
int32 act = 3;
RoomDownsyncFrame rdf = 4;
int32 echoedMsgId = 2;
int32 act = 3;
RoomDownsyncFrame rdf = 4;
repeated InputFrameDownsync inputFrameDownsyncBatch = 5;
BattleColliderInfo bciFrame = 6;
BattleColliderInfo bciFrame = 6;
int32 peerJoinIndex = 7; // Only used when "InputsBufferSnapshot.peerJoinIndex" is used.
}
message InputsBufferSnapshot {
int32 refRenderFrameId = 1;
int32 refRenderFrameId = 1;
uint64 unconfirmedMask = 2;
repeated InputFrameDownsync toSendInputFrameDownsyncs = 3;
bool shouldForceResync = 4;
int32 peerJoinIndex = 5; // Only used when "WsResp.peerJoinIndex" is used.
}
message MeleeBullet {
message MeleeBullet {
// Jargon reference https://www.thegamer.com/fighting-games-frame-data-explained/
// ALL lengths are in world coordinate
// for offender
int32 originatedRenderFrameId = 1;
int32 offenderJoinIndex = 2;
int32 originatedRenderFrameId = 1;
int32 offenderJoinIndex = 2;
int32 startupFrames = 3;
int32 startupFrames = 3;
int32 cancellableStFrame = 4;
int32 cancellableEdFrame = 5;
int32 activeFrames = 6;
int32 activeFrames = 6;
int32 hitStunFrames = 7;
int32 blockStunFrames = 8;
int32 pushbackVelX = 9;
int32 pushbackVelY = 10;
int32 damage = 11;
int32 hitStunFrames = 7;
int32 blockStunFrames = 8;
int32 pushbackVelX = 9;
int32 pushbackVelY = 10;
int32 damage = 11;
int32 selfLockVelX = 12;
int32 selfLockVelY = 13;
int32 selfLockVelX = 12;
int32 selfLockVelY = 13;
int32 hitboxOffsetX = 14;
int32 hitboxOffsetY = 15;
int32 hitboxSizeX = 16;
int32 hitboxOffsetX = 14;
int32 hitboxOffsetY = 15;
int32 hitboxSizeX = 16;
int32 hitboxSizeY = 17;
bool blowUp = 18;
int32 teamId = 19;
int32 bulletLocalId = 20;
}
int32 bulletLocalId = 20;
int32 speciesId = 21;
int32 explosionFrames = 22;
message FireballBullet {
int32 originatedRenderFrameId = 1;
int32 offenderJoinIndex = 2;
int32 blState = 23;
int32 framesInBlState = 24;
}
int32 startupFrames = 3;
message FireballBullet {
int32 originatedRenderFrameId = 1;
int32 offenderJoinIndex = 2;
int32 startupFrames = 3;
int32 cancellableStFrame = 4;
int32 cancellableEdFrame = 5;
int32 activeFrames = 6;
int32 activeFrames = 6;
int32 hitStunFrames = 7;
int32 blockStunFrames = 8;
int32 pushbackVelX = 9;
int32 pushbackVelY = 10;
int32 damage = 11;
int32 hitStunFrames = 7;
int32 blockStunFrames = 8;
int32 pushbackVelX = 9;
int32 pushbackVelY = 10;
int32 damage = 11;
int32 selfLockVelX = 12;
int32 selfLockVelY = 13;
int32 selfLockVelX = 12;
int32 selfLockVelY = 13;
int32 hitboxOffsetX = 14;
int32 hitboxOffsetY = 15;
int32 hitboxSizeX = 16;
int32 hitboxOffsetX = 14;
int32 hitboxOffsetY = 15;
int32 hitboxSizeX = 16;
int32 hitboxSizeY = 17;
bool blowUp = 18;
int32 teamId = 19;
int32 bulletLocalId = 20;
int32 speciesId = 21;
int32 bulletLocalId = 20;
int32 speciesId = 21;
int32 explosionFrames = 22;
int32 blState = 23;
int32 framesInBlState = 24;
int32 virtualGridX = 999;
int32 virtualGridY = 1000;
@@ -159,20 +173,20 @@ message FireballBullet {
int32 velX = 1003;
int32 velY = 1004;
int32 speed = 1005;
}
}
message BattleColliderInfo {
string stageName = 1;
int32 intervalToPing = 2;
int32 intervalToPing = 2;
int32 willKickIfInactiveFor = 3;
int32 boundRoomId = 4;
int64 battleDurationNanos = 5;
int32 inputFrameUpsyncDelayTolerance = 6;
int32 boundRoomId = 4;
int64 battleDurationNanos = 5;
int32 inputFrameUpsyncDelayTolerance = 6;
int32 maxChasingRenderFramesPerUpdate = 7;
double rollbackEstimatedDtMillis = 8;
int64 rollbackEstimatedDtNanos = 9;
int32 renderCacheSize = 10;
double spaceOffsetX = 11;
double spaceOffsetY = 12;
@@ -186,7 +200,7 @@ message RoomDownsyncFrame {
repeated PlayerDownsync playersArr = 2;
int64 countdownNanos = 3;
repeated MeleeBullet meleeBullets = 4; // I don't know how to mimic inheritance/composition in protobuf by far, thus using an array for each type of bullet as a compromise
repeated FireballBullet fireballBullets = 5;
repeated FireballBullet fireballBullets = 5;
uint64 backendUnconfirmedMask = 1024; // Indexed by "joinIndex", same compression concern as stated in InputFrameDownsync
bool shouldForceResync = 1025;

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -24,11 +24,11 @@
"_active": true,
"_components": [
{
"__id__": 8
"__id__": 12
}
],
"_prefab": {
"__id__": 9
"__id__": 13
},
"_opacity": 255,
"_color": {
@@ -87,12 +87,15 @@
"_children": [
{
"__id__": 3
},
{
"__id__": 7
}
],
"_active": true,
"_components": [],
"_prefab": {
"__id__": 7
"__id__": 11
},
"_opacity": 255,
"_color": {
@@ -254,6 +257,9 @@
"_clips": [
{
"__uuid__": "ba12416b-eec3-4260-8402-7fc25b125624"
},
{
"__uuid__": "7941215a-2b8c-4798-954b-4f1b16d5f6f5"
}
],
"playOnLoad": false,
@@ -270,6 +276,135 @@
"fileId": "5f1s6pDt5F3rknJTu0gQW7",
"sync": false
},
{
"__type__": "cc.Node",
"_name": "MeleeExplosion",
"_objFlags": 0,
"_parent": {
"__id__": 2
},
"_children": [],
"_active": false,
"_components": [
{
"__id__": 8
},
{
"__id__": 9
}
],
"_prefab": {
"__id__": 10
},
"_opacity": 255,
"_color": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_contentSize": {
"__type__": "cc.Size",
"width": 0,
"height": 0
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_trs": {
"__type__": "TypedArray",
"ctor": "Float64Array",
"array": [
24,
8,
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.Animation",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 7
},
"_enabled": true,
"_defaultClip": null,
"_clips": [
{
"__uuid__": "954a2924-89df-4df4-93fc-36d2b22e7619"
},
{
"__uuid__": "5bd304eb-c8ba-426f-a9ab-5698ac62de85"
},
{
"__uuid__": "5054633c-a588-4506-b4ac-eef29b1d8511"
}
],
"playOnLoad": false,
"_id": ""
},
{
"__type__": "cc.Sprite",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 7
},
"_enabled": true,
"_materials": [],
"_srcBlendFactor": 770,
"_dstBlendFactor": 771,
"_spriteFrame": null,
"_type": 0,
"_sizeMode": 1,
"_fillType": 0,
"_fillCenter": {
"__type__": "cc.Vec2",
"x": 0,
"y": 0
},
"_fillStart": 0,
"_fillRange": 0,
"_isTrimmedMode": true,
"_atlas": {
"__uuid__": "1c4c1dcb-54af-485b-9119-abd6d6d84526"
},
"_id": ""
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__uuid__": "d92d4831-cd65-4eb5-90bd-b77021aec35b"
},
"fileId": "fd9jQiClRJSI00917fifB8",
"sync": false
},
{
"__type__": "cc.PrefabInfo",
"root": {

View File

@@ -21,20 +21,20 @@
"__id__": 2
},
{
"__id__": 10
"__id__": 5
}
],
"_active": true,
"_components": [
{
"__id__": 13
"__id__": 12
},
{
"__id__": 14
"__id__": 13
}
],
"_prefab": {
"__id__": 15
"__id__": 14
},
"_opacity": 255,
"_color": {
@@ -46,8 +46,72 @@
},
"_contentSize": {
"__type__": "cc.Size",
"width": 1024,
"height": 1920
"width": 960,
"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": {
"__type__": "cc.Vec2",
@@ -83,6 +147,51 @@
"groupIndex": 0,
"_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",
"_name": "modeButton",
@@ -92,20 +201,20 @@
},
"_children": [
{
"__id__": 3
"__id__": 6
}
],
"_active": true,
"_components": [
{
"__id__": 7
"__id__": 9
},
{
"__id__": 8
"__id__": 10
}
],
"_prefab": {
"__id__": 9
"__id__": 11
},
"_opacity": 255,
"_color": {
@@ -117,8 +226,8 @@
},
"_contentSize": {
"__type__": "cc.Size",
"width": 280,
"height": 130
"width": 240,
"height": 100
},
"_anchorPoint": {
"__type__": "cc.Vec2",
@@ -130,7 +239,7 @@
"ctor": "Float64Array",
"array": [
0,
-564,
-90.495,
0,
0,
0,
@@ -159,20 +268,17 @@
"_name": "Label",
"_objFlags": 0,
"_parent": {
"__id__": 2
"__id__": 5
},
"_children": [],
"_active": true,
"_components": [
{
"__id__": 4
},
{
"__id__": 5
"__id__": 7
}
],
"_prefab": {
"__id__": 6
"__id__": 8
},
"_opacity": 255,
"_color": {
@@ -226,7 +332,7 @@
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 3
"__id__": 6
},
"_enabled": true,
"_materials": [
@@ -235,8 +341,8 @@
}
],
"_useOriginalSize": false,
"_string": "gameRule.mode",
"_N$string": "gameRule.mode",
"_string": "1 v 1",
"_N$string": "1 v 1",
"_fontSize": 55,
"_lineHeight": 50,
"_enableWrapText": false,
@@ -251,17 +357,6 @@
"_N$cacheMode": 0,
"_id": ""
},
{
"__type__": "744dcs4DCdNprNhG0xwq6FK",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 3
},
"_enabled": true,
"_dataID": "gameRule.mode",
"_id": ""
},
{
"__type__": "cc.PrefabInfo",
"root": {
@@ -278,7 +373,7 @@
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 2
"__id__": 5
},
"_enabled": true,
"_materials": [
@@ -312,7 +407,7 @@
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 2
"__id__": 5
},
"_enabled": true,
"_normalMaterial": null,
@@ -375,7 +470,7 @@
"hoverSprite": null,
"_N$disabledSprite": null,
"_N$target": {
"__id__": 2
"__id__": 5
},
"_id": ""
},
@@ -390,115 +485,6 @@
"fileId": "c54lqSflFD8ogSYAhsAkKh",
"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",
"_name": "",
@@ -508,41 +494,36 @@
},
"_enabled": true,
"modeButton": {
"__id__": 8
"__id__": 10
},
"mapNode": null,
"_id": ""
},
{
"__type__": "cc.Sprite",
"__type__": "cc.Widget",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 1
},
"_enabled": true,
"_materials": [
{
"__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432"
}
],
"_srcBlendFactor": 770,
"_dstBlendFactor": 771,
"_spriteFrame": {
"__uuid__": "7838f276-ab48-445a-b858-937dd27d9520"
},
"_type": 0,
"_sizeMode": 0,
"_fillType": 0,
"_fillCenter": {
"__type__": "cc.Vec2",
"x": 0,
"y": 0
},
"_fillStart": 0,
"_fillRange": 0,
"_isTrimmedMode": true,
"_atlas": null,
"alignMode": 1,
"_target": null,
"_alignFlags": 18,
"_left": 0,
"_right": 0,
"_top": 0,
"_bottom": 0,
"_verticalCenter": 0,
"_horizontalCenter": 0,
"_isAbsLeft": true,
"_isAbsRight": true,
"_isAbsTop": true,
"_isAbsBottom": true,
"_isAbsHorizontalCenter": true,
"_isAbsVerticalCenter": true,
"_originalWidth": 0,
"_originalHeight": 0,
"_id": ""
},
{

View File

@@ -8,7 +8,8 @@
"__id__": 1
},
"optimizationPolicy": 0,
"asyncLoadAssets": false
"asyncLoadAssets": false,
"readonly": false
},
{
"__type__": "cc.Node",
@@ -20,18 +21,17 @@
"__id__": 2
},
{
"__id__": 6
"__id__": 5
}
],
"_active": true,
"_level": 1,
"_components": [
{
"__id__": 9
"__id__": 8
}
],
"_prefab": {
"__id__": 10
"__id__": 9
},
"_opacity": 255,
"_color": {
@@ -51,24 +51,12 @@
"x": 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": {
"__type__": "TypedArray",
"ctor": "Float64Array",
"array": [
512,
0,
480,
480,
0,
0,
0,
@@ -78,7 +66,19 @@
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",
@@ -89,17 +89,13 @@
},
"_children": [],
"_active": true,
"_level": 0,
"_components": [
{
"__id__": 3
},
{
"__id__": 4
}
],
"_prefab": {
"__id__": 5
"__id__": 4
},
"_opacity": 255,
"_color": {
@@ -111,32 +107,20 @@
},
"_contentSize": {
"__type__": "cc.Size",
"width": 303.5,
"height": 30
"width": 805.7,
"height": 35.28
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 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": {
"__type__": "TypedArray",
"ctor": "Float64Array",
"array": [
0,
210,
-150,
0,
0,
0,
@@ -146,7 +130,19 @@
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",
@@ -156,32 +152,26 @@
"__id__": 2
},
"_enabled": true,
"_srcBlendFactor": 1,
"_dstBlendFactor": 771,
"_materials": [
{
"__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432"
}
],
"_useOriginalSize": false,
"_string": "login.tips.loginSuccess",
"_N$string": "login.tips.loginSuccess",
"_fontSize": 30,
"_lineHeight": 30,
"_string": "Logged in successfully, loading game resources...",
"_N$string": "Logged in successfully, loading game resources...",
"_fontSize": 28,
"_lineHeight": 28,
"_enableWrapText": true,
"_N$file": null,
"_isSystemFontUsed": true,
"_spacingX": 0,
"_batchAsBitmap": false,
"_N$horizontalAlign": 1,
"_N$verticalAlign": 1,
"_N$fontFamily": "Arial",
"_N$overflow": 0,
"_id": ""
},
{
"__type__": "744dcs4DCdNprNhG0xwq6FK",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 2
},
"_enabled": true,
"_dataID": "login.tips.loginSuccess",
"_N$overflow": 3,
"_N$cacheMode": 0,
"_id": ""
},
{
@@ -204,14 +194,13 @@
},
"_children": [],
"_active": true,
"_level": 0,
"_components": [
{
"__id__": 7
"__id__": 6
}
],
"_prefab": {
"__id__": 8
"__id__": 7
},
"_opacity": 255,
"_color": {
@@ -231,24 +220,12 @@
"x": 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": {
"__type__": "TypedArray",
"ctor": "Float64Array",
"array": [
0,
333,
0,
0,
0,
0,
@@ -258,16 +235,29 @@
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__": 6
"__id__": 5
},
"_enabled": true,
"_materials": [],
"_srcBlendFactor": 770,
"_dstBlendFactor": 771,
"_spriteFrame": null,
@@ -282,7 +272,6 @@
"_fillStart": 0,
"_fillRange": 0,
"_isTrimmedMode": true,
"_state": 0,
"_atlas": null,
"_id": ""
},
@@ -307,7 +296,7 @@
"_enabled": true,
"alignMode": 0,
"_target": null,
"_alignFlags": 20,
"_alignFlags": 18,
"_left": 0,
"_right": 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"],
Dashing: [15, "Dashing"],
OnWall: [16, "OnWall"],
TurnAround1: [17, "TurnAround1"],
};
window.ATK_CHARACTER_STATE_ARR = [];
@@ -93,7 +94,7 @@ cc.Class({
} else if (0 < rdfPlayer.DirX) {
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) {
this.animNode.scaleX = (-1.0);
} else {

View File

@@ -0,0 +1,36 @@
window.BULLET_STATE = {
Startup: 0,
Active: 1,
Exploding: 2,
};
cc.Class({
extends: cc.Component,
properties: {
animNode: {
type: cc.Node,
default: null
},
},
updateAnim(newAnimName, frameIdxInAnim, dirX, spontaneousLooping, rdf, newAnimIdx) {
this.animComp = this.effAnimNode.getComponent(cc.Animation);
// Update directions
if (this.animComp && this.animComp.node) {
if (0 > dirX) {
this.animNode.scaleX = (-1.0);
} else if (0 < dirX) {
this.animNode.scaleX = (1.0);
}
}
const currentClip = this.animComp.currentClip;
if (true == spontaneousLooping && (null != currentClip && currentClip.name == newAnimName)) {
return;
}
const targetClip = this.animComp.getClips()[newAnimIdx];
let fromTime = (frameIdxInAnim / targetClip.sample); // TODO: Anyway to avoid using division here?
this.animComp.play(newAnimName, fromTime);
},
});

View File

@@ -0,0 +1,9 @@
{
"ver": "1.0.5",
"uuid": "a4b909c4-56a8-4b70-b6ea-b7f928077747",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@@ -14,10 +14,6 @@ cc.Class({
type: cc.Node,
default: null
},
myAvatarNode: {
type: cc.Node,
default: null
},
exitBtnNode: {
type: cc.Node,
default: null
@@ -25,8 +21,7 @@ cc.Class({
},
// LIFE-CYCLE CALLBACKS:
onLoad() {
},
onLoad() {},
init() {
if (null != this.firstPlayerInfoNode) {
@@ -70,29 +65,20 @@ cc.Class({
const playerInfoNode = this.playersInfoNode[playerMeta.joinIndex];
if (null == playerInfoNode) {
cc.error("There's no playerInfoNode for joinIndex == ", joinIndex, ", as `this.playerInfoNode` is currently ", this.playersInfoNode);
}
}
playerInfoNode.active = true;
if (2 == playerMeta.joinIndex) {
if (null != this.findingAnimNode) {
if (null != this.findingAnimNode) {
this.findingAnimNode.active = false;
}
}
}
//显示自己的头像名称以及他人的头像名称
for (let i in playerMetas) {
const playerMeta = playerMetas[i];
console.log("Showing playerMeta:", playerMeta);
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) {
return str == null || str == ''
}

View File

@@ -1,12 +1,7 @@
cc.Class({
extends: cc.Component,
const Bullet = require("./Bullet");
properties: {
animNode: {
type: cc.Node,
default: null
},
},
cc.Class({
extends: Bullet,
ctor() {
this.lastUsed = -1;
@@ -27,22 +22,8 @@ cc.Class({
this.speciesName = speciesName;
this.effAnimNode = this.animNode.getChildByName(this.speciesName);
this.effAnimNode.active = true;
this.updateAnim(speciesName, fireballBullet, rdf);
},
onLoad() {},
updateAnim(speciesName, fireballBullet, rdf) {
this.animComp = this.effAnimNode.getComponent(cc.Animation);
// Update directions
if (this.animComp && this.animComp.node) {
if (0 > fireballBullet.DirX) {
this.animNode.scaleX = (-1.0);
} else if (0 < fireballBullet.DirX) {
this.animNode.scaleX = (1.0);
}
}
this.animComp.play(speciesName);
},
});

View File

@@ -68,6 +68,8 @@ cc.Class({
// LIFE-CYCLE CALLBACKS:
onLoad() {
cc.view.setOrientation(cc.macro.ORIENTATION_AUTO);
cc.view.enableAutoFullScreen(true);
window.atFirstLocationHref = window.location.href.split('#')[0];
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
const RingBuffer = require('./RingBuffer');
const NetworkDoctor = require('./NetworkDoctor');
const PriorityQueue = require("./PriorityQueue");
window.ALL_MAP_STATES = {
@@ -96,16 +97,26 @@ cc.Class({
type: cc.Integer,
default: 4 // implies (renderFrameIdLagTolerance >> inputScaleFrames) count of inputFrameIds
},
jigglingEps1D: {
type: cc.Float,
default: 1e-3
sendingQLabel: {
type: cc.Label,
default: null
},
bulletTriggerEnabled: {
default: false
inputFrameDownsyncQLabel: {
type: cc.Label,
default: null
},
closeOnForcedtoResyncNotSelf: {
default: true
peerInputFrameUpsyncQLabel: {
type: cc.Label,
default: null
},
rollbackFramesLabel: {
type: cc.Label,
default: null
},
skippedRenderFrameCntLabel: {
type: cc.Label,
default: null
}
},
_inputFrameIdDebuggable(inputFrameId) {
@@ -134,7 +145,7 @@ cc.Class({
previousSelfInput = (null == previousInputFrameDownsync ? null : previousInputFrameDownsync.InputList[joinIndex - 1]);
if (null != existingInputFrame) {
// This could happen upon either [type#1] or [type#2] forceConfirmation, where "refRenderFrame" is accompanied by some "inputFrameDownsyncs". The check here also guarantees that we don't override history
console.log(`noDelayInputFrameId=${inputFrameId} already exists in recentInputCache: recentInputCache=${self._stringifyRecentInputCache(false)}`);
//console.log(`noDelayInputFrameId=${inputFrameId} already exists in recentInputCache: recentInputCache=${self._stringifyRecentInputCache(false)}`);
return [previousSelfInput, existingInputFrame.InputList[joinIndex - 1]];
}
@@ -184,6 +195,7 @@ cc.Class({
// Upon resync, "self.lastUpsyncInputFrameId" might not have been updated properly.
batchInputFrameIdSt = self.recentInputCache.StFrameId;
}
self.networkDoctor.logSending(batchInputFrameIdSt, latestLocalInputFrameId);
for (let i = batchInputFrameIdSt; i <= latestLocalInputFrameId; ++i) {
const inputFrameDownsync = self.recentInputCache.GetByFrameId(i);
if (null == inputFrameDownsync) {
@@ -308,7 +320,7 @@ cc.Class({
const newFireball = newFireballNode.getComponent("Fireball");
newFireballNode.setPosition(cc.v2(Number.MAX_VALUE, Number.MAX_VALUE));
safelyAddChild(self.node, newFireballNode);
setLocalZOrder(newFireballNode, 5);
setLocalZOrder(newFireballNode, 10);
newFireball.lastUsed = -1;
newFireball.bulletLocalId = -1;
const initLookupKey = -(k + 1); // there's definitely no suck "bulletLocalId"
@@ -342,6 +354,9 @@ cc.Class({
self.othersForcedDownsyncRenderFrameDict = new Map();
self.rdfIdToActuallyUsedInput = new Map();
self.networkDoctor = new NetworkDoctor(20);
self.skipRenderFrameFlag = false;
self.countdownNanos = null;
if (self.countdownLabel) {
self.countdownLabel.string = "";
@@ -409,11 +424,16 @@ cc.Class({
},
onLoad() {
cc.game.setFrameRate(60);
cc.view.setOrientation(cc.macro.ORIENTATION_LANDSCAPE);
cc.view.enableAutoFullScreen(true);
const self = this;
window.mapIns = self;
window.forceBigEndianFloatingNumDecoding = self.forceBigEndianFloatingNumDecoding;
self.showCriticalCoordinateLabels = false;
self.showNetworkDoctorInfo = true;
console.warn("+++++++ Map onLoad()");
@@ -473,7 +493,6 @@ cc.Class({
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".
Object.assign(self, parsedBattleColliderInfo);
self.tooFastDtIntervalMillis = 0.5 * self.rollbackEstimatedDtMillis;
const tiledMapIns = self.node.getComponent(cc.TiledMap);
@@ -607,19 +626,19 @@ cc.Class({
const jsPlayersArr = new Array(pbRdf.playersArr.length).fill(null);
for (let k = 0; k < pbRdf.playersArr.length; ++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;
}
const jsMeleeBulletsArr = new Array(pbRdf.meleeBullets.length).fill(null);
for (let k = 0; k < pbRdf.meleeBullets.length; ++k) {
const pbBullet = pbRdf.meleeBullets[k];
const jsMeleeBullet = gopkgs.NewMeleeBulletJs(pbBullet.bulletLocalId, pbBullet.originatedRenderFrameId, pbBullet.offenderJoinIndex, pbBullet.startupFrames, pbBullet.cancellableStFrame, pbBullet.cancellableEdFrame, pbBullet.activeFrames, pbBullet.hitStunFrames, pbBullet.blockStunFrames, pbBullet.pushbackVelX, pbBullet.pushbackVelY, pbBullet.damage, pbBullet.selfLockVelX, pbBullet.selfLockVelY, pbBullet.hitboxOffsetX, pbBullet.hitboxOffsetY, pbBullet.hitboxSizeX, pbBullet.hitboxSizeY, pbBullet.blowUp, pbBullet.teamId);
const jsMeleeBullet = gopkgs.NewMeleeBulletJs(pbBullet.bulletLocalId, pbBullet.originatedRenderFrameId, pbBullet.offenderJoinIndex, pbBullet.startupFrames, pbBullet.cancellableStFrame, pbBullet.cancellableEdFrame, pbBullet.activeFrames, pbBullet.hitStunFrames, pbBullet.blockStunFrames, pbBullet.pushbackVelX, pbBullet.pushbackVelY, pbBullet.damage, pbBullet.selfLockVelX, pbBullet.selfLockVelY, pbBullet.hitboxOffsetX, pbBullet.hitboxOffsetY, pbBullet.hitboxSizeX, pbBullet.hitboxSizeY, pbBullet.blowUp, pbBullet.teamId, pbBullet.blState, pbBullet.framesInBlState, pbBullet.explosionFrames, pbBullet.speciesId);
jsMeleeBulletsArr[k] = jsMeleeBullet;
}
const jsFireballBulletsArr = new Array(pbRdf.fireballBullets.length).fill(null);
for (let k = 0; k < pbRdf.fireballBullets.length; ++k) {
const pbBullet = pbRdf.fireballBullets[k];
const jsFireballBullet = gopkgs.NewFireballBulletJs(pbBullet.bulletLocalId, pbBullet.originatedRenderFrameId, pbBullet.offenderJoinIndex, pbBullet.startupFrames, pbBullet.cancellableStFrame, pbBullet.cancellableEdFrame, pbBullet.activeFrames, pbBullet.hitStunFrames, pbBullet.blockStunFrames, pbBullet.pushbackVelX, pbBullet.pushbackVelY, pbBullet.damage, pbBullet.selfLockVelX, pbBullet.selfLockVelY, pbBullet.hitboxOffsetX, pbBullet.hitboxOffsetY, pbBullet.hitboxSizeX, pbBullet.hitboxSizeY, pbBullet.blowUp, pbBullet.teamId, pbBullet.virtualGridX, pbBullet.virtualGridY, pbBullet.dirX, pbBullet.dirY, pbBullet.velX, pbBullet.velY, pbBullet.speed, pbBullet.speciesId);
const jsFireballBullet = gopkgs.NewFireballBulletJs(pbBullet.bulletLocalId, pbBullet.originatedRenderFrameId, pbBullet.offenderJoinIndex, pbBullet.startupFrames, pbBullet.cancellableStFrame, pbBullet.cancellableEdFrame, pbBullet.activeFrames, pbBullet.hitStunFrames, pbBullet.blockStunFrames, pbBullet.pushbackVelX, pbBullet.pushbackVelY, pbBullet.damage, pbBullet.selfLockVelX, pbBullet.selfLockVelY, pbBullet.hitboxOffsetX, pbBullet.hitboxOffsetY, pbBullet.hitboxSizeX, pbBullet.hitboxSizeY, pbBullet.blowUp, pbBullet.teamId, pbBullet.virtualGridX, pbBullet.virtualGridY, pbBullet.dirX, pbBullet.dirY, pbBullet.velX, pbBullet.velY, pbBullet.speed, pbBullet.blState, pbBullet.framesInBlState, pbBullet.explosionFrames, pbBullet.speciesId);
jsFireballBulletsArr[k] = jsFireballBullet;
}
@@ -688,6 +707,7 @@ cc.Class({
self.lastRenderFrameIdTriggeredAt = performance.now();
// In this case it must be true that "rdf.id > chaserRenderFrameId".
self.chaserRenderFrameId = rdf.Id;
self.networkDoctor.logRollbackFrames(0);
const canvasNode = self.canvasNode;
self.ctrl = canvasNode.getComponent("TouchEventsManager");
@@ -763,7 +783,6 @@ cc.Class({
if (lhs.VelX != rhs.VelX) return false;
if (lhs.VelY != rhs.VelY) return false;
if (lhs.Speed != rhs.Speed) return false;
if (lhs.SpeciesId != rhs.SpeciesId) return false;
return true;
},
@@ -795,6 +814,7 @@ cc.Class({
return;
}
self.networkDoctor.logInputFrameDownsync(batch[0].inputFrameId, batch[batch.length - 1].inputFrameId);
let firstPredictedYetIncorrectInputFrameId = null;
for (let k in batch) {
const inputFrameDownsync = batch[k];
@@ -838,11 +858,45 @@ cc.Class({
--------------------------------------------------------
*/
// 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}
recentInputCache=${self._stringifyRecentInputCache(false)}
batchInputFrameIdRange=[${batch[0].inputFrameId}, ${batch[batch.length - 1].inputFrameId}]`);
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 */ ) {
@@ -909,21 +963,33 @@ batchInputFrameIdRange=[${batch[0].inputFrameId}, ${batch[batch.length - 1].inpu
update(dt) {
const self = this;
if (ALL_BATTLE_STATES.IN_BATTLE == self.battleState) {
const elapsedMillisSinceLastFrameIdTriggered = performance.now() - self.lastRenderFrameIdTriggeredAt;
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!
// console.debug("Avoiding too fast frame@renderFrameId=", self.renderFrameId, ": elapsedMillisSinceLastFrameIdTriggered=", elapsedMillisSinceLastFrameIdTriggered);
/*
[WARNING] Different devices might differ in the rate of calling "update(dt)", and the game engine is responsible of keeping this rate statistically constant.
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;
}
try {
let st = performance.now();
const noDelayInputFrameId = gopkgs.ConvertToNoDelayInputFrameId(self.renderFrameId);
let prevSelfInput = null,
currSelfInput = null;
const noDelayInputFrameId = gopkgs.ConvertToNoDelayInputFrameId(self.renderFrameId);
if (gopkgs.ShouldGenerateInputFrameUpsync(self.renderFrameId)) {
[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();
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?
@@ -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.
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],
rdf = latestRdfResults[1];
/*
@@ -969,9 +1036,13 @@ othersForcedDownsyncRenderFrame=${JSON.stringify(othersForcedDownsyncRenderFrame
}
self.applyRoomDownsyncFrameDynamics(rdf, prevRdf);
self.showDebugBoundaries(rdf);
if (self.showNetworkDoctorInfo) {
self.showNetworkDoctorLabels();
}
++self.renderFrameId; // [WARNING] It's important to increment the renderFrameId AFTER all the operations above!!!
self.lastRenderFrameIdTriggeredAt = performance.now();
let t3 = performance.now();
self.skipRenderFrameFlag = self.networkDoctor.isTooFast();
} catch (err) {
console.error("Error during Map.update", err);
self.onBattleStopped(); // TODO: Popup to ask player to refresh browser
@@ -1114,25 +1185,61 @@ othersForcedDownsyncRenderFrame=${JSON.stringify(othersForcedDownsyncRenderFrame
const fireball = pqNode.value;
fireball.node.setPosition(cc.v2(Number.MAX_VALUE, Number.MAX_VALUE));
}
for (let k in rdf.MeleeBullets) {
const meleeBullet = rdf.MeleeBullets[k];
const isExploding = (window.BULLET_STATE.Exploding == meleeBullet.BlState);
if (isExploding) {
let pqNode = self.cachedFireballs.popAny(meleeBullet.BattleAttr.BulletLocalId);
let speciesName = `MeleeExplosion`;
let animName = `MeleeExplosion${meleeBullet.Bullet.SpeciesId}`;
const offender = rdf.PlayersArr[meleeBullet.BattleAttr.OffenderJoinIndex - 1];
let xfac = 1; // By now, straight Punch offset doesn't respect "y-axis"
if (0 > offender.DirX) {
xfac = -1;
}
const [wx, wy] = gopkgs.VirtualGridToWorldPos(offender.VirtualGridX + xfac * meleeBullet.Bullet.HitboxOffsetX, offender.VirtualGridY);
if (null == pqNode) {
pqNode = self.cachedFireballs.pop();
//console.log(`@rdf.Id=${rdf.Id}, origRdfId=${meleeBullet.BattleAttr.OriginatedRenderFrameId}, startupFrames=${meleeBullet.Bullet.StartupFrames}, using a new fireball node for rendering for bulletLocalId=${meleeBullet.BattleAttr.BulletLocalId} at wpos=(${wx},${wy})`);
} else {
//console.log(`@rdf.Id=${rdf.Id}, origRdfId=${meleeBullet.BattleAttr.OriginatedRenderFrameId}, startupFrames=${meleeBullet.Bullet.StartupFrames}, using a cached fireball node for rendering for bulletLocalId=${meleeBullet.BattleAttr.BulletLocalId} at wpos=(${wx},${wy})`);
}
const cachedFireball = pqNode.value;
cachedFireball.setSpecies(speciesName, meleeBullet, rdf);
const newAnimIdx = meleeBullet.Bullet.SpeciesId - 1;
cachedFireball.updateAnim(animName, meleeBullet.FramesInBlState, offender.DirX, false, rdf, newAnimIdx);
cachedFireball.lastUsed = self.renderFrameId;
cachedFireball.bulletLocalId = meleeBullet.BattleAttr.BulletLocalId;
cachedFireball.node.setPosition(cc.v2(wx, wy));
self.cachedFireballs.push(cachedFireball.lastUsed, cachedFireball, meleeBullet.BattleAttr.BulletLocalId);
} else {
//console.log(`@rdf.Id=${rdf.Id}, origRdfId=${meleeBullet.BattleAttr.OriginatedRenderFrameId}, startupFrames=${meleeBullet.Bullet.StartupFrames}, activeFrames=${meleeBullet.Bullet.ActiveFrames}, not rendering melee node for bulletLocalId=${meleeBullet.BattleAttr.BulletLocalId}`);
}
}
for (let k in rdf.FireballBullets) {
const fireballBullet = rdf.FireballBullets[k];
if (
fireballBullet.BattleAttr.OriginatedRenderFrameId + fireballBullet.Bullet.StartupFrames <= rdf.Id
&&
fireballBullet.BattleAttr.OriginatedRenderFrameId + fireballBullet.Bullet.StartupFrames + fireballBullet.Bullet.ActiveFrames > rdf.Id
) {
const isExploding = (window.BULLET_STATE.Exploding == fireballBullet.BlState);
if (gopkgs.IsFireballBulletActive(fireballBullet, rdf) || isExploding) {
let pqNode = self.cachedFireballs.popAny(fireballBullet.BattleAttr.BulletLocalId);
const speciesName = `Fireball${fireballBullet.SpeciesId}`;
let speciesName = `Fireball${fireballBullet.Bullet.SpeciesId}`;
let animName = (BULLET_STATE.Exploding == fireballBullet.BlState ? `Fireball${fireballBullet.Bullet.SpeciesId}Explosion` : speciesName);
const [wx, wy] = gopkgs.VirtualGridToWorldPos(fireballBullet.VirtualGridX, fireballBullet.VirtualGridY);
if (null == pqNode) {
pqNode = self.cachedFireballs.pop();
//console.log(`@rdf.Id=${rdf.Id}, origRdfId=${fireballBullet.BattleAttr.OriginatedRenderFrameId}, startupFrames=${fireballBullet.Bullet.StartupFrames}, using a new fireball node for rendering for bulletLocalId=${fireballBullet.BattleAttr.BulletLocalId} at wpos=(${wx},${wy})`);
//console.log(`@rdf.Id=${rdf.Id}, origRdfId=${fireballBullet.BattleAttr.OriginatedRenderFrameId}, startupFrames=${fireballBullet.Bullet.StartupFrames}, using a new fireball node for rendering for bulletLocalId=${fireballBullet.BattleAttr.BulletLocalId} at wpos=(${wx},${wy})`);
} else {
//console.log(`@rdf.Id=${rdf.Id}, origRdfId=${fireballBullet.BattleAttr.OriginatedRenderFrameId}, startupFrames=${fireballBullet.Bullet.StartupFrames}, using a cached fireball node for rendering for bulletLocalId=${fireballBullet.BattleAttr.BulletLocalId} at wpos=(${wx},${wy})`);
}
const cachedFireball = pqNode.value;
cachedFireball.setSpecies(speciesName, fireballBullet, rdf);
const spontaneousLooping = !isExploding;
const newAnimIdx = (spontaneousLooping ? 0 : 1);
cachedFireball.updateAnim(animName, fireballBullet.FramesInBlState, fireballBullet.DirX, spontaneousLooping, rdf, newAnimIdx);
cachedFireball.lastUsed = self.renderFrameId;
cachedFireball.bulletLocalId = fireballBullet.BattleAttr.BulletLocalId;
cachedFireball.node.setPosition(cc.v2(wx, wy));
@@ -1160,13 +1267,26 @@ 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`;
}
const j = gopkgs.ConvertToDelayedInputFrameId(i);
const delayedInputFrame = self.recentInputCache.GetByFrameId(j); // Don't make prediction here, the inputFrameDownsyncs in recentInputCache was already predicted while prefabbing
if (null == delayedInputFrame) {
// Shouldn't happen!
throw `Failed to get cached delayedInputFrame for i=${i}, j=${j}, renderFrameId=${self.renderFrameId}, lastUpsyncInputFrameId=${self.lastUpsyncInputFrameId}, lastAllConfirmedInputFrameId=${self.lastAllConfirmedInputFrameId}, chaserRenderFrameId=${self.chaserRenderFrameId}; recentRenderCache=${self._stringifyRecentRenderCache(false)}, recentInputCache=${self._stringifyRecentInputCache(false)}`;
}
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`);
}
}
*/
const jPrev = gopkgs.ConvertToDelayedInputFrameId(i - 1);
if (self.frameDataLoggingEnabled) {
const actuallyUsedInputClone = delayedInputFrame.InputList.slice();
const inputFrameDownsyncClone = {
@@ -1363,11 +1483,7 @@ actuallyUsedinputList:{${self.inputFrameDownsyncStr(actuallyUsedInputClone)}}`);
for (let k in rdf.MeleeBullets) {
const meleeBullet = rdf.MeleeBullets[k];
if (
meleeBullet.BattleAttr.OriginatedRenderFrameId + meleeBullet.Bullet.StartupFrames <= rdf.Id
&&
meleeBullet.BattleAttr.OriginatedRenderFrameId + meleeBullet.Bullet.StartupFrames + meleeBullet.Bullet.ActiveFrames > rdf.Id
) {
if (gopkgs.IsMeleeBulletActive(meleeBullet, rdf)) {
const offender = rdf.PlayersArr[meleeBullet.BattleAttr.OffenderJoinIndex - 1];
if (1 == offender.JoinIndex) {
g2.strokeColor = cc.Color.BLUE;
@@ -1395,11 +1511,7 @@ actuallyUsedinputList:{${self.inputFrameDownsyncStr(actuallyUsedInputClone)}}`);
for (let k in rdf.FireballBullets) {
const fireballBullet = rdf.FireballBullets[k];
if (
fireballBullet.BattleAttr.OriginatedRenderFrameId + fireballBullet.Bullet.StartupFrames <= rdf.Id
&&
fireballBullet.BattleAttr.OriginatedRenderFrameId + fireballBullet.Bullet.StartupFrames + fireballBullet.Bullet.ActiveFrames > rdf.Id
) {
if (gopkgs.IsFireballBulletActive(fireballBullet, rdf)) {
const offender = rdf.PlayersArr[fireballBullet.BattleAttr.OffenderJoinIndex - 1];
if (1 == offender.JoinIndex) {
g2.strokeColor = cc.Color.BLUE;
@@ -1422,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",
"uuid": "477c07c3-0d50-4d55-96f0-6eaf9f25e2da",
"uuid": "affd726a-02f0-4079-aace-39fe525d7478",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,

View File

@@ -11,9 +11,13 @@ cc.Class({
},
onLoad() {
cc.game.setFrameRate(60);
cc.view.setOrientation(cc.macro.ORIENTATION_LANDSCAPE);
cc.view.enableAutoFullScreen(true);
const self = this;
window.mapIns = self;
self.showCriticalCoordinateLabels = true;
self.showCriticalCoordinateLabels = false;
self.showNetworkDoctorInfo = true;
const mapNode = self.node;
const canvasNode = mapNode.parent;
@@ -94,7 +98,7 @@ cc.Class({
const p2Vpos = gopkgs.WorldToVirtualGridPos(boundaryObjs.playerStartingPositions[1].x, boundaryObjs.playerStartingPositions[1].y);
const colliderRadiusV = gopkgs.WorldToVirtualGridPos(12.0, 0);
const speciesIdList = [4096, 1];
const speciesIdList = [1, 4096];
const chConfigsOrderedByJoinIndex = gopkgs.GetCharacterConfigsOrderedByJoinIndex(speciesIdList);
const startRdf = window.pb.protos.RoomDownsyncFrame.create({
@@ -154,7 +158,7 @@ cc.Class({
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!
// console.debug("Avoiding too fast frame@renderFrameId=", self.renderFrameId, ": elapsedMillisSinceLastFrameIdTriggered=", elapsedMillisSinceLastFrameIdTriggered);
return;
//return;
}
try {
let st = performance.now();

View File

@@ -11,14 +11,6 @@ cc.Class({
type: cc.Object,
default: null
},
myAvatarNode: {
type: cc.Node,
default: null,
},
myNameNode: {
type: cc.Node,
default: null,
},
rankingNodes: {
type: [cc.Node],
default: [],
@@ -46,22 +38,6 @@ cc.Class({
showPlayerInfo(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) {
@@ -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) {
if (this.node.parent) {
this.node.parent.removeChild(this.node);

View File

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

View File

@@ -106,8 +106,13 @@ cc.Class({
this.cachedBtnDownLevel = 0;
this.cachedBtnLeftLevel = 0;
this.cachedBtnRightLevel = 0;
this.realtimeBtnALevel = 0;
this.cachedBtnALevel = 0;
this.btnAEdgeTriggerLock = false;
this.realtimeBtnBLevel = 0;
this.cachedBtnBLevel = 0;
this.btnBEdgeTriggerLock = false;
this.canvasNode = this.mapNode.parent;
this.mainCameraNode = this.canvasNode.getChildByName("Main Camera"); // Cannot drag and assign the `mainCameraNode` from CocosCreator EDITOR directly, otherwise it'll cause an infinite loading time, till v2.1.0.
@@ -163,31 +168,25 @@ cc.Class({
if (self.btnA) {
self.btnA.on(cc.Node.EventType.TOUCH_START, function(evt) {
self.cachedBtnALevel = 1;
evt.target.runAction(cc.scaleTo(0.1, 0.3));
self._triggerEdgeBtnA(true);
});
self.btnA.on(cc.Node.EventType.TOUCH_END, function(evt) {
self.cachedBtnALevel = 0;
evt.target.runAction(cc.scaleTo(0.1, 1.0));
self._triggerEdgeBtnA(false);
});
self.btnA.on(cc.Node.EventType.TOUCH_CANCEL, function(evt) {
self.cachedBtnALevel = 0;
evt.target.runAction(cc.scaleTo(0.1, 1.0));
self._triggerEdgeBtnA(false);
});
}
if (self.btnB) {
self.btnB.on(cc.Node.EventType.TOUCH_START, function(evt) {
self.cachedBtnBLevel = 1;
evt.target.runAction(cc.scaleTo(0.1, 0.3));
self._triggerEdgeBtnB(true);
});
self.btnB.on(cc.Node.EventType.TOUCH_END, function(evt) {
self.cachedBtnBLevel = 0;
evt.target.runAction(cc.scaleTo(0.1, 1.0));
self._triggerEdgeBtnB(false);
});
self.btnB.on(cc.Node.EventType.TOUCH_CANCEL, function(evt) {
self.cachedBtnBLevel = 0;
evt.target.runAction(cc.scaleTo(0.1, 1.0));
self._triggerEdgeBtnB(false);
});
}
@@ -223,10 +222,10 @@ cc.Class({
self.cachedBtnRightLevel = 1;
break;
case cc.macro.KEY.h:
self.cachedBtnALevel = 1;
self._triggerEdgeBtnA(true);
break;
case cc.macro.KEY.j:
self.cachedBtnBLevel = 1;
self._triggerEdgeBtnB(true);
break;
default:
break;
@@ -248,10 +247,10 @@ cc.Class({
self.cachedBtnRightLevel = 0;
break;
case cc.macro.KEY.h:
self.cachedBtnALevel = 0;
self._triggerEdgeBtnA(false);
break;
case cc.macro.KEY.j:
self.cachedBtnBLevel = 0;
self._triggerEdgeBtnB(false);
break;
default:
break;
@@ -464,6 +463,12 @@ cc.Class({
const discretizedDir = this.discretizeDirection(this.stickhead.x, this.stickhead.y, this.joyStickEps).encodedIdx; // There're only 9 dirs, thus using only the lower 4-bits
const btnALevel = (this.cachedBtnALevel << 4);
const btnBLevel = (this.cachedBtnBLevel << 5);
this.cachedBtnALevel = this.realtimeBtnALevel;
this.cachedBtnBLevel = this.realtimeBtnBLevel;
this.btnAEdgeTriggerLock = false;
this.btnBEdgeTriggerLock = false;
return (btnBLevel + btnALevel + discretizedDir);
},
@@ -482,4 +487,30 @@ cc.Class({
btnBLevel: btnBLevel,
});
},
_triggerEdgeBtnA(rising) {
this.realtimeBtnALevel = (rising ? 1 : 0);
if (!this.btnAEdgeTriggerLock && (1 - this.realtimeBtnALevel) == this.cachedBtnALevel) {
this.cachedBtnALevel = this.realtimeBtnALevel;
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, evt) {
this.realtimeBtnBLevel = (rising ? 1 : 0);
if (!this.btnBEdgeTriggerLock && (1 - this.realtimeBtnBLevel) == this.cachedBtnBLevel) {
this.cachedBtnBLevel = this.realtimeBtnBLevel;
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_BATTLE_STOPPED = 3;
window.DOWNSYNC_MSG_ACT_FORCED_RESYNC = 4;
window.DOWNSYNC_MSG_ACT_PEER_INPUT_BATCH = 5;
window.sendSafely = function(msgStr) {
/**
@@ -65,6 +66,7 @@ window.handleHbRequirements = function(resp) {
}
if (window.handleBattleColliderInfo) {
window.initSecondarySession(null, window.boundRoomId);
window.handleBattleColliderInfo(resp.bciFrame);
}
};
@@ -130,8 +132,6 @@ window.initPersistentSessionClient = function(onopenCb, expectedRoomId) {
}
}
const currentHistoryState = window.history && window.history.state ? window.history.state : {};
const clientSession = new WebSocket(urlToConnect);
clientSession.binaryType = 'arraybuffer'; // Make 'event.data' of 'onmessage' an "ArrayBuffer" instead of a "Blob"
@@ -240,3 +240,56 @@ window.clearLocalStorageAndBackToLoginScene = function(shouldRetainBoundRoomIdIn
cc.director.loadScene('login');
};
// For secondary ws session
window.initSecondarySession = function(onopenCb, boundRoomId) {
if (window.secondarySession && window.secondarySession.readyState == WebSocket.OPEN) {
if (null != onopenCb) {
onopenCb();
}
return;
}
const selfPlayerStr = cc.sys.localStorage.getItem("selfPlayer");
const selfPlayer = null == selfPlayerStr ? null : JSON.parse(selfPlayerStr);
const intAuthToken = null == selfPlayer ? "" : selfPlayer.intAuthToken;
let urlToConnect = backendAddress.PROTOCOL.replace('http', 'ws') + '://' + backendAddress.HOST + ":" + backendAddress.PORT + "/tsrhtSecondary?isSecondary=true&intAuthToken=" + intAuthToken + "&boundRoomId=" + boundRoomId;
const clientSession = new WebSocket(urlToConnect);
clientSession.binaryType = 'arraybuffer'; // Make 'event.data' of 'onmessage' an "ArrayBuffer" instead of a "Blob"
clientSession.onopen = function(evt) {
console.warn("The secondary WS clientSession is opened.");
window.secondarySession = clientSession;
if (null == onopenCb) return;
onopenCb();
};
clientSession.onmessage = function(evt) {
if (null == evt || null == evt.data) {
return;
}
try {
const resp = window.pb.protos.WsResp.decode(new Uint8Array(evt.data));
//console.log(`Got non-empty onmessage decoded: resp.act=${resp.act}`);
switch (resp.act) {
case window.DOWNSYNC_MSG_ACT_PEER_INPUT_BATCH:
mapIns.onPeerInputFrameUpsync(resp.peerJoinIndex, resp.inputFrameDownsyncBatch);
break;
default:
break;
}
} catch (e) {
console.error("Secondary ws session, unexpected error when parsing data of:", evt.data, e);
}
};
clientSession.onerror = function(evt) {
console.error("Secondary ws session, error caught on the WS clientSession: ", evt);
};
clientSession.onclose = function(evt) {
// [WARNING] The callback "onclose" might be called AFTER the webpage is refreshed with "1001 == evt.code".
console.warn(`Secondary ws session is closed: evt=${JSON.stringify(evt)}, evt.code=${evt.code}`);
};
};

View File

@@ -1219,6 +1219,7 @@ $root.protos = (function() {
* @property {boolean|null} [onWall] PlayerDownsync onWall
* @property {number|null} [onWallNormX] PlayerDownsync onWallNormX
* @property {number|null} [onWallNormY] PlayerDownsync onWallNormY
* @property {boolean|null} [capturedByInertia] PlayerDownsync capturedByInertia
* @property {string|null} [name] PlayerDownsync name
* @property {string|null} [displayName] PlayerDownsync displayName
* @property {string|null} [avatar] PlayerDownsync avatar
@@ -1463,6 +1464,14 @@ $root.protos = (function() {
*/
PlayerDownsync.prototype.onWallNormY = 0;
/**
* PlayerDownsync capturedByInertia.
* @member {boolean} capturedByInertia
* @memberof protos.PlayerDownsync
* @instance
*/
PlayerDownsync.prototype.capturedByInertia = false;
/**
* PlayerDownsync name.
* @member {string} name
@@ -1567,6 +1576,8 @@ $root.protos = (function() {
writer.uint32(/* id 27, wireType 0 =*/216).int32(message.onWallNormX);
if (message.onWallNormY != null && Object.hasOwnProperty.call(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"))
writer.uint32(/* id 997, wireType 2 =*/7978).string(message.name);
if (message.displayName != null && Object.hasOwnProperty.call(message, "displayName"))
@@ -1719,6 +1730,10 @@ $root.protos = (function() {
message.onWallNormY = reader.int32();
break;
}
case 29: {
message.capturedByInertia = reader.bool();
break;
}
case 997: {
message.name = reader.string();
break;
@@ -1850,6 +1865,9 @@ $root.protos = (function() {
if (message.onWallNormY != null && message.hasOwnProperty("onWallNormY"))
if (!$util.isInteger(message.onWallNormY))
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 (!$util.isString(message.name))
return "name: string expected";
@@ -1930,6 +1948,8 @@ $root.protos = (function() {
message.onWallNormX = object.onWallNormX | 0;
if (object.onWallNormY != null)
message.onWallNormY = object.onWallNormY | 0;
if (object.capturedByInertia != null)
message.capturedByInertia = Boolean(object.capturedByInertia);
if (object.name != null)
message.name = String(object.name);
if (object.displayName != null)
@@ -1981,6 +2001,7 @@ $root.protos = (function() {
object.onWall = false;
object.onWallNormX = 0;
object.onWallNormY = 0;
object.capturedByInertia = false;
object.name = "";
object.displayName = "";
object.avatar = "";
@@ -2041,6 +2062,8 @@ $root.protos = (function() {
object.onWallNormX = message.onWallNormX;
if (message.onWallNormY != null && message.hasOwnProperty("onWallNormY"))
object.onWallNormY = message.onWallNormY;
if (message.capturedByInertia != null && message.hasOwnProperty("capturedByInertia"))
object.capturedByInertia = message.capturedByInertia;
if (message.name != null && message.hasOwnProperty("name"))
object.name = message.name;
if (message.displayName != null && message.hasOwnProperty("displayName"))
@@ -2360,6 +2383,7 @@ $root.protos = (function() {
* @interface IInputFrameUpsync
* @property {number|null} [inputFrameId] InputFrameUpsync inputFrameId
* @property {number|Long|null} [encoded] InputFrameUpsync encoded
* @property {number|null} [joinIndex] InputFrameUpsync joinIndex
*/
/**
@@ -2393,6 +2417,14 @@ $root.protos = (function() {
*/
InputFrameUpsync.prototype.encoded = $util.Long ? $util.Long.fromBits(0,0,true) : 0;
/**
* InputFrameUpsync joinIndex.
* @member {number} joinIndex
* @memberof protos.InputFrameUpsync
* @instance
*/
InputFrameUpsync.prototype.joinIndex = 0;
/**
* Creates a new InputFrameUpsync instance using the specified properties.
* @function create
@@ -2421,6 +2453,8 @@ $root.protos = (function() {
writer.uint32(/* id 1, wireType 0 =*/8).int32(message.inputFrameId);
if (message.encoded != null && Object.hasOwnProperty.call(message, "encoded"))
writer.uint32(/* id 2, wireType 0 =*/16).uint64(message.encoded);
if (message.joinIndex != null && Object.hasOwnProperty.call(message, "joinIndex"))
writer.uint32(/* id 3, wireType 0 =*/24).int32(message.joinIndex);
return writer;
};
@@ -2463,6 +2497,10 @@ $root.protos = (function() {
message.encoded = reader.uint64();
break;
}
case 3: {
message.joinIndex = reader.int32();
break;
}
default:
reader.skipType(tag & 7);
break;
@@ -2504,6 +2542,9 @@ $root.protos = (function() {
if (message.encoded != null && message.hasOwnProperty("encoded"))
if (!$util.isInteger(message.encoded) && !(message.encoded && $util.isInteger(message.encoded.low) && $util.isInteger(message.encoded.high)))
return "encoded: integer|Long expected";
if (message.joinIndex != null && message.hasOwnProperty("joinIndex"))
if (!$util.isInteger(message.joinIndex))
return "joinIndex: integer expected";
return null;
};
@@ -2530,6 +2571,8 @@ $root.protos = (function() {
message.encoded = object.encoded;
else if (typeof object.encoded === "object")
message.encoded = new $util.LongBits(object.encoded.low >>> 0, object.encoded.high >>> 0).toNumber(true);
if (object.joinIndex != null)
message.joinIndex = object.joinIndex | 0;
return message;
};
@@ -2553,6 +2596,7 @@ $root.protos = (function() {
object.encoded = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long;
} else
object.encoded = options.longs === String ? "0" : 0;
object.joinIndex = 0;
}
if (message.inputFrameId != null && message.hasOwnProperty("inputFrameId"))
object.inputFrameId = message.inputFrameId;
@@ -2561,6 +2605,8 @@ $root.protos = (function() {
object.encoded = options.longs === String ? String(message.encoded) : message.encoded;
else
object.encoded = options.longs === String ? $util.Long.prototype.toString.call(message.encoded) : options.longs === Number ? new $util.LongBits(message.encoded.low >>> 0, message.encoded.high >>> 0).toNumber(true) : message.encoded;
if (message.joinIndex != null && message.hasOwnProperty("joinIndex"))
object.joinIndex = message.joinIndex;
return object;
};
@@ -3513,6 +3559,7 @@ $root.protos = (function() {
* @property {protos.RoomDownsyncFrame|null} [rdf] WsResp rdf
* @property {Array.<protos.InputFrameDownsync>|null} [inputFrameDownsyncBatch] WsResp inputFrameDownsyncBatch
* @property {protos.BattleColliderInfo|null} [bciFrame] WsResp bciFrame
* @property {number|null} [peerJoinIndex] WsResp peerJoinIndex
*/
/**
@@ -3579,6 +3626,14 @@ $root.protos = (function() {
*/
WsResp.prototype.bciFrame = null;
/**
* WsResp peerJoinIndex.
* @member {number} peerJoinIndex
* @memberof protos.WsResp
* @instance
*/
WsResp.prototype.peerJoinIndex = 0;
/**
* Creates a new WsResp instance using the specified properties.
* @function create
@@ -3616,6 +3671,8 @@ $root.protos = (function() {
$root.protos.InputFrameDownsync.encode(message.inputFrameDownsyncBatch[i], writer.uint32(/* id 5, wireType 2 =*/42).fork()).ldelim();
if (message.bciFrame != null && Object.hasOwnProperty.call(message, "bciFrame"))
$root.protos.BattleColliderInfo.encode(message.bciFrame, writer.uint32(/* id 6, wireType 2 =*/50).fork()).ldelim();
if (message.peerJoinIndex != null && Object.hasOwnProperty.call(message, "peerJoinIndex"))
writer.uint32(/* id 7, wireType 0 =*/56).int32(message.peerJoinIndex);
return writer;
};
@@ -3676,6 +3733,10 @@ $root.protos = (function() {
message.bciFrame = $root.protos.BattleColliderInfo.decode(reader, reader.uint32());
break;
}
case 7: {
message.peerJoinIndex = reader.int32();
break;
}
default:
reader.skipType(tag & 7);
break;
@@ -3739,6 +3800,9 @@ $root.protos = (function() {
if (error)
return "bciFrame." + error;
}
if (message.peerJoinIndex != null && message.hasOwnProperty("peerJoinIndex"))
if (!$util.isInteger(message.peerJoinIndex))
return "peerJoinIndex: integer expected";
return null;
};
@@ -3780,6 +3844,8 @@ $root.protos = (function() {
throw TypeError(".protos.WsResp.bciFrame: object expected");
message.bciFrame = $root.protos.BattleColliderInfo.fromObject(object.bciFrame);
}
if (object.peerJoinIndex != null)
message.peerJoinIndex = object.peerJoinIndex | 0;
return message;
};
@@ -3804,6 +3870,7 @@ $root.protos = (function() {
object.act = 0;
object.rdf = null;
object.bciFrame = null;
object.peerJoinIndex = 0;
}
if (message.ret != null && message.hasOwnProperty("ret"))
object.ret = message.ret;
@@ -3820,6 +3887,8 @@ $root.protos = (function() {
}
if (message.bciFrame != null && message.hasOwnProperty("bciFrame"))
object.bciFrame = $root.protos.BattleColliderInfo.toObject(message.bciFrame, options);
if (message.peerJoinIndex != null && message.hasOwnProperty("peerJoinIndex"))
object.peerJoinIndex = message.peerJoinIndex;
return object;
};
@@ -3862,6 +3931,7 @@ $root.protos = (function() {
* @property {number|Long|null} [unconfirmedMask] InputsBufferSnapshot unconfirmedMask
* @property {Array.<protos.InputFrameDownsync>|null} [toSendInputFrameDownsyncs] InputsBufferSnapshot toSendInputFrameDownsyncs
* @property {boolean|null} [shouldForceResync] InputsBufferSnapshot shouldForceResync
* @property {number|null} [peerJoinIndex] InputsBufferSnapshot peerJoinIndex
*/
/**
@@ -3912,6 +3982,14 @@ $root.protos = (function() {
*/
InputsBufferSnapshot.prototype.shouldForceResync = false;
/**
* InputsBufferSnapshot peerJoinIndex.
* @member {number} peerJoinIndex
* @memberof protos.InputsBufferSnapshot
* @instance
*/
InputsBufferSnapshot.prototype.peerJoinIndex = 0;
/**
* Creates a new InputsBufferSnapshot instance using the specified properties.
* @function create
@@ -3945,6 +4023,8 @@ $root.protos = (function() {
$root.protos.InputFrameDownsync.encode(message.toSendInputFrameDownsyncs[i], writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim();
if (message.shouldForceResync != null && Object.hasOwnProperty.call(message, "shouldForceResync"))
writer.uint32(/* id 4, wireType 0 =*/32).bool(message.shouldForceResync);
if (message.peerJoinIndex != null && Object.hasOwnProperty.call(message, "peerJoinIndex"))
writer.uint32(/* id 5, wireType 0 =*/40).int32(message.peerJoinIndex);
return writer;
};
@@ -3997,6 +4077,10 @@ $root.protos = (function() {
message.shouldForceResync = reader.bool();
break;
}
case 5: {
message.peerJoinIndex = reader.int32();
break;
}
default:
reader.skipType(tag & 7);
break;
@@ -4050,6 +4134,9 @@ $root.protos = (function() {
if (message.shouldForceResync != null && message.hasOwnProperty("shouldForceResync"))
if (typeof message.shouldForceResync !== "boolean")
return "shouldForceResync: boolean expected";
if (message.peerJoinIndex != null && message.hasOwnProperty("peerJoinIndex"))
if (!$util.isInteger(message.peerJoinIndex))
return "peerJoinIndex: integer expected";
return null;
};
@@ -4088,6 +4175,8 @@ $root.protos = (function() {
}
if (object.shouldForceResync != null)
message.shouldForceResync = Boolean(object.shouldForceResync);
if (object.peerJoinIndex != null)
message.peerJoinIndex = object.peerJoinIndex | 0;
return message;
};
@@ -4114,6 +4203,7 @@ $root.protos = (function() {
} else
object.unconfirmedMask = options.longs === String ? "0" : 0;
object.shouldForceResync = false;
object.peerJoinIndex = 0;
}
if (message.refRenderFrameId != null && message.hasOwnProperty("refRenderFrameId"))
object.refRenderFrameId = message.refRenderFrameId;
@@ -4129,6 +4219,8 @@ $root.protos = (function() {
}
if (message.shouldForceResync != null && message.hasOwnProperty("shouldForceResync"))
object.shouldForceResync = message.shouldForceResync;
if (message.peerJoinIndex != null && message.hasOwnProperty("peerJoinIndex"))
object.peerJoinIndex = message.peerJoinIndex;
return object;
};
@@ -4187,6 +4279,10 @@ $root.protos = (function() {
* @property {boolean|null} [blowUp] MeleeBullet blowUp
* @property {number|null} [teamId] MeleeBullet teamId
* @property {number|null} [bulletLocalId] MeleeBullet bulletLocalId
* @property {number|null} [speciesId] MeleeBullet speciesId
* @property {number|null} [explosionFrames] MeleeBullet explosionFrames
* @property {number|null} [blState] MeleeBullet blState
* @property {number|null} [framesInBlState] MeleeBullet framesInBlState
*/
/**
@@ -4364,6 +4460,38 @@ $root.protos = (function() {
*/
MeleeBullet.prototype.bulletLocalId = 0;
/**
* MeleeBullet speciesId.
* @member {number} speciesId
* @memberof protos.MeleeBullet
* @instance
*/
MeleeBullet.prototype.speciesId = 0;
/**
* MeleeBullet explosionFrames.
* @member {number} explosionFrames
* @memberof protos.MeleeBullet
* @instance
*/
MeleeBullet.prototype.explosionFrames = 0;
/**
* MeleeBullet blState.
* @member {number} blState
* @memberof protos.MeleeBullet
* @instance
*/
MeleeBullet.prototype.blState = 0;
/**
* MeleeBullet framesInBlState.
* @member {number} framesInBlState
* @memberof protos.MeleeBullet
* @instance
*/
MeleeBullet.prototype.framesInBlState = 0;
/**
* Creates a new MeleeBullet instance using the specified properties.
* @function create
@@ -4428,6 +4556,14 @@ $root.protos = (function() {
writer.uint32(/* id 19, wireType 0 =*/152).int32(message.teamId);
if (message.bulletLocalId != null && Object.hasOwnProperty.call(message, "bulletLocalId"))
writer.uint32(/* id 20, wireType 0 =*/160).int32(message.bulletLocalId);
if (message.speciesId != null && Object.hasOwnProperty.call(message, "speciesId"))
writer.uint32(/* id 21, wireType 0 =*/168).int32(message.speciesId);
if (message.explosionFrames != null && Object.hasOwnProperty.call(message, "explosionFrames"))
writer.uint32(/* id 22, wireType 0 =*/176).int32(message.explosionFrames);
if (message.blState != null && Object.hasOwnProperty.call(message, "blState"))
writer.uint32(/* id 23, wireType 0 =*/184).int32(message.blState);
if (message.framesInBlState != null && Object.hasOwnProperty.call(message, "framesInBlState"))
writer.uint32(/* id 24, wireType 0 =*/192).int32(message.framesInBlState);
return writer;
};
@@ -4542,6 +4678,22 @@ $root.protos = (function() {
message.bulletLocalId = reader.int32();
break;
}
case 21: {
message.speciesId = reader.int32();
break;
}
case 22: {
message.explosionFrames = reader.int32();
break;
}
case 23: {
message.blState = reader.int32();
break;
}
case 24: {
message.framesInBlState = reader.int32();
break;
}
default:
reader.skipType(tag & 7);
break;
@@ -4637,6 +4789,18 @@ $root.protos = (function() {
if (message.bulletLocalId != null && message.hasOwnProperty("bulletLocalId"))
if (!$util.isInteger(message.bulletLocalId))
return "bulletLocalId: integer expected";
if (message.speciesId != null && message.hasOwnProperty("speciesId"))
if (!$util.isInteger(message.speciesId))
return "speciesId: integer expected";
if (message.explosionFrames != null && message.hasOwnProperty("explosionFrames"))
if (!$util.isInteger(message.explosionFrames))
return "explosionFrames: integer expected";
if (message.blState != null && message.hasOwnProperty("blState"))
if (!$util.isInteger(message.blState))
return "blState: integer expected";
if (message.framesInBlState != null && message.hasOwnProperty("framesInBlState"))
if (!$util.isInteger(message.framesInBlState))
return "framesInBlState: integer expected";
return null;
};
@@ -4692,6 +4856,14 @@ $root.protos = (function() {
message.teamId = object.teamId | 0;
if (object.bulletLocalId != null)
message.bulletLocalId = object.bulletLocalId | 0;
if (object.speciesId != null)
message.speciesId = object.speciesId | 0;
if (object.explosionFrames != null)
message.explosionFrames = object.explosionFrames | 0;
if (object.blState != null)
message.blState = object.blState | 0;
if (object.framesInBlState != null)
message.framesInBlState = object.framesInBlState | 0;
return message;
};
@@ -4729,6 +4901,10 @@ $root.protos = (function() {
object.blowUp = false;
object.teamId = 0;
object.bulletLocalId = 0;
object.speciesId = 0;
object.explosionFrames = 0;
object.blState = 0;
object.framesInBlState = 0;
}
if (message.originatedRenderFrameId != null && message.hasOwnProperty("originatedRenderFrameId"))
object.originatedRenderFrameId = message.originatedRenderFrameId;
@@ -4770,6 +4946,14 @@ $root.protos = (function() {
object.teamId = message.teamId;
if (message.bulletLocalId != null && message.hasOwnProperty("bulletLocalId"))
object.bulletLocalId = message.bulletLocalId;
if (message.speciesId != null && message.hasOwnProperty("speciesId"))
object.speciesId = message.speciesId;
if (message.explosionFrames != null && message.hasOwnProperty("explosionFrames"))
object.explosionFrames = message.explosionFrames;
if (message.blState != null && message.hasOwnProperty("blState"))
object.blState = message.blState;
if (message.framesInBlState != null && message.hasOwnProperty("framesInBlState"))
object.framesInBlState = message.framesInBlState;
return object;
};
@@ -4829,6 +5013,9 @@ $root.protos = (function() {
* @property {number|null} [teamId] FireballBullet teamId
* @property {number|null} [bulletLocalId] FireballBullet bulletLocalId
* @property {number|null} [speciesId] FireballBullet speciesId
* @property {number|null} [explosionFrames] FireballBullet explosionFrames
* @property {number|null} [blState] FireballBullet blState
* @property {number|null} [framesInBlState] FireballBullet framesInBlState
* @property {number|null} [virtualGridX] FireballBullet virtualGridX
* @property {number|null} [virtualGridY] FireballBullet virtualGridY
* @property {number|null} [dirX] FireballBullet dirX
@@ -5021,6 +5208,30 @@ $root.protos = (function() {
*/
FireballBullet.prototype.speciesId = 0;
/**
* FireballBullet explosionFrames.
* @member {number} explosionFrames
* @memberof protos.FireballBullet
* @instance
*/
FireballBullet.prototype.explosionFrames = 0;
/**
* FireballBullet blState.
* @member {number} blState
* @memberof protos.FireballBullet
* @instance
*/
FireballBullet.prototype.blState = 0;
/**
* FireballBullet framesInBlState.
* @member {number} framesInBlState
* @memberof protos.FireballBullet
* @instance
*/
FireballBullet.prototype.framesInBlState = 0;
/**
* FireballBullet virtualGridX.
* @member {number} virtualGridX
@@ -5143,6 +5354,12 @@ $root.protos = (function() {
writer.uint32(/* id 20, wireType 0 =*/160).int32(message.bulletLocalId);
if (message.speciesId != null && Object.hasOwnProperty.call(message, "speciesId"))
writer.uint32(/* id 21, wireType 0 =*/168).int32(message.speciesId);
if (message.explosionFrames != null && Object.hasOwnProperty.call(message, "explosionFrames"))
writer.uint32(/* id 22, wireType 0 =*/176).int32(message.explosionFrames);
if (message.blState != null && Object.hasOwnProperty.call(message, "blState"))
writer.uint32(/* id 23, wireType 0 =*/184).int32(message.blState);
if (message.framesInBlState != null && Object.hasOwnProperty.call(message, "framesInBlState"))
writer.uint32(/* id 24, wireType 0 =*/192).int32(message.framesInBlState);
if (message.virtualGridX != null && Object.hasOwnProperty.call(message, "virtualGridX"))
writer.uint32(/* id 999, wireType 0 =*/7992).int32(message.virtualGridX);
if (message.virtualGridY != null && Object.hasOwnProperty.call(message, "virtualGridY"))
@@ -5275,6 +5492,18 @@ $root.protos = (function() {
message.speciesId = reader.int32();
break;
}
case 22: {
message.explosionFrames = reader.int32();
break;
}
case 23: {
message.blState = reader.int32();
break;
}
case 24: {
message.framesInBlState = reader.int32();
break;
}
case 999: {
message.virtualGridX = reader.int32();
break;
@@ -5401,6 +5630,15 @@ $root.protos = (function() {
if (message.speciesId != null && message.hasOwnProperty("speciesId"))
if (!$util.isInteger(message.speciesId))
return "speciesId: integer expected";
if (message.explosionFrames != null && message.hasOwnProperty("explosionFrames"))
if (!$util.isInteger(message.explosionFrames))
return "explosionFrames: integer expected";
if (message.blState != null && message.hasOwnProperty("blState"))
if (!$util.isInteger(message.blState))
return "blState: integer expected";
if (message.framesInBlState != null && message.hasOwnProperty("framesInBlState"))
if (!$util.isInteger(message.framesInBlState))
return "framesInBlState: integer expected";
if (message.virtualGridX != null && message.hasOwnProperty("virtualGridX"))
if (!$util.isInteger(message.virtualGridX))
return "virtualGridX: integer expected";
@@ -5479,6 +5717,12 @@ $root.protos = (function() {
message.bulletLocalId = object.bulletLocalId | 0;
if (object.speciesId != null)
message.speciesId = object.speciesId | 0;
if (object.explosionFrames != null)
message.explosionFrames = object.explosionFrames | 0;
if (object.blState != null)
message.blState = object.blState | 0;
if (object.framesInBlState != null)
message.framesInBlState = object.framesInBlState | 0;
if (object.virtualGridX != null)
message.virtualGridX = object.virtualGridX | 0;
if (object.virtualGridY != null)
@@ -5531,6 +5775,9 @@ $root.protos = (function() {
object.teamId = 0;
object.bulletLocalId = 0;
object.speciesId = 0;
object.explosionFrames = 0;
object.blState = 0;
object.framesInBlState = 0;
object.virtualGridX = 0;
object.virtualGridY = 0;
object.dirX = 0;
@@ -5581,6 +5828,12 @@ $root.protos = (function() {
object.bulletLocalId = message.bulletLocalId;
if (message.speciesId != null && message.hasOwnProperty("speciesId"))
object.speciesId = message.speciesId;
if (message.explosionFrames != null && message.hasOwnProperty("explosionFrames"))
object.explosionFrames = message.explosionFrames;
if (message.blState != null && message.hasOwnProperty("blState"))
object.blState = message.blState;
if (message.framesInBlState != null && message.hasOwnProperty("framesInBlState"))
object.framesInBlState = message.framesInBlState;
if (message.virtualGridX != null && message.hasOwnProperty("virtualGridX"))
object.virtualGridX = message.virtualGridX;
if (message.virtualGridY != null && message.hasOwnProperty("virtualGridY"))

View File

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

View File

@@ -68,7 +68,7 @@
"shelter_z_reducer",
"shelter"
],
"last-module-event-record-time": 1673325961305,
"last-module-event-record-time": 1673930863015,
"simulator-orientation": false,
"simulator-resolution": {
"height": 640,

View File

@@ -6,16 +6,22 @@ all: help
GOPROXY=https://goproxy.io
serve:
gopherjs clean
gopherjs serve $(PROJECTNAME)
build:
gopherjs build $(PROJECTNAME)
rm ../frontend/assets/plugin_scripts/jsexport.js && mv ./jsexport.js ../frontend/assets/plugin_scripts/jsexport.js
clean:
gopherjs clean
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)
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

View File

@@ -1,9 +1,9 @@
package battle
import (
//"fmt"
"math"
"resolv"
//"fmt"
)
const (
@@ -16,7 +16,7 @@ const (
PATTERN_ID_UNABLE_TO_OP = -2
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
GRAVITY_X = int32(0)
@@ -51,6 +51,12 @@ var DIRECTION_DECODER = [][]int32{
{-1, +1},
}
const (
BULLET_STARTUP = int32(0)
BULLET_ACTIVE = int32(1)
BULLET_EXPLODING = int32(2)
)
const (
ATK_CHARACTER_STATE_IDLE1 = int32(0)
ATK_CHARACTER_STATE_WALKING = int32(1)
@@ -71,6 +77,8 @@ const (
ATK_CHARACTER_STATE_DASHING = int32(15)
ATK_CHARACTER_STATE_ONWALL = int32(16)
ATK_CHARACTER_STATE_TURNAROUND = int32(17)
)
var inAirSet = map[int32]bool{
@@ -220,6 +228,34 @@ func isPolygonPairOverlapped(a, b *resolv.ConvexPolygon, result *SatResult) bool
return true
}
func IsMeleeBulletActive(meleeBullet *MeleeBullet, currRenderFrame *RoomDownsyncFrame) bool {
if BULLET_EXPLODING == meleeBullet.BlState {
return false
}
return (meleeBullet.BattleAttr.OriginatedRenderFrameId+meleeBullet.Bullet.StartupFrames <= currRenderFrame.Id) && (meleeBullet.BattleAttr.OriginatedRenderFrameId+meleeBullet.Bullet.StartupFrames+meleeBullet.Bullet.ActiveFrames > currRenderFrame.Id)
}
func IsMeleeBulletAlive(meleeBullet *MeleeBullet, currRenderFrame *RoomDownsyncFrame) bool {
if BULLET_EXPLODING == meleeBullet.BlState {
return meleeBullet.FramesInBlState < meleeBullet.Bullet.ExplosionFrames
}
return (meleeBullet.BattleAttr.OriginatedRenderFrameId+meleeBullet.Bullet.StartupFrames+meleeBullet.Bullet.ActiveFrames > currRenderFrame.Id)
}
func IsFireballBulletActive(fireballBullet *FireballBullet, currRenderFrame *RoomDownsyncFrame) bool {
if BULLET_EXPLODING == fireballBullet.BlState {
return false
}
return (fireballBullet.BattleAttr.OriginatedRenderFrameId+fireballBullet.Bullet.StartupFrames < currRenderFrame.Id) && (fireballBullet.BattleAttr.OriginatedRenderFrameId+fireballBullet.Bullet.StartupFrames+fireballBullet.Bullet.ActiveFrames > currRenderFrame.Id)
}
func IsFireballBulletAlive(fireballBullet *FireballBullet, currRenderFrame *RoomDownsyncFrame) bool {
if BULLET_EXPLODING == fireballBullet.BlState {
return fireballBullet.FramesInBlState < fireballBullet.Bullet.ExplosionFrames
}
return (fireballBullet.BattleAttr.OriginatedRenderFrameId+fireballBullet.Bullet.StartupFrames+fireballBullet.Bullet.ActiveFrames > currRenderFrame.Id)
}
func isPolygonPairSeparatedByDir(a, b *resolv.ConvexPolygon, e resolv.Vector, result *SatResult) bool {
/*
[WARNING] This function is deliberately made private, it shouldn't be used alone (i.e. not along the norms of a polygon), otherwise the pushbacks calculated would be meaningless.
@@ -412,7 +448,7 @@ func calcHardPushbacksNorms(joinIndex int32, currPlayerDownsync, thatPlayerInNex
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)
delayedInputFrameId := ConvertToDelayedInputFrameId(currRenderFrame.Id)
delayedInputFrameIdForPrevRdf := ConvertToDelayedInputFrameId(currRenderFrame.Id - 1)
@@ -442,11 +478,19 @@ func deriveOpPattern(currPlayerDownsync, thatPlayerInNextFrame *PlayerDownsync,
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 {
// Jumping and moving are only allowed here
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 _, 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
} else if ATK_CHARACTER_STATE_ONWALL == currPlayerDownsync.CharacterState {
jumpedOrNot = true
@@ -454,14 +498,19 @@ func deriveOpPattern(currPlayerDownsync, thatPlayerInNextFrame *PlayerDownsync,
}
}
patternId := PATTERN_ID_NO_OP
if decodedInput.BtnALevel > prevBtnALevel {
if 0 > effDy {
patternId = 3
} else if 0 < effDy {
patternId = 2
} else {
patternId = 1
if PATTERN_ID_NO_OP == patternId {
if 0 < decodedInput.BtnALevel {
if decodedInput.BtnALevel > prevBtnALevel {
if 0 > decodedInput.Dy {
patternId = 3
} else if 0 < decodedInput.Dy {
patternId = 2
} else {
patternId = 1
}
} else {
patternId = 4 // Holding
}
}
}
@@ -476,31 +525,32 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
// Make a copy first
for i, currPlayerDownsync := range currRenderFrame.PlayersArr {
nextRenderFramePlayers[i] = &PlayerDownsync{
Id: currPlayerDownsync.Id,
VirtualGridX: currPlayerDownsync.VirtualGridX,
VirtualGridY: currPlayerDownsync.VirtualGridY,
DirX: currPlayerDownsync.DirX,
DirY: currPlayerDownsync.DirY,
VelX: currPlayerDownsync.VelX,
VelY: currPlayerDownsync.VelY,
CharacterState: currPlayerDownsync.CharacterState,
InAir: true,
OnWall: false,
Speed: currPlayerDownsync.Speed,
BattleState: currPlayerDownsync.BattleState,
Score: currPlayerDownsync.Score,
Removed: currPlayerDownsync.Removed,
JoinIndex: currPlayerDownsync.JoinIndex,
Hp: currPlayerDownsync.Hp,
MaxHp: currPlayerDownsync.MaxHp,
FramesToRecover: currPlayerDownsync.FramesToRecover - 1,
FramesInChState: currPlayerDownsync.FramesInChState + 1,
ActiveSkillId: currPlayerDownsync.ActiveSkillId,
ActiveSkillHit: currPlayerDownsync.ActiveSkillHit,
FramesInvinsible: currPlayerDownsync.FramesInvinsible - 1,
ColliderRadius: currPlayerDownsync.ColliderRadius,
OnWallNormX: currPlayerDownsync.OnWallNormX,
OnWallNormY: currPlayerDownsync.OnWallNormY,
Id: currPlayerDownsync.Id,
VirtualGridX: currPlayerDownsync.VirtualGridX,
VirtualGridY: currPlayerDownsync.VirtualGridY,
DirX: currPlayerDownsync.DirX,
DirY: currPlayerDownsync.DirY,
VelX: currPlayerDownsync.VelX,
VelY: currPlayerDownsync.VelY,
CharacterState: currPlayerDownsync.CharacterState,
InAir: true,
OnWall: false,
Speed: currPlayerDownsync.Speed,
BattleState: currPlayerDownsync.BattleState,
Score: currPlayerDownsync.Score,
Removed: currPlayerDownsync.Removed,
JoinIndex: currPlayerDownsync.JoinIndex,
Hp: currPlayerDownsync.Hp,
MaxHp: currPlayerDownsync.MaxHp,
FramesToRecover: currPlayerDownsync.FramesToRecover - 1,
FramesInChState: currPlayerDownsync.FramesInChState + 1,
ActiveSkillId: currPlayerDownsync.ActiveSkillId,
ActiveSkillHit: currPlayerDownsync.ActiveSkillHit,
FramesInvinsible: currPlayerDownsync.FramesInvinsible - 1,
ColliderRadius: currPlayerDownsync.ColliderRadius,
OnWallNormX: currPlayerDownsync.OnWallNormX,
OnWallNormY: currPlayerDownsync.OnWallNormY,
CapturedByInertia: currPlayerDownsync.CapturedByInertia,
}
if nextRenderFramePlayers[i].FramesToRecover < 0 {
nextRenderFramePlayers[i].FramesToRecover = 0
@@ -510,7 +560,6 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
}
}
// [WARNING] For rollback compatibility, MeleeBullets are composed of only static BulletConfig data and move along with the offenders, therefore they can just be copies of the pointers in "RenderFrameBuffer", however, FireballBullets move on their own and must be copies of instances for each RenderFrame!
nextRenderFrameMeleeBullets := make([]*MeleeBullet, 0, len(currRenderFrame.MeleeBullets)) // Is there any better way to reduce malloc/free impact, e.g. smart prediction for fixed memory allocation?
nextRenderFrameFireballBullets := make([]*FireballBullet, 0, len(currRenderFrame.FireballBullets))
effPushbacks := make([]Vec2D, roomCapacity)
@@ -522,7 +571,7 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
for i, currPlayerDownsync := range currRenderFrame.PlayersArr {
chConfig := chConfigsOrderedByJoinIndex[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
joinIndex := currPlayerDownsync.JoinIndex
@@ -548,6 +597,7 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
TeamId: currPlayerDownsync.BulletTeamId,
}
bulletLocalId++
newBullet.BlState = BULLET_STARTUP
nextRenderFrameMeleeBullets = append(nextRenderFrameMeleeBullets, &newBullet)
if NO_LOCK_VEL != v.Bullet.SelfLockVelX {
hasLockVel = true
@@ -571,6 +621,8 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
newBullet.DirY = 0
newBullet.VelX = newBullet.Speed * xfac
newBullet.VelY = 0
newBullet.BlState = BULLET_STARTUP
nextRenderFrameFireballBullets = append(nextRenderFrameFireballBullets, &newBullet)
//fmt.Printf("Created new fireball @currRenderFrame.Id=%d, %p, bulletLocalId=%d, virtualGridX=%d, virtualGridY=%d, offenderVpos=(%d,%d)\n", currRenderFrame.Id, &newBullet, bulletLocalId, newBullet.VirtualGridX, newBullet.VirtualGridY, currPlayerDownsync.VirtualGridX, currPlayerDownsync.VirtualGridY)
if NO_LOCK_VEL != v.Bullet.SelfLockVelX {
@@ -591,24 +643,59 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
}
if 0 == currPlayerDownsync.FramesToRecover {
if 0 != effDx {
xfac := int32(1)
if 0 > effDx {
xfac = -xfac
}
thatPlayerInNextFrame.DirX = effDx
thatPlayerInNextFrame.DirY = effDy
thatPlayerInNextFrame.VelX = xfac * currPlayerDownsync.Speed
if intAbs(thatPlayerInNextFrame.VelX) < intAbs(currPlayerDownsync.VelX) {
// Wall jumping
thatPlayerInNextFrame.VelX = xfac * intAbs(currPlayerDownsync.VelX)
}
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_WALKING
} else {
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_IDLE1
thatPlayerInNextFrame.VelX = 0
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 {
xfac := int32(1)
if 0 > effDx {
xfac = -xfac
}
thatPlayerInNextFrame.DirX = effDx
thatPlayerInNextFrame.DirY = effDy
if isWallJumping {
//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)
thatPlayerInNextFrame.VelX = xfac * intAbs(currPlayerDownsync.VelX)
} else {
thatPlayerInNextFrame.VelX = xfac * currPlayerDownsync.Speed
}
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_WALKING
} else {
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_IDLE1
thatPlayerInNextFrame.VelX = 0
}
}
}
}
@@ -665,6 +752,8 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
if ATK_CHARACTER_STATE_ONWALL == currPlayerDownsync.CharacterState && !jumpedOrNotList[i] {
thatPlayerInNextFrame.VelX += GRAVITY_X
thatPlayerInNextFrame.VelY = chConfig.WallSlidingVelY
} else if ATK_CHARACTER_STATE_DASHING == currPlayerDownsync.CharacterState {
thatPlayerInNextFrame.VelX += GRAVITY_X
} else {
thatPlayerInNextFrame.VelX += GRAVITY_X
thatPlayerInNextFrame.VelY += GRAVITY_Y
@@ -673,46 +762,68 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
}
// 3. Add bullet colliders into collision system
bulletColliders := make([]*resolv.Object, 0, len(currRenderFrame.MeleeBullets)) // Will all be removed at the end of this function due to the need for being rollback-compatible
for _, meleeBullet := range currRenderFrame.MeleeBullets {
if (meleeBullet.BattleAttr.OriginatedRenderFrameId+meleeBullet.Bullet.StartupFrames <= currRenderFrame.Id) && (meleeBullet.BattleAttr.OriginatedRenderFrameId+meleeBullet.Bullet.StartupFrames+meleeBullet.Bullet.ActiveFrames > currRenderFrame.Id) {
offender := currRenderFrame.PlayersArr[meleeBullet.BattleAttr.OffenderJoinIndex-1]
xfac := int32(1) // By now, straight Punch offset doesn't respect "y-axis"
if 0 > offender.DirX {
xfac = -xfac
// [WARNING] For rollback compatibility, static data of "BulletConfig" & "BattleAttr(static since instantiated)" can just be copies of the pointers in "RenderFrameBuffer", however, FireballBullets movement data as well as bullet animation data must be copies of instances for each RenderFrame!
bulletColliders := make([]*resolv.Object, 0, len(currRenderFrame.MeleeBullets)) // Will all be removed at the end of this function due to the need for being rollback-compatible
for _, prevMelee := range currRenderFrame.MeleeBullets {
meleeBullet := &MeleeBullet{
Bullet: prevMelee.Bullet,
BattleAttr: prevMelee.BattleAttr,
FramesInBlState: prevMelee.FramesInBlState + 1,
BlState: prevMelee.BlState,
}
if IsMeleeBulletAlive(meleeBullet, currRenderFrame) {
if IsMeleeBulletActive(meleeBullet, currRenderFrame) {
offender := currRenderFrame.PlayersArr[meleeBullet.BattleAttr.OffenderJoinIndex-1]
xfac := int32(1) // By now, straight Punch offset doesn't respect "y-axis"
if 0 > offender.DirX {
xfac = -xfac
}
bulletWx, bulletWy := VirtualGridToWorldPos(offender.VirtualGridX+xfac*meleeBullet.Bullet.HitboxOffsetX, offender.VirtualGridY)
hitboxSizeWx, hitboxSizeWy := VirtualGridToWorldPos(meleeBullet.Bullet.HitboxSizeX, meleeBullet.Bullet.HitboxSizeY)
newBulletCollider := GenerateRectCollider(bulletWx, bulletWy, hitboxSizeWx, hitboxSizeWy, SNAP_INTO_PLATFORM_OVERLAP, SNAP_INTO_PLATFORM_OVERLAP, SNAP_INTO_PLATFORM_OVERLAP, SNAP_INTO_PLATFORM_OVERLAP, collisionSpaceOffsetX, collisionSpaceOffsetY, meleeBullet, "MeleeBullet")
collisionSys.Add(newBulletCollider)
bulletColliders = append(bulletColliders, newBulletCollider)
meleeBullet.BlState = BULLET_ACTIVE
if meleeBullet.BlState != prevMelee.BlState {
meleeBullet.FramesInBlState = 0
}
}
bulletWx, bulletWy := VirtualGridToWorldPos(offender.VirtualGridX+xfac*meleeBullet.Bullet.HitboxOffsetX, offender.VirtualGridY)
hitboxSizeWx, hitboxSizeWy := VirtualGridToWorldPos(meleeBullet.Bullet.HitboxSizeX, meleeBullet.Bullet.HitboxSizeY)
newBulletCollider := GenerateRectCollider(bulletWx, bulletWy, hitboxSizeWx, hitboxSizeWy, SNAP_INTO_PLATFORM_OVERLAP, SNAP_INTO_PLATFORM_OVERLAP, SNAP_INTO_PLATFORM_OVERLAP, SNAP_INTO_PLATFORM_OVERLAP, collisionSpaceOffsetX, collisionSpaceOffsetY, meleeBullet, "MeleeBullet")
collisionSys.Add(newBulletCollider)
bulletColliders = append(bulletColliders, newBulletCollider)
} else if meleeBullet.BattleAttr.OriginatedRenderFrameId+meleeBullet.Bullet.StartupFrames+meleeBullet.Bullet.ActiveFrames > currRenderFrame.Id {
nextRenderFrameMeleeBullets = append(nextRenderFrameMeleeBullets, meleeBullet)
}
}
for _, prevFireball := range currRenderFrame.FireballBullets {
fireballBullet := &FireballBullet{
VirtualGridX: prevFireball.VirtualGridX,
VirtualGridY: prevFireball.VirtualGridY,
DirX: prevFireball.DirX,
DirY: prevFireball.DirY,
VelX: prevFireball.VelX,
VelY: prevFireball.VelY,
Speed: prevFireball.Speed,
SpeciesId: prevFireball.SpeciesId,
Bullet: prevFireball.Bullet,
BattleAttr: prevFireball.BattleAttr,
VirtualGridX: prevFireball.VirtualGridX,
VirtualGridY: prevFireball.VirtualGridY,
DirX: prevFireball.DirX,
DirY: prevFireball.DirY,
VelX: prevFireball.VelX,
VelY: prevFireball.VelY,
Speed: prevFireball.Speed,
Bullet: prevFireball.Bullet,
BattleAttr: prevFireball.BattleAttr,
FramesInBlState: prevFireball.FramesInBlState + 1,
BlState: prevFireball.BlState,
}
if (fireballBullet.BattleAttr.OriginatedRenderFrameId+fireballBullet.Bullet.StartupFrames < currRenderFrame.Id) && (fireballBullet.BattleAttr.OriginatedRenderFrameId+fireballBullet.Bullet.StartupFrames+fireballBullet.Bullet.ActiveFrames > currRenderFrame.Id) {
bulletWx, bulletWy := VirtualGridToWorldPos(fireballBullet.VirtualGridX, fireballBullet.VirtualGridY)
hitboxSizeWx, hitboxSizeWy := VirtualGridToWorldPos(fireballBullet.Bullet.HitboxSizeX, fireballBullet.Bullet.HitboxSizeY)
newBulletCollider := GenerateRectCollider(bulletWx, bulletWy, hitboxSizeWx, hitboxSizeWy, SNAP_INTO_PLATFORM_OVERLAP, SNAP_INTO_PLATFORM_OVERLAP, SNAP_INTO_PLATFORM_OVERLAP, SNAP_INTO_PLATFORM_OVERLAP, collisionSpaceOffsetX, collisionSpaceOffsetY, fireballBullet, "FireballBullet")
collisionSys.Add(newBulletCollider)
bulletColliders = append(bulletColliders, newBulletCollider)
} else if fireballBullet.BattleAttr.OriginatedRenderFrameId+fireballBullet.Bullet.StartupFrames+fireballBullet.Bullet.ActiveFrames > currRenderFrame.Id {
// fmt.Printf("Pushing static fireball to next frame @currRenderFrame.Id=%d, bulletLocalId=%d, virtualGridX=%d, virtualGridY=%d\n", currRenderFrame.Id, fireballBullet.BattleAttr.BulletLocalId, fireballBullet.VirtualGridX, fireballBullet.VirtualGridY)
if IsFireballBulletAlive(fireballBullet, currRenderFrame) {
if IsFireballBulletActive(fireballBullet, currRenderFrame) {
bulletWx, bulletWy := VirtualGridToWorldPos(fireballBullet.VirtualGridX, fireballBullet.VirtualGridY)
hitboxSizeWx, hitboxSizeWy := VirtualGridToWorldPos(fireballBullet.Bullet.HitboxSizeX, fireballBullet.Bullet.HitboxSizeY)
newBulletCollider := GenerateRectCollider(bulletWx, bulletWy, hitboxSizeWx, hitboxSizeWy, SNAP_INTO_PLATFORM_OVERLAP, SNAP_INTO_PLATFORM_OVERLAP, SNAP_INTO_PLATFORM_OVERLAP, SNAP_INTO_PLATFORM_OVERLAP, collisionSpaceOffsetX, collisionSpaceOffsetY, fireballBullet, "FireballBullet")
collisionSys.Add(newBulletCollider)
bulletColliders = append(bulletColliders, newBulletCollider)
fireballBullet.BlState = BULLET_ACTIVE
if fireballBullet.BlState != prevFireball.BlState {
fireballBullet.FramesInBlState = 0
}
fireballBullet.VirtualGridX, fireballBullet.VirtualGridY = fireballBullet.VirtualGridX+fireballBullet.VelX, fireballBullet.VirtualGridY+fireballBullet.VelY
//fmt.Printf("Pushing active fireball to next frame @currRenderFrame.Id=%d, bulletLocalId=%d, virtualGridX=%d, virtualGridY=%d, blState=%d\n", currRenderFrame.Id, fireballBullet.BattleAttr.BulletLocalId, fireballBullet.VirtualGridX, fireballBullet.VirtualGridY, fireballBullet.BlState)
} else {
//fmt.Printf("Pushing non-active fireball to next frame @currRenderFrame.Id=%d, bulletLocalId=%d, virtualGridX=%d, virtualGridY=%d, blState=%d\n", currRenderFrame.Id, fireballBullet.BattleAttr.BulletLocalId, fireballBullet.VirtualGridX, fireballBullet.VirtualGridY, fireballBullet.BlState)
}
nextRenderFrameFireballBullets = append(nextRenderFrameFireballBullets, fireballBullet)
}
}
@@ -845,7 +956,7 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
for _, bulletCollider := range bulletColliders {
collision := bulletCollider.Check(0, 0)
bulletCollider.Space.Remove(bulletCollider) // Make sure that the bulletCollider is always removed for each renderFrame
addToNextRenderFrame := true
exploded := false
if nil != collision {
switch v := bulletCollider.Data.(type) {
case *MeleeBullet:
@@ -862,7 +973,7 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
if !overlapped {
continue
}
addToNextRenderFrame = false
exploded = true
if _, existent := invinsibleSet[t.CharacterState]; existent {
continue
}
@@ -886,8 +997,6 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
if v.Bullet.HitStunFrames > oldFramesToRecover {
atkedPlayerInNextFrame.FramesToRecover = v.Bullet.HitStunFrames
}
default:
addToNextRenderFrame = false
}
}
case *FireballBullet:
@@ -904,7 +1013,7 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
if !overlapped {
continue
}
addToNextRenderFrame = false
exploded = true
if _, existent := invinsibleSet[t.CharacterState]; existent {
continue
}
@@ -929,18 +1038,21 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
atkedPlayerInNextFrame.FramesToRecover = v.Bullet.HitStunFrames
}
default:
addToNextRenderFrame = false
exploded = true
}
}
}
}
if addToNextRenderFrame {
if exploded {
switch v := bulletCollider.Data.(type) {
case *MeleeBullet:
nextRenderFrameMeleeBullets = append(nextRenderFrameMeleeBullets, v)
v.BlState = BULLET_EXPLODING
v.FramesInBlState = 0
//fmt.Printf("melee exploded @currRenderFrame.Id=%d, bulletLocalId=%d, blState=%d\n", currRenderFrame.Id, v.BattleAttr.BulletLocalId, v.BlState)
case *FireballBullet:
v.VirtualGridX, v.VirtualGridY = v.VirtualGridX+v.VelX, v.VirtualGridY+v.VelY
nextRenderFrameFireballBullets = append(nextRenderFrameFireballBullets, v)
v.BlState = BULLET_EXPLODING
v.FramesInBlState = 0
//fmt.Printf("fireball exploded @currRenderFrame.Id=%d, bulletLocalId=%d, virtualGridX=%d, virtualGridY=%d, blState=%d\n", currRenderFrame.Id, v.BattleAttr.BulletLocalId, v.VirtualGridX, v.VirtualGridY, v.BlState)
}
}
}
@@ -957,7 +1069,7 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
if thatPlayerInNextFrame.InAir {
oldNextCharacterState := thatPlayerInNextFrame.CharacterState
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 {
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_ONWALL
} else if jumpedOrNotList[i] || ATK_CHARACTER_STATE_INAIR_IDLE1_BY_JUMP == currPlayerDownsync.CharacterState {
@@ -1076,8 +1188,10 @@ func AlignPolygon2DToBoundingBox(input *Polygon2D) *Polygon2D {
return output
}
func NewMeleeBullet(bulletLocalId, originatedRenderFrameId, offenderJoinIndex, startupFrames, cancellableStFrame, cancellableEdFrame, activeFrames, hitStunFrames, blockStunFrames, pushbackVelX, pushbackVelY, damage, selfLockVelX, selfLockVelY, hitboxOffsetX, hitboxOffsetY, hitboxSizeX, hitboxSizeY int32, blowUp bool, teamId int32) *MeleeBullet {
func NewMeleeBullet(bulletLocalId, originatedRenderFrameId, offenderJoinIndex, startupFrames, cancellableStFrame, cancellableEdFrame, activeFrames, hitStunFrames, blockStunFrames, pushbackVelX, pushbackVelY, damage, selfLockVelX, selfLockVelY, hitboxOffsetX, hitboxOffsetY, hitboxSizeX, hitboxSizeY int32, blowUp bool, teamId, blState, framesInBlState, explosionFrames, speciesId int32) *MeleeBullet {
return &MeleeBullet{
BlState: blState,
FramesInBlState: framesInBlState,
BattleAttr: &BulletBattleAttr{
BulletLocalId: bulletLocalId,
OriginatedRenderFrameId: originatedRenderFrameId,
@@ -1104,12 +1218,14 @@ func NewMeleeBullet(bulletLocalId, originatedRenderFrameId, offenderJoinIndex, s
HitboxSizeX: hitboxSizeX,
HitboxSizeY: hitboxSizeY,
BlowUp: blowUp,
BlowUp: blowUp,
ExplosionFrames: explosionFrames,
SpeciesId: speciesId,
},
}
}
func NewFireballBullet(bulletLocalId, originatedRenderFrameId, offenderJoinIndex, startupFrames, cancellableStFrame, cancellableEdFrame, activeFrames, hitStunFrames, blockStunFrames, pushbackVelX, pushbackVelY, damage, selfLockVelX, selfLockVelY, hitboxOffsetX, hitboxOffsetY, hitboxSizeX, hitboxSizeY int32, blowUp bool, teamId int32, virtualGridX, virtualGridY, dirX, dirY, velX, velY, speed, speciesId int32) *FireballBullet {
func NewFireballBullet(bulletLocalId, originatedRenderFrameId, offenderJoinIndex, startupFrames, cancellableStFrame, cancellableEdFrame, activeFrames, hitStunFrames, blockStunFrames, pushbackVelX, pushbackVelY, damage, selfLockVelX, selfLockVelY, hitboxOffsetX, hitboxOffsetY, hitboxSizeX, hitboxSizeY int32, blowUp bool, teamId int32, virtualGridX, virtualGridY, dirX, dirY, velX, velY, speed, blState, framesInBlState, explosionFrames, speciesId int32) *FireballBullet {
return &FireballBullet{
VirtualGridX: virtualGridX,
VirtualGridY: virtualGridY,
@@ -1118,7 +1234,6 @@ func NewFireballBullet(bulletLocalId, originatedRenderFrameId, offenderJoinIndex
VelX: velX,
VelY: velY,
Speed: speed,
SpeciesId: speciesId,
BattleAttr: &BulletBattleAttr{
BulletLocalId: bulletLocalId,
OriginatedRenderFrameId: originatedRenderFrameId,
@@ -1145,7 +1260,9 @@ func NewFireballBullet(bulletLocalId, originatedRenderFrameId, offenderJoinIndex
HitboxSizeX: hitboxSizeX,
HitboxSizeY: hitboxSizeY,
BlowUp: blowUp,
BlowUp: blowUp,
ExplosionFrames: explosionFrames,
SpeciesId: speciesId,
},
}
}

View File

@@ -15,8 +15,9 @@ type CharacterConfig struct {
GetUpInvinsibleFrames int32
GetUpFramesToRecover int32
Speed int32
JumpingInitVelY int32
Speed int32
JumpingInitVelY int32
JumpingFramesToRecover int32 // Not used yet
DashingEnabled bool
OnWallEnabled bool
@@ -25,6 +26,8 @@ type CharacterConfig struct {
WallJumpingInitVelY int32
WallSlidingVelY int32
InertiaFramesToRecover int32
SkillMapper SkillMapperType
}
@@ -42,8 +45,11 @@ var Characters = map[int]*CharacterConfig{
GetUpInvinsibleFrames: int32(10),
GetUpFramesToRecover: int32(27),
Speed: int32(float64(3.0) * WORLD_TO_VIRTUAL_GRID_RATIO),
JumpingInitVelY: int32(float64(8) * WORLD_TO_VIRTUAL_GRID_RATIO),
Speed: int32(float64(2.1) * WORLD_TO_VIRTUAL_GRID_RATIO),
JumpingInitVelY: int32(float64(8) * WORLD_TO_VIRTUAL_GRID_RATIO),
JumpingFramesToRecover: int32(2),
InertiaFramesToRecover: int32(9),
DashingEnabled: false,
OnWallEnabled: false,
@@ -88,13 +94,16 @@ var Characters = map[int]*CharacterConfig{
GetUpInvinsibleFrames: int32(10),
GetUpFramesToRecover: int32(27),
Speed: int32(float64(4.0) * WORLD_TO_VIRTUAL_GRID_RATIO),
JumpingInitVelY: int32(float64(7.5) * 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),
JumpingFramesToRecover: int32(2),
InertiaFramesToRecover: int32(9),
DashingEnabled: true,
OnWallEnabled: true,
WallJumpingFramesToRecover: int32(9), // 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
WallJumpingFramesToRecover: int32(8), // 8 would be the minimum for an avg human
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),
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
@@ -138,8 +150,11 @@ var Characters = map[int]*CharacterConfig{
GetUpInvinsibleFrames: int32(8),
GetUpFramesToRecover: int32(30),
Speed: int32(float64(3.0) * WORLD_TO_VIRTUAL_GRID_RATIO),
JumpingInitVelY: int32(float64(7.5) * WORLD_TO_VIRTUAL_GRID_RATIO),
Speed: int32(float64(1.8) * WORLD_TO_VIRTUAL_GRID_RATIO),
JumpingInitVelY: int32(float64(7.8) * WORLD_TO_VIRTUAL_GRID_RATIO),
JumpingFramesToRecover: int32(2),
InertiaFramesToRecover: int32(9),
DashingEnabled: false,
OnWallEnabled: false,
@@ -166,11 +181,11 @@ var Characters = map[int]*CharacterConfig{
}
}
} else if 2 == patternId {
if !currPlayerDownsync.InAir {
if 0 == currPlayerDownsync.FramesToRecover && !currPlayerDownsync.InAir {
return 11
}
} else if 3 == patternId {
if !currPlayerDownsync.InAir {
if 0 == currPlayerDownsync.FramesToRecover && !currPlayerDownsync.InAir {
return 10
}
}
@@ -210,7 +225,9 @@ var skills = map[int]*Skill{
CancelTransit: map[int]int{
1: 2,
},
// TODO: Use non-zero "selfLockVel"
BlowUp: false,
ExplosionFrames: 9,
SpeciesId: int32(1),
},
},
},
@@ -242,6 +259,9 @@ var skills = map[int]*Skill{
CancelTransit: map[int]int{
1: 3,
},
BlowUp: false,
ExplosionFrames: 9,
SpeciesId: int32(1),
},
},
},
@@ -269,6 +289,8 @@ var skills = map[int]*Skill{
HitboxSizeX: int32(float64(32) * WORLD_TO_VIRTUAL_GRID_RATIO),
HitboxSizeY: int32(float64(32) * WORLD_TO_VIRTUAL_GRID_RATIO),
BlowUp: true,
ExplosionFrames: 9,
SpeciesId: int32(1),
},
},
},
@@ -301,7 +323,9 @@ var skills = map[int]*Skill{
CancelTransit: map[int]int{
1: 5,
},
// TODO: Use non-zero "selfLockVel"
BlowUp: false,
ExplosionFrames: 15,
SpeciesId: int32(2),
},
},
},
@@ -328,11 +352,14 @@ var skills = map[int]*Skill{
HitboxOffsetY: int32(0),
HitboxSizeX: int32(float64(24) * WORLD_TO_VIRTUAL_GRID_RATIO),
HitboxSizeY: int32(float64(32) * WORLD_TO_VIRTUAL_GRID_RATIO),
CancellableStFrame: int32(22),
CancellableStFrame: int32(23),
CancellableEdFrame: int32(36),
CancelTransit: map[int]int{
1: 6,
},
BlowUp: false,
ExplosionFrames: 15,
SpeciesId: int32(2),
},
},
},
@@ -360,6 +387,8 @@ var skills = map[int]*Skill{
HitboxSizeX: int32(float64(32) * WORLD_TO_VIRTUAL_GRID_RATIO),
HitboxSizeY: int32(float64(32) * WORLD_TO_VIRTUAL_GRID_RATIO),
BlowUp: true,
ExplosionFrames: 15,
SpeciesId: int32(2),
},
},
},
@@ -392,7 +421,9 @@ var skills = map[int]*Skill{
CancelTransit: map[int]int{
1: 8,
},
// TODO: Use non-zero "selfLockVel"
BlowUp: false,
ExplosionFrames: 9,
SpeciesId: int32(1),
},
},
},
@@ -424,6 +455,9 @@ var skills = map[int]*Skill{
CancelTransit: map[int]int{
1: 9,
},
BlowUp: false,
ExplosionFrames: 9,
SpeciesId: int32(1),
},
},
},
@@ -451,6 +485,8 @@ var skills = map[int]*Skill{
HitboxSizeX: int32(float64(32) * WORLD_TO_VIRTUAL_GRID_RATIO),
HitboxSizeY: int32(float64(32) * WORLD_TO_VIRTUAL_GRID_RATIO),
BlowUp: true,
ExplosionFrames: 9,
SpeciesId: int32(1),
},
},
},
@@ -463,10 +499,9 @@ var skills = map[int]*Skill{
BoundChState: ATK_CHARACTER_STATE_ATK4,
Hits: []interface{}{
&FireballBullet{
SpeciesId: int32(1),
Speed: int32(float64(5) * WORLD_TO_VIRTUAL_GRID_RATIO),
Speed: int32(float64(5) * WORLD_TO_VIRTUAL_GRID_RATIO),
Bullet: &BulletConfig{
StartupFrames: int32(15),
StartupFrames: int32(12),
ActiveFrames: MAX_INT32,
HitStunFrames: int32(15),
BlockStunFrames: int32(9),
@@ -475,10 +510,13 @@ var skills = map[int]*Skill{
SelfLockVelY: NO_LOCK_VEL,
PushbackVelX: int32(float64(2) * WORLD_TO_VIRTUAL_GRID_RATIO),
PushbackVelY: int32(0),
HitboxOffsetX: int32(float64(18) * WORLD_TO_VIRTUAL_GRID_RATIO),
HitboxOffsetY: int32(float64(5) * WORLD_TO_VIRTUAL_GRID_RATIO),
HitboxOffsetX: int32(float64(24) * WORLD_TO_VIRTUAL_GRID_RATIO),
HitboxOffsetY: int32(float64(8) * WORLD_TO_VIRTUAL_GRID_RATIO),
HitboxSizeX: int32(float64(48) * WORLD_TO_VIRTUAL_GRID_RATIO),
HitboxSizeY: int32(float64(32) * WORLD_TO_VIRTUAL_GRID_RATIO),
BlowUp: false,
ExplosionFrames: 15,
SpeciesId: int32(1),
},
},
},
@@ -506,6 +544,35 @@ var skills = map[int]*Skill{
HitboxSizeX: int32(float64(40) * WORLD_TO_VIRTUAL_GRID_RATIO),
HitboxSizeY: int32(float64(64) * WORLD_TO_VIRTUAL_GRID_RATIO),
BlowUp: true,
ExplosionFrames: 15,
SpeciesId: int32(3),
},
},
},
},
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,
},
},
},
@@ -532,6 +599,9 @@ var skills = map[int]*Skill{
HitboxOffsetY: int32(0),
HitboxSizeX: int32(float64(32) * WORLD_TO_VIRTUAL_GRID_RATIO),
HitboxSizeY: int32(float64(24) * WORLD_TO_VIRTUAL_GRID_RATIO),
BlowUp: false,
ExplosionFrames: 9,
SpeciesId: int32(1),
},
},
},
@@ -558,6 +628,9 @@ var skills = map[int]*Skill{
HitboxOffsetY: int32(0),
HitboxSizeX: int32(float64(32) * WORLD_TO_VIRTUAL_GRID_RATIO),
HitboxSizeY: int32(float64(24) * WORLD_TO_VIRTUAL_GRID_RATIO),
BlowUp: false,
ExplosionFrames: 15,
SpeciesId: int32(2),
},
},
},
@@ -584,6 +657,9 @@ var skills = map[int]*Skill{
HitboxOffsetY: int32(0),
HitboxSizeX: int32(float64(32) * WORLD_TO_VIRTUAL_GRID_RATIO),
HitboxSizeY: int32(float64(24) * WORLD_TO_VIRTUAL_GRID_RATIO),
BlowUp: false,
ExplosionFrames: 9,
SpeciesId: int32(1),
},
},
},

View File

@@ -37,6 +37,8 @@ type PlayerDownsync struct {
OnWallNormX int32
OnWallNormY int32
CapturedByInertia bool
ActiveSkillId int32
ActiveSkillHit int32
@@ -83,7 +85,9 @@ type BulletConfig struct {
HitboxSizeX int32
HitboxSizeY int32
BlowUp bool
BlowUp bool
ExplosionFrames int32
SpeciesId int32 // For fireball, this SpeciesId specifies both the active animation and the explosion animation, for melee it specifies the explosion animation
CancelTransit map[int]int
}
@@ -98,21 +102,24 @@ type BulletBattleAttr struct {
}
type MeleeBullet struct {
BattleAttr *BulletBattleAttr
Bullet *BulletConfig
BlState int32 // bullet state, e.g. STARTUP, ACTIVE, EXPLODING
FramesInBlState int32
BattleAttr *BulletBattleAttr
Bullet *BulletConfig
}
type FireballBullet struct {
VirtualGridX int32
VirtualGridY int32
DirX int32
DirY int32
VelX int32
VelY int32
Speed int32
SpeciesId int32
BattleAttr *BulletBattleAttr
Bullet *BulletConfig
VirtualGridX int32
VirtualGridY int32
DirX int32
DirY int32
VelX int32
VelY int32
Speed int32
BlState int32 // bullet state, e.g. STARTUP, ACTIVE, EXPLODING
FramesInBlState int32
BattleAttr *BulletBattleAttr
Bullet *BulletConfig
}
type Skill struct {
@@ -123,6 +130,7 @@ type Skill struct {
ReleaseTriggerType int32 // 1: rising-edge, 2: falling-edge
BoundChState int32
Hits []interface{} // Hits within a "Skill" are automatically triggered
// [WARN] Multihit of a fireball is more difficult to handle than that of melee, because we have to count from the fireball's first hit; the situation becomes even more complicated when a multihit fireball is in a crowd -- remains to be designed
}
type RoomDownsyncFrame struct {

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{
Id: id,
VirtualGridX: virtualGridX,
@@ -67,17 +67,18 @@ func NewPlayerDownsyncJs(id, virtualGridX, virtualGridY, dirX, dirY, velX, velY,
OnWall: onWall,
OnWallNormX: onWallNormX,
OnWallNormY: onWallNormY,
CapturedByInertia: capturedByInertia,
BulletTeamId: bulletTeamId,
ChCollisionTeamId: chCollisionTeamId,
})
}
func NewMeleeBulletJs(bulletLocalId, originatedRenderFrameId, offenderJoinIndex, startupFrames, cancellableStFrame, cancellableEdFrame, activeFrames, hitStunFrames, blockStunFrames, pushbackVelX, pushbackVelY, damage, selfLockVelX, selfLockVelY, hitboxOffsetX, hitboxOffsetY, hitboxSizeX, hitboxSizeY int32, blowUp bool, teamId int32) *js.Object {
return js.MakeWrapper(NewMeleeBullet(bulletLocalId, originatedRenderFrameId, offenderJoinIndex, startupFrames, cancellableStFrame, cancellableEdFrame, activeFrames, hitStunFrames, blockStunFrames, pushbackVelX, pushbackVelY, damage, selfLockVelX, selfLockVelY, hitboxOffsetX, hitboxOffsetY, hitboxSizeX, hitboxSizeY, blowUp, teamId))
func NewMeleeBulletJs(bulletLocalId, originatedRenderFrameId, offenderJoinIndex, startupFrames, cancellableStFrame, cancellableEdFrame, activeFrames, hitStunFrames, blockStunFrames, pushbackVelX, pushbackVelY, damage, selfLockVelX, selfLockVelY, hitboxOffsetX, hitboxOffsetY, hitboxSizeX, hitboxSizeY int32, blowUp bool, teamId, blState, framesInBlState, explosionFrames, speciesId int32) *js.Object {
return js.MakeWrapper(NewMeleeBullet(bulletLocalId, originatedRenderFrameId, offenderJoinIndex, startupFrames, cancellableStFrame, cancellableEdFrame, activeFrames, hitStunFrames, blockStunFrames, pushbackVelX, pushbackVelY, damage, selfLockVelX, selfLockVelY, hitboxOffsetX, hitboxOffsetY, hitboxSizeX, hitboxSizeY, blowUp, teamId, blState, framesInBlState, explosionFrames, speciesId))
}
func NewFireballBulletJs(bulletLocalId, originatedRenderFrameId, offenderJoinIndex, startupFrames, cancellableStFrame, cancellableEdFrame, activeFrames, hitStunFrames, blockStunFrames, pushbackVelX, pushbackVelY, damage, selfLockVelX, selfLockVelY, hitboxOffsetX, hitboxOffsetY, hitboxSizeX, hitboxSizeY int32, blowUp bool, teamId int32, virtualGridX, virtualGridY, dirX, dirY, velX, velY, speed, speciesId int32) *js.Object {
return js.MakeWrapper(NewFireballBullet(bulletLocalId, originatedRenderFrameId, offenderJoinIndex, startupFrames, cancellableStFrame, cancellableEdFrame, activeFrames, hitStunFrames, blockStunFrames, pushbackVelX, pushbackVelY, damage, selfLockVelX, selfLockVelY, hitboxOffsetX, hitboxOffsetY, hitboxSizeX, hitboxSizeY, blowUp, teamId, virtualGridX, virtualGridY, dirX, dirY, velX, velY, speed, speciesId))
func NewFireballBulletJs(bulletLocalId, originatedRenderFrameId, offenderJoinIndex, startupFrames, cancellableStFrame, cancellableEdFrame, activeFrames, hitStunFrames, blockStunFrames, pushbackVelX, pushbackVelY, damage, selfLockVelX, selfLockVelY, hitboxOffsetX, hitboxOffsetY, hitboxSizeX, hitboxSizeY int32, blowUp bool, teamId int32, virtualGridX, virtualGridY, dirX, dirY, velX, velY, speed, blState, framesInBlState, explosionFrames, speciesId int32) *js.Object {
return js.MakeWrapper(NewFireballBullet(bulletLocalId, originatedRenderFrameId, offenderJoinIndex, startupFrames, cancellableStFrame, cancellableEdFrame, activeFrames, hitStunFrames, blockStunFrames, pushbackVelX, pushbackVelY, damage, selfLockVelX, selfLockVelY, hitboxOffsetX, hitboxOffsetY, hitboxSizeX, hitboxSizeY, blowUp, teamId, virtualGridX, virtualGridY, dirX, dirY, velX, velY, speed, blState, framesInBlState, explosionFrames, speciesId))
}
func NewNpcPatrolCue(flAct, frAct uint64, x, y float64) *js.Object {
@@ -171,5 +172,9 @@ func main() {
"ConvertToFirstUsedRenderFrameId": ConvertToFirstUsedRenderFrameId,
"ConvertToLastUsedRenderFrameId": ConvertToLastUsedRenderFrameId,
"ShouldGenerateInputFrameUpsync": ShouldGenerateInputFrameUpsync,
"IsMeleeBulletActive": IsMeleeBulletActive,
"IsMeleeBulletAlive": IsMeleeBulletAlive,
"IsFireballBulletActive": IsFireballBulletActive,
"IsFireballBulletAlive": IsFireballBulletAlive,
})
}

View File

@@ -66,4 +66,21 @@ hp application/json application/javascript;
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;
}
}