This commit is contained in:
COMPUTER\EDY 2026-08-26 10:34:57 +08:00
parent 112db74fcd
commit 094cc24afe
30 changed files with 3004 additions and 2636 deletions

21
assets/Block.meta Normal file
View File

@ -0,0 +1,21 @@
{
"ver": "1.1.3",
"uuid": "b29df998-bfa4-4b61-84f4-7bcba8415256",
"importer": "folder",
"isBundle": true,
"bundleName": "",
"priority": 1,
"compressionType": {
"wechatgame": "subpackage"
},
"optimizeHotUpdate": {
"wechatgame": false
},
"inlineSpriteFrames": {
"wechatgame": false
},
"isRemoteBundle": {
"wechatgame": false
},
"subMetas": {}
}

BIN
assets/Block/5color18.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -0,0 +1,38 @@
{
"ver": "2.3.7",
"uuid": "84e3ae1c-a16c-4596-b008-2cc45a3423df",
"importer": "texture",
"type": "sprite",
"wrapMode": "clamp",
"filterMode": "bilinear",
"premultiplyAlpha": false,
"genMipmaps": false,
"packable": true,
"width": 364,
"height": 374,
"platformSettings": {},
"subMetas": {
"5color18": {
"ver": "1.0.6",
"uuid": "20019264-60d6-4197-9c24-4646d9c4e680",
"importer": "sprite-frame",
"rawTextureUuid": "84e3ae1c-a16c-4596-b008-2cc45a3423df",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 0,
"trimY": 0,
"width": 364,
"height": 374,
"rawWidth": 364,
"rawHeight": 374,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"subMetas": {}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -503,7 +503,7 @@ export default class GameManager extends cc.Component {
this.setUserPower(data);
this.setmonth(data);
this.setRevive(data);
this.setRevive();
let levelInfo = cc.fx.StorageMessage.getStorage("level");
//如果本地缓存没有关卡信息,默认为服务器信息为主
if (levelInfo == undefined || levelInfo == "" || levelInfo == null) {
@ -980,10 +980,10 @@ export default class GameManager extends cc.Component {
let dateStr = new Date(data.data.monthCardTime);
cc.fx.StorageMessage.setStorage("mCardDate", dateStr);
}
//#region 复活购买次数初始化
/** 复活购买次数初始化 */
setRevive(data) {
cc.fx.GameConfig.GM_INFO.revive = data.data.rebornGiftCount;
//#region 复活礼包状态初始化
/** 复活礼包不限制购买次数 */
setRevive() {
cc.fx.GameConfig.GM_INFO.revive = 0;
}
//#region 获取有没有分享信息
/** 获取有没有分享信息 */

View File

@ -599,17 +599,34 @@ export default class JiaZai extends cc.Component {
// - onShow:游戏从后台切换到前台
// - onHide:游戏从前台切换到后台
// ============================================
private removeGameLifecycleListeners(): void {
//@ts-ignore
if (typeof wx === 'undefined') return;
if (this.onShowListener) {
//@ts-ignore
wx.offShow(this.onShowListener);
}
if (this.onHideListener) {
//@ts-ignore
wx.offHide(this.onHideListener);
}
this.onShowListener = null;
this.onHideListener = null;
}
onGames() {
if (!this.node || !cc.isValid(this.node)) return;
//@ts-ignore
if (typeof wx !== 'undefined') {
this.onShowListener = null;
this.onHideListener = null;
this.removeGameLifecycleListeners();
// 定义监听函数
this.onShowListener = () => {
if (!this.node || !cc.isValid(this.node)) return;
this.onGameShow();
};
this.onHideListener = () => {
if (!this.node || !cc.isValid(this.node)) return;
this.onGameHide();
};
//@ts-ignore
@ -620,6 +637,10 @@ export default class JiaZai extends cc.Component {
}
}
onDestroy() {
this.removeGameLifecycleListeners();
}
// ============================================
// 游戏隐藏回调方法
// 功能:游戏切入后台时执行的清理操作
@ -655,6 +676,7 @@ export default class JiaZai extends cc.Component {
// 5. 刷新体力值和倒计时
// ============================================
onGameShow() {
if (!this.node || !cc.isValid(this.node)) return;
// console.log("执行开始游戏gameshow");
if (this.shareIng == true) {
let nowTime = Math.floor(Date.now() / 1000);
@ -668,6 +690,7 @@ export default class JiaZai extends cc.Component {
this.refreshStaminaDisplay();
cc.fx.GameTool.getHealth((data) => {
if (!this.node || !cc.isValid(this.node)) return;
if (this.level) {
let kuandu = 43;
if ((cc.fx.GameConfig.GM_INFO.level + 1) > 999) {

View File

@ -4440,9 +4440,9 @@ export default class MapConroler extends cc.Component {
if (this.iceTrue() == false && this.node.parent.parent.parent.getChildByName("Pause").active == false && !this.shopPause) {
this.pause = false;
}
this.timeNumber = 21;
this.add_Time += 20;
NumberToImage.getTimeMargi3(20, 45, "company_", this.timeLabel)
this.timeNumber = 31;
this.add_Time += 30;
NumberToImage.getTimeMargi3(30, 45, "company_", this.timeLabel)
this.blockNum = this.blocks.length;
if (this.blockNum == 0) this.nextLevel(1);
this.node.parent.parent.getChildByName("Lose").active = false;

View File

@ -18,9 +18,6 @@ const { ccclass, property } = cc._decorator;
@ccclass
export default class Revive extends cc.Component {
@property(cc.Node)
btn_Touch: boolean = false;
// LIFE-CYCLE CALLBACKS:
@ -29,6 +26,7 @@ export default class Revive extends cc.Component {
private iosProductId: string = "";
private iosCount: number = 1;
public home: number = 0;
onLoad() {
this.btn_Touch = true;
// 检测微信小游戏切到后台
@ -112,29 +110,22 @@ export default class Revive extends cc.Component {
}
start() {
if (cc.fx.GameConfig.GM_INFO.revive == 1) {
if (this.node) {
this.node.active = false;
}
}
}
init() {
if (!cc.fx.GameConfig.GM_INFO.canIos) {
this.node.active = false;
return;
}
this.node.active = true;
this.addListener();
this.btn_Touch = true;
if (cc.fx.GameConfig.GM_INFO.revive == 1) {
if (this.node) {
this.node.active = false;
}
}
}
addListener() {
if (cc.sys.platform === cc.sys.WECHAT_GAME || cc.sys.platform === cc.sys.BYTEDANCE_GAME) {
if (this.onShowListener) {
//@ts-ignore
wx.offShow(this.onShowListener);
}
// 定义监听函数
this.onShowListener = () => {
this.onShow();
@ -155,7 +146,7 @@ export default class Revive extends cc.Component {
}
//发奖励
revivew() {
cc.fx.GameConfig.GM_INFO.revive = 1;
cc.fx.GameConfig.GM_INFO.revive = 0;
if (MapConroler && MapConroler._instance) {
MapConroler._instance.setPropNum();
}
@ -417,10 +408,6 @@ export default class Revive extends cc.Component {
this.onShow();
}
onDestroy() {
}
iosOldPay(price, productId) {
// 旧版本ios支付
let iosPayInfo = {

View File

@ -151,7 +151,7 @@ export class GameConfig {
doubleCoin: number; //是否双倍
rewardAdCoin: number; //是否双倍
monthTime: number; //月卡时间
revive: number; //复活礼包购买次数
revive: number; //复活礼包可购买状态(不限购时保持为 0)
otherUid: string; //其他被帮助用户id
otherLevel: number; //其他被帮助用户等级
helpLevel: number; //帮助用户等级
@ -348,7 +348,7 @@ export class GameConfig {
vibrateOpen: true, //震动
coinnum: 0, //每局的金币数
paid_user: false, //是否是付费用户
version: "1.0.37", //版本号
version: "1.0.39", //版本号
shushu_DistinctId: "", //数数访客ID
shushu_AccountId: "", //数数账号ID
uid: "", //用户和后端唯一id
@ -361,7 +361,7 @@ export class GameConfig {
doubleCoin: 1, //是否双倍
rewardAdCoin: 1, //是否双倍
monthTime: 0, //月卡时间
revive: 0, //复活礼包购买次数
revive: 0, //复活礼包可购买状态(不限购时保持为 0)
otherUid: "", //其他被帮助用户id
otherLevel: 0, //其他被帮助用户等级
helpLevel: 0, //帮助用户等级

View File

@ -867,7 +867,7 @@ export default class Utils {
uid: cc.fx.GameConfig.GM_INFO.uid,
}
Utils.POST("canRebonGift", setData, res => {
Utils.POST("canRebornGift", setData, res => {
if (res.code === 1) {
//console.log("服务器:canRebonGift'✅ ", res);
if (callBack) callBack(res);

View File

@ -98,7 +98,7 @@
"y": -540,
"z": 0
},
"questionTime": 14,
"questionTime": 6,
"floor": 1,
"floorTime": 8,
"floorMove": false,
@ -498,4 +498,4 @@
}
]
]
}
}

View File

@ -28,10 +28,16 @@
},
{
"__id__": 30
},
{
"__id__": 31
},
{
"__id__": 32
}
],
"_prefab": {
"__id__": 31
"__id__": 33
},
"_opacity": 255,
"_color": {
@ -1160,6 +1166,49 @@
"_originalHeight": 0,
"_id": ""
},
{
"__type__": "cc.Sprite",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 1
},
"_enabled": true,
"_materials": [
{
"__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432"
}
],
"_srcBlendFactor": 770,
"_dstBlendFactor": 771,
"_spriteFrame": null,
"_type": 0,
"_sizeMode": 1,
"_fillType": 0,
"_fillCenter": {
"__type__": "cc.Vec2",
"x": 0,
"y": 0
},
"_fillStart": 0,
"_fillRange": 0,
"_isTrimmedMode": true,
"_atlas": null,
"_id": ""
},
{
"__type__": "2b129+pge9K6ZaB0ZnXUAjA",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 1
},
"_enabled": true,
"effectAsset": {
"__uuid__": "8c246f76-f5f1-4a55-a315-60fdc44ddcbe"
},
"_id": ""
},
{
"__type__": "cc.PrefabInfo",
"root": {

View File

@ -0,0 +1,58 @@
const { ccclass, property, requireComponent } = cc._decorator;
/** 挂到带 Sprite 的节点上,并在 Inspector 中指定 jungle_shine.effect。 */
@ccclass
@requireComponent(cc.Sprite)
export default class JungleShine extends cc.Component {
@property(cc.EffectAsset)
effectAsset: cc.EffectAsset = null;
private material: cc.Material = null;
private delayRemaining: number = 0.15;
private elapsed: number = 0;
protected onLoad(): void {
let sprite = this.getComponent(cc.Sprite);
if (!sprite || !this.effectAsset) {
cc.warn("[JungleShine] 请在 Inspector 中绑定 jungle_shine.effect");
return;
}
let material = new cc.Material();
// @ts-ignore Cocos Creator 2.4 通过 effectAsset 创建运行时材质。
material.effectAsset = this.effectAsset;
material.setProperty("shinePosition", -0.35);
material.setProperty("shineWidth", 0.075);
material.setProperty("shineStrength", 1.8);
material.setProperty("shineAngle", 0.2);
material.setProperty("shineColor", [1.0, 0.95, 0.68, 1.0]);
this.material = material;
sprite.setMaterial(0, material);
}
protected update(dt: number): void {
if (!this.material) {
return;
}
if (this.delayRemaining > 0) {
this.delayRemaining = Math.max(0, this.delayRemaining - dt);
return;
}
this.elapsed += dt;
let progress = Math.min(1, this.elapsed / 0.72);
this.material.setProperty("shinePosition", -0.35 + 1.7 * progress);
if (progress >= 1) {
this.elapsed = 0;
this.delayRemaining = 1.25;
this.material.setProperty("shinePosition", -0.35);
}
}
protected onDestroy(): void {
if (this.material && cc.isValid(this.material)) {
this.material.destroy();
}
this.material = null;
}
}

View File

@ -1,6 +1,6 @@
{
"ver": "1.1.0",
"uuid": "aa27c19b-4e7d-43ef-86d2-69c7e0428f4a",
"uuid": "2b129fa9-81ef-4ae9-9681-d199d75008c0",
"importer": "typescript",
"isPlugin": false,
"loadPluginInWeb": true,

View File

@ -1,6 +1,6 @@
{
"ver": "1.0.27",
"uuid": "2874d4a3-5f10-4d7c-bcaf-40b9d6e6cd30",
"uuid": "8c246f76-f5f1-4a55-a315-60fdc44ddcbe",
"importer": "effect",
"compiledShaders": [
{

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -31,16 +31,22 @@
},
{
"__id__": 42
},
{
"__id__": 45
}
],
"_active": true,
"_components": [
{
"__id__": 45
"__id__": 50
},
{
"__id__": 51
}
],
"_prefab": {
"__id__": 46
"__id__": 52
},
"_opacity": 255,
"_color": {
@ -1674,6 +1680,149 @@
"fileId": "8eNg8XXCtL/qv4zJRaslPp",
"sync": false
},
{
"__type__": "cc.Node",
"_name": "New Label",
"_objFlags": 0,
"_parent": {
"__id__": 1
},
"_children": [],
"_active": true,
"_components": [
{
"__id__": 46
},
{
"__id__": 47
},
{
"__id__": 48
}
],
"_prefab": {
"__id__": 49
},
"_opacity": 255,
"_color": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_contentSize": {
"__type__": "cc.Size",
"width": 420,
"height": 44.32
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_trs": {
"__type__": "TypedArray",
"ctor": "Float64Array",
"array": [
264.065,
114.723,
0,
0,
0,
0,
1,
1,
1,
1
]
},
"_eulerAngles": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_skewX": 0,
"_skewY": 0,
"_is3DNode": false,
"_groupIndex": 0,
"groupIndex": 0,
"_id": ""
},
{
"__type__": "cc.Label",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 45
},
"_enabled": true,
"_materials": [
{
"__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432"
}
],
"_srcBlendFactor": 770,
"_dstBlendFactor": 771,
"_string": "加量不加价,复活时间增加!",
"_N$string": "加量不加价,复活时间增加!",
"_fontSize": 32,
"_lineHeight": 32,
"_enableWrapText": true,
"_N$file": null,
"_isSystemFontUsed": true,
"_spacingX": 0,
"_batchAsBitmap": false,
"_styleFlags": 0,
"_underlineHeight": 0,
"_N$horizontalAlign": 1,
"_N$verticalAlign": 1,
"_N$fontFamily": "Arial",
"_N$overflow": 0,
"_N$cacheMode": 0,
"_id": ""
},
{
"__type__": "ca6a6n/tGlFd6O2N+Cku8D7",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 45
},
"_enabled": true,
"outlineWidth": 2,
"_id": ""
},
{
"__type__": "cc.LabelOutline",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 45
},
"_enabled": true,
"_color": {
"__type__": "cc.Color",
"r": 0,
"g": 0,
"b": 0,
"a": 255
},
"_width": 2,
"_id": ""
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__id__": 0
},
"fileId": "32EGokmchCVahqHpHr9DGz",
"sync": false
},
{
"__type__": "cc.Sprite",
"_name": "",
@ -1706,6 +1855,19 @@
"_atlas": null,
"_id": ""
},
{
"__type__": "2b129+pge9K6ZaB0ZnXUAjA",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 1
},
"_enabled": true,
"effectAsset": {
"__uuid__": "8c246f76-f5f1-4a55-a315-60fdc44ddcbe"
},
"_id": ""
},
{
"__type__": "cc.PrefabInfo",
"root": {

File diff suppressed because it is too large Load Diff

View File

@ -1,77 +0,0 @@
const { ccclass, requireComponent } = cc._decorator;
/** 商城 Jungle 背景专用的横向扫光。 */
@ccclass
@requireComponent(cc.Sprite)
export default class ShopJungleShine extends cc.Component {
private sprite: cc.Sprite = null;
private material: cc.Material = null;
private moveDuration: number = 0.72;
private repeatDelay: number = 1.25;
private delayRemaining: number = 0.15;
private elapsed: number = 0;
private startPosition: number = -0.35;
private endPosition: number = 1.35;
protected onLoad(): void {
this.sprite = this.getComponent(cc.Sprite);
this.loadMaterial();
}
protected update(dt: number): void {
if (!this.material) {
return;
}
if (this.delayRemaining > 0) {
this.delayRemaining = Math.max(0, this.delayRemaining - dt);
return;
}
this.elapsed += dt;
let progress = Math.min(1, this.elapsed / this.moveDuration);
let position = this.startPosition
+ (this.endPosition - this.startPosition) * progress;
this.material.setProperty("shinePosition", position);
if (progress >= 1) {
this.elapsed = 0;
this.delayRemaining = this.repeatDelay;
this.material.setProperty("shinePosition", this.startPosition);
}
}
protected onDestroy(): void {
if (this.material && cc.isValid(this.material)) {
this.material.destroy();
}
this.material = null;
this.sprite = null;
}
private loadMaterial(): void {
let bundle = cc.assetManager.getBundle("shop");
if (!bundle || !this.sprite) {
cc.warn("[ShopJungleShine] 商城分包未加载");
return;
}
bundle.load("effect/jungle_shine", cc.EffectAsset, (error: Error, effect: cc.EffectAsset) => {
if (error || !effect || !cc.isValid(this.node) || !this.sprite) {
if (error) {
cc.warn("[ShopJungleShine] 扫光 Shader 加载失败", error);
}
return;
}
let material = new cc.Material();
// @ts-ignore Cocos Creator 2.4 运行时通过 effectAsset 创建材质。
material.effectAsset = effect;
material.setProperty("shinePosition", this.startPosition);
material.setProperty("shineWidth", 0.075);
material.setProperty("shineStrength", 1.8);
material.setProperty("shineAngle", 0.2);
material.setProperty("shineColor", [1.0, 0.95, 0.68, 1.0]);
this.material = material;
this.sprite.setMaterial(0, material);
});
}
}

View File

@ -6,7 +6,6 @@ import List from "../../Script/module/RankList/List";
import NumberToImage from "../../Script/NumberToImage";
import SceneManager from "../../Script/SceneManager";
import { MiniGameSdk } from "../../Script/Sdk/MiniGameSdk";
import ShopJungleShine from "./ShopJungleShine";
const { ccclass, property } = cc._decorator;
@ -153,9 +152,6 @@ export default class NewClass extends cc.Component {
>= cc.fx.GameConfig.getJungleTreasureUnlockLevel();
let shouldShowJungle = meetsLevel && !this.isJungleTreasureExpired();
jungle.active = shouldShowJungle;
if (shouldShowJungle && jungle.getComponent(cc.Sprite) && !jungle.getComponent(ShopJungleShine)) {
jungle.addComponent(ShopJungleShine);
}
this.jungleSiblingOriginalPositions.forEach((item) => {
if (cc.isValid(item.node)) {
item.node.y = item.y + (!shouldShowJungle && item.node !== jungle ? 380 : 0);

View File

@ -22,20 +22,6 @@ export default async function (ctx: FunctionContext) {
return { code: 0, data: null, msg: "token校验失败" };
}
}
let rebornGiftTime = res.data.rebornGiftTime || 0;
let rebornGiftCount = res.data.rebornGiftCount || 0;
let times = getTodayStartTimestamp();
if (rebornGiftTime < times) {
rebornGiftCount = 0;
}
if (rebornGiftCount >= 1) {
return { code: 0, data: null, msg: "今天购买次数已用完" };
}
db.collection(dbname).where({ _id: uid }).update({ rebornGiftTime: rebornGiftTime, rebornGiftCount: rebornGiftCount });
return { code: 1, data: { rebornGiftTime: rebornGiftTime, rebornGiftCount: rebornGiftCount }, msg: "可以购买" };
const rebornGiftTime = res.data.rebornGiftTime || 0;
return { code: 1, data: { rebornGiftTime, rebornGiftCount: 0 }, msg: "可以购买" };
}
function getTodayStartTimestamp() {
const date = new Date();
date.setHours(0, 0, 0, 0);
return date.getTime();
}

View File

@ -272,11 +272,7 @@ export default async function (ctx: FunctionContext) {
if (dbname === "users") {
userData.abTests = abTests;
}
let rebornGiftTime = userData?.rebornGiftTime || 0;
let times = getTodayStartTimestamp();
if (rebornGiftTime < times) {
userData.rebornGiftCount = 0;
}
userData.rebornGiftCount = 0;
if (userData.isWhite && !userData.film && userData.film != 0) {
userData.film = userData.levelAmount;
}
@ -352,11 +348,6 @@ const propName = {
"宝藏8": "jungle_treasure_8"
};
function getTodayStartTimestamp() {
const date = new Date();
date.setHours(0, 0, 0, 0);
return date.getTime();
}
async function getWXOpenId(code, dbname) {
let appid = "wx30f74367b3d3e7a6";
let appsecret = "a3417fe674feadb77809d8f9a365190d";
@ -430,7 +421,7 @@ async function getIosOrder(openid, ctx) {
await db.collection("users").where({ _id: res1.data._id }).update({ pay_user: true });
break;
case "reborn_Gift":
db.collection("users").where({ _id: res1.data._id }).update({ rebornGiftTime: Date.now(), rebornGiftCount: 1, pay_user: true });
db.collection("users").where({ _id: res1.data._id }).update({ rebornGiftTime: Date.now(), rebornGiftCount: 0, pay_user: true });
break;
case "starter_pack":
db.collection("users").where({ _id: res1.data._id }).update({ starter_packState: 1, pay_user: true });

View File

@ -22,20 +22,7 @@ export default async function (ctx: FunctionContext) {
return { code: 0, data: null, msg: "token校验失败" };
}
}
let rebornGiftTime=res.data.rebornGiftTime||0;
let rebornGiftCount=res.data.rebornGiftCount||0;
let times=getTodayStartTimestamp();
if(rebornGiftTime<times){
rebornGiftCount=0;
}
if(rebornGiftCount>=1){
return { code: 0, data: null, msg: "今天购买次数已用完" };
}
db.collection(dbname).where({ _id: uid }).update({ rebornGiftTime:Date.now(),rebornGiftCount:1});
return { code: 1, data: { rebornGiftTime:Date.now(),rebornGiftCount:rebornGiftCount+1},msg:"可以购买"};
}
function getTodayStartTimestamp() {
const date = new Date();
date.setHours(0, 0, 0, 0);
return date.getTime();
const rebornGiftTime = Date.now();
await db.collection(dbname).where({ _id: uid }).update({ rebornGiftTime, rebornGiftCount: 0 });
return { code: 1, data: { rebornGiftTime, rebornGiftCount: 0 }, msg: "可以购买" };
}

View File

@ -47,7 +47,7 @@ export default async function (ctx: FunctionContext) {
//console.log(data);
let res2 = await db.collection(dbname).where({ _id: uid }).update(data);
if (res2.ok && res2.updated == 1) {
return { code: 1, data: data, msg: "用户数据更新成功" }
return { code: 1, data: null, msg: "用户数据更新成功" }
} else {
return { code: 0, data: null, msg: "用户数据更新失败" }
}
@ -61,12 +61,8 @@ export default async function (ctx: FunctionContext) {
} else {
share = [];
}
let rebornGiftTime = userData.rebornGiftTime || 0;
let rebornGiftCount = userData.rebornGiftCount || 0;
let times = getTodayStartTimestamp();
if (rebornGiftTime < times) {
rebornGiftCount = 0;
}
const rebornGiftTime = userData.rebornGiftTime || 0;
const rebornGiftCount = 0;
let data = {
coinAmount: Number(userData.coinAmount) || 0,
freezeAmount: Number(userData.freezeAmount) || 0,
@ -96,9 +92,4 @@ export default async function (ctx: FunctionContext) {
}
}
function getTodayStartTimestamp() {
const date = new Date();
date.setHours(0, 0, 0, 0);
return date.getTime();
}

View File

@ -52,7 +52,7 @@ export default async function (ctx: FunctionContext) {
await db.collection("users").where({ _id: uid }).update({ pay_user: true });
break;
case "reborn_Gift":
db.collection("users").where({ _id: uid }).update({ rebornGiftTime: Date.now(), rebornGiftCount: 1, pay_user: true });
db.collection("users").where({ _id: uid }).update({ rebornGiftTime: Date.now(), rebornGiftCount: 0, pay_user: true });
break;
case "starter_pack":
db.collection("users").where({ _id: uid }).update({ starter_packState: 1, pay_user: true });

View File

@ -0,0 +1,143 @@
import test from "node:test";
import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import { registerHooks } from "node:module";
const state = { user: null };
globalThis.__rebornGiftCloudMock = {
database() {
return {
collection() {
return {
where(query) {
return {
async getOne() {
return { data: state.user?._id === query._id ? state.user : null };
},
async update(payload) {
if (state.user?._id !== query._id) {
return { updated: 0 };
}
Object.assign(state.user, payload);
return { updated: 1 };
},
};
},
};
},
};
},
};
globalThis.__rebornGiftUtilsMock = {
checkToken(received, expected) {
return received === expected;
},
};
registerHooks({
resolve(specifier, context, nextResolve) {
if (specifier === "@lafjs/cloud") {
return { url: "data:text/javascript,export default globalThis.__rebornGiftCloudMock", shortCircuit: true };
}
if (specifier === "@/Utils") {
return { url: "data:text/javascript,export default globalThis.__rebornGiftUtilsMock", shortCircuit: true };
}
return nextResolve(specifier, context);
},
});
const [{ default: rebornGift }, { default: canRebornGift }, { default: userData }] = await Promise.all([
import(new URL("../functions/rebornGift.ts", import.meta.url)),
import(new URL("../functions/canRebornGift.ts", import.meta.url)),
import(new URL("../functions/userData.ts", import.meta.url)),
]);
function resetUser(count = 0) {
state.user = {
_id: "user-1",
token: "token-1",
rebornGiftTime: 1_700_000_000_000,
rebornGiftCount: count,
};
}
function request(handler) {
return handler({ body: { uid: "user-1", token: "token-1" } });
}
test("reborn gift can be recorded repeatedly even for a legacy limited user", async () => {
resetUser(1);
const first = await request(rebornGift);
const second = await request(rebornGift);
assert.equal(first.code, 1);
assert.equal(second.code, 1);
assert.equal(first.data.rebornGiftCount, 0);
assert.equal(second.data.rebornGiftCount, 0);
assert.equal(state.user.rebornGiftCount, 0);
});
test("reborn gift availability never rejects based on the legacy count", async () => {
resetUser(99);
const result = await request(canRebornGift);
assert.equal(result.code, 1);
assert.equal(result.data.rebornGiftCount, 0);
});
test("user data normalizes the legacy count to an unlimited state", async () => {
resetUser(12);
const result = await userData({ body: { action: "read", uid: "user-1", token: "token-1" } });
assert.equal(result.code, 1);
assert.equal(result.data.rebornGiftCount, 0);
});
test("client keeps the reborn gift available and reopens it after each loss", async () => {
const [gameManager, revive, utils] = await Promise.all([
readFile(new URL("../../../assets/Script/GameManager.ts", import.meta.url), "utf8"),
readFile(new URL("../../../assets/Script/Revive.ts", import.meta.url), "utf8"),
readFile(new URL("../../../assets/Script/module/Pay/Utils.ts", import.meta.url), "utf8"),
]);
assert.match(gameManager, /setRevive\(\)[\s\S]*?GM_INFO\.revive\s*=\s*0/);
assert.match(revive, /init\(\)[\s\S]*?this\.node\.active\s*=\s*true/);
assert.match(revive, /if \(this\.onShowListener\)[\s\S]*?wx\.offShow\(this\.onShowListener\)/);
assert.doesNotMatch(revive, /GM_INFO\.revive\s*={1,3}\s*1/);
assert.doesNotMatch(revive, /GM_INFO\.revive\s*==={0,1}\s*1/);
assert.match(utils, /Utils\.POST\("canRebornGift"/);
});
test("payment recovery paths never restore the removed one-purchase flag", async () => {
const [login, iosGetPayInfo] = await Promise.all([
readFile(new URL("../functions/login.ts", import.meta.url), "utf8"),
readFile(new URL("../functions/wx/iosgetPayInfo.ts", import.meta.url), "utf8"),
]);
assert.doesNotMatch(`${login}\n${iosGetPayInfo}`, /rebornGiftCount:\s*1/);
assert.match(login, /case "reborn_Gift":[\s\S]*?rebornGiftCount:\s*0/);
assert.match(iosGetPayInfo, /case "reborn_Gift":[\s\S]*?rebornGiftCount:\s*0/);
});
test("reborn gift grants 30 seconds while regular revival remains at 20", async () => {
const map = await readFile(new URL("../../../assets/Script/Map.ts", import.meta.url), "utf8");
const regularRevive = map.slice(
map.indexOf(" runRewive(data) {"),
map.indexOf(" //执行复活函数具体执行状态改变操作"),
);
const giftRevive = map.slice(
map.indexOf(" runRewiveCopy() {"),
map.indexOf(" //上传数数游戏完成事件"),
);
assert.match(regularRevive, /timeNumber\s*=\s*21/);
assert.match(regularRevive, /add_Time\s*\+=\s*20/);
assert.match(giftRevive, /timeNumber\s*=\s*31/);
assert.match(giftRevive, /add_Time\s*\+=\s*30/);
assert.match(giftRevive, /getTimeMargi3\(30,/);
});

View File

@ -0,0 +1,26 @@
import assert from "node:assert/strict";
import { access, readFile } from "node:fs/promises";
import test from "node:test";
test("JungleShine is manually attachable and does not load a bundle", async () => {
const [reviveSource, shopSource, componentSource, effectSource, resMetaSource] = await Promise.all([
readFile(new URL("../../../assets/Script/Revive.ts", import.meta.url), "utf8"),
readFile(new URL("../../../assets/shop/script/shop.ts", import.meta.url), "utf8"),
readFile(new URL("../../../assets/res/effect/JungleShine.ts", import.meta.url), "utf8"),
readFile(new URL("../../../assets/res/effect/jungle_shine.effect", import.meta.url), "utf8"),
readFile(new URL("../../../assets/res.meta", import.meta.url), "utf8"),
]);
const resMeta = JSON.parse(resMetaSource);
await assert.rejects(access(new URL("../../../assets/shop/script/ShopJungleShine.ts", import.meta.url)));
await assert.rejects(access(new URL("../../../assets/shop/script/ShopJungleShine.ts.meta", import.meta.url)));
await assert.rejects(access(new URL("../../../assets/shared_shader.meta", import.meta.url)));
assert.doesNotMatch(reviveSource, /ShopJungleShine|shared_shader|loadShineMaterial|RUNTIME_JUNGLE_SHINE/);
assert.doesNotMatch(shopSource, /ShopJungleShine|shared_shader|loadJungleShineMaterial|RUNTIME_JUNGLE_SHINE/);
assert.match(componentSource, /@requireComponent\(cc\.Sprite\)/);
assert.match(componentSource, /@property\(cc\.EffectAsset\)/);
assert.match(componentSource, /material\.effectAsset = this\.effectAsset/);
assert.doesNotMatch(componentSource, /loadBundle|getBundle|cc\.resources|\bimport\b/);
assert.equal(resMeta.isBundle, false);
assert.match(effectSource, /CCProgram shop-jungle-shine-fs/);
});

View File

@ -1,5 +1,5 @@
{
"last-module-event-record-time": 1787023031670,
"last-module-event-record-time": 1787645164957,
"group-list": [
"default",
"Map"