diff --git a/assets/resources/game/heros/cards.png.meta b/assets/resources/game/heros/cards.png.meta index e5b008c9..0b7bb95f 100644 --- a/assets/resources/game/heros/cards.png.meta +++ b/assets/resources/game/heros/cards.png.meta @@ -1,5 +1,5 @@ { - "ver": "1.0.26", + "ver": "1.0.27", "importer": "image", "imported": true, "uuid": "0474d69a-4ed2-4470-a797-19d9f23c09b0", diff --git a/assets/resources/game/heros/equips2.png.meta b/assets/resources/game/heros/equips2.png.meta index cc4df025..8b4b820e 100644 --- a/assets/resources/game/heros/equips2.png.meta +++ b/assets/resources/game/heros/equips2.png.meta @@ -1,5 +1,5 @@ { - "ver": "1.0.26", + "ver": "1.0.27", "importer": "image", "imported": true, "uuid": "15588387-53dc-4224-bf79-8427e1cc1e9a", diff --git a/assets/resources/game/heros/hero/a1.png.meta b/assets/resources/game/heros/hero/a1.png.meta index a8b8698a..f59e761c 100644 --- a/assets/resources/game/heros/hero/a1.png.meta +++ b/assets/resources/game/heros/hero/a1.png.meta @@ -1,5 +1,5 @@ { - "ver": "1.0.26", + "ver": "1.0.27", "importer": "image", "imported": true, "uuid": "2b4c7ab0-b58d-4893-ade9-d8e56e03cf86", diff --git a/assets/resources/game/heros/hero/a2.png.meta b/assets/resources/game/heros/hero/a2.png.meta index 0bff01f8..96d7075b 100644 --- a/assets/resources/game/heros/hero/a2.png.meta +++ b/assets/resources/game/heros/hero/a2.png.meta @@ -1,5 +1,5 @@ { - "ver": "1.0.26", + "ver": "1.0.27", "importer": "image", "imported": true, "uuid": "f35115b6-daca-417b-b2e3-059e6760e173", diff --git a/assets/resources/game/heros/hero/a3.png.meta b/assets/resources/game/heros/hero/a3.png.meta index a11a8365..a937fcc1 100644 --- a/assets/resources/game/heros/hero/a3.png.meta +++ b/assets/resources/game/heros/hero/a3.png.meta @@ -1,5 +1,5 @@ { - "ver": "1.0.26", + "ver": "1.0.27", "importer": "image", "imported": true, "uuid": "3403fbf1-f543-4e09-a6ec-24425bc59177", diff --git a/assets/resources/game/heros/hero/c1.png.meta b/assets/resources/game/heros/hero/c1.png.meta index 5ad49aae..7358730d 100644 --- a/assets/resources/game/heros/hero/c1.png.meta +++ b/assets/resources/game/heros/hero/c1.png.meta @@ -1,5 +1,5 @@ { - "ver": "1.0.26", + "ver": "1.0.27", "importer": "image", "imported": true, "uuid": "459d724d-7610-4d02-bd68-031a7a628d12", diff --git a/assets/resources/game/heros/hero/k1.png.meta b/assets/resources/game/heros/hero/k1.png.meta index ae90922f..ae64d8c3 100644 --- a/assets/resources/game/heros/hero/k1.png.meta +++ b/assets/resources/game/heros/hero/k1.png.meta @@ -1,5 +1,5 @@ { - "ver": "1.0.26", + "ver": "1.0.27", "importer": "image", "imported": true, "uuid": "ddee9ebe-e001-473c-850a-3650df821ca5", diff --git a/assets/resources/game/heros/hero/mf1.png.meta b/assets/resources/game/heros/hero/mf1.png.meta index d6b7a418..a7311308 100644 --- a/assets/resources/game/heros/hero/mf1.png.meta +++ b/assets/resources/game/heros/hero/mf1.png.meta @@ -1,5 +1,5 @@ { - "ver": "1.0.26", + "ver": "1.0.27", "importer": "image", "imported": true, "uuid": "7a7b06c8-a066-4238-869c-cec4f7621361", diff --git a/assets/resources/game/heros/hero/mh1.png.meta b/assets/resources/game/heros/hero/mh1.png.meta index 1049b56f..44494ec5 100644 --- a/assets/resources/game/heros/hero/mh1.png.meta +++ b/assets/resources/game/heros/hero/mh1.png.meta @@ -1,5 +1,5 @@ { - "ver": "1.0.26", + "ver": "1.0.27", "importer": "image", "imported": true, "uuid": "ea52be76-7907-4118-941a-822a9cda1966", diff --git a/assets/resources/game/heros/monster/o1.png.meta b/assets/resources/game/heros/monster/o1.png.meta index 8784de35..6490245f 100644 --- a/assets/resources/game/heros/monster/o1.png.meta +++ b/assets/resources/game/heros/monster/o1.png.meta @@ -1,5 +1,5 @@ { - "ver": "1.0.26", + "ver": "1.0.27", "importer": "image", "imported": true, "uuid": "c3578585-1456-4045-b18d-96a2367dfe3e", diff --git a/assets/resources/game/heros/monster/o2.png.meta b/assets/resources/game/heros/monster/o2.png.meta index f581265f..52d04db4 100644 --- a/assets/resources/game/heros/monster/o2.png.meta +++ b/assets/resources/game/heros/monster/o2.png.meta @@ -1,5 +1,5 @@ { - "ver": "1.0.26", + "ver": "1.0.27", "importer": "image", "imported": true, "uuid": "50fa0bab-1535-4892-94a8-c44c7b4736db", diff --git a/assets/resources/game/heros/monster/o3.png.meta b/assets/resources/game/heros/monster/o3.png.meta index 1d2ff554..6c37d657 100644 --- a/assets/resources/game/heros/monster/o3.png.meta +++ b/assets/resources/game/heros/monster/o3.png.meta @@ -1,5 +1,5 @@ { - "ver": "1.0.26", + "ver": "1.0.27", "importer": "image", "imported": true, "uuid": "3842ed73-2247-4cb4-bd02-b1dfd3b0a2af", diff --git a/assets/resources/game/heros/monster/o4.png.meta b/assets/resources/game/heros/monster/o4.png.meta index 28ac7446..82a7b863 100644 --- a/assets/resources/game/heros/monster/o4.png.meta +++ b/assets/resources/game/heros/monster/o4.png.meta @@ -1,5 +1,5 @@ { - "ver": "1.0.26", + "ver": "1.0.27", "importer": "image", "imported": true, "uuid": "1cc562dd-d004-41b6-ba70-bef23074076a", diff --git a/assets/resources/game/heros/wp.png.meta b/assets/resources/game/heros/wp.png.meta index 34987f2d..c9fcfa29 100644 --- a/assets/resources/game/heros/wp.png.meta +++ b/assets/resources/game/heros/wp.png.meta @@ -1,5 +1,5 @@ { - "ver": "1.0.26", + "ver": "1.0.27", "importer": "image", "imported": true, "uuid": "db035da2-17ca-4877-9579-1ea97b5d8443", diff --git a/assets/resources/game/map/Backgrounds/mp.png.meta b/assets/resources/game/map/Backgrounds/mp.png.meta index 38f3ed4a..42bb226f 100644 --- a/assets/resources/game/map/Backgrounds/mp.png.meta +++ b/assets/resources/game/map/Backgrounds/mp.png.meta @@ -1,5 +1,5 @@ { - "ver": "1.0.26", + "ver": "1.0.27", "importer": "image", "imported": true, "uuid": "099a81bb-31a5-4d85-b854-9f2a8b60d279", diff --git a/assets/resources/game/skills/anm/icez.png.meta b/assets/resources/game/skills/anm/icez.png.meta index 964e8b0c..2ec0032b 100644 --- a/assets/resources/game/skills/anm/icez.png.meta +++ b/assets/resources/game/skills/anm/icez.png.meta @@ -1,5 +1,5 @@ { - "ver": "1.0.26", + "ver": "1.0.27", "importer": "image", "imported": true, "uuid": "85e5c51a-3127-426a-a3c5-36ada6764f8f", diff --git a/assets/resources/game/skills/skill2.png.meta b/assets/resources/game/skills/skill2.png.meta index 085d59ff..fac4d185 100644 --- a/assets/resources/game/skills/skill2.png.meta +++ b/assets/resources/game/skills/skill2.png.meta @@ -1,5 +1,5 @@ { - "ver": "1.0.26", + "ver": "1.0.27", "importer": "image", "imported": true, "uuid": "24774750-953a-4e0b-b361-b985bae02ecb", diff --git a/assets/resources/game/skills/skill4.png.meta b/assets/resources/game/skills/skill4.png.meta index 94fe8e0d..f3ce5b2e 100644 --- a/assets/resources/game/skills/skill4.png.meta +++ b/assets/resources/game/skills/skill4.png.meta @@ -1,5 +1,5 @@ { - "ver": "1.0.26", + "ver": "1.0.27", "importer": "image", "imported": true, "uuid": "ad487883-575b-4cdf-a4b8-ecd284aa53cb", diff --git a/assets/resources/game/skills/skill_icon.png.meta b/assets/resources/game/skills/skill_icon.png.meta index 153301e8..5f1c20e1 100644 --- a/assets/resources/game/skills/skill_icon.png.meta +++ b/assets/resources/game/skills/skill_icon.png.meta @@ -1,5 +1,5 @@ { - "ver": "1.0.26", + "ver": "1.0.27", "importer": "image", "imported": true, "uuid": "697e2bd1-01c2-4282-94c2-e8cf6370ca7d", diff --git a/assets/resources/game/skills/skillpng/lvup.png.meta b/assets/resources/game/skills/skillpng/lvup.png.meta index 61299ddc..e5b4027a 100644 --- a/assets/resources/game/skills/skillpng/lvup.png.meta +++ b/assets/resources/game/skills/skillpng/lvup.png.meta @@ -1,5 +1,5 @@ { - "ver": "1.0.26", + "ver": "1.0.27", "importer": "image", "imported": true, "uuid": "266933cf-0ed2-497e-98af-49472013e126", diff --git a/assets/resources/game/skills/skillpng/spup.png.meta b/assets/resources/game/skills/skillpng/spup.png.meta index 7c5797bc..5537e4d3 100644 --- a/assets/resources/game/skills/skillpng/spup.png.meta +++ b/assets/resources/game/skills/skillpng/spup.png.meta @@ -1,5 +1,5 @@ { - "ver": "1.0.26", + "ver": "1.0.27", "importer": "image", "imported": true, "uuid": "c53c26db-4847-4d14-887b-da9e1b2e748a", diff --git a/assets/resources/game/skills/skills.png.meta b/assets/resources/game/skills/skills.png.meta index c913066d..98e6f3ef 100644 --- a/assets/resources/game/skills/skills.png.meta +++ b/assets/resources/game/skills/skills.png.meta @@ -1,5 +1,5 @@ { - "ver": "1.0.26", + "ver": "1.0.27", "importer": "image", "imported": true, "uuid": "cd104e76-5215-49fe-a074-e65ffa26583e", diff --git a/assets/resources/game/skills/skills3.png.meta b/assets/resources/game/skills/skills3.png.meta index aa14d289..93139b4f 100644 --- a/assets/resources/game/skills/skills3.png.meta +++ b/assets/resources/game/skills/skills3.png.meta @@ -1,5 +1,5 @@ { - "ver": "1.0.26", + "ver": "1.0.27", "importer": "image", "imported": true, "uuid": "ebe57f11-acc7-4969-a421-464c625f2041", diff --git a/assets/resources/game/skills/skills5.png.meta b/assets/resources/game/skills/skills5.png.meta index 832dc8f1..36997807 100644 --- a/assets/resources/game/skills/skills5.png.meta +++ b/assets/resources/game/skills/skills5.png.meta @@ -1,5 +1,5 @@ { - "ver": "1.0.26", + "ver": "1.0.27", "importer": "image", "imported": true, "uuid": "5f017fb0-494a-409b-99ed-ceae143e0f6f", diff --git a/assets/resources/gui/Hinfo.prefab b/assets/resources/gui/Hinfo.prefab index 0f4a9418..f9acff36 100644 --- a/assets/resources/gui/Hinfo.prefab +++ b/assets/resources/gui/Hinfo.prefab @@ -23429,10 +23429,10 @@ "__id__": 1028 }, "templateMode": true, - "watchPath": "data.mission_data.exp", + "watchPath": "data.data.exp", "labelType": "cc.Label", "watchPathArr": [ - "data.mission_data.exp" + "data.data.exp" ], "_id": "" }, @@ -24211,10 +24211,10 @@ "__id__": 1060 }, "templateMode": true, - "watchPath": "data.mission_data.gold", + "watchPath": "data.data.gold", "labelType": "cc.Label", "watchPathArr": [ - "data.mission_data.gold" + "data.data.gold" ], "_id": "" }, diff --git a/assets/resources/gui/element/lucky.prefab b/assets/resources/gui/element/lucky.prefab index b97bb5a0..7114ade2 100644 --- a/assets/resources/gui/element/lucky.prefab +++ b/assets/resources/gui/element/lucky.prefab @@ -737,7 +737,7 @@ "__id__": 28 }, "templateMode": false, - "watchPath": "data.mission_data.gold", + "watchPath": "data.data.gold", "labelType": "cc.Label", "watchPathArr": [], "_id": "" @@ -1191,7 +1191,7 @@ "__id__": 48 }, "templateMode": false, - "watchPath": "data.mission_data.diamond", + "watchPath": "data.data.diamond", "labelType": "cc.Label", "watchPathArr": [], "_id": "" @@ -1645,7 +1645,7 @@ "__id__": 68 }, "templateMode": false, - "watchPath": "data.mission_data.mission", + "watchPath": "data.data.mission", "labelType": "cc.Label", "watchPathArr": [], "_id": "" diff --git a/assets/resources/gui/gui2.png.meta b/assets/resources/gui/gui2.png.meta index c0655ca0..3b915a90 100644 --- a/assets/resources/gui/gui2.png.meta +++ b/assets/resources/gui/gui2.png.meta @@ -1,5 +1,5 @@ { - "ver": "1.0.26", + "ver": "1.0.27", "importer": "image", "imported": true, "uuid": "486aac0a-12a3-438a-8902-c797ec07aedc", diff --git a/assets/resources/gui/items.png.meta b/assets/resources/gui/items.png.meta index 67eff48a..8ad73842 100644 --- a/assets/resources/gui/items.png.meta +++ b/assets/resources/gui/items.png.meta @@ -1,5 +1,5 @@ { - "ver": "1.0.26", + "ver": "1.0.27", "importer": "image", "imported": true, "uuid": "4ca85ea7-6d3d-4e52-bb59-e0ad41ff0599", diff --git a/assets/resources/gui/role_controller.prefab b/assets/resources/gui/role_controller.prefab index 4a858922..c65834be 100644 --- a/assets/resources/gui/role_controller.prefab +++ b/assets/resources/gui/role_controller.prefab @@ -5961,10 +5961,10 @@ "__id__": 259 }, "templateMode": true, - "watchPath": "data.mission_data.mission", + "watchPath": "data.data.mission", "labelType": "cc.Label", "watchPathArr": [ - "data.mission_data.mission" + "data.data.mission" ], "_id": "" }, @@ -15857,10 +15857,10 @@ "__id__": 691 }, "templateMode": true, - "watchPath": "data.mission_data.mission", + "watchPath": "data.data.mission", "labelType": "cc.Label", "watchPathArr": [ - "data.mission_data.mission" + "data.data.mission" ], "_id": "" }, @@ -38082,7 +38082,7 @@ "__id__": 1744 }, "templateMode": false, - "watchPath": "data.mission_data.gold", + "watchPath": "data.data.gold", "labelType": "cc.Label", "watchPathArr": [], "_id": "" @@ -38536,7 +38536,7 @@ "__id__": 1764 }, "templateMode": false, - "watchPath": "data.mission_data.diamond", + "watchPath": "data.data.diamond", "labelType": "cc.Label", "watchPathArr": [], "_id": "" @@ -38990,7 +38990,7 @@ "__id__": 1784 }, "templateMode": false, - "watchPath": "data.mission_data.meat", + "watchPath": "data.data.meat", "labelType": "cc.Label", "watchPathArr": [], "_id": "" diff --git a/assets/resources/gui/ui1.png.meta b/assets/resources/gui/ui1.png.meta index c763ce7d..b442c582 100644 --- a/assets/resources/gui/ui1.png.meta +++ b/assets/resources/gui/ui1.png.meta @@ -1,5 +1,5 @@ { - "ver": "1.0.26", + "ver": "1.0.27", "importer": "image", "imported": true, "uuid": "b2d8f297-8058-482c-a848-956b5594d717", diff --git a/assets/resources/gui/ui2.png.meta b/assets/resources/gui/ui2.png.meta index a415e5bf..7594439b 100644 --- a/assets/resources/gui/ui2.png.meta +++ b/assets/resources/gui/ui2.png.meta @@ -1,5 +1,5 @@ { - "ver": "1.0.26", + "ver": "1.0.27", "importer": "image", "imported": true, "uuid": "f42b9fb1-b246-4d57-8733-31a1365729a6", diff --git a/assets/resources/language/TFat.png.meta b/assets/resources/language/TFat.png.meta index 5c080d6b..5c85ab5a 100644 --- a/assets/resources/language/TFat.png.meta +++ b/assets/resources/language/TFat.png.meta @@ -1,5 +1,5 @@ { - "ver": "1.0.26", + "ver": "1.0.27", "importer": "image", "imported": true, "uuid": "4e4d1811-5bd5-4b5d-9535-a118dc3c970f", @@ -129,6 +129,6 @@ "type": "sprite-frame", "hasAlpha": true, "fixAlphaTransparencyArtifacts": false, - "redirect": "4e4d1811-5bd5-4b5d-9535-a118dc3c970f@f9941" + "redirect": "4e4d1811-5bd5-4b5d-9535-a118dc3c970f@6c48a" } } diff --git a/assets/resources/language/texture/en/image.jpg.meta b/assets/resources/language/texture/en/image.jpg.meta index ef129c29..399c097d 100644 --- a/assets/resources/language/texture/en/image.jpg.meta +++ b/assets/resources/language/texture/en/image.jpg.meta @@ -1,5 +1,5 @@ { - "ver": "1.0.26", + "ver": "1.0.27", "importer": "image", "imported": true, "uuid": "3d5b607a-face-426b-8200-acf8384108db", @@ -128,7 +128,7 @@ "userData": { "hasAlpha": true, "type": "sprite-frame", - "redirect": "3d5b607a-face-426b-8200-acf8384108db@f9941", + "redirect": "3d5b607a-face-426b-8200-acf8384108db@6c48a", "fixAlphaTransparencyArtifacts": false } } diff --git a/assets/resources/language/texture/zh/image.jpg.meta b/assets/resources/language/texture/zh/image.jpg.meta index b60e8062..444eca05 100644 --- a/assets/resources/language/texture/zh/image.jpg.meta +++ b/assets/resources/language/texture/zh/image.jpg.meta @@ -1,5 +1,5 @@ { - "ver": "1.0.26", + "ver": "1.0.27", "importer": "image", "imported": true, "uuid": "a65eaaec-d315-4134-a79e-23bb817d1939", @@ -128,7 +128,7 @@ "userData": { "hasAlpha": true, "type": "sprite-frame", - "redirect": "a65eaaec-d315-4134-a79e-23bb817d1939@f9941", + "redirect": "a65eaaec-d315-4134-a79e-23bb817d1939@6c48a", "fixAlphaTransparencyArtifacts": false } } diff --git a/assets/script/Design.md.meta b/assets/script/Design.md.meta index 259c1262..caf18712 100644 --- a/assets/script/Design.md.meta +++ b/assets/script/Design.md.meta @@ -1,5 +1,5 @@ { - "ver": "1.0.2", + "ver": "1.0.1", "importer": "text", "imported": true, "uuid": "ecad0109-344e-47b2-aaa9-ee5902b9b016", diff --git a/assets/script/Main.ts b/assets/script/Main.ts index 9cc63fa8..53aa5219 100644 --- a/assets/script/Main.ts +++ b/assets/script/Main.ts @@ -12,13 +12,12 @@ import { WxCloudApi } from './game/wx_clound_client_api/WxCloudApi'; const { ccclass, property } = _decorator; -// WxCloudApi.init("cloud1-6gknw0qk911036d8") @ccclass('Main') export class Main extends Root { start() { - if(this.isWxClient()){ - WxCloudApi.init("cloud1-6gknw0qk911036d8") - } + // if(this.isWxClient()){ + // WxCloudApi.init("cloud1-6gknw0qk911036d8") + // } PhysicsSystem2D.instance.debugDrawFlags = EPhysics2DDrawFlags.Aabb | EPhysics2DDrawFlags.Pair // EPhysics2DDrawFlags.CenterOfMass | diff --git a/assets/script/Main.ts.meta b/assets/script/Main.ts.meta index f215f20b..0b9ee9c3 100644 --- a/assets/script/Main.ts.meta +++ b/assets/script/Main.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "0eec0b38-aab6-45ee-89cf-95806b0fecbe", diff --git a/assets/script/game/BezierMove/BezierMove.ts.meta b/assets/script/game/BezierMove/BezierMove.ts.meta index 19b7ff4d..d6d89747 100644 --- a/assets/script/game/BezierMove/BezierMove.ts.meta +++ b/assets/script/game/BezierMove/BezierMove.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "f680d91a-831f-4f99-b7ea-b45e3adff51a", diff --git a/assets/script/game/common/GameDataSyncManager.ts b/assets/script/game/common/GameDataSyncManager.ts new file mode 100644 index 00000000..e0305942 --- /dev/null +++ b/assets/script/game/common/GameDataSyncManager.ts @@ -0,0 +1,568 @@ +import { WxCloudApi ,UserGameData} from "../wx_clound_client_api/WxCloudApi"; +import { smc } from "./SingletonModuleComp"; + +/** + * 游戏数据同步管理器 + * 负责管理fight_heros、heros、items、tals、equips的远程操作和本地同步 + * 只有在远程修改成功后才同步修改本地数据 + */ +export class GameDataSyncManager { + private static instance: GameDataSyncManager; + + private constructor() {} + + public static getInstance(): GameDataSyncManager { + if (!GameDataSyncManager.instance) { + GameDataSyncManager.instance = new GameDataSyncManager(); + } + return GameDataSyncManager.instance; + } + + /** + * 用远程数据覆盖本地数据(统一方法) + * @param remoteData 远程数据(云端或本地调试) + * @param dataSource 数据源描述 + */ + async overrideLocalDataWithRemote(remoteData: UserGameData, dataSource: string) { + try { + console.log(`[Initialize]: 开始用${dataSource}数据覆盖客户端数据...`); + + // 直接覆盖基础游戏数据 + if (remoteData.data) { + Object.assign(smc.data, remoteData.data); + console.log(`[Initialize]: 基础游戏数据已从${dataSource}覆盖`); + } + + // 直接覆盖出战英雄配置 + if (remoteData.fight_heros) { + Object.assign(smc.fight_heros, remoteData.fight_heros); + console.log(`[Initialize]: 出战英雄配置已从${dataSource}覆盖`); + } + + // 直接覆盖英雄数据 + if (remoteData.heros) { + smc.heros = { ...remoteData.heros }; + console.log(`[Initialize]: 英雄数据已从${dataSource}覆盖`); + } + + // 直接覆盖道具数据 + if (remoteData.items) { + Object.assign(smc.itmes, remoteData.items); + console.log(`[Initialize]: 道具数据已从${dataSource}覆盖`); + } + + // 直接覆盖天赋数据 + if (remoteData.tals) { + Object.assign(smc.tals, remoteData.tals); + console.log(`[Initialize]: 天赋数据已从${dataSource}覆盖`); + } + + // 直接覆盖装备数据 + if (remoteData.equips) { + Object.assign(smc.equips, remoteData.equips); + console.log(`[Initialize]: 装备数据已从${dataSource}覆盖`); + } + + // 同步ViewModel数据 + smc.syncData(); + + // 保存到本地存储(确保数据持久化) + // smc.saveGameData(); + + console.log(`[Initialize]: ${dataSource}数据覆盖完成,已保存到本地`); + + } catch (error) { + console.error(`[Initialize]: ${dataSource}数据覆盖失败:`, error); + } +} + /** + * 批量更新出战英雄配置 + * @param fightHeros 出战英雄配置对象 + * @returns 是否成功 + */ + async updateFightHeros(fightHeros: any): Promise { + try { + console.log(`[GameDataSyncManager]: 批量更新出战英雄配置:`, fightHeros); + + const result = await WxCloudApi.updateFightHeros(fightHeros); + + if (result.result.code === 200) { + // 远程修改成功,同步本地数据 + Object.assign(smc.fight_heros, fightHeros); + console.log(`[GameDataSyncManager]: 出战英雄配置更新成功,本地数据已同步`); + return true; + } else { + console.warn(`[GameDataSyncManager]: 出战英雄配置更新失败: ${result.result.msg}`); + return false; + } + } catch (error) { + console.error(`[GameDataSyncManager]: 更新出战英雄配置异常:`, error); + return false; + } + } + + + /** + * 重置出战英雄配置为默认值 + * @returns 是否成功 + */ + async resetFightHeros(): Promise { + try { + console.log(`[GameDataSyncManager]: 重置出战英雄配置`); + + const result = await WxCloudApi.resetFightHeros(); + + if (result.result.code === 200) { + // 远程修改成功,同步本地数据 + smc.fight_heros = result.result.data; + console.log(`[GameDataSyncManager]: 出战英雄配置重置成功,本地数据已同步`); + return true; + } else { + console.warn(`[GameDataSyncManager]: 出战英雄配置重置失败: ${result.result.msg}`); + return false; + } + } catch (error) { + console.error(`[GameDataSyncManager]: 重置出战英雄配置异常:`, error); + return false; + } + } + + // ==================== 英雄管理 ==================== + + /** + * 添加新英雄到用户库存 + * @param heroId 英雄ID + * @param heroData 英雄数据(可选) + * @returns 是否成功 + */ + async addHero(heroId: number, heroData?: any): Promise { + try { + console.log(`[GameDataSyncManager]: 添加英雄 ID:${heroId}, 数据:`, heroData); + + const result = await WxCloudApi.addHero(heroId, heroData); + + if (result.result.code === 200) { + // 远程修改成功,同步本地数据 + smc.heros[heroId] = result.result.data; + console.log(`[GameDataSyncManager]: 英雄添加成功,本地数据已同步`); + return true; + } else { + console.warn(`[GameDataSyncManager]: 英雄添加失败: ${result.result.msg}`); + return false; + } + } catch (error) { + console.error(`[GameDataSyncManager]: 添加英雄异常:`, error); + return false; + } + } + + /** + * 更新英雄的多个属性 + * @param heroId 英雄ID + * @param updateData 要更新的属性 + * @returns 是否成功 + */ + async updateHero(heroId: number, updateData: any): Promise { + try { + console.log(`[GameDataSyncManager]: 更新英雄 ID:${heroId}, 更新数据:`, updateData); + + const result = await WxCloudApi.updateHero(heroId, updateData); + + if (result.result.code === 200) { + // 远程修改成功,同步本地数据 + Object.assign(smc.heros[heroId], result.result.data.new_data); + console.log(`[GameDataSyncManager]: 英雄更新成功,本地数据已同步`); + return true; + } else { + console.warn(`[GameDataSyncManager]: 英雄更新失败: ${result.result.msg}`); + return false; + } + } catch (error) { + console.error(`[GameDataSyncManager]: 更新英雄异常:`, error); + return false; + } + } + + /** + * 设置英雄的单个属性值 + * @param heroId 英雄ID + * @param property 属性名 + * @param value 属性值 + * @returns 是否成功 + */ + async setHeroProperty(heroId: number, property: any, value: any): Promise { + try { + console.log(`[GameDataSyncManager]: 设置英雄属性 ID:${heroId}, 属性:${property}, 值:${value}`); + + const result = await WxCloudApi.setHeroProperty(heroId, property, value); + + if (result.result.code === 200) { + // 远程修改成功,同步本地数据 + smc.heros[heroId][property] = value; + console.log(`[GameDataSyncManager]: 英雄属性设置成功,本地数据已同步`); + return true; + } else { + console.warn(`[GameDataSyncManager]: 英雄属性设置失败: ${result.result.msg}`); + return false; + } + } catch (error) { + console.error(`[GameDataSyncManager]: 设置英雄属性异常:`, error); + return false; + } + } + + /** + * 英雄升级指定级数 + * @param heroId 英雄ID + * @param levels 升级级数(默认1级) + * @returns 是否成功 + */ + async levelUpHero(heroId: number, exp:number,gold:number,levels: number = 1,): Promise { + try { + console.log(`[GameDataSyncManager]: 英雄升级 ID:${heroId}, 级数:${levels}`); + + const result = await WxCloudApi.levelUpHero(heroId, exp,gold,levels); + + if (result.result.code === 200) { + // 远程修改成功,同步本地数据 + smc.heros[heroId].lv = result.result.data.new_value; + console.log(`[GameDataSyncManager]: 英雄升级成功,本地数据已同步`); + return true; + } else { + console.warn(`[GameDataSyncManager]: 英雄升级失败: ${result.result.msg}`); + return false; + } + } catch (error) { + console.error(`[GameDataSyncManager]: 英雄升级异常:`, error); + return false; + } + } + + /** + * 删除指定英雄 + * @param heroId 英雄ID + * @returns 是否成功 + */ + async deleteHero(heroId: number): Promise { + try { + console.log(`[GameDataSyncManager]: 删除英雄 ID:${heroId}`); + + const result = await WxCloudApi.deleteHero(heroId); + + if (result.result.code === 200) { + // 远程修改成功,同步本地数据 + delete smc.heros[heroId]; + console.log(`[GameDataSyncManager]: 英雄删除成功,本地数据已同步`); + return true; + } else { + console.warn(`[GameDataSyncManager]: 英雄删除失败: ${result.result.msg}`); + return false; + } + } catch (error) { + console.error(`[GameDataSyncManager]: 删除英雄异常:`, error); + return false; + } + } + + // ==================== 库存管理 (items, tals, equips) ==================== + + /** + * 增加指定物品的数量 + * @param type 库存类型 ('items', 'tals', 'equips') + * @param itemId 物品ID + * @param count 添加数量 + * @returns 是否成功 + */ + async addInventoryItem(type: 'items' | 'tals' | 'equips', itemId: number, count: number): Promise { + try { + console.log(`[GameDataSyncManager]: 增加库存物品 类型:${type}, ID:${itemId}, 数量:${count}`); + + const result = await WxCloudApi.addInventoryItem(type, itemId, count); + + if (result.result.code === 200) { + // 远程修改成功,同步本地数据 + const targetData = this.getTargetData(type); + targetData[itemId] = (targetData[itemId] || 0) + count; + console.log(`[GameDataSyncManager]: 库存物品增加成功,本地数据已同步`); + return true; + } else { + console.warn(`[GameDataSyncManager]: 库存物品增加失败: ${result.result.msg}`); + return false; + } + } catch (error) { + console.error(`[GameDataSyncManager]: 增加库存物品异常:`, error); + return false; + } + } + + /** + * 消耗指定数量的物品 + * @param type 库存类型 ('items', 'tals', 'equips') + * @param itemId 物品ID + * @param count 消耗数量 + * @returns 是否成功 + */ + async consumeInventoryItem(type: 'items' | 'tals' | 'equips', itemId: number, count: number): Promise { + try { + console.log(`[GameDataSyncManager]: 消耗库存物品 类型:${type}, ID:${itemId}, 数量:${count}`); + + const result = await WxCloudApi.consumeInventoryItem(type, itemId, count); + + if (result.result.code === 200) { + // 远程修改成功,同步本地数据 + const targetData = this.getTargetData(type); + targetData[itemId] = Math.max(0, (targetData[itemId] || 0) - count); + console.log(`[GameDataSyncManager]: 库存物品消耗成功,本地数据已同步`); + return true; + } else { + console.warn(`[GameDataSyncManager]: 库存物品消耗失败: ${result.result.msg}`); + return false; + } + } catch (error) { + console.error(`[GameDataSyncManager]: 消耗库存物品异常:`, error); + return false; + } + } + + /** + * 直接设置物品的数量 + * @param type 库存类型 ('items', 'tals', 'equips') + * @param itemId 物品ID + * @param count 新的数量 + * @returns 是否成功 + */ + async setInventoryItem(type: 'items' | 'tals' | 'equips', itemId: number, count: number): Promise { + try { + console.log(`[GameDataSyncManager]: 设置库存物品 类型:${type}, ID:${itemId}, 数量:${count}`); + + const result = await WxCloudApi.setInventoryItem(type, itemId, count); + + if (result.result.code === 200) { + // 远程修改成功,同步本地数据 + const targetData = this.getTargetData(type); + targetData[itemId] = count; + console.log(`[GameDataSyncManager]: 库存物品设置成功,本地数据已同步`); + return true; + } else { + console.warn(`[GameDataSyncManager]: 库存物品设置失败: ${result.result.msg}`); + return false; + } + } catch (error) { + console.error(`[GameDataSyncManager]: 设置库存物品异常:`, error); + return false; + } + } + + /** + * 批量更新多个物品的数量 + * @param type 库存类型 ('items', 'tals', 'equips') + * @param data 更新数据对象 + * @param merge 是否合并更新(默认true) + * @returns 是否成功 + */ + async updateInventory(type: 'items' | 'tals' | 'equips', data: any, merge: boolean = true): Promise { + try { + console.log(`[GameDataSyncManager]: 批量更新库存 类型:${type}, 数据:`, data); + + const result = await WxCloudApi.updateInventory(type, data, merge); + + if (result.result.code === 200) { + // 远程修改成功,同步本地数据 + const targetData = this.getTargetData(type); + if (merge) { + Object.assign(targetData, data); + } else { + Object.keys(targetData).forEach(key => delete targetData[key]); + Object.assign(targetData, data); + } + console.log(`[GameDataSyncManager]: 库存批量更新成功,本地数据已同步`); + return true; + } else { + console.warn(`[GameDataSyncManager]: 库存批量更新失败: ${result.result.msg}`); + return false; + } + } catch (error) { + console.error(`[GameDataSyncManager]: 批量更新库存异常:`, error); + return false; + } + } + + /** + * 重置指定类型的库存为默认值 + * @param type 库存类型 ('items', 'tals', 'equips') + * @returns 是否成功 + */ + async resetInventory(type: 'items' | 'tals' | 'equips'): Promise { + try { + console.log(`[GameDataSyncManager]: 重置库存 类型:${type}`); + + const result = await WxCloudApi.resetInventory(type); + + if (result.result.code === 200) { + // 远程修改成功,同步本地数据 + const targetData = this.getTargetData(type); + Object.keys(targetData).forEach(key => delete targetData[key]); + Object.assign(targetData, result.result.data); + console.log(`[GameDataSyncManager]: 库存重置成功,本地数据已同步`); + return true; + } else { + console.warn(`[GameDataSyncManager]: 库存重置失败: ${result.result.msg}`); + return false; + } + } catch (error) { + console.error(`[GameDataSyncManager]: 重置库存异常:`, error); + return false; + } + } + + // ==================== 便捷方法 ==================== + + /** + * 增加道具 + * @param itemId 道具ID + * @param count 数量 + * @returns 是否成功 + */ + async addItem(itemId: number, count: number): Promise { + return this.addInventoryItem('items', itemId, count); + } + + /** + * 消耗道具 + * @param itemId 道具ID + * @param count 数量 + * @returns 是否成功 + */ + async consumeItem(itemId: number, count: number): Promise { + return this.consumeInventoryItem('items', itemId, count); + } + + /** + * 增加天赋点 + * @param talId 天赋ID + * @param count 数量 + * @returns 是否成功 + */ + async addTalent(talId: number, count: number): Promise { + return this.addInventoryItem('tals', talId, count); + } + + /** + * 消耗天赋点 + * @param talId 天赋ID + * @param count 数量 + * @returns 是否成功 + */ + async consumeTalent(talId: number, count: number): Promise { + return this.consumeInventoryItem('tals', talId, count); + } + + /** + * 增加装备 + * @param equipId 装备ID + * @param count 数量 + * @returns 是否成功 + */ + async addEquipment(equipId: number, count: number): Promise { + return this.addInventoryItem('equips', equipId, count); + } + + /** + * 消耗装备 + * @param equipId 装备ID + * @param count 数量 + * @returns 是否成功 + */ + async consumeEquipment(equipId: number, count: number): Promise { + return this.consumeInventoryItem('equips', equipId, count); + } + + // ==================== 私有辅助方法 ==================== + + /** + * 根据类型获取对应的目标数据对象 + * @param type 库存类型 + * @returns 对应的数据对象 + */ + private getTargetData(type: 'items' | 'tals' | 'equips'): any { + switch (type) { + case 'items': + return smc.itmes; + case 'tals': + return smc.tals; + case 'equips': + return smc.equips; + default: + throw new Error(`未知的库存类型: ${type}`); + } + } + + /** + * 从云端加载所有游戏数据并同步到本地 + * @returns 是否成功 + */ + async loadAllGameData(): Promise { + try { + console.log(`[GameDataSyncManager]: 从云端加载所有游戏数据`); + + const result = await WxCloudApi.getAllGameData(); + + if (result.result.code === 200) { + // 远程数据获取成功,同步本地数据 + const cloudData = result.result.data; + smc.data = cloudData.data; + smc.fight_heros = cloudData.fight_heros; + smc.heros = cloudData.heros; + smc.itmes = cloudData.items; + smc.tals = cloudData.tals; + smc.equips = cloudData.equips; + + // 同步vmdata + smc.syncData(); + + console.log(`[GameDataSyncManager]: 云端数据加载成功,本地数据已同步`); + return true; + } else { + console.warn(`[GameDataSyncManager]: 云端数据加载失败: ${result.result.msg}`); + return false; + } + } catch (error) { + console.error(`[GameDataSyncManager]: 加载云端数据异常:`, error); + return false; + } + } +} + + + + + + +// 导出单例实例 +export const gameDataSyncManager = GameDataSyncManager.getInstance(); + +/* +使用示例: + +// 1. 出战英雄管理 +await gameDataSyncManager.setFightHero(0, 5001); // 设置位置0的英雄 +await gameDataSyncManager.swapFightHeros(0, 1); // 交换位置0和1的英雄 +await gameDataSyncManager.updateFightHeros({0: 5001, 1: 5005}); // 批量更新 + +// 2. 英雄管理 +await gameDataSyncManager.addHero(5008, {uuid: 5008, lv: 1}); // 添加新英雄 +await gameDataSyncManager.levelUpHero(5001, 5); // 英雄升级5级 +await gameDataSyncManager.setHeroProperty(5001, "exp", 1000); // 设置英雄经验 + +// 3. 库存管理 +await gameDataSyncManager.addItem(1001, 10); // 增加道具 +await gameDataSyncManager.consumeItem(1001, 2); // 消耗道具 +await gameDataSyncManager.addTalent(2001, 5); // 增加天赋点 +await gameDataSyncManager.addEquipment(3001, 2); // 增加装备 + +// 4. 数据加载 +await gameDataSyncManager.loadAllGameData(); // 从云端加载所有数据 + +注意:所有方法都返回 Promise,true表示成功,false表示失败 +只有在远程修改成功后,本地数据才会被同步修改 +*/ diff --git a/assets/script/game/common/GameDataSyncManager.ts.meta b/assets/script/game/common/GameDataSyncManager.ts.meta new file mode 100644 index 00000000..53c176c7 --- /dev/null +++ b/assets/script/game/common/GameDataSyncManager.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.24", + "importer": "typescript", + "imported": true, + "uuid": "89c45a3b-d0bf-4e45-9e27-b7d714ba7e29", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/common/SingletonModuleComp.ts b/assets/script/game/common/SingletonModuleComp.ts index 26e0f1e4..9d1821ad 100644 --- a/assets/script/game/common/SingletonModuleComp.ts +++ b/assets/script/game/common/SingletonModuleComp.ts @@ -4,6 +4,10 @@ import { Initialize } from "../initialize/Initialize"; import { GameMap } from "../map/GameMap"; import { HeroUI, VmInfo } from "./config/Mission"; import { oops } from "../../../../extensions/oops-plugin-framework/assets/core/Oops"; +import { WxCloudApi } from "../wx_clound_client_api/WxCloudApi"; +import { gameDataSyncManager } from "./GameDataSyncManager"; +import { GameSet } from "./config/BoxSet"; +import { Test } from "./Test"; // import { Role } from "../role/Role"; @@ -15,6 +19,8 @@ export class SingletonModuleComp extends ecs.Comp { initialize: Initialize = null!; /** 游戏地图 */ map: GameMap = null!; + /** 游戏数据同步管理器 */ + private gameDataSyncManager = gameDataSyncManager; mission:any={ status:0, //0:未开始 1:进行中 2:胜利 3:失败 play:false, @@ -37,21 +43,19 @@ export class SingletonModuleComp extends ecs.Comp { ckey:0, //铜钥匙 解锁稀有英雄 也可以直接兑换金币 skey:0, //银钥匙 解锁史诗英雄 也可以直接兑换金币 gkey:0, //金钥匙 解锁传说英雄 也可以直接兑换金币 - - } - fight_heros:any={ - 0:5001, - 1:5005, - 2:0, - 3:0, - 4:0, } + fight_heros:any={ 0:5001, 1:5005, 2:0, 3:0, 4:0, } heros:any = { 5001:{uuid:5001,lv:1}, 5005:{uuid:5005,lv:1}, 5007:{uuid:5007,lv:1}, }; - + itmes:any={ + } + tals:any={ + } + equips:any={ + } monsters:any = []; sk_info:any = [] monsters_dead:any = [] @@ -60,32 +64,46 @@ export class SingletonModuleComp extends ecs.Comp { vmdata: any = { game_over:false, game_pause:false, + data:{ + score:0, + mission:1, + gold:100, //升级主要资源 + diamond:100, //商店购买 及 双倍奖励资源 + meat:0, + exp:0, //升级经验 + ghstone:0, //英雄石 绿色 普通英雄升星 + bhstone:0, //英雄石 蓝色 稀有英雄升星 + phlestone:0, //英雄石 紫色 史诗英雄升星 + rhstone:0, //英雄石 红色 传说英雄升星 + herocard:0, //英雄卡,抽卡凭证 + ckey:0, //铜钥匙 解锁稀有英雄 也可以直接兑换金币 + skey:0, //银钥匙 解锁史诗英雄 也可以直接兑换金币 + gkey:0, //金钥匙 解锁传说英雄 也可以直接兑换金币 + }, mission_data:{ - gold:1000,//金币 - exp:0,//经验 - score:0,//分数 - diamond:0,//钻石 - mission:1,//关卡 - chapter:1,//章节 - level:1,//关卡等级 - max_mission:4,//最大关卡 - meat:0,//肉 mon_num:0,//怪物数量 hero_num:0,//英雄数量 wave_time_num:0,//波次时间 in_fight:false, fight_time:0,//战斗时间 + level:1,//关卡等级 + max_mission:4,//最大关卡 }, reward:{ - gold:0, - meat:0, - diamond:0, score:0, - exp:0, - gcard:0, - bcard:0, - pcard:0, - ycard:0, + mission:0, + gold:0, //升级主要资源 + diamond:0, //商店购买 及 双倍奖励资源 + meat:0, + exp:0, //升级经验 + ghstone:0, //英雄石 绿色 普通英雄升星 + bhstone:0, //英雄石 蓝色 稀有英雄升星 + phlestone:0, //英雄石 紫色 史诗英雄升星 + rhstone:0, //英雄石 红色 传说英雄升星 + herocard:0, //英雄卡,抽卡凭证 + ckey:0, //铜钥匙 解锁稀有英雄 也可以直接兑换金币 + skey:0, //银钥匙 解锁史诗英雄 也可以直接兑换金币 + gkey:0, //金钥匙 解锁传说英雄 也可以直接兑换金币 } }; vmAdd() { @@ -97,483 +115,97 @@ export class SingletonModuleComp extends ecs.Comp { } } - // ==================== 本地存储管理方法 ==================== - - /** - * 初始化默认游戏数据 - */ - initDefaultData() { - // 确保出战英雄有默认值 - if (!this.fight_heros || Object.keys(this.fight_heros).length === 0) { - this.fight_heros = { - 0: 5001, - 1: 5005, - 2: 0, - 3: 0, - 4: 0, - }; - } - - // 确保英雄属性有默认值 - if (!this.heros || Object.keys(this.heros).length === 0) { - this.heros = { - 5001: {lv: 1}, - 5005: {lv: 1}, - 5007: {lv: 1}, - }; - } - - // 确保游戏数据有默认值 - if (!this.data || Object.keys(this.data).length === 0) { - this.data = { - score: 888, - mission: 1, - gold: 100, - diamond: 100, - }; - } - - console.log("[SMC]: 默认数据已初始化 - 出战英雄:", this.fight_heros, "英雄属性:", this.heros, "游戏数据:", this.data); - } - - /** - * 保存游戏数据到本地存储 - */ - saveGameData() { - try { - // 保存出战英雄数据 - const fightHerosJson = JSON.stringify(this.fight_heros); - oops.storage.set("fight_heros", fightHerosJson); - - // 保存英雄属性数据 - const herosJson = JSON.stringify(this.heros); - oops.storage.set("heros", herosJson); - - // 保存游戏数据(金币、钻石等) - const dataJson = JSON.stringify(this.data); - oops.storage.set("game_data", dataJson); - - console.log("[SMC]: 游戏数据已保存 - 出战英雄:", this.fight_heros, "英雄属性:", this.heros, "游戏数据:", this.data); - return true; - } catch (error) { - console.error("[SMC]: 保存游戏数据失败:", error); - return false; - } - } - - /** - * 保存英雄数据到本地存储(兼容旧方法名) - */ - saveHeroData() { - return this.saveGameData(); - } - - /** - * 从本地存储加载游戏数据 - */ - loadGameData() { - console.log("[SMC]: 加载游戏数据") - try { - let hasAnyData = false; - - // 加载出战英雄数据 - const savedFightHeros = oops.storage.get("fight_heros"); - if (savedFightHeros && savedFightHeros !== "") { - const fightHerosData = JSON.parse(savedFightHeros); - this.fight_heros = fightHerosData; - console.log("[SMC]: 从本地加载出战英雄数据:", fightHerosData); - hasAnyData = true; - } else { - console.log("[SMC]: 未找到本地出战英雄数据,使用默认配置"); - } - - // 加载英雄属性数据 - const savedHeros = oops.storage.get("heros"); - if (savedHeros && savedHeros !== "") { - const herosData = JSON.parse(savedHeros); - this.heros = herosData; - console.log("[SMC]: 从本地加载英雄属性数据:", herosData); - hasAnyData = true; - } else { - console.log("[SMC]: 未找到本地英雄属性数据,使用默认配置"); - } - - // 加载游戏数据 - const savedData = oops.storage.get("game_data"); - if (savedData && savedData !== "") { - const gameData = JSON.parse(savedData); - this.data = gameData; - console.log("[SMC]: 从本地加载游戏数据:", gameData); - hasAnyData = true; - } else { - console.log("[SMC]: 未找到本地游戏数据,使用默认配置"); - } - - // 如果没有任何本地数据,说明是首次启动,初始化并保存默认数据 - if (!hasAnyData) { - console.log("[SMC]: 首次启动,初始化默认游戏数据"); - this.initDefaultData(); - this.saveGameData(); - return true; // 首次启动也算成功 - } - - return hasAnyData; - } catch (error) { - console.error("[SMC]: 加载游戏数据失败:", error); - return false; - } - } - - /** - * 从本地存储加载英雄数据(兼容旧方法名) - */ - loadHeroData() { - return this.loadGameData(); - } - - /** - * 设置出战英雄 - * @param position 出战位置 (0-4) - * @param heroId 英雄ID,0表示移除 - * @param autoSave 是否自动保存 (默认true) - */ - setFightHero(position: number, heroId: number, autoSave: boolean = true) { - if (position < 0 || position > 4) { - console.warn("[SMC]: 出战位置无效:", position); - return false; - } - - this.fight_heros[position] = heroId; - console.log(`[SMC]: 设置出战位置${position} -> 英雄${heroId}`); - - if (autoSave) { - this.saveGameData(); - } - return true; - } - - /** - * 获取出战英雄ID - * @param position 出战位置 (0-4) - */ - getFightHero(position: number): number { - if (position < 0 || position > 4) { - console.warn("[SMC]: 出战位置无效:", position); - return 0; - } - return this.fight_heros[position] || 0; - } - - /** - * 获取当前出战英雄列表(不包含空位) - */ - getActiveFightHeros(): number[] { - const activeHeros: number[] = []; - for (let i = 0; i < 5; i++) { - const heroId = this.fight_heros[i]; - if (heroId && heroId > 0) { - activeHeros.push(heroId); - } - } - return activeHeros; - } - - /** - * 设置英雄属性 - * @param heroId 英雄ID - * @param property 属性名 (如: lv, exp等) - * @param value 属性值 - * @param autoSave 是否自动保存 (默认true) - */ - setHeroProperty(heroId: number, property: string, value: any, autoSave: boolean = true) { - if (!this.heros[heroId]) { - this.heros[heroId] = {}; - } - - this.heros[heroId][property] = value; - console.log(`[SMC]: 设置英雄${heroId}的${property} = ${value}`); - - if (autoSave) { - this.saveGameData(); - } - } - - /** - * 获取英雄属性 - * @param heroId 英雄ID - * @param property 属性名 - * @param defaultValue 默认值 - */ - getHeroProperty(heroId: number, property: string, defaultValue: any = null): any { - if (!this.heros[heroId]) { - return defaultValue; - } - return this.heros[heroId][property] !== undefined ? this.heros[heroId][property] : defaultValue; - } - - /** - * 英雄升级 - * @param heroId 英雄ID - * @param levels 升级级数 (默认1级) - * @param autoSave 是否自动保存 (默认true) - */ - levelUpHero(heroId: number, levels: number = 1, autoSave: boolean = true) { - const currentLevel = this.getHeroProperty(heroId, "lv", 1); - const newLevel = currentLevel + levels; - this.setHeroProperty(heroId, "lv", newLevel, autoSave); - console.log(`[SMC]: 英雄${heroId}升级: ${currentLevel} -> ${newLevel}`); - } - getHasHeroUUID() { - return Object.keys(this.heros).map(Number) - } - /** - * 获取英雄等级 - * @param heroId 英雄ID - */ - getHeroLevel(heroId: number): number { - return this.getHeroProperty(heroId, "lv", 1); - } - - /** - * 清除所有本地存储数据 - */ - clearAllSaveData() { - try { - oops.storage.remove("fight_heros"); - oops.storage.remove("heros"); - oops.storage.remove("game_data"); - console.log("[SMC]: 已清除所有本地存储数据"); - return true; - } catch (error) { - console.error("[SMC]: 清除存储数据失败:", error); - return false; - } - } - - /** - * 重置英雄数据为默认值 - * @param autoSave 是否自动保存 (默认true) - */ - resetHeroData(autoSave: boolean = true) { - // 重置为默认出战英雄 - this.fight_heros = { - 0: 5001, - 1: 5005, - 2: 0, - 3: 0, - 4: 0, - }; - - // 重置为默认英雄属性 - this.heros = { - 5001: {lv: 1}, - 5005: {lv: 1}, - 5007: {lv: 1}, - }; - - console.log("[SMC]: 英雄数据已重置为默认值"); - - if (autoSave) { - this.saveGameData(); - } - } - - // ==================== 游戏数据管理方法 ==================== - - /** - * 设置游戏数据属性 - * @param property 属性名 (如: score, mission, gold, diamond) - * @param value 属性值 - * @param autoSave 是否自动保存 (默认true) - */ - setGameProperty(property: string, value: any, autoSave: boolean = true) { - this.data[property] = value; - this.vmdata.mission_data[property] = value; - console.log(`[SMC]: 设置游戏数据 ${property} = ${value}`); - if (autoSave) { - this.saveGameData(); - } - } - addGameProperty(property: string, value: any, autoSave: boolean = true) { - this.data[property] = this.data[property] + value; - this.vmdata.mission_data[property] = this.data[property] - console.log(`[SMC]:增加游戏数据 ${property} = ${value}`); - if (autoSave) { - this.saveGameData(); - } - } - spendGameProperty(property: string, value: any, autoSave: boolean = true) { - this.data[property] = this.data[property] - value; - this.vmdata.mission_data[property] = this.data[property] - console.log(`[SMC]: 消耗游戏数据 ${property} = ${value}`); - if (autoSave) { - this.saveGameData(); - } - } - /** - * 获取游戏数据属性 - * @param property 属性名 - * @param defaultValue 默认值 - */ - getGameProperty(property: string, defaultValue: any = null): any { - return this.data[property] !== undefined ? this.data[property] : defaultValue; - } - - - syncData(){ - this.vmdata.mission_data.gold=this.getGameProperty("gold", 0) - this.vmdata.mission_data.meat=this.getGameProperty("meat", 0) - this.vmdata.mission_data.diamond=this.getGameProperty("diamond", 0) - this.vmdata.mission_data.mission=this.getGameProperty("mission", 1) - this.vmdata.mission_data.score=this.getGameProperty("score", 0) - this.vmdata.mission_data.exp=this.getGameProperty("exp", 0) - // // 计算章节和关卡等级 - // const currentMission = this.getGameProperty("mission", 1) - // this.vmdata.mission_data.chapter = Math.floor((currentMission - 1) / 10) + 1 - // this.vmdata.mission_data.level = ((currentMission - 1) % 10) + 1 - } - initReward(){ - this.vmdata.reward.gold=0 - this.vmdata.reward.meat=0 - this.vmdata.reward.diamond=0 - this.vmdata.reward.score=0 - this.vmdata.reward.exp=0 - this.vmdata.reward.gcard=0 - this.vmdata.reward.bcard=0 - this.vmdata.reward.pcard=0 - this.vmdata.reward.ycard=0 - } - /** - * 增加金币 - * @param amount 金币数量 - * @param autoSave 是否自动保存 (默认true) - */ - addGold(amount: number, autoSave: boolean = true) { - const currentGold = this.getGameProperty("gold", 0); - const newGold = Math.max(0, currentGold + amount); - this.setGameProperty("gold", newGold, autoSave); - console.log(`[SMC]: 金币变更: ${currentGold} -> ${newGold} (${amount > 0 ? '+' : ''}${amount})`); - return newGold; - } + // ==================== 数据管理方法 ==================== /** - * 消耗金币 - * @param amount 消耗数量 + * 同步数据到vmdata + */ + syncData(){ + this.vmdata.data = this.data; + } +/** + * 判断是否为微信客户端 + */ + private isWxClient(): boolean { + // 检查是否存在微信API + return typeof wx !== 'undefined' && typeof (wx as any).getSystemInfoSync === 'function'; + } + //调试用 + syncDataFromLocal(){ + if(this.isWxClient()) return + const loginResult = new Test().load_data_from_local() + this.gameDataSyncManager.overrideLocalDataWithRemote(loginResult, "本地调试"); + } + + setFightHero(position:number,heroId:number,autoSave:boolean=true){ + this.fight_heros[position] = heroId; + if(autoSave){ + this.updateFightHeros() + } + } + updateFightHeros(){ + this.gameDataSyncManager.updateFightHeros(this.fight_heros); + } + resetFightHeros(){ + this.gameDataSyncManager.resetFightHeros(); + } + getHasHeroUUID(){ + let heros=this.heros + let heros_uuid=[] + for(let key in heros){ + heros_uuid.push(heros[key].uuid) + } + return heros_uuid + } + levelUpHero(heroId:number,exp:number,gold:number){ + let result=this.gameDataSyncManager.levelUpHero(heroId,exp,gold); + if(result){ + this.heros[heroId].lv++; + } + return result; + } + + + // ==================== 统一的数据操作接口 ==================== + + /** + * 增加游戏数据属性(统一接口) + * @param property 属性名 + * @param value 增加的值 + * @param autoSave 是否自动保存 (默认true) + * @returns 操作结果 + */ + async addGameProperty(property: string, value: any, autoSave: boolean = true): Promise { + const currentValue = this.data[property] || 0; + const newValue = currentValue + value; + + this.data[property] = newValue; + this.vmdata.data[property] = newValue; + + console.log(`[SMC]: 增加游戏数据 ${property} = ${value}, 当前值: ${newValue}`); + return newValue; + } + + /** + * 消耗游戏数据属性(统一接口) + * @param property 属性名 + * @param value 消耗的值 * @param autoSave 是否自动保存 (默认true) * @returns 是否成功消耗 */ - spendGold(amount: number, autoSave: boolean = true): boolean { - const currentGold = this.getGameProperty("gold", 0); - if (currentGold < amount) { - console.warn(`[SMC]: 金币不足,当前: ${currentGold}, 需要: ${amount}`); + async spendGameProperty(property: string, value: any, autoSave: boolean = true): Promise { + const currentValue = this.data[property] || 0; + if (currentValue < value) { + console.warn(`[SMC]: ${property} 不足,当前: ${currentValue}, 需要: ${value}`); return false; } - - this.addGold(-amount, autoSave); + const newValue = currentValue - value; + this.data[property] = newValue; + this.vmdata.data[property] = newValue; + console.log(`[SMC]: 消耗游戏数据 ${property} = ${value}, 当前值: ${newValue}`); return true; } - - /** - * 增加钻石 - * @param amount 钻石数量 - * @param autoSave 是否自动保存 (默认true) - */ - addDiamond(amount: number, autoSave: boolean = true) { - const currentDiamond = this.getGameProperty("diamond", 0); - const newDiamond = Math.max(0, currentDiamond + amount); - this.setGameProperty("diamond", newDiamond, autoSave); - console.log(`[SMC]: 钻石变更: ${currentDiamond} -> ${newDiamond} (${amount > 0 ? '+' : ''}${amount})`); - return newDiamond; - } - - /** - * 消耗钻石 - * @param amount 消耗数量 - * @param autoSave 是否自动保存 (默认true) - * @returns 是否成功消耗 - */ - spendDiamond(amount: number, autoSave: boolean = true): boolean { - const currentDiamond = this.getGameProperty("diamond", 0); - if (currentDiamond < amount) { - console.warn(`[SMC]: 钻石不足,当前: ${currentDiamond}, 需要: ${amount}`); - return false; - } - - this.addDiamond(-amount, autoSave); - return true; - } - - - /** - * 增加关卡进度 - * @param amount 增加的关卡数 (默认1) - * @param autoSave 是否自动保存 (默认true) - */ - addMission(amount: number = 1, autoSave: boolean = true) { - const currentMission = this.getGameProperty("mission", 1); - const newMission = currentMission + amount; - this.setGameProperty("mission", newMission, autoSave); - console.log(`[SMC]: 关卡进度增加: ${currentMission} -> ${newMission} (+${amount})`); - // 计算章节和关卡等级 - // this.vmdata.mission_data.chapter = Math.floor((newMission - 1) / 10) + 1 - // this.vmdata.mission_data.level = ((newMission - 1) % 10) + 1 - return newMission; - } - - - /** - * 增加分数 - * @param score 分数 - * @param autoSave 是否自动保存 (默认true) - */ - addScore(score: number, autoSave: boolean = true) { - const currentScore = this.getGameProperty("score", 0); - const newScore = currentScore + score; - this.setGameProperty("score", newScore, autoSave); - console.log(`[SMC]: 分数增加: ${currentScore} -> ${newScore} (+${score})`); - return newScore; - } - - /** - * 重置游戏数据为默认值 - * @param autoSave 是否自动保存 (默认true) - */ - resetGameData(autoSave: boolean = true) { - this.data = { - score: 888, - mission: 1, - gold: 100, - diamond: 100, - }; - - console.log("[SMC]: 游戏数据已重置为默认值:", this.data); - - if (autoSave) { - this.saveGameData(); - } - } - - /** - * 检查本地存储状态(调试用) - */ - checkLocalStorage() { - const fightHeros = oops.storage.get("fight_heros"); - const heros = oops.storage.get("heros"); - const gameData = oops.storage.get("game_data"); - - console.log("[SMC]: 本地存储状态检查:"); - console.log(" - fight_heros:", fightHeros ? "存在" : "不存在", fightHeros); - console.log(" - heros:", heros ? "存在" : "不存在", heros); - console.log(" - game_data:", gameData ? "存在" : "不存在", gameData); - - return { - hasFightHeros: !!fightHeros, - hasHeros: !!heros, - hasGameData: !!gameData, - isFirstTime: !fightHeros && !heros && !gameData - }; - } } export var smc: SingletonModuleComp = ecs.getSingleton(SingletonModuleComp); \ No newline at end of file diff --git a/assets/script/game/common/SingletonModuleComp.ts.meta b/assets/script/game/common/SingletonModuleComp.ts.meta index bbb4e46a..56838c38 100644 --- a/assets/script/game/common/SingletonModuleComp.ts.meta +++ b/assets/script/game/common/SingletonModuleComp.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "58714c1c-3ffe-4ad1-959a-82e5dfeb2dc3", diff --git a/assets/script/game/common/Test.ts b/assets/script/game/common/Test.ts new file mode 100644 index 00000000..be88eca5 --- /dev/null +++ b/assets/script/game/common/Test.ts @@ -0,0 +1,49 @@ +import { oops } from "db://oops-framework/core/Oops" + +export class Test{ + load_data_from_local() { + let local_data = this.get_local_data() + if(!local_data.data||!local_data.fight_heros||!local_data.heros||!local_data.items||!local_data.tals||!local_data.equips){ + return this.init_local_data() + } + return local_data + } + get_local_data(){ + let local_data ={ + user_id: "local_debug", + openid: "local_debug", + regist_time: Date.now(), + data: JSON.parse(oops.storage.get("data")), + fight_heros: JSON.parse(oops.storage.get("fight_heros")), + heros: JSON.parse(oops.storage.get("heros")), + items: JSON.parse(oops.storage.get("items")), + tals: JSON.parse(oops.storage.get("tals")), + equips: JSON.parse(oops.storage.get("equips")) + } + return local_data + } + init_local_data(){ + let init_data = { + data : { + score: 0, mission: 1, gold: 100, diamond: 100, meat: 0, exp: 0, + ghstone: 0, bhstone: 0, phlestone: 0, rhstone: 0, herocard: 0, + ckey: 0, skey: 0, gkey: 0,}, + fight_heros: { 0: 0, 1: 0, 2: 0, 3: 0, 4: 0 }, + heros: { + 5001: { uuid: 5001, lv: 1 }, + 5005: { uuid: 5005, lv: 1 }, + 5007: { uuid: 5007, lv: 1 } + }, + items: {}, + tals: {}, + equips: {} + } + oops.storage.set("data", JSON.stringify(init_data.data)) + oops.storage.set("fight_heros", JSON.stringify(init_data.fight_heros)) + oops.storage.set("heros", JSON.stringify(init_data.heros)) + oops.storage.set("items", JSON.stringify(init_data.items)) + oops.storage.set("tals", JSON.stringify(init_data.tals)) + oops.storage.set("equips", JSON.stringify(init_data.equips)) + return this.get_local_data() + } +} \ No newline at end of file diff --git a/assets/script/game/common/Test.ts.meta b/assets/script/game/common/Test.ts.meta new file mode 100644 index 00000000..252ec12d --- /dev/null +++ b/assets/script/game/common/Test.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.24", + "importer": "typescript", + "imported": true, + "uuid": "893646a7-1cf0-4c80-8fe1-39ac111130fc", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/common/config/BoxSet.ts.meta b/assets/script/game/common/config/BoxSet.ts.meta index a5e5c9be..b2268562 100644 --- a/assets/script/game/common/config/BoxSet.ts.meta +++ b/assets/script/game/common/config/BoxSet.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "28d11009-6d68-462a-9880-8b31cf5975fd", diff --git a/assets/script/game/common/config/CardSet.ts.meta b/assets/script/game/common/config/CardSet.ts.meta index 93b4d5b1..f7dbbce3 100644 --- a/assets/script/game/common/config/CardSet.ts.meta +++ b/assets/script/game/common/config/CardSet.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "ffda71d7-624d-40de-8c09-712edd44bfdc", diff --git a/assets/script/game/common/config/Equips.ts.meta b/assets/script/game/common/config/Equips.ts.meta index a9ba269c..135c6143 100644 --- a/assets/script/game/common/config/Equips.ts.meta +++ b/assets/script/game/common/config/Equips.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "6f6a81bc-e767-4001-b181-2c18c896cfd0", diff --git a/assets/script/game/common/config/GameEvent.ts.meta b/assets/script/game/common/config/GameEvent.ts.meta index 364fb1d8..a1b036f8 100644 --- a/assets/script/game/common/config/GameEvent.ts.meta +++ b/assets/script/game/common/config/GameEvent.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "28ac0ad6-53bf-471a-9256-ae7c8ad351a7", diff --git a/assets/script/game/common/config/GameUIConfig.ts.meta b/assets/script/game/common/config/GameUIConfig.ts.meta index 4f9e6636..6ca559dc 100644 --- a/assets/script/game/common/config/GameUIConfig.ts.meta +++ b/assets/script/game/common/config/GameUIConfig.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "14663cf6-fb92-4921-8ba9-c836b2667737", diff --git a/assets/script/game/common/config/Items.ts.meta b/assets/script/game/common/config/Items.ts.meta index f5411d07..6c74e1d0 100644 --- a/assets/script/game/common/config/Items.ts.meta +++ b/assets/script/game/common/config/Items.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "49217bd4-ee11-49f7-b404-e8d40478fa2d", diff --git a/assets/script/game/common/config/LevelUp.ts.meta b/assets/script/game/common/config/LevelUp.ts.meta index 53f3ed59..8e8ff46f 100644 --- a/assets/script/game/common/config/LevelUp.ts.meta +++ b/assets/script/game/common/config/LevelUp.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "bbef9ac6-154b-4e27-9c56-e964e27ef2d5", diff --git a/assets/script/game/common/config/Mission.ts.meta b/assets/script/game/common/config/Mission.ts.meta index 34a1919a..847eee62 100644 --- a/assets/script/game/common/config/Mission.ts.meta +++ b/assets/script/game/common/config/Mission.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "26aee2e6-ab33-4155-a0aa-221c6be8d030", diff --git a/assets/script/game/common/config/MissionEvent.ts.meta b/assets/script/game/common/config/MissionEvent.ts.meta index 57c876a6..22cff3a2 100644 --- a/assets/script/game/common/config/MissionEvent.ts.meta +++ b/assets/script/game/common/config/MissionEvent.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "167eb23c-6d7e-4e30-96ca-06fec16eeaa8", diff --git a/assets/script/game/common/config/RewardSet.ts.meta b/assets/script/game/common/config/RewardSet.ts.meta index a7352fbb..54a8a492 100644 --- a/assets/script/game/common/config/RewardSet.ts.meta +++ b/assets/script/game/common/config/RewardSet.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "0388f0b8-c77d-4020-8b9a-dabf774f6502", diff --git a/assets/script/game/common/config/RoleSet.ts.meta b/assets/script/game/common/config/RoleSet.ts.meta index 77b8c187..8a83ac6e 100644 --- a/assets/script/game/common/config/RoleSet.ts.meta +++ b/assets/script/game/common/config/RoleSet.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "bde4950f-acae-4c3e-a6a7-39248c34613d", diff --git a/assets/script/game/common/config/SkillSet.ts.meta b/assets/script/game/common/config/SkillSet.ts.meta index 637fd880..d805ff78 100644 --- a/assets/script/game/common/config/SkillSet.ts.meta +++ b/assets/script/game/common/config/SkillSet.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "bb894d46-7785-4e72-9314-8e384a338ab3", diff --git a/assets/script/game/common/config/TalentSet.ts.meta b/assets/script/game/common/config/TalentSet.ts.meta index bfd9ba09..bb853430 100644 --- a/assets/script/game/common/config/TalentSet.ts.meta +++ b/assets/script/game/common/config/TalentSet.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "5fdc5c44-f438-4c0e-8c5c-a2673d49aafd", diff --git a/assets/script/game/common/config/heroSet.ts.meta b/assets/script/game/common/config/heroSet.ts.meta index cf037cbb..e7ed6960 100644 --- a/assets/script/game/common/config/heroSet.ts.meta +++ b/assets/script/game/common/config/heroSet.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "91ba5d4e-bef8-4b0d-8c64-7ce0f37e43d2", diff --git a/assets/script/game/common/ecs/position/BattleMoveComp.ts.meta b/assets/script/game/common/ecs/position/BattleMoveComp.ts.meta index 7d680f7e..87cba881 100644 --- a/assets/script/game/common/ecs/position/BattleMoveComp.ts.meta +++ b/assets/script/game/common/ecs/position/BattleMoveComp.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "196aaacb-556c-4bb2-925c-9a70dc3e56fc", diff --git a/assets/script/game/common/ecs/position/BattleMoveSystem.ts.meta b/assets/script/game/common/ecs/position/BattleMoveSystem.ts.meta index 75b87457..8ff1ffcb 100644 --- a/assets/script/game/common/ecs/position/BattleMoveSystem.ts.meta +++ b/assets/script/game/common/ecs/position/BattleMoveSystem.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "9f62614b-42c3-4f21-a3d6-68c9190082e8", diff --git a/assets/script/game/common/ecs/position/EcsPositionSystem.ts.meta b/assets/script/game/common/ecs/position/EcsPositionSystem.ts.meta index c7692039..2900eb81 100644 --- a/assets/script/game/common/ecs/position/EcsPositionSystem.ts.meta +++ b/assets/script/game/common/ecs/position/EcsPositionSystem.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "b44c446b-ce5f-4079-ac42-269837dbf580", diff --git a/assets/script/game/common/stoast.ts.meta b/assets/script/game/common/stoast.ts.meta index cbd33cf1..8ee2bb7a 100644 --- a/assets/script/game/common/stoast.ts.meta +++ b/assets/script/game/common/stoast.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "d26fa84f-22b4-4136-bb46-d7e978683365", diff --git a/assets/script/game/data/data.ts.meta b/assets/script/game/data/data.ts.meta index 7b361e0a..fc42c0f8 100644 --- a/assets/script/game/data/data.ts.meta +++ b/assets/script/game/data/data.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "cb9afa42-2112-471e-b86c-79407ba6abd4", diff --git a/assets/script/game/data/dataModelComp.ts.meta b/assets/script/game/data/dataModelComp.ts.meta index b958d579..afdb9e9a 100644 --- a/assets/script/game/data/dataModelComp.ts.meta +++ b/assets/script/game/data/dataModelComp.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "0aefc30a-9392-4ada-b3d0-8c15625e8cfc", diff --git a/assets/script/game/data/dataViewComp.ts.meta b/assets/script/game/data/dataViewComp.ts.meta index edad6608..b403d790 100644 --- a/assets/script/game/data/dataViewComp.ts.meta +++ b/assets/script/game/data/dataViewComp.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "8ae6d033-ff0f-44d5-9ff7-c57751bd4ea1", diff --git a/assets/script/game/data/dataViewVM.ts.meta b/assets/script/game/data/dataViewVM.ts.meta index bb04b7c1..ca322ad8 100644 --- a/assets/script/game/data/dataViewVM.ts.meta +++ b/assets/script/game/data/dataViewVM.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "4209bcee-3867-4c0b-83c9-a4eeee989328", diff --git a/assets/script/game/hero/BuffComp.ts.meta b/assets/script/game/hero/BuffComp.ts.meta index d40dba8a..bcf711cf 100644 --- a/assets/script/game/hero/BuffComp.ts.meta +++ b/assets/script/game/hero/BuffComp.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "7eb34351-e975-447f-bf07-0a2e5e00a2e6", diff --git a/assets/script/game/hero/Hero.ts.meta b/assets/script/game/hero/Hero.ts.meta index 386b79a5..b6f1f902 100644 --- a/assets/script/game/hero/Hero.ts.meta +++ b/assets/script/game/hero/Hero.ts.meta @@ -1 +1,9 @@ -{"ver":"4.0.23","importer":"typescript","imported":true,"uuid":"31289da2-91ea-4ffe-85f3-879a3ac7641d","files":[],"subMetas":{},"userData":{}} +{ + "ver": "4.0.24", + "importer": "typescript", + "imported": true, + "uuid": "31289da2-91ea-4ffe-85f3-879a3ac7641d", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/hero/HeroAnmComp-001.ts.meta b/assets/script/game/hero/HeroAnmComp-001.ts.meta index 1098eed7..0b56cc32 100644 --- a/assets/script/game/hero/HeroAnmComp-001.ts.meta +++ b/assets/script/game/hero/HeroAnmComp-001.ts.meta @@ -1 +1,9 @@ -{"ver":"4.0.23","importer":"typescript","imported":true,"uuid":"d8a3d973-c3c2-449f-82bd-adb9f6d5149d","files":[],"subMetas":{},"userData":{}} +{ + "ver": "4.0.24", + "importer": "typescript", + "imported": true, + "uuid": "d8a3d973-c3c2-449f-82bd-adb9f6d5149d", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/hero/HeroAnmComp.ts b/assets/script/game/hero/HeroAnmComp.ts index b2f565e0..2b35bf94 100644 --- a/assets/script/game/hero/HeroAnmComp.ts +++ b/assets/script/game/hero/HeroAnmComp.ts @@ -17,7 +17,6 @@ export default class HeroAnmComp extends Component{ stop () { - // this.spine?.clearTrack(0); this._hasStop = true; } onAnimationFinished(type:Animation.EventType, state:AnimationState){ diff --git a/assets/script/game/hero/HeroAnmComp.ts.meta b/assets/script/game/hero/HeroAnmComp.ts.meta index c99e221d..64cea858 100644 --- a/assets/script/game/hero/HeroAnmComp.ts.meta +++ b/assets/script/game/hero/HeroAnmComp.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "4ba4ac2e-cfcb-45df-8aea-e13919f56d52", diff --git a/assets/script/game/hero/HeroConComp.ts.meta b/assets/script/game/hero/HeroConComp.ts.meta index d5b2195c..56698ccf 100644 --- a/assets/script/game/hero/HeroConComp.ts.meta +++ b/assets/script/game/hero/HeroConComp.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "846e0307-e55e-4bc3-a9db-b387c89ad671", diff --git a/assets/script/game/hero/HeroModelComp.ts.meta b/assets/script/game/hero/HeroModelComp.ts.meta index 07a09bcc..64d4d15e 100644 --- a/assets/script/game/hero/HeroModelComp.ts.meta +++ b/assets/script/game/hero/HeroModelComp.ts.meta @@ -1 +1,9 @@ -{"ver":"4.0.23","importer":"typescript","imported":true,"uuid":"c9121e83-b457-492d-aa56-2119d79a3360","files":[],"subMetas":{},"userData":{}} +{ + "ver": "4.0.24", + "importer": "typescript", + "imported": true, + "uuid": "c9121e83-b457-492d-aa56-2119d79a3360", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/hero/HeroSpine.ts.meta b/assets/script/game/hero/HeroSpine.ts.meta index 17a7a660..5f1281e2 100644 --- a/assets/script/game/hero/HeroSpine.ts.meta +++ b/assets/script/game/hero/HeroSpine.ts.meta @@ -1 +1,9 @@ -{"ver":"4.0.23","importer":"typescript","imported":true,"uuid":"a03797e6-86f0-4771-b35c-045fe5e373bc","files":[],"subMetas":{},"userData":{}} +{ + "ver": "4.0.24", + "importer": "typescript", + "imported": true, + "uuid": "a03797e6-86f0-4771-b35c-045fe5e373bc", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/hero/HeroViewComp.ts.meta b/assets/script/game/hero/HeroViewComp.ts.meta index edc01acd..6cd757e6 100644 --- a/assets/script/game/hero/HeroViewComp.ts.meta +++ b/assets/script/game/hero/HeroViewComp.ts.meta @@ -1 +1,9 @@ -{"ver":"4.0.23","importer":"typescript","imported":true,"uuid":"873f877e-4a89-4c12-8f03-8934f1651878","files":[],"subMetas":{},"userData":{}} +{ + "ver": "4.0.24", + "importer": "typescript", + "imported": true, + "uuid": "873f877e-4a89-4c12-8f03-8934f1651878", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/hero/Mon.ts.meta b/assets/script/game/hero/Mon.ts.meta index 5b29d269..2b322d8b 100644 --- a/assets/script/game/hero/Mon.ts.meta +++ b/assets/script/game/hero/Mon.ts.meta @@ -1 +1,9 @@ -{"ver":"4.0.23","importer":"typescript","imported":true,"uuid":"c1d7128f-5af5-4f7c-b4a1-6bb6fd4f12e0","files":[],"subMetas":{},"userData":{}} +{ + "ver": "4.0.24", + "importer": "typescript", + "imported": true, + "uuid": "c1d7128f-5af5-4f7c-b4a1-6bb6fd4f12e0", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/hero/MonModelComp.ts.meta b/assets/script/game/hero/MonModelComp.ts.meta index b9430677..61963d2c 100644 --- a/assets/script/game/hero/MonModelComp.ts.meta +++ b/assets/script/game/hero/MonModelComp.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "118ca580-773a-458b-8544-ab6c3cb2b376", diff --git a/assets/script/game/hero/SkillConComp.ts.meta b/assets/script/game/hero/SkillConComp.ts.meta index 351a8317..521d4e18 100644 --- a/assets/script/game/hero/SkillConComp.ts.meta +++ b/assets/script/game/hero/SkillConComp.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "6f882a1f-6f5a-4ef5-9ea0-21a0192c2785", diff --git a/assets/script/game/initialize/Initialize.ts b/assets/script/game/initialize/Initialize.ts index 95611d4b..a7166abd 100644 --- a/assets/script/game/initialize/Initialize.ts +++ b/assets/script/game/initialize/Initialize.ts @@ -12,8 +12,9 @@ import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ec import { UIID } from "../common/config/GameUIConfig"; import { LoadingViewComp } from "./view/LoadingViewComp"; import { smc } from "../common/SingletonModuleComp"; -import { WxCloudApi } from "../wx_clound_client_api/WxCloudApi"; - +import { WxCloudApi, UserGameData } from "../wx_clound_client_api/WxCloudApi"; +import { GameDataSyncManager } from "../common/GameDataSyncManager"; +import { Test } from "../common/Test"; // import {data} from "../data/data"; /** @@ -47,18 +48,20 @@ export class Initialize extends ecs.Entity { /** 加载自定义内容(可选) */ private loadCustom(queue: AsyncQueue) { queue.push(async (next: NextFunction, params: any, args: any) => { - // 加载多语言对应字体 - oops.res.load("language/font/" + oops.language.current, () => { - // 加载本地英雄数据 - this.loadHeroDataFromLocal(); - // 判断是否为微信客户端,是的话才加载云端数据 - if (this.isWxClient()) { - this.loadWxDataFromCloud(); - } - next(); - }); + try { + // 加载多语言对应字体 + oops.res.load("language/font/" + oops.language.current, async () => { + // 统一的数据加载流程 + await this.loadGameDataUnified(); + + next(); + }); //加载精灵配置表 // oops.res.load("config/game/heros", next); + } catch (error) { + console.error("[Initialize]: 自定义内容加载失败:", error); + next(); // 即使失败也要继续,不阻塞游戏启动 + } }); } @@ -96,42 +99,87 @@ export class Initialize extends ecs.Entity { return typeof wx !== 'undefined' && typeof (wx as any).getSystemInfoSync === 'function'; } - private loadWxDataFromCloud() { - WxCloudApi.login().then(loginRes=>{ - console.log("login res", loginRes); - }); - } /** - * 从本地存储加载游戏数据 + * 统一的游戏数据加载流程 + * 微信客户端:使用云端数据 + * 非微信客户端:使用本地调试数据 */ - private loadHeroDataFromLocal() { - // 检查本地存储状态 - const storageStatus = smc.checkLocalStorage(); - - if (storageStatus.isFirstTime) { - console.log("[Initialize]: 检测到首次启动游戏"); - } - - // 使用SingletonModuleComp的加载方法 - // loadGameData方法已经包含了首次启动的处理逻辑 - const success = smc.loadGameData(); - if (success) { - console.log("[Initialize]: 游戏数据加载完成"); - } else { - console.log("[Initialize]: 游戏数据加载失败,使用默认配置"); - // 如果加载失败,初始化默认数据并保存 - smc.initDefaultData(); - smc.saveGameData(); - } - - // 再次检查存储状态,确认数据已保存 - if (storageStatus.isFirstTime) { - const newStatus = smc.checkLocalStorage(); - if (newStatus.hasFightHeros && newStatus.hasHeros && newStatus.hasGameData) { - console.log("[Initialize]: 首次启动数据保存成功"); + private async loadGameDataUnified() { + try { + console.log("[Initialize]: 开始统一数据加载流程..."); + + if (this.isWxClient()) { + // 微信客户端:加载云端数据 + console.log("[Initialize]: 检测到微信客户端,使用云端数据"); + await this.loadFromCloud(); } else { - console.warn("[Initialize]: 首次启动数据保存可能失败"); + // 非微信客户端:使用本地调试数据 + console.log("[Initialize]: 非微信客户端,使用本地调试数据"); + await this.loadFromLocalDebug(); } + + } catch (error) { + console.error("[Initialize]: 统一数据加载失败:", error); + // 失败时使用默认数据 游戏需要退出 + } + } + + /** + * 从云端加载数据(微信客户端) + */ + private async loadFromCloud() { + try { + // 1. 初始化微信云环境 + this.initWxCloudEnv(); + + // 2. 登录并获取云端数据 + const loginResult = await WxCloudApi.login(); + const response = loginResult.result; + + if (response.code === 200) { + console.log("[Initialize]: 云端登录成功"); + const cloudData = response.data; + + // 3. 用云端数据覆盖本地数据 + GameDataSyncManager.getInstance().overrideLocalDataWithRemote(cloudData, "云端"); + } else { + console.warn("[Initialize]: 云端登录失败:", response.msg); + // 登录失败时使用本地数据 游戏需要退出 + console.log("[Initialize]: 云端登录失败:", response.msg); + } + + } catch (error) { + console.error("[Initialize]: 云端数据加载异常:", error); + // 异常时使用本地数据 游戏需要退出 + } + } + + /** + * 从本地调试数据加载(非微信客户端) + */ + private async loadFromLocalDebug() { + try { + // 使用本地调试API,模拟云端接口 + const loginResult = new Test().load_data_from_local() + + // 用本地调试数据覆盖客户端数据 + GameDataSyncManager.getInstance().overrideLocalDataWithRemote(loginResult, "本地调试"); + } catch (error) { + console.error("[Initialize]: 本地调试数据加载异常:", error); + } + } + + /** + * 初始化微信云环境 + */ + private initWxCloudEnv() { + try { + // 请替换为您的实际云环境ID + const cloudEnvId = "cloud1-6gknw0qk911036d8"; // TODO: 配置您的云环境ID + WxCloudApi.init(cloudEnvId); + console.log("[Initialize]: 微信云环境初始化完成"); + } catch (error) { + console.error("[Initialize]: 微信云环境初始化失败:", error); } } diff --git a/assets/script/game/initialize/Initialize.ts.meta b/assets/script/game/initialize/Initialize.ts.meta index 65a18a4f..61788e6c 100644 --- a/assets/script/game/initialize/Initialize.ts.meta +++ b/assets/script/game/initialize/Initialize.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "ffbce42c-e99f-48a0-8e73-ea6b756af330", diff --git a/assets/script/game/initialize/view/LoadingViewComp.ts.meta b/assets/script/game/initialize/view/LoadingViewComp.ts.meta index 6aa7ea9b..3186a198 100644 --- a/assets/script/game/initialize/view/LoadingViewComp.ts.meta +++ b/assets/script/game/initialize/view/LoadingViewComp.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "92429ca4-4e7c-450a-b706-c96e7c2568e3", diff --git a/assets/script/game/map/CardComp.ts b/assets/script/game/map/CardComp.ts index 828128fd..25750724 100644 --- a/assets/script/game/map/CardComp.ts +++ b/assets/script/game/map/CardComp.ts @@ -364,11 +364,11 @@ export class CardComp extends CCComp { this.reset_card() } cost_gold_check(){ - if(smc.vmdata.mission_data.gold< this.cost_gold){ + if(smc.vmdata.data.gold< this.cost_gold){ oops.gui.toast("[cardcomp]:金币不足", false); return false } - smc.vmdata.mission_data.gold-=this.cost_gold + smc.vmdata.data.gold-=this.cost_gold return true } reset() { diff --git a/assets/script/game/map/CardComp.ts.meta b/assets/script/game/map/CardComp.ts.meta index 7a8e5f54..9dfacb7f 100644 --- a/assets/script/game/map/CardComp.ts.meta +++ b/assets/script/game/map/CardComp.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "e06b1406-878e-482d-99dd-46eb7ed2c7a8", diff --git a/assets/script/game/map/CardController.ts.meta b/assets/script/game/map/CardController.ts.meta index 5c97cec4..05599135 100644 --- a/assets/script/game/map/CardController.ts.meta +++ b/assets/script/game/map/CardController.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "ee99b110-f3d9-44b5-abc0-1d0b18dac6da", diff --git a/assets/script/game/map/CardsComp.ts.meta b/assets/script/game/map/CardsComp.ts.meta index 4613180d..e9280940 100644 --- a/assets/script/game/map/CardsComp.ts.meta +++ b/assets/script/game/map/CardsComp.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "3d183133-c60d-44c0-933f-a629bea43331", diff --git a/assets/script/game/map/FlashSprite.ts.meta b/assets/script/game/map/FlashSprite.ts.meta index 66cfac4a..3290238f 100644 --- a/assets/script/game/map/FlashSprite.ts.meta +++ b/assets/script/game/map/FlashSprite.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "df953176-a9fa-4f3e-865e-7956fccc4c52", diff --git a/assets/script/game/map/GameMap.ts.meta b/assets/script/game/map/GameMap.ts.meta index 0c2446d7..569ddea3 100644 --- a/assets/script/game/map/GameMap.ts.meta +++ b/assets/script/game/map/GameMap.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "d15fc8d4-c897-4a5c-a97c-b65114b41a69", diff --git a/assets/script/game/map/HCardUICom.ts.meta b/assets/script/game/map/HCardUICom.ts.meta index 9d9d1adb..b588c425 100644 --- a/assets/script/game/map/HCardUICom.ts.meta +++ b/assets/script/game/map/HCardUICom.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "d625f285-3706-4f2e-bf30-e03e34f16650", diff --git a/assets/script/game/map/HInfoComp.ts b/assets/script/game/map/HInfoComp.ts index 3df2e289..ff95ad46 100644 --- a/assets/script/game/map/HInfoComp.ts +++ b/assets/script/game/map/HInfoComp.ts @@ -56,16 +56,17 @@ export class HInfoComp extends Component { this.node.getChildByName("luck").active=lv == 0 } uplevel(){ - let hero_data = HeroInfo[this.h_uuid] let lv=smc.heros[this.h_uuid].lv let {experience,gold}=getUpgradeResources(lv) - if(smc.vmdata.mission_data.exp<=experience||smc.vmdata.mission_data.gold<=gold){ + if(smc.vmdata.data.exp<=experience||smc.vmdata.data.gold<=gold){ oops.gui.toast("经验或金币不足") return } - smc.spendGameProperty("exp",experience) - smc.spendGameProperty("gold",gold) - smc.levelUpHero(this.h_uuid) + let result=smc.levelUpHero(this.h_uuid,experience,gold) + if(!result){ + oops.gui.toast("网络出错了,升级失败,请重试") + return + } this.update_data(this.h_uuid) oops.message.dispatchEvent(GameEvent.UpdateHero, {}) } diff --git a/assets/script/game/map/HInfoComp.ts.meta b/assets/script/game/map/HInfoComp.ts.meta index d50a0dc0..01965bfb 100644 --- a/assets/script/game/map/HInfoComp.ts.meta +++ b/assets/script/game/map/HInfoComp.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "f8dd2383-61ab-4cf9-9879-0d0fe2cd6c2f", diff --git a/assets/script/game/map/HeroPageComp.ts b/assets/script/game/map/HeroPageComp.ts index 4a756ec0..067b4553 100644 --- a/assets/script/game/map/HeroPageComp.ts +++ b/assets/script/game/map/HeroPageComp.ts @@ -38,9 +38,9 @@ export class HeroPageComp extends Component { console.error("[Skill] 预制体加载失败:", path); return; } - const node = instantiate(prefab); - node.parent=parent - let hcard=node.getComponent(HCardUICom)! + const node = instantiate(prefab) as unknown as Node; + node.parent = parent; + let hcard = node.getComponent(HCardUICom)!; hcard.update_data(uuid,{type:HeroConSet.INFO}) } clear_heros(){ diff --git a/assets/script/game/map/HeroPageComp.ts.meta b/assets/script/game/map/HeroPageComp.ts.meta index 3a7f281e..a9f3746c 100644 --- a/assets/script/game/map/HeroPageComp.ts.meta +++ b/assets/script/game/map/HeroPageComp.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "985ee2ae-8a25-4d68-a4f3-d909f5b2c225", diff --git a/assets/script/game/map/HeroReadyCom.ts b/assets/script/game/map/HeroReadyCom.ts index 557d2d34..f370c419 100644 --- a/assets/script/game/map/HeroReadyCom.ts +++ b/assets/script/game/map/HeroReadyCom.ts @@ -24,6 +24,7 @@ export class HeroReadyCom extends Component { } update_hero(){ let hero = smc.fight_heros[this.slot] + console.log("[HeroReadyCom]hero",hero,smc.fight_heros,this.slot) if(hero==0){ this.no_hero() return diff --git a/assets/script/game/map/HeroReadyCom.ts.meta b/assets/script/game/map/HeroReadyCom.ts.meta index 5e2caeaa..9af7a2ed 100644 --- a/assets/script/game/map/HeroReadyCom.ts.meta +++ b/assets/script/game/map/HeroReadyCom.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "11781c25-08d5-41fc-af3e-b2dfd46dc5d7", diff --git a/assets/script/game/map/HeroSelectCom.ts b/assets/script/game/map/HeroSelectCom.ts index 4c33b5ba..ddb4e008 100644 --- a/assets/script/game/map/HeroSelectCom.ts +++ b/assets/script/game/map/HeroSelectCom.ts @@ -50,9 +50,9 @@ export class HeroSelectCom extends Component { console.error("[Skill] 预制体加载失败:", path); return; } - const node = instantiate(prefab); - node.parent=parent - let hcard=node.getComponent(HCardUICom)! + const node = instantiate(prefab) as unknown as Node; + node.parent = parent; + let hcard = node.getComponent(HCardUICom)!; hcard.update_data(uuid,{type:HeroConSet.SELECT,slot:this.slot}) } diff --git a/assets/script/game/map/HeroSelectCom.ts.meta b/assets/script/game/map/HeroSelectCom.ts.meta index 2e6bd99b..62ff6b46 100644 --- a/assets/script/game/map/HeroSelectCom.ts.meta +++ b/assets/script/game/map/HeroSelectCom.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "0c9b9c74-9486-4b43-b797-f602d26f2f1a", diff --git a/assets/script/game/map/LuckCardComp.ts.meta b/assets/script/game/map/LuckCardComp.ts.meta index ae81fb5a..05edd80c 100644 --- a/assets/script/game/map/LuckCardComp.ts.meta +++ b/assets/script/game/map/LuckCardComp.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "598155fc-f31b-4496-b1e4-82219435f425", diff --git a/assets/script/game/map/MSkillComp.ts.meta b/assets/script/game/map/MSkillComp.ts.meta index a0745711..e529a8d6 100644 --- a/assets/script/game/map/MSkillComp.ts.meta +++ b/assets/script/game/map/MSkillComp.ts.meta @@ -1 +1,9 @@ -{"ver":"4.0.23","importer":"typescript","imported":true,"uuid":"e0acc008-a00f-4682-ba4f-c47506bddf26","files":[],"subMetas":{},"userData":{}} +{ + "ver": "4.0.24", + "importer": "typescript", + "imported": true, + "uuid": "e0acc008-a00f-4682-ba4f-c47506bddf26", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/map/MapView.ts.meta b/assets/script/game/map/MapView.ts.meta index 9e74688e..ebf5d847 100644 --- a/assets/script/game/map/MapView.ts.meta +++ b/assets/script/game/map/MapView.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "3748c53e-6b9b-479f-aba0-87fc123ce161", diff --git a/assets/script/game/map/MissionComp.ts b/assets/script/game/map/MissionComp.ts index 2634783c..6c165d78 100644 --- a/assets/script/game/map/MissionComp.ts +++ b/assets/script/game/map/MissionComp.ts @@ -55,7 +55,7 @@ export class MissionComp extends CCComp { oops.message.dispatchEvent(GameEvent.NewWave) return } - smc.addMission(1) + smc.addGameProperty("mission",1) oops.message.dispatchEvent(GameEvent.FightEnd,{victory:true}) oops.gui.open(UIID.Victory,{victory:true}) } @@ -135,7 +135,6 @@ export class MissionComp extends CCComp { smc.vmdata.mission_data.in_fight=false smc.vmdata.mission_data.fight_time=0 smc.vmdata.mission_data.level=0 - smc.initReward() console.log("[MissionComp]局内数据初始化",smc.vmdata.mission_data) } diff --git a/assets/script/game/map/MissionComp.ts.meta b/assets/script/game/map/MissionComp.ts.meta index 11beedf5..32642e91 100644 --- a/assets/script/game/map/MissionComp.ts.meta +++ b/assets/script/game/map/MissionComp.ts.meta @@ -1 +1,9 @@ -{"ver":"4.0.23","importer":"typescript","imported":true,"uuid":"e7482754-5692-4425-9cc7-92a265d5958f","files":[],"subMetas":{},"userData":{}} +{ + "ver": "4.0.24", + "importer": "typescript", + "imported": true, + "uuid": "e7482754-5692-4425-9cc7-92a265d5958f", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/map/MissionHeroComp.ts b/assets/script/game/map/MissionHeroComp.ts index b94b552a..c8759c38 100644 --- a/assets/script/game/map/MissionHeroComp.ts +++ b/assets/script/game/map/MissionHeroComp.ts @@ -126,31 +126,8 @@ export class MissionHeroCompComp extends CCComp { hero.load(pos,scale,uuid); } - get_info_and_remove(fight_pos:number,uuid:number){ - let info:any={ap:0,hp:0,lv:1,crit:0,crit_d:0,dod:0,dod_no:false,crit_no:false} - let heros=ecs.query(ecs.allOf(HeroModelComp)) - if(heros.length>0){ - let hero = heros[0] - let hv = hero.get(HeroViewComp) - info.ap=hv.ap - info.hp=hv.hp_max - info.lv=hv.lv - info.crit=hv.crit - info.crit_d=hv.crit_d - info.dod=hv.dod - info.dod_no=hv.dod_no - info.crit_no=hv.crit_no - hero.destroy() - return info - - } - return info - } - do_hero_change(){ - //金币加1 - smc.vmdata.mission_data.gold+=1 - } + /** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */ reset() { diff --git a/assets/script/game/map/MissionHeroComp.ts.meta b/assets/script/game/map/MissionHeroComp.ts.meta index 2dd7b489..d82fa465 100644 --- a/assets/script/game/map/MissionHeroComp.ts.meta +++ b/assets/script/game/map/MissionHeroComp.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "0e186bfb-2282-449d-9f50-757559af2d96", diff --git a/assets/script/game/map/MissionHomeComp.ts b/assets/script/game/map/MissionHomeComp.ts index 034ba32c..e8d9cc0a 100644 --- a/assets/script/game/map/MissionHomeComp.ts +++ b/assets/script/game/map/MissionHomeComp.ts @@ -39,6 +39,7 @@ export class MissionHomeComp extends CCComp { smc.syncData() } btn_func(e:string,data:any){ + smc.syncDataFromLocal() //调试用,正式环境去掉 // console.log("[MissionHomeComp]:btn_func",e,data) let page_heros=this.node.getChildByName("heros_page") let page_shop=this.node.getChildByName("shop_page") diff --git a/assets/script/game/map/MissionHomeComp.ts.meta b/assets/script/game/map/MissionHomeComp.ts.meta index 4e44c438..cd76c400 100644 --- a/assets/script/game/map/MissionHomeComp.ts.meta +++ b/assets/script/game/map/MissionHomeComp.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "114984db-549a-4eea-a999-f26f64e79671", diff --git a/assets/script/game/map/MissionMonComp.ts b/assets/script/game/map/MissionMonComp.ts index 3f4769e3..48d0d64c 100644 --- a/assets/script/game/map/MissionMonComp.ts +++ b/assets/script/game/map/MissionMonComp.ts @@ -113,7 +113,7 @@ export class MissionMonCompComp extends CCComp { // 添加刷怪队列 - 使 // 根据新的关卡配置生成怪物 private generateMonstersFromStageConfig(monsterConfigs: any[]) { - const currentStage = smc.vmdata.mission_data.mission; + const currentStage = smc.vmdata.data.mission; // 设置怪物总数 console.log("[MissionMonComp] generateMonstersFromStageConfig",monsterConfigs) diff --git a/assets/script/game/map/MissionMonComp.ts.meta b/assets/script/game/map/MissionMonComp.ts.meta index 100ca584..33b4adc0 100644 --- a/assets/script/game/map/MissionMonComp.ts.meta +++ b/assets/script/game/map/MissionMonComp.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "032d623d-38de-4117-9dcb-68ec75f124f5", diff --git a/assets/script/game/map/RogueConfig.ts.meta b/assets/script/game/map/RogueConfig.ts.meta index 8579202e..4be7ceca 100644 --- a/assets/script/game/map/RogueConfig.ts.meta +++ b/assets/script/game/map/RogueConfig.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "f432a03f-6b3c-43a9-bdd8-845aeec7a019", diff --git a/assets/script/game/map/VictoryComp.ts.meta b/assets/script/game/map/VictoryComp.ts.meta index 61da582d..b5a79a9f 100644 --- a/assets/script/game/map/VictoryComp.ts.meta +++ b/assets/script/game/map/VictoryComp.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "463c788d-edc9-436c-b06e-b89e9fa9642f", diff --git a/assets/script/game/map/model/MapModelComp.ts.meta b/assets/script/game/map/model/MapModelComp.ts.meta index dc9f78ae..0654f30a 100644 --- a/assets/script/game/map/model/MapModelComp.ts.meta +++ b/assets/script/game/map/model/MapModelComp.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "2f2380b0-3fa7-48ee-8e30-24e5d718f91e", diff --git a/assets/script/game/map/move.ts.meta b/assets/script/game/map/move.ts.meta index ac9cb953..0e495af4 100644 --- a/assets/script/game/map/move.ts.meta +++ b/assets/script/game/map/move.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "c68767c6-5154-4de2-97e5-895a76f9f8ea", diff --git a/assets/script/game/map/view/MapViewComp.ts.meta b/assets/script/game/map/view/MapViewComp.ts.meta index e6a70bcb..07f59006 100644 --- a/assets/script/game/map/view/MapViewComp.ts.meta +++ b/assets/script/game/map/view/MapViewComp.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "b9f0df21-67f9-460a-8306-caf12042a78f", diff --git a/assets/script/game/map/view/MapViewScene.ts.meta b/assets/script/game/map/view/MapViewScene.ts.meta index 07f5a839..f90a9aa8 100644 --- a/assets/script/game/map/view/MapViewScene.ts.meta +++ b/assets/script/game/map/view/MapViewScene.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "a31682ea-e44b-4122-b411-6761895ab6b0", diff --git a/assets/script/game/map/view/MoveUV.ts.meta b/assets/script/game/map/view/MoveUV.ts.meta index 18906632..4744e335 100644 --- a/assets/script/game/map/view/MoveUV.ts.meta +++ b/assets/script/game/map/view/MoveUV.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "e399b82b-77ce-4ae0-bb2d-81ae88e3fc91", diff --git a/assets/script/game/map/view/map/layer/EntityLayer.ts.meta b/assets/script/game/map/view/map/layer/EntityLayer.ts.meta index 6861d132..703e38d1 100644 --- a/assets/script/game/map/view/map/layer/EntityLayer.ts.meta +++ b/assets/script/game/map/view/map/layer/EntityLayer.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "6639aca8-e031-4a65-8094-d8e059cf26fe", diff --git a/assets/script/game/map/view/map/layer/MapLayer.ts.meta b/assets/script/game/map/view/map/layer/MapLayer.ts.meta index 86fd3512..8f2f07b1 100644 --- a/assets/script/game/map/view/map/layer/MapLayer.ts.meta +++ b/assets/script/game/map/view/map/layer/MapLayer.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "753fb70a-638e-44d4-b736-f8696df44858", diff --git a/assets/script/game/map/view/map/layer/SkillLayer.ts.meta b/assets/script/game/map/view/map/layer/SkillLayer.ts.meta index 7cae80a3..a7414c4f 100644 --- a/assets/script/game/map/view/map/layer/SkillLayer.ts.meta +++ b/assets/script/game/map/view/map/layer/SkillLayer.ts.meta @@ -1 +1,11 @@ -{"ver":"4.0.23","importer":"typescript","imported":true,"uuid":"7852ab4a-120b-4c93-9d76-9b48c382599f","files":[],"subMetas":{},"userData":{"simulateGlobals":[]}} +{ + "ver": "4.0.24", + "importer": "typescript", + "imported": true, + "uuid": "7852ab4a-120b-4c93-9d76-9b48c382599f", + "files": [], + "subMetas": {}, + "userData": { + "simulateGlobals": [] + } +} diff --git a/assets/script/game/map/view/map/layer/light.ts b/assets/script/game/map/view/map/layer/light.ts index 53ccba8a..39fed1e2 100644 --- a/assets/script/game/map/view/map/layer/light.ts +++ b/assets/script/game/map/view/map/layer/light.ts @@ -1,18 +1,14 @@ -import { _decorator, Component, Node, sp } from 'cc'; +import { _decorator, Component, Node } from 'cc'; const { ccclass, property ,} = _decorator; @ccclass('light') export class light extends Component { - private spine!: sp.Skeleton; start() { } protected onLoad(): void { - this.spine = this.getComponent(sp.Skeleton)!; - this.spine.setCompleteListener(trackEntry => { - this.node.destroy() - }); + } update(deltaTime: number) { diff --git a/assets/script/game/map/view/map/layer/light.ts.meta b/assets/script/game/map/view/map/layer/light.ts.meta index 7c21e110..df7fec2b 100644 --- a/assets/script/game/map/view/map/layer/light.ts.meta +++ b/assets/script/game/map/view/map/layer/light.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "fc960e39-45c0-41bf-8ff8-04a4acca0c38", diff --git a/assets/script/game/skill/HeroSkillSystem.ts.meta b/assets/script/game/skill/HeroSkillSystem.ts.meta index 363cbcbf..2087a30f 100644 --- a/assets/script/game/skill/HeroSkillSystem.ts.meta +++ b/assets/script/game/skill/HeroSkillSystem.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "36448c83-0bd9-495b-806d-6e7d640370e3", diff --git a/assets/script/game/skills/AnmEndCom.ts b/assets/script/game/skills/AnmEndCom.ts index a336e327..08cd6b9f 100644 --- a/assets/script/game/skills/AnmEndCom.ts +++ b/assets/script/game/skills/AnmEndCom.ts @@ -1,4 +1,4 @@ -import { _decorator, Animation, Component, Node, sp } from 'cc'; +import { _decorator, Animation, Component, Node } from 'cc'; const { ccclass, property } = _decorator; @ccclass('AnmEndCom') @@ -11,16 +11,7 @@ export class AnmEndCom extends Component { anim.on(Animation.EventType.FINISHED, this.onAnimationFinished, this); } - if(this.node.getChildByName('anm')){ - if(this.node.getChildByName('anm').getComponent('sp.Skeleton')){ - var spine = this.node.getChildByName('anm').getComponent('sp.Skeleton') as sp.Skeleton; - console.log("has spine",spine) - spine.setCompleteListener((trackEntry) => { - this.onAnimationFinished() - console.log("[track %s][animation %s] complete: %s", trackEntry.trackIndex); - }); - } - } + } onAnimationFinished(){ this.node.destroy() diff --git a/assets/script/game/skills/AnmEndCom.ts.meta b/assets/script/game/skills/AnmEndCom.ts.meta index bcea9199..22e3f3a9 100644 --- a/assets/script/game/skills/AnmEndCom.ts.meta +++ b/assets/script/game/skills/AnmEndCom.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "9a6c0cbd-2b5b-4ecd-85d3-c017de7a5b2a", diff --git a/assets/script/game/skills/BezCom.ts.meta b/assets/script/game/skills/BezCom.ts.meta index 892d5c5a..236642b9 100644 --- a/assets/script/game/skills/BezCom.ts.meta +++ b/assets/script/game/skills/BezCom.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "5ebc6679-2a71-424f-bacf-48f20949fbd3", diff --git a/assets/script/game/skills/Skill.ts.meta b/assets/script/game/skills/Skill.ts.meta index e410bf67..bae769b0 100644 --- a/assets/script/game/skills/Skill.ts.meta +++ b/assets/script/game/skills/Skill.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "e7bac796-7cc3-47b4-904b-85a95cc15390", diff --git a/assets/script/game/skills/SkillCom.ts.meta b/assets/script/game/skills/SkillCom.ts.meta index 4b8f5b1f..63da91da 100644 --- a/assets/script/game/skills/SkillCom.ts.meta +++ b/assets/script/game/skills/SkillCom.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "45646a08-c887-40db-85be-d1ce6b7442c3", diff --git a/assets/script/game/skills/Tooltip.ts.meta b/assets/script/game/skills/Tooltip.ts.meta index 81396a77..b4e62600 100644 --- a/assets/script/game/skills/Tooltip.ts.meta +++ b/assets/script/game/skills/Tooltip.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "a5e3c618-6636-439e-aa36-d4ee97793b18", diff --git a/assets/script/game/skills/TooltipCom.ts.meta b/assets/script/game/skills/TooltipCom.ts.meta index df838660..81572474 100644 --- a/assets/script/game/skills/TooltipCom.ts.meta +++ b/assets/script/game/skills/TooltipCom.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "49ffd76d-7069-4947-b170-62cd72619ede", diff --git a/assets/script/game/skills/atked.ts.meta b/assets/script/game/skills/atked.ts.meta index 0b92d382..97b4b4a4 100644 --- a/assets/script/game/skills/atked.ts.meta +++ b/assets/script/game/skills/atked.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "65d6266f-bba6-4b98-8343-2a67642ec7eb", diff --git a/assets/script/game/skills/com/AtkCom.ts.meta b/assets/script/game/skills/com/AtkCom.ts.meta index f062716b..e6215ec6 100644 --- a/assets/script/game/skills/com/AtkCom.ts.meta +++ b/assets/script/game/skills/com/AtkCom.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "b1d8ed59-0347-4bb6-ab9f-86276714afca", diff --git a/assets/script/game/skills/debuff.ts.meta b/assets/script/game/skills/debuff.ts.meta index 0b8c3193..f543054a 100644 --- a/assets/script/game/skills/debuff.ts.meta +++ b/assets/script/game/skills/debuff.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "69132caf-02ba-40a8-a835-30baced39701", diff --git a/assets/script/game/skills/once.ts b/assets/script/game/skills/once.ts index 2b44c923..1717a51b 100644 --- a/assets/script/game/skills/once.ts +++ b/assets/script/game/skills/once.ts @@ -1,18 +1,13 @@ -import { _decorator, Component, Node, sp } from 'cc'; +import { _decorator, Component, Node } from 'cc'; const { ccclass, property ,} = _decorator; @ccclass('once') export class once extends Component { - private spine!: sp.Skeleton; start() { - this.spine.setAnimation(0, "animation", true); } protected onLoad(): void { - this.spine = this.node.getChildByName("skill").getComponent(sp.Skeleton)!; - this.spine.setCompleteListener(trackEntry => { - if(this.node.isValid) this.node.active = false; - }); + } update(deltaTime: number) { diff --git a/assets/script/game/skills/once.ts.meta b/assets/script/game/skills/once.ts.meta index c8388bc4..04327fc3 100644 --- a/assets/script/game/skills/once.ts.meta +++ b/assets/script/game/skills/once.ts.meta @@ -1 +1,9 @@ -{"ver":"4.0.23","importer":"typescript","imported":true,"uuid":"6e0a995d-16c1-4554-8f80-29394f24213b","files":[],"subMetas":{},"userData":{}} +{ + "ver": "4.0.24", + "importer": "typescript", + "imported": true, + "uuid": "6e0a995d-16c1-4554-8f80-29394f24213b", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/skills/oncend.ts.meta b/assets/script/game/skills/oncend.ts.meta index 8d27de74..1a35b8c6 100644 --- a/assets/script/game/skills/oncend.ts.meta +++ b/assets/script/game/skills/oncend.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "0f3c4261-15b1-4eda-b105-a81249ee116f", diff --git a/assets/script/game/skills/timedCom.ts.meta b/assets/script/game/skills/timedCom.ts.meta index 4aaaa872..79227ae7 100644 --- a/assets/script/game/skills/timedCom.ts.meta +++ b/assets/script/game/skills/timedCom.ts.meta @@ -1 +1,9 @@ -{"ver":"4.0.23","importer":"typescript","imported":true,"uuid":"f140b15c-7345-4364-818e-787001fb1c19","files":[],"subMetas":{},"userData":{}} +{ + "ver": "4.0.24", + "importer": "typescript", + "imported": true, + "uuid": "f140b15c-7345-4364-818e-787001fb1c19", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/wx_clound_client_api/USAGE.md b/assets/script/game/wx_clound_client_api/USAGE.md new file mode 100644 index 00000000..ca4706fb --- /dev/null +++ b/assets/script/game/wx_clound_client_api/USAGE.md @@ -0,0 +1,443 @@ +# WxCloudApi 客户端使用指南 + +## 📋 概述 + +`WxCloudApi` 是游戏客户端与微信云函数交互的统一接口层,提供了完整的类型安全和便捷的调用方法。 + +## 🚀 快速开始 + +### 1. 初始化 +```typescript +// 在游戏启动时初始化云环境 +WxCloudApi.init("your-cloud-env-id"); +``` + +### 2. 用户登录 +```typescript +// 用户登录,获取完整的游戏数据 +const loginResult = await WxCloudApi.login(); +if (loginResult.result.code === 200) { + const userData = loginResult.result.data; + console.log("用户ID:", userData.user_id); + console.log("金币:", userData.data.gold); + console.log("出战英雄:", userData.fight_heros); +} +``` + +## 🎮 基础游戏数据操作 + +### 获取游戏数据 +```typescript +const gameData = await WxCloudApi.getGameData(); +if (gameData.result.code === 200) { + console.log("当前金币:", gameData.result.data.gold); + console.log("当前钻石:", gameData.result.data.diamond); +} +``` + +### 增加金币 +```typescript +// 方式1:使用便捷方法 +const result = await WxCloudApi.addGold(100); + +// 方式2:使用通用方法 +const result = await WxCloudApi.addGameDataField('gold', 100); + +if (result.result.code === 200) { + console.log("金币增加成功:", result.result.data); +} +``` + +### 消耗金币 +```typescript +// 消耗金币(会检查是否足够) +const result = await WxCloudApi.spendGold(50); +if (result.result.code === 200) { + console.log("金币消耗成功"); +} else if (result.result.code === -6) { + console.log("金币不足"); +} +``` + +### 批量更新游戏数据 +```typescript +const result = await WxCloudApi.updateGameData({ + gold: 1000, + diamond: 200, + exp: 500 +}, true); // true表示合并更新 +``` + +## ⚔️ 出战英雄管理 + +### 获取出战英雄配置 +```typescript +const fightHeros = await WxCloudApi.getFightHeros(); +if (fightHeros.result.code === 200) { + console.log("出战配置:", fightHeros.result.data); + // { 0: 5001, 1: 5005, 2: 0, 3: 0, 4: 0 } +} +``` + +### 设置出战英雄 +```typescript +// 将英雄5007设置到位置2 +const result = await WxCloudApi.setFightHero(2, 5007); +if (result.result.code === 200) { + console.log("设置成功:", result.result.data); +} + +// 移除位置2的英雄 +await WxCloudApi.setFightHero(2, 0); +``` + +### 批量更新出战英雄 +```typescript +const result = await WxCloudApi.updateFightHeros({ + 0: 5001, + 1: 5005, + 2: 5007 +}); +``` + +### 交换英雄位置 +```typescript +// 交换位置0和位置2的英雄 +const result = await WxCloudApi.swapFightHeros(0, 2); +``` + +### 获取激活的出战英雄 +```typescript +const activeHeros = await WxCloudApi.getActiveFightHeros(); +if (activeHeros.result.code === 200) { + const heros = activeHeros.result.data.active_heros; + heros.forEach(hero => { + console.log(`位置${hero.position}: 英雄${hero.hero_id}, 等级${hero.hero_data.lv}`); + }); +} +``` + +## 🦸 英雄管理 + +### 获取所有英雄 +```typescript +const heros = await WxCloudApi.getHeros(); +if (heros.result.code === 200) { + Object.entries(heros.result.data).forEach(([heroId, heroData]) => { + console.log(`英雄${heroId}: 等级${heroData.lv}, 战力${heroData.power}`); + }); +} +``` + +### 添加新英雄 +```typescript +// 添加英雄(使用默认属性) +const result = await WxCloudApi.addHero(5008); + +// 添加英雄(自定义属性) +const result = await WxCloudApi.addHero(5008, { + lv: 5, + exp: 1000, + star: 2, + power: 150 +}); +``` + +### 英雄升级 +```typescript +// 升级1级 +const result = await WxCloudApi.levelUpHero(5001); + +// 升级3级 +const result = await WxCloudApi.levelUpHero(5001, 3); + +if (result.result.code === 200) { + console.log("升级成功:", result.result.data); +} +``` + +### 更新英雄属性 +```typescript +// 批量更新 +const result = await WxCloudApi.updateHero(5001, { + lv: 15, + exp: 2000, + star: 3 +}); + +// 单个属性更新 +const result = await WxCloudApi.setHeroProperty(5001, 'power', 200); +``` + +### 删除英雄 +```typescript +const result = await WxCloudApi.deleteHero(5008); +if (result.result.code === -8) { + console.log("英雄正在出战中,无法删除"); +} +``` + +## 🎒 库存管理 + +### 道具操作 +```typescript +// 获取所有道具 +const items = await WxCloudApi.getItems(); + +// 添加道具 +const result = await WxCloudApi.addItem(1001, 10); + +// 消耗道具 +const result = await WxCloudApi.consumeItem(1001, 3); + +// 获取指定道具数量 +const itemInfo = await WxCloudApi.getInventoryItem('items', 1001); +console.log("道具1001数量:", itemInfo.result.data.count); +``` + +### 天赋操作 +```typescript +// 获取所有天赋 +const talents = await WxCloudApi.getTalents(); + +// 添加天赋点 +const result = await WxCloudApi.addTalent(1001, 1); + +// 消耗天赋点 +const result = await WxCloudApi.consumeTalent(1001, 1); +``` + +### 装备操作 +```typescript +// 获取所有装备 +const equipments = await WxCloudApi.getEquipments(); + +// 添加装备 +const result = await WxCloudApi.addEquipment(1001, 2); + +// 消耗装备 +const result = await WxCloudApi.consumeEquipment(1001, 1); +``` + +### 批量库存操作 +```typescript +// 批量更新道具 +const result = await WxCloudApi.updateInventory('items', { + 1001: 20, + 1002: 15, + 1003: 10 +}); + +// 获取拥有的道具列表(数量>0) +const ownedItems = await WxCloudApi.getOwnedItems('items'); +console.log("拥有的道具:", ownedItems.result.data.owned_items); +``` + +## 🔐 认证和版本管理 + +### 检查版本信息 +```typescript +const versionInfo = await WxCloudApi.checkVersion(); +if (versionInfo.result.code === 200) { + const compatibility = versionInfo.result.data.compatibility; + if (compatibility.needsUpgrade) { + console.log("需要升级数据:", compatibility.message); + // 可以选择自动升级 + await WxCloudApi.upgradeUserData(); + } +} +``` + +### 获取用户基本信息 +```typescript +const userInfo = await WxCloudApi.getUserInfo(); +if (userInfo.result.code === 200) { + console.log("用户信息:", userInfo.result.data); +} +``` + +## 🛠️ 错误处理 + +### 统一错误处理 +```typescript +async function handleApiCall(apiCall: Promise>>) { + try { + const result = await apiCall; + const response = result.result; + + switch (response.code) { + case 200: + console.log("操作成功:", response.data); + return response.data; + + case -3: + console.error("参数错误:", response.msg); + break; + + case -4: + console.error("用户未找到:", response.msg); + break; + + case -5: + console.error("系统错误:", response.msg); + break; + + case -6: + console.error("资源不足:", response.msg); + break; + + default: + console.error("未知错误:", response.code, response.msg); + } + } catch (error) { + console.error("网络错误:", error); + } + return null; +} + +// 使用示例 +const gameData = await handleApiCall(WxCloudApi.getGameData()); +``` + +### 资源不足处理示例 +```typescript +async function trySpendGold(amount: number): Promise { + const result = await WxCloudApi.spendGold(amount); + const response = result.result; + + if (response.code === 200) { + console.log("金币消耗成功"); + return true; + } else if (response.code === -6) { + console.log("金币不足,当前:", response.data?.current, "需要:", response.data?.required); + // 可以提示用户充值或其他操作 + return false; + } + + console.error("消耗失败:", response.msg); + return false; +} +``` + +## 📊 完整游戏流程示例 + +```typescript +export class GameDataManager { + // 游戏启动时初始化 + public static async initialize() { + // 1. 初始化云环境 + WxCloudApi.init("your-cloud-env-id"); + + // 2. 用户登录 + const loginResult = await WxCloudApi.login(); + if (loginResult.result.code !== 200) { + console.error("登录失败"); + return false; + } + + const userData = loginResult.result.data; + console.log("登录成功,用户数据:", userData); + + // 3. 检查版本兼容性 + const versionResult = await WxCloudApi.checkVersion(); + if (versionResult.result.data.compatibility.needsUpgrade) { + console.log("正在升级数据..."); + await WxCloudApi.upgradeUserData(); + } + + return true; + } + + // 战斗结算 + public static async settleBattle(rewards: {gold: number, exp: number, items: {[id: number]: number}}) { + try { + // 1. 增加金币和经验 + await WxCloudApi.addGold(rewards.gold); + await WxCloudApi.addGameDataField('exp', rewards.exp); + + // 2. 增加道具奖励 + for (const [itemId, count] of Object.entries(rewards.items)) { + await WxCloudApi.addItem(parseInt(itemId), count); + } + + console.log("战斗结算完成"); + return true; + } catch (error) { + console.error("战斗结算失败:", error); + return false; + } + } + + // 英雄升级 + public static async upgradeHero(heroId: number, levels: number): Promise { + // 假设每级需要100金币 + const cost = levels * 100; + + // 1. 检查金币是否足够 + const spendResult = await WxCloudApi.spendGold(cost); + if (spendResult.result.code !== 200) { + console.log("金币不足,无法升级"); + return false; + } + + // 2. 升级英雄 + const upgradeResult = await WxCloudApi.levelUpHero(heroId, levels); + if (upgradeResult.result.code === 200) { + console.log("英雄升级成功"); + return true; + } else { + // 升级失败,退还金币 + await WxCloudApi.addGold(cost); + console.error("英雄升级失败"); + return false; + } + } + + // 设置出战阵容 + public static async setupFightTeam(heroIds: number[]): Promise { + const fightHeros: Partial = {}; + + // 最多5个位置 + for (let i = 0; i < Math.min(heroIds.length, 5); i++) { + fightHeros[i] = heroIds[i]; + } + + // 清空剩余位置 + for (let i = heroIds.length; i < 5; i++) { + fightHeros[i] = 0; + } + + const result = await WxCloudApi.updateFightHeros(fightHeros); + return result.result.code === 200; + } +} +``` + +## 🎯 最佳实践 + +### 1. 错误处理 +- 始终检查返回的 `code` 字段 +- 对不同错误码进行相应处理 +- 网络错误要有重试机制 + +### 2. 性能优化 +- 批量操作优于多次单独操作 +- 合理使用缓存,避免频繁请求 +- 关键操作添加加载状态 + +### 3. 数据一致性 +- 重要操作后及时同步本地数据 +- 使用乐观锁机制处理并发 +- 定期全量同步数据 + +### 4. 用户体验 +- 操作前进行客户端验证 +- 提供友好的错误提示 +- 重要操作添加确认对话框 + +--- + +**版本**: 1.0.0 +**更新时间**: 2024年 +**维护者**: 游戏开发团队 + diff --git a/assets/script/game/wx_clound_client_api/USAGE.md.meta b/assets/script/game/wx_clound_client_api/USAGE.md.meta new file mode 100644 index 00000000..e84e9516 --- /dev/null +++ b/assets/script/game/wx_clound_client_api/USAGE.md.meta @@ -0,0 +1,11 @@ +{ + "ver": "1.0.1", + "importer": "text", + "imported": true, + "uuid": "f07f89b5-9257-48a8-a6ab-06f662e5e726", + "files": [ + ".json" + ], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/wx_clound_client_api/WxCloudApi.ts b/assets/script/game/wx_clound_client_api/WxCloudApi.ts index 3e8a02ef..83c3000f 100644 --- a/assets/script/game/wx_clound_client_api/WxCloudApi.ts +++ b/assets/script/game/wx_clound_client_api/WxCloudApi.ts @@ -1,9 +1,92 @@ +// 云函数返回类型定义 export type CloudReturnType = { - code: number,// 200成功 - msg?:string, - data?:T + code: number, // 200成功,其他都是失败 + msg?: string, // 消息信息 + data?: T, // 返回数据 + timestamp?: number, // 时间戳 + version?: string, // 数据版本 + execution_time?: number // 执行时间(ms) } +// 用户信息类型 +export type UserInfo = { + user_id: string, + openid: string, + regist_time: number, + init_time?: number, + data_version?: string, + last_save_time?: number +} + +// 完整用户数据类型 +export type UserGameData = UserInfo & { + data: GameData, + fight_heros: FightHeros, + heros: Heros, + items: Items, + tals: Tals, + equips: Equips +} + +// 基础游戏数据类型 +export type GameData = { + score: number, + mission: number, + gold: number, + diamond: number, + meat: number, + exp: number, + ghstone: number, // 绿色英雄石 + bhstone: number, // 蓝色英雄石 + phlestone: number, // 紫色英雄石 + rhstone: number, // 红色英雄石 + herocard: number, // 英雄卡 + ckey: number, // 铜钥匙 + skey: number, // 银钥匙 + gkey: number // 金钥匙 +} + +// 出战英雄类型 +export type FightHeros = { + [position: number]: number // 位置 -> 英雄ID +} + +// 英雄数据类型 +export type HeroData = { + uuid: number, + lv: number, + exp?: number, + star?: number, + power?: number +} + +export type Heros = { + [heroId: number]: HeroData +} + +// 库存类型 +export type Items = { + [itemId: number]: number +} + +export type Tals = { + [talId: number]: number +} + +export type Equips = { + [equipId: number]: number +} + +// 版本兼容性检查结果 +export type VersionCompatibility = { + compatible: boolean, + needsUpgrade: boolean, + message: string +} + +// 库存类型枚举 +export type InventoryType = 'items' | 'tals' | 'equips' + export class WxCloudApi{ /** * @en init the cloud @@ -16,30 +99,14 @@ export class WxCloudApi{ }); } + // ==================== 认证相关接口 ==================== + /** * @en Login to the cloud - * @zh 登录云 - * @return 返回结果 - * 参考: - * result.result = { - * code: number, // 200成功,其他都是失败 - * msg: string, // 如果失败,这里是失败原因等信息 - * data: { // 成功才有 - * openid: string, // 用户微信平台openid - * regist_time: number, // 时间戳,用户注册时间 - * game_data: object, // 开发者自己保存的数据 - * } - * } - * 如果这个泛型令你报错(一般是因为你删了wx.api.d.ts导致),请使用以下签名: - * login():Promise<{result: CloudReturnType<{openid: string, regist_time: number, game_data: object}>}> - * 或者你是个“不拘小节”的老哥,可以用以下简洁版签名(参考上方的数据结构例子使用即可) - * login():Promise + * @zh 用户登录,获取完整的用户和游戏数据 + * @return Promise>> */ - public static async login(): Promise>>{ + public static async login(): Promise>> { return await wx?.cloud.callFunction({ name: 'cocos_cloud', data: { @@ -49,29 +116,488 @@ export class WxCloudApi{ } /** - * @en Save game data to the cloud - * @zh 把客户端数据写入云,此为全覆盖写入,请自行管理完整数据 - * @return 返回结果 - * 参考: - * result.result = { - * code: number, // 200成功,其他都是失败 - * msg: string, // 如果失败,这里是失败原因等信息 - * data: { - * errMsg: "document.update:ok", // 数据库返回结果 - * stats: { - * updated: number, // 更新了几条数据(正常是1) - * } - * } - * 如果这个泛型令你报错(一般是因为你删了wx.api.d.ts导致),请使用以下签名: - * save(gameData: any): Promise<{resoult:CloudReturnType}> - * 或者你是个“不拘小节”的老哥,可以用以下简洁版签名(参考上方的数据结构例子使用即可) - * login():Promise + * @en Get user basic info + * @zh 获取用户基本信息(不包含游戏数据) + * @return Promise>> + */ + public static async getUserInfo(): Promise>> { + return await wx?.cloud.callFunction({ + name: 'cocos_cloud', + data: { + cmd: "user_info" + } + }); + } + + /** + * @en Check data version compatibility + * @zh 检查数据版本兼容性 + * @return Promise>> + */ + public static async checkVersion(): Promise>> { + return await wx?.cloud.callFunction({ + name: 'cocos_cloud', + data: { + cmd: "version" + } + }); + } + + /** + * @en Force upgrade user data + * @zh 强制升级用户数据结构 + * @return Promise>> + */ + public static async upgradeUserData(): Promise>> { + return await wx?.cloud.callFunction({ + name: 'cocos_cloud', + data: { + cmd: "upgrade" + } + }); + } + + // ==================== 基础游戏数据接口 ==================== + + /** + * @en Get game data + * @zh 获取基础游戏数据(金币、钻石、经验等) + * @return Promise>> + */ + public static async getGameData(): Promise>> { + return await wx?.cloud.callFunction({ + name: 'cocos_cloud', + data: { + cmd: "data_get" + } + }); + } + + /** + * @en Update game data + * @zh 批量更新基础游戏数据 + * @param data 要更新的数据 + * @param merge 是否合并更新(默认true) + * @return Promise>> + */ + public static async updateGameData(data: Partial, merge: boolean = true): Promise>> { + return await wx?.cloud.callFunction({ + name: 'cocos_cloud', + data: { + cmd: "data_update", + data: data, + merge: merge + } + }); + } + + /** + * @en Add to game data field + * @zh 增加指定字段的数值 + * @param field 字段名 + * @param amount 增加的数量 + * @return Promise>> + */ + public static async addGameDataField(field: keyof GameData, amount: number): Promise>> { + return await wx?.cloud.callFunction({ + name: 'cocos_cloud', + data: { + cmd: "data_add", + field: field, + amount: amount + } + }); + } + + /** + * @en Spend game data field + * @zh 消耗指定字段的数值(会检查是否足够) + * @param field 字段名 + * @param amount 消耗的数量 + * @return Promise>> + */ + public static async spendGameDataField(field: keyof GameData, amount: number): Promise>> { + return await wx?.cloud.callFunction({ + name: 'cocos_cloud', + data: { + cmd: "data_spend", + field: field, + amount: amount + } + }); + } + + /** + * @en Set game data field + * @zh 直接设置某个字段的值 + * @param field 字段名 + * @param value 新的值 + * @return Promise>> + */ + public static async setGameDataField(field: keyof GameData, value: any): Promise>> { + return await wx?.cloud.callFunction({ + name: 'cocos_cloud', + data: { + cmd: "data_set", + field: field, + value: value + } + }); + } + + /** + * @en Reset game data + * @zh 重置基础游戏数据为默认值 + * @return Promise>> + */ + public static async resetGameData(): Promise>> { + return await wx?.cloud.callFunction({ + name: 'cocos_cloud', + data: { + cmd: "data_reset" + } + }); + } + + // 便捷方法:金币操作 + /** + * @en Add gold + * @zh 增加金币 + * @param amount 金币数量 + */ + public static async addGold(amount: number) { + return await this.addGameDataField('gold', amount); + } + + /** + * @en Spend gold + * @zh 消耗金币 + * @param amount 金币数量 + */ + public static async spendGold(amount: number) { + return await this.spendGameDataField('gold', amount); + } + + // 便捷方法:钻石操作 + /** + * @en Add diamond + * @zh 增加钻石 + * @param amount 钻石数量 + */ + public static async addDiamond(amount: number) { + return await this.addGameDataField('diamond', amount); + } + + /** + * @en Spend diamond + * @zh 消耗钻石 + * @param amount 钻石数量 + */ + public static async spendDiamond(amount: number) { + return await this.spendGameDataField('diamond', amount); + } + + // ==================== 出战英雄接口 ==================== + + /** + * @en Get fight heros + * @zh 获取出战英雄配置 + * @return Promise>> + */ + public static async getFightHeros(): Promise>> { + return await wx?.cloud.callFunction({ + name: 'cocos_cloud', + data: { + cmd: "fight_heros_get" + } + }); + } + + /** + * @en Set fight hero + * @zh 设置指定位置的出战英雄 + * @param position 出战位置 (0-4) + * @param heroId 英雄ID,0表示移除 + * @return Promise>> + */ + public static async setFightHero(position: number, heroId: number): Promise>> { + return await wx?.cloud.callFunction({ + name: 'cocos_cloud', + data: { + cmd: "fight_hero_set", + position: position, + hero_id: heroId + } + }); + } + + /** + * @en Update fight heros + * @zh 批量更新出战英雄配置 + * @param fightHeros 出战英雄配置对象 + * @return Promise>> + */ + public static async updateFightHeros(fightHeros: Partial): Promise>> { + return await wx?.cloud.callFunction({ + name: 'cocos_cloud', + data: { + cmd: "fight_heros_update", + fight_heros: fightHeros + } + }); + } + + /** + * @en Get active fight heros + * @zh 获取当前出战的英雄列表(不包含空位) + * @return Promise, total_count: number}>>> + */ + public static async getActiveFightHeros(): Promise, + total_count: number + }>>> { + return await wx?.cloud.callFunction({ + name: 'cocos_cloud', + data: { + cmd: "fight_heros_active" + } + }); + } + + /** + * @en Swap fight heros + * @zh 交换两个出战位置的英雄 + * @param position1 位置1 (0-4) + * @param position2 位置2 (0-4) + * @return Promise>> + */ + public static async swapFightHeros(position1: number, position2: number): Promise>> { + return await wx?.cloud.callFunction({ + name: 'cocos_cloud', + data: { + cmd: "fight_heros_swap", + position1: position1, + position2: position2 + } + }); + } + + /** + * @en Reset fight heros + * @zh 重置出战英雄配置为默认值 + * @return Promise>> + */ + public static async resetFightHeros(): Promise>> { + return await wx?.cloud.callFunction({ + name: 'cocos_cloud', + data: { + cmd: "fight_heros_reset" + } + }); + } + + // ==================== 英雄管理接口 ==================== + + /** + * @en Get all heros + * @zh 获取用户拥有的所有英雄数据 + * @return Promise>> + */ + public static async getHeros(): Promise>> { + return await wx?.cloud.callFunction({ + name: 'cocos_cloud', + data: { + cmd: "heros_get" + } + }); + } + + /** + * @en Get single hero + * @zh 获取指定英雄的详细数据 + * @param heroId 英雄ID + * @return Promise>> + */ + public static async getHero(heroId: number): Promise>> { + return await wx?.cloud.callFunction({ + name: 'cocos_cloud', + data: { + cmd: "hero_get", + hero_id: heroId + } + }); + } + + /** + * @en Add new hero + * @zh 添加新英雄到用户库存 + * @param heroId 英雄ID + * @param heroData 英雄数据(可选) + * @return Promise>> + */ + public static async addHero(heroId: number, heroData?: Partial): Promise>> { + return await wx?.cloud.callFunction({ + name: 'cocos_cloud', + data: { + cmd: "hero_add", + hero_id: heroId, + hero_data: heroData + } + }); + } + + /** + * @en Update hero + * @zh 批量更新英雄的多个属性 + * @param heroId 英雄ID + * @param updateData 要更新的属性 + * @return Promise>> + */ + public static async updateHero(heroId: number, updateData: Partial): Promise>> { + return await wx?.cloud.callFunction({ + name: 'cocos_cloud', + data: { + cmd: "hero_update", + hero_id: heroId, + update_data: updateData + } + }); + } + + /** + * @en Set hero property + * @zh 设置英雄的单个属性值 + * @param heroId 英雄ID + * @param property 属性名 + * @param value 属性值 + * @return Promise>> + */ + public static async setHeroProperty(heroId: number, property: keyof HeroData, value: any): Promise>> { + return await wx?.cloud.callFunction({ + name: 'cocos_cloud', + data: { + cmd: "hero_property_set", + hero_id: heroId, + property: property, + value: value + } + }); + } + + /** + * @en Level up hero + * @zh 英雄升级指定级数 + * @param heroId 英雄ID + * @param levels 升级级数(默认1级) + * @return Promise>> + */ + public static async levelUpHero(heroId: number, exp:number,gold:number,levels: number = 1): Promise>> { + return await wx?.cloud.callFunction({ + name: 'cocos_cloud', + data: { + cmd: "hero_levelup", + hero_id: heroId, + exp: exp, + gold:gold, + levels: levels + } + }); + } + + /** + * @en Delete hero + * @zh 删除指定英雄(会检查是否在出战阵容中) + * @param heroId 英雄ID + * @return Promise>> + */ + public static async deleteHero(heroId: number): Promise>> { + return await wx?.cloud.callFunction({ + name: 'cocos_cloud', + data: { + cmd: "hero_delete", + hero_id: heroId + } + }); + } + + /** + * @en Get owned hero IDs + * @zh 获取用户拥有的所有英雄ID + * @return Promise>> + */ + public static async getOwnedHeroIds(): Promise>> { + return await wx?.cloud.callFunction({ + name: 'cocos_cloud', + data: { + cmd: "heros_owned" + } + }); + } + + // ==================== 兼容旧接口 ==================== + + /** + * @en Save game data to the cloud (Legacy) + * @zh 把客户端数据写入云,此为全覆盖写入,请自行管理完整数据(兼容旧接口) + * @param gameData 游戏数据 + * @return Promise>> */ public static async save(gameData: any): Promise>> { return await wx?.cloud.callFunction({ name: 'cocos_cloud', @@ -81,4 +607,284 @@ export class WxCloudApi{ } }); } + + // ==================== 库存管理接口 (items, tals, equips) ==================== + + /** + * @en Get inventory + * @zh 获取指定类型的所有库存数据 + * @param type 库存类型 ('items', 'tals', 'equips') + * @return Promise>> + */ + public static async getInventory(type: InventoryType): Promise>> { + return await wx?.cloud.callFunction({ + name: 'cocos_cloud', + data: { + cmd: "inventory_get", + type: type + } + }); + } + + /** + * @en Get inventory item + * @zh 获取指定物品的数量 + * @param type 库存类型 + * @param itemId 物品ID + * @return Promise>> + */ + public static async getInventoryItem(type: InventoryType, itemId: number): Promise>> { + return await wx?.cloud.callFunction({ + name: 'cocos_cloud', + data: { + cmd: "inventory_item_get", + type: type, + item_id: itemId + } + }); + } + + /** + * @en Add inventory item + * @zh 增加指定物品的数量 + * @param type 库存类型 + * @param itemId 物品ID + * @param count 添加数量 + * @return Promise>> + */ + public static async addInventoryItem(type: InventoryType, itemId: number, count: number): Promise>> { + return await wx?.cloud.callFunction({ + name: 'cocos_cloud', + data: { + cmd: "inventory_item_add", + type: type, + item_id: itemId, + count: count + } + }); + } + + /** + * @en Consume inventory item + * @zh 消耗指定数量的物品(会检查是否足够) + * @param type 库存类型 + * @param itemId 物品ID + * @param count 消耗数量 + * @return Promise>> + */ + public static async consumeInventoryItem(type: InventoryType, itemId: number, count: number): Promise>> { + return await wx?.cloud.callFunction({ + name: 'cocos_cloud', + data: { + cmd: "inventory_item_consume", + type: type, + item_id: itemId, + count: count + } + }); + } + + /** + * @en Set inventory item + * @zh 直接设置物品的数量 + * @param type 库存类型 + * @param itemId 物品ID + * @param count 新的数量 + * @return Promise>> + */ + public static async setInventoryItem(type: InventoryType, itemId: number, count: number): Promise>> { + return await wx?.cloud.callFunction({ + name: 'cocos_cloud', + data: { + cmd: "inventory_item_set", + type: type, + item_id: itemId, + count: count + } + }); + } + + /** + * @en Update inventory + * @zh 批量更新多个物品的数量 + * @param type 库存类型 + * @param data 更新数据对象 + * @param merge 是否合并更新(默认true) + * @return Promise>> + */ + public static async updateInventory(type: InventoryType, data: Partial, merge: boolean = true): Promise>> { + return await wx?.cloud.callFunction({ + name: 'cocos_cloud', + data: { + cmd: "inventory_update", + type: type, + data: data, + merge: merge + } + }); + } + + /** + * @en Reset inventory + * @zh 重置指定类型的库存为默认值 + * @param type 库存类型 + * @return Promise>> + */ + public static async resetInventory(type: InventoryType): Promise>> { + return await wx?.cloud.callFunction({ + name: 'cocos_cloud', + data: { + cmd: "inventory_reset", + type: type + } + }); + } + + /** + * @en Get owned items + * @zh 获取数量大于0的物品列表 + * @param type 库存类型 + * @return Promise, total_types: number}>>> + */ + public static async getOwnedItems(type: InventoryType): Promise, + total_types: number + }>>> { + return await wx?.cloud.callFunction({ + name: 'cocos_cloud', + data: { + cmd: "inventory_owned", + type: type + } + }); + } + + // ==================== 便捷方法:道具操作 ==================== + + /** + * @en Get items + * @zh 获取所有道具数据 + */ + public static async getItems() { + return await this.getInventory('items'); + } + + /** + * @en Add item + * @zh 添加道具 + * @param itemId 道具ID + * @param count 数量 + */ + public static async addItem(itemId: number, count: number) { + return await this.addInventoryItem('items', itemId, count); + } + + /** + * @en Consume item + * @zh 消耗道具 + * @param itemId 道具ID + * @param count 数量 + */ + public static async consumeItem(itemId: number, count: number) { + return await this.consumeInventoryItem('items', itemId, count); + } + + // ==================== 便捷方法:天赋操作 ==================== + + /** + * @en Get talents + * @zh 获取所有天赋数据 + */ + public static async getTalents() { + return await this.getInventory('tals'); + } + + /** + * @en Add talent + * @zh 添加天赋点 + * @param talId 天赋ID + * @param count 数量 + */ + public static async addTalent(talId: number, count: number) { + return await this.addInventoryItem('tals', talId, count); + } + + /** + * @en Consume talent + * @zh 消耗天赋点 + * @param talId 天赋ID + * @param count 数量 + */ + public static async consumeTalent(talId: number, count: number) { + return await this.consumeInventoryItem('tals', talId, count); + } + + // ==================== 便捷方法:装备操作 ==================== + + /** + * @en Get equipments + * @zh 获取所有装备数据 + */ + public static async getEquipments() { + return await this.getInventory('equips'); + } + + /** + * @en Add equipment + * @zh 添加装备 + * @param equipId 装备ID + * @param count 数量 + */ + public static async addEquipment(equipId: number, count: number) { + return await this.addInventoryItem('equips', equipId, count); + } + + /** + * @en Consume equipment + * @zh 消耗装备 + * @param equipId 装备ID + * @param count 数量 + */ + public static async consumeEquipment(equipId: number, count: number) { + return await this.consumeInventoryItem('equips', equipId, count); + } + + // ==================== 其他便捷方法 ==================== + + /** + * @en Load game data (Legacy compatible) + * @zh 加载游戏数据(兼容旧接口) + */ + public static async load() { + return await this.login(); + } + + /** + * @en Get all game data at once + * @zh 一次性获取所有游戏数据 + * @return Promise>> + */ + public static async getAllGameData(): Promise>> { + return await this.login(); + } } \ No newline at end of file diff --git a/assets/script/game/wx_clound_client_api/WxCloudApi.ts.meta b/assets/script/game/wx_clound_client_api/WxCloudApi.ts.meta index 22af3c90..23d8bd19 100644 --- a/assets/script/game/wx_clound_client_api/WxCloudApi.ts.meta +++ b/assets/script/game/wx_clound_client_api/WxCloudApi.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "0b5acaf6-aa85-428d-a38c-97bf645cc1db", diff --git a/assets/script/game/wx_clound_client_api/wx.aip.d.ts.meta b/assets/script/game/wx_clound_client_api/wx.aip.d.ts.meta index 7659ce9c..c5d500b0 100644 --- a/assets/script/game/wx_clound_client_api/wx.aip.d.ts.meta +++ b/assets/script/game/wx_clound_client_api/wx.aip.d.ts.meta @@ -1,5 +1,5 @@ { - "ver": "4.0.23", + "ver": "4.0.24", "importer": "typescript", "imported": true, "uuid": "845c60fa-24b5-49c9-85d3-ef55ed459817", diff --git a/assets/script/heros.md.meta b/assets/script/heros.md.meta index 172186e6..538ca76c 100644 --- a/assets/script/heros.md.meta +++ b/assets/script/heros.md.meta @@ -1,5 +1,5 @@ { - "ver": "1.0.2", + "ver": "1.0.1", "importer": "text", "imported": true, "uuid": "26a4b42d-75ab-44bc-b368-2fae9d83f9cd", diff --git a/assets/script/todo.md.meta b/assets/script/todo.md.meta index 0aa35d76..21e274b4 100644 --- a/assets/script/todo.md.meta +++ b/assets/script/todo.md.meta @@ -1,5 +1,5 @@ { - "ver": "1.0.2", + "ver": "1.0.1", "importer": "text", "imported": true, "uuid": "fb132ece-b235-4872-92f6-7f5f43d793d8", diff --git a/assets/script/wp.md.meta b/assets/script/wp.md.meta index 69ca14f4..46c3ba21 100644 --- a/assets/script/wp.md.meta +++ b/assets/script/wp.md.meta @@ -1,5 +1,5 @@ { - "ver": "1.0.2", + "ver": "1.0.1", "importer": "text", "imported": true, "uuid": "a34c8fe6-ba55-4bcb-b918-14c046cd5ef2", diff --git a/build-templates/wechatgame/cloud_functions/cocos_cloud/API.md b/build-templates/wechatgame/cloud_functions/cocos_cloud/API.md new file mode 100644 index 00000000..49046561 --- /dev/null +++ b/build-templates/wechatgame/cloud_functions/cocos_cloud/API.md @@ -0,0 +1,913 @@ +# 游戏云函数 API 文档 + +## 📋 概述 + +本文档详细说明了游戏云函数的所有可用接口,包括认证、数据管理、英雄系统、库存管理等功能。 + +## 🏗️ 项目结构 + +``` +cocos_cloud/ +├── index.js # 路由入口文件 +├── user_init_data.js # 用户初始化数据配置 +├── modules/ # 功能模块目录 +│ ├── auth.js # 认证模块 +│ ├── gameData.js # 基础游戏数据模块 +│ ├── fightHeros.js # 出战英雄模块 +│ ├── heros.js # 英雄管理模块 +│ ├── inventory.js # 库存管理模块 +│ └── response.js # 响应处理模块 +├── README.md # 项目说明文档 +└── API.md # API接口文档 +``` + +## 🚀 通用调用格式 + +```javascript +wx.cloud.callFunction({ + name: 'cocos_cloud', + data: { + cmd: '命令名', + // 其他参数... + } +}).then(res => { + console.log('调用结果:', res.result); +}).catch(err => { + console.error('调用失败:', err); +}); +``` + +## 📊 通用响应格式 + +```javascript +{ + code: 200, // 状态码 (200=成功, 负数=错误) + msg: "Success", // 响应消息 + data: { /* 返回数据 */ }, // 具体数据 + timestamp: 1234567890, // 时间戳 + version: "1.0.0", // 数据版本 + execution_time: 50 // 执行时间(ms) +} +``` + +## 🔐 认证相关接口 + +### 1. 用户登录 +获取用户完整信息和游戏数据。 + +```javascript +// 请求 +{ cmd: 'login' } + +// 响应 +{ + code: 200, + data: { + user_id: "用户ID", + openid: "微信OpenID", + regist_time: 1234567890, + data: { /* 基础游戏数据 */ }, + fight_heros: { /* 出战英雄配置 */ }, + heros: { /* 英雄属性数据 */ }, + items: { /* 道具数据 */ }, + tals: { /* 天赋数据 */ }, + equips: { /* 装备数据 */ }, + data_version: "1.0.0", + last_save_time: 1234567890 + } +} +``` + +### 2. 获取用户信息 +获取用户基本信息(不包含游戏数据)。 + +```javascript +// 请求 +{ cmd: 'user_info' } + +// 响应 +{ + code: 200, + data: { + user_id: "用户ID", + openid: "微信OpenID", + regist_time: 1234567890, + init_time: 1234567890, + data_version: "1.0.0", + last_save_time: 1234567890 + } +} +``` + +### 3. 检查版本信息 +检查用户数据版本兼容性。 + +```javascript +// 请求 +{ cmd: 'version' } + +// 响应 +{ + code: 200, + data: { + user_version: "1.0.0", + current_version: "1.1.0", + compatibility: { + compatible: true, + needsUpgrade: true, + message: "Minor version update available" + }, + init_time: 1234567890, + regist_time: 1234567890, + last_save_time: 1234567890 + } +} +``` + +### 4. 强制升级数据 +手动触发用户数据结构升级。 + +```javascript +// 请求 +{ cmd: 'upgrade' } + +// 响应 +{ + code: 200, + data: { + old_version: "1.0.0", + new_version: "1.1.0", + upgrade_time: 1234567890, + // ... 升级后的完整数据 + } +} +``` + +## 🎮 基础游戏数据接口 + +### 1. 获取游戏数据 +获取用户的基础游戏数据(金币、钻石、经验等)。 + +```javascript +// 请求 +{ cmd: 'data_get' } + +// 响应 +{ + code: 200, + data: { + score: 0, + mission: 1, + gold: 100, + diamond: 100, + meat: 0, + exp: 0, + // ... 更多字段 + } +} +``` + +### 2. 更新游戏数据 +批量更新基础游戏数据。 + +```javascript +// 请求 +{ + cmd: 'data_update', + data: { + gold: 1000, + diamond: 200, + exp: 500 + }, + merge: true // 可选,默认true(合并更新) +} + +// 响应 +{ + code: 200, + data: { + // 更新后的完整数据 + } +} +``` + +### 3. 增加指定字段 +增加某个字段的数值。 + +```javascript +// 请求 +{ + cmd: 'data_add', + field: 'gold', + amount: 100 +} + +// 响应 +{ + code: 200, + data: { + field: 'gold', + old_value: 1000, + new_value: 1100, + change: 100 + } +} +``` + +### 4. 消耗指定字段 +消耗某个字段的数值(会检查是否足够)。 + +```javascript +// 请求 +{ + cmd: 'data_spend', + field: 'gold', + amount: 50 +} + +// 响应 +{ + code: 200, + data: { + field: 'gold', + old_value: 1100, + new_value: 1050, + change: -50 + } +} +``` + +### 5. 设置指定字段 +直接设置某个字段的值。 + +```javascript +// 请求 +{ + cmd: 'data_set', + field: 'mission', + value: 5 +} + +// 响应 +{ + code: 200, + data: { + field: 'mission', + old_value: 1, + new_value: 5 + } +} +``` + +### 6. 重置游戏数据 +重置基础游戏数据为默认值。 + +```javascript +// 请求 +{ cmd: 'data_reset' } + +// 响应 +{ + code: 200, + data: { + // 重置后的默认数据 + } +} +``` + +## ⚔️ 出战英雄接口 + +### 1. 获取出战英雄配置 +获取当前的出战英雄配置。 + +```javascript +// 请求 +{ cmd: 'fight_heros_get' } + +// 响应 +{ + code: 200, + data: { + 0: 5001, // 位置0: 英雄5001 + 1: 5005, // 位置1: 英雄5005 + 2: 0, // 位置2: 空 + 3: 0, // 位置3: 空 + 4: 0 // 位置4: 空 + } +} +``` + +### 2. 设置单个出战英雄 +设置指定位置的出战英雄。 + +```javascript +// 请求 +{ + cmd: 'fight_hero_set', + position: 2, + hero_id: 5007 +} + +// 响应 +{ + code: 200, + data: { + position: 2, + old_hero_id: 0, + new_hero_id: 5007 + } +} +``` + +### 3. 批量更新出战英雄 +批量更新多个位置的出战英雄。 + +```javascript +// 请求 +{ + cmd: 'fight_heros_update', + fight_heros: { + 0: 5001, + 1: 5005, + 2: 5007 + } +} + +// 响应 +{ + code: 200, + data: { + // 更新后的完整出战配置 + } +} +``` + +### 4. 获取激活的出战英雄 +获取当前出战的英雄列表(不包含空位)。 + +```javascript +// 请求 +{ cmd: 'fight_heros_active' } + +// 响应 +{ + code: 200, + data: { + active_heros: [ + { + position: 0, + hero_id: 5001, + hero_data: { /* 英雄详细数据 */ } + }, + { + position: 1, + hero_id: 5005, + hero_data: { /* 英雄详细数据 */ } + } + ], + total_count: 2 + } +} +``` + +### 5. 交换出战英雄位置 +交换两个位置的英雄。 + +```javascript +// 请求 +{ + cmd: 'fight_heros_swap', + position1: 0, + position2: 2 +} + +// 响应 +{ + code: 200, + data: { + position1: 0, + position2: 2, + hero1_moved_to: 5007, + hero2_moved_to: 5001 + } +} +``` + +### 6. 重置出战英雄 +重置出战英雄配置为默认值。 + +```javascript +// 请求 +{ cmd: 'fight_heros_reset' } + +// 响应 +{ + code: 200, + data: { + // 重置后的默认配置 + } +} +``` + +## 🦸 英雄管理接口 + +### 1. 获取所有英雄 +获取用户拥有的所有英雄数据。 + +```javascript +// 请求 +{ cmd: 'heros_get' } + +// 响应 +{ + code: 200, + data: { + 5001: { uuid: 5001, lv: 10, exp: 500, star: 2, power: 150 }, + 5005: { uuid: 5005, lv: 8, exp: 300, star: 1, power: 120 }, + 5007: { uuid: 5007, lv: 1, exp: 0, star: 1, power: 90 } + } +} +``` + +### 2. 获取单个英雄 +获取指定英雄的详细数据。 + +```javascript +// 请求 +{ + cmd: 'hero_get', + hero_id: 5001 +} + +// 响应 +{ + code: 200, + data: { + uuid: 5001, + lv: 10, + exp: 500, + star: 2, + power: 150 + } +} +``` + +### 3. 添加新英雄 +添加新英雄到用户库存。 + +```javascript +// 请求 +{ + cmd: 'hero_add', + hero_id: 5008, + hero_data: { // 可选,不提供则使用默认数据 + lv: 1, + exp: 0, + star: 1, + power: 110 + } +} + +// 响应 +{ + code: 200, + data: { + uuid: 5008, + lv: 1, + exp: 0, + star: 1, + power: 110 + } +} +``` + +### 4. 更新英雄属性 +批量更新英雄的多个属性。 + +```javascript +// 请求 +{ + cmd: 'hero_update', + hero_id: 5001, + update_data: { + lv: 15, + exp: 800, + star: 3 + } +} + +// 响应 +{ + code: 200, + data: { + old_data: { /* 更新前的数据 */ }, + new_data: { /* 更新后的数据 */ } + } +} +``` + +### 5. 设置英雄单个属性 +设置英雄的单个属性值。 + +```javascript +// 请求 +{ + cmd: 'hero_property_set', + hero_id: 5001, + property: 'lv', + value: 20 +} + +// 响应 +{ + code: 200, + data: { + hero_id: 5001, + property: 'lv', + old_value: 15, + new_value: 20 + } +} +``` + +### 6. 英雄升级 +英雄升级指定级数。 + +```javascript +// 请求 +{ + cmd: 'hero_levelup', + hero_id: 5001, + levels: 3 // 可选,默认1级 +} + +// 响应 +{ + code: 200, + data: { + hero_id: 5001, + property: 'lv', + old_value: 20, + new_value: 23 + } +} +``` + +### 7. 删除英雄 +删除指定英雄(会检查是否在出战阵容中)。 + +```javascript +// 请求 +{ + cmd: 'hero_delete', + hero_id: 5008 +} + +// 响应 +{ + code: 200, + data: { + // 被删除的英雄数据 + } +} +``` + +### 8. 获取拥有的英雄ID列表 +获取用户拥有的所有英雄ID。 + +```javascript +// 请求 +{ cmd: 'heros_owned' } + +// 响应 +{ + code: 200, + data: { + hero_ids: [5001, 5005, 5007], + total_count: 3 + } +} +``` + +## 🎒 库存管理接口 + +库存管理接口支持三种类型的数据: +- `items`: 道具 +- `tals`: 天赋 +- `equips`: 装备 + +### 1. 获取库存数据 +获取指定类型的所有库存数据。 + +```javascript +// 请求 +{ + cmd: 'inventory_get', + type: 'items' // 'items', 'tals', 'equips' +} + +// 响应 +{ + code: 200, + data: { + 1001: 5, // 道具1001: 5个 + 1002: 3, // 道具1002: 3个 + 1003: 0, // 道具1003: 0个 + // ... + } +} +``` + +### 2. 获取单个物品 +获取指定物品的数量。 + +```javascript +// 请求 +{ + cmd: 'inventory_item_get', + type: 'items', + item_id: 1001 +} + +// 响应 +{ + code: 200, + data: { + item_id: 1001, + count: 5 + } +} +``` + +### 3. 添加物品 +增加指定物品的数量。 + +```javascript +// 请求 +{ + cmd: 'inventory_item_add', + type: 'items', + item_id: 1001, + count: 10 +} + +// 响应 +{ + code: 200, + data: { + item_id: 1001, + old_count: 5, + new_count: 15, + added: 10 + } +} +``` + +### 4. 消耗物品 +消耗指定数量的物品(会检查是否足够)。 + +```javascript +// 请求 +{ + cmd: 'inventory_item_consume', + type: 'items', + item_id: 1001, + count: 3 +} + +// 响应 +{ + code: 200, + data: { + item_id: 1001, + old_count: 15, + new_count: 12, + added: -3 + } +} +``` + +### 5. 设置物品数量 +直接设置物品的数量。 + +```javascript +// 请求 +{ + cmd: 'inventory_item_set', + type: 'items', + item_id: 1001, + count: 20 +} + +// 响应 +{ + code: 200, + data: { + item_id: 1001, + old_count: 12, + new_count: 20 + } +} +``` + +### 6. 批量更新库存 +批量更新多个物品的数量。 + +```javascript +// 请求 +{ + cmd: 'inventory_update', + type: 'items', + data: { + 1001: 25, + 1002: 10, + 1003: 5 + }, + merge: true // 可选,默认true(合并更新) +} + +// 响应 +{ + code: 200, + data: { + // 更新后的完整库存数据 + } +} +``` + +### 7. 重置库存 +重置指定类型的库存为默认值。 + +```javascript +// 请求 +{ + cmd: 'inventory_reset', + type: 'items' +} + +// 响应 +{ + code: 200, + data: { + // 重置后的默认库存数据 + } +} +``` + +### 8. 获取拥有的物品 +获取数量大于0的物品列表。 + +```javascript +// 请求 +{ + cmd: 'inventory_owned', + type: 'items' +} + +// 响应 +{ + code: 200, + data: { + owned_items: [ + { item_id: 1001, count: 25 }, + { item_id: 1002, count: 10 }, + { item_id: 1003, count: 5 } + ], + total_types: 3 + } +} +``` + +## 🔄 兼容旧接口 + +为了保持向后兼容,保留了一些旧接口: + +### 1. 加载数据 (兼容) +等同于 `login` 命令。 + +```javascript +// 请求 +{ cmd: 'load' } + +// 响应:与login相同 +``` + +### 2. 保存数据 (兼容) +批量保存多种类型的数据。 + +```javascript +// 请求 +{ + cmd: 'save', + data: { + data: { gold: 1000, diamond: 200 }, + fight_heros: { 0: 5001, 1: 5005 }, + heros: { 5001: { lv: 10, exp: 500 } }, + items: { 1001: 10, 1002: 5 }, + tals: { 1001: 1 }, + equips: { 1001: 2 } + } +} + +// 响应 +{ + code: 200, + data: { + results: [ + // 各个模块的保存结果 + ] + }, + msg: "All data saved successfully" +} +``` + +## ❌ 错误码说明 + +| 错误码 | 说明 | 示例 | +|-------|------|------| +| 200 | 成功 | 操作成功完成 | +| -1 | 操作失败 | 数据库更新失败 | +| -2 | 未知命令 | 命令不存在 | +| -3 | 参数错误 | 缺少必需参数或参数格式错误 | +| -4 | 用户未找到 | 用户不存在或创建失败 | +| -5 | 系统错误 | 服务器内部错误 | +| -6 | 资源不足 | 金币、道具等资源不够 | +| -7 | 资源已存在 | 英雄已存在等 | +| -8 | 操作被拒绝 | 英雄正在出战中无法删除等 | + +## 📝 使用示例 + +### 完整的游戏流程示例 + +```javascript +// 1. 用户登录 +wx.cloud.callFunction({ + name: 'cocos_cloud', + data: { cmd: 'login' } +}).then(res => { + console.log('用户登录成功:', res.result.data); + + // 2. 增加金币 + return wx.cloud.callFunction({ + name: 'cocos_cloud', + data: { + cmd: 'data_add', + field: 'gold', + amount: 100 + } + }); +}).then(res => { + console.log('金币增加成功:', res.result.data); + + // 3. 添加新英雄 + return wx.cloud.callFunction({ + name: 'cocos_cloud', + data: { + cmd: 'hero_add', + hero_id: 5008 + } + }); +}).then(res => { + console.log('英雄添加成功:', res.result.data); + + // 4. 设置出战英雄 + return wx.cloud.callFunction({ + name: 'cocos_cloud', + data: { + cmd: 'fight_hero_set', + position: 2, + hero_id: 5008 + } + }); +}).then(res => { + console.log('出战英雄设置成功:', res.result.data); +}).catch(err => { + console.error('操作失败:', err); +}); +``` + +## 🔧 开发调试 + +### 1. 启用调试日志 +在开发环境中,云函数会输出详细的调试日志: + +```javascript +// 请求日志 +[data_add] Request from oxxx: { field: 'gold', amount: 100 } + +// 响应日志 +[data_add] Response (45ms): 200 gold updated successfully +``` + +### 2. 性能监控 +每个响应都包含 `execution_time` 字段,显示接口执行时间。 + +### 3. 版本管理 +使用 `version` 命令检查数据版本兼容性,确保客户端和服务端数据结构一致。 + +--- + +**版本**: 1.0.0 +**更新时间**: 2024年 +**维护者**: 游戏开发团队 + diff --git a/build-templates/wechatgame/cloud_functions/cocos_cloud/README.md b/build-templates/wechatgame/cloud_functions/cocos_cloud/README.md new file mode 100644 index 00000000..f0cafa11 --- /dev/null +++ b/build-templates/wechatgame/cloud_functions/cocos_cloud/README.md @@ -0,0 +1,270 @@ +# 微信云函数游戏数据管理系统 + +## 📁 文件结构 + +``` +cocos_cloud/ +├── index.js # 主云函数文件 +├── user_init_data.js # 新用户初始化数据配置 +└── README.md # 说明文档 +``` + +## 🎮 功能特性 + +### 1. 数据结构管理 +- **平级数据存储**: 所有游戏数据字段与用户基本信息平级存储 +- **版本控制**: 支持数据结构版本管理和自动升级 +- **数据验证**: 完整的数据结构和类型验证 +- **默认值管理**: 集中管理新用户初始化数据 + +### 2. 支持的命令 + +| 命令 | 功能 | 说明 | +|------|------|------| +| `login` | 用户登录 | 返回完整的用户和游戏数据 | +| `load` | 加载游戏数据 | 获取用户的所有游戏数据 | +| `save` | 保存游戏数据 | 支持增量更新,自动合并数据 | +| `reset` | 重置游戏数据 | 恢复为默认初始值 | +| `backup` | 创建数据备份 | 在独立集合中创建备份记录 | +| `version` | 查看版本信息 | 检查数据版本兼容性 | +| `upgrade` | 强制升级数据 | 手动触发数据结构升级 | + +## 📊 数据结构 + +### 用户数据库结构 (cocos_users 集合) +```javascript +{ + _id: "用户ID", + _openid: "微信OpenID", + regist_time: "注册时间戳", + init_time: "初始化时间戳", + last_save_time: "最后保存时间", + data_version: "数据版本号", + + // 游戏数据字段(与基本信息平级) + data: { + score: 0, // 游戏分数 + mission: 1, // 当前关卡 + gold: 100, // 金币 + diamond: 100, // 钻石 + meat: 0, // 肉类资源 + exp: 0, // 升级经验 + ghstone: 0, // 绿色英雄石 + bhstone: 0, // 蓝色英雄石 + phlestone: 0, // 紫色英雄石 + rhstone: 0, // 红色英雄石 + herocard: 0, // 英雄卡 + ckey: 0, // 铜钥匙 + skey: 0, // 银钥匙 + gkey: 0 // 金钥匙 + }, + fight_heros: { + 0: 5001, // 出战位置1 + 1: 5005, // 出战位置2 + 2: 0, // 出战位置3(空) + 3: 0, // 出战位置4(空) + 4: 0 // 出战位置5(空) + }, + heros: { + 5001: { uuid: 5001, lv: 1, exp: 0, star: 1, power: 100 }, + 5005: { uuid: 5005, lv: 1, exp: 0, star: 1, power: 120 }, + 5007: { uuid: 5007, lv: 1, exp: 0, star: 1, power: 90 } + }, + items: { + 1001: 0, // 生命药水 + 1002: 0, // 魔法药水 + 1003: 0, // 力量药水 + // ... 更多道具 + }, + tals: { + 1001: 0, // 攻击强化 + 1002: 0, // 防御强化 + 1003: 0, // 生命强化 + // ... 更多天赋 + }, + equips: { + 1001: 0, // 武器 + 1002: 0, // 头盔 + 1003: 0, // 胸甲 + // ... 更多装备 + } +} +``` + +### 备份数据库结构 (game_backups 集合) +```javascript +{ + user_id: "用户ID", + openid: "微信OpenID", + data: { /* 基础游戏数据 */ }, + fight_heros: { /* 出战英雄配置 */ }, + heros: { /* 英雄属性数据 */ }, + items: { /* 道具数据 */ }, + tals: { /* 天赋数据 */ }, + equips: { /* 装备数据 */ }, + backup_time: "备份时间戳", + original_save_time: "原始保存时间" +} +``` + +## 🚀 使用示例 + +### 客户端调用示例 + +#### 1. 用户登录 +```javascript +wx.cloud.callFunction({ + name: 'cocos_cloud', + data: { cmd: 'login' } +}).then(res => { + console.log('登录成功:', res.result); + // res.result.data 包含完整的用户和游戏数据 +}); +``` + +#### 2. 保存游戏数据 +```javascript +wx.cloud.callFunction({ + name: 'cocos_cloud', + data: { + cmd: 'save', + data: { + data: { gold: 1000, diamond: 50 }, + fight_heros: { 0: 5001, 1: 5005 }, + heros: { 5001: { lv: 10, exp: 100 } }, + items: { 1001: 5 } + } + } +}); +``` + +#### 3. 加载游戏数据 +```javascript +wx.cloud.callFunction({ + name: 'cocos_cloud', + data: { cmd: 'load' } +}).then(res => { + const gameData = res.result.data; + console.log('游戏数据:', gameData); +}); +``` + +#### 4. 检查版本信息 +```javascript +wx.cloud.callFunction({ + name: 'cocos_cloud', + data: { cmd: 'version' } +}).then(res => { + console.log('版本信息:', res.result.data); + if (res.result.data.compatibility.needsUpgrade) { + console.log('需要升级数据'); + } +}); +``` + +#### 5. 创建数据备份 +```javascript +wx.cloud.callFunction({ + name: 'cocos_cloud', + data: { cmd: 'backup' } +}).then(res => { + console.log('备份成功:', res.result.data.backup_id); +}); +``` + +## 🔧 配置管理 + +### 修改默认数据 +编辑 `user_init_data.js` 文件中的常量: + +```javascript +// 修改默认金币数量 +const DEFAULT_GAME_DATA = { + // ... + gold: 200, // 从100改为200 + // ... +}; + +// 添加新英雄 +const DEFAULT_HEROS = { + // 现有英雄... + 5008: { uuid: 5008, lv: 1, exp: 0, star: 1, power: 110 } +}; +``` + +### 版本升级 +当数据结构发生变化时,更新版本号: + +```javascript +// 在 user_init_data.js 中 +const DATA_VERSION = "1.1.0"; // 从1.0.0升级到1.1.0 +``` + +## 📈 版本控制 + +### 版本号格式 +- **MAJOR.MINOR.PATCH** (如: 1.2.3) +- **MAJOR**: 重大结构变更,不向后兼容 +- **MINOR**: 新增字段,向后兼容 +- **PATCH**: 数值调整,完全兼容 + +### 自动升级机制 +- 用户登录时自动检查版本兼容性 +- 如需升级,自动合并新的默认数据 +- 保留用户的现有数据,只补充缺失字段 + +## 🛡️ 错误处理 + +### 错误码说明 +- `200`: 成功 +- `-1`: 操作失败 +- `-2`: 未知命令 +- `-3`: 数据结构无效 +- `-4`: 用户创建/获取失败 +- `-5`: 系统错误 + +### 日志记录 +- 新用户创建日志 +- 数据版本升级日志 +- 错误操作日志 +- 性能监控日志 + +## 🔍 调试和监控 + +### 查看用户数据版本 +```javascript +wx.cloud.callFunction({ + name: 'cocos_cloud', + data: { cmd: 'version' } +}); +``` + +### 强制升级用户数据 +```javascript +wx.cloud.callFunction({ + name: 'cocos_cloud', + data: { cmd: 'upgrade' } +}); +``` + +## 📝 注意事项 + +1. **数据备份**: 重要操作前建议创建备份 +2. **版本兼容**: 升级数据结构时注意向后兼容性 +3. **性能优化**: 大量数据操作时注意性能影响 +4. **安全验证**: 所有输入数据都经过严格验证 +5. **错误处理**: 完善的错误处理和日志记录 + +## 🚀 部署说明 + +1. 将整个 `cocos_cloud` 文件夹上传到微信云开发 +2. 在微信开发者工具中部署云函数 +3. 确保数据库权限配置正确 +4. 测试各项功能是否正常工作 + +--- + +**版本**: 1.0.0 +**更新时间**: 2024年 +**维护者**: 游戏开发团队 + diff --git a/build-templates/wechatgame/cloud_functions/cocos_cloud/index.js b/build-templates/wechatgame/cloud_functions/cocos_cloud/index.js index e94f1fcf..fceb921a 100644 --- a/build-templates/wechatgame/cloud_functions/cocos_cloud/index.js +++ b/build-templates/wechatgame/cloud_functions/cocos_cloud/index.js @@ -1,80 +1,272 @@ -// 云函数入口文件 +// 云函数路由入口文件 const cloud = require('wx-server-sdk'); -const user_db_name = "cocos_users"; +// 导入各个模块 +const authModule = require('./modules/auth'); +const gameDataModule = require('./modules/gameData'); +const fightHerosModule = require('./modules/fightHeros'); +const herosModule = require('./modules/heros'); +const inventoryModule = require('./modules/inventory'); +const responseModule = require('./modules/response'); + cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }); // 使用当前云环境 // 云函数入口函数 exports.main = async (event, context) => { - let cmd = event.cmd; - if (cmd == null) { - return { - code: -1, - msg: "no cmd!" - }; - } - + const startTime = Date.now(); + + try { + // 验证命令参数 + const validation = responseModule.validateRequiredParams(event, ['cmd']); + if (validation) { + return validation; + } + + const { cmd, ...params } = event; const wxContext = cloud.getWXContext(); const db = cloud.database({ env: cloud.DYNAMIC_CURRENT_ENV, throwOnNotFound: false }); - const _ = db.command; - - if (cmd === "login") { - let user = await getOrCreaterUser(db, wxContext.OPENID); - return { - code: 200, - data: user, - }; - } else if (cmd === "save") { - let data = event.data; - let user = await getOrCreaterUser(db, wxContext.OPENID); - let saveDataRes = await db.collection(user_db_name).doc(user._id).update({ - data: { - game_data: _.set(data) - } - }); - - console.log("Save data:", saveDataRes, data); - if (saveDataRes?.stats?.updated >= 1) { - return { - code: 200, - data: saveDataRes - }; + + console.log(`[${cmd}] Request from ${wxContext.OPENID}:`, params); + + // 路由分发 + let result; + switch (cmd) { + // ==================== 认证相关 ==================== + case 'login': + result = await authModule.login(db, wxContext); + break; + + case 'user_info': + result = await authModule.getUserInfo(db, wxContext.OPENID); + break; + + case 'version': + result = await authModule.checkVersion(db, wxContext.OPENID); + break; + + case 'upgrade': + result = await authModule.upgradeUserData(db, wxContext.OPENID); + break; + + // ==================== 基础游戏数据 ==================== + case 'data_get': + result = await gameDataModule.getData(db, wxContext.OPENID); + break; + + case 'data_update': + const merge = params.merge !== false; // 默认合并 + result = await gameDataModule.updateData(db, wxContext.OPENID, params.data, merge); + break; + + case 'data_add': + const fieldValidation = responseModule.validateRequiredParams(params, ['field', 'amount']); + if (fieldValidation) return fieldValidation; + result = await gameDataModule.addDataField(db, wxContext.OPENID, params.field, params.amount); + break; + + case 'data_spend': + const spendValidation = responseModule.validateRequiredParams(params, ['field', 'amount']); + if (spendValidation) return spendValidation; + result = await gameDataModule.spendDataField(db, wxContext.OPENID, params.field, params.amount); + break; + + case 'data_set': + const setValidation = responseModule.validateRequiredParams(params, ['field', 'value']); + if (setValidation) return setValidation; + result = await gameDataModule.setDataField(db, wxContext.OPENID, params.field, params.value); + break; + + case 'data_reset': + result = await gameDataModule.resetData(db, wxContext.OPENID); + break; + + // ==================== 出战英雄 ==================== + case 'fight_heros_get': + result = await fightHerosModule.getFightHeros(db, wxContext.OPENID); + break; + + case 'fight_hero_set': + const heroSetValidation = responseModule.validateRequiredParams(params, ['position', 'hero_id']); + if (heroSetValidation) return heroSetValidation; + result = await fightHerosModule.setFightHero(db, wxContext.OPENID, params.position, params.hero_id); + break; + + case 'fight_heros_update': + const herosUpdateValidation = responseModule.validateRequiredParams(params, ['fight_heros']); + if (herosUpdateValidation) return herosUpdateValidation; + result = await fightHerosModule.updateFightHeros(db, wxContext.OPENID, params.fight_heros); + break; + + case 'fight_heros_active': + result = await fightHerosModule.getActiveFightHeros(db, wxContext.OPENID); + break; + + case 'fight_heros_swap': + const swapValidation = responseModule.validateRequiredParams(params, ['position1', 'position2']); + if (swapValidation) return swapValidation; + result = await fightHerosModule.swapFightHeros(db, wxContext.OPENID, params.position1, params.position2); + break; + + case 'fight_heros_reset': + result = await fightHerosModule.resetFightHeros(db, wxContext.OPENID); + break; + + // ==================== 英雄管理 ==================== + case 'heros_get': + result = await herosModule.getHeros(db, wxContext.OPENID); + break; + + case 'hero_get': + const heroGetValidation = responseModule.validateRequiredParams(params, ['hero_id']); + if (heroGetValidation) return heroGetValidation; + result = await herosModule.getHero(db, wxContext.OPENID, params.hero_id); + break; + + case 'hero_add': + const heroAddValidation = responseModule.validateRequiredParams(params, ['hero_id']); + if (heroAddValidation) return heroAddValidation; + result = await herosModule.addHero(db, wxContext.OPENID, params.hero_id, params.hero_data); + break; + + case 'hero_update': + const heroUpdateValidation = responseModule.validateRequiredParams(params, ['hero_id', 'update_data']); + if (heroUpdateValidation) return heroUpdateValidation; + result = await herosModule.updateHero(db, wxContext.OPENID, params.hero_id, params.update_data); + break; + + case 'hero_property_set': + const propValidation = responseModule.validateRequiredParams(params, ['hero_id', 'property', 'value']); + if (propValidation) return propValidation; + result = await herosModule.setHeroProperty(db, wxContext.OPENID, params.hero_id, params.property, params.value); + break; + + case 'hero_levelup': + const levelValidation = responseModule.validateRequiredParams(params, ['hero_id']); + if (levelValidation) return levelValidation; + result = await herosModule.levelUpHero(db, wxContext.OPENID, params.hero_id, params.levels); + break; + + case 'hero_delete': + const deleteValidation = responseModule.validateRequiredParams(params, ['hero_id']); + if (deleteValidation) return deleteValidation; + result = await herosModule.deleteHero(db, wxContext.OPENID, params.hero_id); + break; + + case 'heros_owned': + result = await herosModule.getOwnedHeroIds(db, wxContext.OPENID); + break; + + // ==================== 库存管理 (items, tals, equips) ==================== + case 'inventory_get': + const invGetValidation = responseModule.validateRequiredParams(params, ['type']); + if (invGetValidation) return invGetValidation; + result = await inventoryModule.getInventory(db, wxContext.OPENID, params.type); + break; + + case 'inventory_item_get': + const itemGetValidation = responseModule.validateRequiredParams(params, ['type', 'item_id']); + if (itemGetValidation) return itemGetValidation; + result = await inventoryModule.getInventoryItem(db, wxContext.OPENID, params.type, params.item_id); + break; + + case 'inventory_item_add': + const itemAddValidation = responseModule.validateRequiredParams(params, ['type', 'item_id', 'count']); + if (itemAddValidation) return itemAddValidation; + result = await inventoryModule.addInventoryItem(db, wxContext.OPENID, params.type, params.item_id, params.count); + break; + + case 'inventory_item_consume': + const itemConsumeValidation = responseModule.validateRequiredParams(params, ['type', 'item_id', 'count']); + if (itemConsumeValidation) return itemConsumeValidation; + result = await inventoryModule.consumeInventoryItem(db, wxContext.OPENID, params.type, params.item_id, params.count); + break; + + case 'inventory_item_set': + const itemSetValidation = responseModule.validateRequiredParams(params, ['type', 'item_id', 'count']); + if (itemSetValidation) return itemSetValidation; + result = await inventoryModule.setInventoryItem(db, wxContext.OPENID, params.type, params.item_id, params.count); + break; + + case 'inventory_update': + const invUpdateValidation = responseModule.validateRequiredParams(params, ['type', 'data']); + if (invUpdateValidation) return invUpdateValidation; + const invMerge = params.merge !== false; + result = await inventoryModule.updateInventory(db, wxContext.OPENID, params.type, params.data, invMerge); + break; + + case 'inventory_reset': + const invResetValidation = responseModule.validateRequiredParams(params, ['type']); + if (invResetValidation) return invResetValidation; + result = await inventoryModule.resetInventory(db, wxContext.OPENID, params.type); + break; + + case 'inventory_owned': + const invOwnedValidation = responseModule.validateRequiredParams(params, ['type']); + if (invOwnedValidation) return invOwnedValidation; + result = await inventoryModule.getOwnedItems(db, wxContext.OPENID, params.type); + break; + + // ==================== 兼容旧接口 ==================== + case 'load': + result = await authModule.login(db, wxContext); + break; + + case 'save': + // 兼容旧的保存接口 + if (params.data) { + const tasks = []; + if (params.data.data) tasks.push(gameDataModule.updateData(db, wxContext.OPENID, params.data.data)); + if (params.data.fight_heros) tasks.push(fightHerosModule.updateFightHeros(db, wxContext.OPENID, params.data.fight_heros)); + if (params.data.heros) { + // 批量更新英雄 + for (const heroId in params.data.heros) { + tasks.push(herosModule.updateHero(db, wxContext.OPENID, parseInt(heroId), params.data.heros[heroId])); + } + } + if (params.data.items) tasks.push(inventoryModule.updateInventory(db, wxContext.OPENID, 'items', params.data.items)); + if (params.data.tals) tasks.push(inventoryModule.updateInventory(db, wxContext.OPENID, 'tals', params.data.tals)); + if (params.data.equips) tasks.push(inventoryModule.updateInventory(db, wxContext.OPENID, 'equips', params.data.equips)); + + const results = await Promise.all(tasks); + const hasError = results.some(r => r.code !== 200); + + if (hasError) { + result = responseModule.error(-1, "Partial save failed", { results }); + } else { + result = responseModule.success({ results }, "All data saved successfully"); + } } else { - return { - code: -1, - msg: `Save fail, ${JSON.stringify(saveDataRes)}` - }; + result = responseModule.badRequest("No data to save"); + } + break; + + default: + const availableCommands = [ + 'login', 'user_info', 'version', 'upgrade', + 'data_get', 'data_update', 'data_add', 'data_spend', 'data_set', 'data_reset', + 'fight_heros_get', 'fight_hero_set', 'fight_heros_update', 'fight_heros_active', 'fight_heros_swap', 'fight_heros_reset', + 'heros_get', 'hero_get', 'hero_add', 'hero_update', 'hero_property_set', 'hero_levelup', 'hero_delete', 'heros_owned', + 'inventory_get', 'inventory_item_get', 'inventory_item_add', 'inventory_item_consume', 'inventory_item_set', 'inventory_update', 'inventory_reset', 'inventory_owned', + 'load', 'save' + ]; + result = responseModule.unknownCommand(cmd, availableCommands); + break; } - } - - return { - code: -2, - msg: `Unknow cmd: ${event?.cmd}`, - }; -}; - -async function getOrCreaterUser(db, openid) { - try { - let res = await db.collection(user_db_name).where({ _openid: openid }).get(); - let userData = null; - if (res == null || res.data == null || res.data.length <= 0) { - userData = { - _openid: openid, - regist_time: Date.now(), - }; - let addResult = await db.collection(user_db_name).add({ - data: userData - }); - userData._id = addResult._id; - } else { - userData = res.data[0]; + + // 添加执行时间 + const executionTime = Date.now() - startTime; + if (result && typeof result === 'object') { + result.execution_time = executionTime; } - return userData; - } catch (err) { - console.error(`Get or create user err`, err); - return null; + + console.log(`[${cmd}] Response (${executionTime}ms):`, result.code, result.msg); + return result; + + } catch (error) { + console.error("Cloud function error:", error); + return responseModule.systemError("Cloud function execution failed", error); } -} \ No newline at end of file +}; \ No newline at end of file diff --git a/build-templates/wechatgame/cloud_functions/cocos_cloud/modules/auth.js b/build-templates/wechatgame/cloud_functions/cocos_cloud/modules/auth.js new file mode 100644 index 00000000..e906f150 --- /dev/null +++ b/build-templates/wechatgame/cloud_functions/cocos_cloud/modules/auth.js @@ -0,0 +1,280 @@ +// 登录认证模块 +const { + getNewUserInitData, + mergeUserDataWithDefaults, + checkDataVersionCompatibility +} = require('../user_init_data'); + +const user_db_name = "cocos_users"; + +/** + * 用户登录处理 + * @param {Object} db 数据库实例 + * @param {Object} wxContext 微信上下文 + * @returns {Object} 登录结果 + */ +async function login(db, wxContext) { + try { + let user = await getOrCreaterUser(db, wxContext.OPENID); + if (!user) { + return { + code: -4, + msg: "Failed to get or create user" + }; + } + + return { + code: 200, + data: { + user_id: user._id, + openid: user._openid, + regist_time: user.regist_time, + data: user.data, + fight_heros: user.fight_heros, + heros: user.heros, + items: user.items, + tals: user.tals, + equips: user.equips, + data_version: user.data_version, + last_save_time: user.last_save_time || null + }, + msg: "Login successful" + }; + } catch (error) { + console.error("Login error:", error); + return { + code: -5, + msg: `Login error: ${error.message}` + }; + } +} + +/** + * 获取或创建用户 + * @param {Object} db 数据库实例 + * @param {string} openid 用户openid + * @returns {Object} 用户数据 + */ +async function getOrCreaterUser(db, openid) { + try { + let res = await db.collection(user_db_name).where({ _openid: openid }).get(); + let userData = null; + + if (res == null || res.data == null || res.data.length <= 0) { + // 创建新用户时使用初始化数据配置 + let initData = getNewUserInitData(); + userData = { + _openid: openid, + regist_time: Date.now(), + data: initData.data, + fight_heros: initData.fight_heros, + heros: initData.heros, + items: initData.items, + tals: initData.tals, + equips: initData.equips, + data_version: initData.data_version, + init_time: initData.init_time + }; + + let addResult = await db.collection(user_db_name).add({ + data: userData + }); + userData._id = addResult._id; + + console.log(`New user created: ${openid}, version: ${initData.data_version}`); + } else { + userData = res.data[0]; + + // 检查数据版本兼容性 + const versionCheck = checkDataVersionCompatibility(userData.data_version); + console.log(`User ${openid} data version check:`, versionCheck); + + if (versionCheck.needsUpgrade) { + // 使用新的数据管理系统合并和升级数据 + const upgradedData = mergeUserDataWithDefaults({ + data: userData.data, + fight_heros: userData.fight_heros, + heros: userData.heros, + items: userData.items, + tals: userData.tals, + equips: userData.equips, + data_version: userData.data_version + }); + + // 更新用户数据 + userData.data = upgradedData.data; + userData.fight_heros = upgradedData.fight_heros; + userData.heros = upgradedData.heros; + userData.items = upgradedData.items; + userData.tals = upgradedData.tals; + userData.equips = upgradedData.equips; + userData.data_version = upgradedData.data_version; + + console.log(`User ${openid} data upgraded to version: ${upgradedData.data_version}`); + } + } + + return userData; + } catch (err) { + console.error(`Get or create user err`, err); + return null; + } +} + +/** + * 获取用户基本信息 + * @param {Object} db 数据库实例 + * @param {string} openid 用户openid + * @returns {Object} 用户基本信息 + */ +async function getUserInfo(db, openid) { + try { + let user = await getOrCreaterUser(db, openid); + if (!user) { + return { + code: -4, + msg: "User not found" + }; + } + + return { + code: 200, + data: { + user_id: user._id, + openid: user._openid, + regist_time: user.regist_time, + init_time: user.init_time, + data_version: user.data_version, + last_save_time: user.last_save_time + }, + msg: "User info retrieved successfully" + }; + } catch (error) { + console.error("Get user info error:", error); + return { + code: -5, + msg: `Get user info error: ${error.message}` + }; + } +} + +/** + * 检查用户数据版本 + * @param {Object} db 数据库实例 + * @param {string} openid 用户openid + * @returns {Object} 版本检查结果 + */ +async function checkVersion(db, openid) { + try { + let user = await getOrCreaterUser(db, openid); + if (!user) { + return { + code: -4, + msg: "User not found" + }; + } + + const versionCheck = checkDataVersionCompatibility(user.data_version); + + return { + code: 200, + data: { + user_version: user.data_version || "unknown", + current_version: require('../user_init_data').DATA_VERSION, + compatibility: versionCheck, + init_time: user.init_time, + regist_time: user.regist_time, + last_save_time: user.last_save_time + }, + msg: "Version information retrieved successfully" + }; + } catch (error) { + console.error("Check version error:", error); + return { + code: -5, + msg: `Check version error: ${error.message}` + }; + } +} + +/** + * 强制升级用户数据 + * @param {Object} db 数据库实例 + * @param {string} openid 用户openid + * @returns {Object} 升级结果 + */ +async function upgradeUserData(db, openid) { + try { + const _ = db.command; + let user = await getOrCreaterUser(db, openid); + if (!user) { + return { + code: -4, + msg: "User not found" + }; + } + + // 强制升级用户数据 + const upgradedData = mergeUserDataWithDefaults({ + data: user.data, + fight_heros: user.fight_heros, + heros: user.heros, + items: user.items, + tals: user.tals, + equips: user.equips, + data_version: user.data_version + }); + + let upgradeDataRes = await db.collection(user_db_name).doc(user._id).update({ + data: { + data: _.set(upgradedData.data), + fight_heros: _.set(upgradedData.fight_heros), + heros: _.set(upgradedData.heros), + items: _.set(upgradedData.items), + tals: _.set(upgradedData.tals), + equips: _.set(upgradedData.equips), + data_version: _.set(upgradedData.data_version), + last_save_time: _.set(Date.now()), + upgrade_time: _.set(Date.now()) + } + }); + + if (upgradeDataRes?.stats?.updated >= 1) { + return { + code: 200, + data: { + old_version: user.data_version || "unknown", + new_version: upgradedData.data_version, + upgrade_time: Date.now(), + data: upgradedData.data, + fight_heros: upgradedData.fight_heros, + heros: upgradedData.heros, + items: upgradedData.items, + tals: upgradedData.tals, + equips: upgradedData.equips + }, + msg: "Data upgrade completed successfully" + }; + } else { + return { + code: -1, + msg: `Upgrade fail, ${JSON.stringify(upgradeDataRes)}` + }; + } + } catch (error) { + console.error("Upgrade user data error:", error); + return { + code: -5, + msg: `Upgrade error: ${error.message}` + }; + } +} + +module.exports = { + login, + getOrCreaterUser, + getUserInfo, + checkVersion, + upgradeUserData +}; + diff --git a/build-templates/wechatgame/cloud_functions/cocos_cloud/modules/fightHeros.js b/build-templates/wechatgame/cloud_functions/cocos_cloud/modules/fightHeros.js new file mode 100644 index 00000000..be8c503c --- /dev/null +++ b/build-templates/wechatgame/cloud_functions/cocos_cloud/modules/fightHeros.js @@ -0,0 +1,370 @@ +// 出战英雄操作模块 +const { getOrCreaterUser } = require('./auth'); + +const user_db_name = "cocos_users"; + +/** + * 获取出战英雄配置 + * @param {Object} db 数据库实例 + * @param {string} openid 用户openid + * @returns {Object} 操作结果 + */ +async function getFightHeros(db, openid) { + try { + let user = await getOrCreaterUser(db, openid); + if (!user) { + return { + code: -4, + msg: "User not found" + }; + } + + return { + code: 200, + data: user.fight_heros, + msg: "Fight heros retrieved successfully" + }; + } catch (error) { + console.error("Get fight heros error:", error); + return { + code: -5, + msg: `Get fight heros error: ${error.message}` + }; + } +} + +/** + * 设置出战英雄 + * @param {Object} db 数据库实例 + * @param {string} openid 用户openid + * @param {number} position 出战位置 (0-4) + * @param {number} heroId 英雄ID,0表示移除 + * @returns {Object} 操作结果 + */ +async function setFightHero(db, openid, position, heroId) { + try { + const _ = db.command; + let user = await getOrCreaterUser(db, openid); + if (!user) { + return { + code: -4, + msg: "User not found" + }; + } + + // 验证位置参数 + if (position < 0 || position > 4) { + return { + code: -3, + msg: "Invalid position, must be 0-4" + }; + } + + // 验证英雄ID + if (typeof heroId !== 'number' || heroId < 0) { + return { + code: -3, + msg: "Invalid hero ID" + }; + } + + // 如果不是移除操作,检查英雄是否存在 + if (heroId > 0 && !user.heros[heroId]) { + return { + code: -6, + msg: "Hero not owned" + }; + } + + const oldHeroId = user.fight_heros[position]; + + let updateRes = await db.collection(user_db_name).doc(user._id).update({ + data: { + [`fight_heros.${position}`]: _.set(heroId), + last_save_time: _.set(Date.now()) + } + }); + + if (updateRes?.stats?.updated >= 1) { + return { + code: 200, + data: { + position: position, + old_hero_id: oldHeroId, + new_hero_id: heroId + }, + msg: `Fight hero position ${position} updated successfully` + }; + } else { + return { + code: -1, + msg: `Set fight hero fail` + }; + } + } catch (error) { + console.error("Set fight hero error:", error); + return { + code: -5, + msg: `Set fight hero error: ${error.message}` + }; + } +} + +/** + * 批量设置出战英雄 + * @param {Object} db 数据库实例 + * @param {string} openid 用户openid + * @param {Object} fightHeros 出战英雄配置对象 + * @returns {Object} 操作结果 + */ +async function updateFightHeros(db, openid, fightHeros) { + try { + const _ = db.command; + let user = await getOrCreaterUser(db, openid); + if (!user) { + return { + code: -4, + msg: "User not found" + }; + } + + // 验证数据格式 + if (!fightHeros || typeof fightHeros !== 'object') { + return { + code: -3, + msg: "Invalid fight heros data format" + }; + } + + // 验证每个位置和英雄ID + for (const pos in fightHeros) { + const position = parseInt(pos); + const heroId = fightHeros[pos]; + + if (isNaN(position) || position < 0 || position > 4) { + return { + code: -3, + msg: `Invalid position: ${pos}` + }; + } + + if (typeof heroId !== 'number' || heroId < 0) { + return { + code: -3, + msg: `Invalid hero ID for position ${pos}: ${heroId}` + }; + } + + // 如果不是移除操作,检查英雄是否存在 + if (heroId > 0 && !user.heros[heroId]) { + return { + code: -6, + msg: `Hero ${heroId} not owned for position ${pos}` + }; + } + } + + const newFightHeros = { ...user.fight_heros, ...fightHeros }; + + let updateRes = await db.collection(user_db_name).doc(user._id).update({ + data: { + fight_heros: _.set(newFightHeros), + last_save_time: _.set(Date.now()) + } + }); + + if (updateRes?.stats?.updated >= 1) { + return { + code: 200, + data: newFightHeros, + msg: "Fight heros updated successfully" + }; + } else { + return { + code: -1, + msg: `Update fight heros fail` + }; + } + } catch (error) { + console.error("Update fight heros error:", error); + return { + code: -5, + msg: `Update fight heros error: ${error.message}` + }; + } +} + +/** + * 获取当前出战英雄列表(不包含空位) + * @param {Object} db 数据库实例 + * @param {string} openid 用户openid + * @returns {Object} 操作结果 + */ +async function getActiveFightHeros(db, openid) { + try { + let user = await getOrCreaterUser(db, openid); + if (!user) { + return { + code: -4, + msg: "User not found" + }; + } + + const activeHeros = []; + for (let i = 0; i < 5; i++) { + const heroId = user.fight_heros[i]; + if (heroId && heroId > 0) { + activeHeros.push({ + position: i, + hero_id: heroId, + hero_data: user.heros[heroId] || null + }); + } + } + + return { + code: 200, + data: { + active_heros: activeHeros, + total_count: activeHeros.length + }, + msg: "Active fight heros retrieved successfully" + }; + } catch (error) { + console.error("Get active fight heros error:", error); + return { + code: -5, + msg: `Get active fight heros error: ${error.message}` + }; + } +} + +/** + * 交换两个出战位置的英雄 + * @param {Object} db 数据库实例 + * @param {string} openid 用户openid + * @param {number} position1 位置1 (0-4) + * @param {number} position2 位置2 (0-4) + * @returns {Object} 操作结果 + */ +async function swapFightHeros(db, openid, position1, position2) { + try { + const _ = db.command; + let user = await getOrCreaterUser(db, openid); + if (!user) { + return { + code: -4, + msg: "User not found" + }; + } + + // 验证位置参数 + if (position1 < 0 || position1 > 4 || position2 < 0 || position2 > 4) { + return { + code: -3, + msg: "Invalid positions, must be 0-4" + }; + } + + if (position1 === position2) { + return { + code: -3, + msg: "Cannot swap same position" + }; + } + + const hero1 = user.fight_heros[position1]; + const hero2 = user.fight_heros[position2]; + + let updateRes = await db.collection(user_db_name).doc(user._id).update({ + data: { + [`fight_heros.${position1}`]: _.set(hero2), + [`fight_heros.${position2}`]: _.set(hero1), + last_save_time: _.set(Date.now()) + } + }); + + if (updateRes?.stats?.updated >= 1) { + return { + code: 200, + data: { + position1: position1, + position2: position2, + hero1_moved_to: hero1, + hero2_moved_to: hero2 + }, + msg: `Fight heros swapped successfully` + }; + } else { + return { + code: -1, + msg: `Swap fight heros fail` + }; + } + } catch (error) { + console.error("Swap fight heros error:", error); + return { + code: -5, + msg: `Swap fight heros error: ${error.message}` + }; + } +} + +/** + * 重置出战英雄配置 + * @param {Object} db 数据库实例 + * @param {string} openid 用户openid + * @returns {Object} 操作结果 + */ +async function resetFightHeros(db, openid) { + try { + const _ = db.command; + const { getNewUserInitData } = require('../user_init_data'); + let user = await getOrCreaterUser(db, openid); + if (!user) { + return { + code: -4, + msg: "User not found" + }; + } + + const defaultData = getNewUserInitData(); + + let resetRes = await db.collection(user_db_name).doc(user._id).update({ + data: { + fight_heros: _.set(defaultData.fight_heros), + last_save_time: _.set(Date.now()), + reset_time: _.set(Date.now()) + } + }); + + if (resetRes?.stats?.updated >= 1) { + return { + code: 200, + data: defaultData.fight_heros, + msg: "Fight heros reset successfully" + }; + } else { + return { + code: -1, + msg: `Reset fail, ${JSON.stringify(resetRes)}` + }; + } + } catch (error) { + console.error("Reset fight heros error:", error); + return { + code: -5, + msg: `Reset fight heros error: ${error.message}` + }; + } +} + +module.exports = { + getFightHeros, + setFightHero, + updateFightHeros, + getActiveFightHeros, + swapFightHeros, + resetFightHeros +}; + diff --git a/build-templates/wechatgame/cloud_functions/cocos_cloud/modules/gameData.js b/build-templates/wechatgame/cloud_functions/cocos_cloud/modules/gameData.js new file mode 100644 index 00000000..bb2fd4d2 --- /dev/null +++ b/build-templates/wechatgame/cloud_functions/cocos_cloud/modules/gameData.js @@ -0,0 +1,315 @@ +// 基础游戏数据操作模块 (data字段) +const { getOrCreaterUser } = require('./auth'); +const { validateDataStructure, mergeUserDataWithDefaults } = require('../user_init_data'); + +const user_db_name = "cocos_users"; + +/** + * 获取基础游戏数据 + * @param {Object} db 数据库实例 + * @param {string} openid 用户openid + * @returns {Object} 操作结果 + */ +async function getData(db, openid) { + try { + let user = await getOrCreaterUser(db, openid); + if (!user) { + return { + code: -4, + msg: "用户未找到" + }; + } + + return { + code: 200, + data: user.data, + msg: "游戏数据获取成功" + }; + } catch (error) { + console.error("获取游戏数据错误:", error); + return { + code: -5, + msg: `获取游戏数据错误: ${error.message}` + }; + } +} + +/** + * 更新基础游戏数据 + * @param {Object} db 数据库实例 + * @param {string} openid 用户openid + * @param {Object} updateData 要更新的数据 + * @param {boolean} merge 是否合并更新(默认true) + * @returns {Object} 操作结果 + */ +async function updateData(db, openid, updateData, merge = true) { + try { + const _ = db.command; + let user = await getOrCreaterUser(db, openid); + if (!user) { + return { + code: -4, + msg: "用户未找到" + }; + } + + // 验证数据格式 + if (!updateData || typeof updateData !== 'object') { + return { + code: -3, + msg: "无效的更新数据格式" + }; + } + + let newData; + if (merge) { + // 合并更新 + newData = { ...user.data, ...updateData }; + } else { + // 完全替换 + newData = updateData; + } + + let updateRes = await db.collection(user_db_name).doc(user._id).update({ + data: { + data: _.set(newData), + last_save_time: _.set(Date.now()) + } + }); + + if (updateRes?.stats?.updated >= 1) { + return { + code: 200, + data: newData, + msg: "游戏数据更新成功" + }; + } else { + return { + code: -1, + msg: `更新失败, ${JSON.stringify(updateRes)}` + }; + } + } catch (error) { + console.error("更新游戏数据错误:", error); + return { + code: -5, + msg: `更新游戏数据错误: ${error.message}` + }; + } +} + +/** + * 增加指定字段的数值 + * @param {Object} db 数据库实例 + * @param {string} openid 用户openid + * @param {string} field 字段名 + * @param {number} amount 增加的数量 + * @returns {Object} 操作结果 + */ +async function addDataField(db, openid, field, amount) { + try { + const _ = db.command; + let user = await getOrCreaterUser(db, openid); + if (!user) { + return { + code: -4, + msg: "用户未找到" + }; + } + + if (typeof amount !== 'number') { + return { + code: -3, + msg: "数量必须是数字" + }; + } + + const currentValue = user.data[field] || 0; + const newValue = Math.max(0, currentValue + amount); + + let updateRes = await db.collection(user_db_name).doc(user._id).update({ + data: { + [`data.${field}`]: _.set(newValue), + last_save_time: _.set(Date.now()) + } + }); + + if (updateRes?.stats?.updated >= 1) { + return { + code: 200, + data: { + field: field, + old_value: currentValue, + new_value: newValue, + change: amount + }, + msg: `${field} 更新成功` + }; + } else { + return { + code: -1, + msg: `更新 ${field} 失败` + }; + } + } catch (error) { + console.error(`增加 ${field} 错误:`, error); + return { + code: -5, + msg: `增加 ${field} 错误: ${error.message}` + }; + } +} + +/** + * 消耗指定字段的数值 + * @param {Object} db 数据库实例 + * @param {string} openid 用户openid + * @param {string} field 字段名 + * @param {number} amount 消耗的数量 + * @returns {Object} 操作结果 + */ +async function spendDataField(db, openid, field, amount) { + try { + let user = await getOrCreaterUser(db, openid); + if (!user) { + return { + code: -4, + msg: "用户未找到" + }; + } + + if (typeof amount !== 'number' || amount < 0) { + return { + code: -3, + msg: "数量必须是正数" + }; + } + + const currentValue = user.data[field] || 0; + if (currentValue < amount) { + return { + code: -6, + msg: `${field} 不足, 当前: ${currentValue}, 需要: ${amount}` + }; + } + + return await addDataField(db, openid, field, -amount); + } catch (error) { + console.error(`消耗 ${field} 错误:`, error); + return { + code: -5, + msg: `消耗 ${field} 错误: ${error.message}` + }; + } +} + +/** + * 设置指定字段的数值 + * @param {Object} db 数据库实例 + * @param {string} openid 用户openid + * @param {string} field 字段名 + * @param {any} value 新的值 + * @returns {Object} 操作结果 + */ +async function setDataField(db, openid, field, value) { + try { + const _ = db.command; + let user = await getOrCreaterUser(db, openid); + if (!user) { + return { + code: -4, + msg: "用户未找到" + }; + } + + const oldValue = user.data[field]; + + let updateRes = await db.collection(user_db_name).doc(user._id).update({ + data: { + [`data.${field}`]: _.set(value), + last_save_time: _.set(Date.now()) + } + }); + + if (updateRes?.stats?.updated >= 1) { + return { + code: 200, + data: { + field: field, + old_value: oldValue, + new_value: value + }, + msg: `${field} 设置成功` + }; + } else { + return { + code: -1, + msg: `设置 ${field} 失败` + }; + } + } catch (error) { + console.error(`设置 ${field} 错误:`, error); + return { + code: -5, + msg: `设置 ${field} 错误: ${error.message}` + }; + } +} + +/** + * 重置基础游戏数据 + * @param {Object} db 数据库实例 + * @param {string} openid 用户openid + * @returns {Object} 操作结果 + */ +async function resetData(db, openid) { + try { + const _ = db.command; + const { getNewUserInitData } = require('../user_init_data'); + let user = await getOrCreaterUser(db, openid); + if (!user) { + return { + code: -4, + msg: "用户未找到" + }; + } + + const defaultData = getNewUserInitData(); + + let resetRes = await db.collection(user_db_name).doc(user._id).update({ + data: { + data: _.set(defaultData.data), + last_save_time: _.set(Date.now()), + reset_time: _.set(Date.now()) + } + }); + + if (resetRes?.stats?.updated >= 1) { + return { + code: 200, + data: defaultData.data, + msg: "游戏数据重置成功" + }; + } else { + return { + code: -1, + msg: `重置失败, ${JSON.stringify(resetRes)}` + }; + } + } catch (error) { + console.error("重置游戏数据错误:", error); + return { + code: -5, + msg: `重置游戏数据错误: ${error.message}` + }; + } +} + +module.exports = { + getData, + updateData, + addDataField, + spendDataField, + setDataField, + resetData +}; diff --git a/build-templates/wechatgame/cloud_functions/cocos_cloud/modules/heros.js b/build-templates/wechatgame/cloud_functions/cocos_cloud/modules/heros.js new file mode 100644 index 00000000..c63ccb00 --- /dev/null +++ b/build-templates/wechatgame/cloud_functions/cocos_cloud/modules/heros.js @@ -0,0 +1,456 @@ +// 英雄数据操作模块 +const { getOrCreaterUser } = require('./auth'); + +const user_db_name = "cocos_users"; + +/** + * 获取所有英雄数据 + * @param {Object} db 数据库实例 + * @param {string} openid 用户openid + * @returns {Object} 操作结果 + */ +async function getHeros(db, openid) { + try { + let user = await getOrCreaterUser(db, openid); + if (!user) { + return { + code: -4, + msg: "未找到用户" + }; + } + + return { + code: 200, + data: user.heros, + msg: "获取英雄列表成功" + }; + } catch (error) { + console.error("获取英雄列表错误:", error); + return { + code: -5, + msg: `获取英雄列表错误: ${error.message}` + }; + } +} + +/** + * 获取单个英雄数据 + * @param {Object} db 数据库实例 + * @param {string} openid 用户openid + * @param {number} heroId 英雄ID + * @returns {Object} 操作结果 + */ +async function getHero(db, openid, heroId) { + try { + let user = await getOrCreaterUser(db, openid); + if (!user) { + return { + code: -4, + msg: "未找到用户" + }; + } + + const hero = user.heros[heroId]; + if (!hero) { + return { + code: -6, + msg: "未找到英雄" + }; + } + + return { + code: 200, + data: hero, + msg: "获取英雄成功" + }; + } catch (error) { + console.error("获取英雄错误:", error); + return { + code: -5, + msg: `获取英雄错误: ${error.message}` + }; + } +} + +/** + * 添加新英雄 + * @param {Object} db 数据库实例 + * @param {string} openid 用户openid + * @param {number} heroId 英雄ID + * @param {Object} heroData 英雄数据(可选) + * @returns {Object} 操作结果 + */ +async function addHero(db, openid, heroId, heroData = null) { + try { + const _ = db.command; + let user = await getOrCreaterUser(db, openid); + if (!user) { + return { + code: -4, + msg: "未找到用户" + }; + } + + // 检查英雄是否已存在 + if (user.heros[heroId]) { + return { + code: -7, + msg: "英雄已存在" + }; + } + + // 使用提供的数据或默认数据 + const newHero = heroData || { + uuid: heroId, + lv: 1, + exp: 0, + star: 1, + power: 100 + }; + + // 确保uuid字段正确 + newHero.uuid = heroId; + + let updateRes = await db.collection(user_db_name).doc(user._id).update({ + data: { + [`heros.${heroId}`]: _.set(newHero), + last_save_time: _.set(Date.now()) + } + }); + + if (updateRes?.stats?.updated >= 1) { + return { + code: 200, + data: newHero, + msg: `英雄 ${heroId} 添加成功` + }; + } else { + return { + code: -1, + msg: `添加英雄失败` + }; + } + } catch (error) { + console.error("添加英雄错误:", error); + return { + code: -5, + msg: `添加英雄错误: ${error.message}` + }; + } +} + +/** + * 更新英雄属性 + * @param {Object} db 数据库实例 + * @param {string} openid 用户openid + * @param {number} heroId 英雄ID + * @param {Object} updateData 要更新的属性 + * @returns {Object} 操作结果 + */ +async function updateHero(db, openid, heroId, updateData) { + try { + const _ = db.command; + let user = await getOrCreaterUser(db, openid); + if (!user) { + return { + code: -4, + msg: "未找到用户" + }; + } + + // 检查英雄是否存在 + if (!user.heros[heroId]) { + return { + code: -6, + msg: "未找到英雄" + }; + } + + // 验证更新数据 + if (!updateData || typeof updateData !== 'object') { + return { + code: -3, + msg: "无效的更新数据格式" + }; + } + + const currentHero = user.heros[heroId]; + const newHero = { ...currentHero, ...updateData }; + + // 确保uuid字段不被修改 + newHero.uuid = heroId; + + let updateRes = await db.collection(user_db_name).doc(user._id).update({ + data: { + [`heros.${heroId}`]: _.set(newHero), + last_save_time: _.set(Date.now()) + } + }); + + if (updateRes?.stats?.updated >= 1) { + return { + code: 200, + data: { + old_data: currentHero, + new_data: newHero + }, + msg: `英雄 ${heroId} 更新成功` + }; + } else { + return { + code: -1, + msg: `更新英雄失败` + }; + } + } catch (error) { + console.error("更新英雄错误:", error); + return { + code: -5, + msg: `更新英雄错误: ${error.message}` + }; + } +} + +/** + * 设置英雄属性 + * @param {Object} db 数据库实例 + * @param {string} openid 用户openid + * @param {number} heroId 英雄ID + * @param {string} property 属性名 + * @param {any} value 属性值 + * @returns {Object} 操作结果 + */ +async function setHeroProperty(db, openid, heroId, property, value) { + try { + const _ = db.command; + let user = await getOrCreaterUser(db, openid); + if (!user) { + return { + code: -4, + msg: "未找到用户" + }; + } + + // 检查英雄是否存在 + if (!user.heros[heroId]) { + return { + code: -6, + msg: "未找到英雄" + }; + } + + // 防止修改uuid + if (property === 'uuid') { + return { + code: -3, + msg: "不可修改英雄UUID" + }; + } + + const oldValue = user.heros[heroId][property]; + + let updateRes = await db.collection(user_db_name).doc(user._id).update({ + data: { + [`heros.${heroId}.${property}`]: _.set(value), + last_save_time: _.set(Date.now()) + } + }); + + if (updateRes?.stats?.updated >= 1) { + return { + code: 200, + data: { + hero_id: heroId, + property: property, + old_value: oldValue, + new_value: value + }, + msg: `英雄 ${heroId} 属性 ${property} 更新成功` + }; + } else { + return { + code: -1, + msg: `设置英雄属性失败` + }; + } + } catch (error) { + console.error("设置英雄属性错误:", error); + return { + code: -5, + msg: `设置英雄属性错误: ${error.message}` + }; + } +} + +/** + * 英雄升级 + * @param {Object} db 数据库实例 + * @param {string} openid 用户openid + * @param {number} heroId 英雄ID + * @param {number} levels 升级级数(默认1级) + * @returns {Object} 操作结果 + */ +async function levelUpHero(db, openid, heroId, exp,gold,levels = 1) { + try { + let user = await getOrCreaterUser(db, openid); + if (!user) { + return { + code: -4, + msg: "未找到用户" + }; + } + + // 检查英雄是否存在 + if (!user.heros[heroId]) { + return { + code: -6, + msg: "未找到英雄" + }; + } + + if (typeof levels !== 'number' || levels < 1) { + return { + code: -3, + msg: "等级必须为正数" + }; + } + + let exp_result=await spendDataField(db, openid, 'exp', exp); + if(exp_result.code!==200){ + return { + code: -1, + msg: `升级失败,经验不足` + }; + } + let gold_result=await spendDataField(db, openid, 'gold', gold); + if(gold_result.code!==200){ + await addDataField(db, openid, 'exp', exp); + return { + code: -1, + msg: `升级失败,金币不足` + }; + } + const currentLevel = user.heros[heroId].lv || 1; + const newLevel = currentLevel + levels; + return await setHeroProperty(db, openid, heroId, 'lv', newLevel); + } catch (error) { + console.error("英雄升级错误:", error); + return { + code: -5, + msg: `英雄升级错误: ${error.message}` + }; + } +} + +/** + * 删除英雄 + * @param {Object} db 数据库实例 + * @param {string} openid 用户openid + * @param {number} heroId 英雄ID + * @returns {Object} 操作结果 + */ +async function deleteHero(db, openid, heroId) { + try { + const _ = db.command; + let user = await getOrCreaterUser(db, openid); + if (!user) { + return { + code: -4, + msg: "未找到用户" + }; + } + + // 检查英雄是否存在 + if (!user.heros[heroId]) { + return { + code: -6, + msg: "未找到英雄" + }; + } + + // 检查英雄是否在出战阵容中 + for (let pos = 0; pos < 5; pos++) { + if (user.fight_heros[pos] === heroId) { + return { + code: -8, + msg: `英雄位于出战位置 ${pos},请先从出战阵容移除` + }; + } + } + + const deletedHero = user.heros[heroId]; + + let updateRes = await db.collection(user_db_name).doc(user._id).update({ + data: { + [`heros.${heroId}`]: _.remove(), + last_save_time: _.set(Date.now()) + } + }); + + if (updateRes?.stats?.updated >= 1) { + return { + code: 200, + data: deletedHero, + msg: `英雄 ${heroId} 删除成功` + }; + } else { + return { + code: -1, + msg: `删除英雄失败` + }; + } + } catch (error) { + console.error("删除英雄错误:", error); + return { + code: -5, + msg: `删除英雄错误: ${error.message}` + }; + } +} + +/** + * 获取已拥有的英雄ID列表 + * @param {Object} db 数据库实例 + * @param {string} openid 用户openid + * @returns {Object} 操作结果 + */ +async function getOwnedHeroIds(db, openid) { + try { + let user = await getOrCreaterUser(db, openid); + if (!user) { + return { + code: -4, + msg: "未找到用户" + }; + } + + const heroIds = Object.keys(user.heros).map(Number); + + return { + code: 200, + data: { + hero_ids: heroIds, + total_count: heroIds.length + }, + msg: "获取已拥有英雄ID成功" + }; + } catch (error) { + console.error("获取已拥有英雄ID错误:", error); + return { + code: -5, + msg: `获取已拥有英雄ID错误: ${error.message}` + }; + } +} + +module.exports = { + getHeros, + getHero, + addHero, + updateHero, + setHeroProperty, + levelUpHero, + deleteHero, + getOwnedHeroIds +}; + diff --git a/build-templates/wechatgame/cloud_functions/cocos_cloud/modules/inventory.js b/build-templates/wechatgame/cloud_functions/cocos_cloud/modules/inventory.js new file mode 100644 index 00000000..bcf9e117 --- /dev/null +++ b/build-templates/wechatgame/cloud_functions/cocos_cloud/modules/inventory.js @@ -0,0 +1,498 @@ +// 通用库存操作模块 (items, tals, equips) +const { getOrCreaterUser } = require('./auth'); + +const user_db_name = "cocos_users"; + +// 支持的数据类型 +const SUPPORTED_TYPES = ['items', 'tals', 'equips']; + +/** + * 验证数据类型 + * @param {string} dataType 数据类型 + * @returns {boolean} 是否有效 + */ +function validateDataType(dataType) { + return SUPPORTED_TYPES.includes(dataType); +} + +/** + * 获取库存数据 + * @param {Object} db 数据库实例 + * @param {string} openid 用户openid + * @param {string} dataType 数据类型 ('items', 'tals', 'equips') + * @returns {Object} 操作结果 + */ +async function getInventory(db, openid, dataType) { + try { + if (!validateDataType(dataType)) { + return { + code: -3, + msg: `Invalid data type: ${dataType}` + }; + } + + let user = await getOrCreaterUser(db, openid); + if (!user) { + return { + code: -4, + msg: "User not found" + }; + } + + return { + code: 200, + data: user[dataType], + msg: `${dataType} retrieved successfully` + }; + } catch (error) { + console.error(`Get ${dataType} error:`, error); + return { + code: -5, + msg: `Get ${dataType} error: ${error.message}` + }; + } +} + +/** + * 获取单个物品数据 + * @param {Object} db 数据库实例 + * @param {string} openid 用户openid + * @param {string} dataType 数据类型 + * @param {number} itemId 物品ID + * @returns {Object} 操作结果 + */ +async function getInventoryItem(db, openid, dataType, itemId) { + try { + if (!validateDataType(dataType)) { + return { + code: -3, + msg: `Invalid data type: ${dataType}` + }; + } + + let user = await getOrCreaterUser(db, openid); + if (!user) { + return { + code: -4, + msg: "User not found" + }; + } + + const itemCount = user[dataType][itemId]; + if (itemCount === undefined) { + return { + code: -6, + msg: `${dataType.slice(0, -1)} ${itemId} not found` + }; + } + + return { + code: 200, + data: { + item_id: itemId, + count: itemCount + }, + msg: `${dataType.slice(0, -1)} ${itemId} retrieved successfully` + }; + } catch (error) { + console.error(`Get ${dataType} item error:`, error); + return { + code: -5, + msg: `Get ${dataType} item error: ${error.message}` + }; + } +} + +/** + * 添加物品 + * @param {Object} db 数据库实例 + * @param {string} openid 用户openid + * @param {string} dataType 数据类型 + * @param {number} itemId 物品ID + * @param {number} count 添加数量 + * @returns {Object} 操作结果 + */ +async function addInventoryItem(db, openid, dataType, itemId, count) { + try { + if (!validateDataType(dataType)) { + return { + code: -3, + msg: `Invalid data type: ${dataType}` + }; + } + + const _ = db.command; + let user = await getOrCreaterUser(db, openid); + if (!user) { + return { + code: -4, + msg: "User not found" + }; + } + + if (typeof count !== 'number' || count < 0) { + return { + code: -3, + msg: "Count must be a non-negative number" + }; + } + + const currentCount = user[dataType][itemId] || 0; + const newCount = currentCount + count; + + let updateRes = await db.collection(user_db_name).doc(user._id).update({ + data: { + [`${dataType}.${itemId}`]: _.set(newCount), + last_save_time: _.set(Date.now()) + } + }); + + if (updateRes?.stats?.updated >= 1) { + return { + code: 200, + data: { + item_id: itemId, + old_count: currentCount, + new_count: newCount, + added: count + }, + msg: `${dataType.slice(0, -1)} ${itemId} added successfully` + }; + } else { + return { + code: -1, + msg: `Add ${dataType.slice(0, -1)} fail` + }; + } + } catch (error) { + console.error(`Add ${dataType} item error:`, error); + return { + code: -5, + msg: `Add ${dataType} item error: ${error.message}` + }; + } +} + +/** + * 消耗物品 + * @param {Object} db 数据库实例 + * @param {string} openid 用户openid + * @param {string} dataType 数据类型 + * @param {number} itemId 物品ID + * @param {number} count 消耗数量 + * @returns {Object} 操作结果 + */ +async function consumeInventoryItem(db, openid, dataType, itemId, count) { + try { + if (!validateDataType(dataType)) { + return { + code: -3, + msg: `Invalid data type: ${dataType}` + }; + } + + let user = await getOrCreaterUser(db, openid); + if (!user) { + return { + code: -4, + msg: "User not found" + }; + } + + if (typeof count !== 'number' || count < 0) { + return { + code: -3, + msg: "Count must be a non-negative number" + }; + } + + const currentCount = user[dataType][itemId] || 0; + if (currentCount < count) { + return { + code: -6, + msg: `Insufficient ${dataType.slice(0, -1)} ${itemId}, current: ${currentCount}, required: ${count}` + }; + } + + return await addInventoryItem(db, openid, dataType, itemId, -count); + } catch (error) { + console.error(`Consume ${dataType} item error:`, error); + return { + code: -5, + msg: `Consume ${dataType} item error: ${error.message}` + }; + } +} + +/** + * 设置物品数量 + * @param {Object} db 数据库实例 + * @param {string} openid 用户openid + * @param {string} dataType 数据类型 + * @param {number} itemId 物品ID + * @param {number} count 新的数量 + * @returns {Object} 操作结果 + */ +async function setInventoryItem(db, openid, dataType, itemId, count) { + try { + if (!validateDataType(dataType)) { + return { + code: -3, + msg: `Invalid data type: ${dataType}` + }; + } + + const _ = db.command; + let user = await getOrCreaterUser(db, openid); + if (!user) { + return { + code: -4, + msg: "User not found" + }; + } + + if (typeof count !== 'number' || count < 0) { + return { + code: -3, + msg: "Count must be a non-negative number" + }; + } + + const oldCount = user[dataType][itemId] || 0; + + let updateRes = await db.collection(user_db_name).doc(user._id).update({ + data: { + [`${dataType}.${itemId}`]: _.set(count), + last_save_time: _.set(Date.now()) + } + }); + + if (updateRes?.stats?.updated >= 1) { + return { + code: 200, + data: { + item_id: itemId, + old_count: oldCount, + new_count: count + }, + msg: `${dataType.slice(0, -1)} ${itemId} set successfully` + }; + } else { + return { + code: -1, + msg: `Set ${dataType.slice(0, -1)} fail` + }; + } + } catch (error) { + console.error(`Set ${dataType} item error:`, error); + return { + code: -5, + msg: `Set ${dataType} item error: ${error.message}` + }; + } +} + +/** + * 批量更新库存 + * @param {Object} db 数据库实例 + * @param {string} openid 用户openid + * @param {string} dataType 数据类型 + * @param {Object} updateData 更新数据对象 + * @param {boolean} merge 是否合并更新(默认true) + * @returns {Object} 操作结果 + */ +async function updateInventory(db, openid, dataType, updateData, merge = true) { + try { + if (!validateDataType(dataType)) { + return { + code: -3, + msg: `Invalid data type: ${dataType}` + }; + } + + const _ = db.command; + let user = await getOrCreaterUser(db, openid); + if (!user) { + return { + code: -4, + msg: "User not found" + }; + } + + // 验证更新数据 + if (!updateData || typeof updateData !== 'object') { + return { + code: -3, + msg: "Invalid update data format" + }; + } + + // 验证所有值都是非负数 + for (const itemId in updateData) { + const count = updateData[itemId]; + if (typeof count !== 'number' || count < 0) { + return { + code: -3, + msg: `Invalid count for item ${itemId}: ${count}` + }; + } + } + + let newData; + if (merge) { + // 合并更新 + newData = { ...user[dataType], ...updateData }; + } else { + // 完全替换 + newData = updateData; + } + + let updateRes = await db.collection(user_db_name).doc(user._id).update({ + data: { + [dataType]: _.set(newData), + last_save_time: _.set(Date.now()) + } + }); + + if (updateRes?.stats?.updated >= 1) { + return { + code: 200, + data: newData, + msg: `${dataType} updated successfully` + }; + } else { + return { + code: -1, + msg: `Update ${dataType} fail` + }; + } + } catch (error) { + console.error(`Update ${dataType} error:`, error); + return { + code: -5, + msg: `Update ${dataType} error: ${error.message}` + }; + } +} + +/** + * 重置库存数据 + * @param {Object} db 数据库实例 + * @param {string} openid 用户openid + * @param {string} dataType 数据类型 + * @returns {Object} 操作结果 + */ +async function resetInventory(db, openid, dataType) { + try { + if (!validateDataType(dataType)) { + return { + code: -3, + msg: `Invalid data type: ${dataType}` + }; + } + + const _ = db.command; + const { getNewUserInitData } = require('../user_init_data'); + let user = await getOrCreaterUser(db, openid); + if (!user) { + return { + code: -4, + msg: "User not found" + }; + } + + const defaultData = getNewUserInitData(); + + let resetRes = await db.collection(user_db_name).doc(user._id).update({ + data: { + [dataType]: _.set(defaultData[dataType]), + last_save_time: _.set(Date.now()), + reset_time: _.set(Date.now()) + } + }); + + if (resetRes?.stats?.updated >= 1) { + return { + code: 200, + data: defaultData[dataType], + msg: `${dataType} reset successfully` + }; + } else { + return { + code: -1, + msg: `Reset ${dataType} fail` + }; + } + } catch (error) { + console.error(`Reset ${dataType} error:`, error); + return { + code: -5, + msg: `Reset ${dataType} error: ${error.message}` + }; + } +} + +/** + * 获取拥有的物品列表(数量大于0的) + * @param {Object} db 数据库实例 + * @param {string} openid 用户openid + * @param {string} dataType 数据类型 + * @returns {Object} 操作结果 + */ +async function getOwnedItems(db, openid, dataType) { + try { + if (!validateDataType(dataType)) { + return { + code: -3, + msg: `Invalid data type: ${dataType}` + }; + } + + let user = await getOrCreaterUser(db, openid); + if (!user) { + return { + code: -4, + msg: "User not found" + }; + } + + const ownedItems = []; + for (const itemId in user[dataType]) { + const count = user[dataType][itemId]; + if (count > 0) { + ownedItems.push({ + item_id: parseInt(itemId), + count: count + }); + } + } + + return { + code: 200, + data: { + owned_items: ownedItems, + total_types: ownedItems.length + }, + msg: `Owned ${dataType} retrieved successfully` + }; + } catch (error) { + console.error(`Get owned ${dataType} error:`, error); + return { + code: -5, + msg: `Get owned ${dataType} error: ${error.message}` + }; + } +} + +module.exports = { + getInventory, + getInventoryItem, + addInventoryItem, + consumeInventoryItem, + setInventoryItem, + updateInventory, + resetInventory, + getOwnedItems, + SUPPORTED_TYPES +}; + diff --git a/build-templates/wechatgame/cloud_functions/cocos_cloud/modules/response.js b/build-templates/wechatgame/cloud_functions/cocos_cloud/modules/response.js new file mode 100644 index 00000000..b55aef86 --- /dev/null +++ b/build-templates/wechatgame/cloud_functions/cocos_cloud/modules/response.js @@ -0,0 +1,267 @@ +// 统一响应处理模块 +const { DATA_VERSION } = require('../user_init_data'); + +/** + * 成功响应 + * @param {any} data 返回数据 + * @param {string} message 成功消息 + * @param {Object} extra 额外信息 + * @returns {Object} 响应对象 + */ +function success(data = null, message = "Success", extra = {}) { + return { + code: 200, + data: data, + msg: message, + timestamp: Date.now(), + version: DATA_VERSION, + ...extra + }; +} + +/** + * 错误响应 + * @param {number} code 错误码 + * @param {string} message 错误消息 + * @param {any} data 错误相关数据 + * @returns {Object} 响应对象 + */ +function error(code, message, data = null) { + return { + code: code, + msg: message, + data: data, + timestamp: Date.now(), + version: DATA_VERSION + }; +} + +/** + * 参数错误响应 + * @param {string} message 错误消息 + * @param {any} data 错误相关数据 + * @returns {Object} 响应对象 + */ +function badRequest(message = "Bad request", data = null) { + return error(-3, message, data); +} + +/** + * 用户未找到响应 + * @param {string} message 错误消息 + * @returns {Object} 响应对象 + */ +function userNotFound(message = "User not found") { + return error(-4, message); +} + +/** + * 系统错误响应 + * @param {string} message 错误消息 + * @param {Error} err 错误对象 + * @returns {Object} 响应对象 + */ +function systemError(message = "System error", err = null) { + const errorData = err ? { + error_message: err.message, + error_stack: process.env.NODE_ENV === 'development' ? err.stack : undefined + } : null; + + return error(-5, message, errorData); +} + +/** + * 资源不足响应 + * @param {string} resource 资源名称 + * @param {number} current 当前数量 + * @param {number} required 需要数量 + * @returns {Object} 响应对象 + */ +function insufficientResource(resource, current = 0, required = 0) { + return error(-6, `Insufficient ${resource}`, { + resource: resource, + current: current, + required: required, + shortage: required - current + }); +} + +/** + * 资源已存在响应 + * @param {string} resource 资源名称 + * @param {any} identifier 资源标识 + * @returns {Object} 响应对象 + */ +function resourceExists(resource, identifier = null) { + return error(-7, `${resource} already exists`, { + resource: resource, + identifier: identifier + }); +} + +/** + * 操作被拒绝响应 + * @param {string} reason 拒绝原因 + * @param {any} data 相关数据 + * @returns {Object} 响应对象 + */ +function operationDenied(reason, data = null) { + return error(-8, `Operation denied: ${reason}`, data); +} + +/** + * 未知命令响应 + * @param {string} command 命令名 + * @param {Array} availableCommands 可用命令列表 + * @returns {Object} 响应对象 + */ +function unknownCommand(command, availableCommands = []) { + return error(-2, `Unknown command: ${command}`, { + command: command, + available_commands: availableCommands + }); +} + +/** + * 包装异步操作,统一错误处理 + * @param {Function} operation 异步操作函数 + * @param {string} operationName 操作名称 + * @returns {Function} 包装后的函数 + */ +function wrapAsync(operation, operationName = "Operation") { + return async (...args) => { + try { + const result = await operation(...args); + + // 如果操作返回的是错误格式,直接返回 + if (result && typeof result === 'object' && result.code !== undefined) { + return result; + } + + // 如果是成功结果,包装为成功响应 + return success(result, `${operationName} completed successfully`); + } catch (error) { + console.error(`${operationName} error:`, error); + return systemError(`${operationName} failed`, error); + } + }; +} + +/** + * 验证必需参数 + * @param {Object} params 参数对象 + * @param {Array} requiredFields 必需字段列表 + * @returns {Object|null} 如果验证失败返回错误响应,否则返回null + */ +function validateRequiredParams(params, requiredFields) { + if (!params || typeof params !== 'object') { + return badRequest("Invalid parameters"); + } + + const missingFields = []; + for (const field of requiredFields) { + if (params[field] === undefined || params[field] === null) { + missingFields.push(field); + } + } + + if (missingFields.length > 0) { + return badRequest(`Missing required parameters: ${missingFields.join(', ')}`, { + missing_fields: missingFields, + required_fields: requiredFields + }); + } + + return null; +} + +/** + * 验证数值参数 + * @param {any} value 要验证的值 + * @param {string} fieldName 字段名 + * @param {Object} options 验证选项 + * @returns {Object|null} 如果验证失败返回错误响应,否则返回null + */ +function validateNumber(value, fieldName, options = {}) { + const { + min = Number.NEGATIVE_INFINITY, + max = Number.POSITIVE_INFINITY, + integer = false + } = options; + + if (typeof value !== 'number' || isNaN(value)) { + return badRequest(`${fieldName} must be a number`); + } + + if (integer && !Number.isInteger(value)) { + return badRequest(`${fieldName} must be an integer`); + } + + if (value < min) { + return badRequest(`${fieldName} must be at least ${min}`); + } + + if (value > max) { + return badRequest(`${fieldName} must be at most ${max}`); + } + + return null; +} + +/** + * 创建分页响应 + * @param {Array} items 数据项 + * @param {number} total 总数 + * @param {number} page 当前页 + * @param {number} pageSize 页大小 + * @param {string} message 成功消息 + * @returns {Object} 响应对象 + */ +function paginated(items, total, page, pageSize, message = "Data retrieved successfully") { + const totalPages = Math.ceil(total / pageSize); + + return success({ + items: items, + pagination: { + current_page: page, + page_size: pageSize, + total_items: total, + total_pages: totalPages, + has_next: page < totalPages, + has_prev: page > 1 + } + }, message); +} + +/** + * 错误码常量 + */ +const ERROR_CODES = { + SUCCESS: 200, + OPERATION_FAILED: -1, + UNKNOWN_COMMAND: -2, + BAD_REQUEST: -3, + USER_NOT_FOUND: -4, + SYSTEM_ERROR: -5, + INSUFFICIENT_RESOURCE: -6, + RESOURCE_EXISTS: -7, + OPERATION_DENIED: -8 +}; + +module.exports = { + success, + error, + badRequest, + userNotFound, + systemError, + insufficientResource, + resourceExists, + operationDenied, + unknownCommand, + wrapAsync, + validateRequiredParams, + validateNumber, + paginated, + ERROR_CODES +}; + diff --git a/build-templates/wechatgame/cloud_functions/cocos_cloud/user_init_data.js b/build-templates/wechatgame/cloud_functions/cocos_cloud/user_init_data.js new file mode 100644 index 00000000..db2562d4 --- /dev/null +++ b/build-templates/wechatgame/cloud_functions/cocos_cloud/user_init_data.js @@ -0,0 +1,274 @@ +// 新用户初始化数据配置文件 +// 用于管理新用户注册时的默认游戏数据 + +/** + * 数据版本号 - 用于数据结构升级和兼容性管理 + * 格式: MAJOR.MINOR.PATCH + * MAJOR: 重大结构变更,不向后兼容 + * MINOR: 新增字段,向后兼容 + * PATCH: 数值调整,完全兼容 + */ +const DATA_VERSION = "1.0.0"; + +/** + * 基础游戏数据默认值 + */ +const DEFAULT_GAME_DATA = { + score: 0, // 游戏分数 + mission: 1, // 当前关卡 + gold: 100, // 金币 - 升级主要资源 + diamond: 100, // 钻石 - 商店购买及双倍奖励资源 + meat: 0, // 肉类资源 + exp: 0, // 升级经验 + + // 英雄升星石头资源 + ghstone: 0, // 绿色英雄石 - 普通英雄升星 + bhstone: 0, // 蓝色英雄石 - 稀有英雄升星 + phlestone: 0, // 紫色英雄石 - 史诗英雄升星 + rhstone: 0, // 红色英雄石 - 传说英雄升星 + + // 抽卡和解锁资源 + herocard: 0, // 英雄卡 - 抽卡凭证 + ckey: 0, // 铜钥匙 - 解锁稀有英雄/兑换金币 + skey: 0, // 银钥匙 - 解锁史诗英雄/兑换金币 + gkey: 0 // 金钥匙 - 解锁传说英雄/兑换金币 +}; + +/** + * 默认出战英雄配置 + * 位置 0-4 对应 5个出战位置 + * 0 表示该位置为空 + */ +const DEFAULT_FIGHT_HEROS = { + 0: 5001, // 第1个位置:默认英雄5001 + 1: 5005, // 第2个位置:默认英雄5005 + 2: 0, // 第3个位置:空 + 3: 0, // 第4个位置:空 + 4: 0 // 第5个位置:空 +}; + +/** + * 默认英雄属性数据 + * 每个英雄包含: uuid(唯一标识), lv(等级), 其他属性可扩展 + */ +const DEFAULT_HEROS = { + 5001: { + uuid: 5001, + lv: 1, // 初始等级 + exp: 0, // 英雄经验 + star: 1, // 星级 + power: 100 // 战力 + }, + 5005: { + uuid: 5005, + lv: 1, + exp: 0, + star: 1, + power: 120 + }, + 5007: { + uuid: 5007, + lv: 1, + exp: 0, + star: 1, + power: 90 + } +}; + +/** + * 默认道具数据 + * ID 1001-1007 对应不同类型的道具 + */ +const DEFAULT_ITEMS = { + 1001: 0, // 生命药水 + 1002: 0, // 魔法药水 + 1003: 0, // 力量药水 + 1004: 0, // 敏捷药水 + 1005: 0, // 智力药水 + 1006: 0, // 复活卷轴 + 1007: 0 // 传送卷轴 +}; + +/** + * 默认天赋数据 + * ID 1001-1007 对应不同的天赋技能 + */ +const DEFAULT_TALS = { + 1001: 0, // 攻击强化 + 1002: 0, // 防御强化 + 1003: 0, // 生命强化 + 1004: 0, // 速度强化 + 1005: 0, // 暴击强化 + 1006: 0, // 经验强化 + 1007: 0 // 金币强化 +}; + +/** + * 默认装备数据 + * ID 1001-1005 对应不同部位的装备 + */ +const DEFAULT_EQUIPS = { + 1001: 0, // 武器 + 1002: 0, // 头盔 + 1003: 0, // 胸甲 + 1004: 0, // 护腿 + 1005: 0 // 靴子 +}; + +/** + * 获取完整的新用户初始化数据 + * @returns {Object} 包含所有默认数据的对象 + */ +function getNewUserInitData() { + return { + data_version: DATA_VERSION, + init_time: Date.now(), + data: { ...DEFAULT_GAME_DATA }, + fight_heros: { ...DEFAULT_FIGHT_HEROS }, + heros: JSON.parse(JSON.stringify(DEFAULT_HEROS)), // 深拷贝避免引用问题 + items: { ...DEFAULT_ITEMS }, + tals: { ...DEFAULT_TALS }, + equips: { ...DEFAULT_EQUIPS } + }; +} + +/** + * 获取特定类型的默认数据 + * @param {string} dataType 数据类型: 'data', 'fight_heros', 'heros', 'items', 'tals', 'equips' + * @returns {Object} 指定类型的默认数据 + */ +function getDefaultDataByType(dataType) { + const dataMap = { + data: DEFAULT_GAME_DATA, + fight_heros: DEFAULT_FIGHT_HEROS, + heros: DEFAULT_HEROS, + items: DEFAULT_ITEMS, + tals: DEFAULT_TALS, + equips: DEFAULT_EQUIPS + }; + + const defaultData = dataMap[dataType]; + if (!defaultData) { + throw new Error(`Unknown data type: ${dataType}`); + } + + // 返回深拷贝以避免修改原始数据 + return JSON.parse(JSON.stringify(defaultData)); +} + +/** + * 检查数据版本兼容性 + * @param {string} userDataVersion 用户数据版本 + * @returns {Object} 兼容性检查结果 + */ +function checkDataVersionCompatibility(userDataVersion) { + if (!userDataVersion) { + return { + compatible: false, + needsUpgrade: true, + message: "No version found, needs full upgrade" + }; + } + + const [userMajor, userMinor, userPatch] = userDataVersion.split('.').map(Number); + const [currentMajor, currentMinor, currentPatch] = DATA_VERSION.split('.').map(Number); + + if (userMajor < currentMajor) { + return { + compatible: false, + needsUpgrade: true, + message: "Major version mismatch, needs full upgrade" + }; + } + + if (userMajor === currentMajor && userMinor < currentMinor) { + return { + compatible: true, + needsUpgrade: true, + message: "Minor version update available" + }; + } + + if (userMajor === currentMajor && userMinor === currentMinor && userPatch < currentPatch) { + return { + compatible: true, + needsUpgrade: true, + message: "Patch update available" + }; + } + + return { + compatible: true, + needsUpgrade: false, + message: "Data version is up to date" + }; +} + +/** + * 合并用户数据和默认数据 + * 确保用户数据包含所有必需的字段 + * @param {Object} userData 用户现有数据 + * @returns {Object} 合并后的完整数据 + */ +function mergeUserDataWithDefaults(userData) { + const defaultData = getNewUserInitData(); + const mergedData = { + data_version: DATA_VERSION, + init_time: userData.init_time || Date.now(), + data: { ...defaultData.data, ...userData.data }, + fight_heros: { ...defaultData.fight_heros, ...userData.fight_heros }, + heros: { ...defaultData.heros, ...userData.heros }, + items: { ...defaultData.items, ...userData.items }, + tals: { ...defaultData.tals, ...userData.tals }, + equips: { ...defaultData.equips, ...userData.equips } + }; + + return mergedData; +} + +/** + * 验证数据结构完整性 + * @param {Object} gameData 要验证的游戏数据 + * @returns {Object} 验证结果 + */ +function validateDataStructure(gameData) { + const requiredFields = ['data', 'fight_heros', 'heros', 'items', 'tals', 'equips']; + const missingFields = []; + + for (const field of requiredFields) { + if (!gameData[field] || typeof gameData[field] !== 'object') { + missingFields.push(field); + } + } + + if (missingFields.length > 0) { + return { + valid: false, + missingFields, + message: `Missing or invalid fields: ${missingFields.join(', ')}` + }; + } + + return { + valid: true, + message: "Data structure is valid" + }; +} + +// 导出所有功能函数 +module.exports = { + DATA_VERSION, + getNewUserInitData, + getDefaultDataByType, + checkDataVersionCompatibility, + mergeUserDataWithDefaults, + validateDataStructure, + + // 导出原始数据常量(只读) + DEFAULT_GAME_DATA: Object.freeze({ ...DEFAULT_GAME_DATA }), + DEFAULT_FIGHT_HEROS: Object.freeze({ ...DEFAULT_FIGHT_HEROS }), + DEFAULT_HEROS: Object.freeze(JSON.parse(JSON.stringify(DEFAULT_HEROS))), + DEFAULT_ITEMS: Object.freeze({ ...DEFAULT_ITEMS }), + DEFAULT_TALS: Object.freeze({ ...DEFAULT_TALS }), + DEFAULT_EQUIPS: Object.freeze({ ...DEFAULT_EQUIPS }) +}; diff --git a/package.json b/package.json index c1591d28..d3084b1c 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,9 @@ { "_sourceId": "9863f48f-eb18-49fa-8644-4334bd927ee3", "creator": { - "version": "3.8.2" + "version": "3.8.6" }, - "name": "oops-rpg-2d", + "name": "pixel_hero", "uuid": "9ee6c3ed-db87-4cc3-9019-02413dec22fb", "dependencies": { "crypto-es": "^2.1.0" diff --git a/settings/v2/packages/builder.json b/settings/v2/packages/builder.json index 01ff4b27..9c64b7a4 100644 --- a/settings/v2/packages/builder.json +++ b/settings/v2/packages/builder.json @@ -1,5 +1,5 @@ { - "__version__": "1.3.7", + "__version__": "1.3.9", "textureCompressConfig": { "genMipmaps": false }, diff --git a/settings/v2/packages/engine.json b/settings/v2/packages/engine.json index 5331b8e0..11ee393a 100644 --- a/settings/v2/packages/engine.json +++ b/settings/v2/packages/engine.json @@ -1,153 +1,228 @@ { "modules": { - "cache": { - "base": { - "_value": true - }, - "graphcis": { - "_value": true - }, - "gfx-webgl": { - "_value": true - }, - "gfx-webgl2": { - "_value": true - }, - "animation": { - "_value": true - }, - "skeletal-animation": { - "_value": true - }, - "3d": { - "_value": false - }, - "2d": { - "_value": true - }, - "xr": { - "_value": false - }, - "ui": { - "_value": true - }, - "particle": { - "_value": false - }, - "physics": { - "_value": false, - "_option": "physics-ammo" - }, - "physics-ammo": { - "_value": false - }, - "physics-cannon": { - "_value": false - }, - "physics-physx": { - "_value": false - }, - "physics-builtin": { - "_value": false - }, - "physics-2d": { - "_value": true, - "_option": "physics-2d-box2d" - }, - "physics-2d-box2d": { - "_value": false - }, - "physics-2d-builtin": { - "_value": false - }, - "intersection-2d": { - "_value": true - }, - "primitive": { - "_value": false - }, - "profiler": { - "_value": true - }, - "occlusion-query": { - "_value": false - }, - "geometry-renderer": { - "_value": false - }, - "debug-renderer": { - "_value": false - }, - "particle-2d": { - "_value": true - }, - "audio": { - "_value": true - }, - "video": { - "_value": false - }, - "webview": { - "_value": false - }, - "tween": { - "_value": true - }, - "websocket": { - "_value": false - }, - "websocket-server": { - "_value": false - }, - "terrain": { - "_value": false - }, - "light-probe": { - "_value": false - }, - "tiled-map": { - "_value": false - }, - "spine": { - "_value": true - }, - "dragon-bones": { - "_value": true - }, - "marionette": { - "_value": false - }, - "procedural-animation": { - "_value": false - }, - "custom-pipeline": { - "_value": false + "graphics": { + "pipeline": "legacy-pipeline" + }, + "configs": { + "migrationsConfig": { + "cache": { + "base": { + "_value": true + }, + "gfx-webgl": { + "_value": true + }, + "gfx-webgl2": { + "_value": true + }, + "gfx-webgpu": { + "_value": false + }, + "animation": { + "_value": true + }, + "skeletal-animation": { + "_value": true + }, + "3d": { + "_value": false + }, + "meshopt": { + "_value": false + }, + "2d": { + "_value": true + }, + "xr": { + "_value": false + }, + "rich-text": { + "_value": true + }, + "mask": { + "_value": true + }, + "graphics": { + "_value": true + }, + "ui-skew": { + "_value": false + }, + "affine-transform": { + "_value": true + }, + "ui": { + "_value": true + }, + "particle": { + "_value": false + }, + "physics": { + "_value": false, + "_option": "physics-ammo" + }, + "physics-ammo": { + "_value": false, + "_flags": { + "LOAD_BULLET_MANUALLY": false + } + }, + "physics-cannon": { + "_value": false + }, + "physics-physx": { + "_value": false, + "_flags": { + "LOAD_PHYSX_MANUALLY": false + } + }, + "physics-builtin": { + "_value": false + }, + "physics-2d": { + "_value": true, + "_option": "physics-2d-box2d" + }, + "physics-2d-box2d": { + "_value": false + }, + "physics-2d-box2d-wasm": { + "_value": false, + "_flags": { + "LOAD_BOX2D_MANUALLY": false + } + }, + "physics-2d-builtin": { + "_value": false + }, + "physics-2d-box2d-jsb": { + "_value": false + }, + "intersection-2d": { + "_value": true + }, + "primitive": { + "_value": false + }, + "profiler": { + "_value": true + }, + "occlusion-query": { + "_value": false + }, + "geometry-renderer": { + "_value": false + }, + "debug-renderer": { + "_value": false + }, + "particle-2d": { + "_value": true + }, + "audio": { + "_value": true + }, + "video": { + "_value": false + }, + "webview": { + "_value": false + }, + "tween": { + "_value": true + }, + "websocket": { + "_value": false + }, + "websocket-server": { + "_value": false + }, + "terrain": { + "_value": false + }, + "light-probe": { + "_value": false + }, + "tiled-map": { + "_value": false + }, + "vendor-google": { + "_value": false + }, + "spine": { + "_value": true, + "_option": "spine-3.8" + }, + "spine-3.8": { + "_value": true, + "_flags": { + "LOAD_SPINE_MANUALLY": false + } + }, + "spine-4.2": { + "_value": false, + "_flags": { + "LOAD_SPINE_MANUALLY": false + } + }, + "dragon-bones": { + "_value": true + }, + "marionette": { + "_value": false + }, + "procedural-animation": { + "_value": false + }, + "custom-pipeline-post-process": { + "_value": false + }, + "render-pipeline": { + "_value": true, + "_option": "legacy-pipeline" + }, + "custom-pipeline": { + "_value": true + }, + "legacy-pipeline": { + "_value": false + } + }, + "flags": { + "LOAD_SPINE_MANUALLY": false + }, + "name": "迁移生成的配置", + "includeModules": [ + "2d", + "affine-transform", + "animation", + "audio", + "base", + "dragon-bones", + "gfx-webgl", + "gfx-webgl2", + "graphics", + "intersection-2d", + "legacy-pipeline", + "mask", + "particle-2d", + "physics-2d-box2d", + "profiler", + "rich-text", + "skeletal-animation", + "spine-3.8", + "tween", + "ui" + ], + "noDeprecatedFeatures": { + "value": false, + "version": "" + } } }, - "includeModules": [ - "2d", - "animation", - "audio", - "base", - "dragon-bones", - "gfx-webgl", - "gfx-webgl2", - "intersection-2d", - "particle-2d", - "physics-2d-box2d", - "profiler", - "skeletal-animation", - "spine", - "tween", - "ui" - ], - "flags": {}, - "noDeprecatedFeatures": { - "value": false, - "version": "" - } + "globalConfigKey": "migrationsConfig" }, - "__version__": "1.0.8", + "__version__": "1.0.12", "macroConfig": { "BATCHER2D_MEM_INCREMENT": 144 }