1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-04-22 04:37:47 +00:00
sapphire/src/servers/sapphire_zone/Network/Handlers/GMCommandHandlers.cpp

573 lines
18 KiB
C++
Raw Normal View History

#include <boost/format.hpp>
2018-03-06 22:22:19 +01:00
#include <Common.h>
#include <Network/CommonNetwork.h>
#include <Network/GamePacketNew.h>
#include <Logging/Logger.h>
#include <Network/PacketContainer.h>
#include <Network/CommonActorControl.h>
2018-07-06 19:47:35 +10:00
#include <Network/PacketDef/Zone/ClientZoneDef.h>
#include <unordered_map>
#include "Network/GameConnection.h"
#include "Session.h"
2018-01-27 23:52:49 +01:00
#include "Zone/TerritoryMgr.h"
#include "Zone/Zone.h"
2018-03-15 23:37:21 +01:00
#include "Zone/InstanceContent.h"
#include "Network/PacketWrappers/InitUIPacket.h"
#include "Network/PacketWrappers/PingPacket.h"
#include "Network/PacketWrappers/MoveActorPacket.h"
#include "Network/PacketWrappers/ChatPacket.h"
#include "Network/PacketWrappers/ServerNoticePacket.h"
#include "Network/PacketWrappers/ActorControlPacket142.h"
#include "Network/PacketWrappers/ActorControlPacket143.h"
#include "Network/PacketWrappers/ActorControlPacket144.h"
#include "Network/PacketWrappers/EventStartPacket.h"
#include "Network/PacketWrappers/EventFinishPacket.h"
#include "Network/PacketWrappers/PlayerStateFlagsPacket.h"
#include "ServerZone.h"
#include "Framework.h"
extern Core::Framework g_fw;
using namespace Core::Common;
using namespace Core::Network::Packets;
using namespace Core::Network::Packets::Server;
using namespace Core::Network::ActorControl;
enum GmCommand
{
2017-09-11 18:59:50 +02:00
Pos = 0x0000,
Lv = 0x0001,
Race = 0x0002,
Tribe = 0x0003,
Sex = 0x0004,
Time = 0x0005,
Weather = 0x0006,
Call = 0x0007,
Inspect = 0x0008,
Speed = 0x0009,
Invis = 0x000D,
Raise = 0x0010,
Kill = 0x000E,
Icon = 0x0012,
Hp = 0x0064,
Mp = 0x0065,
Tp = 0x0066,
Gp = 0x0067,
Exp = 0x0068,
2017-10-01 01:14:43 +02:00
Inv = 0x006A,
2017-09-11 18:59:50 +02:00
2017-10-09 20:09:49 +02:00
Orchestrion = 0x0074,
2017-09-11 18:59:50 +02:00
Item = 0x00C8,
Gil = 0x00C9,
Collect = 0x00CA,
QuestAccept = 0x012C,
QuestCancel = 0x012D,
QuestComplete = 0x012E,
QuestIncomplete = 0x012F,
QuestSequence = 0x0130,
QuestInspect = 0x0131,
GC = 0x0154,
GCRank = 0x0155,
2017-10-04 11:48:58 +02:00
Aetheryte = 0x015E,
Teri = 0x0258,
Kick = 0x025C,
2017-09-22 17:15:10 +10:00
TeriInfo = 0x025D,
2017-09-11 18:59:50 +02:00
Jump = 0x025E,
JumpNpc = 0x025F,
};
void Core::Network::GameConnection::gm1Handler( const Packets::FFXIVARR_PACKET_RAW& inPacket, Entity::Player& player )
{
if( player.getGmRank() <= 0 )
2017-09-11 18:59:50 +02:00
return;
const auto packet = ZoneChannelPacket< Client::FFXIVIpcGmCommand1 >( inPacket );
const auto& commandId = packet.data().commandId;
const auto& param1 = packet.data().param1;
const auto& param2 = packet.data().param2;
const auto& param3 = packet.data().param3;
2017-09-11 18:59:50 +02:00
auto pLog = g_fw.get< Logger >();
pLog->debug( player.getName() + " used GM1 commandId: " + std::to_string( commandId ) +
2017-09-11 18:59:50 +02:00
", params: " + std::to_string( param1 ) + ", " +
std::to_string( param2 ) + ", " + std::to_string( param3 ) );
Core::Entity::ActorPtr targetActor;
2017-09-11 18:59:50 +02:00
if( player.getId() == param3 )
2017-09-11 18:59:50 +02:00
{
targetActor = player.getAsPlayer();
2017-09-11 18:59:50 +02:00
}
else
{
auto inRange = player.getInRangeActors();
for( auto& actor : inRange )
2017-09-11 18:59:50 +02:00
{
if( actor->getId() == param3 )
targetActor = actor;
2017-09-11 18:59:50 +02:00
}
}
if( !targetActor )
return;
auto targetPlayer = targetActor->getAsPlayer();
switch( commandId )
{
case GmCommand::Lv:
2017-09-11 18:59:50 +02:00
{
targetPlayer->setLevel( param1 );
player.sendNotice( "Level for " + targetPlayer->getName() + " was set to " + std::to_string( param1 ) );
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::Race:
2017-09-11 18:59:50 +02:00
{
targetPlayer->setLookAt( CharaLook::Race, param1 );
player.sendNotice( "Race for " + targetPlayer->getName() + " was set to " + std::to_string( param1 ) );
targetPlayer->spawn( targetPlayer );
auto inRange = targetPlayer->getInRangeActors();
for( auto actor : inRange )
{
targetPlayer->despawn( actor->getAsPlayer() );
targetPlayer->spawn( actor->getAsPlayer() );
}
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::Tribe:
2017-09-11 18:59:50 +02:00
{
targetPlayer->setLookAt( CharaLook::Tribe, param1 );
player.sendNotice( "Tribe for " + targetPlayer->getName() + " was set to " + std::to_string( param1 ) );
targetPlayer->spawn( targetPlayer );
auto inRange = targetPlayer->getInRangeActors();
for( auto actor : inRange )
{
targetPlayer->despawn( actor->getAsPlayer() );
targetPlayer->spawn( actor->getAsPlayer() );
}
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::Sex:
2017-09-11 18:59:50 +02:00
{
targetPlayer->setLookAt( CharaLook::Gender, param1 );
player.sendNotice( "Sex for " + targetPlayer->getName() + " was set to " + std::to_string( param1 ) );
targetPlayer->spawn( targetPlayer );
auto inRange = targetActor->getInRangeActors();
for( auto actor : inRange )
{
targetPlayer->despawn( actor->getAsPlayer() );
targetPlayer->spawn( actor->getAsPlayer() );
}
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::Time:
2017-09-11 18:59:50 +02:00
{
player.setEorzeaTimeOffset( param2 );
player.sendNotice( "Eorzea time offset: " + std::to_string( param2 ) );
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::Weather:
2017-09-11 18:59:50 +02:00
{
targetPlayer->getCurrentZone()->setWeatherOverride( static_cast< Common::Weather >( param1 ) );
player.sendNotice( "Weather in Zone \"" + targetPlayer->getCurrentZone()->getName() + "\" of " +
targetPlayer->getName() + " set in range." );
break;
}
2018-01-20 02:04:38 +11:00
case GmCommand::Call:
{
if( targetPlayer->getZoneId() != player.getZoneId() )
2018-01-20 02:04:38 +11:00
targetPlayer->setZone( player.getZoneId() );
targetPlayer->changePosition( player.getPos().x, player.getPos().y, player.getPos().z, player.getRot() );
2018-01-20 02:04:38 +11:00
player.sendNotice( "Calling " + targetPlayer->getName() );
break;
}
case GmCommand::Inspect:
{
player.sendNotice( "Name: " + targetPlayer->getName() +
"\nGil: " + std::to_string( targetPlayer->getCurrency( CurrencyType::Gil ) ) +
"\nZone: " + targetPlayer->getCurrentZone()->getName() +
"(" + std::to_string( targetPlayer->getZoneId() ) + ")" +
"\nClass: " + std::to_string( static_cast< uint8_t >( targetPlayer->getClass() ) ) +
"\nLevel: " + std::to_string( targetPlayer->getLevel() ) +
"\nExp: " + std::to_string( targetPlayer->getExp() ) +
"\nSearchMessage: " + targetPlayer->getSearchMessage() +
"\nPlayTime: " + std::to_string( targetPlayer->getPlayTime() ) );
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::Speed:
{
2018-06-28 00:07:07 +02:00
targetPlayer->queuePacket( boost::make_shared< ActorControlPacket143 >( player.getId(), Flee, param1 ) );
player.sendNotice( "Speed for " + targetPlayer->getName() + " was set to " + std::to_string( param1 ) );
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::Invis:
{
2018-04-19 22:47:03 +10:00
player.setGmInvis( !player.getGmInvis() );
player.sendNotice( "Invisibility flag for " + player.getName() +
" was toggled to " + std::to_string( !player.getGmInvis() ) );
for( auto actor : player.getInRangeActors() )
{
2018-04-19 22:47:03 +10:00
player.despawn( actor->getAsPlayer() );
player.spawn( actor->getAsPlayer() );
}
2018-04-19 22:47:03 +10:00
break;
}
case GmCommand::Kill:
2017-09-11 18:59:50 +02:00
{
targetActor->getAsChara()->takeDamage( 9999999 );
player.sendNotice( "Killed " + std::to_string( targetActor->getId() ) );
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::Icon:
2017-09-11 18:59:50 +02:00
{
targetPlayer->setOnlineStatusMask( param1 );
2018-06-28 00:07:07 +02:00
auto statusPacket = makeZonePacket< FFXIVIpcSetOnlineStatus >( player.getId() );
statusPacket->data().onlineStatusFlags = param1;
queueOutPacket( statusPacket );
2018-06-28 00:07:07 +02:00
auto searchInfoPacket = makeZonePacket< FFXIVIpcSetSearchInfo >( player.getId() );
searchInfoPacket->data().onlineStatusFlags = param1;
searchInfoPacket->data().selectRegion = targetPlayer->getSearchSelectRegion();
strcpy( searchInfoPacket->data().searchMessage, targetPlayer->getSearchMessage() );
targetPlayer->queuePacket( searchInfoPacket );
2018-06-28 00:07:07 +02:00
targetPlayer->sendToInRangeSet( boost::make_shared< ActorControlPacket142 >( player.getId(), SetStatusIcon,
static_cast< uint8_t >( player.getOnlineStatus() ) ),
true );
player.sendNotice( "Icon for " + targetPlayer->getName() + " was set to " + std::to_string( param1 ) );
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::Hp:
{
targetPlayer->setHp( param1 );
player.sendNotice( "Hp for " + targetPlayer->getName() + " was set to " + std::to_string( param1 ) );
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::Mp:
{
targetPlayer->setMp( param1 );
player.sendNotice( "Mp for " + targetPlayer->getName() + " was set to " + std::to_string( param1 ) );
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::Gp:
{
targetPlayer->setHp( param1 );
player.sendNotice( "Gp for " + targetPlayer->getName() + " was set to " + std::to_string( param1 ) );
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::Exp:
{
targetPlayer->gainExp( param1 );
player.sendNotice( std::to_string( param1 ) + " Exp was added to " + targetPlayer->getName() );
break;
}
case GmCommand::Inv:
2017-09-11 18:59:50 +02:00
{
if( targetActor->getAsChara()->getInvincibilityType() == Common::InvincibilityType::InvincibilityRefill )
targetActor->getAsChara()->setInvincibilityType( Common::InvincibilityType::InvincibilityNone );
else
targetActor->getAsChara()->setInvincibilityType( Common::InvincibilityType::InvincibilityRefill );
player.sendNotice( "Invincibility for " + targetPlayer->getName() +
" was switched." );
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::Orchestrion:
2017-09-11 18:59:50 +02:00
{
if( param1 == 1 )
2017-09-11 18:59:50 +02:00
{
if( param2 == 0 )
{
for( uint8_t i = 0; i < 255; i++ )
targetActor->getAsPlayer()->learnSong( i, 0 );
player.sendNotice( "All Songs for " + targetPlayer->getName() +
" were turned on." );
}
else
{
targetActor->getAsPlayer()->learnSong( param2, 0 );
player.sendNotice( "Song " + std::to_string( param2 ) + " for " + targetPlayer->getName() +
" was turned on." );
}
2017-09-11 18:59:50 +02:00
}
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::Item:
{
auto quantity = param2;
if( quantity < 1 || quantity > 999 )
2017-09-11 18:59:50 +02:00
{
quantity = 1;
2017-09-11 18:59:50 +02:00
}
if( ( param1 == 0xcccccccc ) )
{
player.sendUrgent( "Syntaxerror." );
2017-09-11 18:59:50 +02:00
return;
}
if( !targetPlayer->addItem( param1, quantity ) )
player.sendUrgent( "Item " + std::to_string( param1 ) + " could not be added to inventory." );
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::Gil:
2017-09-11 18:59:50 +02:00
{
targetPlayer->addCurrency( CurrencyType::Gil, param1 );
2018-07-26 23:38:58 +10:00
player.sendNotice( "Added " + std::to_string( param1 ) + " Gil for " + targetPlayer->getName() );
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::Collect:
{
uint32_t gil = targetPlayer->getCurrency( CurrencyType::Gil );
2017-09-11 18:59:50 +02:00
if( gil < param1 )
2017-09-11 18:59:50 +02:00
{
player.sendUrgent( "Player does not have enough Gil(" + std::to_string( gil ) + ")" );
2017-09-11 18:59:50 +02:00
}
else
{
targetPlayer->removeCurrency( CurrencyType::Gil, param1 );
player.sendNotice( "Removed " + std::to_string( param1 ) +
2017-09-11 18:59:50 +02:00
" Gil from " + targetPlayer->getName() +
"(" + std::to_string( gil ) + " before)" );
}
break;
}
case GmCommand::QuestAccept:
2017-09-11 18:59:50 +02:00
{
targetPlayer->updateQuest( param1, 1 );
break;
}
case GmCommand::QuestCancel:
{
targetPlayer->removeQuest( param1 );
break;
}
case GmCommand::QuestComplete:
{
targetPlayer->finishQuest( param1 );
break;
}
case GmCommand::QuestIncomplete:
{
targetPlayer->unfinishQuest( param1 );
break;
}
case GmCommand::QuestSequence:
{
targetPlayer->updateQuest( param1, param2 );
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::GC:
{
targetPlayer->setGc( param1 );
player.sendNotice( "GC for " + targetPlayer->getName() +
2017-09-11 18:59:50 +02:00
" was set to " + std::to_string( targetPlayer->getGc() ) );
break;
}
case GmCommand::GCRank:
{
targetPlayer->setGcRankAt( targetPlayer->getGc() - 1, param1 );
player.sendNotice( "GC Rank for " + targetPlayer->getName() +
2017-09-11 18:59:50 +02:00
" for GC " + std::to_string( targetPlayer->getGc() ) +
" was set to " + std::to_string( targetPlayer->getGcRankArray()[targetPlayer->getGc() - 1] ) );
break;
}
2017-10-04 11:48:58 +02:00
case GmCommand::Aetheryte:
{
if( param1 == 0 )
2017-10-04 11:48:58 +02:00
{
if( param2 == 0 )
2017-10-04 11:48:58 +02:00
{
for( uint8_t i = 0; i < 255; i++ )
2017-10-04 11:48:58 +02:00
targetActor->getAsPlayer()->registerAetheryte( i );
player.sendNotice( "All Aetherytes for " + targetPlayer->getName() +
" were turned on." );
2017-10-04 11:48:58 +02:00
}
else
{
targetActor->getAsPlayer()->registerAetheryte( param2 );
player.sendNotice( "Aetheryte " + std::to_string( param2 ) + " for " + targetPlayer->getName() +
2017-10-04 11:48:58 +02:00
" was turned on." );
}
}
2017-10-09 20:09:49 +02:00
break;
}
case GmCommand::Teri:
2017-10-09 20:09:49 +02:00
{
auto pTeriMgr = g_fw.get< TerritoryMgr >();
if( auto instance = pTeriMgr->getInstanceZonePtr( param1 ) )
2017-10-09 20:09:49 +02:00
{
2018-01-29 00:40:34 +11:00
player.sendDebug( "Found instance: " + instance->getName() + ", id: " + std::to_string( param1 ) );
2018-03-15 23:37:21 +01:00
// if the zone is an instanceContent instance, make sure the player is actually bound to it
auto pInstance = instance->getAsInstanceContent();
// pInstance will be nullptr if you're accessing a normal zone via its allocated instance id rather than its zoneid
if( pInstance && !pInstance->isPlayerBound( player.getId() ) )
2018-03-15 23:37:21 +01:00
{
player.sendUrgent( "Not able to join instance: " + std::to_string( param1 ) );
player.sendUrgent( "Player not bound! ( run !instance bind <instanceId> first ) " + std::to_string( param1 ) );
break;
}
player.setInstance( instance );
}
else if( !pTeriMgr->isValidTerritory( param1 ) )
2017-10-09 20:09:49 +02:00
{
player.sendUrgent( "Invalid zone " + std::to_string( param1 ) );
}
else
{
auto pZone = pTeriMgr->getZoneByTerriId( param1 );
2018-01-27 23:52:49 +01:00
if( !pZone )
{
player.sendUrgent( "No zone instance found for " + std::to_string( param1 ) );
break;
}
2018-03-15 23:37:21 +01:00
targetPlayer->setPos( targetPlayer->getPos() );
targetPlayer->performZoning( param1, targetPlayer->getPos(), 0 );
2018-03-15 23:37:21 +01:00
player.sendNotice( targetPlayer->getName() + " was warped to zone " +
std::to_string( param1 ) + " (" + pZone->getName() + ")" );
2017-10-09 20:09:49 +02:00
}
2017-10-04 11:48:58 +02:00
break;
}
case GmCommand::TeriInfo:
{
auto pCurrentZone = player.getCurrentZone();
player.sendNotice( "ZoneId: " + std::to_string( player.getZoneId() ) +
"\nName: " + pCurrentZone->getName() +
"\nInternalName: " + pCurrentZone->getInternalName() +
"\nGuId: " + std::to_string( pCurrentZone->getGuId() ) +
"\nPopCount: " + std::to_string( pCurrentZone->getPopCount() ) +
"\nCurrentWeather: " + std::to_string( static_cast< uint8_t >( pCurrentZone->getCurrentWeather() ) ) +
"\nNextWeather: " + std::to_string( static_cast< uint8_t >( pCurrentZone->getNextWeather() ) ) );
break;
}
case GmCommand::Jump:
{
2017-09-11 18:59:50 +02:00
auto inRange = player.getInRangeActors();
player.changePosition( targetActor->getPos().x, targetActor->getPos().y, targetActor->getPos().z,
targetActor->getRot() );
player.sendNotice( "Jumping to " + targetPlayer->getName() + " in range." );
break;
}
2017-09-11 18:59:50 +02:00
default:
player.sendUrgent( "GM1 Command not implemented: " + std::to_string( commandId ) );
2017-09-11 18:59:50 +02:00
break;
}
}
void Core::Network::GameConnection::gm2Handler( const Packets::FFXIVARR_PACKET_RAW& inPacket, Entity::Player& player )
{
if( player.getGmRank() <= 0 )
2017-09-11 18:59:50 +02:00
return;
auto pLog = g_fw.get< Logger >();
auto pServerZone = g_fw.get< ServerZone >();
2017-09-11 18:59:50 +02:00
const auto packet = ZoneChannelPacket< Client::FFXIVIpcGmCommand2 >( inPacket );
const auto& commandId = packet.data().commandId;
const auto& param1 = std::string( packet.data().param1 );
2017-09-11 18:59:50 +02:00
pLog->debug( player.getName() + " used GM2 commandId: " + std::to_string( commandId ) + ", params: " + param1 );
2017-09-11 18:59:50 +02:00
auto targetSession = pServerZone->getSession( param1 );
Core::Entity::CharaPtr targetActor;
2017-09-11 18:59:50 +02:00
if( targetSession != nullptr )
{
targetActor = targetSession->getPlayer();
}
else
{
if( param1 == "self" )
{
targetActor = player.getAsPlayer();
2017-09-11 18:59:50 +02:00
}
else
{
player.sendUrgent( "Player " + param1 + " not found on this server." );
2017-09-11 18:59:50 +02:00
return;
}
}
if( !targetActor )
return;
2017-09-11 18:59:50 +02:00
auto targetPlayer = targetActor->getAsPlayer();
switch( commandId )
{
case GmCommand::Raise:
{
targetPlayer->resetHp();
targetPlayer->resetMp();
targetPlayer->setStatus( Entity::Chara::ActorStatus::Idle );
targetPlayer->sendZoneInPackets( 0x01, 0x01, 0, 113, true );
2017-09-11 18:59:50 +02:00
2018-06-28 00:07:07 +02:00
targetPlayer->sendToInRangeSet( boost::make_shared< ActorControlPacket143 >( player.getId(), ZoneIn, 0x01, 0x01, 0, 113 ), true );
targetPlayer->sendToInRangeSet( boost::make_shared< ActorControlPacket142 >( player.getId(), SetStatus,
static_cast< uint8_t >( Entity::Chara::ActorStatus::Idle ) ), true );
player.sendNotice( "Raised " + targetPlayer->getName() );
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::Jump:
{
if( targetPlayer->getZoneId() != player.getZoneId() )
2017-09-11 18:59:50 +02:00
{
player.setZone( targetPlayer->getZoneId() );
2017-09-11 18:59:50 +02:00
}
player.changePosition( targetActor->getPos().x, targetActor->getPos().y, targetActor->getPos().z,
targetActor->getRot() );
player.sendNotice( "Jumping to " + targetPlayer->getName() );
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::Call:
{
// We shouldn't be able to call a player into an instance, only call them out of one
if( player.getCurrentInstance() )
{
2018-07-10 20:25:08 +10:00
player.sendUrgent( "You are unable to call a player while bound to a battle instance." );
return;
}
targetPlayer->setInstance( player.getCurrentZone() );
targetPlayer->changePosition( player.getPos().x, player.getPos().y, player.getPos().z, player.getRot() );
player.sendNotice( "Calling " + targetPlayer->getName() );
break;
}
2017-09-11 18:59:50 +02:00
default:
player.sendUrgent( "GM2 Command not implemented: " + std::to_string( commandId ) );
2017-09-11 18:59:50 +02:00
break;
}
}