Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7302fccb48 | ||
|
|
eb2fe6175a |
@@ -4,6 +4,7 @@ import { GAMEPLAY_ATLAS_PATHS } from "../Tool/GameplayAtlasFrames";
|
|||||||
import { MiniGameSdk } from "../../Sdk/MiniGameSdk";
|
import { MiniGameSdk } from "../../Sdk/MiniGameSdk";
|
||||||
import { GameTool } from "../Tool/GameTool";
|
import { GameTool } from "../Tool/GameTool";
|
||||||
import BlockAssetManager from "../Tool/BlockAssetManager";
|
import BlockAssetManager from "../Tool/BlockAssetManager";
|
||||||
|
import { LEVEL_TIME_BONUS } from "./LevelTimeBonusConfig";
|
||||||
|
|
||||||
interface GameplayEntryPreparation {
|
interface GameplayEntryPreparation {
|
||||||
startedAt: number;
|
startedAt: number;
|
||||||
@@ -1365,7 +1366,11 @@ export class GameConfig {
|
|||||||
static applyLevelData(jsonData: any, type: any, time: any, levelNumber = Number(jsonData.LEVEL_INFO[0].id), preparation?: GameplayEntryPreparation) {
|
static applyLevelData(jsonData: any, type: any, time: any, levelNumber = Number(jsonData.LEVEL_INFO[0].id), preparation?: GameplayEntryPreparation) {
|
||||||
this.loadedLevelNumber = levelNumber;
|
this.loadedLevelNumber = levelNumber;
|
||||||
this.BLOCK_INFO = jsonData["BLOCK_INFO"];
|
this.BLOCK_INFO = jsonData["BLOCK_INFO"];
|
||||||
this.LEVEL_INFO = jsonData["LEVEL_INFO"];
|
const extraTime = this.GM_INFO?.abTests?.layer_three === 2 ? LEVEL_TIME_BONUS[levelNumber] || 0 : 0;
|
||||||
|
// 只调整本局时限,保留资源缓存中的原始时间,避免重开时重复加时。
|
||||||
|
this.LEVEL_INFO = extraTime
|
||||||
|
? jsonData["LEVEL_INFO"].map((info, index) => index === 0 ? { ...info, time: info.time + extraTime } : info)
|
||||||
|
: jsonData["LEVEL_INFO"];
|
||||||
this.WALL_INFO = jsonData["WALL_INFO"];
|
this.WALL_INFO = jsonData["WALL_INFO"];
|
||||||
console.log("关卡配置加载完成");
|
console.log("关卡配置加载完成");
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,103 @@
|
|||||||
|
// layer_three B 组的逐关加时,单位:秒。
|
||||||
|
export const LEVEL_TIME_BONUS: { readonly [level: number]: number } = {
|
||||||
|
114: 30,
|
||||||
|
132: 20,
|
||||||
|
222: 10,
|
||||||
|
259: 30,
|
||||||
|
302: 30,
|
||||||
|
317: 20,
|
||||||
|
329: 10,
|
||||||
|
383: 30,
|
||||||
|
400: 30,
|
||||||
|
411: 20,
|
||||||
|
416: 20,
|
||||||
|
422: 20,
|
||||||
|
426: 30,
|
||||||
|
433: 30,
|
||||||
|
444: 40,
|
||||||
|
452: 30,
|
||||||
|
504: 30,
|
||||||
|
517: 40,
|
||||||
|
521: 20,
|
||||||
|
524: 30,
|
||||||
|
535: 50,
|
||||||
|
536: 20,
|
||||||
|
542: 20,
|
||||||
|
548: 30,
|
||||||
|
557: 20,
|
||||||
|
563: 20,
|
||||||
|
566: 20,
|
||||||
|
595: 10,
|
||||||
|
604: 20,
|
||||||
|
612: 20,
|
||||||
|
630: 30,
|
||||||
|
648: 20,
|
||||||
|
651: 30,
|
||||||
|
666: 20,
|
||||||
|
688: 30,
|
||||||
|
690: 30,
|
||||||
|
745: 20,
|
||||||
|
748: 40,
|
||||||
|
750: 30,
|
||||||
|
789: 20,
|
||||||
|
798: 30,
|
||||||
|
799: 30,
|
||||||
|
828: 20,
|
||||||
|
868: 20,
|
||||||
|
881: 20,
|
||||||
|
895: 30,
|
||||||
|
916: 20,
|
||||||
|
962: 30,
|
||||||
|
963: 40,
|
||||||
|
981: 20,
|
||||||
|
991: 20,
|
||||||
|
1003: 30,
|
||||||
|
1008: 20,
|
||||||
|
1023: 20,
|
||||||
|
1024: 20,
|
||||||
|
1026: 30,
|
||||||
|
1027: 30,
|
||||||
|
1043: 20,
|
||||||
|
1061: 20,
|
||||||
|
1063: 30,
|
||||||
|
1077: 20,
|
||||||
|
1087: 20,
|
||||||
|
1093: 20,
|
||||||
|
1107: 20,
|
||||||
|
1122: 40,
|
||||||
|
1123: 40,
|
||||||
|
1129: 20,
|
||||||
|
1137: 10,
|
||||||
|
1139: 30,
|
||||||
|
1143: 30,
|
||||||
|
1146: 20,
|
||||||
|
1154: 40,
|
||||||
|
1164: 20,
|
||||||
|
1166: 30,
|
||||||
|
1171: 40,
|
||||||
|
1173: 20,
|
||||||
|
1175: 10,
|
||||||
|
1185: 30,
|
||||||
|
1195: 20,
|
||||||
|
1202: 20,
|
||||||
|
1204: 20,
|
||||||
|
1205: 30,
|
||||||
|
1206: 20,
|
||||||
|
1207: 40,
|
||||||
|
1209: 20,
|
||||||
|
1210: 30,
|
||||||
|
1212: 40,
|
||||||
|
1222: 60,
|
||||||
|
1225: 30,
|
||||||
|
1227: 20,
|
||||||
|
1228: 20,
|
||||||
|
1239: 30,
|
||||||
|
1241: 30,
|
||||||
|
1242: 40,
|
||||||
|
1264: 20,
|
||||||
|
1266: 30,
|
||||||
|
1268: 40,
|
||||||
|
1275: 60,
|
||||||
|
1279: 40,
|
||||||
|
1281: 40,
|
||||||
|
};
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.1.0",
|
||||||
|
"uuid": "df6e40f7-1279-4724-afe3-55fade9817c0",
|
||||||
|
"importer": "typescript",
|
||||||
|
"isPlugin": false,
|
||||||
|
"loadPluginInWeb": true,
|
||||||
|
"loadPluginInNative": true,
|
||||||
|
"loadPluginInEditor": false,
|
||||||
|
"subMetas": {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
const test = require('node:test');
|
||||||
|
const assert = require('node:assert/strict');
|
||||||
|
const fs = require('node:fs');
|
||||||
|
const { loadMembers, loadModule, resolveFile } = require('./new-player-ab-test-support.cjs');
|
||||||
|
const { LEVEL_TIME_BONUS } = loadModule('assets/Script/module/Config/LevelTimeBonusConfig.ts');
|
||||||
|
const configFile = 'assets/Script/module/Config/GameConfig.ts';
|
||||||
|
const readLevel = level => JSON.parse(fs.readFileSync(resolveFile(`assets/custom/Json/level${level}.json`), 'utf8'));
|
||||||
|
const plain = value => JSON.parse(JSON.stringify(value));
|
||||||
|
|
||||||
|
function config(info = {}) {
|
||||||
|
const Config = loadMembers(configFile, ['applyLevelData', 'LEVEL_INFO_init', 'getLevelConfigPath'], {
|
||||||
|
LEVEL_TIME_BONUS, console: { log() {} }, cc,
|
||||||
|
});
|
||||||
|
Config.GM_INFO = info;
|
||||||
|
return Config;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exercise the actual loader so file numbers, help levels and endless levels use the same key.
|
||||||
|
const requests = [];
|
||||||
|
const cc = {
|
||||||
|
v2: (x, y) => ({ x, y }), director: { getScene: () => null },
|
||||||
|
fx: { GameTool: { maxLevel: () => false } },
|
||||||
|
assetManager: {
|
||||||
|
loadBundle(_name, _options, done) { done(null, {}); },
|
||||||
|
loadAny(request, _options, done) {
|
||||||
|
requests.push(request.path);
|
||||||
|
done(null, { json: readLevel(Number(request.path.replace('Json/level', ''))) });
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
test('A, unassigned and other groups retain the original time for every configured level', () => {
|
||||||
|
assert.equal(Object.keys(LEVEL_TIME_BONUS).length, 100);
|
||||||
|
for (const info of [undefined, {}, { abTests: {} }, ...[0, 1, 3].map(layer_three => ({ abTests: { layer_three } }))]) {
|
||||||
|
const Config = config(info);
|
||||||
|
for (const level of Object.keys(LEVEL_TIME_BONUS)) {
|
||||||
|
const data = readLevel(level);
|
||||||
|
Config.applyLevelData(data, false, 0, Number(level));
|
||||||
|
assert.equal(Config.LEVEL_INFO[0].time, data.LEVEL_INFO[0].time);
|
||||||
|
assert.equal(Config.LEVEL_INFO, data.LEVEL_INFO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('B adds time once, preserves cached data and returns to original time when switched to A', () => {
|
||||||
|
const Config = config({ abTests: { layer_three: 2 } });
|
||||||
|
for (const [level, bonus] of Object.entries(LEVEL_TIME_BONUS)) {
|
||||||
|
assert.ok(Number.isInteger(bonus) && bonus > 0);
|
||||||
|
const data = readLevel(level), before = structuredClone(data);
|
||||||
|
Config.GM_INFO.abTests.layer_three = 2;
|
||||||
|
for (let retry = 0; retry < 2; retry++) {
|
||||||
|
Config.applyLevelData(data, false, 0, Number(level));
|
||||||
|
const expected = structuredClone(before.LEVEL_INFO);
|
||||||
|
expected[0].time += bonus;
|
||||||
|
assert.deepEqual(plain(Config.LEVEL_INFO), expected);
|
||||||
|
assert.equal(Config.BLOCK_INFO, data.BLOCK_INFO);
|
||||||
|
assert.equal(Config.WALL_INFO, data.WALL_INFO);
|
||||||
|
assert.deepEqual(data, before);
|
||||||
|
}
|
||||||
|
Config.GM_INFO.abTests.layer_three = 1;
|
||||||
|
Config.applyLevelData(data, false, 0, Number(level));
|
||||||
|
assert.equal(Config.LEVEL_INFO[0].time, before.LEVEL_INFO[0].time);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('B leaves unlisted levels unchanged and uses the file number instead of a stale internal id', () => {
|
||||||
|
const Config = config({ abTests: { layer_three: 2 } });
|
||||||
|
for (const level of [1, 113, 115, 1282]) {
|
||||||
|
const data = readLevel(level);
|
||||||
|
Config.applyLevelData(data, false, 0, level);
|
||||||
|
assert.equal(Config.LEVEL_INFO, data.LEVEL_INFO);
|
||||||
|
}
|
||||||
|
const data = readLevel(222);
|
||||||
|
assert.equal(data.LEVEL_INFO[0].id, '158');
|
||||||
|
Config.applyLevelData(data, false, 0, 222);
|
||||||
|
assert.equal(Config.LEVEL_INFO[0].time, 70);
|
||||||
|
assert.equal(Config.LEVEL_INFO[0].id, '158');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('loader applies B bonuses to the requested mainline, help and endless level', () => {
|
||||||
|
for (const mode of ['mainline', 'help', 'endless']) {
|
||||||
|
const Config = config({ level: mode === 'mainline' ? 221 : 0,
|
||||||
|
otherLevel: mode === 'help' ? 222 : 0, randomLevel: 222, abTests: { layer_three: 2 } });
|
||||||
|
cc.fx.GameConfig = Config;
|
||||||
|
Config.levelLoadRequest = Config.sceneLoadRequest = 0;
|
||||||
|
Config.takeEntryDownloadRelease = () => null;
|
||||||
|
Config.LEVEL_INFO_init(false, 0, mode === 'help', mode === 'endless');
|
||||||
|
assert.equal(requests.at(-1), 'Json/level222');
|
||||||
|
assert.equal(Config.LEVEL_INFO[0].time, 70, mode);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('server A/B assignments select original and bonus times before entering the scene', () => {
|
||||||
|
const Manager = loadMembers('assets/Script/GameManager.ts', ['setABTests'], { cc });
|
||||||
|
const manager = new Manager();
|
||||||
|
const Config = config();
|
||||||
|
cc.fx.GameConfig = Config;
|
||||||
|
const seen = [];
|
||||||
|
Config.enterGameSceneWhenReady = (time, preparation) => seen.push([Config.LEVEL_INFO[0].time, time, preparation]);
|
||||||
|
const preparation = {};
|
||||||
|
for (const [group, expected] of [['A', 135], ['B', 165], [1, 135], [2, 165]]) {
|
||||||
|
manager.setABTests({ layer_3: { group } });
|
||||||
|
Config.applyLevelData(readLevel(114), true, 0.5, 114, preparation);
|
||||||
|
assert.deepEqual(seen.at(-1), [expected, 0.5, preparation]);
|
||||||
|
}
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user