Merge branch 'main' into naming-of-models

This commit is contained in:
David Markowitz 2024-05-23 19:51:45 -07:00
commit d4e6939dbd
8 changed files with 550 additions and 44 deletions

View File

@ -32,6 +32,8 @@
#include "eGameMasterLevel.h"
#include "eMissionState.h"
#include "dNavMesh.h"
#include "eGameActivity.h"
#include "eStateChangeType.h"
std::unordered_map<LWOOBJID, LWOOBJID> PetComponent::currentActivities{};
std::unordered_map<LWOOBJID, LWOOBJID> PetComponent::activePets{};
@ -210,24 +212,23 @@ void PetComponent::OnUse(Entity* originator) {
if (dpWorld::IsLoaded()) {
NiPoint3 attempt = petPosition + forward * interactionDistance;
float y = dpWorld::GetNavMesh()->GetHeightAtPoint(attempt);
NiPoint3 nearestPoint = dpWorld::GetNavMesh()->NearestPoint(attempt);
while (std::abs(y - petPosition.y) > 4 && interactionDistance > 10) {
while (std::abs(nearestPoint.y - petPosition.y) > 4 && interactionDistance > 10) {
const NiPoint3 forward = m_Parent->GetRotation().GetForwardVector();
attempt = originatorPosition + forward * interactionDistance;
y = dpWorld::GetNavMesh()->GetHeightAtPoint(attempt);
nearestPoint = dpWorld::GetNavMesh()->NearestPoint(attempt);
interactionDistance -= 0.5f;
}
position = attempt;
position = nearestPoint;
} else {
position = petPosition + forward * interactionDistance;
}
auto rotation = NiQuaternion::LookAt(position, petPosition);
GameMessages::SendNotifyPetTamingMinigame(
@ -246,11 +247,11 @@ void PetComponent::OnUse(Entity* originator) {
m_Parent->GetObjectID(),
LWOOBJID_EMPTY,
originator->GetObjectID(),
true,
false,
ePetTamingNotifyType::BEGIN,
petPosition,
position,
rotation,
NiPoint3Constant::ZERO,
NiPoint3Constant::ZERO,
NiQuaternion(0.0f, 0.0f, 0.0f, 0.0f),
UNASSIGNED_SYSTEM_ADDRESS
);
@ -258,11 +259,18 @@ void PetComponent::OnUse(Entity* originator) {
m_Tamer = originator->GetObjectID();
SetStatus(5);
Game::entityManager->SerializeEntity(m_Parent);
currentActivities.insert_or_assign(m_Tamer, m_Parent->GetObjectID());
// Notify the start of a pet taming minigame
m_Parent->GetScript()->OnNotifyPetTamingMinigame(m_Parent, originator, ePetTamingNotifyType::BEGIN);
auto* characterComponent = originator->GetComponent<CharacterComponent>();
if (characterComponent != nullptr) {
characterComponent->SetCurrentActivity(eGameActivity::PET_TAMING);
Game::entityManager->SerializeEntity(originator);
}
}
void PetComponent::Update(float deltaTime) {
@ -627,6 +635,11 @@ void PetComponent::RequestSetPetName(std::u16string name) {
UNASSIGNED_SYSTEM_ADDRESS
);
auto* characterComponent = tamer->GetComponent<CharacterComponent>();
if (characterComponent != nullptr) {
characterComponent->SetCurrentActivity(eGameActivity::NONE);
Game::entityManager->SerializeEntity(tamer);
}
GameMessages::SendTerminateInteraction(m_Tamer, eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID());
auto* modelEntity = Game::entityManager->GetEntity(m_ModelId);
@ -666,6 +679,11 @@ void PetComponent::ClientExitTamingMinigame(bool voluntaryExit) {
UNASSIGNED_SYSTEM_ADDRESS
);
auto* characterComponent = tamer->GetComponent<CharacterComponent>();
if (characterComponent != nullptr) {
characterComponent->SetCurrentActivity(eGameActivity::NONE);
Game::entityManager->SerializeEntity(tamer);
}
GameMessages::SendNotifyTamingModelLoadedOnServer(m_Tamer, tamer->GetSystemAddress());
GameMessages::SendTerminateInteraction(m_Tamer, eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID());
@ -712,6 +730,11 @@ void PetComponent::ClientFailTamingMinigame() {
UNASSIGNED_SYSTEM_ADDRESS
);
auto* characterComponent = tamer->GetComponent<CharacterComponent>();
if (characterComponent != nullptr) {
characterComponent->SetCurrentActivity(eGameActivity::NONE);
Game::entityManager->SerializeEntity(tamer);
}
GameMessages::SendNotifyTamingModelLoadedOnServer(m_Tamer, tamer->GetSystemAddress());
GameMessages::SendTerminateInteraction(m_Tamer, eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID());

View File

@ -562,3 +562,35 @@ void Item::LoadConfigXml(const tinyxml2::XMLElement& i) {
config.push_back(LDFBaseData::DataFromString(value));
}
}
void Item::SaveConfigXml(tinyxml2::XMLElement& i) const {
tinyxml2::XMLElement* x = nullptr;
for (const auto* config : this->config) {
const auto& key = GeneralUtils::UTF16ToWTF8(config->GetKey());
const auto saveKey = ExtraSettingAbbreviations.find(key);
if (saveKey == ExtraSettingAbbreviations.end()) {
continue;
}
if (!x) {
x = i.InsertNewChildElement("x");
}
const auto dataToSave = config->GetString(false);
x->SetAttribute(saveKey->second.c_str(), dataToSave.c_str());
}
}
void Item::LoadConfigXml(const tinyxml2::XMLElement& i) {
const auto* x = i.FirstChildElement("x");
if (!x) return;
for (const auto& pair : ExtraSettingAbbreviations) {
const auto* data = x->Attribute(pair.second.c_str());
if (!data) continue;
const auto value = pair.first + "=" + data;
config.push_back(LDFBaseData::DataFromString(value));
}
}

View File

@ -454,6 +454,16 @@ void Mission::YieldRewards() {
}
}
// Even with no repeatable column, reputation is repeatable
if (info.reward_reputation > 0) {
missionComponent->Progress(eMissionTaskType::EARN_REPUTATION, 0, LWOOBJID_EMPTY, "", info.reward_reputation);
auto* const character = entity->GetComponent<CharacterComponent>();
if (character) {
character->SetReputation(character->GetReputation() + info.reward_reputation);
GameMessages::SendUpdateReputation(entity->GetObjectID(), character->GetReputation(), entity->GetSystemAddress());
}
}
if (m_Completions > 0) {
std::vector<std::pair<LOT, uint32_t>> items;
@ -532,15 +542,6 @@ void Mission::YieldRewards() {
modelInventory->SetSize(modelInventory->GetSize() + info.reward_bankinventory);
}
if (info.reward_reputation > 0) {
missionComponent->Progress(eMissionTaskType::EARN_REPUTATION, 0, 0L, "", info.reward_reputation);
auto character = entity->GetComponent<CharacterComponent>();
if (character) {
character->SetReputation(character->GetReputation() + info.reward_reputation);
GameMessages::SendUpdateReputation(entity->GetObjectID(), character->GetReputation(), entity->GetSystemAddress());
}
}
if (info.reward_maxhealth > 0) {
destroyableComponent->SetMaxHealth(destroyableComponent->GetMaxHealth() + static_cast<float>(info.reward_maxhealth), true);
}

View File

@ -8,6 +8,7 @@
#include "SlashCommandHandler.h"
#include <iomanip>
#include <ranges>
#include "DEVGMCommands.h"
#include "GMGreaterThanZeroCommands.h"
@ -60,11 +61,9 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& chat, Entity*
if (commandHandle.requiredLevel > eGameMasterLevel::CIVILIAN) Database::Get()->InsertSlashCommandUsage(entity->GetObjectID(), input);
commandHandle.handle(entity, sysAddr, args);
} else if (entity->GetGMLevel() != eGameMasterLevel::CIVILIAN) {
// We don't need to tell civilians they aren't high enough level
error = "You are not high enough GM level to use \"" + command + "\"";
}
} else if (entity->GetGMLevel() == eGameMasterLevel::CIVILIAN) {
// We don't need to tell civilians commands don't exist
error = "Command " + command + " does not exist!";
}
@ -75,32 +74,74 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& chat, Entity*
void GMZeroCommands::Help(Entity* entity, const SystemAddress& sysAddr, const std::string args) {
std::ostringstream feedback;
if (args.empty()) {
feedback << "----- Commands -----";
for (const auto& [alias, command] : CommandInfos) {
// TODO: Limit displaying commands based on GM level they require
if (command.requiredLevel > entity->GetGMLevel()) continue;
LOG("Help command: %s", alias.c_str());
feedback << "\n/" << alias << ": " << command.help;
constexpr size_t pageSize = 10;
std::string trimmedArgs = args;
trimmedArgs.erase(trimmedArgs.begin(), std::find_if_not(trimmedArgs.begin(), trimmedArgs.end(), [](unsigned char ch) {
return std::isspace(ch);
}));
trimmedArgs.erase(std::find_if_not(trimmedArgs.rbegin(), trimmedArgs.rend(), [](unsigned char ch) {
return std::isspace(ch);
}).base(), trimmedArgs.end());
std::optional<uint32_t> parsedPage = GeneralUtils::TryParse<uint32_t>(trimmedArgs);
if (trimmedArgs.empty() || parsedPage.has_value()) {
size_t page = parsedPage.value_or(1);
std::map<std::string, Command> accessibleCommands;
for (const auto& [commandName, command] : CommandInfos) {
if (command.requiredLevel <= entity->GetGMLevel()) {
accessibleCommands.emplace(commandName, command);
}
}
size_t totalPages = (accessibleCommands.size() + pageSize - 1) / pageSize;
if (page < 1 || page > totalPages) {
feedback << "Invalid page number. Total pages: " << totalPages;
GameMessages::SendSlashCommandFeedbackText(entity, GeneralUtils::ASCIIToUTF16(feedback.str()));
return;
}
auto it = accessibleCommands.begin();
std::advance(it, (page - 1) * pageSize);
size_t endIdx = std::min(page * pageSize, accessibleCommands.size());
feedback << "----- Commands (Page " << page << " of " << totalPages << ") -----";
for (size_t i = (page - 1) * pageSize; i < endIdx; ++i, ++it) {
feedback << "\n/" << it->first << ": " << it->second.help;
}
const auto feedbackStr = feedback.str();
if (!feedbackStr.empty()) {
GameMessages::SendSlashCommandFeedbackText(entity, GeneralUtils::ASCIIToUTF16(feedbackStr));
}
return;
}
auto it = std::ranges::find_if(CommandInfos, [&trimmedArgs](const auto& pair) {
return std::ranges::find(pair.second.aliases, trimmedArgs) != pair.second.aliases.end();
});
if (it != CommandInfos.end() && entity->GetGMLevel() >= it->second.requiredLevel) {
const auto& command = it->second;
feedback << "----- " << it->first << " Info -----\n";
feedback << command.info << "\n";
if (command.aliases.size() > 1) {
feedback << "Aliases: ";
for (size_t i = 0; i < command.aliases.size(); ++i) {
if (i > 0) feedback << ", ";
feedback << command.aliases[i];
}
}
} else {
auto it = CommandInfos.find(args);
if (it != CommandInfos.end() && entity->GetGMLevel() >= it->second.requiredLevel) {
feedback << "----- " << args << " -----\n";
feedback << it->second.info;
if (it->second.aliases.size() > 1) {
feedback << "\nAliases: ";
for (size_t i = 0; i < it->second.aliases.size(); i++) {
if (i > 0) feedback << ", ";
feedback << it->second.aliases[i];
}
}
} else if (entity->GetGMLevel() > eGameMasterLevel::CIVILIAN) {
feedback << "Command " << std::quoted(args) << " does not exist!";
}
feedback << "Command not found.";
}
const auto feedbackStr = feedback.str();
if (!feedbackStr.empty()) GameMessages::SendSlashCommandFeedbackText(entity, GeneralUtils::ASCIIToUTF16(feedbackStr));
if (!feedbackStr.empty()) {
GameMessages::SendSlashCommandFeedbackText(entity, GeneralUtils::ASCIIToUTF16(feedbackStr));
}
}
void SlashCommandHandler::SendAnnouncement(const std::string& title, const std::string& message) {
@ -1007,4 +1048,383 @@ void SlashCommandHandler::Startup() {
};
RegisterCommand(InstanceInfoCommand);
//Commands that are handled by the client
Command faqCommand{
.help = "Show the LU FAQ Page",
.info = "Show the LU FAQ Page",
.aliases = {"faq","faqs"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(faqCommand);
Command teamChatCommand{
.help = "Send a message to your teammates.",
.info = "Send a message to your teammates.",
.aliases = {"team","t"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(teamChatCommand);
Command showStoreCommand{
.help = "Show the LEGO shop page.",
.info = "Show the LEGO shop page.",
.aliases = {"shop","store"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(showStoreCommand);
Command minigamesCommand{
.help = "Show the LEGO minigames page!",
.info = "Show the LEGO minigames page!",
.aliases = {"minigames"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(minigamesCommand);
Command forumsCommand{
.help = "Show the LU Forums!",
.info = "Show the LU Forums!",
.aliases = {"forums"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(forumsCommand);
Command exitGameCommand{
.help = "Exit to desktop",
.info = "Exit to desktop",
.aliases = {"exit","quit"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(exitGameCommand);
Command thumbsUpCommand{
.help = "Oh, yeah!",
.info = "Oh, yeah!",
.aliases = {"thumb","thumbs","thumbsup"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(thumbsUpCommand);
Command victoryCommand{
.help = "Victory!",
.info = "Victory!",
.aliases = {"victory!"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(victoryCommand);
Command backflipCommand{
.help = "Do a flip!",
.info = "Do a flip!",
.aliases = {"backflip"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(backflipCommand);
Command clapCommand{
.help = "A round of applause!",
.info = "A round of applause!",
.aliases = {"clap"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(clapCommand);
Command logoutCharacterCommand{
.help = "Returns you to the character select screen.",
.info = "Returns you to the character select screen.",
.aliases = {"camp","logoutcharacter"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(logoutCharacterCommand);
Command sayCommand{
.help = "Say something outloud so that everyone can hear you",
.info = "Say something outloud so that everyone can hear you",
.aliases = {"s","say"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(sayCommand);
Command whisperCommand{
.help = "Send a private message to another player.",
.info = "Send a private message to another player.",
.aliases = {"tell","w","whisper"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(whisperCommand);
Command locationCommand{
.help = "Output your current location on the map to the chat box.",
.info = "Output your current location on the map to the chat box.",
.aliases = {"loc","locate","location"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(locationCommand);
Command logoutCommand{
.help = "Returns you to the login screen.",
.info = "Returns you to the login screen.",
.aliases = {"logout","logoutaccount"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(logoutCommand);
Command shrugCommand{
.help = "I dunno...",
.info = "I dunno...",
.aliases = {"shrug"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(shrugCommand);
Command leaveTeamCommand{
.help = "Leave your current team.",
.info = "Leave your current team.",
.aliases = {"leave","leaveteam","teamleave","tleave"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(leaveTeamCommand);
Command teamLootTypeCommand{
.help = "[rr|ffa] Set the loot for your current team (round-robin/free for all).",
.info = "[rr|ffa] Set the loot for your current team (round-robin/free for all).",
.aliases = {"setloot","teamsetloot","tloot","tsetloot"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(teamLootTypeCommand);
Command removeFriendCommand{
.help = "[name] Removes a player from your friends list.",
.info = "[name] Removes a player from your friends list.",
.aliases = {"removefriend"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(removeFriendCommand);
Command yesCommand{
.help = "Aye aye, captain!",
.info = "Aye aye, captain!",
.aliases = {"yes"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(yesCommand);
Command teamInviteCommand{
.help = "[name] Invite a player to your team.",
.info = "[name] Invite a player to your team.",
.aliases = {"invite","inviteteam","teaminvite","tinvite"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(teamInviteCommand);
Command danceCommand{
.help = "Dance 'til you can't dance no more.",
.info = "Dance 'til you can't dance no more.",
.aliases = {"dance"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(danceCommand);
Command sighCommand{
.help = "Another day, another brick.",
.info = "Another day, another brick.",
.aliases = {"sigh"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(sighCommand);
Command recommendedOptionsCommand{
.help = "Sets the recommended performance options in the cfg file",
.info = "Sets the recommended performance options in the cfg file",
.aliases = {"recommendedperfoptions"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(recommendedOptionsCommand);
Command setTeamLeaderCommand{
.help = "[name] Set the leader for your current team.",
.info = "[name] Set the leader for your current team.",
.aliases = {"leader","setleader","teamsetleader","tleader","tsetleader"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(setTeamLeaderCommand);
Command cringeCommand{
.help = "I don't even want to talk about it...",
.info = "I don't even want to talk about it...",
.aliases = {"cringe"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(cringeCommand);
Command talkCommand{
.help = "Jibber Jabber",
.info = "Jibber Jabber",
.aliases = {"talk"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(talkCommand);
Command cancelQueueCommand{
.help = "Cancel Your position in the queue if you are in one.",
.info = "Cancel Your position in the queue if you are in one.",
.aliases = {"cancelqueue"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(cancelQueueCommand);
Command lowPerformanceCommand{
.help = "Sets the default low-spec performance options in the cfg file",
.info = "Sets the default low-spec performance options in the cfg file",
.aliases = {"perfoptionslow"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(lowPerformanceCommand);
Command kickFromTeamCommand{
.help = "[name] Kick a player from your current team.",
.info = "[name] Kick a player from your current team.",
.aliases = {"kick","kickplayer","teamkickplayer","tkick","tkickplayer"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(kickFromTeamCommand);
Command thanksCommand{
.help = "Express your gratitude for another.",
.info = "Express your gratitude for another.",
.aliases = {"thanks"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(thanksCommand);
Command waveCommand{
.help = "Wave to other players.",
.info = "Wave to other players.",
.aliases = {"wave"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(waveCommand);
Command whyCommand{
.help = "Why|!?!!",
.info = "Why|!?!!",
.aliases = {"why"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(whyCommand);
Command midPerformanceCommand{
.help = "Sets the default medium-spec performance options in the cfg file",
.info = "Sets the default medium-spec performance options in the cfg file",
.aliases = {"perfoptionsmid"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(midPerformanceCommand);
Command highPerformanceCommand{
.help = "Sets the default high-spec performance options in the cfg file",
.info = "Sets the default high-spec performance options in the cfg file",
.aliases = {"perfoptionshigh"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(highPerformanceCommand);
Command gaspCommand{
.help = "Oh my goodness!",
.info = "Oh my goodness!",
.aliases = {"gasp"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(gaspCommand);
Command ignoreCommand{
.help = "[name] Add a player to your ignore list.",
.info = "[name] Add a player to your ignore list.",
.aliases = {"addignore"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(ignoreCommand);
Command addFriendCommand{
.help = "[name] Add a player to your friends list.",
.info = "[name] Add a player to your friends list.",
.aliases = {"addfriend"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(addFriendCommand);
Command cryCommand{
.help = "Show everyone your 'Aw' face.",
.info = "Show everyone your 'Aw' face.",
.aliases = {"cry"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(cryCommand);
Command giggleCommand{
.help = "A good little chuckle",
.info = "A good little chuckle",
.aliases = {"giggle"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(giggleCommand);
Command saluteCommand{
.help = "For those about to build...",
.info = "For those about to build...",
.aliases = {"salute"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(saluteCommand);
Command removeIgnoreCommand{
.help = "[name] Removes a player from your ignore list.",
.info = "[name] Removes a player from your ignore list.",
.aliases = {"removeIgnore"},
.handle = GMZeroCommands::ClientHandled,
.requiredLevel = eGameMasterLevel::CIVILIAN
};
RegisterCommand(removeIgnoreCommand);
}

View File

@ -224,5 +224,9 @@ namespace GMZeroCommands {
ChatPackets::SendSystemMessage(sysAddr, u"Map: " + (GeneralUtils::to_u16string(zoneId.GetMapID())) + u"\nClone: " + (GeneralUtils::to_u16string(zoneId.GetCloneID())) + u"\nInstance: " + (GeneralUtils::to_u16string(zoneId.GetInstanceID())));
}
//For client side commands
void ClientHandled(Entity* entity, const SystemAddress& sysAddr, const std::string args) {}
};

View File

@ -15,6 +15,7 @@ namespace GMZeroCommands {
void LeaveZone(Entity* entity, const SystemAddress& sysAddr, const std::string args);
void Resurrect(Entity* entity, const SystemAddress& sysAddr, const std::string args);
void InstanceInfo(Entity* entity, const SystemAddress& sysAddr, const std::string args);
void ClientHandled(Entity* entity, const SystemAddress& sysAddr, const std::string args);
}
#endif //!GMZEROCOMMANDS_H

View File

@ -112,6 +112,31 @@ void dNavMesh::LoadNavmesh() {
m_NavMesh = mesh;
}
NiPoint3 dNavMesh::NearestPoint(const NiPoint3& location, const float halfExtent) const {
NiPoint3 toReturn = location;
if (m_NavMesh != nullptr) {
float pos[3];
pos[0] = location.x;
pos[1] = location.y;
pos[2] = location.z;
dtPolyRef nearestRef = 0;
float polyPickExt[3] = { halfExtent, halfExtent, halfExtent };
float nearestPoint[3] = { 0.0f, 0.0f, 0.0f };
dtQueryFilter filter{};
auto hasPoly = m_NavQuery->findNearestPoly(pos, polyPickExt, &filter, &nearestRef, nearestPoint);
if (hasPoly != DT_SUCCESS) {
toReturn = location;
} else {
toReturn.x = nearestPoint[0];
toReturn.y = nearestPoint[1];
toReturn.z = nearestPoint[2];
}
}
return toReturn;
}
float dNavMesh::GetHeightAtPoint(const NiPoint3& location, const float halfExtentsHeight) const {
if (m_NavMesh == nullptr) {
return location.y;

View File

@ -29,7 +29,7 @@ public:
*/
float GetHeightAtPoint(const NiPoint3& location, const float halfExtentsHeight = 32.0f) const;
std::vector<NiPoint3> GetPath(const NiPoint3& startPos, const NiPoint3& endPos, float speed = 10.0f);
NiPoint3 NearestPoint(const NiPoint3& location, const float halfExtent = 32.0f) const;
bool IsNavmeshLoaded() { return m_NavMesh != nullptr; }
private: