mirror of
https://github.com/genxium/DelayNoMore
synced 2025-10-17 04:29:00 +00:00
Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
1c6ad5c8f8 | ||
|
34e0893eb8 | ||
|
cc7524becd | ||
|
d06cb18a08 | ||
|
00816fb636 | ||
|
ff24bea055 | ||
|
56d66a128a | ||
|
2f097dfec5 | ||
|
ff48b47ecc |
@@ -69,4 +69,10 @@ To summarize, if UDP is used we need
|
||||
When using UDP, it's also necessary to verify authorization of each incoming packet, e.g. by simple time limited symmetric key, due to being connectionless.
|
||||
|
||||
## Why not hybrid?
|
||||
Instead of replacing all use of TCP by UDP, it's more reasonable to keep using TCP for login and the "all-confirmed downsync inputFrames" from server to players (and possibly "upsync inputFrames" from player to server, but tradeoff on that remains to be discussed), while using UDP for broadcasting inputFrames of each individual player asap (either using p2p or not) just for **better prediction performance**!
|
||||
Instead of replacing all use of TCP by UDP, it's more reasonable to keep using TCP for login and the "all-confirmed downsync inputFrames" from server to players (and possibly "upsync inputFrames" from player to server, but tradeoff on that remains to be discussed), while using a `UDP secondary session` for broadcasting inputFrames of each individual player asap (either using p2p or not) just for **better prediction performance**!
|
||||
|
||||
## How do you actually implement the `UDP secondary session`?
|
||||
It's not a global consensus, but in practice many UDP communications are platform specific due to their paired asynchronous I/O choices, e.g. epoll in Linux and kqueue in BSD-ish. Of course there're many 3rd party higher level encapsulated tools for cross-platform use but that introduces extra debugging when things go wrong.
|
||||
|
||||
Therefore, the following plan doesn't assume use of any specific 3rd party encapsulation of UDP communication.
|
||||

|
13
README.md
13
README.md
@@ -3,19 +3,14 @@
|
||||
This project is a demo for a websocket-based rollback netcode inspired by [GGPO](https://github.com/pond3r/ggpo/blob/master/doc/README.md). As lots of feedbacks ask for a discussion on using UDP instead, I tried to summarize my personal opinion about it in [ConcerningEdgeCases](./ConcerningEdgeCases.md) -- not necessarily correct but that's indeed a question to face :)
|
||||
|
||||
The following video is recorded over INTERNET using an input delay of 4 frames and it feels SMOOTH when playing! Please also checkout these demo videos
|
||||
- [source video of the first gif](https://pan.baidu.com/s/1ML6hNupaPHPJRd5rcTvQvw?pwd=8ruc)
|
||||
- [phone v.s. PC over internet battle#1](https://pan.baidu.com/s/1NuGxuMwrV_jalcToyUZPLg?pwd=kfkr)
|
||||
- [phone v.s. PC over internet battle#2](https://pan.baidu.com/s/1kMiFdwDHyJpZJ0GGU1Y3eA?pwd=46gd)
|
||||
- [PC Wifi viewing Phone 4g](https://pan.baidu.com/s/1PJEtC9iB_fcabMWhbx2oAg?pwd=tp7k)
|
||||
- [PC Wifi viewing Phone Wifi (over internet of course)](https://pan.baidu.com/s/108rvC1CcUdiQeMauXWsLJg?pwd=mn39)
|
||||
- [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.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
All gifs are sped up to ~1.5x for file size reduction, kindly note that animations are resumed from a partial progress!
|
||||

|
||||
|
||||
# Notable Features
|
||||
- Backend dynamics toggle via [Room.BackendDynamicsEnabled](https://github.com/genxium/DelayNoMore/blob/v0.9.14/battle_srv/models/room.go#L786)
|
||||
@@ -111,3 +106,5 @@ Moreover, in practice I found that to spot sync anomalies, the following tools a
|
||||
- Detection of [prediction mismatch on the frontend](https://github.com/genxium/DelayNoMore/blob/v0.9.19/frontend/assets/scripts/Map.js#L842).
|
||||
- Detection of [type#1 forceConfirmation on the backend](https://github.com/genxium/DelayNoMore/blob/v0.9.19/battle_srv/models/room.go#L1246).
|
||||
- Detection of [type#2 forceConfirmation on the backend](https://github.com/genxium/DelayNoMore/blob/v0.9.19/battle_srv/models/room.go#L1259).
|
||||
|
||||
There's also some useful information displayed on the frontend when `true == Map.showNetworkDoctorInfo`.
|
||||
|
File diff suppressed because one or more lines are too long
BIN
charts/UDPEssentials.jpg
Normal file
BIN
charts/UDPEssentials.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 417 KiB |
BIN
charts/internet_dash_turnaround_cut_spedup.gif
Normal file
BIN
charts/internet_dash_turnaround_cut_spedup.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.7 MiB |
Binary file not shown.
Before Width: | Height: | Size: 11 MiB |
@@ -1,66 +0,0 @@
|
||||
function NetworkDoctor(serverFps, clientUpsyncFps) {
|
||||
this.serverFps = serverFps;
|
||||
this.clientUpsyncFps = clientUpsyncFps;
|
||||
this.millisPerServerFrame = parseInt(1000 / this.serverFps);
|
||||
this._tooLongSinceLastFrameDiffReceivedThreshold = (this.millisPerServerFrame << 6);
|
||||
|
||||
this.setupFps = function(fps) {
|
||||
this.serverFps = this.clientUpsyncFps = fps;
|
||||
this.millisPerServerFrame = parseInt(1000 / this.serverFps);
|
||||
this._tooLongSinceLastFrameDiffReceivedThreshold = (this.millisPerServerFrame << 6);
|
||||
}
|
||||
|
||||
this._lastFrameDiffRecvTime = null;
|
||||
this._tooLongSinceLastFrameDiffReceived = function() {
|
||||
if (undefined === this._lastFrameDiffRecvTime || null === this._lastFrameDiffRecvTime) return false;
|
||||
return (this._tooLongSinceLastFrameDiffReceivedThreshold <= (Date.now() - this._lastFrameDiffRecvTime));
|
||||
};
|
||||
|
||||
this._consecutiveALittleLongFrameDiffReceivedIntervalCount = 0;
|
||||
this._consecutiveALittleLongFrameDiffReceivedIntervalCountThreshold = 120;
|
||||
|
||||
this.onNewFrameDiffReceived = function(frameDiff) {
|
||||
var now = Date.now();
|
||||
if (undefined !== this._lastFrameDiffRecvTime && null !== this._lastFrameDiffRecvTime) {
|
||||
var intervalFromLastFrameDiff = (now - this._lastFrameDiffRecvTime);
|
||||
if ((this.millisPerServerFrame << 5) < intervalFromLastFrameDiff) {
|
||||
++this._consecutiveALittleLongFrameDiffReceivedIntervalCount;
|
||||
console.log('Medium delay, intervalFromLastFrameDiff is', intervalFromLastFrameDiff);
|
||||
} else {
|
||||
this._consecutiveALittleLongFrameDiffReceivedIntervalCount = 0;
|
||||
}
|
||||
}
|
||||
this._lastFrameDiffRecvTime = now;
|
||||
};
|
||||
|
||||
this._networkComplaintPrefix = "\nNetwork is not good >_<\n";
|
||||
|
||||
this.generateNetworkComplaint = function(excludeTypeConstantALittleLongFrameDiffReceivedInterval, excludeTypeTooLongSinceLastFrameDiffReceived) {
|
||||
if (this.hasBattleStopped) return null;
|
||||
var shouldComplain = false;
|
||||
var ret = this._networkComplaintPrefix;
|
||||
if (true != excludeTypeConstantALittleLongFrameDiffReceivedInterval && this._consecutiveALittleLongFrameDiffReceivedIntervalCountThreshold <= this._consecutiveALittleLongFrameDiffReceivedIntervalCount) {
|
||||
this._consecutiveALittleLongFrameDiffReceivedIntervalCount = 0;
|
||||
ret += "\nConstantly having a little long recv interval.\n";
|
||||
shouldComplain = true;
|
||||
}
|
||||
if (true != excludeTypeTooLongSinceLastFrameDiffReceived && this._tooLongSinceLastFrameDiffReceived()) {
|
||||
ret += "\nToo long since last received frameDiff.\n";
|
||||
shouldComplain = true;
|
||||
}
|
||||
return (shouldComplain ? ret : null);
|
||||
};
|
||||
|
||||
this.hasBattleStopped = false;
|
||||
this.onBattleStopped = function() {
|
||||
this.hasBattleStopped = true;
|
||||
};
|
||||
|
||||
this.isClientSessionConnected = function() {
|
||||
if (!window.game) return false;
|
||||
if (!window.game.clientSession) return false;
|
||||
return window.game.clientSession.connected;
|
||||
};
|
||||
}
|
||||
|
||||
window.NetworkDoctor = NetworkDoctor;
|
File diff suppressed because one or more lines are too long
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "d41313ca-b2c3-4436-a05f-7e0eb290b1e6",
|
||||
"uuid": "40edd08e-316c-44b8-a50f-bd173554c554",
|
||||
"isPlugin": true,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
|
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"__type__": "cc.AnimationClip",
|
||||
"_name": "TurnAround1",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_duration": 0.15,
|
||||
"sample": 60,
|
||||
"speed": 1,
|
||||
"wrapMode": 1,
|
||||
"curveData": {
|
||||
"comps": {
|
||||
"cc.Sprite": {
|
||||
"spriteFrame": [
|
||||
{
|
||||
"frame": 0,
|
||||
"value": {
|
||||
"__uuid__": "28ee1f29-e538-4d36-bb5c-275f9e3b392b"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.03333333333333333,
|
||||
"value": {
|
||||
"__uuid__": "211a73bb-31d7-4e6c-901e-f6939d9214e0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.08333333333333333,
|
||||
"value": {
|
||||
"__uuid__": "048c41dc-fc00-4bc4-8041-6003e7c2b6e4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.13333333333333333,
|
||||
"value": {
|
||||
"__uuid__": "9435195e-4560-495e-b1ae-083c0c87e8a0"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": []
|
||||
}
|
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"ver": "2.1.0",
|
||||
"uuid": "e906322d-a08b-4477-a2e9-98acd42fa034",
|
||||
"subMetas": {}
|
||||
}
|
43
frontend/assets/resources/animation/Monk/TurnAround1.anim
Normal file
43
frontend/assets/resources/animation/Monk/TurnAround1.anim
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"__type__": "cc.AnimationClip",
|
||||
"_name": "TurnAround1",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_duration": 0.15,
|
||||
"sample": 60,
|
||||
"speed": 1,
|
||||
"wrapMode": 1,
|
||||
"curveData": {
|
||||
"comps": {
|
||||
"cc.Sprite": {
|
||||
"spriteFrame": [
|
||||
{
|
||||
"frame": 0,
|
||||
"value": {
|
||||
"__uuid__": "ee5e05fa-b515-470f-bc3c-43544f02cb92"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.03333333333333333,
|
||||
"value": {
|
||||
"__uuid__": "ffa521b6-118e-46e8-be1c-51cc54381ec8"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.08333333333333333,
|
||||
"value": {
|
||||
"__uuid__": "0b27d2c9-c5a3-4020-adbe-0297c1ba3aeb"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.13333333333333333,
|
||||
"value": {
|
||||
"__uuid__": "a47f518e-62fb-4549-8897-4f2d387bd145"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": []
|
||||
}
|
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"ver": "2.1.0",
|
||||
"uuid": "edd23b2f-1caa-4836-88a7-e4af1f26743e",
|
||||
"subMetas": {}
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"__type__": "cc.AnimationClip",
|
||||
"_name": "TurnAround1",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_duration": 0.15,
|
||||
"sample": 60,
|
||||
"speed": 1,
|
||||
"wrapMode": 1,
|
||||
"curveData": {
|
||||
"comps": {
|
||||
"cc.Sprite": {
|
||||
"spriteFrame": [
|
||||
{
|
||||
"frame": 0,
|
||||
"value": {
|
||||
"__uuid__": "c1a00209-f74d-41b5-a5da-df5720ac34b4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.03333333333333333,
|
||||
"value": {
|
||||
"__uuid__": "2b52c0f1-2360-4a2b-9233-bf5662de09a5"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.08333333333333333,
|
||||
"value": {
|
||||
"__uuid__": "e3f9dfe7-ed91-4dc3-b68b-a3a3c2637074"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.13333333333333333,
|
||||
"value": {
|
||||
"__uuid__": "7515ef50-3a14-4e58-8811-a0c890fc40f3"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": []
|
||||
}
|
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"ver": "2.1.0",
|
||||
"uuid": "6e1139d4-03dd-4bd4-9510-606e94f629fe",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,11 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.2" tiledversion="1.2.3" orientation="orthogonal" renderorder="right-down" width="128" height="64" tilewidth="16" tileheight="16" infinite="0" nextlayerid="7" nextobjectid="135">
|
||||
<map version="1.2" tiledversion="1.2.3" orientation="orthogonal" renderorder="right-down" width="128" height="64" tilewidth="16" tileheight="16" infinite="0" nextlayerid="7" nextobjectid="137">
|
||||
<tileset firstgid="1" source="tiles0.tsx"/>
|
||||
<tileset firstgid="65" source="tiles1.tsx"/>
|
||||
<tileset firstgid="129" source="tiles2.tsx"/>
|
||||
<layer id="6" name="Ground" width="128" height="64">
|
||||
<data encoding="base64" compression="zlib">
|
||||
eJzt2ztuAjEURmELlIYuiKRHyk4iGjo2wP6XkRDGUmThxwx3fC3+U3wNw8v3eEyabEMIWwAAAAAAAAAAAADo4IQ/3h08+3t/B2/KM1BeOzPQXjsz0F47M6iv/c3oc6zeh/7+/Q+NHr1P6z7YGz2H/svWXur1TP/SvqL/OP1LnSz6t7Qt9a1dp//4/VvOgJJeM3hlLf2tzNljI83glY2+9vcMpRko9E/PgFz3NfbBKDNQ7r+kvdU+GHEGHv2/Gl9zNHrOKOh/t5vQX8dt7d+JeC19PDo2yr1+NHEG3i28+m8m8f6//jpnbAzkfsNr15eqfR/1+z/tfxP/Fvj/mFX/0dD/7pz0fsR69p8rmHv20D9vl5mZ1flb67VkP81pT/8QPialmT1z/5f2QK/7v7Q/6Z/vb6F0DvToXzuf1PvDv4Nn/4s4+mujvzb6a6O/Nvpro782+mujvzb6a6O/Nvpro782+mujvzb6a6O/Nvpro782+mujvzb6a6O/tvg/UN4t6E9/+tO/d3+s1/8HUhSy6A==
|
||||
eJzt201uwjAQhuEIxCY7KugeqTepumHXC/T+xyCqYimy4sQ4E2bE9y6eDf+e1w4bOHZddwQAAAAAAAAAAACAF/jBP+8Onv29P4M35Rkor50ZaK+dGWivnRlor50ZtK39UmnL5/owegz94/X/on8Ykfsv9V27n/72a0/drPqfBucZeeMSjxm8m5b+W1m9Dv3fv//c9eG88f3p397fytr1vNR9j31A/1hq21vtg4gziNz/ZvQY+vubrr0fefdv3QOt+0O9/3cm3ZffntwqlZ4fTZqBdwuv/odROv9/g3vBwUDpjFq8dst7q5//vP/0O2B6m1V/T/Qv979nvedY9/jcwTPXHPov9+lXZldjrb/1fqL/c/2vo6W5bTn/S3tg7/Nfsz/pX+5v+Z1L/3i8f3cdhXcHz/6/4uivjf7a6K+N/tror43+2uivjf7a6K+N/tror43+2uivjf7a6K+N/tror43+2uivjf7a6K+N/trSf6C8W9Cf/vSn/6v7Y7/+Dyz1uAA=
|
||||
</data>
|
||||
</layer>
|
||||
<objectgroup id="1" name="PlayerStartingPos">
|
||||
@@ -64,7 +64,7 @@
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object id="60" x="1232" y="432" width="208" height="16">
|
||||
<object id="60" x="1232" y="448" width="208" height="16">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
@@ -99,7 +99,7 @@
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object id="90" x="1232" y="496" width="320" height="16">
|
||||
<object id="90" x="1248" y="464" width="320" height="16">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
@@ -114,37 +114,37 @@
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object id="100" x="1552" y="576" width="128" height="16">
|
||||
<object id="100" x="1538" y="560" width="144" height="32">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object id="101" x="1568" y="560" width="112" height="16">
|
||||
<object id="101" x="1568" y="528" width="112" height="32">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object id="102" x="1584" y="544" width="96" height="16">
|
||||
<object id="102" x="1136" y="368" width="96" height="16">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object id="103" x="1600" y="528" width="80" height="16">
|
||||
<object id="103" x="1600" y="496" width="80" height="32">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object id="104" x="768" y="382" width="304" height="16">
|
||||
<object id="104" x="816" y="414" width="304" height="16">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object id="105" x="768" y="302" width="16" height="96">
|
||||
<object id="105" x="816" y="366" width="16" height="64">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object id="106" x="1056" y="302" width="16" height="96">
|
||||
<object id="106" x="1104" y="334" width="16" height="96">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
@@ -164,42 +164,7 @@
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object id="120" x="736" y="512" width="16" height="16">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object id="121" x="736" y="336" width="16" height="16">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object id="125" x="688" y="448" width="16" height="16">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object id="127" x="1088" y="320" width="16" height="16">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object id="128" x="1120" y="336" width="16" height="16">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object id="129" x="1136" y="368" width="16" height="16">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object id="130" x="1168" y="384" width="16" height="16">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object id="132" x="1184" y="416" width="16" height="16">
|
||||
<object id="136" x="1232" y="432" width="208" height="16">
|
||||
<properties>
|
||||
<property name="boundary_type" value="barrier"/>
|
||||
</properties>
|
||||
|
@@ -482,6 +482,13 @@
|
||||
},
|
||||
{
|
||||
"__uuid__": "e8247e2a-1b5b-4618-86f8-224b25246b55"
|
||||
},
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
{
|
||||
"__uuid__": "6e1139d4-03dd-4bd4-9510-606e94f629fe"
|
||||
}
|
||||
],
|
||||
"playOnLoad": false,
|
||||
@@ -653,6 +660,9 @@
|
||||
},
|
||||
{
|
||||
"__uuid__": "411f964a-4dd8-424c-b2e2-d92b10474ce2"
|
||||
},
|
||||
{
|
||||
"__uuid__": "e906322d-a08b-4477-a2e9-98acd42fa034"
|
||||
}
|
||||
],
|
||||
"playOnLoad": false,
|
||||
@@ -822,6 +832,11 @@
|
||||
},
|
||||
{
|
||||
"__uuid__": "0abbd156-980e-475e-9994-3c958bd913fc"
|
||||
},
|
||||
null,
|
||||
null,
|
||||
{
|
||||
"__uuid__": "edd23b2f-1caa-4836-88a7-e4af1f26743e"
|
||||
}
|
||||
],
|
||||
"playOnLoad": false,
|
||||
|
@@ -78,19 +78,19 @@
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 40
|
||||
"__id__": 48
|
||||
},
|
||||
{
|
||||
"__id__": 41
|
||||
"__id__": 49
|
||||
},
|
||||
{
|
||||
"__id__": 42
|
||||
"__id__": 50
|
||||
},
|
||||
{
|
||||
"__id__": 43
|
||||
"__id__": 51
|
||||
},
|
||||
{
|
||||
"__id__": 44
|
||||
"__id__": 52
|
||||
}
|
||||
],
|
||||
"_prefab": null,
|
||||
@@ -158,7 +158,7 @@
|
||||
"__id__": 5
|
||||
},
|
||||
{
|
||||
"__id__": 39
|
||||
"__id__": 47
|
||||
}
|
||||
],
|
||||
"_prefab": null,
|
||||
@@ -247,10 +247,10 @@
|
||||
"__uuid__": "670b477e-61a1-4778-879b-35913f7c79d2"
|
||||
},
|
||||
"boundRoomIdLabel": {
|
||||
"__id__": 16
|
||||
"__id__": 24
|
||||
},
|
||||
"countdownLabel": {
|
||||
"__id__": 23
|
||||
"__id__": 31
|
||||
},
|
||||
"resultPanelPrefab": {
|
||||
"__uuid__": "c4cfe3bd-c59e-4d5b-95cb-c933b120e184"
|
||||
@@ -269,9 +269,18 @@
|
||||
},
|
||||
"forceBigEndianFloatingNumDecoding": false,
|
||||
"renderFrameIdLagTolerance": 4,
|
||||
"jigglingEps1D": 0.001,
|
||||
"bulletTriggerEnabled": true,
|
||||
"closeOnForcedtoResyncNotSelf": true,
|
||||
"sendingQLabel": {
|
||||
"__id__": 13
|
||||
},
|
||||
"inputFrameDownsyncQLabel": {
|
||||
"__id__": 15
|
||||
},
|
||||
"peerInputFrameUpsyncQLabel": {
|
||||
"__id__": 17
|
||||
},
|
||||
"rollbackFramesLabel": {
|
||||
"__id__": 19
|
||||
},
|
||||
"_id": "d12gkAmppNlIzqcRDELa91"
|
||||
},
|
||||
{
|
||||
@@ -283,13 +292,13 @@
|
||||
},
|
||||
"_children": [
|
||||
{
|
||||
"__id__": 33
|
||||
"__id__": 41
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 38
|
||||
"__id__": 46
|
||||
}
|
||||
],
|
||||
"_prefab": null,
|
||||
@@ -352,19 +361,19 @@
|
||||
"__id__": 6
|
||||
},
|
||||
{
|
||||
"__id__": 22
|
||||
"__id__": 30
|
||||
},
|
||||
{
|
||||
"__id__": 24
|
||||
"__id__": 32
|
||||
},
|
||||
{
|
||||
"__id__": 28
|
||||
"__id__": 36
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 32
|
||||
"__id__": 40
|
||||
}
|
||||
],
|
||||
"_prefab": null,
|
||||
@@ -433,7 +442,7 @@
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 21
|
||||
"__id__": 29
|
||||
}
|
||||
],
|
||||
"_prefab": null,
|
||||
@@ -527,7 +536,7 @@
|
||||
"array": [
|
||||
0,
|
||||
0,
|
||||
209.57814771583418,
|
||||
216.50635094610968,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
@@ -596,15 +605,27 @@
|
||||
"_children": [
|
||||
{
|
||||
"__id__": 12
|
||||
},
|
||||
{
|
||||
"__id__": 14
|
||||
},
|
||||
{
|
||||
"__id__": 16
|
||||
},
|
||||
{
|
||||
"__id__": 18
|
||||
},
|
||||
{
|
||||
"__id__": 20
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 19
|
||||
"__id__": 27
|
||||
},
|
||||
{
|
||||
"__id__": 20
|
||||
"__id__": 28
|
||||
}
|
||||
],
|
||||
"_prefab": null,
|
||||
@@ -655,6 +676,374 @@
|
||||
"groupIndex": 0,
|
||||
"_id": "35scg40jVAnKrTPiei5ckg"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "sendingQ",
|
||||
"_objFlags": 0,
|
||||
"_parent": {
|
||||
"__id__": 11
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 13
|
||||
}
|
||||
],
|
||||
"_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.5,
|
||||
"y": 0.5
|
||||
},
|
||||
"_trs": {
|
||||
"__type__": "TypedArray",
|
||||
"ctor": "Float64Array",
|
||||
"array": [
|
||||
64,
|
||||
85.51,
|
||||
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": "ack7XH+0lEj6chSUsKBLU5"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Label",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"node": {
|
||||
"__id__": 12
|
||||
},
|
||||
"_enabled": true,
|
||||
"_materials": [
|
||||
{
|
||||
"__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432"
|
||||
}
|
||||
],
|
||||
"_useOriginalSize": false,
|
||||
"_string": "0",
|
||||
"_N$string": "0",
|
||||
"_fontSize": 22,
|
||||
"_lineHeight": 23,
|
||||
"_enableWrapText": true,
|
||||
"_N$file": null,
|
||||
"_isSystemFontUsed": true,
|
||||
"_spacingX": 0,
|
||||
"_batchAsBitmap": false,
|
||||
"_N$horizontalAlign": 0,
|
||||
"_N$verticalAlign": 1,
|
||||
"_N$fontFamily": "Arial",
|
||||
"_N$overflow": 0,
|
||||
"_N$cacheMode": 0,
|
||||
"_id": "deCJfLuoFO36c/O4lXWJ1N"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "inputFrameDownsyncQ",
|
||||
"_objFlags": 0,
|
||||
"_parent": {
|
||||
"__id__": 11
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 15
|
||||
}
|
||||
],
|
||||
"_prefab": null,
|
||||
"_opacity": 255,
|
||||
"_color": {
|
||||
"__type__": "cc.Color",
|
||||
"r": 255,
|
||||
"g": 255,
|
||||
"b": 255,
|
||||
"a": 255
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 12.24,
|
||||
"height": 28.98
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0.5
|
||||
},
|
||||
"_trs": {
|
||||
"__type__": "TypedArray",
|
||||
"ctor": "Float64Array",
|
||||
"array": [
|
||||
64,
|
||||
56.53000000000001,
|
||||
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": "d9n+NRm9pA0YtKxvy4bW+U"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Label",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"node": {
|
||||
"__id__": 14
|
||||
},
|
||||
"_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": "90NvjGFrpBFqqzl1WZczta"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "peerInputFrameUpsyncQ",
|
||||
"_objFlags": 0,
|
||||
"_parent": {
|
||||
"__id__": 11
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 17
|
||||
}
|
||||
],
|
||||
"_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.5,
|
||||
"y": 0.5
|
||||
},
|
||||
"_trs": {
|
||||
"__type__": "TypedArray",
|
||||
"ctor": "Float64Array",
|
||||
"array": [
|
||||
64,
|
||||
27.550000000000004,
|
||||
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": "45FAmgRLZNNbLt/GcnTXVx"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Label",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"node": {
|
||||
"__id__": 16
|
||||
},
|
||||
"_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": "42PRTrjEpDw6Z8N5yWFTpd"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "rollbackFrames",
|
||||
"_objFlags": 0,
|
||||
"_parent": {
|
||||
"__id__": 11
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 19
|
||||
}
|
||||
],
|
||||
"_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.5,
|
||||
"y": 0.5
|
||||
},
|
||||
"_trs": {
|
||||
"__type__": "TypedArray",
|
||||
"ctor": "Float64Array",
|
||||
"array": [
|
||||
64,
|
||||
-1.4299999999999962,
|
||||
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": "f5SBs3b1pPNbHbnqVLYsHp"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Label",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"node": {
|
||||
"__id__": 18
|
||||
},
|
||||
"_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": "77aNARt1VATLsjIzwbqvkh"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "RoomIdIndicator",
|
||||
@@ -664,19 +1053,19 @@
|
||||
},
|
||||
"_children": [
|
||||
{
|
||||
"__id__": 13
|
||||
"__id__": 21
|
||||
},
|
||||
{
|
||||
"__id__": 15
|
||||
"__id__": 23
|
||||
}
|
||||
],
|
||||
"_active": false,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 17
|
||||
"__id__": 25
|
||||
},
|
||||
{
|
||||
"__id__": 18
|
||||
"__id__": 26
|
||||
}
|
||||
],
|
||||
"_prefab": null,
|
||||
@@ -732,13 +1121,13 @@
|
||||
"_name": "label",
|
||||
"_objFlags": 0,
|
||||
"_parent": {
|
||||
"__id__": 12
|
||||
"__id__": 20
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 14
|
||||
"__id__": 22
|
||||
}
|
||||
],
|
||||
"_prefab": null,
|
||||
@@ -794,7 +1183,7 @@
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"node": {
|
||||
"__id__": 13
|
||||
"__id__": 21
|
||||
},
|
||||
"_enabled": true,
|
||||
"_materials": [],
|
||||
@@ -822,13 +1211,13 @@
|
||||
"_name": "BoundRoomIdLabel",
|
||||
"_objFlags": 0,
|
||||
"_parent": {
|
||||
"__id__": 12
|
||||
"__id__": 20
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 16
|
||||
"__id__": 24
|
||||
}
|
||||
],
|
||||
"_prefab": null,
|
||||
@@ -884,7 +1273,7 @@
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"node": {
|
||||
"__id__": 15
|
||||
"__id__": 23
|
||||
},
|
||||
"_enabled": true,
|
||||
"_materials": [],
|
||||
@@ -912,7 +1301,7 @@
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"node": {
|
||||
"__id__": 12
|
||||
"__id__": 20
|
||||
},
|
||||
"_enabled": true,
|
||||
"_layoutSize": {
|
||||
@@ -945,7 +1334,7 @@
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"node": {
|
||||
"__id__": 12
|
||||
"__id__": 20
|
||||
},
|
||||
"_enabled": true,
|
||||
"_materials": [],
|
||||
@@ -1067,7 +1456,7 @@
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 23
|
||||
"__id__": 31
|
||||
}
|
||||
],
|
||||
"_prefab": null,
|
||||
@@ -1123,7 +1512,7 @@
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"node": {
|
||||
"__id__": 22
|
||||
"__id__": 30
|
||||
},
|
||||
"_enabled": true,
|
||||
"_materials": [
|
||||
@@ -1157,7 +1546,7 @@
|
||||
},
|
||||
"_children": [
|
||||
{
|
||||
"__id__": 25
|
||||
"__id__": 33
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
@@ -1215,16 +1604,16 @@
|
||||
"_name": "Background",
|
||||
"_objFlags": 0,
|
||||
"_parent": {
|
||||
"__id__": 24
|
||||
"__id__": 32
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 26
|
||||
"__id__": 34
|
||||
},
|
||||
{
|
||||
"__id__": 27
|
||||
"__id__": 35
|
||||
}
|
||||
],
|
||||
"_prefab": null,
|
||||
@@ -1280,7 +1669,7 @@
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"node": {
|
||||
"__id__": 25
|
||||
"__id__": 33
|
||||
},
|
||||
"_enabled": true,
|
||||
"_materials": [
|
||||
@@ -1314,7 +1703,7 @@
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"node": {
|
||||
"__id__": 25
|
||||
"__id__": 33
|
||||
},
|
||||
"_enabled": true,
|
||||
"alignMode": 0,
|
||||
@@ -1345,7 +1734,7 @@
|
||||
},
|
||||
"_children": [
|
||||
{
|
||||
"__id__": 29
|
||||
"__id__": 37
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
@@ -1403,16 +1792,16 @@
|
||||
"_name": "Background",
|
||||
"_objFlags": 0,
|
||||
"_parent": {
|
||||
"__id__": 28
|
||||
"__id__": 36
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 30
|
||||
"__id__": 38
|
||||
},
|
||||
{
|
||||
"__id__": 31
|
||||
"__id__": 39
|
||||
}
|
||||
],
|
||||
"_prefab": null,
|
||||
@@ -1468,7 +1857,7 @@
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"node": {
|
||||
"__id__": 29
|
||||
"__id__": 37
|
||||
},
|
||||
"_enabled": true,
|
||||
"_materials": [
|
||||
@@ -1502,7 +1891,7 @@
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"node": {
|
||||
"__id__": 29
|
||||
"__id__": 37
|
||||
},
|
||||
"_enabled": true,
|
||||
"alignMode": 0,
|
||||
@@ -1560,16 +1949,16 @@
|
||||
},
|
||||
"_children": [
|
||||
{
|
||||
"__id__": 34
|
||||
"__id__": 42
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 36
|
||||
"__id__": 44
|
||||
},
|
||||
{
|
||||
"__id__": 37
|
||||
"__id__": 45
|
||||
}
|
||||
],
|
||||
"_prefab": null,
|
||||
@@ -1625,13 +2014,13 @@
|
||||
"_name": "Joystick",
|
||||
"_objFlags": 0,
|
||||
"_parent": {
|
||||
"__id__": 33
|
||||
"__id__": 41
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 35
|
||||
"__id__": 43
|
||||
}
|
||||
],
|
||||
"_prefab": null,
|
||||
@@ -1687,7 +2076,7 @@
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"node": {
|
||||
"__id__": 34
|
||||
"__id__": 42
|
||||
},
|
||||
"_enabled": true,
|
||||
"_materials": [
|
||||
@@ -1721,7 +2110,7 @@
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"node": {
|
||||
"__id__": 33
|
||||
"__id__": 41
|
||||
},
|
||||
"_enabled": true,
|
||||
"_materials": [
|
||||
@@ -1755,7 +2144,7 @@
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"node": {
|
||||
"__id__": 33
|
||||
"__id__": 41
|
||||
},
|
||||
"_enabled": true,
|
||||
"alignMode": 0,
|
||||
@@ -1908,10 +2297,10 @@
|
||||
"__id__": 3
|
||||
},
|
||||
"stickhead": {
|
||||
"__id__": 34
|
||||
"__id__": 42
|
||||
},
|
||||
"base": {
|
||||
"__id__": 33
|
||||
"__id__": 41
|
||||
},
|
||||
"joyStickEps": 0.1,
|
||||
"magicLeanLowerBound": 0.414,
|
||||
@@ -1932,10 +2321,10 @@
|
||||
"linearMovingEps": 0.1,
|
||||
"scaleByEps": 0.0375,
|
||||
"btnA": {
|
||||
"__id__": 24
|
||||
"__id__": 32
|
||||
},
|
||||
"btnB": {
|
||||
"__id__": 28
|
||||
"__id__": 36
|
||||
},
|
||||
"_id": "e9oVYTr7ROlpp/IrNjBUmR"
|
||||
}
|
||||
|
@@ -362,7 +362,7 @@
|
||||
"array": [
|
||||
0,
|
||||
0,
|
||||
215.64032554232523,
|
||||
216.50635094610968,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -18,6 +18,7 @@ window.ATK_CHARACTER_STATE = {
|
||||
Atk5: [14, "Atk5"],
|
||||
Dashing: [15, "Dashing"],
|
||||
OnWall: [16, "OnWall"],
|
||||
TurnAround1: [17, "TurnAround1"],
|
||||
};
|
||||
|
||||
window.ATK_CHARACTER_STATE_ARR = [];
|
||||
@@ -93,7 +94,7 @@ cc.Class({
|
||||
} else if (0 < rdfPlayer.DirX) {
|
||||
this.animNode.scaleX = (+1.0);
|
||||
}
|
||||
if (ATK_CHARACTER_STATE.OnWall[0] == newCharacterState) {
|
||||
if (ATK_CHARACTER_STATE.OnWall[0] == newCharacterState || ATK_CHARACTER_STATE.TurnAround1[0] == newCharacterState) {
|
||||
if (0 < rdfPlayer.OnWallNormX) {
|
||||
this.animNode.scaleX = (-1.0);
|
||||
} else {
|
||||
|
@@ -2,6 +2,7 @@ const i18n = require('LanguageData');
|
||||
i18n.init(window.language); // languageID should be equal to the one we input in New Language ID input field
|
||||
|
||||
const RingBuffer = require('./RingBuffer');
|
||||
const NetworkDoctor = require('./NetworkDoctor');
|
||||
const PriorityQueue = require("./PriorityQueue");
|
||||
|
||||
window.ALL_MAP_STATES = {
|
||||
@@ -96,15 +97,21 @@ cc.Class({
|
||||
type: cc.Integer,
|
||||
default: 4 // implies (renderFrameIdLagTolerance >> inputScaleFrames) count of inputFrameIds
|
||||
},
|
||||
jigglingEps1D: {
|
||||
type: cc.Float,
|
||||
default: 1e-3
|
||||
sendingQLabel: {
|
||||
type: cc.Label,
|
||||
default: null
|
||||
},
|
||||
bulletTriggerEnabled: {
|
||||
default: false
|
||||
inputFrameDownsyncQLabel: {
|
||||
type: cc.Label,
|
||||
default: null
|
||||
},
|
||||
closeOnForcedtoResyncNotSelf: {
|
||||
default: true
|
||||
peerInputFrameUpsyncQLabel: {
|
||||
type: cc.Label,
|
||||
default: null
|
||||
},
|
||||
rollbackFramesLabel: {
|
||||
type: cc.Label,
|
||||
default: null
|
||||
},
|
||||
},
|
||||
|
||||
@@ -184,6 +191,7 @@ cc.Class({
|
||||
// Upon resync, "self.lastUpsyncInputFrameId" might not have been updated properly.
|
||||
batchInputFrameIdSt = self.recentInputCache.StFrameId;
|
||||
}
|
||||
self.networkDoctor.logSending(batchInputFrameIdSt, latestLocalInputFrameId);
|
||||
for (let i = batchInputFrameIdSt; i <= latestLocalInputFrameId; ++i) {
|
||||
const inputFrameDownsync = self.recentInputCache.GetByFrameId(i);
|
||||
if (null == inputFrameDownsync) {
|
||||
@@ -342,6 +350,8 @@ cc.Class({
|
||||
self.othersForcedDownsyncRenderFrameDict = new Map();
|
||||
self.rdfIdToActuallyUsedInput = new Map();
|
||||
|
||||
self.networkDoctor = new NetworkDoctor(20);
|
||||
|
||||
self.countdownNanos = null;
|
||||
if (self.countdownLabel) {
|
||||
self.countdownLabel.string = "";
|
||||
@@ -409,6 +419,7 @@ cc.Class({
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
cc.game.setFrameRate(60);
|
||||
cc.view.setOrientation(cc.macro.ORIENTATION_LANDSCAPE);
|
||||
cc.view.enableAutoFullScreen(true);
|
||||
|
||||
@@ -417,6 +428,7 @@ cc.Class({
|
||||
window.forceBigEndianFloatingNumDecoding = self.forceBigEndianFloatingNumDecoding;
|
||||
|
||||
self.showCriticalCoordinateLabels = false;
|
||||
self.showNetworkDoctorInfo = true;
|
||||
|
||||
console.warn("+++++++ Map onLoad()");
|
||||
|
||||
@@ -796,6 +808,7 @@ cc.Class({
|
||||
return;
|
||||
}
|
||||
|
||||
self.networkDoctor.logInputFrameDownsync(batch[0].inputFrameId, batch[batch.length - 1].inputFrameId);
|
||||
let firstPredictedYetIncorrectInputFrameId = null;
|
||||
for (let k in batch) {
|
||||
const inputFrameDownsync = batch[k];
|
||||
@@ -839,6 +852,7 @@ cc.Class({
|
||||
--------------------------------------------------------
|
||||
*/
|
||||
// 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 firstPredictedYetIncorrectInputFrameId: ${firstPredictedYetIncorrectInputFrameId}
|
||||
lastAllConfirmedInputFrameId=${self.lastAllConfirmedInputFrameId}
|
||||
recentInputCache=${self._stringifyRecentInputCache(false)}
|
||||
@@ -860,6 +874,7 @@ batchInputFrameIdRange=[${batch[0].inputFrameId}, ${batch[batch.length - 1].inpu
|
||||
return;
|
||||
}
|
||||
|
||||
self.networkDoctor.logPeerInputFrameUpsync(batch[0].inputFrameId, batch[batch.length - 1].inputFrameId);
|
||||
//console.log(`Received peer inputFrameUpsync batch w/ inputFrameId in [${batch[0].inputFrameId}, ${batch[batch.length - 1].inputFrameId}] for prediction assistance`);
|
||||
for (let k in batch) {
|
||||
const inputFrameDownsync = batch[k];
|
||||
@@ -956,7 +971,7 @@ batchInputFrameIdRange=[${batch[0].inputFrameId}, ${batch[batch.length - 1].inpu
|
||||
|
||||
const delayedInputFrameId = gopkgs.ConvertToDelayedInputFrameId(self.renderFrameId);
|
||||
if (null == self.recentInputCache.GetByFrameId(delayedInputFrameId)) {
|
||||
// Possible edge case after resync
|
||||
// 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);
|
||||
}
|
||||
|
||||
@@ -1005,6 +1020,9 @@ othersForcedDownsyncRenderFrame=${JSON.stringify(othersForcedDownsyncRenderFrame
|
||||
}
|
||||
self.applyRoomDownsyncFrameDynamics(rdf, prevRdf);
|
||||
self.showDebugBoundaries(rdf);
|
||||
if (self.showNetworkDoctorInfo) {
|
||||
self.showNetworkDoctorLabels();
|
||||
}
|
||||
++self.renderFrameId; // [WARNING] It's important to increment the renderFrameId AFTER all the operations above!!!
|
||||
self.lastRenderFrameIdTriggeredAt = performance.now();
|
||||
let t3 = performance.now();
|
||||
@@ -1499,4 +1517,12 @@ actuallyUsedinputList:{${self.inputFrameDownsyncStr(actuallyUsedInputClone)}}`);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
showNetworkDoctorLabels() {
|
||||
const self = this;
|
||||
self.sendingQLabel.string = self.networkDoctor.statSending();
|
||||
self.inputFrameDownsyncQLabel.string = self.networkDoctor.statInputFrameDownsync();
|
||||
self.peerInputFrameUpsyncQLabel.string = self.networkDoctor.statPeerInputFrameUpsync();
|
||||
self.rollbackFramesLabel.string = self.networkDoctor.statRollbackFrames();
|
||||
},
|
||||
});
|
||||
|
74
frontend/assets/scripts/NetworkDoctor.js
Normal file
74
frontend/assets/scripts/NetworkDoctor.js
Normal file
@@ -0,0 +1,74 @@
|
||||
const RingBuffer = require('./RingBuffer');
|
||||
|
||||
var NetworkDoctor = function(capacity) {
|
||||
this.reset(capacity);
|
||||
};
|
||||
|
||||
NetworkDoctor.prototype.reset = function(capacity) {
|
||||
this.sendingQ = new RingBuffer(capacity);
|
||||
this.inputFrameDownsyncQ = new RingBuffer(capacity);
|
||||
this.peerInputFrameUpsyncQ = new RingBuffer(capacity);
|
||||
this.peerInputFrameUpsyncCnt = 0;
|
||||
this.immediateRollbackFrames = 0;
|
||||
};
|
||||
|
||||
NetworkDoctor.prototype.logSending = function(stFrameId, edFrameId) {
|
||||
this.sendingQ.put({
|
||||
i: stFrameId,
|
||||
j: edFrameId,
|
||||
t: Date.now()
|
||||
});
|
||||
};
|
||||
|
||||
NetworkDoctor.prototype.logInputFrameDownsync = function(stFrameId, edFrameId) {
|
||||
this.inputFrameDownsyncQ.put({
|
||||
i: stFrameId,
|
||||
j: edFrameId,
|
||||
t: Date.now()
|
||||
});
|
||||
};
|
||||
|
||||
NetworkDoctor.prototype.logPeerInputFrameUpsync = function(stFrameId, edFrameId) {
|
||||
const firstPopped = this.peerInputFrameUpsyncQ.put({
|
||||
i: stFrameId,
|
||||
j: edFrameId,
|
||||
t: Date.now()
|
||||
});
|
||||
if (null != firstPopped) {
|
||||
this.peerInputFrameUpsyncCnt -= (firstPopped.j - firstPopped.i + 1);
|
||||
}
|
||||
this.peerInputFrameUpsyncCnt += (edFrameId - stFrameId + 1);
|
||||
};
|
||||
|
||||
NetworkDoctor.prototype.statSending = function() {
|
||||
if (1 >= this.sendingQ.cnt) return `0 fps sending`;
|
||||
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() {
|
||||
if (1 >= this.inputFrameDownsyncQ.cnt) return `0 fps srv downsync`;
|
||||
const st = this.inputFrameDownsyncQ.getByFrameId(this.inputFrameDownsyncQ.stFrameId);
|
||||
const ed = this.inputFrameDownsyncQ.getByFrameId(this.inputFrameDownsyncQ.edFrameId - 1);
|
||||
const elapsedMillis = ed.t - st.t;
|
||||
const fps = Math.round((ed.j - st.i) * 1000 / elapsedMillis);
|
||||
return `${fps} fps srv downsync`;
|
||||
};
|
||||
|
||||
NetworkDoctor.prototype.statPeerInputFrameUpsync = function() {
|
||||
if (1 >= this.peerInputFrameUpsyncQ.cnt) return `0 fps peer upsync`;
|
||||
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() {
|
||||
return `${this.immediateRollbackFrames} rollback frames`;
|
||||
};
|
||||
|
||||
module.exports = NetworkDoctor;
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "477c07c3-0d50-4d55-96f0-6eaf9f25e2da",
|
||||
"uuid": "affd726a-02f0-4079-aace-39fe525d7478",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
@@ -11,11 +11,13 @@ cc.Class({
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
cc.game.setFrameRate(60);
|
||||
cc.view.setOrientation(cc.macro.ORIENTATION_LANDSCAPE);
|
||||
cc.view.enableAutoFullScreen(true);
|
||||
const self = this;
|
||||
window.mapIns = self;
|
||||
self.showCriticalCoordinateLabels = false;
|
||||
self.showNetworkDoctorInfo = true;
|
||||
|
||||
const mapNode = self.node;
|
||||
const canvasNode = mapNode.parent;
|
||||
@@ -96,7 +98,7 @@ cc.Class({
|
||||
const p2Vpos = gopkgs.WorldToVirtualGridPos(boundaryObjs.playerStartingPositions[1].x, boundaryObjs.playerStartingPositions[1].y);
|
||||
const colliderRadiusV = gopkgs.WorldToVirtualGridPos(12.0, 0);
|
||||
|
||||
const speciesIdList = [1, 4096];
|
||||
const speciesIdList = [4096, 1];
|
||||
const chConfigsOrderedByJoinIndex = gopkgs.GetCharacterConfigsOrderedByJoinIndex(speciesIdList);
|
||||
|
||||
const startRdf = window.pb.protos.RoomDownsyncFrame.create({
|
||||
|
@@ -13,9 +13,12 @@ var RingBuffer = function(capacity) {
|
||||
};
|
||||
|
||||
RingBuffer.prototype.put = function(item) {
|
||||
let firstPopped = null;
|
||||
while (0 < this.cnt && this.cnt >= this.n) {
|
||||
// Make room for the new element
|
||||
this.pop();
|
||||
const popped = this.pop();
|
||||
if (null == firstPopped)
|
||||
firstPopped = popped;
|
||||
}
|
||||
this.eles[this.ed] = item
|
||||
this.edFrameId++;
|
||||
@@ -24,6 +27,7 @@ RingBuffer.prototype.put = function(item) {
|
||||
if (this.ed >= this.n) {
|
||||
this.ed -= this.n; // Deliberately not using "%" operator for performance concern
|
||||
}
|
||||
return firstPopped;
|
||||
};
|
||||
|
||||
RingBuffer.prototype.pop = function() {
|
||||
|
@@ -38,7 +38,7 @@
|
||||
"orientation": "portrait"
|
||||
},
|
||||
"startScene": "2ff474d9-0c9e-4fe3-87ec-fbff7cae85b4",
|
||||
"title": "TreasureHunterX",
|
||||
"title": "DelayNoMore",
|
||||
"webOrientation": "portrait",
|
||||
"wechatgame": {
|
||||
"REMOTE_SERVER_ROOT": "https://bgmoba.lokcol.com/static/",
|
||||
|
@@ -16,7 +16,7 @@ const (
|
||||
PATTERN_ID_UNABLE_TO_OP = -2
|
||||
PATTERN_ID_NO_OP = -1
|
||||
|
||||
WORLD_TO_VIRTUAL_GRID_RATIO = float64(100)
|
||||
WORLD_TO_VIRTUAL_GRID_RATIO = float64(100.0)
|
||||
VIRTUAL_GRID_TO_WORLD_RATIO = float64(1.0) / WORLD_TO_VIRTUAL_GRID_RATIO
|
||||
|
||||
GRAVITY_X = int32(0)
|
||||
@@ -448,7 +448,7 @@ func calcHardPushbacksNorms(joinIndex int32, currPlayerDownsync, thatPlayerInNex
|
||||
return &ret
|
||||
}
|
||||
|
||||
func deriveOpPattern(currPlayerDownsync, thatPlayerInNextFrame *PlayerDownsync, currRenderFrame *RoomDownsyncFrame, inputsBuffer *RingBuffer) (int, bool, int32, int32) {
|
||||
func deriveOpPattern(currPlayerDownsync, thatPlayerInNextFrame *PlayerDownsync, currRenderFrame *RoomDownsyncFrame, chConfig *CharacterConfig, inputsBuffer *RingBuffer) (int, bool, int32, int32) {
|
||||
// returns (patternId, jumpedOrNot, effectiveDx, effectiveDy)
|
||||
delayedInputFrameId := ConvertToDelayedInputFrameId(currRenderFrame.Id)
|
||||
delayedInputFrameIdForPrevRdf := ConvertToDelayedInputFrameId(currRenderFrame.Id - 1)
|
||||
@@ -478,11 +478,19 @@ func deriveOpPattern(currPlayerDownsync, thatPlayerInNextFrame *PlayerDownsync,
|
||||
prevBtnBLevel = prevDecodedInput.BtnBLevel
|
||||
}
|
||||
|
||||
// Jumping is partially allowed within "CapturedByInertia", but moving is only allowed when "0 == FramesToRecover" (constrained later in "ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame")
|
||||
if 0 == currPlayerDownsync.FramesToRecover {
|
||||
// Jumping and moving are only allowed here
|
||||
effDx, effDy = decodedInput.Dx, decodedInput.Dy
|
||||
}
|
||||
|
||||
patternId := PATTERN_ID_NO_OP
|
||||
canJumpWithinInertia := currPlayerDownsync.CapturedByInertia && ((chConfig.InertiaFramesToRecover >> 1) > currPlayerDownsync.FramesToRecover)
|
||||
if 0 == currPlayerDownsync.FramesToRecover || canJumpWithinInertia {
|
||||
if decodedInput.BtnBLevel > prevBtnBLevel {
|
||||
if _, existent := inAirSet[currPlayerDownsync.CharacterState]; !existent {
|
||||
if chConfig.DashingEnabled && 0 > decodedInput.Dy {
|
||||
// Checking "DashingEnabled" here to allow jumping when dashing-disabled players pressed "DOWN + BtnB"
|
||||
patternId = 5
|
||||
} else if _, existent := inAirSet[currPlayerDownsync.CharacterState]; !existent {
|
||||
jumpedOrNot = true
|
||||
} else if ATK_CHARACTER_STATE_ONWALL == currPlayerDownsync.CharacterState {
|
||||
jumpedOrNot = true
|
||||
@@ -490,18 +498,19 @@ func deriveOpPattern(currPlayerDownsync, thatPlayerInNextFrame *PlayerDownsync,
|
||||
}
|
||||
}
|
||||
|
||||
patternId := PATTERN_ID_NO_OP
|
||||
if 0 < decodedInput.BtnALevel {
|
||||
if decodedInput.BtnALevel > prevBtnALevel {
|
||||
if 0 > effDy {
|
||||
patternId = 3
|
||||
} else if 0 < effDy {
|
||||
patternId = 2
|
||||
if PATTERN_ID_NO_OP == patternId {
|
||||
if 0 < decodedInput.BtnALevel {
|
||||
if decodedInput.BtnALevel > prevBtnALevel {
|
||||
if 0 > decodedInput.Dy {
|
||||
patternId = 3
|
||||
} else if 0 < decodedInput.Dy {
|
||||
patternId = 2
|
||||
} else {
|
||||
patternId = 1
|
||||
}
|
||||
} else {
|
||||
patternId = 1
|
||||
patternId = 4 // Holding
|
||||
}
|
||||
} else {
|
||||
patternId = 4 // Holding
|
||||
}
|
||||
}
|
||||
|
||||
@@ -562,7 +571,7 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
|
||||
for i, currPlayerDownsync := range currRenderFrame.PlayersArr {
|
||||
chConfig := chConfigsOrderedByJoinIndex[i]
|
||||
thatPlayerInNextFrame := nextRenderFramePlayers[i]
|
||||
patternId, jumpedOrNot, effDx, effDy := deriveOpPattern(currPlayerDownsync, thatPlayerInNextFrame, currRenderFrame, inputsBuffer)
|
||||
patternId, jumpedOrNot, effDx, effDy := deriveOpPattern(currPlayerDownsync, thatPlayerInNextFrame, currRenderFrame, chConfig, inputsBuffer)
|
||||
|
||||
jumpedOrNotList[i] = jumpedOrNot
|
||||
joinIndex := currPlayerDownsync.JoinIndex
|
||||
@@ -642,15 +651,17 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
|
||||
}
|
||||
*/
|
||||
alignedWithInertia := true
|
||||
exactTurningAround := false
|
||||
if 0 == effDx && 0 != thatPlayerInNextFrame.VelX {
|
||||
alignedWithInertia = false
|
||||
} else if 0 != effDx && 0 == thatPlayerInNextFrame.VelX {
|
||||
alignedWithInertia = false
|
||||
} else if 0 > effDx*thatPlayerInNextFrame.VelX {
|
||||
alignedWithInertia = false
|
||||
exactTurningAround = true
|
||||
}
|
||||
|
||||
if !isWallJumping && !prevCapturedByInertia && !alignedWithInertia {
|
||||
if !jumpedOrNot && !isWallJumping && !prevCapturedByInertia && !alignedWithInertia {
|
||||
/*
|
||||
[WARNING] A "turn-around", or in more generic direction schema a "change in direction" is a hurdle for our current "prediction+rollback" approach, yet applying a "FramesToRecover" for "turn-around" can alleviate the graphical inconsistence to a huge extent! For better operational experience, this is intentionally NOT APPLIED TO WALL JUMPING!
|
||||
|
||||
@@ -659,6 +670,9 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
|
||||
//fmt.Printf("joinIndex=%d is not wall jumping and not aligned w/ inertia\n{renderFrame.id: %d, effDx: %d, thatPlayerInNextFrame.VelX: %d}\n", currPlayerDownsync.JoinIndex, currRenderFrame.Id, effDx, thatPlayerInNextFrame.VelX)
|
||||
thatPlayerInNextFrame.CapturedByInertia = true
|
||||
thatPlayerInNextFrame.FramesToRecover = chConfig.InertiaFramesToRecover
|
||||
if exactTurningAround {
|
||||
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_TURNAROUND
|
||||
}
|
||||
} else {
|
||||
thatPlayerInNextFrame.CapturedByInertia = false
|
||||
if 0 != effDx {
|
||||
@@ -1053,7 +1067,7 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
|
||||
if thatPlayerInNextFrame.InAir {
|
||||
oldNextCharacterState := thatPlayerInNextFrame.CharacterState
|
||||
switch oldNextCharacterState {
|
||||
case ATK_CHARACTER_STATE_IDLE1, ATK_CHARACTER_STATE_WALKING:
|
||||
case ATK_CHARACTER_STATE_IDLE1, ATK_CHARACTER_STATE_WALKING, ATK_CHARACTER_STATE_TURNAROUND:
|
||||
if thatPlayerInNextFrame.OnWall {
|
||||
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_ONWALL
|
||||
} else if jumpedOrNotList[i] || ATK_CHARACTER_STATE_INAIR_IDLE1_BY_JUMP == currPlayerDownsync.CharacterState {
|
||||
|
@@ -45,11 +45,11 @@ var Characters = map[int]*CharacterConfig{
|
||||
GetUpInvinsibleFrames: int32(10),
|
||||
GetUpFramesToRecover: int32(27),
|
||||
|
||||
Speed: int32(float64(2.5) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
Speed: int32(float64(2.1) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
JumpingInitVelY: int32(float64(8) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
JumpingFramesToRecover: int32(2),
|
||||
|
||||
InertiaFramesToRecover: int32(5),
|
||||
InertiaFramesToRecover: int32(8),
|
||||
|
||||
DashingEnabled: false,
|
||||
OnWallEnabled: false,
|
||||
@@ -94,11 +94,11 @@ var Characters = map[int]*CharacterConfig{
|
||||
GetUpInvinsibleFrames: int32(10),
|
||||
GetUpFramesToRecover: int32(27),
|
||||
|
||||
Speed: int32(float64(2.6) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
Speed: int32(float64(2.19) * WORLD_TO_VIRTUAL_GRID_RATIO), // I don't know why "2.2" is so special that it throws a compile error
|
||||
JumpingInitVelY: int32(float64(7.5) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
JumpingFramesToRecover: int32(2),
|
||||
|
||||
InertiaFramesToRecover: int32(5),
|
||||
InertiaFramesToRecover: int32(8),
|
||||
|
||||
DashingEnabled: true,
|
||||
OnWallEnabled: true,
|
||||
@@ -128,6 +128,9 @@ var Characters = map[int]*CharacterConfig{
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if 5 == patternId {
|
||||
// Dashing is already constrained by "FramesToRecover & CapturedByInertia" in "deriveOpPattern"
|
||||
return 12
|
||||
}
|
||||
|
||||
// By default no skill can be fired
|
||||
@@ -147,11 +150,11 @@ var Characters = map[int]*CharacterConfig{
|
||||
GetUpInvinsibleFrames: int32(8),
|
||||
GetUpFramesToRecover: int32(30),
|
||||
|
||||
Speed: int32(float64(2.0) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
JumpingInitVelY: int32(float64(7.5) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
Speed: int32(float64(1.8) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
JumpingInitVelY: int32(float64(7.8) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
JumpingFramesToRecover: int32(2),
|
||||
|
||||
InertiaFramesToRecover: int32(5),
|
||||
InertiaFramesToRecover: int32(8),
|
||||
|
||||
DashingEnabled: false,
|
||||
OnWallEnabled: false,
|
||||
@@ -178,11 +181,11 @@ var Characters = map[int]*CharacterConfig{
|
||||
}
|
||||
}
|
||||
} else if 2 == patternId {
|
||||
if !currPlayerDownsync.InAir {
|
||||
if 0 == currPlayerDownsync.FramesToRecover && !currPlayerDownsync.InAir {
|
||||
return 11
|
||||
}
|
||||
} else if 3 == patternId {
|
||||
if !currPlayerDownsync.InAir {
|
||||
if 0 == currPlayerDownsync.FramesToRecover && !currPlayerDownsync.InAir {
|
||||
return 10
|
||||
}
|
||||
}
|
||||
@@ -508,7 +511,7 @@ var skills = map[int]*Skill{
|
||||
PushbackVelX: int32(float64(2) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
PushbackVelY: int32(0),
|
||||
HitboxOffsetX: int32(float64(24) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
HitboxOffsetY: int32(float64(5) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
HitboxOffsetY: int32(float64(8) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
HitboxSizeX: int32(float64(48) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
HitboxSizeY: int32(float64(32) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
BlowUp: false,
|
||||
@@ -547,6 +550,33 @@ var skills = map[int]*Skill{
|
||||
},
|
||||
},
|
||||
},
|
||||
12: &Skill{
|
||||
RecoveryFrames: int32(15),
|
||||
RecoveryFramesOnBlock: int32(15),
|
||||
RecoveryFramesOnHit: int32(15),
|
||||
ReleaseTriggerType: int32(1),
|
||||
BoundChState: ATK_CHARACTER_STATE_DASHING,
|
||||
Hits: []interface{}{
|
||||
&MeleeBullet{
|
||||
Bullet: &BulletConfig{
|
||||
StartupFrames: int32(0),
|
||||
ActiveFrames: int32(0),
|
||||
HitStunFrames: MAX_INT32,
|
||||
BlockStunFrames: int32(0),
|
||||
Damage: int32(0),
|
||||
SelfLockVelX: int32(float64(9) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||
SelfLockVelY: int32(0),
|
||||
PushbackVelX: NO_LOCK_VEL,
|
||||
PushbackVelY: NO_LOCK_VEL,
|
||||
HitboxOffsetX: int32(0),
|
||||
HitboxOffsetY: int32(0),
|
||||
HitboxSizeX: int32(0),
|
||||
HitboxSizeY: int32(0),
|
||||
BlowUp: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
255: &Skill{
|
||||
RecoveryFrames: int32(30),
|
||||
RecoveryFramesOnBlock: int32(30),
|
||||
|
Reference in New Issue
Block a user