2022-02-27 07:53:44 -05:00
# include <STDInclude.hpp>
2022-12-26 07:07:24 -05:00
# include "Playlist.hpp"
2017-01-19 16:23:59 -05:00
namespace Components
{
std : : string Playlist : : CurrentPlaylistBuffer ;
std : : string Playlist : : ReceivedPlaylistBuffer ;
std : : unordered_map < const void * , std : : string > Playlist : : MapRelocation ;
void Playlist : : LoadPlaylist ( )
{
// Check if playlist already loaded
2022-12-25 12:23:53 -05:00
if ( * Game : : s_havePlaylists ) return ;
2017-01-19 16:23:59 -05:00
// Don't load playlists when dedi and no party
if ( Dedicated : : IsEnabled ( ) & & ! Dvar : : Var ( " party_enable " ) . get < bool > ( ) )
{
2022-12-25 12:23:53 -05:00
* Game : : s_havePlaylists = true ;
2017-01-19 16:23:59 -05:00
Dvar : : Var ( " xblive_privateserver " ) . set ( true ) ;
return ;
}
Dvar : : Var ( " xblive_privateserver " ) . set ( false ) ;
2022-12-25 12:23:53 -05:00
const auto playlistFilename = Dvar : : Var ( " playlistFilename " ) . get < std : : string > ( ) ;
2017-01-19 16:23:59 -05:00
FileSystem : : File playlist ( playlistFilename ) ;
if ( playlist . exists ( ) )
{
2022-06-12 17:07:53 -04:00
Logger : : Print ( " Parsing playlist '{}'... \n " , playlist . getName ( ) ) ;
2017-01-19 16:23:59 -05:00
Game : : Playlist_ParsePlaylists ( playlist . getBuffer ( ) . data ( ) ) ;
2022-12-25 12:23:53 -05:00
* Game : : s_havePlaylists = true ;
2017-01-19 16:23:59 -05:00
}
else
{
2022-06-12 17:07:53 -04:00
Logger : : Print ( " Unable to load playlist '{}'! \n " , playlist . getName ( ) ) ;
2017-01-19 16:23:59 -05:00
}
}
2022-12-25 12:23:53 -05:00
char * Playlist : : Com_ParseOnLine_Hk ( const char * * data_p )
2017-01-19 16:23:59 -05:00
{
2022-12-25 12:23:53 -05:00
MapRelocation . clear ( ) ;
CurrentPlaylistBuffer = Utils : : Compression : : ZLib : : Compress ( * data_p ) ;
return Game : : Com_ParseOnLine ( data_p ) ;
2017-01-19 16:23:59 -05:00
}
2022-05-20 18:12:46 -04:00
void Playlist : : PlaylistRequest ( const Network : : Address & address , [[maybe_unused]] const std : : string & data )
2017-01-19 16:23:59 -05:00
{
2022-12-25 12:23:53 -05:00
const auto * password = ( * Game : : g_password ) - > current . string ;
2022-05-20 18:12:46 -04:00
2022-12-25 12:23:53 -05:00
if ( * password )
2017-06-21 23:17:13 -04:00
{
if ( password ! = data )
{
Network : : SendCommand ( address , " playlistInvalidPassword " ) ;
return ;
}
}
2017-01-19 16:23:59 -05:00
Logger : : Print ( " Received playlist request, sending currently stored buffer. \n " ) ;
2022-12-25 12:23:53 -05:00
std : : string compressedList = CurrentPlaylistBuffer ;
2017-01-19 16:23:59 -05:00
Proto : : Party : : Playlist list ;
list . set_hash ( Utils : : Cryptography : : JenkinsOneAtATime : : Compute ( compressedList ) ) ;
list . set_buffer ( compressedList ) ;
Network : : SendCommand ( address , " playlistResponse " , list . SerializeAsString ( ) ) ;
}
2022-12-25 12:23:53 -05:00
void Playlist : : PlaylistResponse ( const Network : : Address & address , [[maybe_unused]] const std : : string & data )
2017-01-19 16:23:59 -05:00
{
2022-12-25 12:23:53 -05:00
if ( ! Party : : PlaylistAwaiting ( ) )
2017-01-19 16:23:59 -05:00
{
2022-12-25 12:23:53 -05:00
Logger : : Print ( " Received stray playlist response, ignoring it. \n " ) ;
return ;
}
if ( address ! = Party : : Target ( ) )
{
Logger : : Print ( " Received playlist from someone else than our target host, ignoring it. \n " ) ;
return ;
}
Proto : : Party : : Playlist list ;
if ( ! list . ParseFromString ( data ) )
{
Party : : PlaylistError ( std : : format ( " Received playlist response from {}, but it is invalid. " , address . getString ( ) ) ) ;
ReceivedPlaylistBuffer . clear ( ) ;
2017-01-19 16:23:59 -05:00
}
else
{
2022-12-25 12:23:53 -05:00
// Generate buffer and hash
const auto & compressedData = list . buffer ( ) ;
const auto hash = Utils : : Cryptography : : JenkinsOneAtATime : : Compute ( compressedData ) ;
// Validate hashes
if ( hash ! = list . hash ( ) )
{
Party : : PlaylistError ( std : : format ( " Received playlist response from {}, but the checksum did not match ({} != {}). " , address . getString ( ) , list . hash ( ) , hash ) ) ;
ReceivedPlaylistBuffer . clear ( ) ;
return ;
}
// Decompress buffer
ReceivedPlaylistBuffer = Utils : : Compression : : ZLib : : Decompress ( compressedData ) ;
// Load and continue connection
Logger : : Print ( " Received playlist, loading and continuing connection... \n " ) ;
Game : : Playlist_ParsePlaylists ( ReceivedPlaylistBuffer . data ( ) ) ;
Party : : PlaylistContinue ( ) ;
2017-01-19 16:23:59 -05:00
}
}
2022-05-20 18:12:46 -04:00
void Playlist : : PlaylistInvalidPassword ( [[maybe_unused]] const Network::Address& address, [[maybe_unused]] const std : : string & data )
2017-06-21 23:17:13 -04:00
{
Party : : PlaylistError ( " Error: Invalid Password for Party. " ) ;
}
2022-12-25 12:23:53 -05:00
void Playlist : : MapNameCopy ( char * dest , const char * src , int destsize )
2017-01-19 16:23:59 -05:00
{
Utils : : Hook : : Call < void ( char * , const char * , int ) > ( 0x4D6F80 ) ( dest , src , destsize ) ;
2022-12-25 12:23:53 -05:00
MapRelocation [ dest ] = src ;
2017-01-19 16:23:59 -05:00
}
2022-12-25 12:23:53 -05:00
void Playlist : : SetMapName ( const char * dvarName , const char * value )
2017-01-19 16:23:59 -05:00
{
2022-12-25 12:23:53 -05:00
auto i = MapRelocation . find ( value ) ;
if ( i ! = MapRelocation . end ( ) )
2017-01-19 16:23:59 -05:00
{
value = i - > second . data ( ) ;
}
2022-12-25 12:23:53 -05:00
Game : : Dvar_SetStringByName ( dvarName , value ) ;
2017-01-19 16:23:59 -05:00
}
int Playlist : : GetMapIndex ( const char * mapname )
{
2022-12-25 12:23:53 -05:00
auto i = MapRelocation . find ( mapname ) ;
if ( i ! = MapRelocation . end ( ) )
2017-01-19 16:23:59 -05:00
{
mapname = i - > second . data ( ) ;
}
return Game : : Live_GetMapIndex ( mapname ) ;
}
Playlist : : Playlist ( )
{
// Default playlists
2020-12-09 14:13:34 -05:00
Utils : : Hook : : Set < const char * > ( 0x60B06E , " playlists_default.info " ) ;
2017-01-19 16:23:59 -05:00
2022-12-25 12:23:53 -05:00
// Disable playlist download function
2017-01-19 16:23:59 -05:00
Utils : : Hook : : Set < BYTE > ( 0x4D4790 , 0xC3 ) ;
// Load playlist, but don't delete it
Utils : : Hook : : Nop ( 0x4D6EBB , 5 ) ;
Utils : : Hook : : Nop ( 0x4D6E67 , 5 ) ;
Utils : : Hook : : Nop ( 0x4D6E71 , 2 ) ;
2022-12-25 12:23:53 -05:00
// Disable Playlist_ValidatePlaylistNum
2017-01-19 16:23:59 -05:00
Utils : : Hook : : Set < BYTE > ( 0x4B1170 , 0xC3 ) ;
2022-12-25 12:23:53 -05:00
// Disable playlist checking
Utils : : Hook : : Set < BYTE > ( 0x5B69E9 , 0xEB ) ; // Too new
Utils : : Hook : : Set < BYTE > ( 0x5B696E , 0xEB ) ; // Too old
2017-01-19 16:23:59 -05:00
2022-12-25 12:23:53 -05:00
// Got playlists is true
2017-01-19 16:23:59 -05:00
//Utils::Hook::Set<bool>(0x1AD3680, true);
2022-12-25 12:23:53 -05:00
Utils : : Hook ( 0x497DB5 , GetMapIndex , HOOK_CALL ) . install ( ) - > quick ( ) ;
Utils : : Hook ( 0x42A19D , MapNameCopy , HOOK_CALL ) . install ( ) - > quick ( ) ;
Utils : : Hook ( 0x4A6FEE , SetMapName , HOOK_CALL ) . install ( ) - > quick ( ) ;
2017-01-19 16:23:59 -05:00
// Store playlist buffer on load
2022-12-25 12:23:53 -05:00
Utils : : Hook ( 0x42961C , Com_ParseOnLine_Hk , HOOK_CALL ) . install ( ) - > quick ( ) ; // Playlist_ParsePlaylists
2017-01-19 16:23:59 -05:00
//if (Dedicated::IsDedicated())
{
// Custom playlist loading
2022-12-25 12:23:53 -05:00
Utils : : Hook ( 0x420B5A , LoadPlaylist , HOOK_JUMP ) . install ( ) - > quick ( ) ;
2017-01-19 16:23:59 -05:00
2022-12-25 12:23:53 -05:00
// disable playlist.ff loading function (Win_LoadPlaylistFastfile)
Utils : : Hook : : Set < std : : uint8_t > ( 0x4D6E60 , 0xC3 ) ;
2017-01-19 16:23:59 -05:00
}
2022-08-19 19:10:35 -04:00
Network : : OnClientPacket ( " getPlaylist " , PlaylistRequest ) ;
2022-12-25 12:23:53 -05:00
Network : : OnClientPacket ( " playlistResponse " , PlaylistResponse ) ;
2022-08-19 19:10:35 -04:00
Network : : OnClientPacket ( " playlistInvalidPassword " , PlaylistInvalidPassword ) ;
2017-01-19 16:23:59 -05:00
}
}