mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2025-08-05 18:24:12 +00:00
feat: allow for teleporting to player or relative position (#1683)
* allow for teleporting to player or relative position * Update Commands.md * Update Commands.md * Update SlashCommandHandler.cpp
This commit is contained in:
@@ -287,8 +287,8 @@ void SlashCommandHandler::Startup() {
|
||||
RegisterCommand(SpawnPhysicsVertsCommand);
|
||||
|
||||
Command TeleportCommand{
|
||||
.help = "Teleports you",
|
||||
.info = "Teleports you. If no Y is given, you are teleported to the height of the terrain or physics object at (x, z)",
|
||||
.help = "Teleports you to a position or a player to another player.",
|
||||
.info = "Teleports you. If no Y is given, you are teleported to the height of the terrain or physics object at (x, z). Any of the coordinates can use the syntax of an exact position (10.0), or a relative position (~+10.0). A ~ means use the current value of that axis as the base value. Addition or subtraction is supported (~+10) (~-10). If source player and target player are players that exist in the world, then the source player will be teleported to target player.",
|
||||
.aliases = { "teleport", "tele", "tp" },
|
||||
.handle = DEVGMCommands::Teleport,
|
||||
.requiredLevel = eGameMasterLevel::JUNIOR_DEVELOPER
|
||||
|
@@ -555,25 +555,45 @@ namespace DEVGMCommands {
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<float> ParseRelativeAxis(const float sourcePos, const std::string& toParse) {
|
||||
if (toParse.empty()) return std::nullopt;
|
||||
|
||||
// relative offset from current position
|
||||
if (toParse[0] == '~') {
|
||||
if (toParse.size() == 1) return sourcePos;
|
||||
|
||||
if (toParse.size() < 3 || !(toParse[1] != '+' || toParse[1] != '-')) return std::nullopt;
|
||||
|
||||
const auto offset = GeneralUtils::TryParse<float>(toParse.substr(2));
|
||||
if (!offset.has_value()) return std::nullopt;
|
||||
|
||||
bool isNegative = toParse[1] == '-';
|
||||
return isNegative ? sourcePos - offset.value() : sourcePos + offset.value();
|
||||
}
|
||||
|
||||
return GeneralUtils::TryParse<float>(toParse);
|
||||
}
|
||||
|
||||
void Teleport(Entity* entity, const SystemAddress& sysAddr, const std::string args) {
|
||||
const auto splitArgs = GeneralUtils::SplitString(args, ' ');
|
||||
|
||||
const auto& sourcePos = entity->GetPosition();
|
||||
NiPoint3 pos{};
|
||||
auto* sourceEntity = entity;
|
||||
if (splitArgs.size() == 3) {
|
||||
|
||||
const auto x = GeneralUtils::TryParse<float>(splitArgs.at(0));
|
||||
const auto x = ParseRelativeAxis(sourcePos.x, splitArgs[0]);
|
||||
if (!x) {
|
||||
ChatPackets::SendSystemMessage(sysAddr, u"Invalid x.");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto y = GeneralUtils::TryParse<float>(splitArgs.at(1));
|
||||
const auto y = ParseRelativeAxis(sourcePos.y, splitArgs[1]);
|
||||
if (!y) {
|
||||
ChatPackets::SendSystemMessage(sysAddr, u"Invalid y.");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto z = GeneralUtils::TryParse<float>(splitArgs.at(2));
|
||||
const auto z = ParseRelativeAxis(sourcePos.z, splitArgs[2]);
|
||||
if (!z) {
|
||||
ChatPackets::SendSystemMessage(sysAddr, u"Invalid z.");
|
||||
return;
|
||||
@@ -584,32 +604,39 @@ namespace DEVGMCommands {
|
||||
pos.SetZ(z.value());
|
||||
|
||||
LOG("Teleporting objectID: %llu to %f, %f, %f", entity->GetObjectID(), pos.x, pos.y, pos.z);
|
||||
GameMessages::SendTeleport(entity->GetObjectID(), pos, NiQuaternion(), sysAddr);
|
||||
} else if (splitArgs.size() == 2) {
|
||||
const auto x = ParseRelativeAxis(sourcePos.x, splitArgs[0]);
|
||||
auto* sourcePlayer = PlayerManager::GetPlayer(splitArgs[0]);
|
||||
if (!x && !sourcePlayer) {
|
||||
ChatPackets::SendSystemMessage(sysAddr, u"Invalid x or source player not found.");
|
||||
return;
|
||||
}
|
||||
if (sourcePlayer) sourceEntity = sourcePlayer;
|
||||
|
||||
const auto x = GeneralUtils::TryParse<float>(splitArgs.at(0));
|
||||
if (!x) {
|
||||
ChatPackets::SendSystemMessage(sysAddr, u"Invalid x.");
|
||||
const auto z = ParseRelativeAxis(sourcePos.z, splitArgs[1]);
|
||||
const auto* const targetPlayer = PlayerManager::GetPlayer(splitArgs[1]);
|
||||
if (!z && !targetPlayer) {
|
||||
ChatPackets::SendSystemMessage(sysAddr, u"Invalid z or target player not found.");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto z = GeneralUtils::TryParse<float>(splitArgs.at(1));
|
||||
if (!z) {
|
||||
ChatPackets::SendSystemMessage(sysAddr, u"Invalid z.");
|
||||
if (x && z) {
|
||||
pos.SetX(x.value());
|
||||
pos.SetY(0.0f);
|
||||
pos.SetZ(z.value());
|
||||
} else if (sourcePlayer && targetPlayer) {
|
||||
pos = targetPlayer->GetPosition();
|
||||
} else {
|
||||
ChatPackets::SendSystemMessage(sysAddr, u"Unable to teleport.");
|
||||
return;
|
||||
}
|
||||
|
||||
pos.SetX(x.value());
|
||||
pos.SetY(0.0f);
|
||||
pos.SetZ(z.value());
|
||||
|
||||
LOG("Teleporting objectID: %llu to X: %f, Z: %f", entity->GetObjectID(), pos.x, pos.z);
|
||||
GameMessages::SendTeleport(entity->GetObjectID(), pos, NiQuaternion(), sysAddr);
|
||||
} else {
|
||||
ChatPackets::SendSystemMessage(sysAddr, u"Correct usage: /teleport <x> (<y>) <z> - if no Y given, will teleport to the height of the terrain (or any physics object).");
|
||||
}
|
||||
GameMessages::SendTeleport(sourceEntity->GetObjectID(), pos, sourceEntity->GetRotation(), sourceEntity->GetSystemAddress());
|
||||
|
||||
auto* possessorComponent = entity->GetComponent<PossessorComponent>();
|
||||
auto* possessorComponent = sourceEntity->GetComponent<PossessorComponent>();
|
||||
if (possessorComponent) {
|
||||
auto* possassableEntity = Game::entityManager->GetEntity(possessorComponent->GetPossessable());
|
||||
|
||||
|
Reference in New Issue
Block a user