更新最新UI修改,复活礼包修改。

This commit is contained in:
COMPUTER\EDY 2026-09-21 18:05:43 +08:00
parent 4018dbfbfc
commit b6ddb8a613
18 changed files with 1414 additions and 1289 deletions

File diff suppressed because it is too large Load Diff

View File

@ -2898,8 +2898,8 @@
},
"_contentSize": {
"__type__": "cc.Size",
"width": 139,
"height": 122
"width": 292,
"height": 247
},
"_anchorPoint": {
"__type__": "cc.Vec2",
@ -2917,8 +2917,8 @@
0,
0,
1,
0.72,
0.72,
0.35,
0.35,
1
]
},
@ -2954,7 +2954,7 @@
"__uuid__": "419e6dd8-8ab5-4910-bf94-b82afe18191b"
},
"_type": 0,
"_sizeMode": 1,
"_sizeMode": 0,
"_fillType": 0,
"_fillCenter": {
"__type__": "cc.Vec2",
@ -26238,9 +26238,9 @@
"vibrate": {
"__id__": 580
},
"exit": null,
"win": null,
"win2": null,
"giveUpFrames": [],
"_id": "a9bjcHbyRE1bK9nCTiACma"
},
{

View File

@ -1167,7 +1167,8 @@ export default class MapConroler extends cc.Component {
// this.node.getChildByName("Wall").zIndex = 10;
this.timeLabel = this.node.parent.getChildByName("Top").getChildByName("time");
this.levelLabel = this.node.parent.getChildByName("Top").getChildByName("level");
this.coin = this.node.parent.getChildByName("Top").getChildByName("shop").getChildByName("coin");
const shop = this.SceneManager.ensureGameShop();
this.coin = shop && shop.getChildByName("coin");
this.timeNumber = cc.fx.GameConfig.LEVEL_INFO[0].time;
// console.log("当前关卡时间", this.timeNumber);
@ -6968,12 +6969,18 @@ export default class MapConroler extends cc.Component {
// topNode.scale = gmScale;
if (topNode) {
if (gmScale == 0.7) {
const shop = this.SceneManager.ensureGameShop();
// 修改Widget的top属性
const widget = topNode.getComponent(cc.Widget);
if (widget) {
widget.top -= 80; // 减去偏移量使节点向上移动
widget.updateAlignment(); // 强制更新对齐
}
const shopWidget = shop && shop.getComponent(cc.Widget);
if (shopWidget) {
shopWidget.top -= 80;
shopWidget.updateAlignment();
}
this.node.y = this.node.y + 40;
} else {

View File

@ -85,6 +85,32 @@ export default class SceneManager extends cc.Component {
return loading;
}
ensureGameShop(): cc.Node {
const game = this.node && this.node.getChildByName("Game");
if (!game) return null;
let shop = game.getChildByName("shop");
// 编辑器仍使用旧场景时,同步迁移顶部入口,避免新脚本与旧层级不一致。
if (!shop) {
const top = cc.find("GameNode/Top", game);
shop = top && top.getChildByName("shop");
if (!shop) return null;
const topWidget = top.getComponent(cc.Widget);
if (topWidget) topWidget.updateAlignment();
const position = game.convertToNodeSpaceAR(shop.convertToWorldSpaceAR(cc.v2(0, 0)));
shop.parent = game;
shop.setPosition(position);
}
if (!shop.getComponent(cc.Widget)) {
const widget = shop.addComponent(cc.Widget);
widget.isAlignTop = true;
widget.top = game.height * (1 - game.anchorY) - shop.y
- shop.height * (1 - shop.anchorY) * shop.scaleY;
widget.alignMode = cc.Widget.AlignMode.ON_WINDOW_RESIZE;
}
shop.zIndex = cc.macro.MAX_ZINDEX - 1;
return shop;
}
/** 动态弹窗加载期间使用;层级高于业务弹窗,低于 Loading 和失败重试层。 */
private ensureDynamicPopupIntercept(): cc.Node {
if (!this.node || !cc.isValid(this.node)) return null;
@ -853,6 +879,7 @@ export default class SceneManager extends cc.Component {
this.popupBundleWarmupStarted = false;
this.refreshGameplayInfo();
this.ensureLoadingOnTop();
if (!this.ensureGameShop()) cc.error("GameScene 缺少顶部商店入口 Game/shop");
const intercept = this.ensureDynamicPopupIntercept();
if (intercept) intercept.active = false;
this.winLevelName = this.resolveWinLevelName();
@ -974,10 +1001,7 @@ export default class SceneManager extends cc.Component {
if (!this.node || !cc.isValid(this.node)) {
return null;
}
const game = this.node.getChildByName("Game");
const gameNode = game && game.getChildByName("GameNode");
const top = gameNode && (gameNode.getChildByName("top") || gameNode.getChildByName("Top"));
const shop = top && top.getChildByName("shop");
const shop = this.ensureGameShop();
return shop && shop.getChildByName("coins");
}
//更新关卡获得金币
@ -1023,7 +1047,7 @@ export default class SceneManager extends cc.Component {
}
const targetNode = this.getWinCoinFlyTarget();
if (!targetNode || !cc.isValid(targetNode)) {
console.warn("playWinCoinFly skip: target GameNode/top/shop/coins missing");
console.warn("playWinCoinFly skip: target Game/shop/coins missing");
this.updateGameCoinDisplay();
return;
}

View File

@ -736,7 +736,7 @@ export class GameConfig {
vibrateOpen: true, //震动
coinnum: 0, //每局的金币数
paid_user: false, //是否是付费用户
version: "1.0.62", //版本号
version: "1.0.64", //版本号
shushu_DistinctId: "", //数数访客ID
shushu_AccountId: "", //数数账号ID
uid: "", //用户和后端唯一id

View File

@ -4524,8 +4524,8 @@
},
"_contentSize": {
"__type__": "cc.Size",
"width": 82,
"height": 72
"width": 292,
"height": 247
},
"_anchorPoint": {
"__type__": "cc.Vec2",
@ -4543,8 +4543,8 @@
0,
0,
1,
1.1,
1.1,
0.3,
0.3,
1
]
},
@ -4577,7 +4577,7 @@
"_srcBlendFactor": 770,
"_dstBlendFactor": 771,
"_spriteFrame": {
"__uuid__": "48dbc128-13f7-471a-a97f-da8a0de98e2e"
"__uuid__": "419e6dd8-8ab5-4910-bf94-b82afe18191b"
},
"_type": 0,
"_sizeMode": 1,
@ -4590,9 +4590,7 @@
"_fillStart": 0,
"_fillRange": 0,
"_isTrimmedMode": true,
"_atlas": {
"__uuid__": "2e466cd1-95aa-4e3c-bb69-759c50404dd1"
},
"_atlas": null,
"_id": ""
},
{

View File

@ -3654,8 +3654,8 @@
},
"_contentSize": {
"__type__": "cc.Size",
"width": 139,
"height": 122
"width": 292,
"height": 247
},
"_anchorPoint": {
"__type__": "cc.Vec2",
@ -3673,8 +3673,8 @@
0,
0,
1,
1.2,
1.2,
0.6,
0.6,
1
]
},
@ -3780,8 +3780,8 @@
0,
0,
1,
1,
1,
0.9,
0.9,
1
]
},
@ -3882,15 +3882,15 @@
"__type__": "TypedArray",
"ctor": "Float64Array",
"array": [
-14.248,
-18.514,
-56.041,
0,
0,
0,
0,
1,
1,
1,
0.9,
0.9,
1
]
},
@ -3991,7 +3991,7 @@
"__type__": "TypedArray",
"ctor": "Float64Array",
"array": [
59.038,
52.876,
-56.041,
0,
0,

View File

@ -31,7 +31,7 @@ export default class LosePanel extends cc.Component {
const affordable = cc.fx.GameConfig.GM_INFO.coin >= this.reviveCost;
if (affordable === this.reviveAffordable) return;
this.reviveAffordable = affordable;
const color = affordable ? cc.color(255, 215, 0) : cc.color(255, 64, 64);
const color = affordable ? cc.Color.WHITE : cc.color(255, 64, 64);
this.reviveCoin.children.forEach(digit => digit.color = color);
}

View File

@ -8,8 +8,8 @@
"premultiplyAlpha": false,
"genMipmaps": false,
"packable": true,
"width": 441,
"height": 76,
"width": 383,
"height": 65,
"platformSettings": {},
"subMetas": {
"title_hammer": {

View File

@ -1,13 +0,0 @@
{
"ver": "1.1.3",
"uuid": "7a3a4a1a-e1d9-45af-bbbe-309e82708822",
"importer": "folder",
"isBundle": false,
"bundleName": "",
"priority": 1,
"compressionType": {},
"optimizeHotUpdate": {},
"inlineSpriteFrames": {},
"isRemoteBundle": {},
"subMetas": {}
}

View File

@ -8,8 +8,8 @@
"premultiplyAlpha": false,
"genMipmaps": false,
"packable": true,
"width": 383,
"height": 65,
"width": 441,
"height": 76,
"platformSettings": {},
"subMetas": {
"title_hammer": {

View File

@ -8,8 +8,8 @@
"premultiplyAlpha": false,
"genMipmaps": false,
"packable": true,
"width": 139,
"height": 123,
"width": 292,
"height": 247,
"platformSettings": {},
"subMetas": {
"skyLine": {

View File

@ -19269,8 +19269,8 @@
},
"_contentSize": {
"__type__": "cc.Size",
"width": 139,
"height": 122
"width": 292,
"height": 247
},
"_anchorPoint": {
"__type__": "cc.Vec2",
@ -19281,15 +19281,15 @@
"__type__": "TypedArray",
"ctor": "Float64Array",
"array": [
-109.091,
-96.229,
0.027,
0,
0,
0,
0,
1,
0.72,
0.72,
0.35,
0.35,
1
]
},

View File

@ -34,10 +34,10 @@ export default async function (ctx: FunctionContext) {
const from = body.from;
const supportsWucaiMigration = Number(body.wucai_capability) >= 1;
let dbname = "users";
const gameName = body.gameName;
if (gameName == "iaa") {
dbname = "usersAd";
}
// const gameName = body.gameName;
// if (gameName == "iaa") {
// dbname = "usersAd";
// }
if (from === "wucai" && dbname !== "users") {
return wucaiLoginFail("WUCAI_UNSUPPORTED_GAME", "五彩账号迁移仅支持主用户库");
}
@ -96,6 +96,7 @@ export default async function (ctx: FunctionContext) {
userPowerTime: migratedUser?.userPowerTime ?? 0,
monthCardReward: migratedUser?.monthCardReward ?? 0,
monthCardTime: migratedUser?.monthCardTime ?? 0,
miniProgramWelfare: { favorite: false, desktop: false },
rebornGiftCount: 0,
rebornGiftTime: 0,
useravatar: Math.floor(Math.random() * 4) + "",
@ -303,6 +304,11 @@ export default async function (ctx: FunctionContext) {
userData.shareLv = [];
}
userData.careerAmount = userData.careerAmount || 0;
// 老用户缺少字段或某一项时按未领取返回,不写回整对象,避免覆盖并发领取。
userData.miniProgramWelfare = {
favorite: userData.miniProgramWelfare?.favorite === true,
desktop: userData.miniProgramWelfare?.desktop === true,
};
if (dbname === "users") {
userData.abTests = abTests;
}
@ -379,29 +385,6 @@ const getClientIp = (req) => {
);
};
const propName = {
"金币包1": "gold_1",
"金币包2": "gold_2",
"金币包3": "gold_3",
"金币包4": "gold_4",
"金币包5": "gold_5",
"金币包6": "gold_6",
"无限体力组合包1": "unlimited_health_bundle_1",
"无限体力组合包2": "unlimited_health_bundle_2",
"无限体力组合包3": "unlimited_health_bundle_3",
"局内购买冻结": "freeze_in_game",
"局内购买锤子": "hammer_in_game",
"局内购买魔棒": "wand_in_gamerefill",
"补满体力": "health",
"宝藏1": "jungle_treasure_1",
"宝藏2": "jungle_treasure_2",
"宝藏3": "jungle_treasure_3",
"宝藏4": "jungle_treasure_4",
"宝藏5": "jungle_treasure_5",
"宝藏6": "jungle_treasure_6",
"宝藏7": "jungle_treasure_7",
"宝藏8": "jungle_treasure_8"
};
async function getWXOpenId(code, dbname) {
let appid = process.env.WX_MINIGAME_APP_ID;
@ -589,7 +572,7 @@ async function sign(outTradeNo, nonceStr, timestamp) {
// 更新签名内容
sign.update(data);
// 获取存储桶
const bucket = cloud.storage.bucket('j3k323ol-colorblock-oss');
const bucket = cloud.storage.bucket(process.env.WX_PAY_PRIVATE_KEY_BUCKET);
// 获取文件列表
const res = await bucket.readFile('apiclient_key.pem');
const privateKeyPem = await res.Body.transformToString();

View File

@ -9,7 +9,6 @@ import {
getSignInClaims,
getSignInConfig,
getUserSignInLevel,
getUserSignInTriggerLevel,
normalizeSignInState,
} from "@/SignInActivity";
@ -40,8 +39,7 @@ export default async function (ctx: FunctionContext) {
if (!config) {
return { code: 0, data: null, msg: "签到活动配置不存在或配置无效" };
}
const triggerLevel = getUserSignInTriggerLevel(user, config);
const triggerReached = getUserSignInLevel(user) >= triggerLevel;
const triggerReached = getUserSignInLevel(user) >= Number(config.triggerLevel);
if (!state && !triggerReached) {
return { code: 1, data: false, msg: "未达到签到活动开启关卡" };
}
@ -80,7 +78,7 @@ export default async function (ctx: FunctionContext) {
serverNow: now,
activityId: config.activityId,
status,
triggerLevel,
triggerLevel: Number(config.triggerLevel),
triggerReached,
startAt: state.startAt,
endAt: state.endAt,

View File

@ -68,7 +68,7 @@ async function sign(nonceStr, timestamp, body) {
// 更新签名内容
sign.update(data);
// 获取存储桶
const bucket = cloud.storage.bucket('j3k323ol-colorblock-oss');
const bucket = cloud.storage.bucket(process.env.WX_PAY_PRIVATE_KEY_BUCKET);
// 获取文件列表
const res = await bucket.readFile('apiclient_key.pem');
const privateKeyPem = await res.Body.transformToString();
@ -88,7 +88,7 @@ async function frontsign(data) {
// 更新签名内容
sign.update(data);
// 获取存储桶
const bucket = cloud.storage.bucket('j3k323ol-colorblock-oss');
const bucket = cloud.storage.bucket(process.env.WX_PAY_PRIVATE_KEY_BUCKET);
// 获取文件列表
const res = await bucket.readFile('apiclient_key.pem');
const privateKeyPem = await res.Body.transformToString();

View File

@ -10,6 +10,11 @@ export default async function (ctx: FunctionContext) {
if (!order.data) {
return { code: 0, data: null, msg: "未获取到充值订单" };
}
// 月卡由 monthlyCard 在成功加时后完成订单,避免两次请求之间断线导致无法补发。
if (isUpgradeOrder(order.data)) return { code: 0, msg: '请在新版战令中完成发放' };
if (order.data.itemid !== "month_Card") {
await db.collection("order").where({ outTradeNo: outTradeNo }).update({ state: 2, getTime: new Date(Date.now() + 8 * 3600000) });
}
if (/^reborn_Gift(?:_[2-5])?$/.test(order.data.itemid)) {
const user = await db.collection("users").where({ _id: ctx.body.uid }).getOne();
if (!user.data || user.data.openid !== order.data.openid) {
@ -19,10 +24,5 @@ export default async function (ctx: FunctionContext) {
return { code: 0, data: null, msg: "充值尚未成功" };
}
}
// 月卡由 monthlyCard 在成功加时后完成订单,避免两次请求之间断线导致无法补发。
if (isUpgradeOrder(order.data)) return { code: 0, msg: '请在新版战令中完成发放' };
if (order.data.itemid !== "month_Card") {
await db.collection("order").where({ outTradeNo: outTradeNo }).update({ state: 2, getTime: new Date(Date.now() + 8 * 3600000) });
}
return { code: 1, data: "ok", msg: "成功" };
}

98
tools/test-game-shop.cjs Normal file
View File

@ -0,0 +1,98 @@
const test = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const { loadMembers } = require('./new-player-ab-test-support.cjs');
function fixture(legacy = false) {
const data = JSON.parse(fs.readFileSync('assets/Scene/GameScene.fire', 'utf8'));
class Widget {
static AlignMode = { ON_WINDOW_RESIZE: 1 };
updateAlignment() {
const node = this.node;
node.y = node.parent.height * (1 - node.parent.anchorY) - this.top
- node.height * (1 - node.anchorY) * node.scaleY;
}
}
const nodes = data.map(n => n.__type__ === 'cc.Node' ? {
name: n._name, children: [], components: [],
x: n._trs.array[0], y: n._trs.array[1], scaleY: n._trs.array[8],
height: n._contentSize.height, anchorY: n._anchorPoint.y,
get parent() { return this._parent; },
set parent(value) {
if (this._parent) this._parent.children = this._parent.children.filter(n => n !== this);
this._parent = value;
value.children.push(this);
},
getChildByName(name) { return this.children.find(n => n.name === name) || null; },
getComponent(type) { return this.components.find(c => c instanceof type) || null; },
addComponent(type) { const c = new type(); c.node = this; this.components.push(c); return c; },
setPosition(p) { this.x = p.x; this.y = p.y; },
convertToWorldSpaceAR(p) {
const result = { x: p.x + this.x, y: p.y + this.y };
return this.parent ? this.parent.convertToWorldSpaceAR(result) : result;
},
convertToNodeSpaceAR(p) {
const origin = this.convertToWorldSpaceAR({ x: 0, y: 0 });
return { x: p.x - origin.x, y: p.y - origin.y };
},
} : null);
nodes.forEach((node, i) => {
if (!node) return;
if (nodes[data[i]._parent?.__id__]) node.parent = nodes[data[i]._parent.__id__];
for (const ref of data[i]._components) {
const c = data[ref.__id__];
if (c.__type__ === 'cc.Widget') Object.assign(node.addComponent(Widget), { top: c._top });
}
});
const canvas = nodes.find(n => n?.name === 'Canvas');
const game = canvas.getChildByName('Game');
const gameNode = game.getChildByName('GameNode');
const top = gameNode.getChildByName('Top');
const shop = game.getChildByName('shop');
top.getComponent(Widget).updateAlignment();
if (legacy) {
shop.parent = top;
shop.y = -67.741;
shop.components = [];
} else if (shop.getComponent(Widget)) shop.getComponent(Widget).updateAlignment();
const cc = {
Widget, macro: { MAX_ZINDEX: 32767 }, isValid: node => !!node,
v2: (x, y) => ({ x, y }),
find: (path, root) => path.split('/').reduce((node, name) => node && node.getChildByName(name), root),
};
const Manager = loadMembers('assets/Script/SceneManager.ts', ['ensureGameShop', 'getWinCoinFlyTarget'], { cc });
return { manager: Object.assign(new Manager(), { node: canvas }), game, top, shop, Widget };
}
for (const legacy of [false, true]) {
test(`${legacy ? 'old' : 'new'} scene keeps Shop above Lose with valid coin children and unchanged position`, () => {
for (const height of [1280, 1920, 2400]) {
const { manager, game, shop, top, Widget } = fixture(legacy);
const before = shop.convertToWorldSpaceAR({ x: 0, y: 0 });
assert.equal(manager.ensureGameShop(), shop);
assert.equal(shop.parent, game);
assert.equal(top.getChildByName('shop'), null);
assert.equal(shop.zIndex, 32766);
shop.getComponent(Widget).updateAlignment();
assert.deepEqual(shop.convertToWorldSpaceAR({ x: 0, y: 0 }), before);
assert.ok(shop.getChildByName('coin'));
assert.equal(manager.getWinCoinFlyTarget(), shop.getChildByName('coins'));
assert.equal(manager.ensureGameShop(), shop);
assert.equal(shop.components.filter(c => c instanceof Widget).length, 1);
assert.equal(game.children.filter(n => n === shop).length, 1);
game.height = height;
shop.getComponent(Widget).updateAlignment();
assert.ok(Math.abs(shop.y - (height / 2 - 297.741)) < 1e-9);
}
});
}
test('missing Shop returns null instead of throwing while setting zIndex or resolving coins', () => {
const { manager, game, shop } = fixture();
game.children = game.children.filter(n => n !== shop);
assert.equal(manager.ensureGameShop(), null);
assert.equal(manager.getWinCoinFlyTarget(), null);
manager.node = null;
assert.equal(manager.ensureGameShop(), null);
assert.equal(manager.getWinCoinFlyTarget(), null);
});