Code owners
Assign users and groups as approvers for specific file changes. Learn more.
alchatcommand.cpp 10.95 KiB
/**
* @file alchatcommand.cpp
* @brief ALChatCommand implementation for chat input commands
*
* $LicenseInfo:firstyear=2013&license=viewerlgpl$
* Copyright (C) 2013 Drake Arconis
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* $/LicenseInfo$
**/
#include "llviewerprecompiledheaders.h"
#include "alchatcommand.h"
// lib includes
#include "llcalc.h"
#include "llparcel.h"
#include "llstring.h"
#include "material_codes.h"
#include "object_flags.h"
// viewer includes
#include "alaoengine.h"
#include "llagent.h"
#include "llagentcamera.h"
#include "llagentui.h"
#include "llcommandhandler.h"
#include "llfloaterimnearbychat.h"
#include "llfloaterreg.h"
#include "llfloaterregioninfo.h"
#include "llnotificationsutil.h"
#include "llregioninfomodel.h"
#include "llstartup.h"
#include "lltrans.h"
#include "llviewercontrol.h"
#include "llviewermessage.h"
#include "llviewerobjectlist.h"
#include "llviewerparcelmgr.h"
#include "llviewerregion.h"
#include "llvoavatarself.h"
#include "llvolume.h"
#include "llvolumemessage.h"
bool ALChatCommand::parseCommand(std::string data)
{
static LLCachedControl<bool> enableChatCmd(gSavedSettings, "AlchemyChatCommandEnable", true);
if (enableChatCmd)
{
utf8str_tolower(data);
std::istringstream input(data);
std::string cmd;
if (!(input >> cmd)) return false;
static LLCachedControl<std::string> sDrawDistanceCommand(gSavedSettings, "AlchemyChatCommandDrawDistance", "/dd");
static LLCachedControl<std::string> sHeightCommand(gSavedSettings, "AlchemyChatCommandHeight", "/gth");
static LLCachedControl<std::string> sGroundCommand(gSavedSettings, "AlchemyChatCommandGround", "/flr");
static LLCachedControl<std::string> sPosCommand(gSavedSettings, "AlchemyChatCommandPos", "/pos");
static LLCachedControl<std::string> sRezPlatCommand(gSavedSettings, "AlchemyChatCommandRezPlat", "/plat");
static LLCachedControl<std::string> sHomeCommand(gSavedSettings, "AlchemyChatCommandHome", "/home");
static LLCachedControl<std::string> sSetHomeCommand(gSavedSettings, "AlchemyChatCommandSetHome", "/sethome");
static LLCachedControl<std::string> sCalcCommand(gSavedSettings, "AlchemyChatCommandCalc", "/calc");
static LLCachedControl<std::string> sMaptoCommand(gSavedSettings, "AlchemyChatCommandMapto", "/mapto");
static LLCachedControl<std::string> sClearCommand(gSavedSettings, "AlchemyChatCommandClearNearby", "/clr");
static LLCachedControl<std::string> sRegionMsgCommand(gSavedSettings, "AlchemyChatCommandRegionMessage", "/regionmsg");
static LLCachedControl<std::string> sSetNearbyChatChannelCmd(gSavedSettings, "AlchemyChatCommandSetChatChannel", "/setchannel");
static LLCachedControl<std::string> sResyncAnimCommand(gSavedSettings, "AlchemyChatCommandResyncAnim", "/resync");
static LLCachedControl<std::string> sTeleportToCam(gSavedSettings, "AlchemyChatCommandTeleportToCam", "/tp2cam");
static LLCachedControl<std::string> sHoverHeight(gSavedSettings, "AlchemyChatCommandHoverHeight", "/hover");
static LLCachedControl<std::string> sAOCommand(gSavedSettings, "AlchemyChatCommandAnimationOverride", "/ao");
if (cmd == utf8str_tolower(sDrawDistanceCommand())) // dd
{
F32 dist;
if (input >> dist)
{
dist = llclamp(dist, 16.f, 512.f);
gSavedSettings.setF32("RenderFarClip", dist);
gAgentCamera.mDrawDistance = dist;
return true;
}
}
else if (cmd == utf8str_tolower(sHeightCommand())) // gth
{
F64 z;
if (input >> z)
{
LLVector3d pos_global = gAgent.getPositionGlobal();
pos_global.mdV[VZ] = z;
gAgent.teleportViaLocation(pos_global);
return true;
}
}
else if (cmd == utf8str_tolower(sGroundCommand())) // flr
{
LLVector3d pos_global = gAgent.getPositionGlobal();
pos_global.mdV[VZ] = 0.0;
gAgent.teleportViaLocation(pos_global);
return true;
}
else if (cmd == utf8str_tolower(sPosCommand())) // pos
{
F64 x, y, z;
if ((input >> x) && (input >> y) && (input >> z))
{
LLViewerRegion* regionp = gAgent.getRegion();
if (regionp)
{
LLVector3d target_pos = regionp->getPosGlobalFromRegion(LLVector3((F32) x, (F32) y, (F32) z));
gAgent.teleportViaLocation(target_pos);
}
return true;
}
}
else if (cmd == utf8str_tolower(sRezPlatCommand())) // plat
{
F32 size;
if (!(input >> size))
size = static_cast<F32>(gSavedSettings.getF32("AlchemyChatCommandRezPlatSize"));
const LLVector3& agent_pos = gAgent.getPositionAgent();
const LLVector3 rez_pos(agent_pos.mV[VX], agent_pos.mV[VY], agent_pos.mV[VZ] - ((gAgentAvatarp->getScale().mV[VZ] / 2.f) + 0.25f + (gAgent.getVelocity().magVec() * 0.333f)));
LLMessageSystem* msg = gMessageSystem;
msg->newMessageFast(_PREHASH_ObjectAdd);
msg->nextBlockFast(_PREHASH_AgentData);
msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
LLUUID group_id = gAgent.getGroupForRezzing();
msg->addUUIDFast(_PREHASH_GroupID, group_id);
msg->nextBlockFast(_PREHASH_ObjectData);
msg->addU8Fast(_PREHASH_PCode, LL_PCODE_VOLUME);
msg->addU8Fast(_PREHASH_Material, LL_MCODE_STONE);
msg->addU32Fast(_PREHASH_AddFlags, agent_pos.mV[VZ] > 4096.f ? FLAGS_CREATE_SELECTED : 0U);
LLVolumeParams volume_params;
volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
volume_params.setBeginAndEndS(0.f, 1.f);
volume_params.setBeginAndEndT(0.f, 1.f);
volume_params.setRatio(1.f, 1.f);
volume_params.setShear(0.f, 0.f);
LLVolumeMessage::packVolumeParams(&volume_params, msg);
msg->addVector3Fast(_PREHASH_Scale, LLVector3(size, size, 0.25f));
msg->addQuatFast(_PREHASH_Rotation, LLQuaternion());
msg->addVector3Fast(_PREHASH_RayStart, rez_pos);
msg->addVector3Fast(_PREHASH_RayEnd, rez_pos);
msg->addUUIDFast(_PREHASH_RayTargetID, LLUUID::null);
msg->addU8Fast(_PREHASH_BypassRaycast, TRUE);
msg->addU8Fast(_PREHASH_RayEndIsIntersection, FALSE);
msg->addU8Fast(_PREHASH_State, FALSE);
msg->sendReliable(gAgent.getRegionHost());
return true;
}
else if (cmd == utf8str_tolower(sHomeCommand())) // home
{
gAgent.teleportHome();
return true;
}
else if (cmd == utf8str_tolower(sSetHomeCommand())) // sethome
{
gAgent.setStartPosition(START_LOCATION_ID_HOME);
return true;
}
else if (cmd == utf8str_tolower(sCalcCommand())) // calc
{
if (data.length() > cmd.length() + 1)
{
F32 result = 0.f;
std::string expr = data.substr(cmd.length() + 1);
LLStringUtil::toUpper(expr);
if (LLCalc::getInstance()->evalString(expr, result))
{
LLSD args;
args["EXPRESSION"] = expr;
args["RESULT"] = result;
LLNotificationsUtil::add("ChatCommandCalc", args);
return true;
}
LLNotificationsUtil::add("ChatCommandCalcFailed");
return true;
}
}
else if (cmd == utf8str_tolower(sMaptoCommand())) // mapto
{
const std::string::size_type length = cmd.length() + 1;
if (data.length() > length)
{
const LLVector3d& pos = gAgent.getPositionGlobal();
LLSD params;
params.append(data.substr(length));
params.append(fmodf(static_cast<F32>(pos.mdV[VX]), REGION_WIDTH_METERS));
params.append(fmodf(static_cast<F32>(pos.mdV[VY]), REGION_WIDTH_METERS));
params.append(fmodf(static_cast<F32>(pos.mdV[VZ]), REGION_HEIGHT_METERS));
LLCommandDispatcher::dispatch("teleport", params, LLSD(), nullptr, "clicked", true);
return true;
}
}
else if (cmd == utf8str_tolower(sClearCommand()))
{
LLFloaterIMNearbyChat* nearby_chat = LLFloaterReg::findTypedInstance<LLFloaterIMNearbyChat>("nearby_chat");
if (nearby_chat)
{
nearby_chat->reloadMessages(true);
}
return true;
}
else if (cmd == "/droll")
{
S32 dice_sides;
if (!(input >> dice_sides))
dice_sides = 6;
LLSD args;
args["RESULT"] = (ll_rand(dice_sides) + 1);
LLNotificationsUtil::add("ChatCommandDiceRoll", args);
return true;
}
else if (cmd == utf8str_tolower(sRegionMsgCommand())) // Region Message / Dialog
{
if (data.length() > cmd.length() + 1)
{
std::string notification_message = data.substr(cmd.length() + 1);
std::vector<std::string> strings(5, "-1");
// [0] grid_x, unused here
// [1] grid_y, unused here
strings[2] = gAgentID.asString(); // [2] agent_id of sender
// [3] senter name
std::string name;
LLAgentUI::buildFullname(name);
strings[3] = name;
strings[4] = notification_message; // [4] message
LLRegionInfoModel::sendEstateOwnerMessage(gMessageSystem, "simulatormessage", LLFloaterRegionInfo::getLastInvoice(), strings);
return true;
}
}
else if (cmd == utf8str_tolower(sSetNearbyChatChannelCmd())) // Set nearby chat channel
{
S32 chan;
if (input >> chan)
{
gSavedSettings.setS32("AlchemyNearbyChatChannel", chan);
return true;
}
}
else if (cmd == utf8str_tolower(sTeleportToCam()))
{
gAgent.teleportViaLocation(gAgentCamera.getCameraPositionGlobal());
return true;
}
else if (cmd == utf8str_tolower(sHoverHeight())) // Hover height
{
F32 height;
if (input >> height)
{
gSavedPerAccountSettings.set("AvatarHoverOffsetZ",
llclamp<F32>(height, MIN_HOVER_Z, MAX_HOVER_Z));
return true;
}
}
else if (cmd == utf8str_tolower(sResyncAnimCommand())) // Resync Animations
{
for (S32 i = 0; i < gObjectList.getNumObjects(); i++)
{
LLViewerObject* object = gObjectList.getObject(i);
if (object && object->isAvatar())
{
LLVOAvatar* avatarp = (LLVOAvatar*)object;
if (avatarp)
{
for (const std::pair<LLUUID, S32> playpair : avatarp->mPlayingAnimations)
{
avatarp->stopMotion(playpair.first, TRUE);
avatarp->startMotion(playpair.first);
}
}
}
}
return true;
}
else if (cmd == utf8str_tolower(sAOCommand()))
{
std::string subcmd;
if (input >> subcmd)
{
if (subcmd == "on")
{
gSavedPerAccountSettings.setBOOL("AlchemyAOEnable", TRUE);
return true;
}
else if (subcmd == "off")
{
gSavedPerAccountSettings.setBOOL("AlchemyAOEnable", FALSE);
return true;
}
else if (subcmd == "sit")
{
auto ao_set = ALAOEngine::instance().getSetByName(ALAOEngine::instance().getCurrentSetName());
if (input >> subcmd)
{
if (subcmd == "on")
{
ALAOEngine::instance().setOverrideSits(ao_set, true);
}
else if (subcmd == "off")
{
ALAOEngine::instance().setOverrideSits(ao_set, false);
}
}
else
{
ALAOEngine::instance().setOverrideSits(ao_set, !ao_set->getSitOverride());
}
return true;
}
}
}
}
return false;
}