Compare commits
57 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b12a81e9c2 | |||
| 3f69ce8bb7 | |||
| 2e87a1403a | |||
| f505d2792f | |||
| 74fad546ff | |||
| 16a6cdaf79 | |||
| 832f1e8b59 | |||
| 281e6ccf48 | |||
| 013c756b9e | |||
| e602d3b420 | |||
| a4373d7494 | |||
| 34616e1631 | |||
| 226cfbc8a1 | |||
| 8853e3b48e | |||
| e50d678411 | |||
| 727794bc95 | |||
| cc9b95ddef | |||
| 22c4807612 | |||
| 86adaa738f | |||
| c2f2b9867a | |||
| d77d0ca9eb | |||
| 5646824daf | |||
| d9530047db | |||
| 8012008d83 | |||
| 8528c5ffce | |||
| 3047434b33 | |||
| f8f1cdd1f4 | |||
| 1102b5af23 | |||
| fd5a4c3136 | |||
| 63f5a1d49e | |||
| 811abdd375 | |||
| 712f28e207 | |||
| fafe6b63cd | |||
| d6a72c895c | |||
| 2c9e6fe272 | |||
| f9e24f4e16 | |||
| a6f5ab9d23 | |||
| e6e2a5fda6 | |||
| 123c699db9 | |||
| f2f786d69b | |||
| 8444dee9e9 | |||
| 26169102a0 | |||
| 87711e4034 | |||
| fd09f61473 | |||
| 9345236b93 | |||
| 7484764024 | |||
| 782fa77950 | |||
| 8a93d69590 | |||
| bb010b4b1e | |||
| 5d24301ef5 | |||
| 36dc93222a | |||
| 54ae60576d | |||
| a38eec743a | |||
| 18ed9778d8 | |||
| af96174e07 | |||
| cb79c4a9c6 | |||
| aaa52c2b34 |
@@ -232,6 +232,37 @@ jobs:
|
||||
done
|
||||
done
|
||||
|
||||
- name: Prepare standalone Rust crate dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# agent-runtime-core / agent-runtime-orchestration 被 server-rs/Cargo.toml 的
|
||||
# exclude 排除,不参与上面的 workspace 锁文件,因此上面那次锁定 fetch 覆盖不到它们;
|
||||
# 而 check:native-shells 会经 agent-runtime-*:check 用 `cargo test --manifest-path`
|
||||
# 单独跑这两个 crate。不在这里预热的话,这两条测试会在测试阶段自己
|
||||
# `Updating crates.io index`,crates.io 一抖动整条 native shell 作业就红
|
||||
# (见 #327 / PR #316 run 1950)。
|
||||
# 两个 crate 都没有提交 Cargo.lock,所以这里只能做不带锁标志的 fetch:
|
||||
# 加锁标志会因为缺少锁文件直接失败。生成的 Cargo.lock 落在两个 crate 目录内,
|
||||
# 已被各自的 .gitignore 忽略,只留在容器里;随后的测试阶段因此能用锁定版本
|
||||
# 解析,不再触碰 registry index。
|
||||
for manifest_path in \
|
||||
server-rs/crates/agent-runtime-core/Cargo.toml \
|
||||
server-rs/crates/agent-runtime-orchestration/Cargo.toml; do
|
||||
for attempt in $(seq 1 5); do
|
||||
if cargo fetch \
|
||||
--target x86_64-unknown-linux-gnu \
|
||||
--manifest-path "${manifest_path}"; then
|
||||
break
|
||||
fi
|
||||
if [[ "${attempt}" -eq 5 ]]; then
|
||||
echo "standalone crate dependency fetch failed after 5 attempts: ${manifest_path}" >&2
|
||||
exit 1
|
||||
fi
|
||||
sleep $((attempt * 2))
|
||||
done
|
||||
done
|
||||
|
||||
- name: Run native shell gates
|
||||
run: npm run check:native-shells
|
||||
|
||||
|
||||
@@ -40,8 +40,6 @@ temp*build*/
|
||||
/apps/ai-game-creator-shell/src-tauri/resources/codex/win-x64/codex-path/
|
||||
/apps/ai-game-creator-shell/src-tauri/resources/codex/win-x64/codex-resources/
|
||||
/apps/ai-game-creator-shell/src-tauri/resources/codex/win-x64/codex-package.json
|
||||
/apps/ai-game-creator-shell/src-tauri/resources/plugins/
|
||||
/plugins/agc-cocos-editor/native/payload/
|
||||
/apps/ai-game-creator-shell/logs/
|
||||
/apps/ai-game-creator-shell/.llm-drafts/
|
||||
/apps/ai-game-creator-shell/game-creator.config.local.json
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
# resources/plugins 由 build.rs 从 plugins/ 复制生成,属于构建产物。
|
||||
# 它在 dev 监听范围内,重新生成会让 Tauri dev 误判为源码改动而触发
|
||||
# “构建 -> 监听 -> 再构建”的自触发循环。
|
||||
resources/plugins/
|
||||
@@ -4,11 +4,6 @@ import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
import {
|
||||
defaultEditorFeatures,
|
||||
withDefaultCargoFeatures,
|
||||
} from './cargo-features.mjs';
|
||||
|
||||
const appRoot = fileURLToPath(new URL('..', import.meta.url));
|
||||
const defaultReleaseTarget = 'x86_64-pc-windows-msvc';
|
||||
const releaseTarget =
|
||||
@@ -164,30 +159,10 @@ export async function prepareReleaseVersion() {
|
||||
return nextVersion;
|
||||
}
|
||||
|
||||
export function buildTauriBuildArguments(
|
||||
args = [],
|
||||
target = releaseTarget,
|
||||
platform = process.platform,
|
||||
) {
|
||||
const noBundle = args.includes('--no-bundle');
|
||||
const targetIndex = args.indexOf('--target');
|
||||
const explicitTarget =
|
||||
targetIndex >= 0
|
||||
? args[targetIndex + 1]
|
||||
: args
|
||||
.find((value) => value.startsWith('--target='))
|
||||
?.slice('--target='.length);
|
||||
const targetArgs = noBundle || explicitTarget ? [] : ['--target', target];
|
||||
const features = defaultEditorFeatures(
|
||||
explicitTarget || (noBundle ? platform : target),
|
||||
);
|
||||
return [
|
||||
'build',
|
||||
...withDefaultCargoFeatures([...targetArgs, ...args], features),
|
||||
];
|
||||
}
|
||||
|
||||
export function runTauriBuild(args = []) {
|
||||
const noBundle = args.includes('--no-bundle');
|
||||
const hasTarget = args.includes('--target');
|
||||
const targetArgs = noBundle || hasTarget ? [] : ['--target', releaseTarget];
|
||||
const npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
||||
const result = spawnSync(
|
||||
npmCommand,
|
||||
@@ -197,7 +172,9 @@ export function runTauriBuild(args = []) {
|
||||
'exec',
|
||||
'tauri',
|
||||
'--',
|
||||
...buildTauriBuildArguments(args),
|
||||
'build',
|
||||
...targetArgs,
|
||||
...args,
|
||||
],
|
||||
{ cwd: appRoot, stdio: 'inherit', shell: process.platform === 'win32' },
|
||||
);
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
/** 默认桌面能力;显式 feature 参数优先,不把应用参数当 Cargo 参数。 */
|
||||
export function withDefaultCargoFeatures(argv, features) {
|
||||
const separator = argv.indexOf('--');
|
||||
const cargoArgs = separator < 0 ? argv : argv.slice(0, separator);
|
||||
if (
|
||||
!features.length ||
|
||||
cargoArgs.some(
|
||||
(value) =>
|
||||
value === '--features' ||
|
||||
value === '-f' ||
|
||||
value.startsWith('--features=') ||
|
||||
/^-f.+/u.test(value),
|
||||
)
|
||||
) {
|
||||
return argv;
|
||||
}
|
||||
return [`--features=${features.join(',')}`, ...argv];
|
||||
}
|
||||
|
||||
export function defaultEditorFeatures(target) {
|
||||
return target === 'win32' || target.includes('windows')
|
||||
? ['cocos-editor-execute']
|
||||
: [];
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { test } from 'node:test';
|
||||
|
||||
import { buildTauriBuildArguments } from './build-release.mjs';
|
||||
import { withDefaultCargoFeatures } from './cargo-features.mjs';
|
||||
|
||||
test('Windows release includes the same editor feature as development', () => {
|
||||
assert.deepEqual(
|
||||
buildTauriBuildArguments([], 'x86_64-pc-windows-msvc', 'win32'),
|
||||
[
|
||||
'build',
|
||||
'--features=cocos-editor-execute',
|
||||
'--target',
|
||||
'x86_64-pc-windows-msvc',
|
||||
],
|
||||
);
|
||||
assert.deepEqual(
|
||||
buildTauriBuildArguments(
|
||||
['--no-bundle'],
|
||||
'x86_64-pc-windows-msvc',
|
||||
'linux',
|
||||
),
|
||||
['build', '--no-bundle'],
|
||||
);
|
||||
assert.deepEqual(
|
||||
buildTauriBuildArguments(['--target=aarch64-apple-darwin']),
|
||||
['build', '--target=aarch64-apple-darwin'],
|
||||
);
|
||||
});
|
||||
test('explicit Cargo features override defaults in every supported spelling', () => {
|
||||
for (const args of [
|
||||
['--features', 'custom'],
|
||||
['--features=custom'],
|
||||
['-f', 'custom'],
|
||||
['-fcustom'],
|
||||
]) {
|
||||
assert.deepEqual(
|
||||
withDefaultCargoFeatures(args, ['cocos-editor-execute']),
|
||||
args,
|
||||
);
|
||||
}
|
||||
assert.deepEqual(
|
||||
withDefaultCargoFeatures(
|
||||
['--', '--features=app'],
|
||||
['cocos-editor-execute'],
|
||||
),
|
||||
['--features=cocos-editor-execute', '--', '--features=app'],
|
||||
);
|
||||
});
|
||||
@@ -114,19 +114,10 @@ const allowedUncalledTauriCommands = [
|
||||
'open_game_creator_launcher_window',
|
||||
'open_game_creator_workspace_window',
|
||||
'read_direct_project_conversation',
|
||||
'reset_design_agent_session',
|
||||
'stop_local_game_preview_if_matches',
|
||||
'start_game_creator_external_mcp',
|
||||
'stop_game_creator_external_mcp',
|
||||
'list_agc_plugins',
|
||||
'list_agc_extensions',
|
||||
'refresh_agc_plugins',
|
||||
'start_agc_plugin',
|
||||
'stop_agc_plugin',
|
||||
'reload_agc_plugin',
|
||||
'call_agc_plugin',
|
||||
'read_agc_plugin_panel',
|
||||
'set_agc_plugin_project_path',
|
||||
'set_agc_plugin_enabled',
|
||||
];
|
||||
const sourceExtensions = new Set([
|
||||
'.json',
|
||||
@@ -1295,7 +1286,10 @@ if (tauriConfig.identifier !== 'world.genarrative.ai-game-creator') {
|
||||
throw new Error('AI game creator shell identifier drifted');
|
||||
}
|
||||
|
||||
const expectedBundledWindowsResources = {
|
||||
const expectedBundledDesignAgentResources = {
|
||||
'design-agent': 'design-agent',
|
||||
};
|
||||
const expectedBundledCodexResources = {
|
||||
'resources/codex/win-x64/bin/codex.exe': 'codex/win-x64/bin/codex.exe',
|
||||
'resources/codex/win-x64/bin/codex-code-mode-host.exe':
|
||||
'codex/win-x64/bin/codex-code-mode-host.exe',
|
||||
@@ -1309,18 +1303,34 @@ const expectedBundledWindowsResources = {
|
||||
'codex/win-x64/codex-package.json',
|
||||
'resources/codex/win-x64/NOTICE.md': 'codex/win-x64/NOTICE.md',
|
||||
'resources/codex/win-x64/manifest.json': 'codex/win-x64/manifest.json',
|
||||
'resources/plugins': 'plugins',
|
||||
};
|
||||
if (tauriConfig.bundle?.resources !== undefined) {
|
||||
throw new Error(
|
||||
'AI game creator shell base Tauri config must not require Windows-only Codex resources',
|
||||
);
|
||||
assert.deepEqual(
|
||||
tauriConfig.bundle?.resources,
|
||||
expectedBundledDesignAgentResources,
|
||||
'AI game creator shell base Tauri config must bundle the design-agent resource pack',
|
||||
);
|
||||
for (const key of Object.keys(tauriConfig.bundle?.resources ?? {})) {
|
||||
if (String(key).includes('codex')) {
|
||||
throw new Error(
|
||||
'AI game creator shell base Tauri config must not require Windows-only Codex resources',
|
||||
);
|
||||
}
|
||||
}
|
||||
assert.deepEqual(
|
||||
windowsTauriConfig.bundle?.resources,
|
||||
expectedBundledWindowsResources,
|
||||
'AI game creator shell Windows Tauri config must bundle the complete pinned Codex resource set and Cocos bridge payload directory',
|
||||
expectedBundledCodexResources,
|
||||
'AI game creator shell Windows Tauri config must bundle the complete pinned Codex resource set',
|
||||
);
|
||||
if (
|
||||
Object.prototype.hasOwnProperty.call(
|
||||
windowsTauriConfig.bundle?.resources ?? {},
|
||||
'design-agent',
|
||||
)
|
||||
) {
|
||||
throw new Error(
|
||||
'design-agent resource pack must not be mixed into the Windows Codex sidecar bundle',
|
||||
);
|
||||
}
|
||||
if (windowsTauriConfig.bundle?.useLocalToolsDir !== true) {
|
||||
throw new Error(
|
||||
'AI game creator shell Windows Tauri config must cache bundling tools in the project target directory',
|
||||
|
||||
@@ -436,10 +436,6 @@ function spawnChild(command, args, options, spawnImpl = spawn) {
|
||||
const child = spawnImpl(command, args, {
|
||||
...options,
|
||||
shell: useShell,
|
||||
// npm.cmd and the Windows shell otherwise create a visible console for
|
||||
// every service in the dev stack. Their stdout/stderr is already inherited
|
||||
// by the launcher, so no separate terminal window is useful.
|
||||
windowsHide: process.platform === 'win32' ? true : options.windowsHide,
|
||||
// POSIX 下让每个长驻服务拥有独立进程组,退出时可以连同 npm、
|
||||
// Node、Cargo 及其子进程一起清理,避免残留订阅任务持续刷日志。
|
||||
detached: isPosix,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { resolve } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
import { withDefaultCargoFeatures } from './cargo-features.mjs';
|
||||
import {
|
||||
readAgcDevEndpoint,
|
||||
resolveAgcDevEndpoint,
|
||||
@@ -21,6 +20,10 @@ import {
|
||||
const appRoot = fileURLToPath(new URL('..', import.meta.url));
|
||||
const repoRoot = resolve(appRoot, '../..');
|
||||
const tauriCliPath = resolve(repoRoot, 'node_modules/@tauri-apps/cli/tauri.js');
|
||||
const AGC_DESIGN_DEBUG_ENV = 'GENARRATIVE_AGC_DESIGN_DEBUG';
|
||||
const AGC_DESIGN_DEBUG_VITE_ENV = 'VITE_GENARRATIVE_AGC_DESIGN_DEBUG';
|
||||
const designDebugEnabled =
|
||||
process.env[AGC_DESIGN_DEBUG_ENV]?.trim() === '0' ? '0' : '1';
|
||||
|
||||
function buildTauriArguments(argv, devUrl = readAgcDevEndpoint().url) {
|
||||
const args = [...argv];
|
||||
@@ -44,24 +47,6 @@ function buildTauriArguments(argv, devUrl = readAgcDevEndpoint().url) {
|
||||
];
|
||||
}
|
||||
|
||||
// `agc_cocos_execute` 与 Cocos 编辑器适配器只在 `cocos-editor-execute` feature 下
|
||||
// 注册。开发构建默认在 Windows 打开它,否则 Agent 的工具清单里根本没有该工具,
|
||||
// 只能退化成改写脚本。可用 AGC_DEV_CARGO_FEATURES(逗号分隔)覆盖,传空串即关闭。
|
||||
function readDevCargoFeatures(env = process.env) {
|
||||
const override = env.AGC_DEV_CARGO_FEATURES;
|
||||
if (override !== undefined) {
|
||||
return override
|
||||
.split(',')
|
||||
.map((value) => value.trim())
|
||||
.filter(Boolean);
|
||||
}
|
||||
return process.platform === 'win32' ? ['cocos-editor-execute'] : [];
|
||||
}
|
||||
|
||||
function withDevCargoFeatures(argv, features = readDevCargoFeatures()) {
|
||||
return withDefaultCargoFeatures(argv, features);
|
||||
}
|
||||
|
||||
function spawnTauriCli(argv, { env = process.env } = {}) {
|
||||
return spawnChild(process.execPath, [tauriCliPath, ...argv], {
|
||||
cwd: appRoot,
|
||||
@@ -125,12 +110,13 @@ async function runTauriDev(
|
||||
shutdownRequested.then(() => false),
|
||||
]);
|
||||
if (!prepared || shutdownSignal) return 1;
|
||||
const tauriArguments = buildTauriArguments(
|
||||
withDevCargoFeatures(argv),
|
||||
endpoint.url,
|
||||
);
|
||||
const tauriArguments = buildTauriArguments(argv, endpoint.url);
|
||||
child = spawnCli(tauriArguments, {
|
||||
env: withAgcDevEndpointEnv(endpoint),
|
||||
env: {
|
||||
...withAgcDevEndpointEnv(endpoint),
|
||||
[AGC_DESIGN_DEBUG_ENV]: designDebugEnabled,
|
||||
[AGC_DESIGN_DEBUG_VITE_ENV]: designDebugEnabled,
|
||||
},
|
||||
});
|
||||
const childResult = waitForCli(child);
|
||||
const outcome = await Promise.race([
|
||||
@@ -179,7 +165,13 @@ async function prepareFrontendDev(endpoint, { onChild, signal }) {
|
||||
const frontend = spawnChild(
|
||||
process.platform === 'win32' ? 'npm.cmd' : 'npm',
|
||||
['run', 'agc:serve'],
|
||||
{ cwd: repoRoot, env: withAgcDevEndpointEnv(endpoint) },
|
||||
{
|
||||
cwd: repoRoot,
|
||||
env: {
|
||||
...withAgcDevEndpointEnv(endpoint),
|
||||
[AGC_DESIGN_DEBUG_VITE_ENV]: designDebugEnabled,
|
||||
},
|
||||
},
|
||||
);
|
||||
onChild(frontend);
|
||||
console.log(
|
||||
@@ -215,7 +207,6 @@ export {
|
||||
isDirectModuleExecution,
|
||||
runTauriDev,
|
||||
spawnTauriCli,
|
||||
withDevCargoFeatures,
|
||||
};
|
||||
|
||||
if (isDirectModuleExecution()) {
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
# resources/plugins 由 build.rs 从 plugins/ 复制生成,属于构建产物。
|
||||
# 它在 dev 监听范围内,重新生成会让 Tauri dev 误判为源码改动而触发
|
||||
# “构建 -> 监听 -> 再构建”的自触发循环。
|
||||
resources/plugins/
|
||||
-25
@@ -733,20 +733,6 @@ dependencies = [
|
||||
"error-code",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cocos-editor-bridge"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"editor-adapter-api",
|
||||
"reqwest 0.12.28",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"tungstenite",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "combine"
|
||||
version = "4.6.7"
|
||||
@@ -1219,14 +1205,6 @@ version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
|
||||
|
||||
[[package]]
|
||||
name = "editor-adapter-api"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.16.0"
|
||||
@@ -1731,8 +1709,6 @@ dependencies = [
|
||||
"axum",
|
||||
"base64 0.22.1",
|
||||
"chromiumoxide",
|
||||
"cocos-editor-bridge",
|
||||
"editor-adapter-api",
|
||||
"futures",
|
||||
"getrandom 0.3.4",
|
||||
"http",
|
||||
@@ -4305,7 +4281,6 @@ dependencies = [
|
||||
"cookie",
|
||||
"cookie_store",
|
||||
"encoding_rs",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2",
|
||||
|
||||
@@ -6,9 +6,6 @@ publish = false
|
||||
|
||||
[features]
|
||||
default = []
|
||||
cocos-editor = ["cocos-editor-bridge/process-discovery"]
|
||||
cocos-editor-execute = ["cocos-editor", "cocos-editor-bridge/windows-bootstrap"]
|
||||
cocos-editor-injection = ["cocos-editor-execute", "cocos-editor-bridge/windows-injection"]
|
||||
|
||||
[build-dependencies]
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
@@ -22,8 +19,6 @@ ts-rs = "12.0.1"
|
||||
typed_floats = { version = "1.0.7", features = ["serde"] }
|
||||
nalgebra = { version = "0.35.0", features = ["serde-serialize"] }
|
||||
agent-runtime-core = { path = "../../../server-rs/crates/agent-runtime-core" }
|
||||
cocos-editor-bridge = { path = "../../../plugins/agc-cocos-editor/native/cocos-editor-bridge", default-features = false }
|
||||
editor-adapter-api = { path = "../../../server-rs/crates/editor-adapter-api" }
|
||||
base64 = "0.22"
|
||||
axum = "0.8"
|
||||
chromiumoxide = "0.9.1"
|
||||
@@ -79,6 +74,14 @@ codegen-units = 256
|
||||
lto = "off"
|
||||
incremental = true
|
||||
|
||||
# Runner 启动阶段会对当前 Debug 可执行文件计算 SHA-256。仅优化密码学依赖,
|
||||
# 保持业务代码的 Debug 编译速度,同时避免整份 Debug 构建因未优化 hash 热点而阻塞启动。
|
||||
[profile.dev.package.sha2]
|
||||
opt-level = 3
|
||||
|
||||
[profile.dev.package.digest]
|
||||
opt-level = 3
|
||||
|
||||
[profile.test]
|
||||
opt-level = 0
|
||||
debug = 1
|
||||
|
||||
@@ -182,8 +182,6 @@ fn main() {
|
||||
);
|
||||
let manifest_path = manifest_dir.join("prompts/runtime/manifest.json");
|
||||
stage_bundled_codex_cli(&manifest_dir);
|
||||
stage_plugin_workspace(&manifest_dir);
|
||||
stage_cocos_editor_payload(&manifest_dir);
|
||||
let compiled = runtime_prompt_bundle::compile_manifest(&manifest_path)
|
||||
.unwrap_or_else(|error| panic!("Prompt Bundle 编译失败:{error}"));
|
||||
validate_seed_task_catalog(&compiled);
|
||||
@@ -205,146 +203,3 @@ fn main() {
|
||||
}
|
||||
tauri_build::build()
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn stage_cocos_editor_payload(manifest_dir: &std::path::Path) {
|
||||
if std::env::var_os("CARGO_FEATURE_COCOS_EDITOR_INJECTION").is_none() {
|
||||
return;
|
||||
}
|
||||
let out_dir = std::path::PathBuf::from(std::env::var_os("OUT_DIR").expect("OUT_DIR"));
|
||||
let profile_dir = out_dir
|
||||
.ancestors()
|
||||
.find(|path| path.file_name().is_some_and(|name| name == "build"))
|
||||
.and_then(|build_dir| build_dir.parent())
|
||||
.expect("AGC Cargo profile directory not found");
|
||||
let candidates = [
|
||||
profile_dir.join("deps/cocos_editor_bridge.dll"),
|
||||
profile_dir.join("cocos_editor_bridge.dll"),
|
||||
];
|
||||
let source = candidates
|
||||
.iter()
|
||||
.find(|path| path.is_file())
|
||||
.unwrap_or_else(|| {
|
||||
panic!(
|
||||
"Cocos bridge native payload 未构建:{}",
|
||||
candidates
|
||||
.iter()
|
||||
.map(|p| p.display().to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(";")
|
||||
)
|
||||
});
|
||||
for destination in [
|
||||
// 插件工作区里的 payload 是开发态与打包态的唯一真源。
|
||||
manifest_dir
|
||||
.join("../../../plugins/agc-cocos-editor/native/payload/cocos-editor-bridge.dll"),
|
||||
// 随包资源目录与 tauri.windows.conf.json 的 `resources/plugins` 映射保持一致。
|
||||
manifest_dir
|
||||
.join("resources/plugins/agc-cocos-editor/native/payload/cocos-editor-bridge.dll"),
|
||||
] {
|
||||
std::fs::create_dir_all(destination.parent().expect("payload resource parent"))
|
||||
.expect("创建 Cocos bridge payload 目录失败");
|
||||
std::fs::copy(source, &destination).expect("复制 Cocos bridge native payload 失败");
|
||||
}
|
||||
println!("cargo:rerun-if-changed={}", source.display());
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
fn stage_cocos_editor_payload(_manifest_dir: &std::path::Path) {}
|
||||
|
||||
/// 把 `plugins/` 工作区里的插件包随包映射到应用资源目录。
|
||||
///
|
||||
/// 只复制插件运行需要的清单、入口、面板和 native payload,不复制 native 源码、
|
||||
/// Cargo target 目录或 node_modules。
|
||||
#[cfg(windows)]
|
||||
fn stage_plugin_workspace(manifest_dir: &std::path::Path) {
|
||||
let repo_root = manifest_dir
|
||||
.parent()
|
||||
.and_then(|app_root| app_root.parent())
|
||||
.and_then(|apps_dir| apps_dir.parent())
|
||||
.expect("AGC 应用必须位于仓库 apps 目录下")
|
||||
.to_path_buf();
|
||||
let workspace = repo_root.join("plugins");
|
||||
let destination_root = manifest_dir.join("resources/plugins");
|
||||
std::fs::create_dir_all(&destination_root).expect("创建插件资源目录失败");
|
||||
let entries = match std::fs::read_dir(&workspace) {
|
||||
Ok(entries) => entries,
|
||||
Err(_) => return,
|
||||
};
|
||||
for entry in entries.flatten() {
|
||||
let plugin_root = entry.path();
|
||||
if !plugin_root.is_dir() || !plugin_root.join("plugin.json").is_file() {
|
||||
continue;
|
||||
}
|
||||
let name = entry.file_name();
|
||||
let destination = destination_root.join(&name);
|
||||
copy_plugin_file(
|
||||
&plugin_root.join("plugin.json"),
|
||||
&destination.join("plugin.json"),
|
||||
);
|
||||
for relative in [
|
||||
std::path::PathBuf::from("src"),
|
||||
std::path::PathBuf::from("panels"),
|
||||
std::path::PathBuf::from("native/payload"),
|
||||
] {
|
||||
copy_plugin_tree(&plugin_root.join(&relative), &destination.join(&relative));
|
||||
}
|
||||
println!("cargo:rerun-if-changed={}", plugin_root.display());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn stage_plugin_file(source: &std::path::Path, destination: &std::path::Path) {
|
||||
let Ok(bytes) = std::fs::read(source) else {
|
||||
return;
|
||||
};
|
||||
if std::fs::read(destination).is_ok_and(|existing| existing == bytes) {
|
||||
return;
|
||||
}
|
||||
if let Some(parent) = destination.parent() {
|
||||
std::fs::create_dir_all(parent).expect("创建插件资源目录失败");
|
||||
}
|
||||
std::fs::write(destination, bytes).expect("复制插件资源失败");
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn copy_plugin_tree(source: &std::path::Path, destination: &std::path::Path) {
|
||||
let entries = match std::fs::read_dir(source) {
|
||||
Ok(entries) => entries,
|
||||
Err(_) => return,
|
||||
};
|
||||
for entry in entries.flatten() {
|
||||
let target = destination.join(entry.file_name());
|
||||
let path = entry.path();
|
||||
if path.is_dir() {
|
||||
let name = entry.file_name();
|
||||
let name = name.to_string_lossy();
|
||||
if matches!(name.as_ref(), "target" | "node_modules" | ".git") {
|
||||
continue;
|
||||
}
|
||||
std::fs::create_dir_all(&target).expect("创建插件资源目录失败");
|
||||
copy_plugin_tree(&path, &target);
|
||||
} else {
|
||||
// 测试文件不随包分发。
|
||||
let name = entry.file_name();
|
||||
let name = name.to_string_lossy();
|
||||
if name.contains(".test.") {
|
||||
continue;
|
||||
}
|
||||
stage_plugin_file(&path, &target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn copy_plugin_file(source: &std::path::Path, destination: &std::path::Path) {
|
||||
if !source.is_file() {
|
||||
return;
|
||||
}
|
||||
std::fs::create_dir_all(destination.parent().expect("插件资源父目录"))
|
||||
.expect("创建插件资源目录失败");
|
||||
std::fs::copy(source, destination).expect("复制插件资源失败");
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
fn stage_plugin_workspace(_manifest_dir: &std::path::Path) {}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
当前阶段:系统架构。明确系统清单、职责边界、依赖和数据归属。
|
||||
@@ -0,0 +1,6 @@
|
||||
共享过程文件(如需维护,请使用这些相对路径):
|
||||
- project/analysis.md
|
||||
- project/决策台账.md
|
||||
- project/dialog.md
|
||||
不要把正式产物写在工作区根目录,也不要等审批失败后再迁移。
|
||||
阶段审批工具:当你判断本阶段必需产物已完成时,必须提交阶段审批。用户批准后 Runtime 自动进入下一阶段;你不能自行切换阶段。
|
||||
@@ -0,0 +1 @@
|
||||
当前阶段:概念设计。明确游戏是什么、不是什么,并形成概念设计产物。
|
||||
@@ -0,0 +1,4 @@
|
||||
顾问阶段不需要继续自主推动项目或主动安排下一步;遵照用户的具体指示行动。
|
||||
根据用户指示回答问题、读取相关文档、修改工作区文件,并说明改动可能影响的已有产物。
|
||||
涉及方向性变化或多个可行方案时,先向用户说明影响并等待用户决定;不要替用户做决定。
|
||||
顾问阶段没有下一层,也不需要提交阶段审批。
|
||||
@@ -0,0 +1 @@
|
||||
当前阶段:项目顾问。五个策划阶段已经完成,后续由用户指示驱动协作。
|
||||
@@ -0,0 +1,44 @@
|
||||
概念阶段定稿时,还必须创建或更新 `project/速览卡.md`。Runtime 只检查该文件是否存在,不检查内容。请使用下面的固定结构,不要加入审批操作说明或独立的决定状态段落:
|
||||
|
||||
# 速览卡:《游戏名》
|
||||
|
||||
## 1. 游戏名称
|
||||
|
||||
## 2. 游戏分类
|
||||
|
||||
## 3. 美术风格
|
||||
- 视觉类型:
|
||||
- 风格关键词:
|
||||
- 色彩与氛围:
|
||||
- MVP 美术边界:
|
||||
|
||||
## 4. 一句话描述
|
||||
|
||||
## 5. 游戏支柱
|
||||
| 支柱 | 玩家感受 | 实现机制 |
|
||||
|---|---|---|
|
||||
|
||||
## 6. 核心循环
|
||||
|
||||
## 7. 目标用户
|
||||
- 核心用户:
|
||||
- 游戏偏好:
|
||||
- 单次游玩时长:
|
||||
- 参考游戏与参考点:
|
||||
|
||||
## 8. 平台事实
|
||||
|
||||
## 9. 最小 MVP 系统
|
||||
| 系统 | 最小功能 | 为什么必须有 | 验证方法 |
|
||||
|---|---|---|---|
|
||||
|
||||
## 10. 给创作者的关键提示
|
||||
- 先做:
|
||||
- 暂时不做:
|
||||
- 这样验证:
|
||||
- 达标再扩展:
|
||||
|
||||
### 待原型验证项
|
||||
- 问题:
|
||||
- 原型:
|
||||
- 观察:
|
||||
@@ -0,0 +1 @@
|
||||
当前阶段:系统文档。逐个完成已确定系统的内部规则、接口和验证标准。
|
||||
@@ -0,0 +1 @@
|
||||
当前阶段:技术文档。完成数据与配表、技术实现、美术圣经和总册。
|
||||
@@ -0,0 +1 @@
|
||||
当前阶段:顶层设计。明确玩家持续游玩的循环、资源流、节奏和系统范围。
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,384 @@
|
||||
{
|
||||
"version": 1,
|
||||
"resources": [
|
||||
{
|
||||
"path": "skills/concept.md",
|
||||
"id": "skills.concept",
|
||||
"summary": "概念阶段写作规则。",
|
||||
"category": "skills",
|
||||
"title": "概念设计分册",
|
||||
"inject_phases": [
|
||||
"concept"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "skills/top_design.md",
|
||||
"id": "skills.top_design",
|
||||
"summary": "顶层设计阶段写作规则。",
|
||||
"category": "skills",
|
||||
"title": "顶层设计分册",
|
||||
"inject_phases": [
|
||||
"top_design"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "skills/architecture.md",
|
||||
"id": "skills.architecture",
|
||||
"summary": "系统架构阶段写作规则。",
|
||||
"category": "skills",
|
||||
"title": "系统架构分册",
|
||||
"inject_phases": [
|
||||
"architecture"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "skills/systems.md",
|
||||
"id": "skills.systems",
|
||||
"summary": "系统文档阶段写作规则。",
|
||||
"category": "skills",
|
||||
"title": "系统文档分册",
|
||||
"inject_phases": [
|
||||
"systems"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "skills/tdd.md",
|
||||
"id": "skills.tdd",
|
||||
"summary": "技术文档阶段写作规则。",
|
||||
"category": "skills",
|
||||
"title": "技术文档分册",
|
||||
"inject_phases": [
|
||||
"tdd"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "templates.analysis",
|
||||
"category": "templates",
|
||||
"title": "analysis",
|
||||
"summary": "策划文档结构模板。",
|
||||
"path": "templates/analysis.md"
|
||||
},
|
||||
{
|
||||
"id": "templates.architecture",
|
||||
"category": "templates",
|
||||
"title": "architecture",
|
||||
"summary": "策划文档结构模板。",
|
||||
"path": "templates/architecture.md"
|
||||
},
|
||||
{
|
||||
"id": "templates.concept_design",
|
||||
"category": "templates",
|
||||
"title": "concept-design",
|
||||
"summary": "策划文档结构模板。",
|
||||
"path": "templates/concept-design.md"
|
||||
},
|
||||
{
|
||||
"id": "templates.stardew_analysis",
|
||||
"category": "templates",
|
||||
"title": "stardew-analysis",
|
||||
"summary": "策划文档结构模板。",
|
||||
"path": "templates/stardew-analysis.md"
|
||||
},
|
||||
{
|
||||
"id": "templates.tdd_art_bible",
|
||||
"category": "templates",
|
||||
"title": "tdd-art-bible",
|
||||
"summary": "策划文档结构模板。",
|
||||
"path": "templates/tdd-art-bible.md"
|
||||
},
|
||||
{
|
||||
"id": "templates.tdd_data",
|
||||
"category": "templates",
|
||||
"title": "tdd-data",
|
||||
"summary": "策划文档结构模板。",
|
||||
"path": "templates/tdd-data.md"
|
||||
},
|
||||
{
|
||||
"id": "templates.tdd_master",
|
||||
"category": "templates",
|
||||
"title": "tdd-master",
|
||||
"summary": "策划文档结构模板。",
|
||||
"path": "templates/tdd-master.md"
|
||||
},
|
||||
{
|
||||
"id": "templates.tdd_tech",
|
||||
"category": "templates",
|
||||
"title": "tdd-tech",
|
||||
"summary": "策划文档结构模板。",
|
||||
"path": "templates/tdd-tech.md"
|
||||
},
|
||||
{
|
||||
"id": "templates.top_design",
|
||||
"category": "templates",
|
||||
"title": "top-design",
|
||||
"summary": "策划文档结构模板。",
|
||||
"path": "templates/top-design.md"
|
||||
},
|
||||
{
|
||||
"id": "exemplars.decision_log",
|
||||
"category": "exemplars",
|
||||
"title": "decision-log",
|
||||
"summary": "策划文档范例或需求附件。",
|
||||
"path": "exemplars/decision-log.md"
|
||||
},
|
||||
{
|
||||
"id": "exemplars.fast_gdd",
|
||||
"category": "exemplars",
|
||||
"title": "fast-gdd",
|
||||
"summary": "策划文档范例或需求附件。",
|
||||
"path": "exemplars/fast-gdd.md"
|
||||
},
|
||||
{
|
||||
"id": "exemplars.overview_card",
|
||||
"category": "exemplars",
|
||||
"title": "overview-card",
|
||||
"summary": "策划文档范例或需求附件。",
|
||||
"path": "exemplars/overview-card.md"
|
||||
},
|
||||
{
|
||||
"id": "exemplars.stardew_architecture",
|
||||
"category": "exemplars",
|
||||
"title": "stardew-architecture",
|
||||
"summary": "策划文档范例或需求附件。",
|
||||
"path": "exemplars/stardew-architecture.md"
|
||||
},
|
||||
{
|
||||
"id": "exemplars.stardew_concept",
|
||||
"category": "exemplars",
|
||||
"title": "stardew-concept",
|
||||
"summary": "策划文档范例或需求附件。",
|
||||
"path": "exemplars/stardew-concept.md"
|
||||
},
|
||||
{
|
||||
"id": "exemplars.stardew_s06_combat",
|
||||
"category": "exemplars",
|
||||
"title": "stardew-s06-combat",
|
||||
"summary": "策划文档范例或需求附件。",
|
||||
"path": "exemplars/stardew-s06-combat.md"
|
||||
},
|
||||
{
|
||||
"id": "exemplars.stardew_tdd_art_bible",
|
||||
"category": "exemplars",
|
||||
"title": "stardew-tdd-art-bible",
|
||||
"summary": "策划文档范例或需求附件。",
|
||||
"path": "exemplars/stardew-tdd-art-bible.md"
|
||||
},
|
||||
{
|
||||
"id": "exemplars.stardew_tdd_data",
|
||||
"category": "exemplars",
|
||||
"title": "stardew-tdd-data",
|
||||
"summary": "策划文档范例或需求附件。",
|
||||
"path": "exemplars/stardew-tdd-data.md"
|
||||
},
|
||||
{
|
||||
"id": "exemplars.stardew_tdd_master",
|
||||
"category": "exemplars",
|
||||
"title": "stardew-tdd-master",
|
||||
"summary": "策划文档范例或需求附件。",
|
||||
"path": "exemplars/stardew-tdd-master.md"
|
||||
},
|
||||
{
|
||||
"id": "exemplars.stardew_tdd_tech",
|
||||
"category": "exemplars",
|
||||
"title": "stardew-tdd-tech",
|
||||
"summary": "策划文档范例或需求附件。",
|
||||
"path": "exemplars/stardew-tdd-tech.md"
|
||||
},
|
||||
{
|
||||
"id": "exemplars.stardew_top_design",
|
||||
"category": "exemplars",
|
||||
"title": "stardew-top-design",
|
||||
"summary": "策划文档范例或需求附件。",
|
||||
"path": "exemplars/stardew-top-design.md"
|
||||
},
|
||||
{
|
||||
"id": "exemplars.tdd_art_bible_SKILL",
|
||||
"category": "exemplars",
|
||||
"title": "tdd-art-bible-SKILL",
|
||||
"summary": "策划文档范例或需求附件。",
|
||||
"path": "exemplars/tdd-art-bible-SKILL.md"
|
||||
},
|
||||
{
|
||||
"id": "exemplars.tdd_data_SKILL",
|
||||
"category": "exemplars",
|
||||
"title": "tdd-data-SKILL",
|
||||
"summary": "策划文档范例或需求附件。",
|
||||
"path": "exemplars/tdd-data-SKILL.md"
|
||||
},
|
||||
{
|
||||
"id": "exemplars.tdd_tech_SKILL",
|
||||
"category": "exemplars",
|
||||
"title": "tdd-tech-SKILL",
|
||||
"summary": "策划文档范例或需求附件。",
|
||||
"path": "exemplars/tdd-tech-SKILL.md"
|
||||
},
|
||||
{
|
||||
"id": "system_types.核心玩法编排.skill",
|
||||
"category": "system_types",
|
||||
"title": "01_核心玩法编排 skill",
|
||||
"summary": "系统类型写法规则或模板。",
|
||||
"path": "modules/system-types/01_核心玩法编排/SKILL.md"
|
||||
},
|
||||
{
|
||||
"id": "system_types.核心玩法编排.template",
|
||||
"category": "system_types",
|
||||
"title": "01_核心玩法编排 template",
|
||||
"summary": "系统类型写法规则或模板。",
|
||||
"path": "modules/system-types/01_核心玩法编排/模板.md"
|
||||
},
|
||||
{
|
||||
"id": "system_types.时间与日程.skill",
|
||||
"category": "system_types",
|
||||
"title": "02_时间与日程 skill",
|
||||
"summary": "系统类型写法规则或模板。",
|
||||
"path": "modules/system-types/02_时间与日程/SKILL.md"
|
||||
},
|
||||
{
|
||||
"id": "system_types.时间与日程.template",
|
||||
"category": "system_types",
|
||||
"title": "02_时间与日程 template",
|
||||
"summary": "系统类型写法规则或模板。",
|
||||
"path": "modules/system-types/02_时间与日程/模板.md"
|
||||
},
|
||||
{
|
||||
"id": "system_types.生产种植经营.skill",
|
||||
"category": "system_types",
|
||||
"title": "03_生产种植经营 skill",
|
||||
"summary": "系统类型写法规则或模板。",
|
||||
"path": "modules/system-types/03_生产种植经营/SKILL.md"
|
||||
},
|
||||
{
|
||||
"id": "system_types.生产种植经营.template",
|
||||
"category": "system_types",
|
||||
"title": "03_生产种植经营 template",
|
||||
"summary": "系统类型写法规则或模板。",
|
||||
"path": "modules/system-types/03_生产种植经营/模板.md"
|
||||
},
|
||||
{
|
||||
"id": "system_types.地图与探索.skill",
|
||||
"category": "system_types",
|
||||
"title": "04_地图与探索 skill",
|
||||
"summary": "系统类型写法规则或模板。",
|
||||
"path": "modules/system-types/04_地图与探索/SKILL.md"
|
||||
},
|
||||
{
|
||||
"id": "system_types.地图与探索.template",
|
||||
"category": "system_types",
|
||||
"title": "04_地图与探索 template",
|
||||
"summary": "系统类型写法规则或模板。",
|
||||
"path": "modules/system-types/04_地图与探索/模板.md"
|
||||
},
|
||||
{
|
||||
"id": "system_types.采集与支线活动.skill",
|
||||
"category": "system_types",
|
||||
"title": "05_采集与支线活动 skill",
|
||||
"summary": "系统类型写法规则或模板。",
|
||||
"path": "modules/system-types/05_采集与支线活动/SKILL.md"
|
||||
},
|
||||
{
|
||||
"id": "system_types.采集与支线活动.template",
|
||||
"category": "system_types",
|
||||
"title": "05_采集与支线活动 template",
|
||||
"summary": "系统类型写法规则或模板。",
|
||||
"path": "modules/system-types/05_采集与支线活动/模板.md"
|
||||
},
|
||||
{
|
||||
"id": "system_types.战斗与敌人.skill",
|
||||
"category": "system_types",
|
||||
"title": "06_战斗与敌人 skill",
|
||||
"summary": "系统类型写法规则或模板。",
|
||||
"path": "modules/system-types/06_战斗与敌人/SKILL.md"
|
||||
},
|
||||
{
|
||||
"id": "system_types.战斗与敌人.template",
|
||||
"category": "system_types",
|
||||
"title": "06_战斗与敌人 template",
|
||||
"summary": "系统类型写法规则或模板。",
|
||||
"path": "modules/system-types/06_战斗与敌人/模板.md"
|
||||
},
|
||||
{
|
||||
"id": "system_types.物品背包与制作.skill",
|
||||
"category": "system_types",
|
||||
"title": "07_物品背包与制作 skill",
|
||||
"summary": "系统类型写法规则或模板。",
|
||||
"path": "modules/system-types/07_物品背包与制作/SKILL.md"
|
||||
},
|
||||
{
|
||||
"id": "system_types.物品背包与制作.template",
|
||||
"category": "system_types",
|
||||
"title": "07_物品背包与制作 template",
|
||||
"summary": "系统类型写法规则或模板。",
|
||||
"path": "modules/system-types/07_物品背包与制作/模板.md"
|
||||
},
|
||||
{
|
||||
"id": "system_types.成长与技能.skill",
|
||||
"category": "system_types",
|
||||
"title": "08_成长与技能 skill",
|
||||
"summary": "系统类型写法规则或模板。",
|
||||
"path": "modules/system-types/08_成长与技能/SKILL.md"
|
||||
},
|
||||
{
|
||||
"id": "system_types.成长与技能.template",
|
||||
"category": "system_types",
|
||||
"title": "08_成长与技能 template",
|
||||
"summary": "系统类型写法规则或模板。",
|
||||
"path": "modules/system-types/08_成长与技能/模板.md"
|
||||
},
|
||||
{
|
||||
"id": "system_types.NPC关系与任务.skill",
|
||||
"category": "system_types",
|
||||
"title": "09_NPC关系与任务 skill",
|
||||
"summary": "系统类型写法规则或模板。",
|
||||
"path": "modules/system-types/09_NPC关系与任务/SKILL.md"
|
||||
},
|
||||
{
|
||||
"id": "system_types.NPC关系与任务.template",
|
||||
"category": "system_types",
|
||||
"title": "09_NPC关系与任务 template",
|
||||
"summary": "系统类型写法规则或模板。",
|
||||
"path": "modules/system-types/09_NPC关系与任务/模板.md"
|
||||
},
|
||||
{
|
||||
"id": "system_types.经济与商店.skill",
|
||||
"category": "system_types",
|
||||
"title": "10_经济与商店 skill",
|
||||
"summary": "系统类型写法规则或模板。",
|
||||
"path": "modules/system-types/10_经济与商店/SKILL.md"
|
||||
},
|
||||
{
|
||||
"id": "system_types.经济与商店.template",
|
||||
"category": "system_types",
|
||||
"title": "10_经济与商店 template",
|
||||
"summary": "系统类型写法规则或模板。",
|
||||
"path": "modules/system-types/10_经济与商店/模板.md"
|
||||
},
|
||||
{
|
||||
"id": "system_types.事件与节日.skill",
|
||||
"category": "system_types",
|
||||
"title": "11_事件与节日 skill",
|
||||
"summary": "系统类型写法规则或模板。",
|
||||
"path": "modules/system-types/11_事件与节日/SKILL.md"
|
||||
},
|
||||
{
|
||||
"id": "system_types.事件与节日.template",
|
||||
"category": "system_types",
|
||||
"title": "11_事件与节日 template",
|
||||
"summary": "系统类型写法规则或模板。",
|
||||
"path": "modules/system-types/11_事件与节日/模板.md"
|
||||
},
|
||||
{
|
||||
"id": "system_types.UI与文本呈现.skill",
|
||||
"category": "system_types",
|
||||
"title": "12_UI与文本呈现 skill",
|
||||
"summary": "系统类型写法规则或模板。",
|
||||
"path": "modules/system-types/12_UI与文本呈现/SKILL.md"
|
||||
},
|
||||
{
|
||||
"id": "system_types.UI与文本呈现.template",
|
||||
"category": "system_types",
|
||||
"title": "12_UI与文本呈现 template",
|
||||
"summary": "系统类型写法规则或模板。",
|
||||
"path": "modules/system-types/12_UI与文本呈现/模板.md"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
# 决策台账:《星露谷物语》金样项目
|
||||
|
||||
版本:v3 | 规则:台账放活队列——design 只放结论、分析只放论证、决定与开放问题住这里。编号连续不复用;被推翻的行标 overturned 挂新行,不删行。
|
||||
状态六态:`confirmed`(用户亲口/亲选)/ `auto_decided`(技术类代决,必带理由+推翻条件,用户一键可翻)/ `default_pending`(默认建议兜底,用户未点头)/ `prototype_pending`(待原型验证)/ `pending_user`(等用户拍板)/ `overturned`(被推翻,挂旧行编号)。
|
||||
|
||||
> 编号口径:D-01~D-13 与 exemplars/stardew-analysis.md 台账节选一致(D-04~D-06、D-08~D-10、D-12 原为"就地小权衡,直接登记未开条目",此处按登记口径展开);D-14 起为技术文档期新增,与 stardew-tdd-tech.md 开放问题回执互引。
|
||||
|
||||
## 当前待办(活队列)
|
||||
|
||||
### 等用户拍板(pending_user)
|
||||
|
||||
| 编号 | 决定 | 层 | 谁 | 依据 | 推翻条件 | 状态 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| D-14 | 体力与战斗共享单池 | TDD | user | 风险资源统一制造取舍(概念张力一);**暂按共享实现,改单拆只需改 S02 成本入口** | 战斗参与率实测过低(玩家回避矿井) | pending_user(暂按共享实现) |
|
||||
| D-15 | 背包格子制 vs 重量制 | TDD | user | 格子制直觉、重量制焦虑感与 T5"休闲不打卡"冲突;暂按格子制实现、存档预留 capacity_type 字段 | 格子管理成为主要负面反馈 | pending_user(B 级阻断存档结构,暂按格子制) |
|
||||
|
||||
### 待原型验证(prototype_pending)
|
||||
|
||||
| 编号 | 决定 | 层 | 谁 | 依据 | 推翻条件 | 状态 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| D-13b | 战斗判定窗口手感(前摇帧数/无敌帧 450ms 基准) | 系统 | user | 数值可定、手感不可纸面验证 | 原型显示节奏拖慢/玩家困惑 | prototype_pending(规则本体见 D-13 confirmed) |
|
||||
|
||||
### 默认建议兜底(default_pending)
|
||||
|
||||
| 编号 | 决定 | 层 | 谁 | 依据 | 推翻条件 | 状态 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| D-19 | 天气权重表具体数值(晴/雨/风暴按季节) | TDD | agent | 概念层只定"雨免浇水"定性;数值推内容期填 | 前 5 日出现连续 3 日雨/全无雨 | default_pending(默认值已进数据表,带 designer_note) |
|
||||
|
||||
## 已采用决定
|
||||
|
||||
### 用户确认(confirmed)
|
||||
|
||||
| 编号 | 决定 | 层 | 谁 | 依据 | 推翻条件 | 状态 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| D-01 | 定调:牧场物语系参照、治愈慢节奏 | 概念 | user | 用户原始需求 | — | confirmed |
|
||||
| D-02 | 单人体验,无多人 | 概念 | user | 概念层非目标 | — | confirmed |
|
||||
| D-03 | 战斗保持伴生风险,不做装备驱动主轴 | 概念 | user | 概念期问题一 | 矿井流失率过半且归因战斗 | confirmed |
|
||||
| D-07 | 日目标自设,季节与社区提供低频牵引 | 顶层 | user | 顶层期问题一 | 新手周流失归因无方向 | confirmed |
|
||||
| D-11 | 采集/钓鱼/战斗统一"活动结果"接口 | 架构 | user | 架构期问题一 | 第三活动类型出现结构性差异 | confirmed |
|
||||
| D-13 | 战斗采用节奏/指令判定 | 系统 | user | S06 问题一 | 原型显示节奏拖慢/玩家困惑 | confirmed(手感部分拆 D-13b prototype_pending) |
|
||||
|
||||
### 技术代决(auto_decided——带理由与推翻条件,用户一键可翻)
|
||||
|
||||
| 编号 | 决定 | 层 | 谁 | 依据(理由) | 推翻条件 | 状态 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| D-04 | 时间片制:700ms=10 游戏分钟 | 概念 | agent | 原作实证节拍;一天≈14 分钟真实时间贴合 T5"休闲" | 内测一天体感过短/过长 | auto_decided |
|
||||
| D-05 | 分区域切换(区域独立场景,非连续地图) | 概念 | agent | 概念层"不是什么:无边界开放世界";区域小网络全部步行可达 | 场景切换成为移动负担反馈 | auto_decided |
|
||||
| D-06 | 28 日/季、四季/年 | 顶层 | agent | 季节窗口制造"本季计划"节奏(支柱二) | 换季频率在测试中被无视 | auto_decided |
|
||||
| D-09 | 商店营业时段走条件表 | 架构 | agent | 与配方/区域解锁共用 check(condition_id) 单一入口 | 条件表规模膨胀难维护 | auto_decided |
|
||||
| D-10 | 出货箱日终统一结算 | 架构 | agent | 收入集中进日终面板,强化"一天一结算"叙事;商店现卖保留即时通道 | 玩家普遍绕开出货箱 | auto_decided |
|
||||
| D-12 | 工具升级期间该工具不可用 | 系统 | agent | 升级=时间成本换效率(顶层张力二);备用旧工具暂不做(开放问题) | 升级期挫败感集中爆发 | auto_decided |
|
||||
| D-16 | 矿井逐层生成本期不做(P2) | TDD | agent | GDD 已标"不做无限地牢";首期按布局池 8~12 模板拼装 | 内测要求深度爬塔玩法 | auto_decided |
|
||||
| D-17 | 换装首期 5 层(基础体/裤/衣/发型/饰件),非 19 层 | TDD | agent | 外观自定义非首期卖点;层结构预留到 19 层 | 外观系统成核心诉求 | auto_decided |
|
||||
| D-18 | 作物品质三档:普通/银/金 | TDD | agent | 经济分层需要(即时变现 vs 等待升值的取舍) | 银金档无人区分、一律普通出售 | auto_decided |
|
||||
|
||||
### 已推翻(overturned——旧行保留,挂新行)
|
||||
|
||||
| 编号 | 决定 | 层 | 谁 | 依据 | 推翻条件 | 状态 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| D-08 | 作物品质两档:普通/银 | TDD | agent | 早期小权衡:两档最简 | — | **overturned → D-18**(经济分层不足,改三档;铱档留 P1) |
|
||||
|
||||
## 队列纪律(给 agent 的使用说明)
|
||||
|
||||
- 新决定入队:拿下一号(当前最大 D-19,下一号 D-20);就现代决可登记不开条目,但状态必须写 auto_decided 并带理由+推翻条件。
|
||||
- 用户翻案:旧行标 overturned 挂新行,受影响文档节重写(本台账只记录,不代改)。
|
||||
- 概念层变更定稿后:速览卡"决定状态与原型验证项"字段随本文件最新版同步(prompt 级纪律)。
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user