Add relative positioning support to execute command using ~ syntax

Co-authored-by: aronwk-aaron <26027722+aronwk-aaron@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2025-09-02 15:10:44 +00:00
parent 09aa6f40d7
commit d972b0de2f
2 changed files with 36 additions and 11 deletions

View File

@@ -1671,10 +1671,11 @@ namespace DEVGMCommands {
ChatPackets::SendSystemMessage(sysAddr, u"Subcommands:"); ChatPackets::SendSystemMessage(sysAddr, u"Subcommands:");
ChatPackets::SendSystemMessage(sysAddr, u" as <playername> - Execute as different player"); ChatPackets::SendSystemMessage(sysAddr, u" as <playername> - Execute as different player");
ChatPackets::SendSystemMessage(sysAddr, u" at <playername> - Execute from player's position"); ChatPackets::SendSystemMessage(sysAddr, u" at <playername> - Execute from player's position");
ChatPackets::SendSystemMessage(sysAddr, u" positioned <x> <y> <z> - Execute from coordinates"); ChatPackets::SendSystemMessage(sysAddr, u" positioned <x> <y> <z> - Execute from coordinates (absolute or relative with ~)");
ChatPackets::SendSystemMessage(sysAddr, u"Examples:"); ChatPackets::SendSystemMessage(sysAddr, u"Examples:");
ChatPackets::SendSystemMessage(sysAddr, u" /execute as Player1 run pos"); ChatPackets::SendSystemMessage(sysAddr, u" /execute as Player1 run pos");
ChatPackets::SendSystemMessage(sysAddr, u" /execute at Player2 positioned 100 200 300 run spawn 1234"); ChatPackets::SendSystemMessage(sysAddr, u" /execute at Player2 positioned 100 200 300 run spawn 1234");
ChatPackets::SendSystemMessage(sysAddr, u" /execute positioned ~5 ~10 ~ run spawn 1234");
return; return;
} }
@@ -1739,20 +1740,44 @@ namespace DEVGMCommands {
} }
try { try {
float x = std::stof(splitArgs[i + 1]); // Parse coordinates with support for relative positioning (~)
float y = std::stof(splitArgs[i + 2]); auto parseCoordinate = [&](const std::string& coord, float currentValue) -> float {
float z = std::stof(splitArgs[i + 3]); if (coord.empty()) {
throw std::invalid_argument("Empty coordinate");
}
// Basic coordinate validation if (coord[0] == '~') {
if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(z)) { // Relative coordinate
ChatPackets::SendSystemMessage(sysAddr, u"Error: Coordinates must be finite numbers"); if (coord.length() == 1) {
return; // Just "~" means current position (offset 0)
} return currentValue;
} else {
// "~<offset>" means current position + offset
std::string offsetStr = coord.substr(1);
float offset = std::stof(offsetStr);
if (!std::isfinite(offset)) {
throw std::invalid_argument("Invalid offset");
}
return currentValue + offset;
}
} else {
// Absolute coordinate
float absolute = std::stof(coord);
if (!std::isfinite(absolute)) {
throw std::invalid_argument("Invalid absolute coordinate");
}
return absolute;
}
};
float x = parseCoordinate(splitArgs[i + 1], execPosition.x);
float y = parseCoordinate(splitArgs[i + 2], execPosition.y);
float z = parseCoordinate(splitArgs[i + 3], execPosition.z);
execPosition = NiPoint3(x, y, z); execPosition = NiPoint3(x, y, z);
positionOverridden = true; positionOverridden = true;
} catch (const std::exception&) { } catch (const std::exception&) {
ChatPackets::SendSystemMessage(sysAddr, u"Error: Invalid coordinates for 'positioned'. Use numeric values."); ChatPackets::SendSystemMessage(sysAddr, u"Error: Invalid coordinates for 'positioned'. Use numeric values or relative coordinates with ~.");
return; return;
} }

View File

@@ -116,7 +116,7 @@ These commands are primarily for development and testing. The usage of many of t
|setrewardcode|`/setrewardcode <code>`|Sets the rewardcode for the account you are logged into if it's a valid rewardcode, See cdclient table `RewardCodes`|8| |setrewardcode|`/setrewardcode <code>`|Sets the rewardcode for the account you are logged into if it's a valid rewardcode, See cdclient table `RewardCodes`|8|
|barfight|`/barfight start`|Starts a barfight (turns everyones pvp on)|8| |barfight|`/barfight start`|Starts a barfight (turns everyones pvp on)|8|
|despawn|`/despawn <objectID>`|Despawns the entity objectID IF it was spawned in through a slash command.|8| |despawn|`/despawn <objectID>`|Despawns the entity objectID IF it was spawned in through a slash command.|8|
|execute|`/execute <subcommand> ... run <command>`|Execute commands with modified context (Minecraft-style). Subcommands: `as <playername>` (execute as different player), `at <playername>` (execute from player's position), `positioned <x> <y> <z>` (execute from coordinates). Example: `/execute as Player1 run pos`|8| |execute|`/execute <subcommand> ... run <command>`|Execute commands with modified context (Minecraft-style). Subcommands: `as <playername>` (execute as different player), `at <playername>` (execute from player's position), `positioned <x> <y> <z>` (execute from coordinates - supports absolute coordinates like `100 200 300` or relative coordinates like `~5 ~10 ~` where `~` means current position). Example: `/execute as Player1 run pos`, `/execute positioned ~5 ~ ~-3 run spawn 1234`|8|
|crash|`/crash`|Crashes the server.|9| |crash|`/crash`|Crashes the server.|9|
|rollloot|`/rollloot <loot matrix index> <item id> <amount>`|Given a `loot matrix index`, look for `item id` in that matrix `amount` times and print to the chat box statistics of rolling that loot matrix.|9| |rollloot|`/rollloot <loot matrix index> <item id> <amount>`|Given a `loot matrix index`, look for `item id` in that matrix `amount` times and print to the chat box statistics of rolling that loot matrix.|9|
|castskill|`/castskill <skill id>`|Casts the skill as the player|9| |castskill|`/castskill <skill id>`|Casts the skill as the player|9|