


YapYap_Native-Settings-UI-Lib/YapYap_Native-Settings-UI-Demo/一个用于 YapYap(BepInEx) 的设置界面注入库:在游戏自带 UISettings 界面中,自动创建自定义 Tab 与 Section,并在其中生成按钮、开关、下拉、滑条、标签、编辑框等控件。
本 README 重点介绍 公开接口 与参数含义。
典型用法:
var tab = NativeSettingsUI.RegisterTab(
guid: "com.yourmod.settings.tab",
title: new LocalText("TAB_TITLE", "我的设置", "My Settings"),
showInGame: true
);
tab.CreateToggle(
id: "Toggle_Enabled",
settingKey: "com.yourmod.Enabled",
title: new LocalText("ENABLED", "启用", "Enabled"),
initialValue: true,
onChanged: v => enabled = v,
showInGame: true
);
RegisterTab(...) 会在 UISettings 可用时,自动:
UISettings.sections 实现)LocalText 用来提供“中文/英文”两套文本:
new LocalText(key: "EXAMPLE", chinese: "中文", english: "English")
chinese或者 english 留空,但是至少要提供一个非空字符串Chinese/ChineseSimplified/ChineseTraditional)时显示 chineseenglishUISettings 的对象不是在 Awake 立刻存在,控件会“稍后”才被克隆/创建出来。
CreateXxx() 返回 UiRef<T>:
IsReady:是否已经拿到了真实 UI 组件引用Value:真实引用(未就绪时为 null)Ready:当真实引用出现时触发UiRef<TMP_Text> labelRef = tab.CreateLabel(...);
labelRef.Ready += tmp =>
{
// tmp 就是真实的 TMP_Text
};
命名空间:Yap_NativeSettingsUI
public static SettingsTab RegisterTab(string guid, LocalText title, bool showInGame)
guid:Tab 的唯一标识(建议用你的 ModId 前缀),重复注册同 guid 会返回同一个 Tabtitle:Tab 标题(支持中/英切换)showInGame:是否在“游戏内打开的设置界面”也显示该 Tab(Tab 自身不开启则控件再开也不会显示)用于给某个 TMP_Text 绑定/解绑 LocalText 的自动刷新逻辑。
public static void BindText(TMP_Text tmp, LocalText text)
public static void UnbindText(TMP_Text tmp)
适用场景:
BindTextUnbindText 再 tmp.text = ...RegisterTab(...) 返回 SettingsTab,所有控件都在 Tab 上创建。
以下参数在多数控件中都有:
id
"Toggle_Enabled"、"Button_Save"showInGame
showInGame=truepreferredSize(可选)
anchoredPositionOffset(可选)
public UiRef<Button> CreateButton(
string id,
LocalText text,
Action onClick,
bool showInGame = true,
Vector2? preferredSize = null,
Vector2? anchoredPositionOffset = null)
text:按钮显示文本(中/英)onClick:点击回调public UiRef<TMP_Text> CreateLabel(
string id,
LocalText text,
bool showInGame = true,
Vector2? preferredSize = null,
Vector2? anchoredPositionOffset = null)
text:标签文本(中/英)public UiRef<UISettingToggle> CreateToggle(
string id,
string settingKey,
LocalText title,
bool initialValue,
Action<bool> onChanged,
bool showInGame = true,
Vector2? preferredSize = null,
Vector2? anchoredPositionOffset = null)
title:控件标题(中/英)initialValue:初始值onChanged:值变化回调settingKey:持久化键名(见下文“settingKey 是什么”)public UiRef<UISettingDropdownString> CreateDropdownString(
string id,
string settingKey,
LocalText title,
IList<string> options,
string initialValue,
Action<string> onChanged,
bool showInGame = true,
Vector2? preferredSize = null,
Vector2? anchoredPositionOffset = null)
options:下拉可选项(字符串列表)initialValue:初始选中项onChanged:选择变化回调settingKey:持久化键名public UiRef<UICustomSlider> CreateSliderInt(
string id,
string settingKey,
LocalText title,
int minValue,
int maxValue,
int initialValue,
Action<int> onChanged,
bool showInGame = true,
Vector2? preferredSize = null,
Vector2? anchoredPositionOffset = null)
minValue / maxValue:整数范围initialValue:初始值(会被 clamp 到范围内)onChanged:值变化回调settingKey:持久化键名public UiRef<TMP_InputField> CreateInputString(
string id,
string settingKey,
LocalText title,
string initialValue,
Action<string> onChanged,
bool showInGame = true,
Vector2? preferredSize = null,
Vector2? anchoredPositionOffset = null)
实现说明(与示例一致):
Slider 子节点下的 Value、Fill Area、HandleSlider 子节点重命名为 InputYAPYAP.UICustomSlider 组件InputField 对象被激活(模板里它可能默认是未激活)数据行为:
settingKey 非空:启动时 PlayerPrefs.GetString(settingKey, initialValue)onEndEdit 时保存:PlayerPrefs.SetString(settingKey, v) 并回调 onChanged(v)settingKey 用于 游戏原生设置系统的持久化键名(本质是 PlayerPrefs 的 key)。
推荐规则:
例如:
com.yourmod.Toggle.Enabledcom.yourmod.Dropdown.Modecom.yourmod.Input.NoteUiRef<TMP_Text> labelRef = tab.CreateLabel(
id: "Label_Runtime",
text: new LocalText("RUNTIME", "等待加载", "Waiting for UI")
);
labelRef.Ready += tmp =>
{
NativeSettingsUI.UnbindText(tmp);
tmp.text = "Runtime label ready.";
};
tab.CreateDropdownString(
id: "Dropdown_Mode",
settingKey: "com.yourmod.Mode",
title: new LocalText("MODE", "模式", "Mode"),
options: new [] { "Normal", "Hard" },
initialValue: "Normal",
onChanged: v => gameMode = v ,
showInGame: false
);
An injection library MOD for YapYap (BepInEx). It hooks into the built-in UISettings screen, automatically creates a custom Tab + Section, and provides helper APIs to generate common controls such as buttons, toggles, dropdowns, sliders, labels, and input fields.
Typical usage:
var tab = NativeSettingsUI.RegisterTab(
guid: "com.yourmod.settings.tab",
title: new LocalText("TAB_TITLE", "我的设置", "My Settings"),
showInGame: true
);
tab.CreateToggle(
id: "Toggle_Enabled",
settingKey: "com.yourmod.Enabled",
title: new LocalText("ENABLED", "启用", "Enabled"),
initialValue: true,
onChanged: v => enabled = v,
showInGame: true
);
RegisterTab(...) automatically does the following when UISettings becomes available:
UISettings.sections)LocalText holds two versions of a string (Chinese / English):
new LocalText(key: "EXAMPLE", chinese: "中文", english: "English")
Chinese/ChineseSimplified/ChineseTraditional), the library shows chineseenglishUISettings objects do not necessarily exist at Awake, and controls are created later.
Each CreateXxx() returns UiRef<T>:
IsReady: whether the real component instance is availableValue: the actual UI component (null before ready)Ready: fired once the actual component instance becomes availableUiRef<TMP_Text> labelRef = tab.CreateLabel(...);
labelRef.Ready += tmp =>
{
// tmp is the real TMP_Text instance
};
Namespace: Yap_NativeSettingsUI
public static SettingsTab RegisterTab(string guid, LocalText title, bool showInGame)
guid: Unique tab id. Registering the same guid multiple times returns the same SettingsTab instance. Recommended to prefix with your ModId.title: Tab title (Chinese/English switching supported)showInGame: Whether this tab should also appear in the in-game settings UI. If the tab itself is not shown in-game, controls won't be shown in-game either.Bind or unbind the automatic LocalText refresh behavior for a TMP_Text.
public static void BindText(TMP_Text tmp, LocalText text)
public static void UnbindText(TMP_Text tmp)
Use cases:
BindTextUnbindText and then set tmp.text = ...RegisterTab(...) returns a SettingsTab. All controls are created from the tab instance.
Most control creation methods share these parameters:
id
"Toggle_Enabled", "Button_Save"showInGame
showInGame=truepreferredSize (optional)
anchoredPositionOffset (optional)
public UiRef<Button> CreateButton(
string id,
LocalText text,
Action onClick,
bool showInGame = true,
Vector2? preferredSize = null,
Vector2? anchoredPositionOffset = null)
text: Button text (Chinese/English)onClick: Click callbackpublic UiRef<TMP_Text> CreateLabel(
string id,
LocalText text,
bool showInGame = true,
Vector2? preferredSize = null,
Vector2? anchoredPositionOffset = null)
text: Label text (Chinese/English)public UiRef<UISettingToggle> CreateToggle(
string id,
string settingKey,
LocalText title,
bool initialValue,
Action<bool> onChanged,
bool showInGame = true,
Vector2? preferredSize = null,
Vector2? anchoredPositionOffset = null)
title: Control title (Chinese/English)initialValue: Initial valueonChanged: Callback when the value changessettingKey: Persistent key (see “What is settingKey?” below)public UiRef<UISettingDropdownString> CreateDropdownString(
string id,
string settingKey,
LocalText title,
IList<string> options,
string initialValue,
Action<string> onChanged,
bool showInGame = true,
Vector2? preferredSize = null,
Vector2? anchoredPositionOffset = null)
options: Dropdown options (string list)initialValue: Initially selected itemonChanged: Callback when selection changessettingKey: Persistent keypublic UiRef<UICustomSlider> CreateSliderInt(
string id,
string settingKey,
LocalText title,
int minValue,
int maxValue,
int initialValue,
Action<int> onChanged,
bool showInGame = true,
Vector2? preferredSize = null,
Vector2? anchoredPositionOffset = null)
minValue / maxValue: Integer rangeinitialValue: Initial value (clamped into the range)onChanged: Callback when value changessettingKey: Persistent keypublic UiRef<TMP_InputField> CreateInputString(
string id,
string settingKey,
LocalText title,
string initialValue,
Action<string> onChanged,
bool showInGame = true,
Vector2? preferredSize = null,
Vector2? anchoredPositionOffset = null)
Implementation notes (as in the example):
Value, Fill Area, Handle under the Slider childSlider child to InputYAPYAP.UICustomSlider component on the rootInputField object is active (the template may keep it disabled by default)Data behavior:
settingKey is non-empty: initial text uses PlayerPrefs.GetString(settingKey, initialValue)onEndEdit: saves PlayerPrefs.SetString(settingKey, v) and calls onChanged(v)settingKey is the persistent key name used by the game’s settings system (effectively a PlayerPrefs key).
Recommended practice:
Examples:
com.yourmod.Toggle.Enabledcom.yourmod.Dropdown.Modecom.yourmod.Input.NoteUiRef<TMP_Text> labelRef = tab.CreateLabel(
id: "Label_Runtime",
text: new LocalText("RUNTIME", "等待加载", "Waiting for UI")
);
labelRef.Ready += tmp =>
{
NativeSettingsUI.UnbindText(tmp);
tmp.text = "Runtime label ready.";
};
tab.CreateDropdownString(
id: "Dropdown_Mode",
settingKey: "com.yourmod.Mode",
title: new LocalText("MODE", "模式", "Mode"),
options: new [] { "Normal", "Hard" },
initialValue: "Normal",
onChanged: v => { },
showInGame: false
);