181404010226 5 сар өмнө
parent
commit
67a77bb246
26 өөрчлөгдсөн 636 нэмэгдсэн , 1437 устгасан
  1. BIN
      UI.zip
  2. 208 846
      assets/Scenes/GameLevel.scene
  3. 14 133
      assets/Scenes/TestScene.scene
  4. 8 8
      assets/assets/Prefabs/PelletContainer.prefab
  5. 1 1
      assets/resources/Animation/WeaponTx/tx0001.meta
  6. 1 2
      assets/resources/Animation/WeaponTx/tx0001/tx0001.atlas
  7. 1 1
      assets/resources/Animation/WeaponTx/tx0001/tx0001.atlas.meta
  8. 2 2
      assets/resources/Animation/WeaponTx/tx0001/tx0001.json.meta
  9. 6 6
      assets/resources/Animation/WeaponTx/tx0001/tx0001.png.meta
  10. 1 1
      assets/resources/Animation/WeaponTx/tx0002.meta
  11. 1 1
      assets/resources/Animation/WeaponTx/tx0002/tx0002.atlas
  12. 1 1
      assets/resources/Animation/WeaponTx/tx0003.meta
  13. 1 1
      assets/resources/Animation/WeaponTx/tx0004.meta
  14. 1 1
      assets/resources/Animation/WeaponTx/tx0005.meta
  15. 1 1
      assets/resources/Animation/WeaponTx/tx0006.meta
  16. 1 1
      assets/resources/Animation/WeaponTx/tx0007.meta
  17. 15 0
      assets/resources/data/player_data.json
  18. 11 0
      assets/resources/data/player_data.json.meta
  19. 22 14
      assets/scripts/CombatSystem/BlockManager.ts
  20. 8 5
      assets/scripts/CombatSystem/EnemyController.ts
  21. 43 0
      assets/scripts/Core/LevelSessionManager.ts
  22. 9 0
      assets/scripts/Core/LevelSessionManager.ts.meta
  23. 107 49
      assets/scripts/LevelSystem/GameManager.ts
  24. 159 363
      assets/scripts/LevelSystem/MainUIController.ts
  25. 5 0
      assets/scripts/LevelSystem/SaveDataManager.ts
  26. 9 0
      assets/scripts/TestScene.meta

BIN
UI.zip


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 208 - 846
assets/Scenes/GameLevel.scene


+ 14 - 133
assets/Scenes/TestScene.scene

@@ -23,7 +23,7 @@
     "_active": true,
     "_components": [],
     "_prefab": {
-      "__id__": 16
+      "__id__": 8
     },
     "_lpos": {
       "__type__": "cc.Vec3",
@@ -54,7 +54,7 @@
     },
     "autoReleaseAssets": false,
     "_globals": {
-      "__id__": 17
+      "__id__": 9
     },
     "_id": "8a125a67-dbc5-4c64-b398-6a616deee4aa"
   },
@@ -69,21 +69,18 @@
     "_children": [
       {
         "__id__": 3
-      },
-      {
-        "__id__": 5
       }
     ],
     "_active": true,
     "_components": [
       {
-        "__id__": 13
+        "__id__": 5
       },
       {
-        "__id__": 14
+        "__id__": 6
       },
       {
-        "__id__": 15
+        "__id__": 7
       }
     ],
     "_prefab": null,
@@ -207,117 +204,6 @@
     "_trackingType": 0,
     "_id": "63WIch3o5BEYRlXzTT0oWc"
   },
-  {
-    "__type__": "cc.Node",
-    "_objFlags": 0,
-    "_parent": {
-      "__id__": 2
-    },
-    "_prefab": {
-      "__id__": 6
-    },
-    "__editorExtras__": {}
-  },
-  {
-    "__type__": "cc.PrefabInfo",
-    "root": {
-      "__id__": 5
-    },
-    "asset": {
-      "__uuid__": "425d97ad-14a3-4092-ac74-6ada1ee28fa9",
-      "__expectedType__": "cc.Prefab"
-    },
-    "fileId": "2fgmWEQyhIGr02gKDR/YNr",
-    "instance": {
-      "__id__": 7
-    },
-    "targetOverrides": null,
-    "nestedPrefabInstanceRoots": null
-  },
-  {
-    "__type__": "cc.PrefabInstance",
-    "fileId": "50ay3Dg9NOLqQ1/lYJy8vF",
-    "prefabRootNode": null,
-    "mountedChildren": [],
-    "mountedComponents": [],
-    "propertyOverrides": [
-      {
-        "__id__": 8
-      },
-      {
-        "__id__": 10
-      },
-      {
-        "__id__": 11
-      },
-      {
-        "__id__": 12
-      }
-    ],
-    "removedComponents": []
-  },
-  {
-    "__type__": "CCPropertyOverrideInfo",
-    "targetInfo": {
-      "__id__": 9
-    },
-    "propertyPath": [
-      "_name"
-    ],
-    "value": "WeaponBlock"
-  },
-  {
-    "__type__": "cc.TargetInfo",
-    "localID": [
-      "2fgmWEQyhIGr02gKDR/YNr"
-    ]
-  },
-  {
-    "__type__": "CCPropertyOverrideInfo",
-    "targetInfo": {
-      "__id__": 9
-    },
-    "propertyPath": [
-      "_lpos"
-    ],
-    "value": {
-      "__type__": "cc.Vec3",
-      "x": 0,
-      "y": -6.766,
-      "z": 0
-    }
-  },
-  {
-    "__type__": "CCPropertyOverrideInfo",
-    "targetInfo": {
-      "__id__": 9
-    },
-    "propertyPath": [
-      "_lrot"
-    ],
-    "value": {
-      "__type__": "cc.Quat",
-      "x": 0,
-      "y": 0,
-      "z": 0,
-      "w": 1
-    }
-  },
-  {
-    "__type__": "CCPropertyOverrideInfo",
-    "targetInfo": {
-      "__id__": 9
-    },
-    "propertyPath": [
-      "_euler"
-    ],
-    "value": {
-      "__type__": "cc.Vec3",
-      "x": 0,
-      "y": 0,
-      "z": 0
-    }
-  },
   {
     "__type__": "cc.UITransform",
     "_name": "",
@@ -392,38 +278,33 @@
     "asset": null,
     "fileId": "8a125a67-dbc5-4c64-b398-6a616deee4aa",
     "instance": null,
-    "targetOverrides": null,
-    "nestedPrefabInstanceRoots": [
-      {
-        "__id__": 5
-      }
-    ]
+    "targetOverrides": null
   },
   {
     "__type__": "cc.SceneGlobals",
     "ambient": {
-      "__id__": 18
+      "__id__": 10
     },
     "shadows": {
-      "__id__": 19
+      "__id__": 11
     },
     "_skybox": {
-      "__id__": 20
+      "__id__": 12
     },
     "fog": {
-      "__id__": 21
+      "__id__": 13
     },
     "octree": {
-      "__id__": 22
+      "__id__": 14
     },
     "skin": {
-      "__id__": 23
+      "__id__": 15
     },
     "lightProbeInfo": {
-      "__id__": 24
+      "__id__": 16
     },
     "postSettings": {
-      "__id__": 25
+      "__id__": 17
     },
     "bakedWithStationaryMainLight": false,
     "bakedWithHighpLightmap": false

+ 8 - 8
assets/assets/Prefabs/PelletContainer.prefab

@@ -55,8 +55,8 @@
     },
     "_lscale": {
       "__type__": "cc.Vec3",
-      "x": 0.5,
-      "y": 0.5,
+      "x": 0.6,
+      "y": 0.6,
       "z": 1
     },
     "_mobility": 0,
@@ -108,8 +108,8 @@
     },
     "_lscale": {
       "__type__": "cc.Vec3",
-      "x": 0.5,
-      "y": 0.5,
+      "x": 1,
+      "y": 1,
       "z": 1
     },
     "_mobility": 0,
@@ -136,8 +136,8 @@
     },
     "_contentSize": {
       "__type__": "cc.Size",
-      "width": 114,
-      "height": 114
+      "width": 57,
+      "height": 57
     },
     "_anchorPoint": {
       "__type__": "cc.Vec2",
@@ -342,11 +342,11 @@
       "a": 255
     },
     "_skeletonData": {
-      "__uuid__": "03e20616-4f08-4682-848d-7b9e8e27af35",
+      "__uuid__": "15209fa2-9c09-477e-a266-1bd7596cc915",
       "__expectedType__": "sp.SkeletonData"
     },
     "defaultSkin": "default",
-    "defaultAnimation": "<None>",
+    "defaultAnimation": "",
     "_premultipliedAlpha": true,
     "_timeScale": 1,
     "_preCacheMode": 0,

+ 1 - 1
assets/resources/Animation/WeaponTx/tx0001.meta

@@ -2,7 +2,7 @@
   "ver": "1.2.0",
   "importer": "directory",
   "imported": true,
-  "uuid": "b14b8208-24a0-4778-af7a-1d47a1bae58d",
+  "uuid": "d127f9dc-377c-4563-aa61-c6cd27aa7a96",
   "files": [],
   "subMetas": {},
   "userData": {}

+ 1 - 2
assets/resources/Animation/WeaponTx/tx0001/tx0001.atlas

@@ -1,5 +1,4 @@
-
-tx000.png
+tx0001.png
 size: 53, 172
 format: RGBA8888
 filter: Linear, Linear

+ 1 - 1
assets/resources/Animation/WeaponTx/tx0001/tx0001.atlas.meta

@@ -2,7 +2,7 @@
   "ver": "1.0.0",
   "importer": "*",
   "imported": true,
-  "uuid": "03ef8c81-7e07-4710-a6bd-3148221a80ef",
+  "uuid": "d974b1b0-8591-4a93-97ee-921630789964",
   "files": [
     ".atlas",
     ".json"

+ 2 - 2
assets/resources/Animation/WeaponTx/tx0001/tx0001.json.meta

@@ -2,12 +2,12 @@
   "ver": "1.2.7",
   "importer": "spine-data",
   "imported": true,
-  "uuid": "03e20616-4f08-4682-848d-7b9e8e27af35",
+  "uuid": "15209fa2-9c09-477e-a266-1bd7596cc915",
   "files": [
     ".json"
   ],
   "subMetas": {},
   "userData": {
-    "atlasUuid": "03ef8c81-7e07-4710-a6bd-3148221a80ef"
+    "atlasUuid": "d974b1b0-8591-4a93-97ee-921630789964"
   }
 }

+ 6 - 6
assets/resources/Animation/WeaponTx/tx0001/tx0001.png.meta

@@ -2,7 +2,7 @@
   "ver": "1.0.27",
   "importer": "image",
   "imported": true,
-  "uuid": "5d62b7b6-0932-4e8a-86ef-63e3ea0a08c3",
+  "uuid": "10990bce-6040-45ea-9167-319f1de50c61",
   "files": [
     ".json",
     ".png"
@@ -10,14 +10,14 @@
   "subMetas": {
     "6c48a": {
       "importer": "texture",
-      "uuid": "5d62b7b6-0932-4e8a-86ef-63e3ea0a08c3@6c48a",
+      "uuid": "10990bce-6040-45ea-9167-319f1de50c61@6c48a",
       "displayName": "tx0001",
       "id": "6c48a",
       "name": "texture",
       "userData": {
         "wrapModeS": "clamp-to-edge",
         "wrapModeT": "clamp-to-edge",
-        "imageUuidOrDatabaseUri": "5d62b7b6-0932-4e8a-86ef-63e3ea0a08c3",
+        "imageUuidOrDatabaseUri": "10990bce-6040-45ea-9167-319f1de50c61",
         "isUuid": true,
         "visible": false,
         "minfilter": "linear",
@@ -34,7 +34,7 @@
     },
     "f9941": {
       "importer": "sprite-frame",
-      "uuid": "5d62b7b6-0932-4e8a-86ef-63e3ea0a08c3@f9941",
+      "uuid": "10990bce-6040-45ea-9167-319f1de50c61@f9941",
       "displayName": "tx0001",
       "id": "f9941",
       "name": "spriteFrame",
@@ -113,7 +113,7 @@
           ]
         },
         "isUuid": true,
-        "imageUuidOrDatabaseUri": "5d62b7b6-0932-4e8a-86ef-63e3ea0a08c3@6c48a",
+        "imageUuidOrDatabaseUri": "10990bce-6040-45ea-9167-319f1de50c61@6c48a",
         "atlasUuid": "",
         "trimType": "auto"
       },
@@ -129,6 +129,6 @@
     "type": "sprite-frame",
     "hasAlpha": true,
     "fixAlphaTransparencyArtifacts": false,
-    "redirect": "5d62b7b6-0932-4e8a-86ef-63e3ea0a08c3@6c48a"
+    "redirect": "10990bce-6040-45ea-9167-319f1de50c61@6c48a"
   }
 }

+ 1 - 1
assets/resources/Animation/WeaponTx/tx0002.meta

@@ -2,7 +2,7 @@
   "ver": "1.2.0",
   "importer": "directory",
   "imported": true,
-  "uuid": "9634e58d-3229-4cda-85ff-e4ed19f3e203",
+  "uuid": "820913e3-ac99-4f6a-8ef5-7f2a727ffa7a",
   "files": [],
   "subMetas": {},
   "userData": {}

+ 1 - 1
assets/resources/Animation/WeaponTx/tx0002/tx0002.atlas

@@ -1,5 +1,5 @@
 
-tx0001.png
+tx0002.png
 size: 128, 130
 format: RGBA8888
 filter: Linear, Linear

+ 1 - 1
assets/resources/Animation/WeaponTx/tx0003.meta

@@ -2,7 +2,7 @@
   "ver": "1.2.0",
   "importer": "directory",
   "imported": true,
-  "uuid": "2c6d5fad-f286-4ee7-afab-1bae62d624b2",
+  "uuid": "494e2723-65b3-4fd0-8491-9d5357941a55",
   "files": [],
   "subMetas": {},
   "userData": {}

+ 1 - 1
assets/resources/Animation/WeaponTx/tx0004.meta

@@ -2,7 +2,7 @@
   "ver": "1.2.0",
   "importer": "directory",
   "imported": true,
-  "uuid": "35f28f7c-7337-49f5-a173-d5b4bd074a65",
+  "uuid": "546bc9f8-9520-4d87-a60b-7f90f06fe909",
   "files": [],
   "subMetas": {},
   "userData": {}

+ 1 - 1
assets/resources/Animation/WeaponTx/tx0005.meta

@@ -2,7 +2,7 @@
   "ver": "1.2.0",
   "importer": "directory",
   "imported": true,
-  "uuid": "b76eedf0-481d-40eb-ae06-2d3de98e5202",
+  "uuid": "2f0373f7-2ccb-4a27-8635-41825eadd311",
   "files": [],
   "subMetas": {},
   "userData": {}

+ 1 - 1
assets/resources/Animation/WeaponTx/tx0006.meta

@@ -2,7 +2,7 @@
   "ver": "1.2.0",
   "importer": "directory",
   "imported": true,
-  "uuid": "d4c7bdd7-7678-4176-b5e2-b8a746428739",
+  "uuid": "86c324f6-84e9-45a2-9eaa-1fb7a58dd8a2",
   "files": [],
   "subMetas": {},
   "userData": {}

+ 1 - 1
assets/resources/Animation/WeaponTx/tx0007.meta

@@ -2,7 +2,7 @@
   "ver": "1.2.0",
   "importer": "directory",
   "imported": true,
-  "uuid": "d23cbc72-433c-49be-ac0a-bb775d8643a8",
+  "uuid": "80d2630a-8185-417b-8cfd-abf60273ffc7",
   "files": [],
   "subMetas": {},
   "userData": {}

+ 15 - 0
assets/resources/data/player_data.json

@@ -0,0 +1,15 @@
+{
+  "playerId": "gid-20240711-001",
+  "createTime": 1720634200000,
+  "playerLevel": 3,
+  "coins": 1230,
+  "diamonds": 75,
+  "gems": 6,
+
+  "currentLevel": 1,
+  "maxUnlockedLevel": 1,
+
+  "wallBaseHealth": 105,
+  "inventory": { },
+  "statistics": { }
+}

+ 11 - 0
assets/resources/data/player_data.json.meta

@@ -0,0 +1,11 @@
+{
+  "ver": "2.0.1",
+  "importer": "json",
+  "imported": true,
+  "uuid": "f73ef160-7a4d-4726-8f27-3d52f2870d85",
+  "files": [
+    ".json"
+  ],
+  "subMetas": {},
+  "userData": {}
+}

+ 22 - 14
assets/scripts/CombatSystem/BlockManager.ts

@@ -1,5 +1,7 @@
 import { _decorator, Component, Node, Prefab, instantiate, Vec3, EventTouch, Vec2, UITransform, find, Rect, Label, Color, Size, Sprite, SpriteFrame, resources, Button } from 'cc';
 import { ConfigManager, WeaponConfig } from '../Core/ConfigManager';
+import { SaveDataManager } from '../LevelSystem/SaveDataManager';
+import { LevelSessionManager } from '../Core/LevelSessionManager';
 const { ccclass, property } = _decorator;
 
 @ccclass('BlockManager')
@@ -45,8 +47,10 @@ export class BlockManager extends Component {
     })
     public blockMoveCooldown: number = 1;
     
-    // 玩家金币数量
-    private playerCoins: number = 69999;
+    // SaveDataManager 单例
+    private saveDataManager: SaveDataManager = null; // 仅用于局外数据
+
+    private session: LevelSessionManager = null;
     
     // 方块价格标签映射
     private blockPriceMap: Map<Node, Node> = new Map();
@@ -176,6 +180,10 @@ export class BlockManager extends Component {
         // 确保有PlacedBlocks节点用于存放已放置的方块
         this.ensurePlacedBlocksNode();
         
+        // 获取数据管理器
+        this.saveDataManager = SaveDataManager.getInstance();
+        this.session = LevelSessionManager.inst;
+        
         // 初始化玩家金币显示
         this.updateCoinDisplay();
         
@@ -395,7 +403,8 @@ export class BlockManager extends Component {
         if (this.coinLabelNode) {
             const label = this.coinLabelNode.getComponent(Label);
             if (label) {
-                label.string = this.playerCoins.toString();
+                const coins = this.session.getCoins();
+                label.string = coins.toString();
             }
         }
     }
@@ -433,17 +442,16 @@ export class BlockManager extends Component {
     
     // 扣除玩家金币
     deductPlayerCoins(amount: number): boolean {
-        if (this.playerCoins >= amount) {
-            this.playerCoins -= amount;
+        const success = this.session.spendCoins(amount);
+        if (success) {
             this.updateCoinDisplay();
-            return true;
         }
-        return false;
+        return success;
     }
     
     // 归还玩家金币
     refundPlayerCoins(amount: number) {
-        this.playerCoins += amount;
+        this.session.addCoins(amount);
         this.updateCoinDisplay();
     }
     
@@ -1030,22 +1038,22 @@ export class BlockManager extends Component {
         let price: number;
         switch (rarity) {
             case 'common':
-                price = 50;
+                price = 10;
                 break;
             case 'uncommon':
-                price = 100;
+                price = 20;
                 break;
             case 'rare':
-                price = 200;
+                price = 50;
                 break;
             case 'epic':
-                price = 350;
+                price = 100;
                 break;
             case 'legendary':
-                price = 500;
+                price = 150;
                 break;
             default:
-                price = 50;
+                price = 200;
         }
         
         label.string = price.toString();

+ 8 - 5
assets/scripts/CombatSystem/EnemyController.ts

@@ -4,6 +4,7 @@ import { ConfigManager, EnemyConfig } from '../Core/ConfigManager';
 import { EnemyComponent } from '../CombatSystem/EnemyComponent';
 import { EnemyInstance } from './EnemyInstance';
 import { BaseSingleton } from '../Core/BaseSingleton';
+import { SaveDataManager } from '../LevelSystem/SaveDataManager';
 const { ccclass, property } = _decorator;
 
 // 前向声明EnemyInstance类型,避免循环引用
@@ -54,11 +55,8 @@ export class EnemyController extends BaseSingleton {
     })
     public wallHealth: number = 1200;
 
-    @property({
-        type: Node,
-        tooltip: '墙体血量显示节点'
-    })
-    public wallHealthNode: Node = null;
+    // 墙体血量显示节点(运行时动态查找)
+    private wallHealthNode: Node = null;
 
     // 游戏区域边界 - 改为public,让敌人实例可以访问
     public gameBounds = {
@@ -127,6 +125,11 @@ export class EnemyController extends BaseSingleton {
         // 查找墙体节点
         this.findWallNodes();
         
+        // 从存档读取墙体基础血量,如果有的话
+        const sdm = SaveDataManager.getInstance();
+        const base = (sdm.getPlayerData() as any)?.wallBaseHealth;
+        if (typeof base === 'number' && base > 0) this.wallHealth = base;
+        
         // 初始化墙体血量显示
         this.initWallHealthDisplay();
         

+ 43 - 0
assets/scripts/Core/LevelSessionManager.ts

@@ -0,0 +1,43 @@
+export interface LevelRuntimeData {
+  levelId: number;               // 本局关卡
+  wallHealth: number;            // 当前墙血
+  enemiesTotal: number;          // 本关总敌人
+  enemiesKilled: number;         // 已击杀
+  currentWave: number;           // 当前波
+  //drops: DropItemData[];         // 已掉落的道具
+  startTime: number;
+
+  sessionCoins: number;          // 本局金币(购买方块)
+}
+
+export class LevelSessionManager {
+  private static _inst: LevelSessionManager;
+  public static get inst() { return this._inst || (this._inst = new LevelSessionManager()); }
+
+  private data: LevelRuntimeData = null;
+
+  /** 准备本关运行期数据 */
+  public initialize(levelId: number, wallHealth: number) {
+    this.data = {
+      levelId,
+      wallHealth,
+      enemiesTotal: 0,
+      enemiesKilled: 0,
+      currentWave: 1,
+      //drops: [],
+      startTime: Date.now(),
+      sessionCoins: 45
+    };
+  }
+
+  public get runtime() { return this.data; }
+
+  /** 关卡结束后调用,让 GC 自动回收 */
+  public clear() { this.data = null; }
+
+  // ======== 本局金币接口 ========
+  public getCoins(): number { return this.data?.sessionCoins ?? 0; }
+  public addCoins(amt:number){ if(this.data) this.data.sessionCoins += amt; }
+  /** 成功返回true */
+  public spendCoins(amt:number):boolean{ if(!this.data || amt<=0) return false; if(this.data.sessionCoins<amt) return false; this.data.sessionCoins-=amt; return true; }
+}

+ 9 - 0
assets/scripts/Core/LevelSessionManager.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "1ca4abe9-a410-48cb-b7fd-413a22150165",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 107 - 49
assets/scripts/LevelSystem/GameManager.ts

@@ -9,6 +9,8 @@ import EventBus, { GameEvents } from '../Core/EventBus';
 import { PhysicsManager } from '../Core/PhysicsManager';
 import { MainUIController } from './MainUIController';
 import { BallController } from '../CombatSystem/BallController';
+import { BlockManager } from '../CombatSystem/BlockManager';
+import { LevelSessionManager } from '../Core/LevelSessionManager';
 const { ccclass, property } = _decorator;
 
 /**
@@ -73,10 +75,8 @@ export class GameManager extends Component {
     public gameDefeatUI: Node = null;
 
     // === 游戏配置属性 ===
-    @property({
-        tooltip: '墙体初始血量'
-    })
-    public wallHealth: number = 1200;
+    // 墙体基础血量由存档决定,不再通过属性面板设置
+    private wallHealth: number = 100;
 
     @property({
         tooltip: '初始血量'
@@ -195,6 +195,12 @@ export class GameManager extends Component {
         // 初始化存档管理器
         this.saveDataManager = SaveDataManager.getInstance();
         this.saveDataManager.initialize();
+
+        // 从存档读取墙体基础血量
+        const pd = this.saveDataManager.getPlayerData();
+        if (pd && typeof pd.wallBaseHealth === 'number') {
+            this.wallHealth = pd.wallBaseHealth;
+        }
     }
 
     // === 游戏状态初始化 ===
@@ -283,26 +289,9 @@ export class GameManager extends Component {
             this.heartLabel.string = this.wallHealth.toString();
         }
         
-        // 通知敌人控制器墙体血量节点
-        if (this.enemyController && this.heartLabelNode) {
-            this.updateEnemyControllerWallHealth(this.heartLabelNode);
-        }
-    }
-
-    // === 更新EnemyController的墙体血量 ===
-    private updateEnemyControllerWallHealth(wallHealthNode: Node) {
-        if (this.enemyController) {
-            // 同步血量值
-            this.enemyController.wallHealth = this.wallHealth;
-            
-            // 设置血量显示节点
-            const heartLabelNode = find('Canvas/GameLevelUI/HeartNode/HeartLabeld');
-            if (heartLabelNode) {
-                this.enemyController.wallHealthNode = heartLabelNode;
-            }
-            
-            // 让EnemyController更新显示
-            this.enemyController.updateWallHealthDisplay();
+        // 让 EnemyController 自行查找/刷新血量 UI
+        if (this.enemyController.initWallHealthDisplay) {
+            this.enemyController.initWallHealthDisplay();
         }
     }
 
@@ -595,7 +584,7 @@ export class GameManager extends Component {
             if (nextLevelBtn) {
                 const button = nextLevelBtn.getComponent(Button);
                 if (button) {
-                    button.node.on(Button.EventType.CLICK, this.onNextLevelClick, this);
+                    button.node.on(Button.EventType.CLICK, this.onRestartClick, this);
                 }
             }
 
@@ -661,27 +650,6 @@ export class GameManager extends Component {
     }
 
     // === 按钮点击事件处理 ===
-    private async onNextLevelClick() {
-        if (!this.saveDataManager) return;
-        
-        const currentLevel = this.saveDataManager.getCurrentLevel();
-        const nextLevel = currentLevel + 1;
-        
-        // 检查下一关是否已解锁
-        if (this.saveDataManager.isLevelUnlocked(nextLevel)) {
-            // 设置下一关为当前关
-            const playerData = this.saveDataManager.getPlayerData();
-            if (playerData) {
-                playerData.currentLevel = nextLevel;
-                this.saveDataManager.savePlayerData();
-                
-                // 重新开始游戏
-                this.restartGame();
-                await this.loadCurrentLevelConfig();
-            }
-        }
-    }
-    
     private onRestartClick() {
         this.restartGame();
     }
@@ -773,6 +741,11 @@ export class GameManager extends Component {
         
         // 开始生成敌人
         this.forceStartEnemySpawning();
+
+        LevelSessionManager.inst.initialize(
+            SaveDataManager.getInstance().getCurrentLevel(),
+            this.wallHealth
+        );
     }
     
     private spawnBall() {
@@ -816,10 +789,39 @@ export class GameManager extends Component {
         this.currentWave = 1;
         this.currentWaveEnemyCount = 0;
         
+        // 关闭胜利/失败界面,确保重新进入时是正常状态
+        if (this.gameSuccessUI) {
+            this.gameSuccessUI.active = false;
+        }
+        if (this.gameDefeatUI) {
+            this.gameDefeatUI.active = false;
+        }
+ 
         // 通知BlockManager游戏重置
-        const blockManager = find('Canvas/GameLevelUI')?.getComponent('BlockManager');
-        if (blockManager && blockManager['onGameReset']) {
-            blockManager['onGameReset']();
+        const blockMgrNode = find('Canvas/GameLevelUI/BlockController');
+        const blockManager = blockMgrNode?.getComponent(BlockManager);
+        if (blockManager) {
+            blockManager.onGameReset?.();
+        }
+ 
+        // 清空关卡剩余敌人
+        if (this.enemyController && this.enemyController.clearAllEnemies) {
+            this.enemyController.clearAllEnemies();
+        }
+ 
+        // 重置墙体血量显示
+        this.initWallHealthDisplay();
+ 
+        // 初始化本局数据(金币45等)
+        LevelSessionManager.inst.clear();
+        LevelSessionManager.inst.initialize(
+            this.saveDataManager.getCurrentLevel(),
+            this.wallHealth
+        );
+
+        // 刷新方块金币显示(如果 BlockManager 已存在)
+        if (blockManager) {
+            blockManager.updateCoinDisplay?.();
         }
     }
 
@@ -1077,4 +1079,60 @@ export class GameManager extends Component {
             }
         }
     }
+
+    /* ========= 墙体血量 / 等级相关 ========= */
+
+    private wallHpMap: Record<number, number> = {
+        1: 100,
+        2: 1000,
+        3: 1200,
+        4: 1500,
+        5: 2000
+    };
+
+    /** 根据等级获取墙体血量 */
+    public getWallHealthByLevel(level: number): number {
+        return this.wallHpMap[level] || (100 + (level - 1) * 200);
+    }
+
+    /** 获取当前墙壁等级 */
+    public getCurrentWallLevel(): number {
+        return this.saveDataManager?.getPlayerData().playerLevel || 1;
+    }
+
+    /** 获取当前墙体血量 */
+    public getCurrentWallHealth(): number {
+        return this.saveDataManager?.getPlayerData().wallBaseHealth || this.getWallHealthByLevel(1);
+    }
+
+    /** 升级墙体等级,返回升级后信息,失败返回null */
+    public upgradeWallLevel(): { currentLevel: number; currentHp: number; nextLevel: number; nextHp: number } | null {
+        if (!this.saveDataManager) return null;
+
+        const pd = this.saveDataManager.getPlayerData();
+        const curLvl = pd.playerLevel || 1;
+        if (curLvl >= 5) return null; // 已达最高级
+
+        const newLvl = curLvl + 1;
+        const newHp = this.getWallHealthByLevel(newLvl);
+
+        pd.playerLevel = newLvl;
+        pd.wallBaseHealth = newHp;
+
+        this.saveDataManager.savePlayerData(true);
+
+        // 更新内存中的数值
+        this.wallHealth = newHp;
+        if (this.enemyController) {
+            this.enemyController.wallHealth = newHp;
+            this.enemyController.updateWallHealthDisplay?.();
+        }
+
+        return {
+            currentLevel: newLvl,
+            currentHp: newHp,
+            nextLevel: newLvl + 1,
+            nextHp: this.getWallHealthByLevel(newLvl + 1)
+        };
+    }
 } 

+ 159 - 363
assets/scripts/LevelSystem/MainUIController.ts

@@ -1,372 +1,168 @@
-import { _decorator, Component, Node, Label, Button, find } from 'cc';
+// MainUIController.ts
+import { _decorator, Component, Node, Button, Label, find } from 'cc';
 import { SaveDataManager } from './SaveDataManager';
 import { GameManager } from './GameManager';
 const { ccclass, property } = _decorator;
 
-/**
- * 主界面控制器
- * 负责显示玩家信息和处理主界面交互
- */
 @ccclass('MainUIController')
 export class MainUIController extends Component {
-    
-    @property({
-        type: Node,
-        tooltip: '玩家等级显示节点'
-    })
-    public playerLevelLabel: Node = null;
-    
-    @property({
-        type: Node,
-        tooltip: '当前关卡显示节点'
-    })
-    public currentLevelLabel: Node = null;
-    
-    @property({
-        type: Node,
-        tooltip: '金币显示节点'
-    })
-    public coinsLabel: Node = null;
-    
-    @property({
-        type: Node,
-        tooltip: '钻石显示节点'
-    })
-    public diamondsLabel: Node = null;
-    
-    @property({
-        type: Node,
-        tooltip: '宝石显示节点'
-    })
-    public gemsLabel: Node = null;
-    
-    @property({
-        type: Node,
-        tooltip: '战斗按钮节点'
-    })
-    public battleButton: Node = null;
-    
-    @property({
-        type: Node,
-        tooltip: '商店按钮节点'
-    })
-    public shopButton: Node = null;
-    
-    @property({
-        type: Node,
-        tooltip: '设置按钮节点'
-    })
-    public settingsButton: Node = null;
-    
-    private saveDataManager: SaveDataManager = null;
-    
-    start() {
-        // 初始化存档管理器
-        this.saveDataManager = SaveDataManager.getInstance();
-        this.saveDataManager.initialize();
-        
-        // 自动查找UI节点(如果没有手动拖拽设置)
-        this.findUINodes();
-        
-        // 更新UI显示
-        this.updateUI();
-        
-        // 设置按钮事件
-        this.setupButtons();
-    }
-    
-    /**
-     * 自动查找UI节点
-     */
-    private findUINodes() {
-        if (!this.playerLevelLabel) {
-            this.playerLevelLabel = find('Canvas/MainUI/PlayerInfo/LevelLabel');
-        }
-        
-        if (!this.currentLevelLabel) {
-            this.currentLevelLabel = find('Canvas/MainUI/LevelInfo/CurrentLevelLabel');
-        }
-        
-        if (!this.coinsLabel) {
-            this.coinsLabel = find('Canvas/MainUI/Currency/CoinsLabel');
-        }
-        
-        if (!this.diamondsLabel) {
-            this.diamondsLabel = find('Canvas/MainUI/Currency/DiamondsLabel');
-        }
-        
-        if (!this.gemsLabel) {
-            this.gemsLabel = find('Canvas/MainUI/Currency/GemsLabel');
-        }
-        
-        if (!this.battleButton) {
-            this.battleButton = find('Canvas/MainUI/BattleButtonNode');
-        }
-        
-        if (!this.shopButton) {
-            this.shopButton = find('Canvas/MainUI/ShopButton');
-        }
-        
-        if (!this.settingsButton) {
-            this.settingsButton = find('Canvas/MainUI/SettingsButton');
-        }
-    }
-    
-    /**
-     * 更新UI显示
-     */
-    public updateUI() {
-        if (!this.saveDataManager) return;
-        
-        // 更新玩家等级显示
-        if (this.playerLevelLabel) {
-            const label = this.playerLevelLabel.getComponent(Label);
-            if (label) {
-                const playerLevel = this.saveDataManager.getPlayerLevel();
-                label.string = `Lv.${playerLevel}`;
-            }
-        }
-        
-        // 更新当前关卡显示
-        if (this.currentLevelLabel) {
-            const label = this.currentLevelLabel.getComponent(Label);
-            if (label) {
-                const currentLevel = this.saveDataManager.getCurrentLevel();
-                const maxUnlocked = this.saveDataManager.getMaxUnlockedLevel();
-                label.string = `关卡 ${currentLevel} (最高 ${maxUnlocked})`;
-            }
-        }
-        
-        // 更新货币显示
-        this.updateCurrencyDisplay();
-        
-        // 更新按钮状态
-        this.updateButtonStates();
-    }
-    
-    /**
-     * 更新货币显示
-     */
-    private updateCurrencyDisplay() {
-        if (!this.saveDataManager) return;
-        
-        // 金币
-        if (this.coinsLabel) {
-            const label = this.coinsLabel.getComponent(Label);
-            if (label) {
-                const coins = this.saveDataManager.getCoins();
-                label.string = this.formatNumber(coins);
-            }
-        }
-        
-        // 钻石
-        if (this.diamondsLabel) {
-            const label = this.diamondsLabel.getComponent(Label);
-            if (label) {
-                const diamonds = this.saveDataManager.getDiamonds();
-                label.string = this.formatNumber(diamonds);
-            }
-        }
-        
-        // 宝石
-        if (this.gemsLabel) {
-            const label = this.gemsLabel.getComponent(Label);
-            if (label) {
-                const gems = this.saveDataManager.getGems();
-                label.string = this.formatNumber(gems);
-            }
-        }
-    }
-    
-    /**
-     * 更新按钮状态
-     */
-    private updateButtonStates() {
-        // 这里可以根据玩家状态启用/禁用某些按钮
-        // 例如:如果没有解锁某些功能,可以禁用相应按钮
-    }
-    
-    /**
-     * 设置按钮事件
-     */
-    private setupButtons() {
-        // 战斗按钮
-        if (this.battleButton) {
-            const button = this.battleButton.getComponent(Button);
-            if (button) {
-                button.node.on(Button.EventType.CLICK, this.onBattleButtonClick, this);
-            }
-        }
-        
-        // 商店按钮
-        if (this.shopButton) {
-            const button = this.shopButton.getComponent(Button);
-            if (button) {
-                button.node.on(Button.EventType.CLICK, this.onShopButtonClick, this);
-            }
-        }
-        
-        // 设置按钮
-        if (this.settingsButton) {
-            const button = this.settingsButton.getComponent(Button);
-            if (button) {
-                button.node.on(Button.EventType.CLICK, this.onSettingsButtonClick, this);
-            }
-        }
-    }
-    
-    /**
-     * 战斗按钮点击事件
-     */
-    private onBattleButtonClick() {
-        // 保存数据
-        if (this.saveDataManager) {
-            this.saveDataManager.savePlayerData();
-        }
+  /* 顶部资源 & 关卡 */
+  @property(Node) moneyAddBtn: Node = null;          // 绿色 +
+  @property(Node) diamondAddBtn: Node = null;        // 紫色 +
+  @property(Node) moneyLabel: Node = null;           // 金币数字
+  @property(Node) diamondLabel: Node = null;         // 钻石数字
+  @property(Label) levelNumberLabel: Label = null;   // 第 X 关文本
 
-        // 切换 UI:隐藏主界面,显示关卡界面
-        const mainUI = find('Canvas/MainUI');
-        const gameLevelUI = find('Canvas/GameLevelUI');
-        if (mainUI) mainUI.active = false;
-        if (gameLevelUI) gameLevelUI.active = true;
+  /* 奖励节点 */
+  @property(Node) rewardMoneyNode: Node = null;      // 左金币奖励
+  @property(Node) rewardDiamondNode: Node = null;    // 右钻石奖励
 
-        // 重置并加载关卡
-        const gmNode = find('Canvas/GameLevelUI/GameManager');
-        if (gmNode) {
-            const gm = gmNode.getComponent(GameManager);
-            if (gm) {
-                gm.restartGame();          // 清理上一局数据
-                gm.loadCurrentLevelConfig(); // 加载当前(或下一)关配置
-            }
-        }
-    }
-    
-    /**
-     * 商店按钮点击事件
-     */
-    private onShopButtonClick() {
-        // UI 切换:隐藏主界面,显示商城界面(如果存在)
-        const mainUI = find('Canvas/MainUI');
-        const shopUI = find('Canvas/ShopUI');
-        if (mainUI) mainUI.active = false;
-        if (shopUI) {
-            shopUI.active = true;
-        } else {
-            console.warn('未找到商城界面节点 Canvas/ShopUI');
-        }
-    }
-    
-    /**
-     * 设置按钮点击事件
-     */
-    private onSettingsButtonClick() {
-        // 这里可以打开设置界面
-        // 暂时只显示调试信息
-        this.showCurrentLevelInfo();
-    }
-    
-    /**
-     * 显示当前关卡信息(调试用)
-     */
-    private showCurrentLevelInfo() {
-        if (!this.saveDataManager) return;
-        
-        const currentLevel = this.saveDataManager.getCurrentLevel();
-        const isCompleted = this.saveDataManager.isLevelCompleted(currentLevel);
-        
-        if (isCompleted) {
-            const progress = this.saveDataManager.getLevelProgress(currentLevel);
-            if (progress) {
-                // 显示关卡完成信息
-            }
-        }
-    }
-    
-    /**
-     * 格式化数字显示
-     */
-    private formatNumber(num: number): string {
-        if (num >= 1000000) {
-            return (num / 1000000).toFixed(1) + 'M';
-        } else if (num >= 1000) {
-            return (num / 1000).toFixed(1) + 'K';
-        }
-        return num.toString();
-    }
-    
-    /**
-     * 添加货币(用于测试)
-     */
-    public addTestCoins(amount: number = 1000) {
-        if (this.saveDataManager) {
-            this.saveDataManager.addCoins(amount, 'test');
-            this.updateUI();
-        }
-    }
-    
-    /**
-     * 添加钻石(用于测试)
-     */
-    public addTestDiamonds(amount: number = 100) {
-        if (this.saveDataManager) {
-            this.saveDataManager.addDiamonds(amount, 'test');
-            this.updateUI();
-        }
-    }
-    
-    /**
-     * 解锁关卡(用于测试)
-     */
-    public unlockLevel(level: number) {
-        if (this.saveDataManager) {
-            // 直接设置玩家数据中的最大解锁关卡
-            const playerData = this.saveDataManager.getPlayerData();
-            if (level > playerData.maxUnlockedLevel) {
-                playerData.maxUnlockedLevel = level;
-                this.saveDataManager.savePlayerData();
-                this.updateUI();
-            }
-        }
-    }
-    
-    /**
-     * 重置存档(用于测试)
-     */
-    public resetSaveData() {
-        if (this.saveDataManager) {
-            this.saveDataManager.resetAllData();
-            this.updateUI();
-        }
-    }
-    
-    /**
-     * 获取存档管理器(供其他脚本使用)
-     */
-    public getSaveDataManager(): SaveDataManager {
-        return this.saveDataManager;
-    }
-    
-    onDestroy() {
-        // 清理按钮事件
-        if (this.battleButton) {
-            const button = this.battleButton.getComponent(Button);
-            if (button) {
-                button.node.off(Button.EventType.CLICK, this.onBattleButtonClick, this);
-            }
-        }
-        
-        if (this.shopButton) {
-            const button = this.shopButton.getComponent(Button);
-            if (button) {
-                button.node.off(Button.EventType.CLICK, this.onShopButtonClick, this);
-            }
-        }
-        
-        if (this.settingsButton) {
-            const button = this.settingsButton.getComponent(Button);
-            if (button) {
-                button.node.off(Button.EventType.CLICK, this.onSettingsButtonClick, this);
-            }
-        }
+  /* 升级 */
+  @property(Button) upgradeBtn: Button = null;       // 升级按钮
+  @property(Node) upgradeCostLabel: Node = null;     // 消耗金币数字
+  @property(Node) upgradeHpLabel: Node = null;       // "105>>1000"
+
+  /* 主功能按钮 */
+  @property(Node) battleBtn: Node = null;            // 战斗
+  @property(Node) shopBtn: Node = null;              // 商店
+  @property(Node) navUpgradeBtn: Node = null;        // 底栏 UPGRADE
+  @property(Node) navBattleBtn: Node = null;         // 底栏 BATTLE
+  @property(Node) navSkillBtn: Node = null;          // 底栏 SKILL
+
+  private sdm: SaveDataManager = null;
+
+  onLoad () {
+    this.sdm = SaveDataManager.getInstance();
+    this.sdm.initialize();
+
+    this.bindButtons();
+    this.refreshAll();
+  }
+
+
+
+  /* 绑定按钮事件 */
+  private bindButtons () {
+    this.moneyAddBtn?.on(Button.EventType.CLICK, () => this.addCoins(100), this);
+    this.diamondAddBtn?.on(Button.EventType.CLICK, () => this.addDiamonds(20), this);
+
+    this.rewardMoneyNode?.on(Node.EventType.TOUCH_END, () => this.takeRewardCoins(), this);
+    this.rewardDiamondNode?.on(Node.EventType.TOUCH_END, () => this.takeRewardDiamonds(), this);
+
+    this.upgradeBtn?.node.on(Button.EventType.CLICK, this.upgradeWallHp, this);
+
+    this.battleBtn?.on(Button.EventType.CLICK, this.onBattle, this);
+    this.shopBtn?.on(Button.EventType.CLICK, this.onShop, this);
+
+    // 底栏按钮暂只打印
+    this.navUpgradeBtn?.on(Button.EventType.CLICK, () => console.log('底栏 UPGRADE'), this);
+    this.navBattleBtn?.on(Button.EventType.CLICK, () => console.log('底栏 BATTLE'), this);
+    this.navSkillBtn?.on(Button.EventType.CLICK, () => console.log('底栏 SKILL'), this);
+  }
+
+  /* ================= 业务逻辑 ================= */
+  private addCoins (v:number) { this.sdm.addCoins(v, 'ad'); this.refreshCurrency(); }
+  private addDiamonds (v:number){ this.sdm.addDiamonds(v,'ad'); this.refreshCurrency(); }
+
+  private takeRewardCoins () {
+    const lbl = this.rewardMoneyNode?.getComponent(Label) || this.rewardMoneyNode?.getComponentInChildren(Label);
+    if (!lbl) return;
+    const amt = parseInt(lbl.string||'0');
+    if (amt>0) { this.addCoins(amt); this.rewardMoneyNode.active = false; }
+  }
+  private takeRewardDiamonds () {
+    const lbl = this.rewardDiamondNode?.getComponent(Label) || this.rewardDiamondNode?.getComponentInChildren(Label);
+    if (!lbl) return;
+    const amt = parseInt(lbl.string||'0');
+    if (amt>0) { this.addDiamonds(amt); this.rewardDiamondNode.active = false; }
+  }
+
+  private upgradeWallHp () {
+    const costLbl = this.upgradeCostLabel?.getComponent(Label);
+    if (!costLbl) return;
+    const cost = parseInt(costLbl.string || '0');
+    if (!this.sdm.spendCoins(cost)) return; // 金币不足
+
+    // 升级墙体
+    const gmNode = find('Canvas/GameLevelUI/GameManager');
+    const gm = gmNode?.getComponent(GameManager);
+    if (!gm) return;
+
+    const info = gm.upgradeWallLevel?.();
+    if (!info) return;
+
+    // 更新显示
+    const hpLbl = this.upgradeHpLabel?.getComponent(Label);
+    if (hpLbl) {
+      hpLbl.string = `${info.currentHp}>>${info.nextHp}`;
     }
-} 
+
+    this.refreshCurrency();
+  }
+
+  private onBattle () {
+    // 若上一关已完成则自动+1
+    const lvl = this.sdm.getCurrentLevel();
+    if (this.sdm.isLevelCompleted(lvl)) {
+      const pd = this.sdm.getPlayerData();
+      pd.currentLevel = lvl + 1;
+      this.sdm.savePlayerData();
+    }
+    this.refreshLevelNumber();
+
+    // 切场景 UI
+    const mainUI = find('Canvas/MainUI');
+    const gameUI = find('Canvas/GameLevelUI');
+    if (mainUI) mainUI.active = false;
+    if (gameUI) gameUI.active = true;
+
+    const gmNode = find('Canvas/GameLevelUI/GameManager');
+    const gm = gmNode?.getComponent(GameManager);
+    gm?.restartGame();
+    gm?.loadCurrentLevelConfig();
+  }
+
+  private onShop () {
+    const mainUI = find('Canvas/MainUI');
+    const shopUI = find('Canvas/ShopUI');
+    if (mainUI) mainUI.active = false;
+    if (shopUI) shopUI.active = true;
+  }
+
+  /* ================= 刷新 ================= */
+  private refreshCurrency () {
+    const mLbl = this.moneyLabel?.getComponent(Label) || this.moneyLabel as unknown as Label;
+    if (mLbl) mLbl.string = this.format(this.sdm.getCoins());
+    const dLbl = this.diamondLabel?.getComponent(Label) || this.diamondLabel as unknown as Label;
+    if (dLbl) dLbl.string = this.format(this.sdm.getDiamonds());
+  }
+  private refreshLevelNumber(){
+    if (this.levelNumberLabel) this.levelNumberLabel.string = `第 ${this.sdm.getCurrentLevel()} 关`;
+  }
+  private refreshAll(){
+    this.refreshCurrency();
+    this.refreshLevelNumber();
+
+    this.refreshUpgradeInfo();
+  }
+
+  /** 刷新升级信息显示 */
+  private refreshUpgradeInfo () {
+    const gmNode = find('Canvas/GameLevelUI/GameManager');
+    const gm = gmNode?.getComponent(GameManager);
+    const hpLbl   = this.upgradeHpLabel?.getComponent(Label);
+    if (!gm || !hpLbl) return;
+
+    const curHp = gm.getCurrentWallHealth?.() || 0;
+    const nextHp = gm.getWallHealthByLevel?.(gm.getCurrentWallLevel?.() + 1) || curHp;
+    hpLbl.string = `${curHp}>>${nextHp}`;
+  }
+
+  // 供外部(如 GameManager)调用的公共刷新接口
+  public updateUI (): void {
+    this.refreshAll();
+  }
+  
+  /* =============== Util =============== */
+  private format(n:number){ return n>=1000000? (n/1e6).toFixed(1)+'M' : n>=1000? (n/1e3).toFixed(1)+'K' : n.toString(); }
+}

+ 5 - 0
assets/scripts/LevelSystem/SaveDataManager.ts

@@ -21,6 +21,9 @@ export interface PlayerData {
     coins: number;           // 金币
     diamonds: number;        // 钻石
     gems: number;           // 宝石
+
+    // 墙体基础血量
+    wallBaseHealth: number;
     
     // 关卡进度
     currentLevel: number;
@@ -228,6 +231,7 @@ export class SaveDataManager {
             coins: 1000,        // 初始金币
             diamonds: 50,       // 初始钻石
             gems: 0,
+            wallBaseHealth: 100, // 初始墙体基础血量
             
             currentLevel: 1,
             maxUnlockedLevel: 1,
@@ -306,6 +310,7 @@ export class SaveDataManager {
             coins: 1000,
             diamonds: 50,
             gems: 0,
+            wallBaseHealth: 100, // 初始墙体基础血量
             currentLevel: 1,
             maxUnlockedLevel: 1,
             levelProgress: {},

+ 9 - 0
assets/scripts/TestScene.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "1.2.0",
+  "importer": "directory",
+  "imported": true,
+  "uuid": "f70ee6b4-04e9-4391-a638-cd7809989750",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно