@lily-cooperative/custom-farm 0.37.0 → 0.38.1
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/README.md +39 -11
- package/describe.json +8 -0
- package/dist/webui.js +137 -53
- package/overlay/README.md +4 -0
- package/overlay/overlay-webview.ps1 +270 -0
- package/overlay/webview2/LICENSE.txt +27 -0
- package/overlay/webview2/Microsoft.Web.WebView2.Core.dll +0 -0
- package/overlay/webview2/Microsoft.Web.WebView2.Wpf.dll +0 -0
- package/overlay/webview2/NOTICE.txt +85 -0
- package/overlay/webview2/WebView2Loader.dll +0 -0
- package/overlay-electron/launch.js +43 -30
- package/overlay-electron/main.js +86 -34
- package/overlay-electron/renderer.js +39 -11
- package/overlay-electron/zorder.ps1 +70 -0
- package/package.json +2 -7
- package/src/catalog.js +3 -0
- package/src/farm.js +7 -0
- package/src/index.js +28 -1
- package/src/paths.js +2 -1
- package/src/world.js +251 -64
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
| 面板 | 能改什么 |
|
|
22
22
|
|---|---|
|
|
23
23
|
| **农场自定义 → 农场** | 地面贴图、地表高度、农田大小、导入自己的 PNG |
|
|
24
|
-
| **农场自定义 → 农作物** |
|
|
24
|
+
| **农场自定义 → 农作物** | 增删作物、阶段数、每阶段天数、产物卖价、种子买价、各阶段/种子/产物贴图、上下图层 |
|
|
25
25
|
| **农场自定义 → 杂草** | 增删杂草、阶段与天数、出现权重、上下图层、收获物名字/价值/贴图 |
|
|
26
26
|
| **农场自定义 → 浇水特效 / 枯萎** | 浇水帧序列、水花帧序列、帧间隔、枯萎贴图 |
|
|
27
27
|
| **生态自定义** | 一个游戏日多长、离线最多补几天、刷新间隔、每天是否推事件、浇水蒸发/补水/枯萎天数、天气 |
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
| **状态自定义** | 数值状态、开关状态、条件规则、消耗行为(例如饥饿时自动吃背包里的东西) |
|
|
30
30
|
| **道具自定义** | 种子/农作物/消耗品/装饰的买价卖价、能不能吃、吃掉后的状态效果、图标、摆放贴图、图层、缩放 |
|
|
31
31
|
| **合成表** | 1~4 个材料合成 1 个产物,桌宠可以用 `farm_craft` 合成 |
|
|
32
|
+
| **性能** | 图层节流:不节流(默认)/ 自动 / 节流;改完自动重启图层 |
|
|
32
33
|
| **设置模板 ZIP** | 导出/导入全部设置和自定义贴图(不含存档) |
|
|
33
34
|
| **环境提示词** | 发给桌宠的静态提示词,写“饿了怎么办、什么时候提醒主人”等 |
|
|
34
35
|
|
|
@@ -61,6 +62,8 @@
|
|
|
61
62
|
|
|
62
63
|
扩展包自带 `overlay` / `overlay-electron` / `assets`,第一次启动会把它们复制到安装目录,不需要另外准备项目文件夹。
|
|
63
64
|
|
|
65
|
+
**扩展不再把 Electron 作为 npm 依赖下载。** 安装时只装扩展本身;有没有 Electron 运行时都不会影响安装。桌面图层按下面的「环境自检 / 图层引擎」选择。
|
|
66
|
+
|
|
64
67
|
### 本地开发
|
|
65
68
|
|
|
66
69
|
```powershell
|
|
@@ -73,6 +76,28 @@ Invoke-RestMethod -Method Post http://127.0.0.1:17788/api/run/restart
|
|
|
73
76
|
|
|
74
77
|
## 游戏配置
|
|
75
78
|
|
|
79
|
+
### 环境自检 / 图层引擎
|
|
80
|
+
|
|
81
|
+
**游戏配置页顶部**有「环境自检」按钮,会检查:
|
|
82
|
+
|
|
83
|
+
- 当前平台和 Node 版本
|
|
84
|
+
- 是否能找到 `electron.exe`
|
|
85
|
+
- 安装目录里的 `overlay-webview.ps1`、WebView2 库和 WebView2 运行时是否可用
|
|
86
|
+
|
|
87
|
+
自检会明确显示「缺少 Electron 运行时」还是「WPF/WebView2 图层可用」。下面的「图层引擎」切选单可以选:
|
|
88
|
+
|
|
89
|
+
- **自动**:有备用 Electron 就用,没有就用 WPF/WebView2(推荐,不会下载 Electron)
|
|
90
|
+
- **备用 Electron**:只使用检测到的 Electron,需要 `electron.exe`
|
|
91
|
+
- **WPF(WebView2)**:完全不使用 Electron,但加载和 Electron 相同的 `renderer.html/renderer.js`
|
|
92
|
+
|
|
93
|
+
WPF 回退现在是 WebView2 宿主,不再用另一套 WPF 自绘;因此缩放、精灵位置、阴影、粒子、水滴、晃动等视觉效果和 Electron 基本完全一致。需要 Windows 10/11 自带的 WebView2 Runtime。
|
|
94
|
+
|
|
95
|
+
自检里的「Electron 包」下拉会列出检测到的路径;也可以在「备用 Electron」配置项里手动选 `electron.exe`。
|
|
96
|
+
|
|
97
|
+
第一次启用时还会自动做一次自检;如果当前引擎缺运行时,会推一次 `farm.env` 事件,让桌宠把“缺少 Electron 运行时 / 怎么修”转告主人。之后不会重复提醒。
|
|
98
|
+
|
|
99
|
+
Coopanion 只提供打包后的 `Coopanion.exe`,没有可复用的独立 `electron.exe`;所以默认不再下载第二份 Electron。备用 Electron 可以放在安装目录的 `node_modules\electron\dist\electron.exe`,或在「备用 Electron」里手动选择路径。
|
|
100
|
+
|
|
76
101
|
### 安装路径
|
|
77
102
|
|
|
78
103
|
在 Coopanion 的 **游戏配置 → 安装** 里可以直接看到和修改安装路径:
|
|
@@ -88,23 +113,24 @@ Invoke-RestMethod -Method Post http://127.0.0.1:17788/api/run/restart
|
|
|
88
113
|
|
|
89
114
|
- 「自动」使用主屏
|
|
90
115
|
- 下拉里会列出当前所有显示器,改完约 1 秒内移动到目标屏幕
|
|
91
|
-
- 这个设置作用于 Electron 图层;WPF
|
|
116
|
+
- 这个设置作用于 Electron 图层;WPF/WebView2 回退使用主屏(与现有 WPF 行为一致)
|
|
92
117
|
|
|
93
118
|
### 备份与重置
|
|
94
119
|
|
|
95
|
-
**游戏配置**
|
|
120
|
+
**游戏配置** 页最上面有「存档与重置」,不再单独占页签:
|
|
96
121
|
|
|
97
122
|
- **备份存档**:把 `state.json` 和 `custom.json` 复制到 `data\farm\backups\backup-时间\`
|
|
98
123
|
- **重置一切**:先自动备份,再清空 `state.json` 和 `custom.json`,World 自动重启并生成默认目录;安装路径和已上传的 PNG 文件不会被删除
|
|
99
124
|
|
|
100
|
-
也可以从「存档与重置」页签操作同样的按钮。
|
|
101
|
-
|
|
102
125
|
## 桌面图层
|
|
103
126
|
|
|
104
|
-
-
|
|
105
|
-
-
|
|
127
|
+
- 图层拆成 `bg` / `top` 两个透明窗口:`bg` 在桌宠下面,`top` 是桌宠的 owned window,永远在桌宠上面。
|
|
128
|
+
- 野草、装饰、作物、掉落物和特效按 `layer` 设置分配到两个窗口;上层野草/装饰可以正常遮挡桌宠,下层作物在桌宠后面。
|
|
129
|
+
- 层级守护每 500ms 重新确认桌宠窗口;桌宠重新置顶、显示/隐藏、被点击或窗口重建后,会自动重新挂 owner / 把 `bg` 放回桌宠下面,防止图层整体翻转。
|
|
130
|
+
- **Windows 10/11**:默认「自动」——检测到备用 Electron 就用 Electron,否则用 WPF/WebView2;不会为了安装扩展下载 Electron。两个引擎都使用同一套 Canvas renderer,缩放和特效一致。
|
|
131
|
+
- **macOS / Linux**:暂不支持;`os` 已收紧为 `win32`。
|
|
106
132
|
- 图层跟着桌宠显示/隐藏/退出;任务栏换边、换屏会重新计算位置。
|
|
107
|
-
-
|
|
133
|
+
- 背包、商店、农场预览、摆放和手动合成都在 WebUI。
|
|
108
134
|
|
|
109
135
|
## 工具
|
|
110
136
|
|
|
@@ -124,7 +150,7 @@ Invoke-RestMethod -Method Post http://127.0.0.1:17788/api/run/restart
|
|
|
124
150
|
| `farm_sell` | 卖背包里的道具 |
|
|
125
151
|
| `farm_place` | 把装饰放到地上 |
|
|
126
152
|
|
|
127
|
-
事件:`farm.ripe`、`farm.dry`、`farm.day`、`farm.state`。`farm.day` 默认关,`dailyEvent=true`
|
|
153
|
+
事件:`farm.ripe`、`farm.dry`、`farm.day`、`farm.state`、`farm.env`。`farm.day` 默认关,`dailyEvent=true` 才推;`farm.env` 只在第一次启用自检失败时推一次,让桌宠把环境问题转告主人。
|
|
128
154
|
|
|
129
155
|
## 默认参数
|
|
130
156
|
|
|
@@ -155,7 +181,7 @@ Invoke-RestMethod -Method Post http://127.0.0.1:17788/api/run/restart
|
|
|
155
181
|
| `dist/webui.js` / `.css` | 「自定义农场」面板 |
|
|
156
182
|
| `icon.png` | 扩展图标(安装页显示) |
|
|
157
183
|
| `describe.json` | 工具/事件自描述 |
|
|
158
|
-
| `overlay/` | WPF
|
|
184
|
+
| `overlay/` | WPF/WebView2 回退(同一套渲染器) |
|
|
159
185
|
| `overlay-electron/` | Electron 图层 |
|
|
160
186
|
| `assets/` | 内置作物/杂草/地面/装饰/图标 |
|
|
161
187
|
|
|
@@ -169,7 +195,9 @@ Invoke-RestMethod -Method Post http://127.0.0.1:17788/api/run/restart
|
|
|
169
195
|
|
|
170
196
|
- Coopanion `>= 0.2.13`,World API `6`
|
|
171
197
|
- Node.js `>= 22`(Coopanion 自带)
|
|
172
|
-
-
|
|
198
|
+
- 仅 Windows 10/11;macOS / Linux 暂不支持,等后续测试
|
|
199
|
+
- Electron 不是 npm 依赖;备用 Electron 可选,Windows 没有时用 WPF/WebView2
|
|
200
|
+
- WPF 回退需要 Windows 10/11 的 WebView2 Runtime(系统一般自带)
|
|
173
201
|
- Windows 10/11 已实机测试;macOS / Linux 未实机测试
|
|
174
202
|
|
|
175
203
|
## 许可
|
package/describe.json
CHANGED
|
@@ -340,6 +340,14 @@
|
|
|
340
340
|
"en": "A custom state triggered a consume action: e.g. hunger ate a crop (the text says what and the state change), or asks the pet to use farm_consume; also fires when nothing edible is in the bag."
|
|
341
341
|
},
|
|
342
342
|
"trigger": "debounce"
|
|
343
|
+
},
|
|
344
|
+
{
|
|
345
|
+
"type": "farm.env",
|
|
346
|
+
"description": {
|
|
347
|
+
"zh": "第一次启用时环境自检发现 Electron/WPF 运行时缺失;正文说明缺什么、怎么在「游戏配置 → 环境自检」里修复,让桌宠转告主人。",
|
|
348
|
+
"en": "The first-start environment check found a missing Electron/WPF runtime; the text says what is missing and how to fix it in Game Config → Environment check, so the pet can tell its owner."
|
|
349
|
+
},
|
|
350
|
+
"trigger": "debounce"
|
|
343
351
|
}
|
|
344
352
|
]
|
|
345
353
|
}
|
package/dist/webui.js
CHANGED
|
@@ -20,29 +20,137 @@ function renameFarmConfigTab() {
|
|
|
20
20
|
} catch { /* 不是浏览器环境就算了 */ }
|
|
21
21
|
}
|
|
22
22
|
if (typeof document !== 'undefined') {
|
|
23
|
-
const
|
|
23
|
+
const refreshFarmConfigUi = () => {
|
|
24
24
|
renameFarmConfigTab();
|
|
25
|
+
injectFarmEnvCheck();
|
|
25
26
|
injectFarmConfigActions();
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
};
|
|
28
|
+
const start = () => {
|
|
29
|
+
refreshFarmConfigUi();
|
|
30
|
+
new MutationObserver(refreshFarmConfigUi).observe(document.body, { childList: true, subtree: true, characterData: true });
|
|
31
|
+
window.addEventListener('hashchange', refreshFarmConfigUi);
|
|
32
|
+
setInterval(refreshFarmConfigUi, 1000);
|
|
29
33
|
};
|
|
30
34
|
if (document.body) start();
|
|
31
35
|
else document.addEventListener('DOMContentLoaded', start, { once: true });
|
|
32
36
|
}
|
|
33
37
|
|
|
34
|
-
/** 调 World 的 manage 面板:备份 /
|
|
35
|
-
async function farmManageCall(method) {
|
|
36
|
-
const res = await fetch('/api/webui/providers/' + encodeURIComponent('world:farm') + '/panels/
|
|
38
|
+
/** 调 World 的 manage 面板:备份 / 重置 / 自检。 */
|
|
39
|
+
async function farmManageCall(method, args = []) {
|
|
40
|
+
const res = await fetch('/api/webui/providers/' + encodeURIComponent('world:farm') + '/panels/customize/' + method, {
|
|
37
41
|
method: 'POST',
|
|
38
42
|
headers: { 'content-type': 'application/json' },
|
|
39
|
-
body: JSON.stringify({ args
|
|
43
|
+
body: JSON.stringify({ args }),
|
|
40
44
|
});
|
|
41
45
|
const data = await res.json().catch(() => ({}));
|
|
42
46
|
if (!res.ok) throw new Error(data.error || ('HTTP ' + res.status));
|
|
43
47
|
return data;
|
|
44
48
|
}
|
|
45
49
|
|
|
50
|
+
/** 游戏配置顶部的环境自检 + Electron/WPF 切选单。 */
|
|
51
|
+
function injectFarmEnvCheck() {
|
|
52
|
+
try {
|
|
53
|
+
const hash = String(location.hash || '');
|
|
54
|
+
if (!hash.includes('world%3Afarm') && !hash.includes('world:farm')) return;
|
|
55
|
+
const view = document.querySelector('.configview');
|
|
56
|
+
if (!view || view.querySelector('[data-farm-env]')) return;
|
|
57
|
+
|
|
58
|
+
const section = document.createElement('div');
|
|
59
|
+
section.className = 'tsection';
|
|
60
|
+
section.dataset.farmEnv = '1';
|
|
61
|
+
section.textContent = '环境自检';
|
|
62
|
+
|
|
63
|
+
const desc = document.createElement('div');
|
|
64
|
+
desc.className = 'tsecdesc';
|
|
65
|
+
desc.textContent = '检查图层运行时是否齐全。Coopanion 不提供独立的 electron.exe;没有备用 Electron 时会用 WPF 图层,不会为了安装扩展再下载 Electron。';
|
|
66
|
+
|
|
67
|
+
const row = document.createElement('div');
|
|
68
|
+
row.className = 'trow';
|
|
69
|
+
const label = document.createElement('span');
|
|
70
|
+
label.className = 'tlabel';
|
|
71
|
+
label.textContent = '图层引擎';
|
|
72
|
+
const field = document.createElement('div');
|
|
73
|
+
field.className = 'tfield';
|
|
74
|
+
field.style.display = 'flex';
|
|
75
|
+
field.style.gap = '8px';
|
|
76
|
+
field.style.flexWrap = 'wrap';
|
|
77
|
+
|
|
78
|
+
const select = document.createElement('select');
|
|
79
|
+
select.className = 'field';
|
|
80
|
+
for (const [value, text] of [['auto', '自动(有备用 Electron 就用,否则 WPF/WebView2)'], ['electron', '备用 Electron(需要 electron.exe)'], ['wpf', 'WPF/WebView2(不需要 Electron)']]) {
|
|
81
|
+
const opt = document.createElement('option');
|
|
82
|
+
opt.value = value;
|
|
83
|
+
opt.textContent = text;
|
|
84
|
+
select.appendChild(opt);
|
|
85
|
+
}
|
|
86
|
+
const checkBtn = document.createElement('button');
|
|
87
|
+
checkBtn.type = 'button';
|
|
88
|
+
checkBtn.className = 'btn sm primary';
|
|
89
|
+
checkBtn.textContent = '环境自检';
|
|
90
|
+
const electronSelect = document.createElement('select');
|
|
91
|
+
electronSelect.className = 'field';
|
|
92
|
+
const electronAuto = document.createElement('option');
|
|
93
|
+
electronAuto.value = '';
|
|
94
|
+
electronAuto.textContent = 'Electron:自动查找';
|
|
95
|
+
electronSelect.appendChild(electronAuto);
|
|
96
|
+
const status = document.createElement('div');
|
|
97
|
+
status.className = 'tdesc';
|
|
98
|
+
status.style.whiteSpace = 'pre-line';
|
|
99
|
+
status.style.marginTop = '6px';
|
|
100
|
+
|
|
101
|
+
const render = (data) => {
|
|
102
|
+
if (!data) return;
|
|
103
|
+
if (data.engine) select.value = data.engine;
|
|
104
|
+
const current = data.electron && data.electron.path ? data.electron.path : '';
|
|
105
|
+
electronSelect.replaceChildren(electronAuto);
|
|
106
|
+
electronAuto.textContent = 'Electron:自动查找';
|
|
107
|
+
for (const row of data.electronCandidates || []) {
|
|
108
|
+
const opt = document.createElement('option');
|
|
109
|
+
opt.value = row.path;
|
|
110
|
+
opt.textContent = 'Electron:' + row.label + (row.ok ? '' : '(缺失)');
|
|
111
|
+
opt.disabled = !row.ok;
|
|
112
|
+
electronSelect.appendChild(opt);
|
|
113
|
+
}
|
|
114
|
+
if (current) electronSelect.value = current;
|
|
115
|
+
if (!current && !(data.electronCandidates || []).some((r) => r.ok)) {
|
|
116
|
+
const opt = document.createElement('option');
|
|
117
|
+
opt.value = '';
|
|
118
|
+
opt.textContent = 'Electron:未找到';
|
|
119
|
+
opt.disabled = true;
|
|
120
|
+
electronSelect.appendChild(opt);
|
|
121
|
+
}
|
|
122
|
+
status.textContent = data.message || data.text || '';
|
|
123
|
+
status.style.color = data.ok ? '' : 'var(--extension-alert, #c0392b)';
|
|
124
|
+
};
|
|
125
|
+
const check = async () => {
|
|
126
|
+
checkBtn.disabled = true;
|
|
127
|
+
try { render(await farmManageCall('check')); } catch (err) { status.textContent = '自检失败:' + ((err && err.message) || err); } finally { checkBtn.disabled = false; }
|
|
128
|
+
};
|
|
129
|
+
checkBtn.addEventListener('click', check);
|
|
130
|
+
select.addEventListener('change', async () => {
|
|
131
|
+
status.textContent = '正在切换图层引擎…';
|
|
132
|
+
try {
|
|
133
|
+
render(await farmManageCall('setEngine', [select.value]));
|
|
134
|
+
} catch (err) {
|
|
135
|
+
status.textContent = '切换失败:' + ((err && err.message) || err);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
electronSelect.addEventListener('change', async () => {
|
|
139
|
+
status.textContent = '正在切换 Electron…';
|
|
140
|
+
try {
|
|
141
|
+
render(await farmManageCall('setElectronPath', [electronSelect.value]));
|
|
142
|
+
} catch (err) {
|
|
143
|
+
status.textContent = '切换失败:' + ((err && err.message) || err);
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
field.append(select, electronSelect, checkBtn);
|
|
148
|
+
row.append(label, field);
|
|
149
|
+
view.prepend(section, desc, row, status);
|
|
150
|
+
void check();
|
|
151
|
+
} catch { /* 不是宿主的配置页就算了 */ }
|
|
152
|
+
}
|
|
153
|
+
|
|
46
154
|
/** 往宿主的「游戏配置」页里塞「存档与重置」按钮。 */
|
|
47
155
|
function injectFarmConfigActions() {
|
|
48
156
|
try {
|
|
@@ -111,7 +219,7 @@ function injectFarmConfigActions() {
|
|
|
111
219
|
|
|
112
220
|
field.append(backup, reset, status);
|
|
113
221
|
row.append(label, field);
|
|
114
|
-
view.
|
|
222
|
+
view.prepend(section, desc, row);
|
|
115
223
|
} catch { /* 不是宿主的配置页就算了 */ }
|
|
116
224
|
}
|
|
117
225
|
|
|
@@ -169,6 +277,9 @@ const TEXT = {
|
|
|
169
277
|
weedLayer: '图层',
|
|
170
278
|
weedLayerTop: '上(和作物/桌宠同前台层)',
|
|
171
279
|
weedLayerBottom: '下(背景层,作物后方)',
|
|
280
|
+
cropLayer: '图层',
|
|
281
|
+
cropLayerTop: '上(和桌宠同前台层)',
|
|
282
|
+
cropLayerBottom: '下(背景层,桌宠后方)',
|
|
172
283
|
addWeed: '添加杂草',
|
|
173
284
|
name: '名字',
|
|
174
285
|
stages: '阶段数',
|
|
@@ -273,6 +384,9 @@ const TEXT = {
|
|
|
273
384
|
weedLayer: 'Layer',
|
|
274
385
|
weedLayerTop: 'Top (foreground with crops/pet)',
|
|
275
386
|
weedLayerBottom: 'Bottom (background, behind crops)',
|
|
387
|
+
cropLayer: 'Layer',
|
|
388
|
+
cropLayerTop: 'Top (foreground with pet)',
|
|
389
|
+
cropLayerBottom: 'Bottom (background, behind pet)',
|
|
276
390
|
addWeed: 'Add weed',
|
|
277
391
|
name: 'Name',
|
|
278
392
|
stages: 'Stages',
|
|
@@ -568,6 +682,7 @@ function panel(ctx) {
|
|
|
568
682
|
preview: [...c.preview],
|
|
569
683
|
previewSeed: c.previewSeed,
|
|
570
684
|
previewItem: c.previewItem,
|
|
685
|
+
layer: c.layer === 'top' ? 'top' : 'bottom',
|
|
571
686
|
};
|
|
572
687
|
const details = ui.h('details', 'cf-card');
|
|
573
688
|
if (!c.builtin) details.open = false;
|
|
@@ -578,10 +693,20 @@ function panel(ctx) {
|
|
|
578
693
|
ui.pill(c.builtin ? T.builtin : T.custom, c.builtin ? 'plain' : 'on'),
|
|
579
694
|
ui.chip(c.stages + ' 阶段', 'plain'),
|
|
580
695
|
ui.chip(T.daysTotal(c.totalDays), 'plain'),
|
|
696
|
+
ui.chip(c.layer === 'top' ? T.cropLayerTop : T.cropLayerBottom, c.layer === 'top' ? 'on' : 'plain'),
|
|
581
697
|
);
|
|
582
698
|
const body = ui.h('div', 'cf-body');
|
|
583
699
|
details.append(summary, body);
|
|
584
700
|
|
|
701
|
+
const layerSel = ui.select({
|
|
702
|
+
value: draft.layer,
|
|
703
|
+
options: [
|
|
704
|
+
{ value: 'top', label: T.cropLayerTop },
|
|
705
|
+
{ value: 'bottom', label: T.cropLayerBottom },
|
|
706
|
+
],
|
|
707
|
+
});
|
|
708
|
+
layerSel.addEventListener('change', () => { draft.layer = layerSel.value; }, { signal: ctx.signal });
|
|
709
|
+
|
|
585
710
|
const row1 = ui.h('div', 'cf-row');
|
|
586
711
|
row1.append(
|
|
587
712
|
ui.field(T.name, textInput(draft.name, (v) => { draft.name = v; title.textContent = v || c.key; })),
|
|
@@ -591,6 +716,7 @@ function panel(ctx) {
|
|
|
591
716
|
resizeSprites(draft);
|
|
592
717
|
paintStages();
|
|
593
718
|
})),
|
|
719
|
+
ui.field(T.cropLayer, layerSel),
|
|
594
720
|
);
|
|
595
721
|
|
|
596
722
|
const stagesBox = ui.h('div', 'cf-stages');
|
|
@@ -651,6 +777,7 @@ function panel(ctx) {
|
|
|
651
777
|
sprites: draft.sprites,
|
|
652
778
|
seedSprite: draft.seedSprite,
|
|
653
779
|
itemSprite: draft.itemSprite,
|
|
780
|
+
layer: draft.layer,
|
|
654
781
|
}], { toast: T.saved });
|
|
655
782
|
off.dispose();
|
|
656
783
|
})(),
|
|
@@ -2785,52 +2912,8 @@ function ecologyPanel(ctx) {
|
|
|
2785
2912
|
reload();
|
|
2786
2913
|
}
|
|
2787
2914
|
|
|
2788
|
-
function managePanel(ctx) {
|
|
2789
|
-
const { ui } = ctx;
|
|
2790
|
-
const root = ui.h('div', 'cf-root');
|
|
2791
|
-
ctx.root.appendChild(root);
|
|
2792
|
-
const sheet = ui.sheet({
|
|
2793
|
-
title: '存档与重置',
|
|
2794
|
-
desc: '备份会复制 state.json 和 custom.json 到 data/farm/backups;重置会先备份,再清空存档和全部自定义设置,World 随后重启。',
|
|
2795
|
-
});
|
|
2796
|
-
const bar = ui.rowbar();
|
|
2797
|
-
const status = ui.h('p', 'cf-note', '');
|
|
2798
|
-
const backup = ui.button('备份存档', {
|
|
2799
|
-
variant: 'primary',
|
|
2800
|
-
onClick: async () => {
|
|
2801
|
-
backup.disabled = true;
|
|
2802
|
-
status.textContent = '正在备份…';
|
|
2803
|
-
try {
|
|
2804
|
-
const r = await ctx.invoke('backup');
|
|
2805
|
-
status.textContent = r.text || '已备份';
|
|
2806
|
-
} catch (err) {
|
|
2807
|
-
status.textContent = '备份失败:' + ((err && err.message) || err);
|
|
2808
|
-
} finally { backup.disabled = false; }
|
|
2809
|
-
},
|
|
2810
|
-
});
|
|
2811
|
-
const reset = ui.button('重置一切', {
|
|
2812
|
-
onClick: async () => {
|
|
2813
|
-
if (!window.confirm('确定重置一切?会清空存档和全部自定义设置(会先自动备份)。')) return;
|
|
2814
|
-
reset.disabled = true;
|
|
2815
|
-
status.textContent = '正在重置…';
|
|
2816
|
-
try {
|
|
2817
|
-
const r = await ctx.invoke('reset');
|
|
2818
|
-
status.textContent = r.text || '已重置,World 正在重启…';
|
|
2819
|
-
setTimeout(() => { try { location.reload(); } catch { /* ignore */ } }, 3000);
|
|
2820
|
-
} catch (err) {
|
|
2821
|
-
status.textContent = '重置失败:' + ((err && err.message) || err);
|
|
2822
|
-
reset.disabled = false;
|
|
2823
|
-
}
|
|
2824
|
-
},
|
|
2825
|
-
});
|
|
2826
|
-
bar.append(backup, reset);
|
|
2827
|
-
sheet.body.append(bar, status);
|
|
2828
|
-
root.appendChild(sheet.el);
|
|
2829
|
-
}
|
|
2830
|
-
|
|
2831
2915
|
export default {
|
|
2832
2916
|
panels: {
|
|
2833
|
-
manage: { mount: managePanel },
|
|
2834
2917
|
bag: { mount: bagPanel },
|
|
2835
2918
|
shop: { mount: shopPanel },
|
|
2836
2919
|
customize: { mount: panel },
|
|
@@ -2839,3 +2922,4 @@ export default {
|
|
|
2839
2922
|
items: { mount: itemsPanel },
|
|
2840
2923
|
},
|
|
2841
2924
|
};
|
|
2925
|
+
|
package/overlay/README.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# 桌面图层(overlay)· 使用说明
|
|
2
2
|
|
|
3
|
+
> 运行时 WPF 回退已改为 WebView2 宿主 `overlay-webview.ps1`,加载与 Electron 相同的
|
|
4
|
+
> `overlay-electron/renderer.html` / `renderer.js`;本文档描述的是保留的旧 WPF 自绘
|
|
5
|
+
> 实现(`overlay.ps1`),正常启动不再使用它。
|
|
6
|
+
>
|
|
3
7
|
> v4:作物种在任务栏上沿的全宽透明条带上;统一缩放、掉落物、摇晃、浇水/枯萎特效、
|
|
4
8
|
> 收割的作物**不发光**。图层只渲染,状态全从 `state.json` 读。
|
|
5
9
|
|