185 lines
9.9 KiB
TypeScript
185 lines
9.9 KiB
TypeScript
import Utils from './module/Pay/Utils';
|
|
import { MiniGameSdk } from './Sdk/MiniGameSdk';
|
|
import HomePopupQueue from '../home_popup_queue/HomePopupQueue';
|
|
const { ccclass } = cc._decorator;
|
|
const BUNDLE = 'coin_madness';
|
|
|
|
/** Resident bridge only: never import the bundle's UI class or preload its assets. */
|
|
@ccclass
|
|
export default class CoinMadnessHost extends cc.Component {
|
|
private static occupied = false;
|
|
private bundle: cc.AssetManager.Bundle = null;
|
|
private panel: cc.Node = null;
|
|
private entry: cc.Node = null;
|
|
private loading = false;
|
|
private releasing = false;
|
|
private requestId = 0;
|
|
private data: any = null;
|
|
private finishQueue: () => void = null;
|
|
private alive = true;
|
|
private refreshing = false;
|
|
private busy = false;
|
|
private revision = 0;
|
|
private shown = () => this.refresh();
|
|
|
|
private static receiptKey(): string { return 'coinMadnessReceipt_' + cc.fx.GameConfig.GM_INFO.uid; }
|
|
static restorePending(user: any): void {
|
|
let pending = user && user.coinMadnessPending;
|
|
if (typeof pending === 'string') { try { pending = JSON.parse(pending); } catch { return; } }
|
|
if (!pending || !Number.isSafeInteger(pending.balance)) return;
|
|
// Login already includes the server grant. Override only coins, not other progression.
|
|
cc.fx.GameConfig.GM_INFO.coin = pending.balance;
|
|
cc.fx.StorageMessage.setStorage('coin', { coin: pending.balance, timestamp: Date.now(), coinMadnessReceipt: pending.id });
|
|
cc.fx.StorageMessage.setStorage(this.receiptKey(), pending.id);
|
|
}
|
|
start() { cc.game.on(cc.game.EVENT_SHOW, this.shown, this); this.refresh(); }
|
|
private request(action: string, body: any, done: (result: any) => void) {
|
|
Utils.POST('coinMadness', { uid: cc.fx.GameConfig.GM_INFO.uid, action, ...body }, done);
|
|
}
|
|
private refresh() {
|
|
if (!this.alive || this.refreshing || this.busy || !cc.fx.GameConfig.GM_INFO.uid
|
|
|| cc.fx.GameConfig.GM_INFO.canIos === false) return;
|
|
this.refreshing = true;
|
|
const revision = this.revision;
|
|
this.request('read', {}, result => {
|
|
this.refreshing = false;
|
|
if (!this.alive || revision !== this.revision || result?.code !== 1) return;
|
|
this.data = result.data; this.updateEntry();
|
|
this.unschedule(this.refresh);
|
|
if (this.data.state && !this.data.state.settled) {
|
|
const remaining = (this.data.state.config.endsAt - this.data.serverNow) / 1000;
|
|
if (remaining > 0) this.scheduleOnce(this.refresh, Math.min(remaining + 0.1, 60));
|
|
}
|
|
if (this.panel) this.panel.getComponent('CoinMadnessPanel').render(this.data);
|
|
if (this.data.pending || this.data.needsSettlement) this.queueSettlement();
|
|
});
|
|
}
|
|
private updateEntry() {
|
|
const visible = this.data?.available && (!this.data.state?.settled || this.data.pending);
|
|
if (!visible) { if (this.entry) this.entry.destroy(); this.entry = null; return; }
|
|
if (!this.entry) {
|
|
this.entry = new cc.Node('CoinMadnessEntry');
|
|
(this.node.getChildByName('Load') || this.node).addChild(this.entry);
|
|
this.entry.setContentSize(146, 112);
|
|
const widget = this.entry.addComponent(cc.Widget);
|
|
widget.isAlignLeft = true; widget.left = 24; widget.isAlignBottom = true; widget.bottom = 425;
|
|
const g = this.entry.addComponent(cc.Graphics);
|
|
g.fillColor = new cc.Color(231, 121, 24); g.roundRect(-73, -56, 146, 112, 22); g.fill();
|
|
const title = new cc.Node('Title'); this.entry.addChild(title);
|
|
const label = title.addComponent(cc.Label); label.string = '金币狂热'; label.fontSize = 27;
|
|
label.useSystemFont = true;
|
|
label.lineHeight = 31;
|
|
title.color = cc.Color.WHITE;
|
|
this.entry.on(cc.Node.EventType.TOUCH_END, this.open, this);
|
|
}
|
|
const state = this.data.state;
|
|
const target = state.config.stages[state.stage];
|
|
const ready = state.paidAt && target && state.progress >= target.wins;
|
|
this.entry.getChildByName('Title').getComponent(cc.Label).string = '金币狂热\n'
|
|
+ (ready ? '可领取' : state.paidAt ? '闯关领奖' : '限时活动');
|
|
this.entry.active = true;
|
|
}
|
|
open() {
|
|
if (this.loading || this.releasing || this.panel || this.busy || !this.data) return;
|
|
HomePopupQueue.get(this.node).enqueue('coinMadness', 55, done => {
|
|
if (!this.alive) { done(); return; }
|
|
this.finishQueue = done; this.load();
|
|
});
|
|
}
|
|
private load() {
|
|
if (CoinMadnessHost.occupied) { this.close(); this.toast('活动资源释放中,请稍后重试'); return; }
|
|
CoinMadnessHost.occupied = true;
|
|
this.loading = true;
|
|
const requestId = ++this.requestId;
|
|
cc.assetManager.loadBundle(BUNDLE, (error, bundle) => {
|
|
if (error) { CoinMadnessHost.occupied = false; this.loading = false; this.close(); this.toast('活动加载失败,请重试'); return; }
|
|
if (!this.alive || requestId !== this.requestId) { this.release(bundle); return; }
|
|
this.bundle = bundle;
|
|
bundle.load('CoinMadness', cc.Prefab, (loadError, prefab: cc.Prefab) => {
|
|
this.loading = false;
|
|
if (!this.alive || requestId !== this.requestId) { this.release(bundle); return; }
|
|
if (loadError) { this.close(); this.toast('活动资源加载失败,请重试'); return; }
|
|
this.panel = cc.instantiate(prefab); this.node.addChild(this.panel);
|
|
this.panel.zIndex = cc.macro.MAX_ZINDEX - 1;
|
|
this.panel.getComponent('CoinMadnessPanel').initialize(this.data, {
|
|
close: () => this.close(), refresh: () => this.refresh(),
|
|
request: (action, body, done) => this.action(action, body, done),
|
|
order: (endpoint, body, done) => Utils.POST(endpoint, { uid: cc.fx.GameConfig.GM_INFO.uid,
|
|
coinMadnessLevel: cc.fx.GameConfig.GM_INFO.level, ...body }, done),
|
|
});
|
|
this.refresh();
|
|
});
|
|
});
|
|
}
|
|
private action(action: string, body: any, done: (result: any) => void) {
|
|
if (this.busy) return;
|
|
this.busy = true;
|
|
this.revision++;
|
|
const uid = cc.fx.GameConfig.GM_INFO.uid;
|
|
this.request(action, { ...body, coinAmount: Math.floor(cc.fx.GameConfig.GM_INFO.coin) }, result => {
|
|
if (uid !== cc.fx.GameConfig.GM_INFO.uid) { this.busy = false; return; }
|
|
if (result?.code !== 1) { this.busy = false; if (this.alive) done(result); return; }
|
|
this.acceptReceipt(result.data, acknowledged => {
|
|
this.busy = false;
|
|
if (!this.alive) return;
|
|
this.data = acknowledged.data || result.data; this.updateEntry(); done(acknowledged);
|
|
});
|
|
});
|
|
}
|
|
private acceptReceipt(data: any, done: (result: any) => void) {
|
|
const receipt = data.pending;
|
|
if (!receipt) { done({ code: 1, data }); return; }
|
|
const info = cc.fx.GameConfig.GM_INFO;
|
|
const coinCache = cc.fx.StorageMessage.getStorage('coin');
|
|
if (cc.fx.StorageMessage.getStorage(CoinMadnessHost.receiptKey()) !== receipt.id && coinCache?.coinMadnessReceipt !== receipt.id) {
|
|
info.coin += receipt.coins;
|
|
cc.fx.StorageMessage.setStorage('coin', { coin: info.coin, timestamp: Date.now(), coinMadnessReceipt: receipt.id });
|
|
cc.fx.StorageMessage.setStorage(CoinMadnessHost.receiptKey(), receipt.id);
|
|
}
|
|
const home: any = cc.isValid(this.node) && this.node.getComponent('JiaZai');
|
|
if (home) home.updateCoin();
|
|
this.request('ack', { receiptId: receipt.id, coinAmount: Math.floor(info.coin) }, result => {
|
|
if (result?.code === 1 && this.alive) this.toast((receipt.expired ? '到期补发 ' : '获得 ') + receipt.coins + ' 金币');
|
|
done(result);
|
|
});
|
|
}
|
|
private queueSettlement() {
|
|
if (this.panel) return;
|
|
HomePopupQueue.get(this.node).enqueue('coinMadnessSettlement', 54, done => {
|
|
if (!this.alive || this.busy) { done(); return; }
|
|
const mask = new cc.Node('CoinMadnessSettlement'); this.node.addChild(mask);
|
|
mask.setContentSize(this.node.getContentSize()); mask.zIndex = cc.macro.MAX_ZINDEX - 1;
|
|
mask.addComponent(cc.BlockInputEvents);
|
|
this.action(this.data.pending ? 'read' : 'settle', { periodId: this.data.state?.config.periodId }, result => {
|
|
mask.destroy(); done();
|
|
if (result?.code !== 1) { this.toast('活动奖励待同步,请稍后打开活动重试'); return; }
|
|
this.refresh();
|
|
});
|
|
});
|
|
}
|
|
close() {
|
|
if (this.busy && this.alive) return;
|
|
++this.requestId;
|
|
const wasLoading = this.loading; this.loading = false;
|
|
if (this.panel) { this.panel.destroy(); this.panel = null; }
|
|
const bundle = this.bundle; this.bundle = null;
|
|
if (bundle && !wasLoading) this.release(bundle);
|
|
const done = this.finishQueue; this.finishQueue = null; if (done) done();
|
|
}
|
|
private release(bundle: cc.AssetManager.Bundle) {
|
|
this.releasing = true;
|
|
cc.director.once(cc.Director.EVENT_AFTER_DRAW, () => {
|
|
bundle.releaseAll();
|
|
if (cc.assetManager.getBundle(BUNDLE) === bundle) cc.assetManager.removeBundle(bundle);
|
|
this.releasing = false;
|
|
CoinMadnessHost.occupied = false;
|
|
});
|
|
}
|
|
private toast(message: string) { if (this.alive) MiniGameSdk.API.showToast(message); }
|
|
onDestroy() {
|
|
this.alive = false; this.unscheduleAllCallbacks();
|
|
cc.game.off(cc.game.EVENT_SHOW, this.shown, this); this.close(); this.data = null;
|
|
if (this.entry) this.entry.destroy(); this.entry = null;
|
|
}
|
|
}
|