NDBS update

This commit is contained in:
wjsjwr 2026-01-18 12:38:03 +08:00
parent d29c7e4881
commit cb6217d0cd
5 changed files with 1689 additions and 9 deletions

67
GEMINI.md Normal file
View File

@ -0,0 +1,67 @@
# GEMINI.md - Context & Instructions for "Super Mentor" (最强导师)
## 1. Project Overview
**Project Name:** Super Mentor (最强导师 / Supervisor Simulator)
**Type:** Simulation / Strategy / Roguelite Game
**Engine:** Godot 4.x (C# / .NET)
**Platform:** Windows (Win32), likely cross-platform capable.
**Core Concept:**
A "survival horror" simulation of academic life. Players manage a lab, recruit students, publish papers, secure funding, and navigate academic politics ("publish or perish").
## 2. Architecture & Directory Structure
### 2.1 Game Engine (Godot/C#)
* **Root:** Contains `project.godot`, `.sln`, `.csproj`.
* **`scripts/`**: The core C# source code.
* `Core/`: Game systems (TurnSystem, TaskSystem, EconomySystem, SynergySystem) and Interfaces.
* `Models/`: Data models (StudentModel, TaskModel, etc.) and Definitions.
* `[Node classes]`: `Player.cs`, `Student.cs` (Godot Node behaviors).
* **`resources/definitions/`**: Data-driven design files.
* `.json`: Archetypes, Roles, Traits.
* `.tres`: Discipline specific resources (Godot Text Resource).
* **`scenes/`**: Godot `.tscn` scene files.
* **`docs/`**: Detailed game design documents (GDD).
### 2.2 Tooling: Numerical Design & Balancing System (NDBS)
Located in `tools/ndbs/`, this is a web-based tool for designers to edit game data and write scripts.
* **Backend:** Python 3.14 (FastAPI), managed by `uv`.
* **Frontend:** Vue.js (Vite, Naive UI/Element Plus).
* **Spec:** `specs/numerical_design_system.md`.
## 3. Building & Development
### 3.1 Game (Godot)
* **Prerequisites:** Godot Engine (Mono version), .NET SDK.
* **Build:** Standard Godot build process or via IDE (Visual Studio / JetBrains Rider / VS Code).
* **Run:** Open `project.godot` in Godot Editor or run via CLI.
### 3.2 NDBS Tool (`tools/ndbs`)
* **Backend (`tools/ndbs/server`):**
* Manager: `uv`
* Run: `uv run main.py` (or `uvicorn main:app --reload`)
* **Frontend (`tools/ndbs/client`):**
* Manager: `npm` / `yarn`
* Build: `npm run build` (Output consumed by Python server).
## 4. Key Conventions
### 4.1 C# / Godot
* **Systems Pattern:** Core logic is decoupled from Godot Nodes where possible, residing in `scripts/Core` implementing `IGameSystem`.
* **Rule System:** Game logic "rules" (Buffs/Debuffs) are referenced by string IDs (`RuleIds`) and executed via a `RuleManager` (using Reflection).
* **Data Driven:** Heavy reliance on JSON/TRES definitions for content.
### 4.2 Code Style
* **C#:** Standard .NET conventions (PascalCase for public, camelCase for private/locals).
* **Python:** Type hints required (Python 3.14+). Pydantic for data validation.
* **Frontend:** Vue Composition API (`<script setup lang="ts">`).
## 5. Current Task Context (As of Jan 2026)
The project is actively implementing the **NDBS Tool** defined in `specs/numerical_design_system.md`.
**Goal:** Create a unified service where a Python backend serves a Vue frontend to allow editing of `resources/definitions` and generation of `scripts/Rules/Generated/*.cs` files.
**Immediate Next Steps:**
1. Initialize the Python backend using `uv`.
2. Set up the Vue frontend.
3. Implement the File System API for JSON/TRES handling.

View File

@ -0,0 +1,188 @@
# 配置定义系统文档 (Definition System)
本文档详细说明了《最强导师》游戏中的数据定义系统。该系统采用数据驱动Data-Driven的设计理念将核心游戏内容如学科、角色、特质等与代码逻辑分离存储为 JSON 格式的配置文件。这不仅便于开发过程中的数值调整,也为未来的 Mod 支持打下了基础。
## 1. 系统概述
游戏的核心数据存储在 `resources/definitions/` 目录下。游戏启动时,`ContentRegistry`(位于 `scripts/Core/ContentRegistry.cs`)负责加载这些文件,并将它们反序列化为 C# 对象,最终汇聚在 `GameContentDatabase` 中供游戏逻辑查询。
**主要特点:**
* **格式统一**:主要使用 JSON 格式。
* **支持热加载/Mod**:设计上支持从多个源(`res://` 或 `user://`)加载并合并数据。
* **国际化支持**:所有名称和描述都包含 `Key` (本地化键) 和 `Fallback` (默认文本)。
## 2. 核心数据结构
几乎所有的定义文件都复用了以下核心数据结构。
### 2.1 DefinitionHeader (通用头部)
所有定义对象都包含一个 `Header` 字段,用于标识身份。
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `Id` | `string` | 唯一标识符,建议格式 `namespace:type_name` (如 `core:archetype_grinder`)。 |
| `Name` | `LocalizedText` | 显示名称。 |
| `Description` | `LocalizedText` | 详细描述。 |
| `IconPath` | `string` | 图标资源路径 (可选)。 |
| `Tags` | `List<string>` | 标签列表,用于分类或过滤。 |
### 2.2 LocalizedText (本地化文本)
用于支持多语言。
| 字段名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `Key` | `string` | 翻译文件中的 Key (如 `archetype.grinder.name`)。 |
| `Fallback` | `string` | 当找不到翻译时的默认显示文本。 |
### 2.3 ModifierBundle (数值修正包)
用于描述 Buff、Debuff 或被动效果。它不直接修改数值,而是提供加成或规则 ID。
* **AttributeModifiers**: 属性修正 (如 `Academic`, `Engineering`)。
* `Type`: 属性枚举。
* `Add`: 固定加值。
* `Multiplier`: 乘法倍率 (默认为 1.0)。
* **StatusModifiers**: 状态修正 (如 `Mood`, `Stress`)。
* **ResourceModifiers**: 资源修正 (如 `Money`)。
* **RuleIds**: `List<string>`,特殊规则的 ID (如 `rule:no_sleep`),由代码逻辑解析具体效果。
---
## 3. 定义类型详解
以下是各类定义文件的详细说明。
### 3.1 学科 (Disciplines)
**文件**: `resources/definitions/disciplines.json`
**对应类**: `DisciplineDefinition`
定义了游戏中的学术流派(如“经济学”、“计算机科学”)。学科决定了核心的资源循环机制和允许使用的角色。
* **Buff**: 学科全局 Buff通常提供特定资源产出或属性加成。
* **RolePoolIds**: 该学科允许使用的角色 ID 列表。
* **ItemPoolIds**: 该学科关联的特殊物品池。
* **TaskKeywordIds**: 任务生成的关键词偏好。
**示例片段**:
```json
{
"Header": { "Id": "core:discipline_computer", ... },
"Buff": {
"Name": { "Fallback": "Overclock" },
"Modifiers": {
"AttributeModifiers": [{ "Type": "Engineering", "Add": 5, "Multiplier": 1.05 }]
}
},
"RolePoolIds": [ "core:role_geek", "core:role_coder" ]
}
```
### 3.2 角色身份 (Roles)
**文件**: `resources/definitions/roles.json`
**对应类**: `RoleDefinition` (推测)
定义了学生在实验室中的具体分工(如“码农”、“实验员”)。
* **Tiers**: 角色等级列表。通常随人数或投入增加解锁更高级别的修正。
* `RequiredCount`: 激活该层级所需数量。
* `Modifiers`: 该层级提供的修正包。
* **AllowedDisciplineIds**: (可选) 限制该角色只能在特定学科中使用。
**示例片段**:
```json
{
"Header": { "Id": "core:role_coder", ... },
"Tiers": [
{
"RequiredCount": 2,
"Modifiers": { "AttributeModifiers": [{ "Type": "Engineering", "Multiplier": 1.20 }] }
}
]
}
```
### 3.3 原型 (Archetypes)
**文件**: `resources/definitions/archetypes.json`
**对应类**: `ArchetypeDefinition` (推测)
定义了学生的性格原型(如“卷王”、“摸鱼怪”)。类似于种族天赋,随同类学生数量增加而增强。
* **Tiers**: 羁绊等级列表。
* `RequiredCount`: 激活羁绊所需人数。
* `Modifiers`: 羁绊效果。
**示例片段**:
```json
{
"Header": { "Id": "core:archetype_grinder", ... },
"Tiers": [
{
"RequiredCount": 2,
"Modifiers": { "AttributeModifiers": [{ "Type": "Activation", "Multiplier": 1.15 }] }
}
]
}
```
### 3.4 特质 (Traits)
**文件**: `resources/definitions/traits.json`
**对应类**: `TraitDefinition` (推测)
定义了学生个体的具体特征(如“咖啡依赖”、“夜猫子”)。
* **Modifiers**: 特质带来的修正效果,通常直接包含 `RuleIds` 来触发特殊逻辑。
**示例片段**:
```json
{
"Header": { "Id": "core:trait_night_owl", ... },
"Modifiers": { "RuleIds": [ "rule:trait_night_owl" ] }
}
```
### 3.5 校园行为与模拟参数 (Campus Behavior)
**文件**: `resources/definitions/campus_behavior.json`
**对应结构**: 模拟配置对象 (非标准 Definition)
定义了模拟系统的全局常数和行为交互规则。
* **Thresholds**: 各种状态的阈值(如 `CriticalStressThreshold`: 90
* **Decay/Growth Rates**: 状态随时间变化的速率(如 `HungerDecayPerSecond`)。
* **ActionConfigs**: 定义学生可执行的具体动作。
* `ActionId`: 动作 ID (如 `Eating`)。
* `LocationId`: 执行地点 (如 `Canteen`)。
* `DurationSeconds`: 持续时间。
* `*Delta`: 执行该动作对各项数值的影响 (如 `HungerDelta`, `StressDelta`)。
**示例片段**:
```json
{
"CriticalStressThreshold": 90,
"ActionConfigs": [
{
"ActionId": "Eating",
"LocationId": "Canteen",
"HungerDelta": 3.00,
"StressDelta": -0.50
}
]
}
```
## 4. 如何添加新内容
1. **找到对应文件**: 在 `resources/definitions/` 下找到对应类型的 JSON 文件。
2. **复制模板**: 复制现有的一个对象块。
3. **修改 ID**: 确保 `Header.Id` 是全局唯一的。
4. **配置参数**: 修改名称、描述和修正数值。
5. **重启游戏**: 数据将在游戏启动时重新加载。
## 5. 关联代码文件
* **加载逻辑**: `scripts/Core/ContentRegistry.cs`
* **数据仓库**: `scripts/Models/GameContentDatabase.cs`
* **学科定义**: `scripts/Models/DisciplineDefinitions.cs`
* **修正结构**: `scripts/Models/Modifiers.cs`
* **通用结构**: `scripts/Models/DefinitionSupport.cs`
---
*文档生成日期: 2026-01-17*

File diff suppressed because it is too large Load Diff

View File

@ -53,6 +53,21 @@
<div id="build-output" class="build-output"></div> <div id="build-output" class="build-output"></div>
</section> </section>
<section class="panel guide">
<div class="panel-title">Definition guide</div>
<div id="guide-title" class="guide-title">No definition selected</div>
<div id="guide-desc" class="guide-desc">
Select a definition file to see expected fields and templates.
</div>
<div id="guide-fields" class="guide-fields"></div>
<div class="guide-actions">
<button id="insert-template" class="ghost">Insert template</button>
<button id="validate-file">Validate file</button>
<button id="validate-all" class="ghost">Validate all</button>
</div>
<div id="validation-output" class="build-output hidden"></div>
</section>
<section class="panel editor-panel"> <section class="panel editor-panel">
<div class="editor-header"> <div class="editor-header">
<div> <div>
@ -62,17 +77,31 @@
</div> </div>
</div> </div>
<div class="editor-actions"> <div class="editor-actions">
<div class="view-toggle">
<button id="view-raw" class="ghost">Raw</button>
<button id="view-structured">Structured</button>
</div>
<button id="format-button" class="ghost">Format</button> <button id="format-button" class="ghost">Format</button>
<button id="save-button">Save</button> <button id="save-button">Save</button>
</div> </div>
</div> </div>
<div id="schema-summary" class="schema-summary hidden"></div> <div id="schema-summary" class="schema-summary hidden"></div>
<textarea <div id="structured-editor" class="structured hidden">
id="editor-textarea" <div class="structured-toolbar">
class="code-area" <select id="entry-select" class="text-input"></select>
spellcheck="false" <button id="add-entry" class="ghost">Add entry</button>
placeholder="Open a file to start editing." <button id="delete-entry" class="ghost">Delete entry</button>
></textarea> </div>
<div id="structured-form" class="structured-form"></div>
</div>
<div id="raw-editor" class="raw-editor">
<textarea
id="editor-textarea"
class="code-area"
spellcheck="false"
placeholder="Open a file to start editing."
></textarea>
</div>
<div id="status-message" class="status-message"></div> <div id="status-message" class="status-message"></div>
</section> </section>
</main> </main>

View File

@ -72,6 +72,13 @@ button:hover {
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12); box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);
} }
button:disabled {
opacity: 0.5;
cursor: not-allowed;
transform: none;
box-shadow: none;
}
button.ghost { button.ghost {
background: transparent; background: transparent;
} }
@ -86,6 +93,15 @@ input.filter-input {
font-size: 13px; font-size: 13px;
} }
select.text-input {
width: 100%;
border: 1px solid rgba(18, 33, 38, 0.16);
border-radius: 12px;
padding: 8px 10px;
background: rgba(255, 255, 255, 0.8);
font-size: 13px;
}
.app-shell { .app-shell {
position: relative; position: relative;
display: grid; display: grid;
@ -271,6 +287,41 @@ input.filter-input {
gap: 12px; gap: 12px;
} }
.guide {
display: flex;
flex-direction: column;
gap: 10px;
}
.guide-title {
font-family: "KenneyFuture", "AlibabaPuHuiTi", serif;
font-size: 16px;
}
.guide-desc {
color: var(--ink-2);
font-size: 13px;
}
.guide-fields {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.guide-field {
padding: 3px 8px;
border-radius: 999px;
background: rgba(245, 158, 11, 0.16);
font-size: 12px;
}
.guide-actions {
display: flex;
gap: 10px;
flex-wrap: wrap;
}
.control-row { .control-row {
display: flex; display: flex;
gap: 12px; gap: 12px;
@ -297,6 +348,24 @@ input.filter-input {
gap: 10px; gap: 10px;
} }
.view-toggle {
display: flex;
gap: 6px;
padding: 4px;
border-radius: 12px;
background: rgba(24, 33, 38, 0.08);
}
.view-toggle button {
padding: 6px 10px;
border-radius: 8px;
font-size: 12px;
}
.view-toggle button.active {
background: rgba(245, 158, 11, 0.86);
}
.code-area { .code-area {
width: 100%; width: 100%;
min-height: 420px; min-height: 420px;
@ -312,6 +381,83 @@ input.filter-input {
outline: none; outline: none;
} }
.structured {
display: flex;
flex-direction: column;
gap: 14px;
}
.structured-toolbar {
display: flex;
gap: 10px;
flex-wrap: wrap;
align-items: center;
}
.structured-form {
display: flex;
flex-direction: column;
gap: 16px;
}
.form-section {
border: 1px solid rgba(18, 33, 38, 0.12);
border-radius: 14px;
padding: 12px;
background: rgba(255, 255, 255, 0.7);
}
.form-section h3 {
margin: 0 0 8px;
font-size: 14px;
font-family: "KenneyFuture", "AlibabaPuHuiTi", serif;
}
.form-row {
display: grid;
grid-template-columns: 160px 1fr;
gap: 10px;
align-items: center;
margin-bottom: 8px;
}
.form-row:last-child {
margin-bottom: 0;
}
.form-label {
font-size: 12px;
color: var(--ink-2);
}
.form-input {
border: 1px solid rgba(18, 33, 38, 0.16);
border-radius: 10px;
padding: 6px 8px;
background: rgba(255, 255, 255, 0.9);
font-size: 12px;
}
.form-input[type="checkbox"] {
width: auto;
}
.array-row {
display: flex;
gap: 8px;
align-items: center;
margin-bottom: 6px;
}
.array-row input {
flex: 1;
}
.array-row button {
padding: 4px 8px;
font-size: 11px;
}
.schema-summary { .schema-summary {
display: flex; display: flex;
gap: 10px; gap: 10px;