Integrated basic holepunching for multiplayer codebase.

This commit is contained in:
genxium
2023-01-25 18:26:13 +08:00
parent 5df545e168
commit 8536521136
16 changed files with 1522 additions and 981 deletions

View File

@@ -77,22 +77,12 @@ message WsReq {
HeartbeatUpsync hb = 8;
}
message WsResp {
int32 ret = 1;
int32 echoedMsgId = 2;
int32 act = 3;
RoomDownsyncFrame rdf = 4;
repeated InputFrameDownsync inputFrameDownsyncBatch = 5;
BattleColliderInfo bciFrame = 6;
int32 peerJoinIndex = 7; // Only used when "InputsBufferSnapshot.peerJoinIndex" is used.
}
message InputsBufferSnapshot {
int32 refRenderFrameId = 1;
uint64 unconfirmedMask = 2;
repeated InputFrameDownsync toSendInputFrameDownsyncs = 3;
bool shouldForceResync = 4;
int32 peerJoinIndex = 5; // Only used when "WsResp.peerJoinIndex" is used.
int32 peerJoinIndex = 5;
}
message MeleeBullet {
@@ -191,10 +181,23 @@ message BattleColliderInfo {
double spaceOffsetX = 11;
double spaceOffsetY = 12;
int32 collisionMinStep = 13;
int32 boundRoomCapacity = 14;
bool frameDataLoggingEnabled = 1024;
}
message HolePunchUpsync {
string intAuthToken = 1;
int32 boundRoomId = 2;
int32 authKey = 3;
}
message PeerUdpAddr {
string ip = 1;
int32 port = 2;
int32 authKey = 3;
}
message RoomDownsyncFrame {
int32 id = 1;
repeated PlayerDownsync playersArr = 2;
@@ -207,11 +210,15 @@ message RoomDownsyncFrame {
repeated int32 speciesIdList = 1026;
int32 bulletLocalIdCounter = 1027;
repeated PeerUdpAddr peerUdpAddrList = 1028;
}
message HolePunchUpsync {
int32 joinIndex = 1;
string intAuthToken = 2;
int32 boundRoomId = 3;
int32 authKey = 4;
message WsResp {
int32 ret = 1;
int32 echoedMsgId = 2;
int32 act = 3;
RoomDownsyncFrame rdf = 4;
repeated InputFrameDownsync inputFrameDownsyncBatch = 5;
BattleColliderInfo bciFrame = 6;
int32 peerJoinIndex = 7;
}

View File

@@ -54,7 +54,7 @@ cc.Class({
exitBtnOnClick(evt) {
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
window.closeWSConnection();
window.closeWSConnection(constants.RET_CODE.UNKNOWN_ERROR, "");
cc.director.loadScene('login');
},

View File

@@ -336,7 +336,6 @@ cc.Class({
self.recentRenderCache = new RingBuffer(self.renderCacheSize);
self.selfPlayerInfo = null; // This field is kept for distinguishing "self" and "others".
self.recentInputCache = gopkgs.NewRingBufferJs((self.renderCacheSize >> 1) + 1);
self.gopkgsCollisionSys = gopkgs.NewCollisionSpaceJs((self.spaceOffsetX << 1), (self.spaceOffsetY << 1), self.collisionMinStep, self.collisionMinStep);
@@ -500,7 +499,7 @@ cc.Class({
const fullPathOfTmxFile = cc.js.formatStr("map/%s/map", parsedBattleColliderInfo.stageName);
cc.loader.loadRes(fullPathOfTmxFile, cc.TiledMapAsset, (err, tmxAsset) => {
if (null != err) {
console.error(err);
console.error(`Error occurred when loading tiled stage ${parsedBattleColliderInfo.stageName}`, err);
return;
}
@@ -549,10 +548,6 @@ cc.Class({
const collisionBarrierIndex = (self.collisionBarrierIndexPrefix + barrierIdCounter);
self.gopkgsCollisionSysMap[collisionBarrierIndex] = newBarrierCollider;
}
self.selfPlayerInfo = JSON.parse(cc.sys.localStorage.getItem('selfPlayer'));
Object.assign(self.selfPlayerInfo, {
Id: self.selfPlayerInfo.playerId
});
self.initDebugDrawers();
const reqData = window.pb.protos.WsReq.encode({
msgId: Date.now(),
@@ -920,7 +915,7 @@ batchInputFrameIdRange=[${batch[0].inputFrameId}, ${batch[batch.length - 1].inpu
return;
}
self._stringifyRdfIdToActuallyUsedInput();
window.closeWSConnection(constants.RET_CODE.BATTLE_STOPPED);
window.closeWSConnection(constants.RET_CODE.BATTLE_STOPPED, "");
self.battleState = ALL_BATTLE_STATES.IN_SETTLEMENT;
self.countdownNanos = null;
if (self.musicEffectManagerScriptIns) {
@@ -1273,24 +1268,6 @@ othersForcedDownsyncRenderFrame=${JSON.stringify(othersForcedDownsyncRenderFrame
}
const j = gopkgs.ConvertToDelayedInputFrameId(i);
const delayedInputFrame = self.recentInputCache.GetByFrameId(j);
/*
const prevJ = gopkgs.ConvertToDelayedInputFrameId(i - 1);
const prevDelayedInputFrame = self.recentInputCache.GetByFrameId(prevJ);
const prevBtnALevel = (null == prevDelayedInputFrame ? 0 : ((prevDelayedInputFrame.InputList[self.selfPlayerInfo.JoinIndex - 1] >> 4) & 1));
const btnALevel = ((delayedInputFrame.InputList[self.selfPlayerInfo.JoinIndex - 1] >> 4) & 1);
if (
ATK_CHARACTER_STATE.Atk1[0] == currRdf.PlayersArr[self.selfPlayerInfo.JoinIndex - 1].CharacterState
||
ATK_CHARACTER_STATE.Atk2[0] == currRdf.PlayersArr[self.selfPlayerInfo.JoinIndex - 1].CharacterState
) {
console.log(`rdf.Id=${i}, (btnALevel,j)=(${btnALevel},${j}), (prevBtnALevel,prevJ) is (${prevBtnALevel},${prevJ}), in cancellable atk!`);
}
if (btnALevel > 0) {
if (btnALevel > prevBtnALevel) {
console.log(`rdf.Id=${i}, rising edge of btnA triggered`);
}
}
*/
if (self.frameDataLoggingEnabled) {
const actuallyUsedInputClone = delayedInputFrame.InputList.slice();
@@ -1336,7 +1313,7 @@ othersForcedDownsyncRenderFrame=${JSON.stringify(othersForcedDownsyncRenderFrame
const selfPlayerId = self.selfPlayerInfo.Id;
if (selfPlayerId == playerId) {
self.selfPlayerInfo.JoinIndex = immediatePlayerInfo.JoinIndex;
self.selfPlayerInfo.JoinIndex = immediatePlayerInfo.JoinIndex; // Update here in case of any change during WAITING phase
nodeAndScriptIns[1].showArrowTipNode();
}
}

View File

@@ -156,13 +156,12 @@ cc.Class({
cc.log(`#2 Js called back by CPP: onUdpMessage: ${JSON.stringify(echoed)}`);
};
const res1 = DelayNoMore.UdpSession.openUdpSession(8888 + self.selfPlayerInfo.JoinIndex);
const holePunchDate = window.pb.protos.HolePunchUpsync.encode({
joinIndex: self.selfPlayerInfo.JoinIndex,
const holePunchData = window.pb.protos.HolePunchUpsync.encode({
boundRoomId: 22,
intAuthToken: "foobar",
authKey: Math.floor(Math.random() * 65535),
}).finish()
const res2 = DelayNoMore.UdpSession.punchToServer("127.0.0.1", 3000, holePunchDate);
const res2 = DelayNoMore.UdpSession.punchToServer("127.0.0.1", 3000, holePunchData);
const res3 = DelayNoMore.UdpSession.upsertPeerUdpAddr(self.selfPlayerInfo.JoinIndex, "192.168.31.194", 6789, 123456, 2, self.selfPlayerInfo.JoinIndex);
//const res4 = DelayNoMore.UdpSession.closeUdpSession();
}

View File

@@ -12,6 +12,7 @@ window.DOWNSYNC_MSG_ACT_INPUT_BATCH = 2;
window.DOWNSYNC_MSG_ACT_BATTLE_STOPPED = 3;
window.DOWNSYNC_MSG_ACT_FORCED_RESYNC = 4;
window.DOWNSYNC_MSG_ACT_PEER_INPUT_BATCH = 5;
window.DOWNSYNC_MSG_ACT_PEER_UDP_ADDR = 6;
window.sendSafely = function(msgStr) {
/**
@@ -46,9 +47,19 @@ window.getBoundRoomIdFromPersistentStorage = function() {
return cc.sys.localStorage.getItem("boundRoomId");
};
window.getBoundRoomCapacityFromPersistentStorage = function() {
const boundRoomIdExpiresAt = parseInt(cc.sys.localStorage.getItem("boundRoomIdExpiresAt"));
if (!boundRoomIdExpiresAt || Date.now() >= boundRoomIdExpiresAt) {
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();
return null;
}
return cc.sys.localStorage.getItem("boundRoomCapacity");
};
window.clearBoundRoomIdInBothVolatileAndPersistentStorage = function() {
window.boundRoomId = null;
cc.sys.localStorage.removeItem("boundRoomId");
cc.sys.localStorage.removeItem("boundRoomCapacity");
cc.sys.localStorage.removeItem("boundRoomIdExpiresAt");
};
@@ -57,20 +68,44 @@ window.clearSelfPlayer = function() {
};
window.boundRoomId = getBoundRoomIdFromPersistentStorage();
window.boundRoomCapacity = getBoundRoomCapacityFromPersistentStorage();
window.handleHbRequirements = function(resp) {
console.log(`Handle hb requirements #1`);
if (constants.RET_CODE.OK != resp.ret) return;
if (null == window.boundRoomId) {
// The assignment of "window.mapIns" is inside "Map.onLoad", which precedes "initPersistentSessionClient".
window.mapIns.selfPlayerInfo = JSON.parse(cc.sys.localStorage.getItem('selfPlayer')); // This field is kept for distinguishing "self" and "others".
window.mapIns.selfPlayerInfo.Id = window.mapIns.selfPlayerInfo.playerId;
window.mapIns.selfPlayerInfo.JoinIndex = resp.peerJoinIndex;
console.log(`Handle hb requirements #2`);
if (null == window.boundRoomId || null == window.boundRoomCapacity) {
window.boundRoomId = resp.bciFrame.boundRoomId;
window.boundRoomCapacity = resp.bciFrame.boundRoomCapacity;
cc.sys.localStorage.setItem('boundRoomId', window.boundRoomId);
cc.sys.localStorage.setItem('boundRoomCapacity', window.boundRoomCapacity);
cc.sys.localStorage.setItem('boundRoomIdExpiresAt', Date.now() + 10 * 60 * 1000); // Temporarily hardcoded, for `boundRoomId` only.
}
console.log(`Handle hb requirements #3`);
if (window.handleBattleColliderInfo) {
if (!cc.sys.isNative) {
window.initSecondarySession(null, window.boundRoomId);
}
window.handleBattleColliderInfo(resp.bciFrame);
}
console.log(`Handle hb requirements #4`);
if (!cc.sys.isNative) {
console.log(`Handle hb requirements #5, web`);
window.initSecondarySession(null, window.boundRoomId);
} else {
console.log(`Handle hb requirements #5, native`);
const res1 = DelayNoMore.UdpSession.openUdpSession(8888 + window.mapIns.selfPlayerInfo.JoinIndex);
const intAuthToken = window.mapIns.selfPlayerInfo.intAuthToken;
const authKey = Math.floor(Math.random() * 65535);
window.mapIns.selfPlayerInfo.authKey = authKey;
const holePunchData = window.pb.protos.HolePunchUpsync.encode({
boundRoomId: window.boundRoomId,
intAuthToken: intAuthToken,
authKey: authKey,
}).finish();
const res2 = DelayNoMore.UdpSession.punchToServer(backendAddress.HOST, 3000, holePunchData);
}
};
function _uint8ToBase64(uint8Arr) {
@@ -128,6 +163,7 @@ window.initPersistentSessionClient = function(onopenCb, expectedRoomId) {
urlToConnect = urlToConnect + "&expectedRoomId=" + expectedRoomId;
} else {
window.boundRoomId = getBoundRoomIdFromPersistentStorage();
window.boundRoomCapacity = getBoundRoomCapacityFromPersistentStorage();
if (null != window.boundRoomId) {
console.log("initPersistentSessionClient with boundRoomId == " + boundRoomId);
urlToConnect = urlToConnect + "&boundRoomId=" + window.boundRoomId;
@@ -178,6 +214,16 @@ window.initPersistentSessionClient = function(onopenCb, expectedRoomId) {
}
mapIns.onRoomDownsyncFrame(resp.rdf, resp.inputFrameDownsyncBatch);
break;
case window.DOWNSYNC_MSG_ACT_PEER_UDP_ADDR:
console.warn(`Got DOWNSYNC_MSG_ACT_PEER_UDP_ADDR resp=${JSON.stringify(resp, null, 2)}`);
if (cc.sys.isNative) {
const peerJoinIndex = resp.peerJoinIndex;
const peerAddrList = resp.rdf.peerUdpAddrList;
const peerAddr = peerAddrList[peerJoinIndex - 1];
console.log(`Got DOWNSYNC_MSG_ACT_PEER_UDP_ADDR peerAddr=${peerAddr}; boundRoomCapacity=${window.boundRoomCapacity}, mapIns.selfPlayerInfo=${window.mapIns.selfPlayerInfo}`);
DelayNoMore.UdpSession.upsertPeerUdpAddr(peerJoinIndex, peerAddr.ip, peerAddr.port, peerAddr.authKey, window.boundRoomCapacity, window.mapIns.selfPlayerInfo.JoinIndex);
}
break;
default:
break;
}
@@ -224,6 +270,9 @@ window.initPersistentSessionClient = function(onopenCb, expectedRoomId) {
default:
break;
}
if (cc.sys.isNative) {
DelayNoMore.UdpSession.closeUdpSession();
}
};
};
@@ -234,7 +283,7 @@ window.clearLocalStorageAndBackToLoginScene = function(shouldRetainBoundRoomIdIn
window.mapIns.musicEffectManagerScriptIns.stopAllMusic();
}
window.closeWSConnection();
window.closeWSConnection(constants.RET_CODE.UNKNOWN_ERROR, "");
window.clearSelfPlayer();
if (true != shouldRetainBoundRoomIdInBothVolatileAndPersistentStorage) {
window.clearBoundRoomIdInBothVolatileAndPersistentStorage();