1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-04-24 21:57:44 +00:00

Added basic capture replay

This commit is contained in:
goaaats 2018-01-08 21:42:44 +01:00
parent 8519f118fe
commit da906586ea
5 changed files with 128 additions and 12 deletions

View file

@ -45,16 +45,17 @@ extern Core::ServerZone g_serverZone;
Core::DebugCommandHandler::DebugCommandHandler() Core::DebugCommandHandler::DebugCommandHandler()
{ {
// Push all commands onto the register map ( command name - function - description - required GM level ) // Push all commands onto the register map ( command name - function - description - required GM level )
registerCommand( "set", &DebugCommandHandler::set, "Loads and injects a premade Packet.", 1 ); registerCommand( "set", &DebugCommandHandler::set, "Executes SET commands.", 1 );
registerCommand( "get", &DebugCommandHandler::get, "Loads and injects a premade Packet.", 1 ); registerCommand( "get", &DebugCommandHandler::get, "Executes GET commands.", 1 );
registerCommand( "add", &DebugCommandHandler::add, "Loads and injects a premade Packet.", 1 ); registerCommand( "add", &DebugCommandHandler::add, "Executes ADD commands.", 1 );
registerCommand( "inject", &DebugCommandHandler::injectPacket, "Loads and injects a premade packet.", 1 ); registerCommand( "inject", &DebugCommandHandler::injectPacket, "Loads and injects a premade packet.", 1 );
registerCommand( "injectc", &DebugCommandHandler::injectChatPacket, "Loads and injects a premade chat packet.", 1 ); registerCommand( "injectc", &DebugCommandHandler::injectChatPacket, "Loads and injects a premade chat packet.", 1 );
registerCommand( "nudge", &DebugCommandHandler::nudge, "Nudges you forward/up/down", 1 ); registerCommand( "replay", &DebugCommandHandler::replay, "Replays a saved capture folder.", 1 );
registerCommand( "info", &DebugCommandHandler::serverInfo, "Send server info", 0 ); registerCommand( "nudge", &DebugCommandHandler::nudge, "Nudges you forward/up/down.", 1 );
registerCommand( "unlock", &DebugCommandHandler::unlockCharacter, "Unlock character", 1 ); registerCommand( "info", &DebugCommandHandler::serverInfo, "Show server info.", 0 );
registerCommand( "help", &DebugCommandHandler::help, "Shows registered commands", 0 ); registerCommand( "unlock", &DebugCommandHandler::unlockCharacter, "Unlock character.", 1 );
registerCommand( "script", &DebugCommandHandler::script, "Server script utilities", 1 ); registerCommand( "help", &DebugCommandHandler::help, "Shows registered commands.", 0 );
registerCommand( "script", &DebugCommandHandler::script, "Server script utilities.", 1 );
} }
// clear all loaded commands // clear all loaded commands
@ -455,6 +456,50 @@ void Core::DebugCommandHandler::injectChatPacket( char * data, Entity::Player& p
pSession->getChatConnection()->injectPacket( data + 8, player ); pSession->getChatConnection()->injectPacket( data + 8, player );
} }
void Core::DebugCommandHandler::replay( char * data, Entity::Player& player, boost::shared_ptr< DebugCommand > command )
{
std::string subCommand;
std::string params = "";
// check if the command has parameters
std::string tmpCommand = std::string( data + command->getName().length() + 1 );
std::size_t pos = tmpCommand.find_first_of( " " );
if( pos != std::string::npos )
// command has parameters, grab the first part
subCommand = tmpCommand.substr( 0, pos );
else
// no subcommand given
subCommand = tmpCommand;
if( command->getName().length() + 1 + pos + 1 < strlen( data ) )
params = std::string( data + command->getName().length() + 1 + pos + 1 );
g_log.debug( "[" + std::to_string( player.getId() ) + "] " +
"subCommand " + subCommand + " params: " + params );
if( subCommand == "start" )
{
auto pSession = g_serverZone.getSession( player.getId() );
if( pSession )
pSession->startReplay( params );
}
else if( subCommand == "stop" )
{
auto pSession = g_serverZone.getSession( player.getId() );
if( pSession )
pSession->stopReplay();
}
else
{
player.sendUrgent( subCommand + " is not a valid replay command." );
}
}
void Core::DebugCommandHandler::nudge( char * data, Entity::Player& player, boost::shared_ptr< DebugCommand > command ) void Core::DebugCommandHandler::nudge( char * data, Entity::Player& player, boost::shared_ptr< DebugCommand > command )
{ {
std::string subCommand; std::string subCommand;

View file

@ -38,6 +38,7 @@ public:
void injectPacket( char * data, Entity::Player& player, boost::shared_ptr< DebugCommand > command ); void injectPacket( char * data, Entity::Player& player, boost::shared_ptr< DebugCommand > command );
void injectChatPacket( char * data, Entity::Player& player, boost::shared_ptr< DebugCommand > command ); void injectChatPacket( char * data, Entity::Player& player, boost::shared_ptr< DebugCommand > command );
void replay( char * data, Entity::Player& player, boost::shared_ptr< DebugCommand > command );
void nudge( char* data, Entity::Player& player, boost::shared_ptr< DebugCommand > command ); void nudge( char* data, Entity::Player& player, boost::shared_ptr< DebugCommand > command );
void serverInfo( char * data, Entity::Player& player, boost::shared_ptr< DebugCommand > command ); void serverInfo( char * data, Entity::Player& player, boost::shared_ptr< DebugCommand > command );

View file

@ -307,7 +307,7 @@ void Core::Network::GameConnection::sendSinglePacket( Packets::GamePacket* pPack
sendPackets( &pRP ); sendPackets( &pRP );
} }
void Core::Network::GameConnection::injectPacket( const std::string& packetpath, Core::Entity::Player& pPlayer ) void Core::Network::GameConnection::injectPacket( const std::string& packetpath, Core::Entity::Player& player )
{ {
char packet[0x11570]; char packet[0x11570];
@ -318,7 +318,7 @@ void Core::Network::GameConnection::injectPacket( const std::string& packetpath,
fp = fopen( packetpath.c_str(), "rb" ); fp = fopen( packetpath.c_str(), "rb" );
if( fp == nullptr ) if( fp == nullptr )
{ {
g_log.error( "Packet " + packetpath + " not found!" ); player.sendDebug( "Packet " + packetpath + " not found!" );
return; return;
} }
@ -328,7 +328,7 @@ void Core::Network::GameConnection::injectPacket( const std::string& packetpath,
rewind( fp ); rewind( fp );
if ( fread( packet, sizeof( char ), size, fp ) != size ) if ( fread( packet, sizeof( char ), size, fp ) != size )
{ {
g_log.error( "Packet " + packetpath + " did not read full size: " + std::to_string( size ) ); player.sendDebug( "Packet " + packetpath + " did not read full size: " + std::to_string( size ) );
return; return;
} }
fclose( fp ); fclose( fp );
@ -336,7 +336,7 @@ void Core::Network::GameConnection::injectPacket( const std::string& packetpath,
// cycle through the packet entries and queue each one // cycle through the packet entries and queue each one
for( int32_t k = 0x18; k < size; ) for( int32_t k = 0x18; k < size; )
{ {
uint32_t tmpId = pPlayer.getId(); uint32_t tmpId = player.getId();
// replace ids in the entryheader if needed // replace ids in the entryheader if needed
if( !memcmp( packet + k + 0x04, packet + k + 0x08, 4 ) ) if( !memcmp( packet + k + 0x04, packet + k + 0x08, 4 ) )
{ {

View file

@ -6,6 +6,10 @@
#include "Session.h" #include "Session.h"
#include "Actor/Player.h" #include "Actor/Player.h"
#include <boost/filesystem/operations.hpp>
#include <common/Logging/Logger.h>
extern Core::Logger g_log;
Core::Session::Session( uint32_t sessionId ) Core::Session::Session( uint32_t sessionId )
: m_sessionId( sessionId ) : m_sessionId( sessionId )
@ -107,8 +111,68 @@ void Core::Session::updateLastSqlTime()
m_lastSqlTime = static_cast< uint32_t >( Util::getTimeSeconds() ); m_lastSqlTime = static_cast< uint32_t >( Util::getTimeSeconds() );
} }
void Core::Session::startReplay( const std::string& folderpath )
{
if( !boost::filesystem::exists(folderpath) )
{
getPlayer()->sendDebug( "Couldn't find folder." );
return;
}
m_replayCache.clear();
std::vector<std::tuple<uint64_t, std::string>> loadedSets;
for( auto it = boost::filesystem::directory_iterator( boost::filesystem::path( folderpath ) ); it != boost::filesystem::directory_iterator(); ++it )
{
// Get the filename of the current element
auto filename = it->path().filename().string();
auto unixtime = atoi( filename.substr( 0, 10 ).c_str() );
if( unixtime > 1000000000)
{
loadedSets.push_back( std::tuple<uint64_t, std::string>( unixtime, it->path().string() ) );
}
}
sort( loadedSets.begin(), loadedSets.end(), [ ]( const std::tuple<uint64_t, std::string>& left, const std::tuple<uint64_t, std::string>& right)
{
return std::get<0>( left ) < std::get<0>( right );
} );
int startTime = std::get<0>( loadedSets.at( 0 ) );
for( auto thing : loadedSets )
{
m_replayCache.push_back( std::tuple<uint64_t, std::string>( Util::getTimeSeconds() + ( std::get<0>( thing ) - startTime ), std::get<1>( thing ) ) );
g_log.info( "Registering " + std::get<1>( thing ) + " for " + std::to_string( std::get<0>( thing ) - startTime ) );
}
getPlayer()->sendDebug( "Registered " + std::to_string( m_replayCache.size() ) + " sets for replay" );
m_isReplaying = true;
}
void Core::Session::stopReplay()
{
m_isReplaying = false;
m_replayCache.clear();
}
void Core::Session::update() void Core::Session::update()
{ {
if( m_isReplaying )
{
int at = 0;
for( auto const& set : m_replayCache ) {
if( std::get<0>( set ) == Util::getTimeSeconds() )
{
m_pZoneConnection->injectPacket( std::get<1>( set ), *getPlayer().get() );
m_replayCache.erase( m_replayCache.begin() + at );
}
at++;
}
}
if( m_pZoneConnection ) if( m_pZoneConnection )
{ {
m_pZoneConnection->processInQueue(); m_pZoneConnection->processInQueue();

View file

@ -26,6 +26,9 @@ namespace Core {
void updateLastDataTime(); void updateLastDataTime();
void updateLastSqlTime(); void updateLastSqlTime();
void startReplay( const std::string& folderpath );
void stopReplay();
void close(); void close();
uint32_t getId() const; uint32_t getId() const;
@ -48,6 +51,9 @@ namespace Core {
uint32_t m_lastSqlTime; uint32_t m_lastSqlTime;
bool m_isValid; bool m_isValid;
bool m_isReplaying;
std::vector<std::tuple<uint64_t, std::string>> m_replayCache;
Network::GameConnectionPtr m_pZoneConnection; Network::GameConnectionPtr m_pZoneConnection;
Network::GameConnectionPtr m_pChatConnection; Network::GameConnectionPtr m_pChatConnection;