Compare commits

..

65 Commits

Author SHA1 Message Date
Wing
7e89d703ba Fixed typo. 2023-11-28 08:37:11 +08:00
yflu
dc1e6d3e09 Updated frontend "onPeerInputFrameUpsync" handling for force confirmation. 2023-04-18 07:03:22 +08:00
genxium
28e5c18f00 Fixed typo. 2023-04-14 07:28:01 +08:00
genxium
a241912e7a Updated README. 2023-03-30 15:47:02 +08:00
genxium
c582071f4f Fixes for BackendDynamics disabled. 2023-03-30 15:05:34 +08:00
genxium
59d6300880 Updated README. 2023-03-18 13:22:58 +08:00
yflu
6713feded1 Added back important comment. 2023-03-16 17:35:47 +08:00
genxium
da1204dc63 Minor update. 2023-03-10 16:20:40 +08:00
genxium
ea14ced958 Improved stability. 2023-03-10 15:40:45 +08:00
genxium
b9beee549f Simplified resolv_tailored. 2023-03-02 10:22:27 +08:00
genxium
04d8013cbb Preparing for go2cs transpiling. 2023-03-01 18:20:54 +08:00
genxium
6b503ec95d Updated README. 2023-03-01 10:53:22 +08:00
genxium
71f2a1ecdf Updated documentation. 2023-03-01 07:03:49 +08:00
genxium
de9f3c9090 Minor update. 2023-02-27 14:58:21 +08:00
genxium
96e355eab3 Fixed frontend rollback upon UpdateOnDynamics. 2023-02-27 14:35:19 +08:00
genxium
16e1d8a913 Minor fix. 2023-02-27 12:02:01 +08:00
genxium
04b033be7e Fixed frame data logging. 2023-02-27 11:09:22 +08:00
genxium
7fd96b335a Minor fix. 2023-02-26 23:33:47 +08:00
genxium
8cd5f1d475 Fixed resync. 2023-02-26 23:25:47 +08:00
genxium
21806a3754 Minor updates. 2023-02-26 20:57:40 +08:00
genxium
e213fdfb04 Removed redundant collision related codes. 2023-02-26 20:39:30 +08:00
genxium
b9827f8430 Refined experimental toggle for in-place inputsBuffer update upon dynamics. 2023-02-26 14:59:27 +08:00
genxium
91d16b1cc4 Added an experimental toggle for in-place inputsBuffer update upon dynamics. 2023-02-25 23:40:57 +08:00
genxium
b19868920a Minor update. 2023-02-25 23:27:01 +08:00
genxium
be5200663c Updated input prediction approach upon dynamics. 2023-02-25 23:05:25 +08:00
genxium
7b878ff947 Fixes for backend Golang select-multi-channel implementation. 2023-02-21 22:07:48 +08:00
genxium
c78c480f99 Enhanced UDP session resource management. 2023-02-21 15:21:15 +08:00
genxium
b50874f5c4 Enhanced RecvRingBuff in cpp. 2023-02-21 11:54:06 +08:00
genxium
f1db2972fd Updates for RecvRingBuff. 2023-02-20 08:53:06 +08:00
genxium
16c27b0ce0 Minor fix. 2023-02-19 21:26:49 +08:00
genxium
a44535cad2 Fixes for revival dynamics. 2023-02-19 21:05:25 +08:00
genxium
8b5a96e825 Enhanced exception handling on frontend. 2023-02-19 13:42:25 +08:00
genxium
618531f5c6 Minor fix. 2023-02-18 13:21:34 +08:00
genxium
8345d55e76 Updated collision constant setup. 2023-02-18 11:46:01 +08:00
genxium
a48e2f3cc0 Fixed bullet cloning. 2023-02-18 11:13:33 +08:00
yflu
83419a6f23 Fixed debug boundary drawing. 2023-02-17 22:44:21 +08:00
genxium
b19549b0a8 Enhanced inplace rdf update. 2023-02-17 18:54:51 +08:00
genxium
60866674b5 Fixed multiplayer mode for new dynamics calculation. 2023-02-17 15:38:37 +08:00
genxium
a4941c1273 Minor fix. 2023-02-17 14:35:42 +08:00
genxium
2b304eaa75 A temp dirty commit having mysterious left moving players. 2023-02-17 12:26:07 +08:00
genxium
c6b98855af Reduced externalization cost. 2023-02-16 22:23:12 +08:00
genxium
4e0928cb1b Drafted inplace memory version of game dynamics. 2023-02-16 17:13:09 +08:00
genxium
fb42533f55 Temp update to remove use of MakeFullWrapper for reducing redundant CPU time in profiling. 2023-02-16 10:14:37 +08:00
genxium
9dff989e02 Drafted inplace_ring_buff. 2023-02-15 21:34:27 +08:00
genxium
5b7f35b874 Applied ringbuff to resolv_tailored for reducing memory usage. 2023-02-15 15:38:20 +08:00
genxium
2d179d0cdf Minor update. 2023-02-14 23:27:21 +08:00
genxium
f4b303eb91 Started preparation of in-place clone utilities in jsexport. 2023-02-14 15:38:21 +08:00
genxium
5d92b339f6 Enhanced logging efficiency. 2023-02-13 15:37:13 +08:00
genxium
642adff919 Minor fix. 2023-02-13 11:52:47 +08:00
genxium
62c51b1838 Enhanced pre-battle start GUI. 2023-02-13 10:34:56 +08:00
genxium
2751569e0c Fixed data path for character select. 2023-02-12 23:04:20 +08:00
genxium
d623916b3c Minor fix. 2023-02-12 22:10:42 +08:00
genxium
efd070a11b Merge branch 'main' of github.com:genxium/DelayNoMore 2023-02-12 18:46:13 +08:00
genxium
d111de0a7a Drafted character selection. 2023-02-12 18:45:57 +08:00
yflu
c2fa251e69 Updated documentation. 2023-02-12 12:10:20 +08:00
genxium
de16e8e8de Simplified bullet handling. 2023-02-11 12:08:01 +08:00
genxium
365177a3af Renamed CPP files. 2023-02-10 11:38:21 +08:00
genxium
b79e2dc935 Enhanced UDP message callback handling. 2023-02-09 23:34:00 +08:00
genxium
7b0c807496 Drafted enhancement of UDP message callback. 2023-02-09 10:18:23 +08:00
genxium
5c611b626d Minor fix. 2023-02-08 19:28:40 +08:00
genxium
38149279bd Drafted hp handling. 2023-02-08 18:32:59 +08:00
genxium
a762c563d9 Updated skill sets and animations. 2023-02-07 11:31:59 +08:00
genxium
6a0d729dee Added more animation resources. 2023-02-06 12:02:44 +08:00
genxium
f10389bf55 Minor update. 2023-02-05 20:24:09 +08:00
genxium
6b3d1ed49a Enhanced UI handling upon battle started. 2023-02-05 18:44:37 +08:00
119 changed files with 13843 additions and 4611 deletions

View File

@@ -75,4 +75,18 @@ Instead of replacing all use of TCP by UDP, it's more reasonable to keep using T
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. 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. Therefore, the following plan doesn't assume use of any specific 3rd party encapsulation of UDP communication.
![UDP_secondary_session](./charts/UDPEssentials.jpg) ![UDP_secondary_session](./charts/UDPEssentials.jpg)
# Would using WebRTC for all frontends be a `UDP for all` solution?
Theoretically yes.
## Plan to integrate WebRTC
The actual integration of WebRTC to enable `browser v.s. native app w/ WebRTC` requires detailed planning :)
In my current implementation, there's only 1 backend process and it's responsible for all of the following things. The plan for integrating/migrating each item is written respectively.
- TURN for UDP tunneling/relay
- Some minor modification to [Room.PlayerSecondaryDownsyncSessionDict](https://github.com/genxium/DelayNoMore/blob/365177a3af6033f1cd629a4a4d59beb4557cc311/battle_srv/models/room.go#L126) should be enough to yield a WebRTC API friendly TURN. It's interesting that [though UDP based in transport layer, a WebRTC session is stateful and more similar to WebSocket in terms of API](https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API).
- STUN for UDP holepunching
- Some minor modification to [Player.UdpAddr](https://github.com/genxium/DelayNoMore/blob/365177a3af6033f1cd629a4a4d59beb4557cc311/battle_srv/models/player.go#L56) should be enough to yield a WebRTC API friendly STUN.
- reconnection recovery
- Not sure whether or not I should separate this feature from STUN and TURN, but if I were to do so, [both `Room.RenderFrameBuffer` and `Room.InputsBuffer`](https://github.com/genxium/DelayNoMore/blob/365177a3af6033f1cd629a4a4d59beb4557cc311/battle_srv/models/room.go) should be moved to a shared fast I/O storage (e.g. using Redis) to achieve the same level of `High Availability` in design as STUN and TURN.

View File

@@ -1,21 +1,31 @@
Please refer to [DelayNoMoreUnity](https://github.com/genxium/DelayNoMoreUnity) for a Unity rebuild with .net backend.
# Preface # 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).
[Demo recorded over INTERNET (Phone-Wifi v.s. PC-Wifi UDP holepunched) using an input delay of 6 frames](https://pan.baidu.com/s/1UArwqDShLoPjYppjjqsTqQ?pwd=10wc), and it feels SMOOTH when playing! [Demo recorded over INTERNET (Phone-Wifi v.s. PC-Wifi UDP holepunched) using an input delay of 6 frames](https://pan.baidu.com/s/1UArwqDShLoPjYppjjqsTqQ?pwd=10wc), and it feels SMOOTH when playing!
![Merged_cut_annotated_spedup](./charts/Merged_cut_annotated_spedup.gif) ![Merged_cut_annotated_spedup](./charts/Merged_cut_annotated_spedup.gif)
(battle between 2 celluar 4G users using Android phones, [original video here](https://pan.baidu.com/s/1m50d-VZxEGT3IgeZtww49g?pwd=eqx1))
![Phone4g_battle_spedup](./charts/Phone4g_battle_spedup.gif)
**Since v1.0.13, smoothness in worst cases (e.g. turn-around on ground, in air and after dashing) is drastically improved due to update of prediction approach. The gifs and corresponding screenrecordings above are not updated because there's no big difference when network is good -- however, `input delay` is now set to `4 frames` -- while `input delay = 6 frames` was used in the screenrecordings -- and smoothness is even better now (well there's [a new screenrecording for PcWifi vs Android4g here](https://pan.baidu.com/s/1iNrQ2l_wqbWkURMIfyG88w?pwd=fe2f)).** Key changes are listed below.
- [change#1](https://github.com/genxium/DelayNoMore/blob/c582071f4f2e3dd7e83d65562c7c99981252c358/jsexport/battle/battle.go#L647)
- [change#2](https://github.com/genxium/DelayNoMore/blob/c582071f4f2e3dd7e83d65562c7c99981252c358/frontend/assets/scripts/Map.js#L1446)
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) -- **since v0.9.25, the project is actually equipped with UDP capabilities as follows**. 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) -- **since v0.9.25, the project is actually equipped with UDP capabilities as follows**.
- When using the so called `native apps` on `Android` and `Windows` (I'm working casually hard to support `iOS` next), the frontends will try to use UDP hole-punching w/ the help of backend as a registry. If UDP hole-punching is working, the rollback is often less than `turn-around frames to recover` and thus not noticeable, being much better than using websocket alone. This video shows how the UDP holepunched p2p performs for [Phone-Wifi v.s. PC-Wifi (viewed by PC side)](https://pan.baidu.com/s/1K6704bJKlrSBTVqGcXhajA?pwd=l7ok). - When using the so called `native apps` on `Android` and `Windows` (I'm working casually hard to support `iOS` next), the frontends will try to use UDP hole-punching w/ the help of backend as a registry. If UDP hole-punching is working, the rollback is often less than `turn-around frames to recover` and thus not noticeable, being much better than using websocket alone. This video shows how the UDP holepunched p2p performs for [Phone-Wifi v.s. PC-Wifi (viewed by PC side)](https://pan.baidu.com/s/1K6704bJKlrSBTVqGcXhajA?pwd=l7ok).
- If UDP hole-punching is not working, e.g. for Symmetric NAT like in 4G/5G cellular network, the frontends will use backend as a UDP tunnel (or relay, whatever you like to call it). This video shows how the UDP tunnel performs for [Phone-4G v.s. PC-Wifi (viewed by PC side)](https://pan.baidu.com/s/1IZVa5wVgAdeH6D-xsZYFUw?pwd=dgkj). - If UDP hole-punching is not working, e.g. for Symmetric NAT like in 4G/5G cellular network, the frontends will use backend as a UDP tunnel (or relay, whatever you like to call it). This video shows how the UDP tunnel performs for [Phone-4G v.s. PC-Wifi (merged view@v0.9.34, excellent synchronization)](https://pan.baidu.com/s/1yeIrN5TSf6_av_8-N3vdVg?pwd=7tzw).
- Browser vs `native app` is possible but in that case only websocket is used. - Browser vs `native app` is possible but in that case only websocket is used. For WebRTC integration plan please see [ConcerningEdgeCases](./ConcerningEdgeCases.md). You might also be interested in visiting [netplayjs](https://github.com/rameshvarun/netplayjs) to see how others use WebRTC for browser game synchronization as well.
# Notable Features # Notable Features
- Backend dynamics toggle via [Room.BackendDynamicsEnabled](https://github.com/genxium/DelayNoMore/blob/v0.9.14/battle_srv/models/room.go#L786) - Backend dynamics toggle via [Room.BackendDynamicsEnabled](https://github.com/genxium/DelayNoMore/blob/c582071f4f2e3dd7e83d65562c7c99981252c358/battle_srv/models/room.go#L147)
- Recovery upon reconnection (only if backend dynamics is ON) - 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 - Automatic 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 - Frame data logging toggle for both frontend & backend, useful for debugging out of sync entities when developing new features
_(how input delay roughly works)_ _(how input delay roughly works)_
@@ -88,7 +98,14 @@ The easy way is to try out 2 players with test accounts on a same machine.
- Open one browser instance, visit _http://localhost:7456?expectedRoomId=1_, input `add`on the username box and click to request a captcha, this is a test account so a captcha would be returned by the backend and filled automatically (as shown in the figure below), then click and click to proceed to a matching scene. - Open one browser instance, visit _http://localhost:7456?expectedRoomId=1_, input `add`on the username box and click to request a captcha, this is a test account so a captcha would be returned by the backend and filled automatically (as shown in the figure below), then click and click to proceed to a matching scene.
- Open another browser instance, visit _http://localhost:7456?expectedRoomId=1_, input `bdd`on the username box and click to request a captcha, this is another test account so a captcha would be returned by the backend and filled automatically, then click and click to proceed, when matched a `battle`(but no competition rule yet) would start. - Open another browser instance, visit _http://localhost:7456?expectedRoomId=1_, input `bdd`on the username box and click to request a captcha, this is another test account so a captcha would be returned by the backend and filled automatically, then click and click to proceed, when matched a `battle`(but no competition rule yet) would start.
- Try out the onscreen virtual joysticks to move the cars and see if their movements are in-sync. - Try out the onscreen virtual joysticks to move the cars and see if their movements are in-sync.
![screenshot-2](./charts/screenshot-2.png)
![How-to-play-1](./charts/How-to-play-1.png)
![How-to-play-2](./charts/How-to-play-2.png)
![How-to-play-3](./charts/How-to-play-3.png)
![How-to-play-4](./charts/How-to-play-4.png)
## 2 Troubleshooting ## 2 Troubleshooting
@@ -103,9 +120,9 @@ Just restart your `redis-server` process.
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. 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". 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 [prediction mismatch on the frontend](https://github.com/genxium/DelayNoMore/blob/c582071f4f2e3dd7e83d65562c7c99981252c358/frontend/assets/scripts/Map.js#L968).
- 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#1 forceConfirmation on the backend](https://github.com/genxium/DelayNoMore/blob/c582071f4f2e3dd7e83d65562c7c99981252c358/battle_srv/models/room.go#L1315).
- Detection of [type#2 forceConfirmation on the backend](https://github.com/genxium/DelayNoMore/blob/v0.9.19/battle_srv/models/room.go#L1259). - Detection of [type#2 forceConfirmation on the backend](https://github.com/genxium/DelayNoMore/blob/c582071f4f2e3dd7e83d65562c7c99981252c358/battle_srv/models/room.go#L1328).
There's also some useful information displayed on the frontend when `true == Map.showNetworkDoctorInfo`. There's also some useful information displayed on the frontend when `true == Map.showNetworkDoctorInfo`.
![networkstats](./charts/networkstats.png) ![networkstats](./charts/networkstats.png)
@@ -116,6 +133,24 @@ When building for native platforms, it's much more convenient to trigger the Coc
``` ```
shell> cd <proj-root> shell> cd <proj-root>
shell> /path/to/CocosCreator.exe --path ./frontend --build "platform=win32;debug=true" shell> /path/to/CocosCreator.exe --path ./frontend --build "platform=win32;debug=true"
shell> cd ./frontend/build/jsb-link/frameworks/runtime-src/proj.win32 && MSBUILD DelayNoMore.vcxproj -property:Configuration=Debug
```
or
```
shell> cd <proj-root>
shell> /path/to/CocosCreator.exe --path ./frontend --build "platform=win32;debug=false"
shell> cd ./frontend/build/jsb-link/frameworks/runtime-src/proj.win32 && MSBUILD DelayNoMore.vcxproj -property:Configuration=Release
```
for release.
If `MSBUILD` command is not yet added to `PATH`, Use `Get-Command MSBUILD` in `Developer Command Prompt for VS 2017/2019` to see where the command should come from and add it to `PATH`.
Similarly for Android release build
```
shell> cd <proj-root>
shell> /path/to/CocosCreator.exe --path ./frontend --build "platform=android;debug=false"
shell> cd ./frontend/build/jsb-link/frameworks/runtime-src/proj.android-studio && ./gradlew assembleRelease
``` ```
### 2.4 CococCreator native build reloading ### 2.4 CococCreator native build reloading

View File

@@ -4,9 +4,24 @@ ROOT_DIR=.
GOPROXY=https://goproxy.io GOPROXY=https://goproxy.io
all: help all: help
# To install `gojson` executable
# ```
# go install github.com/ChimeraCoder/gojson/gojson@latest
# ```
#
# OS detection reference https://stackoverflow.com/a/12099167
gen-constants: gen-constants:
gojson -pkg common -name constants -input common/constants.json -o common/constants_struct.go gojson -pkg common -name constants -input common/constants.json -o common/constants_struct.go
ifeq ($(OS),Windows_NT)
sed -i 's/int64/int/g' common/constants_struct.go sed -i 's/int64/int/g' common/constants_struct.go
else
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Darwin)
sed -i '' -e 's/int64/int/g' common/constants_struct.go
else
sed -i 's/int64/int/g' common/constants_struct.go
endif
endif
run-test: build run-test: build
ServerEnv=TEST ./$(PROJECTNAME) ServerEnv=TEST ./$(PROJECTNAME)

View File

@@ -85,7 +85,6 @@ func (p *playerController) SMSCaptchaGet(c *gin.Context) {
c.Set(api.RET, Constants.RetCode.SmsCaptchaRequestedTooFrequently) c.Set(api.RET, Constants.RetCode.SmsCaptchaRequestedTooFrequently)
return return
} }
Logger.Info("A new SmsCaptcha record is needed for: ", zap.String("key", redisKey))
pass := false pass := false
var succRet int var succRet int
if Conf.General.ServerEnv == SERVER_ENV_TEST { if Conf.General.ServerEnv == SERVER_ENV_TEST {
@@ -93,32 +92,28 @@ func (p *playerController) SMSCaptchaGet(c *gin.Context) {
if nil == err && nil != player { if nil == err && nil != player {
pass = true pass = true
succRet = Constants.RetCode.IsTestAcc succRet = Constants.RetCode.IsTestAcc
Logger.Info("A new SmsCaptcha record is needed for: ", zap.String("key", redisKey), zap.Any("player", player))
} }
} }
if !pass { /*
player, err := models.GetPlayerByName(req.Num) // Real phonenum is not supported yet!
if nil == err && nil != player { if !pass {
pass = true if RE_PHONE_NUM.MatchString(req.Num) {
succRet = Constants.RetCode.IsBotAcc succRet = Constants.RetCode.Ok
} pass = true
} }
if req.CountryCode == "86" {
if !pass { if RE_CHINA_PHONE_NUM.MatchString(req.Num) {
if RE_PHONE_NUM.MatchString(req.Num) { succRet = Constants.RetCode.Ok
succRet = Constants.RetCode.Ok pass = true
pass = true } else {
} succRet = Constants.RetCode.InvalidRequestParam
if req.CountryCode == "86" { pass = false
if RE_CHINA_PHONE_NUM.MatchString(req.Num) { }
succRet = Constants.RetCode.Ok }
pass = true
} else {
succRet = Constants.RetCode.InvalidRequestParam
pass = false
} }
} */
}
if !pass { if !pass {
c.Set(api.RET, Constants.RetCode.InvalidRequestParam) c.Set(api.RET, Constants.RetCode.InvalidRequestParam)
return return
@@ -481,16 +476,6 @@ func (p *playerController) maybeCreateNewPlayer(req smsCaptchaReq) (*models.Play
Logger.Info("Got a test env player:", zap.Any("phonenum", req.Num), zap.Any("playerId", player.Id)) Logger.Info("Got a test env player:", zap.Any("phonenum", req.Num), zap.Any("playerId", player.Id))
return player, nil return player, nil
} }
} else {
botPlayer, err := models.GetPlayerByName(req.Num)
if err != nil {
Logger.Error("Seeking bot player error:", zap.Error(err))
return nil, err
}
if botPlayer != nil {
Logger.Info("Got a bot player:", zap.Any("phonenum", req.Num), zap.Any("playerId", botPlayer.Id))
return botPlayer, nil
}
} }
bind, err := models.GetPlayerAuthBinding(Constants.AuthChannel.Sms, extAuthID) bind, err := models.GetPlayerAuthBinding(Constants.AuthChannel.Sms, extAuthID)

View File

@@ -74,7 +74,7 @@ func Test_SMSCaptchaGet_illegalPhone(t *testing.T) {
func Test_SMSCaptchaGet_testAcc(t *testing.T) { func Test_SMSCaptchaGet_testAcc(t *testing.T) {
player, err := getTestPlayer() player, err := getTestPlayer()
if err == nil && player != nil { if nil == err && nil != player {
resp := mustDoSmsCaptchaGetReq(fakeSMSCaptchReq(player.Name), t) resp := mustDoSmsCaptchaGetReq(fakeSMSCaptchReq(player.Name), t)
if resp.Ret != Constants.RetCode.IsTestAcc { if resp.Ret != Constants.RetCode.IsTestAcc {
t.Fail() t.Fail()

View File

@@ -44,10 +44,10 @@
"PASSWORD_RESET_CODE_GENERATION_PER_EMAIL_TOO_FREQUENTLY": 2020, "PASSWORD_RESET_CODE_GENERATION_PER_EMAIL_TOO_FREQUENTLY": 2020,
"TRADE_CREATION_TOO_FREQUENTLY": 2021, "TRADE_CREATION_TOO_FREQUENTLY": 2021,
"MAP_NOT_UNLOCKED": 2022, "MAP_NOT_UNLOCKED": 2022,
"GET_SMS_CAPTCHA_RESP_ERROR_CODE": 2023, "GET_SMS_CAPTCHA_RESP_ERROR_CODE": 2023,
"SMS_CAPTCHA_REQUESTED_TOO_FREQUENTLY": 2024, "SMS_CAPTCHA_REQUESTED_TOO_FREQUENTLY": 2024,
"SMS_CAPTCHA_NOT_MATCH": 2025, "SMS_CAPTCHA_NOT_MATCH": 2025,
"SAME_PLAYER_ALREADY_IN_SAME_ROOM": 2026,
"NOT_IMPLEMENTED_YET": 65535 "NOT_IMPLEMENTED_YET": 65535
}, },

View File

@@ -17,6 +17,7 @@ type constants struct {
RetCode struct { RetCode struct {
ActiveWatchdog int `json:"ACTIVE_WATCHDOG"` ActiveWatchdog int `json:"ACTIVE_WATCHDOG"`
BattleStopped int `json:"BATTLE_STOPPED"` BattleStopped int `json:"BATTLE_STOPPED"`
ClientMismatchedRenderFrame int `json:"CLIENT_MISMATCHED_RENDER_FRAME"`
Duplicated int `json:"DUPLICATED"` Duplicated int `json:"DUPLICATED"`
FailedToCreate int `json:"FAILED_TO_CREATE"` FailedToCreate int `json:"FAILED_TO_CREATE"`
FailedToDelete int `json:"FAILED_TO_DELETE"` FailedToDelete int `json:"FAILED_TO_DELETE"`
@@ -51,6 +52,7 @@ type constants struct {
PlayerNotAddableToRoom int `json:"PLAYER_NOT_ADDABLE_TO_ROOM"` PlayerNotAddableToRoom int `json:"PLAYER_NOT_ADDABLE_TO_ROOM"`
PlayerNotFound int `json:"PLAYER_NOT_FOUND"` PlayerNotFound int `json:"PLAYER_NOT_FOUND"`
PlayerNotReaddableToRoom int `json:"PLAYER_NOT_READDABLE_TO_ROOM"` PlayerNotReaddableToRoom int `json:"PLAYER_NOT_READDABLE_TO_ROOM"`
SamePlayerAlreadyInSameRoom int `json:"SAME_PLAYER_ALREADY_IN_SAME_ROOM"`
SendEmailTimeout int `json:"SEND_EMAIL_TIMEOUT"` SendEmailTimeout int `json:"SEND_EMAIL_TIMEOUT"`
SmsCaptchaNotMatch int `json:"SMS_CAPTCHA_NOT_MATCH"` SmsCaptchaNotMatch int `json:"SMS_CAPTCHA_NOT_MATCH"`
SmsCaptchaRequestedTooFrequently int `json:"SMS_CAPTCHA_REQUESTED_TOO_FREQUENTLY"` SmsCaptchaRequestedTooFrequently int `json:"SMS_CAPTCHA_REQUESTED_TOO_FREQUENTLY"`

View File

@@ -3,6 +3,7 @@ module battle_srv
go 1.18 go 1.18
require ( require (
dnmshared v0.0.0
github.com/Masterminds/squirrel v0.0.0-20180815162352-8a7e65843414 github.com/Masterminds/squirrel v0.0.0-20180815162352-8a7e65843414
github.com/davecgh/go-spew v1.1.1 github.com/davecgh/go-spew v1.1.1
github.com/gin-contrib/cors v0.0.0-20180514151808-6f0a820f94be github.com/gin-contrib/cors v0.0.0-20180514151808-6f0a820f94be
@@ -19,14 +20,12 @@ require (
github.com/thoas/go-funk v0.0.0-20180716193722-1060394a7713 github.com/thoas/go-funk v0.0.0-20180716193722-1060394a7713
go.uber.org/zap v1.9.1 go.uber.org/zap v1.9.1
google.golang.org/protobuf v1.28.1 google.golang.org/protobuf v1.28.1
jsexport v0.0.0
dnmshared v0.0.0 resolv v0.0.0
jsexport v0.0.0
resolv v0.0.0
) )
require ( require (
github.com/ChimeraCoder/gojson v1.0.0 // indirect github.com/ChimeraCoder/gojson v1.1.0 // indirect
github.com/fatih/color v1.7.0 // indirect github.com/fatih/color v1.7.0 // indirect
github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7 // indirect github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7 // indirect
github.com/githubnemo/CompileDaemon v1.0.0 // indirect github.com/githubnemo/CompileDaemon v1.0.0 // indirect
@@ -44,11 +43,11 @@ require (
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 // indirect golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 // indirect
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 // indirect gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 // indirect
gopkg.in/go-playground/validator.v8 v8.18.2 // indirect gopkg.in/go-playground/validator.v8 v8.18.2 // indirect
gopkg.in/yaml.v2 v2.2.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
) )
replace ( replace (
dnmshared => ../dnmshared dnmshared => ../dnmshared
jsexport => ../jsexport jsexport => ../jsexport
resolv => ../resolv_tailored resolv => ../resolv_tailored
) )

View File

@@ -2,6 +2,8 @@ github.com/ByteArena/box2d v1.0.2 h1:f7f9KEQWhCs1n516DMLzi5w6u0MeeE78Mes4fWMcj9k
github.com/ByteArena/box2d v1.0.2/go.mod h1:LzEuxY9iCz+tskfWCY3o0ywYBRafDDugdSj+/YGI6sE= github.com/ByteArena/box2d v1.0.2/go.mod h1:LzEuxY9iCz+tskfWCY3o0ywYBRafDDugdSj+/YGI6sE=
github.com/ChimeraCoder/gojson v1.0.0 h1:gAYKGTV+xfQ4+l/4C/nazPbiQDUidG0G3ukAJnE7LNE= github.com/ChimeraCoder/gojson v1.0.0 h1:gAYKGTV+xfQ4+l/4C/nazPbiQDUidG0G3ukAJnE7LNE=
github.com/ChimeraCoder/gojson v1.0.0/go.mod h1:nYbTQlu6hv8PETM15J927yM0zGj3njIldp72UT1MqSw= github.com/ChimeraCoder/gojson v1.0.0/go.mod h1:nYbTQlu6hv8PETM15J927yM0zGj3njIldp72UT1MqSw=
github.com/ChimeraCoder/gojson v1.1.0 h1:/6S8djl/jColpJGTYniA3xrqJWuKeyEozzPtpr5L4Pw=
github.com/ChimeraCoder/gojson v1.1.0/go.mod h1:nYbTQlu6hv8PETM15J927yM0zGj3njIldp72UT1MqSw=
github.com/Masterminds/squirrel v0.0.0-20180815162352-8a7e65843414 h1:VHdYPA0V0YgL97gdjHevN6IVPRX+fOoNMqcYvUAzwNU= github.com/Masterminds/squirrel v0.0.0-20180815162352-8a7e65843414 h1:VHdYPA0V0YgL97gdjHevN6IVPRX+fOoNMqcYvUAzwNU=
github.com/Masterminds/squirrel v0.0.0-20180815162352-8a7e65843414/go.mod h1:xnKTFzjGUiZtiOagBsfnvomW+nJg2usB1ZpordQWqNM= github.com/Masterminds/squirrel v0.0.0-20180815162352-8a7e65843414/go.mod h1:xnKTFzjGUiZtiOagBsfnvomW+nJg2usB1ZpordQWqNM=
github.com/Pallinder/go-randomdata v0.0.0-20180616180521-15df0648130a h1:0OnS8GR4uI3nau+f/juCZlAq+zCrsHXRJlENrUQ4eU8= github.com/Pallinder/go-randomdata v0.0.0-20180616180521-15df0648130a h1:0OnS8GR4uI3nau+f/juCZlAq+zCrsHXRJlENrUQ4eU8=
@@ -92,3 +94,5 @@ gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2G
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=

View File

@@ -25,9 +25,16 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
"net" "net"
// _ "net/http/pprof"
) )
func main() { func main() {
/*
// Only used for profiling
go func() {
http.ListenAndServe("0.0.0.0:6060", nil)
}()
*/
MustParseConfig() MustParseConfig()
MustParseConstants() MustParseConstants()
storage.Init() storage.Init()

View File

@@ -22,34 +22,36 @@ func toPbRoomDownsyncFrame(rdf *battle.RoomDownsyncFrame) *pb.RoomDownsyncFrame
for i, last := range rdf.PlayersArr { for i, last := range rdf.PlayersArr {
pbPlayer := &pb.PlayerDownsync{ pbPlayer := &pb.PlayerDownsync{
Id: last.Id, Id: last.Id,
VirtualGridX: last.VirtualGridX, VirtualGridX: last.VirtualGridX,
VirtualGridY: last.VirtualGridY, VirtualGridY: last.VirtualGridY,
DirX: last.DirX, DirX: last.DirX,
DirY: last.DirY, DirY: last.DirY,
VelX: last.VelX, VelX: last.VelX,
VelY: last.VelY, VelY: last.VelY,
FramesToRecover: last.FramesToRecover, FramesToRecover: last.FramesToRecover,
FramesInChState: last.FramesInChState, FramesInChState: last.FramesInChState,
ActiveSkillId: last.ActiveSkillId, ActiveSkillId: last.ActiveSkillId,
ActiveSkillHit: last.ActiveSkillHit, ActiveSkillHit: last.ActiveSkillHit,
FramesInvinsible: last.FramesInvinsible, FramesInvinsible: last.FramesInvinsible,
Speed: last.Speed, Speed: last.Speed,
BattleState: last.BattleState, BattleState: last.BattleState,
CharacterState: last.CharacterState, CharacterState: last.CharacterState,
InAir: last.InAir, InAir: last.InAir,
OnWall: last.OnWall, OnWall: last.OnWall,
OnWallNormX: last.OnWallNormX, OnWallNormX: last.OnWallNormX,
OnWallNormY: last.OnWallNormY, OnWallNormY: last.OnWallNormY,
CapturedByInertia: last.CapturedByInertia, CapturedByInertia: last.CapturedByInertia,
JoinIndex: last.JoinIndex, JoinIndex: last.JoinIndex,
BulletTeamId: last.BulletTeamId, BulletTeamId: last.BulletTeamId,
ChCollisionTeamId: last.ChCollisionTeamId, ChCollisionTeamId: last.ChCollisionTeamId,
Hp: last.Hp, Hp: last.Hp,
MaxHp: last.MaxHp, MaxHp: last.MaxHp,
ColliderRadius: last.ColliderRadius, RevivalVirtualGridX: last.RevivalVirtualGridX,
Score: last.Score, RevivalVirtualGridY: last.RevivalVirtualGridY,
Removed: last.Removed, ColliderRadius: last.ColliderRadius,
Score: last.Score,
Removed: last.Removed,
} }
ret.PlayersArr[i] = pbPlayer ret.PlayersArr[i] = pbPlayer
} }
@@ -147,32 +149,36 @@ func toPbPlayers(modelInstances map[int32]*Player, withMetaInfo bool) []*pb.Play
for _, last := range modelInstances { for _, last := range modelInstances {
pbPlayer := &pb.PlayerDownsync{ pbPlayer := &pb.PlayerDownsync{
Id: last.Id, Id: last.Id,
VirtualGridX: last.VirtualGridX, VirtualGridX: last.VirtualGridX,
VirtualGridY: last.VirtualGridY, VirtualGridY: last.VirtualGridY,
DirX: last.DirX, DirX: last.DirX,
DirY: last.DirY, DirY: last.DirY,
VelX: last.VelX, VelX: last.VelX,
VelY: last.VelY, VelY: last.VelY,
FramesToRecover: last.FramesToRecover, FramesToRecover: last.FramesToRecover,
FramesInChState: last.FramesInChState, FramesInChState: last.FramesInChState,
ActiveSkillId: last.ActiveSkillId, ActiveSkillId: last.ActiveSkillId,
ActiveSkillHit: last.ActiveSkillHit, ActiveSkillHit: last.ActiveSkillHit,
FramesInvinsible: last.FramesInvinsible, FramesInvinsible: last.FramesInvinsible,
Speed: last.Speed, Speed: last.Speed,
BattleState: last.BattleState, BattleState: last.BattleState,
CharacterState: last.CharacterState, CharacterState: last.CharacterState,
InAir: last.InAir, InAir: last.InAir,
OnWall: last.OnWall, OnWall: last.OnWall,
OnWallNormX: last.OnWallNormX, OnWallNormX: last.OnWallNormX,
OnWallNormY: last.OnWallNormY, OnWallNormY: last.OnWallNormY,
CapturedByInertia: last.CapturedByInertia, CapturedByInertia: last.CapturedByInertia,
JoinIndex: last.JoinIndex, JoinIndex: last.JoinIndex,
BulletTeamId: last.BulletTeamId, BulletTeamId: last.BulletTeamId,
ChCollisionTeamId: last.ChCollisionTeamId, ChCollisionTeamId: last.ChCollisionTeamId,
ColliderRadius: last.ColliderRadius, Hp: last.Hp,
Score: last.Score, MaxHp: last.MaxHp,
Removed: last.Removed, RevivalVirtualGridX: last.RevivalVirtualGridX,
RevivalVirtualGridY: last.RevivalVirtualGridY,
ColliderRadius: last.ColliderRadius,
Score: last.Score,
Removed: last.Removed,
} }
if withMetaInfo { if withMetaInfo {
pbPlayer.Name = last.Name pbPlayer.Name = last.Name
@@ -193,34 +199,36 @@ func toJsPlayers(modelInstances map[int32]*Player) []*battle.PlayerDownsync {
for _, last := range modelInstances { for _, last := range modelInstances {
toRet[last.JoinIndex-1] = &battle.PlayerDownsync{ toRet[last.JoinIndex-1] = &battle.PlayerDownsync{
Id: last.Id, Id: last.Id,
VirtualGridX: last.VirtualGridX, VirtualGridX: last.VirtualGridX,
VirtualGridY: last.VirtualGridY, VirtualGridY: last.VirtualGridY,
DirX: last.DirX, DirX: last.DirX,
DirY: last.DirY, DirY: last.DirY,
VelX: last.VelX, VelX: last.VelX,
VelY: last.VelY, VelY: last.VelY,
FramesToRecover: last.FramesToRecover, FramesToRecover: last.FramesToRecover,
FramesInChState: last.FramesInChState, FramesInChState: last.FramesInChState,
ActiveSkillId: last.ActiveSkillId, ActiveSkillId: last.ActiveSkillId,
ActiveSkillHit: last.ActiveSkillHit, ActiveSkillHit: last.ActiveSkillHit,
FramesInvinsible: last.FramesInvinsible, FramesInvinsible: last.FramesInvinsible,
Speed: last.Speed, Speed: last.Speed,
BattleState: last.BattleState, BattleState: last.BattleState,
CharacterState: last.CharacterState, CharacterState: last.CharacterState,
JoinIndex: last.JoinIndex, JoinIndex: last.JoinIndex,
BulletTeamId: last.BulletTeamId, BulletTeamId: last.BulletTeamId,
ChCollisionTeamId: last.ChCollisionTeamId, ChCollisionTeamId: last.ChCollisionTeamId,
Hp: last.Hp, Hp: last.Hp,
MaxHp: last.MaxHp, MaxHp: last.MaxHp,
ColliderRadius: last.ColliderRadius, RevivalVirtualGridX: last.RevivalVirtualGridX,
InAir: last.InAir, RevivalVirtualGridY: last.RevivalVirtualGridY,
OnWall: last.OnWall, ColliderRadius: last.ColliderRadius,
OnWallNormX: last.OnWallNormX, InAir: last.InAir,
OnWallNormY: last.OnWallNormY, OnWall: last.OnWall,
CapturedByInertia: last.CapturedByInertia, OnWallNormX: last.OnWallNormX,
Score: last.Score, OnWallNormY: last.OnWallNormY,
Removed: last.Removed, CapturedByInertia: last.CapturedByInertia,
Score: last.Score,
Removed: last.Removed,
} }
} }

View File

@@ -47,11 +47,10 @@ type Player struct {
TutorialStage int `db:"tutorial_stage"` TutorialStage int `db:"tutorial_stage"`
// other in-battle info fields // other in-battle info fields
LastReceivedInputFrameId int32 LastConsecutiveRecvInputFrameId int32
LastUdpReceivedInputFrameId int32 LastSentInputFrameId int32
LastSentInputFrameId int32 AckingFrameId int32
AckingFrameId int32 AckingInputFrameId int32
AckingInputFrameId int32
UdpAddr *PeerUdpAddr UdpAddr *PeerUdpAddr
BattleUdpTunnelAddr *net.UDPAddr // This addr is used by backend only, not visible to frontend BattleUdpTunnelAddr *net.UDPAddr // This addr is used by backend only, not visible to frontend
@@ -78,13 +77,14 @@ func getPlayer(cond sq.Eq) (*Player, error) {
return nil, err return nil, err
} }
rows, err := storage.MySQLManagerIns.Queryx(query, args...) rows, err := storage.MySQLManagerIns.Queryx(query, args...)
if err != nil { if nil != err {
return nil, err return nil, err
} }
cols, err := rows.Columns() cols, err := rows.Columns()
if nil != err { if nil != err {
panic(err) panic(err)
} }
cnt := 0
for rows.Next() { for rows.Next() {
// TODO: Do it more elegantly, but by now I don't have time to learn reflection of Golang // TODO: Do it more elegantly, but by now I don't have time to learn reflection of Golang
vals := rowValues(rows, cols) vals := rowValues(rows, cols)
@@ -106,9 +106,14 @@ func getPlayer(cond sq.Eq) (*Player, error) {
} }
} }
Logger.Debug("Queried player from db", zap.Any("cond", cond), zap.Any("p", p), zap.Any("pd", pd), zap.Any("cols", cols), zap.Any("rowValues", vals)) Logger.Debug("Queried player from db", zap.Any("cond", cond), zap.Any("p", p), zap.Any("pd", pd), zap.Any("cols", cols), zap.Any("rowValues", vals))
cnt++
}
if 0 < cnt {
p.PlayerDownsync = pd
return &p, nil
} else {
return nil, nil
} }
p.PlayerDownsync = pd
return &p, nil
} }
func (p *Player) Insert(tx *sqlx.Tx) error { func (p *Player) Insert(tx *sqlx.Tx) error {

View File

@@ -135,9 +135,9 @@ type Room struct {
CurDynamicsRenderFrameId int32 // [WARNING] The dynamics of backend is ALWAYS MOVING FORWARD BY ALL-CONFIRMED INPUTFRAMES (either by upsync or forced), i.e. no rollback; Moreover when "true == BackendDynamicsEnabled" we always have "Room.CurDynamicsRenderFrameId >= Room.RenderFrameId" because each "all-confirmed inputFrame" is applied on "all applicable renderFrames" in one-go hence often sees a future "renderFrame" earlier CurDynamicsRenderFrameId int32 // [WARNING] The dynamics of backend is ALWAYS MOVING FORWARD BY ALL-CONFIRMED INPUTFRAMES (either by upsync or forced), i.e. no rollback; Moreover when "true == BackendDynamicsEnabled" we always have "Room.CurDynamicsRenderFrameId >= Room.RenderFrameId" because each "all-confirmed inputFrame" is applied on "all applicable renderFrames" in one-go hence often sees a future "renderFrame" earlier
EffectivePlayerCount int32 EffectivePlayerCount int32
DismissalWaitGroup sync.WaitGroup DismissalWaitGroup sync.WaitGroup
InputsBuffer *battle.RingBuffer // Indices are STRICTLY consecutive InputsBuffer *resolv.RingBuffer // Indices are STRICTLY consecutive
InputsBufferLock sync.Mutex // Guards [InputsBuffer, LatestPlayerUpsyncedInputFrameId, LastAllConfirmedInputFrameId, LastAllConfirmedInputList, LastAllConfirmedInputFrameIdWithChange, LastIndividuallyConfirmedInputList, player.LastReceivedInputFrameId, player.LastUdpReceivedInputFrameId] InputsBufferLock sync.Mutex // Guards [InputsBuffer, LatestPlayerUpsyncedInputFrameId, LastAllConfirmedInputFrameId, LastAllConfirmedInputList, LastAllConfirmedInputFrameIdWithChange, LastIndividuallyConfirmedInputFrameId, LastIndividuallyConfirmedInputList, player.LastConsecutiveRecvInputFrameId]
RenderFrameBuffer *battle.RingBuffer // Indices are STRICTLY consecutive RenderFrameBuffer *resolv.RingBuffer // Indices are STRICTLY consecutive
LatestPlayerUpsyncedInputFrameId int32 LatestPlayerUpsyncedInputFrameId int32
LastAllConfirmedInputFrameId int32 LastAllConfirmedInputFrameId int32
LastAllConfirmedInputFrameIdWithChange int32 LastAllConfirmedInputFrameIdWithChange int32
@@ -156,31 +156,38 @@ type Room struct {
TmxPointsMap StrToVec2DListMap TmxPointsMap StrToVec2DListMap
TmxPolygonsMap StrToPolygon2DListMap TmxPolygonsMap StrToPolygon2DListMap
rdfIdToActuallyUsedInput map[int32]*pb.InputFrameDownsync rdfIdToActuallyUsedInput map[int32]*pb.InputFrameDownsync
LastIndividuallyConfirmedInputList []uint64 LastIndividuallyConfirmedInputFrameId []int32
LastIndividuallyConfirmedInputList []uint64
BattleUdpTunnelLock sync.Mutex BattleUdpTunnelLock sync.Mutex
BattleUdpTunnelAddr *pb.PeerUdpAddr BattleUdpTunnelAddr *pb.PeerUdpAddr
BattleUdpTunnel *net.UDPConn BattleUdpTunnel *net.UDPConn
collisionHolder *resolv.Collision
effPushbacks []*battle.Vec2D
hardPushbackNormsArr [][]*battle.Vec2D
jumpedOrNotList []bool
dynamicRectangleColliders []*resolv.Object
} }
func (pR *Room) updateScore() { func (pR *Room) updateScore() {
pR.Score = calRoomScore(pR.EffectivePlayerCount, pR.Capacity, pR.State) pR.Score = calRoomScore(pR.EffectivePlayerCount, pR.Capacity, pR.State)
} }
func (pR *Room) AddPlayerIfPossible(pPlayerFromDbInit *Player, session *websocket.Conn, signalToCloseConnOfThisPlayer SignalToCloseConnCbType) bool { func (pR *Room) AddPlayerIfPossible(pPlayerFromDbInit *Player, speciesId int, session *websocket.Conn, signalToCloseConnOfThisPlayer SignalToCloseConnCbType) int {
playerId := pPlayerFromDbInit.Id playerId := pPlayerFromDbInit.Id
// TODO: Any thread-safety concern for accessing "pR" here? // TODO: Any thread-safety concern for accessing "pR" here?
if RoomBattleStateIns.IDLE != pR.State && RoomBattleStateIns.WAITING != pR.State { if RoomBattleStateIns.IDLE != pR.State && RoomBattleStateIns.WAITING != pR.State {
Logger.Warn("AddPlayerIfPossible error, roomState:", zap.Any("playerId", playerId), zap.Any("roomId", pR.Id), zap.Any("roomState", pR.State), zap.Any("roomEffectivePlayerCount", pR.EffectivePlayerCount)) Logger.Warn("AddPlayerIfPossible error, roomState:", zap.Any("playerId", playerId), zap.Any("roomId", pR.Id), zap.Any("roomState", pR.State), zap.Any("roomEffectivePlayerCount", pR.EffectivePlayerCount))
return false return Constants.RetCode.PlayerNotAddableToRoom
} }
if _, existent := pR.Players[playerId]; existent { if _, existent := pR.Players[playerId]; existent {
Logger.Warn("AddPlayerIfPossible error, existing in the room.PlayersDict:", zap.Any("playerId", playerId), zap.Any("roomId", pR.Id), zap.Any("roomState", pR.State), zap.Any("roomEffectivePlayerCount", pR.EffectivePlayerCount)) Logger.Warn("AddPlayerIfPossible error, existing in the room.PlayersDict:", zap.Any("playerId", playerId), zap.Any("roomId", pR.Id), zap.Any("roomState", pR.State), zap.Any("roomEffectivePlayerCount", pR.EffectivePlayerCount))
return false return Constants.RetCode.SamePlayerAlreadyInSameRoom
} }
defer pR.onPlayerAdded(playerId) defer pR.onPlayerAdded(playerId, speciesId)
pPlayerFromDbInit.UdpAddr = nil pPlayerFromDbInit.UdpAddr = nil
pPlayerFromDbInit.BattleUdpTunnelAddr = nil pPlayerFromDbInit.BattleUdpTunnelAddr = nil
@@ -188,8 +195,7 @@ func (pR *Room) AddPlayerIfPossible(pPlayerFromDbInit *Player, session *websocke
pPlayerFromDbInit.AckingFrameId = -1 pPlayerFromDbInit.AckingFrameId = -1
pPlayerFromDbInit.AckingInputFrameId = -1 pPlayerFromDbInit.AckingInputFrameId = -1
pPlayerFromDbInit.LastSentInputFrameId = MAGIC_LAST_SENT_INPUT_FRAME_ID_NORMAL_ADDED pPlayerFromDbInit.LastSentInputFrameId = MAGIC_LAST_SENT_INPUT_FRAME_ID_NORMAL_ADDED
pPlayerFromDbInit.LastReceivedInputFrameId = MAGIC_LAST_SENT_INPUT_FRAME_ID_NORMAL_ADDED pPlayerFromDbInit.LastConsecutiveRecvInputFrameId = MAGIC_LAST_SENT_INPUT_FRAME_ID_NORMAL_ADDED
pPlayerFromDbInit.LastUdpReceivedInputFrameId = MAGIC_LAST_SENT_INPUT_FRAME_ID_NORMAL_ADDED
pPlayerFromDbInit.BattleState = PlayerBattleStateIns.ADDED_PENDING_BATTLE_COLLIDER_ACK pPlayerFromDbInit.BattleState = PlayerBattleStateIns.ADDED_PENDING_BATTLE_COLLIDER_ACK
pPlayerFromDbInit.ColliderRadius = DEFAULT_PLAYER_RADIUS // Hardcoded pPlayerFromDbInit.ColliderRadius = DEFAULT_PLAYER_RADIUS // Hardcoded
@@ -204,19 +210,19 @@ func (pR *Room) AddPlayerIfPossible(pPlayerFromDbInit *Player, session *websocke
}) })
newWatchdog.Stop() newWatchdog.Stop()
pR.PlayerActiveWatchdogDict[playerId] = newWatchdog pR.PlayerActiveWatchdogDict[playerId] = newWatchdog
return true return Constants.RetCode.Ok
} }
func (pR *Room) ReAddPlayerIfPossible(pTmpPlayerInstance *Player, session *websocket.Conn, signalToCloseConnOfThisPlayer SignalToCloseConnCbType) bool { func (pR *Room) ReAddPlayerIfPossible(pTmpPlayerInstance *Player, session *websocket.Conn, signalToCloseConnOfThisPlayer SignalToCloseConnCbType) int {
playerId := pTmpPlayerInstance.Id playerId := pTmpPlayerInstance.Id
// TODO: Any thread-safety concern for accessing "pR" and "pEffectiveInRoomPlayerInstance" here? // TODO: Any thread-safety concern for accessing "pR" and "pEffectiveInRoomPlayerInstance" here?
if RoomBattleStateIns.PREPARE != pR.State && RoomBattleStateIns.WAITING != pR.State && RoomBattleStateIns.IN_BATTLE != pR.State && RoomBattleStateIns.IN_SETTLEMENT != pR.State && RoomBattleStateIns.IN_DISMISSAL != pR.State { if RoomBattleStateIns.PREPARE != pR.State && RoomBattleStateIns.WAITING != pR.State && RoomBattleStateIns.IN_BATTLE != pR.State && RoomBattleStateIns.IN_SETTLEMENT != pR.State && RoomBattleStateIns.IN_DISMISSAL != pR.State {
Logger.Warn("ReAddPlayerIfPossible error due to roomState:", zap.Any("playerId", playerId), zap.Any("roomId", pR.Id), zap.Any("roomState", pR.State), zap.Any("roomEffectivePlayerCount", pR.EffectivePlayerCount)) Logger.Warn("ReAddPlayerIfPossible error due to roomState:", zap.Any("playerId", playerId), zap.Any("roomId", pR.Id), zap.Any("roomState", pR.State), zap.Any("roomEffectivePlayerCount", pR.EffectivePlayerCount))
return false return Constants.RetCode.PlayerNotReaddableToRoom
} }
if _, existent := pR.Players[playerId]; !existent { if _, existent := pR.Players[playerId]; !existent {
Logger.Warn("ReAddPlayerIfPossible error due to player nonexistent for room:", zap.Any("playerId", playerId), zap.Any("roomId", pR.Id), zap.Any("roomState", pR.State), zap.Any("roomEffectivePlayerCount", pR.EffectivePlayerCount)) Logger.Warn("ReAddPlayerIfPossible error due to player nonexistent for room:", zap.Any("playerId", playerId), zap.Any("roomId", pR.Id), zap.Any("roomState", pR.State), zap.Any("roomEffectivePlayerCount", pR.EffectivePlayerCount))
return false return Constants.RetCode.PlayerNotReaddableToRoom
} }
/* /*
* WARNING: The "pTmpPlayerInstance *Player" used here is a temporarily constructed * WARNING: The "pTmpPlayerInstance *Player" used here is a temporarily constructed
@@ -231,7 +237,7 @@ func (pR *Room) ReAddPlayerIfPossible(pTmpPlayerInstance *Player, session *webso
pEffectiveInRoomPlayerInstance.AckingFrameId = -1 pEffectiveInRoomPlayerInstance.AckingFrameId = -1
pEffectiveInRoomPlayerInstance.AckingInputFrameId = -1 pEffectiveInRoomPlayerInstance.AckingInputFrameId = -1
pEffectiveInRoomPlayerInstance.LastSentInputFrameId = MAGIC_LAST_SENT_INPUT_FRAME_ID_READDED pEffectiveInRoomPlayerInstance.LastSentInputFrameId = MAGIC_LAST_SENT_INPUT_FRAME_ID_READDED
// [WARNING] DON'T reset "player.LastReceivedInputFrameId" & "player.LastUdpReceivedInputFrameId" upon reconnection! // [WARNING] DON'T reset "player.LastConsecutiveRecvInputFrameId" & "pR.LastIndividuallyConfirmedInputFrameId[...]" upon reconnection!
pEffectiveInRoomPlayerInstance.BattleState = PlayerBattleStateIns.READDED_PENDING_BATTLE_COLLIDER_ACK pEffectiveInRoomPlayerInstance.BattleState = PlayerBattleStateIns.READDED_PENDING_BATTLE_COLLIDER_ACK
pEffectiveInRoomPlayerInstance.ColliderRadius = DEFAULT_PLAYER_RADIUS // Hardcoded pEffectiveInRoomPlayerInstance.ColliderRadius = DEFAULT_PLAYER_RADIUS // Hardcoded
@@ -245,7 +251,7 @@ func (pR *Room) ReAddPlayerIfPossible(pTmpPlayerInstance *Player, session *webso
}) // For ReAdded player the new watchdog starts immediately }) // For ReAdded player the new watchdog starts immediately
Logger.Warn("ReAddPlayerIfPossible finished.", zap.Any("roomId", pR.Id), zap.Any("playerId", playerId), zap.Any("joinIndex", pEffectiveInRoomPlayerInstance.JoinIndex), zap.Any("playerBattleState", pEffectiveInRoomPlayerInstance.BattleState), zap.Any("roomState", pR.State), zap.Any("roomEffectivePlayerCount", pR.EffectivePlayerCount), zap.Any("AckingFrameId", pEffectiveInRoomPlayerInstance.AckingFrameId), zap.Any("AckingInputFrameId", pEffectiveInRoomPlayerInstance.AckingInputFrameId), zap.Any("LastSentInputFrameId", pEffectiveInRoomPlayerInstance.LastSentInputFrameId)) Logger.Warn("ReAddPlayerIfPossible finished.", zap.Any("roomId", pR.Id), zap.Any("playerId", playerId), zap.Any("joinIndex", pEffectiveInRoomPlayerInstance.JoinIndex), zap.Any("playerBattleState", pEffectiveInRoomPlayerInstance.BattleState), zap.Any("roomState", pR.State), zap.Any("roomEffectivePlayerCount", pR.EffectivePlayerCount), zap.Any("AckingFrameId", pEffectiveInRoomPlayerInstance.AckingFrameId), zap.Any("AckingInputFrameId", pEffectiveInRoomPlayerInstance.AckingInputFrameId), zap.Any("LastSentInputFrameId", pEffectiveInRoomPlayerInstance.LastSentInputFrameId))
return true return Constants.RetCode.Ok
} }
func (pR *Room) ChooseStage() error { func (pR *Room) ChooseStage() error {
@@ -400,6 +406,9 @@ func (pR *Room) rdfIdToActuallyUsedInputString() string {
} }
fireballsStrBldr := make([]string, 0, len(rdf.FireballBullets)) fireballsStrBldr := make([]string, 0, len(rdf.FireballBullets))
for _, fireball := range rdf.FireballBullets { for _, fireball := range rdf.FireballBullets {
if 0 > fireball.BattleAttr.BulletLocalId {
break
}
fireballsStrBldr = append(fireballsStrBldr, pR.fireballDownsyncStr(fireball)) fireballsStrBldr = append(fireballsStrBldr, pR.fireballDownsyncStr(fireball))
} }
s = append(s, fmt.Sprintf("rdfId:%d\nplayers:[%v]\nfireballs:[%v]\nactuallyUsedinputList:{%v}", rdfId, strings.Join(playersStrBldr, ","), strings.Join(fireballsStrBldr, ","), pR.inputFrameDownsyncStr(pR.rdfIdToActuallyUsedInput[rdfId]))) s = append(s, fmt.Sprintf("rdfId:%d\nplayers:[%v]\nfireballs:[%v]\nactuallyUsedinputList:{%v}", rdfId, strings.Join(playersStrBldr, ","), strings.Join(fireballsStrBldr, ","), pR.inputFrameDownsyncStr(pR.rdfIdToActuallyUsedInput[rdfId])))
@@ -416,24 +425,14 @@ func (pR *Room) StartBattle() {
pR.RenderFrameId = 0 pR.RenderFrameId = 0
for _, player := range pR.Players {
speciesId := int(player.JoinIndex - 1) // FIXME: Hardcoded the values for now
if player.JoinIndex == 1 {
speciesId = 4096
}
chosenCh := battle.Characters[speciesId]
pR.CharacterConfigsArr[player.JoinIndex-1] = chosenCh
pR.SpeciesIdList[player.JoinIndex-1] = int32(speciesId)
}
Logger.Info("[StartBattle] ", zap.Any("roomId", pR.Id), zap.Any("roomState", pR.State), zap.Any("SpeciesIdList", pR.SpeciesIdList)) Logger.Info("[StartBattle] ", zap.Any("roomId", pR.Id), zap.Any("roomState", pR.State), zap.Any("SpeciesIdList", pR.SpeciesIdList))
// Initialize the "collisionSys" as well as "RenderFrameBuffer" // Initialize the "collisionSys" as well as "RenderFrameBuffer"
pR.CurDynamicsRenderFrameId = 0 pR.CurDynamicsRenderFrameId = 0
kickoffFrameJs := &battle.RoomDownsyncFrame{ kickoffFrameJs := battle.NewPreallocatedRoomDownsyncFrame(len(pR.Players), 64, 64)
Id: pR.RenderFrameId, battle.CloneRoomDownsyncFrame(pR.RenderFrameId, toJsPlayers(pR.Players), 0, make([]*battle.MeleeBullet, 0), make([]*battle.FireballBullet, 0), kickoffFrameJs)
PlayersArr: toJsPlayers(pR.Players), kickoffFrameJs.CountdownNanos = pR.BattleDurationNanos
CountdownNanos: pR.BattleDurationNanos,
}
pR.RenderFrameBuffer.Put(kickoffFrameJs) pR.RenderFrameBuffer.Put(kickoffFrameJs)
// Refresh "Colliders" // Refresh "Colliders"
@@ -487,7 +486,7 @@ func (pR *Room) StartBattle() {
*/ */
totalElapsedNanos := utils.UnixtimeNano() - battleStartedAt totalElapsedNanos := utils.UnixtimeNano() - battleStartedAt
nextRenderFrameId := int32((totalElapsedNanos + pR.dilutedRollbackEstimatedDtNanos - 1) / pR.dilutedRollbackEstimatedDtNanos) // fast ceiling nextRenderFrameId := int32((totalElapsedNanos + pR.dilutedRollbackEstimatedDtNanos - 1) / pR.dilutedRollbackEstimatedDtNanos) // fast ceiling
toSleepNanos := int64(0) toSleepNanos := int64(pR.dilutedRollbackEstimatedDtNanos >> 1) // Sleep half-frame time by default
if nextRenderFrameId > pR.RenderFrameId { if nextRenderFrameId > pR.RenderFrameId {
if 0 == pR.RenderFrameId { if 0 == pR.RenderFrameId {
// It's important to send kickoff frame iff "0 == pR.RenderFrameId && nextRenderFrameId > pR.RenderFrameId", otherwise it might send duplicate kickoff frames // It's important to send kickoff frame iff "0 == pR.RenderFrameId && nextRenderFrameId > pR.RenderFrameId", otherwise it might send duplicate kickoff frames
@@ -519,7 +518,7 @@ func (pR *Room) StartBattle() {
pR.LastRenderFrameIdTriggeredAt = utils.UnixtimeNano() pR.LastRenderFrameIdTriggeredAt = utils.UnixtimeNano()
elapsedInCalculation := (utils.UnixtimeNano() - stCalculation) elapsedInCalculation := (utils.UnixtimeNano() - stCalculation)
toSleepNanos = pR.dilutedRollbackEstimatedDtNanos - elapsedInCalculation // don't sleep if "nextRenderFrame == pR.RenderFrameId" toSleepNanos = pR.dilutedRollbackEstimatedDtNanos - elapsedInCalculation
if elapsedInCalculation > pR.RollbackEstimatedDtNanos { if elapsedInCalculation > pR.RollbackEstimatedDtNanos {
Logger.Warn(fmt.Sprintf("SLOW FRAME! Elapsed time statistics: roomId=%v, room.RenderFrameId=%v, elapsedInCalculation=%v ns, dynamicsDuration=%v ns, RollbackEstimatedDtNanos=%v, dilutedRollbackEstimatedDtNanos=%v", pR.Id, pR.RenderFrameId, elapsedInCalculation, dynamicsDuration, pR.RollbackEstimatedDtNanos, pR.dilutedRollbackEstimatedDtNanos)) Logger.Warn(fmt.Sprintf("SLOW FRAME! Elapsed time statistics: roomId=%v, room.RenderFrameId=%v, elapsedInCalculation=%v ns, dynamicsDuration=%v ns, RollbackEstimatedDtNanos=%v, dilutedRollbackEstimatedDtNanos=%v", pR.Id, pR.RenderFrameId, elapsedInCalculation, dynamicsDuration, pR.RollbackEstimatedDtNanos, pR.dilutedRollbackEstimatedDtNanos))
} }
@@ -548,13 +547,13 @@ func (pR *Room) StartBattle() {
} }
select { select {
// [WARNING] DON'T put a "default" block here! Otherwise "for { select {... default: } }" pattern would NEVER block on empty channel and thus consume a lot of CPU time unnecessarily!
case inputsBufferSnapshot := <-playerDownsyncChan: case inputsBufferSnapshot := <-playerDownsyncChan:
pR.downsyncToSinglePlayer(playerId, player, inputsBufferSnapshot.RefRenderFrameId, inputsBufferSnapshot.UnconfirmedMask, inputsBufferSnapshot.ToSendInputFrameDownsyncs, inputsBufferSnapshot.ShouldForceResync) pR.downsyncToSinglePlayer(playerId, player, inputsBufferSnapshot.RefRenderFrameId, inputsBufferSnapshot.UnconfirmedMask, inputsBufferSnapshot.ToSendInputFrameDownsyncs, inputsBufferSnapshot.ShouldForceResync)
//Logger.Info(fmt.Sprintf("Sent inputsBufferSnapshot(refRenderFrameId:%d, unconfirmedMask:%v) to for (roomId: %d, playerId:%d)#2", inputsBufferSnapshot.RefRenderFrameId, inputsBufferSnapshot.UnconfirmedMask, pR.Id, playerId)) //Logger.Info(fmt.Sprintf("Sent inputsBufferSnapshot(refRenderFrameId:%d, unconfirmedMask:%v) to for (roomId: %d, playerId:%d)#2", inputsBufferSnapshot.RefRenderFrameId, inputsBufferSnapshot.UnconfirmedMask, pR.Id, playerId))
case inputsBufferSnapshot2 := <-playerSecondaryDownsyncChan: case inputsBufferSnapshot2 := <-playerSecondaryDownsyncChan:
pR.downsyncPeerInputFrameUpsyncToSinglePlayer(playerId, player, inputsBufferSnapshot2.ToSendInputFrameDownsyncs, inputsBufferSnapshot2.PeerJoinIndex) 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)) //Logger.Info(fmt.Sprintf("Sent secondary inputsBufferSnapshot to for (roomId: %d, playerId:%d)#2", pR.Id, playerId))
default:
} }
} }
} }
@@ -781,7 +780,7 @@ func (pR *Room) OnDismissed() {
// Always instantiates new HeapRAM blocks and let the old blocks die out due to not being retained by any root reference. // Always instantiates new HeapRAM blocks and let the old blocks die out due to not being retained by any root reference.
pR.BulletBattleLocalIdCounter = 0 pR.BulletBattleLocalIdCounter = 0
pR.CollisionMinStep = 8 // the approx minimum distance a player can move per frame in world coordinate pR.CollisionMinStep = 16 // the approx minimum distance a player can move per frame in world coordinate
pR.Players = make(map[int32]*Player) pR.Players = make(map[int32]*Player)
pR.PlayersArr = make([]*Player, pR.Capacity) pR.PlayersArr = make([]*Player, pR.Capacity)
pR.SpeciesIdList = make([]int32, pR.Capacity) pR.SpeciesIdList = make([]int32, pR.Capacity)
@@ -805,9 +804,13 @@ func (pR *Room) OnDismissed() {
pR.PlayerSecondarySignalToCloseDict = make(map[int32]SignalToCloseConnCbType) pR.PlayerSecondarySignalToCloseDict = make(map[int32]SignalToCloseConnCbType)
pR.JoinIndexBooleanArr = make([]bool, pR.Capacity) pR.JoinIndexBooleanArr = make([]bool, pR.Capacity)
pR.RenderCacheSize = 1024 pR.RenderCacheSize = 1024
pR.RenderFrameBuffer = battle.NewRingBuffer(pR.RenderCacheSize) pR.RenderFrameBuffer = resolv.NewRingBuffer(pR.RenderCacheSize)
pR.InputsBuffer = battle.NewRingBuffer((pR.RenderCacheSize >> 1) + 1) pR.InputsBuffer = resolv.NewRingBuffer((pR.RenderCacheSize >> 1) + 1)
pR.rdfIdToActuallyUsedInput = make(map[int32]*pb.InputFrameDownsync) pR.rdfIdToActuallyUsedInput = make(map[int32]*pb.InputFrameDownsync)
pR.LastIndividuallyConfirmedInputFrameId = make([]int32, pR.Capacity)
for i := 0; i < pR.Capacity; i++ {
pR.LastIndividuallyConfirmedInputFrameId[i] = MAGIC_LAST_SENT_INPUT_FRAME_ID_NORMAL_ADDED
}
pR.LastIndividuallyConfirmedInputList = make([]uint64, pR.Capacity) pR.LastIndividuallyConfirmedInputList = make([]uint64, pR.Capacity)
pR.LatestPlayerUpsyncedInputFrameId = -1 pR.LatestPlayerUpsyncedInputFrameId = -1
@@ -819,6 +822,24 @@ func (pR *Room) OnDismissed() {
pR.CurDynamicsRenderFrameId = 0 pR.CurDynamicsRenderFrameId = 0
pR.NstDelayFrames = 24 pR.NstDelayFrames = 24
pR.collisionHolder = resolv.NewCollision()
pR.effPushbacks = make([]*battle.Vec2D, pR.Capacity)
for i := 0; i < pR.Capacity; i++ {
pR.effPushbacks[i] = &battle.Vec2D{X: 0, Y: 0}
}
pR.hardPushbackNormsArr = make([][]*battle.Vec2D, pR.Capacity)
for i := 0; i < pR.Capacity; i++ {
pR.hardPushbackNormsArr[i] = make([]*battle.Vec2D, 5)
for j := 0; j < len(pR.hardPushbackNormsArr[i]); j++ {
pR.hardPushbackNormsArr[i][j] = &battle.Vec2D{X: 0, Y: 0}
}
}
pR.jumpedOrNotList = make([]bool, pR.Capacity)
pR.dynamicRectangleColliders = make([]*resolv.Object, 64)
for i := 0; i < len(pR.dynamicRectangleColliders); i++ {
pR.dynamicRectangleColliders[i] = battle.GenerateRectCollider(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, nil, "")
}
serverFps := 60 serverFps := 60
pR.RollbackEstimatedDtMillis = 16.667 // Use fixed-and-low-precision to mitigate the inconsistent floating-point-number issue between Golang and JavaScript pR.RollbackEstimatedDtMillis = 16.667 // Use fixed-and-low-precision to mitigate the inconsistent floating-point-number issue between Golang and JavaScript
pR.RollbackEstimatedDtNanos = 16666666 // A little smaller than the actual per frame time, just for logging FAST FRAME pR.RollbackEstimatedDtNanos = 16666666 // A little smaller than the actual per frame time, just for logging FAST FRAME
@@ -954,7 +975,7 @@ func (pR *Room) clearPlayerNetworkSession(playerId int32) {
} }
} }
func (pR *Room) onPlayerAdded(playerId int32) { func (pR *Room) onPlayerAdded(playerId int32, speciesId int) {
pR.EffectivePlayerCount++ pR.EffectivePlayerCount++
if 1 == pR.EffectivePlayerCount { if 1 == pR.EffectivePlayerCount {
@@ -966,8 +987,9 @@ func (pR *Room) onPlayerAdded(playerId int32) {
pR.Players[playerId].JoinIndex = int32(index) + 1 pR.Players[playerId].JoinIndex = int32(index) + 1
pR.JoinIndexBooleanArr[index] = true pR.JoinIndexBooleanArr[index] = true
speciesId := index // FIXME pR.SpeciesIdList[index] = int32(speciesId)
chosenCh := battle.Characters[speciesId] chosenCh := battle.Characters[speciesId]
pR.CharacterConfigsArr[index] = chosenCh
pR.Players[playerId].Speed = chosenCh.Speed pR.Players[playerId].Speed = chosenCh.Speed
// Lazily assign the initial position of "Player" for "RoomDownsyncFrame". // Lazily assign the initial position of "Player" for "RoomDownsyncFrame".
@@ -980,7 +1002,10 @@ func (pR *Room) onPlayerAdded(playerId int32) {
if nil == playerPos { if nil == playerPos {
panic(fmt.Sprintf("onPlayerAdded error, nil == playerPos, roomId=%v, playerId=%v, roomState=%v, roomEffectivePlayerCount=%v", pR.Id, playerId, pR.State, pR.EffectivePlayerCount)) panic(fmt.Sprintf("onPlayerAdded error, nil == playerPos, roomId=%v, playerId=%v, roomState=%v, roomEffectivePlayerCount=%v", pR.Id, playerId, pR.State, pR.EffectivePlayerCount))
} }
pR.Players[playerId].VirtualGridX, pR.Players[playerId].VirtualGridY = battle.WorldToVirtualGridPos(playerPos.X, playerPos.Y) pR.Players[playerId].RevivalVirtualGridX, pR.Players[playerId].RevivalVirtualGridY = battle.WorldToVirtualGridPos(playerPos.X, playerPos.Y)
pR.Players[playerId].VirtualGridX, pR.Players[playerId].VirtualGridY = pR.Players[playerId].RevivalVirtualGridX, pR.Players[playerId].RevivalVirtualGridY
pR.Players[playerId].MaxHp = 100 // Hardcoded for now
pR.Players[playerId].Hp = pR.Players[playerId].MaxHp
// Hardcoded initial character orientation/facing // Hardcoded initial character orientation/facing
if 0 == (pR.Players[playerId].JoinIndex % 2) { if 0 == (pR.Players[playerId].JoinIndex % 2) {
pR.Players[playerId].DirX = -2 pR.Players[playerId].DirX = -2
@@ -1172,9 +1197,10 @@ func (pR *Room) markConfirmationIfApplicable(inputFrameUpsyncBatch []*pb.InputFr
Logger.Debug(fmt.Sprintf("Omitting obsolete inputFrameUpsync#1: roomId=%v, playerId=%v, clientInputFrameId=%v, InputsBuffer=%v", pR.Id, playerId, clientInputFrameId, pR.InputsBufferString(false))) Logger.Debug(fmt.Sprintf("Omitting obsolete inputFrameUpsync#1: roomId=%v, playerId=%v, clientInputFrameId=%v, InputsBuffer=%v", pR.Id, playerId, clientInputFrameId, pR.InputsBufferString(false)))
continue continue
} }
if clientInputFrameId < player.LastReceivedInputFrameId { if clientInputFrameId < player.LastConsecutiveRecvInputFrameId {
// [WARNING] It's important for correctness that we use "player.LastReceivedInputFrameId" instead of "player.LastUdpReceivedInputFrameId" here! // [WARNING] It's important for correctness that we use "player.LastConsecutiveRecvInputFrameId" instead of "pR.LastIndividuallyConfirmedInputFrameId[player.JoinIndex-1]" here!
Logger.Debug(fmt.Sprintf("Omitting obsolete inputFrameUpsync#2: roomId=%v, playerId=%v, clientInputFrameId=%v, playerLastReceivedInputFrameId=%v, InputsBuffer=%v", pR.Id, playerId, clientInputFrameId, player.LastReceivedInputFrameId, pR.InputsBufferString(false))) //Logger.Debug(fmt.Sprintf("Omitting obsolete inputFrameUpsync#2: roomId=%v, playerId=%v, clientInputFrameId=%v, playerLastConsecutiveRecvInputFrameId=%v, InputsBuffer=%v", pR.Id, playerId, clientInputFrameId, player.LastConsecutiveRecvInputFrameId, pR.InputsBufferString(false)))
Logger.Debug(fmt.Sprintf("Omitting obsolete inputFrameUpsync#2: roomId=%v, playerId=%v, clientInputFrameId=%v, playerLastConsecutiveRecvInputFrameId=%v", pR.Id, playerId, clientInputFrameId, player.LastConsecutiveRecvInputFrameId))
continue continue
} }
if clientInputFrameId > pR.InputsBuffer.EdFrameId { if clientInputFrameId > pR.InputsBuffer.EdFrameId {
@@ -1187,22 +1213,22 @@ func (pR *Room) markConfirmationIfApplicable(inputFrameUpsyncBatch []*pb.InputFr
targetInputFrameDownsync.ConfirmedList |= uint64(1 << uint32(player.JoinIndex-1)) targetInputFrameDownsync.ConfirmedList |= uint64(1 << uint32(player.JoinIndex-1))
if false == fromUDP { if false == fromUDP {
/* /**
[WARNING] We have to distinguish whether or not the incoming batch is from UDP here, otherwise "pR.LatestPlayerUpsyncedInputFrameId - pR.LastAllConfirmedInputFrameId" might become unexpectedly large in case of "UDP packet loss + slow ws session"! [WARNING] We have to distinguish whether or not the incoming batch is from UDP here, otherwise "pR.LatestPlayerUpsyncedInputFrameId - pR.LastAllConfirmedInputFrameId" might become unexpectedly large in case of "UDP packet loss + slow ws session"!
Moreover, only ws session upsyncs should advance "player.LastReceivedInputFrameId" & "pR.LatestPlayerUpsyncedInputFrameId". Moreover, only ws session upsyncs should advance "player.LastConsecutiveRecvInputFrameId" & "pR.LatestPlayerUpsyncedInputFrameId".
Kindly note that the updates of "player.LastReceivedInputFrameId" could be discrete before and after reconnection. Kindly note that the updates of "player.LastConsecutiveRecvInputFrameId" could be discrete before and after reconnection.
*/ */
player.LastReceivedInputFrameId = clientInputFrameId player.LastConsecutiveRecvInputFrameId = clientInputFrameId
if clientInputFrameId > pR.LatestPlayerUpsyncedInputFrameId { if clientInputFrameId > pR.LatestPlayerUpsyncedInputFrameId {
pR.LatestPlayerUpsyncedInputFrameId = clientInputFrameId pR.LatestPlayerUpsyncedInputFrameId = clientInputFrameId
} }
} }
if clientInputFrameId > player.LastUdpReceivedInputFrameId { if clientInputFrameId > pR.LastIndividuallyConfirmedInputFrameId[player.JoinIndex-1] {
// No need to update "player.LastUdpReceivedInputFrameId" only when "true == fromUDP", we should keep "player.LastUdpReceivedInputFrameId >= player.LastReceivedInputFrameId" at any moment. // No need to update "pR.LastIndividuallyConfirmedInputFrameId[player.JoinIndex-1]" only when "true == fromUDP", we should keep "pR.LastIndividuallyConfirmedInputFrameId[player.JoinIndex-1] >= player.LastConsecutiveRecvInputFrameId" at any moment.
player.LastUdpReceivedInputFrameId = clientInputFrameId pR.LastIndividuallyConfirmedInputFrameId[player.JoinIndex-1] = clientInputFrameId
// It's safe (in terms of getting an eventually correct "RenderFrameBuffer") to put the following update of "pR.LastIndividuallyConfirmedInputList" which is ONLY used for prediction in "InputsBuffer" out of "false == fromUDP" block. // It's safe (in terms of getting an eventually correct "RenderFrameBuffer") to put the following update of "pR.LastIndividuallyConfirmedInputList" which is ONLY used for prediction in "InputsBuffer" out of "false == fromUDP" block.
pR.LastIndividuallyConfirmedInputList[player.JoinIndex-1] = inputFrameUpsync.Encoded pR.LastIndividuallyConfirmedInputList[player.JoinIndex-1] = inputFrameUpsync.Encoded
} }
@@ -1232,7 +1258,7 @@ func (pR *Room) markConfirmationIfApplicable(inputFrameUpsyncBatch []*pb.InputFr
shouldBreakConfirmation = true // Could be an `ACTIVE SLOW TICKER` here, but no action needed for now shouldBreakConfirmation = true // Could be an `ACTIVE SLOW TICKER` here, but no action needed for now
break break
} }
Logger.Debug(fmt.Sprintf("markConfirmationIfApplicable for roomId=%v, skipping UNCONFIRMED BUT INACTIVE player(id:%v, joinIndex:%v) while checking inputFrameId=[%v, %v): InputsBuffer=%v", pR.Id, player.Id, player.JoinIndex, inputFrameId1, pR.InputsBuffer.EdFrameId, pR.InputsBufferString(false))) //Logger.Debug(fmt.Sprintf("markConfirmationIfApplicable for roomId=%v, skipping UNCONFIRMED BUT INACTIVE player(id:%v, joinIndex:%v) while checking inputFrameId=[%v, %v): InputsBuffer=%v", pR.Id, player.Id, player.JoinIndex, inputFrameId1, pR.InputsBuffer.EdFrameId, pR.InputsBufferString(false)))
} }
} }
@@ -1256,7 +1282,7 @@ func (pR *Room) markConfirmationIfApplicable(inputFrameUpsyncBatch []*pb.InputFr
snapshotStFrameId := (pR.LastAllConfirmedInputFrameId - newAllConfirmedCount) snapshotStFrameId := (pR.LastAllConfirmedInputFrameId - newAllConfirmedCount)
refRenderFrameIdIfNeeded := pR.CurDynamicsRenderFrameId - 1 refRenderFrameIdIfNeeded := pR.CurDynamicsRenderFrameId - 1
refSnapshotStFrameId := battle.ConvertToDelayedInputFrameId(refRenderFrameIdIfNeeded) refSnapshotStFrameId := battle.ConvertToDelayedInputFrameId(refRenderFrameIdIfNeeded)
if refSnapshotStFrameId < snapshotStFrameId { if pR.BackendDynamicsEnabled && refSnapshotStFrameId < snapshotStFrameId {
snapshotStFrameId = refSnapshotStFrameId snapshotStFrameId = refSnapshotStFrameId
} }
Logger.Debug(fmt.Sprintf("markConfirmationIfApplicable for roomId=%v returning newAllConfirmedCount=%d: InputsBuffer=%v", pR.Id, newAllConfirmedCount, pR.InputsBufferString(false))) Logger.Debug(fmt.Sprintf("markConfirmationIfApplicable for roomId=%v returning newAllConfirmedCount=%d: InputsBuffer=%v", pR.Id, newAllConfirmedCount, pR.InputsBufferString(false)))
@@ -1286,7 +1312,7 @@ func (pR *Room) forceConfirmationIfApplicable(prevRenderFrameId int32) uint64 {
pR.onInputFrameDownsyncAllConfirmed(inputFrameDownsync, -1) pR.onInputFrameDownsyncAllConfirmed(inputFrameDownsync, -1)
} }
if 0 < unconfirmedMask { if 0 < unconfirmedMask {
Logger.Info(fmt.Sprintf("[type#1 forceConfirmation] For roomId=%d@renderFrameId=%d, curDynamicsRenderFrameId=%d, LatestPlayerUpsyncedInputFrameId:%d, oldLastAllConfirmedInputFrameId:%d, newLastAllConfirmedInputFrameId:%d, InputFrameUpsyncDelayTolerance:%d, unconfirmedMask=%d; there's a slow ticker suspect, forcing all-confirmation", pR.Id, pR.RenderFrameId, pR.CurDynamicsRenderFrameId, pR.LatestPlayerUpsyncedInputFrameId, oldLastAllConfirmedInputFrameId, pR.LastAllConfirmedInputFrameId, pR.InputFrameUpsyncDelayTolerance, unconfirmedMask)) Logger.Info(fmt.Sprintf("[type#1 forceConfirmation] For roomId=%d@renderFrameId=%d, curDynamicsRenderFrameId=%d, LatestPlayerUpsyncedInputFrameId:%d, LastAllConfirmedInputFrameId:%d -> %d, InputFrameUpsyncDelayTolerance:%d, unconfirmedMask=%d; there's a slow ticker suspect, forcing all-confirmation", pR.Id, pR.RenderFrameId, pR.CurDynamicsRenderFrameId, pR.LatestPlayerUpsyncedInputFrameId, oldLastAllConfirmedInputFrameId, pR.LastAllConfirmedInputFrameId, pR.InputFrameUpsyncDelayTolerance, unconfirmedMask))
} }
} else { } else {
// Type#2 helps resolve the edge case when all players are disconnected temporarily // Type#2 helps resolve the edge case when all players are disconnected temporarily
@@ -1310,7 +1336,7 @@ func (pR *Room) forceConfirmationIfApplicable(prevRenderFrameId int32) uint64 {
func (pR *Room) produceInputsBufferSnapshotWithCurDynamicsRenderFrameAsRef(unconfirmedMask uint64, snapshotStFrameId, snapshotEdFrameId int32) *pb.InputsBufferSnapshot { func (pR *Room) produceInputsBufferSnapshotWithCurDynamicsRenderFrameAsRef(unconfirmedMask uint64, snapshotStFrameId, snapshotEdFrameId int32) *pb.InputsBufferSnapshot {
// [WARNING] This function MUST BE called while "pR.InputsBufferLock" is locked! // [WARNING] This function MUST BE called while "pR.InputsBufferLock" is locked!
refRenderFrameIdIfNeeded := pR.CurDynamicsRenderFrameId - 1 refRenderFrameIdIfNeeded := pR.CurDynamicsRenderFrameId - 1
if 0 > refRenderFrameIdIfNeeded { if pR.BackendDynamicsEnabled && 0 > refRenderFrameIdIfNeeded {
return nil return nil
} }
// Duplicate downsynced inputFrameIds will be filtered out by frontend. // Duplicate downsynced inputFrameIds will be filtered out by frontend.
@@ -1361,8 +1387,7 @@ func (pR *Room) applyInputFrameDownsyncDynamics(fromRenderFrameId int32, toRende
} }
} }
nextRenderFrame := battle.ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(pR.InputsBuffer, currRenderFrame, pR.Space, pR.CollisionSysMap, pR.SpaceOffsetX, pR.SpaceOffsetY, pR.CharacterConfigsArr) battle.ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(pR.InputsBuffer, currRenderFrame.Id, pR.Space, pR.CollisionSysMap, pR.SpaceOffsetX, pR.SpaceOffsetY, pR.CharacterConfigsArr, pR.RenderFrameBuffer, pR.collisionHolder, pR.effPushbacks, pR.hardPushbackNormsArr, pR.jumpedOrNotList, pR.dynamicRectangleColliders, pR.LastIndividuallyConfirmedInputFrameId, pR.LastIndividuallyConfirmedInputList, false, MAGIC_JOIN_INDEX_INVALID) // DON'T mutate inputs upon dynamics on backend to avoid complicating the edge cases
pR.RenderFrameBuffer.Put(nextRenderFrame)
pR.CurDynamicsRenderFrameId++ pR.CurDynamicsRenderFrameId++
} }
} }
@@ -1513,6 +1538,7 @@ func (pR *Room) downsyncToAllPlayers(inputsBufferSnapshot *pb.InputsBufferSnapsh
break break
} }
} }
} }
for _, player := range pR.PlayersArr { for _, player := range pR.PlayersArr {
@@ -1529,11 +1555,16 @@ func (pR *Room) downsyncToAllPlayers(inputsBufferSnapshot *pb.InputsBufferSnapsh
if playerDownsyncChan, existent := pR.PlayerDownsyncChanDict[player.Id]; existent { if playerDownsyncChan, existent := pR.PlayerDownsyncChanDict[player.Id]; existent {
playerDownsyncChan <- (*inputsBufferSnapshot) playerDownsyncChan <- (*inputsBufferSnapshot)
//Logger.Info(fmt.Sprintf("Sent inputsBufferSnapshot(refRenderFrameId:%d, unconfirmedMask:%v) to for (roomId: %d, playerId:%d, playerDownsyncChan:%p)#1", inputsBufferSnapshot.RefRenderFrameId, inputsBufferSnapshot.UnconfirmedMask, pR.Id, player.Id, playerDownsyncChan)) //Logger.Info(fmt.Sprintf("Sent inputsBufferSnapshot{refRenderFrameId:%d, unconfirmedMask:%v} to {roomId: %d, playerId:%d, playerDownsyncChan:%p}#1", inputsBufferSnapshot.RefRenderFrameId, inputsBufferSnapshot.UnconfirmedMask, pR.Id, player.Id, playerDownsyncChan))
} else { } else {
Logger.Warn(fmt.Sprintf("playerDownsyncChan for (roomId: %d, playerId:%d) is gone", pR.Id, player.Id)) Logger.Warn(fmt.Sprintf("playerDownsyncChan for (roomId: %d, playerId:%d) is gone", pR.Id, player.Id))
} }
} }
/*
toSendInputFrameDownsyncs := inputsBufferSnapshot.ToSendInputFrameDownsyncs
toSendInputFrameIdSt, toSendInputFrameIdEd := toSendInputFrameDownsyncs[0].InputFrameId, toSendInputFrameDownsyncs[len(toSendInputFrameDownsyncs)-1].InputFrameId+1
Logger.Info(fmt.Sprintf("Sent inputsBufferSnapshot{refRenderFrameId:%d, unconfirmedMask:%v, inputFrameIdRange:[%d, %d)} to {roomId: %d}", inputsBufferSnapshot.RefRenderFrameId, inputsBufferSnapshot.UnconfirmedMask, toSendInputFrameIdSt, toSendInputFrameIdEd, pR.Id))
*/
} }
func (pR *Room) downsyncToSinglePlayer(playerId int32, player *Player, refRenderFrameId int32, unconfirmedMask uint64, toSendInputFrameDownsyncsSnapshot []*pb.InputFrameDownsync, shouldForceResync bool) { func (pR *Room) downsyncToSinglePlayer(playerId int32, player *Player, refRenderFrameId int32, unconfirmedMask uint64, toSendInputFrameDownsyncsSnapshot []*pb.InputFrameDownsync, shouldForceResync bool) {
@@ -1576,9 +1607,10 @@ func (pR *Room) downsyncToSinglePlayer(playerId int32, player *Player, refRender
pbRefRenderFrame := toPbRoomDownsyncFrame(refRenderFrame) pbRefRenderFrame := toPbRoomDownsyncFrame(refRenderFrame)
pbRefRenderFrame.SpeciesIdList = pR.SpeciesIdList pbRefRenderFrame.SpeciesIdList = pR.SpeciesIdList
pR.sendSafely(pbRefRenderFrame, toSendInputFrameDownsyncsSnapshot, DOWNSYNC_MSG_ACT_FORCED_RESYNC, playerId, false, MAGIC_JOIN_INDEX_DEFAULT) pR.sendSafely(pbRefRenderFrame, toSendInputFrameDownsyncsSnapshot, DOWNSYNC_MSG_ACT_FORCED_RESYNC, playerId, false, MAGIC_JOIN_INDEX_DEFAULT)
//Logger.Warn(fmt.Sprintf("Sent refRenderFrameId=%v & inputFrameIds [%d, %d), for roomId=%v, playerId=%d, playerJoinIndex=%d, renderFrameId=%d, curDynamicsRenderFrameId=%d, playerLastSentInputFrameId=%d: InputsBuffer=%v", refRenderFrameId, toSendInputFrameIdSt, toSendInputFrameIdEd, pR.Id, playerId, player.JoinIndex, pR.RenderFrameId, pR.CurDynamicsRenderFrameId, player.LastSentInputFrameId, pR.InputsBufferString(false)))
if shouldResync1 || shouldResync3 { if shouldResync1 || shouldResync3 {
Logger.Debug(fmt.Sprintf("Sent refRenderFrameId=%v & inputFrameIds [%d, %d), for roomId=%v, playerId=%d, playerJoinIndex=%d, renderFrameId=%d, curDynamicsRenderFrameId=%d, playerLastSentInputFrameId=%d: shouldResync1=%v, shouldResync2=%v, shouldResync3=%v, playerBattleState=%d", refRenderFrameId, toSendInputFrameIdSt, toSendInputFrameIdEd, pR.Id, playerId, player.JoinIndex, pR.RenderFrameId, pR.CurDynamicsRenderFrameId, player.LastSentInputFrameId, shouldResync1, shouldResync2, shouldResync3, playerBattleState)) Logger.Debug(fmt.Sprintf("Sent refRenderFrameId=%v & inputFrameIds [%d, %d), for roomId=%v, playerId=%d, playerJoinIndex=%d, renderFrameId=%d, curDynamicsRenderFrameId=%d, playerLastSentInputFrameId=%d: shouldResync1=%v, shouldResync2=%v, shouldResync3=%v, playerBattleState=%d", refRenderFrameId, toSendInputFrameIdSt, toSendInputFrameIdEd, pR.Id, playerId, player.JoinIndex, pR.RenderFrameId, pR.CurDynamicsRenderFrameId, player.LastSentInputFrameId, shouldResync1, shouldResync2, shouldResync3, playerBattleState))
} else {
//Logger.Debug(fmt.Sprintf("Sent refRenderFrameId=%v & inputFrameIds [%d, %d), for roomId=%v, playerId=%d, playerJoinIndex=%d, renderFrameId=%d, curDynamicsRenderFrameId=%d, playerLastSentInputFrameId=%d: InputsBuffer=%v", refRenderFrameId, toSendInputFrameIdSt, toSendInputFrameIdEd, pR.Id, playerId, player.JoinIndex, pR.RenderFrameId, pR.CurDynamicsRenderFrameId, player.LastSentInputFrameId, pR.InputsBufferString(false)))
} }
} else { } else {
pR.sendSafely(nil, toSendInputFrameDownsyncsSnapshot, DOWNSYNC_MSG_ACT_INPUT_BATCH, playerId, false, MAGIC_JOIN_INDEX_DEFAULT) pR.sendSafely(nil, toSendInputFrameDownsyncsSnapshot, DOWNSYNC_MSG_ACT_INPUT_BATCH, playerId, false, MAGIC_JOIN_INDEX_DEFAULT)
@@ -1776,7 +1808,7 @@ func (pR *Room) startBattleUdpTunnel() {
} }
_, wrerr := conn.WriteTo(bytes, otherPlayer.BattleUdpTunnelAddr) _, wrerr := conn.WriteTo(bytes, otherPlayer.BattleUdpTunnelAddr)
if nil != wrerr { if nil != wrerr {
Logger.Warn(fmt.Sprintf("`BattleUdpTunnel` for roomId=%d failed to forward upsync from (playerId:%d, joinIndex:%d, addr:%s) to (otherPlayerId:%d, otherPlayerJoinIndex:%d, otherPlayerAddr:%s)\n", pR.Id, playerId, peerJoinIndex, remote, otherPlayer.Id, otherPlayer.JoinIndex, otherPlayer.BattleUdpTunnelAddr)) //Logger.Debug(fmt.Sprintf("`BattleUdpTunnel` for roomId=%d failed to forward upsync from (playerId:%d, joinIndex:%d, addr:%s) to (otherPlayerId:%d, otherPlayerJoinIndex:%d, otherPlayerAddr:%s)\n", pR.Id, playerId, peerJoinIndex, remote, otherPlayer.Id, otherPlayer.JoinIndex, otherPlayer.BattleUdpTunnelAddr))
} }
} }
pR.OnBattleCmdReceived(pReq, true) // To help advance "pR.LastAllConfirmedInputFrameId" asap, and even if "pR.LastAllConfirmedInputFrameId" is not advanced due to packet loss, these UDP packets would help prefill the "InputsBuffer" with correct player "future inputs (compared to ws session)" such that when "forceConfirmation" occurs we have as many correct predictions as possible pR.OnBattleCmdReceived(pReq, true) // To help advance "pR.LastAllConfirmedInputFrameId" asap, and even if "pR.LastAllConfirmedInputFrameId" is not advanced due to packet loss, these UDP packets would help prefill the "InputsBuffer" with correct player "future inputs (compared to ws session)" such that when "forceConfirmation" occurs we have as many correct predictions as possible

View File

@@ -26,38 +26,40 @@ type PlayerDownsync struct {
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
VirtualGridX int32 `protobuf:"varint,2,opt,name=virtualGridX,proto3" json:"virtualGridX,omitempty"` VirtualGridX int32 `protobuf:"varint,2,opt,name=virtualGridX,proto3" json:"virtualGridX,omitempty"`
VirtualGridY int32 `protobuf:"varint,3,opt,name=virtualGridY,proto3" json:"virtualGridY,omitempty"` VirtualGridY int32 `protobuf:"varint,3,opt,name=virtualGridY,proto3" json:"virtualGridY,omitempty"`
DirX int32 `protobuf:"varint,4,opt,name=dirX,proto3" json:"dirX,omitempty"` DirX int32 `protobuf:"varint,4,opt,name=dirX,proto3" json:"dirX,omitempty"`
DirY int32 `protobuf:"varint,5,opt,name=dirY,proto3" json:"dirY,omitempty"` DirY int32 `protobuf:"varint,5,opt,name=dirY,proto3" json:"dirY,omitempty"`
VelX int32 `protobuf:"varint,6,opt,name=velX,proto3" json:"velX,omitempty"` VelX int32 `protobuf:"varint,6,opt,name=velX,proto3" json:"velX,omitempty"`
VelY int32 `protobuf:"varint,7,opt,name=velY,proto3" json:"velY,omitempty"` // "velX" and "velY" is used to record the accumulated effect by inertia and accelerations (including gravity) VelY int32 `protobuf:"varint,7,opt,name=velY,proto3" json:"velY,omitempty"` // "velX" and "velY" is used to record the accumulated effect by inertia and accelerations (including gravity)
Speed int32 `protobuf:"varint,8,opt,name=speed,proto3" json:"speed,omitempty"` // this is the instantaneous scalar attribute of a character, different from but will be accounted in "velX" and "velY" Speed int32 `protobuf:"varint,8,opt,name=speed,proto3" json:"speed,omitempty"` // this is the instantaneous scalar attribute of a character, different from but will be accounted in "velX" and "velY"
BattleState int32 `protobuf:"varint,9,opt,name=battleState,proto3" json:"battleState,omitempty"` BattleState int32 `protobuf:"varint,9,opt,name=battleState,proto3" json:"battleState,omitempty"`
JoinIndex int32 `protobuf:"varint,10,opt,name=joinIndex,proto3" json:"joinIndex,omitempty"` JoinIndex int32 `protobuf:"varint,10,opt,name=joinIndex,proto3" json:"joinIndex,omitempty"`
ColliderRadius int32 `protobuf:"varint,11,opt,name=colliderRadius,proto3" json:"colliderRadius,omitempty"` ColliderRadius int32 `protobuf:"varint,11,opt,name=colliderRadius,proto3" json:"colliderRadius,omitempty"`
Removed bool `protobuf:"varint,12,opt,name=removed,proto3" json:"removed,omitempty"` Removed bool `protobuf:"varint,12,opt,name=removed,proto3" json:"removed,omitempty"`
Score int32 `protobuf:"varint,13,opt,name=score,proto3" json:"score,omitempty"` Score int32 `protobuf:"varint,13,opt,name=score,proto3" json:"score,omitempty"`
LastMoveGmtMillis int32 `protobuf:"varint,14,opt,name=lastMoveGmtMillis,proto3" json:"lastMoveGmtMillis,omitempty"` LastMoveGmtMillis int32 `protobuf:"varint,14,opt,name=lastMoveGmtMillis,proto3" json:"lastMoveGmtMillis,omitempty"`
FramesToRecover int32 `protobuf:"varint,15,opt,name=framesToRecover,proto3" json:"framesToRecover,omitempty"` FramesToRecover int32 `protobuf:"varint,15,opt,name=framesToRecover,proto3" json:"framesToRecover,omitempty"`
Hp int32 `protobuf:"varint,16,opt,name=hp,proto3" json:"hp,omitempty"` Hp int32 `protobuf:"varint,16,opt,name=hp,proto3" json:"hp,omitempty"`
MaxHp int32 `protobuf:"varint,17,opt,name=maxHp,proto3" json:"maxHp,omitempty"` MaxHp int32 `protobuf:"varint,17,opt,name=maxHp,proto3" json:"maxHp,omitempty"`
CharacterState int32 `protobuf:"varint,18,opt,name=characterState,proto3" json:"characterState,omitempty"` CharacterState int32 `protobuf:"varint,18,opt,name=characterState,proto3" json:"characterState,omitempty"`
InAir bool `protobuf:"varint,19,opt,name=inAir,proto3" json:"inAir,omitempty"` // 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. "inAir (prev -> curr)" InAir bool `protobuf:"varint,19,opt,name=inAir,proto3" json:"inAir,omitempty"` // 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. "inAir (prev -> curr)"
FramesInChState int32 `protobuf:"varint,20,opt,name=framesInChState,proto3" json:"framesInChState,omitempty"` // number of frames elapsed in the current character state FramesInChState int32 `protobuf:"varint,20,opt,name=framesInChState,proto3" json:"framesInChState,omitempty"` // number of frames elapsed in the current character state
ActiveSkillId int32 `protobuf:"varint,21,opt,name=activeSkillId,proto3" json:"activeSkillId,omitempty"` ActiveSkillId int32 `protobuf:"varint,21,opt,name=activeSkillId,proto3" json:"activeSkillId,omitempty"`
ActiveSkillHit int32 `protobuf:"varint,22,opt,name=activeSkillHit,proto3" json:"activeSkillHit,omitempty"` ActiveSkillHit int32 `protobuf:"varint,22,opt,name=activeSkillHit,proto3" json:"activeSkillHit,omitempty"`
FramesInvinsible int32 `protobuf:"varint,23,opt,name=framesInvinsible,proto3" json:"framesInvinsible,omitempty"` FramesInvinsible int32 `protobuf:"varint,23,opt,name=framesInvinsible,proto3" json:"framesInvinsible,omitempty"`
BulletTeamId int32 `protobuf:"varint,24,opt,name=bulletTeamId,proto3" json:"bulletTeamId,omitempty"` BulletTeamId int32 `protobuf:"varint,24,opt,name=bulletTeamId,proto3" json:"bulletTeamId,omitempty"`
ChCollisionTeamId int32 `protobuf:"varint,25,opt,name=chCollisionTeamId,proto3" json:"chCollisionTeamId,omitempty"` ChCollisionTeamId int32 `protobuf:"varint,25,opt,name=chCollisionTeamId,proto3" json:"chCollisionTeamId,omitempty"`
OnWall bool `protobuf:"varint,26,opt,name=onWall,proto3" json:"onWall,omitempty"` // like "inAir", its by design a standalone field only inferred by the collision result of "applyInputFrameDownsyncDynamicsOnSingleRenderFrame" instead of "characterState", because we need check the transition for "characterState" from this field, i.e. "onWall (prev -> curr)" OnWall bool `protobuf:"varint,26,opt,name=onWall,proto3" json:"onWall,omitempty"` // like "inAir", its by design a standalone field only inferred by the collision result of "applyInputFrameDownsyncDynamicsOnSingleRenderFrame" instead of "characterState", because we need check the transition for "characterState" from this field, i.e. "onWall (prev -> curr)"
OnWallNormX int32 `protobuf:"varint,27,opt,name=onWallNormX,proto3" json:"onWallNormX,omitempty"` OnWallNormX int32 `protobuf:"varint,27,opt,name=onWallNormX,proto3" json:"onWallNormX,omitempty"`
OnWallNormY int32 `protobuf:"varint,28,opt,name=onWallNormY,proto3" json:"onWallNormY,omitempty"` OnWallNormY int32 `protobuf:"varint,28,opt,name=onWallNormY,proto3" json:"onWallNormY,omitempty"`
CapturedByInertia bool `protobuf:"varint,29,opt,name=capturedByInertia,proto3" json:"capturedByInertia,omitempty"` // like "inAir", its by design a standalone field only inferred by the calc result of "applyInputFrameDownsyncDynamicsOnSingleRenderFrame" instead of "characterState" 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"` RevivalVirtualGridX int32 `protobuf:"varint,30,opt,name=revivalVirtualGridX,proto3" json:"revivalVirtualGridX,omitempty"`
DisplayName string `protobuf:"bytes,998,opt,name=displayName,proto3" json:"displayName,omitempty"` RevivalVirtualGridY int32 `protobuf:"varint,31,opt,name=revivalVirtualGridY,proto3" json:"revivalVirtualGridY,omitempty"`
Avatar string `protobuf:"bytes,999,opt,name=avatar,proto3" json:"avatar,omitempty"` Name string `protobuf:"bytes,997,opt,name=name,proto3" json:"name,omitempty"`
DisplayName string `protobuf:"bytes,998,opt,name=displayName,proto3" json:"displayName,omitempty"`
Avatar string `protobuf:"bytes,999,opt,name=avatar,proto3" json:"avatar,omitempty"`
} }
func (x *PlayerDownsync) Reset() { func (x *PlayerDownsync) Reset() {
@@ -295,6 +297,20 @@ func (x *PlayerDownsync) GetCapturedByInertia() bool {
return false return false
} }
func (x *PlayerDownsync) GetRevivalVirtualGridX() int32 {
if x != nil {
return x.RevivalVirtualGridX
}
return 0
}
func (x *PlayerDownsync) GetRevivalVirtualGridY() int32 {
if x != nil {
return x.RevivalVirtualGridY
}
return 0
}
func (x *PlayerDownsync) GetName() string { func (x *PlayerDownsync) GetName() string {
if x != nil { if x != nil {
return x.Name return x.Name
@@ -1782,7 +1798,7 @@ var file_room_downsync_frame_proto_rawDesc = []byte{
0x0a, 0x19, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x0a, 0x19, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x5f,
0x66, 0x72, 0x61, 0x6d, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06, 0x70, 0x72, 0x6f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x73, 0x1a, 0x0e, 0x67, 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x74, 0x6f, 0x73, 0x1a, 0x0e, 0x67, 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x22, 0xf3, 0x07, 0x0a, 0x0e, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x44, 0x6f, 0x6f, 0x74, 0x6f, 0x22, 0xd7, 0x08, 0x0a, 0x0e, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x44, 0x6f,
0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61,
0x6c, 0x47, 0x72, 0x69, 0x64, 0x58, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x76, 0x69, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x58, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x76, 0x69,
@@ -1840,319 +1856,325 @@ var file_room_downsync_frame_proto_rawDesc = []byte{
0x6e, 0x57, 0x61, 0x6c, 0x6c, 0x4e, 0x6f, 0x72, 0x6d, 0x59, 0x12, 0x2c, 0x0a, 0x11, 0x63, 0x61, 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, 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, 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, 0x79, 0x49, 0x6e, 0x65, 0x72, 0x74, 0x69, 0x61, 0x12, 0x30, 0x0a, 0x13, 0x72, 0x65, 0x76, 0x69,
0x18, 0xe5, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x76, 0x61, 0x6c, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x58, 0x18,
0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0xe6, 0x07, 0x20, 0x1e, 0x20, 0x01, 0x28, 0x05, 0x52, 0x13, 0x72, 0x65, 0x76, 0x69, 0x76, 0x61, 0x6c, 0x56, 0x69,
0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x58, 0x12, 0x30, 0x0a, 0x13, 0x72, 0x65,
0x12, 0x17, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0xe7, 0x07, 0x20, 0x01, 0x28, 0x76, 0x69, 0x76, 0x61, 0x6c, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x47, 0x72, 0x69, 0x64,
0x09, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x22, 0x6f, 0x0a, 0x11, 0x49, 0x6e, 0x70, 0x59, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x05, 0x52, 0x13, 0x72, 0x65, 0x76, 0x69, 0x76, 0x61, 0x6c,
0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x12, 0x0e, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x59, 0x12, 0x13, 0x0a, 0x04,
0x0a, 0x02, 0x64, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x64, 0x78, 0x12, 0x0e, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0xe5, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d,
0x0a, 0x02, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x64, 0x79, 0x12, 0x1c, 0x65, 0x12, 0x21, 0x0a, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65,
0x0a, 0x09, 0x62, 0x74, 0x6e, 0x41, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x18, 0xe6, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79,
0x05, 0x52, 0x09, 0x62, 0x74, 0x6e, 0x41, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x17, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0xe7,
0x62, 0x74, 0x6e, 0x42, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x22, 0x6f, 0x0a,
0x09, 0x62, 0x74, 0x6e, 0x42, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0x6e, 0x0a, 0x10, 0x49, 0x6e, 0x11, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x65, 0x63, 0x6f, 0x64,
0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x22, 0x65, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x64, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02,
0x0a, 0x0c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x18, 0x01, 0x64, 0x78, 0x12, 0x0e, 0x0a, 0x02, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02,
0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x64, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x74, 0x6e, 0x41, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x18,
0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x62, 0x74, 0x6e, 0x41, 0x4c, 0x65, 0x76, 0x65, 0x6c,
0x01, 0x28, 0x04, 0x52, 0x07, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x74, 0x6e, 0x42, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x04, 0x20,
0x6a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x01, 0x28, 0x05, 0x52, 0x09, 0x62, 0x74, 0x6e, 0x42, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0x6e,
0x09, 0x6a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x7c, 0x0a, 0x12, 0x49, 0x6e, 0x0a, 0x10, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x73, 0x79,
0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x6e, 0x63, 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65,
0x12, 0x22, 0x0a, 0x0c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46,
0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65,
0x6d, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x4c, 0x69, 0x73, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64,
0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x04, 0x52, 0x09, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x4c, 0x69, 0x12, 0x1c, 0x0a, 0x09, 0x6a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, 0x20,
0x73, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4c, 0x01, 0x28, 0x05, 0x52, 0x09, 0x6a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x7c,
0x69, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x0a, 0x12, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e,
0x72, 0x6d, 0x65, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x3b, 0x0a, 0x0f, 0x48, 0x65, 0x61, 0x72, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61,
0x74, 0x62, 0x65, 0x61, 0x74, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x28, 0x0a, 0x0f, 0x63, 0x6d, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x69, 0x6e, 0x70, 0x75,
0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x70, 0x75,
0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x04, 0x52, 0x09, 0x69, 0x6e, 0x70,
0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0xd2, 0x02, 0x0a, 0x05, 0x57, 0x73, 0x52, 0x65, 0x71, 0x12, 0x75, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72,
0x14, 0x0a, 0x05, 0x6d, 0x73, 0x67, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6d, 0x65, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x63,
0x6d, 0x73, 0x67, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x3b, 0x0a, 0x0f,
0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x12,
0x64, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x28, 0x0a, 0x0f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
0x61, 0x63, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74,
0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x6a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0xd2, 0x02, 0x0a, 0x05, 0x57, 0x73,
0x78, 0x12, 0x24, 0x0a, 0x0d, 0x61, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x73, 0x67, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01,
0x49, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x61, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x28, 0x05, 0x52, 0x05, 0x6d, 0x73, 0x67, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61,
0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x12, 0x61, 0x63, 0x6b, 0x69, 0x6e, 0x79, 0x65, 0x72, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x6c, 0x61,
0x67, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x18, 0x06, 0x20, 0x79, 0x65, 0x72, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01,
0x01, 0x28, 0x05, 0x52, 0x12, 0x61, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x28, 0x05, 0x52, 0x03, 0x61, 0x63, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6a, 0x6f, 0x69, 0x6e, 0x49,
0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x75, 0x74, 0x68, 0x4b, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x6a, 0x6f, 0x69, 0x6e,
0x65, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x61, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x24, 0x0a, 0x0d, 0x61, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x46,
0x79, 0x12, 0x4e, 0x0a, 0x15, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x61, 0x63,
0x70, 0x73, 0x79, 0x6e, 0x63, 0x42, 0x61, 0x74, 0x63, 0x68, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x6b, 0x69, 0x6e, 0x67, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x12, 0x61,
0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49,
0x72, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x52, 0x15, 0x69, 0x6e, 0x70, 0x75, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x61, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x49,
0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x42, 0x61, 0x74, 0x63, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61,
0x68, 0x12, 0x27, 0x0a, 0x02, 0x68, 0x62, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x61, 0x75,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x12, 0x4e, 0x0a, 0x15, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72,
0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x52, 0x02, 0x68, 0x62, 0x22, 0x9a, 0x02, 0x0a, 0x14, 0x49, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x42, 0x61, 0x74, 0x63, 0x68, 0x18, 0x08,
0x6e, 0x70, 0x75, 0x74, 0x73, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x49, 0x6e,
0x68, 0x6f, 0x74, 0x12, 0x2a, 0x0a, 0x10, 0x72, 0x65, 0x66, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x52, 0x15,
0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x10, 0x72, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63,
0x65, 0x66, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x42, 0x61, 0x74, 0x63, 0x68, 0x12, 0x27, 0x0a, 0x02, 0x68, 0x62, 0x18, 0x09, 0x20, 0x01, 0x28,
0x28, 0x0a, 0x0f, 0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4d, 0x61, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x48, 0x65, 0x61, 0x72, 0x74,
0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x62, 0x65, 0x61, 0x74, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x52, 0x02, 0x68, 0x62, 0x22, 0x9a,
0x69, 0x72, 0x6d, 0x65, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x12, 0x58, 0x0a, 0x19, 0x74, 0x6f, 0x53, 0x02, 0x0a, 0x14, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x53,
0x65, 0x6e, 0x64, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x2a, 0x0a, 0x10, 0x72, 0x65, 0x66, 0x52, 0x65,
0x6e, 0x73, 0x79, 0x6e, 0x63, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x05, 0x52, 0x10, 0x72, 0x65, 0x66, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d,
0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x52, 0x19, 0x74, 0x6f, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x0f, 0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d,
0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x65, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x75, 0x6e,
0x6e, 0x63, 0x73, 0x12, 0x2c, 0x0a, 0x11, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x46, 0x6f, 0x72, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x12, 0x58, 0x0a,
0x63, 0x65, 0x52, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x19, 0x74, 0x6f, 0x53, 0x65, 0x6e, 0x64, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d,
0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x79, 0x6e, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b,
0x63, 0x12, 0x24, 0x0a, 0x0d, 0x70, 0x65, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46,
0x65, 0x78, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x70, 0x65, 0x65, 0x72, 0x4a, 0x6f, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x52, 0x19, 0x74, 0x6f,
0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x89, 0x07, 0x0a, 0x0b, 0x4d, 0x65, 0x6c, 0x65, 0x53, 0x65, 0x6e, 0x64, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f,
0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x12, 0x38, 0x0a, 0x17, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x73, 0x12, 0x2c, 0x0a, 0x11, 0x73, 0x68, 0x6f, 0x75, 0x6c,
0x6e, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x64, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x04, 0x20, 0x01,
0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x17, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x28, 0x08, 0x52, 0x11, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x52,
0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x24, 0x0a, 0x0d, 0x70, 0x65, 0x65, 0x72, 0x4a, 0x6f, 0x69,
0x64, 0x12, 0x2c, 0x0a, 0x11, 0x6f, 0x66, 0x66, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x70, 0x65,
0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x6f, 0x66, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x89, 0x07, 0x0a, 0x0b,
0x66, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x4d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x12, 0x38, 0x0a, 0x17, 0x6f,
0x24, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46,
0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x17, 0x6f, 0x72,
0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x2e, 0x0a, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72,
0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x2c, 0x0a, 0x11, 0x6f, 0x66, 0x66, 0x65, 0x6e, 0x64, 0x65,
0x05, 0x52, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05,
0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x52, 0x11, 0x6f, 0x66, 0x66, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e,
0x61, 0x62, 0x6c, 0x65, 0x45, 0x64, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x64, 0x65, 0x78, 0x12, 0x24, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x46, 0x72,
0x05, 0x52, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x64, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x73, 0x74, 0x61, 0x72,
0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x74, 0x75, 0x70, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x2e, 0x0a, 0x12, 0x63, 0x61, 0x6e,
0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x61, 0x63, 0x74, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x18,
0x69, 0x76, 0x65, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62,
0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x6c, 0x65, 0x53, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x12, 0x63, 0x61, 0x6e,
0x52, 0x0d, 0x68, 0x69, 0x74, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x64, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x18,
0x28, 0x0a, 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62,
0x65, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x6c, 0x65, 0x45, 0x64, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x63, 0x74,
0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x75, 0x73, 0x69, 0x76, 0x65, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52,
0x68, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x24, 0x0a,
0x0c, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58, 0x12, 0x22, 0x0a, 0x0d, 0x68, 0x69, 0x74, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x07,
0x0c, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x59, 0x18, 0x0a, 0x20, 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, 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, 0x58, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c,
0x05, 0x52, 0x06, 0x64, 0x61, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x65, 0x6c, 0x59, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63,
0x66, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x05, 0x52, 0x6b, 0x56, 0x65, 0x6c, 0x59, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x61, 0x6d, 0x61, 0x67, 0x65, 0x18,
0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58, 0x12, 0x22, 0x0a, 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, 0x59, 0x18, 0x0d, 0x20, 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, 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, 0x58, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c,
0x74, 0x58, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x59, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63,
0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x58, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x6b, 0x56, 0x65, 0x6c, 0x59, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f,
0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x59, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x66, 0x66, 0x73, 0x65, 0x74, 0x58, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x68, 0x69,
0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x59, 0x12, 0x20, 0x0a, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x58, 0x12, 0x24, 0x0a, 0x0d, 0x68,
0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x58, 0x18, 0x10, 0x20, 0x01, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x59, 0x18, 0x0f, 0x20, 0x01,
0x28, 0x05, 0x52, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x58, 0x12, 0x28, 0x05, 0x52, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74,
0x20, 0x0a, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x59, 0x18, 0x11, 0x59, 0x12, 0x20, 0x0a, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x58,
0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x10, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69,
0x59, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x6c, 0x6f, 0x77, 0x55, 0x70, 0x18, 0x12, 0x20, 0x01, 0x28, 0x7a, 0x65, 0x58, 0x12, 0x20, 0x0a, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a,
0x08, 0x52, 0x06, 0x62, 0x6c, 0x6f, 0x77, 0x55, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x65, 0x61, 0x65, 0x59, 0x18, 0x11, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78,
0x6d, 0x49, 0x64, 0x18, 0x13, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x74, 0x65, 0x61, 0x6d, 0x49, 0x53, 0x69, 0x7a, 0x65, 0x59, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x6c, 0x6f, 0x77, 0x55, 0x70, 0x18,
0x64, 0x12, 0x24, 0x0a, 0x0d, 0x62, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x12, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x62, 0x6c, 0x6f, 0x77, 0x55, 0x70, 0x12, 0x16, 0x0a,
0x49, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x62, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x06, 0x74, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x18, 0x13, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x74,
0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x70, 0x65, 0x63, 0x69, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x62, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x4c,
0x65, 0x73, 0x49, 0x64, 0x18, 0x15, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x70, 0x65, 0x63, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x62, 0x75,
0x69, 0x65, 0x73, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x0f, 0x65, 0x78, 0x70, 0x6c, 0x6f, 0x73, 0x69, 0x6c, 0x6c, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x73,
0x6f, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x16, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x70, 0x65, 0x63, 0x69, 0x65, 0x73, 0x49, 0x64, 0x18, 0x15, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09,
0x65, 0x78, 0x70, 0x6c, 0x6f, 0x73, 0x69, 0x6f, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x73, 0x70, 0x65, 0x63, 0x69, 0x65, 0x73, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x0f, 0x65, 0x78, 0x70,
0x18, 0x0a, 0x07, 0x62, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x17, 0x20, 0x01, 0x28, 0x05, 0x6c, 0x6f, 0x73, 0x69, 0x6f, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x16, 0x20, 0x01,
0x52, 0x07, 0x62, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x66, 0x72, 0x61, 0x28, 0x05, 0x52, 0x0f, 0x65, 0x78, 0x70, 0x6c, 0x6f, 0x73, 0x69, 0x6f, 0x6e, 0x46, 0x72, 0x61,
0x6d, 0x65, 0x73, 0x49, 0x6e, 0x42, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x18, 0x20, 0x01, 0x6d, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x17,
0x28, 0x05, 0x52, 0x0f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x49, 0x6e, 0x42, 0x6c, 0x53, 0x74, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x62, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x28, 0x0a,
0x61, 0x74, 0x65, 0x22, 0xc1, 0x08, 0x0a, 0x0e, 0x46, 0x69, 0x72, 0x65, 0x62, 0x61, 0x6c, 0x6c, 0x0f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x49, 0x6e, 0x42, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65,
0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x12, 0x38, 0x0a, 0x17, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x18, 0x18, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x49, 0x6e,
0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x42, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0xc1, 0x08, 0x0a, 0x0e, 0x46, 0x69, 0x72, 0x65,
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x17, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x62, 0x61, 0x6c, 0x6c, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x12, 0x38, 0x0a, 0x17, 0x6f, 0x72,
0x74, 0x65, 0x64, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72,
0x12, 0x2c, 0x0a, 0x11, 0x6f, 0x66, 0x66, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x17, 0x6f, 0x72, 0x69,
0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x6f, 0x66, 0x66, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61,
0x65, 0x6e, 0x64, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x24, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x2c, 0x0a, 0x11, 0x6f, 0x66, 0x66, 0x65, 0x6e, 0x64, 0x65, 0x72,
0x0a, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52,
0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x46, 0x72, 0x11, 0x6f, 0x66, 0x66, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64,
0x61, 0x6d, 0x65, 0x73, 0x12, 0x2e, 0x0a, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x65, 0x78, 0x12, 0x24, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x46, 0x72, 0x61,
0x62, 0x6c, 0x65, 0x53, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x6d, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74,
0x52, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x46, 0x75, 0x70, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x2e, 0x0a, 0x12, 0x63, 0x61, 0x6e, 0x63,
0x72, 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x18, 0x04,
0x62, 0x6c, 0x65, 0x45, 0x64, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c,
0x52, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x64, 0x46, 0x65, 0x53, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x12, 0x63, 0x61, 0x6e, 0x63,
0x72, 0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x72, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x64, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x18, 0x05,
0x61, 0x6d, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x62, 0x6c,
0x76, 0x65, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74, 0x53, 0x65, 0x45, 0x64, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x63, 0x74, 0x69,
0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x76, 0x65, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c,
0x0d, 0x68, 0x69, 0x74, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x28, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x24, 0x0a, 0x0d,
0x0a, 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x68, 0x69, 0x74, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x07, 0x20,
0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x74, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x68, 0x69, 0x74, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d,
0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x75, 0x73, 0x68, 0x65, 0x73, 0x12, 0x28, 0x0a, 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x74, 0x75, 0x6e, 0x46,
0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x62, 0x6c, 0x6f,
0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58, 0x12, 0x22, 0x0a, 0x0c, 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, 0x59, 0x18, 0x0a, 0x20, 0x01, 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, 0x59, 0x28, 0x05, 0x52, 0x0c, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58,
0x12, 0x16, 0x0a, 0x06, 0x64, 0x61, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x59,
0x52, 0x06, 0x64, 0x61, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x65, 0x6c, 0x66, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x70, 0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b,
0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x56, 0x65, 0x6c, 0x59, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x61, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x0b,
0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58, 0x12, 0x22, 0x0a, 0x0c, 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, 0x59, 0x18, 0x0d, 0x20, 0x01, 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, 0x59, 0x28, 0x05, 0x52, 0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x58,
0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x6c, 0x59,
0x58, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x73, 0x65, 0x6c, 0x66, 0x4c, 0x6f, 0x63, 0x6b,
0x66, 0x66, 0x73, 0x65, 0x74, 0x58, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x56, 0x65, 0x6c, 0x59, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66,
0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x59, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x68, 0x66, 0x73, 0x65, 0x74, 0x58, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x68, 0x69, 0x74,
0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x59, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x58, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69,
0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x58, 0x18, 0x10, 0x20, 0x01, 0x28, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x59, 0x18, 0x0f, 0x20, 0x01, 0x28,
0x05, 0x52, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x58, 0x12, 0x20, 0x05, 0x52, 0x0d, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x59,
0x0a, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x59, 0x18, 0x11, 0x20, 0x12, 0x20, 0x0a, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x58, 0x18,
0x01, 0x28, 0x05, 0x52, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x59, 0x10, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a,
0x12, 0x16, 0x0a, 0x06, 0x62, 0x6c, 0x6f, 0x77, 0x55, 0x70, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, 0x65, 0x58, 0x12, 0x20, 0x0a, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65,
0x52, 0x06, 0x62, 0x6c, 0x6f, 0x77, 0x55, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x65, 0x61, 0x6d, 0x59, 0x18, 0x11, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53,
0x49, 0x64, 0x18, 0x13, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x74, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x69, 0x7a, 0x65, 0x59, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x6c, 0x6f, 0x77, 0x55, 0x70, 0x18, 0x12,
0x12, 0x24, 0x0a, 0x0d, 0x62, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x62, 0x6c, 0x6f, 0x77, 0x55, 0x70, 0x12, 0x16, 0x0a, 0x06,
0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x62, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x4c, 0x74, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x18, 0x13, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x74, 0x65,
0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x70, 0x65, 0x63, 0x69, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x62, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x4c, 0x6f,
0x73, 0x49, 0x64, 0x18, 0x15, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x70, 0x65, 0x63, 0x69, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x62, 0x75, 0x6c,
0x65, 0x73, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x0f, 0x65, 0x78, 0x70, 0x6c, 0x6f, 0x73, 0x69, 0x6f, 0x6c, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x70,
0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x16, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x65, 0x65, 0x63, 0x69, 0x65, 0x73, 0x49, 0x64, 0x18, 0x15, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73,
0x78, 0x70, 0x6c, 0x6f, 0x73, 0x69, 0x6f, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x18, 0x70, 0x65, 0x63, 0x69, 0x65, 0x73, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x0f, 0x65, 0x78, 0x70, 0x6c,
0x0a, 0x07, 0x62, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x17, 0x20, 0x01, 0x28, 0x05, 0x52, 0x6f, 0x73, 0x69, 0x6f, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x16, 0x20, 0x01, 0x28,
0x07, 0x62, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x66, 0x72, 0x61, 0x6d, 0x05, 0x52, 0x0f, 0x65, 0x78, 0x70, 0x6c, 0x6f, 0x73, 0x69, 0x6f, 0x6e, 0x46, 0x72, 0x61, 0x6d,
0x65, 0x73, 0x49, 0x6e, 0x42, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x18, 0x20, 0x01, 0x28, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x17, 0x20,
0x05, 0x52, 0x0f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x49, 0x6e, 0x42, 0x6c, 0x53, 0x74, 0x61, 0x01, 0x28, 0x05, 0x52, 0x07, 0x62, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x28, 0x0a, 0x0f,
0x74, 0x65, 0x12, 0x23, 0x0a, 0x0c, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x47, 0x72, 0x69, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x49, 0x6e, 0x42, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18,
0x64, 0x58, 0x18, 0xe7, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x76, 0x69, 0x72, 0x74, 0x75, 0x18, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x49, 0x6e, 0x42,
0x61, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x58, 0x12, 0x23, 0x0a, 0x0c, 0x76, 0x69, 0x72, 0x74, 0x75, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x23, 0x0a, 0x0c, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61,
0x61, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x59, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x58, 0x18, 0xe7, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x76,
0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x59, 0x12, 0x13, 0x0a, 0x04, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x58, 0x12, 0x23, 0x0a, 0x0c, 0x76,
0x64, 0x69, 0x72, 0x58, 0x18, 0xe9, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x64, 0x69, 0x72, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x59, 0x18, 0xe8, 0x07, 0x20, 0x01,
0x58, 0x12, 0x13, 0x0a, 0x04, 0x64, 0x69, 0x72, 0x59, 0x18, 0xea, 0x07, 0x20, 0x01, 0x28, 0x05, 0x28, 0x05, 0x52, 0x0c, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x59,
0x52, 0x04, 0x64, 0x69, 0x72, 0x59, 0x12, 0x13, 0x0a, 0x04, 0x76, 0x65, 0x6c, 0x58, 0x18, 0xeb, 0x12, 0x13, 0x0a, 0x04, 0x64, 0x69, 0x72, 0x58, 0x18, 0xe9, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52,
0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x76, 0x65, 0x6c, 0x58, 0x12, 0x13, 0x0a, 0x04, 0x76, 0x04, 0x64, 0x69, 0x72, 0x58, 0x12, 0x13, 0x0a, 0x04, 0x64, 0x69, 0x72, 0x59, 0x18, 0xea, 0x07,
0x65, 0x6c, 0x59, 0x18, 0xec, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x76, 0x65, 0x6c, 0x59, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x64, 0x69, 0x72, 0x59, 0x12, 0x13, 0x0a, 0x04, 0x76, 0x65,
0x12, 0x15, 0x0a, 0x05, 0x73, 0x70, 0x65, 0x65, 0x64, 0x18, 0xed, 0x07, 0x20, 0x01, 0x28, 0x05, 0x6c, 0x58, 0x18, 0xeb, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x76, 0x65, 0x6c, 0x58, 0x12,
0x52, 0x05, 0x73, 0x70, 0x65, 0x65, 0x64, 0x22, 0x71, 0x0a, 0x0f, 0x48, 0x6f, 0x6c, 0x65, 0x50, 0x13, 0x0a, 0x04, 0x76, 0x65, 0x6c, 0x59, 0x18, 0xec, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04,
0x75, 0x6e, 0x63, 0x68, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x6e, 0x76, 0x65, 0x6c, 0x59, 0x12, 0x15, 0x0a, 0x05, 0x73, 0x70, 0x65, 0x65, 0x64, 0x18, 0xed, 0x07,
0x74, 0x41, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x73, 0x70, 0x65, 0x65, 0x64, 0x22, 0x71, 0x0a, 0x0f, 0x48,
0x52, 0x0c, 0x69, 0x6e, 0x74, 0x41, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x20, 0x6f, 0x6c, 0x65, 0x50, 0x75, 0x6e, 0x63, 0x68, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x22,
0x0a, 0x0b, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x18, 0x02, 0x20, 0x0a, 0x0c, 0x69, 0x6e, 0x74, 0x41, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x69, 0x6e, 0x74, 0x41, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b,
0x65, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x6f, 0x6f, 0x6d, 0x49,
0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x6f,
0x6f, 0x6d, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x18,
0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x61, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x22, 0x4b,
0x0a, 0x0b, 0x50, 0x65, 0x65, 0x72, 0x55, 0x64, 0x70, 0x41, 0x64, 0x64, 0x72, 0x12, 0x0e, 0x0a,
0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x12, 0x12, 0x0a,
0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x6f, 0x72,
0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01,
0x28, 0x05, 0x52, 0x07, 0x61, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x22, 0xb6, 0x06, 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, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x64,
0x12, 0x18, 0x0a, 0x07, 0x61, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x12, 0x30, 0x0a, 0x13, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69,
0x05, 0x52, 0x07, 0x61, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x22, 0x4b, 0x0a, 0x0b, 0x50, 0x65, 0x6f, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x13, 0x62,
0x65, 0x72, 0x55, 0x64, 0x70, 0x41, 0x64, 0x64, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6e,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x6f, 0x73, 0x12, 0x46, 0x0a, 0x1e, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65,
0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x18, 0x0a, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x54, 0x6f, 0x6c, 0x65, 0x72,
0x07, 0x61, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x1e, 0x69, 0x6e, 0x70, 0x75,
0x61, 0x75, 0x74, 0x68, 0x4b, 0x65, 0x79, 0x22, 0xb6, 0x06, 0x0a, 0x12, 0x42, 0x61, 0x74, 0x74, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x44, 0x65, 0x6c, 0x61,
0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x6c, 0x69, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1c, 0x79, 0x54, 0x6f, 0x6c, 0x65, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x48, 0x0a, 0x1f, 0x6d, 0x61,
0x0a, 0x09, 0x73, 0x74, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x78, 0x43, 0x68, 0x61, 0x73, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72,
0x09, 0x52, 0x09, 0x73, 0x74, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x61, 0x6d, 0x65, 0x73, 0x50, 0x65, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x07, 0x20,
0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x54, 0x6f, 0x50, 0x69, 0x6e, 0x67, 0x18, 0x02, 0x01, 0x28, 0x05, 0x52, 0x1f, 0x6d, 0x61, 0x78, 0x43, 0x68, 0x61, 0x73, 0x69, 0x6e, 0x67, 0x52,
0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x54, 0x6f, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x50, 0x65, 0x72, 0x55, 0x70,
0x50, 0x69, 0x6e, 0x67, 0x12, 0x34, 0x0a, 0x15, 0x77, 0x69, 0x6c, 0x6c, 0x4b, 0x69, 0x63, 0x6b, 0x64, 0x61, 0x74, 0x65, 0x12, 0x3c, 0x0a, 0x19, 0x72, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b,
0x49, 0x66, 0x49, 0x6e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x64, 0x44, 0x74, 0x4d, 0x69, 0x6c, 0x6c, 0x69,
0x01, 0x28, 0x05, 0x52, 0x15, 0x77, 0x69, 0x6c, 0x6c, 0x4b, 0x69, 0x63, 0x6b, 0x49, 0x66, 0x49, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x01, 0x52, 0x19, 0x72, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63,
0x6e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x6f, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x6f, 0x6b, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x64, 0x44, 0x74, 0x4d, 0x69, 0x6c, 0x6c,
0x75, 0x6e, 0x64, 0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x69, 0x73, 0x12, 0x3a, 0x0a, 0x18, 0x72, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x45, 0x73,
0x0b, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x13, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x64, 0x44, 0x74, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x18, 0x09,
0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x20, 0x01, 0x28, 0x03, 0x52, 0x18, 0x72, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x45, 0x73,
0x6e, 0x6f, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x13, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x64, 0x44, 0x74, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x12, 0x28,
0x65, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x12, 0x46, 0x0a, 0x0f, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x43, 0x61, 0x63, 0x68, 0x65, 0x53, 0x69, 0x7a,
0x0a, 0x1e, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x73, 0x79, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x43,
0x6e, 0x63, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x54, 0x6f, 0x6c, 0x65, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x61, 0x63, 0x68, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x70, 0x61, 0x63,
0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x1e, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x58, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0c,
0x6d, 0x65, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x54, 0x6f, 0x6c, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x58, 0x12, 0x22, 0x0a, 0x0c,
0x65, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x48, 0x0a, 0x1f, 0x6d, 0x61, 0x78, 0x43, 0x68, 0x61, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x59, 0x18, 0x0c, 0x20, 0x01,
0x73, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x28, 0x01, 0x52, 0x0c, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x59,
0x50, 0x65, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x2a, 0x0a, 0x10, 0x63, 0x6f, 0x6c, 0x6c, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x69, 0x6e,
0x1f, 0x6d, 0x61, 0x78, 0x43, 0x68, 0x61, 0x73, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x53, 0x74, 0x65, 0x70, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x05, 0x52, 0x10, 0x63, 0x6f, 0x6c, 0x6c,
0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x50, 0x65, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x69, 0x6e, 0x53, 0x74, 0x65, 0x70, 0x12, 0x2c, 0x0a, 0x11,
0x12, 0x3c, 0x0a, 0x19, 0x72, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x45, 0x73, 0x74, 0x69, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x6f, 0x6f, 0x6d, 0x43, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74,
0x6d, 0x61, 0x74, 0x65, 0x64, 0x44, 0x74, 0x4d, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x18, 0x08, 0x20, 0x79, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x6f,
0x01, 0x28, 0x01, 0x52, 0x19, 0x72, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x45, 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x12, 0x3d, 0x0a, 0x0f, 0x62, 0x61,
0x69, 0x6d, 0x61, 0x74, 0x65, 0x64, 0x44, 0x74, 0x4d, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x12, 0x3a, 0x74, 0x74, 0x6c, 0x65, 0x55, 0x64, 0x70, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x0f, 0x20,
0x0a, 0x18, 0x72, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x50, 0x65, 0x65,
0x74, 0x65, 0x64, 0x44, 0x74, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x72, 0x55, 0x64, 0x70, 0x41, 0x64, 0x64, 0x72, 0x52, 0x0f, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65,
0x52, 0x18, 0x72, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x45, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x55, 0x64, 0x70, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x39, 0x0a, 0x17, 0x66, 0x72, 0x61,
0x74, 0x65, 0x64, 0x44, 0x74, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x12, 0x28, 0x0a, 0x0f, 0x72, 0x65, 0x6d, 0x65, 0x44, 0x61, 0x74, 0x61, 0x4c, 0x6f, 0x67, 0x67, 0x69, 0x6e, 0x67, 0x45, 0x6e, 0x61,
0x6e, 0x64, 0x65, 0x72, 0x43, 0x61, 0x63, 0x68, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x0a, 0x20, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x80, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x17, 0x66, 0x72, 0x61,
0x01, 0x28, 0x05, 0x52, 0x0f, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x43, 0x61, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x44, 0x61, 0x74, 0x61, 0x4c, 0x6f, 0x67, 0x67, 0x69, 0x6e, 0x67, 0x45, 0x6e, 0x61,
0x53, 0x69, 0x7a, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x66, 0x66, 0x62, 0x6c, 0x65, 0x64, 0x22, 0x82, 0x04, 0x0a, 0x11, 0x52, 0x6f, 0x6f, 0x6d, 0x44, 0x6f, 0x77,
0x73, 0x65, 0x74, 0x58, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0c, 0x73, 0x70, 0x61, 0x63, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64,
0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x58, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x70, 0x61, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x36, 0x0a, 0x0a, 0x70, 0x6c,
0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x59, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x41, 0x72, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16,
0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x59, 0x12, 0x2a, 0x0a, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x44, 0x6f,
0x63, 0x6f, 0x6c, 0x6c, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x69, 0x6e, 0x53, 0x74, 0x65, 0x70, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x52, 0x0a, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x41,
0x18, 0x0d, 0x20, 0x01, 0x28, 0x05, 0x52, 0x10, 0x63, 0x6f, 0x6c, 0x6c, 0x69, 0x73, 0x69, 0x6f, 0x72, 0x72, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x4e,
0x6e, 0x4d, 0x69, 0x6e, 0x53, 0x74, 0x65, 0x70, 0x12, 0x2c, 0x0a, 0x11, 0x62, 0x6f, 0x75, 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x63, 0x6f, 0x75, 0x6e,
0x64, 0x52, 0x6f, 0x6f, 0x6d, 0x43, 0x61, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x18, 0x0e, 0x20, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x12, 0x37, 0x0a, 0x0c, 0x6d, 0x65,
0x01, 0x28, 0x05, 0x52, 0x11, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x6f, 0x6f, 0x6d, 0x43, 0x61, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b,
0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x12, 0x3d, 0x0a, 0x0f, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x4d, 0x65, 0x6c, 0x65, 0x65, 0x42,
0x55, 0x64, 0x70, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x52, 0x0c, 0x6d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c,
0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x55, 0x64, 0x70, 0x65, 0x74, 0x73, 0x12, 0x40, 0x0a, 0x0f, 0x66, 0x69, 0x72, 0x65, 0x62, 0x61, 0x6c, 0x6c, 0x42,
0x41, 0x64, 0x64, 0x72, 0x52, 0x0f, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x55, 0x64, 0x70, 0x54, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70,
0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x39, 0x0a, 0x17, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x61, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x46, 0x69, 0x72, 0x65, 0x62, 0x61, 0x6c, 0x6c, 0x42, 0x75,
0x74, 0x61, 0x4c, 0x6f, 0x67, 0x67, 0x69, 0x6e, 0x67, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x6c, 0x6c, 0x65, 0x74, 0x52, 0x0f, 0x66, 0x69, 0x72, 0x65, 0x62, 0x61, 0x6c, 0x6c, 0x42, 0x75,
0x18, 0x80, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x17, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x12, 0x37, 0x0a, 0x16, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64,
0x74, 0x61, 0x4c, 0x6f, 0x67, 0x67, 0x69, 0x6e, 0x67, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x18,
0x22, 0x82, 0x04, 0x0a, 0x11, 0x52, 0x6f, 0x6f, 0x6d, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x80, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x16, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x55,
0x63, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x12, 0x2d,
0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x36, 0x0a, 0x0a, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x0a, 0x11, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73,
0x73, 0x41, 0x72, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x79, 0x6e, 0x63, 0x18, 0x81, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x73, 0x68, 0x6f, 0x75,
0x74, 0x6f, 0x73, 0x2e, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6c, 0x64, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x25, 0x0a,
0x6e, 0x63, 0x52, 0x0a, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x41, 0x72, 0x72, 0x12, 0x26, 0x0d, 0x73, 0x70, 0x65, 0x63, 0x69, 0x65, 0x73, 0x49, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x82,
0x0a, 0x0e, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x08, 0x20, 0x03, 0x28, 0x05, 0x52, 0x0d, 0x73, 0x70, 0x65, 0x63, 0x69, 0x65, 0x73, 0x49, 0x64,
0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x64, 0x6f, 0x77, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x33, 0x0a, 0x14, 0x62, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x4c, 0x6f,
0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x12, 0x37, 0x0a, 0x0c, 0x6d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x83, 0x08, 0x20,
0x75, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x01, 0x28, 0x05, 0x52, 0x14, 0x62, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x6c,
0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x4d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x49, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x3e, 0x0a, 0x0f, 0x70, 0x65, 0x65,
0x74, 0x52, 0x0c, 0x6d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x12, 0x72, 0x55, 0x64, 0x70, 0x41, 0x64, 0x64, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x84, 0x08, 0x20,
0x40, 0x0a, 0x0f, 0x66, 0x69, 0x72, 0x65, 0x62, 0x61, 0x6c, 0x6c, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x50, 0x65, 0x65,
0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x72, 0x55, 0x64, 0x70, 0x41, 0x64, 0x64, 0x72, 0x52, 0x0f, 0x70, 0x65, 0x65, 0x72, 0x55, 0x64,
0x73, 0x2e, 0x46, 0x69, 0x72, 0x65, 0x62, 0x61, 0x6c, 0x6c, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x70, 0x41, 0x64, 0x64, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x22, 0xaf, 0x02, 0x0a, 0x06, 0x57, 0x73,
0x52, 0x0f, 0x66, 0x69, 0x72, 0x65, 0x62, 0x61, 0x6c, 0x6c, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x10, 0x0a, 0x03, 0x72, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28,
0x73, 0x12, 0x37, 0x0a, 0x16, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x55, 0x6e, 0x63, 0x6f, 0x05, 0x52, 0x03, 0x72, 0x65, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x63, 0x68, 0x6f, 0x65, 0x64,
0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x18, 0x80, 0x08, 0x20, 0x01, 0x4d, 0x73, 0x67, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x65, 0x63, 0x68,
0x28, 0x04, 0x52, 0x16, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x6f, 0x65, 0x64, 0x4d, 0x73, 0x67, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x63, 0x74, 0x18,
0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x12, 0x2d, 0x0a, 0x11, 0x73, 0x68, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x61, 0x63, 0x74, 0x12, 0x2b, 0x0a, 0x03, 0x72, 0x64,
0x6f, 0x75, 0x6c, 0x64, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x66, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73,
0x81, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x46, 0x6f, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x46, 0x72, 0x61,
0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x25, 0x0a, 0x0d, 0x73, 0x70, 0x65, 0x6d, 0x65, 0x52, 0x03, 0x72, 0x64, 0x66, 0x12, 0x54, 0x0a, 0x17, 0x69, 0x6e, 0x70, 0x75, 0x74,
0x63, 0x69, 0x65, 0x73, 0x49, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x82, 0x08, 0x20, 0x03, 0x28, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x42, 0x61, 0x74,
0x05, 0x52, 0x0d, 0x73, 0x70, 0x65, 0x63, 0x69, 0x65, 0x73, 0x49, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x63, 0x68, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x12, 0x33, 0x0a, 0x14, 0x62, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x73, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e,
0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x83, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x73, 0x79, 0x6e, 0x63, 0x52, 0x17, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65,
0x14, 0x62, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x43, 0x6f, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x42, 0x61, 0x74, 0x63, 0x68, 0x12, 0x36, 0x0a,
0x75, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x3e, 0x0a, 0x0f, 0x70, 0x65, 0x65, 0x72, 0x55, 0x64, 0x70, 0x08, 0x62, 0x63, 0x69, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x41, 0x64, 0x64, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x84, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x42, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x43,
0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x55, 0x64, 0x70, 0x6f, 0x6c, 0x6c, 0x69, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x62, 0x63, 0x69,
0x41, 0x64, 0x64, 0x72, 0x52, 0x0f, 0x70, 0x65, 0x65, 0x72, 0x55, 0x64, 0x70, 0x41, 0x64, 0x64, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x70, 0x65, 0x65, 0x72, 0x4a, 0x6f, 0x69,
0x72, 0x4c, 0x69, 0x73, 0x74, 0x22, 0xaf, 0x02, 0x0a, 0x06, 0x57, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x70, 0x65,
0x12, 0x10, 0x0a, 0x03, 0x72, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x72, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x42, 0x13, 0x5a, 0x11, 0x62,
0x65, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x63, 0x68, 0x6f, 0x65, 0x64, 0x4d, 0x73, 0x67, 0x49, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x5f, 0x73, 0x72, 0x76, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73,
0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x65, 0x63, 0x68, 0x6f, 0x65, 0x64, 0x4d, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
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, 0x42, 0x13, 0x5a, 0x11, 0x62, 0x61, 0x74, 0x74, 0x6c,
0x65, 0x5f, 0x73, 0x72, 0x76, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x62, 0x06, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (

View File

@@ -50,7 +50,17 @@ func Serve(c *gin.Context) {
boundRoomId := 0 boundRoomId := 0
expectedRoomId := 0 expectedRoomId := 0
speciesId := 0
var err error var err error
if speciesIdStr, hasSpeciesId := c.GetQuery("speciesId"); hasSpeciesId {
speciesId, err = strconv.Atoi(speciesIdStr)
if err != nil {
// TODO: Abort with specific message.
c.AbortWithStatus(http.StatusBadRequest)
return
}
}
if boundRoomIdStr, hasBoundRoomId := c.GetQuery("boundRoomId"); hasBoundRoomId { if boundRoomIdStr, hasBoundRoomId := c.GetQuery("boundRoomId"); hasBoundRoomId {
boundRoomId, err = strconv.Atoi(boundRoomIdStr) boundRoomId, err = strconv.Atoi(boundRoomIdStr)
if err != nil { if err != nil {
@@ -178,34 +188,33 @@ func Serve(c *gin.Context) {
}() }()
Logger.Debug("Acquired RoomHeapMux for player:", zap.Any("playerId", playerId)) Logger.Debug("Acquired RoomHeapMux for player:", zap.Any("playerId", playerId))
// Logger.Info("The RoomHeapManagerIns has:", zap.Any("addr", fmt.Sprintf("%p", models.RoomHeapManagerIns)), zap.Any("size", len(*(models.RoomHeapManagerIns)))) // Logger.Info("The RoomHeapManagerIns has:", zap.Any("addr", fmt.Sprintf("%p", models.RoomHeapManagerIns)), zap.Any("size", len(*(models.RoomHeapManagerIns))))
playerSuccessfullyAddedToRoom := false playerRoomRelation := Constants.RetCode.UnknownError
if 0 < boundRoomId { if 0 < boundRoomId {
if tmpPRoom, existent := (*models.RoomMapManagerIns)[int32(boundRoomId)]; existent { if tmpPRoom, existent := (*models.RoomMapManagerIns)[int32(boundRoomId)]; existent {
pRoom = tmpPRoom pRoom = tmpPRoom
res := pRoom.ReAddPlayerIfPossible(pPlayer, conn, signalToCloseConnOfThisPlayer) playerRoomRelation = pRoom.ReAddPlayerIfPossible(pPlayer, conn, signalToCloseConnOfThisPlayer)
if !res { if Constants.RetCode.Ok != playerRoomRelation {
Logger.Warn("Failed to get:\n", zap.Any("roomId", pRoom.Id), zap.Any("playerId", playerId), zap.Any("forBoundRoomId", boundRoomId)) Logger.Warn("Failed to get:\n", zap.Any("roomId", pRoom.Id), zap.Any("playerId", playerId), zap.Any("forBoundRoomId", boundRoomId))
} else {
playerSuccessfullyAddedToRoom = true
} }
} }
} else if 0 < expectedRoomId { } else if 0 < expectedRoomId {
if tmpRoom, existent := (*models.RoomMapManagerIns)[int32(expectedRoomId)]; existent { if tmpRoom, existent := (*models.RoomMapManagerIns)[int32(expectedRoomId)]; existent {
pRoom = tmpRoom pRoom = tmpRoom
playerRoomRelation = pRoom.ReAddPlayerIfPossible(pPlayer, conn, signalToCloseConnOfThisPlayer)
if pRoom.ReAddPlayerIfPossible(pPlayer, conn, signalToCloseConnOfThisPlayer) { if Constants.RetCode.Ok != playerRoomRelation {
playerSuccessfullyAddedToRoom = true playerRoomRelation = pRoom.AddPlayerIfPossible(pPlayer, speciesId, conn, signalToCloseConnOfThisPlayer)
} else if pRoom.AddPlayerIfPossible(pPlayer, conn, signalToCloseConnOfThisPlayer) { }
playerSuccessfullyAddedToRoom = true if Constants.RetCode.Ok != playerRoomRelation {
} else { Logger.Warn("Failed to get:\n", zap.Any("roomId", pRoom.Id), zap.Any("playerId", playerId), zap.Any("forExpectedRoomId", expectedRoomId))
Logger.Warn("Failed to get:\n", zap.Any("roomId", pRoom.Id), zap.Any("playerId", playerId), zap.Any("forExpectedRoomId", expectedRoomId))
playerSuccessfullyAddedToRoom = false
} }
} }
} }
if false == playerSuccessfullyAddedToRoom { if Constants.RetCode.SamePlayerAlreadyInSameRoom == playerRoomRelation {
signalToCloseConnOfThisPlayer(playerRoomRelation, fmt.Sprintf("playerId == %v is already in a room, this account is possibly stolen!", playerId))
}
if Constants.RetCode.Ok != playerRoomRelation {
defer func() { defer func() {
if pRoom != nil { if pRoom != nil {
heap.Push(models.RoomHeapManagerIns, pRoom) heap.Push(models.RoomHeapManagerIns, pRoom)
@@ -219,9 +228,9 @@ func Serve(c *gin.Context) {
} else { } else {
pRoom = tmpRoom pRoom = tmpRoom
Logger.Info("Successfully popped:\n", zap.Any("roomId", pRoom.Id), zap.Any("forPlayerId", playerId)) Logger.Info("Successfully popped:\n", zap.Any("roomId", pRoom.Id), zap.Any("forPlayerId", playerId))
res := pRoom.AddPlayerIfPossible(pPlayer, conn, signalToCloseConnOfThisPlayer) playerRoomRelation = pRoom.AddPlayerIfPossible(pPlayer, speciesId, conn, signalToCloseConnOfThisPlayer)
if !res { if Constants.RetCode.Ok != playerRoomRelation {
signalToCloseConnOfThisPlayer(Constants.RetCode.PlayerNotAddableToRoom, fmt.Sprintf("AddPlayerIfPossible returns false for roomId == %v, playerId == %v!", pRoom.Id, playerId)) signalToCloseConnOfThisPlayer(playerRoomRelation, fmt.Sprintf("AddPlayerIfPossible returns false for roomId == %v, playerId == %v!", pRoom.Id, playerId))
} }
} }
} }

BIN
charts/How-to-play-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
charts/How-to-play-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
charts/How-to-play-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

BIN
charts/How-to-play-4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 684 KiB

View File

@@ -12,8 +12,9 @@ func NormVec2D(dx, dy float64) Vec2D {
} }
func ConvexPolygonStr(body *resolv.ConvexPolygon) string { func ConvexPolygonStr(body *resolv.ConvexPolygon) string {
var s []string = make([]string, len(body.Points)) var s []string = make([]string, body.Points.Cnt)
for i, p := range body.Points { for i := int32(0); i < body.Points.Cnt; i++ {
p := body.GetPointByOffset(i)
s[i] = fmt.Sprintf("[%.2f, %.2f]", p[0]+body.X, p[1]+body.Y) s[i] = fmt.Sprintf("[%.2f, %.2f]", p[0]+body.X, p[1]+body.Y)
} }

View File

@@ -109,6 +109,7 @@ var constants = {
"GET_SMS_CAPTCHA_RESP_ERROR_CODE": 2023, "GET_SMS_CAPTCHA_RESP_ERROR_CODE": 2023,
"SMS_CAPTCHA_REQUESTED_TOO_FREQUENTLY": 2024, "SMS_CAPTCHA_REQUESTED_TOO_FREQUENTLY": 2024,
"SMS_CAPTCHA_NOT_MATCH": 2025, "SMS_CAPTCHA_NOT_MATCH": 2025,
"SAME_PLAYER_ALREADY_IN_SAME_ROOM": 2026,
"NOT_IMPLEMENTED_YET": 65535 "NOT_IMPLEMENTED_YET": 65535
}, },

View File

@@ -3,7 +3,7 @@
"_name": "Fireball1Explosion", "_name": "Fireball1Explosion",
"_objFlags": 0, "_objFlags": 0,
"_native": "", "_native": "",
"_duration": 0.26666666666666666, "_duration": 0.5,
"sample": 60, "sample": 60,
"speed": 1, "speed": 1,
"wrapMode": 1, "wrapMode": 1,
@@ -30,19 +30,19 @@
} }
}, },
{ {
"frame": 0.15, "frame": 0.16666666666666666,
"value": { "value": {
"__uuid__": "8b566f26-b34d-4da6-bdaa-078358a5b685" "__uuid__": "8b566f26-b34d-4da6-bdaa-078358a5b685"
} }
}, },
{ {
"frame": 0.2, "frame": 0.31666666666666665,
"value": { "value": {
"__uuid__": "6ec5f75d-307e-4292-b667-cbbb5a52c2f6" "__uuid__": "6ec5f75d-307e-4292-b667-cbbb5a52c2f6"
} }
}, },
{ {
"frame": 0.25, "frame": 0.48333333333333334,
"value": { "value": {
"__uuid__": "d89977f1-d927-4a08-9591-9feb1daf68c8" "__uuid__": "d89977f1-d927-4a08-9591-9feb1daf68c8"
} }

View File

@@ -0,0 +1,85 @@
{
"__type__": "cc.AnimationClip",
"_name": "Fireball2Explosion",
"_objFlags": 0,
"_native": "",
"_duration": 0.5,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "a1979f05-3ecc-4d70-9ea9-7822e35602c3"
}
},
{
"frame": 0.05,
"value": {
"__uuid__": "850884ca-2e6a-4d04-94d9-fd929ac33942"
}
},
{
"frame": 0.08333333333333333,
"value": {
"__uuid__": "88b9c254-1fd8-451f-902e-4a43a7ef5d51"
}
},
{
"frame": 0.13333333333333333,
"value": {
"__uuid__": "566342a3-cfde-44c9-afbe-7d9469653ccb"
}
},
{
"frame": 0.18333333333333332,
"value": {
"__uuid__": "d1620a98-de62-4069-8910-122f361d22a4"
}
},
{
"frame": 0.23333333333333334,
"value": {
"__uuid__": "2e9ed070-e592-4e77-8fa1-c5250deb006b"
}
},
{
"frame": 0.2833333333333333,
"value": {
"__uuid__": "a3e8357d-39da-42e8-b26b-f5ae7a68aed7"
}
},
{
"frame": 0.3333333333333333,
"value": {
"__uuid__": "3f3cb45c-732d-4bea-89b4-5495fb0d2c37"
}
},
{
"frame": 0.38333333333333336,
"value": {
"__uuid__": "d7aeb01a-4e04-4037-a2c4-ba72f45f69f3"
}
},
{
"frame": 0.43333333333333335,
"value": {
"__uuid__": "fe4a97a0-1207-4b81-a541-c2da0bf0a6f3"
}
},
{
"frame": 0.48333333333333334,
"value": {
"__uuid__": "97014ab9-8bdd-4b71-9f61-0639327f9159"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "14b92f5c-af81-416a-a162-e5822d20fe68",
"subMetas": {}
}

View File

@@ -0,0 +1,79 @@
{
"__type__": "cc.AnimationClip",
"_name": "Fireball3Explosion",
"_objFlags": 0,
"_native": "",
"_duration": 0.5,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "0e003318-f8c2-40f7-b144-140b5ca1e46a"
}
},
{
"frame": 0.06666666666666667,
"value": {
"__uuid__": "9c2b0cc2-9a52-4052-b796-cd6c6bd940d4"
}
},
{
"frame": 0.11666666666666667,
"value": {
"__uuid__": "76fe0c09-d2d6-432d-bacb-20d297eb4966"
}
},
{
"frame": 0.2,
"value": {
"__uuid__": "0735a7ff-0e50-472a-b0f9-8e2cc97be7e7"
}
},
{
"frame": 0.2833333333333333,
"value": {
"__uuid__": "993199a8-54a9-40d1-8d2f-12bf16af934c"
}
},
{
"frame": 0.35,
"value": {
"__uuid__": "5d8d9ffc-b4d6-4518-9946-953929ec055c"
}
},
{
"frame": 0.38333333333333336,
"value": {
"__uuid__": "6501ae08-b0ff-43ad-b5c5-cb6dc67f989d"
}
},
{
"frame": 0.4166666666666667,
"value": {
"__uuid__": "616cfa00-1dba-4a71-8141-36774933b6a9"
}
},
{
"frame": 0.45,
"value": {
"__uuid__": "4b296e86-2e96-4276-b6de-6a6b22530344"
}
},
{
"frame": 0.48333333333333334,
"value": {
"__uuid__": "f9cc8e37-c9c2-4f20-9d7e-4533c4e859fe"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "0dbb90ed-a08a-448c-b06e-4831260e9213",
"subMetas": {}
}

View File

@@ -0,0 +1,97 @@
{
"__type__": "cc.AnimationClip",
"_name": "Fireball2",
"_objFlags": 0,
"_native": "",
"_duration": 0.21666666666666667,
"sample": 60,
"speed": 1,
"wrapMode": 2,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "db4c7e6f-9bee-4e7a-8628-d41b8bcaff42"
}
},
{
"frame": 0.016666666666666666,
"value": {
"__uuid__": "42796576-72b3-49c2-8c5a-ea946fbe1525"
}
},
{
"frame": 0.03333333333333333,
"value": {
"__uuid__": "0aa5a52f-a92a-4a4a-b49b-aee2b5a3eb55"
}
},
{
"frame": 0.05,
"value": {
"__uuid__": "0a7b5e41-acdc-4af3-beff-0a42aca9f91a"
}
},
{
"frame": 0.06666666666666667,
"value": {
"__uuid__": "de0b22b7-65ca-455f-bcd1-2ddd6cc114e2"
}
},
{
"frame": 0.08333333333333333,
"value": {
"__uuid__": "e9ce1383-9e3d-4d44-9f80-ab5fa2224138"
}
},
{
"frame": 0.1,
"value": {
"__uuid__": "5b22df7e-414b-44a3-989f-640c5b9417b9"
}
},
{
"frame": 0.11666666666666667,
"value": {
"__uuid__": "f459615c-70a4-421b-b649-a28460332364"
}
},
{
"frame": 0.13333333333333333,
"value": {
"__uuid__": "c2723b9d-fbd8-4524-a0dd-b110451e4e32"
}
},
{
"frame": 0.15,
"value": {
"__uuid__": "4286b3d1-fea2-41fd-8829-7635f546def4"
}
},
{
"frame": 0.16666666666666666,
"value": {
"__uuid__": "4e0d6419-62df-4382-893e-dd7cc47f7770"
}
},
{
"frame": 0.18333333333333332,
"value": {
"__uuid__": "f0cd9259-b323-4fba-ad8b-02d5e56c2cd4"
}
},
{
"frame": 0.2,
"value": {
"__uuid__": "0193b66d-06bb-49f9-b2f5-51fff8b16015"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "d2c65ac4-a5b3-411e-8d2d-18d3980649d7",
"subMetas": {}
}

View File

@@ -0,0 +1,73 @@
{
"__type__": "cc.AnimationClip",
"_name": "Fireball3",
"_objFlags": 0,
"_native": "",
"_duration": 0.5666666666666667,
"sample": 60,
"speed": 1,
"wrapMode": 2,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "6af65d40-470c-47de-8b3d-f53c3923bf90"
}
},
{
"frame": 0.05,
"value": {
"__uuid__": "ebf64819-79a5-4366-bf70-08f3b1c6114c"
}
},
{
"frame": 0.13333333333333333,
"value": {
"__uuid__": "e03d879b-5227-4c11-a4b9-0a426967d28a"
}
},
{
"frame": 0.2,
"value": {
"__uuid__": "a1aa0c83-4a34-43ae-9a8f-56189808df68"
}
},
{
"frame": 0.26666666666666666,
"value": {
"__uuid__": "3cc28dd0-2518-4162-a39d-4e4b19f9d60b"
}
},
{
"frame": 0.35,
"value": {
"__uuid__": "1b41f500-c55b-4cbf-a040-287b6cc0e958"
}
},
{
"frame": 0.43333333333333335,
"value": {
"__uuid__": "cfa24c51-0ad4-4e3b-b571-c5500002d6e9"
}
},
{
"frame": 0.5,
"value": {
"__uuid__": "d4a46a6a-401c-4694-a192-0a7b3ce6f603"
}
},
{
"frame": 0.55,
"value": {
"__uuid__": "c88c5293-9f21-4a1a-a6b6-649e403dc7a2"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "6aef5812-d16c-4da1-96a3-a38ac227c823",
"subMetas": {}
}

View File

@@ -0,0 +1,73 @@
{
"__type__": "cc.AnimationClip",
"_name": "Atk4",
"_objFlags": 0,
"_native": "",
"_duration": 1.0166666666666666,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "da597a30-22da-4053-b4ee-1cfa27980a75"
}
},
{
"frame": 0.08333333333333333,
"value": {
"__uuid__": "b3604b4c-426f-4843-bb76-f09a9687950d"
}
},
{
"frame": 0.16666666666666666,
"value": {
"__uuid__": "24b51487-6c91-42d9-bd12-afbbf70f2e4b"
}
},
{
"frame": 0.2833333333333333,
"value": {
"__uuid__": "c318ad71-7a5e-43b0-8098-b7a34a6e6fbe"
}
},
{
"frame": 0.38333333333333336,
"value": {
"__uuid__": "85d6d8d7-81cf-4369-a501-6ad72d70f5a2"
}
},
{
"frame": 0.5,
"value": {
"__uuid__": "42b76eaf-db36-4835-9072-893337c83425"
}
},
{
"frame": 0.6,
"value": {
"__uuid__": "152f23a1-f70f-4db6-bb28-68625aef930f"
}
},
{
"frame": 0.8833333333333333,
"value": {
"__uuid__": "9c907eb5-84ab-4fa9-9404-9085f29706cc"
}
},
{
"frame": 1,
"value": {
"__uuid__": "74f0ffc8-cc25-4fcf-a6d8-bf093daba9ca"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "2aef91f9-ef47-4bb4-bf43-5441723aa639",
"subMetas": {}
}

View File

@@ -0,0 +1,103 @@
{
"__type__": "cc.AnimationClip",
"_name": "Dying",
"_objFlags": 0,
"_native": "",
"_duration": 0.5333333333333333,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "700f93f9-ef84-4cb2-b759-f39ceac1c1d1"
}
},
{
"frame": 0.016666666666666666,
"value": {
"__uuid__": "5b4ea047-594e-4d0b-8e08-e24117bf1e67"
}
},
{
"frame": 0.05,
"value": {
"__uuid__": "a822576c-d2eb-4c17-8969-03dd1da5a93e"
}
},
{
"frame": 0.1,
"value": {
"__uuid__": "85e92afc-4359-4a8d-bdfa-958a6134cd6a"
}
},
{
"frame": 0.15,
"value": {
"__uuid__": "88d6e560-1b65-4d78-949c-cbc0e67d33cc"
}
},
{
"frame": 0.2,
"value": {
"__uuid__": "9ac16319-c1af-41d1-910b-99cbfd6230b2"
}
},
{
"frame": 0.23333333333333334,
"value": {
"__uuid__": "2a6b168a-458f-4d19-a985-9b00cc6e37e8"
}
},
{
"frame": 0.26666666666666666,
"value": {
"__uuid__": "f8482295-dc0d-4265-be56-0b0a9f6f6b9b"
}
},
{
"frame": 0.31666666666666665,
"value": {
"__uuid__": "0d4a314c-119a-46b9-8dce-dbaacf2523e5"
}
},
{
"frame": 0.36666666666666664,
"value": {
"__uuid__": "18d4ff6c-6b57-461b-8588-03521fafc9d1"
}
},
{
"frame": 0.4,
"value": {
"__uuid__": "f25280f2-442a-4ad7-914e-0f96cbf108f5"
}
},
{
"frame": 0.45,
"value": {
"__uuid__": "ccccb669-d44d-4a5c-89a1-9aba9476ce12"
}
},
{
"frame": 0.48333333333333334,
"value": {
"__uuid__": "4a45c23d-7bc8-4c5e-b761-ac1100b12a09"
}
},
{
"frame": 0.5166666666666667,
"value": {
"__uuid__": "1c4359c5-b303-403d-82ad-8d5e6ae6ec99"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "ac90c9b8-3b06-4866-89ce-2c953a9d5a9a",
"subMetas": {}
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 KiB

After

Width:  |  Height:  |  Size: 175 KiB

View File

@@ -0,0 +1,61 @@
{
"__type__": "cc.AnimationClip",
"_name": "Dashing",
"_objFlags": 0,
"_native": "",
"_duration": 0.18333333333333332,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "ec69a078-4153-49e1-9450-656942c2a567"
}
},
{
"frame": 0.016666666666666666,
"value": {
"__uuid__": "bbf23710-9dc6-4bbb-9565-df8848819d07"
}
},
{
"frame": 0.03333333333333333,
"value": {
"__uuid__": "cc7b4103-1d6b-44c1-8e0c-ee1c49052837"
}
},
{
"frame": 0.05,
"value": {
"__uuid__": "90409bfe-7b6c-4eab-953b-ea630585fad4"
}
},
{
"frame": 0.06666666666666667,
"value": {
"__uuid__": "9614dc2a-9bfe-4b85-9aa6-d7d62feec82b"
}
},
{
"frame": 0.15,
"value": {
"__uuid__": "c326e3c0-140f-457b-a086-fe95c025d576"
}
},
{
"frame": 0.16666666666666666,
"value": {
"__uuid__": "8e2d7c5b-452d-44db-b0b4-8ee03b36e7f2"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "337d57ad-118c-40e2-be90-2aa1505c152b",
"subMetas": {}
}

View File

@@ -0,0 +1,115 @@
{
"__type__": "cc.AnimationClip",
"_name": "Dying",
"_objFlags": 0,
"_native": "",
"_duration": 0.5333333333333333,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "6d1cd049-7a44-4dcb-9018-4f0fbbf3fdf8"
}
},
{
"frame": 0.03333333333333333,
"value": {
"__uuid__": "50245b04-bcb1-4488-951c-49944c1037da"
}
},
{
"frame": 0.06666666666666667,
"value": {
"__uuid__": "7a6721bb-2321-4947-832f-9a317565ea88"
}
},
{
"frame": 0.11666666666666667,
"value": {
"__uuid__": "c3553a29-e04a-42e2-8b46-82aa85706e26"
}
},
{
"frame": 0.15,
"value": {
"__uuid__": "e221838e-740f-45b1-8fd5-80d4ab8563c3"
}
},
{
"frame": 0.2,
"value": {
"__uuid__": "37ebbd1d-9a18-4514-8331-1358a59cab83"
}
},
{
"frame": 0.23333333333333334,
"value": {
"__uuid__": "b4a9ee91-4315-4fb9-9900-6d763406c81d"
}
},
{
"frame": 0.26666666666666666,
"value": {
"__uuid__": "e5388e53-5268-4f54-9a93-f6506db5b77b"
}
},
{
"frame": 0.3,
"value": {
"__uuid__": "078814c3-90e2-4b17-a90b-d2046df9a351"
}
},
{
"frame": 0.3333333333333333,
"value": {
"__uuid__": "c605bf48-9cc5-41f1-8ace-a273298f7b21"
}
},
{
"frame": 0.38333333333333336,
"value": {
"__uuid__": "5b5083ca-8fca-4827-9b76-eaa08685b031"
}
},
{
"frame": 0.4166666666666667,
"value": {
"__uuid__": "b454af6f-9e07-4b34-952b-eca69dc13d5e"
}
},
{
"frame": 0.45,
"value": {
"__uuid__": "af921d09-a72e-4b48-8585-ba72377ba410"
}
},
{
"frame": 0.48333333333333334,
"value": {
"__uuid__": "733d339e-ed74-49ab-8955-641d21528fcc"
}
},
{
"frame": 0.5,
"value": {
"__uuid__": "b7335bea-2985-4331-92c2-08c4c2a5ec86"
}
},
{
"frame": 0.5166666666666667,
"value": {
"__uuid__": "0ae606ea-93c0-4815-9e24-62c5fb59decc"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "657d4193-2224-44ea-94f7-0305a9f2b322",
"subMetas": {}
}

View File

@@ -48,13 +48,13 @@
} }
}, },
{ {
"frame": 0.45, "frame": 0.4,
"value": { "value": {
"__uuid__": "487b65c3-44e3-4b0e-9350-e0d1c952785b" "__uuid__": "487b65c3-44e3-4b0e-9350-e0d1c952785b"
} }
}, },
{ {
"frame": 0.5, "frame": 0.4166666666666667,
"value": { "value": {
"__uuid__": "9a5357ae-a160-4198-a6d5-cc9631fde754" "__uuid__": "9a5357ae-a160-4198-a6d5-cc9631fde754"
} }

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: 269 KiB

After

Width:  |  Height:  |  Size: 314 KiB

View File

@@ -0,0 +1,91 @@
{
"__type__": "cc.AnimationClip",
"_name": "Atk4",
"_objFlags": 0,
"_native": "",
"_duration": 0.5333333333333333,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "a9a10466-1e80-4fb8-9c32-2019ee2c988d"
}
},
{
"frame": 0.05,
"value": {
"__uuid__": "e0e3907f-520c-4c4c-991a-ec554e24f368"
}
},
{
"frame": 0.1,
"value": {
"__uuid__": "e4bec6fe-db19-4cf6-a8cc-bfcc3e892d5e"
}
},
{
"frame": 0.15,
"value": {
"__uuid__": "c36ceda7-2e5d-42f4-ae7b-02064348a1c2"
}
},
{
"frame": 0.18333333333333332,
"value": {
"__uuid__": "07004da9-abd4-4a05-baee-447235dcdf2d"
}
},
{
"frame": 0.23333333333333334,
"value": {
"__uuid__": "dd047451-9715-4e68-9ae5-4e4556007190"
}
},
{
"frame": 0.2833333333333333,
"value": {
"__uuid__": "7b2acb5e-3ee8-4c26-b950-f201346cefde"
}
},
{
"frame": 0.31666666666666665,
"value": {
"__uuid__": "b378b873-fae7-49dd-8581-15136046e2f1"
}
},
{
"frame": 0.36666666666666664,
"value": {
"__uuid__": "845b1de6-648f-422a-8289-98222175b787"
}
},
{
"frame": 0.4166666666666667,
"value": {
"__uuid__": "df09902a-52d8-4dec-9d05-62d3428c4625"
}
},
{
"frame": 0.4666666666666667,
"value": {
"__uuid__": "da55a31c-ce4a-4003-a119-8c76fd6d1a80"
}
},
{
"frame": 0.5166666666666667,
"value": {
"__uuid__": "bd3f63fb-6d6d-47d2-9d96-2b58292fccfa"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "168df303-4b6a-4376-940c-3d36fa9e98d8",
"subMetas": {}
}

View File

@@ -0,0 +1,55 @@
{
"__type__": "cc.AnimationClip",
"_name": "Dashing",
"_objFlags": 0,
"_native": "",
"_duration": 0.18333333333333332,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "b8c177cf-013e-4936-a031-2d3480cf975b"
}
},
{
"frame": 0.03333333333333333,
"value": {
"__uuid__": "ae2d8041-e7ee-4300-b3d6-3e85b146f33c"
}
},
{
"frame": 0.06666666666666667,
"value": {
"__uuid__": "f0518811-8fc9-4f9c-9ec4-401abdb3917d"
}
},
{
"frame": 0.1,
"value": {
"__uuid__": "3117e445-fe0f-425f-83af-5b719bf8a009"
}
},
{
"frame": 0.13333333333333333,
"value": {
"__uuid__": "f9d00d7d-2143-4893-be61-32cf1490c9f2"
}
},
{
"frame": 0.16666666666666666,
"value": {
"__uuid__": "daff32df-5e22-4d4e-94d2-6e4522a02138"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "d7b6d7c4-d2b5-49c6-bbcb-d8d80f52ae7e",
"subMetas": {}
}

View File

@@ -0,0 +1,61 @@
{
"__type__": "cc.AnimationClip",
"_name": "Dying",
"_objFlags": 0,
"_native": "",
"_duration": 0.45,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "0b31e6af-6d24-4915-b87b-772c6eb10ca7"
}
},
{
"frame": 0.06666666666666667,
"value": {
"__uuid__": "c597fb09-4621-4d1f-abf9-6484405a6330"
}
},
{
"frame": 0.13333333333333333,
"value": {
"__uuid__": "8c8be852-b65d-41d8-800f-04cbb3cad094"
}
},
{
"frame": 0.2,
"value": {
"__uuid__": "f9522b47-812e-4020-845a-5d9f6d9aca90"
}
},
{
"frame": 0.26666666666666666,
"value": {
"__uuid__": "1ff63b81-49d8-4d68-9526-5f0dc4c88ef0"
}
},
{
"frame": 0.3333333333333333,
"value": {
"__uuid__": "4e96b6fd-2cd1-412b-98a8-7f22040af589"
}
},
{
"frame": 0.43333333333333335,
"value": {
"__uuid__": "a827896b-00b5-4385-9648-2c40414b29c3"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "86706adc-e079-4997-883b-3e269d223065",
"subMetas": {}
}

View File

@@ -59,6 +59,12 @@
"__uuid__": "0ecf4a0c-0f13-42fa-a214-b4826acd8556" "__uuid__": "0ecf4a0c-0f13-42fa-a214-b4826acd8556"
} }
}, },
{
"frame": 0.3,
"value": {
"__uuid__": "cabf9cb6-99ca-426d-9a23-95cdec6f06b9"
}
},
{ {
"frame": 0.3333333333333333, "frame": 0.3333333333333333,
"value": { "value": {

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 227 KiB

View File

@@ -0,0 +1,25 @@
{
"__type__": "cc.AnimationClip",
"_name": "OnWall",
"_objFlags": 0,
"_native": "",
"_duration": 0.016666666666666666,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "d5c1e6b4-1048-43e2-96f9-801dc23cf418"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "57358699-1d1b-44db-898c-df0c3ce9aab0",
"subMetas": {}
}

View File

@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<map version="1.2" tiledversion="1.2.3" orientation="orthogonal" renderorder="right-down" width="128" height="64" tilewidth="16" tileheight="16" infinite="0" nextlayerid="7" nextobjectid="137"> <map version="1.2" tiledversion="1.2.3" orientation="orthogonal" renderorder="right-down" width="128" height="64" tilewidth="16" tileheight="16" infinite="0" nextlayerid="9" nextobjectid="138">
<tileset firstgid="1" source="tiles0.tsx"/> <tileset firstgid="1" source="tiles0.tsx"/>
<tileset firstgid="65" source="tiles1.tsx"/> <tileset firstgid="65" source="tiles1.tsx"/>
<tileset firstgid="129" source="tiles2.tsx"/> <tileset firstgid="129" source="tiles2.tsx"/>
<layer id="6" name="Ground" width="128" height="64"> <layer id="8" name="Ground" width="128" height="64">
<data encoding="base64" compression="zlib"> <data encoding="base64" compression="zlib">
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= eJzt2j1uwkAQgFEESkNHlKRHyk2iNHRcIPc/RlCEJWSxtrHHmRX7itfw651v1zTsNpvNDgAAAAAAAOAffPMnu0Nm/+xryNbyDFpeuxm0vXYzaHvtZtD22s1g3trfJlpyXa9Br9G/vv6f+lej5v5Dfcee1z9+7V23qP4vF4c7+o1LMmbwbOb0Xyrqc/R//v737g+Hhd+v//z+Ucbu56Xua+wD/esytX3UPqhxBjX3Pwa9Rv98t2vfX2X3n7sH5u6P1vt/9XTP9R/vHCcqvb823QyyW2T131515//n4lSwDVA6oxGfPee7Wz///f63vwG3j0X1z6R/uf+p1/ue6B4fK3jknqP/cJ/9yOymGOsfvZ/0f6z/+9XQ3Jac/6E9sPb5n7I/9S/3j/zN1b8+2f+7rkV2h8z+58bp37Y1+x8qlz37WmR30F9//fXXX38AAAAAAAAAAAAg1y8jXMSV
</data> </data>
</layer> </layer>
<objectgroup id="1" name="PlayerStartingPos"> <objectgroup id="1" name="PlayerStartingPos">
@@ -84,12 +84,12 @@
<property name="boundary_type" value="barrier"/> <property name="boundary_type" value="barrier"/>
</properties> </properties>
</object> </object>
<object id="84" x="640" y="224" width="16" height="800"> <object id="84" x="640" y="224" width="16" height="416">
<properties> <properties>
<property name="boundary_type" value="barrier"/> <property name="boundary_type" value="barrier"/>
</properties> </properties>
</object> </object>
<object id="85" x="1680" y="224" width="16" height="800"> <object id="85" x="1680" y="224" width="16" height="416">
<properties> <properties>
<property name="boundary_type" value="barrier"/> <property name="boundary_type" value="barrier"/>
</properties> </properties>
@@ -149,17 +149,12 @@
<property name="boundary_type" value="barrier"/> <property name="boundary_type" value="barrier"/>
</properties> </properties>
</object> </object>
<object id="113" x="640" y="1008" width="1056" height="16">
<properties>
<property name="boundary_type" value="barrier"/>
</properties>
</object>
<object id="114" x="640" y="224" width="1056" height="16"> <object id="114" x="640" y="224" width="1056" height="16">
<properties> <properties>
<property name="boundary_type" value="barrier"/> <property name="boundary_type" value="barrier"/>
</properties> </properties>
</object> </object>
<object id="119" x="656" y="592" width="1024" height="416"> <object id="119" x="656" y="592" width="512" height="48">
<properties> <properties>
<property name="boundary_type" value="barrier"/> <property name="boundary_type" value="barrier"/>
</properties> </properties>
@@ -169,5 +164,10 @@
<property name="boundary_type" value="barrier"/> <property name="boundary_type" value="barrier"/>
</properties> </properties>
</object> </object>
<object id="137" x="1168" y="592" width="512" height="48">
<properties>
<property name="boundary_type" value="barrier"/>
</properties>
</object>
</objectgroup> </objectgroup>
</map> </map>

View File

@@ -37,6 +37,8 @@ message PlayerDownsync {
int32 onWallNormY = 28; int32 onWallNormY = 28;
bool capturedByInertia = 29; // like "inAir", its by design a standalone field only inferred by the calc result of "applyInputFrameDownsyncDynamicsOnSingleRenderFrame" instead of "characterState" bool capturedByInertia = 29; // like "inAir", its by design a standalone field only inferred by the calc result of "applyInputFrameDownsyncDynamicsOnSingleRenderFrame" instead of "characterState"
int32 revivalVirtualGridX = 30;
int32 revivalVirtualGridY = 31;
string name = 997; string name = 997;
string displayName = 998; string displayName = 998;

View File

@@ -25,16 +25,19 @@
}, },
{ {
"__id__": 8 "__id__": 8
},
{
"__id__": 22
} }
], ],
"_active": true, "_active": true,
"_components": [ "_components": [
{ {
"__id__": 22 "__id__": 29
} }
], ],
"_prefab": { "_prefab": {
"__id__": 23 "__id__": 30
}, },
"_opacity": 255, "_opacity": 255,
"_color": { "_color": {
@@ -324,8 +327,8 @@
"_color": { "_color": {
"__type__": "cc.Color", "__type__": "cc.Color",
"r": 255, "r": 255,
"g": 255, "g": 0,
"b": 255, "b": 0,
"a": 255 "a": 255
}, },
"_contentSize": { "_contentSize": {
@@ -483,12 +486,21 @@
{ {
"__uuid__": "e8247e2a-1b5b-4618-86f8-224b25246b55" "__uuid__": "e8247e2a-1b5b-4618-86f8-224b25246b55"
}, },
null, {
null, "__uuid__": "168df303-4b6a-4376-940c-3d36fa9e98d8"
null, },
null, null,
{
"__uuid__": "d7b6d7c4-d2b5-49c6-bbcb-d8d80f52ae7e"
},
{
"__uuid__": "57358699-1d1b-44db-898c-df0c3ce9aab0"
},
{ {
"__uuid__": "6e1139d4-03dd-4bd4-9510-606e94f629fe" "__uuid__": "6e1139d4-03dd-4bd4-9510-606e94f629fe"
},
{
"__uuid__": "86706adc-e079-4997-883b-3e269d223065"
} }
], ],
"playOnLoad": false, "playOnLoad": false,
@@ -653,7 +665,9 @@
{ {
"__uuid__": "9b500cb0-8048-4715-81db-cc975c914225" "__uuid__": "9b500cb0-8048-4715-81db-cc975c914225"
}, },
null, {
"__uuid__": "2aef91f9-ef47-4bb4-bf43-5441723aa639"
},
null, null,
{ {
"__uuid__": "38b2c892-347b-4009-93f8-65b2ab1614f0" "__uuid__": "38b2c892-347b-4009-93f8-65b2ab1614f0"
@@ -663,6 +677,9 @@
}, },
{ {
"__uuid__": "e906322d-a08b-4477-a2e9-98acd42fa034" "__uuid__": "e906322d-a08b-4477-a2e9-98acd42fa034"
},
{
"__uuid__": "ac90c9b8-3b06-4866-89ce-2c953a9d5a9a"
} }
], ],
"playOnLoad": false, "playOnLoad": false,
@@ -833,10 +850,15 @@
{ {
"__uuid__": "0abbd156-980e-475e-9994-3c958bd913fc" "__uuid__": "0abbd156-980e-475e-9994-3c958bd913fc"
}, },
null, {
"__uuid__": "337d57ad-118c-40e2-be90-2aa1505c152b"
},
null, null,
{ {
"__uuid__": "edd23b2f-1caa-4836-88a7-e4af1f26743e" "__uuid__": "edd23b2f-1caa-4836-88a7-e4af1f26743e"
},
{
"__uuid__": "657d4193-2224-44ea-94f7-0305a9f2b322"
} }
], ],
"playOnLoad": false, "playOnLoad": false,
@@ -892,6 +914,244 @@
"fileId": "7aN7Gcc/tBw5EGlTJVBj2+", "fileId": "7aN7Gcc/tBw5EGlTJVBj2+",
"sync": false "sync": false
}, },
{
"__type__": "cc.Node",
"_name": "HpBar",
"_objFlags": 0,
"_parent": {
"__id__": 1
},
"_children": [
{
"__id__": 23
}
],
"_active": true,
"_components": [
{
"__id__": 26
},
{
"__id__": 27
}
],
"_prefab": {
"__id__": 28
},
"_opacity": 255,
"_color": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_contentSize": {
"__type__": "cc.Size",
"width": 50,
"height": 8
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_trs": {
"__type__": "TypedArray",
"ctor": "Float64Array",
"array": [
0,
42.256,
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": "bar",
"_objFlags": 0,
"_parent": {
"__id__": 22
},
"_children": [],
"_active": true,
"_components": [
{
"__id__": 24
}
],
"_prefab": {
"__id__": 25
},
"_opacity": 255,
"_color": {
"__type__": "cc.Color",
"r": 10,
"g": 252,
"b": 0,
"a": 255
},
"_contentSize": {
"__type__": "cc.Size",
"width": 50,
"height": 8
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0,
"y": 0.5
},
"_trs": {
"__type__": "TypedArray",
"ctor": "Float64Array",
"array": [
-25,
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__": 23
},
"_enabled": true,
"_materials": [
{
"__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432"
}
],
"_srcBlendFactor": 770,
"_dstBlendFactor": 771,
"_spriteFrame": {
"__uuid__": "67e68bc9-dad5-4ad9-a2d8-7e03d458e32f"
},
"_type": 1,
"_sizeMode": 0,
"_fillType": 0,
"_fillCenter": {
"__type__": "cc.Vec2",
"x": 0,
"y": 0
},
"_fillStart": 0,
"_fillRange": 0,
"_isTrimmedMode": true,
"_atlas": null,
"_id": ""
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__uuid__": "59bff7a2-23e1-4d69-bce7-afb37eae196a"
},
"fileId": "1b5Rz5KABPK5Nv1wogghs6",
"sync": false
},
{
"__type__": "cc.Sprite",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 22
},
"_enabled": true,
"_materials": [
{
"__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432"
}
],
"_srcBlendFactor": 770,
"_dstBlendFactor": 771,
"_spriteFrame": {
"__uuid__": "88e79fd5-96b4-4a77-a1f4-312467171014"
},
"_type": 1,
"_sizeMode": 0,
"_fillType": 0,
"_fillCenter": {
"__type__": "cc.Vec2",
"x": 0,
"y": 0
},
"_fillStart": 0,
"_fillRange": 0,
"_isTrimmedMode": true,
"_atlas": null,
"_id": ""
},
{
"__type__": "cc.ProgressBar",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 22
},
"_enabled": true,
"_N$totalLength": 50,
"_N$barSprite": {
"__id__": 24
},
"_N$mode": 0,
"_N$progress": 1,
"_N$reverse": false,
"_id": ""
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__uuid__": "59bff7a2-23e1-4d69-bce7-afb37eae196a"
},
"fileId": "1cDdFO9Z5KYIcRR52ZmtqO",
"sync": false
},
{ {
"__type__": "b74b05YDqZFRo4OkZRFZX8k", "__type__": "b74b05YDqZFRo4OkZRFZX8k",
"_name": "", "_name": "",
@@ -910,6 +1170,9 @@
"coordLabel": { "coordLabel": {
"__id__": 3 "__id__": 3
}, },
"hpBar": {
"__id__": 27
},
"_id": "" "_id": ""
}, },
{ {

View File

@@ -22,6 +22,9 @@
}, },
{ {
"__id__": 5 "__id__": 5
},
{
"__id__": 11
} }
], ],
"_active": true, "_active": true,
@@ -59,7 +62,7 @@
"ctor": "Float64Array", "ctor": "Float64Array",
"array": [ "array": [
480, 480,
320, 480,
0, 0,
0, 0,
0, 0,
@@ -192,102 +195,28 @@
"fileId": "ab6G+s0otA4rXhUsO3czRN", "fileId": "ab6G+s0otA4rXhUsO3czRN",
"sync": false "sync": false
}, },
{
"__type__": "cc.Node",
"_name": "VerticalLayout",
"_objFlags": 0,
"_parent": {
"__id__": 1
},
"_children": [
{
"__id__": 6
},
{
"__id__": 12
}
],
"_active": true,
"_components": [
{
"__id__": 53
},
{
"__id__": 54
}
],
"_prefab": {
"__id__": 55
},
"_opacity": 255,
"_color": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_contentSize": {
"__type__": "cc.Size",
"width": 960,
"height": 265
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_trs": {
"__type__": "TypedArray",
"ctor": "Float64Array",
"array": [
0,
128,
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", "__type__": "cc.Node",
"_name": "exitButton", "_name": "exitButton",
"_objFlags": 0, "_objFlags": 0,
"_parent": { "_parent": {
"__id__": 5 "__id__": 1
}, },
"_children": [], "_children": [],
"_active": true, "_active": true,
"_components": [ "_components": [
{
"__id__": 6
},
{ {
"__id__": 7 "__id__": 7
}, },
{ {
"__id__": 8 "__id__": 9
},
{
"__id__": 10
} }
], ],
"_prefab": { "_prefab": {
"__id__": 11 "__id__": 10
}, },
"_opacity": 255, "_opacity": 255,
"_color": { "_color": {
@@ -312,7 +241,7 @@
"ctor": "Float64Array", "ctor": "Float64Array",
"array": [ "array": [
-379.577, -379.577,
100.5, 140,
0, 0,
0, 0,
0, 0,
@@ -341,7 +270,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 6 "__id__": 5
}, },
"_enabled": true, "_enabled": true,
"_materials": [ "_materials": [
@@ -375,7 +304,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 6 "__id__": 5
}, },
"_enabled": true, "_enabled": true,
"_normalMaterial": null, "_normalMaterial": null,
@@ -384,7 +313,7 @@
"zoomScale": 1.2, "zoomScale": 1.2,
"clickEvents": [ "clickEvents": [
{ {
"__id__": 9 "__id__": 8
} }
], ],
"_N$interactable": true, "_N$interactable": true,
@@ -440,7 +369,7 @@
"hoverSprite": null, "hoverSprite": null,
"_N$disabledSprite": null, "_N$disabledSprite": null,
"_N$target": { "_N$target": {
"__id__": 6 "__id__": 5
}, },
"_id": "" "_id": ""
}, },
@@ -459,7 +388,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 6 "__id__": 5
}, },
"_enabled": true, "_enabled": true,
"alignMode": 1, "alignMode": 1,
@@ -489,15 +418,86 @@
"asset": { "asset": {
"__uuid__": "dc804c5c-ff76-445e-ac69-52269055c3c5" "__uuid__": "dc804c5c-ff76-445e-ac69-52269055c3c5"
}, },
"fileId": "1cUg34ZtdK9JfdGIG+lpdF", "fileId": "3cdlb7LxhMzLDzxdQv8Z/x",
"sync": false "sync": false
}, },
{
"__type__": "cc.Node",
"_name": "VerticalLayout",
"_objFlags": 0,
"_parent": {
"__id__": 1
},
"_children": [
{
"__id__": 12
}
],
"_active": true,
"_components": [
{
"__id__": 53
},
{
"__id__": 54
}
],
"_prefab": {
"__id__": 55
},
"_opacity": 255,
"_color": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_contentSize": {
"__type__": "cc.Size",
"width": 960,
"height": 137
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_trs": {
"__type__": "TypedArray",
"ctor": "Float64Array",
"array": [
0,
-13.057,
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", "__type__": "cc.Node",
"_name": "HorizontalLayout", "_name": "HorizontalLayout",
"_objFlags": 0, "_objFlags": 0,
"_parent": { "_parent": {
"__id__": 5 "__id__": 11
}, },
"_children": [ "_children": [
{ {
@@ -545,7 +545,7 @@
"ctor": "Float64Array", "ctor": "Float64Array",
"array": [ "array": [
0, 0,
-64, 0,
0, 0,
0, 0,
0, 0,
@@ -1953,7 +1953,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 5 "__id__": 11
}, },
"_enabled": true, "_enabled": true,
"_materials": [ "_materials": [
@@ -1983,13 +1983,13 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 5 "__id__": 11
}, },
"_enabled": true, "_enabled": true,
"_layoutSize": { "_layoutSize": {
"__type__": "cc.Size", "__type__": "cc.Size",
"width": 960, "width": 960,
"height": 265 "height": 137
}, },
"_resize": 1, "_resize": 1,
"_N$layoutType": 2, "_N$layoutType": 2,
@@ -2040,7 +2040,7 @@
"__id__": 43 "__id__": 43
}, },
"exitBtnNode": { "exitBtnNode": {
"__id__": 6 "__id__": 5
}, },
"_id": "" "_id": ""
}, },

View File

@@ -24,11 +24,11 @@
"_active": true, "_active": true,
"_components": [ "_components": [
{ {
"__id__": 12 "__id__": 20
} }
], ],
"_prefab": { "_prefab": {
"__id__": 13 "__id__": 21
}, },
"_opacity": 255, "_opacity": 255,
"_color": { "_color": {
@@ -90,12 +90,18 @@
}, },
{ {
"__id__": 7 "__id__": 7
},
{
"__id__": 11
},
{
"__id__": 15
} }
], ],
"_active": true, "_active": true,
"_components": [], "_components": [],
"_prefab": { "_prefab": {
"__id__": 11 "__id__": 19
}, },
"_opacity": 255, "_opacity": 255,
"_color": { "_color": {
@@ -211,38 +217,6 @@
"groupIndex": 0, "groupIndex": 0,
"_id": "" "_id": ""
}, },
{
"__type__": "cc.Sprite",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 3
},
"_enabled": true,
"_materials": [
{
"__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432"
}
],
"_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__": "6dcd5722-8ef9-47fd-9520-861d2713e274"
},
"_id": ""
},
{ {
"__type__": "cc.Animation", "__type__": "cc.Animation",
"_name": "", "_name": "",
@@ -265,6 +239,34 @@
"playOnLoad": false, "playOnLoad": false,
"_id": "" "_id": ""
}, },
{
"__type__": "cc.Sprite",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 3
},
"_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__": "6dcd5722-8ef9-47fd-9520-861d2713e274"
},
"_id": ""
},
{ {
"__type__": "cc.PrefabInfo", "__type__": "cc.PrefabInfo",
"root": { "root": {
@@ -278,7 +280,7 @@
}, },
{ {
"__type__": "cc.Node", "__type__": "cc.Node",
"_name": "MeleeExplosion", "_name": "Fireball2",
"_objFlags": 0, "_objFlags": 0,
"_parent": { "_parent": {
"__id__": 2 "__id__": 2
@@ -314,6 +316,258 @@
"x": 0.5, "x": 0.5,
"y": 0.5 "y": 0.5
}, },
"_trs": {
"__type__": "TypedArray",
"ctor": "Float64Array",
"array": [
0,
0,
0,
0,
0,
0,
1,
0.5,
0.5,
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__": "d2c65ac4-a5b3-411e-8d2d-18d3980649d7"
},
{
"__uuid__": "14b92f5c-af81-416a-a162-e5822d20fe68"
}
],
"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__": "725c90f9-56f8-48ea-9159-4d2949cd3ce0"
},
"_id": ""
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__uuid__": "d92d4831-cd65-4eb5-90bd-b77021aec35b"
},
"fileId": "b0ZpleOHlFqIjwc8HDI9df",
"sync": false
},
{
"__type__": "cc.Node",
"_name": "Fireball3",
"_objFlags": 0,
"_parent": {
"__id__": 2
},
"_children": [],
"_active": false,
"_components": [
{
"__id__": 12
},
{
"__id__": 13
}
],
"_prefab": {
"__id__": 14
},
"_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": [
0,
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.Animation",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 11
},
"_enabled": true,
"_defaultClip": null,
"_clips": [
{
"__uuid__": "6aef5812-d16c-4da1-96a3-a38ac227c823"
},
{
"__uuid__": "0dbb90ed-a08a-448c-b06e-4831260e9213"
}
],
"playOnLoad": false,
"_id": ""
},
{
"__type__": "cc.Sprite",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 11
},
"_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__": "579bc0c1-f5e2-4a5d-889b-9d567e53b0e6"
},
"_id": ""
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__uuid__": "d92d4831-cd65-4eb5-90bd-b77021aec35b"
},
"fileId": "03W6UmKHVAz4hCpMvTCpP9",
"sync": false
},
{
"__type__": "cc.Node",
"_name": "MeleeExplosion",
"_objFlags": 0,
"_parent": {
"__id__": 2
},
"_children": [],
"_active": false,
"_components": [
{
"__id__": 16
},
{
"__id__": 17
}
],
"_prefab": {
"__id__": 18
},
"_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": { "_trs": {
"__type__": "TypedArray", "__type__": "TypedArray",
"ctor": "Float64Array", "ctor": "Float64Array",
@@ -348,7 +602,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 7 "__id__": 15
}, },
"_enabled": true, "_enabled": true,
"_defaultClip": null, "_defaultClip": null,
@@ -371,7 +625,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 7 "__id__": 15
}, },
"_enabled": true, "_enabled": true,
"_materials": [], "_materials": [],

File diff suppressed because it is too large Load Diff

View File

@@ -88,7 +88,7 @@
"__id__": 1 "__id__": 1
}, },
"_children": [], "_children": [],
"_active": true, "_active": false,
"_components": [ "_components": [
{ {
"__id__": 3 "__id__": 3

View File

@@ -77,9 +77,6 @@
], ],
"_active": true, "_active": true,
"_components": [ "_components": [
{
"__id__": 50
},
{ {
"__id__": 51 "__id__": 51
}, },
@@ -91,6 +88,9 @@
}, },
{ {
"__id__": 54 "__id__": 54
},
{
"__id__": 55
} }
], ],
"_prefab": null, "_prefab": null,
@@ -156,9 +156,6 @@
}, },
{ {
"__id__": 5 "__id__": 5
},
{
"__id__": 49
} }
], ],
"_prefab": null, "_prefab": null,
@@ -247,10 +244,10 @@
"__uuid__": "670b477e-61a1-4778-879b-35913f7c79d2" "__uuid__": "670b477e-61a1-4778-879b-35913f7c79d2"
}, },
"boundRoomIdLabel": { "boundRoomIdLabel": {
"__id__": 26 "__id__": 28
}, },
"countdownLabel": { "countdownLabel": {
"__id__": 33 "__id__": 35
}, },
"resultPanelPrefab": { "resultPanelPrefab": {
"__uuid__": "c4cfe3bd-c59e-4d5b-95cb-c933b120e184" "__uuid__": "c4cfe3bd-c59e-4d5b-95cb-c933b120e184"
@@ -264,26 +261,26 @@
"countdownToBeginGamePrefab": { "countdownToBeginGamePrefab": {
"__uuid__": "230eeb1f-e0f9-4a41-ab6c-05b3771cbf3e" "__uuid__": "230eeb1f-e0f9-4a41-ab6c-05b3771cbf3e"
}, },
"playersInfoPrefab": {
"__uuid__": "b4e519f4-e698-4403-9ff2-47b8dacb077e"
},
"forceBigEndianFloatingNumDecoding": false, "forceBigEndianFloatingNumDecoding": false,
"renderFrameIdLagTolerance": 4, "renderFrameIdLagTolerance": 4,
"sendingQLabel": { "inputFrameFrontLabel": {
"__id__": 13 "__id__": 13
}, },
"inputFrameDownsyncQLabel": { "sendingQLabel": {
"__id__": 15 "__id__": 15
}, },
"peerInputFrameUpsyncQLabel": { "inputFrameDownsyncQLabel": {
"__id__": 17 "__id__": 17
}, },
"rollbackFramesLabel": { "peerInputFrameUpsyncQLabel": {
"__id__": 19 "__id__": 19
}, },
"skippedRenderFrameCntLabel": { "rollbackFramesLabel": {
"__id__": 21 "__id__": 21
}, },
"skippedRenderFrameCntLabel": {
"__id__": 23
},
"_id": "d12gkAmppNlIzqcRDELa91" "_id": "d12gkAmppNlIzqcRDELa91"
}, },
{ {
@@ -295,13 +292,13 @@
}, },
"_children": [ "_children": [
{ {
"__id__": 43 "__id__": 45
} }
], ],
"_active": true, "_active": true,
"_components": [ "_components": [
{ {
"__id__": 48 "__id__": 50
} }
], ],
"_prefab": null, "_prefab": null,
@@ -363,20 +360,20 @@
{ {
"__id__": 6 "__id__": 6
}, },
{
"__id__": 32
},
{ {
"__id__": 34 "__id__": 34
}, },
{ {
"__id__": 38 "__id__": 36
},
{
"__id__": 40
} }
], ],
"_active": true, "_active": true,
"_components": [ "_components": [
{ {
"__id__": 42 "__id__": 44
} }
], ],
"_prefab": null, "_prefab": null,
@@ -403,7 +400,7 @@
"ctor": "Float64Array", "ctor": "Float64Array",
"array": [ "array": [
0, 0,
0, 32,
0, 0,
0, 0,
0, 0,
@@ -445,7 +442,7 @@
"_active": true, "_active": true,
"_components": [ "_components": [
{ {
"__id__": 31 "__id__": 33
} }
], ],
"_prefab": null, "_prefab": null,
@@ -539,7 +536,7 @@
"array": [ "array": [
0, 0,
0, 0,
209.6693197428241, 210.43877906529718,
0, 0,
0, 0,
0, 0,
@@ -623,15 +620,18 @@
}, },
{ {
"__id__": 22 "__id__": 22
},
{
"__id__": 24
} }
], ],
"_active": true, "_active": true,
"_components": [ "_components": [
{ {
"__id__": 29 "__id__": 31
}, },
{ {
"__id__": 30 "__id__": 32
} }
], ],
"_prefab": null, "_prefab": null,
@@ -684,7 +684,7 @@
}, },
{ {
"__type__": "cc.Node", "__type__": "cc.Node",
"_name": "sendingQ", "_name": "inputFrameFront",
"_objFlags": 0, "_objFlags": 0,
"_parent": { "_parent": {
"__id__": 11 "__id__": 11
@@ -742,7 +742,7 @@
"_is3DNode": false, "_is3DNode": false,
"_groupIndex": 0, "_groupIndex": 0,
"groupIndex": 0, "groupIndex": 0,
"_id": "ack7XH+0lEj6chSUsKBLU5" "_id": "83n6IAj9tAkop6CA/MyM0A"
}, },
{ {
"__type__": "cc.Label", "__type__": "cc.Label",
@@ -774,11 +774,11 @@
"_N$fontFamily": "Arial", "_N$fontFamily": "Arial",
"_N$overflow": 0, "_N$overflow": 0,
"_N$cacheMode": 0, "_N$cacheMode": 0,
"_id": "deCJfLuoFO36c/O4lXWJ1N" "_id": "a4CfeVmexNm7nULcCRHcVl"
}, },
{ {
"__type__": "cc.Node", "__type__": "cc.Node",
"_name": "inputFrameDownsyncQ", "_name": "sendingQ",
"_objFlags": 0, "_objFlags": 0,
"_parent": { "_parent": {
"__id__": 11 "__id__": 11
@@ -836,7 +836,7 @@
"_is3DNode": false, "_is3DNode": false,
"_groupIndex": 0, "_groupIndex": 0,
"groupIndex": 0, "groupIndex": 0,
"_id": "d9n+NRm9pA0YtKxvy4bW+U" "_id": "ack7XH+0lEj6chSUsKBLU5"
}, },
{ {
"__type__": "cc.Label", "__type__": "cc.Label",
@@ -868,11 +868,11 @@
"_N$fontFamily": "Arial", "_N$fontFamily": "Arial",
"_N$overflow": 0, "_N$overflow": 0,
"_N$cacheMode": 0, "_N$cacheMode": 0,
"_id": "90NvjGFrpBFqqzl1WZczta" "_id": "deCJfLuoFO36c/O4lXWJ1N"
}, },
{ {
"__type__": "cc.Node", "__type__": "cc.Node",
"_name": "peerInputFrameUpsyncQ", "_name": "inputFrameDownsyncQ",
"_objFlags": 0, "_objFlags": 0,
"_parent": { "_parent": {
"__id__": 11 "__id__": 11
@@ -930,7 +930,7 @@
"_is3DNode": false, "_is3DNode": false,
"_groupIndex": 0, "_groupIndex": 0,
"groupIndex": 0, "groupIndex": 0,
"_id": "45FAmgRLZNNbLt/GcnTXVx" "_id": "d9n+NRm9pA0YtKxvy4bW+U"
}, },
{ {
"__type__": "cc.Label", "__type__": "cc.Label",
@@ -962,11 +962,11 @@
"_N$fontFamily": "Arial", "_N$fontFamily": "Arial",
"_N$overflow": 0, "_N$overflow": 0,
"_N$cacheMode": 0, "_N$cacheMode": 0,
"_id": "42PRTrjEpDw6Z8N5yWFTpd" "_id": "90NvjGFrpBFqqzl1WZczta"
}, },
{ {
"__type__": "cc.Node", "__type__": "cc.Node",
"_name": "rollbackFrames", "_name": "peerInputFrameUpsyncQ",
"_objFlags": 0, "_objFlags": 0,
"_parent": { "_parent": {
"__id__": 11 "__id__": 11
@@ -1024,7 +1024,7 @@
"_is3DNode": false, "_is3DNode": false,
"_groupIndex": 0, "_groupIndex": 0,
"groupIndex": 0, "groupIndex": 0,
"_id": "f5SBs3b1pPNbHbnqVLYsHp" "_id": "45FAmgRLZNNbLt/GcnTXVx"
}, },
{ {
"__type__": "cc.Label", "__type__": "cc.Label",
@@ -1056,11 +1056,11 @@
"_N$fontFamily": "Arial", "_N$fontFamily": "Arial",
"_N$overflow": 0, "_N$overflow": 0,
"_N$cacheMode": 0, "_N$cacheMode": 0,
"_id": "77aNARt1VATLsjIzwbqvkh" "_id": "42PRTrjEpDw6Z8N5yWFTpd"
}, },
{ {
"__type__": "cc.Node", "__type__": "cc.Node",
"_name": "skippedCnt", "_name": "rollbackFrames",
"_objFlags": 0, "_objFlags": 0,
"_parent": { "_parent": {
"__id__": 11 "__id__": 11
@@ -1076,9 +1076,9 @@
"_opacity": 255, "_opacity": 255,
"_color": { "_color": {
"__type__": "cc.Color", "__type__": "cc.Color",
"r": 243, "r": 255,
"g": 225, "g": 255,
"b": 11, "b": 255,
"a": 255 "a": 255
}, },
"_contentSize": { "_contentSize": {
@@ -1118,7 +1118,7 @@
"_is3DNode": false, "_is3DNode": false,
"_groupIndex": 0, "_groupIndex": 0,
"groupIndex": 0, "groupIndex": 0,
"_id": "cdlF8Z8TZEdLRHQQ8T8qX7" "_id": "f5SBs3b1pPNbHbnqVLYsHp"
}, },
{ {
"__type__": "cc.Label", "__type__": "cc.Label",
@@ -1150,6 +1150,100 @@
"_N$fontFamily": "Arial", "_N$fontFamily": "Arial",
"_N$overflow": 0, "_N$overflow": 0,
"_N$cacheMode": 0, "_N$cacheMode": 0,
"_id": "77aNARt1VATLsjIzwbqvkh"
},
{
"__type__": "cc.Node",
"_name": "skippedCnt",
"_objFlags": 0,
"_parent": {
"__id__": 11
},
"_children": [],
"_active": true,
"_components": [
{
"__id__": 23
}
],
"_prefab": null,
"_opacity": 255,
"_color": {
"__type__": "cc.Color",
"r": 243,
"g": 225,
"b": 11,
"a": 255
},
"_contentSize": {
"__type__": "cc.Size",
"width": 18.33,
"height": 22.61
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0,
"y": 0.5
},
"_trs": {
"__type__": "TypedArray",
"ctor": "Float64Array",
"array": [
0,
-24.355000000000018,
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": "cdlF8Z8TZEdLRHQQ8T8qX7"
},
{
"__type__": "cc.Label",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 22
},
"_enabled": true,
"_materials": [
{
"__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432"
}
],
"_useOriginalSize": false,
"_string": "0",
"_N$string": "0",
"_fontSize": 22,
"_lineHeight": 37,
"_enableWrapText": true,
"_N$file": {
"__uuid__": "a564b3db-b8cb-48b4-952e-25bb56949116"
},
"_isSystemFontUsed": false,
"_spacingX": 0,
"_batchAsBitmap": false,
"_N$horizontalAlign": 0,
"_N$verticalAlign": 1,
"_N$fontFamily": "Arial",
"_N$overflow": 0,
"_N$cacheMode": 0,
"_id": "2flWrlaK1PeJMUB/in+S1W" "_id": "2flWrlaK1PeJMUB/in+S1W"
}, },
{ {
@@ -1161,19 +1255,19 @@
}, },
"_children": [ "_children": [
{ {
"__id__": 23 "__id__": 25
}, },
{ {
"__id__": 25 "__id__": 27
} }
], ],
"_active": false, "_active": false,
"_components": [ "_components": [
{ {
"__id__": 27 "__id__": 29
}, },
{ {
"__id__": 28 "__id__": 30
} }
], ],
"_prefab": null, "_prefab": null,
@@ -1229,13 +1323,13 @@
"_name": "label", "_name": "label",
"_objFlags": 0, "_objFlags": 0,
"_parent": { "_parent": {
"__id__": 22 "__id__": 24
}, },
"_children": [], "_children": [],
"_active": true, "_active": true,
"_components": [ "_components": [
{ {
"__id__": 24 "__id__": 26
} }
], ],
"_prefab": null, "_prefab": null,
@@ -1291,7 +1385,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 23 "__id__": 25
}, },
"_enabled": true, "_enabled": true,
"_materials": [], "_materials": [],
@@ -1319,13 +1413,13 @@
"_name": "BoundRoomIdLabel", "_name": "BoundRoomIdLabel",
"_objFlags": 0, "_objFlags": 0,
"_parent": { "_parent": {
"__id__": 22 "__id__": 24
}, },
"_children": [], "_children": [],
"_active": true, "_active": true,
"_components": [ "_components": [
{ {
"__id__": 26 "__id__": 28
} }
], ],
"_prefab": null, "_prefab": null,
@@ -1381,7 +1475,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 25 "__id__": 27
}, },
"_enabled": true, "_enabled": true,
"_materials": [], "_materials": [],
@@ -1409,7 +1503,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 22 "__id__": 24
}, },
"_enabled": true, "_enabled": true,
"_layoutSize": { "_layoutSize": {
@@ -1442,7 +1536,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 22 "__id__": 24
}, },
"_enabled": true, "_enabled": true,
"_materials": [], "_materials": [],
@@ -1564,7 +1658,7 @@
"_active": true, "_active": true,
"_components": [ "_components": [
{ {
"__id__": 33 "__id__": 35
} }
], ],
"_prefab": null, "_prefab": null,
@@ -1620,7 +1714,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 32 "__id__": 34
}, },
"_enabled": true, "_enabled": true,
"_materials": [ "_materials": [
@@ -1654,7 +1748,7 @@
}, },
"_children": [ "_children": [
{ {
"__id__": 35 "__id__": 37
} }
], ],
"_active": true, "_active": true,
@@ -1712,16 +1806,16 @@
"_name": "Background", "_name": "Background",
"_objFlags": 0, "_objFlags": 0,
"_parent": { "_parent": {
"__id__": 34 "__id__": 36
}, },
"_children": [], "_children": [],
"_active": true, "_active": true,
"_components": [ "_components": [
{ {
"__id__": 36 "__id__": 38
}, },
{ {
"__id__": 37 "__id__": 39
} }
], ],
"_prefab": null, "_prefab": null,
@@ -1777,7 +1871,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 35 "__id__": 37
}, },
"_enabled": true, "_enabled": true,
"_materials": [ "_materials": [
@@ -1811,7 +1905,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 35 "__id__": 37
}, },
"_enabled": true, "_enabled": true,
"alignMode": 0, "alignMode": 0,
@@ -1842,7 +1936,7 @@
}, },
"_children": [ "_children": [
{ {
"__id__": 39 "__id__": 41
} }
], ],
"_active": true, "_active": true,
@@ -1900,16 +1994,16 @@
"_name": "Background", "_name": "Background",
"_objFlags": 0, "_objFlags": 0,
"_parent": { "_parent": {
"__id__": 38 "__id__": 40
}, },
"_children": [], "_children": [],
"_active": true, "_active": true,
"_components": [ "_components": [
{ {
"__id__": 40 "__id__": 42
}, },
{ {
"__id__": 41 "__id__": 43
} }
], ],
"_prefab": null, "_prefab": null,
@@ -1965,7 +2059,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 39 "__id__": 41
}, },
"_enabled": true, "_enabled": true,
"_materials": [ "_materials": [
@@ -1999,7 +2093,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 39 "__id__": 41
}, },
"_enabled": true, "_enabled": true,
"alignMode": 0, "alignMode": 0,
@@ -2035,7 +2129,7 @@
"_left": 0, "_left": 0,
"_right": 0, "_right": 0,
"_top": 0, "_top": 0,
"_bottom": 640, "_bottom": 672,
"_verticalCenter": 0, "_verticalCenter": 0,
"_horizontalCenter": 0, "_horizontalCenter": 0,
"_isAbsLeft": true, "_isAbsLeft": true,
@@ -2057,16 +2151,16 @@
}, },
"_children": [ "_children": [
{ {
"__id__": 44 "__id__": 46
} }
], ],
"_active": true, "_active": true,
"_components": [ "_components": [
{ {
"__id__": 46 "__id__": 48
}, },
{ {
"__id__": 47 "__id__": 49
} }
], ],
"_prefab": null, "_prefab": null,
@@ -2122,13 +2216,13 @@
"_name": "Joystick", "_name": "Joystick",
"_objFlags": 0, "_objFlags": 0,
"_parent": { "_parent": {
"__id__": 43 "__id__": 45
}, },
"_children": [], "_children": [],
"_active": true, "_active": true,
"_components": [ "_components": [
{ {
"__id__": 45 "__id__": 47
} }
], ],
"_prefab": null, "_prefab": null,
@@ -2184,7 +2278,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 44 "__id__": 46
}, },
"_enabled": true, "_enabled": true,
"_materials": [ "_materials": [
@@ -2218,7 +2312,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 43 "__id__": 45
}, },
"_enabled": true, "_enabled": true,
"_materials": [ "_materials": [
@@ -2252,7 +2346,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 43 "__id__": 45
}, },
"_enabled": true, "_enabled": true,
"alignMode": 0, "alignMode": 0,
@@ -2301,24 +2395,6 @@
"_originalHeight": 0, "_originalHeight": 0,
"_id": "2cxYjEIwNO6rUtXX4WcfnV" "_id": "2cxYjEIwNO6rUtXX4WcfnV"
}, },
{
"__type__": "09e1b/tEy5K2qaPIpqHDbae",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 3
},
"_enabled": true,
"BGMEffect": null,
"crashedByTrapBullet": null,
"highScoreTreasurePicked": null,
"treasurePicked": null,
"countDown10SecToEnd": null,
"mapNode": {
"__id__": 3
},
"_id": "3crA1nz5xPSLAnCSLQIPOq"
},
{ {
"__type__": "cc.Canvas", "__type__": "cc.Canvas",
"_name": "", "_name": "",
@@ -2405,10 +2481,10 @@
"__id__": 3 "__id__": 3
}, },
"stickhead": { "stickhead": {
"__id__": 44 "__id__": 46
}, },
"base": { "base": {
"__id__": 43 "__id__": 45
}, },
"joyStickEps": 0.1, "joyStickEps": 0.1,
"magicLeanLowerBound": 0.414, "magicLeanLowerBound": 0.414,
@@ -2429,10 +2505,10 @@
"linearMovingEps": 0.1, "linearMovingEps": 0.1,
"scaleByEps": 0.0375, "scaleByEps": 0.0375,
"btnA": { "btnA": {
"__id__": 34 "__id__": 36
}, },
"btnB": { "btnB": {
"__id__": 38 "__id__": 40
}, },
"_id": "e9oVYTr7ROlpp/IrNjBUmR" "_id": "e9oVYTr7ROlpp/IrNjBUmR"
} }

View File

@@ -461,7 +461,7 @@
"array": [ "array": [
0, 0,
0, 0,
209.6693197428241, 209.57814771583418,
0, 0,
0, 0,
0, 0,

View File

@@ -72,14 +72,11 @@
"__id__": 3 "__id__": 3
}, },
{ {
"__id__": 10 "__id__": 9
} }
], ],
"_active": true, "_active": true,
"_components": [ "_components": [
{
"__id__": 49
},
{ {
"__id__": 50 "__id__": 50
}, },
@@ -91,6 +88,9 @@
}, },
{ {
"__id__": 53 "__id__": 53
},
{
"__id__": 54
} }
], ],
"_prefab": null, "_prefab": null,
@@ -156,9 +156,6 @@
}, },
{ {
"__id__": 5 "__id__": 5
},
{
"__id__": 6
} }
], ],
"_prefab": null, "_prefab": null,
@@ -220,34 +217,6 @@
"_tmxFile": null, "_tmxFile": null,
"_id": "c8MqKDLJdKz7VhPwMjScDw" "_id": "c8MqKDLJdKz7VhPwMjScDw"
}, },
{
"__type__": "09e1b/tEy5K2qaPIpqHDbae",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 3
},
"_enabled": true,
"BGMEffect": {
"__uuid__": "64a79efa-97de-4cb5-b2a9-01500c60573a"
},
"crashedByTrapBullet": {
"__uuid__": "1d604e42-8cee-466f-884d-e74cae21ce3b"
},
"highScoreTreasurePicked": {
"__uuid__": "0164d22c-d965-461f-867e-b30e2d56cc5c"
},
"treasurePicked": {
"__uuid__": "7704b97e-6367-420c-b7af-d0750a2bbb30"
},
"countDown10SecToEnd": {
"__uuid__": "261d1d7d-a5cc-4cb7-a737-194427055fd4"
},
"mapNode": {
"__id__": 3
},
"_id": "3crA1nz5xPSLAnCSLQIPOq"
},
{ {
"__type__": "b3810kDSWtD14RhiYzulYVI", "__type__": "b3810kDSWtD14RhiYzulYVI",
"_name": "", "_name": "",
@@ -266,7 +235,7 @@
"__uuid__": "d92d4831-cd65-4eb5-90bd-b77021aec35b" "__uuid__": "d92d4831-cd65-4eb5-90bd-b77021aec35b"
}, },
"joystickInputControllerNode": { "joystickInputControllerNode": {
"__id__": 7 "__id__": 6
}, },
"confirmLogoutPrefab": null, "confirmLogoutPrefab": null,
"simplePressToGoDialogPrefab": null, "simplePressToGoDialogPrefab": null,
@@ -276,20 +245,22 @@
"gameRulePrefab": null, "gameRulePrefab": null,
"findingPlayerPrefab": null, "findingPlayerPrefab": null,
"countdownToBeginGamePrefab": null, "countdownToBeginGamePrefab": null,
"playersInfoPrefab": null,
"forceBigEndianFloatingNumDecoding": false, "forceBigEndianFloatingNumDecoding": false,
"renderFrameIdLagTolerance": 4, "renderFrameIdLagTolerance": 4,
"inputFrameFrontLabel": {
"__id__": 13
},
"sendingQLabel": { "sendingQLabel": {
"__id__": 14 "__id__": 15
}, },
"inputFrameDownsyncQLabel": { "inputFrameDownsyncQLabel": {
"__id__": 16 "__id__": 17
}, },
"peerInputFrameUpsyncQLabel": { "peerInputFrameUpsyncQLabel": {
"__id__": 18 "__id__": 19
}, },
"rollbackFramesLabel": { "rollbackFramesLabel": {
"__id__": 20 "__id__": 21
}, },
"skippedRenderFrameCntLabel": null, "skippedRenderFrameCntLabel": null,
"_id": "e5xQdv12xLoIRr0b36Pie+" "_id": "e5xQdv12xLoIRr0b36Pie+"
@@ -299,17 +270,17 @@
"_name": "JoystickContainer", "_name": "JoystickContainer",
"_objFlags": 0, "_objFlags": 0,
"_parent": { "_parent": {
"__id__": 8 "__id__": 7
}, },
"_children": [ "_children": [
{ {
"__id__": 43 "__id__": 44
} }
], ],
"_active": true, "_active": true,
"_components": [ "_components": [
{ {
"__id__": 48 "__id__": 49
} }
], ],
"_prefab": null, "_prefab": null,
@@ -365,26 +336,26 @@
"_name": "Interactive", "_name": "Interactive",
"_objFlags": 0, "_objFlags": 0,
"_parent": { "_parent": {
"__id__": 9 "__id__": 8
}, },
"_children": [ "_children": [
{ {
"__id__": 7 "__id__": 6
}, },
{ {
"__id__": 32 "__id__": 33
}, },
{ {
"__id__": 34 "__id__": 35
}, },
{ {
"__id__": 38 "__id__": 39
} }
], ],
"_active": true, "_active": true,
"_components": [ "_components": [
{ {
"__id__": 42 "__id__": 43
} }
], ],
"_prefab": null, "_prefab": null,
@@ -411,7 +382,7 @@
"ctor": "Float64Array", "ctor": "Float64Array",
"array": [ "array": [
0, 0,
0, 32,
0, 0,
0, 0,
0, 0,
@@ -440,20 +411,20 @@
"_name": "WidgetsAboveAll", "_name": "WidgetsAboveAll",
"_objFlags": 0, "_objFlags": 0,
"_parent": { "_parent": {
"__id__": 10 "__id__": 9
}, },
"_children": [ "_children": [
{ {
"__id__": 12 "__id__": 11
}, },
{ {
"__id__": 8 "__id__": 7
} }
], ],
"_active": true, "_active": true,
"_components": [ "_components": [
{ {
"__id__": 31 "__id__": 32
} }
], ],
"_prefab": null, "_prefab": null,
@@ -513,13 +484,13 @@
}, },
"_children": [ "_children": [
{ {
"__id__": 9 "__id__": 8
} }
], ],
"_active": true, "_active": true,
"_components": [ "_components": [
{ {
"__id__": 11 "__id__": 10
} }
], ],
"_prefab": null, "_prefab": null,
@@ -547,7 +518,7 @@
"array": [ "array": [
0, 0,
0, 0,
209.6693197428241, 210.4441731196186,
0, 0,
0, 0,
0, 0,
@@ -575,7 +546,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 10 "__id__": 9
}, },
"_enabled": true, "_enabled": true,
"_cullingMask": 4294967295, "_cullingMask": 4294967295,
@@ -611,32 +582,35 @@
"_name": "DebugInfo", "_name": "DebugInfo",
"_objFlags": 0, "_objFlags": 0,
"_parent": { "_parent": {
"__id__": 9 "__id__": 8
}, },
"_children": [ "_children": [
{ {
"__id__": 13 "__id__": 12
}, },
{ {
"__id__": 15 "__id__": 14
}, },
{ {
"__id__": 17 "__id__": 16
}, },
{ {
"__id__": 19 "__id__": 18
}, },
{ {
"__id__": 21 "__id__": 20
}, },
{ {
"__id__": 23 "__id__": 22
},
{
"__id__": 24
} }
], ],
"_active": true, "_active": true,
"_components": [ "_components": [
{ {
"__id__": 30 "__id__": 31
} }
], ],
"_prefab": null, "_prefab": null,
@@ -689,16 +663,16 @@
}, },
{ {
"__type__": "cc.Node", "__type__": "cc.Node",
"_name": "sendingQ", "_name": "inputFrameFront",
"_objFlags": 0, "_objFlags": 0,
"_parent": { "_parent": {
"__id__": 12 "__id__": 11
}, },
"_children": [], "_children": [],
"_active": true, "_active": true,
"_components": [ "_components": [
{ {
"__id__": 14 "__id__": 13
} }
], ],
"_prefab": null, "_prefab": null,
@@ -725,7 +699,99 @@
"ctor": "Float64Array", "ctor": "Float64Array",
"array": [ "array": [
0, 0,
76.48, 79.66666666666667,
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": "16ecz642FAMIrtMtKWTI/3"
},
{
"__type__": "cc.Label",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 12
},
"_enabled": true,
"_materials": [
{
"__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432"
}
],
"_useOriginalSize": false,
"_string": "0",
"_N$string": "0",
"_fontSize": 22,
"_lineHeight": 23,
"_enableWrapText": true,
"_N$file": null,
"_isSystemFontUsed": true,
"_spacingX": 0,
"_batchAsBitmap": false,
"_N$horizontalAlign": 0,
"_N$verticalAlign": 1,
"_N$fontFamily": "Arial",
"_N$overflow": 0,
"_N$cacheMode": 0,
"_id": "e2W8Kja+VG7IEwuBQapscC"
},
{
"__type__": "cc.Node",
"_name": "sendingQ",
"_objFlags": 0,
"_parent": {
"__id__": 11
},
"_children": [],
"_active": true,
"_components": [
{
"__id__": 15
}
],
"_prefab": null,
"_opacity": 255,
"_color": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_contentSize": {
"__type__": "cc.Size",
"width": 12.24,
"height": 28.98
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0,
"y": 0.5
},
"_trs": {
"__type__": "TypedArray",
"ctor": "Float64Array",
"array": [
0,
47.8,
0, 0,
0, 0,
0, 0,
@@ -754,7 +820,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 13 "__id__": 14
}, },
"_enabled": true, "_enabled": true,
"_materials": [ "_materials": [
@@ -784,13 +850,13 @@
"_name": "inputFrameDownsyncQ", "_name": "inputFrameDownsyncQ",
"_objFlags": 0, "_objFlags": 0,
"_parent": { "_parent": {
"__id__": 12 "__id__": 11
}, },
"_children": [], "_children": [],
"_active": true, "_active": true,
"_components": [ "_components": [
{ {
"__id__": 16 "__id__": 17
} }
], ],
"_prefab": null, "_prefab": null,
@@ -817,7 +883,7 @@
"ctor": "Float64Array", "ctor": "Float64Array",
"array": [ "array": [
0, 0,
38.239999999999995, 15.933333333333325,
0, 0,
0, 0,
0, 0,
@@ -846,7 +912,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 15 "__id__": 16
}, },
"_enabled": true, "_enabled": true,
"_materials": [ "_materials": [
@@ -876,13 +942,13 @@
"_name": "peerInputFrameUpsyncQ", "_name": "peerInputFrameUpsyncQ",
"_objFlags": 0, "_objFlags": 0,
"_parent": { "_parent": {
"__id__": 12 "__id__": 11
}, },
"_children": [], "_children": [],
"_active": true, "_active": true,
"_components": [ "_components": [
{ {
"__id__": 18 "__id__": 19
} }
], ],
"_prefab": null, "_prefab": null,
@@ -909,7 +975,7 @@
"ctor": "Float64Array", "ctor": "Float64Array",
"array": [ "array": [
0, 0,
-7.105427357601002e-15, -15.933333333333346,
0, 0,
0, 0,
0, 0,
@@ -938,7 +1004,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 17 "__id__": 18
}, },
"_enabled": true, "_enabled": true,
"_materials": [ "_materials": [
@@ -968,13 +1034,13 @@
"_name": "rollbackFrames", "_name": "rollbackFrames",
"_objFlags": 0, "_objFlags": 0,
"_parent": { "_parent": {
"__id__": 12 "__id__": 11
}, },
"_children": [], "_children": [],
"_active": true, "_active": true,
"_components": [ "_components": [
{ {
"__id__": 20 "__id__": 21
} }
], ],
"_prefab": null, "_prefab": null,
@@ -1001,7 +1067,7 @@
"ctor": "Float64Array", "ctor": "Float64Array",
"array": [ "array": [
0, 0,
-38.24000000000001, -47.80000000000002,
0, 0,
0, 0,
0, 0,
@@ -1030,7 +1096,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 19 "__id__": 20
}, },
"_enabled": true, "_enabled": true,
"_materials": [ "_materials": [
@@ -1060,13 +1126,13 @@
"_name": "skippedCnt", "_name": "skippedCnt",
"_objFlags": 0, "_objFlags": 0,
"_parent": { "_parent": {
"__id__": 12 "__id__": 11
}, },
"_children": [], "_children": [],
"_active": true, "_active": true,
"_components": [ "_components": [
{ {
"__id__": 22 "__id__": 23
} }
], ],
"_prefab": null, "_prefab": null,
@@ -1093,7 +1159,7 @@
"ctor": "Float64Array", "ctor": "Float64Array",
"array": [ "array": [
0, 0,
-76.48000000000002, -79.66666666666669,
0, 0,
0, 0,
0, 0,
@@ -1122,7 +1188,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 21 "__id__": 22
}, },
"_enabled": true, "_enabled": true,
"_materials": [ "_materials": [
@@ -1154,23 +1220,23 @@
"_name": "RoomIdIndicator", "_name": "RoomIdIndicator",
"_objFlags": 0, "_objFlags": 0,
"_parent": { "_parent": {
"__id__": 12 "__id__": 11
}, },
"_children": [ "_children": [
{ {
"__id__": 24 "__id__": 25
}, },
{ {
"__id__": 26 "__id__": 27
} }
], ],
"_active": false, "_active": false,
"_components": [ "_components": [
{ {
"__id__": 28 "__id__": 29
}, },
{ {
"__id__": 29 "__id__": 30
} }
], ],
"_prefab": null, "_prefab": null,
@@ -1226,13 +1292,13 @@
"_name": "label", "_name": "label",
"_objFlags": 0, "_objFlags": 0,
"_parent": { "_parent": {
"__id__": 23 "__id__": 24
}, },
"_children": [], "_children": [],
"_active": true, "_active": true,
"_components": [ "_components": [
{ {
"__id__": 25 "__id__": 26
} }
], ],
"_prefab": null, "_prefab": null,
@@ -1288,7 +1354,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 24 "__id__": 25
}, },
"_enabled": true, "_enabled": true,
"_materials": [], "_materials": [],
@@ -1316,13 +1382,13 @@
"_name": "BoundRoomIdLabel", "_name": "BoundRoomIdLabel",
"_objFlags": 0, "_objFlags": 0,
"_parent": { "_parent": {
"__id__": 23 "__id__": 24
}, },
"_children": [], "_children": [],
"_active": true, "_active": true,
"_components": [ "_components": [
{ {
"__id__": 27 "__id__": 28
} }
], ],
"_prefab": null, "_prefab": null,
@@ -1378,7 +1444,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 26 "__id__": 27
}, },
"_enabled": true, "_enabled": true,
"_materials": [], "_materials": [],
@@ -1406,7 +1472,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 23 "__id__": 24
}, },
"_enabled": true, "_enabled": true,
"_layoutSize": { "_layoutSize": {
@@ -1439,7 +1505,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 23 "__id__": 24
}, },
"_enabled": true, "_enabled": true,
"_materials": [], "_materials": [],
@@ -1469,7 +1535,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 12 "__id__": 11
}, },
"_enabled": true, "_enabled": true,
"_layoutSize": { "_layoutSize": {
@@ -1502,7 +1568,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 9 "__id__": 8
}, },
"_enabled": true, "_enabled": true,
"alignMode": 1, "alignMode": 1,
@@ -1529,13 +1595,13 @@
"_name": "CountdownSeconds", "_name": "CountdownSeconds",
"_objFlags": 0, "_objFlags": 0,
"_parent": { "_parent": {
"__id__": 8 "__id__": 7
}, },
"_children": [], "_children": [],
"_active": true, "_active": true,
"_components": [ "_components": [
{ {
"__id__": 33 "__id__": 34
} }
], ],
"_prefab": null, "_prefab": null,
@@ -1591,7 +1657,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 32 "__id__": 33
}, },
"_enabled": true, "_enabled": true,
"_materials": [ "_materials": [
@@ -1621,11 +1687,11 @@
"_name": "BtnA", "_name": "BtnA",
"_objFlags": 0, "_objFlags": 0,
"_parent": { "_parent": {
"__id__": 8 "__id__": 7
}, },
"_children": [ "_children": [
{ {
"__id__": 35 "__id__": 36
} }
], ],
"_active": true, "_active": true,
@@ -1683,16 +1749,16 @@
"_name": "Background", "_name": "Background",
"_objFlags": 0, "_objFlags": 0,
"_parent": { "_parent": {
"__id__": 34 "__id__": 35
}, },
"_children": [], "_children": [],
"_active": true, "_active": true,
"_components": [ "_components": [
{ {
"__id__": 36 "__id__": 37
}, },
{ {
"__id__": 37 "__id__": 38
} }
], ],
"_prefab": null, "_prefab": null,
@@ -1748,7 +1814,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 35 "__id__": 36
}, },
"_enabled": true, "_enabled": true,
"_materials": [ "_materials": [
@@ -1782,7 +1848,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 35 "__id__": 36
}, },
"_enabled": true, "_enabled": true,
"alignMode": 0, "alignMode": 0,
@@ -1809,11 +1875,11 @@
"_name": "BtnB", "_name": "BtnB",
"_objFlags": 0, "_objFlags": 0,
"_parent": { "_parent": {
"__id__": 8 "__id__": 7
}, },
"_children": [ "_children": [
{ {
"__id__": 39 "__id__": 40
} }
], ],
"_active": true, "_active": true,
@@ -1871,16 +1937,16 @@
"_name": "Background", "_name": "Background",
"_objFlags": 0, "_objFlags": 0,
"_parent": { "_parent": {
"__id__": 38 "__id__": 39
}, },
"_children": [], "_children": [],
"_active": true, "_active": true,
"_components": [ "_components": [
{ {
"__id__": 40 "__id__": 41
}, },
{ {
"__id__": 41 "__id__": 42
} }
], ],
"_prefab": null, "_prefab": null,
@@ -1936,7 +2002,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 39 "__id__": 40
}, },
"_enabled": true, "_enabled": true,
"_materials": [ "_materials": [
@@ -1970,7 +2036,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 39 "__id__": 40
}, },
"_enabled": true, "_enabled": true,
"alignMode": 0, "alignMode": 0,
@@ -1997,7 +2063,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 8 "__id__": 7
}, },
"_enabled": true, "_enabled": true,
"alignMode": 1, "alignMode": 1,
@@ -2024,20 +2090,20 @@
"_name": "JoystickBG", "_name": "JoystickBG",
"_objFlags": 0, "_objFlags": 0,
"_parent": { "_parent": {
"__id__": 7 "__id__": 6
}, },
"_children": [ "_children": [
{ {
"__id__": 44 "__id__": 45
} }
], ],
"_active": true, "_active": true,
"_components": [ "_components": [
{ {
"__id__": 46 "__id__": 47
}, },
{ {
"__id__": 47 "__id__": 48
} }
], ],
"_prefab": null, "_prefab": null,
@@ -2093,13 +2159,13 @@
"_name": "Joystick", "_name": "Joystick",
"_objFlags": 0, "_objFlags": 0,
"_parent": { "_parent": {
"__id__": 43 "__id__": 44
}, },
"_children": [], "_children": [],
"_active": true, "_active": true,
"_components": [ "_components": [
{ {
"__id__": 45 "__id__": 46
} }
], ],
"_prefab": null, "_prefab": null,
@@ -2155,7 +2221,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 44 "__id__": 45
}, },
"_enabled": true, "_enabled": true,
"_materials": [ "_materials": [
@@ -2189,7 +2255,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 43 "__id__": 44
}, },
"_enabled": true, "_enabled": true,
"_materials": [ "_materials": [
@@ -2223,7 +2289,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 43 "__id__": 44
}, },
"_enabled": true, "_enabled": true,
"alignMode": 0, "alignMode": 0,
@@ -2250,7 +2316,7 @@
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
"__id__": 7 "__id__": 6
}, },
"_enabled": true, "_enabled": true,
"alignMode": 0, "alignMode": 0,
@@ -2352,16 +2418,16 @@
}, },
"_enabled": true, "_enabled": true,
"translationListenerNode": { "translationListenerNode": {
"__id__": 7 "__id__": 6
}, },
"zoomingListenerNode": { "zoomingListenerNode": {
"__id__": 3 "__id__": 3
}, },
"stickhead": { "stickhead": {
"__id__": 44 "__id__": 45
}, },
"base": { "base": {
"__id__": 43 "__id__": 44
}, },
"joyStickEps": 0.1, "joyStickEps": 0.1,
"magicLeanLowerBound": 0.414, "magicLeanLowerBound": 0.414,
@@ -2382,10 +2448,10 @@
"linearMovingEps": 0.1, "linearMovingEps": 0.1,
"scaleByEps": 0.0375, "scaleByEps": 0.0375,
"btnA": { "btnA": {
"__id__": 34 "__id__": 35
}, },
"btnB": { "btnB": {
"__id__": 38 "__id__": 39
}, },
"_id": "e9oVYTr7ROlpp/IrNjBUmR" "_id": "e9oVYTr7ROlpp/IrNjBUmR"
} }

View File

@@ -19,6 +19,7 @@ window.ATK_CHARACTER_STATE = {
Dashing: [15, "Dashing"], Dashing: [15, "Dashing"],
OnWall: [16, "OnWall"], OnWall: [16, "OnWall"],
TurnAround1: [17, "TurnAround1"], TurnAround1: [17, "TurnAround1"],
Dying: [18, "Dying"],
}; };
window.ATK_CHARACTER_STATE_ARR = []; window.ATK_CHARACTER_STATE_ARR = [];
@@ -63,9 +64,6 @@ cc.Class({
ctor() { ctor() {
this.speciesName = null; this.speciesName = null;
this.hp = 100;
this.maxHp = 100;
this.inAir = true;
}, },
setSpecies(speciesName) { setSpecies(speciesName) {
@@ -85,17 +83,17 @@ cc.Class({
updateCharacterAnim(rdfPlayer, prevRdfPlayer, forceAnimSwitch, chConfig) { updateCharacterAnim(rdfPlayer, prevRdfPlayer, forceAnimSwitch, chConfig) {
// As this function might be called after many frames of a rollback, it's possible that the playing animation was predicted, different from "prevRdfPlayer.CharacterState" but same as "newCharacterState". More granular checks are needed to determine whether we should interrupt the playing animation. // As this function might be called after many frames of a rollback, it's possible that the playing animation was predicted, different from "prevRdfPlayer.CharacterState" but same as "newCharacterState". More granular checks are needed to determine whether we should interrupt the playing animation.
let newCharacterState = rdfPlayer.CharacterState; let newCharacterState = rdfPlayer.GetCharacterState();
// Update directions // Update directions
if (this.animComp && this.animComp.node) { if (this.animComp && this.animComp.node) {
if (0 > rdfPlayer.DirX) { if (0 > rdfPlayer.GetDirX()) {
this.animNode.scaleX = (-1.0); this.animNode.scaleX = (-1.0);
} else if (0 < rdfPlayer.DirX) { } else if (0 < rdfPlayer.GetDirX()) {
this.animNode.scaleX = (+1.0); this.animNode.scaleX = (+1.0);
} }
if (ATK_CHARACTER_STATE.OnWall[0] == newCharacterState || ATK_CHARACTER_STATE.TurnAround1[0] == newCharacterState) { if (ATK_CHARACTER_STATE.OnWall[0] == newCharacterState || ATK_CHARACTER_STATE.TurnAround1[0] == newCharacterState) {
if (0 < rdfPlayer.OnWallNormX) { if (0 < rdfPlayer.GetOnWallNormX()) {
this.animNode.scaleX = (-1.0); this.animNode.scaleX = (-1.0);
} else { } else {
this.animNode.scaleX = (+1.0); this.animNode.scaleX = (+1.0);
@@ -115,7 +113,6 @@ cc.Class({
playingAnimName = (!underlyingAnimationCtrl ? null : underlyingAnimationCtrl.name); playingAnimName = (!underlyingAnimationCtrl ? null : underlyingAnimationCtrl.name);
//} //}
// It turns out that "prevRdfPlayer.CharacterState" is not useful in this function :)
if (newAnimName == playingAnimName && window.ATK_CHARACTER_STATE_INTERRUPT_WAIVE_SET.has(newCharacterState)) { if (newAnimName == playingAnimName && window.ATK_CHARACTER_STATE_INTERRUPT_WAIVE_SET.has(newCharacterState)) {
// No need to interrupt // No need to interrupt
// console.warn(`JoinIndex=${rdfPlayer.joinIndex}, not interrupting ${newAnimName} while the playing anim is also ${playingAnimName}, player rdf changed from: ${null == prevRdfPlayer ? null : JSON.stringify(prevRdfPlayer)}, to: ${JSON.stringify(rdfPlayer)}`); // console.warn(`JoinIndex=${rdfPlayer.joinIndex}, not interrupting ${newAnimName} while the playing anim is also ${playingAnimName}, player rdf changed from: ${null == prevRdfPlayer ? null : JSON.stringify(prevRdfPlayer)}, to: ${JSON.stringify(rdfPlayer)}`);
@@ -150,7 +147,7 @@ cc.Class({
} }
// The "playTimes" counterpart is managed by each "cc.AnimationClip.wrapMode", already preset in the editor. // The "playTimes" counterpart is managed by each "cc.AnimationClip.wrapMode", already preset in the editor.
const targetClip = this.animComp.getClips()[newCharacterState]; // The clips follow the exact order in ATK_CHARACTER_STATE const targetClip = this.animComp.getClips()[newCharacterState]; // The clips follow the exact order in ATK_CHARACTER_STATE
let frameIdxInAnim = rdfPlayer.FramesInChState; let frameIdxInAnim = rdfPlayer.GetFramesInChState();
if (window.ATK_CHARACTER_STATE.InAirIdle1ByJump == newCharacterState && null != chConfig) { if (window.ATK_CHARACTER_STATE.InAirIdle1ByJump == newCharacterState && null != chConfig) {
frameIdxInAnim = chConfig.InAirIdleFrameIdxTurningPoint + (frameIdxInAnim - chConfig.InAirIdleFrameIdxTurningPoint) % chConfig.InAirIdleFrameIdxTurnedCycle; // TODO: Anyway to avoid using division here? frameIdxInAnim = chConfig.InAirIdleFrameIdxTurningPoint + (frameIdxInAnim - chConfig.InAirIdleFrameIdxTurningPoint) % chConfig.InAirIdleFrameIdxTurnedCycle; // TODO: Anyway to avoid using division here?
} }

View File

@@ -25,7 +25,7 @@ cc.Class({
if (!self.mapScriptIns) return; if (!self.mapScriptIns) return;
if (!self.mapScriptIns.selfPlayerInfo) return; if (!self.mapScriptIns.selfPlayerInfo) return;
if (!self.mapScriptIns.playerRichInfoDict) return; if (!self.mapScriptIns.playerRichInfoDict) return;
const selfPlayerRichInfo = self.mapScriptIns.playerRichInfoDict.get(self.mapScriptIns.selfPlayerInfo.Id); const selfPlayerRichInfo = self.mapScriptIns.playerRichInfoDict.get(self.mapScriptIns.selfPlayerInfo.id);
if (!selfPlayerRichInfo) return; if (!selfPlayerRichInfo) return;
const selfPlayerNode = selfPlayerRichInfo.node; const selfPlayerNode = selfPlayerRichInfo.node;
if (!selfPlayerNode) return; if (!selfPlayerNode) return;

View File

@@ -0,0 +1,41 @@
cc.Class({
extends: cc.Component,
properties: {
panelNode: {
type: cc.Node,
default: null
},
chosenFlag: {
type: cc.Sprite,
default: null
},
avatarNode: {
type: cc.Button,
default: null
},
animNode: {
type: cc.Node,
default: null
},
speciesId: {
type: cc.Integer,
default: 0
},
},
ctor() {},
setInteractable(enabled) {
this.avatarNode.interactable = enabled;
},
onLoad() {
const avatarNodeClickEventHandler = new cc.Component.EventHandler();
avatarNodeClickEventHandler.target = this.panelNode;
avatarNodeClickEventHandler.component = "GameRule";
avatarNodeClickEventHandler.handler = "onSpeciesSelected";
avatarNodeClickEventHandler.customEventData = this.speciesId;
this.avatarNode.clickEvents.push(avatarNodeClickEventHandler);
},
});

View File

@@ -1,6 +1,6 @@
{ {
"ver": "1.0.5", "ver": "1.0.5",
"uuid": "09e1bfed-132e-4ada-a68f-229a870db69e", "uuid": "6dd2c047-fa5c-4080-8221-27fabfd275d6",
"isPlugin": false, "isPlugin": false,
"loadPluginInWeb": true, "loadPluginInWeb": true,
"loadPluginInNative": true, "loadPluginInNative": true,

View File

@@ -10,7 +10,11 @@ cc.Class({
coordLabel: { coordLabel: {
type: cc.Label, type: cc.Label,
default: null default: null
} },
hpBar: {
type: cc.ProgressBar,
default: null
},
}, },
onLoad() { onLoad() {

View File

@@ -47,7 +47,7 @@ cc.Class({
}, },
hideExitButton() { hideExitButton() {
if (null == this.exitBtnNode != null) { if (null == this.exitBtnNode) {
return; return;
} }
this.exitBtnNode.active = false; this.exitBtnNode.active = false;

View File

@@ -13,9 +13,9 @@ cc.Class({
if (speciesName == this.speciesName) return; if (speciesName == this.speciesName) return;
if (null != this.speciesName) { if (null != this.speciesName) {
for (let k in this.animNode.children) { for (let k in this.animNode.children) {
const child = this.children[k]; const child = this.animNode.children[k];
if (!child.active) continue; if (!child.active) continue;
if (child == effAnimNode || child.name == speciesName) continue; if (child == this.effAnimNode || child.name == speciesName) continue;
child.active = false; child.active = false;
} }
} }

View File

@@ -10,15 +10,46 @@ cc.Class({
type: cc.Node, type: cc.Node,
default: null default: null
}, },
characterSelectCells: {
type: cc.Node,
default: []
},
chosenSpeciesId: {
type: cc.Integer,
default: 0
},
loadingNode: {
default: null,
type: cc.Node
},
}, },
// LIFE-CYCLE CALLBACKS: // LIFE-CYCLE CALLBACKS:
onLoad() { onLoad() {
const modeBtnClickEventHandler = new cc.Component.EventHandler(); },
modeBtnClickEventHandler.target = this.mapNode;
modeBtnClickEventHandler.component = "Map"; onSpeciesSelected(evt, val) {
modeBtnClickEventHandler.handler = "onGameRule1v1ModeClicked"; for (let cell of this.characterSelectCells) {
this.modeButton.clickEvents.push(modeBtnClickEventHandler); const comp = cell.getComponent("CharacterSelectCell");
} if (comp.speciesId != val) {
comp.chosenFlag.node.active = false;
} else {
comp.chosenFlag.node.active = true;
this.chosenSpeciesId = val;
}
}
},
onModeButtonClicked(evt) {
for (let cell of this.characterSelectCells) {
const comp = cell.getComponent("CharacterSelectCell");
comp.setInteractable(false);
}
this.modeButton.node.active = false;
this.loadingNode.active = true;
this.loadingNode.runAction(
cc.repeatForever(cc.rotateBy(1.0, 360))
);
this.mapNode.getComponent("Map").onGameRule1v1ModeClicked(this.chosenSpeciesId);
},
}); });

View File

@@ -337,6 +337,7 @@ cc.Class({
const date = Number(res.expiresAt); const date = Number(res.expiresAt);
const selfPlayer = { const selfPlayer = {
expiresAt: date, expiresAt: date,
id: res.playerId,
playerId: res.playerId, playerId: res.playerId,
intAuthToken: res.intAuthToken, intAuthToken: res.intAuthToken,
avatar: res.avatar, avatar: res.avatar,
@@ -354,6 +355,7 @@ cc.Class({
self.loadingNode.getChildByName('loadingSprite').runAction( self.loadingNode.getChildByName('loadingSprite').runAction(
cc.repeatForever(cc.rotateBy(1.0, 360)) cc.repeatForever(cc.rotateBy(1.0, 360))
); );
self.loadingNode.getChildByName('loadingLabel').active = true;
cc.director.loadScene('default_map'); cc.director.loadScene('default_map');
} else { } else {
console.log("OnLoggedIn failed, about to remove `selfPlayer` in local cache.") console.log("OnLoggedIn failed, about to remove `selfPlayer` in local cache.")

File diff suppressed because it is too large Load Diff

View File

@@ -1,66 +0,0 @@
cc.Class({
extends: cc.Component,
properties: {
BGMEffect: {
type: cc.AudioClip,
default: null
},
crashedByTrapBullet: {
type: cc.AudioClip,
default: null
},
highScoreTreasurePicked: {
type: cc.AudioClip,
default: null
},
treasurePicked: {
type: cc.AudioClip,
default: null
},
countDown10SecToEnd: {
type: cc.AudioClip,
default: null
},
mapNode: {
type: cc.Node,
default: null
},
},
// LIFE-CYCLE CALLBACKS:
onLoad() {
cc.audioEngine.setEffectsVolume(1);
cc.audioEngine.setMusicVolume(0.5);
},
stopAllMusic() {
cc.audioEngine.stopAll();
},
playBGM() {
if(this.BGMEffect) {
cc.audioEngine.playMusic(this.BGMEffect, true);
}
},
playCrashedByTrapBullet() {
if(this.crashedByTrapBullet) {
cc.audioEngine.playEffect(this.crashedByTrapBullet, false);
}
},
playHighScoreTreasurePicked() {
if(this.highScoreTreasurePicked) {
cc.audioEngine.playEffect(this.highScoreTreasurePicked, false);
}
},
playTreasurePicked() {
if(this.treasurePicked) {
cc.audioEngine.playEffect(this.treasurePicked, false);
}
},
playCountDown10SecToEnd() {
if(this.countDown10SecToEnd) {
cc.audioEngine.playEffect(this.countDown10SecToEnd, false);
}
},
});

View File

@@ -5,6 +5,7 @@ var NetworkDoctor = function(capacity) {
}; };
NetworkDoctor.prototype.reset = function(capacity) { NetworkDoctor.prototype.reset = function(capacity) {
this.inputFrameIdFront = 0;
this.sendingQ = new RingBuffer(capacity); this.sendingQ = new RingBuffer(capacity);
this.inputFrameDownsyncQ = new RingBuffer(capacity); this.inputFrameDownsyncQ = new RingBuffer(capacity);
this.peerInputFrameUpsyncQ = new RingBuffer(capacity); this.peerInputFrameUpsyncQ = new RingBuffer(capacity);
@@ -17,6 +18,10 @@ NetworkDoctor.prototype.reset = function(capacity) {
this.rollbackFramesThreshold = 8; // Roughly the minimum "TurnAroundFramesToRecover". this.rollbackFramesThreshold = 8; // Roughly the minimum "TurnAroundFramesToRecover".
}; };
NetworkDoctor.prototype.logInputFrameIdFront = function(inputFrameId) {
this.inputFrameIdFront = inputFrameId;
};
NetworkDoctor.prototype.logSending = function(stFrameId, edFrameId) { NetworkDoctor.prototype.logSending = function(stFrameId, edFrameId) {
this.sendingQ.put({ this.sendingQ.put({
i: stFrameId, i: stFrameId,
@@ -50,7 +55,8 @@ NetworkDoctor.prototype.logRollbackFrames = function(x) {
}; };
NetworkDoctor.prototype.stats = function() { NetworkDoctor.prototype.stats = function() {
let sendingFps = 0, let inputFrameIdFront = this.inputFrameIdFront,
sendingFps = 0,
srvDownsyncFps = 0, srvDownsyncFps = 0,
peerUpsyncFps = 0, peerUpsyncFps = 0,
rollbackFrames = this.immediateRollbackFrames; rollbackFrames = this.immediateRollbackFrames;
@@ -72,7 +78,7 @@ NetworkDoctor.prototype.stats = function() {
const elapsedMillis = ed.t - st.t; const elapsedMillis = ed.t - st.t;
peerUpsyncFps = Math.round(this.peerInputFrameUpsyncCnt * 1000 / elapsedMillis); peerUpsyncFps = Math.round(this.peerInputFrameUpsyncCnt * 1000 / elapsedMillis);
} }
return [sendingFps, srvDownsyncFps, peerUpsyncFps, rollbackFrames, this.skippedRenderFrameCnt]; return [inputFrameIdFront, sendingFps, srvDownsyncFps, peerUpsyncFps, rollbackFrames, this.skippedRenderFrameCnt];
}; };
NetworkDoctor.prototype.logSkippedRenderFrameCnt = function() { NetworkDoctor.prototype.logSkippedRenderFrameCnt = function() {
@@ -80,31 +86,36 @@ NetworkDoctor.prototype.logSkippedRenderFrameCnt = function() {
} }
NetworkDoctor.prototype.isTooFast = function(mapIns) { NetworkDoctor.prototype.isTooFast = function(mapIns) {
const [sendingFps, srvDownsyncFps, peerUpsyncFps, rollbackFrames, skippedRenderFrameCnt] = this.stats(); const [inputFrameIdFront, sendingFps, srvDownsyncFps, peerUpsyncFps, rollbackFrames, skippedRenderFrameCnt] = this.stats();
if (sendingFps >= this.inputRateThreshold + 3) { if (sendingFps >= this.inputRateThreshold + 3) {
// Don't send too fast // Don't send too fast
console.log(`Sending too fast, sendingFps=${sendingFps}`); if (CC_DEBUG) {
return true; // Printing of this message might induce a performance impact.
// console.log(`Sending too fast, sendingFps=${sendingFps}`);
}
return [true, inputFrameIdFront, sendingFps, srvDownsyncFps, peerUpsyncFps, rollbackFrames, skippedRenderFrameCnt];
} else { } else {
const sendingFpsNormal = (sendingFps >= this.inputRateThreshold); const sendingFpsNormal = (sendingFps >= this.inputRateThreshold);
// An outstanding lag within the "inputFrameDownsyncQ" will reduce "srvDownsyncFps", HOWEVER, a constant lag wouldn't impact "srvDownsyncFps"! In native platforms we might use PING value might help as a supplement information to confirm that the "selfPlayer" is not lagged within the time accounted by "inputFrameDownsyncQ". // An outstanding lag within the "inputFrameDownsyncQ" will reduce "srvDownsyncFps", HOWEVER, a constant lag wouldn't impact "srvDownsyncFps"! In native platforms we might use PING value might help as a supplement information to confirm that the "selfPlayer" is not lagged within the time accounted by "inputFrameDownsyncQ".
const recvFpsNormal = (srvDownsyncFps >= this.inputRateThreshold || peerUpsyncFps >= this.inputRateThreshold * (window.boundRoomCapacity - 1)); const recvFpsNormal = (srvDownsyncFps >= this.inputRateThreshold || peerUpsyncFps >= this.inputRateThreshold * (window.boundRoomCapacity - 1));
if (sendingFpsNormal && recvFpsNormal) { if (sendingFpsNormal && recvFpsNormal) {
let selfInputFrameIdFront = gopkgs.ConvertToNoDelayInputFrameId(mapIns.renderFrameId);
let minInputFrameIdFront = Number.MAX_VALUE; let minInputFrameIdFront = Number.MAX_VALUE;
for (let k = 0; k < window.boundRoomCapacity; ++k) { for (let k = 0; k < window.boundRoomCapacity; ++k) {
if (k + 1 == mapIns.selfPlayerInfo.JoinIndex) continue; if (k + 1 == mapIns.selfPlayerInfo.JoinIndex) continue;
if (mapIns.lastIndividuallyConfirmedInputFrameId[k] >= minInputFrameIdFront) continue; if (mapIns.lastIndividuallyConfirmedInputFrameId[k] >= minInputFrameIdFront) continue;
minInputFrameIdFront = mapIns.lastIndividuallyConfirmedInputFrameId[k]; minInputFrameIdFront = mapIns.lastIndividuallyConfirmedInputFrameId[k];
} }
if ((selfInputFrameIdFront > minInputFrameIdFront) && ((selfInputFrameIdFront - minInputFrameIdFront) > (mapIns.inputFrameUpsyncDelayTolerance + 1))) { if ((inputFrameIdFront > minInputFrameIdFront) && ((inputFrameIdFront - minInputFrameIdFront) > (mapIns.inputFrameUpsyncDelayTolerance + 1))) {
// first comparison condition is to avoid numeric overflow // first comparison condition is to avoid numeric overflow
console.log(`Game logic ticking too fast, selfInputFrameIdFront=${selfInputFrameIdFront}, minInputFrameIdFront=${minInputFrameIdFront}, inputFrameUpsyncDelayTolerance=${mapIns.inputFrameUpsyncDelayTolerance}`); if (CC_DEBUG) {
return true; // Printing of this message might induce a performance impact.
// console.log(`Game logic ticking too fast, selfInputFrameIdFront=${inputFrameIdFront}, minInputFrameIdFront=${minInputFrameIdFront}, inputFrameUpsyncDelayTolerance=${mapIns.inputFrameUpsyncDelayTolerance}`);
}
return [true, inputFrameIdFront, sendingFps, srvDownsyncFps, peerUpsyncFps, rollbackFrames, skippedRenderFrameCnt];
} }
} }
} }
return false; return [false, inputFrameIdFront, sendingFps, srvDownsyncFps, peerUpsyncFps, rollbackFrames, skippedRenderFrameCnt];
}; };
module.exports = NetworkDoctor; module.exports = NetworkDoctor;

View File

@@ -11,13 +11,13 @@ cc.Class({
}, },
onLoad() { onLoad() {
cc.game.setFrameRate(60); cc.game.setFrameRate(59.9);
cc.view.setOrientation(cc.macro.ORIENTATION_LANDSCAPE); cc.view.setOrientation(cc.macro.ORIENTATION_LANDSCAPE);
cc.view.enableAutoFullScreen(true); cc.view.enableAutoFullScreen(true);
const self = this; const self = this;
window.mapIns = self; window.mapIns = self;
self.showCriticalCoordinateLabels = false; self.showCriticalCoordinateLabels = false;
self.showNetworkDoctorInfo = true; self.showNetworkDoctorInfo = false;
const mapNode = self.node; const mapNode = self.node;
const canvasNode = mapNode.parent; const canvasNode = mapNode.parent;
@@ -33,9 +33,9 @@ cc.Class({
/** Init required prefab ended. */ /** Init required prefab ended. */
self.inputFrameUpsyncDelayTolerance = 2; self.inputFrameUpsyncDelayTolerance = 2;
self.collisionMinStep = 2; self.collisionMinStep = 16;
self.renderCacheSize = 1024; self.renderCacheSize = 128;
self.serverFps = 60; self.serverFps = 60;
self.rollbackEstimatedDt = 0.016667; self.rollbackEstimatedDt = 0.016667;
self.rollbackEstimatedDtMillis = 16.667; self.rollbackEstimatedDtMillis = 16.667;
@@ -73,6 +73,7 @@ cc.Class({
self.spaceOffsetX = ((newMapSize.width * newTileSize.width) >> 1); self.spaceOffsetX = ((newMapSize.width * newTileSize.width) >> 1);
self.spaceOffsetY = ((newMapSize.height * newTileSize.height) >> 1); self.spaceOffsetY = ((newMapSize.height * newTileSize.height) >> 1);
window.boundRoomCapacity = 2;
self._resetCurrentMatch(); self._resetCurrentMatch();
let barrierIdCounter = 0; let barrierIdCounter = 0;
const boundaryObjs = tileCollisionManager.extractBoundaryObjects(self.node); const boundaryObjs = tileCollisionManager.extractBoundaryObjects(self.node);
@@ -98,7 +99,7 @@ cc.Class({
const p2Vpos = gopkgs.WorldToVirtualGridPos(boundaryObjs.playerStartingPositions[1].x, boundaryObjs.playerStartingPositions[1].y); const p2Vpos = gopkgs.WorldToVirtualGridPos(boundaryObjs.playerStartingPositions[1].x, boundaryObjs.playerStartingPositions[1].y);
const colliderRadiusV = gopkgs.WorldToVirtualGridPos(12.0, 0); const colliderRadiusV = gopkgs.WorldToVirtualGridPos(12.0, 0);
const speciesIdList = [1, 4096]; const speciesIdList = [1, 0];
const chConfigsOrderedByJoinIndex = gopkgs.GetCharacterConfigsOrderedByJoinIndex(speciesIdList); const chConfigsOrderedByJoinIndex = gopkgs.GetCharacterConfigsOrderedByJoinIndex(speciesIdList);
const startRdf = window.pb.protos.RoomDownsyncFrame.create({ const startRdf = window.pb.protos.RoomDownsyncFrame.create({
@@ -109,7 +110,9 @@ cc.Class({
joinIndex: 1, joinIndex: 1,
virtualGridX: p1Vpos[0], virtualGridX: p1Vpos[0],
virtualGridY: p1Vpos[1], virtualGridY: p1Vpos[1],
speed: chConfigsOrderedByJoinIndex[0].Speed, revivalVirtualGridX: p1Vpos[0],
revivalVirtualGridY: p1Vpos[1],
speed: chConfigsOrderedByJoinIndex[0].GetSpeed(),
colliderRadius: colliderRadiusV[0], colliderRadius: colliderRadiusV[0],
characterState: window.ATK_CHARACTER_STATE.InAirIdle1NoJump[0], characterState: window.ATK_CHARACTER_STATE.InAirIdle1NoJump[0],
framesToRecover: 0, framesToRecover: 0,
@@ -119,13 +122,17 @@ cc.Class({
velY: 0, velY: 0,
inAir: true, inAir: true,
onWall: false, onWall: false,
hp: 100,
maxHp: 100,
}), }),
window.pb.protos.PlayerDownsync.create({ window.pb.protos.PlayerDownsync.create({
id: 11, id: 11,
joinIndex: 2, joinIndex: 2,
virtualGridX: p2Vpos[0], virtualGridX: p2Vpos[0],
virtualGridY: p2Vpos[1], virtualGridY: p2Vpos[1],
speed: chConfigsOrderedByJoinIndex[1].Speed, revivalVirtualGridX: p2Vpos[0],
revivalVirtualGridY: p2Vpos[1],
speed: chConfigsOrderedByJoinIndex[1].GetSpeed(),
colliderRadius: colliderRadiusV[0], colliderRadius: colliderRadiusV[0],
characterState: window.ATK_CHARACTER_STATE.InAirIdle1NoJump[0], characterState: window.ATK_CHARACTER_STATE.InAirIdle1NoJump[0],
framesToRecover: 0, framesToRecover: 0,
@@ -135,14 +142,16 @@ cc.Class({
velY: 0, velY: 0,
inAir: true, inAir: true,
onWall: false, onWall: false,
hp: 100,
maxHp: 100,
}), }),
], ],
speciesIdList: speciesIdList, speciesIdList: speciesIdList,
}); });
self.selfPlayerInfo = { self.selfPlayerInfo = {
Id: 10, id: 10,
JoinIndex: 1, joinIndex: 1,
}; };
if (cc.sys.isNative) { if (cc.sys.isNative) {
window.onUdpMessage = (args) => { window.onUdpMessage = (args) => {
@@ -155,7 +164,7 @@ cc.Class({
const echoed = window.pb.protos.HolePunchUpsync.decode(ui8Arr); const echoed = window.pb.protos.HolePunchUpsync.decode(ui8Arr);
cc.log(`#2 Js called back by CPP: onUdpMessage: ${JSON.stringify(echoed)}`); cc.log(`#2 Js called back by CPP: onUdpMessage: ${JSON.stringify(echoed)}`);
}; };
const res1 = DelayNoMore.UdpSession.openUdpSession(8888 + self.selfPlayerInfo.JoinIndex); const res1 = DelayNoMore.UdpSession.openUdpSession(8888 + self.selfPlayerInfo.joinIndex);
const holePunchData = window.pb.protos.HolePunchUpsync.encode({ const holePunchData = window.pb.protos.HolePunchUpsync.encode({
boundRoomId: 22, boundRoomId: 22,
intAuthToken: "foobar", intAuthToken: "foobar",

View File

@@ -58,10 +58,21 @@ window.getBoundRoomCapacityFromPersistentStorage = function() {
return (null == boundRoomCapacityStr ? null : parseInt(boundRoomCapacityStr)); return (null == boundRoomCapacityStr ? null : parseInt(boundRoomCapacityStr));
}; };
window.getChosenSpeciesIdFromPersistentStorage = function() {
const boundRoomIdExpiresAt = parseInt(cc.sys.localStorage.getItem("boundRoomIdExpiresAt"));
if (!boundRoomIdExpiresAt || Date.now() >= boundRoomIdExpiresAt) {
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
return null;
}
const chosenSpeciesIdStr = cc.sys.localStorage.getItem("chosenSpeciesId");
return (null == chosenSpeciesIdStr ? 0 : parseInt(chosenSpeciesIdStr));
};
window.clearBoundRoomIdInBothVolatileAndPersistentStorage = function() { window.clearBoundRoomIdInBothVolatileAndPersistentStorage = function() {
window.boundRoomId = null; window.boundRoomId = null;
cc.sys.localStorage.removeItem("boundRoomId"); cc.sys.localStorage.removeItem("boundRoomId");
cc.sys.localStorage.removeItem("boundRoomCapacity"); cc.sys.localStorage.removeItem("boundRoomCapacity");
cc.sys.localStorage.removeItem("chosenSpeciesId");
cc.sys.localStorage.removeItem("boundRoomIdExpiresAt"); cc.sys.localStorage.removeItem("boundRoomIdExpiresAt");
}; };
@@ -76,14 +87,15 @@ window.handleHbRequirements = function(resp) {
if (constants.RET_CODE.OK != resp.ret) return; if (constants.RET_CODE.OK != resp.ret) return;
// The assignment of "window.mapIns" is inside "Map.onLoad", which precedes "initPersistentSessionClient". // The assignment of "window.mapIns" is inside "Map.onLoad", which precedes "initPersistentSessionClient".
window.mapIns.selfPlayerInfo = JSON.parse(cc.sys.localStorage.getItem('selfPlayer')); // This field is kept for distinguishing "self" and "others". window.mapIns.selfPlayerInfo = JSON.parse(cc.sys.localStorage.getItem('selfPlayer')); // This field is kept for distinguishing "self" and "others".
window.mapIns.selfPlayerInfo.Id = window.mapIns.selfPlayerInfo.playerId; window.mapIns.selfPlayerInfo.id = window.mapIns.selfPlayerInfo.playerId;
window.mapIns.selfPlayerInfo.JoinIndex = resp.peerJoinIndex; window.mapIns.selfPlayerInfo.joinIndex = resp.peerJoinIndex;
console.log(`Handle hb requirements #2`); console.log(`Handle hb requirements #2`);
if (null == window.boundRoomId || null == window.boundRoomCapacity) { if (null == window.boundRoomId || null == window.boundRoomCapacity) {
window.boundRoomId = resp.bciFrame.boundRoomId; window.boundRoomId = resp.bciFrame.boundRoomId;
window.boundRoomCapacity = resp.bciFrame.boundRoomCapacity; window.boundRoomCapacity = resp.bciFrame.boundRoomCapacity;
cc.sys.localStorage.setItem('boundRoomId', window.boundRoomId); cc.sys.localStorage.setItem('boundRoomId', window.boundRoomId);
cc.sys.localStorage.setItem('boundRoomCapacity', window.boundRoomCapacity); cc.sys.localStorage.setItem('boundRoomCapacity', window.boundRoomCapacity);
cc.sys.localStorage.setItem('chosenSpeciesId', window.chosenSpeciesId);
cc.sys.localStorage.setItem('boundRoomIdExpiresAt', Date.now() + 10 * 60 * 1000); // Temporarily hardcoded, for `boundRoomId` only. cc.sys.localStorage.setItem('boundRoomIdExpiresAt', Date.now() + 10 * 60 * 1000); // Temporarily hardcoded, for `boundRoomId` only.
} }
console.log(`Handle hb requirements #3`); console.log(`Handle hb requirements #3`);
@@ -97,7 +109,7 @@ window.handleHbRequirements = function(resp) {
window.initSecondarySession(null, window.boundRoomId); window.initSecondarySession(null, window.boundRoomId);
} else { } else {
console.log(`Handle hb requirements #5, native, bciFrame.battleUdpTunnel=${resp.bciFrame.battleUdpTunnel}, selfPlayerInfo=${JSON.stringify(window.mapIns.selfPlayerInfo)}`); console.log(`Handle hb requirements #5, native, bciFrame.battleUdpTunnel=${resp.bciFrame.battleUdpTunnel}, selfPlayerInfo=${JSON.stringify(window.mapIns.selfPlayerInfo)}`);
const res1 = DelayNoMore.UdpSession.openUdpSession(8888 + window.mapIns.selfPlayerInfo.JoinIndex); const res1 = DelayNoMore.UdpSession.openUdpSession(8888 + window.mapIns.selfPlayerInfo.joinIndex);
window.mapIns.selfPlayerInfo.udpTunnelAuthKey = resp.bciFrame.battleUdpTunnel.authKey; window.mapIns.selfPlayerInfo.udpTunnelAuthKey = resp.bciFrame.battleUdpTunnel.authKey;
const intAuthToken = window.mapIns.selfPlayerInfo.intAuthToken; const intAuthToken = window.mapIns.selfPlayerInfo.intAuthToken;
const authKey = Math.floor(Math.random() * 65535); const authKey = Math.floor(Math.random() * 65535);
@@ -109,7 +121,7 @@ window.handleHbRequirements = function(resp) {
}).finish(); }).finish();
const udpTunnelHolePunchData = window.pb.protos.WsReq.encode({ const udpTunnelHolePunchData = window.pb.protos.WsReq.encode({
msgId: Date.now(), msgId: Date.now(),
playerId: window.mapIns.selfPlayerInfo.Id, playerId: window.mapIns.selfPlayerInfo.id,
act: window.UPSYNC_MSG_ACT_PLAYER_CMD, act: window.UPSYNC_MSG_ACT_PLAYER_CMD,
authKey: resp.bciFrame.battleUdpTunnel.authKey, authKey: resp.bciFrame.battleUdpTunnel.authKey,
}).finish(); }).finish();
@@ -179,6 +191,13 @@ window.initPersistentSessionClient = function(onopenCb, expectedRoomId) {
} }
} }
if (null == window.chosenSpeciesId) {
window.chosenSpeciesId = getChosenSpeciesIdFromPersistentStorage();
}
if (null != window.chosenSpeciesId) {
urlToConnect = urlToConnect + "&speciesId=" + window.chosenSpeciesId;
}
const clientSession = new WebSocket(urlToConnect); const clientSession = new WebSocket(urlToConnect);
clientSession.binaryType = 'arraybuffer'; // Make 'event.data' of 'onmessage' an "ArrayBuffer" instead of a "Blob" clientSession.binaryType = 'arraybuffer'; // Make 'event.data' of 'onmessage' an "ArrayBuffer" instead of a "Blob"
@@ -230,9 +249,9 @@ window.initPersistentSessionClient = function(onopenCb, expectedRoomId) {
const peerAddrList = resp.rdf.peerUdpAddrList; const peerAddrList = resp.rdf.peerUdpAddrList;
console.log(`Got DOWNSYNC_MSG_ACT_PEER_UDP_ADDR peerAddrList=${JSON.stringify(peerAddrList)}; boundRoomCapacity=${window.boundRoomCapacity}`); console.log(`Got DOWNSYNC_MSG_ACT_PEER_UDP_ADDR peerAddrList=${JSON.stringify(peerAddrList)}; boundRoomCapacity=${window.boundRoomCapacity}`);
for (let j = 0; j < 3; ++j) { for (let j = 0; j < 3; ++j) {
setTimeout(()=> { setTimeout(() => {
DelayNoMore.UdpSession.upsertPeerUdpAddr(peerAddrList, window.boundRoomCapacity, window.mapIns.selfPlayerInfo.JoinIndex); // In C++ impl it actually broadcasts the peer-punching message to all known peers within "window.boundRoomCapacity" DelayNoMore.UdpSession.upsertPeerUdpAddr(peerAddrList, window.boundRoomCapacity, window.mapIns.selfPlayerInfo.joinIndex); // In C++ impl it actually broadcasts the peer-punching message to all known peers within "window.boundRoomCapacity"
}, j*500); }, j * 500);
} }
} }
break; break;
@@ -269,13 +288,21 @@ window.initPersistentSessionClient = function(onopenCb, expectedRoomId) {
`); `);
} }
break; break;
case constants.RET_CODE.SAME_PLAYER_ALREADY_IN_SAME_ROOM:
mapIns.popupSimplePressToGo("You just logged into a conflicting account, please use a different account to retry", false, () => {
window.clearLocalStorageAndBackToLoginScene(true);
});
break;
case constants.RET_CODE.PLAYER_NOT_ADDABLE_TO_ROOM: case constants.RET_CODE.PLAYER_NOT_ADDABLE_TO_ROOM:
case constants.RET_CODE.PLAYER_NOT_READDABLE_TO_ROOM: case constants.RET_CODE.PLAYER_NOT_READDABLE_TO_ROOM:
window.clearBoundRoomIdInBothVolatileAndPersistentStorage(); // To favor the player to join other rooms mapIns.popupSimplePressToGo("Couldn't join any room at the moment, please retry", false, () => {
mapIns.onManualRejoinRequired("Couldn't join any room at the moment, please retry"); window.clearLocalStorageAndBackToLoginScene(true);
});
break; break;
case constants.RET_CODE.ACTIVE_WATCHDOG: case constants.RET_CODE.ACTIVE_WATCHDOG:
mapIns.onManualRejoinRequired("Disconnected due to long-time inactivity, please rejoin"); mapIns.popupSimplePressToGo("Couldn't join any room at the moment, please retry", false, () => {
window.clearLocalStorageAndBackToLoginScene(true);
});
break; break;
case constants.RET_CODE.UNKNOWN_ERROR: case constants.RET_CODE.UNKNOWN_ERROR:
case constants.RET_CODE.MYSQL_ERROR: case constants.RET_CODE.MYSQL_ERROR:
@@ -286,9 +313,19 @@ window.initPersistentSessionClient = function(onopenCb, expectedRoomId) {
console.warn(`${mapIns._stringifyRdfIdToActuallyUsedInput()} console.warn(`${mapIns._stringifyRdfIdToActuallyUsedInput()}
`); `);
} }
window.clearLocalStorageAndBackToLoginScene(true); mapIns.popupSimplePressToGo("Disconnected unexpectedly, please retry", false, () => {
break; window.clearLocalStorageAndBackToLoginScene(true);
});
default: default:
if (cc.sys.isNative) {
// [WARNING] This could be a BUG in CocosCreator JSB implementation of WebSocket client, the "evt.code" is always "undefined" in the "onclose" callback!
if (window.ALL_BATTLE_STATES.IN_SETTLEMENT != mapIns.battleState && window.ALL_BATTLE_STATES.IN_DISMISSAL != mapIns.battleState) {
mapIns.popupSimplePressToGo("Disconnected unexpectedly, please retry", false, () => {
window.clearLocalStorageAndBackToLoginScene(true);
});
}
}
break; break;
} }
}; };

File diff suppressed because one or more lines are too long

View File

@@ -1,7 +1,7 @@
{ {
"ver": "1.0.5", "ver": "1.0.5",
"uuid": "22e2b0ab-1350-4f5e-9960-f2b45b0bf353", "uuid": "02c5cdc1-9797-49ab-bc11-963215909926",
"isPlugin": false, "isPlugin": true,
"loadPluginInWeb": true, "loadPluginInWeb": true,
"loadPluginInNative": true, "loadPluginInNative": true,
"loadPluginInEditor": false, "loadPluginInEditor": false,

View File

@@ -1220,6 +1220,8 @@ $root.protos = (function() {
* @property {number|null} [onWallNormX] PlayerDownsync onWallNormX * @property {number|null} [onWallNormX] PlayerDownsync onWallNormX
* @property {number|null} [onWallNormY] PlayerDownsync onWallNormY * @property {number|null} [onWallNormY] PlayerDownsync onWallNormY
* @property {boolean|null} [capturedByInertia] PlayerDownsync capturedByInertia * @property {boolean|null} [capturedByInertia] PlayerDownsync capturedByInertia
* @property {number|null} [revivalVirtualGridX] PlayerDownsync revivalVirtualGridX
* @property {number|null} [revivalVirtualGridY] PlayerDownsync revivalVirtualGridY
* @property {string|null} [name] PlayerDownsync name * @property {string|null} [name] PlayerDownsync name
* @property {string|null} [displayName] PlayerDownsync displayName * @property {string|null} [displayName] PlayerDownsync displayName
* @property {string|null} [avatar] PlayerDownsync avatar * @property {string|null} [avatar] PlayerDownsync avatar
@@ -1472,6 +1474,22 @@ $root.protos = (function() {
*/ */
PlayerDownsync.prototype.capturedByInertia = false; PlayerDownsync.prototype.capturedByInertia = false;
/**
* PlayerDownsync revivalVirtualGridX.
* @member {number} revivalVirtualGridX
* @memberof protos.PlayerDownsync
* @instance
*/
PlayerDownsync.prototype.revivalVirtualGridX = 0;
/**
* PlayerDownsync revivalVirtualGridY.
* @member {number} revivalVirtualGridY
* @memberof protos.PlayerDownsync
* @instance
*/
PlayerDownsync.prototype.revivalVirtualGridY = 0;
/** /**
* PlayerDownsync name. * PlayerDownsync name.
* @member {string} name * @member {string} name
@@ -1578,6 +1596,10 @@ $root.protos = (function() {
writer.uint32(/* id 28, wireType 0 =*/224).int32(message.onWallNormY); writer.uint32(/* id 28, wireType 0 =*/224).int32(message.onWallNormY);
if (message.capturedByInertia != null && Object.hasOwnProperty.call(message, "capturedByInertia")) if (message.capturedByInertia != null && Object.hasOwnProperty.call(message, "capturedByInertia"))
writer.uint32(/* id 29, wireType 0 =*/232).bool(message.capturedByInertia); writer.uint32(/* id 29, wireType 0 =*/232).bool(message.capturedByInertia);
if (message.revivalVirtualGridX != null && Object.hasOwnProperty.call(message, "revivalVirtualGridX"))
writer.uint32(/* id 30, wireType 0 =*/240).int32(message.revivalVirtualGridX);
if (message.revivalVirtualGridY != null && Object.hasOwnProperty.call(message, "revivalVirtualGridY"))
writer.uint32(/* id 31, wireType 0 =*/248).int32(message.revivalVirtualGridY);
if (message.name != null && Object.hasOwnProperty.call(message, "name")) if (message.name != null && Object.hasOwnProperty.call(message, "name"))
writer.uint32(/* id 997, wireType 2 =*/7978).string(message.name); writer.uint32(/* id 997, wireType 2 =*/7978).string(message.name);
if (message.displayName != null && Object.hasOwnProperty.call(message, "displayName")) if (message.displayName != null && Object.hasOwnProperty.call(message, "displayName"))
@@ -1734,6 +1756,14 @@ $root.protos = (function() {
message.capturedByInertia = reader.bool(); message.capturedByInertia = reader.bool();
break; break;
} }
case 30: {
message.revivalVirtualGridX = reader.int32();
break;
}
case 31: {
message.revivalVirtualGridY = reader.int32();
break;
}
case 997: { case 997: {
message.name = reader.string(); message.name = reader.string();
break; break;
@@ -1868,6 +1898,12 @@ $root.protos = (function() {
if (message.capturedByInertia != null && message.hasOwnProperty("capturedByInertia")) if (message.capturedByInertia != null && message.hasOwnProperty("capturedByInertia"))
if (typeof message.capturedByInertia !== "boolean") if (typeof message.capturedByInertia !== "boolean")
return "capturedByInertia: boolean expected"; return "capturedByInertia: boolean expected";
if (message.revivalVirtualGridX != null && message.hasOwnProperty("revivalVirtualGridX"))
if (!$util.isInteger(message.revivalVirtualGridX))
return "revivalVirtualGridX: integer expected";
if (message.revivalVirtualGridY != null && message.hasOwnProperty("revivalVirtualGridY"))
if (!$util.isInteger(message.revivalVirtualGridY))
return "revivalVirtualGridY: integer expected";
if (message.name != null && message.hasOwnProperty("name")) if (message.name != null && message.hasOwnProperty("name"))
if (!$util.isString(message.name)) if (!$util.isString(message.name))
return "name: string expected"; return "name: string expected";
@@ -1950,6 +1986,10 @@ $root.protos = (function() {
message.onWallNormY = object.onWallNormY | 0; message.onWallNormY = object.onWallNormY | 0;
if (object.capturedByInertia != null) if (object.capturedByInertia != null)
message.capturedByInertia = Boolean(object.capturedByInertia); message.capturedByInertia = Boolean(object.capturedByInertia);
if (object.revivalVirtualGridX != null)
message.revivalVirtualGridX = object.revivalVirtualGridX | 0;
if (object.revivalVirtualGridY != null)
message.revivalVirtualGridY = object.revivalVirtualGridY | 0;
if (object.name != null) if (object.name != null)
message.name = String(object.name); message.name = String(object.name);
if (object.displayName != null) if (object.displayName != null)
@@ -2002,6 +2042,8 @@ $root.protos = (function() {
object.onWallNormX = 0; object.onWallNormX = 0;
object.onWallNormY = 0; object.onWallNormY = 0;
object.capturedByInertia = false; object.capturedByInertia = false;
object.revivalVirtualGridX = 0;
object.revivalVirtualGridY = 0;
object.name = ""; object.name = "";
object.displayName = ""; object.displayName = "";
object.avatar = ""; object.avatar = "";
@@ -2064,6 +2106,10 @@ $root.protos = (function() {
object.onWallNormY = message.onWallNormY; object.onWallNormY = message.onWallNormY;
if (message.capturedByInertia != null && message.hasOwnProperty("capturedByInertia")) if (message.capturedByInertia != null && message.hasOwnProperty("capturedByInertia"))
object.capturedByInertia = message.capturedByInertia; object.capturedByInertia = message.capturedByInertia;
if (message.revivalVirtualGridX != null && message.hasOwnProperty("revivalVirtualGridX"))
object.revivalVirtualGridX = message.revivalVirtualGridX;
if (message.revivalVirtualGridY != null && message.hasOwnProperty("revivalVirtualGridY"))
object.revivalVirtualGridY = message.revivalVirtualGridY;
if (message.name != null && message.hasOwnProperty("name")) if (message.name != null && message.hasOwnProperty("name"))
object.name = message.name; object.name = message.name;
if (message.displayName != null && message.hasOwnProperty("displayName")) if (message.displayName != null && message.hasOwnProperty("displayName"))

View File

@@ -0,0 +1,7 @@
{
"engine_version": "2.2.1",
"has_native": true,
"project_type": "js",
"projectName": "DelayNoMore",
"packageName": "org.genxium.delaynomore"
}

View File

@@ -18,11 +18,11 @@
"from": "cocos/scripting/js-bindings/manual/jsb_module_register.cpp", "from": "cocos/scripting/js-bindings/manual/jsb_module_register.cpp",
"to": "frameworks/runtime-src/Classes/jsb_module_register.cpp" "to": "frameworks/runtime-src/Classes/jsb_module_register.cpp"
}, { }, {
"from": "frameworks/runtime-src/Classes/send_ring_buff.hpp", "from": "frameworks/runtime-src/Classes/ring_buff.hpp",
"to": "frameworks/runtime-src/Classes/send_ring_buff.hpp" "to": "frameworks/runtime-src/Classes/ring_buff.hpp"
}, { }, {
"from": "frameworks/runtime-src/Classes/send_ring_buff.cpp", "from": "frameworks/runtime-src/Classes/ring_buff.cpp",
"to": "frameworks/runtime-src/Classes/send_ring_buff.cpp" "to": "frameworks/runtime-src/Classes/ring_buff.cpp"
}, { }, {
"from": "frameworks/runtime-src/Classes/udp_session.hpp", "from": "frameworks/runtime-src/Classes/udp_session.hpp",
"to": "frameworks/runtime-src/Classes/udp_session.hpp" "to": "frameworks/runtime-src/Classes/udp_session.hpp"

View File

@@ -27,7 +27,7 @@
#include "cocos2d.h" #include "cocos2d.h"
#include "cocos/audio/include/AudioEngine.h" //#include "cocos/audio/include/AudioEngine.h"
#include "cocos/scripting/js-bindings/manual/jsb_module_register.hpp" #include "cocos/scripting/js-bindings/manual/jsb_module_register.hpp"
#include "cocos/scripting/js-bindings/manual/jsb_global.h" #include "cocos/scripting/js-bindings/manual/jsb_global.h"
#include "cocos/scripting/js-bindings/jswrapper/SeApi.h" #include "cocos/scripting/js-bindings/jswrapper/SeApi.h"
@@ -81,13 +81,13 @@ void AppDelegate::applicationDidEnterBackground()
{ {
EventDispatcher::dispatchEnterBackgroundEvent(); EventDispatcher::dispatchEnterBackgroundEvent();
// Ensure that handle AudioEngine enter background after all enter background events are handled // Ensure that handle AudioEngine enter background after all enter background events are handled
AudioEngine::onEnterBackground(); //AudioEngine::onEnterBackground();
} }
// this function will be called when the app is active again // this function will be called when the app is active again
void AppDelegate::applicationWillEnterForeground() void AppDelegate::applicationWillEnterForeground()
{ {
// Ensure that handle AudioEngine enter foreground before all enter foreground events are handled // Ensure that handle AudioEngine enter foreground before all enter foreground events are handled
AudioEngine::onEnterForeground(); //AudioEngine::onEnterForeground();
EventDispatcher::dispatchEnterForegroundEvent(); EventDispatcher::dispatchEnterForegroundEvent();
} }

View File

@@ -0,0 +1,127 @@
#include <string.h>
#include "ring_buff.hpp"
// Sending
void SendRingBuff::put(BYTEC* const newBytes, size_t newBytesLen, PeerAddr* pNewPeerAddr) {
while (0 < cnt && cnt >= n) {
// Make room for the new element
this->pop();
}
eles[ed].bytesLen = newBytesLen;
memset(eles[ed].bytes, 0, sizeof eles[ed].bytes);
memcpy(eles[ed].bytes, newBytes, newBytesLen);
eles[ed].peerAddr = *(pNewPeerAddr);
ed++;
cnt++;
if (ed >= n) {
ed -= n; // Deliberately not using "%" operator for performance concern
}
}
SendWork* SendRingBuff::pop() {
if (0 == cnt) {
return NULL;
}
SendWork* ret = &(eles[st]);
cnt--;
st++;
if (st >= n) {
st -= n;
}
return ret;
}
// Recving
bool isFullWithLoadedVals(int n, int oldCnt, int oldSt, int oldEd) {
return (n <= oldCnt && oldEd == oldSt) || (n > oldCnt && 0 < oldCnt && oldEd == oldSt);
}
void RecvRingBuff::put(char* newBytes, size_t newBytesLen) {
RecvWork* slotEle = (&eles[ed.load()]); // Save for later update
// "RecvRingBuff.ed" is only accessed in "UvRecvThread", thus the order of it relative to the other two is not important.
int oldEd = ed.load();
// We want to increase the success rate of "pop()" if it's being executed by "GameThread/pollUdpRecvRingBuff", thus the below order of loading is IMPORTANT, i.e. load "cnt" first because it's decremented earlier than "st" being incremented.
int oldCnt = cnt.load();
/*
[WARNING]
Note that "RecvRingBuff.st" might have decremented in "GameThread" by a successful "pop()" between "cnt.load()" and "st.load()" here in "UvRecvThread"! Therefore "n <= oldCnt" doesn't necessarily imply "oldEd == oldSt"!
*/
int oldSt = st.load(); // Used to guard against "cnt decremented in pop(...), but st not yet incremented and thus return value not yet copied to avoid contamination"
int tried = 0;
/*
1. When "n <= oldCnt", it might still be true "oldEd != oldSt" (see the note above);
2. When "n > oldCnt", it might still be true that "oldEd == oldSt" if "pop()" hasn't successfully incremented "st" due to any reason;
3. When "oldEd == oldSt", it doesn't imply anything useful, because any of the following could be true
- a. "n <= oldCnt", i.e. the ringbuff is full
- b. "n > oldCnt && 0 < oldCnt" during the execution of "pop()", i.e. the ringbuff is still effectively full
- c. "n > oldCnt && 0 == oldCnt", i.e. the ringbuff is empty
*/
bool isFull = isFullWithLoadedVals(n, oldCnt, oldSt, oldEd);
while (isFull && 3 > tried) {
// Make room for the new element
this->pop(NULL);
oldCnt = cnt.load(); // If "pop()" above failed, it'd only be due to concurrent calls to "pop()", either way the updated "cnt" should be good to go
oldSt = st.load();
isFull = isFullWithLoadedVals(n, oldCnt, oldSt, oldEd);
++tried;
}
if (isFull && 3 == tried) {
// Failed silently, UDP packet can be dropped.
return;
}
slotEle->bytesLen = newBytesLen;
memset(slotEle->ui8Arr, 0, sizeof slotEle->ui8Arr);
for (size_t i = 0; i < newBytesLen; i++) {
*(slotEle->ui8Arr + i) = *(newBytes + i);
}
// No need to compare-and-swap, only "UvRecvThread" will access "RecvRingBuff.ed".
int newEd = oldEd+1;
if (newEd >= n) {
newEd -= n; // Deliberately not using "%" operator for performance concern
}
ed.compare_exchange_weak(oldEd, newEd); // Definitely succeeds because "RecvRingBuff.ed" is only accessed in "UvRecvThread"
// Only increment cnt when the putting of new element is fully done.
cnt++;
}
bool RecvRingBuff::pop(RecvWork* out) {
int oldCnt = std::atomic_fetch_sub(&cnt, 1);
/*
[WARNING]
After here, two cases should be taken care of.
1. If "n == oldCnt", we need guard against "put" to avoid contaminating "ret" by the "putting".
2. If "0 >= oldCnt", we need guard against another "pop" to avoid over-popping.
*/
if (0 >= oldCnt) {
// "pop" could be accessed by either "GameThread/pollUdpRecvRingBuff" or "UvRecvThread/put", thus we should be proactively guarding against concurrent popping while "1 == cnt"
++cnt;
return false;
}
// When concurrent "pop"s reach here, over-popping is definitely avoided.
int oldSt = st.load();
if (out) {
RecvWork* src = (&eles[oldSt]);
memset(out->ui8Arr, 0, sizeof out->ui8Arr);
memcpy(out->ui8Arr, src, src->bytesLen);
out->bytesLen = src->bytesLen;
}
int newSt = oldSt + 1;
if (newSt >= n) {
newSt -= n;
}
if (st.compare_exchange_weak(oldSt, newSt)) {
return true;
} else {
// Failed concurrent access should recover the "cnt"
++cnt;
return false;
}
}

View File

@@ -4,6 +4,8 @@
#include "uv/uv.h" #include "uv/uv.h"
#define __SSIZE_T // Otherwise "ssize_t" would have conflicting macros error that stops compiling #define __SSIZE_T // Otherwise "ssize_t" would have conflicting macros error that stops compiling
#include <atomic>
int const RING_BUFF_CONSECUTIVE_SET = 0; int const RING_BUFF_CONSECUTIVE_SET = 0;
int const RING_BUFF_NON_CONSECUTIVE_SET = 1; int const RING_BUFF_NON_CONSECUTIVE_SET = 1;
int const RING_BUFF_FAILED_TO_SET = 2; int const RING_BUFF_FAILED_TO_SET = 2;
@@ -41,4 +43,32 @@ public:
SendWork* pop(); SendWork* pop();
}; };
// TODO: Move "RecvXxxx" to a dedicated class.
class RecvWork {
public:
uint8_t ui8Arr[maxUdpPayloadBytes]; // Wasting some RAM here thus no need for explicit recursive destruction
size_t bytesLen;
};
/*
[WARNING] This class is specific to "RecvWork"; its "put" and "pop" methods are designed to be thread-safe & lock-free for our particular case, i.e. only concurrent access from "UvRecvThread" & "GameThread", in a sense more sophisticated than the Golang or JavaScript versions.
There's yet no plan to support thread-safe & lock-free "getByFrameId/setByFrameId" -- being thread-safe is easy by use of mutex, which is very SLOWWWWW when used in 60fps race-conditions.
The generic "thread-safe, lock-free ring buffer or circular buffer" is a big problem, widely discussed over the internet and in literatures, search "lock-free circular buffer" for more information.
*/
class RecvRingBuff {
public:
int n;
std::atomic_int ed, st, cnt;
RecvWork eles[maxBuffedMsgs]; // preallocated on stack to save heap alloc/dealloc time
RecvRingBuff(int newN) {
this->n = newN;
this->st = this->ed = this->cnt = 0;
}
void put(char* newBytes, size_t newBytesLen);
bool pop(RecvWork* out);
};
#endif #endif

View File

@@ -1,31 +0,0 @@
#include <string.h>
#include "send_ring_buff.hpp"
void SendRingBuff::put(BYTEC* const newBytes, size_t newBytesLen, PeerAddr* pNewPeerAddr) {
while (0 < cnt && cnt >= n) {
// Make room for the new element
this->pop();
}
eles[ed].bytesLen = newBytesLen;
memset(eles[ed].bytes, 0, sizeof eles[ed].bytes);
memcpy(eles[ed].bytes, newBytes, newBytesLen);
eles[ed].peerAddr = *(pNewPeerAddr);
ed++;
cnt++;
if (ed >= n) {
ed -= n; // Deliberately not using "%" operator for performance concern
}
}
SendWork* SendRingBuff::pop() {
if (0 == cnt) {
return NULL;
}
SendWork* ret = &(eles[st]);
cnt--;
st++;
if (st >= n) {
st -= n;
}
return ret;
}

View File

@@ -16,11 +16,15 @@ uv_loop_t *recvLoop = NULL, *sendLoop = NULL;
uv_mutex_t sendRingBuffLock; // used along with "uvSendLoopTriggerSig" as a "uv_cond_t" uv_mutex_t sendRingBuffLock; // used along with "uvSendLoopTriggerSig" as a "uv_cond_t"
SendRingBuff* sendRingBuff = NULL; SendRingBuff* sendRingBuff = NULL;
uv_mutex_t recvRingBuffLock;
RecvRingBuff* recvRingBuff = NULL;
char SRV_IP[256]; char SRV_IP[256];
int SRV_PORT = 0; int SRV_PORT = 0;
int UDP_TUNNEL_SRV_PORT = 0; int UDP_TUNNEL_SRV_PORT = 0;
struct PeerAddr udpPunchingServerAddr, udpTunnelAddr; struct PeerAddr udpPunchingServerAddr, udpTunnelAddr;
struct PeerAddr peerAddrList[maxPeerCnt]; struct PeerAddr peerAddrList[maxPeerCnt];
bool peerPunchedMarks[maxPeerCnt];
void _onRead(uv_udp_t* req, ssize_t nread, uv_buf_t const* buf, struct sockaddr const* addr, unsigned flags) { void _onRead(uv_udp_t* req, ssize_t nread, uv_buf_t const* buf, struct sockaddr const* addr, unsigned flags) {
if (nread < 0) { if (nread < 0) {
@@ -29,6 +33,8 @@ void _onRead(uv_udp_t* req, ssize_t nread, uv_buf_t const* buf, struct sockaddr
free(buf->base); free(buf->base);
return; return;
} }
struct sockaddr_in const* sockAddr = (struct sockaddr_in const*)addr;
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0) #if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
char ip[INET_ADDRSTRLEN]; char ip[INET_ADDRSTRLEN];
memset(ip, 0, sizeof ip); memset(ip, 0, sizeof ip);
@@ -38,10 +44,8 @@ void _onRead(uv_udp_t* req, ssize_t nread, uv_buf_t const* buf, struct sockaddr
// The null check for "addr" is necessary, on Android there'd be such mysterious call to "_onRead"! // The null check for "addr" is necessary, on Android there'd be such mysterious call to "_onRead"!
switch (addr->sa_family) { switch (addr->sa_family) {
case AF_INET: { case AF_INET: {
struct sockaddr_in const* sockAddr = (struct sockaddr_in const*)addr;
uv_inet_ntop(sockAddr->sin_family, &(sockAddr->sin_addr), ip, INET_ADDRSTRLEN); uv_inet_ntop(sockAddr->sin_family, &(sockAddr->sin_addr), ip, INET_ADDRSTRLEN);
port = ntohs(sockAddr->sin_port); port = ntohs(sockAddr->sin_port);
CCLOG("UDP received %u bytes from %s:%d", nread, ip, port);
break; break;
} }
default: default:
@@ -53,37 +57,24 @@ void _onRead(uv_udp_t* req, ssize_t nread, uv_buf_t const* buf, struct sockaddr
#endif #endif
if (6 == nread) { if (6 == nread) {
// holepunching // Peer holepunching
} else if (0 < nread) { for (int i = 0; i < maxPeerCnt; i++) {
// Non-holepunching; it might be more effective in RAM usage to use a threadsafe RingBuff to pass msg to GameThread here, but as long as it's not a performance blocker don't bother optimize here... if (peerAddrList[i].sockAddrIn.sin_addr.s_addr != sockAddr->sin_addr.s_addr) continue;
uint8_t* const ui8Arr = (uint8_t*)malloc(maxUdpPayloadBytes*sizeof(uint8_t)); if (peerAddrList[i].sockAddrIn.sin_port != sockAddr->sin_port) continue;
memset(ui8Arr, 0, sizeof(ui8Arr)); peerPunchedMarks[i] = true;
for (int i = 0; i < nread; i++) { #if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
*(ui8Arr+i) = *(buf->base + i); CCLOG("UDP received peer-holepunching from %s:%d", ip, port);
#endif
break;
} }
cocos2d::Application::getInstance()->getScheduler()->performFunctionInCocosThread([=]() { } else if (0 < nread) {
// [WARNING] Use of the "ScriptEngine" is only allowed in "GameThread a.k.a. CocosThread"! // Non-holepunching; the previously used "cocos2d::Application::getInstance()->getScheduler()->performFunctionInCocosThread(...)" approach was so non-deterministic in terms of the lag till GameThread actually recognizes this latest received packet due to scheduler uncertainty -- and was also heavier in RAM due to lambda usage
se::Value onUdpMessageCb; #if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
se::ScriptEngine::getInstance()->getGlobalObject()->getProperty("onUdpMessage", &onUdpMessageCb); CCLOG("UDP received %u bytes inputFrameUpsync from %s:%d", nread, ip, port);
// [WARNING] Declaring "AutoHandleScope" is critical here, otherwise "onUdpMessageCb.toObject()" wouldn't be recognized as a function of the ScriptEngine! #endif
se::AutoHandleScope hs; //uv_mutex_lock(&recvRingBuffLock);
//CCLOG("UDP received %d bytes upsync -- 1", nread); recvRingBuff->put(buf->base, nread);
se::Object* const gameThreadMsg = se::Object::createTypedArray(se::Object::TypedArrayType::UINT8, ui8Arr, nread); //uv_mutex_unlock(&recvRingBuffLock);
//CCLOG("UDP received %d bytes upsync -- 2", nread);
se::ValueArray args = { se::Value(gameThreadMsg) };
if (onUdpMessageCb.isObject() && onUdpMessageCb.toObject()->isFunction()) {
// Temporarily assume that the "this" ptr within callback is NULL.
bool ok = onUdpMessageCb.toObject()->call(args, NULL);
if (!ok) {
se::ScriptEngine::getInstance()->clearException();
}
}
//CCLOG("UDP received %d bytes upsync -- 3", nread);
gameThreadMsg->decRef(); // Reference http://docs.cocos.com/creator/2.2/manual/en/advanced-topics/JSB2.0-learning.html#seobject
//CCLOG("UDP received %d bytes upsync -- 4", nread);
free(ui8Arr);
//CCLOG("UDP received %d bytes upsync -- 5", nread);
});
} }
free(buf->base); free(buf->base);
@@ -182,7 +173,6 @@ void startSendLoop(void* arg) {
int uvCloseRet = uv_loop_close(l); int uvCloseRet = uv_loop_close(l);
CCLOG("UDP send loop is closed in UvSendThread, uvCloseRet=%d", uvCloseRet); CCLOG("UDP send loop is closed in UvSendThread, uvCloseRet=%d", uvCloseRet);
uv_mutex_destroy(&sendRingBuffLock);
} }
int initSendLoop(struct sockaddr const* pUdpAddr) { int initSendLoop(struct sockaddr const* pUdpAddr) {
@@ -196,6 +186,7 @@ int initSendLoop(struct sockaddr const* pUdpAddr) {
} }
uv_mutex_init(&sendRingBuffLock); uv_mutex_init(&sendRingBuffLock);
sendRingBuff = new SendRingBuff(maxBuffedMsgs); sendRingBuff = new SendRingBuff(maxBuffedMsgs);
uv_async_init(sendLoop, &uvSendLoopStopSig, _onUvStopSig); uv_async_init(sendLoop, &uvSendLoopStopSig, _onUvStopSig);
uv_async_init(sendLoop, &uvSendLoopTriggerSig, _onUvSthNewToSend); uv_async_init(sendLoop, &uvSendLoopTriggerSig, _onUvSthNewToSend);
@@ -212,6 +203,9 @@ bool initRecvLoop(struct sockaddr const* pUdpAddr) {
CCLOGERROR("Failed to bind recv; recvSockInitRes=%d, recvbindRes=%d, reason=%s", recvSockInitRes, recvbindRes, uv_strerror(recvbindRes)); CCLOGERROR("Failed to bind recv; recvSockInitRes=%d, recvbindRes=%d, reason=%s", recvSockInitRes, recvbindRes, uv_strerror(recvbindRes));
exit(-1); exit(-1);
} }
uv_mutex_init(&recvRingBuffLock);
recvRingBuff = new RecvRingBuff(maxBuffedMsgs);
uv_udp_recv_start(udpRecvSocket, _allocBuffer, _onRead); uv_udp_recv_start(udpRecvSocket, _allocBuffer, _onRead);
uv_async_init(recvLoop, &uvRecvLoopStopSig, _onUvStopSig); uv_async_init(recvLoop, &uvRecvLoopStopSig, _onUvStopSig);
@@ -222,6 +216,12 @@ bool DelayNoMore::UdpSession::openUdpSession(int port) {
struct sockaddr_in udpAddr; struct sockaddr_in udpAddr;
uv_ip4_addr("0.0.0.0", port, &udpAddr); uv_ip4_addr("0.0.0.0", port, &udpAddr);
struct sockaddr const* pUdpAddr = (struct sockaddr const*)&udpAddr; struct sockaddr const* pUdpAddr = (struct sockaddr const*)&udpAddr;
memset(peerPunchedMarks, false, sizeof(peerPunchedMarks));
for (int i = 0; i < maxPeerCnt; i++) {
peerAddrList[i].authKey = -1; // hardcoded for now
memset((char*)&peerAddrList[i].sockAddrIn, 0, sizeof(peerAddrList[i].sockAddrIn));
}
/* /*
[WARNING] On Android, the libuv documentation of "UV_UDP_REUSEADDR" is true, i.e. only the socket that binds later on the same port will be triggered the recv callback; however on Windows, experiment shows that the exact reverse is true instead. [WARNING] On Android, the libuv documentation of "UV_UDP_REUSEADDR" is true, i.e. only the socket that binds later on the same port will be triggered the recv callback; however on Windows, experiment shows that the exact reverse is true instead.
@@ -246,24 +246,42 @@ bool DelayNoMore::UdpSession::openUdpSession(int port) {
bool DelayNoMore::UdpSession::closeUdpSession() { bool DelayNoMore::UdpSession::closeUdpSession() {
CCLOG("About to close udp session and dealloc all resources..."); CCLOG("About to close udp session and dealloc all resources...");
/*
[WARNING] It's possible that "closeUdpSession" is called when "openUdpSession" was NEVER CALLED, thus we have to avoid program crash in this case.
uv_async_send(&uvSendLoopStopSig); In general one shouldn't just check the state of "sendTid" by whether or not "NULL == sendLoop", but in this particular game, both "openUdpSession" and "closeUdpSession" are only called from "GameThread", no thread-safety concern here, i.e. if "openUdpSession" was ever called earlier, then "sendLoop" wouldn't be NULL when "closeUdpSession" is later called.
CCLOG("Signaling UvSendThread to end in GameThread..."); */
uv_thread_join(&sendTid); if (NULL != sendLoop) {
free(udpSendSocket); uv_async_send(&uvSendLoopStopSig);
free(sendLoop); CCLOG("Signaling UvSendThread to end in GameThread...");
delete sendRingBuff; uv_thread_join(&sendTid);
free(udpSendSocket);
free(sendLoop);
delete sendRingBuff;
udpSendSocket = NULL;
sendLoop = NULL;
sendRingBuff = NULL;
uv_async_send(&uvRecvLoopStopSig); // The few if not only guaranteed thread safe utility of libuv :) See http://docs.libuv.org/en/v1.x/async.html#c.uv_async_send uv_mutex_destroy(&sendRingBuffLock);
CCLOG("Signaling UvRecvThread to end in GameThread...");
uv_thread_join(&recvTid);
free(udpRecvSocket);
free(recvLoop);
for (int i = 0; i < maxPeerCnt; i++) {
peerAddrList[i].authKey = -1; // hardcoded for now
memset((char*)&peerAddrList[i].sockAddrIn, 0, sizeof(peerAddrList[i].sockAddrIn));
} }
if (NULL != recvLoop) {
uv_async_send(&uvRecvLoopStopSig); // The few if not only guaranteed thread safe utility of libuv :) See http://docs.libuv.org/en/v1.x/async.html#c.uv_async_send
CCLOG("Signaling UvRecvThread to end in GameThread...");
uv_thread_join(&recvTid);
free(udpRecvSocket);
free(recvLoop);
delete recvRingBuff;
udpRecvSocket = NULL;
recvLoop = NULL;
recvRingBuff = NULL;
uv_mutex_destroy(&recvRingBuffLock);
}
CCLOG("Closed udp session and dealloc all resources in GameThread..."); CCLOG("Closed udp session and dealloc all resources in GameThread...");
return true; return true;
@@ -321,8 +339,7 @@ bool DelayNoMore::UdpSession::broadcastInputFrameUpsync(BYTEC* const bytes, size
uv_mutex_lock(&sendRingBuffLock); uv_mutex_lock(&sendRingBuffLock);
// Might want to send several times for better arrival rate // Might want to send several times for better arrival rate
for (int j = 0; j < broadcastUpsyncCnt; j++) { for (int j = 0; j < broadcastUpsyncCnt; j++) {
// Send to room udp tunnel in case of hole punching failure int peerPunchedCnt = 0;
sendRingBuff->put(bytes, bytesLen, &udpTunnelAddr);
for (int i = 0; i < roomCapacity; i++) { for (int i = 0; i < roomCapacity; i++) {
if (i + 1 == selfJoinIndex) { if (i + 1 == selfJoinIndex) {
continue; continue;
@@ -331,8 +348,17 @@ bool DelayNoMore::UdpSession::broadcastInputFrameUpsync(BYTEC* const bytes, size
// Peer addr not initialized // Peer addr not initialized
continue; continue;
} }
if (false == peerPunchedMarks[i]) {
// Not punched yet, save some bandwidth
continue;
}
sendRingBuff->put(bytes, bytesLen, &(peerAddrList[i]));
++peerPunchedCnt;
}
sendRingBuff->put(bytes, bytesLen, &(peerAddrList[i])); // Content hardcoded for now if (peerPunchedCnt + 1 < roomCapacity) {
// Send to room udp tunnel in case of ANY hole punching failure
sendRingBuff->put(bytes, bytesLen, &udpTunnelAddr);
} }
} }
@@ -341,3 +367,39 @@ bool DelayNoMore::UdpSession::broadcastInputFrameUpsync(BYTEC* const bytes, size
return true; return true;
} }
bool DelayNoMore::UdpSession::pollUdpRecvRingBuff() {
// This function is called by GameThread 60 fps.
//uv_mutex_lock(&recvRingBuffLock);
while (true && NULL != recvLoop) {
RecvWork f;
bool res = recvRingBuff->pop(&f);
if (!res) {
// Deliberately returning "true" here to prevent "jswrapper" from printing "Failed to invoke Xxx..." too frequently
return true;
}
// [WARNING] Declaring "AutoHandleScope" is critical here, otherwise "onUdpMessageCb.toObject()" wouldn't be recognized as a function of the ScriptEngine!
se::AutoHandleScope hs;
// [WARNING] Use of the "ScriptEngine" is only allowed in "GameThread a.k.a. CocosThread"!
se::Value onUdpMessageCb;
se::ScriptEngine::getInstance()->getGlobalObject()->getProperty("onUdpMessage", &onUdpMessageCb);
if (onUdpMessageCb.isObject() && onUdpMessageCb.toObject()->isFunction()) {
//CCLOG("UDP received %d bytes upsync -- 1", nread);
se::Object* const gameThreadMsg = se::Object::createTypedArray(se::Object::TypedArrayType::UINT8, f.ui8Arr, f.bytesLen);
//CCLOG("UDP received %d bytes upsync -- 2", nread);
se::ValueArray args = { se::Value(gameThreadMsg) };
// Temporarily assume that the "this" ptr within callback is NULL.
bool ok = onUdpMessageCb.toObject()->call(args, NULL);
if (!ok) {
se::ScriptEngine::getInstance()->clearException();
}
//CCLOG("UDP received %d bytes upsync -- 3", nread);
gameThreadMsg->decRef(); // Reference http://docs.cocos.com/creator/2.2/manual/en/advanced-topics/JSB2.0-learning.html#seobject
//CCLOG("UDP received %d bytes upsync -- 4", nread);
}
}
//uv_mutex_unlock(&recvRingBuffLock);
return true;
}

View File

@@ -1,7 +1,7 @@
#ifndef udp_session_hpp #ifndef udp_session_hpp
#define udp_session_hpp #define udp_session_hpp
#include "send_ring_buff.hpp" #include "ring_buff.hpp"
int const maxPeerCnt = 10; int const maxPeerCnt = 10;
@@ -14,6 +14,7 @@ namespace DelayNoMore {
//static bool clearPeerUDPAddrList(); //static bool clearPeerUDPAddrList();
static bool punchToServer(CHARC* const srvIp, int const srvPort, BYTEC* const bytes, size_t bytesLen, int const udpTunnelSrvPort, BYTEC* const udpTunnelBytes, size_t udpTunnelBytesBytesLen); static bool punchToServer(CHARC* const srvIp, int const srvPort, BYTEC* const bytes, size_t bytesLen, int const udpTunnelSrvPort, BYTEC* const udpTunnelBytes, size_t udpTunnelBytesBytesLen);
static bool broadcastInputFrameUpsync(BYTEC* const bytes, size_t bytesLen, int roomCapacity, int selfJoinIndex); static bool broadcastInputFrameUpsync(BYTEC* const bytes, size_t bytesLen, int roomCapacity, int selfJoinIndex);
static bool pollUdpRecvRingBuff();
}; };
} }
#endif #endif

View File

@@ -126,6 +126,20 @@ bool upsertPeerUdpAddr(se::State& s) {
} }
SE_BIND_FUNC(upsertPeerUdpAddr) SE_BIND_FUNC(upsertPeerUdpAddr)
bool pollUdpRecvRingBuff(se::State& s) {
const auto& args = s.args();
size_t argc = args.size();
CC_UNUSED bool ok = true;
if (0 == argc) {
SE_PRECONDITION2(ok, false, "upsertPeerUdpAddr: Error processing arguments");
return DelayNoMore::UdpSession::pollUdpRecvRingBuff();
}
SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d; or wrong arg type!", (int)argc, 0);
return false;
}
SE_BIND_FUNC(pollUdpRecvRingBuff)
static bool udpSessionFinalize(se::State& s) { static bool udpSessionFinalize(se::State& s) {
CCLOGINFO("jsbindings: finalizing JS object %p (DelayNoMore::UdpSession)", s.nativeThisObject()); CCLOGINFO("jsbindings: finalizing JS object %p (DelayNoMore::UdpSession)", s.nativeThisObject());
auto iter = se::NonRefNativePtrCreatedByCtorMap::find(s.nativeThisObject()); auto iter = se::NonRefNativePtrCreatedByCtorMap::find(s.nativeThisObject());
@@ -158,6 +172,7 @@ bool registerUdpSession(se::Object* obj) {
cls->defineStaticFunction("broadcastInputFrameUpsync", _SE(broadcastInputFrameUpsync)); cls->defineStaticFunction("broadcastInputFrameUpsync", _SE(broadcastInputFrameUpsync));
cls->defineStaticFunction("closeUdpSession", _SE(closeUdpSession)); cls->defineStaticFunction("closeUdpSession", _SE(closeUdpSession));
cls->defineStaticFunction("upsertPeerUdpAddr", _SE(upsertPeerUdpAddr)); cls->defineStaticFunction("upsertPeerUdpAddr", _SE(upsertPeerUdpAddr));
cls->defineStaticFunction("pollUdpRecvRingBuff", _SE(pollUdpRecvRingBuff));
cls->defineFinalizeFunction(_SE(udpSessionFinalize)); cls->defineFinalizeFunction(_SE(udpSessionFinalize));
cls->install(); cls->install();

View File

@@ -15,5 +15,5 @@ SE_DECLARE_FUNC(punchToServer);
SE_DECLARE_FUNC(broadcastInputFrameUpsync); SE_DECLARE_FUNC(broadcastInputFrameUpsync);
SE_DECLARE_FUNC(closeUdpSession); SE_DECLARE_FUNC(closeUdpSession);
SE_DECLARE_FUNC(upsertPeerUdpAddr); SE_DECLARE_FUNC(upsertPeerUdpAddr);
SE_DECLARE_FUNC(pollUdpRecvRingBuff);
#endif #endif

View File

@@ -27,8 +27,7 @@
android:label="@string/app_name" android:label="@string/app_name"
android:usesCleartextTraffic="true" android:usesCleartextTraffic="true"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen" android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:launchMode="singleTask" android:launchMode="singleTask">
android:taskAffinity="" >
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />

View File

@@ -15,7 +15,7 @@ LOCAL_SRC_FILES := hellojavascript/main.cpp \
../../../Classes/jsb_module_register.cpp \ ../../../Classes/jsb_module_register.cpp \
../../../Classes/udp_session.cpp \ ../../../Classes/udp_session.cpp \
../../../Classes/udp_session_bridge.cpp \ ../../../Classes/udp_session_bridge.cpp \
../../../Classes/send_ring_buff.cpp ../../../Classes/ring_buff.cpp
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../../Classes LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../../Classes

View File

@@ -190,11 +190,11 @@ copy "$(ProjectDir)..\..\..\project.json" "$(OutDir)\" /Y</Command>
<ClCompile Include="..\Classes\AppDelegate.cpp" /> <ClCompile Include="..\Classes\AppDelegate.cpp" />
<ClCompile Include="..\Classes\udp_session.cpp" /> <ClCompile Include="..\Classes\udp_session.cpp" />
<ClCompile Include="..\Classes\udp_session_bridge.cpp" /> <ClCompile Include="..\Classes\udp_session_bridge.cpp" />
<ClCompile Include="..\Classes\send_ring_buff.cpp" /> <ClCompile Include="..\Classes\ring_buff.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="main.h" /> <ClInclude Include="main.h" />
<ClInclude Include="..\Classes\send_ring_buff.hpp" /> <ClInclude Include="..\Classes\ring_buff.hpp" />
<ClInclude Include="..\Classes\udp_session.hpp" /> <ClInclude Include="..\Classes\udp_session.hpp" />
<ClInclude Include="..\Classes\udp_session_bridge.hpp" /> <ClInclude Include="..\Classes\udp_session_bridge.hpp" />
<ClInclude Include="..\Classes\AppDelegate.h" /> <ClInclude Include="..\Classes\AppDelegate.h" />

View File

@@ -22,7 +22,7 @@
<ClCompile Include="..\Classes\jsb_module_register.cpp"> <ClCompile Include="..\Classes\jsb_module_register.cpp">
<Filter>Classes</Filter> <Filter>Classes</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\Classes\send_ring_buff.cpp"> <ClCompile Include="..\Classes\ring_buff.cpp">
<Filter>Classes</Filter> <Filter>Classes</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\Classes\udp_session.cpp"> <ClCompile Include="..\Classes\udp_session.cpp">
@@ -40,7 +40,7 @@
<Filter>win32</Filter> <Filter>win32</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="resource.h" /> <ClInclude Include="resource.h" />
<ClInclude Include="..\Classes\send_ring_buff.hpp"> <ClInclude Include="..\Classes\ring_buff.hpp">
<Filter>Classes</Filter> <Filter>Classes</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\Classes\udp_session.hpp"> <ClInclude Include="..\Classes\udp_session.hpp">

Some files were not shown because too many files have changed in this diff Show More