Touhou Maid: Affection
Bring affectionate interactions, bond progression, and lasting companionship to Touhou Little Maid.
Overview
Touhou Maid: Affection is an affection and bond companion expansion for Touhou Little Maid (TLM).
Express your love through affectionate interactions, raise favorability by kissing, and unlock an exclusive Bond System as your relationship deepens. Bond abilities include relaxing Lap Pillows, personalized Morning Kisses, Emergency Rescues in fatal situations, and thoughtful Random Gifts. The mod also integrates with TLM's native AI chat and TTS speech system, alongside full datapack support for custom dialogue and voice lines.
Core Mechanics
Kiss Interaction
- Keybind Actions: Aim your crosshair at your maid and press the kiss key. When carrying your maid using a saddle, use the dedicated carried kiss key to interact directly.
- Visual & Audio Feedback: Each kiss brings heart particles, playful sound effects, and a brief close-up camera zoom.
- Favorability Progression: Kissing steadily increases maid favorability. Higher favorability levels grant shorter kiss cooldowns.
- Maid's Prayer: Rapid consecutive kisses reward both player and maid with the "Maid's Prayer" regeneration buff.
Bond System
When a maid reaches Favorability Level 3 (Max), the Bond Tab unlocks at the top of her inventory GUI. Players can spend P-Points (PowerPoint items in inventory) to unlock unique bond abilities:
| Bond Ability | Description |
|---|---|
| Lap Pillow | Rest together sitting or lying down. Supports adjustable offsets, camera lock, and YSM custom animations. |
| Morning Kiss | Scheduled morning greeting upon waking. The maid approaches with a morning kiss, custom lines, and voice playback. |
| Emergency Rescue | When you suffer fatal damage, bonded maids rush in to shield you and restore emergency health with unique rescue lines. |
| Random Gift | Bonded maids gather and present thoughtful gifts over time, with progress tracked directly in the GUI. |
AI Morning Kiss & Bilingual Voice System
Morning Kiss can leverage Touhou Little Maid's configured AI chat and TTS providers to pre-generate morning greetings in the background.
- Bilingual Combinations: Display text and spoken voice languages are completely decoupled, supporting combinations like English text with Japanese voice.
- Auto Matching: Defaults to
auto, where text matches your Minecraft language and voice inherits the maid's TLM AI voice settings. - Unified Management: Directly uses your existing TLM AI providers and API keys without redundant setup.
How to Use
Keybindings
Configure the following keys under Options → Controls → Key Binds:
- Targeted Kiss: Kiss the maid in your crosshair.
- Carried Maid Kiss: Kiss while carrying a maid with a saddle.
- Lap Pillow: Trigger the lap pillow rest pose.
- Lock View Angle: Lock the camera angle during a lap pillow session.
In-Game Settings Panel
Click the gear beside Bond Abilities, inside the panel header, to open settings:
- Status: Monitoring is grouped by Random Gift and AI Morning Kiss. Select a maid in the gift section; AI switches, languages, and cache statistics form subsections.
- Features: Toggle bond abilities, adjust AI cache policy, and choose the gift pool, preparation interval, and queue limit.
- Voice: Switch display/voice languages, edit the Morning Kiss prompt template live, or jump directly to TLM's AI provider settings.
- Volume: Adjust volume sliders in real-time for kiss sounds, morning kiss voices, rescue lines, and voice previews.
If an upgraded save produces a narrow selection of gifts, turn off Features → Gift preparation → Tag-only pool to select the broad pool. Existing configurations retain their saved choice. The Status tab displays server snapshots; use Refresh to update them. Delivery also depends on distance and cooldown after a gift is prepared. Hover and scroll over the contents row to inspect longer item lists.
Admin Commands
All data and settings follow server-authoritative validation. Operators (Permission Level 2) can manage features via /tma:
/tma morning_kiss status # View morning kiss status and AI cache stats
/tma morning_kiss clear_ai_cache [all|maid...] # Clear generated dialogue and voice cache
/tma rescue on|off|toggle # Enable or disable emergency rescue server-wide
/tma bond prune [days] # Clean up bond data for maids inactive over N days (default: 90)
Custom Datapack Voices
Expand dialogue pools and .ogg voice lines via Datapacks:
- Datapack paths:
data/touhou_maid_affection/morning_kiss/andemergency_rescue/ - Ready-to-use sample pack: examples/TMA-Custom-Voice-Pack
- Detailed tutorial: 早安吻相关配置说明.md
- Modpack author guide (Chinese): PACK_AUTHORING.md — gift allowlists/blacklists, pack formats, config timing, voices, and reload limits.
Important Notes
- Server Authority: Favorability growth, cooldowns, line-of-sight checks, and ability activation are fully validated by the server. Singleplayer and multiplayer servers share identical behavior.
- Volume Attenuation: In-game volume sliders control client-side attenuation (
0.0for mute,1.0for full volume). Increase master/system volume for higher output. - Permissions: On dedicated servers, global toggles, language rules, and prompt templates are operator-only. Non-op players view the settings panel in read-only mode.
- Data Persistence: Maid bond data is safely preserved across maid deaths, chunk unloads, or dimensional transfers. Use
/tma bond pruneto purge abandoned data.
Miscellaneous & Compatibility
Mod Integrations
- Touhou Little Maid (TLM): Required core dependency (built against
1.5.3-forge+mc1.20.1). - MaidFileManager: Seamlessly carries bond levels, unlocked abilities, and voice settings across
.maidfile migrations. - Epic Fight: Compatible with
[史诗战斗:车万女仆]bridge &Epic Fight - Avalon; bond tab automatically avoids GUI tab collisions. - Yes Steve Model (YSM): Supports custom animation sync during lap pillows.
- Tweakerge / Tweakeroo: Fully compatible with Free Camera mode without causing player pose conflicts.
Installation
- Install Minecraft
1.20.1and Forge47.4.x. - Install Touhou Little Maid for Forge 1.20.1 (
1.5.0+). - Place
touhou-maid-affection-1.7.5.2.jarinto your.minecraft/modsdirectory. - Launch the game.
Developer & Architecture Docs
- PROJECT_ARCHITECTURE.md: Architecture overview and module boundaries.
- CHANGELOG.md: Complete version history.
- 早安吻相关配置说明.md: Datapack dialogue, voice, and AI guide.
- TESTING.md: Testing suite and regression workflows.
License
This project is open-source under the MIT License.
All Versions
+ Add Version| Name | Game version | Platforms | Published | Downloads | Actions |
|---|---|---|---|---|---|
| 1d ago | 1 | ||||
|
R
v1.7.5.2
|
1d ago | 1 | |||
| 1d ago | 1 | ||||
|
R
v1.7.5.1
|
1d ago | 1 | |||
| 1d ago | 1 | ||||
|
R
v1.7.5.0
|
1d ago | 1 | |||
|
R
v1.7.2.2
|
1d ago | 1 | |||
| 1d ago | 1 | ||||
|
R
v1.7.2.1
|
1d ago | 1 | |||
| 1d ago | 1 | ||||
|
R
v1.7.2
|
1d ago | 1 | |||
| 1d ago | 1 | ||||
|
R
v1.7.1.4
|
1d ago | 1 | |||
| 1d ago | 1 | ||||
|
R
v1.7.1.3
|
1d ago | 1 | |||
| 1d ago | 1 | ||||
|
R
v1.7.1.2
|
1d ago | 1 | |||
|
R
v1.7.1.1
|
1d ago | 1 | |||
| 1d ago | 1 | ||||
|
R
v1.6.1
|
1d ago | 1 | |||
| 1d ago | 1 | ||||
|
R
v1.6.0
|
1d ago | 1 | |||
| 1d ago | 1 | ||||
|
R
v1.5.0
|
1d ago | 1 | |||
|
R
v1.4.0
|
1d ago | 1 | |||
|
R
v1.3.1
|
1d ago | 1 | |||
|
R
v1.3.0
|
1d ago | 1 | |||
| 1d ago | 1 | ||||
| 1d ago | 1 |
### Fixed
- 随机礼物的新配置默认恢复广泛物品池。旧配置的
curatedPoolOnly选择保留,可在「设置 → 功能 → 礼物准备」中关闭「仅标签物品池」,恢复原版与模组物品抽样。黑名单继续优先生效。 - 模组物品每批备礼重新抽样,避免世界种子固定后长期只从同一小批物品中选择。
- 礼物详情读取保持只读;查询膝枕等待条件时也保持玩家存档不变。
### Added
- 全局设置「状态」tab 顶部新增女仆下拉框与固定礼物详情区:查看选中女仆的积攒份数、已准备物品、下一份准备时间、上次送礼记录和等待条件。刷新保留女仆选择,多个网络分页中的女仆均可选择;物品列表较长时可在悬浮提示内滚动。设置页保持原有四个 tab。
- 「功能」tab 新增礼物池模式、模组物品开关、准备间隔与队列上限,沿用管理员权限校验。
- 礼物在备好时确定并保存物品,送出时按队列取用。旧存档积攒份数保留,降低队列上限保留已积攒礼物,已准备物品支持随
.maid导出导入;上次送礼记录保留在原存档。 - 新增整合包作者教程 [PACK_AUTHORING.md](PACK_AUTHORING.md),说明如何通过数据包定制现有内容,并提供可直接参考的示例与排障指引。
### Changed
- 设置入口移到「羁绊能力」标题右侧,以边框内的齿轮图标显示;渲染、提示和点击范围保持一致,避开 TLM 顶部页签。
- 状态页按「随机礼物」「AI 早安吻」两个同级功能分区;女仆选择、开关、语种、缓存与具体数据采用下级缩进和留白。
- 羁绊面板与二级页的较长文字按可用空间适配缩放,按钮文字限制在按钮宽度内,减少溢出与重叠。
### Notes
- 界面继续使用 Minecraft 默认字体,保留原有面板背景与整体风格。
- 准星亲吻与抱起亲吻继续使用自定义按键,Shift+右键仍保留 TLM 原生交互。
### Fixed
- 随机礼物的新配置默认恢复广泛物品池。旧配置的
curatedPoolOnly选择保留,可在「设置 → 功能 → 礼物准备」中关闭「仅标签物品池」,恢复原版与模组物品抽样。黑名单继续优先生效。 - 模组物品每批备礼重新抽样,避免世界种子固定后长期只从同一小批物品中选择。
- 礼物详情读取保持只读;查询膝枕等待条件时也保持玩家存档不变。
### Added
- 全局设置「状态」tab 顶部新增女仆下拉框与固定礼物详情区:查看选中女仆的积攒份数、已准备物品、下一份准备时间、上次送礼记录和等待条件。刷新保留女仆选择,多个网络分页中的女仆均可选择;物品列表较长时可在悬浮提示内滚动。设置页保持原有四个 tab。
- 「功能」tab 新增礼物池模式、模组物品开关、准备间隔与队列上限,沿用管理员权限校验。
- 礼物在备好时确定并保存物品,送出时按队列取用。旧存档积攒份数保留,降低队列上限保留已积攒礼物,已准备物品支持随
.maid导出导入;上次送礼记录保留在原存档。 - 新增整合包作者教程
PACK_AUTHORING.md,说明礼物标签数据包、服务端配置、台词与语音资源包的制作方式、覆盖规则及当前定制边界。
### Changed
- 改善较窄界面中的文字适配缩放及按钮宽度约束,保留原有羁绊面板、二级页和设置背景。
- 设置入口移到「羁绊能力」标题右侧,使用边框内的 12px 齿轮图标,渲染、提示和点击共用同一矩形,避开 TLM 顶部页签。
- 状态页按「随机礼物」「AI 早安吻」两个同级功能分区;女仆选择、开关、语种、缓存与具体数据采用下级缩进和留白。
- 界面继续使用 Minecraft 默认字体,不内封或替换字体。
### Notes
- 准星亲吻与抱起亲吻继续使用自定义按键。本轮保持 Shift+右键的 TLM 原生交互。
### Fixed
- 修复与 Tweakeroo / Tweakerge 自由视角(“灵魂出窍”)在膝枕平躺态下同时使用时的客户端崩溃(issue #7,
LocalPlayer.canAutoJump对 nullinput的 NPE):Tweakeroo 的自由摄像机是一个复制了本地玩家 UUID、但input为 null 的假LocalPlayer。膝枕平躺桥接此前以 **UUID 相等** 判定目标玩家,因而也命中了这个摄像机实体,强行让它onGround()返回 true;当玩家开启原版“自动跳跃”时,canAutoJump()越过“在地面”判定继续走到hasEnoughImpulseToStartSprinting()→this.input.getMoveVector(),对 nullinput解引用即崩溃。改为 **实例相等**(player == Minecraft.getInstance().player),平躺桥接只作用于真正的本地玩家;Tweakeroo 摄像机、Replay Mod 摄像机等共享 UUID 的副本实体不再被误伤。 - 修复与史诗战斗(Epic Fight)等同样往女仆界面顶部加页签的模组同装时,羁绊页签与对方页签重叠、点击无响应(issue #8):附属页签的注册监听器执行顺序不确定,两个模组会各自把页签放到“内建页签之后的第一个槽位”而落到同一坐标。现在在界面
init完成后(此时所有模组的页签都已是实际控件)复查一次,**仅当** 羁绊页签确实与顶部同排的其他控件重叠时,才把它移到该排第一个空槽(25px 网格);单附属的常见布局保持不变。
### Fixed
- 修复与 Tweakeroo / Tweakerge 自由视角(“灵魂出窍”)在膝枕平躺态下同时使用时的客户端崩溃(issue #7,
LocalPlayer.canAutoJump对 nullinput的 NPE):Tweakeroo 的自由摄像机是一个复制了本地玩家 UUID、但input为 null 的假LocalPlayer。膝枕平躺桥接此前以 **UUID 相等** 判定目标玩家,因而也命中了这个摄像机实体,强行让它onGround()返回 true;当玩家开启原版“自动跳跃”时,canAutoJump()越过“在地面”判定继续走到hasEnoughImpulseToStartSprinting()→this.input.getMoveVector(),对 nullinput解引用即崩溃。改为 **实例相等**(player == Minecraft.getInstance().player),平躺桥接只作用于真正的本地玩家;Tweakeroo 摄像机、Replay Mod 摄像机等共享 UUID 的副本实体不再被误伤。 - 修复与史诗战斗(Epic Fight)等同样往女仆界面顶部加页签的模组同装时,羁绊页签与对方页签重叠、点击无响应(issue #8):附属页签的注册监听器执行顺序不确定,两个模组会各自把页签放到“内建页签之后的第一个槽位”而落到同一坐标。现在在界面
init完成后(此时所有模组的页签都已是实际控件)复查一次,**仅当** 羁绊页签确实与顶部同排的其他控件重叠时,才把它移到该排第一个空槽(25px 网格);单附属的常见布局保持不变。
### Added
- 设置面板「功能」tab 末尾新增「缓存策略」区(
bond.settings.section.cache_policy):每池目标条数/扫描间隔两个整数(复用紧凑数值控件BondNumberField)与消费即用胶囊开关,全部走既有服务端权威通道(OP2 +[TMA Settings]审计 + 状态回推 + pending 状态点,不新造视觉)。为此新增 4 个白名单键——morning_kiss.immediate_fallback_enabled(映射ModConfig.BOND_MORNING_KISS_AI_DIALOGUE_IMMEDIATE_FALLBACK_ENABLED)、morning_kiss.cache_target_per_pool、morning_kiss.cache_scan_interval_ticks、morning_kiss.cache_consume_on_use(映射ModConfig.BOND_MORNING_KISS_AI_DIALOGUE_CACHE_CONSUME_ON_USE),白名单从 **10 项扩到 14 项**(9 开关 + 2 语种 + 1 文本 + 2 整数)。TmaSettingsKeys新增取值类型Type.INT:只接受纯数字,逐键按ModConfigdefineInRange的上下界校验(每池目标条数 1..8、扫描间隔 20..72000 tick),非数字/越界一律拒绝,并沿用既有的整包拒绝语义。morning_kiss.cache_consume_on_use已从「功能」tab 的通用布尔列表里排除(TOGGLE_KEYS过滤),「消费即用」在整个面板里**只出现一次**(就在缓存策略区内)。 - 新增紧凑数值输入控件
BondNumberField(单行原版EditBox,关闭原版边框、复用面板字段式配色;只允许数字、失焦提交、提交前按范围夹取、右侧显示单位如1200t)。范围跨度 20..72000 用滑块精度不可用,因此不做滑块。 - 新增中英 lang 键:
bond.settings.section.cache_policy、bond.settings.key.morning_kiss.cache_target_per_pool/bond.settings.sub.morning_kiss.cache_target_per_pool、bond.settings.key.morning_kiss.cache_scan_interval_ticks/bond.settings.sub.morning_kiss.cache_scan_interval_ticks、bond.settings.status.pool.general(通用 / Any)、bond.settings.key.morning_kiss.immediate_fallback_enabled与bond.settings.sub.morning_kiss.immediate_fallback_enabled、bond.settings.key.morning_kiss.cache_consume_on_use与bond.settings.sub.morning_kiss.cache_consume_on_use、bond.settings.number.tip,以及状态页恢复只读后重新引用的bond.settings.status.language.auto.display/bond.settings.status.language.auto.voice。 - 新增游戏内「全局设置」面板「语音」tab 的「台词提示词」多行编辑框:直接编辑早安吻 AI 台词模板(占位符
{maid}女仆名 /{player}玩家名 /{pool}时段 /{time}允许时段),带占位符图例与「恢复默认」按钮。这是服务端权威的新设置类型TEXT(逻辑键morning_kiss.text_prompt,上限 1024 字符,保存空值写回内置默认模板),沿用现有 OP2 + 审计日志的写入路径。字数计数画在编辑框**内部右下角**(次要文字色),占位符图例独占编辑框下方一整行、占满内容区整宽(完整显示、不再截断),「恢复默认」按钮移到编辑框上方标签行右对齐,「恢复默认」改用面板通用的文字按钮渲染(与「打开」「清空」同一个drawTextButton模板,无权限时置灰)。编辑框本身支持**框内滚动**:新增子类BondPromptBox把滚动步长(scrollRate()= 9px)与滚动上限(9 × (总行数 − 可见行数))都吸附到文本行网格,编辑框高度取9 × 行数 + 4(49px = 5 行 + 内边距),因此文字永远按整行显示、不会从行中间被切断;鼠标在框内滚轮只滚框内文本、不再带动面板,光标移出可视区时由原版光标监听自动滚动保持可见。 - 新增设置面板「状态」tab:移植
/tma morning_kiss status与/tma morning_kiss cache的信息,**全部只读**——开关(早安吻 / AI 台词 / AI 语音 / 立即兜底)、语种(文本语种/配音语种,未配置显示auto(跟随游戏语言)/auto(跟随女仆 AI 设置))、缓存策略(每池目标 / 扫描间隔 / 消费即用)都用纯文本行渲染(没有胶囊开关 / 下拉框 / 数值框 / pending 状态点),缓存统计(条目语音/纯文本、女仆数 / 在途 / 版本号)与按女仆列表(名字 + 各时段池条目数 + 总条目/目标 + 行内「清空」)同样只读。配套新增只读状态通道TmaAiStatusRequestPayload/TmaAiStatusPayload与清缓存操作包TmaAiCacheClearPayload:状态只回该玩家名下的女仆,清缓存需 OP2 + 审计日志并复用/tma morning_kiss clear_ai_cache完全相同的服务方法。 - 新增设置面板「语音」tab 的「打开车万女仆的 AI 设置」按钮:跳转 TLM 原生
AIChatSettingsHubScreen(parent 传本面板,关闭后回到这里),是全局唯一的 AI 入口;TMA 不自建站点表单。 - 新增游戏内「全局设置」面板:在羁绊页顶部右侧(原 TMA AI Hub 按钮的槽位)新增「设置」入口,面板与当前女仆无关,分四个 tab——状态(只读)、功能开关(早安吻 / 女仆主动早安吻 / AI 台词 / AI 语音 / 立即兜底 / 残血救护 / 随机礼物 / 少女祈祷 Buff,末尾是「缓存策略」区:每池目标条数 / 扫描间隔 / 消费即用)、语音(文本语种 / 配音语种下拉框 + 台词提示词 + AI 站点入口)、音量(亲吻音效 / 早安吻语音 / 残血救护 / 语音试听,0.0–1.0 步进 0.05)。无需再手改 toml。
- 新增服务端权威设置同步通道:
TmaSettingsRequestPayload(C2S,空列表表示只读状态)与TmaSettingsStatePayload(S2C,回推全部白名单键的当前值与canEdit)。面板里的开关与语种由服务端校验、应用并回推,单人存档与多人服务器行为一致。 - 新增自绘滑块组件
BondSlider,供设置面板的音量项使用。
### Fixed
- 修复设置面板下拉弹层被下层控件文字穿透(「恢复默认」浮在展开的列表之上):根因是
GuiGraphics把填充与文字分入不同 render type 缓冲、同帧按创建顺序刷出(填充先、文字后),于是先画的文字会盖住后画的填充。修法:画弹层前graphics.flush()先把此前的填充+文字落地、弹层底色改为不透明,并在弹层矩形**确实覆盖**某控件时跳过绘制该控件(BondDropdown#overlayCovers判定,未覆盖时控件照常显示)。 - 修复「状态」tab「按女仆」行的池计数渲染成原始 key
bond.settings.status.pool.general:lang 文件缺GENERAL池的键,现已补齐中英两语言;并新增回归测试TmaSettingsLangKeysTest,逐一遍历DialoguePool的全部取值断言中英 lang 都存在bond.settings.status.pool.<小写枚举名>,同时断言每个可编辑键的bond.settings.key.*/bond.settings.sub.*与状态页相关键存在(缺键时直接测试失败,而不是等到界面上露出原始 key)。 - 修复「状态」tab 行内文本压到「清空」按钮下面的问题:只读值行与女仆行一律在「控件左边界 − 间距」处用
clip(...)截断并补省略号(女仆行拆成名字列 + 右对齐的计数列),长值(24 (18 / 6)、3 / 1 / 42、早 9 · 晚 9 · 通用 0 · 18/12)不再与控件重叠。 - 修复「语音」tab 占位符图例被截断(原可用宽度仅 218px,中英文案分别需 309px / 348px):图例改为独占一整行、使用内容区整宽 270px,文案缩短为
{maid} 女仆 · {player} 玩家 · {pool} 时段 · {time} 允许时段(260px)与{maid} maid · {player} player · {pool} pool · {time} range(261px),中英双语都完整显示;「恢复默认」按钮移到上方标签行右对齐。 - 修复设置面板语种下拉框最后一项被裁剪的问题:展开的弹层不再受面板内容区 scissor 约束,改为夹在屏幕范围内——向下会溢出屏幕底部时翻到表头之上渲染,命中测试/高亮/点击与实际渲染位置保持一致,所有候选条目可达。
.maid迁移不再携带运行态/调度键:导出(BondData.exportMaidData)剔除BondKeys.RUNTIME_KEYS——礼物计时(RandomGiftLastWallClock/RandomGiftLastDelivery/RandomGiftLastIntervalMinutes)、早安吻窗口标记(MorningKissScheduledWindow/MorningKissScheduledAttemptTick/MorningKissLastAutoAttemptGameTime/MorningKissLastSuccessWindow/MorningKissLastFailedWindow)与本地记账LastSeen——导入时再防御性剔一遍。此前这些会话/世界相关的绝对时间会随.maid迁到新女仆/新存档,导致刚导入就被判定「今天已亲过」或礼物计时错乱。待发礼物队列RandomGiftQueue是耐久状态,仍然随迁;extras对外形状与整体替换语义不变。- 空字符串不再落盘/导出:所有「getter 缺省值本就是空串」的字符串 setter(声音包、YSM 档案、救护动作、膝枕动作、早安吻计划/窗口标记、玩家粒度早安吻选择、早安吻与救护语音选择里的空字段)改为空串时移除键而非写入空值,避免无意义键堆积进存档与
.maid。
### Changed
- 设置面板改为**单张整页底图 + 控件叠加**:外框、表头分隔线、侧栏分隔线、footer 分隔线与左下角写实玫瑰全部烘进
textures/gui/settings_panel.png(1020×690 RGBA,已烘入 0.90 不透明度),面板背景改为一次 blit(按面板 340×230 逻辑尺寸在 GUI scale 3 下 1:1,不缩放、不额外着色),代码不再自绘面板底色 / 边框 / 分隔线;屏幕压暗层、tab 高亮、所有控件与配色 token、footer 按钮保持不变。为对齐底图,BondGuiTokens.MODAL_TITLE_HEIGHT24→20(表头分隔线落在面板高的 20/230)、NAV_WIDTH46→50(侧栏分隔线落在面板宽的 50/340),因此内容可视高 168→172px、内容区宽 274→270px(占位符图例 260px / 261px 仍不截断),各 tab 的maxScroll随可视高自动收敛。 - 「状态」tab「按女仆」列表对同名女仆去歧义:名字列新增纯逻辑助手
bond/settings/TmaMaidLabels,输入该玩家的女仆(uuid, 名字)列表输出显示标签——名字唯一时原样显示(不加噪声),同名出现 ≥2 次时这些行追加#+ UUID 前 4 位十六进制(小写),如精灵酒狐 #a1b2;名字为空/空白回退为可本地化的占位名(新增 lang 键bond.settings.status.maid.unknown,zh未知女仆/ enUnknown maid,由TmaSettingsScreen传入Component.translatable(...).getString()),并追加短 ID,如未知女仆 #a1b2。名字列仍按原有clip(...)规则截断到可用宽度,不挤占行内「清空」按钮。配套单测TmaMaidLabelsTest,TmaSettingsLangKeysTest一并守护该新键。 - 设置面板间距放宽(用户反馈「配置页间距太挤」):
SECTION_HEADER_HEIGHT12→15、ROW_GAP3→6、LANGUAGE_ROW_HEIGHT17→20、PROMPT_BOX_HEIGHT36→49(= 9 × 5 行 + 内边距)、PROMPT_ROW_HEIGHT12→14、STATUS_KV_HEIGHT12→13、STATUS_ROW_GAP2→6。上一轮的「语音 tab 打开即免滚动」要求随之作废:功能(294px)/ 语音(208px)/ 状态三个 tab 超出内容可视高 172px(230 模态高 − 20 标题 − 8 内容上留白 − 30 footer)时一律走面板内部滚动。占位符图例仍独占一整行、占满内容区整宽 270px(340 − 2 − 50 − 8 − 2 − 8,横向槽位不受间距常量影响),中英文案按原版字宽表复算为 260px / 261px,均 ≤ 270px、不截断。 - 设置面板 tab 顺序改为「状态 / 功能 / 语音 / 音量」:「状态」提到第一位并作为打开面板的默认选中项(
activeTab默认 0、tabLabel、导航命中测试与文档同步),状态 tab 请求 AI 状态改在init()里发起;「缓存策略」三个控件从状态页搬到「功能」tab 末尾,状态页对应的三行改回只读纯文本。 - 设置面板尺寸 300×188 → 340×230,侧栏 tab 从 3 个(功能 / 语音 / 音量)扩到 4 个(新增「状态」);内容超出可视区走内部滚动。配色 token、服务端权威语义与既有状态机不变。
- 羁绊页「设置」按钮从左上空位移到面板右上角(原 TMA AI Hub 按钮的槽位):尺寸 50×12,位置
x = panelX + panelWidth - 50 - 2、y = panelY - 12 - 3(即原 AI 按钮的 Y),文案仍是「设置」、居中绘制;命中测试与 tooltip 同步更新,左上空位不再有按钮。 - 音量上限从
4.0收至1.0:四项音量配置(cooldown.kissSoundVolume、morningKissBehavior.voiceVolume、emergencyRescueBehavior.volume、voicePreview.volume)与设置面板滑块现在**只做衰减**——0.0静音、1.0保持原有响度,不再放大。需要更大音量请使用 Minecraft 或系统音量。旧配置里大于1.0的值会被配置系统在加载时纠正为1.0(ForgedefineInRange行为)。 - 音量四项(
cooldown.kissSoundVolume、morningKissBehavior.voiceVolume、emergencyRescueBehavior.volume、voicePreview.volume)是纯客户端配置,面板里拖动即写入本机配置并立即生效,不走网络。 - 语音试听冷却从 5 秒降到 0.5 秒(100 → 10 tick);被限流时给客户端一行 action bar 提示「试听过快,请稍候」,不再静默丢弃;非数据包(本地)试听请求不再占用限流额度。
- 早安吻 AI 台词缓存改为按语种读取:
pollRandom/peekRandom与预热满度判定(countMatching、addIfBelowTarget)都按当前解析出的显示/配音语种过滤,改了显示或配音语种后会自动按新语种重新预热,旧语种条目保留但不再被选中,也不再阻塞重新预热(仍可手动clear_ai_cache)。目标语种为空(auto)时不过滤,保持旧行为。 /tma morning_kiss status的语种行改为两行说人话:文本语种:<值>(未配置显示auto)、配音语种:<值>(未配置显示auto),删掉 AI 覆盖与生效优先级两行。- 早安吻语种语义统一为两个:**文本语种**(
displayLanguage,内置数据包台词 + AI 生成台词用哪种语言显示;auto= 跟随游戏语言,内置台词按客户端语言渲染、未标记数据包台词通配、AI 台词沿用女仆的 TLM 聊天语言)与**配音语种**(voiceLanguage,数据包语音 + AI 合成语音用哪种语言;auto= 跟随女仆的 TLM AI 语言设置,数据包语音不按语言过滤、AI 合成沿用女仆的 TLM TTS 语言)。具体 locale(zh_cn/ja_jp…)固定该语言。旧关键字tlm/inherit/default继续接受,等价于auto,但面板与状态页一律显示归一化后的auto。 - 全局羁绊 UI 配色统一为「暖木底 + 玫瑰(交互面 / 装饰)+ 金(仅高亮文字)」:
BondGuiTokens换用新调色板(保留原常量名,新增开关 / 字段 / 滑块 / 导航等语义色常量),所有调用点自动跟随。设置面板同步按设计稿收口:300×188 模态框、46px 侧栏三 tab、胶囊开关、78×20 字段式下拉、88×13 滑块(数值金色居中)、分区作用域标签、行内请求状态点与「完成 / 重载」footer。不影响功能与其它二级页布局尺寸(仍为 172×150)。 - 设置面板从「女仆 GUI 内嵌二级页」改为**独立 Screen**(
TmaSettingsScreen,删除SettingsSecondaryPage):在羁绊页「设置」按钮处用Minecraft#setScreen打开,自带全屏压暗背景,关闭(footer「完成」/ESC/点击压暗区)返回来源的女仆 GUI。面板尺寸/配色/控件与交互 token 不变,服务端权威语义、payload、状态机与音量直写零变更;除设置页外的其它二级页与BondSecondaryPage接口不受影响。 - 设置面板语种从 4 项砍到 2 项:白名单变为 **7 开关 + 2 语种 = 9 项**,面板只保留「文本语种」(
display_language)与「配音语种」(voice_language),两者统管内置数据包与 AI 两条链路。 - 羁绊数据改为**按女仆嵌套存储**:女仆粒度数据从「根上扁平键
<base>_<女仆UUID>」改为touhou_maid_affection.bond.maids.<女仆UUID>.<base>子树,玩家粒度键(早安吻选择)仍在根上;键名常量集中到BondKeys。首次读取旧存档时自动执行**一次性迁移**(根上新增SchemaVersion,先写后删、幂等、无法解析的键原样保留),旧存档无损升级,无需手动操作。反查(按能力找女仆、按模型 ID 找女仆、按救护 provider 找女仆、批量重置能力)改为遍历女仆子树,不再全键扫描。 - 新增
/tma bond prune [days](默认 90 天,权限等级 2):清理执行者羁绊数据中LastSeen早于阈值的女仆子树(缺失LastSeen的历史数据视为过旧;days <= 0只统计不删除),并回显删除/保留数量。LastSeen在同步女仆档案时刷新;**不**在女仆死亡 / 卸载 / 换主人时自动删除数据(TLM 灵魂玩偶、椅子等会临时移除实体,自动删会丢数据),只能靠该命令显式清理。 .maid迁移(MaidFileManager SPI)的附加数据对外格式**不变**:仍是「base 名 → 值」的 compound(即女仆子树本身),旧导出文件仍可导入,导入后刷新LastSeen。- 删除若干零调用者死代码:
BondData/BondManager.getUnlockedMaidModelIdsForAbility、BondData/BondManager.findMaidProfileByRescueProviderId、MorningKissGeneratedDialogueService.hasCachedLine(两个重载)、MorningKissGeneratedDialogueCache.isEmpty,以及已被BondKeys取代的compat/maidfm/MaidDataKeyCodec。
### Removed
- 删除独立玫瑰贴图
textures/gui/rose_vine.png及其绘制代码:TmaSettingsScreen#renderVine、ROSE_VINE资源常量、NAV_VINE_WIDTH/NAV_VINE_HEIGHT/NAV_VINE_TEXTURE_WIDTH/NAV_VINE_TEXTURE_HEIGHT尺寸常量与相关 javadoc 一并移除(全仓grep -ri rose_vine零命中),玫瑰改由整页底图承载。 - 删除 AI 专用语种覆盖层:
ModConfig的morningKissBehavior.aiDialogueLanguage/aiDialogueVoiceLanguage两项(含 toml 键aiDialogueLanguage/aiDialogueVoiceLanguage)与解析链里的优先级逻辑(MorningKissLanguageSettings#liveChatLanguage的「AI 显式 > 全局显式 > 旧语义」判定、resolveGeneratedTextLanguage/resolveGeneratedVoiceTextLanguage的 AI 专用入参与配音继承显示语种的规则)。若此前用 AI 覆盖让 AI 台词/配音与内置台词/语音用了不同语言,现在统一由**文本语种**与**配音语种**控制——把原来的值填到这两项即可(例:原来aiDialogueLanguage=zh_cn+aiDialogueVoiceLanguage=ja_jp,现在填displayLanguage=zh_cn+voiceLanguage=ja_jp)。旧 toml 里残留的这两个键不再被定义,配置系统直接忽略,无需手动清理。 - 删除 TMA 自研的 AI 站点适配层:
com.github.touhoumaidaffection.ai.mimo整包(TmaMimoAdapterExtensionprovider 注册、MimoLLMSite/MimoTTSSite站点类型与 serializer、MimoTTSFormLayout站点表单、MimoLLMClient/MimoTTSClient/MimoHttp/MimoProtocol/MimoCodecHelper协议实现、BoundedHttpClient/BoundedHttpResponse有界响应工具)及其单元测试(MimoProtocolTest7 例、BoundedHttpResponseTest3 例)。 - 删除
ModConfig的tmaMimoAdapter配置段:enabled/apiKey/chatUrl/ttsUrl/maxCompletionTokens/ttsVoicePrompt/ttsAudioFormat七项。旧 toml 里残留的[tmaMimoAdapter]键不再被定义,配置系统会直接忽略,**无需手动清理,也没有迁移代码**。 - 删除中英文文案中的 MiMo 站点名与入口文案(各 6 个键)。
- 羁绊页顶部不再有任何 AI 入口:原右上角「TMA AI Hub」按钮整条删除(含字段、渲染、命中测试、tooltip、
BondPrimaryPageHost#openMimoAdapterSettings/isMimoAdapterAvailable及其实现与 TLM AI hub 跳转)。AI 相关配置今后由 TMA 自己的设置面板承担。 - 早安吻的 LLM/TTS 本就完全走
maid.getAiChatManager()里 TLM 自己的站点,删除适配层不影响任何功能;TMA 也不再提供全局音色提示词(音色由 TLM 站点配置决定,GPT-SoVITS 站点另有其原生 prompt 字段)。 - 旧站点条目处理:TLM 读取
config/touhou_little_maid/sites/{llm,tts}.json时,api_type找不到对应 serializer 的条目只记一条 error 日志并跳过(**不抛异常、不崩溃**),随后 TLM 保存站点时把该条目从文件里清掉。**实测**:删掉适配层后启动服务器,日志出现Unknown LLM site type: tma_mimo_chat与Unknown TTS site type: tma_mimo_tts,服务器正常完成启动,且tma_mimo_chat/tma_mimo_tts两个条目已从两个 json 中消失——玩家无需手动删旧站点条目。
### Notes
- MaidFileManager **1.4.0 已正式发布**(GitHub Releases,fabric/forge/neoforge 四产物):官方 SPI 与我们所 vendored 的版本**逐字节一致**,集成无需改动;官方把
.maid格式版本从 5 升到 6,但迁移只作用于女仆实体 NBT,extras(我们的羁绊数据)不受影响,旧 v5 导出文件仍可导入。两实例已把自建 1.4.0 换成官方产物。 - 权限:开关、语种与缓存策略属于服务端权威设置,**只有 OP(权限等级 2)可以修改**;普通玩家能看、不能改,界面底部会显示「只读」提示,按钮 tooltip 提示需要管理员权限。每次成功修改都会在服务端日志打印
[TMA Settings] player=... key=... old=... new=...;越权或非法请求打印 WARN。 - 非法请求(未知 key、非法布尔、非法语种、超长值)整包拒绝,不会部分生效。
- 语种下拉框只提供
auto与常见 locale,当前值若不在列表里会动态补上;旧关键字tlm/inherit/default仍是合法值(服务端原样存储、语义等价auto),但面板与状态页显示归一化后的auto,不再作为候选条目出现。
## [1.7.4.0] - 2026-09-24
### Added
- 新增
morningKissBehavior.displayLanguage(默认auto)与morningKissBehavior.voiceLanguage(默认auto),把原先只存在于 AI 链路的「显示语种 / 配音语种」解耦提升为全局可配,并让数据包链路同样支持按语种选择台词与语音。 - 数据包
data/touhou_maid_affection/morning_kiss/profile.json纯增量扩展:dialogue.<pool>元素接受{"text": "...", "language": "zh_cn"},voice_files元素接受{"file": "x.ogg", "language": "ja_jp", "text": "可选字幕", "text_language": "zh_cn"};旧的纯字符串写法保留并视为「未标记」通配,向后兼容。 voice_files[].text/text_language支持语音与字幕配对:选中该语音时直接显示配对字幕,不再随机抽台词;text_language与目标显示语种不一致时退回随机台词。
### Changed
- 语言解析优先级统一为「AI 专用显式 locale > 全局显式 locale > 旧语义(
tlm/inherit/auto)」;tlm/inherit/auto语义与翻译、缓存机制保持不变。旧配置项名字与默认值不变。 - 数据包台词与语音选择新增语种优先级:匹配目标语种的条目 → 未标记条目 → 全部条目。
dialogue_mode=append时内置台词按「语言 = 客户端语言」参与同一筛选。 auto(默认值)下行为与 1.7.3.0 完全一致:不启用任何语种筛选。
### Notes
- 内置台词仍是 i18n key,由客户端按自身语言渲染,服务端无法指定渲染语种;TLM 音包没有语言元数据,天然单语种,不参与筛选。
## [1.7.3.0] - 2026-07-24
### Added
- 新增
cooldown.kissSoundVolume配置项,可在0.0到4.0之间调整普通亲吻与早安吻复用亲吻音效的音量;0.0可静音,1.0保持旧版默认响度。 - 新增
morningKissBehavior.voiceVolume、emergencyRescueBehavior.volume与voicePreview.volume配置项,分别控制早安吻语音、残血救护语音/兜底音效和羁绊页语音试听音量。 - 新增
morningKissBehavior.aiDialogueVoiceLanguage,可将 AI 早安吻的显示文本与配音文本设为不同语言;例如aiDialogueLanguage=zh_cn、aiDialogueVoiceLanguage=ja_jp会显示中文台词,并先翻译为日文后请求 TTS。 - 新增
randomGiftBehavior.curatedPoolOnly,默认只从touhou_maid_affection:bond_random_gift_pool物品标签抽取礼物;可通过bond_random_gift_blacklist继续追加黑名单。 - 新增可选的残血救护最大生命百分比阈值配置;启用后按最大生命的 20% 触发,在原版 20 点生命下仍等于旧版 4 点阈值。为兼容旧服自定义配置,该模式默认关闭。
- 接入 MaidFileManager(女仆档案管理器)迁移 SPI:导出
.maid时携带该女仆的羁绊数据(羁绊等级、能力解锁、语音池与播放模式、膝枕姿态、随机礼物队列与计时、早安吻计划/窗口、救援动作与提供者 id 等),导入到新存档/新版本时按新 UUID 自动还原;未安装管理器时静默不生效。
### Changed
- 休闲膝枕按键默认改为未绑定,仍可在 Minecraft 控制设置中自行绑定,避免默认占用常见的
B键。 - 羁绊页中的休闲膝枕触发提示与能力描述改为显示当前实际绑定按键,不再固定显示
B。 - 随机礼物默认不再遍历几乎全部物品注册表;显式标签池成为默认来源,旧的广泛抽样模式仍可通过配置恢复。
- 羁绊解锁提示现在显示背包中的 P 点物品数量,并明确其不是神社庭灯存储的 P 点数值;点击不可用按钮时会显示失败原因。
- 早安吻调度、对话来源与语音池策略拆分为独立模块;客户端内存语音统一复用格式检测、异步解码和实体跟随实现,减少不同播放入口之间的行为漂移。
### Fixed
- 拒绝膝枕姿态中的
NaN/无限坐标,避免无效网络数据污染玩家存档和实体姿态。 - 对持久化 AI 早安吻语音执行 2 MiB 单文件上限并隔离可变字节数组,避免异常 TTS 或手工缓存文件造成内存放大与缓存篡改。
- 拒绝膝枕角度锁中的非有限旋转值,并在启动与持续执行期间复核女仆当前所有权。
- 数据包语音改为有界流式读取,并在构造资源位置前过滤非法大小写、空格和路径字符,避免资源重载期间的过量分配或中断。
- 限制客户端可控语音配置和动作标识的持久化长度,并为数据包语音试听增加每玩家 100 tick 冷却和请求字段上限,避免玩家 NBT 超限和小请求放大为连续大响应。
- 旧版广泛随机礼物模式仅默认排除屏障、命令方块、结构方块、调试棒等破坏沉浸感的技术/管理物品;基岩与刷怪蛋仍可正常出现。显式礼物池标签可覆盖默认排除规则。
- MiMo Chat 与 TTS 响应改为有界流式接收:聊天响应上限 1 MiB、TTS JSON 响应上限 4 MiB、解码后音频上限 2 MiB;远端错误正文只保留 512 字符摘要,避免异常响应造成内存和日志放大。
### Removed
- 移除潜行空手右击女仆的亲吻入口及其
cooldown.rightClickKissEnabled配置,避免永久占用 TLM 坐下/站起交互;亲吻改用准星目标或公主抱专用按键。
<p align="center">
<b>Kiss your Touhou Little Maid. Because she deserves it.</b><br/>
<i>亲亲你的女仆吧,她值得。</i>
</p>
<p align="center">
<img src="https://img.shields.io/badge/Minecraft-1.21.1-green?style=flat-square" alt="MC 1.21.1"/>
<img src="https://img.shields.io/badge/NeoForge-21.1.x-orange?style=flat-square" alt="NeoForge"/>
<img src="https://img.shields.io/badge/Requires-Touhou_Little_Maid_1.5.0+-blue?style=flat-square" alt="TLM"/>
<img src="https://img.shields.io/badge/License-MIT-yellow?style=flat-square" alt="MIT"/>
</p>
## ✨ 功能特性
| 特性 | 描述 |
| ------------------------ | -------------------------------------------- |
| 💋**亲吻互动** | 潜行 + 空手右击你的女仆,触发亲吻 |
| 💕**爱心粒子** | 亲吻时在两人之间生成浪漫的爱心粒子效果 |
| 🔊**亲吻音效** | 播放清脆的亲吻音效 |
| 📈**好感度提升** | 每次亲吻为女仆增加**+3 好感度**(30 秒冷却) |
| 👀**女仆凝视** | 亲吻时女仆会转头看向你 |
| ⏱️**防刷屏** | 2 秒交互冷却,防止粒子刷屏 |
| 📦**CarryOn 兼容** | 自动检测 CarryOn 模组,智能避免操作冲突 |
| 🧲**副手吸引** | 副手持有诱惑物品(默认蛋糕)也能吸引女仆过来 |
## 🎮 触发条件
### 默认(无 CarryOn)
``
潜行(Shift)+ 空手 + 右击你的女仆
`
### 安装了 CarryOn 时
由于 CarryOn 使用「潜行 + 双手空 + 右击」来搬起实体,本模组会自动调整触发方式以避免冲突:
`
潜行(Shift)+ 主手为空 + 副手持有任意物品 + 右击你的女仆
`
> 💡 **提示**:副手放一个火把、花或任何物品即可。双手全空时将由 CarryOn 接管(搬起女仆)。
## 🧲 副手吸引女仆
原版 TouhouLittleMaid 中,只有**主手**持蛋糕才能吸引女仆。本模组通过 Mixin 扩展了这一行为:
`
副手持有诱惑物品(默认蛋糕)→ 女仆也会被吸引过来
`
> 🎀 **搭配 CarryOn 使用的最佳姿势**:副手放蛋糕吸引女仆过来,然后潜行右击亲吻——一气呵成!
## 📥 安装
1. 安装 **Minecraft 1.21.1** + **NeoForge 21.1.x**
2. 安装 **[Touhou Little Maid](https://modrinth.com/mod/touhou-little-maid)** 1.5.0+
3. 将 maid-affection-x.x.x.jar 放入 .minecraft/mods/ 文件夹
4. 启动游戏!
## 🛠️ 从源码构建
`bash
git clone https://github.com/yabo083/maid-affection.git
cd maid-affection
./gradlew build
`
构建产物在 build/libs/maid-affection-x.x.x.jar。
## 📋 技术细节
- Mod ID**:
maid_affectionAPI**: 使用 TouhouLittleMaid 提供的 InteractMaidEvent 事件 API网络**: 自定义 KissMaidPayload 包(Server → Client)用于同步粒子效果兼容性**: 通过 ModList.isLoaded() 软检测 CarryOn,零硬依赖好感度**: 使用 TLM 内置的 FavorabilityManager + 自定义 Type("Kiss", 3, 600)`## 📄 License
[MIT License](LICENSE) — 自由使用、修改和分发。
<p align="center">
<i>Made with ❤️ for the Touhou Little Maid community</i>
</p>