mirror of
https://github.com/genxium/DelayNoMore
synced 2025-10-19 21:46:56 +00:00
Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
b5b43bb596 | ||
|
59767c1ed5 | ||
|
1c6ad5c8f8 | ||
|
34e0893eb8 | ||
|
cc7524becd |
14
README.md
14
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 :)
|
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
|
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)
|
- [source video of the first gif (earlier version)](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)
|
- [source video of the second gif (added turn-around optimization & dashing)](https://pan.baidu.com/s/1isMcLvxax4NNkDgitV_FDg?pwd=s1i6)
|
||||||
- [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)
|
|
||||||
|
|
||||||
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.
|
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
|
# 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)
|
||||||
@@ -111,3 +106,6 @@ 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 [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#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).
|
- 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`.
|
||||||
|

|
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 |
BIN
charts/networkstats.png
Normal file
BIN
charts/networkstats.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.2 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
@@ -78,19 +78,19 @@
|
|||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 40
|
"__id__": 50
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 41
|
"__id__": 51
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 42
|
"__id__": 52
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 43
|
"__id__": 53
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 44
|
"__id__": 54
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -158,7 +158,7 @@
|
|||||||
"__id__": 5
|
"__id__": 5
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 39
|
"__id__": 49
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -247,10 +247,10 @@
|
|||||||
"__uuid__": "670b477e-61a1-4778-879b-35913f7c79d2"
|
"__uuid__": "670b477e-61a1-4778-879b-35913f7c79d2"
|
||||||
},
|
},
|
||||||
"boundRoomIdLabel": {
|
"boundRoomIdLabel": {
|
||||||
"__id__": 16
|
"__id__": 26
|
||||||
},
|
},
|
||||||
"countdownLabel": {
|
"countdownLabel": {
|
||||||
"__id__": 23
|
"__id__": 33
|
||||||
},
|
},
|
||||||
"resultPanelPrefab": {
|
"resultPanelPrefab": {
|
||||||
"__uuid__": "c4cfe3bd-c59e-4d5b-95cb-c933b120e184"
|
"__uuid__": "c4cfe3bd-c59e-4d5b-95cb-c933b120e184"
|
||||||
@@ -269,9 +269,21 @@
|
|||||||
},
|
},
|
||||||
"forceBigEndianFloatingNumDecoding": false,
|
"forceBigEndianFloatingNumDecoding": false,
|
||||||
"renderFrameIdLagTolerance": 4,
|
"renderFrameIdLagTolerance": 4,
|
||||||
"jigglingEps1D": 0.001,
|
"sendingQLabel": {
|
||||||
"bulletTriggerEnabled": true,
|
"__id__": 13
|
||||||
"closeOnForcedtoResyncNotSelf": true,
|
},
|
||||||
|
"inputFrameDownsyncQLabel": {
|
||||||
|
"__id__": 15
|
||||||
|
},
|
||||||
|
"peerInputFrameUpsyncQLabel": {
|
||||||
|
"__id__": 17
|
||||||
|
},
|
||||||
|
"rollbackFramesLabel": {
|
||||||
|
"__id__": 19
|
||||||
|
},
|
||||||
|
"skippedRenderFrameCntLabel": {
|
||||||
|
"__id__": 21
|
||||||
|
},
|
||||||
"_id": "d12gkAmppNlIzqcRDELa91"
|
"_id": "d12gkAmppNlIzqcRDELa91"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -283,13 +295,13 @@
|
|||||||
},
|
},
|
||||||
"_children": [
|
"_children": [
|
||||||
{
|
{
|
||||||
"__id__": 33
|
"__id__": 43
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 38
|
"__id__": 48
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -352,19 +364,19 @@
|
|||||||
"__id__": 6
|
"__id__": 6
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 22
|
"__id__": 32
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 24
|
"__id__": 34
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 28
|
"__id__": 38
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 32
|
"__id__": 42
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -433,7 +445,7 @@
|
|||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 21
|
"__id__": 31
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -527,7 +539,7 @@
|
|||||||
"array": [
|
"array": [
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
209.57814771583418,
|
210.16474188040044,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@@ -596,15 +608,30 @@
|
|||||||
"_children": [
|
"_children": [
|
||||||
{
|
{
|
||||||
"__id__": 12
|
"__id__": 12
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 14
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 18
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 22
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 19
|
"__id__": 29
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 20
|
"__id__": 30
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -631,7 +658,7 @@
|
|||||||
"ctor": "Float64Array",
|
"ctor": "Float64Array",
|
||||||
"array": [
|
"array": [
|
||||||
-447.294,
|
-447.294,
|
||||||
135.702,
|
138.942,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@@ -655,6 +682,476 @@
|
|||||||
"groupIndex": 0,
|
"groupIndex": 0,
|
||||||
"_id": "35scg40jVAnKrTPiei5ckg"
|
"_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": 18.33,
|
||||||
|
"height": 22.61
|
||||||
|
},
|
||||||
|
"_anchorPoint": {
|
||||||
|
"__type__": "cc.Vec2",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0.5
|
||||||
|
},
|
||||||
|
"_trs": {
|
||||||
|
"__type__": "TypedArray",
|
||||||
|
"ctor": "Float64Array",
|
||||||
|
"array": [
|
||||||
|
0,
|
||||||
|
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": "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": 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": "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": 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,
|
||||||
|
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": 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": "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": 18.33,
|
||||||
|
"height": 22.61
|
||||||
|
},
|
||||||
|
"_anchorPoint": {
|
||||||
|
"__type__": "cc.Vec2",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0.5
|
||||||
|
},
|
||||||
|
"_trs": {
|
||||||
|
"__type__": "TypedArray",
|
||||||
|
"ctor": "Float64Array",
|
||||||
|
"array": [
|
||||||
|
0,
|
||||||
|
43.47499999999998,
|
||||||
|
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": 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": "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": 18.33,
|
||||||
|
"height": 22.61
|
||||||
|
},
|
||||||
|
"_anchorPoint": {
|
||||||
|
"__type__": "cc.Vec2",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0.5
|
||||||
|
},
|
||||||
|
"_trs": {
|
||||||
|
"__type__": "TypedArray",
|
||||||
|
"ctor": "Float64Array",
|
||||||
|
"array": [
|
||||||
|
0,
|
||||||
|
20.86499999999998,
|
||||||
|
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": 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": "77aNARt1VATLsjIzwbqvkh"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.Node",
|
||||||
|
"_name": "skippedCnt",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"_parent": {
|
||||||
|
"__id__": 11
|
||||||
|
},
|
||||||
|
"_children": [],
|
||||||
|
"_active": true,
|
||||||
|
"_components": [
|
||||||
|
{
|
||||||
|
"__id__": 21
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"_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,
|
||||||
|
-1.7450000000000188,
|
||||||
|
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__": 20
|
||||||
|
},
|
||||||
|
"_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",
|
||||||
@@ -664,19 +1161,19 @@
|
|||||||
},
|
},
|
||||||
"_children": [
|
"_children": [
|
||||||
{
|
{
|
||||||
"__id__": 13
|
"__id__": 23
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 15
|
"__id__": 25
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_active": false,
|
"_active": false,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 17
|
"__id__": 27
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 18
|
"__id__": 28
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -732,13 +1229,13 @@
|
|||||||
"_name": "label",
|
"_name": "label",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 12
|
"__id__": 22
|
||||||
},
|
},
|
||||||
"_children": [],
|
"_children": [],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 14
|
"__id__": 24
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -794,7 +1291,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 13
|
"__id__": 23
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [],
|
"_materials": [],
|
||||||
@@ -822,13 +1319,13 @@
|
|||||||
"_name": "BoundRoomIdLabel",
|
"_name": "BoundRoomIdLabel",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 12
|
"__id__": 22
|
||||||
},
|
},
|
||||||
"_children": [],
|
"_children": [],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 16
|
"__id__": 26
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -884,7 +1381,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 15
|
"__id__": 25
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [],
|
"_materials": [],
|
||||||
@@ -912,7 +1409,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 12
|
"__id__": 22
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_layoutSize": {
|
"_layoutSize": {
|
||||||
@@ -945,7 +1442,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 12
|
"__id__": 22
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [],
|
"_materials": [],
|
||||||
@@ -1067,7 +1564,7 @@
|
|||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 23
|
"__id__": 33
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -1123,7 +1620,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 22
|
"__id__": 32
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -1157,7 +1654,7 @@
|
|||||||
},
|
},
|
||||||
"_children": [
|
"_children": [
|
||||||
{
|
{
|
||||||
"__id__": 25
|
"__id__": 35
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
@@ -1215,16 +1712,16 @@
|
|||||||
"_name": "Background",
|
"_name": "Background",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 24
|
"__id__": 34
|
||||||
},
|
},
|
||||||
"_children": [],
|
"_children": [],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 26
|
"__id__": 36
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 27
|
"__id__": 37
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -1280,7 +1777,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 25
|
"__id__": 35
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -1314,7 +1811,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 25
|
"__id__": 35
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"alignMode": 0,
|
"alignMode": 0,
|
||||||
@@ -1345,7 +1842,7 @@
|
|||||||
},
|
},
|
||||||
"_children": [
|
"_children": [
|
||||||
{
|
{
|
||||||
"__id__": 29
|
"__id__": 39
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
@@ -1403,16 +1900,16 @@
|
|||||||
"_name": "Background",
|
"_name": "Background",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 28
|
"__id__": 38
|
||||||
},
|
},
|
||||||
"_children": [],
|
"_children": [],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 30
|
"__id__": 40
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 31
|
"__id__": 41
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -1468,7 +1965,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 29
|
"__id__": 39
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -1502,7 +1999,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 29
|
"__id__": 39
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"alignMode": 0,
|
"alignMode": 0,
|
||||||
@@ -1560,16 +2057,16 @@
|
|||||||
},
|
},
|
||||||
"_children": [
|
"_children": [
|
||||||
{
|
{
|
||||||
"__id__": 34
|
"__id__": 44
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 36
|
"__id__": 46
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 37
|
"__id__": 47
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -1625,13 +2122,13 @@
|
|||||||
"_name": "Joystick",
|
"_name": "Joystick",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"_parent": {
|
"_parent": {
|
||||||
"__id__": 33
|
"__id__": 43
|
||||||
},
|
},
|
||||||
"_children": [],
|
"_children": [],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 35
|
"__id__": 45
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@@ -1687,7 +2184,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 34
|
"__id__": 44
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -1721,7 +2218,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 33
|
"__id__": 43
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
@@ -1755,7 +2252,7 @@
|
|||||||
"_name": "",
|
"_name": "",
|
||||||
"_objFlags": 0,
|
"_objFlags": 0,
|
||||||
"node": {
|
"node": {
|
||||||
"__id__": 33
|
"__id__": 43
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"alignMode": 0,
|
"alignMode": 0,
|
||||||
@@ -1908,10 +2405,10 @@
|
|||||||
"__id__": 3
|
"__id__": 3
|
||||||
},
|
},
|
||||||
"stickhead": {
|
"stickhead": {
|
||||||
"__id__": 34
|
"__id__": 44
|
||||||
},
|
},
|
||||||
"base": {
|
"base": {
|
||||||
"__id__": 33
|
"__id__": 43
|
||||||
},
|
},
|
||||||
"joyStickEps": 0.1,
|
"joyStickEps": 0.1,
|
||||||
"magicLeanLowerBound": 0.414,
|
"magicLeanLowerBound": 0.414,
|
||||||
@@ -1932,10 +2429,10 @@
|
|||||||
"linearMovingEps": 0.1,
|
"linearMovingEps": 0.1,
|
||||||
"scaleByEps": 0.0375,
|
"scaleByEps": 0.0375,
|
||||||
"btnA": {
|
"btnA": {
|
||||||
"__id__": 24
|
"__id__": 34
|
||||||
},
|
},
|
||||||
"btnB": {
|
"btnB": {
|
||||||
"__id__": 28
|
"__id__": 38
|
||||||
},
|
},
|
||||||
"_id": "e9oVYTr7ROlpp/IrNjBUmR"
|
"_id": "e9oVYTr7ROlpp/IrNjBUmR"
|
||||||
}
|
}
|
||||||
|
@@ -362,7 +362,7 @@
|
|||||||
"array": [
|
"array": [
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
210.43934936178934,
|
216.6734179122529,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -2,6 +2,7 @@ const i18n = require('LanguageData');
|
|||||||
i18n.init(window.language); // languageID should be equal to the one we input in New Language ID input field
|
i18n.init(window.language); // languageID should be equal to the one we input in New Language ID input field
|
||||||
|
|
||||||
const RingBuffer = require('./RingBuffer');
|
const RingBuffer = require('./RingBuffer');
|
||||||
|
const NetworkDoctor = require('./NetworkDoctor');
|
||||||
const PriorityQueue = require("./PriorityQueue");
|
const PriorityQueue = require("./PriorityQueue");
|
||||||
|
|
||||||
window.ALL_MAP_STATES = {
|
window.ALL_MAP_STATES = {
|
||||||
@@ -96,16 +97,26 @@ cc.Class({
|
|||||||
type: cc.Integer,
|
type: cc.Integer,
|
||||||
default: 4 // implies (renderFrameIdLagTolerance >> inputScaleFrames) count of inputFrameIds
|
default: 4 // implies (renderFrameIdLagTolerance >> inputScaleFrames) count of inputFrameIds
|
||||||
},
|
},
|
||||||
jigglingEps1D: {
|
sendingQLabel: {
|
||||||
type: cc.Float,
|
type: cc.Label,
|
||||||
default: 1e-3
|
default: null
|
||||||
},
|
},
|
||||||
bulletTriggerEnabled: {
|
inputFrameDownsyncQLabel: {
|
||||||
default: false
|
type: cc.Label,
|
||||||
|
default: null
|
||||||
},
|
},
|
||||||
closeOnForcedtoResyncNotSelf: {
|
peerInputFrameUpsyncQLabel: {
|
||||||
default: true
|
type: cc.Label,
|
||||||
|
default: null
|
||||||
},
|
},
|
||||||
|
rollbackFramesLabel: {
|
||||||
|
type: cc.Label,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
skippedRenderFrameCntLabel: {
|
||||||
|
type: cc.Label,
|
||||||
|
default: null
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_inputFrameIdDebuggable(inputFrameId) {
|
_inputFrameIdDebuggable(inputFrameId) {
|
||||||
@@ -184,6 +195,7 @@ cc.Class({
|
|||||||
// Upon resync, "self.lastUpsyncInputFrameId" might not have been updated properly.
|
// Upon resync, "self.lastUpsyncInputFrameId" might not have been updated properly.
|
||||||
batchInputFrameIdSt = self.recentInputCache.StFrameId;
|
batchInputFrameIdSt = self.recentInputCache.StFrameId;
|
||||||
}
|
}
|
||||||
|
self.networkDoctor.logSending(batchInputFrameIdSt, latestLocalInputFrameId);
|
||||||
for (let i = batchInputFrameIdSt; i <= latestLocalInputFrameId; ++i) {
|
for (let i = batchInputFrameIdSt; i <= latestLocalInputFrameId; ++i) {
|
||||||
const inputFrameDownsync = self.recentInputCache.GetByFrameId(i);
|
const inputFrameDownsync = self.recentInputCache.GetByFrameId(i);
|
||||||
if (null == inputFrameDownsync) {
|
if (null == inputFrameDownsync) {
|
||||||
@@ -342,6 +354,9 @@ cc.Class({
|
|||||||
self.othersForcedDownsyncRenderFrameDict = new Map();
|
self.othersForcedDownsyncRenderFrameDict = new Map();
|
||||||
self.rdfIdToActuallyUsedInput = new Map();
|
self.rdfIdToActuallyUsedInput = new Map();
|
||||||
|
|
||||||
|
self.networkDoctor = new NetworkDoctor(20);
|
||||||
|
self.skipRenderFrameFlag = false;
|
||||||
|
|
||||||
self.countdownNanos = null;
|
self.countdownNanos = null;
|
||||||
if (self.countdownLabel) {
|
if (self.countdownLabel) {
|
||||||
self.countdownLabel.string = "";
|
self.countdownLabel.string = "";
|
||||||
@@ -409,6 +424,7 @@ cc.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
onLoad() {
|
onLoad() {
|
||||||
|
cc.game.setFrameRate(60);
|
||||||
cc.view.setOrientation(cc.macro.ORIENTATION_LANDSCAPE);
|
cc.view.setOrientation(cc.macro.ORIENTATION_LANDSCAPE);
|
||||||
cc.view.enableAutoFullScreen(true);
|
cc.view.enableAutoFullScreen(true);
|
||||||
|
|
||||||
@@ -417,6 +433,7 @@ cc.Class({
|
|||||||
window.forceBigEndianFloatingNumDecoding = self.forceBigEndianFloatingNumDecoding;
|
window.forceBigEndianFloatingNumDecoding = self.forceBigEndianFloatingNumDecoding;
|
||||||
|
|
||||||
self.showCriticalCoordinateLabels = false;
|
self.showCriticalCoordinateLabels = false;
|
||||||
|
self.showNetworkDoctorInfo = true;
|
||||||
|
|
||||||
console.warn("+++++++ Map onLoad()");
|
console.warn("+++++++ Map onLoad()");
|
||||||
|
|
||||||
@@ -690,6 +707,7 @@ cc.Class({
|
|||||||
self.lastRenderFrameIdTriggeredAt = performance.now();
|
self.lastRenderFrameIdTriggeredAt = performance.now();
|
||||||
// In this case it must be true that "rdf.id > chaserRenderFrameId".
|
// In this case it must be true that "rdf.id > chaserRenderFrameId".
|
||||||
self.chaserRenderFrameId = rdf.Id;
|
self.chaserRenderFrameId = rdf.Id;
|
||||||
|
self.networkDoctor.logRollbackFrames(0);
|
||||||
|
|
||||||
const canvasNode = self.canvasNode;
|
const canvasNode = self.canvasNode;
|
||||||
self.ctrl = canvasNode.getComponent("TouchEventsManager");
|
self.ctrl = canvasNode.getComponent("TouchEventsManager");
|
||||||
@@ -796,6 +814,7 @@ cc.Class({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.networkDoctor.logInputFrameDownsync(batch[0].inputFrameId, batch[batch.length - 1].inputFrameId);
|
||||||
let firstPredictedYetIncorrectInputFrameId = null;
|
let firstPredictedYetIncorrectInputFrameId = null;
|
||||||
for (let k in batch) {
|
for (let k in batch) {
|
||||||
const inputFrameDownsync = batch[k];
|
const inputFrameDownsync = batch[k];
|
||||||
@@ -844,6 +863,7 @@ lastAllConfirmedInputFrameId=${self.lastAllConfirmedInputFrameId}
|
|||||||
recentInputCache=${self._stringifyRecentInputCache(false)}
|
recentInputCache=${self._stringifyRecentInputCache(false)}
|
||||||
batchInputFrameIdRange=[${batch[0].inputFrameId}, ${batch[batch.length - 1].inputFrameId}]`);
|
batchInputFrameIdRange=[${batch[0].inputFrameId}, ${batch[batch.length - 1].inputFrameId}]`);
|
||||||
self.chaserRenderFrameId = renderFrameId1;
|
self.chaserRenderFrameId = renderFrameId1;
|
||||||
|
self.networkDoctor.logRollbackFrames(self.renderFrameId - self.chaserRenderFrameId);
|
||||||
},
|
},
|
||||||
|
|
||||||
onPeerInputFrameUpsync(peerJoinIndex, batch /* []*pb.InputFrameDownsync */ ) {
|
onPeerInputFrameUpsync(peerJoinIndex, batch /* []*pb.InputFrameDownsync */ ) {
|
||||||
@@ -860,6 +880,7 @@ batchInputFrameIdRange=[${batch[0].inputFrameId}, ${batch[batch.length - 1].inpu
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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`);
|
||||||
for (let k in batch) {
|
for (let k in batch) {
|
||||||
const inputFrameDownsync = batch[k];
|
const inputFrameDownsync = batch[k];
|
||||||
@@ -867,11 +888,15 @@ batchInputFrameIdRange=[${batch[0].inputFrameId}, ${batch[batch.length - 1].inpu
|
|||||||
if (inputFrameDownsyncId <= self.lastAllConfirmedInputFrameId) {
|
if (inputFrameDownsyncId <= self.lastAllConfirmedInputFrameId) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
effCnt += 1;
|
||||||
self.getOrPrefabInputFrameUpsync(inputFrameDownsyncId); // Make sure that inputFrame exists locally
|
self.getOrPrefabInputFrameUpsync(inputFrameDownsyncId); // Make sure that inputFrame exists locally
|
||||||
const existingInputFrame = self.recentInputCache.GetByFrameId(inputFrameDownsyncId);
|
const existingInputFrame = self.recentInputCache.GetByFrameId(inputFrameDownsyncId);
|
||||||
existingInputFrame.InputList[peerJoinIndex - 1] = inputFrameDownsync.inputList[peerJoinIndex - 1]; // No need to change "confirmedList", leave it to "onInputFrameDownsyncBatch" -- we're just helping prediction here
|
existingInputFrame.InputList[peerJoinIndex - 1] = inputFrameDownsync.inputList[peerJoinIndex - 1]; // No need to change "confirmedList", leave it to "onInputFrameDownsyncBatch" -- we're just helping prediction here
|
||||||
self.recentInputCache.SetByFrameId(existingInputFrame, inputFrameDownsyncId);
|
self.recentInputCache.SetByFrameId(existingInputFrame, inputFrameDownsyncId);
|
||||||
}
|
}
|
||||||
|
if (0 < effCnt) {
|
||||||
|
self.networkDoctor.logPeerInputFrameUpsync(batch[0].inputFrameId, batch[batch.length - 1].inputFrameId);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onPlayerAdded(rdf /* pb.RoomDownsyncFrame */ ) {
|
onPlayerAdded(rdf /* pb.RoomDownsyncFrame */ ) {
|
||||||
@@ -945,6 +970,11 @@ 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();
|
||||||
const noDelayInputFrameId = gopkgs.ConvertToNoDelayInputFrameId(self.renderFrameId);
|
const noDelayInputFrameId = gopkgs.ConvertToNoDelayInputFrameId(self.renderFrameId);
|
||||||
@@ -981,6 +1011,7 @@ batchInputFrameIdRange=[${batch[0].inputFrameId}, ${batch[batch.length - 1].inpu
|
|||||||
|
|
||||||
// Inside the following "self.rollbackAndChase" actually ROLLS FORWARD w.r.t. the corresponding delayedInputFrame, REGARDLESS OF whether or not "self.chaserRenderFrameId == self.renderFrameId" now.
|
// Inside the following "self.rollbackAndChase" actually ROLLS FORWARD w.r.t. the corresponding delayedInputFrame, REGARDLESS OF whether or not "self.chaserRenderFrameId == self.renderFrameId" now.
|
||||||
const latestRdfResults = self.rollbackAndChase(self.renderFrameId, self.renderFrameId + 1, self.gopkgsCollisionSys, self.gopkgsCollisionSysMap, false);
|
const latestRdfResults = self.rollbackAndChase(self.renderFrameId, self.renderFrameId + 1, self.gopkgsCollisionSys, self.gopkgsCollisionSysMap, false);
|
||||||
|
self.networkDoctor.logRollbackFrames(self.renderFrameId - self.chaserRenderFrameId);
|
||||||
let prevRdf = latestRdfResults[0],
|
let prevRdf = latestRdfResults[0],
|
||||||
rdf = latestRdfResults[1];
|
rdf = latestRdfResults[1];
|
||||||
/*
|
/*
|
||||||
@@ -1005,9 +1036,13 @@ othersForcedDownsyncRenderFrame=${JSON.stringify(othersForcedDownsyncRenderFrame
|
|||||||
}
|
}
|
||||||
self.applyRoomDownsyncFrameDynamics(rdf, prevRdf);
|
self.applyRoomDownsyncFrameDynamics(rdf, prevRdf);
|
||||||
self.showDebugBoundaries(rdf);
|
self.showDebugBoundaries(rdf);
|
||||||
|
if (self.showNetworkDoctorInfo) {
|
||||||
|
self.showNetworkDoctorLabels();
|
||||||
|
}
|
||||||
++self.renderFrameId; // [WARNING] It's important to increment the renderFrameId AFTER all the operations above!!!
|
++self.renderFrameId; // [WARNING] It's important to increment the renderFrameId AFTER all the operations above!!!
|
||||||
self.lastRenderFrameIdTriggeredAt = performance.now();
|
self.lastRenderFrameIdTriggeredAt = performance.now();
|
||||||
let t3 = performance.now();
|
let t3 = performance.now();
|
||||||
|
self.skipRenderFrameFlag = self.networkDoctor.isTooFast();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Error during Map.update", err);
|
console.error("Error during Map.update", err);
|
||||||
self.onBattleStopped(); // TODO: Popup to ask player to refresh browser
|
self.onBattleStopped(); // TODO: Popup to ask player to refresh browser
|
||||||
@@ -1499,4 +1534,44 @@ actuallyUsedinputList:{${self.inputFrameDownsyncStr(actuallyUsedInputClone)}}`);
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
showNetworkDoctorLabels() {
|
||||||
|
const self = this;
|
||||||
|
const [sendingFps, srvDownsyncFps, peerUpsyncFps, rollbackFrames, skippedRenderFrameCnt] = self.networkDoctor.stats();
|
||||||
|
if (self.sendingQLabel) {
|
||||||
|
self.sendingQLabel.string = `${sendingFps} fps sending`;
|
||||||
|
if (sendingFps < self.networkDoctor.inputRateThreshold) {
|
||||||
|
self.sendingQLabel.node.color = cc.Color.RED;
|
||||||
|
} else {
|
||||||
|
self.sendingQLabel.node.color = cc.Color.WHITE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (self.inputFrameDownsyncQLabel) {
|
||||||
|
self.inputFrameDownsyncQLabel.string = `${srvDownsyncFps} fps srv-downsync`;
|
||||||
|
if (srvDownsyncFps < self.networkDoctor.inputRateThreshold) {
|
||||||
|
self.inputFrameDownsyncQLabel.node.color = cc.Color.RED;
|
||||||
|
} else {
|
||||||
|
self.inputFrameDownsyncQLabel.node.color = cc.Color.WHITE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (self.peerInputFrameUpsyncQLabel) {
|
||||||
|
self.peerInputFrameUpsyncQLabel.string = `${peerUpsyncFps} fps peer-upsync`;
|
||||||
|
if (peerUpsyncFps > self.networkDoctor.peerUpsyncFps) {
|
||||||
|
self.peerInputFrameUpsyncQLabel.node.color = cc.Color.RED;
|
||||||
|
} else {
|
||||||
|
self.peerInputFrameUpsyncQLabel.node.color = cc.Color.WHITE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (self.rollbackFramesLabel) {
|
||||||
|
self.rollbackFramesLabel.string = `rollbackFrames: ${rollbackFrames}`
|
||||||
|
if (rollbackFrames > self.networkDoctor.rollbackFramesThreshold) {
|
||||||
|
self.rollbackFramesLabel.node.color = cc.Color.RED;
|
||||||
|
} else {
|
||||||
|
self.rollbackFramesLabel.node.color = cc.Color.WHITE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (self.skippedRenderFrameCntLabel) {
|
||||||
|
self.skippedRenderFrameCntLabel.string = `${skippedRenderFrameCnt} frames skipped`
|
||||||
|
}
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
94
frontend/assets/scripts/NetworkDoctor.js
Normal file
94
frontend/assets/scripts/NetworkDoctor.js
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
const RingBuffer = require('./RingBuffer');
|
||||||
|
|
||||||
|
var NetworkDoctor = function(capacity) {
|
||||||
|
this.reset(capacity);
|
||||||
|
};
|
||||||
|
|
||||||
|
NetworkDoctor.prototype.reset = function(capacity) {
|
||||||
|
this.sendingQ = new RingBuffer(capacity);
|
||||||
|
this.inputFrameDownsyncQ = new RingBuffer(capacity);
|
||||||
|
this.peerInputFrameUpsyncQ = new RingBuffer(capacity);
|
||||||
|
this.peerInputFrameUpsyncCnt = 0;
|
||||||
|
this.immediateRollbackFrames = 0;
|
||||||
|
this.skippedRenderFrameCnt = 0;
|
||||||
|
|
||||||
|
this.inputRateThreshold = gopkgs.ConvertToNoDelayInputFrameId(60);
|
||||||
|
this.peerUpsyncThreshold = 8;
|
||||||
|
this.rollbackFramesThreshold = 4; // Slightly smaller than the minimum "TurnAroundFramesToRecover".
|
||||||
|
};
|
||||||
|
|
||||||
|
NetworkDoctor.prototype.logSending = function(stFrameId, edFrameId) {
|
||||||
|
this.sendingQ.put({
|
||||||
|
i: stFrameId,
|
||||||
|
j: edFrameId,
|
||||||
|
t: Date.now()
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
NetworkDoctor.prototype.logInputFrameDownsync = function(stFrameId, edFrameId) {
|
||||||
|
this.inputFrameDownsyncQ.put({
|
||||||
|
i: stFrameId,
|
||||||
|
j: edFrameId,
|
||||||
|
t: Date.now()
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
NetworkDoctor.prototype.logPeerInputFrameUpsync = function(stFrameId, edFrameId) {
|
||||||
|
const firstPopped = this.peerInputFrameUpsyncQ.put({
|
||||||
|
i: stFrameId,
|
||||||
|
j: edFrameId,
|
||||||
|
t: Date.now()
|
||||||
|
});
|
||||||
|
if (null != firstPopped) {
|
||||||
|
this.peerInputFrameUpsyncCnt -= (firstPopped.j - firstPopped.i + 1);
|
||||||
|
}
|
||||||
|
this.peerInputFrameUpsyncCnt += (edFrameId - stFrameId + 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
NetworkDoctor.prototype.logRollbackFrames = function(x) {
|
||||||
|
this.immediateRollbackFrames = x;
|
||||||
|
};
|
||||||
|
|
||||||
|
NetworkDoctor.prototype.stats = function() {
|
||||||
|
let sendingFps = 0,
|
||||||
|
srvDownsyncFps = 0,
|
||||||
|
peerUpsyncFps = 0,
|
||||||
|
rollbackFrames = this.immediateRollbackFrames;
|
||||||
|
if (1 < this.sendingQ.cnt) {
|
||||||
|
const st = this.sendingQ.getByFrameId(this.sendingQ.stFrameId);
|
||||||
|
const ed = this.sendingQ.getByFrameId(this.sendingQ.edFrameId - 1);
|
||||||
|
const elapsedMillis = ed.t - st.t;
|
||||||
|
sendingFps = Math.round((ed.j - st.i) * 1000 / elapsedMillis);
|
||||||
|
}
|
||||||
|
if (1 < this.inputFrameDownsyncQ.cnt) {
|
||||||
|
const st = this.inputFrameDownsyncQ.getByFrameId(this.inputFrameDownsyncQ.stFrameId);
|
||||||
|
const ed = this.inputFrameDownsyncQ.getByFrameId(this.inputFrameDownsyncQ.edFrameId - 1);
|
||||||
|
const elapsedMillis = ed.t - st.t;
|
||||||
|
srvDownsyncFps = Math.round((ed.j - st.i) * 1000 / elapsedMillis);
|
||||||
|
}
|
||||||
|
if (1 < this.peerInputFrameUpsyncQ.cnt) {
|
||||||
|
const st = this.peerInputFrameUpsyncQ.getByFrameId(this.peerInputFrameUpsyncQ.stFrameId);
|
||||||
|
const ed = this.peerInputFrameUpsyncQ.getByFrameId(this.peerInputFrameUpsyncQ.edFrameId - 1);
|
||||||
|
const elapsedMillis = ed.t - st.t;
|
||||||
|
peerUpsyncFps = Math.round(this.peerInputFrameUpsyncCnt * 1000 / elapsedMillis);
|
||||||
|
}
|
||||||
|
return [sendingFps, srvDownsyncFps, peerUpsyncFps, rollbackFrames, this.skippedRenderFrameCnt];
|
||||||
|
};
|
||||||
|
|
||||||
|
NetworkDoctor.prototype.logSkippedRenderFrameCnt = function() {
|
||||||
|
this.skippedRenderFrameCnt += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
NetworkDoctor.prototype.isTooFast = function() {
|
||||||
|
const [sendingFps, srvDownsyncFps, peerUpsyncFps, rollbackFrames, skippedRenderFrameCnt] = this.stats();
|
||||||
|
if (sendingFps >= this.inputRateThreshold && srvDownsyncFps >= this.inputRateThreshold) {
|
||||||
|
// At least my network is OK for both TX & RX directions.
|
||||||
|
if (rollbackFrames >= this.rollbackFramesThreshold) {
|
||||||
|
// I got many frames rolled back while none of my peers effectively helped my preciction. Deliberately not using "peerUpsyncThreshold" here because when using UDP p2p upsync broadcasting, we expect to receive effective p2p upsyncs from every other player.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = NetworkDoctor;
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"ver": "1.0.5",
|
"ver": "1.0.5",
|
||||||
"uuid": "477c07c3-0d50-4d55-96f0-6eaf9f25e2da",
|
"uuid": "affd726a-02f0-4079-aace-39fe525d7478",
|
||||||
"isPlugin": false,
|
"isPlugin": false,
|
||||||
"loadPluginInWeb": true,
|
"loadPluginInWeb": true,
|
||||||
"loadPluginInNative": true,
|
"loadPluginInNative": true,
|
@@ -11,11 +11,13 @@ cc.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
onLoad() {
|
onLoad() {
|
||||||
|
cc.game.setFrameRate(60);
|
||||||
cc.view.setOrientation(cc.macro.ORIENTATION_LANDSCAPE);
|
cc.view.setOrientation(cc.macro.ORIENTATION_LANDSCAPE);
|
||||||
cc.view.enableAutoFullScreen(true);
|
cc.view.enableAutoFullScreen(true);
|
||||||
const self = this;
|
const self = this;
|
||||||
window.mapIns = self;
|
window.mapIns = self;
|
||||||
self.showCriticalCoordinateLabels = false;
|
self.showCriticalCoordinateLabels = false;
|
||||||
|
self.showNetworkDoctorInfo = true;
|
||||||
|
|
||||||
const mapNode = self.node;
|
const mapNode = self.node;
|
||||||
const canvasNode = mapNode.parent;
|
const canvasNode = mapNode.parent;
|
||||||
@@ -96,7 +98,7 @@ cc.Class({
|
|||||||
const p2Vpos = gopkgs.WorldToVirtualGridPos(boundaryObjs.playerStartingPositions[1].x, boundaryObjs.playerStartingPositions[1].y);
|
const p2Vpos = gopkgs.WorldToVirtualGridPos(boundaryObjs.playerStartingPositions[1].x, boundaryObjs.playerStartingPositions[1].y);
|
||||||
const colliderRadiusV = gopkgs.WorldToVirtualGridPos(12.0, 0);
|
const colliderRadiusV = gopkgs.WorldToVirtualGridPos(12.0, 0);
|
||||||
|
|
||||||
const speciesIdList = [4096, 1];
|
const speciesIdList = [1, 4096];
|
||||||
const chConfigsOrderedByJoinIndex = gopkgs.GetCharacterConfigsOrderedByJoinIndex(speciesIdList);
|
const chConfigsOrderedByJoinIndex = gopkgs.GetCharacterConfigsOrderedByJoinIndex(speciesIdList);
|
||||||
|
|
||||||
const startRdf = window.pb.protos.RoomDownsyncFrame.create({
|
const startRdf = window.pb.protos.RoomDownsyncFrame.create({
|
||||||
|
@@ -13,9 +13,12 @@ var RingBuffer = function(capacity) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
RingBuffer.prototype.put = function(item) {
|
RingBuffer.prototype.put = function(item) {
|
||||||
|
let firstPopped = null;
|
||||||
while (0 < this.cnt && this.cnt >= this.n) {
|
while (0 < this.cnt && this.cnt >= this.n) {
|
||||||
// Make room for the new element
|
// Make room for the new element
|
||||||
this.pop();
|
const popped = this.pop();
|
||||||
|
if (null == firstPopped)
|
||||||
|
firstPopped = popped;
|
||||||
}
|
}
|
||||||
this.eles[this.ed] = item
|
this.eles[this.ed] = item
|
||||||
this.edFrameId++;
|
this.edFrameId++;
|
||||||
@@ -24,6 +27,7 @@ RingBuffer.prototype.put = function(item) {
|
|||||||
if (this.ed >= this.n) {
|
if (this.ed >= this.n) {
|
||||||
this.ed -= this.n; // Deliberately not using "%" operator for performance concern
|
this.ed -= this.n; // Deliberately not using "%" operator for performance concern
|
||||||
}
|
}
|
||||||
|
return firstPopped;
|
||||||
};
|
};
|
||||||
|
|
||||||
RingBuffer.prototype.pop = function() {
|
RingBuffer.prototype.pop = function() {
|
||||||
|
@@ -22,7 +22,7 @@ const (
|
|||||||
GRAVITY_X = int32(0)
|
GRAVITY_X = int32(0)
|
||||||
GRAVITY_Y = -int32(float64(0.5) * WORLD_TO_VIRTUAL_GRID_RATIO) // makes all "playerCollider.Y" a multiple of 0.5 in all cases
|
GRAVITY_Y = -int32(float64(0.5) * WORLD_TO_VIRTUAL_GRID_RATIO) // makes all "playerCollider.Y" a multiple of 0.5 in all cases
|
||||||
|
|
||||||
INPUT_DELAY_FRAMES = int32(8) // in the count of render frames
|
INPUT_DELAY_FRAMES = int32(4) // in the count of render frames
|
||||||
INPUT_SCALE_FRAMES = uint32(2) // inputDelayedAndScaledFrameId = ((originalFrameId - InputDelayFrames) >> InputScaleFrames)
|
INPUT_SCALE_FRAMES = uint32(2) // inputDelayedAndScaledFrameId = ((originalFrameId - InputDelayFrames) >> InputScaleFrames)
|
||||||
NST_DELAY_FRAMES = int32(16) // network-single-trip delay in the count of render frames, proposed to be (InputDelayFrames >> 1) because we expect a round-trip delay to be exactly "InputDelayFrames"
|
NST_DELAY_FRAMES = int32(16) // network-single-trip delay in the count of render frames, proposed to be (InputDelayFrames >> 1) because we expect a round-trip delay to be exactly "InputDelayFrames"
|
||||||
|
|
||||||
@@ -644,7 +644,7 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
|
|||||||
|
|
||||||
if 0 == currPlayerDownsync.FramesToRecover {
|
if 0 == currPlayerDownsync.FramesToRecover {
|
||||||
prevCapturedByInertia := currPlayerDownsync.CapturedByInertia
|
prevCapturedByInertia := currPlayerDownsync.CapturedByInertia
|
||||||
isWallJumping := (currPlayerDownsync.Speed < intAbs(currPlayerDownsync.VelX))
|
isWallJumping := (chConfig.OnWallEnabled && chConfig.WallJumpingInitVelX == intAbs(currPlayerDownsync.VelX))
|
||||||
/*
|
/*
|
||||||
if isWallJumping {
|
if isWallJumping {
|
||||||
fmt.Printf("joinIndex=%d is wall jumping\n{renderFrame.id: %d, currPlayerDownsync.Speed: %d, currPlayerDownsync.VelX: %d}\n", currPlayerDownsync.JoinIndex, currRenderFrame.Id, currPlayerDownsync.Speed, currPlayerDownsync.VelX)
|
fmt.Printf("joinIndex=%d is wall jumping\n{renderFrame.id: %d, currPlayerDownsync.Speed: %d, currPlayerDownsync.VelX: %d}\n", currPlayerDownsync.JoinIndex, currRenderFrame.Id, currPlayerDownsync.Speed, currPlayerDownsync.VelX)
|
||||||
@@ -752,6 +752,8 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(inputsBuffer *RingBuffer
|
|||||||
if ATK_CHARACTER_STATE_ONWALL == currPlayerDownsync.CharacterState && !jumpedOrNotList[i] {
|
if ATK_CHARACTER_STATE_ONWALL == currPlayerDownsync.CharacterState && !jumpedOrNotList[i] {
|
||||||
thatPlayerInNextFrame.VelX += GRAVITY_X
|
thatPlayerInNextFrame.VelX += GRAVITY_X
|
||||||
thatPlayerInNextFrame.VelY = chConfig.WallSlidingVelY
|
thatPlayerInNextFrame.VelY = chConfig.WallSlidingVelY
|
||||||
|
} else if ATK_CHARACTER_STATE_DASHING == currPlayerDownsync.CharacterState {
|
||||||
|
thatPlayerInNextFrame.VelX += GRAVITY_X
|
||||||
} else {
|
} else {
|
||||||
thatPlayerInNextFrame.VelX += GRAVITY_X
|
thatPlayerInNextFrame.VelX += GRAVITY_X
|
||||||
thatPlayerInNextFrame.VelY += GRAVITY_Y
|
thatPlayerInNextFrame.VelY += GRAVITY_Y
|
||||||
|
@@ -49,7 +49,7 @@ var Characters = map[int]*CharacterConfig{
|
|||||||
JumpingInitVelY: int32(float64(8) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
JumpingInitVelY: int32(float64(8) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||||
JumpingFramesToRecover: int32(2),
|
JumpingFramesToRecover: int32(2),
|
||||||
|
|
||||||
InertiaFramesToRecover: int32(8),
|
InertiaFramesToRecover: int32(9),
|
||||||
|
|
||||||
DashingEnabled: false,
|
DashingEnabled: false,
|
||||||
OnWallEnabled: false,
|
OnWallEnabled: false,
|
||||||
@@ -98,7 +98,7 @@ var Characters = map[int]*CharacterConfig{
|
|||||||
JumpingInitVelY: int32(float64(7.5) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
JumpingInitVelY: int32(float64(7.5) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||||
JumpingFramesToRecover: int32(2),
|
JumpingFramesToRecover: int32(2),
|
||||||
|
|
||||||
InertiaFramesToRecover: int32(8),
|
InertiaFramesToRecover: int32(9),
|
||||||
|
|
||||||
DashingEnabled: true,
|
DashingEnabled: true,
|
||||||
OnWallEnabled: true,
|
OnWallEnabled: true,
|
||||||
@@ -154,7 +154,7 @@ var Characters = map[int]*CharacterConfig{
|
|||||||
JumpingInitVelY: int32(float64(7.8) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
JumpingInitVelY: int32(float64(7.8) * WORLD_TO_VIRTUAL_GRID_RATIO),
|
||||||
JumpingFramesToRecover: int32(2),
|
JumpingFramesToRecover: int32(2),
|
||||||
|
|
||||||
InertiaFramesToRecover: int32(8),
|
InertiaFramesToRecover: int32(9),
|
||||||
|
|
||||||
DashingEnabled: false,
|
DashingEnabled: false,
|
||||||
OnWallEnabled: false,
|
OnWallEnabled: false,
|
||||||
@@ -551,9 +551,9 @@ var skills = map[int]*Skill{
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
12: &Skill{
|
12: &Skill{
|
||||||
RecoveryFrames: int32(15),
|
RecoveryFrames: int32(12),
|
||||||
RecoveryFramesOnBlock: int32(15),
|
RecoveryFramesOnBlock: int32(12),
|
||||||
RecoveryFramesOnHit: int32(15),
|
RecoveryFramesOnHit: int32(12),
|
||||||
ReleaseTriggerType: int32(1),
|
ReleaseTriggerType: int32(1),
|
||||||
BoundChState: ATK_CHARACTER_STATE_DASHING,
|
BoundChState: ATK_CHARACTER_STATE_DASHING,
|
||||||
Hits: []interface{}{
|
Hits: []interface{}{
|
||||||
|
Reference in New Issue
Block a user