Add splitscreen types to SDK

R5 'MAX_SPLITSCREEN_CLIENTS' appears to be max 1.
This commit is contained in:
Kawe Mazidjatari 2023-06-03 18:10:32 +02:00
parent 3d80049ad4
commit 3d18be9ebb
5 changed files with 177 additions and 2 deletions

View File

@ -63,6 +63,7 @@
#include "rtech/rui/rui.h"
#include "engine/client/cl_ents_parse.h"
#include "engine/client/cl_main.h"
#include "engine/client/cl_splitscreen.h"
#endif // !DEDICATED
#include "engine/client/client.h"
#ifndef DEDICATED
@ -466,6 +467,7 @@ void DetourRegister() // Register detour classes to be searched and hooked.
#ifndef DEDICATED
REGISTER(VClientState);
REGISTER(VCL_Main);
REGISTER(VSplitScreen);
#endif // !DEDICATED
// RTech

View File

@ -118,6 +118,8 @@ add_sources( SOURCE_GROUP "Client"
"client/cl_ents_parse.cpp"
"client/cl_ents_parse.h"
"client/cl_main.h"
"client/cl_splitscreen.cpp"
"client/cl_splitscreen.h"
"client/client.cpp"
"client/client.h"
)

View File

@ -0,0 +1,23 @@
//=============================================================================
// Splitscreen manager
//
//=============================================================================
#include "cl_splitscreen.h"
CSplitScreen* g_pSplitScreenMgr;
#ifndef DEDICATED
CSetActiveSplitScreenPlayerGuard::CSetActiveSplitScreenPlayerGuard(char const* pchContext, int nLine, int slot)
{
m_pchContext = pchContext;
m_nLine = nLine;
m_nSaveSlot = g_pSplitScreenMgr->SetActiveSplitScreenPlayerSlot(slot);
m_bResolvable = g_pSplitScreenMgr->SetLocalPlayerIsResolvable(pchContext, nLine, true);
}
CSetActiveSplitScreenPlayerGuard::~CSetActiveSplitScreenPlayerGuard()
{
g_pSplitScreenMgr->SetActiveSplitScreenPlayerSlot(m_nSaveSlot);
g_pSplitScreenMgr->SetLocalPlayerIsResolvable(m_pchContext, m_nLine, m_bResolvable);
}
#endif

View File

@ -0,0 +1,148 @@
//===== Copyright <20> 1996-2008, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
// $NoKeywords: $
//===========================================================================//
#include "clientstate.h"
#ifndef CL_SPLITSCREEN_H
#define CL_SPLITSCREEN_H
#ifdef _WIN32
#pragma once
#endif
class CNetChan;
class ISplitScreen
{
public:
virtual bool Init() = 0;
virtual void Shutdown() = 0;
virtual bool AddSplitScreenUser( int nSlot, int nPlayerIndex ) = 0;
virtual bool AddBaseUser( int nSlot, int nPlayerIndex ) = 0;
virtual bool RemoveSplitScreenUser( int nSlot, int nPlayerIndex ) = 0;
virtual int GetActiveSplitScreenPlayerSlot() = 0;
virtual int SetActiveSplitScreenPlayerSlot( int nSlot ) = 0;
virtual bool IsValidSplitScreenSlot( int nSlot ) = 0;
virtual int FirstValidSplitScreenSlot() = 0; // -1 == invalid
virtual int NextValidSplitScreenSlot( int nPreviousSlot ) = 0; // -1 == invalid
virtual int GetNumSplitScreenPlayers() = 0;
virtual int GetSplitScreenPlayerEntity( int nSlot ) = 0;
virtual CNetChan *GetSplitScreenPlayerNetChan( int nSlot ) = 0;
virtual bool IsDisconnecting( int nSlot ) = 0;
virtual void SetDisconnecting( int nSlot, bool bState ) = 0;
virtual bool SetLocalPlayerIsResolvable( char const *pchContext, int nLine, bool bResolvable ) = 0;
virtual bool IsLocalPlayerResolvable() = 0;
};
class CSplitScreen : public ISplitScreen
{
// Commented as 'CClientState' uses virtual functions,
// which are pure in the SDK since its implemented in
// shipped engine code, but this should be the struct:
//public:
// struct SplitPlayer_t
// {
// bool m_bActive;
// CClientState m_Client;
// };
//
// SplitPlayer_t m_SplitScreenPlayers[MAX_SPLITSCREEN_CLIENTS];
// int m_nActiveSplitScreenUserCount;
};
#ifndef DEDICATED
extern CSplitScreen* g_pSplitScreenMgr;
#endif
class CSetActiveSplitScreenPlayerGuard
{
public:
CSetActiveSplitScreenPlayerGuard( char const *pchContext, int nLine, int slot );
~CSetActiveSplitScreenPlayerGuard();
private:
char const *m_pchContext;
int m_nLine;
int m_nSaveSlot;
bool m_bResolvable;
};
// If this is defined, all of the scopeguard objects are NULL'd out to reduce overhead
#ifdef DEDICATED
#define SPLIT_SCREEN_STUBS
#endif
#if defined( CSTRIKE15 ) // && !defined( _GAMECONSOLE ) // Split screen removed from console.
#define SPLIT_SCREEN_STUBS
#endif
#if defined( SPLIT_SCREEN_STUBS )
#define IS_LOCAL_PLAYER_RESOLVABLE true
#define SET_LOCAL_PLAYER_RESOLVABLE( a, b, c ) true
#define SET_ACTIVE_SPLIT_SCREEN_PLAYER_SLOT( x )
#define ACTIVE_SPLITSCREEN_PLAYER_GUARD( slot )
#define FORCE_DEFAULT_SPLITSCREEN_PLAYER_GUARD
#define FOR_EACH_VALID_SPLITSCREEN_PLAYER( iteratorName ) for ( int iteratorName = 0; iteratorName == 0; ++iteratorName )
#define FOR_EACH_SPLITSCREEN_PLAYER FOR_EACH_VALID_SPLITSCREEN_PLAYER
#define ASSERT_LOCAL_PLAYER_RESOLVABLE()
#define GET_ACTIVE_SPLITSCREEN_SLOT() ( 0 )
#define GET_NUM_SPLIT_SCREEN_PLAYERS() 1
#define IS_VALID_SPLIT_SCREEN_SLOT( i ) ( ( i ) == 0 )
#else
#define IS_LOCAL_PLAYER_RESOLVABLE ( g_pSplitScreenMgr->IsLocalPlayerResolvable() )
#define SET_LOCAL_PLAYER_RESOLVABLE( a, b, c ) ( g_pSplitScreenMgr->SetLocalPlayerIsResolvable( a, b, c ) )
#define ACTIVE_SPLITSCREEN_PLAYER_GUARD( slot ) CSetActiveSplitScreenPlayerGuard g_SSGuard( __FILE__, __LINE__, slot );
#define FORCE_DEFAULT_SPLITSCREEN_PLAYER_GUARD CSetActiveSplitScreenPlayerGuard g_SSGuard( __FILE__, __LINE__, 0 );
#define FOR_EACH_VALID_SPLITSCREEN_PLAYER( iteratorName ) \
for ( int iteratorName = g_pSplitScreenMgr->FirstValidSplitScreenSlot(); \
iteratorName != -1; \
iteratorName = g_pSplitScreenMgr->NextValidSplitScreenSlot( iteratorName ) )
#define FOR_EACH_SPLITSCREEN_PLAYER( iteratorName ) for ( int iteratorName = 0; iteratorName < MAX_SPLITSCREEN_CLIENTS; ++iteratorName )
#define ASSERT_LOCAL_PLAYER_RESOLVABLE() Assert( g_pSplitScreenMgr->IsLocalPlayerResolvable() );
#define GET_ACTIVE_SPLITSCREEN_SLOT() g_pSplitScreenMgr->GetActiveSplitScreenPlayerSlot()
#define SET_ACTIVE_SPLIT_SCREEN_PLAYER_SLOT( x ) g_pSplitScreenMgr->SetActiveSplitScreenPlayerSlot( x )
#define GET_NUM_SPLIT_SCREEN_PLAYERS() ( g_pSplitScreenMgr->GetNumSplitScreenPlayers() )
#define IS_VALID_SPLIT_SCREEN_SLOT( i ) ( g_pSplitScreenMgr->IsValidSplitScreenSlot( i ) )
#endif
class VSplitScreen : public IDetour
{
virtual void GetAdr(void) const
{
LogVarAdr("g_SplitScreenMgr", reinterpret_cast<uintptr_t>(g_pSplitScreenMgr));
}
virtual void GetFun(void) const { }
virtual void GetVar(void) const
{
const char* pszPattern;
const char* pszInstruction;
#if defined (GAMEDLL_S0) || defined (GAMEDLL_S1)
pszPattern = "83 FA FF 75 22 48 8D 05 ?? ?? ?? ??";
pszInstruction = "4C 8D";
#elif defined (GAMEDLL_S2) || defined (GAMEDLL_S3)
pszPattern = "40 53 48 83 EC 20 48 8D 1D ?? ?? ?? ?? 83 FA FF 75 12 48 8B 05 ?? ?? ?? ?? 48 8B CB FF 50 28 48 63 C8 EB 03 48 63 CA 48 69 C1 ?? ?? ?? ?? 66 C7 84 18 ?? ?? ?? ?? ?? ??";
pszInstruction = "48 8D";
#endif
g_pSplitScreenMgr = g_GameDll.FindPatternSIMD(pszPattern).FindPatternSelf(pszInstruction).ResolveRelativeAddressSelf(0x3, 0x7).RCast<CSplitScreen*>();
}
virtual void GetCon(void) const { }
virtual void Attach(void) const { };
virtual void Detach(void) const { };
};
#endif // CL_SPLITSCREEN_H

View File

@ -134,8 +134,8 @@
#define IsX360() IsPlatformX360()
#define IsPS3() IsPlatformPS3()
#define MAX_SPLITSCREEN_CLIENT_BITS 2 // Max 2 player splitscreen in portal (don't merge this back), saves a bunch of memory [8/31/2010 tom]
#define MAX_SPLITSCREEN_CLIENTS ( 1 << MAX_SPLITSCREEN_CLIENT_BITS ) // 4 // this should == MAX_JOYSTICKS in InputEnums.h
#define MAX_SPLITSCREEN_CLIENT_BITS 0 // R5 doesn't support splitscreen; engine is hardcoded to only have 1 player.
#define MAX_SPLITSCREEN_CLIENTS ( 1 << MAX_SPLITSCREEN_CLIENT_BITS ) // 1 // this should == MAX_JOYSTICKS in InputEnums.h
#define MAX_PLAYERS 128 // Max R5 players.