fix: 每日任务合并分支导致的代码缺失

This commit is contained in:
guanchao
2026-10-19 17:01:55 +08:00
parent 9d30991cd3
commit 9cfc11fd26
5 changed files with 201 additions and 18 deletions
@@ -11998,6 +11998,111 @@
},
"rewardHours": {
"__uuid__": "a30964ac-908f-46f8-ade5-f5b987643f4e"
},
"countDigits": [
{
"__uuid__": "e9fbe63d-d11b-48ab-b60f-6cddbbe26df0"
},
{
"__uuid__": "468c687e-b161-4a91-b257-d66cb6d11eaa"
},
{
"__uuid__": "c09a6ad9-172d-48f1-924e-21a8768f09c0"
},
{
"__uuid__": "3d0db06a-8634-41b4-bef3-82a795065496"
},
{
"__uuid__": "7052389a-a4a8-4947-b68c-7fbd4a030d40"
},
{
"__uuid__": "b057bda0-9352-4c28-99a8-2eae260195f4"
},
{
"__uuid__": "4146d0fe-f5d3-42ca-a7d3-1129026c4d88"
},
{
"__uuid__": "6b254656-5b82-4cb3-8eb0-8ba25ad9cb23"
},
{
"__uuid__": "87f0dfbe-399a-4f4c-be85-862d33c43678"
},
{
"__uuid__": "3335805a-3829-4041-83e0-a55557d60f85"
}
],
"weeklyDigits": [
{
"__uuid__": "b9f95770-d594-41da-b106-f620b88c4eb3"
},
{
"__uuid__": "25d61f1b-bb4e-4a13-ba88-2452a0418489"
},
{
"__uuid__": "c8918990-0fd0-4ca3-8459-37236b9cf54d"
},
{
"__uuid__": "ff941762-7142-46ac-80d2-fef5c0dc2623"
},
{
"__uuid__": "02fdfef7-2e71-421e-b5da-1fda5e3c75cf"
},
{
"__uuid__": "0783a277-bb41-4632-ae1d-638d91e479fa"
},
{
"__uuid__": "d920d392-bed5-4812-b04c-54eb5caa89b8"
},
{
"__uuid__": "14007ec1-6ce7-4de9-9776-b3fe516dadaf"
},
{
"__uuid__": "71969ac6-4207-41c2-8cd4-1699391686a0"
},
{
"__uuid__": "e1a14164-45a8-45b8-b295-4772a1629884"
}
],
"taskDigits": [
{
"__uuid__": "15971cf2-b96f-45c2-9c65-f1f4321eedc5"
},
{
"__uuid__": "4d83c3d0-343e-4c5e-bf25-b8c7567ca664"
},
{
"__uuid__": "a6ab3a21-a200-4356-830e-88db8281c607"
},
{
"__uuid__": "232c7624-5016-4c8f-a221-9fe61544f63b"
},
{
"__uuid__": "a5b67720-4006-4b08-b6bc-bb5ede3736f5"
},
{
"__uuid__": "ce8dfee3-2f18-429c-b48a-bd0e697d2c27"
},
{
"__uuid__": "dadc09ce-c919-4eed-b4b8-59568d8e935c"
},
{
"__uuid__": "e3a812ba-0f71-448f-a2f7-891ef3d4657c"
},
{
"__uuid__": "e6271735-4665-49c2-a545-58a4f5900770"
},
{
"__uuid__": "37d118ec-14ad-4033-8832-94d7f94e730c"
}
],
"taskSlash": {
"__uuid__": "cd19b7f8-cbf2-4087-864f-43436ab573f1"
},
"countMinutes": {
"__uuid__": "7b7922e5-327e-44c0-b3cc-060808b27e8c"
},
"countPlus": {
"__uuid__": "8595bc55-9288-4ca6-b1c7-5c6df0855e61"
}
},
{
+72 -2
View File
@@ -45,6 +45,26 @@ export default class DailyQuests extends cc.Component {
@property(cc.SpriteFrame)
rewardHours: cc.SpriteFrame = null;
@property([cc.SpriteFrame])
countDigits: cc.SpriteFrame[] = [];
@property([cc.SpriteFrame])
weeklyDigits: cc.SpriteFrame[] = [];
@property([cc.SpriteFrame])
taskDigits: cc.SpriteFrame[] = [];
@property(cc.SpriteFrame)
taskSlash: cc.SpriteFrame = null;
@property(cc.SpriteFrame)
countMinutes: cc.SpriteFrame = null;
@property(cc.SpriteFrame)
countPlus: cc.SpriteFrame = null;
private countSignatures = new WeakMap<cc.Node, string>();
public juwai = false;
btn_Touch: boolean = false;
@@ -444,6 +464,52 @@ export default class DailyQuests extends cc.Component {
if (richText) richText.string = text;
}
private setCountText(node: cc.Node, text: string, digits: cc.SpriteFrame[] = this.countDigits, maxHeight: number = 40): void {
const signature = `${text}:${node.width}:${node.height}:${maxHeight}`;
if (this.countSignatures.get(node) === signature) return;
this.countSignatures.set(node, signature);
node.children.slice().forEach(child => { child.removeFromParent(); child.destroy(); });
const height = Math.min(maxHeight, node.height);
const tokens = text.match(/分钟|./g) || [];
const frames = tokens.map(token => /^\d$/.test(token) ? digits[Number(token)]
: token === "分钟" ? this.countMinutes : token === "+" ? this.countPlus : token === "/" ? this.taskSlash : null);
const widths = tokens.map((token, index) => {
const rect = frames[index] && frames[index].getRect();
return rect ? height * rect.width / rect.height : height * 0.5;
});
const totalWidth = widths.reduce((sum, width) => sum + width, 0);
const scale = Math.min(1, node.width / Math.max(1, totalWidth));
let left = -totalWidth / 2;
tokens.forEach((token, index) => {
const glyph = new cc.Node(`count_${token}`);
node.addChild(glyph);
if (frames[index]) {
const sprite = glyph.addComponent(cc.Sprite);
sprite.spriteFrame = frames[index];
sprite.sizeMode = cc.Sprite.SizeMode.CUSTOM;
} else if (token === "×" || token === ".") {
// num 目录只有数字;乘号和小数点保留文字,数字始终使用图片。
const label = glyph.addComponent(cc.Label);
label.string = token;
label.fontSize = height;
label.lineHeight = height;
label.horizontalAlign = cc.Label.HorizontalAlign.CENTER;
label.verticalAlign = cc.Label.VerticalAlign.CENTER;
label.overflow = cc.Label.Overflow.SHRINK;
label.enableBold = true;
const outline = glyph.addComponent(cc.LabelOutline);
outline.color = cc.color(150, 83, 44);
outline.width = 3;
} else {
cc.error(`DailyQuests: 缺少数量图片 ${token}`);
}
glyph.setContentSize(widths[index], height);
glyph.scale = scale;
glyph.setPosition((left + widths[index] / 2) * scale, 0);
left += widths[index];
});
}
private setRewardCount(node: cc.Node, text: string): void {
if (!node) return;
const label = node.getComponent(cc.Label);
@@ -458,8 +524,12 @@ export default class DailyQuests extends cc.Component {
if (label) { label.string = text; label.enabled = !ready; }
if (content) content.active = ready;
if (!ready) return;
if (!content) { content = new cc.Node("RewardCountGlyphs"); node.addChild(content); }
const height = label ? label.fontSize : node.height;
if (!content) {
// The merged prefab includes an editor-preview digit; replace its visible output.
node.children.forEach(child => child.active = false);
content = new cc.Node("RewardCountGlyphs"); node.addChild(content);
}
const height = Math.min(label ? label.fontSize : 40, node.height);
const scales = tokens.map(token => token === "×" || token === "x" ? 0.6 : 1);
const widths = tokens.map((token, index) => {
const frame = frames[index];
+12 -4
View File
@@ -4,7 +4,8 @@ const assert = require('node:assert/strict');
const directory = path.resolve(__dirname, '../assets/action_bundle/img/dailyQuest');
function frame(name, character) {
const meta = Object.values(JSON.parse(fs.readFileSync(path.join(directory, name + '.png.meta'))).subMetas)[0];
return { character, uuid: meta.uuid, getRect: () => ({ width: meta.width, height: meta.height }) };
return { character, uuid: meta.uuid, getRect: () => ({ width: meta.width, height: meta.height }),
getOriginalSize: () => ({ width: meta.rawWidth, height: meta.rawHeight }) };
}
function installCountFrames(daily) {
daily.countDigits = Array.from({ length: 10 }, (_, index) => frame('num/' + index, String(index)));
@@ -13,15 +14,22 @@ function installCountFrames(daily) {
daily.taskSlash = frame('task_digits/xiegan', '/');
daily.countMinutes = frame('fenzhong', '分钟');
daily.countPlus = frame('jiahao', '+');
daily.rewardDigits = daily.countDigits;
const font = JSON.parse(fs.readFileSync(path.resolve(directory, '../../../common/publicFont.plist.meta'))).subMetas;
for (const [field, name, character] of [['rewardMultiply', 'big_cheng.png', '×'], ['rewardMinutes', 'big_fenzhong.png', '分钟'], ['rewardHours', 'big_xiaoshi.png', '小时']]) {
const meta = font[name];
daily[field] = { character, uuid: meta.uuid, getOriginalSize: () => ({ width: meta.rawWidth, height: meta.rawHeight }) };
}
}
function countText(node) {
if (!node) return undefined;
assert.equal(node.getComponent('cc.Label'), null, 'count is a sprite container, not a Label');
return node.children.map(child => {
const content = node.getChildByName('RewardCountGlyphs') || node;
return content.children.filter(child => child.active).map(child => {
const sprite = child.getComponent('cc.Sprite');
if (sprite) return sprite.spriteFrame.character;
if (sprite && sprite.enabled !== false) return sprite.spriteFrame.character;
const text = child.getComponent('cc.Label').string;
assert.match(text, /^[×.]$/, 'digits must use supplied sprite frames');
assert.match(text, /^[×.+]$/, 'digits must use supplied sprite frames');
return text;
}).join('');
}
+7 -9
View File
@@ -30,14 +30,17 @@ test('reward number bindings use dailyQuest digits and publicFont big_cheng', ()
test('daily reward counts render the requested digit art, fit the count box and use the multiply sprite', () => {
const h = setup([{ type: 'coin', count: 1023456789 }, { type: 'hammer', count: 2 }]);
const slots = h.row.getChildByName('rewards').children;
for (const [index, text] of [[0, '6'], [1, '1023456789'], [2, '×2']]) {
for (const [index, text] of [[0, '1023456789'], [1, '×2'], [2, '6']]) {
const count = slots[index].getChildByName('count'), glyphs = count.getChildByName('RewardCountGlyphs');
assert.equal(count.getComponent('cc.Label').enabled, false);
assert.equal(count.getComponent('cc.Label'), null);
assert(count.children.filter(node => node !== glyphs).every(node => !node.active), 'editor-preview digits must not overlap live quantities');
const visible = glyphs.children.filter(node => node.active);
assert.deepEqual(visible.map(node => node.getComponent('cc.Sprite').spriteFrame.uuid),
[...text].map(char => char === '×' ? h.daily.rewardMultiply.uuid : h.daily.rewardDigits[Number(char)].uuid));
for (const node of visible) {
assert(Number.isFinite(node.x));
assert(node.height <= 40, 'label-free counts retain the original maximum digit height');
assert.equal(node.scale, node.getComponent('cc.Sprite').spriteFrame === h.daily.rewardMultiply ? 0.6 : 1);
assert((Math.abs(node.x) + node.width * node.scale / 2) * glyphs.scale <= count.width / 2 + 1e-8);
}
}
@@ -45,7 +48,7 @@ test('daily reward counts render the requested digit art, fit the count box and
test('count updates preserve fractional minutes and hide old glyphs when switching to shorter rewards', () => {
const h = setup([{ type: 'infinite_health', count: 90 }]);
const count = h.row.getChildByName('rewards').children[1].getChildByName('count');
const count = h.row.getChildByName('rewards').children[0].getChildByName('count');
const content = count.getChildByName('RewardCountGlyphs');
assert.deepEqual(content.children.filter(node => node.active).map(node => node.getComponent('cc.Sprite')?.enabled
? node.getComponent('cc.Sprite').spriteFrame.uuid : node.getComponent('cc.Label').string),
@@ -58,6 +61,7 @@ test('count updates preserve fractional minutes and hide old glyphs when switchi
assert.equal(content.children[0].getComponent('cc.Sprite').spriteFrame.uuid, h.daily.rewardMultiply.uuid);
assert.equal(content.children[1].getComponent('cc.Label').enabled, false, 'old decimal label is disabled');
h.daily.setRewardCount(count, '+30');
assert.equal(content.children[0].scale, 1, 'reusing the multiply slot resets its scale');
assert.equal(content.children[0].getComponent('cc.Sprite').enabled, false);
assert.equal(content.children[0].getComponent('cc.Label').string, '+');
assert.equal(content.children[1].getComponent('cc.Sprite').spriteFrame.uuid, h.daily.rewardDigits[3].uuid);
@@ -225,12 +229,6 @@ function setup(rewards = [{ type: 'coin', count: 50 }, { type: 'hammer', count:
const daily = new context.DailyQuests(); installCountFrames(daily); daily.node = build(1); canvas.addChild(daily.node);
daily.content = daily.node.getChildByName('bg').getChildByName('content');
daily.taskNormal = 'normal-frame'; daily.taskClaimable = 'claimable-frame';
const numberFrame = meta => ({ uuid: meta.uuid, getOriginalSize: () => ({ width: meta.rawWidth, height: meta.rawHeight }) });
daily.rewardDigits = Array.from({ length: 10 }, (_, digit) => numberFrame(JSON.parse(fs.readFileSync(
path.join(root, `assets/action_bundle/img/dailyQuest/num/${digit}.png.meta`), 'utf8')).subMetas[digit]));
daily.rewardMultiply = numberFrame(JSON.parse(fs.readFileSync(path.join(root, 'assets/common/publicFont.plist.meta'), 'utf8')).subMetas['big_cheng.png']);
daily.rewardMinutes = numberFrame(JSON.parse(fs.readFileSync(path.join(root, 'assets/common/publicFont.plist.meta'), 'utf8')).subMetas['big_fenzhong.png']);
daily.rewardHours = numberFrame(JSON.parse(fs.readFileSync(path.join(root, 'assets/common/publicFont.plist.meta'), 'utf8')).subMetas['big_xiaoshi.png']);
daily.rewardIcons = ['xinCoin', 'ice', 'hammer', 'magic', 'skyLine'].map(name => {
const meta = JSON.parse(fs.readFileSync(path.join(root, `assets/res/public/${name}.png.meta`), 'utf8')).subMetas[name];
return { getRect: () => ({ width: meta.width, height: meta.height }) };
+5 -3
View File
@@ -458,11 +458,11 @@ test('coin and infinite health icons use the configured 0.75 scale while other r
assert.equal(icon.height,coinRect.height);
});
test('preview icons match the outer coin height and retain count labels without action buttons',()=>{
test('preview icons match the outer coin height and retain image counts without action buttons',()=>{
const {daily,preview}=setup(0);daily.selectWeeklyReward(null,'weekly_35');
const rewards=preview.getChildByName('rewards');assert.equal(rewards.scaleX,1);
assert.equal(preview.width,344);assert.equal(preview.height,180);
for(const slot of rewards.children){
for(const slot of rewards.children.filter(slot=>slot.active)){
assert.equal(slot.scaleX,1);
const icon=slot.getChildByName('icon');
assert.equal(icon.scaleX,icon.scaleY);
@@ -471,7 +471,9 @@ test('preview icons match the outer coin height and retain count labels without
assert.ok(Math.abs(icon.height*icon.scaleY-daily.rewardIcons[0].getRect().height*([daily.rewardIcons[0],daily.rewardIcons[4]].includes(icon.getComponent('cc.Sprite').spriteFrame)?0.75:1))<1e-8);
assert.equal(icon.width/icon.height,frame.getRect().width/frame.getRect().height);
}
assert.ok(slot.getChildByName('count').children.every(glyph=>glyph.height===40));
const count=slot.getChildByName('count'),glyphs=count.getChildByName('RewardCountGlyphs');
assert.ok(glyphs.children.filter(glyph=>glyph.active).every(glyph=>glyph.height===40));
assert.ok(count.children.filter(child=>child!==glyphs).every(child=>!child.active));
assert.equal(slot.getChildByName('plus').active,false);
}
assert.equal(preview.getChildByName('btnClaim'),undefined);assert.equal(preview.getChildByName('close'),undefined);