Skip to content

Commit 9499a33

Browse files
fix(android): 布局编辑器列出全部场景条件按键
游戏布局预览此前只包含跳跃/冲刺/抓取/交互,MiaoNet 聊天与玩家、CollabUtils 大厅地图以及未知 Mod 场景的确定/返回在游戏里会出现,却不在编辑器中显示,只能停在默认位置无法编辑。现在由 ControlProfile.forEditor 统一生成编辑器预览,列出该布局在任何场景可能出现的全部控件;运行时 profile 的按条件显示行为不变。 ControlProfileTest 新增两个回归用例覆盖两套预览。
1 parent 7eae47c commit 9499a33

4 files changed

Lines changed: 68 additions & 15 deletions

File tree

‎android/runtime/TOUCH_CONTROLS.md‎

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@ one-tap resume.
7272
actions/stick and menu actions/D-pad have separate positions; pause/resume and
7373
auxiliary icons use shared positions. Menu primary/secondary positions remain
7474
consistent when confirm changes to continue, character entry, or close.
75+
- The preview lists every control its layout can show, including the ones only
76+
some scenes display: 交互 (Talk) away from an NPC, MiaoNet 聊天 / 玩家, CollabUtils
77+
大厅地图 and the 确定 / 返回 pair of unknown Mod scenes. Each keeps an editable
78+
position and style per layout instead of appearing only during play at a default
79+
position no edit could reach.
7580
- **保存** applies and persists both previews. **取消** or Android Back discards
7681
edits. **重置** asks for confirmation and resets the current orientation's draft;
7782
it is not permanent until Save, and Cancel can still undo it.
@@ -315,9 +320,11 @@ direction and bind its MoveOnly/DashOnly alternatives; check movement and diagon
315320
dash with both stick and D-pad. Clear a binding and assign its old default to another
316321
action: the unbound virtual button must not trigger that other action. Change a
317322
binding during a hold and verify the old key is released without a delayed pulse.
318-
For the editor: drag jump and stick, switch preview and drag confirm, Save, reopen
319-
and verify, Cancel a second edit, verify Back cancels without unpausing, and test
320-
Reset both with Cancel and Save. Relaunch to verify positions persist.
323+
For the editor: drag jump and stick, switch preview and drag confirm, keep a
324+
聊天 / 玩家 / 大厅地图 Mod shortcut and the 确定 / 返回 pair of an unknown Mod scene
325+
editable instead of frozen at a default, Save, reopen and verify, Cancel a second
326+
edit, verify Back cancels without unpausing, and test Reset both with Cancel and
327+
Save. Relaunch to verify positions persist.
321328
For direct touch: initial title tap; main-menu button tap and swipe; pause row tap;
322329
horizontal slider drag followed by vertical list drag; verify no release-confirm;
323330
both chapter swipe axes and map-search shortcut; native text Cancel/accept; journal

‎android/runtime/src/com/celemod/runtime/ControlProfile.kt‎

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,13 @@ data class ControlProfile(
3434
) {
3535
companion object {
3636
fun forState(state: ControlState, buttons: Boolean, joystick: Boolean, direct: Boolean = false,
37-
directionMode: DirectionControlMode = DirectionControlMode.default(joystick)): ControlProfile {
37+
directionMode: DirectionControlMode = DirectionControlMode.default(joystick),
38+
preview: Boolean = false): ControlProfile {
3839
val enabled = buttons || joystick
3940
val mode = state.mode
41+
// The layout editor must show every control its layout can display, otherwise
42+
// scene-conditional buttons stay stuck at an uneditable default position.
43+
val conditional = preview && mode in setOf(ControlMode.GAMEPLAY, ControlMode.FALLBACK)
4044
val lobbyMap = mode in setOf(ControlMode.LOBBY_MAP, ControlMode.LOBBY_MAP_VIEW)
4145
val playing = mode in setOf(ControlMode.GAMEPLAY, ControlMode.PICO8, ControlMode.FALLBACK)
4246
val navigation = mode in setOf(ControlMode.PAUSE, ControlMode.PAUSE_MENU, ControlMode.MENU, ControlMode.CHAPTER,
@@ -47,13 +51,14 @@ data class ControlProfile(
4751
val actions = when (mode) {
4852
ControlMode.GAMEPLAY, ControlMode.FALLBACK -> if (buttons) buildList {
4953
add(ControlAction("Jump", "跳")); add(ControlAction("Dash", "冲")); add(ControlAction("Grab", "抓"))
50-
if (state.canTalk) add(ControlAction("Talk", "交互"))
54+
if (state.canTalk || conditional) add(ControlAction("Talk", "交互"))
5155
if (mode == ControlMode.GAMEPLAY) {
52-
if (!state.bindings["MiaoChat"].isNullOrEmpty()) add(ControlAction("MiaoChat", "聊天", ControlIcon.CHAT))
53-
if (!state.bindings["MiaoPlayers"].isNullOrEmpty()) add(ControlAction("MiaoPlayers", "玩家"))
54-
if (!state.bindings["CollabMap"].isNullOrEmpty()) add(ControlAction("CollabMap", "大厅地图", ControlIcon.BOOK))
56+
if (conditional || !state.bindings["MiaoChat"].isNullOrEmpty()) add(ControlAction("MiaoChat", "聊天", ControlIcon.CHAT))
57+
if (conditional || !state.bindings["MiaoPlayers"].isNullOrEmpty()) add(ControlAction("MiaoPlayers", "玩家"))
58+
if (conditional || !state.bindings["CollabMap"].isNullOrEmpty()) add(ControlAction("CollabMap", "大厅地图", ControlIcon.BOOK))
5559
}
56-
if (mode == ControlMode.FALLBACK) { add(confirm); add(cancel) }
60+
// Unknown Mod scenes add confirm/cancel; keep them editable as well.
61+
if (mode == ControlMode.FALLBACK || conditional) { add(confirm); add(cancel) }
5762
} else emptyList()
5863
ControlMode.PICO8 -> if (buttons) listOf(ControlAction("Jump", "跳"), ControlAction("Dash", "冲")) else emptyList()
5964
ControlMode.TITLE -> listOf(confirm.copy(label = "开始"))
@@ -101,5 +106,20 @@ data class ControlProfile(
101106
diagonalDirections = enabled && !direct && playing && directionMode == DirectionControlMode.EIGHT_BUTTONS
102107
)
103108
}
109+
110+
/**
111+
* Layout editor preview. It shows every control the layout can display in any scene,
112+
* including scene-conditional ones (Talk away from an NPC, MiaoNet 聊天 / 玩家,
113+
* CollabUtils 大厅地图 and the confirm/cancel pair of unknown Mod scenes), so positions,
114+
* sizes, slide behavior and feedback stay editable before a scene shows them.
115+
*/
116+
fun forEditor(game: Boolean, joystick: Boolean,
117+
directionMode: DirectionControlMode = DirectionControlMode.default(joystick)): ControlProfile =
118+
if (game) forState(ControlState(ControlMode.GAMEPLAY), true, joystick,
119+
directionMode = directionMode, preview = true)
120+
else forState(ControlState(ControlMode.PAUSE), true, false).let {
121+
it.copy(actions = it.actions + ControlAction("Pause", "完成", ControlIcon.CONFIRM),
122+
auxiliary = ControlAction("MenuJournal", "日志", ControlIcon.BOOK))
123+
}
104124
}
105125
}

‎android/runtime/src/com/celemod/runtime/TouchControls.kt‎

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -182,12 +182,9 @@ class TouchControls(
182182
toolbarBounds = ControlBounds(safe.left.toFloat(), safe.top.toFloat(),
183183
safe.left + margin + toolbarCount * (topSize + margin), safe.top + topSize + 2 * margin)
184184
profile = if (!editing) ControlProfile.forState(state, buttons, joystick, direct, directionMode)
185-
else if (editingGame) ControlProfile.forState(ControlState(ControlMode.GAMEPLAY, canTalk = true), true, joystick,
186-
directionMode = directionMode)
187-
else ControlProfile.forState(ControlState(ControlMode.PAUSE), true, false).let {
188-
it.copy(actions = it.actions + ControlAction("Pause", "完成", ControlIcon.CONFIRM),
189-
auxiliary = ControlAction("MenuJournal", "日志", ControlIcon.BOOK))
190-
}
185+
// The editor previews every control of the selected layout, including the ones
186+
// only some scenes show, so all of them can be positioned and styled.
187+
else ControlProfile.forEditor(editingGame, joystick, directionMode)
191188
fun key(id: String, action: ControlAction, x: Float, y: Float, side: Float = size,
192189
direction: Boolean = false, iconOnly: Boolean = false, codes: Set<Int>? = null) {
193190
val actualSide = if (id.startsWith("fixed/")) side else side * style(id).scale

‎src-tauri/gen/android/app/src/test/java/com/celemod/runtime/ControlProfileTest.kt‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,4 +184,33 @@ class ControlProfileTest {
184184
("Jump" to listOf("K"))), "Jump"))
185185
assertEquals(setOf(111), ControlKeys.resolveAll(state, "ESC"))
186186
}
187+
188+
@Test fun editorPreviewExposesSceneConditionalGameplayButtons() {
189+
// Buttons that only appear in some scenes (Talk near an NPC, Mod shortcuts, the
190+
// confirm/cancel pair of unknown Mod scenes) must stay editable in the preview.
191+
val game = ControlProfile.forEditor(game = true, joystick = true)
192+
assertEquals(listOf("Jump", "Dash", "Grab", "Talk", "MiaoChat", "MiaoPlayers", "CollabMap",
193+
"MenuConfirm", "MenuCancel"), game.actions.map { it.binding })
194+
assertTrue(game.stick); assertFalse(game.directions)
195+
assertEquals("Pause", game.top?.binding)
196+
// Live profiles stay conditional: the preview never invents runtime buttons.
197+
val live = profile(ControlMode.GAMEPLAY)
198+
assertFalse(live.actions.any { it.binding in setOf("Talk", "MiaoChat", "MiaoPlayers", "CollabMap", "MenuConfirm") })
199+
val available = ControlProfile.forState(ControlState(ControlMode.GAMEPLAY,
200+
bindings = mapOf("MiaoChat" to listOf("Y"), "MiaoPlayers" to emptyList())), true, true)
201+
assertEquals(listOf("Jump", "Dash", "Grab", "MiaoChat"), available.actions.map { it.binding })
202+
}
203+
204+
@Test fun editorPreviewCoversEveryMenuControlAndStaysCardinal() {
205+
val menu = ControlProfile.forEditor(game = false, joystick = true)
206+
assertEquals(listOf("MenuConfirm", "MenuCancel", "Pause"), menu.actions.map { it.binding })
207+
assertEquals("MenuJournal", menu.auxiliary?.binding)
208+
assertEquals("Pause", menu.top?.binding)
209+
assertTrue(menu.directions); assertTrue(menu.menuDirections); assertFalse(menu.stick)
210+
// Eight-key gameplay previews keep the four diagonals of the game layout editable.
211+
val eight = ControlProfile.forEditor(game = true, joystick = false, directionMode = DirectionControlMode.EIGHT_BUTTONS)
212+
assertTrue(eight.directions); assertTrue(eight.diagonalDirections); assertFalse(eight.stick); assertFalse(eight.menuDirections)
213+
val pad = ControlProfile.forEditor(game = true, joystick = false, directionMode = DirectionControlMode.FOUR_BUTTONS)
214+
assertTrue(pad.directions); assertFalse(pad.diagonalDirections)
215+
}
187216
}

0 commit comments

Comments
 (0)