Fixes for melee attack sync.

This commit is contained in:
genxium
2022-11-24 19:45:48 +08:00
parent 2290c57c1c
commit 04de4666d5
13 changed files with 271 additions and 238 deletions

File diff suppressed because one or more lines are too long

View File

@@ -1,7 +1,7 @@
{
"ver": "1.0.0",
"uuid": "2f5ba371-9006-4e2d-8dd4-df91fcea1df2",
"uuid": "e9e703e9-3589-4713-b889-28b23406d220",
"atlasJson": "{\"SubTexture\":[{\"y\":50,\"frameX\":-2,\"frameY\":-2,\"width\":19,\"frameWidth\":23,\"height\":19,\"name\":\"biu\",\"frameHeight\":22,\"x\":1},{\"width\":9,\"y\":50,\"height\":14,\"name\":\"rightArm\",\"x\":42},{\"y\":34,\"frameX\":-6,\"frameY\":0,\"width\":20,\"frameWidth\":29,\"height\":32,\"name\":\"yinmoqe00\",\"frameHeight\":32,\"x\":88},{\"y\":1,\"frameX\":0,\"frameY\":0,\"width\":33,\"frameWidth\":34,\"height\":39,\"name\":\"body\",\"frameHeight\":41,\"x\":53},{\"width\":9,\"y\":56,\"height\":13,\"name\":\"rightShoulder\",\"x\":74},{\"y\":50,\"frameX\":0,\"frameY\":0,\"width\":18,\"frameWidth\":19,\"height\":17,\"name\":\"rightFrontArm\",\"frameHeight\":18,\"x\":22},{\"width\":14,\"y\":50,\"height\":14,\"name\":\"rightHand\",\"x\":110},{\"width\":12,\"y\":42,\"height\":12,\"name\":\"leftArm\",\"x\":74},{\"width\":13,\"y\":66,\"height\":12,\"name\":\"leftShoulder\",\"x\":110},{\"y\":42,\"frameX\":-1,\"frameY\":0,\"width\":19,\"frameWidth\":20,\"height\":21,\"name\":\"leftFrontArm\",\"frameHeight\":21,\"x\":53},{\"width\":50,\"y\":1,\"height\":47,\"name\":\"head2\",\"x\":1},{\"y\":1,\"frameX\":-1,\"frameY\":0,\"width\":32,\"frameWidth\":33,\"height\":31,\"name\":\"head\",\"frameHeight\":32,\"x\":88},{\"width\":16,\"y\":34,\"height\":14,\"name\":\"leftHand\",\"x\":110},{\"y\":1,\"frameX\":-2,\"frameY\":-3,\"width\":2,\"frameWidth\":8,\"height\":2,\"name\":\"huomiao01\",\"frameHeight\":8,\"x\":122}],\"width\":128,\"height\":128,\"name\":\"SoldierWaterGhost\",\"imagePath\":\"SoldierWaterGhost_tex.png\"}",
"texture": "62ea1a78-b096-4b8c-afb4-8edd4be142f7",
"texture": "def168c3-3f07-43f9-a460-36b397c70a57",
"subMetas": {}
}

View File

@@ -1,6 +1,6 @@
{
"ver": "2.3.3",
"uuid": "62ea1a78-b096-4b8c-afb4-8edd4be142f7",
"uuid": "def168c3-3f07-43f9-a460-36b397c70a57",
"type": "sprite",
"wrapMode": "clamp",
"filterMode": "bilinear",
@@ -11,8 +11,8 @@
"subMetas": {
"SoldierWaterGhost_tex": {
"ver": "1.0.4",
"uuid": "e7b96c0e-a9b8-40eb-8568-73bd2803cd31",
"rawTextureUuid": "62ea1a78-b096-4b8c-afb4-8edd4be142f7",
"uuid": "52fb0606-bbea-433c-803b-bf5ce936a0df",
"rawTextureUuid": "def168c3-3f07-43f9-a460-36b397c70a57",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,

View File

@@ -108,24 +108,25 @@ message BattleColliderInfo {
int32 intervalToPing = 8;
int32 willKickIfInactiveFor = 9;
int32 boundRoomId = 10;
int64 battleDurationNanos = 11;
int32 serverFps = 12;
int32 inputDelayFrames = 13;
uint32 inputScaleFrames = 14;
int32 nstDelayFrames = 15;
int32 inputFrameUpsyncDelayTolerance = 16;
int32 maxChasingRenderFramesPerUpdate = 17;
int32 playerBattleState = 18;
double rollbackEstimatedDtMillis = 19;
int64 rollbackEstimatedDtNanos = 20;
int32 battleDurationFrames = 12;
int64 battleDurationNanos = 13;
int32 serverFps = 14;
int32 inputDelayFrames = 15; // in the count of render frames
uint32 inputScaleFrames = 16; // inputDelayedAndScaledFrameId = ((originalFrameId - InputDelayFrames) >> InputScaleFrames)
int32 nstDelayFrames = 17; // 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"
int32 inputFrameUpsyncDelayTolerance = 18;
int32 maxChasingRenderFramesPerUpdate = 19;
int32 playerBattleState = 20;
double rollbackEstimatedDtMillis = 21;
int64 rollbackEstimatedDtNanos = 22;
double worldToVirtualGridRatio = 21;
double virtualGridToWorldRatio = 22;
double worldToVirtualGridRatio = 23;
double virtualGridToWorldRatio = 24;
int32 spAtkLookupFrames = 23;
int32 renderCacheSize = 24;
int32 spAtkLookupFrames = 25;
int32 renderCacheSize = 26;
map<int32, MeleeBullet> meleeSkillConfig = 25; // skillId -> skill
map<int32, MeleeBullet> meleeSkillConfig = 27; // skillId -> skill
}
message RoomDownsyncFrame {

View File

@@ -860,7 +860,7 @@
"_cacheMode": 0,
"playTimes": -1,
"premultipliedAlpha": false,
"_armatureKey": "73b7e7d4-6ad0-41ea-9d17-1104c463aad2#2f5ba371-9006-4e2d-8dd4-df91fcea1df2",
"_armatureKey": "a9d7bbc2-134b-4eb4-ba16-6541f3e51e06#e9e703e9-3589-4713-b889-28b23406d220",
"_accTime": 0,
"_playCount": 0,
"_frameCache": null,
@@ -868,10 +868,10 @@
"_playing": false,
"_armatureCache": null,
"_N$dragonAsset": {
"__uuid__": "73b7e7d4-6ad0-41ea-9d17-1104c463aad2"
"__uuid__": "a9d7bbc2-134b-4eb4-ba16-6541f3e51e06"
},
"_N$dragonAtlasAsset": {
"__uuid__": "2f5ba371-9006-4e2d-8dd4-df91fcea1df2"
"__uuid__": "e9e703e9-3589-4713-b889-28b23406d220"
},
"_N$_defaultArmatureIndex": 0,
"_N$_animationIndex": 8,

View File

@@ -440,7 +440,7 @@
"array": [
0,
0,
210.23252687912068,
216.50635094610968,
0,
0,
0,

View File

@@ -454,7 +454,7 @@
"array": [
0,
0,
210.23252687912068,
216.50635094610968,
0,
0,
0,

View File

@@ -991,7 +991,7 @@ cc.Class({
const lastAllConfirmedInputFrame = self.recentInputCache.getByFrameId(self.lastAllConfirmedInputFrameId);
for (let i = 0; i < inputFrameDownsync.inputList.length; ++i) {
if (i == self.selfPlayerInfo.joinIndex - 1) continue;
inputFrameDownsync.inputList[i] = lastAllConfirmedInputFrame.inputList[i];
inputFrameDownsync.inputList[i] = (lastAllConfirmedInputFrame.inputList[i] & 15); // Don't predict attack input!
}
}
@@ -1141,7 +1141,7 @@ cc.Class({
playerCollider.x += bulletPushbacks[joinIndex - 1][0];
playerCollider.y += bulletPushbacks[joinIndex - 1][1];
if (0 != bulletPushbacks[joinIndex - 1][0] || 0 != bulletPushbacks[joinIndex - 1][1]) {
console.log(`playerId=${playerId}, joinIndex=${joinIndex} is pushbacked back by ${bulletPushbacks[joinIndex - 1]} by bullet impacts, now its framesToRecover is ${currPlayerDownsync.framesToRecover}`);
console.log(`playerId=${playerId}, joinIndex=${joinIndex} is pushbacked back by ${bulletPushbacks[joinIndex - 1]} by bullet impacts, now its framesToRecover is ${thatPlayerInNextFrame.framesToRecover}`);
}
continue;
}
@@ -1154,14 +1154,16 @@ cc.Class({
if (1 == decodedInput.btnALevel && 0 == prevBtnALevel) {
// console.log(`playerId=${playerId} triggered a rising-edge of btnA at renderFrame.id=${currRenderFrame.id}, delayedInputFrame.id=${delayedInputFrame.inputFrameId}`);
if (self.bulletTriggerEnabled) {
thatPlayerInNextFrame.framesToRecover = window.PunchAtkConfig.recoveryFrames;
const punch = window.pb.protos.MeleeBullet.create(window.PunchAtkConfig);
const punchSkillId = 1;
const punch = window.pb.protos.MeleeBullet.create(self.meleeSkillConfig[punchSkillId]);
thatPlayerInNextFrame.framesToRecover = punch.recoveryFrames;
punch.battleLocalId = self.bulletBattleLocalIdCounter++;
punch.offenderJoinIndex = joinIndex;
punch.offenderPlayerId = playerId;
punch.originatedRenderFrameId = currRenderFrame.id;
toRet.meleeBullets.push(punch);
console.log(`A rising-edge of meleeBullet is created at renderFrame.id=${currRenderFrame.id}, delayedInputFrame.id=${delayedInputFrame.inputFrameId}: ${self._stringifyRecentInputCache(true)}`);
// console.log(`A rising-edge of meleeBullet is created at renderFrame.id=${currRenderFrame.id}, delayedInputFrame.id=${delayedInputFrame.inputFrameId}: ${self._stringifyRecentInputCache(true)}`);
// console.log(`A rising-edge of meleeBullet is created at renderFrame.id=${currRenderFrame.id}, delayedInputFrame.id=${delayedInputFrame.inputFrameId}`);
thatPlayerInNextFrame.characterState = window.ATK_CHARACTER_STATE.Atk1[0];
}

View File

@@ -3,31 +3,6 @@ i18n.init(window.language); // languageID should be equal to the one we input in
const OnlineMap = require('./Map');
window.PunchAtkConfig = {
// for offender
startupFrames: 18,
activeFrames: 42,
recoveryFrames: 61, // usually but not always "startupFrames+activeFrames", I hereby set it to be 1 frame more than the actual animation to avoid critical transition, i.e. when the animation is 1 frame from ending but "rdfPlayer.framesToRecover" is already counted 0 and the player triggers an other same attack, making an effective bullet trigger but no animation is played due to same animName is still playing
recoveryFramesOnBlock: 61,
recoveryFramesOnHit: 61,
moveforward: {
x: 0,
y: 0,
},
hitboxOffset: 12.0, // should be about the radius of the PlayerCollider
hitboxSize: {
x: 45.0,
y: 32.0,
},
// for defender
hitStunFrames: 18,
blockStunFrames: 9,
pushback: 22.0,
releaseTriggerType: 1, // 1: rising-edge, 2: falling-edge
damage: 5
};
cc.Class({
extends: OnlineMap,
@@ -64,6 +39,32 @@ cc.Class({
self.worldToVirtualGridRatio = 1000;
self.virtualGridToWorldRatio = 1.0 / self.worldToVirtualGridRatio;
self.meleeSkillConfig = {
1: {
// for offender
startupFrames: 18,
activeFrames: 42,
recoveryFrames: 61, // usually but not always "startupFrames+activeFrames", I hereby set it to be 1 frame more than the actual animation to avoid critical transition, i.e. when the animation is 1 frame from ending but "rdfPlayer.framesToRecover" is already counted 0 and the player triggers an other same attack, making an effective bullet trigger but no animation is played due to same animName is still playing
recoveryFramesOnBlock: 61,
recoveryFramesOnHit: 61,
moveforward: {
x: 0,
y: 0,
},
hitboxOffset: 12.0, // should be about the radius of the PlayerCollider
hitboxSize: {
x: 45.0,
y: 32.0,
},
// for defender
hitStunFrames: 18,
blockStunFrames: 9,
pushback: 22.0,
releaseTriggerType: 1, // 1: rising-edge, 2: falling-edge
damage: 5
}
};
const tiledMapIns = self.node.getComponent(cc.TiledMap);

View File

@@ -4151,6 +4151,7 @@ $root.protos = (function() {
* @property {number|null} [intervalToPing] BattleColliderInfo intervalToPing
* @property {number|null} [willKickIfInactiveFor] BattleColliderInfo willKickIfInactiveFor
* @property {number|null} [boundRoomId] BattleColliderInfo boundRoomId
* @property {number|null} [battleDurationFrames] BattleColliderInfo battleDurationFrames
* @property {number|Long|null} [battleDurationNanos] BattleColliderInfo battleDurationNanos
* @property {number|null} [serverFps] BattleColliderInfo serverFps
* @property {number|null} [inputDelayFrames] BattleColliderInfo inputDelayFrames
@@ -4266,6 +4267,14 @@ $root.protos = (function() {
*/
BattleColliderInfo.prototype.boundRoomId = 0;
/**
* BattleColliderInfo battleDurationFrames.
* @member {number} battleDurationFrames
* @memberof protos.BattleColliderInfo
* @instance
*/
BattleColliderInfo.prototype.battleDurationFrames = 0;
/**
* BattleColliderInfo battleDurationNanos.
* @member {number|Long} battleDurationNanos
@@ -4436,37 +4445,39 @@ $root.protos = (function() {
writer.uint32(/* id 9, wireType 0 =*/72).int32(message.willKickIfInactiveFor);
if (message.boundRoomId != null && Object.hasOwnProperty.call(message, "boundRoomId"))
writer.uint32(/* id 10, wireType 0 =*/80).int32(message.boundRoomId);
if (message.battleDurationFrames != null && Object.hasOwnProperty.call(message, "battleDurationFrames"))
writer.uint32(/* id 12, wireType 0 =*/96).int32(message.battleDurationFrames);
if (message.battleDurationNanos != null && Object.hasOwnProperty.call(message, "battleDurationNanos"))
writer.uint32(/* id 11, wireType 0 =*/88).int64(message.battleDurationNanos);
writer.uint32(/* id 13, wireType 0 =*/104).int64(message.battleDurationNanos);
if (message.serverFps != null && Object.hasOwnProperty.call(message, "serverFps"))
writer.uint32(/* id 12, wireType 0 =*/96).int32(message.serverFps);
writer.uint32(/* id 14, wireType 0 =*/112).int32(message.serverFps);
if (message.inputDelayFrames != null && Object.hasOwnProperty.call(message, "inputDelayFrames"))
writer.uint32(/* id 13, wireType 0 =*/104).int32(message.inputDelayFrames);
writer.uint32(/* id 15, wireType 0 =*/120).int32(message.inputDelayFrames);
if (message.inputScaleFrames != null && Object.hasOwnProperty.call(message, "inputScaleFrames"))
writer.uint32(/* id 14, wireType 0 =*/112).uint32(message.inputScaleFrames);
writer.uint32(/* id 16, wireType 0 =*/128).uint32(message.inputScaleFrames);
if (message.nstDelayFrames != null && Object.hasOwnProperty.call(message, "nstDelayFrames"))
writer.uint32(/* id 15, wireType 0 =*/120).int32(message.nstDelayFrames);
writer.uint32(/* id 17, wireType 0 =*/136).int32(message.nstDelayFrames);
if (message.inputFrameUpsyncDelayTolerance != null && Object.hasOwnProperty.call(message, "inputFrameUpsyncDelayTolerance"))
writer.uint32(/* id 16, wireType 0 =*/128).int32(message.inputFrameUpsyncDelayTolerance);
writer.uint32(/* id 18, wireType 0 =*/144).int32(message.inputFrameUpsyncDelayTolerance);
if (message.maxChasingRenderFramesPerUpdate != null && Object.hasOwnProperty.call(message, "maxChasingRenderFramesPerUpdate"))
writer.uint32(/* id 17, wireType 0 =*/136).int32(message.maxChasingRenderFramesPerUpdate);
writer.uint32(/* id 19, wireType 0 =*/152).int32(message.maxChasingRenderFramesPerUpdate);
if (message.playerBattleState != null && Object.hasOwnProperty.call(message, "playerBattleState"))
writer.uint32(/* id 18, wireType 0 =*/144).int32(message.playerBattleState);
writer.uint32(/* id 20, wireType 0 =*/160).int32(message.playerBattleState);
if (message.rollbackEstimatedDtMillis != null && Object.hasOwnProperty.call(message, "rollbackEstimatedDtMillis"))
writer.uint32(/* id 19, wireType 1 =*/153).double(message.rollbackEstimatedDtMillis);
writer.uint32(/* id 21, wireType 1 =*/169).double(message.rollbackEstimatedDtMillis);
if (message.rollbackEstimatedDtNanos != null && Object.hasOwnProperty.call(message, "rollbackEstimatedDtNanos"))
writer.uint32(/* id 20, wireType 0 =*/160).int64(message.rollbackEstimatedDtNanos);
writer.uint32(/* id 22, wireType 0 =*/176).int64(message.rollbackEstimatedDtNanos);
if (message.worldToVirtualGridRatio != null && Object.hasOwnProperty.call(message, "worldToVirtualGridRatio"))
writer.uint32(/* id 21, wireType 1 =*/169).double(message.worldToVirtualGridRatio);
writer.uint32(/* id 23, wireType 1 =*/185).double(message.worldToVirtualGridRatio);
if (message.virtualGridToWorldRatio != null && Object.hasOwnProperty.call(message, "virtualGridToWorldRatio"))
writer.uint32(/* id 22, wireType 1 =*/177).double(message.virtualGridToWorldRatio);
writer.uint32(/* id 24, wireType 1 =*/193).double(message.virtualGridToWorldRatio);
if (message.spAtkLookupFrames != null && Object.hasOwnProperty.call(message, "spAtkLookupFrames"))
writer.uint32(/* id 23, wireType 0 =*/184).int32(message.spAtkLookupFrames);
writer.uint32(/* id 25, wireType 0 =*/200).int32(message.spAtkLookupFrames);
if (message.renderCacheSize != null && Object.hasOwnProperty.call(message, "renderCacheSize"))
writer.uint32(/* id 24, wireType 0 =*/192).int32(message.renderCacheSize);
writer.uint32(/* id 26, wireType 0 =*/208).int32(message.renderCacheSize);
if (message.meleeSkillConfig != null && Object.hasOwnProperty.call(message, "meleeSkillConfig"))
for (var keys = Object.keys(message.meleeSkillConfig), i = 0; i < keys.length; ++i) {
writer.uint32(/* id 25, wireType 2 =*/202).fork().uint32(/* id 1, wireType 0 =*/8).int32(keys[i]);
writer.uint32(/* id 27, wireType 2 =*/218).fork().uint32(/* id 1, wireType 0 =*/8).int32(keys[i]);
$root.protos.MeleeBullet.encode(message.meleeSkillConfig[keys[i]], writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim().ldelim();
}
return writer;
@@ -4581,63 +4592,67 @@ $root.protos = (function() {
message.boundRoomId = reader.int32();
break;
}
case 11: {
message.battleDurationNanos = reader.int64();
break;
}
case 12: {
message.serverFps = reader.int32();
message.battleDurationFrames = reader.int32();
break;
}
case 13: {
message.inputDelayFrames = reader.int32();
message.battleDurationNanos = reader.int64();
break;
}
case 14: {
message.inputScaleFrames = reader.uint32();
message.serverFps = reader.int32();
break;
}
case 15: {
message.nstDelayFrames = reader.int32();
message.inputDelayFrames = reader.int32();
break;
}
case 16: {
message.inputFrameUpsyncDelayTolerance = reader.int32();
message.inputScaleFrames = reader.uint32();
break;
}
case 17: {
message.maxChasingRenderFramesPerUpdate = reader.int32();
message.nstDelayFrames = reader.int32();
break;
}
case 18: {
message.playerBattleState = reader.int32();
message.inputFrameUpsyncDelayTolerance = reader.int32();
break;
}
case 19: {
message.rollbackEstimatedDtMillis = reader.double();
message.maxChasingRenderFramesPerUpdate = reader.int32();
break;
}
case 20: {
message.rollbackEstimatedDtNanos = reader.int64();
message.playerBattleState = reader.int32();
break;
}
case 21: {
message.worldToVirtualGridRatio = reader.double();
message.rollbackEstimatedDtMillis = reader.double();
break;
}
case 22: {
message.virtualGridToWorldRatio = reader.double();
message.rollbackEstimatedDtNanos = reader.int64();
break;
}
case 23: {
message.spAtkLookupFrames = reader.int32();
message.worldToVirtualGridRatio = reader.double();
break;
}
case 24: {
message.renderCacheSize = reader.int32();
message.virtualGridToWorldRatio = reader.double();
break;
}
case 25: {
message.spAtkLookupFrames = reader.int32();
break;
}
case 26: {
message.renderCacheSize = reader.int32();
break;
}
case 27: {
if (message.meleeSkillConfig === $util.emptyObject)
message.meleeSkillConfig = {};
var end2 = reader.uint32() + reader.pos;
@@ -4739,6 +4754,9 @@ $root.protos = (function() {
if (message.boundRoomId != null && message.hasOwnProperty("boundRoomId"))
if (!$util.isInteger(message.boundRoomId))
return "boundRoomId: integer expected";
if (message.battleDurationFrames != null && message.hasOwnProperty("battleDurationFrames"))
if (!$util.isInteger(message.battleDurationFrames))
return "battleDurationFrames: integer expected";
if (message.battleDurationNanos != null && message.hasOwnProperty("battleDurationNanos"))
if (!$util.isInteger(message.battleDurationNanos) && !(message.battleDurationNanos && $util.isInteger(message.battleDurationNanos.low) && $util.isInteger(message.battleDurationNanos.high)))
return "battleDurationNanos: integer|Long expected";
@@ -4846,6 +4864,8 @@ $root.protos = (function() {
message.willKickIfInactiveFor = object.willKickIfInactiveFor | 0;
if (object.boundRoomId != null)
message.boundRoomId = object.boundRoomId | 0;
if (object.battleDurationFrames != null)
message.battleDurationFrames = object.battleDurationFrames | 0;
if (object.battleDurationNanos != null)
if ($util.Long)
(message.battleDurationNanos = $util.Long.fromValue(object.battleDurationNanos)).unsigned = false;
@@ -4928,6 +4948,7 @@ $root.protos = (function() {
object.intervalToPing = 0;
object.willKickIfInactiveFor = 0;
object.boundRoomId = 0;
object.battleDurationFrames = 0;
if ($util.Long) {
var long = new $util.Long(0, 0, false);
object.battleDurationNanos = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long;
@@ -4978,6 +4999,8 @@ $root.protos = (function() {
object.willKickIfInactiveFor = message.willKickIfInactiveFor;
if (message.boundRoomId != null && message.hasOwnProperty("boundRoomId"))
object.boundRoomId = message.boundRoomId;
if (message.battleDurationFrames != null && message.hasOwnProperty("battleDurationFrames"))
object.battleDurationFrames = message.battleDurationFrames;
if (message.battleDurationNanos != null && message.hasOwnProperty("battleDurationNanos"))
if (typeof message.battleDurationNanos === "number")
object.battleDurationNanos = options.longs === String ? String(message.battleDurationNanos) : message.battleDurationNanos;