Compare commits
65 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
642adff919 | ||
|
62c51b1838 | ||
|
2751569e0c | ||
|
d623916b3c | ||
|
efd070a11b | ||
|
d111de0a7a | ||
|
c2fa251e69 | ||
|
de16e8e8de | ||
|
365177a3af | ||
|
b79e2dc935 | ||
|
7b0c807496 | ||
|
5c611b626d | ||
|
38149279bd | ||
|
a762c563d9 | ||
|
6a0d729dee | ||
|
f10389bf55 | ||
|
6b3d1ed49a | ||
|
d25bb5ff10 | ||
|
d38d4b4ec9 | ||
|
03828db6ff | ||
|
917fca2bcd | ||
|
680e4f1f59 | ||
|
f367609276 | ||
|
70ae4a4c92 | ||
|
6f561bea87 | ||
|
70a86c27b0 | ||
|
b0f37d2237 | ||
|
09376b827d | ||
|
d560392c79 | ||
|
c75f642011 | ||
|
5cfcac6cf6 | ||
|
d37ebd4c33 | ||
|
1d138b17c3 | ||
|
851678e2f3 | ||
|
2fb6fd6bea | ||
|
e3440a2a06 | ||
|
8de2d6e4e7 | ||
|
ba2dd0b22e | ||
|
754610d31b | ||
|
a35de9b83c | ||
|
2b6cb57050 | ||
|
677e76179c | ||
|
c65c122f45 | ||
|
b5530b352b | ||
|
4e638fb2ec | ||
|
7c454130db | ||
|
5863f88435 | ||
|
bbf07fe518 | ||
|
26660d75d2 | ||
|
76cdbc8f1f | ||
|
4097a8da75 | ||
|
e7bf6ec16b | ||
|
7ab983949c | ||
|
2028f8277d | ||
|
60bb74169e | ||
|
8536521136 | ||
|
5df545e168 | ||
|
6bc3feab58 | ||
|
e21e1b840f | ||
|
ef345e0e48 | ||
|
0168e2182e | ||
|
58b06f6a10 | ||
|
58e60a789f | ||
|
b5b43bb596 | ||
|
59767c1ed5 |
2
.gitignore
vendored
@@ -1,3 +1,5 @@
|
|||||||
|
.vs
|
||||||
|
**/.vs
|
||||||
battle_srv/test_cases/test_cases
|
battle_srv/test_cases/test_cases
|
||||||
battle_srv/test_cases/tests
|
battle_srv/test_cases/tests
|
||||||
*.pid
|
*.pid
|
||||||
|
@@ -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.
|
||||||

|

|
||||||
|
|
||||||
|
# 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.
|
||||||
|
55
README.md
@@ -1,16 +1,20 @@
|
|||||||
# 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). As lots of feedbacks ask for a discussion on using UDP instead, I tried to summarize my personal opinion about it in [ConcerningEdgeCases](./ConcerningEdgeCases.md) -- not necessarily correct but that's indeed a question to face :)
|
This project is a demo for a websocket-based rollback netcode inspired by [GGPO](https://github.com/pond3r/ggpo/blob/master/doc/README.md).
|
||||||
|
|
||||||
The following video is recorded over INTERNET using an input delay of 4 frames and it feels SMOOTH when playing! Please also checkout these demo videos
|
[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!
|
||||||
- [source video of the first gif (earlier version)](https://pan.baidu.com/s/1ML6hNupaPHPJRd5rcTvQvw?pwd=8ruc)
|
|
||||||
- [source video of the second gif (added turn-around optimization & dashing)](https://pan.baidu.com/s/1isMcLvxax4NNkDgitV_FDg?pwd=s1i6)
|
|
||||||
|
|
||||||
to see how this demo carries out a full 60fps synchronization with the help of _batched input upsync/downsync_ for satisfying network I/O performance.
|

|
||||||
|
|
||||||

|
(battle between 2 celluar 4G users using Android phones, [original video here](https://pan.baidu.com/s/1RL-9M-cK8cFS_Q8afMTrJA?pwd=ryzv))
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
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).
|
||||||
|
- 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. 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/v0.9.14/battle_srv/models/room.go#L786)
|
||||||
@@ -22,7 +26,7 @@ _(how input delay roughly works)_
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
_(how rollback-and-chase in this project roughly works, kindly note that by the current implementation, each frontend only maintains a `lastAllConfirmedInputFrameId` for all the other peers, because the backend only downsyncs all-confirmed inputFrames, see [markConfirmationIfApplicable](https://github.com/genxium/DelayNoMore/blob/v0.9.14/battle_srv/models/room.go#L1085) for more information -- if a serverless peer-to-peer communication is seriously needed here, consider porting [markConfirmationIfApplicable](https://github.com/genxium/DelayNoMore/blob/v0.9.14/battle_srv/models/room.go#L1085) into frontend for maintaining `lastAllConfirmedInputFrameId` under chaotic reception order of inputFrames from peers)_
|
_(how rollback-and-chase in this project roughly works)_
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||
@@ -108,3 +112,38 @@ Moreover, in practice I found that to spot sync anomalies, the following tools a
|
|||||||
- 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/v0.9.19/battle_srv/models/room.go#L1259).
|
||||||
|
|
||||||
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`.
|
||||||
|

|
||||||
|
|
||||||
|
### 2.3 WIN32 platform tool versioning
|
||||||
|

|
||||||
|
When building for native platforms, it's much more convenient to trigger the CocosCreator project forming frmo CLI, e.g.
|
||||||
|
```
|
||||||
|
shell> cd <proj-root>
|
||||||
|
shell> /path/to/CocosCreator.exe --path ./frontend --build "platform=win32;debug=true"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.4 CococCreator native build reloading
|
||||||
|
CocosCreator doesn't have perfect file cache management during native project building, use "Developer Tools > Reload" to reset the IDE status upon mysterious errors.
|
||||||
|

|
||||||
|
|
||||||
|
Another issue is with the package name, see the screenshot below, kindly note that after successfully building with a blank package name, you can then re-fill the desired package name and build again!
|
||||||
|

|
||||||
|
|
||||||
|
### 2.5 Checking UDP port binding result
|
||||||
|
__*nix__
|
||||||
|
```
|
||||||
|
netstat -anp | grep <your_port>
|
||||||
|
```
|
||||||
|
|
||||||
|
__Windows__
|
||||||
|
```
|
||||||
|
netstat -ano | grep <your_port>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.6 Checking native code crash on non-rooted Android phone
|
||||||
|
```
|
||||||
|
DeveloperOs> adb bugreport ./logs.zip
|
||||||
|
# The file "logs.zip" will be automatically pulled to current folder of the DeveloperOS, copy "logs/FS/data/tomestones" out of the zip, then use the binary "$NDK_ROOT/ndk-stack" to analyze whichever tombstone you're interested in, for example, I often use the following
|
||||||
|
DeveloperOs> ${NDK_ROOT}/ndk-stack.cmd -sym \path\to\DelayNoMore\frontend\build\jsb-link\frameworks\runtime-src\proj.android-studio\app\build\intermediates\ndkBuild\debug\obj\local\arm64-v8a -dump \path\to\tombstones\tombstone_03
|
||||||
|
# The param "-sym \path\to\objs" tells "ndk-stack" to decode "tombstone_03" with symbols provided by all the files inside that "\path\to\objs".
|
||||||
|
```
|
||||||
|
@@ -37,6 +37,8 @@ type mysqlConf struct {
|
|||||||
|
|
||||||
type sioConf struct {
|
type sioConf struct {
|
||||||
HostAndPort string `json:"hostAndPort"`
|
HostAndPort string `json:"hostAndPort"`
|
||||||
|
UdpHost string `json:"udpHost"`
|
||||||
|
UdpPort int `json:"udpPort"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type botServerConf struct {
|
type botServerConf struct {
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
{
|
{
|
||||||
"hostAndPort": "0.0.0.0:9992"
|
"hostAndPort": "0.0.0.0:9992",
|
||||||
|
"udpHost": "0.0.0.0",
|
||||||
|
"udpPort": 3000
|
||||||
}
|
}
|
||||||
|
@@ -23,6 +23,8 @@ import (
|
|||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/robfig/cron"
|
"github.com/robfig/cron"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
|
||||||
|
"net"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -34,7 +36,7 @@ func main() {
|
|||||||
env_tools.MergeTestPlayerAccounts()
|
env_tools.MergeTestPlayerAccounts()
|
||||||
}
|
}
|
||||||
models.InitRoomHeapManager()
|
models.InitRoomHeapManager()
|
||||||
startScheduler()
|
// startScheduler()
|
||||||
router := gin.Default()
|
router := gin.Default()
|
||||||
setRouter(router)
|
setRouter(router)
|
||||||
|
|
||||||
@@ -54,6 +56,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
Logger.Info("Listening and serving HTTP on", zap.Any("Conf.Sio.HostAndPort", Conf.Sio.HostAndPort))
|
Logger.Info("Listening and serving HTTP on", zap.Any("Conf.Sio.HostAndPort", Conf.Sio.HostAndPort))
|
||||||
}()
|
}()
|
||||||
|
go startGrandUdpServer()
|
||||||
var gracefulStop = make(chan os.Signal)
|
var gracefulStop = make(chan os.Signal)
|
||||||
signal.Notify(gracefulStop, syscall.SIGTERM)
|
signal.Notify(gracefulStop, syscall.SIGTERM)
|
||||||
signal.Notify(gracefulStop, syscall.SIGINT)
|
signal.Notify(gracefulStop, syscall.SIGINT)
|
||||||
@@ -114,3 +117,33 @@ func startScheduler() {
|
|||||||
//c.AddFunc("*/1 * * * * *", FuncName)
|
//c.AddFunc("*/1 * * * * *", FuncName)
|
||||||
c.Start()
|
c.Start()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func startGrandUdpServer() {
|
||||||
|
conn, err := net.ListenUDP("udp", &net.UDPAddr{
|
||||||
|
Port: Conf.Sio.UdpPort,
|
||||||
|
IP: net.ParseIP(Conf.Sio.UdpHost),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
conn.Close()
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
Logger.Error("`GrandUdpServer`, recovery spot#1, recovered from: ", zap.Any("panic", r))
|
||||||
|
}
|
||||||
|
Logger.Info(fmt.Sprintf("The `GrandUdpServer` is stopped"))
|
||||||
|
}()
|
||||||
|
|
||||||
|
Logger.Info(fmt.Sprintf("`GrandUdpServer` started at %s", conn.LocalAddr().String()))
|
||||||
|
|
||||||
|
for {
|
||||||
|
message := make([]byte, 2046)
|
||||||
|
rlen, remote, err := conn.ReadFromUDP(message[:])
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
Logger.Info(fmt.Sprintf("`GrandUdpServer` received: %d bytes from %s\n", rlen, remote))
|
||||||
|
ws.HandleUdpHolePunchingForPlayer(message[0:rlen], remote)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -8,6 +8,7 @@ import (
|
|||||||
sq "github.com/Masterminds/squirrel"
|
sq "github.com/Masterminds/squirrel"
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
"net"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PlayerBattleState struct {
|
type PlayerBattleState struct {
|
||||||
@@ -46,10 +47,15 @@ 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
|
LastReceivedInputFrameId int32
|
||||||
LastSentInputFrameId int32
|
LastUdpReceivedInputFrameId int32
|
||||||
AckingFrameId int32
|
LastSentInputFrameId int32
|
||||||
AckingInputFrameId int32
|
AckingFrameId int32
|
||||||
|
AckingInputFrameId int32
|
||||||
|
|
||||||
|
UdpAddr *PeerUdpAddr
|
||||||
|
BattleUdpTunnelAddr *net.UDPAddr // This addr is used by backend only, not visible to frontend
|
||||||
|
BattleUdpTunnelAuthKey int32
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExistPlayerByName(name string) (bool, error) {
|
func ExistPlayerByName(name string) (bool, error) {
|
||||||
|
@@ -13,6 +13,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"jsexport/battle"
|
"jsexport/battle"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"resolv"
|
"resolv"
|
||||||
@@ -32,6 +33,7 @@ const (
|
|||||||
DOWNSYNC_MSG_ACT_BATTLE_STOPPED = int32(3)
|
DOWNSYNC_MSG_ACT_BATTLE_STOPPED = int32(3)
|
||||||
DOWNSYNC_MSG_ACT_FORCED_RESYNC = int32(4)
|
DOWNSYNC_MSG_ACT_FORCED_RESYNC = int32(4)
|
||||||
DOWNSYNC_MSG_ACT_PEER_INPUT_BATCH = int32(5)
|
DOWNSYNC_MSG_ACT_PEER_INPUT_BATCH = int32(5)
|
||||||
|
DOWNSYNC_MSG_ACT_PEER_UDP_ADDR = int32(6)
|
||||||
|
|
||||||
DOWNSYNC_MSG_ACT_BATTLE_READY_TO_START = int32(-1)
|
DOWNSYNC_MSG_ACT_BATTLE_READY_TO_START = int32(-1)
|
||||||
DOWNSYNC_MSG_ACT_BATTLE_START = int32(0)
|
DOWNSYNC_MSG_ACT_BATTLE_START = int32(0)
|
||||||
@@ -134,7 +136,7 @@ type Room struct {
|
|||||||
EffectivePlayerCount int32
|
EffectivePlayerCount int32
|
||||||
DismissalWaitGroup sync.WaitGroup
|
DismissalWaitGroup sync.WaitGroup
|
||||||
InputsBuffer *battle.RingBuffer // Indices are STRICTLY consecutive
|
InputsBuffer *battle.RingBuffer // Indices are STRICTLY consecutive
|
||||||
InputsBufferLock sync.Mutex // Guards [InputsBuffer, LatestPlayerUpsyncedInputFrameId, LastAllConfirmedInputFrameId, LastAllConfirmedInputList, LastAllConfirmedInputFrameIdWithChange, LastIndividuallyConfirmedInputList, player.LastReceivedInputFrameId]
|
InputsBufferLock sync.Mutex // Guards [InputsBuffer, LatestPlayerUpsyncedInputFrameId, LastAllConfirmedInputFrameId, LastAllConfirmedInputList, LastAllConfirmedInputFrameIdWithChange, LastIndividuallyConfirmedInputList, player.LastReceivedInputFrameId, player.LastUdpReceivedInputFrameId]
|
||||||
RenderFrameBuffer *battle.RingBuffer // Indices are STRICTLY consecutive
|
RenderFrameBuffer *battle.RingBuffer // Indices are STRICTLY consecutive
|
||||||
LatestPlayerUpsyncedInputFrameId int32
|
LatestPlayerUpsyncedInputFrameId int32
|
||||||
LastAllConfirmedInputFrameId int32
|
LastAllConfirmedInputFrameId int32
|
||||||
@@ -156,13 +158,17 @@ type Room struct {
|
|||||||
|
|
||||||
rdfIdToActuallyUsedInput map[int32]*pb.InputFrameDownsync
|
rdfIdToActuallyUsedInput map[int32]*pb.InputFrameDownsync
|
||||||
LastIndividuallyConfirmedInputList []uint64
|
LastIndividuallyConfirmedInputList []uint64
|
||||||
|
|
||||||
|
BattleUdpTunnelLock sync.Mutex
|
||||||
|
BattleUdpTunnelAddr *pb.PeerUdpAddr
|
||||||
|
BattleUdpTunnel *net.UDPConn
|
||||||
}
|
}
|
||||||
|
|
||||||
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) bool {
|
||||||
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 {
|
||||||
@@ -174,12 +180,16 @@ func (pR *Room) AddPlayerIfPossible(pPlayerFromDbInit *Player, session *websocke
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
defer pR.onPlayerAdded(playerId)
|
defer pR.onPlayerAdded(playerId, speciesId)
|
||||||
|
|
||||||
|
pPlayerFromDbInit.UdpAddr = nil
|
||||||
|
pPlayerFromDbInit.BattleUdpTunnelAddr = nil
|
||||||
|
pPlayerFromDbInit.BattleUdpTunnelAuthKey = rand.Int31()
|
||||||
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.LastReceivedInputFrameId = 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
|
||||||
@@ -215,9 +225,13 @@ func (pR *Room) ReAddPlayerIfPossible(pTmpPlayerInstance *Player, session *webso
|
|||||||
*/
|
*/
|
||||||
defer pR.onPlayerReAdded(playerId)
|
defer pR.onPlayerReAdded(playerId)
|
||||||
pEffectiveInRoomPlayerInstance := pR.Players[playerId]
|
pEffectiveInRoomPlayerInstance := pR.Players[playerId]
|
||||||
|
pEffectiveInRoomPlayerInstance.UdpAddr = nil
|
||||||
|
pEffectiveInRoomPlayerInstance.BattleUdpTunnelAddr = nil
|
||||||
|
pEffectiveInRoomPlayerInstance.BattleUdpTunnelAuthKey = rand.Int31()
|
||||||
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!
|
||||||
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
|
||||||
@@ -315,8 +329,8 @@ func (pR *Room) InputsBufferString(allDetails bool) string {
|
|||||||
// Appending of the array of strings can be very SLOW due to on-demand heap allocation! Use this printing with caution.
|
// Appending of the array of strings can be very SLOW due to on-demand heap allocation! Use this printing with caution.
|
||||||
s := make([]string, 0)
|
s := make([]string, 0)
|
||||||
s = append(s, fmt.Sprintf("{renderFrameId: %v, stInputFrameId: %v, edInputFrameId: %v, lastAllConfirmedInputFrameIdWithChange: %v, lastAllConfirmedInputFrameId: %v}", pR.RenderFrameId, pR.InputsBuffer.StFrameId, pR.InputsBuffer.EdFrameId, pR.LastAllConfirmedInputFrameIdWithChange, pR.LastAllConfirmedInputFrameId))
|
s = append(s, fmt.Sprintf("{renderFrameId: %v, stInputFrameId: %v, edInputFrameId: %v, lastAllConfirmedInputFrameIdWithChange: %v, lastAllConfirmedInputFrameId: %v}", pR.RenderFrameId, pR.InputsBuffer.StFrameId, pR.InputsBuffer.EdFrameId, pR.LastAllConfirmedInputFrameIdWithChange, pR.LastAllConfirmedInputFrameId))
|
||||||
for playerId, player := range pR.PlayersArr {
|
for _, player := range pR.PlayersArr {
|
||||||
s = append(s, fmt.Sprintf("{playerId: %v, ackingFrameId: %v, ackingInputFrameId: %v, lastSentInputFrameId: %v}", playerId, player.AckingFrameId, player.AckingInputFrameId, player.LastSentInputFrameId))
|
s = append(s, fmt.Sprintf("{playerId: %v, ackingFrameId: %v, ackingInputFrameId: %v, lastSentInputFrameId: %v}", player.Id, player.AckingFrameId, player.AckingInputFrameId, player.LastSentInputFrameId))
|
||||||
}
|
}
|
||||||
for i := pR.InputsBuffer.StFrameId; i < pR.InputsBuffer.EdFrameId; i++ {
|
for i := pR.InputsBuffer.StFrameId; i < pR.InputsBuffer.EdFrameId; i++ {
|
||||||
tmp := pR.InputsBuffer.GetByFrameId(i)
|
tmp := pR.InputsBuffer.GetByFrameId(i)
|
||||||
@@ -402,15 +416,6 @@ 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"
|
||||||
@@ -562,7 +567,7 @@ func (pR *Room) StartBattle() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pR *Room) OnBattleCmdReceived(pReq *pb.WsReq) {
|
func (pR *Room) OnBattleCmdReceived(pReq *pb.WsReq, fromUDP bool) {
|
||||||
/*
|
/*
|
||||||
[WARNING] This function "OnBattleCmdReceived" could be called by different ws sessions and thus from different threads!
|
[WARNING] This function "OnBattleCmdReceived" could be called by different ws sessions and thus from different threads!
|
||||||
|
|
||||||
@@ -607,20 +612,21 @@ func (pR *Room) OnBattleCmdReceived(pReq *pb.WsReq) {
|
|||||||
//Logger.Debug(fmt.Sprintf("OnBattleCmdReceived-InputsBufferLock unlocked: roomId=%v, fromPlayerId=%v", pR.Id, playerId))
|
//Logger.Debug(fmt.Sprintf("OnBattleCmdReceived-InputsBufferLock unlocked: roomId=%v, fromPlayerId=%v", pR.Id, playerId))
|
||||||
}()
|
}()
|
||||||
|
|
||||||
inputsBufferSnapshot := pR.markConfirmationIfApplicable(inputFrameUpsyncBatch, playerId, player)
|
inputsBufferSnapshot := pR.markConfirmationIfApplicable(inputFrameUpsyncBatch, playerId, player, fromUDP)
|
||||||
if nil != inputsBufferSnapshot {
|
if nil != inputsBufferSnapshot {
|
||||||
pR.downsyncToAllPlayers(inputsBufferSnapshot)
|
pR.downsyncToAllPlayers(inputsBufferSnapshot)
|
||||||
} else {
|
} /*else {
|
||||||
// no new all-confirmed
|
// FIXME: Enable this block after we can proactively detect whether there's any "secondary ws session player" in the battle to avoid waste of resource in creating the snapshot
|
||||||
toSendInputFrameDownsyncs := pR.cloneInputsBuffer(inputFrameUpsyncBatch[0].InputFrameId, inputFrameUpsyncBatch[len(inputFrameUpsyncBatch)-1].InputFrameId+1)
|
// no new all-confirmed
|
||||||
|
toSendInputFrameDownsyncs := pR.cloneInputsBuffer(inputFrameUpsyncBatch[0].InputFrameId, inputFrameUpsyncBatch[len(inputFrameUpsyncBatch)-1].InputFrameId+1)
|
||||||
|
|
||||||
inputsBufferSnapshot = &pb.InputsBufferSnapshot{
|
inputsBufferSnapshot = &pb.InputsBufferSnapshot{
|
||||||
ToSendInputFrameDownsyncs: toSendInputFrameDownsyncs,
|
ToSendInputFrameDownsyncs: toSendInputFrameDownsyncs,
|
||||||
PeerJoinIndex: player.JoinIndex,
|
PeerJoinIndex: player.JoinIndex,
|
||||||
}
|
}
|
||||||
//Logger.Info(fmt.Sprintf("OnBattleCmdReceived no new all-confirmed: roomId=%v, fromPlayerId=%v, forming peer broadcasting snapshot=%v", pR.Id, playerId, inputsBufferSnapshot))
|
//Logger.Info(fmt.Sprintf("OnBattleCmdReceived no new all-confirmed: roomId=%v, fromPlayerId=%v, forming peer broadcasting snapshot=%v", pR.Id, playerId, inputsBufferSnapshot))
|
||||||
pR.broadcastPeerUpsyncForBetterPrediction(inputsBufferSnapshot)
|
pR.broadcastPeerUpsyncForBetterPrediction(inputsBufferSnapshot)
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pR *Room) onInputFrameDownsyncAllConfirmed(inputFrameDownsync *battle.InputFrameDownsync, playerId int32) {
|
func (pR *Room) onInputFrameDownsyncAllConfirmed(inputFrameDownsync *battle.InputFrameDownsync, playerId int32) {
|
||||||
@@ -662,6 +668,10 @@ func (pR *Room) StopBattleForSettlement() {
|
|||||||
if RoomBattleStateIns.IN_BATTLE != pR.State {
|
if RoomBattleStateIns.IN_BATTLE != pR.State {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
pR.BattleUdpTunnelLock.Lock()
|
||||||
|
pR.BattleUdpTunnel.Close()
|
||||||
|
pR.BattleUdpTunnelLock.Unlock()
|
||||||
|
|
||||||
pR.State = RoomBattleStateIns.STOPPING_BATTLE_FOR_SETTLEMENT
|
pR.State = RoomBattleStateIns.STOPPING_BATTLE_FOR_SETTLEMENT
|
||||||
Logger.Info("Stopping the `battleMainLoop` for:", zap.Any("roomId", pR.Id))
|
Logger.Info("Stopping the `battleMainLoop` for:", zap.Any("roomId", pR.Id))
|
||||||
pR.RenderFrameId++
|
pR.RenderFrameId++
|
||||||
@@ -798,7 +808,7 @@ func (pR *Room) OnDismissed() {
|
|||||||
|
|
||||||
pR.RenderFrameId = 0
|
pR.RenderFrameId = 0
|
||||||
pR.CurDynamicsRenderFrameId = 0
|
pR.CurDynamicsRenderFrameId = 0
|
||||||
pR.NstDelayFrames = 16
|
pR.NstDelayFrames = 24
|
||||||
|
|
||||||
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
|
||||||
@@ -806,20 +816,26 @@ func (pR *Room) OnDismissed() {
|
|||||||
dilutedServerFps := float64(58.0) // Don't set this value too small, otherwise we might miss force confirmation needs for slow tickers!
|
dilutedServerFps := float64(58.0) // Don't set this value too small, otherwise we might miss force confirmation needs for slow tickers!
|
||||||
pR.dilutedRollbackEstimatedDtNanos = int64(float64(pR.RollbackEstimatedDtNanos) * float64(serverFps) / dilutedServerFps)
|
pR.dilutedRollbackEstimatedDtNanos = int64(float64(pR.RollbackEstimatedDtNanos) * float64(serverFps) / dilutedServerFps)
|
||||||
pR.BattleDurationFrames = int32(60 * serverFps)
|
pR.BattleDurationFrames = int32(60 * serverFps)
|
||||||
|
//pR.BattleDurationFrames = int32(20 * serverFps)
|
||||||
pR.BattleDurationNanos = int64(pR.BattleDurationFrames) * (pR.RollbackEstimatedDtNanos + 1)
|
pR.BattleDurationNanos = int64(pR.BattleDurationFrames) * (pR.RollbackEstimatedDtNanos + 1)
|
||||||
pR.InputFrameUpsyncDelayTolerance = battle.ConvertToNoDelayInputFrameId(pR.NstDelayFrames) - 1 // this value should be strictly smaller than (NstDelayFrames >> InputScaleFrames), otherwise "type#1 forceConfirmation" might become a lag avalanche
|
pR.InputFrameUpsyncDelayTolerance = battle.ConvertToNoDelayInputFrameId(pR.NstDelayFrames) - 1 // this value should be strictly smaller than (NstDelayFrames >> InputScaleFrames), otherwise "type#1 forceConfirmation" might become a lag avalanche
|
||||||
pR.MaxChasingRenderFramesPerUpdate = 4 // Don't set this value too high to avoid exhausting frontend CPU within a single frame
|
pR.MaxChasingRenderFramesPerUpdate = 9 // Don't set this value too high to avoid exhausting frontend CPU within a single frame, roughly as the "turn-around frames to recover" is empirically OK
|
||||||
|
|
||||||
pR.BackendDynamicsEnabled = true // [WARNING] When "false", recovery upon reconnection wouldn't work!
|
pR.BackendDynamicsEnabled = true // [WARNING] When "false", recovery upon reconnection wouldn't work!
|
||||||
pR.ForceAllResyncOnAnyActiveSlowTicker = true // See tradeoff discussion in "downsyncToAllPlayers"
|
pR.ForceAllResyncOnAnyActiveSlowTicker = true // See tradeoff discussion in "downsyncToAllPlayers"
|
||||||
|
|
||||||
pR.FrameDataLoggingEnabled = false // [WARNING] DON'T ENABLE ON LONG BATTLE DURATION! It consumes A LOT OF MEMORY!
|
pR.FrameDataLoggingEnabled = false // [WARNING] DON'T ENABLE ON LONG BATTLE DURATION! It consumes A LOT OF MEMORY!
|
||||||
|
pR.BattleUdpTunnelLock.Lock()
|
||||||
|
pR.BattleUdpTunnel = nil
|
||||||
|
pR.BattleUdpTunnelAddr = nil
|
||||||
|
pR.BattleUdpTunnelLock.Unlock()
|
||||||
|
|
||||||
pR.ChooseStage()
|
pR.ChooseStage()
|
||||||
pR.EffectivePlayerCount = 0
|
pR.EffectivePlayerCount = 0
|
||||||
|
|
||||||
// [WARNING] It's deliberately ordered such that "pR.State = RoomBattleStateIns.IDLE" is put AFTER all the refreshing operations above.
|
// [WARNING] It's deliberately ordered such that "pR.State = RoomBattleStateIns.IDLE" is put AFTER all the refreshing operations above.
|
||||||
pR.State = RoomBattleStateIns.IDLE
|
pR.State = RoomBattleStateIns.IDLE
|
||||||
|
go pR.startBattleUdpTunnel() // Would reassign "pR.BattleUdpTunnel"
|
||||||
pR.updateScore()
|
pR.updateScore()
|
||||||
|
|
||||||
Logger.Info("The room is completely dismissed(all playerDownsyncChan closed):", zap.Any("roomId", pR.Id))
|
Logger.Info("The room is completely dismissed(all playerDownsyncChan closed):", zap.Any("roomId", pR.Id))
|
||||||
@@ -929,7 +945,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 {
|
||||||
@@ -941,8 +957,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".
|
||||||
@@ -955,7 +972,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
|
||||||
@@ -1068,7 +1088,9 @@ func (pR *Room) sendSafely(roomDownsyncFrame *pb.RoomDownsyncFrame, toSendInputF
|
|||||||
panic(fmt.Sprintf("Error marshaling downsync message: roomId=%v, playerId=%v, roomState=%v, roomEffectivePlayerCount=%v", pR.Id, playerId, pR.State, pR.EffectivePlayerCount))
|
panic(fmt.Sprintf("Error marshaling downsync message: roomId=%v, playerId=%v, roomState=%v, roomEffectivePlayerCount=%v", pR.Id, playerId, pR.State, pR.EffectivePlayerCount))
|
||||||
}
|
}
|
||||||
|
|
||||||
if MAGIC_JOIN_INDEX_DEFAULT == peerJoinIndex {
|
shouldUseSecondaryWsSession := (MAGIC_JOIN_INDEX_DEFAULT != peerJoinIndex && DOWNSYNC_MSG_ACT_INPUT_BATCH == act) // FIXME: Simplify the condition
|
||||||
|
//Logger.Info(fmt.Sprintf("shouldUseSecondaryWsSession=%v: roomId=%v, playerId=%v, roomState=%v, roomEffectivePlayerCount=%v", shouldUseSecondaryWsSession, pR.Id, playerId, pR.State, pR.EffectivePlayerCount))
|
||||||
|
if !shouldUseSecondaryWsSession {
|
||||||
if playerDownsyncSession, existent := pR.PlayerDownsyncSessionDict[playerId]; existent {
|
if playerDownsyncSession, existent := pR.PlayerDownsyncSessionDict[playerId]; existent {
|
||||||
if err := playerDownsyncSession.WriteMessage(websocket.BinaryMessage, theBytes); nil != err {
|
if err := playerDownsyncSession.WriteMessage(websocket.BinaryMessage, theBytes); nil != err {
|
||||||
panic(fmt.Sprintf("Error sending primary downsync message: roomId=%v, playerId=%v, roomState=%v, roomEffectivePlayerCount=%v, err=%v", pR.Id, playerId, pR.State, pR.EffectivePlayerCount, err))
|
panic(fmt.Sprintf("Error sending primary downsync message: roomId=%v, playerId=%v, roomState=%v, roomEffectivePlayerCount=%v, err=%v", pR.Id, playerId, pR.State, pR.EffectivePlayerCount, err))
|
||||||
@@ -1135,7 +1157,7 @@ func (pR *Room) getOrPrefabInputFrameDownsync(inputFrameId int32) *battle.InputF
|
|||||||
return currInputFrameDownsync
|
return currInputFrameDownsync
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pR *Room) markConfirmationIfApplicable(inputFrameUpsyncBatch []*pb.InputFrameUpsync, playerId int32, player *Player) *pb.InputsBufferSnapshot {
|
func (pR *Room) markConfirmationIfApplicable(inputFrameUpsyncBatch []*pb.InputFrameUpsync, playerId int32, player *Player, fromUDP bool) *pb.InputsBufferSnapshot {
|
||||||
// [WARNING] This function MUST BE called while "pR.InputsBufferLock" is locked!
|
// [WARNING] This function MUST BE called while "pR.InputsBufferLock" is locked!
|
||||||
// Step#1, put the received "inputFrameUpsyncBatch" into "pR.InputsBuffer"
|
// Step#1, put the received "inputFrameUpsyncBatch" into "pR.InputsBuffer"
|
||||||
for _, inputFrameUpsync := range inputFrameUpsyncBatch {
|
for _, inputFrameUpsync := range inputFrameUpsyncBatch {
|
||||||
@@ -1146,6 +1168,7 @@ func (pR *Room) markConfirmationIfApplicable(inputFrameUpsyncBatch []*pb.InputFr
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if clientInputFrameId < player.LastReceivedInputFrameId {
|
if clientInputFrameId < player.LastReceivedInputFrameId {
|
||||||
|
// [WARNING] It's important for correctness that we use "player.LastReceivedInputFrameId" instead of "player.LastUdpReceivedInputFrameId" 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, playerLastReceivedInputFrameId=%v, InputsBuffer=%v", pR.Id, playerId, clientInputFrameId, player.LastReceivedInputFrameId, pR.InputsBufferString(false)))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -1158,11 +1181,25 @@ func (pR *Room) markConfirmationIfApplicable(inputFrameUpsyncBatch []*pb.InputFr
|
|||||||
targetInputFrameDownsync.InputList[player.JoinIndex-1] = inputFrameUpsync.Encoded
|
targetInputFrameDownsync.InputList[player.JoinIndex-1] = inputFrameUpsync.Encoded
|
||||||
targetInputFrameDownsync.ConfirmedList |= uint64(1 << uint32(player.JoinIndex-1))
|
targetInputFrameDownsync.ConfirmedList |= uint64(1 << uint32(player.JoinIndex-1))
|
||||||
|
|
||||||
player.LastReceivedInputFrameId = clientInputFrameId
|
if false == fromUDP {
|
||||||
pR.LastIndividuallyConfirmedInputList[player.JoinIndex-1] = inputFrameUpsync.Encoded
|
/*
|
||||||
|
[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"!
|
||||||
|
|
||||||
if clientInputFrameId > pR.LatestPlayerUpsyncedInputFrameId {
|
Moreover, only ws session upsyncs should advance "player.LastReceivedInputFrameId" & "pR.LatestPlayerUpsyncedInputFrameId".
|
||||||
pR.LatestPlayerUpsyncedInputFrameId = clientInputFrameId
|
|
||||||
|
Kindly note that the updates of "player.LastReceivedInputFrameId" could be discrete before and after reconnection.
|
||||||
|
*/
|
||||||
|
player.LastReceivedInputFrameId = clientInputFrameId
|
||||||
|
if clientInputFrameId > pR.LatestPlayerUpsyncedInputFrameId {
|
||||||
|
pR.LatestPlayerUpsyncedInputFrameId = clientInputFrameId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if clientInputFrameId > player.LastUdpReceivedInputFrameId {
|
||||||
|
// No need to update "player.LastUdpReceivedInputFrameId" only when "true == fromUDP", we should keep "player.LastUdpReceivedInputFrameId >= player.LastReceivedInputFrameId" at any moment.
|
||||||
|
player.LastUdpReceivedInputFrameId = 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.
|
||||||
|
pR.LastIndividuallyConfirmedInputList[player.JoinIndex-1] = inputFrameUpsync.Encoded
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1229,6 +1266,7 @@ func (pR *Room) forceConfirmationIfApplicable(prevRenderFrameId int32) uint64 {
|
|||||||
totPlayerCnt := uint32(pR.Capacity)
|
totPlayerCnt := uint32(pR.Capacity)
|
||||||
allConfirmedMask := uint64((1 << totPlayerCnt) - 1)
|
allConfirmedMask := uint64((1 << totPlayerCnt) - 1)
|
||||||
unconfirmedMask := uint64(0)
|
unconfirmedMask := uint64(0)
|
||||||
|
// As "pR.LastAllConfirmedInputFrameId" can be advanced by UDP but "pR.LatestPlayerUpsyncedInputFrameId" could only be advanced by ws session, when the following condition is met we know that the slow ticker is really in trouble!
|
||||||
if pR.LatestPlayerUpsyncedInputFrameId > (pR.LastAllConfirmedInputFrameId + pR.InputFrameUpsyncDelayTolerance + 1) {
|
if pR.LatestPlayerUpsyncedInputFrameId > (pR.LastAllConfirmedInputFrameId + pR.InputFrameUpsyncDelayTolerance + 1) {
|
||||||
// Type#1 check whether there's a significantly slow ticker among players
|
// Type#1 check whether there's a significantly slow ticker among players
|
||||||
oldLastAllConfirmedInputFrameId := pR.LastAllConfirmedInputFrameId
|
oldLastAllConfirmedInputFrameId := pR.LastAllConfirmedInputFrameId
|
||||||
@@ -1350,13 +1388,13 @@ func (pR *Room) printBarrier(barrierCollider *resolv.Object) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (pR *Room) doBattleMainLoopPerTickBackendDynamicsWithProperLocking(prevRenderFrameId int32, pDynamicsDuration *int64) {
|
func (pR *Room) doBattleMainLoopPerTickBackendDynamicsWithProperLocking(prevRenderFrameId int32, pDynamicsDuration *int64) {
|
||||||
Logger.Debug(fmt.Sprintf("doBattleMainLoopPerTickBackendDynamicsWithProperLocking-InputsBufferLock to about lock: roomId=%v", pR.Id))
|
//Logger.Debug(fmt.Sprintf("doBattleMainLoopPerTickBackendDynamicsWithProperLocking-InputsBufferLock to about lock: roomId=%v", pR.Id))
|
||||||
pR.InputsBufferLock.Lock()
|
pR.InputsBufferLock.Lock()
|
||||||
Logger.Debug(fmt.Sprintf("doBattleMainLoopPerTickBackendDynamicsWithProperLocking-InputsBufferLock locked: roomId=%v", pR.Id))
|
//Logger.Debug(fmt.Sprintf("doBattleMainLoopPerTickBackendDynamicsWithProperLocking-InputsBufferLock locked: roomId=%v", pR.Id))
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
pR.InputsBufferLock.Unlock()
|
pR.InputsBufferLock.Unlock()
|
||||||
Logger.Debug(fmt.Sprintf("doBattleMainLoopPerTickBackendDynamicsWithProperLocking-InputsBufferLock unlocked: roomId=%v", pR.Id))
|
//Logger.Debug(fmt.Sprintf("doBattleMainLoopPerTickBackendDynamicsWithProperLocking-InputsBufferLock unlocked: roomId=%v", pR.Id))
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if ok, thatRenderFrameId := battle.ShouldPrefabInputFrameDownsync(prevRenderFrameId, pR.RenderFrameId); ok {
|
if ok, thatRenderFrameId := battle.ShouldPrefabInputFrameDownsync(prevRenderFrameId, pR.RenderFrameId); ok {
|
||||||
@@ -1607,3 +1645,144 @@ func (pR *Room) SetSecondarySession(playerId int32, session *websocket.Conn, sig
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (pR *Room) UpdatePeerUdpAddrList(playerId int32, peerAddr *net.UDPAddr, pReq *pb.HolePunchUpsync) {
|
||||||
|
// TODO: There's a chance that by now "player.JoinIndex" is not yet determined, use a lock to sync
|
||||||
|
if player, ok := pR.Players[playerId]; ok && MAGIC_JOIN_INDEX_DEFAULT != player.JoinIndex {
|
||||||
|
playerBattleState := atomic.LoadInt32(&(player.BattleState))
|
||||||
|
switch playerBattleState {
|
||||||
|
case PlayerBattleStateIns.DISCONNECTED, PlayerBattleStateIns.LOST, PlayerBattleStateIns.EXPELLED_DURING_GAME, PlayerBattleStateIns.EXPELLED_IN_DISMISSAL:
|
||||||
|
// Kindly note that "PlayerBattleStateIns.ADDED_PENDING_BATTLE_COLLIDER_ACK, PlayerBattleStateIns.READDED_PENDING_BATTLE_COLLIDER_ACK" are allowed
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if _, existent := pR.PlayerDownsyncSessionDict[playerId]; existent {
|
||||||
|
player.UdpAddr = &pb.PeerUdpAddr{
|
||||||
|
Ip: peerAddr.IP.String(),
|
||||||
|
Port: int32(peerAddr.Port),
|
||||||
|
AuthKey: pReq.AuthKey,
|
||||||
|
}
|
||||||
|
Logger.Info(fmt.Sprintf("UpdatePeerUdpAddrList done for roomId=%v, playerId=%d, peerAddr=%s", pR.Id, playerId, peerAddr))
|
||||||
|
|
||||||
|
peerJoinIndex := player.JoinIndex
|
||||||
|
peerUdpAddrList := make([]*pb.PeerUdpAddr, pR.Capacity, pR.Capacity)
|
||||||
|
|
||||||
|
for _, otherPlayer := range pR.Players {
|
||||||
|
if MAGIC_JOIN_INDEX_DEFAULT == otherPlayer.JoinIndex {
|
||||||
|
// TODO: Again this shouldn't happen, apply proper locking
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// In case of highly concurrent update that might occur while later marshalling, use the ptr of a copy
|
||||||
|
peerUdpAddrList[otherPlayer.JoinIndex-1] = &pb.PeerUdpAddr{
|
||||||
|
Ip: otherPlayer.UdpAddr.Ip,
|
||||||
|
Port: otherPlayer.UdpAddr.Port,
|
||||||
|
AuthKey: otherPlayer.UdpAddr.AuthKey,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Broadcast this new UDP addr to all the existing players
|
||||||
|
for otherPlayerId, otherPlayer := range pR.Players {
|
||||||
|
otherPlayerBattleState := atomic.LoadInt32(&(otherPlayer.BattleState))
|
||||||
|
switch otherPlayerBattleState {
|
||||||
|
case PlayerBattleStateIns.DISCONNECTED, PlayerBattleStateIns.LOST, PlayerBattleStateIns.EXPELLED_DURING_GAME, PlayerBattleStateIns.EXPELLED_IN_DISMISSAL:
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.Info(fmt.Sprintf("Downsyncing peerUdpAddrList for roomId=%v, playerId=%d", pR.Id, otherPlayerId))
|
||||||
|
pR.sendSafely(&pb.RoomDownsyncFrame{
|
||||||
|
PeerUdpAddrList: peerUdpAddrList,
|
||||||
|
}, nil, DOWNSYNC_MSG_ACT_PEER_UDP_ADDR, otherPlayerId, false, peerJoinIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pR *Room) startBattleUdpTunnel() {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
Logger.Error("`BattleUdpTunnel` recovery spot#1, recovered from: ", zap.Any("roomId", pR.Id), zap.Any("panic", r))
|
||||||
|
}
|
||||||
|
Logger.Info(fmt.Sprintf("`BattleUdpTunnel` stopped for (roomId=%d)@renderFrameId=%v", pR.Id, pR.RenderFrameId))
|
||||||
|
}()
|
||||||
|
|
||||||
|
pR.BattleUdpTunnelLock.Lock()
|
||||||
|
conn, err := net.ListenUDP("udp", &net.UDPAddr{
|
||||||
|
Port: 0,
|
||||||
|
IP: net.ParseIP(Conf.Sio.UdpHost),
|
||||||
|
})
|
||||||
|
if nil != err {
|
||||||
|
// No need to close the "conn" upon error here
|
||||||
|
pR.BattleUdpTunnelLock.Unlock()
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
pR.BattleUdpTunnel = conn
|
||||||
|
switch v := conn.LocalAddr().(type) {
|
||||||
|
case (*net.UDPAddr):
|
||||||
|
pR.BattleUdpTunnelAddr = &pb.PeerUdpAddr{
|
||||||
|
Ip: Conf.Sio.UdpHost,
|
||||||
|
Port: int32(v.Port),
|
||||||
|
AuthKey: 0, // To be determined for each specific player upon joining and sent to it by BattleColliderInfo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pR.BattleUdpTunnelLock.Unlock()
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
Logger.Warn("`BattleUdpTunnel` recovery spot#2, recovered from: ", zap.Any("roomId", pR.Id), zap.Any("panic", r))
|
||||||
|
}
|
||||||
|
Logger.Info(fmt.Sprintf("`BattleUdpTunnel` closed for (roomId=%d)@renderFrameId=%v", pR.Id, pR.RenderFrameId))
|
||||||
|
}()
|
||||||
|
Logger.Info(fmt.Sprintf("`BattleUdpTunnel` started for roomId=%d at %s", pR.Id, conn.LocalAddr().String()))
|
||||||
|
for {
|
||||||
|
message := make([]byte, 128)
|
||||||
|
rlen, remote, err := conn.ReadFromUDP(message[:]) // Would be unblocked when "conn.Close()" is called from another thread/goroutine, reference https://pkg.go.dev/net@go1.18.6#PacketConn
|
||||||
|
if nil != err {
|
||||||
|
// Should proceed to close the "conn" upon error here, if "conn" is already closed it'd just throw another error to be catched by "spot#2"
|
||||||
|
conn.Close()
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
pReq := new(pb.WsReq)
|
||||||
|
bytes := message[0:rlen]
|
||||||
|
if unmarshalErr := proto.Unmarshal(bytes, pReq); nil != unmarshalErr {
|
||||||
|
Logger.Warn(fmt.Sprintf("`BattleUdpTunnel` for roomId=%d failed to unmarshal %d bytes", pR.Id, rlen), zap.Error(unmarshalErr))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
playerId := pReq.PlayerId
|
||||||
|
//Logger.Info(fmt.Sprintf("`BattleUdpTunnel` for roomId=%d received decoded WsReq:", pR.Id), zap.Any("pReq", pReq))
|
||||||
|
if player, exists1 := pR.Players[playerId]; exists1 {
|
||||||
|
authKey := pReq.AuthKey
|
||||||
|
if authKey != player.BattleUdpTunnelAuthKey {
|
||||||
|
Logger.Warn(fmt.Sprintf("`BattleUdpTunnel` for roomId=%d received %d bytes for playerId=%d from %s, but (incomingAuthKey:%d != playerBattleUdpTunnelAuthKey:%d)\n", pR.Id, rlen, playerId, remote, authKey, player.BattleUdpTunnelAuthKey))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, existent := pR.PlayerDownsyncSessionDict[playerId]; existent {
|
||||||
|
player.BattleUdpTunnelAddr = remote
|
||||||
|
//Logger.Info(fmt.Sprintf("`BattleUdpTunnel` for roomId=%d updated battleUdpAddr for playerId=%d to be %s\n", pR.Id, playerId, remote))
|
||||||
|
|
||||||
|
nowBattleState := atomic.LoadInt32(&pR.State)
|
||||||
|
if RoomBattleStateIns.IN_BATTLE == nowBattleState {
|
||||||
|
batch := pReq.InputFrameUpsyncBatch
|
||||||
|
if nil != batch && 0 < len(batch) {
|
||||||
|
peerJoinIndex := pReq.JoinIndex
|
||||||
|
// Broadcast to every other player in the same room/battle
|
||||||
|
for _, otherPlayer := range pR.PlayersArr {
|
||||||
|
if otherPlayer.JoinIndex == peerJoinIndex {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
_, wrerr := conn.WriteTo(bytes, otherPlayer.BattleUdpTunnelAddr)
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Logger.Warn(fmt.Sprintf("`BattleUdpTunnel` for roomId=%d received validated %d bytes for playerId=%d from %s, but primary downsync session for it doesn't exist\n", pR.Id, rlen, playerId, remote))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Logger.Warn(fmt.Sprintf("`BattleUdpTunnel` for roomId=%d received invalid %d bytes for playerId=%d from %s, but it doesn't belong to this room!\n", pR.Id, rlen, playerId, remote))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
@@ -49,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 {
|
||||||
@@ -194,7 +205,7 @@ func Serve(c *gin.Context) {
|
|||||||
|
|
||||||
if pRoom.ReAddPlayerIfPossible(pPlayer, conn, signalToCloseConnOfThisPlayer) {
|
if pRoom.ReAddPlayerIfPossible(pPlayer, conn, signalToCloseConnOfThisPlayer) {
|
||||||
playerSuccessfullyAddedToRoom = true
|
playerSuccessfullyAddedToRoom = true
|
||||||
} else if pRoom.AddPlayerIfPossible(pPlayer, conn, signalToCloseConnOfThisPlayer) {
|
} else if pRoom.AddPlayerIfPossible(pPlayer, speciesId, conn, signalToCloseConnOfThisPlayer) {
|
||||||
playerSuccessfullyAddedToRoom = true
|
playerSuccessfullyAddedToRoom = true
|
||||||
} else {
|
} 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))
|
||||||
@@ -218,7 +229,7 @@ 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)
|
res := pRoom.AddPlayerIfPossible(pPlayer, speciesId, conn, signalToCloseConnOfThisPlayer)
|
||||||
if !res {
|
if !res {
|
||||||
signalToCloseConnOfThisPlayer(Constants.RetCode.PlayerNotAddableToRoom, fmt.Sprintf("AddPlayerIfPossible returns false for roomId == %v, playerId == %v!", pRoom.Id, playerId))
|
signalToCloseConnOfThisPlayer(Constants.RetCode.PlayerNotAddableToRoom, fmt.Sprintf("AddPlayerIfPossible returns false for roomId == %v, playerId == %v!", pRoom.Id, playerId))
|
||||||
}
|
}
|
||||||
@@ -256,17 +267,25 @@ func Serve(c *gin.Context) {
|
|||||||
SpaceOffsetX: pRoom.SpaceOffsetX,
|
SpaceOffsetX: pRoom.SpaceOffsetX,
|
||||||
SpaceOffsetY: pRoom.SpaceOffsetY,
|
SpaceOffsetY: pRoom.SpaceOffsetY,
|
||||||
|
|
||||||
RenderCacheSize: pRoom.RenderCacheSize,
|
RenderCacheSize: pRoom.RenderCacheSize,
|
||||||
CollisionMinStep: pRoom.CollisionMinStep,
|
CollisionMinStep: pRoom.CollisionMinStep,
|
||||||
|
BoundRoomCapacity: int32(pRoom.Capacity),
|
||||||
|
|
||||||
|
BattleUdpTunnel: &pb.PeerUdpAddr{
|
||||||
|
Ip: pRoom.BattleUdpTunnelAddr.Ip,
|
||||||
|
Port: pRoom.BattleUdpTunnelAddr.Port,
|
||||||
|
AuthKey: pThePlayer.BattleUdpTunnelAuthKey,
|
||||||
|
},
|
||||||
|
|
||||||
FrameDataLoggingEnabled: pRoom.FrameDataLoggingEnabled,
|
FrameDataLoggingEnabled: pRoom.FrameDataLoggingEnabled,
|
||||||
}
|
}
|
||||||
|
|
||||||
resp := &pb.WsResp{
|
resp := &pb.WsResp{
|
||||||
Ret: int32(Constants.RetCode.Ok),
|
Ret: int32(Constants.RetCode.Ok),
|
||||||
EchoedMsgId: int32(0),
|
EchoedMsgId: int32(0),
|
||||||
Act: models.DOWNSYNC_MSG_ACT_HB_REQ,
|
Act: models.DOWNSYNC_MSG_ACT_HB_REQ,
|
||||||
BciFrame: bciFrame,
|
BciFrame: bciFrame,
|
||||||
|
PeerJoinIndex: pThePlayer.JoinIndex,
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.Debug("Sending downsync HeartbeatRequirements:", zap.Any("roomId", pRoom.Id), zap.Any("playerId", playerId), zap.Any("resp", resp))
|
Logger.Debug("Sending downsync HeartbeatRequirements:", zap.Any("roomId", pRoom.Id), zap.Any("playerId", playerId), zap.Any("resp", resp))
|
||||||
@@ -379,7 +398,7 @@ func Serve(c *gin.Context) {
|
|||||||
startOrFeedHeartbeatWatchdog(conn)
|
startOrFeedHeartbeatWatchdog(conn)
|
||||||
case models.UPSYNC_MSG_ACT_PLAYER_CMD:
|
case models.UPSYNC_MSG_ACT_PLAYER_CMD:
|
||||||
startOrFeedHeartbeatWatchdog(conn)
|
startOrFeedHeartbeatWatchdog(conn)
|
||||||
pRoom.OnBattleCmdReceived(pReq)
|
pRoom.OnBattleCmdReceived(pReq, false)
|
||||||
case models.UPSYNC_MSG_ACT_PLAYER_COLLIDER_ACK:
|
case models.UPSYNC_MSG_ACT_PLAYER_COLLIDER_ACK:
|
||||||
res := pRoom.OnPlayerBattleColliderAcked(int32(playerId))
|
res := pRoom.OnPlayerBattleColliderAcked(int32(playerId))
|
||||||
if false == res {
|
if false == res {
|
||||||
@@ -432,12 +451,12 @@ func HandleSecondaryWsSessionForPlayer(c *gin.Context) {
|
|||||||
playerId, err := models.GetPlayerIdByToken(token)
|
playerId, err := models.GetPlayerIdByToken(token)
|
||||||
if err != nil || playerId == 0 {
|
if err != nil || playerId == 0 {
|
||||||
// TODO: Abort with specific message.
|
// TODO: Abort with specific message.
|
||||||
Logger.Warn("Secondary ws session playerLogin record not found for ws authentication:", zap.Any("intAuthToken", token))
|
Logger.Warn("Secondary ws session playerLogin record not found:", zap.Any("intAuthToken", token))
|
||||||
c.AbortWithStatus(http.StatusBadRequest)
|
c.AbortWithStatus(http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.Info("Secondary ws session playerLogin record has been found for ws authentication:", zap.Any("playerId", playerId), zap.Any("intAuthToken", token), zap.Any("boundRoomId", boundRoomId))
|
Logger.Info("Secondary ws session playerLogin record has been found:", zap.Any("playerId", playerId), zap.Any("intAuthToken", token), zap.Any("boundRoomId", boundRoomId))
|
||||||
|
|
||||||
conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
|
conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -482,3 +501,32 @@ func HandleSecondaryWsSessionForPlayer(c *gin.Context) {
|
|||||||
|
|
||||||
pRoom.SetSecondarySession(int32(playerId), conn, signalToCloseConnOfThisPlayer)
|
pRoom.SetSecondarySession(int32(playerId), conn, signalToCloseConnOfThisPlayer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func HandleUdpHolePunchingForPlayer(message []byte, peerAddr *net.UDPAddr) {
|
||||||
|
pReq := new(pb.HolePunchUpsync)
|
||||||
|
if unmarshalErr := proto.Unmarshal(message, pReq); nil != unmarshalErr {
|
||||||
|
Logger.Error("`GrandUdpServer` failed to unmarshal", zap.Error(unmarshalErr))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
token := pReq.IntAuthToken
|
||||||
|
boundRoomId := pReq.BoundRoomId
|
||||||
|
|
||||||
|
pRoom, existent := (*models.RoomMapManagerIns)[int32(boundRoomId)]
|
||||||
|
// Deliberately querying playerId after querying room, because the former is against persistent storage and could be slow!
|
||||||
|
if !existent {
|
||||||
|
Logger.Warn("`GrandUdpServer` failed to get:\n", zap.Any("intAuthToken", token), zap.Any("forBoundRoomId", boundRoomId))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Wrap the following 2 stmts by sql transaction!
|
||||||
|
playerId, err := models.GetPlayerIdByToken(token)
|
||||||
|
if err != nil || playerId == 0 {
|
||||||
|
// TODO: Abort with specific message.
|
||||||
|
Logger.Warn("`GrandUdpServer` playerLogin record not found for:", zap.Any("intAuthToken", token))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.Info("`GrandUdpServer` playerLogin record has been found:", zap.Any("playerId", playerId), zap.Any("intAuthToken", token), zap.Any("boundRoomId", boundRoomId), zap.Any("peerAddr", peerAddr))
|
||||||
|
pRoom.UpdatePeerUdpAddrList(int32(playerId), peerAddr, pReq)
|
||||||
|
}
|
||||||
|
BIN
charts/Merged_cut_annotated_spedup.gif
Normal file
After Width: | Height: | Size: 7.4 MiB |
BIN
charts/NativeBuildReload.png
Normal file
After Width: | Height: | Size: 118 KiB |
BIN
charts/PackageNameIssueInCcc.png
Normal file
After Width: | Height: | Size: 135 KiB |
BIN
charts/Phone4g_battle_spedup.gif
Normal file
After Width: | Height: | Size: 4.4 MiB |
Before Width: | Height: | Size: 417 KiB After Width: | Height: | Size: 472 KiB |
BIN
charts/VisualStudioSetup.png
Normal file
After Width: | Height: | Size: 191 KiB |
Before Width: | Height: | Size: 6.7 MiB |
Before Width: | Height: | Size: 3.7 MiB |
BIN
charts/networkstats.png
Normal file
After Width: | Height: | Size: 2.2 MiB |
@@ -198,3 +198,6 @@ window.getOrCreateAnimationClipForGid = function(gid, tiledMapInfo, tilesElListU
|
|||||||
animationClip: animClip,
|
animationClip: animClip,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Node.js, this is a workaround to avoid accessing the non-existent "TextDecoder class" from "jsexport.js".
|
||||||
|
window.fs = function() {};
|
||||||
|
@@ -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"
|
||||||
}
|
}
|
||||||
|
@@ -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": []
|
||||||
|
}
|
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"ver": "2.1.0",
|
||||||
|
"uuid": "14b92f5c-af81-416a-a162-e5822d20fe68",
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
@@ -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": []
|
||||||
|
}
|
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"ver": "2.1.0",
|
||||||
|
"uuid": "0dbb90ed-a08a-448c-b06e-4831260e9213",
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
97
frontend/assets/resources/animation/Fireball/Fireball2.anim
Normal 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": []
|
||||||
|
}
|
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"ver": "2.1.0",
|
||||||
|
"uuid": "d2c65ac4-a5b3-411e-8d2d-18d3980649d7",
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
73
frontend/assets/resources/animation/Fireball/Fireball3.anim
Normal 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": []
|
||||||
|
}
|
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"ver": "2.1.0",
|
||||||
|
"uuid": "6aef5812-d16c-4da1-96a3-a38ac227c823",
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
73
frontend/assets/resources/animation/KnifeGirl/Atk4.anim
Normal 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": []
|
||||||
|
}
|
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"ver": "2.1.0",
|
||||||
|
"uuid": "2aef91f9-ef47-4bb4-bf43-5441723aa639",
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
103
frontend/assets/resources/animation/KnifeGirl/Dying.anim
Normal 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": []
|
||||||
|
}
|
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"ver": "2.1.0",
|
||||||
|
"uuid": "ac90c9b8-3b06-4866-89ce-2c953a9d5a9a",
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
Before Width: | Height: | Size: 119 KiB After Width: | Height: | Size: 175 KiB |
61
frontend/assets/resources/animation/Monk/Dashing.anim
Normal 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": []
|
||||||
|
}
|
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"ver": "2.1.0",
|
||||||
|
"uuid": "337d57ad-118c-40e2-be90-2aa1505c152b",
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
115
frontend/assets/resources/animation/Monk/Dying.anim
Normal 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": []
|
||||||
|
}
|
5
frontend/assets/resources/animation/Monk/Dying.anim.meta
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"ver": "2.1.0",
|
||||||
|
"uuid": "657d4193-2224-44ea-94f7-0305a9f2b322",
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
@@ -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"
|
||||||
}
|
}
|
||||||
|
Before Width: | Height: | Size: 269 KiB After Width: | Height: | Size: 314 KiB |
91
frontend/assets/resources/animation/MonkGirl/Atk4.anim
Normal 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": []
|
||||||
|
}
|
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"ver": "2.1.0",
|
||||||
|
"uuid": "168df303-4b6a-4376-940c-3d36fa9e98d8",
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
55
frontend/assets/resources/animation/MonkGirl/Dashing.anim
Normal 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": []
|
||||||
|
}
|
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"ver": "2.1.0",
|
||||||
|
"uuid": "d7b6d7c4-d2b5-49c6-bbcb-d8d80f52ae7e",
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
61
frontend/assets/resources/animation/MonkGirl/Dying.anim
Normal 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": []
|
||||||
|
}
|
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"ver": "2.1.0",
|
||||||
|
"uuid": "86706adc-e079-4997-883b-3e269d223065",
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
@@ -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": {
|
||||||
|
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 227 KiB |
25
frontend/assets/resources/animation/MonkGirl/OnWall.anim
Normal 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": []
|
||||||
|
}
|
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"ver": "2.1.0",
|
||||||
|
"uuid": "57358699-1d1b-44db-898c-df0c3ce9aab0",
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
@@ -37,6 +37,8 @@ message PlayerDownsync {
|
|||||||
int32 onWallNormY = 28;
|
int32 onWallNormY = 28;
|
||||||
|
|
||||||
bool capturedByInertia = 29; // like "inAir", it’s by design a standalone field only inferred by the calc result of "applyInputFrameDownsyncDynamicsOnSingleRenderFrame" instead of "characterState"
|
bool capturedByInertia = 29; // like "inAir", it’s 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;
|
||||||
@@ -73,18 +75,9 @@ message WsReq {
|
|||||||
int32 joinIndex = 4;
|
int32 joinIndex = 4;
|
||||||
int32 ackingFrameId = 5;
|
int32 ackingFrameId = 5;
|
||||||
int32 ackingInputFrameId = 6;
|
int32 ackingInputFrameId = 6;
|
||||||
repeated InputFrameUpsync inputFrameUpsyncBatch = 7;
|
int32 authKey = 7;
|
||||||
HeartbeatUpsync hb = 8;
|
repeated InputFrameUpsync inputFrameUpsyncBatch = 8;
|
||||||
}
|
HeartbeatUpsync hb = 9;
|
||||||
|
|
||||||
message WsResp {
|
|
||||||
int32 ret = 1;
|
|
||||||
int32 echoedMsgId = 2;
|
|
||||||
int32 act = 3;
|
|
||||||
RoomDownsyncFrame rdf = 4;
|
|
||||||
repeated InputFrameDownsync inputFrameDownsyncBatch = 5;
|
|
||||||
BattleColliderInfo bciFrame = 6;
|
|
||||||
int32 peerJoinIndex = 7; // Only used when "InputsBufferSnapshot.peerJoinIndex" is used.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message InputsBufferSnapshot {
|
message InputsBufferSnapshot {
|
||||||
@@ -92,7 +85,7 @@ message InputsBufferSnapshot {
|
|||||||
uint64 unconfirmedMask = 2;
|
uint64 unconfirmedMask = 2;
|
||||||
repeated InputFrameDownsync toSendInputFrameDownsyncs = 3;
|
repeated InputFrameDownsync toSendInputFrameDownsyncs = 3;
|
||||||
bool shouldForceResync = 4;
|
bool shouldForceResync = 4;
|
||||||
int32 peerJoinIndex = 5; // Only used when "WsResp.peerJoinIndex" is used.
|
int32 peerJoinIndex = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
message MeleeBullet {
|
message MeleeBullet {
|
||||||
@@ -175,6 +168,18 @@ message FireballBullet {
|
|||||||
int32 speed = 1005;
|
int32 speed = 1005;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message HolePunchUpsync {
|
||||||
|
string intAuthToken = 1;
|
||||||
|
int32 boundRoomId = 2;
|
||||||
|
int32 authKey = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message PeerUdpAddr {
|
||||||
|
string ip = 1;
|
||||||
|
int32 port = 2;
|
||||||
|
int32 authKey = 3;
|
||||||
|
}
|
||||||
|
|
||||||
message BattleColliderInfo {
|
message BattleColliderInfo {
|
||||||
string stageName = 1;
|
string stageName = 1;
|
||||||
|
|
||||||
@@ -191,6 +196,8 @@ message BattleColliderInfo {
|
|||||||
double spaceOffsetX = 11;
|
double spaceOffsetX = 11;
|
||||||
double spaceOffsetY = 12;
|
double spaceOffsetY = 12;
|
||||||
int32 collisionMinStep = 13;
|
int32 collisionMinStep = 13;
|
||||||
|
int32 boundRoomCapacity = 14;
|
||||||
|
PeerUdpAddr battleUdpTunnel = 15;
|
||||||
|
|
||||||
bool frameDataLoggingEnabled = 1024;
|
bool frameDataLoggingEnabled = 1024;
|
||||||
}
|
}
|
||||||
@@ -207,4 +214,15 @@ message RoomDownsyncFrame {
|
|||||||
repeated int32 speciesIdList = 1026;
|
repeated int32 speciesIdList = 1026;
|
||||||
|
|
||||||
int32 bulletLocalIdCounter = 1027;
|
int32 bulletLocalIdCounter = 1027;
|
||||||
|
repeated PeerUdpAddr peerUdpAddrList = 1028;
|
||||||
|
}
|
||||||
|
|
||||||
|
message WsResp {
|
||||||
|
int32 ret = 1;
|
||||||
|
int32 echoedMsgId = 2;
|
||||||
|
int32 act = 3;
|
||||||
|
RoomDownsyncFrame rdf = 4;
|
||||||
|
repeated InputFrameDownsync inputFrameDownsyncBatch = 5;
|
||||||
|
BattleColliderInfo bciFrame = 6;
|
||||||
|
int32 peerJoinIndex = 7;
|
||||||
}
|
}
|
||||||
|
@@ -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": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@@ -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": [],
|
||||||
|
@@ -88,7 +88,7 @@
|
|||||||
"__id__": 1
|
"__id__": 1
|
||||||
},
|
},
|
||||||
"_children": [],
|
"_children": [],
|
||||||
"_active": true,
|
"_active": false,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 3
|
"__id__": 3
|
||||||
|
@@ -77,20 +77,20 @@
|
|||||||
],
|
],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
|
||||||
"__id__": 48
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__id__": 49
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__id__": 50
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"__id__": 51
|
"__id__": 51
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 52
|
"__id__": 52
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 53
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 54
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 55
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -156,9 +156,6 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 5
|
"__id__": 5
|
||||||
},
|
|
||||||
{
|
|
||||||
"__id__": 47
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -247,10 +244,10 @@
|
|||||||
"__uuid__": "670b477e-61a1-4778-879b-35913f7c79d2"
|
"__uuid__": "670b477e-61a1-4778-879b-35913f7c79d2"
|
||||||
},
|
},
|
||||||
"boundRoomIdLabel": {
|
"boundRoomIdLabel": {
|
||||||
"__id__": 24
|
"__id__": 28
|
||||||
},
|
},
|
||||||
"countdownLabel": {
|
"countdownLabel": {
|
||||||
"__id__": 31
|
"__id__": 35
|
||||||
},
|
},
|
||||||
"resultPanelPrefab": {
|
"resultPanelPrefab": {
|
||||||
"__uuid__": "c4cfe3bd-c59e-4d5b-95cb-c933b120e184"
|
"__uuid__": "c4cfe3bd-c59e-4d5b-95cb-c933b120e184"
|
||||||
@@ -264,23 +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
|
||||||
},
|
},
|
||||||
|
"rollbackFramesLabel": {
|
||||||
|
"__id__": 21
|
||||||
|
},
|
||||||
|
"skippedRenderFrameCntLabel": {
|
||||||
|
"__id__": 23
|
||||||
|
},
|
||||||
"_id": "d12gkAmppNlIzqcRDELa91"
|
"_id": "d12gkAmppNlIzqcRDELa91"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -292,13 +292,13 @@
|
|||||||
},
|
},
|
||||||
"_children": [
|
"_children": [
|
||||||
{
|
{
|
||||||
"__id__": 41
|
"__id__": 45
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 46
|
"__id__": 50
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -361,19 +361,19 @@
|
|||||||
"__id__": 6
|
"__id__": 6
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 30
|
"__id__": 34
|
||||||
},
|
|
||||||
{
|
|
||||||
"__id__": 32
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 36
|
"__id__": 36
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 40
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 40
|
"__id__": 44
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -442,7 +442,7 @@
|
|||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 29
|
"__id__": 33
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -536,7 +536,7 @@
|
|||||||
"array": [
|
"array": [
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
216.50635094610968,
|
216.65450766436658,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@@ -617,15 +617,21 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 20
|
"__id__": 20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 22
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 24
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 27
|
"__id__": 31
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 28
|
"__id__": 32
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -652,7 +658,7 @@
|
|||||||
"ctor": "Float64Array",
|
"ctor": "Float64Array",
|
||||||
"array": [
|
"array": [
|
||||||
-447.294,
|
-447.294,
|
||||||
135.702,
|
138.942,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@@ -678,7 +684,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__type__": "cc.Node",
|
"__type__": "cc.Node",
|
||||||
"_name": "sendingQ",
|
"_name": "inputFrameFront",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 11
|
"__id__": 11
|
||||||
@@ -701,20 +707,114 @@
|
|||||||
},
|
},
|
||||||
"_contentSize": {
|
"_contentSize": {
|
||||||
"__type__": "cc.Size",
|
"__type__": "cc.Size",
|
||||||
"width": 12.24,
|
"width": 18.33,
|
||||||
"height": 28.98
|
"height": 22.61
|
||||||
},
|
},
|
||||||
"_anchorPoint": {
|
"_anchorPoint": {
|
||||||
"__type__": "cc.Vec2",
|
"__type__": "cc.Vec2",
|
||||||
"x": 0.5,
|
"x": 0,
|
||||||
"y": 0.5
|
"y": 0.5
|
||||||
},
|
},
|
||||||
"_trs": {
|
"_trs": {
|
||||||
"__type__": "TypedArray",
|
"__type__": "TypedArray",
|
||||||
"ctor": "Float64Array",
|
"ctor": "Float64Array",
|
||||||
"array": [
|
"array": [
|
||||||
64,
|
0,
|
||||||
85.51,
|
88.695,
|
||||||
|
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": "83n6IAj9tAkop6CA/MyM0A"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__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": 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": "a4CfeVmexNm7nULcCRHcVl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__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": 18.33,
|
||||||
|
"height": 22.61
|
||||||
|
},
|
||||||
|
"_anchorPoint": {
|
||||||
|
"__type__": "cc.Vec2",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0.5
|
||||||
|
},
|
||||||
|
"_trs": {
|
||||||
|
"__type__": "TypedArray",
|
||||||
|
"ctor": "Float64Array",
|
||||||
|
"array": [
|
||||||
|
0,
|
||||||
|
66.08499999999998,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@@ -743,7 +843,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 12
|
"__id__": 14
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -755,10 +855,12 @@
|
|||||||
"_string": "0",
|
"_string": "0",
|
||||||
"_N$string": "0",
|
"_N$string": "0",
|
||||||
"_fontSize": 22,
|
"_fontSize": 22,
|
||||||
"_lineHeight": 23,
|
"_lineHeight": 37,
|
||||||
"_enableWrapText": true,
|
"_enableWrapText": true,
|
||||||
"_N$file": null,
|
"_N$file": {
|
||||||
"_isSystemFontUsed": true,
|
"__uuid__": "a564b3db-b8cb-48b4-952e-25bb56949116"
|
||||||
|
},
|
||||||
|
"_isSystemFontUsed": false,
|
||||||
"_spacingX": 0,
|
"_spacingX": 0,
|
||||||
"_batchAsBitmap": false,
|
"_batchAsBitmap": false,
|
||||||
"_N$horizontalAlign": 0,
|
"_N$horizontalAlign": 0,
|
||||||
@@ -779,7 +881,7 @@
|
|||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 15
|
"__id__": 17
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -793,20 +895,20 @@
|
|||||||
},
|
},
|
||||||
"_contentSize": {
|
"_contentSize": {
|
||||||
"__type__": "cc.Size",
|
"__type__": "cc.Size",
|
||||||
"width": 12.24,
|
"width": 18.33,
|
||||||
"height": 28.98
|
"height": 22.61
|
||||||
},
|
},
|
||||||
"_anchorPoint": {
|
"_anchorPoint": {
|
||||||
"__type__": "cc.Vec2",
|
"__type__": "cc.Vec2",
|
||||||
"x": 0.5,
|
"x": 0,
|
||||||
"y": 0.5
|
"y": 0.5
|
||||||
},
|
},
|
||||||
"_trs": {
|
"_trs": {
|
||||||
"__type__": "TypedArray",
|
"__type__": "TypedArray",
|
||||||
"ctor": "Float64Array",
|
"ctor": "Float64Array",
|
||||||
"array": [
|
"array": [
|
||||||
64,
|
0,
|
||||||
56.53000000000001,
|
43.47499999999998,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@@ -835,7 +937,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 14
|
"__id__": 16
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -847,10 +949,12 @@
|
|||||||
"_string": "0",
|
"_string": "0",
|
||||||
"_N$string": "0",
|
"_N$string": "0",
|
||||||
"_fontSize": 22,
|
"_fontSize": 22,
|
||||||
"_lineHeight": 23,
|
"_lineHeight": 37,
|
||||||
"_enableWrapText": true,
|
"_enableWrapText": true,
|
||||||
"_N$file": null,
|
"_N$file": {
|
||||||
"_isSystemFontUsed": true,
|
"__uuid__": "a564b3db-b8cb-48b4-952e-25bb56949116"
|
||||||
|
},
|
||||||
|
"_isSystemFontUsed": false,
|
||||||
"_spacingX": 0,
|
"_spacingX": 0,
|
||||||
"_batchAsBitmap": false,
|
"_batchAsBitmap": false,
|
||||||
"_N$horizontalAlign": 0,
|
"_N$horizontalAlign": 0,
|
||||||
@@ -871,7 +975,7 @@
|
|||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 17
|
"__id__": 19
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -885,20 +989,20 @@
|
|||||||
},
|
},
|
||||||
"_contentSize": {
|
"_contentSize": {
|
||||||
"__type__": "cc.Size",
|
"__type__": "cc.Size",
|
||||||
"width": 12.24,
|
"width": 18.33,
|
||||||
"height": 28.98
|
"height": 22.61
|
||||||
},
|
},
|
||||||
"_anchorPoint": {
|
"_anchorPoint": {
|
||||||
"__type__": "cc.Vec2",
|
"__type__": "cc.Vec2",
|
||||||
"x": 0.5,
|
"x": 0,
|
||||||
"y": 0.5
|
"y": 0.5
|
||||||
},
|
},
|
||||||
"_trs": {
|
"_trs": {
|
||||||
"__type__": "TypedArray",
|
"__type__": "TypedArray",
|
||||||
"ctor": "Float64Array",
|
"ctor": "Float64Array",
|
||||||
"array": [
|
"array": [
|
||||||
64,
|
0,
|
||||||
27.550000000000004,
|
20.86499999999998,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@@ -927,7 +1031,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 16
|
"__id__": 18
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -939,10 +1043,12 @@
|
|||||||
"_string": "0",
|
"_string": "0",
|
||||||
"_N$string": "0",
|
"_N$string": "0",
|
||||||
"_fontSize": 22,
|
"_fontSize": 22,
|
||||||
"_lineHeight": 23,
|
"_lineHeight": 37,
|
||||||
"_enableWrapText": true,
|
"_enableWrapText": true,
|
||||||
"_N$file": null,
|
"_N$file": {
|
||||||
"_isSystemFontUsed": true,
|
"__uuid__": "a564b3db-b8cb-48b4-952e-25bb56949116"
|
||||||
|
},
|
||||||
|
"_isSystemFontUsed": false,
|
||||||
"_spacingX": 0,
|
"_spacingX": 0,
|
||||||
"_batchAsBitmap": false,
|
"_batchAsBitmap": false,
|
||||||
"_N$horizontalAlign": 0,
|
"_N$horizontalAlign": 0,
|
||||||
@@ -963,7 +1069,7 @@
|
|||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 19
|
"__id__": 21
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -977,20 +1083,20 @@
|
|||||||
},
|
},
|
||||||
"_contentSize": {
|
"_contentSize": {
|
||||||
"__type__": "cc.Size",
|
"__type__": "cc.Size",
|
||||||
"width": 12.24,
|
"width": 18.33,
|
||||||
"height": 28.98
|
"height": 22.61
|
||||||
},
|
},
|
||||||
"_anchorPoint": {
|
"_anchorPoint": {
|
||||||
"__type__": "cc.Vec2",
|
"__type__": "cc.Vec2",
|
||||||
"x": 0.5,
|
"x": 0,
|
||||||
"y": 0.5
|
"y": 0.5
|
||||||
},
|
},
|
||||||
"_trs": {
|
"_trs": {
|
||||||
"__type__": "TypedArray",
|
"__type__": "TypedArray",
|
||||||
"ctor": "Float64Array",
|
"ctor": "Float64Array",
|
||||||
"array": [
|
"array": [
|
||||||
64,
|
0,
|
||||||
-1.4299999999999962,
|
-1.7450000000000188,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@@ -1019,7 +1125,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 18
|
"__id__": 20
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -1031,10 +1137,12 @@
|
|||||||
"_string": "0",
|
"_string": "0",
|
||||||
"_N$string": "0",
|
"_N$string": "0",
|
||||||
"_fontSize": 22,
|
"_fontSize": 22,
|
||||||
"_lineHeight": 23,
|
"_lineHeight": 37,
|
||||||
"_enableWrapText": true,
|
"_enableWrapText": true,
|
||||||
"_N$file": null,
|
"_N$file": {
|
||||||
"_isSystemFontUsed": true,
|
"__uuid__": "a564b3db-b8cb-48b4-952e-25bb56949116"
|
||||||
|
},
|
||||||
|
"_isSystemFontUsed": false,
|
||||||
"_spacingX": 0,
|
"_spacingX": 0,
|
||||||
"_batchAsBitmap": false,
|
"_batchAsBitmap": false,
|
||||||
"_N$horizontalAlign": 0,
|
"_N$horizontalAlign": 0,
|
||||||
@@ -1044,6 +1152,100 @@
|
|||||||
"_N$cacheMode": 0,
|
"_N$cacheMode": 0,
|
||||||
"_id": "77aNARt1VATLsjIzwbqvkh"
|
"_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"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"__type__": "cc.Node",
|
"__type__": "cc.Node",
|
||||||
"_name": "RoomIdIndicator",
|
"_name": "RoomIdIndicator",
|
||||||
@@ -1053,19 +1255,19 @@
|
|||||||
},
|
},
|
||||||
"_children": [
|
"_children": [
|
||||||
{
|
{
|
||||||
"__id__": 21
|
"__id__": 25
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 23
|
"__id__": 27
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_active": false,
|
"_active": false,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 25
|
"__id__": 29
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 26
|
"__id__": 30
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -1121,13 +1323,13 @@
|
|||||||
"_name": "label",
|
"_name": "label",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 20
|
"__id__": 24
|
||||||
},
|
},
|
||||||
"_children": [],
|
"_children": [],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 22
|
"__id__": 26
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -1183,7 +1385,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 21
|
"__id__": 25
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [],
|
"_materials": [],
|
||||||
@@ -1211,13 +1413,13 @@
|
|||||||
"_name": "BoundRoomIdLabel",
|
"_name": "BoundRoomIdLabel",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 20
|
"__id__": 24
|
||||||
},
|
},
|
||||||
"_children": [],
|
"_children": [],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 24
|
"__id__": 28
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -1273,7 +1475,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 23
|
"__id__": 27
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [],
|
"_materials": [],
|
||||||
@@ -1301,7 +1503,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 20
|
"__id__": 24
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_layoutSize": {
|
"_layoutSize": {
|
||||||
@@ -1334,7 +1536,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 20
|
"__id__": 24
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [],
|
"_materials": [],
|
||||||
@@ -1456,7 +1658,7 @@
|
|||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 31
|
"__id__": 35
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -1512,7 +1714,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 30
|
"__id__": 34
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -1546,7 +1748,7 @@
|
|||||||
},
|
},
|
||||||
"_children": [
|
"_children": [
|
||||||
{
|
{
|
||||||
"__id__": 33
|
"__id__": 37
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
@@ -1604,16 +1806,16 @@
|
|||||||
"_name": "Background",
|
"_name": "Background",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 32
|
"__id__": 36
|
||||||
},
|
},
|
||||||
"_children": [],
|
"_children": [],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 34
|
"__id__": 38
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 35
|
"__id__": 39
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -1669,7 +1871,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 33
|
"__id__": 37
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -1703,7 +1905,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 33
|
"__id__": 37
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"alignMode": 0,
|
"alignMode": 0,
|
||||||
@@ -1734,7 +1936,7 @@
|
|||||||
},
|
},
|
||||||
"_children": [
|
"_children": [
|
||||||
{
|
{
|
||||||
"__id__": 37
|
"__id__": 41
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
@@ -1792,16 +1994,16 @@
|
|||||||
"_name": "Background",
|
"_name": "Background",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 36
|
"__id__": 40
|
||||||
},
|
},
|
||||||
"_children": [],
|
"_children": [],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 38
|
"__id__": 42
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 39
|
"__id__": 43
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -1857,7 +2059,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 37
|
"__id__": 41
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -1891,7 +2093,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 37
|
"__id__": 41
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"alignMode": 0,
|
"alignMode": 0,
|
||||||
@@ -1949,16 +2151,16 @@
|
|||||||
},
|
},
|
||||||
"_children": [
|
"_children": [
|
||||||
{
|
{
|
||||||
"__id__": 42
|
"__id__": 46
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 44
|
"__id__": 48
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 45
|
"__id__": 49
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -2014,13 +2216,13 @@
|
|||||||
"_name": "Joystick",
|
"_name": "Joystick",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 41
|
"__id__": 45
|
||||||
},
|
},
|
||||||
"_children": [],
|
"_children": [],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 43
|
"__id__": 47
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -2076,7 +2278,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 42
|
"__id__": 46
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -2110,7 +2312,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 41
|
"__id__": 45
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -2144,7 +2346,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 41
|
"__id__": 45
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"alignMode": 0,
|
"alignMode": 0,
|
||||||
@@ -2193,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": "",
|
||||||
@@ -2252,7 +2436,7 @@
|
|||||||
"mapNode": {
|
"mapNode": {
|
||||||
"__id__": 3
|
"__id__": 3
|
||||||
},
|
},
|
||||||
"speed": 5000,
|
"speed": 500,
|
||||||
"_id": "76ImpM7XtPSbiLHDXdsJa+"
|
"_id": "76ImpM7XtPSbiLHDXdsJa+"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -2297,10 +2481,10 @@
|
|||||||
"__id__": 3
|
"__id__": 3
|
||||||
},
|
},
|
||||||
"stickhead": {
|
"stickhead": {
|
||||||
"__id__": 42
|
"__id__": 46
|
||||||
},
|
},
|
||||||
"base": {
|
"base": {
|
||||||
"__id__": 41
|
"__id__": 45
|
||||||
},
|
},
|
||||||
"joyStickEps": 0.1,
|
"joyStickEps": 0.1,
|
||||||
"magicLeanLowerBound": 0.414,
|
"magicLeanLowerBound": 0.414,
|
||||||
@@ -2321,10 +2505,10 @@
|
|||||||
"linearMovingEps": 0.1,
|
"linearMovingEps": 0.1,
|
||||||
"scaleByEps": 0.0375,
|
"scaleByEps": 0.0375,
|
||||||
"btnA": {
|
"btnA": {
|
||||||
"__id__": 32
|
"__id__": 36
|
||||||
},
|
},
|
||||||
"btnB": {
|
"btnB": {
|
||||||
"__id__": 36
|
"__id__": 40
|
||||||
},
|
},
|
||||||
"_id": "e9oVYTr7ROlpp/IrNjBUmR"
|
"_id": "e9oVYTr7ROlpp/IrNjBUmR"
|
||||||
}
|
}
|
||||||
|
@@ -72,22 +72,25 @@
|
|||||||
"__id__": 3
|
"__id__": 3
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 7
|
"__id__": 5
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 9
|
"__id__": 9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 11
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
|
||||||
"__id__": 60
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__id__": 61
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"__id__": 62
|
"__id__": 62
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 63
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 64
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -138,6 +141,102 @@
|
|||||||
"groupIndex": 0,
|
"groupIndex": 0,
|
||||||
"_id": "88kscZWXFCIZtNFekdSP/o"
|
"_id": "88kscZWXFCIZtNFekdSP/o"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.Node",
|
||||||
|
"_name": "Background",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"_parent": {
|
||||||
|
"__id__": 2
|
||||||
|
},
|
||||||
|
"_children": [],
|
||||||
|
"_active": true,
|
||||||
|
"_components": [
|
||||||
|
{
|
||||||
|
"__id__": 4
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"_prefab": null,
|
||||||
|
"_opacity": 255,
|
||||||
|
"_color": {
|
||||||
|
"__type__": "cc.Color",
|
||||||
|
"r": 255,
|
||||||
|
"g": 255,
|
||||||
|
"b": 255,
|
||||||
|
"a": 255
|
||||||
|
},
|
||||||
|
"_contentSize": {
|
||||||
|
"__type__": "cc.Size",
|
||||||
|
"width": 1280,
|
||||||
|
"height": 960
|
||||||
|
},
|
||||||
|
"_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": "c8r+ISXVhBZarylAeQMAQK"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.Sprite",
|
||||||
|
"_name": "",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"node": {
|
||||||
|
"__id__": 3
|
||||||
|
},
|
||||||
|
"_enabled": true,
|
||||||
|
"_materials": [
|
||||||
|
{
|
||||||
|
"__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"_srcBlendFactor": 770,
|
||||||
|
"_dstBlendFactor": 771,
|
||||||
|
"_spriteFrame": {
|
||||||
|
"__uuid__": "637f31c2-c53e-4dec-ae11-d56c0c6177ad"
|
||||||
|
},
|
||||||
|
"_type": 0,
|
||||||
|
"_sizeMode": 0,
|
||||||
|
"_fillType": 0,
|
||||||
|
"_fillCenter": {
|
||||||
|
"__type__": "cc.Vec2",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
"_fillStart": 0,
|
||||||
|
"_fillRange": 0,
|
||||||
|
"_isTrimmedMode": true,
|
||||||
|
"_atlas": {
|
||||||
|
"__uuid__": "030d9286-e8a2-40cf-98f8-baf713f0b8c4"
|
||||||
|
},
|
||||||
|
"_id": "6dhdFxELpEwZ4TjXC+WnyS"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"__type__": "cc.Node",
|
"__type__": "cc.Node",
|
||||||
"_name": "Decorations",
|
"_name": "Decorations",
|
||||||
@@ -147,13 +246,13 @@
|
|||||||
},
|
},
|
||||||
"_children": [
|
"_children": [
|
||||||
{
|
{
|
||||||
"__id__": 4
|
"__id__": 6
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 6
|
"__id__": 8
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -209,13 +308,13 @@
|
|||||||
"_name": "Logo",
|
"_name": "Logo",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 3
|
"__id__": 5
|
||||||
},
|
},
|
||||||
"_children": [],
|
"_children": [],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 5
|
"__id__": 7
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -271,7 +370,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 4
|
"__id__": 6
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -301,7 +400,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 3
|
"__id__": 5
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"alignMode": 0,
|
"alignMode": 0,
|
||||||
@@ -334,7 +433,7 @@
|
|||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 8
|
"__id__": 10
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -362,7 +461,7 @@
|
|||||||
"array": [
|
"array": [
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
216.50635094610968,
|
216.65450766436658,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@@ -390,7 +489,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 7
|
"__id__": 9
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_cullingMask": 4294967295,
|
"_cullingMask": 4294967295,
|
||||||
@@ -430,13 +529,13 @@
|
|||||||
},
|
},
|
||||||
"_children": [
|
"_children": [
|
||||||
{
|
{
|
||||||
"__id__": 10
|
"__id__": 12
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 59
|
"__id__": 61
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -492,41 +591,41 @@
|
|||||||
"_name": "InteractiveControls",
|
"_name": "InteractiveControls",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 9
|
"__id__": 11
|
||||||
},
|
},
|
||||||
"_children": [
|
"_children": [
|
||||||
{
|
{
|
||||||
"__id__": 11
|
"__id__": 13
|
||||||
},
|
|
||||||
{
|
|
||||||
"__id__": 19
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 21
|
"__id__": 21
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 30
|
"__id__": 23
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 32
|
"__id__": 32
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 41
|
"__id__": 34
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 48
|
"__id__": 43
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 54
|
"__id__": 50
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 56
|
"__id__": 56
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 58
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 58
|
"__id__": 60
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -582,23 +681,23 @@
|
|||||||
"_name": "phoneCountryCodeInput",
|
"_name": "phoneCountryCodeInput",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 10
|
"__id__": 12
|
||||||
},
|
},
|
||||||
"_children": [
|
"_children": [
|
||||||
{
|
|
||||||
"__id__": 12
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"__id__": 14
|
"__id__": 14
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 16
|
"__id__": 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 18
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 18
|
"__id__": 20
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -654,13 +753,13 @@
|
|||||||
"_name": "BACKGROUND_SPRITE",
|
"_name": "BACKGROUND_SPRITE",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 11
|
"__id__": 13
|
||||||
},
|
},
|
||||||
"_children": [],
|
"_children": [],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 13
|
"__id__": 15
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -716,7 +815,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 12
|
"__id__": 14
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -748,13 +847,13 @@
|
|||||||
"_name": "TEXT_LABEL",
|
"_name": "TEXT_LABEL",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 11
|
"__id__": 13
|
||||||
},
|
},
|
||||||
"_children": [],
|
"_children": [],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 15
|
"__id__": 17
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -810,7 +909,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 14
|
"__id__": 16
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -840,13 +939,13 @@
|
|||||||
"_name": "PLACEHOLDER_LABEL",
|
"_name": "PLACEHOLDER_LABEL",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 11
|
"__id__": 13
|
||||||
},
|
},
|
||||||
"_children": [],
|
"_children": [],
|
||||||
"_active": false,
|
"_active": false,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 17
|
"__id__": 19
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -902,7 +1001,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 16
|
"__id__": 18
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [],
|
"_materials": [],
|
||||||
@@ -928,7 +1027,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 11
|
"__id__": 13
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_useOriginalSize": false,
|
"_useOriginalSize": false,
|
||||||
@@ -941,13 +1040,13 @@
|
|||||||
"editingDidEnded": [],
|
"editingDidEnded": [],
|
||||||
"editingReturn": [],
|
"editingReturn": [],
|
||||||
"_N$textLabel": {
|
"_N$textLabel": {
|
||||||
"__id__": 15
|
|
||||||
},
|
|
||||||
"_N$placeholderLabel": {
|
|
||||||
"__id__": 17
|
"__id__": 17
|
||||||
},
|
},
|
||||||
|
"_N$placeholderLabel": {
|
||||||
|
"__id__": 19
|
||||||
|
},
|
||||||
"_N$background": {
|
"_N$background": {
|
||||||
"__id__": 13
|
"__id__": 15
|
||||||
},
|
},
|
||||||
"_N$inputFlag": 5,
|
"_N$inputFlag": 5,
|
||||||
"_N$inputMode": 3,
|
"_N$inputMode": 3,
|
||||||
@@ -959,13 +1058,13 @@
|
|||||||
"_name": "phoneLabel",
|
"_name": "phoneLabel",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 10
|
"__id__": 12
|
||||||
},
|
},
|
||||||
"_children": [],
|
"_children": [],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 20
|
"__id__": 22
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -1021,7 +1120,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 19
|
"__id__": 21
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -1051,23 +1150,23 @@
|
|||||||
"_name": "phoneNumberInput",
|
"_name": "phoneNumberInput",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 10
|
"__id__": 12
|
||||||
},
|
},
|
||||||
"_children": [
|
"_children": [
|
||||||
{
|
|
||||||
"__id__": 22
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"__id__": 24
|
"__id__": 24
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 26
|
"__id__": 26
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 28
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 29
|
"__id__": 31
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -1123,13 +1222,13 @@
|
|||||||
"_name": "BACKGROUND_SPRITE",
|
"_name": "BACKGROUND_SPRITE",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 21
|
"__id__": 23
|
||||||
},
|
},
|
||||||
"_children": [],
|
"_children": [],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 23
|
"__id__": 25
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -1185,7 +1284,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 22
|
"__id__": 24
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -1217,13 +1316,13 @@
|
|||||||
"_name": "TEXT_LABEL",
|
"_name": "TEXT_LABEL",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 21
|
"__id__": 23
|
||||||
},
|
},
|
||||||
"_children": [],
|
"_children": [],
|
||||||
"_active": false,
|
"_active": false,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 25
|
"__id__": 27
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -1279,7 +1378,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 24
|
"__id__": 26
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [],
|
"_materials": [],
|
||||||
@@ -1305,16 +1404,16 @@
|
|||||||
"_name": "PLACEHOLDER_LABEL",
|
"_name": "PLACEHOLDER_LABEL",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 21
|
"__id__": 23
|
||||||
},
|
},
|
||||||
"_children": [],
|
"_children": [],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 27
|
"__id__": 29
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 28
|
"__id__": 30
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -1370,7 +1469,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 26
|
"__id__": 28
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -1400,7 +1499,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 26
|
"__id__": 28
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_dataID": "login.hint.phoneInputHint",
|
"_dataID": "login.hint.phoneInputHint",
|
||||||
@@ -1411,7 +1510,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 21
|
"__id__": 23
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_useOriginalSize": false,
|
"_useOriginalSize": false,
|
||||||
@@ -1424,13 +1523,13 @@
|
|||||||
"editingDidEnded": [],
|
"editingDidEnded": [],
|
||||||
"editingReturn": [],
|
"editingReturn": [],
|
||||||
"_N$textLabel": {
|
"_N$textLabel": {
|
||||||
"__id__": 25
|
|
||||||
},
|
|
||||||
"_N$placeholderLabel": {
|
|
||||||
"__id__": 27
|
"__id__": 27
|
||||||
},
|
},
|
||||||
|
"_N$placeholderLabel": {
|
||||||
|
"__id__": 29
|
||||||
|
},
|
||||||
"_N$background": {
|
"_N$background": {
|
||||||
"__id__": 23
|
"__id__": 25
|
||||||
},
|
},
|
||||||
"_N$inputFlag": 5,
|
"_N$inputFlag": 5,
|
||||||
"_N$inputMode": 1,
|
"_N$inputMode": 1,
|
||||||
@@ -1442,13 +1541,13 @@
|
|||||||
"_name": " smsLoginCaptchaLabel",
|
"_name": " smsLoginCaptchaLabel",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 10
|
"__id__": 12
|
||||||
},
|
},
|
||||||
"_children": [],
|
"_children": [],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 31
|
"__id__": 33
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -1504,7 +1603,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 30
|
"__id__": 32
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -1534,23 +1633,23 @@
|
|||||||
"_name": "smsLoginCaptchaInput",
|
"_name": "smsLoginCaptchaInput",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 10
|
"__id__": 12
|
||||||
},
|
},
|
||||||
"_children": [
|
"_children": [
|
||||||
{
|
|
||||||
"__id__": 33
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"__id__": 35
|
"__id__": 35
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 37
|
"__id__": 37
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 39
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 40
|
"__id__": 42
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -1606,13 +1705,13 @@
|
|||||||
"_name": "BACKGROUND_SPRITE",
|
"_name": "BACKGROUND_SPRITE",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 32
|
"__id__": 34
|
||||||
},
|
},
|
||||||
"_children": [],
|
"_children": [],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 34
|
"__id__": 36
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -1668,7 +1767,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 33
|
"__id__": 35
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -1700,13 +1799,13 @@
|
|||||||
"_name": "TEXT_LABEL",
|
"_name": "TEXT_LABEL",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 32
|
"__id__": 34
|
||||||
},
|
},
|
||||||
"_children": [],
|
"_children": [],
|
||||||
"_active": false,
|
"_active": false,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 36
|
"__id__": 38
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -1762,7 +1861,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 35
|
"__id__": 37
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [],
|
"_materials": [],
|
||||||
@@ -1788,16 +1887,16 @@
|
|||||||
"_name": "PLACEHOLDER_LABEL",
|
"_name": "PLACEHOLDER_LABEL",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 32
|
"__id__": 34
|
||||||
},
|
},
|
||||||
"_children": [],
|
"_children": [],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 38
|
"__id__": 40
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 39
|
"__id__": 41
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -1853,7 +1952,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 37
|
"__id__": 39
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -1883,7 +1982,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 37
|
"__id__": 39
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_dataID": "login.hint.captchaInputHint",
|
"_dataID": "login.hint.captchaInputHint",
|
||||||
@@ -1894,7 +1993,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 32
|
"__id__": 34
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_useOriginalSize": false,
|
"_useOriginalSize": false,
|
||||||
@@ -1907,13 +2006,13 @@
|
|||||||
"editingDidEnded": [],
|
"editingDidEnded": [],
|
||||||
"editingReturn": [],
|
"editingReturn": [],
|
||||||
"_N$textLabel": {
|
"_N$textLabel": {
|
||||||
"__id__": 36
|
|
||||||
},
|
|
||||||
"_N$placeholderLabel": {
|
|
||||||
"__id__": 38
|
"__id__": 38
|
||||||
},
|
},
|
||||||
|
"_N$placeholderLabel": {
|
||||||
|
"__id__": 40
|
||||||
|
},
|
||||||
"_N$background": {
|
"_N$background": {
|
||||||
"__id__": 34
|
"__id__": 36
|
||||||
},
|
},
|
||||||
"_N$inputFlag": 5,
|
"_N$inputFlag": 5,
|
||||||
"_N$inputMode": 2,
|
"_N$inputMode": 2,
|
||||||
@@ -1925,20 +2024,20 @@
|
|||||||
"_name": "smsLoginCaptchaButton",
|
"_name": "smsLoginCaptchaButton",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 10
|
"__id__": 12
|
||||||
},
|
},
|
||||||
"_children": [
|
"_children": [
|
||||||
{
|
{
|
||||||
"__id__": 42
|
"__id__": 44
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 44
|
"__id__": 46
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 46
|
"__id__": 48
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -1994,13 +2093,13 @@
|
|||||||
"_name": "smsGetCaptcha",
|
"_name": "smsGetCaptcha",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 41
|
"__id__": 43
|
||||||
},
|
},
|
||||||
"_children": [],
|
"_children": [],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 43
|
"__id__": 45
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -2056,7 +2155,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 42
|
"__id__": 44
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -2090,13 +2189,13 @@
|
|||||||
"_name": "captchaLabel",
|
"_name": "captchaLabel",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 41
|
"__id__": 43
|
||||||
},
|
},
|
||||||
"_children": [],
|
"_children": [],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 45
|
"__id__": 47
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -2152,7 +2251,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 44
|
"__id__": 46
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -2182,7 +2281,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 41
|
"__id__": 43
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_normalMaterial": null,
|
"_normalMaterial": null,
|
||||||
@@ -2191,7 +2290,7 @@
|
|||||||
"zoomScale": 1.1,
|
"zoomScale": 1.1,
|
||||||
"clickEvents": [
|
"clickEvents": [
|
||||||
{
|
{
|
||||||
"__id__": 47
|
"__id__": 49
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_N$interactable": true,
|
"_N$interactable": true,
|
||||||
@@ -2257,7 +2356,7 @@
|
|||||||
"__uuid__": "29158224-f8dd-4661-a796-1ffab537140e"
|
"__uuid__": "29158224-f8dd-4661-a796-1ffab537140e"
|
||||||
},
|
},
|
||||||
"_N$target": {
|
"_N$target": {
|
||||||
"__id__": 41
|
"__id__": 43
|
||||||
},
|
},
|
||||||
"_id": "96L9tbxW9DHJHU5hUi9oNc"
|
"_id": "96L9tbxW9DHJHU5hUi9oNc"
|
||||||
},
|
},
|
||||||
@@ -2276,20 +2375,20 @@
|
|||||||
"_name": "loginButton",
|
"_name": "loginButton",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 10
|
"__id__": 12
|
||||||
},
|
},
|
||||||
"_children": [
|
"_children": [
|
||||||
{
|
{
|
||||||
"__id__": 49
|
"__id__": 51
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 51
|
"__id__": 53
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 52
|
"__id__": 54
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -2345,13 +2444,13 @@
|
|||||||
"_name": "loginLabel",
|
"_name": "loginLabel",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 48
|
"__id__": 50
|
||||||
},
|
},
|
||||||
"_children": [],
|
"_children": [],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 50
|
"__id__": 52
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -2407,7 +2506,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 49
|
"__id__": 51
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -2437,7 +2536,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 48
|
"__id__": 50
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -2471,7 +2570,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 48
|
"__id__": 50
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_normalMaterial": null,
|
"_normalMaterial": null,
|
||||||
@@ -2480,7 +2579,7 @@
|
|||||||
"zoomScale": 1.2,
|
"zoomScale": 1.2,
|
||||||
"clickEvents": [
|
"clickEvents": [
|
||||||
{
|
{
|
||||||
"__id__": 53
|
"__id__": 55
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_N$interactable": true,
|
"_N$interactable": true,
|
||||||
@@ -2546,7 +2645,7 @@
|
|||||||
"__uuid__": "29158224-f8dd-4661-a796-1ffab537140e"
|
"__uuid__": "29158224-f8dd-4661-a796-1ffab537140e"
|
||||||
},
|
},
|
||||||
"_N$target": {
|
"_N$target": {
|
||||||
"__id__": 48
|
"__id__": 50
|
||||||
},
|
},
|
||||||
"_id": "0dQu3M5+hO8Ia4FD67Br39"
|
"_id": "0dQu3M5+hO8Ia4FD67Br39"
|
||||||
},
|
},
|
||||||
@@ -2565,13 +2664,13 @@
|
|||||||
"_name": "phoneNumberTips",
|
"_name": "phoneNumberTips",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 10
|
"__id__": 12
|
||||||
},
|
},
|
||||||
"_children": [],
|
"_children": [],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 55
|
"__id__": 57
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -2627,7 +2726,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 54
|
"__id__": 56
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -2657,13 +2756,13 @@
|
|||||||
"_name": "captchaTips",
|
"_name": "captchaTips",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 10
|
"__id__": 12
|
||||||
},
|
},
|
||||||
"_children": [],
|
"_children": [],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 57
|
"__id__": 59
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -2719,7 +2818,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 56
|
"__id__": 58
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -2749,7 +2848,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 10
|
"__id__": 12
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"alignMode": 1,
|
"alignMode": 1,
|
||||||
@@ -2776,7 +2875,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 9
|
"__id__": 11
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"alignMode": 0,
|
"alignMode": 0,
|
||||||
@@ -2854,37 +2953,37 @@
|
|||||||
"__id__": 2
|
"__id__": 2
|
||||||
},
|
},
|
||||||
"backgroundNode": {
|
"backgroundNode": {
|
||||||
"__id__": 9
|
|
||||||
},
|
|
||||||
"interactiveControls": {
|
|
||||||
"__id__": 10
|
|
||||||
},
|
|
||||||
"phoneLabel": {
|
|
||||||
"__id__": 19
|
|
||||||
},
|
|
||||||
"smsLoginCaptchaLabel": {
|
|
||||||
"__id__": 30
|
|
||||||
},
|
|
||||||
"phoneCountryCodeInput": {
|
|
||||||
"__id__": 11
|
"__id__": 11
|
||||||
},
|
},
|
||||||
"phoneNumberInput": {
|
"interactiveControls": {
|
||||||
|
"__id__": 12
|
||||||
|
},
|
||||||
|
"phoneLabel": {
|
||||||
"__id__": 21
|
"__id__": 21
|
||||||
},
|
},
|
||||||
"phoneNumberTips": {
|
"smsLoginCaptchaLabel": {
|
||||||
"__id__": 54
|
|
||||||
},
|
|
||||||
"smsLoginCaptchaInput": {
|
|
||||||
"__id__": 32
|
"__id__": 32
|
||||||
},
|
},
|
||||||
"smsLoginCaptchaButton": {
|
"phoneCountryCodeInput": {
|
||||||
"__id__": 41
|
"__id__": 13
|
||||||
},
|
},
|
||||||
"captchaTips": {
|
"phoneNumberInput": {
|
||||||
|
"__id__": 23
|
||||||
|
},
|
||||||
|
"phoneNumberTips": {
|
||||||
"__id__": 56
|
"__id__": 56
|
||||||
},
|
},
|
||||||
|
"smsLoginCaptchaInput": {
|
||||||
|
"__id__": 34
|
||||||
|
},
|
||||||
|
"smsLoginCaptchaButton": {
|
||||||
|
"__id__": 43
|
||||||
|
},
|
||||||
|
"captchaTips": {
|
||||||
|
"__id__": 58
|
||||||
|
},
|
||||||
"loginButton": {
|
"loginButton": {
|
||||||
"__id__": 48
|
"__id__": 50
|
||||||
},
|
},
|
||||||
"smsWaitCountdownPrefab": {
|
"smsWaitCountdownPrefab": {
|
||||||
"__uuid__": "2c0101b8-c15a-4501-9fce-cd5a014af8bf"
|
"__uuid__": "2c0101b8-c15a-4501-9fce-cd5a014af8bf"
|
||||||
|
@@ -77,20 +77,20 @@
|
|||||||
],
|
],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
|
||||||
"__id__": 47
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__id__": 48
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__id__": 49
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__id__": 50
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"__id__": 51
|
"__id__": 51
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 52
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 53
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 54
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 55
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -276,21 +276,24 @@
|
|||||||
"gameRulePrefab": null,
|
"gameRulePrefab": null,
|
||||||
"findingPlayerPrefab": null,
|
"findingPlayerPrefab": null,
|
||||||
"countdownToBeginGamePrefab": null,
|
"countdownToBeginGamePrefab": null,
|
||||||
"playersInfoPrefab": null,
|
|
||||||
"forceBigEndianFloatingNumDecoding": false,
|
"forceBigEndianFloatingNumDecoding": false,
|
||||||
"renderFrameIdLagTolerance": 4,
|
"renderFrameIdLagTolerance": 4,
|
||||||
"sendingQLabel": {
|
"inputFrameFrontLabel": {
|
||||||
"__id__": 14
|
"__id__": 14
|
||||||
},
|
},
|
||||||
"inputFrameDownsyncQLabel": {
|
"sendingQLabel": {
|
||||||
"__id__": 16
|
"__id__": 16
|
||||||
},
|
},
|
||||||
"peerInputFrameUpsyncQLabel": {
|
"inputFrameDownsyncQLabel": {
|
||||||
"__id__": 18
|
"__id__": 18
|
||||||
},
|
},
|
||||||
"rollbackFramesLabel": {
|
"peerInputFrameUpsyncQLabel": {
|
||||||
"__id__": 20
|
"__id__": 20
|
||||||
},
|
},
|
||||||
|
"rollbackFramesLabel": {
|
||||||
|
"__id__": 22
|
||||||
|
},
|
||||||
|
"skippedRenderFrameCntLabel": null,
|
||||||
"_id": "e5xQdv12xLoIRr0b36Pie+"
|
"_id": "e5xQdv12xLoIRr0b36Pie+"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -302,13 +305,13 @@
|
|||||||
},
|
},
|
||||||
"_children": [
|
"_children": [
|
||||||
{
|
{
|
||||||
"__id__": 41
|
"__id__": 45
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 46
|
"__id__": 50
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -371,19 +374,19 @@
|
|||||||
"__id__": 7
|
"__id__": 7
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 30
|
"__id__": 34
|
||||||
},
|
|
||||||
{
|
|
||||||
"__id__": 32
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 36
|
"__id__": 36
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 40
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 40
|
"__id__": 44
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -452,7 +455,7 @@
|
|||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 29
|
"__id__": 33
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -546,7 +549,7 @@
|
|||||||
"array": [
|
"array": [
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
216.50635094610968,
|
216.65450766436658,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@@ -627,12 +630,18 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 21
|
"__id__": 21
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 23
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 25
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 28
|
"__id__": 32
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -685,7 +694,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__type__": "cc.Node",
|
"__type__": "cc.Node",
|
||||||
"_name": "sendingQ",
|
"_name": "inputFrameFront",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 12
|
"__id__": 12
|
||||||
@@ -708,12 +717,12 @@
|
|||||||
},
|
},
|
||||||
"_contentSize": {
|
"_contentSize": {
|
||||||
"__type__": "cc.Size",
|
"__type__": "cc.Size",
|
||||||
"width": 22.25,
|
"width": 12.24,
|
||||||
"height": 50.4
|
"height": 28.98
|
||||||
},
|
},
|
||||||
"_anchorPoint": {
|
"_anchorPoint": {
|
||||||
"__type__": "cc.Vec2",
|
"__type__": "cc.Vec2",
|
||||||
"x": 0.5,
|
"x": 0,
|
||||||
"y": 0.5
|
"y": 0.5
|
||||||
},
|
},
|
||||||
"_trs": {
|
"_trs": {
|
||||||
@@ -721,7 +730,99 @@
|
|||||||
"ctor": "Float64Array",
|
"ctor": "Float64Array",
|
||||||
"array": [
|
"array": [
|
||||||
0,
|
0,
|
||||||
71.7,
|
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__": 13
|
||||||
|
},
|
||||||
|
"_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__": 12
|
||||||
|
},
|
||||||
|
"_children": [],
|
||||||
|
"_active": true,
|
||||||
|
"_components": [
|
||||||
|
{
|
||||||
|
"__id__": 16
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"_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,
|
||||||
@@ -750,7 +851,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 13
|
"__id__": 15
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -761,14 +862,14 @@
|
|||||||
"_useOriginalSize": false,
|
"_useOriginalSize": false,
|
||||||
"_string": "0",
|
"_string": "0",
|
||||||
"_N$string": "0",
|
"_N$string": "0",
|
||||||
"_fontSize": 40,
|
"_fontSize": 22,
|
||||||
"_lineHeight": 40,
|
"_lineHeight": 23,
|
||||||
"_enableWrapText": true,
|
"_enableWrapText": true,
|
||||||
"_N$file": null,
|
"_N$file": null,
|
||||||
"_isSystemFontUsed": true,
|
"_isSystemFontUsed": true,
|
||||||
"_spacingX": 0,
|
"_spacingX": 0,
|
||||||
"_batchAsBitmap": false,
|
"_batchAsBitmap": false,
|
||||||
"_N$horizontalAlign": 1,
|
"_N$horizontalAlign": 0,
|
||||||
"_N$verticalAlign": 1,
|
"_N$verticalAlign": 1,
|
||||||
"_N$fontFamily": "Arial",
|
"_N$fontFamily": "Arial",
|
||||||
"_N$overflow": 0,
|
"_N$overflow": 0,
|
||||||
@@ -786,7 +887,7 @@
|
|||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 16
|
"__id__": 18
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -800,12 +901,12 @@
|
|||||||
},
|
},
|
||||||
"_contentSize": {
|
"_contentSize": {
|
||||||
"__type__": "cc.Size",
|
"__type__": "cc.Size",
|
||||||
"width": 22.25,
|
"width": 12.24,
|
||||||
"height": 50.4
|
"height": 28.98
|
||||||
},
|
},
|
||||||
"_anchorPoint": {
|
"_anchorPoint": {
|
||||||
"__type__": "cc.Vec2",
|
"__type__": "cc.Vec2",
|
||||||
"x": 0.5,
|
"x": 0,
|
||||||
"y": 0.5
|
"y": 0.5
|
||||||
},
|
},
|
||||||
"_trs": {
|
"_trs": {
|
||||||
@@ -813,7 +914,7 @@
|
|||||||
"ctor": "Float64Array",
|
"ctor": "Float64Array",
|
||||||
"array": [
|
"array": [
|
||||||
0,
|
0,
|
||||||
23.899999999999995,
|
15.933333333333325,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@@ -842,7 +943,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 15
|
"__id__": 17
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -853,14 +954,14 @@
|
|||||||
"_useOriginalSize": false,
|
"_useOriginalSize": false,
|
||||||
"_string": "0",
|
"_string": "0",
|
||||||
"_N$string": "0",
|
"_N$string": "0",
|
||||||
"_fontSize": 40,
|
"_fontSize": 22,
|
||||||
"_lineHeight": 40,
|
"_lineHeight": 23,
|
||||||
"_enableWrapText": true,
|
"_enableWrapText": true,
|
||||||
"_N$file": null,
|
"_N$file": null,
|
||||||
"_isSystemFontUsed": true,
|
"_isSystemFontUsed": true,
|
||||||
"_spacingX": 0,
|
"_spacingX": 0,
|
||||||
"_batchAsBitmap": false,
|
"_batchAsBitmap": false,
|
||||||
"_N$horizontalAlign": 1,
|
"_N$horizontalAlign": 0,
|
||||||
"_N$verticalAlign": 1,
|
"_N$verticalAlign": 1,
|
||||||
"_N$fontFamily": "Arial",
|
"_N$fontFamily": "Arial",
|
||||||
"_N$overflow": 0,
|
"_N$overflow": 0,
|
||||||
@@ -878,7 +979,7 @@
|
|||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 18
|
"__id__": 20
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -892,12 +993,12 @@
|
|||||||
},
|
},
|
||||||
"_contentSize": {
|
"_contentSize": {
|
||||||
"__type__": "cc.Size",
|
"__type__": "cc.Size",
|
||||||
"width": 22.25,
|
"width": 12.24,
|
||||||
"height": 50.4
|
"height": 28.98
|
||||||
},
|
},
|
||||||
"_anchorPoint": {
|
"_anchorPoint": {
|
||||||
"__type__": "cc.Vec2",
|
"__type__": "cc.Vec2",
|
||||||
"x": 0.5,
|
"x": 0,
|
||||||
"y": 0.5
|
"y": 0.5
|
||||||
},
|
},
|
||||||
"_trs": {
|
"_trs": {
|
||||||
@@ -905,7 +1006,7 @@
|
|||||||
"ctor": "Float64Array",
|
"ctor": "Float64Array",
|
||||||
"array": [
|
"array": [
|
||||||
0,
|
0,
|
||||||
-23.90000000000001,
|
-15.933333333333346,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@@ -934,7 +1035,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 17
|
"__id__": 19
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -945,14 +1046,14 @@
|
|||||||
"_useOriginalSize": false,
|
"_useOriginalSize": false,
|
||||||
"_string": "0",
|
"_string": "0",
|
||||||
"_N$string": "0",
|
"_N$string": "0",
|
||||||
"_fontSize": 40,
|
"_fontSize": 22,
|
||||||
"_lineHeight": 40,
|
"_lineHeight": 23,
|
||||||
"_enableWrapText": true,
|
"_enableWrapText": true,
|
||||||
"_N$file": null,
|
"_N$file": null,
|
||||||
"_isSystemFontUsed": true,
|
"_isSystemFontUsed": true,
|
||||||
"_spacingX": 0,
|
"_spacingX": 0,
|
||||||
"_batchAsBitmap": false,
|
"_batchAsBitmap": false,
|
||||||
"_N$horizontalAlign": 1,
|
"_N$horizontalAlign": 0,
|
||||||
"_N$verticalAlign": 1,
|
"_N$verticalAlign": 1,
|
||||||
"_N$fontFamily": "Arial",
|
"_N$fontFamily": "Arial",
|
||||||
"_N$overflow": 0,
|
"_N$overflow": 0,
|
||||||
@@ -970,7 +1071,7 @@
|
|||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 20
|
"__id__": 22
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -984,12 +1085,12 @@
|
|||||||
},
|
},
|
||||||
"_contentSize": {
|
"_contentSize": {
|
||||||
"__type__": "cc.Size",
|
"__type__": "cc.Size",
|
||||||
"width": 22.25,
|
"width": 12.24,
|
||||||
"height": 50.4
|
"height": 28.98
|
||||||
},
|
},
|
||||||
"_anchorPoint": {
|
"_anchorPoint": {
|
||||||
"__type__": "cc.Vec2",
|
"__type__": "cc.Vec2",
|
||||||
"x": 0.5,
|
"x": 0,
|
||||||
"y": 0.5
|
"y": 0.5
|
||||||
},
|
},
|
||||||
"_trs": {
|
"_trs": {
|
||||||
@@ -997,7 +1098,7 @@
|
|||||||
"ctor": "Float64Array",
|
"ctor": "Float64Array",
|
||||||
"array": [
|
"array": [
|
||||||
0,
|
0,
|
||||||
-71.70000000000002,
|
-47.80000000000002,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@@ -1026,7 +1127,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 19
|
"__id__": 21
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -1037,20 +1138,114 @@
|
|||||||
"_useOriginalSize": false,
|
"_useOriginalSize": false,
|
||||||
"_string": "0",
|
"_string": "0",
|
||||||
"_N$string": "0",
|
"_N$string": "0",
|
||||||
"_fontSize": 40,
|
"_fontSize": 22,
|
||||||
"_lineHeight": 40,
|
"_lineHeight": 23,
|
||||||
"_enableWrapText": true,
|
"_enableWrapText": true,
|
||||||
"_N$file": null,
|
"_N$file": null,
|
||||||
"_isSystemFontUsed": true,
|
"_isSystemFontUsed": true,
|
||||||
"_spacingX": 0,
|
"_spacingX": 0,
|
||||||
"_batchAsBitmap": false,
|
"_batchAsBitmap": false,
|
||||||
"_N$horizontalAlign": 1,
|
"_N$horizontalAlign": 0,
|
||||||
"_N$verticalAlign": 1,
|
"_N$verticalAlign": 1,
|
||||||
"_N$fontFamily": "Arial",
|
"_N$fontFamily": "Arial",
|
||||||
"_N$overflow": 0,
|
"_N$overflow": 0,
|
||||||
"_N$cacheMode": 0,
|
"_N$cacheMode": 0,
|
||||||
"_id": "b1otN9g0xJP7pEDUey3UUZ"
|
"_id": "b1otN9g0xJP7pEDUey3UUZ"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.Node",
|
||||||
|
"_name": "skippedCnt",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"_parent": {
|
||||||
|
"__id__": 12
|
||||||
|
},
|
||||||
|
"_children": [],
|
||||||
|
"_active": true,
|
||||||
|
"_components": [
|
||||||
|
{
|
||||||
|
"__id__": 24
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"_prefab": null,
|
||||||
|
"_opacity": 255,
|
||||||
|
"_color": {
|
||||||
|
"__type__": "cc.Color",
|
||||||
|
"r": 255,
|
||||||
|
"g": 235,
|
||||||
|
"b": 0,
|
||||||
|
"a": 255
|
||||||
|
},
|
||||||
|
"_contentSize": {
|
||||||
|
"__type__": "cc.Size",
|
||||||
|
"width": 18.33,
|
||||||
|
"height": 14.06
|
||||||
|
},
|
||||||
|
"_anchorPoint": {
|
||||||
|
"__type__": "cc.Vec2",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0.5
|
||||||
|
},
|
||||||
|
"_trs": {
|
||||||
|
"__type__": "TypedArray",
|
||||||
|
"ctor": "Float64Array",
|
||||||
|
"array": [
|
||||||
|
0,
|
||||||
|
-79.66666666666669,
|
||||||
|
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": "4etY2F7V5E36duhglRpOwR"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.Label",
|
||||||
|
"_name": "",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"node": {
|
||||||
|
"__id__": 23
|
||||||
|
},
|
||||||
|
"_enabled": true,
|
||||||
|
"_materials": [
|
||||||
|
{
|
||||||
|
"__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"_useOriginalSize": false,
|
||||||
|
"_string": "0",
|
||||||
|
"_N$string": "0",
|
||||||
|
"_fontSize": 22,
|
||||||
|
"_lineHeight": 23,
|
||||||
|
"_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": "8bw7zNg/dIv7MaYIupTzUw"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"__type__": "cc.Node",
|
"__type__": "cc.Node",
|
||||||
"_name": "RoomIdIndicator",
|
"_name": "RoomIdIndicator",
|
||||||
@@ -1060,19 +1255,19 @@
|
|||||||
},
|
},
|
||||||
"_children": [
|
"_children": [
|
||||||
{
|
{
|
||||||
"__id__": 22
|
"__id__": 26
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 24
|
"__id__": 28
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_active": false,
|
"_active": false,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 26
|
"__id__": 30
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 27
|
"__id__": 31
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -1128,13 +1323,13 @@
|
|||||||
"_name": "label",
|
"_name": "label",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 21
|
"__id__": 25
|
||||||
},
|
},
|
||||||
"_children": [],
|
"_children": [],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 23
|
"__id__": 27
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -1190,7 +1385,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 22
|
"__id__": 26
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [],
|
"_materials": [],
|
||||||
@@ -1218,13 +1413,13 @@
|
|||||||
"_name": "BoundRoomIdLabel",
|
"_name": "BoundRoomIdLabel",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 21
|
"__id__": 25
|
||||||
},
|
},
|
||||||
"_children": [],
|
"_children": [],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 25
|
"__id__": 29
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -1280,7 +1475,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 24
|
"__id__": 28
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [],
|
"_materials": [],
|
||||||
@@ -1308,7 +1503,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 21
|
"__id__": 25
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_layoutSize": {
|
"_layoutSize": {
|
||||||
@@ -1341,7 +1536,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 21
|
"__id__": 25
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [],
|
"_materials": [],
|
||||||
@@ -1437,7 +1632,7 @@
|
|||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 31
|
"__id__": 35
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -1493,7 +1688,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 30
|
"__id__": 34
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -1527,7 +1722,7 @@
|
|||||||
},
|
},
|
||||||
"_children": [
|
"_children": [
|
||||||
{
|
{
|
||||||
"__id__": 33
|
"__id__": 37
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
@@ -1585,16 +1780,16 @@
|
|||||||
"_name": "Background",
|
"_name": "Background",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 32
|
"__id__": 36
|
||||||
},
|
},
|
||||||
"_children": [],
|
"_children": [],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 34
|
"__id__": 38
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 35
|
"__id__": 39
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -1650,7 +1845,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 33
|
"__id__": 37
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -1684,7 +1879,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 33
|
"__id__": 37
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"alignMode": 0,
|
"alignMode": 0,
|
||||||
@@ -1715,7 +1910,7 @@
|
|||||||
},
|
},
|
||||||
"_children": [
|
"_children": [
|
||||||
{
|
{
|
||||||
"__id__": 37
|
"__id__": 41
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
@@ -1773,16 +1968,16 @@
|
|||||||
"_name": "Background",
|
"_name": "Background",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 36
|
"__id__": 40
|
||||||
},
|
},
|
||||||
"_children": [],
|
"_children": [],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 38
|
"__id__": 42
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 39
|
"__id__": 43
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -1838,7 +2033,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 37
|
"__id__": 41
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -1872,7 +2067,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 37
|
"__id__": 41
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"alignMode": 0,
|
"alignMode": 0,
|
||||||
@@ -1930,16 +2125,16 @@
|
|||||||
},
|
},
|
||||||
"_children": [
|
"_children": [
|
||||||
{
|
{
|
||||||
"__id__": 42
|
"__id__": 46
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 44
|
"__id__": 48
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 45
|
"__id__": 49
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -1995,13 +2190,13 @@
|
|||||||
"_name": "Joystick",
|
"_name": "Joystick",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 41
|
"__id__": 45
|
||||||
},
|
},
|
||||||
"_children": [],
|
"_children": [],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 43
|
"__id__": 47
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -2057,7 +2252,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 42
|
"__id__": 46
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -2091,7 +2286,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 41
|
"__id__": 45
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -2125,7 +2320,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 41
|
"__id__": 45
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"alignMode": 0,
|
"alignMode": 0,
|
||||||
@@ -2215,7 +2410,7 @@
|
|||||||
"mapNode": {
|
"mapNode": {
|
||||||
"__id__": 3
|
"__id__": 3
|
||||||
},
|
},
|
||||||
"speed": 5000,
|
"speed": 500,
|
||||||
"_id": "76ImpM7XtPSbiLHDXdsJa+"
|
"_id": "76ImpM7XtPSbiLHDXdsJa+"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -2260,10 +2455,10 @@
|
|||||||
"__id__": 3
|
"__id__": 3
|
||||||
},
|
},
|
||||||
"stickhead": {
|
"stickhead": {
|
||||||
"__id__": 42
|
"__id__": 46
|
||||||
},
|
},
|
||||||
"base": {
|
"base": {
|
||||||
"__id__": 41
|
"__id__": 45
|
||||||
},
|
},
|
||||||
"joyStickEps": 0.1,
|
"joyStickEps": 0.1,
|
||||||
"magicLeanLowerBound": 0.414,
|
"magicLeanLowerBound": 0.414,
|
||||||
@@ -2284,10 +2479,10 @@
|
|||||||
"linearMovingEps": 0.1,
|
"linearMovingEps": 0.1,
|
||||||
"scaleByEps": 0.0375,
|
"scaleByEps": 0.0375,
|
||||||
"btnA": {
|
"btnA": {
|
||||||
"__id__": 32
|
"__id__": 36
|
||||||
},
|
},
|
||||||
"btnB": {
|
"btnB": {
|
||||||
"__id__": 36
|
"__id__": 40
|
||||||
},
|
},
|
||||||
"_id": "e9oVYTr7ROlpp/IrNjBUmR"
|
"_id": "e9oVYTr7ROlpp/IrNjBUmR"
|
||||||
}
|
}
|
||||||
|
@@ -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 = [];
|
||||||
@@ -75,10 +76,10 @@ cc.Class({
|
|||||||
onLoad() {
|
onLoad() {
|
||||||
BaseCharacter.prototype.onLoad.call(this);
|
BaseCharacter.prototype.onLoad.call(this);
|
||||||
this.effAnimNode = this.animNode.getChildByName(this.speciesName);
|
this.effAnimNode = this.animNode.getChildByName(this.speciesName);
|
||||||
this.animComp = this.effAnimNode.getComponent(dragonBones.ArmatureDisplay);
|
//this.animComp = this.effAnimNode.getComponent(dragonBones.ArmatureDisplay);
|
||||||
if (!this.animComp) {
|
//if (!this.animComp) {
|
||||||
this.animComp = this.effAnimNode.getComponent(cc.Animation);
|
this.animComp = this.effAnimNode.getComponent(cc.Animation);
|
||||||
}
|
//}
|
||||||
this.effAnimNode.active = true;
|
this.effAnimNode.active = true;
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -107,13 +108,13 @@ cc.Class({
|
|||||||
let playingAnimName = null;
|
let playingAnimName = null;
|
||||||
let underlyingAnimationCtrl = null;
|
let underlyingAnimationCtrl = null;
|
||||||
|
|
||||||
if (this.animComp instanceof dragonBones.ArmatureDisplay) {
|
//if (this.animComp instanceof dragonBones.ArmatureDisplay) {
|
||||||
underlyingAnimationCtrl = this.animComp._armature.animation; // ALWAYS use the dragonBones api instead of ccc's wrapper!
|
// underlyingAnimationCtrl = this.animComp._armature.animation; // ALWAYS use the dragonBones api instead of ccc's wrapper!
|
||||||
playingAnimName = underlyingAnimationCtrl.lastAnimationName;
|
// playingAnimName = underlyingAnimationCtrl.lastAnimationName;
|
||||||
} else {
|
//} else {
|
||||||
underlyingAnimationCtrl = this.animComp.currentClip;
|
underlyingAnimationCtrl = this.animComp.currentClip;
|
||||||
playingAnimName = (!underlyingAnimationCtrl ? null : underlyingAnimationCtrl.name);
|
playingAnimName = (!underlyingAnimationCtrl ? null : underlyingAnimationCtrl.name);
|
||||||
}
|
//}
|
||||||
|
|
||||||
// It turns out that "prevRdfPlayer.CharacterState" is not useful in this function :)
|
// 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)) {
|
||||||
@@ -122,11 +123,11 @@ cc.Class({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.animComp instanceof dragonBones.ArmatureDisplay) {
|
//if (this.animComp instanceof dragonBones.ArmatureDisplay) {
|
||||||
this._interruptPlayingAnimAndPlayNewAnimDragonBones(rdfPlayer, prevRdfPlayer, newCharacterState, newAnimName, underlyingAnimationCtrl, playingAnimName, chConfig);
|
// this._interruptPlayingAnimAndPlayNewAnimDragonBones(rdfPlayer, prevRdfPlayer, newCharacterState, newAnimName, underlyingAnimationCtrl, playingAnimName, chConfig);
|
||||||
} else {
|
//} else {
|
||||||
this._interruptPlayingAnimAndPlayNewAnimFrameAnim(rdfPlayer, prevRdfPlayer, newCharacterState, newAnimName, playingAnimName, chConfig);
|
this._interruptPlayingAnimAndPlayNewAnimFrameAnim(rdfPlayer, prevRdfPlayer, newCharacterState, newAnimName, playingAnimName, chConfig);
|
||||||
}
|
//}
|
||||||
},
|
},
|
||||||
|
|
||||||
_interruptPlayingAnimAndPlayNewAnimDragonBones(rdfPlayer, prevRdfPlayer, newCharacterState, newAnimName, underlyingAnimationCtrl, playingAnimName, chConfig) {
|
_interruptPlayingAnimAndPlayNewAnimDragonBones(rdfPlayer, prevRdfPlayer, newCharacterState, newAnimName, underlyingAnimationCtrl, playingAnimName, chConfig) {
|
||||||
|
@@ -8,7 +8,7 @@ cc.Class({
|
|||||||
},
|
},
|
||||||
speed: {
|
speed: {
|
||||||
type: cc.Float,
|
type: cc.Float,
|
||||||
default: 500
|
default: 100
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -29,6 +29,15 @@ cc.Class({
|
|||||||
if (!selfPlayerRichInfo) return;
|
if (!selfPlayerRichInfo) return;
|
||||||
const selfPlayerNode = selfPlayerRichInfo.node;
|
const selfPlayerNode = selfPlayerRichInfo.node;
|
||||||
if (!selfPlayerNode) return;
|
if (!selfPlayerNode) return;
|
||||||
self.mapNode.setPosition(cc.v2().sub(selfPlayerNode.position));
|
const dst = cc.v2().sub(selfPlayerNode.position);
|
||||||
|
const pDiff = dst.sub(self.mapNode.position);
|
||||||
|
const stepLength = dt * self.speed;
|
||||||
|
if (stepLength > pDiff.mag()) {
|
||||||
|
self.mapNode.setPosition(dst);
|
||||||
|
} else {
|
||||||
|
pDiff.normalizeSelf();
|
||||||
|
const newMapPos = self.mapNode.position.add(pDiff.mul(dt * self.speed));
|
||||||
|
self.mapNode.setPosition(newMapPos);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
41
frontend/assets/scripts/CharacterSelectCell.js
Normal 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);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
9
frontend/assets/scripts/CharacterSelectCell.js.meta
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.0.5",
|
||||||
|
"uuid": "6dd2c047-fa5c-4080-8221-27fabfd275d6",
|
||||||
|
"isPlugin": false,
|
||||||
|
"loadPluginInWeb": true,
|
||||||
|
"loadPluginInNative": true,
|
||||||
|
"loadPluginInEditor": false,
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
@@ -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() {
|
||||||
|
@@ -23,7 +23,8 @@ cc.Class({
|
|||||||
// LIFE-CYCLE CALLBACKS:
|
// LIFE-CYCLE CALLBACKS:
|
||||||
onLoad() {},
|
onLoad() {},
|
||||||
|
|
||||||
init() {
|
init(mapIns) {
|
||||||
|
this.mapIns = mapIns;
|
||||||
if (null != this.firstPlayerInfoNode) {
|
if (null != this.firstPlayerInfoNode) {
|
||||||
this.firstPlayerInfoNode.active = false;
|
this.firstPlayerInfoNode.active = false;
|
||||||
}
|
}
|
||||||
@@ -46,16 +47,17 @@ cc.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
hideExitButton() {
|
hideExitButton() {
|
||||||
if (null == this.exitBtnNode != null) {
|
if (null == this.exitBtnNode) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.exitBtnNode.active = false;
|
this.exitBtnNode.active = false;
|
||||||
},
|
},
|
||||||
|
|
||||||
exitBtnOnClick(evt) {
|
exitBtnOnClick(evt) {
|
||||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
this.mapIns.hideFindingPlayersGUI();
|
||||||
window.closeWSConnection();
|
cc.log(`FindingPlayers.exitBtnOnClick`);
|
||||||
cc.director.loadScene('login');
|
window.closeWSConnection(constants.RET_CODE.BATTLE_STOPPED, "");
|
||||||
|
window.clearLocalStorageAndBackToLoginScene(false);
|
||||||
},
|
},
|
||||||
|
|
||||||
updatePlayersInfo(playerMetas) {
|
updatePlayersInfo(playerMetas) {
|
||||||
|
@@ -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);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
@@ -354,6 +354,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.")
|
||||||
|
@@ -34,6 +34,23 @@ window.PlayerBattleState = {
|
|||||||
EXPELLED_IN_DISMISSAL: 6
|
EXPELLED_IN_DISMISSAL: 6
|
||||||
};
|
};
|
||||||
|
|
||||||
|
window.onUdpMessage = (args) => {
|
||||||
|
const self = window.mapIns;
|
||||||
|
const ui8Arr = args;
|
||||||
|
//cc.log(`#1 Js called back by CPP: onUdpMessage: args=${args}, typeof(args)=${typeof (args)}, argslen=${args.length}, ui8Arr=${ui8Arr}`);
|
||||||
|
const req = window.pb.protos.WsReq.decode(ui8Arr);
|
||||||
|
if (req) {
|
||||||
|
//cc.log(`#2 Js called back by CPP for upsync: onUdpMessage: ${JSON.stringify(req)}`);
|
||||||
|
if (req.act && window.UPSYNC_MSG_ACT_PLAYER_CMD == req.act) {
|
||||||
|
let effCnt = 0;
|
||||||
|
const peerJoinIndex = req.joinIndex;
|
||||||
|
if (peerJoinIndex == self.selfPlayerInfo.JoinIndex) return;
|
||||||
|
const batch = req.inputFrameUpsyncBatch;
|
||||||
|
self.onPeerInputFrameUpsync(peerJoinIndex, batch, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
cc.Class({
|
cc.Class({
|
||||||
extends: cc.Component,
|
extends: cc.Component,
|
||||||
|
|
||||||
@@ -86,10 +103,6 @@ cc.Class({
|
|||||||
type: cc.Prefab,
|
type: cc.Prefab,
|
||||||
default: null
|
default: null
|
||||||
},
|
},
|
||||||
playersInfoPrefab: {
|
|
||||||
type: cc.Prefab,
|
|
||||||
default: null
|
|
||||||
},
|
|
||||||
forceBigEndianFloatingNumDecoding: {
|
forceBigEndianFloatingNumDecoding: {
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
@@ -97,6 +110,10 @@ cc.Class({
|
|||||||
type: cc.Integer,
|
type: cc.Integer,
|
||||||
default: 4 // implies (renderFrameIdLagTolerance >> inputScaleFrames) count of inputFrameIds
|
default: 4 // implies (renderFrameIdLagTolerance >> inputScaleFrames) count of inputFrameIds
|
||||||
},
|
},
|
||||||
|
inputFrameFrontLabel: {
|
||||||
|
type: cc.Label,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
sendingQLabel: {
|
sendingQLabel: {
|
||||||
type: cc.Label,
|
type: cc.Label,
|
||||||
default: null
|
default: null
|
||||||
@@ -113,6 +130,10 @@ cc.Class({
|
|||||||
type: cc.Label,
|
type: cc.Label,
|
||||||
default: null
|
default: null
|
||||||
},
|
},
|
||||||
|
skippedRenderFrameCntLabel: {
|
||||||
|
type: cc.Label,
|
||||||
|
default: null
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_inputFrameIdDebuggable(inputFrameId) {
|
_inputFrameIdDebuggable(inputFrameId) {
|
||||||
@@ -123,7 +144,7 @@ cc.Class({
|
|||||||
return (confirmedList + 1) == (1 << this.playerRichInfoDict.size);
|
return (confirmedList + 1) == (1 << this.playerRichInfoDict.size);
|
||||||
},
|
},
|
||||||
|
|
||||||
getOrPrefabInputFrameUpsync(inputFrameId) {
|
getOrPrefabInputFrameUpsync(inputFrameId, canConfirmSelf) {
|
||||||
// TODO: find some kind of synchronization mechanism against "onInputFrameDownsyncBatch"!
|
// TODO: find some kind of synchronization mechanism against "onInputFrameDownsyncBatch"!
|
||||||
const self = this;
|
const self = this;
|
||||||
if (
|
if (
|
||||||
@@ -136,33 +157,48 @@ cc.Class({
|
|||||||
let previousSelfInput = null,
|
let previousSelfInput = null,
|
||||||
currSelfInput = null;
|
currSelfInput = null;
|
||||||
const joinIndex = self.selfPlayerInfo.JoinIndex;
|
const joinIndex = self.selfPlayerInfo.JoinIndex;
|
||||||
|
const selfJoinIndexMask = (1 << (joinIndex - 1));
|
||||||
const existingInputFrame = self.recentInputCache.GetByFrameId(inputFrameId);
|
const existingInputFrame = self.recentInputCache.GetByFrameId(inputFrameId);
|
||||||
const previousInputFrameDownsync = self.recentInputCache.GetByFrameId(inputFrameId - 1);
|
const previousInputFrameDownsync = self.recentInputCache.GetByFrameId(inputFrameId - 1);
|
||||||
previousSelfInput = (null == previousInputFrameDownsync ? null : previousInputFrameDownsync.InputList[joinIndex - 1]);
|
previousSelfInput = (null == previousInputFrameDownsync ? null : previousInputFrameDownsync.InputList[joinIndex - 1]);
|
||||||
if (null != existingInputFrame) {
|
if (
|
||||||
|
null != existingInputFrame
|
||||||
|
&&
|
||||||
|
(true != canConfirmSelf)
|
||||||
|
) {
|
||||||
// This could happen upon either [type#1] or [type#2] forceConfirmation, where "refRenderFrame" is accompanied by some "inputFrameDownsyncs". The check here also guarantees that we don't override history
|
// This could happen upon either [type#1] or [type#2] forceConfirmation, where "refRenderFrame" is accompanied by some "inputFrameDownsyncs". The check here also guarantees that we don't override history
|
||||||
//console.log(`noDelayInputFrameId=${inputFrameId} already exists in recentInputCache: recentInputCache=${self._stringifyRecentInputCache(false)}`);
|
//console.log(`noDelayInputFrameId=${inputFrameId} already exists in recentInputCache: recentInputCache=${self._stringifyRecentInputCache(false)}`);
|
||||||
return [previousSelfInput, existingInputFrame.InputList[joinIndex - 1]];
|
return [previousSelfInput, existingInputFrame.InputList[joinIndex - 1]];
|
||||||
}
|
}
|
||||||
|
|
||||||
const lastAllConfirmedInputFrame = self.recentInputCache.GetByFrameId(self.lastAllConfirmedInputFrameId);
|
|
||||||
const prefabbedInputList = new Array(self.playerRichInfoDict.size).fill(0);
|
const prefabbedInputList = new Array(self.playerRichInfoDict.size).fill(0);
|
||||||
// the returned "gopkgs.NewInputFrameDownsync.InputList" is immutable, thus we can only modify the values in "prefabbedInputList"
|
// the returned "gopkgs.NewInputFrameDownsync.InputList" is immutable, thus we can only modify the values in "prefabbedInputList"
|
||||||
for (let k in prefabbedInputList) {
|
for (let k = 0; k < window.boundRoomCapacity; ++k) {
|
||||||
if (null != previousInputFrameDownsync) {
|
if (null != existingInputFrame) {
|
||||||
|
// When "null != existingInputFrame", it implies that "true == canConfirmSelf" here, we just have to assign "prefabbedInputList[(joinIndex-1)]" specifically and copy all others
|
||||||
|
prefabbedInputList[k] = existingInputFrame.InputList[k];
|
||||||
|
} else if (self.lastIndividuallyConfirmedInputFrameId[k] <= inputFrameId) {
|
||||||
|
prefabbedInputList[k] = self.lastIndividuallyConfirmedInputList[k];
|
||||||
|
// Don't predict "btnA & btnB"!
|
||||||
|
prefabbedInputList[k] = (prefabbedInputList[k] & 15);
|
||||||
|
} else if (null != previousInputFrameDownsync) {
|
||||||
|
// When "self.lastIndividuallyConfirmedInputFrameId[k] > inputFrameId", don't use it to predict a historical input!
|
||||||
prefabbedInputList[k] = previousInputFrameDownsync.InputList[k];
|
prefabbedInputList[k] = previousInputFrameDownsync.InputList[k];
|
||||||
|
// Don't predict "btnA & btnB"!
|
||||||
|
prefabbedInputList[k] = (prefabbedInputList[k] & 15);
|
||||||
}
|
}
|
||||||
if (0 <= self.lastAllConfirmedInputFrameId && inputFrameId - 1 > self.lastAllConfirmedInputFrameId) {
|
}
|
||||||
prefabbedInputList[k] = lastAllConfirmedInputFrame.InputList[k];
|
let initConfirmedList = 0;
|
||||||
}
|
if (null != existingInputFrame) {
|
||||||
// Don't predict "btnA & btnB"!
|
// When "null != existingInputFrame", it implies that "true == canConfirmSelf" here
|
||||||
prefabbedInputList[k] = (prefabbedInputList[k] & 15);
|
initConfirmedList = (existingInputFrame.ConfirmedList | selfJoinIndexMask);
|
||||||
}
|
}
|
||||||
currSelfInput = self.ctrl.getEncodedInput(); // When "null == existingInputFrame", it'd be safe to say that the realtime "self.ctrl.getEncodedInput()" is for the requested "inputFrameId"
|
currSelfInput = self.ctrl.getEncodedInput(); // When "null == existingInputFrame", it'd be safe to say that the realtime "self.ctrl.getEncodedInput()" is for the requested "inputFrameId"
|
||||||
prefabbedInputList[(joinIndex - 1)] = currSelfInput;
|
prefabbedInputList[(joinIndex - 1)] = currSelfInput;
|
||||||
while (self.recentInputCache.EdFrameId <= inputFrameId) {
|
while (self.recentInputCache.EdFrameId <= inputFrameId) {
|
||||||
// Fill the gap
|
// Fill the gap
|
||||||
const prefabbedInputFrameDownsync = gopkgs.NewInputFrameDownsync(self.recentInputCache.EdFrameId, prefabbedInputList.slice(), (1 << (joinIndex - 1)));
|
// [WARNING] Do not blindly use "selfJoinIndexMask" here, as the "actuallyUsedInput for self" couldn't be confirmed while prefabbing, otherwise we'd have confirmed a wrong self input by "_markConfirmationIfApplicable()"!
|
||||||
|
const prefabbedInputFrameDownsync = gopkgs.NewInputFrameDownsync(self.recentInputCache.EdFrameId, prefabbedInputList.slice(), initConfirmedList);
|
||||||
// console.log(`Prefabbed inputFrameId=${prefabbedInputFrameDownsync.InputFrameId}`);
|
// console.log(`Prefabbed inputFrameId=${prefabbedInputFrameDownsync.InputFrameId}`);
|
||||||
self.recentInputCache.Put(prefabbedInputFrameDownsync);
|
self.recentInputCache.Put(prefabbedInputFrameDownsync);
|
||||||
}
|
}
|
||||||
@@ -213,7 +249,11 @@ cc.Class({
|
|||||||
joinIndex: self.selfPlayerInfo.JoinIndex,
|
joinIndex: self.selfPlayerInfo.JoinIndex,
|
||||||
ackingInputFrameId: self.lastAllConfirmedInputFrameId,
|
ackingInputFrameId: self.lastAllConfirmedInputFrameId,
|
||||||
inputFrameUpsyncBatch: inputFrameUpsyncBatch,
|
inputFrameUpsyncBatch: inputFrameUpsyncBatch,
|
||||||
|
authKey: self.selfPlayerInfo.udpTunnelAuthKey,
|
||||||
}).finish();
|
}).finish();
|
||||||
|
if (cc.sys.isNative) {
|
||||||
|
DelayNoMore.UdpSession.broadcastInputFrameUpsync(reqData, window.boundRoomCapacity, self.selfPlayerInfo.JoinIndex);
|
||||||
|
}
|
||||||
window.sendSafely(reqData);
|
window.sendSafely(reqData);
|
||||||
self.lastUpsyncInputFrameId = latestLocalInputFrameId;
|
self.lastUpsyncInputFrameId = latestLocalInputFrameId;
|
||||||
if (self.lastUpsyncInputFrameId >= self.recentInputCache.EdFrameId) {
|
if (self.lastUpsyncInputFrameId >= self.recentInputCache.EdFrameId) {
|
||||||
@@ -240,13 +280,6 @@ cc.Class({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onManualRejoinRequired(labelString) {
|
|
||||||
const self = this;
|
|
||||||
self.battleState = ALL_BATTLE_STATES.NONE; // Effectively stops "update(dt)"
|
|
||||||
self.showPopupInCanvas(self.gameRuleNode);
|
|
||||||
self.popupSimplePressToGo(labelString, false);
|
|
||||||
},
|
|
||||||
|
|
||||||
popupSimplePressToGo(labelString, hideYesButton) {
|
popupSimplePressToGo(labelString, hideYesButton) {
|
||||||
const self = this;
|
const self = this;
|
||||||
self.state = ALL_MAP_STATES.SHOWING_MODAL_POPUP;
|
self.state = ALL_MAP_STATES.SHOWING_MODAL_POPUP;
|
||||||
@@ -330,9 +363,10 @@ cc.Class({
|
|||||||
self.lastUpsyncInputFrameId = -1;
|
self.lastUpsyncInputFrameId = -1;
|
||||||
self.chaserRenderFrameId = -1; // at any moment, "chaserRenderFrameId <= renderFrameId", but "chaserRenderFrameId" would fluctuate according to "onInputFrameDownsyncBatch"
|
self.chaserRenderFrameId = -1; // at any moment, "chaserRenderFrameId <= renderFrameId", but "chaserRenderFrameId" would fluctuate according to "onInputFrameDownsyncBatch"
|
||||||
|
|
||||||
|
self.lastIndividuallyConfirmedInputFrameId = new Array(window.boundRoomCapacity).fill(-1);
|
||||||
|
self.lastIndividuallyConfirmedInputList = new Array(window.boundRoomCapacity).fill(0);
|
||||||
self.recentRenderCache = new RingBuffer(self.renderCacheSize);
|
self.recentRenderCache = new RingBuffer(self.renderCacheSize);
|
||||||
|
|
||||||
self.selfPlayerInfo = null; // This field is kept for distinguishing "self" and "others".
|
|
||||||
self.recentInputCache = gopkgs.NewRingBufferJs((self.renderCacheSize >> 1) + 1);
|
self.recentInputCache = gopkgs.NewRingBufferJs((self.renderCacheSize >> 1) + 1);
|
||||||
|
|
||||||
self.gopkgsCollisionSys = gopkgs.NewCollisionSpaceJs((self.spaceOffsetX << 1), (self.spaceOffsetY << 1), self.collisionMinStep, self.collisionMinStep);
|
self.gopkgsCollisionSys = gopkgs.NewCollisionSpaceJs((self.spaceOffsetX << 1), (self.spaceOffsetY << 1), self.collisionMinStep, self.collisionMinStep);
|
||||||
@@ -351,21 +385,11 @@ cc.Class({
|
|||||||
self.rdfIdToActuallyUsedInput = new Map();
|
self.rdfIdToActuallyUsedInput = new Map();
|
||||||
|
|
||||||
self.networkDoctor = new NetworkDoctor(20);
|
self.networkDoctor = new NetworkDoctor(20);
|
||||||
|
self.skipRenderFrameFlag = false;
|
||||||
|
|
||||||
|
self.allowRollbackOnPeerUpsync = true;
|
||||||
|
|
||||||
self.countdownNanos = null;
|
self.countdownNanos = null;
|
||||||
if (self.countdownLabel) {
|
|
||||||
self.countdownLabel.string = "";
|
|
||||||
}
|
|
||||||
if (self.findingPlayerNode) {
|
|
||||||
const findingPlayerScriptIns = self.findingPlayerNode.getComponent("FindingPlayer");
|
|
||||||
findingPlayerScriptIns.init();
|
|
||||||
}
|
|
||||||
if (self.playersInfoNode) {
|
|
||||||
safelyAddChild(self.widgetsAboveAllNode, self.playersInfoNode);
|
|
||||||
}
|
|
||||||
if (self.findingPlayerNode) {
|
|
||||||
safelyAddChild(self.widgetsAboveAllNode, self.findingPlayerNode);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
initDebugDrawers() {
|
initDebugDrawers() {
|
||||||
@@ -419,7 +443,7 @@ cc.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
onLoad() {
|
onLoad() {
|
||||||
cc.game.setFrameRate(60);
|
cc.game.setFrameRate(59);
|
||||||
cc.view.setOrientation(cc.macro.ORIENTATION_LANDSCAPE);
|
cc.view.setOrientation(cc.macro.ORIENTATION_LANDSCAPE);
|
||||||
cc.view.enableAutoFullScreen(true);
|
cc.view.enableAutoFullScreen(true);
|
||||||
|
|
||||||
@@ -466,9 +490,7 @@ cc.Class({
|
|||||||
self.findingPlayerNode.width = self.canvasNode.width;
|
self.findingPlayerNode.width = self.canvasNode.width;
|
||||||
self.findingPlayerNode.height = self.canvasNode.height;
|
self.findingPlayerNode.height = self.canvasNode.height;
|
||||||
const findingPlayerScriptIns = self.findingPlayerNode.getComponent("FindingPlayer");
|
const findingPlayerScriptIns = self.findingPlayerNode.getComponent("FindingPlayer");
|
||||||
findingPlayerScriptIns.init();
|
findingPlayerScriptIns.init(self);
|
||||||
|
|
||||||
self.playersInfoNode = cc.instantiate(self.playersInfoPrefab);
|
|
||||||
|
|
||||||
self.countdownToBeginGameNode = cc.instantiate(self.countdownToBeginGamePrefab);
|
self.countdownToBeginGameNode = cc.instantiate(self.countdownToBeginGamePrefab);
|
||||||
self.countdownToBeginGameNode.width = self.canvasNode.width;
|
self.countdownToBeginGameNode.width = self.canvasNode.width;
|
||||||
@@ -488,6 +510,7 @@ cc.Class({
|
|||||||
console.log(`Received parsedBattleColliderInfo via ws`);
|
console.log(`Received parsedBattleColliderInfo via ws`);
|
||||||
// TODO: Upon reconnection, the backend might have already been sending down data that'd trigger "onRoomDownsyncFrame & onInputFrameDownsyncBatch", but frontend could reject those data due to "battleState != PlayerBattleState.ACTIVE".
|
// TODO: Upon reconnection, the backend might have already been sending down data that'd trigger "onRoomDownsyncFrame & onInputFrameDownsyncBatch", but frontend could reject those data due to "battleState != PlayerBattleState.ACTIVE".
|
||||||
Object.assign(self, parsedBattleColliderInfo);
|
Object.assign(self, parsedBattleColliderInfo);
|
||||||
|
self.inputFrameUpsyncDelayTolerance = parsedBattleColliderInfo.inputFrameUpsyncDelayTolerance;
|
||||||
|
|
||||||
const tiledMapIns = self.node.getComponent(cc.TiledMap);
|
const tiledMapIns = self.node.getComponent(cc.TiledMap);
|
||||||
|
|
||||||
@@ -495,7 +518,7 @@ cc.Class({
|
|||||||
const fullPathOfTmxFile = cc.js.formatStr("map/%s/map", parsedBattleColliderInfo.stageName);
|
const fullPathOfTmxFile = cc.js.formatStr("map/%s/map", parsedBattleColliderInfo.stageName);
|
||||||
cc.loader.loadRes(fullPathOfTmxFile, cc.TiledMapAsset, (err, tmxAsset) => {
|
cc.loader.loadRes(fullPathOfTmxFile, cc.TiledMapAsset, (err, tmxAsset) => {
|
||||||
if (null != err) {
|
if (null != err) {
|
||||||
console.error(err);
|
console.error(`Error occurred when loading tiled stage ${parsedBattleColliderInfo.stageName}`, err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -510,6 +533,11 @@ cc.Class({
|
|||||||
tiledMapIns.tmxAsset = null;
|
tiledMapIns.tmxAsset = null;
|
||||||
mapNode.removeAllChildren();
|
mapNode.removeAllChildren();
|
||||||
self._resetCurrentMatch();
|
self._resetCurrentMatch();
|
||||||
|
if (self.countdownLabel) {
|
||||||
|
self.countdownLabel.string = "";
|
||||||
|
}
|
||||||
|
self.hideGameRuleNode();
|
||||||
|
self.showFindingPlayerGUI(null);
|
||||||
|
|
||||||
tiledMapIns.tmxAsset = tmxAsset;
|
tiledMapIns.tmxAsset = tmxAsset;
|
||||||
const newMapSize = tiledMapIns.getMapSize();
|
const newMapSize = tiledMapIns.getMapSize();
|
||||||
@@ -544,10 +572,6 @@ cc.Class({
|
|||||||
const collisionBarrierIndex = (self.collisionBarrierIndexPrefix + barrierIdCounter);
|
const collisionBarrierIndex = (self.collisionBarrierIndexPrefix + barrierIdCounter);
|
||||||
self.gopkgsCollisionSysMap[collisionBarrierIndex] = newBarrierCollider;
|
self.gopkgsCollisionSysMap[collisionBarrierIndex] = newBarrierCollider;
|
||||||
}
|
}
|
||||||
self.selfPlayerInfo = JSON.parse(cc.sys.localStorage.getItem('selfPlayer'));
|
|
||||||
Object.assign(self.selfPlayerInfo, {
|
|
||||||
Id: self.selfPlayerInfo.playerId
|
|
||||||
});
|
|
||||||
self.initDebugDrawers();
|
self.initDebugDrawers();
|
||||||
const reqData = window.pb.protos.WsReq.encode({
|
const reqData = window.pb.protos.WsReq.encode({
|
||||||
msgId: Date.now(),
|
msgId: Date.now(),
|
||||||
@@ -560,7 +584,6 @@ cc.Class({
|
|||||||
|
|
||||||
self.initAfterWSConnected = () => {
|
self.initAfterWSConnected = () => {
|
||||||
const self = window.mapIns;
|
const self = window.mapIns;
|
||||||
self.hideGameRuleNode();
|
|
||||||
self.transitToState(ALL_MAP_STATES.WAITING);
|
self.transitToState(ALL_MAP_STATES.WAITING);
|
||||||
self._inputControlEnabled = false;
|
self._inputControlEnabled = false;
|
||||||
}
|
}
|
||||||
@@ -606,7 +629,8 @@ cc.Class({
|
|||||||
if (null == self.gameRuleNode) {
|
if (null == self.gameRuleNode) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.gameRuleNode.active = false;
|
//self.gameRuleNode.active = false;
|
||||||
|
self.gameRuleNode.setPosition(cc.v2(Number.MAX_VALUE, Number.MAX_VALUE));
|
||||||
},
|
},
|
||||||
|
|
||||||
enableInputControls() {
|
enableInputControls() {
|
||||||
@@ -621,7 +645,7 @@ cc.Class({
|
|||||||
const jsPlayersArr = new Array(pbRdf.playersArr.length).fill(null);
|
const jsPlayersArr = new Array(pbRdf.playersArr.length).fill(null);
|
||||||
for (let k = 0; k < pbRdf.playersArr.length; ++k) {
|
for (let k = 0; k < pbRdf.playersArr.length; ++k) {
|
||||||
const pbPlayer = pbRdf.playersArr[k];
|
const pbPlayer = pbRdf.playersArr[k];
|
||||||
const jsPlayer = gopkgs.NewPlayerDownsyncJs(pbPlayer.id, pbPlayer.virtualGridX, pbPlayer.virtualGridY, pbPlayer.dirX, pbPlayer.dirY, pbPlayer.velX, pbPlayer.velY, pbPlayer.framesToRecover, pbPlayer.framesInChState, pbPlayer.activeSkillId, pbPlayer.activeSkillHit, pbPlayer.framesInvinsible, pbPlayer.speed, pbPlayer.battleState, pbPlayer.characterState, pbPlayer.joinIndex, pbPlayer.hp, pbPlayer.maxHp, pbPlayer.colliderRadius, pbPlayer.inAir, pbPlayer.onWall, pbPlayer.onWallNormX, pbPlayer.onWallNormY, pbPlayer.capturedByInertia, pbPlayer.bulletTeamId, pbPlayer.chCollisionTeamId);
|
const jsPlayer = gopkgs.NewPlayerDownsyncJs(pbPlayer.id, pbPlayer.virtualGridX, pbPlayer.virtualGridY, pbPlayer.dirX, pbPlayer.dirY, pbPlayer.velX, pbPlayer.velY, pbPlayer.framesToRecover, pbPlayer.framesInChState, pbPlayer.activeSkillId, pbPlayer.activeSkillHit, pbPlayer.framesInvinsible, pbPlayer.speed, pbPlayer.battleState, pbPlayer.characterState, pbPlayer.joinIndex, pbPlayer.hp, pbPlayer.maxHp, pbPlayer.colliderRadius, pbPlayer.inAir, pbPlayer.onWall, pbPlayer.onWallNormX, pbPlayer.onWallNormY, pbPlayer.capturedByInertia, pbPlayer.bulletTeamId, pbPlayer.chCollisionTeamId, pbPlayer.revivalVirtualGridX, pbPlayer.revivalVirtualGridY);
|
||||||
jsPlayersArr[k] = jsPlayer;
|
jsPlayersArr[k] = jsPlayer;
|
||||||
}
|
}
|
||||||
const jsMeleeBulletsArr = new Array(pbRdf.meleeBullets.length).fill(null);
|
const jsMeleeBulletsArr = new Array(pbRdf.meleeBullets.length).fill(null);
|
||||||
@@ -681,14 +705,6 @@ cc.Class({
|
|||||||
self.chConfigsOrderedByJoinIndex = gopkgs.GetCharacterConfigsOrderedByJoinIndex(pbRdf.speciesIdList);
|
self.chConfigsOrderedByJoinIndex = gopkgs.GetCharacterConfigsOrderedByJoinIndex(pbRdf.speciesIdList);
|
||||||
self._initPlayerRichInfoDict(rdf.PlayersArr);
|
self._initPlayerRichInfoDict(rdf.PlayersArr);
|
||||||
|
|
||||||
// Show the top status indicators for IN_BATTLE
|
|
||||||
if (self.playersInfoNode) {
|
|
||||||
const playersInfoScriptIns = self.playersInfoNode.getComponent("PlayersInfo");
|
|
||||||
for (let i in pbRdf.playersArr) {
|
|
||||||
playersInfoScriptIns.updateData(pbRdf.playersArr[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shouldForceDumping1 || shouldForceDumping2 || shouldForceResync) {
|
if (shouldForceDumping1 || shouldForceDumping2 || shouldForceResync) {
|
||||||
// In fact, not having "window.RING_BUFF_CONSECUTIVE_SET == dumpRenderCacheRet" should already imply that "self.renderFrameId <= rdf.id", but here we double check and log the anomaly
|
// In fact, not having "window.RING_BUFF_CONSECUTIVE_SET == dumpRenderCacheRet" should already imply that "self.renderFrameId <= rdf.id", but here we double check and log the anomaly
|
||||||
|
|
||||||
@@ -698,20 +714,27 @@ cc.Class({
|
|||||||
self.hideFindingPlayersGUI();
|
self.hideFindingPlayersGUI();
|
||||||
console.warn('On battle resynced! renderFrameId=', rdf.Id);
|
console.warn('On battle resynced! renderFrameId=', rdf.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.renderFrameId = rdf.Id;
|
self.renderFrameId = rdf.Id;
|
||||||
self.lastRenderFrameIdTriggeredAt = performance.now();
|
self.lastRenderFrameIdTriggeredAt = performance.now();
|
||||||
// In this case it must be true that "rdf.id > chaserRenderFrameId".
|
// In this case it must be true that "rdf.id > chaserRenderFrameId".
|
||||||
self.chaserRenderFrameId = rdf.Id;
|
self.chaserRenderFrameId = rdf.Id;
|
||||||
|
self.networkDoctor.logRollbackFrames(0);
|
||||||
|
|
||||||
const canvasNode = self.canvasNode;
|
const canvasNode = self.canvasNode;
|
||||||
self.ctrl = canvasNode.getComponent("TouchEventsManager");
|
self.ctrl = canvasNode.getComponent("TouchEventsManager");
|
||||||
self.enableInputControls();
|
self.enableInputControls();
|
||||||
self.transitToState(ALL_MAP_STATES.VISUAL);
|
self.transitToState(ALL_MAP_STATES.VISUAL);
|
||||||
|
|
||||||
|
const selfPlayerRichInfo = self.playerRichInfoDict.get(self.selfPlayerInfo.Id);
|
||||||
|
const newMapPos = cc.v2().sub(selfPlayerRichInfo.node.position);
|
||||||
|
self.node.setPosition(newMapPos);
|
||||||
self.battleState = ALL_BATTLE_STATES.IN_BATTLE;
|
self.battleState = ALL_BATTLE_STATES.IN_BATTLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// [WARNING] "cc.Node.removeChild" would trigger massive update of rendering nodes, thus a performance impact at the beginning of battle, avoid it by just moving the widget to infinitely far away!
|
||||||
if (self.countdownToBeginGameNode && self.countdownToBeginGameNode.parent) {
|
if (self.countdownToBeginGameNode && self.countdownToBeginGameNode.parent) {
|
||||||
self.countdownToBeginGameNode.parent.removeChild(self.countdownToBeginGameNode);
|
self.countdownToBeginGameNode.setPosition(cc.v2(Number.MAX_VALUE, Number.MAX_VALUE));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null != self.musicEffectManagerScriptIns) {
|
if (null != self.musicEffectManagerScriptIns) {
|
||||||
@@ -795,6 +818,19 @@ cc.Class({
|
|||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_markConfirmationIfApplicable() {
|
||||||
|
const self = this;
|
||||||
|
let newAllConfirmedCnt = 0;
|
||||||
|
while (self.recentInputCache.StFrameId <= self.lastAllConfirmedInputFrameId && self.lastAllConfirmedInputFrameId < self.recentInputCache.EdFrameId) {
|
||||||
|
const inputFrameDownsync = self.recentInputCache.GetByFrameId(self.lastAllConfirmedInputFrameId);
|
||||||
|
if (null == inputFrameDownsync) break;
|
||||||
|
if (self._allConfirmed(inputFrameDownsync.ConfirmedList)) break;
|
||||||
|
++self.lastAllConfirmedInputFrameId;
|
||||||
|
++newAllConfirmedCnt;
|
||||||
|
}
|
||||||
|
return newAllConfirmedCnt;
|
||||||
|
},
|
||||||
|
|
||||||
onInputFrameDownsyncBatch(batch /* []*pb.InputFrameDownsync */ ) {
|
onInputFrameDownsyncBatch(batch /* []*pb.InputFrameDownsync */ ) {
|
||||||
// TODO: find some kind of synchronization mechanism against "getOrPrefabInputFrameUpsync"!
|
// TODO: find some kind of synchronization mechanism against "getOrPrefabInputFrameUpsync"!
|
||||||
if (null == batch) {
|
if (null == batch) {
|
||||||
@@ -816,8 +852,9 @@ cc.Class({
|
|||||||
if (inputFrameDownsyncId <= self.lastAllConfirmedInputFrameId) {
|
if (inputFrameDownsyncId <= self.lastAllConfirmedInputFrameId) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// [WARNING] Take all "inputFrameDownsync" from backend as all-confirmed, it'll be later checked by "rollbackAndChase".
|
// [WARNING] Now that "inputFrameDownsyncId > self.lastAllConfirmedInputFrameId", we should make an update immediately because unlike its backend counterpart "Room.LastAllConfirmedInputFrameId", the frontend "mapIns.lastAllConfirmedInputFrameId" might inevitably get gaps among discrete values due to "either type#1 or type#2 forceConfirmation" -- and only "onInputFrameDownsyncBatch" can catch this!
|
||||||
self.lastAllConfirmedInputFrameId = inputFrameDownsyncId;
|
self.lastAllConfirmedInputFrameId = inputFrameDownsyncId;
|
||||||
|
|
||||||
const localInputFrame = self.recentInputCache.GetByFrameId(inputFrameDownsyncId);
|
const localInputFrame = self.recentInputCache.GetByFrameId(inputFrameDownsyncId);
|
||||||
if (null != localInputFrame
|
if (null != localInputFrame
|
||||||
&&
|
&&
|
||||||
@@ -827,16 +864,29 @@ cc.Class({
|
|||||||
) {
|
) {
|
||||||
firstPredictedYetIncorrectInputFrameId = inputFrameDownsyncId;
|
firstPredictedYetIncorrectInputFrameId = inputFrameDownsyncId;
|
||||||
}
|
}
|
||||||
|
// [WARNING] Take all "inputFrameDownsync" from backend as all-confirmed, it'll be later checked by "rollbackAndChase".
|
||||||
inputFrameDownsync.confirmedList = (1 << self.playerRichInfoDict.size) - 1;
|
inputFrameDownsync.confirmedList = (1 << self.playerRichInfoDict.size) - 1;
|
||||||
const inputFrameDownsyncLocal = gopkgs.NewInputFrameDownsync(inputFrameDownsync.inputFrameId, inputFrameDownsync.inputList, inputFrameDownsync.confirmedList); // "battle.InputFrameDownsync" in "jsexport"
|
const inputFrameDownsyncLocal = gopkgs.NewInputFrameDownsync(inputFrameDownsync.inputFrameId, inputFrameDownsync.inputList, inputFrameDownsync.confirmedList); // "battle.InputFrameDownsync" in "jsexport"
|
||||||
|
for (let j in self.playerRichInfoArr) {
|
||||||
|
const jj = parseInt(j);
|
||||||
|
if (inputFrameDownsync.inputFrameId > self.lastIndividuallyConfirmedInputFrameId[jj]) {
|
||||||
|
self.lastIndividuallyConfirmedInputFrameId[jj] = inputFrameDownsync.inputFrameId;
|
||||||
|
self.lastIndividuallyConfirmedInputList[jj] = inputFrameDownsync.inputList[jj];
|
||||||
|
}
|
||||||
|
}
|
||||||
//console.log(`Confirmed inputFrameId=${inputFrameDownsync.inputFrameId}`);
|
//console.log(`Confirmed inputFrameId=${inputFrameDownsync.inputFrameId}`);
|
||||||
const [ret, oldStFrameId, oldEdFrameId] = self.recentInputCache.SetByFrameId(inputFrameDownsyncLocal, inputFrameDownsync.inputFrameId);
|
const [ret, oldStFrameId, oldEdFrameId] = self.recentInputCache.SetByFrameId(inputFrameDownsyncLocal, inputFrameDownsync.inputFrameId);
|
||||||
if (window.RING_BUFF_FAILED_TO_SET == ret) {
|
if (window.RING_BUFF_FAILED_TO_SET == ret) {
|
||||||
throw `Failed to dump input cache (maybe recentInputCache too small)! inputFrameDownsync.inputFrameId=${inputFrameDownsync.inputFrameId}, lastAllConfirmedInputFrameId=${self.lastAllConfirmedInputFrameId}; recentRenderCache=${self._stringifyRecentRenderCache(false)}, recentInputCache=${self._stringifyRecentInputCache(false)}`;
|
throw `Failed to dump input cache (maybe recentInputCache too small)! inputFrameDownsync.inputFrameId=${inputFrameDownsync.inputFrameId}, lastAllConfirmedInputFrameId=${self.lastAllConfirmedInputFrameId}; recentRenderCache=${self._stringifyRecentRenderCache(false)}, recentInputCache=${self._stringifyRecentInputCache(false)}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self._markConfirmationIfApplicable();
|
||||||
|
self._handleIncorrectlyRenderedPrediction(firstPredictedYetIncorrectInputFrameId, batch, false);
|
||||||
|
},
|
||||||
|
|
||||||
|
_handleIncorrectlyRenderedPrediction(firstPredictedYetIncorrectInputFrameId, batch, fromUDP) {
|
||||||
if (null == firstPredictedYetIncorrectInputFrameId) return;
|
if (null == firstPredictedYetIncorrectInputFrameId) return;
|
||||||
|
const self = this;
|
||||||
const renderFrameId1 = gopkgs.ConvertToFirstUsedRenderFrameId(firstPredictedYetIncorrectInputFrameId) - 1;
|
const renderFrameId1 = gopkgs.ConvertToFirstUsedRenderFrameId(firstPredictedYetIncorrectInputFrameId) - 1;
|
||||||
if (renderFrameId1 >= self.chaserRenderFrameId) return;
|
if (renderFrameId1 >= self.chaserRenderFrameId) return;
|
||||||
|
|
||||||
@@ -852,15 +902,21 @@ cc.Class({
|
|||||||
--------------------------------------------------------
|
--------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
// The actual rollback-and-chase would later be executed in update(dt).
|
// The actual rollback-and-chase would later be executed in update(dt).
|
||||||
self.networkDoctor.immediateRollbackFrames = (self.renderFrameId - renderFrameId1);
|
console.log(`Mismatched input detected, resetting chaserRenderFrameId: ${self.chaserRenderFrameId}->${renderFrameId1} by
|
||||||
console.log(`Mismatched input detected, resetting chaserRenderFrameId: ${self.chaserRenderFrameId}->${renderFrameId1} by firstPredictedYetIncorrectInputFrameId: ${firstPredictedYetIncorrectInputFrameId}
|
firstPredictedYetIncorrectInputFrameId: ${firstPredictedYetIncorrectInputFrameId}
|
||||||
lastAllConfirmedInputFrameId=${self.lastAllConfirmedInputFrameId}
|
lastAllConfirmedInputFrameId=${self.lastAllConfirmedInputFrameId}
|
||||||
recentInputCache=${self._stringifyRecentInputCache(false)}
|
recentInputCache=${self._stringifyRecentInputCache(false)}
|
||||||
batchInputFrameIdRange=[${batch[0].inputFrameId}, ${batch[batch.length - 1].inputFrameId}]`);
|
batchInputFrameIdRange=[${batch[0].inputFrameId}, ${batch[batch.length - 1].inputFrameId}]
|
||||||
|
fromUDP=${fromUDP}`);
|
||||||
self.chaserRenderFrameId = renderFrameId1;
|
self.chaserRenderFrameId = renderFrameId1;
|
||||||
|
let rollbackFrames = (self.renderFrameId - self.chaserRenderFrameId);
|
||||||
|
if (0 > rollbackFrames) {
|
||||||
|
rollbackFrames = 0;
|
||||||
|
}
|
||||||
|
self.networkDoctor.logRollbackFrames(rollbackFrames);
|
||||||
},
|
},
|
||||||
|
|
||||||
onPeerInputFrameUpsync(peerJoinIndex, batch /* []*pb.InputFrameDownsync */ ) {
|
onPeerInputFrameUpsync(peerJoinIndex, batch, fromUDP) {
|
||||||
// TODO: find some kind of synchronization mechanism against "getOrPrefabInputFrameUpsync"!
|
// TODO: find some kind of synchronization mechanism against "getOrPrefabInputFrameUpsync"!
|
||||||
// See `<proj-root>/ConcerningEdgeCases.md` for why this method exists.
|
// See `<proj-root>/ConcerningEdgeCases.md` for why this method exists.
|
||||||
if (null == batch) {
|
if (null == batch) {
|
||||||
@@ -870,33 +926,69 @@ batchInputFrameIdRange=[${batch[0].inputFrameId}, ${batch[batch.length - 1].inpu
|
|||||||
if (!self.recentInputCache) {
|
if (!self.recentInputCache) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ALL_BATTLE_STATES.IN_SETTLEMENT == self.battleState) {
|
if (ALL_BATTLE_STATES.IN_BATTLE != self.battleState) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.networkDoctor.logPeerInputFrameUpsync(batch[0].inputFrameId, batch[batch.length - 1].inputFrameId);
|
let effCnt = 0;
|
||||||
//console.log(`Received peer inputFrameUpsync batch w/ inputFrameId in [${batch[0].inputFrameId}, ${batch[batch.length - 1].inputFrameId}] for prediction assistance`);
|
//console.log(`Received peer inputFrameUpsync batch w/ inputFrameId in [${batch[0].inputFrameId}, ${batch[batch.length - 1].inputFrameId}] for prediction assistance`);
|
||||||
|
let firstPredictedYetIncorrectInputFrameId = null;
|
||||||
|
const renderedInputFrameIdUpper = gopkgs.ConvertToDelayedInputFrameId(self.renderFrameId);
|
||||||
for (let k in batch) {
|
for (let k in batch) {
|
||||||
const inputFrameDownsync = batch[k];
|
const inputFrame = batch[k]; // could be either "pb.InputFrameDownsync" or "pb.InputFrameUpsync", depending on "fromUDP"
|
||||||
const inputFrameDownsyncId = inputFrameDownsync.inputFrameId;
|
const inputFrameId = inputFrame.inputFrameId;
|
||||||
if (inputFrameDownsyncId <= self.lastAllConfirmedInputFrameId) {
|
const peerEncodedInput = (true == fromUDP ? inputFrame.encoded : inputFrame.inputList[peerJoinIndex - 1]);
|
||||||
|
if (false == self.allowRollbackOnPeerUpsync && inputFrameId <= renderedInputFrameIdUpper) {
|
||||||
|
// [WARNING] Avoid obfuscating already rendered history, even at "inputFrameId == renderedInputFrameIdUpper", due to the use of "INPUT_SCALE_FRAMES" some previous render frames might already be rendered with "inputFrameId"!
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
self.getOrPrefabInputFrameUpsync(inputFrameDownsyncId); // Make sure that inputFrame exists locally
|
if (inputFrameId <= self.lastAllConfirmedInputFrameId) {
|
||||||
const existingInputFrame = self.recentInputCache.GetByFrameId(inputFrameDownsyncId);
|
// [WARNING] Don't reject it by "inputFrameId <= self.lastIndividuallyConfirmedInputFrameId[peerJoinIndex-1]", the arrival of UDP packets might not reserve their sending order!
|
||||||
existingInputFrame.InputList[peerJoinIndex - 1] = inputFrameDownsync.inputList[peerJoinIndex - 1]; // No need to change "confirmedList", leave it to "onInputFrameDownsyncBatch" -- we're just helping prediction here
|
continue;
|
||||||
self.recentInputCache.SetByFrameId(existingInputFrame, inputFrameDownsyncId);
|
}
|
||||||
|
const peerJoinIndexMask = (1 << (peerJoinIndex - 1));
|
||||||
|
self.getOrPrefabInputFrameUpsync(inputFrameId, false); // Make sure that inputFrame exists locally
|
||||||
|
const existingInputFrame = self.recentInputCache.GetByFrameId(inputFrameId);
|
||||||
|
if (0 < (existingInputFrame.ConfirmedList & peerJoinIndexMask)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (inputFrameId > self.lastIndividuallyConfirmedInputFrameId[peerJoinIndex - 1]) {
|
||||||
|
self.lastIndividuallyConfirmedInputFrameId[peerJoinIndex - 1] = inputFrameId;
|
||||||
|
self.lastIndividuallyConfirmedInputList[peerJoinIndex - 1] = peerEncodedInput;
|
||||||
|
}
|
||||||
|
effCnt += 1;
|
||||||
|
// the returned "gopkgs.NewInputFrameDownsync.InputList" is immutable, thus we can only modify the values in "newInputList" and "newConfirmedList"!
|
||||||
|
let newInputList = existingInputFrame.InputList.slice();
|
||||||
|
newInputList[peerJoinIndex - 1] = peerEncodedInput;
|
||||||
|
let newConfirmedList = (existingInputFrame.ConfirmedList | peerJoinIndex);
|
||||||
|
const newInputFrameDownsyncLocal = gopkgs.NewInputFrameDownsync(inputFrameId, newInputList, newConfirmedList);
|
||||||
|
//console.log(`Updated encoded input of peerJoinIndex=${peerJoinIndex} to ${peerEncodedInput} for inputFrameId=${inputFrameId}/renderedInputFrameIdUpper=${renderedInputFrameIdUpper} from ${JSON.stringify(inputFrame)}; newInputFrameDownsyncLocal=${self.gopkgsInputFrameDownsyncStr(newInputFrameDownsyncLocal)}; existingInputFrame=${self.gopkgsInputFrameDownsyncStr(existingInputFrame)}`);
|
||||||
|
self.recentInputCache.SetByFrameId(newInputFrameDownsyncLocal, inputFrameId);
|
||||||
|
|
||||||
|
if (self.allowRollbackOnPeerUpsync) {
|
||||||
|
// Reaching here implies that "true == self.allowRollbackOnPeerUpsync".
|
||||||
|
// Shall we update the "chaserRenderFrameId" if the rendered history was wrong? It doesn't seem to impact eventual correctness if we allow the update of "chaserRenderFrameId" upon "inputFrameId <= renderedInputFrameIdUpper" here, however UDP upsync doesn't reserve order from a same sender and there might be multiple other senders, hence it might result in unnecessarily frequent chasing.
|
||||||
|
if (
|
||||||
|
null == firstPredictedYetIncorrectInputFrameId
|
||||||
|
&&
|
||||||
|
existingInputFrame.InputList[peerJoinIndex - 1] != peerEncodedInput
|
||||||
|
) {
|
||||||
|
firstPredictedYetIncorrectInputFrameId = inputFrameId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (0 < effCnt) {
|
||||||
|
//self._markConfirmationIfApplicable();
|
||||||
|
self.networkDoctor.logPeerInputFrameUpsync(batch[0].inputFrameId, batch[batch.length - 1].inputFrameId);
|
||||||
|
}
|
||||||
|
if (true == self.allowRollbackOnPeerUpsync) {
|
||||||
|
self._handleIncorrectlyRenderedPrediction(firstPredictedYetIncorrectInputFrameId, batch, fromUDP);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onPlayerAdded(rdf /* pb.RoomDownsyncFrame */ ) {
|
onPlayerAdded(rdf /* pb.RoomDownsyncFrame */ ) {
|
||||||
const self = this;
|
const self = this;
|
||||||
// Update the "finding player" GUI and show it if not previously present
|
self.showFindingPlayerGUI(rdf);
|
||||||
if (!self.findingPlayerNode.parent) {
|
|
||||||
self.showPopupInCanvas(self.findingPlayerNode);
|
|
||||||
}
|
|
||||||
let findingPlayerScriptIns = self.findingPlayerNode.getComponent("FindingPlayer");
|
|
||||||
findingPlayerScriptIns.updatePlayersInfo(rdf.playersArr);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onBattleStopped() {
|
onBattleStopped() {
|
||||||
@@ -904,8 +996,7 @@ batchInputFrameIdRange=[${batch[0].inputFrameId}, ${batch[batch.length - 1].inpu
|
|||||||
if (ALL_BATTLE_STATES.IN_BATTLE != self.battleState) {
|
if (ALL_BATTLE_STATES.IN_BATTLE != self.battleState) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self._stringifyRdfIdToActuallyUsedInput();
|
window.closeWSConnection(constants.RET_CODE.BATTLE_STOPPED, "");
|
||||||
window.closeWSConnection(constants.RET_CODE.BATTLE_STOPPED);
|
|
||||||
self.battleState = ALL_BATTLE_STATES.IN_SETTLEMENT;
|
self.battleState = ALL_BATTLE_STATES.IN_SETTLEMENT;
|
||||||
self.countdownNanos = null;
|
self.countdownNanos = null;
|
||||||
if (self.musicEffectManagerScriptIns) {
|
if (self.musicEffectManagerScriptIns) {
|
||||||
@@ -917,9 +1008,6 @@ batchInputFrameIdRange=[${batch[0].inputFrameId}, ${batch[batch.length - 1].inpu
|
|||||||
resultPanelScriptIns.showPlayerInfo(self.playerRichInfoDict);
|
resultPanelScriptIns.showPlayerInfo(self.playerRichInfoDict);
|
||||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
||||||
self.showPopupInCanvas(resultPanelNode);
|
self.showPopupInCanvas(resultPanelNode);
|
||||||
|
|
||||||
// Clear player info
|
|
||||||
self.playersInfoNode.getComponent("PlayersInfo").clearInfo();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
spawnPlayerNode(joinIndex, vx, vy, playerDownsyncInfo) {
|
spawnPlayerNode(joinIndex, vx, vy, playerDownsyncInfo) {
|
||||||
@@ -960,19 +1048,28 @@ batchInputFrameIdRange=[${batch[0].inputFrameId}, ${batch[batch.length - 1].inpu
|
|||||||
|
|
||||||
Kindly note that Significantly different network bandwidths or delay fluctuations would result in frequent [type#1 forceConfirmation] too, but CAUSE FROM DIFFERENT LOCAL "update(dt)" RATE SHOULD BE THE FIRST TO INVESTIGATE AND ELIMINATE -- because we have control on it, but no one has control on the internet.
|
Kindly note that Significantly different network bandwidths or delay fluctuations would result in frequent [type#1 forceConfirmation] too, but CAUSE FROM DIFFERENT LOCAL "update(dt)" RATE SHOULD BE THE FIRST TO INVESTIGATE AND ELIMINATE -- because we have control on it, but no one has control on the internet.
|
||||||
*/
|
*/
|
||||||
|
if (self.skipRenderFrameFlag) {
|
||||||
|
self.networkDoctor.logSkippedRenderFrameCnt();
|
||||||
|
self.skipRenderFrameFlag = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
let st = performance.now();
|
let st = performance.now();
|
||||||
|
if (cc.sys.isNative) {
|
||||||
|
DelayNoMore.UdpSession.pollUdpRecvRingBuff();
|
||||||
|
}
|
||||||
const noDelayInputFrameId = gopkgs.ConvertToNoDelayInputFrameId(self.renderFrameId);
|
const noDelayInputFrameId = gopkgs.ConvertToNoDelayInputFrameId(self.renderFrameId);
|
||||||
let prevSelfInput = null,
|
let prevSelfInput = null,
|
||||||
currSelfInput = null;
|
currSelfInput = null;
|
||||||
if (gopkgs.ShouldGenerateInputFrameUpsync(self.renderFrameId)) {
|
if (gopkgs.ShouldGenerateInputFrameUpsync(self.renderFrameId)) {
|
||||||
[prevSelfInput, currSelfInput] = self.getOrPrefabInputFrameUpsync(noDelayInputFrameId);
|
[prevSelfInput, currSelfInput] = self.getOrPrefabInputFrameUpsync(noDelayInputFrameId, true);
|
||||||
|
self.networkDoctor.logInputFrameIdFront(noDelayInputFrameId);
|
||||||
}
|
}
|
||||||
|
|
||||||
const delayedInputFrameId = gopkgs.ConvertToDelayedInputFrameId(self.renderFrameId);
|
const delayedInputFrameId = gopkgs.ConvertToDelayedInputFrameId(self.renderFrameId);
|
||||||
if (null == self.recentInputCache.GetByFrameId(delayedInputFrameId)) {
|
if (null == self.recentInputCache.GetByFrameId(delayedInputFrameId)) {
|
||||||
// Possible edge case after resync, kindly note that it's OK to prefab a "future inputFrame" here, because "sendInputFrameUpsyncBatch" would be capped by "noDelayInputFrameId from self.renderFrameId".
|
// Possible edge case after resync, kindly note that it's OK to prefab a "future inputFrame" here, because "sendInputFrameUpsyncBatch" would be capped by "noDelayInputFrameId from self.renderFrameId".
|
||||||
self.getOrPrefabInputFrameUpsync(delayedInputFrameId);
|
self.getOrPrefabInputFrameUpsync(delayedInputFrameId, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
let t0 = performance.now();
|
let t0 = performance.now();
|
||||||
@@ -996,6 +1093,12 @@ batchInputFrameIdRange=[${batch[0].inputFrameId}, ${batch[batch.length - 1].inpu
|
|||||||
|
|
||||||
// Inside the following "self.rollbackAndChase" actually ROLLS FORWARD w.r.t. the corresponding delayedInputFrame, REGARDLESS OF whether or not "self.chaserRenderFrameId == self.renderFrameId" now.
|
// Inside the following "self.rollbackAndChase" actually ROLLS FORWARD w.r.t. the corresponding delayedInputFrame, REGARDLESS OF whether or not "self.chaserRenderFrameId == self.renderFrameId" now.
|
||||||
const latestRdfResults = self.rollbackAndChase(self.renderFrameId, self.renderFrameId + 1, self.gopkgsCollisionSys, self.gopkgsCollisionSysMap, false);
|
const latestRdfResults = self.rollbackAndChase(self.renderFrameId, self.renderFrameId + 1, self.gopkgsCollisionSys, self.gopkgsCollisionSysMap, false);
|
||||||
|
|
||||||
|
let rollbackFrames = (self.renderFrameId - self.chaserRenderFrameId);
|
||||||
|
if (0 > rollbackFrames) {
|
||||||
|
rollbackFrames = 0;
|
||||||
|
}
|
||||||
|
self.networkDoctor.logRollbackFrames(rollbackFrames);
|
||||||
let prevRdf = latestRdfResults[0],
|
let prevRdf = latestRdfResults[0],
|
||||||
rdf = latestRdfResults[1];
|
rdf = latestRdfResults[1];
|
||||||
/*
|
/*
|
||||||
@@ -1012,20 +1115,20 @@ batchInputFrameIdRange=[${batch[0].inputFrameId}, ${batch[batch.length - 1].inpu
|
|||||||
console.warn(`Mismatched render frame@rdf.id=${rdf.Id} w/ inputFrameId=${delayedInputFrameId}:
|
console.warn(`Mismatched render frame@rdf.id=${rdf.Id} w/ inputFrameId=${delayedInputFrameId}:
|
||||||
rdf=${JSON.stringify(rdf)}
|
rdf=${JSON.stringify(rdf)}
|
||||||
othersForcedDownsyncRenderFrame=${JSON.stringify(othersForcedDownsyncRenderFrame)}`);
|
othersForcedDownsyncRenderFrame=${JSON.stringify(othersForcedDownsyncRenderFrame)}`);
|
||||||
// closeWSConnection(constants.RET_CODE.CLIENT_MISMATCHED_RENDER_FRAME, "");
|
|
||||||
// self.onManualRejoinRequired("[DEBUG] CLIENT_MISMATCHED_RENDER_FRAME");
|
|
||||||
rdf = othersForcedDownsyncRenderFrame;
|
rdf = othersForcedDownsyncRenderFrame;
|
||||||
self.othersForcedDownsyncRenderFrameDict.delete(rdf.Id);
|
self.othersForcedDownsyncRenderFrameDict.delete(rdf.Id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.applyRoomDownsyncFrameDynamics(rdf, prevRdf);
|
self.applyRoomDownsyncFrameDynamics(rdf, prevRdf);
|
||||||
self.showDebugBoundaries(rdf);
|
self.showDebugBoundaries(rdf);
|
||||||
if (self.showNetworkDoctorInfo) {
|
|
||||||
self.showNetworkDoctorLabels();
|
|
||||||
}
|
|
||||||
++self.renderFrameId; // [WARNING] It's important to increment the renderFrameId AFTER all the operations above!!!
|
++self.renderFrameId; // [WARNING] It's important to increment the renderFrameId AFTER all the operations above!!!
|
||||||
self.lastRenderFrameIdTriggeredAt = performance.now();
|
self.lastRenderFrameIdTriggeredAt = performance.now();
|
||||||
let t3 = performance.now();
|
let t3 = performance.now();
|
||||||
|
const [skipRenderFrameFlag, inputFrameIdFront, sendingFps, srvDownsyncFps, peerUpsyncFps, doctorRollbackFrames, skippedRenderFrameCnt] = self.networkDoctor.isTooFast(self);
|
||||||
|
self.skipRenderFrameFlag = skipRenderFrameFlag;
|
||||||
|
if (self.showNetworkDoctorInfo) {
|
||||||
|
self.showNetworkDoctorLabels(inputFrameIdFront, sendingFps, srvDownsyncFps, peerUpsyncFps, doctorRollbackFrames, skippedRenderFrameCnt);
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Error during Map.update", err);
|
console.error("Error during Map.update", err);
|
||||||
self.onBattleStopped(); // TODO: Popup to ask player to refresh browser
|
self.onBattleStopped(); // TODO: Popup to ask player to refresh browser
|
||||||
@@ -1049,6 +1152,7 @@ othersForcedDownsyncRenderFrame=${JSON.stringify(othersForcedDownsyncRenderFrame
|
|||||||
logout(byClick /* The case where this param is "true" will be triggered within `ConfirmLogout.js`.*/ , shouldRetainBoundRoomIdInBothVolatileAndPersistentStorage) {
|
logout(byClick /* The case where this param is "true" will be triggered within `ConfirmLogout.js`.*/ , shouldRetainBoundRoomIdInBothVolatileAndPersistentStorage) {
|
||||||
const self = this;
|
const self = this;
|
||||||
const localClearance = () => {
|
const localClearance = () => {
|
||||||
|
window.closeWSConnection(constants.RET_CODE.BATTLE_STOPPED, "");
|
||||||
window.clearLocalStorageAndBackToLoginScene(shouldRetainBoundRoomIdInBothVolatileAndPersistentStorage);
|
window.clearLocalStorageAndBackToLoginScene(shouldRetainBoundRoomIdInBothVolatileAndPersistentStorage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1097,11 +1201,11 @@ othersForcedDownsyncRenderFrame=${JSON.stringify(othersForcedDownsyncRenderFrame
|
|||||||
self.enableInputControls();
|
self.enableInputControls();
|
||||||
},
|
},
|
||||||
|
|
||||||
onGameRule1v1ModeClicked(evt, cb) {
|
onGameRule1v1ModeClicked(chosenSpeciesId) {
|
||||||
const self = this;
|
const self = this;
|
||||||
self.battleState = ALL_BATTLE_STATES.WAITING;
|
self.battleState = ALL_BATTLE_STATES.WAITING;
|
||||||
|
window.chosenSpeciesId = chosenSpeciesId; // TODO: Find a better way to pass it into "self.initAfterWSConnected"!
|
||||||
window.initPersistentSessionClient(self.initAfterWSConnected, null /* Deliberately NOT passing in any `expectedRoomId`. -- YFLu */ );
|
window.initPersistentSessionClient(self.initAfterWSConnected, null /* Deliberately NOT passing in any `expectedRoomId`. -- YFLu */ );
|
||||||
self.hideGameRuleNode();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
showPopupInCanvas(toShowNode) {
|
showPopupInCanvas(toShowNode) {
|
||||||
@@ -1113,23 +1217,30 @@ othersForcedDownsyncRenderFrame=${JSON.stringify(othersForcedDownsyncRenderFrame
|
|||||||
setLocalZOrder(toShowNode, 10);
|
setLocalZOrder(toShowNode, 10);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
showFindingPlayerGUI(rdf) {
|
||||||
|
const self = this;
|
||||||
|
// Update the "finding player" GUI and show it if not previously present
|
||||||
|
if (!self.findingPlayerNode.parent) {
|
||||||
|
self.showPopupInCanvas(self.findingPlayerNode);
|
||||||
|
}
|
||||||
|
if (null != rdf) {
|
||||||
|
const findingPlayerScriptIns = self.findingPlayerNode.getComponent("FindingPlayer");
|
||||||
|
findingPlayerScriptIns.updatePlayersInfo(rdf.playersArr);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
hideFindingPlayersGUI(rdf) {
|
hideFindingPlayersGUI(rdf) {
|
||||||
const self = this;
|
const self = this;
|
||||||
if (null == self.findingPlayerNode.parent) return;
|
// [WARNING] "cc.Node.removeChild" would trigger massive update of rendering nodes, thus a performance impact at the beginning of battle, avoid it by just moving the widget to infinitely far away!
|
||||||
self.findingPlayerNode.parent.removeChild(self.findingPlayerNode);
|
if (self.findingPlayerNode && self.findingPlayerNode.parent) {
|
||||||
|
self.findingPlayerNode.setPosition(cc.v2(Number.MAX_VALUE, Number.MAX_VALUE));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onBattleReadyToStart(rdf /* pb.RoomDownsyncFrame */ ) {
|
onBattleReadyToStart(rdf /* pb.RoomDownsyncFrame */ ) {
|
||||||
const self = this;
|
const self = this;
|
||||||
const players = rdf.playersArr;
|
const players = rdf.playersArr;
|
||||||
|
|
||||||
// Show the top status indicators for IN_BATTLE
|
|
||||||
if (self.playersInfoNode) {
|
|
||||||
const playersInfoScriptIns = self.playersInfoNode.getComponent("PlayersInfo");
|
|
||||||
for (let i in players) {
|
|
||||||
playersInfoScriptIns.updateData(players[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
console.log("Calling `onBattleReadyToStart` with:", players);
|
console.log("Calling `onBattleReadyToStart` with:", players);
|
||||||
if (self.findingPlayerNode) {
|
if (self.findingPlayerNode) {
|
||||||
const findingPlayerScriptIns = self.findingPlayerNode.getComponent("FindingPlayer");
|
const findingPlayerScriptIns = self.findingPlayerNode.getComponent("FindingPlayer");
|
||||||
@@ -1160,6 +1271,7 @@ othersForcedDownsyncRenderFrame=${JSON.stringify(othersForcedDownsyncRenderFrame
|
|||||||
playerRichInfo.node.setPosition(wx, wy);
|
playerRichInfo.node.setPosition(wx, wy);
|
||||||
playerRichInfo.scriptIns.updateSpeed(currPlayerDownsync.Speed);
|
playerRichInfo.scriptIns.updateSpeed(currPlayerDownsync.Speed);
|
||||||
playerRichInfo.scriptIns.updateCharacterAnim(currPlayerDownsync, prevRdfPlayer, false, chConfig);
|
playerRichInfo.scriptIns.updateCharacterAnim(currPlayerDownsync, prevRdfPlayer, false, chConfig);
|
||||||
|
playerRichInfo.scriptIns.hpBar.progress = (currPlayerDownsync.Hp * 1.0) / currPlayerDownsync.MaxHp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move all to infinitely far away first
|
// Move all to infinitely far away first
|
||||||
@@ -1170,7 +1282,7 @@ othersForcedDownsyncRenderFrame=${JSON.stringify(othersForcedDownsyncRenderFrame
|
|||||||
}
|
}
|
||||||
for (let k in rdf.MeleeBullets) {
|
for (let k in rdf.MeleeBullets) {
|
||||||
const meleeBullet = rdf.MeleeBullets[k];
|
const meleeBullet = rdf.MeleeBullets[k];
|
||||||
const isExploding = (window.BULLET_STATE.Exploding == meleeBullet.BlState);
|
const isExploding = (window.BULLET_STATE.Exploding == meleeBullet.BlState && meleeBullet.FramesInBlState < meleeBullet.Bullet.ExplosionFrames);
|
||||||
if (isExploding) {
|
if (isExploding) {
|
||||||
let pqNode = self.cachedFireballs.popAny(meleeBullet.BattleAttr.BulletLocalId);
|
let pqNode = self.cachedFireballs.popAny(meleeBullet.BattleAttr.BulletLocalId);
|
||||||
let speciesName = `MeleeExplosion`;
|
let speciesName = `MeleeExplosion`;
|
||||||
@@ -1251,24 +1363,6 @@ othersForcedDownsyncRenderFrame=${JSON.stringify(othersForcedDownsyncRenderFrame
|
|||||||
}
|
}
|
||||||
const j = gopkgs.ConvertToDelayedInputFrameId(i);
|
const j = gopkgs.ConvertToDelayedInputFrameId(i);
|
||||||
const delayedInputFrame = self.recentInputCache.GetByFrameId(j);
|
const delayedInputFrame = self.recentInputCache.GetByFrameId(j);
|
||||||
/*
|
|
||||||
const prevJ = gopkgs.ConvertToDelayedInputFrameId(i - 1);
|
|
||||||
const prevDelayedInputFrame = self.recentInputCache.GetByFrameId(prevJ);
|
|
||||||
const prevBtnALevel = (null == prevDelayedInputFrame ? 0 : ((prevDelayedInputFrame.InputList[self.selfPlayerInfo.JoinIndex - 1] >> 4) & 1));
|
|
||||||
const btnALevel = ((delayedInputFrame.InputList[self.selfPlayerInfo.JoinIndex - 1] >> 4) & 1);
|
|
||||||
if (
|
|
||||||
ATK_CHARACTER_STATE.Atk1[0] == currRdf.PlayersArr[self.selfPlayerInfo.JoinIndex - 1].CharacterState
|
|
||||||
||
|
|
||||||
ATK_CHARACTER_STATE.Atk2[0] == currRdf.PlayersArr[self.selfPlayerInfo.JoinIndex - 1].CharacterState
|
|
||||||
) {
|
|
||||||
console.log(`rdf.Id=${i}, (btnALevel,j)=(${btnALevel},${j}), (prevBtnALevel,prevJ) is (${prevBtnALevel},${prevJ}), in cancellable atk!`);
|
|
||||||
}
|
|
||||||
if (btnALevel > 0) {
|
|
||||||
if (btnALevel > prevBtnALevel) {
|
|
||||||
console.log(`rdf.Id=${i}, rising edge of btnA triggered`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (self.frameDataLoggingEnabled) {
|
if (self.frameDataLoggingEnabled) {
|
||||||
const actuallyUsedInputClone = delayedInputFrame.InputList.slice();
|
const actuallyUsedInputClone = delayedInputFrame.InputList.slice();
|
||||||
@@ -1314,7 +1408,7 @@ othersForcedDownsyncRenderFrame=${JSON.stringify(othersForcedDownsyncRenderFrame
|
|||||||
|
|
||||||
const selfPlayerId = self.selfPlayerInfo.Id;
|
const selfPlayerId = self.selfPlayerInfo.Id;
|
||||||
if (selfPlayerId == playerId) {
|
if (selfPlayerId == playerId) {
|
||||||
self.selfPlayerInfo.JoinIndex = immediatePlayerInfo.JoinIndex;
|
self.selfPlayerInfo.JoinIndex = immediatePlayerInfo.JoinIndex; // Update here in case of any change during WAITING phase
|
||||||
nodeAndScriptIns[1].showArrowTipNode();
|
nodeAndScriptIns[1].showArrowTipNode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1391,6 +1485,21 @@ othersForcedDownsyncRenderFrame=${JSON.stringify(othersForcedDownsyncRenderFrame
|
|||||||
return s.join(',');
|
return s.join(',');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
gopkgsInputFrameDownsyncStr(inputFrameDownsync) {
|
||||||
|
if (null == inputFrameDownsync) return "{}";
|
||||||
|
const self = this;
|
||||||
|
let s = [];
|
||||||
|
s.push(`InputFrameId:${inputFrameDownsync.InputFrameId}`);
|
||||||
|
let ss = [];
|
||||||
|
for (let k = 0; k < window.boundRoomCapacity; ++k) {
|
||||||
|
ss.push(`"${inputFrameDownsync.InputList[k]}"`);
|
||||||
|
}
|
||||||
|
s.push(`InputList:[${ss.join(',')}]`);
|
||||||
|
s.push(`ConfirmedList:${inputFrameDownsync.ConfirmedList}`);
|
||||||
|
|
||||||
|
return `{${s.join(',')}}`;
|
||||||
|
},
|
||||||
|
|
||||||
_stringifyRdfIdToActuallyUsedInput() {
|
_stringifyRdfIdToActuallyUsedInput() {
|
||||||
const self = this;
|
const self = this;
|
||||||
let s = [];
|
let s = [];
|
||||||
@@ -1518,11 +1627,45 @@ actuallyUsedinputList:{${self.inputFrameDownsyncStr(actuallyUsedInputClone)}}`);
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
showNetworkDoctorLabels() {
|
showNetworkDoctorLabels(inputFrameIdFront, sendingFps, srvDownsyncFps, peerUpsyncFps, rollbackFrames, skippedRenderFrameCnt) {
|
||||||
const self = this;
|
const self = this;
|
||||||
self.sendingQLabel.string = self.networkDoctor.statSending();
|
if (self.inputFrameFrontLabel) {
|
||||||
self.inputFrameDownsyncQLabel.string = self.networkDoctor.statInputFrameDownsync();
|
self.inputFrameFrontLabel.string = `inputFrameId front: ${inputFrameIdFront}`;
|
||||||
self.peerInputFrameUpsyncQLabel.string = self.networkDoctor.statPeerInputFrameUpsync();
|
}
|
||||||
self.rollbackFramesLabel.string = self.networkDoctor.statRollbackFrames();
|
if (self.sendingQLabel) {
|
||||||
|
self.sendingQLabel.string = `fps sending: ${sendingFps}`;
|
||||||
|
if (sendingFps < self.networkDoctor.inputRateThreshold) {
|
||||||
|
self.sendingQLabel.node.color = cc.Color.RED;
|
||||||
|
} else {
|
||||||
|
self.sendingQLabel.node.color = cc.Color.WHITE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (self.inputFrameDownsyncQLabel) {
|
||||||
|
self.inputFrameDownsyncQLabel.string = `fps srv-downsync: ${srvDownsyncFps}`;
|
||||||
|
if (srvDownsyncFps < self.networkDoctor.inputRateThreshold) {
|
||||||
|
self.inputFrameDownsyncQLabel.node.color = cc.Color.RED;
|
||||||
|
} else {
|
||||||
|
self.inputFrameDownsyncQLabel.node.color = cc.Color.WHITE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (self.peerInputFrameUpsyncQLabel) {
|
||||||
|
self.peerInputFrameUpsyncQLabel.string = `fps peer-upsync: ${peerUpsyncFps}`;
|
||||||
|
if (peerUpsyncFps > self.networkDoctor.peerUpsyncFps) {
|
||||||
|
self.peerInputFrameUpsyncQLabel.node.color = cc.Color.RED;
|
||||||
|
} else {
|
||||||
|
self.peerInputFrameUpsyncQLabel.node.color = cc.Color.WHITE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (self.rollbackFramesLabel) {
|
||||||
|
self.rollbackFramesLabel.string = `rollbackFrames: ${rollbackFrames}`
|
||||||
|
if (rollbackFrames > self.networkDoctor.rollbackFramesThreshold) {
|
||||||
|
self.rollbackFramesLabel.node.color = cc.Color.RED;
|
||||||
|
} else {
|
||||||
|
self.rollbackFramesLabel.node.color = cc.Color.WHITE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (self.skippedRenderFrameCntLabel) {
|
||||||
|
self.skippedRenderFrameCntLabel.string = `frames skipped: ${skippedRenderFrameCnt}`
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@@ -5,11 +5,21 @@ 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);
|
||||||
this.peerInputFrameUpsyncCnt = 0;
|
this.peerInputFrameUpsyncCnt = 0;
|
||||||
this.immediateRollbackFrames = 0;
|
this.immediateRollbackFrames = 0;
|
||||||
|
this.skippedRenderFrameCnt = 0;
|
||||||
|
|
||||||
|
this.inputRateThreshold = gopkgs.ConvertToNoDelayInputFrameId(60);
|
||||||
|
this.peerUpsyncThreshold = 8;
|
||||||
|
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) {
|
||||||
@@ -40,35 +50,67 @@ NetworkDoctor.prototype.logPeerInputFrameUpsync = function(stFrameId, edFrameId)
|
|||||||
this.peerInputFrameUpsyncCnt += (edFrameId - stFrameId + 1);
|
this.peerInputFrameUpsyncCnt += (edFrameId - stFrameId + 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
NetworkDoctor.prototype.statSending = function() {
|
NetworkDoctor.prototype.logRollbackFrames = function(x) {
|
||||||
if (1 >= this.sendingQ.cnt) return `0 fps sending`;
|
this.immediateRollbackFrames = x;
|
||||||
const st = this.sendingQ.getByFrameId(this.sendingQ.stFrameId);
|
|
||||||
const ed = this.sendingQ.getByFrameId(this.sendingQ.edFrameId - 1);
|
|
||||||
const elapsedMillis = ed.t - st.t;
|
|
||||||
const fps = Math.round((ed.j - st.i) * 1000 / elapsedMillis);
|
|
||||||
return `${fps} fps sending`;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
NetworkDoctor.prototype.statInputFrameDownsync = function() {
|
NetworkDoctor.prototype.stats = function() {
|
||||||
if (1 >= this.inputFrameDownsyncQ.cnt) return `0 fps srv downsync`;
|
let inputFrameIdFront = this.inputFrameIdFront,
|
||||||
const st = this.inputFrameDownsyncQ.getByFrameId(this.inputFrameDownsyncQ.stFrameId);
|
sendingFps = 0,
|
||||||
const ed = this.inputFrameDownsyncQ.getByFrameId(this.inputFrameDownsyncQ.edFrameId - 1);
|
srvDownsyncFps = 0,
|
||||||
const elapsedMillis = ed.t - st.t;
|
peerUpsyncFps = 0,
|
||||||
const fps = Math.round((ed.j - st.i) * 1000 / elapsedMillis);
|
rollbackFrames = this.immediateRollbackFrames;
|
||||||
return `${fps} fps srv downsync`;
|
if (1 < this.sendingQ.cnt) {
|
||||||
|
const st = this.sendingQ.getByFrameId(this.sendingQ.stFrameId);
|
||||||
|
const ed = this.sendingQ.getByFrameId(this.sendingQ.edFrameId - 1);
|
||||||
|
const elapsedMillis = ed.t - st.t;
|
||||||
|
sendingFps = Math.round((ed.j - st.i) * 1000 / elapsedMillis);
|
||||||
|
}
|
||||||
|
if (1 < this.inputFrameDownsyncQ.cnt) {
|
||||||
|
const st = this.inputFrameDownsyncQ.getByFrameId(this.inputFrameDownsyncQ.stFrameId);
|
||||||
|
const ed = this.inputFrameDownsyncQ.getByFrameId(this.inputFrameDownsyncQ.edFrameId - 1);
|
||||||
|
const elapsedMillis = ed.t - st.t;
|
||||||
|
srvDownsyncFps = Math.round((ed.j - st.i) * 1000 / elapsedMillis);
|
||||||
|
}
|
||||||
|
if (1 < this.peerInputFrameUpsyncQ.cnt) {
|
||||||
|
const st = this.peerInputFrameUpsyncQ.getByFrameId(this.peerInputFrameUpsyncQ.stFrameId);
|
||||||
|
const ed = this.peerInputFrameUpsyncQ.getByFrameId(this.peerInputFrameUpsyncQ.edFrameId - 1);
|
||||||
|
const elapsedMillis = ed.t - st.t;
|
||||||
|
peerUpsyncFps = Math.round(this.peerInputFrameUpsyncCnt * 1000 / elapsedMillis);
|
||||||
|
}
|
||||||
|
return [inputFrameIdFront, sendingFps, srvDownsyncFps, peerUpsyncFps, rollbackFrames, this.skippedRenderFrameCnt];
|
||||||
};
|
};
|
||||||
|
|
||||||
NetworkDoctor.prototype.statPeerInputFrameUpsync = function() {
|
NetworkDoctor.prototype.logSkippedRenderFrameCnt = function() {
|
||||||
if (1 >= this.peerInputFrameUpsyncQ.cnt) return `0 fps peer upsync`;
|
this.skippedRenderFrameCnt += 1;
|
||||||
const st = this.peerInputFrameUpsyncQ.getByFrameId(this.peerInputFrameUpsyncQ.stFrameId);
|
}
|
||||||
const ed = this.peerInputFrameUpsyncQ.getByFrameId(this.peerInputFrameUpsyncQ.edFrameId - 1);
|
|
||||||
const elapsedMillis = ed.t - st.t;
|
|
||||||
const fps = Math.round(this.peerInputFrameUpsyncCnt * 1000 / elapsedMillis);
|
|
||||||
return `${fps} fps peer upsync`;
|
|
||||||
};
|
|
||||||
|
|
||||||
NetworkDoctor.prototype.statRollbackFrames = function() {
|
NetworkDoctor.prototype.isTooFast = function(mapIns) {
|
||||||
return `${this.immediateRollbackFrames} rollback frames`;
|
const [inputFrameIdFront, sendingFps, srvDownsyncFps, peerUpsyncFps, rollbackFrames, skippedRenderFrameCnt] = this.stats();
|
||||||
|
if (sendingFps >= this.inputRateThreshold + 3) {
|
||||||
|
// Don't send too fast
|
||||||
|
console.log(`Sending too fast, sendingFps=${sendingFps}`);
|
||||||
|
return [true, inputFrameIdFront, sendingFps, srvDownsyncFps, peerUpsyncFps, rollbackFrames, skippedRenderFrameCnt];
|
||||||
|
} else {
|
||||||
|
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".
|
||||||
|
const recvFpsNormal = (srvDownsyncFps >= this.inputRateThreshold || peerUpsyncFps >= this.inputRateThreshold * (window.boundRoomCapacity - 1));
|
||||||
|
if (sendingFpsNormal && recvFpsNormal) {
|
||||||
|
let selfInputFrameIdFront = gopkgs.ConvertToNoDelayInputFrameId(mapIns.renderFrameId);
|
||||||
|
let minInputFrameIdFront = Number.MAX_VALUE;
|
||||||
|
for (let k = 0; k < window.boundRoomCapacity; ++k) {
|
||||||
|
if (k + 1 == mapIns.selfPlayerInfo.JoinIndex) continue;
|
||||||
|
if (mapIns.lastIndividuallyConfirmedInputFrameId[k] >= minInputFrameIdFront) continue;
|
||||||
|
minInputFrameIdFront = mapIns.lastIndividuallyConfirmedInputFrameId[k];
|
||||||
|
}
|
||||||
|
if ((selfInputFrameIdFront > minInputFrameIdFront) && ((selfInputFrameIdFront - minInputFrameIdFront) > (mapIns.inputFrameUpsyncDelayTolerance + 1))) {
|
||||||
|
// first comparison condition is to avoid numeric overflow
|
||||||
|
console.log(`Game logic ticking too fast, selfInputFrameIdFront=${selfInputFrameIdFront}, minInputFrameIdFront=${minInputFrameIdFront}, inputFrameUpsyncDelayTolerance=${mapIns.inputFrameUpsyncDelayTolerance}`);
|
||||||
|
return [true, inputFrameIdFront, sendingFps, srvDownsyncFps, peerUpsyncFps, rollbackFrames, skippedRenderFrameCnt];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [false, inputFrameIdFront, sendingFps, srvDownsyncFps, peerUpsyncFps, rollbackFrames, skippedRenderFrameCnt];
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = NetworkDoctor;
|
module.exports = NetworkDoctor;
|
||||||
|
@@ -98,7 +98,7 @@ cc.Class({
|
|||||||
const p2Vpos = gopkgs.WorldToVirtualGridPos(boundaryObjs.playerStartingPositions[1].x, boundaryObjs.playerStartingPositions[1].y);
|
const p2Vpos = gopkgs.WorldToVirtualGridPos(boundaryObjs.playerStartingPositions[1].x, boundaryObjs.playerStartingPositions[1].y);
|
||||||
const colliderRadiusV = gopkgs.WorldToVirtualGridPos(12.0, 0);
|
const colliderRadiusV = gopkgs.WorldToVirtualGridPos(12.0, 0);
|
||||||
|
|
||||||
const speciesIdList = [4096, 1];
|
const speciesIdList = [4096, 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,6 +109,8 @@ cc.Class({
|
|||||||
joinIndex: 1,
|
joinIndex: 1,
|
||||||
virtualGridX: p1Vpos[0],
|
virtualGridX: p1Vpos[0],
|
||||||
virtualGridY: p1Vpos[1],
|
virtualGridY: p1Vpos[1],
|
||||||
|
revivalVirtualGridX: p1Vpos[0],
|
||||||
|
revivalVirtualGridY: p1Vpos[1],
|
||||||
speed: chConfigsOrderedByJoinIndex[0].Speed,
|
speed: chConfigsOrderedByJoinIndex[0].Speed,
|
||||||
colliderRadius: colliderRadiusV[0],
|
colliderRadius: colliderRadiusV[0],
|
||||||
characterState: window.ATK_CHARACTER_STATE.InAirIdle1NoJump[0],
|
characterState: window.ATK_CHARACTER_STATE.InAirIdle1NoJump[0],
|
||||||
@@ -119,12 +121,16 @@ 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],
|
||||||
|
revivalVirtualGridX: p2Vpos[0],
|
||||||
|
revivalVirtualGridY: p2Vpos[1],
|
||||||
speed: chConfigsOrderedByJoinIndex[1].Speed,
|
speed: chConfigsOrderedByJoinIndex[1].Speed,
|
||||||
colliderRadius: colliderRadiusV[0],
|
colliderRadius: colliderRadiusV[0],
|
||||||
characterState: window.ATK_CHARACTER_STATE.InAirIdle1NoJump[0],
|
characterState: window.ATK_CHARACTER_STATE.InAirIdle1NoJump[0],
|
||||||
@@ -135,6 +141,8 @@ cc.Class({
|
|||||||
velY: 0,
|
velY: 0,
|
||||||
inAir: true,
|
inAir: true,
|
||||||
onWall: false,
|
onWall: false,
|
||||||
|
hp: 100,
|
||||||
|
maxHp: 100,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
speciesIdList: speciesIdList,
|
speciesIdList: speciesIdList,
|
||||||
@@ -144,6 +152,35 @@ cc.Class({
|
|||||||
Id: 10,
|
Id: 10,
|
||||||
JoinIndex: 1,
|
JoinIndex: 1,
|
||||||
};
|
};
|
||||||
|
if (cc.sys.isNative) {
|
||||||
|
window.onUdpMessage = (args) => {
|
||||||
|
const len = args.length;
|
||||||
|
const ui8Arr = new Uint8Array(len);
|
||||||
|
for (let i = 0; i < len; i++) {
|
||||||
|
ui8Arr[i] = args.charCodeAt(i);
|
||||||
|
}
|
||||||
|
cc.log(`#1 Js called back by CPP: onUdpMessage: args=${args}, typeof(args)=${typeof (args)}, argslen=${args.length}, ui8Arr=${ui8Arr}`);
|
||||||
|
const echoed = window.pb.protos.HolePunchUpsync.decode(ui8Arr);
|
||||||
|
cc.log(`#2 Js called back by CPP: onUdpMessage: ${JSON.stringify(echoed)}`);
|
||||||
|
};
|
||||||
|
const res1 = DelayNoMore.UdpSession.openUdpSession(8888 + self.selfPlayerInfo.JoinIndex);
|
||||||
|
const holePunchData = window.pb.protos.HolePunchUpsync.encode({
|
||||||
|
boundRoomId: 22,
|
||||||
|
intAuthToken: "foobar",
|
||||||
|
authKey: Math.floor(Math.random() * 65535),
|
||||||
|
}).finish()
|
||||||
|
//const res2 = DelayNoMore.UdpSession.punchToServer("127.0.0.1", 3000, holePunchData, 19999, holePunchData);
|
||||||
|
const res3 = DelayNoMore.UdpSession.upsertPeerUdpAddr([window.pb.protos.PeerUdpAddr.create({
|
||||||
|
ip: "192.168.31.194",
|
||||||
|
port: 6789,
|
||||||
|
authKey: 123456,
|
||||||
|
}), window.pb.protos.PeerUdpAddr.create({
|
||||||
|
ip: "192.168.1.101",
|
||||||
|
port: 8771,
|
||||||
|
authKey: 654321,
|
||||||
|
})], 2, self.selfPlayerInfo.JoinIndex);
|
||||||
|
//const res4 = DelayNoMore.UdpSession.closeUdpSession();
|
||||||
|
}
|
||||||
self.onRoomDownsyncFrame(startRdf);
|
self.onRoomDownsyncFrame(startRdf);
|
||||||
|
|
||||||
self.battleState = ALL_BATTLE_STATES.IN_BATTLE;
|
self.battleState = ALL_BATTLE_STATES.IN_BATTLE;
|
||||||
@@ -154,19 +191,13 @@ cc.Class({
|
|||||||
update(dt) {
|
update(dt) {
|
||||||
const self = this;
|
const self = this;
|
||||||
if (ALL_BATTLE_STATES.IN_BATTLE == self.battleState) {
|
if (ALL_BATTLE_STATES.IN_BATTLE == self.battleState) {
|
||||||
const elapsedMillisSinceLastFrameIdTriggered = performance.now() - self.lastRenderFrameIdTriggeredAt;
|
|
||||||
if (elapsedMillisSinceLastFrameIdTriggered < self.tooFastDtIntervalMillis) {
|
|
||||||
// [WARNING] We should avoid a frontend ticking too fast to prevent cheating, as well as ticking too slow to cause a "resync avalanche" that impacts user experience!
|
|
||||||
// console.debug("Avoiding too fast frame@renderFrameId=", self.renderFrameId, ": elapsedMillisSinceLastFrameIdTriggered=", elapsedMillisSinceLastFrameIdTriggered);
|
|
||||||
//return;
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
let st = performance.now();
|
let st = performance.now();
|
||||||
let prevSelfInput = null,
|
let prevSelfInput = null,
|
||||||
currSelfInput = null;
|
currSelfInput = null;
|
||||||
const noDelayInputFrameId = gopkgs.ConvertToNoDelayInputFrameId(self.renderFrameId); // It's important that "inputDelayFrames == 0" here
|
const noDelayInputFrameId = gopkgs.ConvertToNoDelayInputFrameId(self.renderFrameId); // It's important that "inputDelayFrames == 0" here
|
||||||
if (gopkgs.ShouldGenerateInputFrameUpsync(self.renderFrameId)) {
|
if (gopkgs.ShouldGenerateInputFrameUpsync(self.renderFrameId)) {
|
||||||
const prevAndCurrInputs = self.getOrPrefabInputFrameUpsync(noDelayInputFrameId);
|
const prevAndCurrInputs = self.getOrPrefabInputFrameUpsync(noDelayInputFrameId, true);
|
||||||
prevSelfInput = prevAndCurrInputs[0];
|
prevSelfInput = prevAndCurrInputs[0];
|
||||||
currSelfInput = prevAndCurrInputs[1];
|
currSelfInput = prevAndCurrInputs[1];
|
||||||
}
|
}
|
||||||
|
@@ -12,6 +12,7 @@ window.DOWNSYNC_MSG_ACT_INPUT_BATCH = 2;
|
|||||||
window.DOWNSYNC_MSG_ACT_BATTLE_STOPPED = 3;
|
window.DOWNSYNC_MSG_ACT_BATTLE_STOPPED = 3;
|
||||||
window.DOWNSYNC_MSG_ACT_FORCED_RESYNC = 4;
|
window.DOWNSYNC_MSG_ACT_FORCED_RESYNC = 4;
|
||||||
window.DOWNSYNC_MSG_ACT_PEER_INPUT_BATCH = 5;
|
window.DOWNSYNC_MSG_ACT_PEER_INPUT_BATCH = 5;
|
||||||
|
window.DOWNSYNC_MSG_ACT_PEER_UDP_ADDR = 6;
|
||||||
|
|
||||||
window.sendSafely = function(msgStr) {
|
window.sendSafely = function(msgStr) {
|
||||||
/**
|
/**
|
||||||
@@ -33,7 +34,7 @@ window.closeWSConnection = function(code, reason) {
|
|||||||
console.log(`"window.clientSession" is already closed or destroyed.`);
|
console.log(`"window.clientSession" is already closed or destroyed.`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log(`Closing "window.clientSession" from the client-side.`);
|
console.log(`Closing "window.clientSession" from the client-side with code=${code}.`);
|
||||||
window.clientSession.close(code, reason);
|
window.clientSession.close(code, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,12 +44,35 @@ window.getBoundRoomIdFromPersistentStorage = function() {
|
|||||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return cc.sys.localStorage.getItem("boundRoomId");
|
const boundRoomIdStr = cc.sys.localStorage.getItem("boundRoomId");
|
||||||
|
return (null == boundRoomIdStr ? null : parseInt(boundRoomIdStr));
|
||||||
|
};
|
||||||
|
|
||||||
|
window.getBoundRoomCapacityFromPersistentStorage = function() {
|
||||||
|
const boundRoomIdExpiresAt = parseInt(cc.sys.localStorage.getItem("boundRoomIdExpiresAt"));
|
||||||
|
if (!boundRoomIdExpiresAt || Date.now() >= boundRoomIdExpiresAt) {
|
||||||
|
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const boundRoomCapacityStr = cc.sys.localStorage.getItem("boundRoomCapacity");
|
||||||
|
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("chosenSpeciesId");
|
||||||
cc.sys.localStorage.removeItem("boundRoomIdExpiresAt");
|
cc.sys.localStorage.removeItem("boundRoomIdExpiresAt");
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -57,18 +81,52 @@ window.clearSelfPlayer = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
window.boundRoomId = getBoundRoomIdFromPersistentStorage();
|
window.boundRoomId = getBoundRoomIdFromPersistentStorage();
|
||||||
|
window.boundRoomCapacity = getBoundRoomCapacityFromPersistentStorage();
|
||||||
window.handleHbRequirements = function(resp) {
|
window.handleHbRequirements = function(resp) {
|
||||||
|
console.log(`Handle hb requirements #1`);
|
||||||
if (constants.RET_CODE.OK != resp.ret) return;
|
if (constants.RET_CODE.OK != resp.ret) return;
|
||||||
if (null == window.boundRoomId) {
|
// 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.Id = window.mapIns.selfPlayerInfo.playerId;
|
||||||
|
window.mapIns.selfPlayerInfo.JoinIndex = resp.peerJoinIndex;
|
||||||
|
console.log(`Handle hb requirements #2`);
|
||||||
|
if (null == window.boundRoomId || null == window.boundRoomCapacity) {
|
||||||
window.boundRoomId = resp.bciFrame.boundRoomId;
|
window.boundRoomId = resp.bciFrame.boundRoomId;
|
||||||
|
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('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`);
|
||||||
if (window.handleBattleColliderInfo) {
|
if (window.handleBattleColliderInfo) {
|
||||||
window.initSecondarySession(null, window.boundRoomId);
|
|
||||||
window.handleBattleColliderInfo(resp.bciFrame);
|
window.handleBattleColliderInfo(resp.bciFrame);
|
||||||
}
|
}
|
||||||
|
console.log(`Handle hb requirements #4`);
|
||||||
|
|
||||||
|
if (!cc.sys.isNative) {
|
||||||
|
console.log(`Handle hb requirements #5, web`);
|
||||||
|
window.initSecondarySession(null, window.boundRoomId);
|
||||||
|
} else {
|
||||||
|
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);
|
||||||
|
window.mapIns.selfPlayerInfo.udpTunnelAuthKey = resp.bciFrame.battleUdpTunnel.authKey;
|
||||||
|
const intAuthToken = window.mapIns.selfPlayerInfo.intAuthToken;
|
||||||
|
const authKey = Math.floor(Math.random() * 65535);
|
||||||
|
window.mapIns.selfPlayerInfo.authKey = authKey;
|
||||||
|
const holePunchData = window.pb.protos.HolePunchUpsync.encode({
|
||||||
|
boundRoomId: window.boundRoomId,
|
||||||
|
intAuthToken: intAuthToken,
|
||||||
|
authKey: authKey,
|
||||||
|
}).finish();
|
||||||
|
const udpTunnelHolePunchData = window.pb.protos.WsReq.encode({
|
||||||
|
msgId: Date.now(),
|
||||||
|
playerId: window.mapIns.selfPlayerInfo.Id,
|
||||||
|
act: window.UPSYNC_MSG_ACT_PLAYER_CMD,
|
||||||
|
authKey: resp.bciFrame.battleUdpTunnel.authKey,
|
||||||
|
}).finish();
|
||||||
|
const res2 = DelayNoMore.UdpSession.punchToServer(backendAddress.HOST, 3000, holePunchData, resp.bciFrame.battleUdpTunnel.port, udpTunnelHolePunchData);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function _uint8ToBase64(uint8Arr) {
|
function _uint8ToBase64(uint8Arr) {
|
||||||
@@ -126,12 +184,20 @@ window.initPersistentSessionClient = function(onopenCb, expectedRoomId) {
|
|||||||
urlToConnect = urlToConnect + "&expectedRoomId=" + expectedRoomId;
|
urlToConnect = urlToConnect + "&expectedRoomId=" + expectedRoomId;
|
||||||
} else {
|
} else {
|
||||||
window.boundRoomId = getBoundRoomIdFromPersistentStorage();
|
window.boundRoomId = getBoundRoomIdFromPersistentStorage();
|
||||||
|
window.boundRoomCapacity = getBoundRoomCapacityFromPersistentStorage();
|
||||||
if (null != window.boundRoomId) {
|
if (null != window.boundRoomId) {
|
||||||
console.log("initPersistentSessionClient with boundRoomId == " + boundRoomId);
|
console.log("initPersistentSessionClient with boundRoomId == " + boundRoomId);
|
||||||
urlToConnect = urlToConnect + "&boundRoomId=" + window.boundRoomId;
|
urlToConnect = urlToConnect + "&boundRoomId=" + window.boundRoomId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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"
|
||||||
|
|
||||||
@@ -176,6 +242,19 @@ window.initPersistentSessionClient = function(onopenCb, expectedRoomId) {
|
|||||||
}
|
}
|
||||||
mapIns.onRoomDownsyncFrame(resp.rdf, resp.inputFrameDownsyncBatch);
|
mapIns.onRoomDownsyncFrame(resp.rdf, resp.inputFrameDownsyncBatch);
|
||||||
break;
|
break;
|
||||||
|
case window.DOWNSYNC_MSG_ACT_PEER_UDP_ADDR:
|
||||||
|
console.warn(`Got DOWNSYNC_MSG_ACT_PEER_UDP_ADDR resp=${JSON.stringify(resp, null, 2)}`);
|
||||||
|
if (cc.sys.isNative) {
|
||||||
|
const peerJoinIndex = resp.peerJoinIndex;
|
||||||
|
const peerAddrList = resp.rdf.peerUdpAddrList;
|
||||||
|
console.log(`Got DOWNSYNC_MSG_ACT_PEER_UDP_ADDR peerAddrList=${JSON.stringify(peerAddrList)}; boundRoomCapacity=${window.boundRoomCapacity}`);
|
||||||
|
for (let j = 0; j < 3; ++j) {
|
||||||
|
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"
|
||||||
|
}, j * 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -192,13 +271,21 @@ window.initPersistentSessionClient = function(onopenCb, expectedRoomId) {
|
|||||||
clientSession.onclose = function(evt) {
|
clientSession.onclose = function(evt) {
|
||||||
// [WARNING] The callback "onclose" might be called AFTER the webpage is refreshed with "1001 == evt.code".
|
// [WARNING] The callback "onclose" might be called AFTER the webpage is refreshed with "1001 == evt.code".
|
||||||
console.warn(`The WS clientSession is closed: evt=${JSON.stringify(evt)}, evt.code=${evt.code}`);
|
console.warn(`The WS clientSession is closed: evt=${JSON.stringify(evt)}, evt.code=${evt.code}`);
|
||||||
|
if (cc.sys.isNative) {
|
||||||
|
if (mapIns.frameDataLoggingEnabled) {
|
||||||
|
console.warn(`${mapIns._stringifyRdfIdToActuallyUsedInput()}
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
DelayNoMore.UdpSession.closeUdpSession();
|
||||||
|
}
|
||||||
switch (evt.code) {
|
switch (evt.code) {
|
||||||
case constants.RET_CODE.CLIENT_MISMATCHED_RENDER_FRAME:
|
case constants.RET_CODE.CLIENT_MISMATCHED_RENDER_FRAME:
|
||||||
break;
|
break;
|
||||||
case constants.RET_CODE.BATTLE_STOPPED:
|
case constants.RET_CODE.BATTLE_STOPPED:
|
||||||
// deliberately do nothing
|
// deliberately do nothing
|
||||||
if (mapIns.frameDataLoggingEnabled) {
|
if (mapIns.frameDataLoggingEnabled) {
|
||||||
console.warn(`${mapIns._stringifyRdfIdToActuallyUsedInput()}`);
|
console.warn(`${mapIns._stringifyRdfIdToActuallyUsedInput()}
|
||||||
|
`);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case constants.RET_CODE.PLAYER_NOT_ADDABLE_TO_ROOM:
|
case constants.RET_CODE.PLAYER_NOT_ADDABLE_TO_ROOM:
|
||||||
@@ -213,9 +300,10 @@ window.initPersistentSessionClient = function(onopenCb, expectedRoomId) {
|
|||||||
case constants.RET_CODE.MYSQL_ERROR:
|
case constants.RET_CODE.MYSQL_ERROR:
|
||||||
case constants.RET_CODE.PLAYER_NOT_FOUND:
|
case constants.RET_CODE.PLAYER_NOT_FOUND:
|
||||||
case constants.RET_CODE.PLAYER_CHEATING:
|
case constants.RET_CODE.PLAYER_CHEATING:
|
||||||
case 1006: // Peer(i.e. the backend) gone unexpectedly
|
case 1006: // Peer(i.e. the backend) gone unexpectedly, but not working for "cc.sys.isNative"
|
||||||
if (mapIns.frameDataLoggingEnabled) {
|
if (mapIns.frameDataLoggingEnabled) {
|
||||||
console.warn(`${mapIns._stringifyRdfIdToActuallyUsedInput()}`);
|
console.warn(`${mapIns._stringifyRdfIdToActuallyUsedInput()}
|
||||||
|
`);
|
||||||
}
|
}
|
||||||
window.clearLocalStorageAndBackToLoginScene(true);
|
window.clearLocalStorageAndBackToLoginScene(true);
|
||||||
break;
|
break;
|
||||||
@@ -227,16 +315,15 @@ window.initPersistentSessionClient = function(onopenCb, expectedRoomId) {
|
|||||||
|
|
||||||
window.clearLocalStorageAndBackToLoginScene = function(shouldRetainBoundRoomIdInBothVolatileAndPersistentStorage) {
|
window.clearLocalStorageAndBackToLoginScene = function(shouldRetainBoundRoomIdInBothVolatileAndPersistentStorage) {
|
||||||
console.warn("+++++++ Calling `clearLocalStorageAndBackToLoginScene`");
|
console.warn("+++++++ Calling `clearLocalStorageAndBackToLoginScene`");
|
||||||
|
window.clearSelfPlayer();
|
||||||
|
if (true != shouldRetainBoundRoomIdInBothVolatileAndPersistentStorage) {
|
||||||
|
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
||||||
|
}
|
||||||
|
|
||||||
if (window.mapIns && window.mapIns.musicEffectManagerScriptIns) {
|
if (window.mapIns && window.mapIns.musicEffectManagerScriptIns) {
|
||||||
window.mapIns.musicEffectManagerScriptIns.stopAllMusic();
|
window.mapIns.musicEffectManagerScriptIns.stopAllMusic();
|
||||||
}
|
}
|
||||||
|
|
||||||
window.closeWSConnection();
|
|
||||||
window.clearSelfPlayer();
|
|
||||||
if (true != shouldRetainBoundRoomIdInBothVolatileAndPersistentStorage) {
|
|
||||||
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
|
|
||||||
}
|
|
||||||
cc.director.loadScene('login');
|
cc.director.loadScene('login');
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -274,7 +361,7 @@ window.initSecondarySession = function(onopenCb, boundRoomId) {
|
|||||||
//console.log(`Got non-empty onmessage decoded: resp.act=${resp.act}`);
|
//console.log(`Got non-empty onmessage decoded: resp.act=${resp.act}`);
|
||||||
switch (resp.act) {
|
switch (resp.act) {
|
||||||
case window.DOWNSYNC_MSG_ACT_PEER_INPUT_BATCH:
|
case window.DOWNSYNC_MSG_ACT_PEER_INPUT_BATCH:
|
||||||
mapIns.onPeerInputFrameUpsync(resp.peerJoinIndex, resp.inputFrameDownsyncBatch);
|
mapIns.onPeerInputFrameUpsync(resp.peerJoinIndex, resp.inputFrameDownsyncBatch, false);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"ver": "1.0.5",
|
"ver": "1.0.5",
|
||||||
"uuid": "40edd08e-316c-44b8-a50f-bd173554c554",
|
"uuid": "eeaa56f4-bd6c-4208-bec4-6ab1aa39ca93",
|
||||||
"isPlugin": true,
|
"isPlugin": true,
|
||||||
"loadPluginInWeb": true,
|
"loadPluginInWeb": true,
|
||||||
"loadPluginInNative": true,
|
"loadPluginInNative": true,
|
7
frontend/build-templates/.cocos-project.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"engine_version": "2.2.1",
|
||||||
|
"has_native": true,
|
||||||
|
"project_type": "js",
|
||||||
|
"projectName": "DelayNoMore",
|
||||||
|
"packageName": "org.genxium.delaynomore"
|
||||||
|
}
|
@@ -0,0 +1,81 @@
|
|||||||
|
{
|
||||||
|
"do_default": {
|
||||||
|
"exclude_from_template": [
|
||||||
|
"frameworks/runtime-src"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"do_add_native_support": {
|
||||||
|
"append_from_template": {
|
||||||
|
"from": "frameworks/runtime-src",
|
||||||
|
"to": "frameworks/runtime-src",
|
||||||
|
"exclude": [
|
||||||
|
"proj.win32/Debug.win32",
|
||||||
|
"proj.win32/Release.win32",
|
||||||
|
"proj.win32/DelayNoMore.sdf"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"append_file": [{
|
||||||
|
"from": "cocos/scripting/js-bindings/manual/jsb_module_register.cpp",
|
||||||
|
"to": "frameworks/runtime-src/Classes/jsb_module_register.cpp"
|
||||||
|
}, {
|
||||||
|
"from": "frameworks/runtime-src/Classes/ring_buff.hpp",
|
||||||
|
"to": "frameworks/runtime-src/Classes/ring_buff.hpp"
|
||||||
|
}, {
|
||||||
|
"from": "frameworks/runtime-src/Classes/ring_buff.cpp",
|
||||||
|
"to": "frameworks/runtime-src/Classes/ring_buff.cpp"
|
||||||
|
}, {
|
||||||
|
"from": "frameworks/runtime-src/Classes/udp_session.hpp",
|
||||||
|
"to": "frameworks/runtime-src/Classes/udp_session.hpp"
|
||||||
|
}, {
|
||||||
|
"from": "frameworks/runtime-src/Classes/udp_session.cpp",
|
||||||
|
"to": "frameworks/runtime-src/Classes/udp_session.cpp"
|
||||||
|
}, {
|
||||||
|
"from": "frameworks/runtime-src/Classes/udp_session_bridge.hpp",
|
||||||
|
"to": "frameworks/runtime-src/Classes/udp_session_bridge.hpp"
|
||||||
|
}, {
|
||||||
|
"from": "frameworks/runtime-src/Classes/udp_session_bridge.cpp",
|
||||||
|
"to": "frameworks/runtime-src/Classes/udp_session_bridge.cpp"
|
||||||
|
}],
|
||||||
|
"project_rename": {
|
||||||
|
"src_project_name": "DelayNoMore",
|
||||||
|
"files": [
|
||||||
|
"frameworks/runtime-src/proj.win32/PROJECT_NAME.vcxproj",
|
||||||
|
"frameworks/runtime-src/proj.win32/PROJECT_NAME.vcxproj.filters",
|
||||||
|
"frameworks/runtime-src/proj.win32/PROJECT_NAME.vcxproj.user",
|
||||||
|
"frameworks/runtime-src/proj.win32/PROJECT_NAME.sln"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"project_replace_project_name": {
|
||||||
|
"src_project_name": "DelayNoMore",
|
||||||
|
"files": [
|
||||||
|
"frameworks/runtime-src/proj.win32/PROJECT_NAME.vcxproj",
|
||||||
|
"frameworks/runtime-src/proj.win32/PROJECT_NAME.vcxproj.filters",
|
||||||
|
"frameworks/runtime-src/proj.win32/PROJECT_NAME.vcxproj.user",
|
||||||
|
"frameworks/runtime-src/proj.win32/PROJECT_NAME.sln",
|
||||||
|
"frameworks/runtime-src/proj.win32/main.cpp",
|
||||||
|
"frameworks/runtime-src/proj.android-studio/settings.gradle",
|
||||||
|
"frameworks/runtime-src/proj.android-studio/app/res/values/strings.xml",
|
||||||
|
"frameworks/runtime-src/Classes/AppDelegate.cpp"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"project_replace_package_name": {
|
||||||
|
"src_package_name": "org.genxium.delaynomore",
|
||||||
|
"files": [
|
||||||
|
"frameworks/runtime-src/proj.android-studio/app/build.gradle",
|
||||||
|
"frameworks/runtime-src/proj.android-studio/app/AndroidManifest.xml"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"project_replace_mac_bundleid": {
|
||||||
|
"src_bundle_id": "org.genxium.delaynomore",
|
||||||
|
"files": [
|
||||||
|
"frameworks/runtime-src/proj.ios_mac/mac/Info.plist"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"project_replace_ios_bundleid": {
|
||||||
|
"src_bundle_id": "org.genxium.delaynomore",
|
||||||
|
"files": [
|
||||||
|
"frameworks/runtime-src/proj.ios_mac/ios/Info.plist"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,93 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||||
|
|
||||||
|
http://www.cocos.com
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated engine source code (the "Software"), a limited,
|
||||||
|
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||||
|
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||||
|
not use Cocos Creator software for developing other software or tools that's
|
||||||
|
used for developing games. You are not granted to publish, distribute,
|
||||||
|
sublicense, and/or sell copies of Cocos Creator.
|
||||||
|
|
||||||
|
The software or tools in this License Agreement are licensed, not sold.
|
||||||
|
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "AppDelegate.h"
|
||||||
|
|
||||||
|
#include "cocos2d.h"
|
||||||
|
|
||||||
|
//#include "cocos/audio/include/AudioEngine.h"
|
||||||
|
#include "cocos/scripting/js-bindings/manual/jsb_module_register.hpp"
|
||||||
|
#include "cocos/scripting/js-bindings/manual/jsb_global.h"
|
||||||
|
#include "cocos/scripting/js-bindings/jswrapper/SeApi.h"
|
||||||
|
#include "cocos/scripting/js-bindings/event/EventDispatcher.h"
|
||||||
|
#include "cocos/scripting/js-bindings/manual/jsb_classtype.hpp"
|
||||||
|
#include "udp_session_bridge.hpp"
|
||||||
|
USING_NS_CC;
|
||||||
|
|
||||||
|
AppDelegate::AppDelegate(int width, int height) : Application("Cocos Game", width, height)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
AppDelegate::~AppDelegate()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AppDelegate::applicationDidFinishLaunching()
|
||||||
|
{
|
||||||
|
se::ScriptEngine *se = se::ScriptEngine::getInstance();
|
||||||
|
|
||||||
|
jsb_set_xxtea_key("");
|
||||||
|
jsb_init_file_operation_delegate();
|
||||||
|
|
||||||
|
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
|
||||||
|
// Enable debugger here
|
||||||
|
jsb_enable_debugger("0.0.0.0", 6086, false);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
se->setExceptionCallback([](const char *location, const char *message, const char *stack) {
|
||||||
|
// Send exception information to server like Tencent Bugly.
|
||||||
|
});
|
||||||
|
|
||||||
|
jsb_register_all_modules();
|
||||||
|
se->addRegisterCallback(registerUdpSession);
|
||||||
|
|
||||||
|
se->start();
|
||||||
|
|
||||||
|
se::AutoHandleScope hs;
|
||||||
|
jsb_run_script("jsb-adapter/jsb-builtin.js");
|
||||||
|
jsb_run_script("main.js");
|
||||||
|
|
||||||
|
se->addAfterCleanupHook([]() {
|
||||||
|
JSBClassType::destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function will be called when the app is inactive. When comes a phone call,it's be invoked too
|
||||||
|
void AppDelegate::applicationDidEnterBackground()
|
||||||
|
{
|
||||||
|
EventDispatcher::dispatchEnterBackgroundEvent();
|
||||||
|
// Ensure that handle AudioEngine enter background after all enter background events are handled
|
||||||
|
//AudioEngine::onEnterBackground();
|
||||||
|
}
|
||||||
|
|
||||||
|
// this function will be called when the app is active again
|
||||||
|
void AppDelegate::applicationWillEnterForeground()
|
||||||
|
{
|
||||||
|
// Ensure that handle AudioEngine enter foreground before all enter foreground events are handled
|
||||||
|
//AudioEngine::onEnterForeground();
|
||||||
|
EventDispatcher::dispatchEnterForegroundEvent();
|
||||||
|
}
|
@@ -0,0 +1,102 @@
|
|||||||
|
#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
|
||||||
|
void RecvRingBuff::put(char* newBytes, size_t newBytesLen) {
|
||||||
|
RecvWork* slotEle = (&eles[ed.load()]); // Save for later update
|
||||||
|
|
||||||
|
int oldCnt = cnt.load();
|
||||||
|
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;
|
||||||
|
while (n <= oldCnt && !ed.compare_exchange_weak(oldSt, oldSt) && 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();
|
||||||
|
++tried;
|
||||||
|
}
|
||||||
|
if (n <= oldCnt && !ed.compare_exchange_weak(oldSt, oldSt) && 3 == tried) {
|
||||||
|
// Failed silently, UDP packet can be dropped.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
slotEle->bytesLen = newBytesLen;
|
||||||
|
memset(slotEle->ui8Arr, 0, sizeof slotEle->ui8Arr);
|
||||||
|
for (int i = 0; i < newBytesLen; i++) {
|
||||||
|
*(slotEle->ui8Arr + i) = *(newBytes + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// No need to compare-and-swap, only "UvRecvThread" will access "RecvRingBuff.ed".
|
||||||
|
ed++;
|
||||||
|
if (ed >= n) {
|
||||||
|
ed -= n; // Deliberately not using "%" operator for performance concern
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 guard 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;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,74 @@
|
|||||||
|
#ifndef send_ring_buff_hpp
|
||||||
|
#define send_ring_buff_hpp
|
||||||
|
|
||||||
|
#include "uv/uv.h"
|
||||||
|
#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_NON_CONSECUTIVE_SET = 1;
|
||||||
|
int const RING_BUFF_FAILED_TO_SET = 2;
|
||||||
|
|
||||||
|
typedef char BYTEC;
|
||||||
|
typedef char const CHARC;
|
||||||
|
int const maxUdpPayloadBytes = 128;
|
||||||
|
int const maxBuffedMsgs = 512;
|
||||||
|
|
||||||
|
struct PeerAddr {
|
||||||
|
struct sockaddr_in sockAddrIn;
|
||||||
|
uint32_t authKey;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SendWork {
|
||||||
|
public:
|
||||||
|
BYTEC bytes[maxUdpPayloadBytes]; // Wasting some RAM here thus no need for explicit recursive destruction
|
||||||
|
size_t bytesLen;
|
||||||
|
PeerAddr peerAddr;
|
||||||
|
};
|
||||||
|
|
||||||
|
// [WARNING] This class is specific to "SendWork", designed and implemented only to use in multithreading env and save heap alloc/dealloc timecomplexity, it's by no means comparable to the Golang or JavaScript versions!
|
||||||
|
class SendRingBuff {
|
||||||
|
public:
|
||||||
|
int ed, st, n, cnt;
|
||||||
|
SendWork eles[maxBuffedMsgs]; // preallocated on stack to save heap alloc/dealloc time
|
||||||
|
SendRingBuff(int newN) {
|
||||||
|
this->n = newN;
|
||||||
|
this->st = this->ed = this->cnt = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void put(BYTEC* const newBytes, size_t newBytesLen, PeerAddr* pNewPeerAddr);
|
||||||
|
|
||||||
|
// Sending is always sequential in UvSendThread, no need to return a copy of "SendWork" instance
|
||||||
|
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
|
@@ -0,0 +1,384 @@
|
|||||||
|
#include "udp_session.hpp"
|
||||||
|
#include "base/ccMacros.h"
|
||||||
|
#include "cocos/platform/CCApplication.h"
|
||||||
|
#include "cocos/base/CCScheduler.h"
|
||||||
|
#include "cocos/scripting/js-bindings/jswrapper/SeApi.h"
|
||||||
|
|
||||||
|
int const punchServerCnt = 3;
|
||||||
|
int const punchPeerCnt = 3;
|
||||||
|
int const broadcastUpsyncCnt = 2;
|
||||||
|
|
||||||
|
uv_udp_t *udpRecvSocket = NULL, *udpSendSocket = NULL;
|
||||||
|
uv_thread_t recvTid, sendTid;
|
||||||
|
uv_async_t uvRecvLoopStopSig, uvSendLoopStopSig, uvSendLoopTriggerSig;
|
||||||
|
uv_loop_t *recvLoop = NULL, *sendLoop = NULL;
|
||||||
|
|
||||||
|
uv_mutex_t sendRingBuffLock; // used along with "uvSendLoopTriggerSig" as a "uv_cond_t"
|
||||||
|
SendRingBuff* sendRingBuff = NULL;
|
||||||
|
|
||||||
|
uv_mutex_t recvRingBuffLock;
|
||||||
|
RecvRingBuff* recvRingBuff = NULL;
|
||||||
|
|
||||||
|
char SRV_IP[256];
|
||||||
|
int SRV_PORT = 0;
|
||||||
|
int UDP_TUNNEL_SRV_PORT = 0;
|
||||||
|
struct PeerAddr udpPunchingServerAddr, udpTunnelAddr;
|
||||||
|
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) {
|
||||||
|
if (nread < 0) {
|
||||||
|
CCLOGERROR("Read error %s", uv_err_name(nread));
|
||||||
|
uv_close((uv_handle_t*)req, NULL);
|
||||||
|
free(buf->base);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
struct sockaddr_in const* sockAddr = (struct sockaddr_in const*)addr;
|
||||||
|
|
||||||
|
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
|
||||||
|
char ip[INET_ADDRSTRLEN];
|
||||||
|
memset(ip, 0, sizeof ip);
|
||||||
|
int port = 0;
|
||||||
|
|
||||||
|
if (NULL != addr) {
|
||||||
|
// The null check for "addr" is necessary, on Android there'd be such mysterious call to "_onRead"!
|
||||||
|
switch (addr->sa_family) {
|
||||||
|
case AF_INET: {
|
||||||
|
uv_inet_ntop(sockAddr->sin_family, &(sockAddr->sin_addr), ip, INET_ADDRSTRLEN);
|
||||||
|
port = ntohs(sockAddr->sin_port);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
CCLOG("UDP received %u bytes from unknown sender", nread);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (6 == nread) {
|
||||||
|
// Peer holepunching
|
||||||
|
for (int i = 0; i < maxPeerCnt; i++) {
|
||||||
|
if (peerAddrList[i].sockAddrIn.sin_addr.s_addr != sockAddr->sin_addr.s_addr) continue;
|
||||||
|
if (peerAddrList[i].sockAddrIn.sin_port != sockAddr->sin_port) continue;
|
||||||
|
peerPunchedMarks[i] = true;
|
||||||
|
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
|
||||||
|
CCLOG("UDP received peer-holepunching from %s:%d", ip, port);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (0 < nread) {
|
||||||
|
// 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
|
||||||
|
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
|
||||||
|
CCLOG("UDP received %u bytes inputFrameUpsync from %s:%d", nread, ip, port);
|
||||||
|
#endif
|
||||||
|
//uv_mutex_lock(&recvRingBuffLock);
|
||||||
|
recvRingBuff->put(buf->base, nread);
|
||||||
|
//uv_mutex_unlock(&recvRingBuffLock);
|
||||||
|
}
|
||||||
|
free(buf->base);
|
||||||
|
|
||||||
|
/*
|
||||||
|
// [WARNING] Don't call either of the following statements! They will make "_onRead" no longer called for incoming packets!
|
||||||
|
//uv_udp_recv_stop(req);
|
||||||
|
//uv_close((uv_handle_t*)req, NULL);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _allocBuffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
|
||||||
|
(void)handle;
|
||||||
|
buf->base = (char*)malloc(suggested_size);
|
||||||
|
buf->len = suggested_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onUvStopSig(uv_async_t* handle) {
|
||||||
|
if (!handle) return;
|
||||||
|
uv_stop(handle->loop);
|
||||||
|
CCLOG("UDP loop %p is signaled to stop in UvXxxxThread", handle->loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _afterSend(uv_udp_send_t* req, int status) {
|
||||||
|
if (req) {
|
||||||
|
free(req);
|
||||||
|
}
|
||||||
|
if (status) {
|
||||||
|
CCLOGERROR("uv_udp_send_cb error: %s\n", uv_strerror(status));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onUvSthNewToSend(uv_async_t* handle) {
|
||||||
|
|
||||||
|
bool hasNext = true;
|
||||||
|
while (NULL != handle && true == hasNext) {
|
||||||
|
SendWork* work = NULL;
|
||||||
|
uv_mutex_lock(&sendRingBuffLock);
|
||||||
|
work = sendRingBuff->pop();
|
||||||
|
|
||||||
|
if (NULL == work) {
|
||||||
|
hasNext = false;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
[WARNING] The following "uv_udp_try_send" might block I / O for a long time, hence unlock "as soon as possible" to avoid blocking the "GameThread" which is awaiting to acquire this mutex!
|
||||||
|
|
||||||
|
There's a very small chance where "sendRingBuff->put(...)" could contaminate the just popped "work" in "sendRingBuff->eles", thus "sendRingBuff->n" is made quite large to avoid that, moreover in terms of protecting "work" we're also unlocking "as late as possible"!
|
||||||
|
*/
|
||||||
|
uv_mutex_unlock(&sendRingBuffLock);
|
||||||
|
if (NULL != work) {
|
||||||
|
|
||||||
|
// [WARNING] If "uv_udp_send" is to be used instead of "uv_udp_try_send", as UvSendThread will always be terminated from GameThread, it's a MUST to use the following heap-alloc form to initialize "uv_udp_send_t* req" such that "_afterSend" is guaranteed to be called, otherwise "int uvRunRet2 = uv_run(l, UV_RUN_DEFAULT);" for UvSendThread would block forever due to residual active handles.
|
||||||
|
|
||||||
|
uv_udp_send_t* req = (uv_udp_send_t*)malloc(sizeof(uv_udp_send_t));
|
||||||
|
uv_buf_t sendBuffer = uv_buf_init(work->bytes, work->bytesLen);
|
||||||
|
uv_udp_send(req, udpSendSocket, &sendBuffer, 1, (struct sockaddr const*)&(work->peerAddr.sockAddrIn), _afterSend);
|
||||||
|
|
||||||
|
//uv_buf_t sendBuffer = uv_buf_init(work->bytes, work->bytesLen);
|
||||||
|
//uv_udp_try_send(udpSendSocket, &sendBuffer, 1, (struct sockaddr const*)&(work->peerAddr.sockAddrIn));
|
||||||
|
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
|
||||||
|
char ip[INET_ADDRSTRLEN];
|
||||||
|
memset(ip, 0, sizeof ip);
|
||||||
|
uv_inet_ntop(work->peerAddr.sockAddrIn.sin_family, &(work->peerAddr.sockAddrIn.sin_addr), ip, INET_ADDRSTRLEN);
|
||||||
|
int port = ntohs(work->peerAddr.sockAddrIn.sin_port);
|
||||||
|
CCLOG("UDP sent %d bytes to %s:%d", sendBuffer.len, ip, port);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onWalkCleanup(uv_handle_t* handle, void* data) {
|
||||||
|
(void)data;
|
||||||
|
uv_close(handle, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void startRecvLoop(void* arg) {
|
||||||
|
uv_loop_t* l = (uv_loop_t*)arg;
|
||||||
|
int uvRunRet1 = uv_run(l, UV_RUN_DEFAULT);
|
||||||
|
CCLOG("UDP recv loop is ended in UvRecvThread, uvRunRet1=%d", uvRunRet1);
|
||||||
|
uv_walk(l, _onWalkCleanup, NULL);
|
||||||
|
CCLOG("UDP recv loop is walked in UvRecvThread");
|
||||||
|
int uvRunRet2 = uv_run(l, UV_RUN_DEFAULT);
|
||||||
|
CCLOG("UDP recv loop is run after walking in UvRecvThread, uvRunRet2=%d", uvRunRet2);
|
||||||
|
|
||||||
|
int uvCloseRet = uv_loop_close(l);
|
||||||
|
CCLOG("UDP recv loop is closed in UvRecvThread, uvCloseRet=%d", uvCloseRet);
|
||||||
|
uv_mutex_destroy(&recvRingBuffLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void startSendLoop(void* arg) {
|
||||||
|
uv_loop_t* l = (uv_loop_t*)arg;
|
||||||
|
int uvRunRet1 = uv_run(l, UV_RUN_DEFAULT);
|
||||||
|
CCLOG("UDP send loop is ended in UvSendThread, uvRunRet1=%d", uvRunRet1);
|
||||||
|
uv_walk(l, _onWalkCleanup, NULL);
|
||||||
|
CCLOG("UDP send loop is walked in UvSendThread");
|
||||||
|
int uvRunRet2 = uv_run(l, UV_RUN_DEFAULT);
|
||||||
|
CCLOG("UDP send loop is run after walking in UvSendThread, uvRunRet2=%d", uvRunRet2);
|
||||||
|
|
||||||
|
int uvCloseRet = uv_loop_close(l);
|
||||||
|
CCLOG("UDP send loop is closed in UvSendThread, uvCloseRet=%d", uvCloseRet);
|
||||||
|
uv_mutex_destroy(&sendRingBuffLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
int initSendLoop(struct sockaddr const* pUdpAddr) {
|
||||||
|
sendLoop = uv_loop_new();
|
||||||
|
udpSendSocket = (uv_udp_t*)malloc(sizeof(uv_udp_t));
|
||||||
|
int sendSockInitRes = uv_udp_init(sendLoop, udpSendSocket); // "uv_udp_init" must precede that of "uv_udp_bind" for successful binding!
|
||||||
|
int sendBindRes = uv_udp_bind(udpSendSocket, pUdpAddr, UV_UDP_REUSEADDR);
|
||||||
|
if (0 != sendBindRes) {
|
||||||
|
CCLOGERROR("Failed to bind send; sendSockInitRes=%d, sendBindRes=%d, reason=%s", sendSockInitRes, sendBindRes, uv_strerror(sendBindRes));
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
uv_mutex_init(&sendRingBuffLock);
|
||||||
|
sendRingBuff = new SendRingBuff(maxBuffedMsgs);
|
||||||
|
|
||||||
|
uv_mutex_init(&recvRingBuffLock);
|
||||||
|
recvRingBuff = new RecvRingBuff(maxBuffedMsgs);
|
||||||
|
|
||||||
|
uv_async_init(sendLoop, &uvSendLoopStopSig, _onUvStopSig);
|
||||||
|
uv_async_init(sendLoop, &uvSendLoopTriggerSig, _onUvSthNewToSend);
|
||||||
|
|
||||||
|
return sendBindRes;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool initRecvLoop(struct sockaddr const* pUdpAddr) {
|
||||||
|
recvLoop = uv_loop_new();
|
||||||
|
udpRecvSocket = (uv_udp_t*)malloc(sizeof(uv_udp_t));
|
||||||
|
|
||||||
|
int recvSockInitRes = uv_udp_init(recvLoop, udpRecvSocket);
|
||||||
|
int recvbindRes = uv_udp_bind(udpRecvSocket, pUdpAddr, UV_UDP_REUSEADDR);
|
||||||
|
if (0 != recvbindRes) {
|
||||||
|
CCLOGERROR("Failed to bind recv; recvSockInitRes=%d, recvbindRes=%d, reason=%s", recvSockInitRes, recvbindRes, uv_strerror(recvbindRes));
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
uv_udp_recv_start(udpRecvSocket, _allocBuffer, _onRead);
|
||||||
|
uv_async_init(recvLoop, &uvRecvLoopStopSig, _onUvStopSig);
|
||||||
|
|
||||||
|
return recvbindRes;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DelayNoMore::UdpSession::openUdpSession(int port) {
|
||||||
|
struct sockaddr_in udpAddr;
|
||||||
|
uv_ip4_addr("0.0.0.0", port, &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.
|
||||||
|
|
||||||
|
It's feasible to use a same socket instance for both receiving and sending in different threads, however not knowing the exact thread-safety concerns for "uv_udp_send/uv_udp_try_send" & "uv recv callback" stops me from doing so, I'd prefer to stick to using different socket instances in different threads.
|
||||||
|
*/
|
||||||
|
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
|
||||||
|
initSendLoop(pUdpAddr);
|
||||||
|
initRecvLoop(pUdpAddr);
|
||||||
|
#else
|
||||||
|
initRecvLoop(pUdpAddr);
|
||||||
|
initSendLoop(pUdpAddr);
|
||||||
|
#endif
|
||||||
|
CCLOG("About to open UDP session at port=%d; recvLoop=%p, sendLoop=%p...", port, recvLoop, sendLoop);
|
||||||
|
|
||||||
|
uv_thread_create(&recvTid, startRecvLoop, recvLoop);
|
||||||
|
uv_thread_create(&sendTid, startSendLoop, sendLoop);
|
||||||
|
|
||||||
|
CCLOG("Finished opening UDP session at port=%d", port);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DelayNoMore::UdpSession::closeUdpSession() {
|
||||||
|
CCLOG("About to close udp session and dealloc all resources...");
|
||||||
|
|
||||||
|
uv_async_send(&uvSendLoopStopSig);
|
||||||
|
CCLOG("Signaling UvSendThread to end in GameThread...");
|
||||||
|
uv_thread_join(&sendTid);
|
||||||
|
free(udpSendSocket);
|
||||||
|
free(sendLoop);
|
||||||
|
delete sendRingBuff;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
CCLOG("Closed udp session and dealloc all resources in GameThread...");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DelayNoMore::UdpSession::punchToServer(CHARC* const srvIp, int const srvPort, BYTEC* const bytes, size_t bytesLen, int const udpTunnelSrvPort, BYTEC* const udpTunnelBytes, size_t udpTunnelBytesBytesLen) {
|
||||||
|
memset(SRV_IP, 0, sizeof SRV_IP);
|
||||||
|
memcpy(SRV_IP, srvIp, strlen(srvIp));
|
||||||
|
SRV_PORT = srvPort;
|
||||||
|
UDP_TUNNEL_SRV_PORT = udpTunnelSrvPort;
|
||||||
|
|
||||||
|
struct sockaddr_in udpPunchingServerDestAddr;
|
||||||
|
uv_ip4_addr(SRV_IP, SRV_PORT, &udpPunchingServerDestAddr);
|
||||||
|
udpPunchingServerAddr.sockAddrIn = udpPunchingServerDestAddr;
|
||||||
|
|
||||||
|
struct sockaddr_in udpTunnelDestAddr;
|
||||||
|
uv_ip4_addr(SRV_IP, UDP_TUNNEL_SRV_PORT, &udpTunnelDestAddr);
|
||||||
|
udpTunnelAddr.sockAddrIn = udpTunnelDestAddr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Libuv is really inconvenient here, neither "uv_queue_work" nor "uv_async_init" is threadsafe(http ://docs.libuv.org/en/v1.x/threadpool.html#c.uv_queue_work)! What's the point of such a queue? It's even more difficult than writing my own implementation -- again a threadsafe RingBuff could be used to the rescue, yet I'd like to investigate more into how to make the following threadsafe APIs with minimum cross-platform C++ codes
|
||||||
|
- _sendMessage(...), should be both non-blocking & threadsafe, called from GameThread
|
||||||
|
- _onRead(...), should be called first in UvRecvThread in an edge-triggered manner like idiomatic "epoll" or "kqueue", then dispatch the received message to GameThread by a threadsafe RingBuff
|
||||||
|
*/
|
||||||
|
|
||||||
|
uv_mutex_lock(&sendRingBuffLock);
|
||||||
|
sendRingBuff->put(bytes, bytesLen, &udpPunchingServerAddr);
|
||||||
|
sendRingBuff->put(udpTunnelBytes, udpTunnelBytesBytesLen, &udpTunnelAddr);
|
||||||
|
uv_mutex_unlock(&sendRingBuffLock);
|
||||||
|
uv_async_send(&uvSendLoopTriggerSig);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DelayNoMore::UdpSession::upsertPeerUdpAddr(struct PeerAddr* newPeerAddrList, int roomCapacity, int selfJoinIndex) {
|
||||||
|
// Call timer for multiple sendings from JavaScript?
|
||||||
|
CCLOG("upsertPeerUdpAddr called by js for roomCapacity=%d, selfJoinIndex=%d.", roomCapacity, selfJoinIndex);
|
||||||
|
|
||||||
|
uv_mutex_lock(&sendRingBuffLock);
|
||||||
|
for (int i = 0; i < roomCapacity; i++) {
|
||||||
|
if (i == selfJoinIndex - 1) continue;
|
||||||
|
struct PeerAddr* cand = (newPeerAddrList + i);
|
||||||
|
if (NULL == cand || 0 == cand->sockAddrIn.sin_port) continue; // Not initialized
|
||||||
|
peerAddrList[i].sockAddrIn = cand->sockAddrIn;
|
||||||
|
peerAddrList[i].authKey = cand->authKey;
|
||||||
|
sendRingBuff->put("foobar", 6, &(peerAddrList[i])); // Content hardcoded for now
|
||||||
|
}
|
||||||
|
uv_mutex_unlock(&sendRingBuffLock);
|
||||||
|
uv_async_send(&uvSendLoopTriggerSig);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DelayNoMore::UdpSession::broadcastInputFrameUpsync(BYTEC* const bytes, size_t bytesLen, int roomCapacity, int selfJoinIndex) {
|
||||||
|
uv_mutex_lock(&sendRingBuffLock);
|
||||||
|
// Might want to send several times for better arrival rate
|
||||||
|
for (int j = 0; j < broadcastUpsyncCnt; j++) {
|
||||||
|
int peerPunchedCnt = 0;
|
||||||
|
for (int i = 0; i < roomCapacity; i++) {
|
||||||
|
if (i + 1 == selfJoinIndex) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (0 == peerAddrList[i].sockAddrIn.sin_port) {
|
||||||
|
// Peer addr not initialized
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (false == peerPunchedMarks[i]) {
|
||||||
|
// Not punched yet, save some bandwidth
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sendRingBuff->put(bytes, bytesLen, &(peerAddrList[i]));
|
||||||
|
++peerPunchedCnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (peerPunchedCnt + 1 < roomCapacity) {
|
||||||
|
// Send to room udp tunnel in case of ANY hole punching failure
|
||||||
|
sendRingBuff->put(bytes, bytesLen, &udpTunnelAddr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uv_mutex_unlock(&sendRingBuffLock);
|
||||||
|
uv_async_send(&uvSendLoopTriggerSig);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DelayNoMore::UdpSession::pollUdpRecvRingBuff() {
|
||||||
|
// This function is called by GameThread 60 fps.
|
||||||
|
|
||||||
|
//uv_mutex_lock(&recvRingBuffLock);
|
||||||
|
while (true) {
|
||||||
|
RecvWork f;
|
||||||
|
bool res = recvRingBuff->pop(&f);
|
||||||
|
if (!res) return false;
|
||||||
|
|
||||||
|
// [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;
|
||||||
|
}
|
@@ -0,0 +1,20 @@
|
|||||||
|
#ifndef udp_session_hpp
|
||||||
|
#define udp_session_hpp
|
||||||
|
|
||||||
|
#include "ring_buff.hpp"
|
||||||
|
|
||||||
|
int const maxPeerCnt = 10;
|
||||||
|
|
||||||
|
namespace DelayNoMore {
|
||||||
|
class UdpSession {
|
||||||
|
public:
|
||||||
|
static bool openUdpSession(int port);
|
||||||
|
static bool closeUdpSession();
|
||||||
|
static bool upsertPeerUdpAddr(struct PeerAddr* newPeerAddrList, int roomCapacity, int selfJoinIndex);
|
||||||
|
//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 broadcastInputFrameUpsync(BYTEC* const bytes, size_t bytesLen, int roomCapacity, int selfJoinIndex);
|
||||||
|
static bool pollUdpRecvRingBuff();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
@@ -0,0 +1,184 @@
|
|||||||
|
#include "udp_session.hpp"
|
||||||
|
#include "base/ccMacros.h"
|
||||||
|
#include "scripting/js-bindings/manual/jsb_conversions.hpp"
|
||||||
|
|
||||||
|
bool openUdpSession(se::State& s) {
|
||||||
|
const auto& args = s.args();
|
||||||
|
size_t argc = args.size();
|
||||||
|
CC_UNUSED bool ok = true;
|
||||||
|
if (1 == argc && args[0].isNumber()) {
|
||||||
|
SE_PRECONDITION2(ok, false, "openUdpSession: Error processing arguments");
|
||||||
|
int port = args[0].toInt32();
|
||||||
|
|
||||||
|
return DelayNoMore::UdpSession::openUdpSession(port);
|
||||||
|
}
|
||||||
|
SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d; or wrong arg type!", (int)argc, 1);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SE_BIND_FUNC(openUdpSession)
|
||||||
|
|
||||||
|
bool punchToServer(se::State& s) {
|
||||||
|
const auto& args = s.args();
|
||||||
|
size_t argc = args.size();
|
||||||
|
CC_UNUSED bool ok = true;
|
||||||
|
if (5 == argc && args[0].isString() && args[1].isNumber() && args[2].isObject() && args[2].toObject()->isTypedArray()
|
||||||
|
&& args[3].isNumber() && args[4].isObject() && args[4].toObject()->isTypedArray()
|
||||||
|
) {
|
||||||
|
SE_PRECONDITION2(ok, false, "punchToServer: Error processing arguments");
|
||||||
|
CHARC* srvIp = args[0].toString().c_str();
|
||||||
|
int srvPort = args[1].toInt32();
|
||||||
|
BYTEC bytes[maxUdpPayloadBytes];
|
||||||
|
memset(bytes, 0, sizeof bytes);
|
||||||
|
se::Object* obj = args[2].toObject();
|
||||||
|
size_t sz = 0;
|
||||||
|
uint8_t* ptr = NULL;
|
||||||
|
obj->getTypedArrayData(&ptr, &sz);
|
||||||
|
for (size_t i = 0; i < sz; i++) {
|
||||||
|
bytes[i] = (char)(*(ptr + i));
|
||||||
|
}
|
||||||
|
|
||||||
|
int udpTunnelSrvPort = args[3].toInt32();
|
||||||
|
BYTEC udpTunnelBytes[maxUdpPayloadBytes];
|
||||||
|
memset(udpTunnelBytes, 0, sizeof udpTunnelBytes);
|
||||||
|
se::Object* udpTunnelObj = args[4].toObject();
|
||||||
|
size_t udpTunnelSz = 0;
|
||||||
|
uint8_t* udpTunnelPtr = NULL;
|
||||||
|
udpTunnelObj->getTypedArrayData(&udpTunnelPtr, &udpTunnelSz);
|
||||||
|
for (size_t i = 0; i < udpTunnelSz; i++) {
|
||||||
|
udpTunnelBytes[i] = (char)(*(udpTunnelPtr + i));
|
||||||
|
}
|
||||||
|
|
||||||
|
CCLOG("Should punch %s:%d by %d bytes; should punch udp tunnel %s:%d by %d bytes.", srvIp, srvPort, sz, srvIp, udpTunnelSrvPort, udpTunnelSz);
|
||||||
|
return DelayNoMore::UdpSession::punchToServer(srvIp, srvPort, bytes, sz, udpTunnelSrvPort, udpTunnelBytes, udpTunnelSz);
|
||||||
|
}
|
||||||
|
SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d; or wrong arg type!", (int)argc, 5);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SE_BIND_FUNC(punchToServer)
|
||||||
|
|
||||||
|
bool broadcastInputFrameUpsync(se::State& s) {
|
||||||
|
const auto& args = s.args();
|
||||||
|
size_t argc = args.size();
|
||||||
|
CC_UNUSED bool ok = true;
|
||||||
|
if (3 == argc && args[0].toObject()->isTypedArray() && args[1].isNumber() && args[2].isNumber()) {
|
||||||
|
SE_PRECONDITION2(ok, false, "broadcastInputFrameUpsync: Error processing arguments");
|
||||||
|
BYTEC bytes[1024];
|
||||||
|
memset(bytes, 0, sizeof bytes);
|
||||||
|
se::Object* obj = args[0].toObject();
|
||||||
|
size_t sz = 0;
|
||||||
|
uint8_t* ptr = NULL;
|
||||||
|
obj->getTypedArrayData(&ptr, &sz);
|
||||||
|
for (size_t i = 0; i < sz; i++) {
|
||||||
|
bytes[i] = (char)(*(ptr + i));
|
||||||
|
}
|
||||||
|
int roomCapacity = args[1].toInt32();
|
||||||
|
int selfJoinIndex = args[2].toInt32();
|
||||||
|
CCLOG("Should broadcastInputFrameUpsync %u bytes; roomCapacity=%d, selfJoinIndex=%d.", sz, roomCapacity, selfJoinIndex);
|
||||||
|
return DelayNoMore::UdpSession::broadcastInputFrameUpsync(bytes, sz, roomCapacity, selfJoinIndex);
|
||||||
|
}
|
||||||
|
SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d; or wrong arg type!", (int)argc, 3);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SE_BIND_FUNC(broadcastInputFrameUpsync)
|
||||||
|
|
||||||
|
bool closeUdpSession(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, "closeUdpSession: Error processing arguments");
|
||||||
|
return DelayNoMore::UdpSession::closeUdpSession();
|
||||||
|
}
|
||||||
|
SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d", (int)argc, 0);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SE_BIND_FUNC(closeUdpSession)
|
||||||
|
|
||||||
|
struct PeerAddr newPeerAddrList[maxPeerCnt];
|
||||||
|
bool upsertPeerUdpAddr(se::State& s) {
|
||||||
|
const auto& args = s.args();
|
||||||
|
size_t argc = args.size();
|
||||||
|
CC_UNUSED bool ok = true;
|
||||||
|
if (3 == argc && args[0].isObject() && args[0].toObject()->isArray() && args[1].isNumber() && args[2].isNumber()) {
|
||||||
|
SE_PRECONDITION2(ok, false, "upsertPeerUdpAddr: Error processing arguments");
|
||||||
|
int roomCapacity = args[1].toInt32();
|
||||||
|
int selfJoinIndex = args[2].toInt32();
|
||||||
|
se::Object* newPeerAddrValArr = args[0].toObject();
|
||||||
|
for (int i = 0; i < roomCapacity; i++) {
|
||||||
|
se::Value newPeerAddrVal;
|
||||||
|
newPeerAddrValArr->getArrayElement(i, &newPeerAddrVal);
|
||||||
|
se::Object* newPeerAddrObj = newPeerAddrVal.toObject();
|
||||||
|
se::Value newIp, newPort, newAuthKey;
|
||||||
|
newPeerAddrObj->getProperty("ip", &newIp);
|
||||||
|
newPeerAddrObj->getProperty("port", &newPort);
|
||||||
|
newPeerAddrObj->getProperty("authKey", &newAuthKey);
|
||||||
|
uv_ip4_addr(newIp.toString().c_str(), newPort.toInt32(), &(newPeerAddrList[i].sockAddrIn));
|
||||||
|
newPeerAddrList[i].authKey = newAuthKey.toInt32();
|
||||||
|
}
|
||||||
|
|
||||||
|
return DelayNoMore::UdpSession::upsertPeerUdpAddr(newPeerAddrList, roomCapacity, selfJoinIndex);
|
||||||
|
}
|
||||||
|
SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d; or wrong arg type!", (int)argc, 3);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
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) {
|
||||||
|
CCLOGINFO("jsbindings: finalizing JS object %p (DelayNoMore::UdpSession)", s.nativeThisObject());
|
||||||
|
auto iter = se::NonRefNativePtrCreatedByCtorMap::find(s.nativeThisObject());
|
||||||
|
if (iter != se::NonRefNativePtrCreatedByCtorMap::end()) {
|
||||||
|
se::NonRefNativePtrCreatedByCtorMap::erase(iter);
|
||||||
|
DelayNoMore::UdpSession* cobj = (DelayNoMore::UdpSession*)s.nativeThisObject();
|
||||||
|
delete cobj;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
SE_BIND_FINALIZE_FUNC(udpSessionFinalize)
|
||||||
|
|
||||||
|
se::Object* __jsb_udp_session_proto = nullptr;
|
||||||
|
se::Class* __jsb_udp_session_class = nullptr;
|
||||||
|
bool registerUdpSession(se::Object* obj) {
|
||||||
|
// Get the ns
|
||||||
|
se::Value nsVal;
|
||||||
|
if (!obj->getProperty("DelayNoMore", &nsVal))
|
||||||
|
{
|
||||||
|
se::HandleObject jsobj(se::Object::createPlainObject());
|
||||||
|
nsVal.setObject(jsobj);
|
||||||
|
obj->setProperty("DelayNoMore", nsVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
se::Object* ns = nsVal.toObject();
|
||||||
|
auto cls = se::Class::create("UdpSession", ns, nullptr, nullptr);
|
||||||
|
|
||||||
|
cls->defineStaticFunction("openUdpSession", _SE(openUdpSession));
|
||||||
|
cls->defineStaticFunction("punchToServer", _SE(punchToServer));
|
||||||
|
cls->defineStaticFunction("broadcastInputFrameUpsync", _SE(broadcastInputFrameUpsync));
|
||||||
|
cls->defineStaticFunction("closeUdpSession", _SE(closeUdpSession));
|
||||||
|
cls->defineStaticFunction("upsertPeerUdpAddr", _SE(upsertPeerUdpAddr));
|
||||||
|
cls->defineStaticFunction("pollUdpRecvRingBuff", _SE(pollUdpRecvRingBuff));
|
||||||
|
cls->defineFinalizeFunction(_SE(udpSessionFinalize));
|
||||||
|
cls->install();
|
||||||
|
|
||||||
|
JSBClassType::registerClass<DelayNoMore::UdpSession>(cls);
|
||||||
|
__jsb_udp_session_proto = cls->getProto();
|
||||||
|
__jsb_udp_session_class = cls;
|
||||||
|
se::ScriptEngine::getInstance()->clearException();
|
||||||
|
return true;
|
||||||
|
}
|
@@ -0,0 +1,19 @@
|
|||||||
|
#ifndef udp_session_bridge_hpp
|
||||||
|
#define udp_session_bridge_hpp
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "base/ccConfig.h"
|
||||||
|
#include "cocos/scripting/js-bindings/jswrapper/SeApi.h"
|
||||||
|
|
||||||
|
extern se::Object* __jsb_udp_session_proto;
|
||||||
|
extern se::Class* __jsb_udp_session_class;
|
||||||
|
|
||||||
|
bool registerUdpSession(se::Object* obj);
|
||||||
|
|
||||||
|
SE_DECLARE_FUNC(openUdpSession);
|
||||||
|
SE_DECLARE_FUNC(punchToServer);
|
||||||
|
SE_DECLARE_FUNC(broadcastInputFrameUpsync);
|
||||||
|
SE_DECLARE_FUNC(closeUdpSession);
|
||||||
|
SE_DECLARE_FUNC(upsertPeerUdpAddr);
|
||||||
|
SE_DECLARE_FUNC(pollUdpRecvRingBuff);
|
||||||
|
#endif
|
@@ -0,0 +1,40 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="org.genxium.delaynomore"
|
||||||
|
android:installLocation="auto">
|
||||||
|
|
||||||
|
<uses-feature android:glEsVersion="0x00020000" />
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
|
||||||
|
|
||||||
|
<!-- TODO: Remove "usesCleartextTraffic" in production -->
|
||||||
|
<application
|
||||||
|
android:allowBackup="true"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:usesCleartextTraffic="true"
|
||||||
|
android:icon="@mipmap/ic_launcher">
|
||||||
|
|
||||||
|
<!-- Tell Cocos2dxActivity the name of our .so -->
|
||||||
|
<meta-data android:name="android.app.lib_name"
|
||||||
|
android:value="cocos2djs" />
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name="org.cocos2dx.javascript.AppActivity"
|
||||||
|
android:screenOrientation="sensorLandscape"
|
||||||
|
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:usesCleartextTraffic="true"
|
||||||
|
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
|
||||||
|
android:launchMode="singleTask"
|
||||||
|
android:taskAffinity="" >
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
@@ -0,0 +1,26 @@
|
|||||||
|
LOCAL_PATH := $(call my-dir)
|
||||||
|
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
LOCAL_MODULE := cocos2djs_shared
|
||||||
|
|
||||||
|
LOCAL_MODULE_FILENAME := libcocos2djs
|
||||||
|
|
||||||
|
ifeq ($(USE_ARM_MODE),1)
|
||||||
|
LOCAL_ARM_MODE := arm
|
||||||
|
endif
|
||||||
|
|
||||||
|
LOCAL_SRC_FILES := hellojavascript/main.cpp \
|
||||||
|
../../../Classes/AppDelegate.cpp \
|
||||||
|
../../../Classes/jsb_module_register.cpp \
|
||||||
|
../../../Classes/udp_session.cpp \
|
||||||
|
../../../Classes/udp_session_bridge.cpp \
|
||||||
|
../../../Classes/ring_buff.cpp
|
||||||
|
|
||||||
|
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../../Classes
|
||||||
|
|
||||||
|
LOCAL_STATIC_LIBRARIES := cocos2dx_static
|
||||||
|
|
||||||
|
include $(BUILD_SHARED_LIBRARY)
|
||||||
|
|
||||||
|
$(call import-module, cocos)
|
@@ -0,0 +1,119 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
Copyright (c) 2015-2016 Chukong Technologies Inc.
|
||||||
|
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||||
|
|
||||||
|
http://www.cocos2d-x.org
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
****************************************************************************/
|
||||||
|
package org.cocos2dx.javascript;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.res.Configuration;
|
||||||
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import org.cocos2dx.lib.Cocos2dxActivity;
|
||||||
|
import org.cocos2dx.lib.Cocos2dxGLSurfaceView;
|
||||||
|
|
||||||
|
public class AppActivity extends Cocos2dxActivity {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
// Workaround in https://stackoverflow.com/questions/16283079/re-launch-of-activity-on-home-button-but-only-the-first-time/16447508
|
||||||
|
if (!isTaskRoot()) {
|
||||||
|
// Android launched another instance of the root activity into an existing task
|
||||||
|
// so just quietly finish and go away, dropping the user back into the activity
|
||||||
|
// at the top of the stack (ie: the last state of this task)
|
||||||
|
// Don't need to finish it again since it's finished in super.onCreate .
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// DO OTHER INITIALIZATION BELOW
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Cocos2dxGLSurfaceView onCreateView() {
|
||||||
|
Cocos2dxGLSurfaceView glSurfaceView = new Cocos2dxGLSurfaceView(this);
|
||||||
|
// TestCpp should create stencil buffer
|
||||||
|
glSurfaceView.setEGLConfigChooser(5, 6, 5, 0, 16, 8);
|
||||||
|
|
||||||
|
return glSurfaceView;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onNewIntent(Intent intent) {
|
||||||
|
super.onNewIntent(intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onRestart() {
|
||||||
|
super.onRestart();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onStop() {
|
||||||
|
super.onStop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBackPressed() {
|
||||||
|
super.onBackPressed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onConfigurationChanged(Configuration newConfig) {
|
||||||
|
super.onConfigurationChanged(newConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onRestoreInstanceState(Bundle savedInstanceState) {
|
||||||
|
super.onRestoreInstanceState(savedInstanceState);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onSaveInstanceState(Bundle outState) {
|
||||||
|
super.onSaveInstanceState(outState);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onStart() {
|
||||||
|
super.onStart();
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,30 @@
|
|||||||
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
|
|
||||||
|
buildscript {
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
classpath 'com.android.tools.build:gradle:3.2.0'
|
||||||
|
|
||||||
|
|
||||||
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
|
// in the individual module build.gradle files
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allprojects {
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
jcenter()
|
||||||
|
flatDir {
|
||||||
|
dirs 'libs'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task clean(type: Delete) {
|
||||||
|
delete rootProject.buildDir
|
||||||
|
}
|
@@ -0,0 +1,212 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>{3B0B58B1-2734-488E-A542-ECEC11EB2455}</ProjectGuid>
|
||||||
|
<RootNamespace>DelayNoMore</RootNamespace>
|
||||||
|
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
<PlatformToolset Condition="'$(VisualStudioVersion)' == '12.0'">v120</PlatformToolset>
|
||||||
|
<PlatformToolset Condition="'$(VisualStudioVersion)' == '12.0' and exists('$(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A')">v120_xp</PlatformToolset>
|
||||||
|
<PlatformToolset Condition="'$(VisualStudioVersion)' == '14.0'">v140</PlatformToolset>
|
||||||
|
<PlatformToolset Condition="'$(VisualStudioVersion)' == '14.0' and exists('$(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A')">v140_xp</PlatformToolset>
|
||||||
|
<PlatformToolset Condition="'$(VisualStudioVersion)' == '15.0'">v141</PlatformToolset>
|
||||||
|
<PlatformToolset Condition="'$(VisualStudioVersion)' == '15.0' and exists('$(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A')">v140_xp</PlatformToolset>
|
||||||
|
<PlatformToolset>v140</PlatformToolset>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
<PlatformToolset Condition="'$(VisualStudioVersion)' == '12.0'">v120</PlatformToolset>
|
||||||
|
<PlatformToolset Condition="'$(VisualStudioVersion)' == '12.0' and exists('$(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A')">v120_xp</PlatformToolset>
|
||||||
|
<PlatformToolset Condition="'$(VisualStudioVersion)' == '14.0'">v140</PlatformToolset>
|
||||||
|
<PlatformToolset Condition="'$(VisualStudioVersion)' == '14.0' and exists('$(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A')">v140_xp</PlatformToolset>
|
||||||
|
<PlatformToolset Condition="'$(VisualStudioVersion)' == '15.0'">v141</PlatformToolset>
|
||||||
|
<PlatformToolset Condition="'$(VisualStudioVersion)' == '15.0' and exists('$(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A')">v140_xp</PlatformToolset>
|
||||||
|
<PlatformToolset>v140</PlatformToolset>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
<Import Project="C:\CocosCreator_2.2.1\resources\cocos2d-x\build\cocos2dx.props" />
|
||||||
|
<Import Project="C:\CocosCreator_2.2.1\resources\cocos2d-x\build\cocos2d_headers.props" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
<Import Project="C:\CocosCreator_2.2.1\resources\cocos2d-x\build\cocos2dx.props" />
|
||||||
|
<Import Project="C:\CocosCreator_2.2.1\resources\cocos2d-x\build\cocos2d_headers.props" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<_ProjectFileVersion>12.0.21005.1</_ProjectFileVersion>
|
||||||
|
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration).win32\</OutDir>
|
||||||
|
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration).win32\</IntDir>
|
||||||
|
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</LinkIncremental>
|
||||||
|
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration).win32\</OutDir>
|
||||||
|
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration).win32\</IntDir>
|
||||||
|
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
|
||||||
|
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
|
||||||
|
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
|
||||||
|
<CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
<CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
|
||||||
|
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<LibraryPath>$(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A\lib;$(LibraryPath)</LibraryPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<LibraryPath>$(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A\lib;$(LibraryPath)</LibraryPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<Midl>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<MkTypLibCompatible>false</MkTypLibCompatible>
|
||||||
|
<TargetEnvironment>Win32</TargetEnvironment>
|
||||||
|
<GenerateStublessProxies>true</GenerateStublessProxies>
|
||||||
|
<TypeLibraryName>$(IntDir)game.tlb</TypeLibraryName>
|
||||||
|
<HeaderFileName>game.h</HeaderFileName>
|
||||||
|
<DllDataFileName>
|
||||||
|
</DllDataFileName>
|
||||||
|
<InterfaceIdentifierFileName>game_i.c</InterfaceIdentifierFileName>
|
||||||
|
<ProxyFileName>game_p.c</ProxyFileName>
|
||||||
|
</Midl>
|
||||||
|
<ClCompile>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<AdditionalIncludeDirectories>$(ProjectDir)..\Classes;$(EngineRoot);$(EngineRoot)cocos;$(EngineRoot)cocos\base;$(EngineRoot)cocos\scripting\js-bindings\auto;$(EngineRoot)cocos\scripting\js-bindings\manual;$(EngineRoot)cocos\audio\include;$(EngineRoot)external\win32\include\;$(EngineRoot)external\win32\include\v8;$(EngineRoot)extensions;$(EngineRoot)cocos\editor-support;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>WIN32;_WINDOWS;STRICT;_DEBUG;XP_WIN;JS_HAVE___INTN;JS_INTPTR_TYPE=int;COCOS2D_DEBUG=1;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_USRLIBSIMSTATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<MinimalRebuild>false</MinimalRebuild>
|
||||||
|
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||||
|
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
|
||||||
|
<DisableSpecificWarnings>4267;4251;4244;4800;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||||
|
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||||
|
</ClCompile>
|
||||||
|
<ResourceCompile>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<Culture>0x0409</Culture>
|
||||||
|
<AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A\include;$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
</ResourceCompile>
|
||||||
|
<PreLinkEvent>
|
||||||
|
<Command>
|
||||||
|
</Command>
|
||||||
|
</PreLinkEvent>
|
||||||
|
<Link>
|
||||||
|
<AdditionalDependencies>v8.dll.lib;v8_libbase.dll.lib;v8_libplatform.dll.lib;libuv.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<TargetMachine>MachineX86</TargetMachine>
|
||||||
|
</Link>
|
||||||
|
<PreBuildEvent>
|
||||||
|
<Command>
|
||||||
|
</Command>
|
||||||
|
</PreBuildEvent>
|
||||||
|
<PreBuildEvent>
|
||||||
|
<Command>
|
||||||
|
</Command>
|
||||||
|
</PreBuildEvent>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup>
|
||||||
|
<CustomBuildStep>
|
||||||
|
<Command>xcopy "$(ProjectDir)..\..\..\src" "$(OutDir)\src" /D /E /I /F /Y
|
||||||
|
xcopy "$(ProjectDir)..\..\..\res" "$(OutDir)\res" /D /E /I /F /Y
|
||||||
|
xcopy "$(ProjectDir)..\..\..\jsb-adapter" "$(OutDir)\jsb-adapter" /D /E /I /F /Y
|
||||||
|
copy "$(ProjectDir)..\..\..\main.js" "$(OutDir)\" /Y
|
||||||
|
copy "$(ProjectDir)..\..\..\project.json" "$(OutDir)\" /Y</Command>
|
||||||
|
<Outputs>$(TargetName).cab</Outputs>
|
||||||
|
<Inputs>$(TargetFileName)</Inputs>
|
||||||
|
</CustomBuildStep>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<Midl>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<MkTypLibCompatible>false</MkTypLibCompatible>
|
||||||
|
<TargetEnvironment>Win32</TargetEnvironment>
|
||||||
|
<GenerateStublessProxies>true</GenerateStublessProxies>
|
||||||
|
<TypeLibraryName>$(IntDir)game.tlb</TypeLibraryName>
|
||||||
|
<HeaderFileName>game.h</HeaderFileName>
|
||||||
|
<DllDataFileName>
|
||||||
|
</DllDataFileName>
|
||||||
|
<InterfaceIdentifierFileName>game_i.c</InterfaceIdentifierFileName>
|
||||||
|
<ProxyFileName>game_p.c</ProxyFileName>
|
||||||
|
</Midl>
|
||||||
|
<ClCompile>
|
||||||
|
<AdditionalIncludeDirectories>$(ProjectDir)..\Classes;$(EngineRoot);$(EngineRoot)cocos;$(EngineRoot)cocos\base;$(EngineRoot)cocos\scripting\js-bindings\auto;$(EngineRoot)cocos\scripting\js-bindings\manual;$(EngineRoot)cocos\audio\include;$(EngineRoot)external\win32\include\;$(EngineRoot)external\win32\include\v8;$(EngineRoot)extensions;$(EngineRoot)cocos\editor-support;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>WIN32;_WINDOWS;STRICT;NDEBUG;XP_WIN;JS_HAVE___INTN;JS_INTPTR_TYPE=int;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_USRLIBSIMSTATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ExceptionHandling>
|
||||||
|
</ExceptionHandling>
|
||||||
|
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<DebugInformationFormat>
|
||||||
|
</DebugInformationFormat>
|
||||||
|
<DisableSpecificWarnings>4267;4251;4244;4800;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||||
|
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||||
|
</ClCompile>
|
||||||
|
<ResourceCompile>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<Culture>0x0409</Culture>
|
||||||
|
<AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A\include;$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
</ResourceCompile>
|
||||||
|
<PreLinkEvent>
|
||||||
|
<Command>
|
||||||
|
</Command>
|
||||||
|
</PreLinkEvent>
|
||||||
|
<Link>
|
||||||
|
<AdditionalDependencies>v8.dll.lib;v8_libbase.dll.lib;v8_libplatform.dll.lib;libuv.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<TargetMachine>MachineX86</TargetMachine>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
<PreBuildEvent>
|
||||||
|
<Command>
|
||||||
|
</Command>
|
||||||
|
</PreBuildEvent>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="..\Classes\jsb_module_register.cpp" />
|
||||||
|
<ClCompile Include="main.cpp" />
|
||||||
|
<ClCompile Include="..\Classes\AppDelegate.cpp" />
|
||||||
|
<ClCompile Include="..\Classes\udp_session.cpp" />
|
||||||
|
<ClCompile Include="..\Classes\udp_session_bridge.cpp" />
|
||||||
|
<ClCompile Include="..\Classes\ring_buff.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="main.h" />
|
||||||
|
<ClInclude Include="..\Classes\ring_buff.hpp" />
|
||||||
|
<ClInclude Include="..\Classes\udp_session.hpp" />
|
||||||
|
<ClInclude Include="..\Classes\udp_session_bridge.hpp" />
|
||||||
|
<ClInclude Include="..\Classes\AppDelegate.h" />
|
||||||
|
<ClInclude Include="resource.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ResourceCompile Include="game.rc" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Image Include="res\game.ico" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
@@ -0,0 +1,63 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="resource">
|
||||||
|
<UniqueIdentifier>{ca9c9e15-d942-43a1-aa7a-5f0b74ca1afd}</UniqueIdentifier>
|
||||||
|
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;png;manifest</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="win32">
|
||||||
|
<UniqueIdentifier>{ccb2323b-1cfa-41ea-bcf4-ba5f07309396}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Classes">
|
||||||
|
<UniqueIdentifier>{e93a77e1-af1e-4400-87d3-504b62ebdbb0}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="main.cpp">
|
||||||
|
<Filter>win32</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\Classes\AppDelegate.cpp">
|
||||||
|
<Filter>Classes</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\Classes\jsb_module_register.cpp">
|
||||||
|
<Filter>Classes</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\Classes\ring_buff.cpp">
|
||||||
|
<Filter>Classes</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\Classes\udp_session.cpp">
|
||||||
|
<Filter>Classes</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\Classes\udp_session_bridge.cpp">
|
||||||
|
<Filter>Classes</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="..\Classes\AppDelegate.h">
|
||||||
|
<Filter>Classes</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="main.h">
|
||||||
|
<Filter>win32</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="resource.h" />
|
||||||
|
<ClInclude Include="..\Classes\ring_buff.hpp">
|
||||||
|
<Filter>Classes</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\Classes\udp_session.hpp">
|
||||||
|
<Filter>Classes</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\Classes\udp_session_bridge.hpp">
|
||||||
|
<Filter>Classes</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ResourceCompile Include="game.rc">
|
||||||
|
<Filter>resource</Filter>
|
||||||
|
</ResourceCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Image Include="res\game.ico">
|
||||||
|
<Filter>resource</Filter>
|
||||||
|
</Image>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
@@ -2,7 +2,7 @@
|
|||||||
"android-instant": {
|
"android-instant": {
|
||||||
"REMOTE_SERVER_ROOT": "",
|
"REMOTE_SERVER_ROOT": "",
|
||||||
"host": "",
|
"host": "",
|
||||||
"packageName": "org.cocos2d.helloworld",
|
"packageName": "org.genxium.delaynomore",
|
||||||
"pathPattern": "",
|
"pathPattern": "",
|
||||||
"recordPath": "",
|
"recordPath": "",
|
||||||
"scheme": "https",
|
"scheme": "https",
|
||||||
@@ -15,14 +15,14 @@
|
|||||||
"orientation": "portrait",
|
"orientation": "portrait",
|
||||||
"subContext": ""
|
"subContext": ""
|
||||||
},
|
},
|
||||||
"encryptJs": true,
|
"encryptJs": false,
|
||||||
"excludeScenes": [
|
"excludeScenes": [
|
||||||
"8491a86c-bec9-4813-968a-128ca01639e0"
|
"8491a86c-bec9-4813-968a-128ca01639e0"
|
||||||
],
|
],
|
||||||
"fb-instant-games": {},
|
"fb-instant-games": {},
|
||||||
"includeSDKBox": false,
|
"includeSDKBox": false,
|
||||||
"inlineSpriteFrames": true,
|
"inlineSpriteFrames": true,
|
||||||
"inlineSpriteFrames_native": true,
|
"inlineSpriteFrames_native": false,
|
||||||
"md5Cache": false,
|
"md5Cache": false,
|
||||||
"mergeStartScene": true,
|
"mergeStartScene": true,
|
||||||
"optimizeHotUpdate": false,
|
"optimizeHotUpdate": false,
|
||||||
@@ -32,14 +32,14 @@
|
|||||||
"portrait": false,
|
"portrait": false,
|
||||||
"upsideDown": false
|
"upsideDown": false
|
||||||
},
|
},
|
||||||
"packageName": "org.cocos2d.helloworld",
|
"packageName": "org.genxium.delaynomore",
|
||||||
"qqplay": {
|
"qqplay": {
|
||||||
"REMOTE_SERVER_ROOT": "",
|
"REMOTE_SERVER_ROOT": "",
|
||||||
"orientation": "portrait"
|
"orientation": "portrait"
|
||||||
},
|
},
|
||||||
"startScene": "2ff474d9-0c9e-4fe3-87ec-fbff7cae85b4",
|
"startScene": "2ff474d9-0c9e-4fe3-87ec-fbff7cae85b4",
|
||||||
"title": "DelayNoMore",
|
"title": "DelayNoMore",
|
||||||
"webOrientation": "portrait",
|
"webOrientation": "landscape",
|
||||||
"wechatgame": {
|
"wechatgame": {
|
||||||
"REMOTE_SERVER_ROOT": "https://bgmoba.lokcol.com/static/",
|
"REMOTE_SERVER_ROOT": "https://bgmoba.lokcol.com/static/",
|
||||||
"appid": "wxf497c910a2a25edc",
|
"appid": "wxf497c910a2a25edc",
|
||||||
@@ -48,13 +48,14 @@
|
|||||||
"xxteaKey": "4d54a3d5-e6f3-49",
|
"xxteaKey": "4d54a3d5-e6f3-49",
|
||||||
"zipCompressJs": true,
|
"zipCompressJs": true,
|
||||||
"android": {
|
"android": {
|
||||||
"packageName": "org.cocos2d.helloworld"
|
"packageName": "org.genxium.delaynomore"
|
||||||
},
|
},
|
||||||
"ios": {
|
"ios": {
|
||||||
"packageName": "org.cocos2d.helloworld"
|
"packageName": "org.genxium.delaynomore"
|
||||||
},
|
},
|
||||||
"mac": {
|
"mac": {
|
||||||
"packageName": "org.cocos2d.helloworld"
|
"packageName": "org.genxium.delaynomore"
|
||||||
},
|
},
|
||||||
"win32": {}
|
"win32": {},
|
||||||
|
"includeAnySDK": false
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"excludeScenes": [],
|
"excludeScenes": [],
|
||||||
"packageName": "org.cocos2d.helloworld",
|
"packageName": "org.genxium.delaynomore",
|
||||||
"platform": "web-mobile",
|
"platform": "android",
|
||||||
"startScene": "2d2f792f-a40c-49bb-a189-ed176a246e49",
|
"startScene": "2d2f792f-a40c-49bb-a189-ed176a246e49",
|
||||||
"title": "HelloWorld"
|
"title": "DelayNoMore"
|
||||||
}
|
}
|
||||||
|
@@ -33,15 +33,23 @@
|
|||||||
"design-resolution-height": 640,
|
"design-resolution-height": 640,
|
||||||
"design-resolution-width": 960,
|
"design-resolution-width": 960,
|
||||||
"excluded-modules": [
|
"excluded-modules": [
|
||||||
|
"Audio",
|
||||||
|
"AudioSource",
|
||||||
"Collider",
|
"Collider",
|
||||||
|
"DragonBones",
|
||||||
"Geom Utils",
|
"Geom Utils",
|
||||||
|
"Intersection",
|
||||||
"Mesh",
|
"Mesh",
|
||||||
"MotionStreak",
|
"MotionStreak",
|
||||||
|
"NodePool",
|
||||||
"Physics",
|
"Physics",
|
||||||
"PageView",
|
"PageView",
|
||||||
"PageViewIndicator",
|
"PageViewIndicator",
|
||||||
|
"ParticleSystem",
|
||||||
"RichText",
|
"RichText",
|
||||||
"Slider",
|
"Slider",
|
||||||
|
"ScrollBar",
|
||||||
|
"ScrollView",
|
||||||
"Spine Skeleton",
|
"Spine Skeleton",
|
||||||
"StudioComponent",
|
"StudioComponent",
|
||||||
"VideoPlayer",
|
"VideoPlayer",
|
||||||
@@ -68,7 +76,7 @@
|
|||||||
"shelter_z_reducer",
|
"shelter_z_reducer",
|
||||||
"shelter"
|
"shelter"
|
||||||
],
|
],
|
||||||
"last-module-event-record-time": 1673930863015,
|
"last-module-event-record-time": 1675852779064,
|
||||||
"simulator-orientation": false,
|
"simulator-orientation": false,
|
||||||
"simulator-resolution": {
|
"simulator-resolution": {
|
||||||
"height": 640,
|
"height": 640,
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "TEMPLATES.helloworld.name",
|
"name": "DelayNoMore",
|
||||||
"desc": "TEMPLATES.helloworld.desc",
|
"desc": "DelayNoMore",
|
||||||
"banner": "template-banner.png"
|
"banner": "template-banner.png"
|
||||||
}
|
}
|
||||||
|