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:
parent
8519f118fe
commit
da906586ea
5 changed files with 128 additions and 12 deletions
|
@ -45,16 +45,17 @@ extern Core::ServerZone g_serverZone;
|
|||
Core::DebugCommandHandler::DebugCommandHandler()
|
||||
{
|
||||
// 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( "get", &DebugCommandHandler::get, "Loads and injects a premade Packet.", 1 );
|
||||
registerCommand( "add", &DebugCommandHandler::add, "Loads and injects a premade Packet.", 1 );
|
||||
registerCommand( "set", &DebugCommandHandler::set, "Executes SET commands.", 1 );
|
||||
registerCommand( "get", &DebugCommandHandler::get, "Executes GET commands.", 1 );
|
||||
registerCommand( "add", &DebugCommandHandler::add, "Executes ADD commands.", 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( "nudge", &DebugCommandHandler::nudge, "Nudges you forward/up/down", 1 );
|
||||
registerCommand( "info", &DebugCommandHandler::serverInfo, "Send server info", 0 );
|
||||
registerCommand( "unlock", &DebugCommandHandler::unlockCharacter, "Unlock character", 1 );
|
||||
registerCommand( "help", &DebugCommandHandler::help, "Shows registered commands", 0 );
|
||||
registerCommand( "script", &DebugCommandHandler::script, "Server script utilities", 1 );
|
||||
registerCommand( "replay", &DebugCommandHandler::replay, "Replays a saved capture folder.", 1 );
|
||||
registerCommand( "nudge", &DebugCommandHandler::nudge, "Nudges you forward/up/down.", 1 );
|
||||
registerCommand( "info", &DebugCommandHandler::serverInfo, "Show server info.", 0 );
|
||||
registerCommand( "unlock", &DebugCommandHandler::unlockCharacter, "Unlock character.", 1 );
|
||||
registerCommand( "help", &DebugCommandHandler::help, "Shows registered commands.", 0 );
|
||||
registerCommand( "script", &DebugCommandHandler::script, "Server script utilities.", 1 );
|
||||
}
|
||||
|
||||
// clear all loaded commands
|
||||
|
@ -455,6 +456,50 @@ void Core::DebugCommandHandler::injectChatPacket( char * data, Entity::Player& p
|
|||
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 )
|
||||
{
|
||||
std::string subCommand;
|
||||
|
|
|
@ -38,6 +38,7 @@ public:
|
|||
|
||||
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 replay( 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 );
|
||||
|
||||
|
|
|
@ -307,7 +307,7 @@ void Core::Network::GameConnection::sendSinglePacket( Packets::GamePacket* pPack
|
|||
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];
|
||||
|
@ -318,7 +318,7 @@ void Core::Network::GameConnection::injectPacket( const std::string& packetpath,
|
|||
fp = fopen( packetpath.c_str(), "rb" );
|
||||
if( fp == nullptr )
|
||||
{
|
||||
g_log.error( "Packet " + packetpath + " not found!" );
|
||||
player.sendDebug( "Packet " + packetpath + " not found!" );
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -328,7 +328,7 @@ void Core::Network::GameConnection::injectPacket( const std::string& packetpath,
|
|||
rewind( fp );
|
||||
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;
|
||||
}
|
||||
fclose( fp );
|
||||
|
@ -336,7 +336,7 @@ void Core::Network::GameConnection::injectPacket( const std::string& packetpath,
|
|||
// cycle through the packet entries and queue each one
|
||||
for( int32_t k = 0x18; k < size; )
|
||||
{
|
||||
uint32_t tmpId = pPlayer.getId();
|
||||
uint32_t tmpId = player.getId();
|
||||
// replace ids in the entryheader if needed
|
||||
if( !memcmp( packet + k + 0x04, packet + k + 0x08, 4 ) )
|
||||
{
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
#include "Session.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 )
|
||||
: m_sessionId( sessionId )
|
||||
|
@ -107,8 +111,68 @@ void Core::Session::updateLastSqlTime()
|
|||
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()
|
||||
{
|
||||
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 )
|
||||
{
|
||||
m_pZoneConnection->processInQueue();
|
||||
|
|
|
@ -26,6 +26,9 @@ namespace Core {
|
|||
void updateLastDataTime();
|
||||
void updateLastSqlTime();
|
||||
|
||||
void startReplay( const std::string& folderpath );
|
||||
void stopReplay();
|
||||
|
||||
void close();
|
||||
|
||||
uint32_t getId() const;
|
||||
|
@ -48,6 +51,9 @@ namespace Core {
|
|||
uint32_t m_lastSqlTime;
|
||||
bool m_isValid;
|
||||
|
||||
bool m_isReplaying;
|
||||
std::vector<std::tuple<uint64_t, std::string>> m_replayCache;
|
||||
|
||||
Network::GameConnectionPtr m_pZoneConnection;
|
||||
Network::GameConnectionPtr m_pChatConnection;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue