Playlists.
This commit is contained in:
parent
66ef54791a
commit
9aec8b2a1b
@ -21,6 +21,7 @@ namespace Components
|
|||||||
Loader::Register(new Console());
|
Loader::Register(new Console());
|
||||||
Loader::Register(new IPCPipe());
|
Loader::Register(new IPCPipe());
|
||||||
Loader::Register(new Network());
|
Loader::Register(new Network());
|
||||||
|
Loader::Register(new Playlist());
|
||||||
Loader::Register(new RawFiles());
|
Loader::Register(new RawFiles());
|
||||||
Loader::Register(new Renderer());
|
Loader::Register(new Renderer());
|
||||||
Loader::Register(new UIFeeder());
|
Loader::Register(new UIFeeder());
|
||||||
|
@ -32,6 +32,7 @@ namespace Components
|
|||||||
#include "Modules\IPCPipe.hpp"
|
#include "Modules\IPCPipe.hpp"
|
||||||
#include "Modules\Network.hpp"
|
#include "Modules\Network.hpp"
|
||||||
#include "Modules\Party.hpp" // Destroys the order, but requires network classes :D
|
#include "Modules\Party.hpp" // Destroys the order, but requires network classes :D
|
||||||
|
#include "Modules\Playlist.hpp"
|
||||||
#include "Modules\RawFiles.hpp"
|
#include "Modules\RawFiles.hpp"
|
||||||
#include "Modules\Renderer.hpp"
|
#include "Modules\Renderer.hpp"
|
||||||
#include "Modules\UIFeeder.hpp"
|
#include "Modules\UIFeeder.hpp"
|
||||||
|
@ -129,11 +129,7 @@ namespace Components
|
|||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
__asm
|
Utils::Hook::Call<void>(0x5A8E80);
|
||||||
{
|
|
||||||
mov eax, 5A8E80h
|
|
||||||
call eax
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Dedicated::Dedicated()
|
Dedicated::Dedicated()
|
||||||
@ -231,6 +227,13 @@ namespace Components
|
|||||||
Dedicated::Heartbeat();
|
Dedicated::Heartbeat();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Wrap xstartprivatematch
|
||||||
|
Command::Add("lobby_start", [] (Command::Params params)
|
||||||
|
{
|
||||||
|
Playlist::LoadPlaylist();
|
||||||
|
Command::Execute("xstartprivatematch", false);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,9 +17,15 @@ namespace Components
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Network::Address Party::Target()
|
||||||
|
{
|
||||||
|
return Party::Container.Target;
|
||||||
|
}
|
||||||
|
|
||||||
void Party::Connect(Network::Address target)
|
void Party::Connect(Network::Address target)
|
||||||
{
|
{
|
||||||
Party::Container.Valid = true;
|
Party::Container.Valid = true;
|
||||||
|
Party::Container.AwaitingPlaylist = false;
|
||||||
Party::Container.JoinTime = Game::Com_Milliseconds();
|
Party::Container.JoinTime = Game::Com_Milliseconds();
|
||||||
Party::Container.Target = target;
|
Party::Container.Target = target;
|
||||||
Party::Container.Challenge = Utils::VA("%X", Party::Container.JoinTime);
|
Party::Container.Challenge = Utils::VA("%X", Party::Container.JoinTime);
|
||||||
@ -68,6 +74,26 @@ namespace Components
|
|||||||
return Dvar::Register<int>(name, 1, 1, max, Game::dvar_flag::DVAR_FLAG_WRITEPROTECTED | flag, description).Get<Game::dvar_t*>();
|
return Dvar::Register<int>(name, 1, 1, max, Game::dvar_flag::DVAR_FLAG_WRITEPROTECTED | flag, description).Get<Game::dvar_t*>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Party::PlaylistAwaiting()
|
||||||
|
{
|
||||||
|
return Party::Container.AwaitingPlaylist;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Party::PlaylistContinue()
|
||||||
|
{
|
||||||
|
Party::Container.AwaitingPlaylist = false;
|
||||||
|
|
||||||
|
SteamID id = Party::GenerateLobbyId();
|
||||||
|
|
||||||
|
Party::LobbyMap[id.Bits] = Party::Container.Target;
|
||||||
|
|
||||||
|
Game::Steam_JoinLobby(id, 0);
|
||||||
|
|
||||||
|
// Callback not registered on first try
|
||||||
|
// TODO: Fix :D
|
||||||
|
if (Party::LobbyMap.size() <= 1) Game::Steam_JoinLobby(id, 0);
|
||||||
|
}
|
||||||
|
|
||||||
Party::Party()
|
Party::Party()
|
||||||
{
|
{
|
||||||
// various changes to SV_DirectConnect-y stuff to allow non-party joinees
|
// various changes to SV_DirectConnect-y stuff to allow non-party joinees
|
||||||
@ -126,13 +152,23 @@ namespace Components
|
|||||||
|
|
||||||
Renderer::OnFrame([] ()
|
Renderer::OnFrame([] ()
|
||||||
{
|
{
|
||||||
if (!Party::Container.Valid) return;
|
if (Party::Container.Valid)
|
||||||
|
{
|
||||||
if ((Game::Com_Milliseconds() - Party::Container.JoinTime) > 5000)
|
if ((Game::Com_Milliseconds() - Party::Container.JoinTime) > 5000)
|
||||||
{
|
{
|
||||||
Party::Container.Valid = false;
|
Party::Container.Valid = false;
|
||||||
Party::ConnectError("Server connection timed out.");
|
Party::ConnectError("Server connection timed out.");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Party::Container.AwaitingPlaylist)
|
||||||
|
{
|
||||||
|
if ((Game::Com_Milliseconds() - Party::Container.RequestTime) > 5000)
|
||||||
|
{
|
||||||
|
Party::Container.AwaitingPlaylist = false;
|
||||||
|
Party::ConnectError("Playlist request timed out.");
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Basic info handler
|
// Basic info handler
|
||||||
@ -219,15 +255,10 @@ namespace Components
|
|||||||
// Connect
|
// Connect
|
||||||
else if (matchType == 1) // Party
|
else if (matchType == 1) // Party
|
||||||
{
|
{
|
||||||
SteamID id = Party::GenerateLobbyId();
|
// Send playlist request
|
||||||
|
Party::Container.RequestTime = Game::Com_Milliseconds();
|
||||||
Party::LobbyMap[id.Bits] = address;
|
Party::Container.AwaitingPlaylist = true;
|
||||||
|
Network::Send(address, "getplaylist\n");
|
||||||
Game::Steam_JoinLobby(id, 0);
|
|
||||||
|
|
||||||
// Callback not registered on first try
|
|
||||||
// TODO: Fix :D
|
|
||||||
if (Party::LobbyMap.size() <= 1) Game::Steam_JoinLobby(id, 0);
|
|
||||||
}
|
}
|
||||||
else if (matchType == 2) // Match
|
else if (matchType == 2) // Match
|
||||||
{
|
{
|
||||||
|
@ -7,10 +7,14 @@ namespace Components
|
|||||||
~Party();
|
~Party();
|
||||||
const char* GetName() { return "Party"; };
|
const char* GetName() { return "Party"; };
|
||||||
|
|
||||||
|
static Network::Address Target();
|
||||||
static void Connect(Network::Address target);
|
static void Connect(Network::Address target);
|
||||||
static const char* GetLobbyInfo(SteamID lobby, std::string key);
|
static const char* GetLobbyInfo(SteamID lobby, std::string key);
|
||||||
static void RemoveLobby(SteamID lobby);
|
static void RemoveLobby(SteamID lobby);
|
||||||
|
|
||||||
|
static bool PlaylistAwaiting();
|
||||||
|
static void PlaylistContinue();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct JoinContainer
|
struct JoinContainer
|
||||||
{
|
{
|
||||||
@ -18,6 +22,10 @@ namespace Components
|
|||||||
std::string Challenge;
|
std::string Challenge;
|
||||||
DWORD JoinTime;
|
DWORD JoinTime;
|
||||||
bool Valid;
|
bool Valid;
|
||||||
|
|
||||||
|
// Party-specific stuff
|
||||||
|
DWORD RequestTime;
|
||||||
|
bool AwaitingPlaylist;
|
||||||
};
|
};
|
||||||
|
|
||||||
static JoinContainer Container;
|
static JoinContainer Container;
|
||||||
|
119
src/Components/Modules/Playlist.cpp
Normal file
119
src/Components/Modules/Playlist.cpp
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
#include "..\..\STDInclude.hpp"
|
||||||
|
|
||||||
|
namespace Components
|
||||||
|
{
|
||||||
|
std::string Playlist::CurrentPlaylistBuffer;
|
||||||
|
|
||||||
|
void Playlist::LoadPlaylist()
|
||||||
|
{
|
||||||
|
// Check if playlist already loaded
|
||||||
|
if (Utils::Hook::Get<bool>(0x1AD3680)) return;
|
||||||
|
|
||||||
|
std::string playlistFilename = Dvar::Var("playlistFilename").Get<char*>();
|
||||||
|
FileSystem::File playlist(playlistFilename);
|
||||||
|
|
||||||
|
if (playlist.Exists())
|
||||||
|
{
|
||||||
|
Logger::Print("Parsing playlist '%s'...\n", playlist.GetName().data());
|
||||||
|
Game::Live_ParsePlaylists(playlist.GetBuffer().data());
|
||||||
|
Utils::Hook::Set<bool>(0x1AD3680, true); // Playlist loaded
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger::Print("Unable to load playlist '%s'!\n", playlist.GetName().data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD Playlist::StorePlaylistStub(const char** buffer)
|
||||||
|
{
|
||||||
|
Playlist::CurrentPlaylistBuffer = *buffer;
|
||||||
|
//return Utils::Hook::Call<DWORD>(0x4C0350);
|
||||||
|
__asm
|
||||||
|
{
|
||||||
|
push buffer
|
||||||
|
mov eax, 4C0350h
|
||||||
|
call eax
|
||||||
|
add esp, 4h
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Playlist::PlaylistRequest(Network::Address address, std::string data)
|
||||||
|
{
|
||||||
|
Logger::Print("Received playlist request, sending currently stored buffer.\n");
|
||||||
|
Network::Send(address, std::string("playlistresponse\n") + Playlist::CurrentPlaylistBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Playlist::PlaylistReponse(Network::Address address, std::string data)
|
||||||
|
{
|
||||||
|
if (Party::PlaylistAwaiting())
|
||||||
|
{
|
||||||
|
if (address == Party::Target())
|
||||||
|
{
|
||||||
|
Logger::Print("Received playlist response, loading and continuing connection.\n");
|
||||||
|
Game::Live_ParsePlaylists(data.data());
|
||||||
|
Party::PlaylistContinue();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger::Print("Received playlist from someone else than our target host, ignoring it.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger::Print("Received stray playlist response, ignoring it.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Playlist::Playlist()
|
||||||
|
{
|
||||||
|
// Apply new playlist
|
||||||
|
char* playlist = "mp_playlists_dlc2";
|
||||||
|
Utils::Hook::Set<char*>(0x494803, playlist);
|
||||||
|
Utils::Hook::Set<char*>(0x4C6EC1, playlist);
|
||||||
|
Utils::Hook::Set<char*>(0x4CF7F9, playlist);
|
||||||
|
Utils::Hook::Set<char*>(0x4D6E63, playlist);
|
||||||
|
Utils::Hook::Set<char*>(0x4D7358, playlist);
|
||||||
|
Utils::Hook::Set<char*>(0x4D73C8, playlist);
|
||||||
|
Utils::Hook::Set<char*>(0x4F4EA1, playlist);
|
||||||
|
Utils::Hook::Set<char*>(0x4D47FB, "mp_playlists_dlc2.ff");
|
||||||
|
Utils::Hook::Set<char*>(0x60B06E, "playlists.patch2");
|
||||||
|
|
||||||
|
// disable playlist download function
|
||||||
|
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);
|
||||||
|
|
||||||
|
// playlist dvar 'validity check'
|
||||||
|
Utils::Hook::Set<BYTE>(0x4B1170, 0xC3);
|
||||||
|
|
||||||
|
// disable playlist checking
|
||||||
|
Utils::Hook::Set<BYTE>(0x5B69E9, 0xEB);// too new
|
||||||
|
Utils::Hook::Set<BYTE>(0x5B696E, 0xEB); // too old
|
||||||
|
|
||||||
|
//Got playlists is true
|
||||||
|
//Utils::Hook::Set<bool>(0x1AD3680, true);
|
||||||
|
|
||||||
|
// Store playlist buffer on load
|
||||||
|
Utils::Hook(0x42961C, Playlist::StorePlaylistStub, HOOK_CALL).Install()->Quick();
|
||||||
|
|
||||||
|
if (Dedicated::IsDedicated())
|
||||||
|
{
|
||||||
|
// Custom playlist loading
|
||||||
|
Utils::Hook(0x420B5A, Playlist::LoadPlaylist, HOOK_JUMP).Install()->Quick();
|
||||||
|
|
||||||
|
// disable playlist.ff loading function
|
||||||
|
Utils::Hook::Set<BYTE>(0x4D6E60, 0xC3);
|
||||||
|
}
|
||||||
|
|
||||||
|
Network::Handle("getplaylist", PlaylistRequest);
|
||||||
|
Network::Handle("playlistresponse", PlaylistReponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
Playlist::~Playlist()
|
||||||
|
{
|
||||||
|
Playlist::CurrentPlaylistBuffer.clear();
|
||||||
|
}
|
||||||
|
}
|
22
src/Components/Modules/Playlist.hpp
Normal file
22
src/Components/Modules/Playlist.hpp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
namespace Components
|
||||||
|
{
|
||||||
|
class Playlist : public Component
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef void(*Callback)();
|
||||||
|
|
||||||
|
Playlist();
|
||||||
|
~Playlist();
|
||||||
|
const char* GetName() { return "Playlist"; };
|
||||||
|
|
||||||
|
static void LoadPlaylist();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static std::string CurrentPlaylistBuffer;
|
||||||
|
|
||||||
|
static DWORD StorePlaylistStub(const char** buffer);
|
||||||
|
|
||||||
|
static void PlaylistRequest(Network::Address address, std::string data);
|
||||||
|
static void PlaylistReponse(Network::Address address, std::string data);
|
||||||
|
};
|
||||||
|
}
|
@ -28,35 +28,6 @@ namespace Components
|
|||||||
Utils::Hook::Nop(0x451145, 5);
|
Utils::Hook::Nop(0x451145, 5);
|
||||||
Utils::Hook::Set<BYTE>(0x45114C, 0xEB);
|
Utils::Hook::Set<BYTE>(0x45114C, 0xEB);
|
||||||
|
|
||||||
// Apply new playlist
|
|
||||||
char* playlist = "mp_playlists_dlc2";
|
|
||||||
Utils::Hook::Set<char*>(0x494803, playlist);
|
|
||||||
Utils::Hook::Set<char*>(0x4C6EC1, playlist);
|
|
||||||
Utils::Hook::Set<char*>(0x4CF7F9, playlist);
|
|
||||||
Utils::Hook::Set<char*>(0x4D6E63, playlist);
|
|
||||||
Utils::Hook::Set<char*>(0x4D7358, playlist);
|
|
||||||
Utils::Hook::Set<char*>(0x4D73C8, playlist);
|
|
||||||
Utils::Hook::Set<char*>(0x4F4EA1, playlist);
|
|
||||||
Utils::Hook::Set<char*>(0x4D47FB, "mp_playlists_dlc2.ff");
|
|
||||||
Utils::Hook::Set<char*>(0x60B06E, "playlists.patch2");
|
|
||||||
|
|
||||||
// disable playlist download function
|
|
||||||
Utils::Hook::Set<BYTE>(0x4D4790, 0xC3);
|
|
||||||
|
|
||||||
// disable playlist.ff loading function
|
|
||||||
//Utils::Hook::Set<BYTE>(0x4D6E60, 0xC3);
|
|
||||||
|
|
||||||
// Load playlist, but don't delete it
|
|
||||||
Utils::Hook::Nop(0x4D6EBB, 5);
|
|
||||||
Utils::Hook::Nop(0x4D6E67, 5);
|
|
||||||
Utils::Hook::Nop(0x4D6E71, 2);
|
|
||||||
|
|
||||||
// playlist dvar 'validity check'
|
|
||||||
Utils::Hook::Set<BYTE>(0x4B1170, 0xC3);
|
|
||||||
|
|
||||||
//Got playlists is true
|
|
||||||
//Utils::Hook::Set<bool>(0x1AD3680, true);
|
|
||||||
|
|
||||||
// LSP disabled
|
// LSP disabled
|
||||||
Utils::Hook::Set<BYTE>(0x435950, 0xC3); // LSP HELLO
|
Utils::Hook::Set<BYTE>(0x435950, 0xC3); // LSP HELLO
|
||||||
Utils::Hook::Set<BYTE>(0x49C220, 0xC3); // We wanted to send a logging packet, but we haven't connected to LSP!
|
Utils::Hook::Set<BYTE>(0x49C220, 0xC3); // We wanted to send a logging packet, but we haven't connected to LSP!
|
||||||
|
@ -65,6 +65,7 @@ namespace Game
|
|||||||
NET_StringToAdr_t NET_StringToAdr = (NET_StringToAdr_t)0x409010;
|
NET_StringToAdr_t NET_StringToAdr = (NET_StringToAdr_t)0x409010;
|
||||||
|
|
||||||
Live_MPAcceptInvite_t Live_MPAcceptInvite = (Live_MPAcceptInvite_t)0x420A6D;
|
Live_MPAcceptInvite_t Live_MPAcceptInvite = (Live_MPAcceptInvite_t)0x420A6D;
|
||||||
|
Live_ParsePlaylists_t Live_ParsePlaylists = (Live_ParsePlaylists_t)0x4295A0;
|
||||||
|
|
||||||
LoadInitialFF_t LoadInitialFF = (LoadInitialFF_t)0x506AC0;
|
LoadInitialFF_t LoadInitialFF = (LoadInitialFF_t)0x506AC0;
|
||||||
LoadModdableRawfile_t LoadModdableRawfile = (LoadModdableRawfile_t)0x61ABC0;
|
LoadModdableRawfile_t LoadModdableRawfile = (LoadModdableRawfile_t)0x61ABC0;
|
||||||
|
@ -151,6 +151,9 @@ namespace Game
|
|||||||
typedef void(__cdecl * Live_MPAcceptInvite_t)(_XSESSION_INFO *hostInfo, const int controllerIndex, bool fromGameInvite);
|
typedef void(__cdecl * Live_MPAcceptInvite_t)(_XSESSION_INFO *hostInfo, const int controllerIndex, bool fromGameInvite);
|
||||||
extern Live_MPAcceptInvite_t Live_MPAcceptInvite;
|
extern Live_MPAcceptInvite_t Live_MPAcceptInvite;
|
||||||
|
|
||||||
|
typedef void(__cdecl * Live_ParsePlaylists_t)(const char* data);
|
||||||
|
extern Live_ParsePlaylists_t Live_ParsePlaylists;
|
||||||
|
|
||||||
typedef void(*LoadInitialFF_t)(void);
|
typedef void(*LoadInitialFF_t)(void);
|
||||||
extern LoadInitialFF_t LoadInitialFF;
|
extern LoadInitialFF_t LoadInitialFF;
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#include "..\STDInclude.hpp"
|
#include "..\STDInclude.hpp"
|
||||||
|
|
||||||
#define VA_BUFFER_COUNT 4
|
#define VA_BUFFER_COUNT 4
|
||||||
#define VA_BUFFER_SIZE 4096
|
#define VA_BUFFER_SIZE 65536
|
||||||
|
|
||||||
namespace Utils
|
namespace Utils
|
||||||
{
|
{
|
||||||
@ -13,7 +13,7 @@ namespace Utils
|
|||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
char* dest = g_vaBuffer[g_vaNextBufferIndex];
|
char* dest = g_vaBuffer[g_vaNextBufferIndex];
|
||||||
vsprintf_s(g_vaBuffer[g_vaNextBufferIndex], fmt, ap);
|
vsnprintf(g_vaBuffer[g_vaNextBufferIndex], VA_BUFFER_SIZE, fmt, ap);
|
||||||
g_vaNextBufferIndex = (g_vaNextBufferIndex + 1) % VA_BUFFER_COUNT;
|
g_vaNextBufferIndex = (g_vaNextBufferIndex + 1) % VA_BUFFER_COUNT;
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
return dest;
|
return dest;
|
||||||
|
Loading…
Reference in New Issue
Block a user