Further updates on win32 build templates.

This commit is contained in:
genxium 2023-01-23 14:17:52 +08:00
parent 58b06f6a10
commit 0168e2182e
20 changed files with 242 additions and 43 deletions

2
.gitignore vendored
View File

@ -1,3 +1,5 @@
.vs
**/.vs
battle_srv/test_cases/test_cases
battle_srv/test_cases/tests
*.pid

View File

@ -108,4 +108,27 @@ Moreover, in practice I found that to spot sync anomalies, the following tools a
- Detection of [type#2 forceConfirmation on the backend](https://github.com/genxium/DelayNoMore/blob/v0.9.19/battle_srv/models/room.go#L1259).
There's also some useful information displayed on the frontend when `true == Map.showNetworkDoctorInfo`.
![networkstats](./charts/networkstats.png)
![networkstats](./charts/networkstats.png)
### 2.3 WIN32 platform tool versioning
![visual_studio](./charts/VisualStudioSetup.png)
When building for native platforms, it's much more convenient to trigger the CocosCreator project forming frmo CLI, e.g.
```
shell> cd <proj-root>
shell> /path/to/CocosCreator.exe --path ./frontend --build "platform=win32;debug=true"
```
### 2.4 CococCreator native build reloading
CocosCreator doesn't have perfect file cache management during native project building, use "Developer Tools > Reload" to reset the IDE status upon mysterious errors.
![ccc_reload](./charts/NativeBuildReload.png)
### 2.5 Checking UDP port binding result
__*nix__
```
netstat -anp | grep <your_port>
```
__Windows__
```
netstat -ano | grep <your_port>
```

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 417 KiB

After

Width:  |  Height:  |  Size: 417 KiB

View File

@ -362,7 +362,7 @@
"array": [
0,
0,
216.50635094610968,
216.67832656600567,
0,
0,
0,

View File

@ -547,7 +547,7 @@
"array": [
0,
0,
210.72485222798673,
210.25627653647612,
0,
0,
0,

View File

@ -14,7 +14,7 @@ NetworkDoctor.prototype.reset = function(capacity) {
this.inputRateThreshold = gopkgs.ConvertToNoDelayInputFrameId(60);
this.peerUpsyncThreshold = 8;
this.rollbackFramesThreshold = 4; // Slightly smaller than the minimum "TurnAroundFramesToRecover".
this.rollbackFramesThreshold = 8; // Roughly the minimum "TurnAroundFramesToRecover".
};
NetworkDoctor.prototype.logSending = function(stFrameId, edFrameId) {

View File

@ -144,6 +144,11 @@ cc.Class({
Id: 10,
JoinIndex: 1,
};
if (cc.sys.isNative) {
DelayNoMore.UdpSession.upsertPeerUdpAddr(self.selfPlayerInfo.JoinIndex, "192.168.31.194", 6789, 123456);
const res1 = DelayNoMore.UdpSession.openUdpSession(8888 + self.selfPlayerInfo.JoinIndex);
//const res2 = DelayNoMore.UdpSession.closeUdpSession();
}
self.onRoomDownsyncFrame(startRdf);
self.battleState = ALL_BATTLE_STATES.IN_BATTLE;
@ -154,12 +159,6 @@ cc.Class({
update(dt) {
const self = this;
if (ALL_BATTLE_STATES.IN_BATTLE == self.battleState) {
const elapsedMillisSinceLastFrameIdTriggered = performance.now() - self.lastRenderFrameIdTriggeredAt;
if (elapsedMillisSinceLastFrameIdTriggered < self.tooFastDtIntervalMillis) {
// [WARNING] We should avoid a frontend ticking too fast to prevent cheating, as well as ticking too slow to cause a "resync avalanche" that impacts user experience!
// console.debug("Avoiding too fast frame@renderFrameId=", self.renderFrameId, ": elapsedMillisSinceLastFrameIdTriggered=", elapsedMillisSinceLastFrameIdTriggered);
//return;
}
try {
let st = performance.now();
let prevSelfInput = null,

File diff suppressed because one or more lines are too long

View File

@ -39,6 +39,7 @@
"frameworks/runtime-src/proj.android-studio/app/res/values/strings.xml",
"frameworks/runtime-src/Classes/udp_session.hpp",
"frameworks/runtime-src/Classes/udp_session.cpp",
"frameworks/runtime-src/Classes/udp_session_bridge.hpp",
"frameworks/runtime-src/Classes/udp_session_bridge.cpp",
"frameworks/runtime-src/Classes/AppDelegate.cpp"
]

View File

@ -33,7 +33,7 @@
#include "cocos/scripting/js-bindings/jswrapper/SeApi.h"
#include "cocos/scripting/js-bindings/event/EventDispatcher.h"
#include "cocos/scripting/js-bindings/manual/jsb_classtype.hpp"
#include "udp_session_bridge.hpp"
USING_NS_CC;
AppDelegate::AppDelegate(int width, int height) : Application("Cocos Game", width, height)
@ -61,6 +61,7 @@ bool AppDelegate::applicationDidFinishLaunching()
});
jsb_register_all_modules();
se->addRegisterCallback(registerUdpSession);
se->start();

View File

@ -1,14 +1,95 @@
#include "udp_session.hpp"
#include "base/ccMacros.h"
#include "cocos/scripting/js-bindings/jswrapper/SeApi.h"
#include <stdio.h>
#include "uv/uv.h"
#include <thread>
static uv_udp_t* udpSocket = NULL;
uv_loop_t* loop = NULL; // Only this loop is used for this simple PoC
void _onRead(uv_udp_t* req, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned flags) {
if (nread < 0) {
CCLOGERROR("Read error %s", uv_err_name(nread));
uv_close((uv_handle_t*)req, NULL);
free(buf->base);
return;
}
char sender[17] = { 0 };
uv_ip4_name((const struct sockaddr_in*)addr, sender, 16);
CCLOG("Recv from %s", sender);
free(buf->base);
uv_udp_recv_stop(req);
}
static void _allocBuffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
(void)handle;
buf->base = (char *)malloc(suggested_size);
buf->len = suggested_size;
}
void startRecvLoop(void* arg) {
uv_loop_t* loop = (uv_loop_t*)arg;
uv_run(loop, UV_RUN_DEFAULT);
}
bool DelayNoMore::UdpSession::openUdpSession(int port) {
CCLOG("About to open UDP session at port=%d...", port);
loop = uv_loop_new(); // Only the default loop is used for this simple PoC
udpSocket = (uv_udp_t*)malloc(sizeof(uv_udp_t));
SOCKADDR_IN recv_addr;
uv_ip4_addr("0.0.0.0", port, &recv_addr);
uv_udp_init(loop, udpSocket);
uv_udp_bind(udpSocket, (struct sockaddr const*)&recv_addr, UV_UDP_REUSEADDR);
uv_udp_recv_start(udpSocket, _allocBuffer, _onRead);
uv_thread_t recvTid;
uv_thread_create(&recvTid, startRecvLoop, loop);
//std::thread([=]() {
// udpSocket = (uv_udp_t*)malloc(sizeof(uv_udp_t));
// SOCKADDR_IN recv_addr;
// uv_ip4_addr("0.0.0.0", port, &recv_addr);
//
// uv_udp_init(loop, udpSocket);
//
// uv_udp_bind(udpSocket, (struct sockaddr const*)&recv_addr, UV_UDP_REUSEADDR);
// uv_udp_recv_start(udpSocket, _allocBuffer, _onRead);
//
// startRecvLoop(loop);
//}).detach();
CCLOG("Finished opening UDP session at port=%d", port);
bool DelayNoMore::UdpSession::upsertPeerUdpAddr(int joinIndex, CHARC* const ip, int port, CHARC* const authKey) {
printf("Called by js for joinIndex=%d, ip=%s, port=%d, authKey=%s.", joinIndex, ip, port, authKey);
return true;
}
void DelayNoMore::UdpSession::onMessage(CBYTE* const bytes) {
static void _onWalkCleanup(uv_handle_t* handle, void* data) {
(void)data;
uv_close(handle, NULL);
}
bool DelayNoMore::UdpSession::closeUdpSession() {
CCLOG("About to close udp session and dealloc all resources...");
uv_stop(loop);
uv_walk(loop, _onWalkCleanup, NULL);
uv_loop_close(loop);
free(udpSocket);
free(loop);
CCLOG("Closed udp session and dealloc all resources...");
return true;
}
bool DelayNoMore::UdpSession::upsertPeerUdpAddr(int joinIndex, CHARC* const ip, int port, uint32_t authKey) {
CCLOG("Called by js for joinIndex=%d, ip=%s, port=%d, authKey=%lu.", joinIndex, ip, port, authKey);
return true;
}
void DelayNoMore::UdpSession::onMessage(BYTEC* const bytes) {
se::ScriptEngine* se = se::ScriptEngine::getInstance();
se::Value func;

View File

@ -3,16 +3,18 @@
#include "cocos/scripting/js-bindings/jswrapper/SeApi.h"
typedef unsigned char const CBYTE;
typedef unsigned char const BYTEC;
typedef char const CHARC;
namespace DelayNoMore {
class UdpSession {
public:
static bool upsertPeerUdpAddr(int joinIndex, CHARC* const ip, int port, CHARC* const authKey);
static bool openUdpSession(int port);
static bool closeUdpSession();
static bool upsertPeerUdpAddr(int joinIndex, CHARC* const ip, int port, uint32_t authKey);
//static bool clearPeerUDPAddrList();
//static void punchToServer(CBYTE* const bytes);
static void onMessage(CBYTE* const bytes);
static void onMessage(BYTEC* const bytes);
};
}
#endif

View File

@ -2,6 +2,35 @@
#include "base/ccMacros.h"
#include "scripting/js-bindings/manual/jsb_conversions.hpp"
bool openUdpSession(se::State& s) {
const auto& args = s.args();
size_t argc = args.size();
CC_UNUSED bool ok = true;
if (1 == argc) {
SE_PRECONDITION2(ok, false, "openUdpSession: Error processing arguments");
int port = args[0].toInt32();
return DelayNoMore::UdpSession::openUdpSession(port);
}
SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d", (int)argc, 1);
return false;
}
SE_BIND_FUNC(openUdpSession)
bool closeUdpSession(se::State& s) {
const auto& args = s.args();
size_t argc = args.size();
CC_UNUSED bool ok = true;
if (0 == argc) {
SE_PRECONDITION2(ok, false, "closeUdpSession: Error processing arguments");
return DelayNoMore::UdpSession::closeUdpSession();
}
SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d", (int)argc, 0);
return false;
}
SE_BIND_FUNC(closeUdpSession)
bool upsertPeerUdpAddr(se::State& s) {
const auto& args = s.args();
size_t argc = args.size();
@ -11,13 +40,12 @@ bool upsertPeerUdpAddr(se::State& s) {
int joinIndex = args[0].toInt32();
CHARC* ip = args[1].toString().c_str();
int port = args[2].toInt32();
CHARC* authKey = args[3].toString().c_str();
DelayNoMore::UdpSession::upsertPeerUdpAddr(joinIndex, ip, port, authKey);
return true;
uint32_t authKey = args[3].toUint32();
return DelayNoMore::UdpSession::upsertPeerUdpAddr(joinIndex, ip, port, authKey);
}
SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d", (int)argc, 4);
return true;
return false;
}
SE_BIND_FUNC(upsertPeerUdpAddr)
@ -36,7 +64,7 @@ SE_BIND_FINALIZE_FUNC(udpSessionFinalize)
se::Object* __jsb_udp_session_proto = nullptr;
se::Class* __jsb_udp_session_class = nullptr;
bool register_udp_session(se::Object* obj)
bool registerUdpSession(se::Object* obj)
{
// Get the ns
se::Value nsVal;
@ -49,7 +77,9 @@ bool register_udp_session(se::Object* obj)
se::Object* ns = nsVal.toObject();
auto cls = se::Class::create("UdpSession", ns, nullptr, nullptr);
cls->defineStaticFunction("openUdpSession", _SE(openUdpSession));
cls->defineStaticFunction("closeUdpSession", _SE(closeUdpSession));
cls->defineStaticFunction("upsertPeerUdpAddr", _SE(upsertPeerUdpAddr));
cls->defineFinalizeFunction(_SE(udpSessionFinalize));
cls->install();

View File

@ -8,8 +8,10 @@
extern se::Object* __jsb_udp_session_proto;
extern se::Class* __jsb_udp_session_class;
bool register_udp_session(se::Object* obj);
bool registerUdpSession(se::Object* obj);
SE_DECLARE_FUNC(openUdpSession);
SE_DECLARE_FUNC(closeUdpSession);
SE_DECLARE_FUNC(upsertPeerUdpAddr);
#endif

View File

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="resource">
<UniqueIdentifier>{ca9c9e15-d942-43a1-aa7a-5f0b74ca1afd}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;png;manifest</Extensions>
</Filter>
<Filter Include="win32">
<UniqueIdentifier>{ccb2323b-1cfa-41ea-bcf4-ba5f07309396}</UniqueIdentifier>
</Filter>
<Filter Include="Classes">
<UniqueIdentifier>{e93a77e1-af1e-4400-87d3-504b62ebdbb0}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp">
<Filter>win32</Filter>
</ClCompile>
<ClCompile Include="..\Classes\AppDelegate.cpp">
<Filter>Classes</Filter>
</ClCompile>
<ClCompile Include="..\Classes\jsb_module_register.cpp">
<Filter>Classes</Filter>
</ClCompile>
<ClCompile Include="..\Classes\udp_session.cpp">
<Filter>Classes</Filter>
</ClCompile>
<ClCompile Include="..\Classes\udp_session_bridge.cpp">
<Filter>Classes</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\Classes\AppDelegate.h">
<Filter>Classes</Filter>
</ClInclude>
<ClInclude Include="main.h">
<Filter>win32</Filter>
</ClInclude>
<ClInclude Include="resource.h" />
<ClInclude Include="..\Classes\udp_session.hpp">
<Filter>Classes</Filter>
</ClInclude>
<ClInclude Include="..\Classes\udp_session_bridge.hpp">
<Filter>Classes</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="game.rc">
<Filter>resource</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<Image Include="res\game.ico">
<Filter>resource</Filter>
</Image>
</ItemGroup>
</Project>

View File

@ -2,7 +2,7 @@
"android-instant": {
"REMOTE_SERVER_ROOT": "",
"host": "",
"packageName": "org.cocos2d.helloworld",
"packageName": "org.genxium.delaynomore",
"pathPattern": "",
"recordPath": "",
"scheme": "https",
@ -17,15 +17,14 @@
},
"encryptJs": false,
"excludeScenes": [
"2ff474d9-0c9e-4fe3-87ec-fbff7cae85b4",
"92160186-3e0d-4e0a-ae20-97286170ba58"
"8491a86c-bec9-4813-968a-128ca01639e0"
],
"fb-instant-games": {},
"includeSDKBox": false,
"inlineSpriteFrames": true,
"inlineSpriteFrames_native": true,
"inlineSpriteFrames_native": false,
"md5Cache": false,
"mergeStartScene": false,
"mergeStartScene": true,
"optimizeHotUpdate": false,
"orientation": {
"landscapeLeft": true,
@ -33,12 +32,12 @@
"portrait": false,
"upsideDown": false
},
"packageName": "org.cocos2d.helloworld",
"packageName": "org.genxium.delaynomore",
"qqplay": {
"REMOTE_SERVER_ROOT": "",
"orientation": "portrait"
},
"startScene": "8491a86c-bec9-4813-968a-128ca01639e0",
"startScene": "2ff474d9-0c9e-4fe3-87ec-fbff7cae85b4",
"title": "DelayNoMore",
"webOrientation": "landscape",
"wechatgame": {
@ -49,14 +48,14 @@
"xxteaKey": "4d54a3d5-e6f3-49",
"zipCompressJs": true,
"android": {
"packageName": "org.cocos2d.tsrht"
"packageName": "org.genxium.delaynomore"
},
"ios": {
"packageName": "org.cocos2d.helloworld"
"packageName": "org.genxium.delaynomore"
},
"mac": {
"packageName": "org.cocos2d.helloworld"
"packageName": "org.genxium.delaynomore"
},
"win32": {},
"includeAnySDK": false
"includeAnySDK": null
}

View File

@ -1,5 +1,5 @@
{
"name": "TEMPLATES.helloworld.name",
"desc": "TEMPLATES.helloworld.desc",
"name": "DelayNoMore",
"desc": "DelayNoMore",
"banner": "template-banner.png"
}
}

View File

@ -22,7 +22,7 @@ const (
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
INPUT_DELAY_FRAMES = int32(4) // in the count of render frames
INPUT_DELAY_FRAMES = int32(6) // in the count of render frames
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"
@ -669,9 +669,11 @@ 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
thatPlayerInNextFrame.FramesToRecover = chConfig.InertiaFramesToRecover
} else {
thatPlayerInNextFrame.FramesToRecover = (chConfig.InertiaFramesToRecover >> 1)
}
} else {
thatPlayerInNextFrame.CapturedByInertia = false