@yangyongtao/gaea 1.1.28 → 1.1.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.1.30] - 2026-09-09
4
+
5
+ ### Added
6
+ - Vite 插件生产构建支持:新增 `closeBundle` 钩子,`vite build` 时自动把引擎静态资源(`Gaea.js` / `Gaea.wasm` / `Gaea.pck` / `Gaea.worker.js` / `static/` / `math/` / `image/` / `font/` / `icon/` 等)从包内 `public` 复制到输出目录(默认 `dist`,遵循 `build.outDir`)。修复此前生产包访问 `/Gaea.js` 返回 404 的问题。`configResolved` 记录输出目录;拷贝时跳过输出目录中已存在的文件,保证消费者自身 `public/` 下的资源优先。
7
+
8
+ ## [1.1.29] - 2026-09-04
9
+
10
+ ### Fixed
11
+ - 2D/3D 切换严格隐藏 3D 图标:新增 `_markersVisible` 全局状态,`showAllMarkers` / `hideAllMarkers` 同步更新;`addScreenIcon` 新增图标按当前状态显隐;`setCategoryVisible` 显示分类、复位按钮、`lockedModesSwitch` 解锁恢复图标时均叠加全局可见性判断,杜绝 2D 模式下图标残留
12
+
3
13
  ## [1.1.28] - 2026-09-01
4
14
 
5
15
  ### Changed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yangyongtao/gaea",
3
- "version": "1.1.28",
3
+ "version": "1.1.30",
4
4
  "description": "Gaea 3D visualization component library - Vue 3 components based on Godot WASM engine. Includes WMTS layer loading, camera view control, Vite plugin auto-injection, etc.",
5
5
  "type": "module",
6
6
  "main": "src/index.cjs",
@@ -290,6 +290,7 @@ export class GaeaApp {
290
290
  this.tLayers = [];
291
291
  this.layerCategories = this.config.layerCategories || [];
292
292
  this._screenIconList = [];
293
+ this._markersVisible = true; // 全局图标可见性(2D 模式下强制隐藏,3D 下恢复)
293
294
  this._hiddenCategories = new Set();
294
295
  this._tilesetMap = {}; // 已加载的 3D Tiles 引用,key 为 tileset 名称
295
296
  this._secIsClickArr = [];
@@ -560,9 +561,11 @@ export class GaeaApp {
560
561
  // 解锁视角(内部会调 UseAutoVisible 恢复非断面图标)
561
562
  this.lockedModesSwitch(false);
562
563
  // 恢复被 hiddenScreenWithClass 隐藏的图标 DOM
563
- document.querySelectorAll('.gaea-locationLineStyle, .gaea-iconscreen, .gaea-iconGif').forEach(el => {
564
- el.style.display = '';
565
- });
564
+ if (this._markersVisible) {
565
+ document.querySelectorAll('.gaea-locationLineStyle, .gaea-iconscreen, .gaea-iconGif').forEach(el => {
566
+ el.style.display = '';
567
+ });
568
+ }
566
569
  // 断面模型缩回
567
570
  if (this._raisedSection) {
568
571
  this._raisedSection.TranslateObjectLocal(new Gaea.Vector3(0, -44, 0));
@@ -912,11 +915,11 @@ export class GaeaApp {
912
915
  }
913
916
  const els = document.querySelectorAll('.gaea-cat-' + categoryKey);
914
917
  console.log('[GaeaApp] setCategoryVisible:', categoryKey, visible, '元素数:', els.length);
915
- els.forEach(el => { el.style.display = visible ? '' : 'none'; });
918
+ els.forEach(el => { el.style.display = visible && this._markersVisible ? '' : 'none'; });
916
919
  // 同步引擎可见性
917
920
  const items = this._screenIconList.filter(item => item.category === categoryKey);
918
921
  items.forEach(item => {
919
- if (visible) {
922
+ if (visible && this._markersVisible) {
920
923
  item.element.UseAutoVisible();
921
924
  item.element.EnablePick = true;
922
925
  } else {
@@ -1799,6 +1802,7 @@ export class GaeaApp {
1799
1802
  child.AddChild(screen, false);
1800
1803
  const screenItem = { element: screen, type: type || null, category };
1801
1804
  this._screenIconList.push(screenItem);
1805
+ this._applyMarkerVisibility(screenItem);
1802
1806
  return screen;
1803
1807
  }
1804
1808
  }
@@ -1810,9 +1814,19 @@ export class GaeaApp {
1810
1814
  Gaea.World.Instance.RenderableObjectList.AddLast(screen);
1811
1815
  const screenItem = { element: screen, type: type || null, category };
1812
1816
  this._screenIconList.push(screenItem);
1817
+ this._applyMarkerVisibility(screenItem);
1813
1818
  return screen;
1814
1819
  }
1815
1820
 
1821
+ /** 根据全局图标可见性状态(_markersVisible)应用单个图标显隐 */
1822
+ _applyMarkerVisibility(screenItem) {
1823
+ if (this._markersVisible) return;
1824
+ screenItem.element.ForceSetVisible(false);
1825
+ screenItem.element.EnablePick = false;
1826
+ const el = document.getElementById(screenItem.element.DivID);
1827
+ if (el) el.style.display = 'none';
1828
+ }
1829
+
1816
1830
  /** 记录当前视角,返回 URI 字符串 */
1817
1831
  favorite() {
1818
1832
  return Gaea.GaeaCamera.ConvertBy(Gaea.World.Instance.DefaultCamera).Favorite();
@@ -2095,7 +2109,7 @@ export class GaeaApp {
2095
2109
  Gaea.World.Instance.CameraController.LockedEntity = null;
2096
2110
  // 解锁时恢复非断面图标的自动可见
2097
2111
  this._screenIconList.forEach(item => {
2098
- if (!item.type) {
2112
+ if (!item.type && this._markersVisible) {
2099
2113
  item.element.UseAutoVisible();
2100
2114
  item.element.EnablePick = true;
2101
2115
  }
@@ -2377,6 +2391,7 @@ export class GaeaApp {
2377
2391
 
2378
2392
  /** 显示所有屏幕标记 */
2379
2393
  showAllMarkers = () => {
2394
+ this._markersVisible = true;
2380
2395
  this._screenIconList.forEach(item => {
2381
2396
  // 跳过被隐藏分类的标记
2382
2397
  if (this._hiddenCategories.has(item.category)) return
@@ -2390,6 +2405,7 @@ export class GaeaApp {
2390
2405
 
2391
2406
  /** 隐藏所有屏幕标记 */
2392
2407
  hideAllMarkers = () => {
2408
+ this._markersVisible = false;
2393
2409
  this._screenIconList.forEach(item => {
2394
2410
  item.element.ForceSetVisible(false)
2395
2411
  item.element.EnablePick = false
@@ -6,6 +6,7 @@
6
6
  * 2. 提供 /Gaea.js /Gaea.wasm /Gaea.pck 等静态文件
7
7
  * 3. 设置 COEP/COOP 头(SharedArrayBuffer 必需)
8
8
  * 4. 检测跨域隔离状态并自动刷新
9
+ * 5. 生产构建时把引擎静态资源复制到输出目录(closeBundle)
9
10
  *
10
11
  * 消费者用法(vite.config.js):
11
12
  * import { gaeaVitePlugin } from '@yangyongtao/gaea/plugin';
@@ -19,6 +20,24 @@ const __filename = fileURLToPath(import.meta.url);
19
20
  const __dirname = path.dirname(__filename);
20
21
  const pkgPublic = path.resolve(__dirname, '..', 'public');
21
22
 
23
+ // 生产构建需复制的引擎静态资源:
24
+ // - 顶层引擎文件(与注入的 <script src="/Gaea.js"> 位置保持一致,位于站点根路径)
25
+ // - 子目录(serveLocal 指向 /static/,引擎还会访问 math/ image/ font/ icon/)
26
+ const BUILD_TOP_FILES = [
27
+ 'Gaea.js',
28
+ 'Gaea.wasm',
29
+ 'Gaea.pck',
30
+ 'Gaea.worker.js',
31
+ 'Gaea.audio.worklet.js',
32
+ 'GaeaApp.html',
33
+ 'GaeaModule.html',
34
+ 'index.js',
35
+ 'constants.js',
36
+ 'jsencrypt.min.js',
37
+ 'web-control.min.js',
38
+ ];
39
+ const BUILD_COPY_DIRS = ['static/', 'math/', 'image/', 'font/', 'icon/'];
40
+
22
41
  const MIME = {
23
42
  '.wasm': 'application/wasm',
24
43
  '.pck': 'application/octet-stream',
@@ -37,10 +56,19 @@ const COEP_HEADERS = {
37
56
  };
38
57
 
39
58
  export default function gaeaVitePlugin() {
59
+ let resolvedOutDir = '';
60
+
40
61
  return {
41
62
  name: 'vite-plugin-gaea',
42
63
  enforce: 'pre',
43
64
 
65
+ // 记录生产构建的输出目录(closeBundle 时用于定位拷贝目标)
66
+ configResolved(config) {
67
+ resolvedOutDir = config.build?.outDir
68
+ ? path.resolve(config.root || process.cwd(), config.build.outDir)
69
+ : '';
70
+ },
71
+
44
72
  configureServer(server) {
45
73
  // COEP/COOP 头只对非 WebSocket 请求设置,避免破坏 Vite HMR
46
74
  server.middlewares.stack.unshift({
@@ -97,6 +125,46 @@ export default function gaeaVitePlugin() {
97
125
  });
98
126
  },
99
127
 
128
+ // 生产构建:把引擎静态资源复制到输出目录。
129
+ // configureServer 只在 dev 模式生效,vite build 不会运行,因此这里需自行拷贝。
130
+ closeBundle() {
131
+ const outRoot = resolvedOutDir || path.resolve(process.cwd(), 'dist');
132
+ if (!fs.existsSync(pkgPublic)) {
133
+ console.warn('[gaea] 未找到 gaea public 目录,跳过引擎资源复制:', pkgPublic);
134
+ return;
135
+ }
136
+
137
+ // 不覆盖输出目录中已存在的文件(消费者 public/ 下的资源优先)
138
+ const copyFile = (src, dest) => {
139
+ if (fs.existsSync(dest)) return;
140
+ fs.copyFileSync(src, dest);
141
+ };
142
+ const copyDir = (src, dest) => {
143
+ if (!fs.existsSync(src)) return;
144
+ for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
145
+ const s = path.join(src, entry.name);
146
+ const d = path.join(dest, entry.name);
147
+ if (entry.isDirectory()) {
148
+ copyDir(s, d);
149
+ } else if (!fs.existsSync(d)) {
150
+ fs.mkdirSync(path.dirname(d), { recursive: true });
151
+ fs.copyFileSync(s, d);
152
+ }
153
+ }
154
+ };
155
+
156
+ fs.mkdirSync(outRoot, { recursive: true });
157
+ for (const name of BUILD_TOP_FILES) {
158
+ const src = path.join(pkgPublic, name);
159
+ if (fs.existsSync(src)) copyFile(src, path.join(outRoot, name));
160
+ }
161
+ for (const dir of BUILD_COPY_DIRS) {
162
+ const src = path.join(pkgPublic, dir);
163
+ if (fs.existsSync(src)) copyDir(src, path.join(outRoot, dir));
164
+ }
165
+ console.log('[gaea] 引擎资源已复制到输出目录:', outRoot);
166
+ },
167
+
100
168
  transformIndexHtml(html) {
101
169
  // 自动注入 Gaea.js(消费者无需在 HTML 中手动写 <script src="/Gaea.js">)
102
170
  if (!html.includes('/Gaea.js')) {