Skip to content

Commit ebb9f61

Browse files
committed
MCP: improve controller tool
1 parent 6150bfe commit ebb9f61

File tree

5 files changed

+66
-78
lines changed

5 files changed

+66
-78
lines changed

MCP_README.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ Once configured, you can ask your AI assistant:
166166
- "Pause execution and show me all sprites"
167167
- "Step through the next 5 instructions"
168168
- "Capture a screenshot of the current frame"
169-
- "Press the up button on player 1 controller"
169+
- "Tap the up button on player 1 controller"
170170
- "Set player 1 controller to avenue pad 6 type"
171171

172172
### Advanced Debugging Workflows
@@ -217,7 +217,7 @@ The server exposes tools organized in the following categories:
217217
- `memory_search` - Search memory with operators (<, >, ==, !=, <=, >=), compare types (previous, value, address), and data types (hex, signed, unsigned)
218218

219219
### Disassembly & Debugging
220-
- `get_disassembly` - Get disassembly around PC or specified address
220+
- `get_disassembly` - Get disassembly for specified address range
221221
- `add_symbol` - Add symbol (label) at specified address
222222
- `remove_symbol` - Remove symbol
223223
- `list_symbols` - List all defined symbols
@@ -263,8 +263,7 @@ The server exposes tools organized in the following categories:
263263
- `toggle_fast_forward` - Toggle fast forward mode on/off
264264

265265
### Controller Input
266-
- `controller_press_button` - Press a button on a controller (player 1-5). Buttons: up, down, left, right, select, run, i, ii, iii, iv, v, vi
267-
- `controller_release_button` - Release a button on a controller (player 1-5)
266+
- `controller_button` - Control a button on a controller (player 1-5). Use action 'press' to hold the button, 'release' to let it go, or 'press_and_release' to simulate a quick tap. Buttons: up, down, left, right, select, run, I, II, III, IV, V, VI
268267
- `controller_set_type` - Set controller type for a player: standard (2 buttons), avenue_pad_3 (3 buttons), avenue_pad_6 (6 buttons)
269268
- `controller_get_type` - Get the current controller type for a player (returns: standard, avenue_pad_3, or avenue_pad_6)
270269
- `controller_set_turbo_tap` - Enable or disable Turbo Tap (multitap) for 5-player support

platforms/shared/desktop/mcp/mcp_debug_adapter.cpp

Lines changed: 19 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1496,50 +1496,16 @@ json DebugAdapter::ToggleFastForward(bool enabled)
14961496
return result;
14971497
}
14981498

1499-
json DebugAdapter::ControllerPressButton(int player, const std::string& button)
1499+
json DebugAdapter::ControllerButton(int player, const std::string& button, const std::string& action)
15001500
{
15011501
json result;
15021502

1503-
// Convert player 1-5 to GG_Controllers enum (0-4)
1504-
if (player < 1 || player > 5)
1503+
// Validate action
1504+
if (action != "press" && action != "release" && action != "press_and_release")
15051505
{
1506-
result["error"] = "Invalid player number (must be 1-5)";
1506+
result["error"] = "Invalid action (must be: press, release, press_and_release)";
15071507
return result;
15081508
}
1509-
GG_Controllers controller = static_cast<GG_Controllers>(player - 1);
1510-
1511-
// Convert button string to GG_Keys enum
1512-
GG_Keys key = GG_KEY_NONE;
1513-
if (button == "i") key = GG_KEY_I;
1514-
else if (button == "ii") key = GG_KEY_II;
1515-
else if (button == "select") key = GG_KEY_SELECT;
1516-
else if (button == "run") key = GG_KEY_RUN;
1517-
else if (button == "up") key = GG_KEY_UP;
1518-
else if (button == "right") key = GG_KEY_RIGHT;
1519-
else if (button == "down") key = GG_KEY_DOWN;
1520-
else if (button == "left") key = GG_KEY_LEFT;
1521-
else if (button == "iii") key = GG_KEY_III;
1522-
else if (button == "iv") key = GG_KEY_IV;
1523-
else if (button == "v") key = GG_KEY_V;
1524-
else if (button == "vi") key = GG_KEY_VI;
1525-
else
1526-
{
1527-
result["error"] = "Invalid button name";
1528-
return result;
1529-
}
1530-
1531-
emu_key_pressed(controller, key);
1532-
1533-
result["success"] = true;
1534-
result["player"] = player;
1535-
result["button"] = button;
1536-
1537-
return result;
1538-
}
1539-
1540-
json DebugAdapter::ControllerReleaseButton(int player, const std::string& button)
1541-
{
1542-
json result;
15431509

15441510
// Convert player 1-5 to GG_Controllers enum (0-4)
15451511
if (player < 1 || player > 5)
@@ -1569,11 +1535,25 @@ json DebugAdapter::ControllerReleaseButton(int player, const std::string& button
15691535
return result;
15701536
}
15711537

1572-
emu_key_released(controller, key);
1538+
if (action == "press")
1539+
{
1540+
emu_key_pressed(controller, key);
1541+
}
1542+
else if (action == "release")
1543+
{
1544+
emu_key_released(controller, key);
1545+
}
1546+
else if (action == "press_and_release")
1547+
{
1548+
emu_key_pressed(controller, key);
1549+
// Mark for delayed release - McpManager will handle releasing after some frames
1550+
result["__delayed_release"] = true;
1551+
}
15731552

15741553
result["success"] = true;
15751554
result["player"] = player;
15761555
result["button"] = button;
1556+
result["action"] = action;
15771557

15781558
return result;
15791559
}

platforms/shared/desktop/mcp/mcp_debug_adapter.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,7 @@ class DebugAdapter
144144
json ToggleFastForward(bool enabled);
145145

146146
// Controller input
147-
json ControllerPressButton(int player, const std::string& button);
148-
json ControllerReleaseButton(int player, const std::string& button);
147+
json ControllerButton(int player, const std::string& button, const std::string& action);
149148
json ControllerSetType(int player, const std::string& type);
150149
json ControllerSetTurboTap(bool enabled);
151150
json ControllerGetType(int player);

platforms/shared/desktop/mcp/mcp_manager.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "mcp_server.h"
2424
#include "mcp_transport.h"
2525
#include "mcp_debug_adapter.h"
26+
#include <vector>
2627

2728
extern bool g_mcp_stdio_mode;
2829

@@ -32,6 +33,13 @@ enum McpTransportMode
3233
MCP_TRANSPORT_TCP
3334
};
3435

36+
struct DelayedButtonRelease
37+
{
38+
int player;
39+
std::string button;
40+
int frames_remaining;
41+
};
42+
3543
class McpManager
3644
{
3745
public:
@@ -115,6 +123,18 @@ class McpManager
115123

116124
void PumpCommands()
117125
{
126+
for (size_t i = 0; i < m_delayedReleases.size(); )
127+
{
128+
m_delayedReleases[i].frames_remaining--;
129+
if (m_delayedReleases[i].frames_remaining <= 0)
130+
{
131+
m_debugAdapter->ControllerButton(m_delayedReleases[i].player, m_delayedReleases[i].button, "release");
132+
m_delayedReleases.erase(m_delayedReleases.begin() + i);
133+
}
134+
else
135+
i++;
136+
}
137+
118138
DebugCommand* cmd = NULL;
119139
while ((cmd = m_commandQueue.Pop()) != NULL)
120140
{
@@ -131,6 +151,17 @@ class McpManager
131151
resp->errorMessage = resp->result["error"];
132152
}
133153

154+
if (resp->result.contains("__delayed_release") && resp->result["__delayed_release"] == true)
155+
{
156+
DelayedButtonRelease release;
157+
release.player = resp->result["player"];
158+
release.button = resp->result["button"];
159+
release.frames_remaining = 10;
160+
m_delayedReleases.push_back(release);
161+
162+
resp->result.erase("__delayed_release");
163+
}
164+
134165
m_responseQueue.Push(resp);
135166
SafeDelete(cmd);
136167
}
@@ -143,6 +174,7 @@ class McpManager
143174
ResponseQueue m_responseQueue;
144175
McpTransportMode m_transport_mode;
145176
int m_tcp_port;
177+
std::vector<DelayedButtonRelease> m_delayedReleases;
146178
};
147179

148180
#endif /* MCP_MANAGER_H */

platforms/shared/desktop/mcp/mcp_server.cpp

Lines changed: 11 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -746,8 +746,8 @@ void McpServer::HandleToolsList(const json& request)
746746

747747
// Controller input tools
748748
tools.push_back({
749-
{"name", "controller_press_button"},
750-
{"description", "Press a button on a controller (player 1-5). Buttons: up, down, left, right, select, run, i, ii, iii, iv, v, vi"},
749+
{"name", "controller_button"},
750+
{"description", "Control a button on a controller (player 1-5). Use action 'press' to hold the button down, 'release' to let it go, or 'press_and_release' to simulate a quick button tap (presses and automatically releases after a few frames). Buttons: up, down, left, right, select, run, I, II, III, IV, V, VI"},
751751
{"inputSchema", {
752752
{"type", "object"},
753753
{"properties", {
@@ -759,33 +759,16 @@ void McpServer::HandleToolsList(const json& request)
759759
}},
760760
{"button", {
761761
{"type", "string"},
762-
{"description", "Button name: up, down, left, right, select, run, i, ii, iii, iv, v, vi"},
763-
{"enum", json::array({"up", "down", "left", "right", "select", "run", "i", "ii", "iii", "iv", "v", "vi"})}
764-
}}
765-
}},
766-
{"required", json::array({"player", "button"})}
767-
}}
768-
});
769-
770-
tools.push_back({
771-
{"name", "controller_release_button"},
772-
{"description", "Release a button on a controller (player 1-5). Buttons: up, down, left, right, select, run, i, ii, iii, iv, v, vi"},
773-
{"inputSchema", {
774-
{"type", "object"},
775-
{"properties", {
776-
{"player", {
777-
{"type", "integer"},
778-
{"description", "Player number (1-5)"},
779-
{"minimum", 1},
780-
{"maximum", 5}
762+
{"description", "Button name: up, down, left, right, select, run, I, II, III, IV, V, VI"},
763+
{"enum", json::array({"up", "down", "left", "right", "select", "run", "I", "II", "III", "IV", "V", "VI"})}
781764
}},
782-
{"button", {
765+
{"action", {
783766
{"type", "string"},
784-
{"description", "Button name: up, down, left, right, select, run, i, ii, iii, iv, v, vi"},
785-
{"enum", json::array({"up", "down", "left", "right", "select", "run", "i", "ii", "iii", "iv", "v", "vi"})}
767+
{"description", "Action to perform: 'press' holds the button, 'release' lets it go, 'press_and_release' simulates a quick tap"},
768+
{"enum", json::array({"press", "release", "press_and_release"})}
786769
}}
787770
}},
788-
{"required", json::array({"player", "button"})}
771+
{"required", json::array({"player", "button", "action"})}
789772
}}
790773
});
791774

@@ -1665,17 +1648,12 @@ json McpServer::ExecuteCommand(const std::string& toolName, const json& argument
16651648
bool enabled = arguments["enabled"];
16661649
return m_debugAdapter.ToggleFastForward(enabled);
16671650
}
1668-
else if (normalizedTool == "controller_press_button")
1669-
{
1670-
int player = arguments["player"];
1671-
std::string button = arguments["button"];
1672-
return m_debugAdapter.ControllerPressButton(player, button);
1673-
}
1674-
else if (normalizedTool == "controller_release_button")
1651+
else if (normalizedTool == "controller_button")
16751652
{
16761653
int player = arguments["player"];
16771654
std::string button = arguments["button"];
1678-
return m_debugAdapter.ControllerReleaseButton(player, button);
1655+
std::string action = arguments["action"];
1656+
return m_debugAdapter.ControllerButton(player, button, action);
16791657
}
16801658
else if (normalizedTool == "controller_set_type")
16811659
{

0 commit comments

Comments
 (0)