Skip to content

Commit 97388b5

Browse files
committed
Merge Loading screen support for RedM (pr-3337)
7675ef1 - feat(rdr3): loading screen support
2 parents 1eed77d + 7675ef1 commit 97388b5

File tree

13 files changed

+594
-211
lines changed

13 files changed

+594
-211
lines changed

code/components/config.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ component 'gta-net-rdr3'
132132
component 'extra-natives-rdr3'
133133
component 'citizen-playernames-rdr3'
134134
component 'devtools-rdr3'
135+
component 'loading-screens-rdr3'
135136

136137
component 'gta-game-ny'
137138
component 'rage-graphics-ny'

code/components/conhost-v2/src/ConsoleHostGui.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -914,7 +914,7 @@ static void EnsureConsoles()
914914

915915
bool IsNonProduction()
916916
{
917-
#if !defined(GTA_FIVE) || defined(_DEBUG)
917+
#if (!defined(GTA_FIVE) && !defined(IS_RDR3)) || defined(_DEBUG)
918918
return true;
919919
#else
920920
static ConVar<int> moo("moo", ConVar_None, 0);
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#pragma once
2+
3+
enum HostState
4+
{
5+
SESSION_STATE_NONE,
6+
SESSION_STATE_ENTER,
7+
SESSION_STATE_START_JOINING,
8+
SESSION_STATE_JOINING,
9+
SESSION_STATE_JOINED,
10+
SESSION_STATE_5,
11+
SESSION_STATE_6,
12+
SESSION_STATE_7,
13+
};
14+
15+
inline const char* HostStateToString(HostState hs)
16+
{
17+
#define TS_HELPER(x) \
18+
case x: \
19+
return #x;
20+
21+
switch (hs)
22+
{
23+
TS_HELPER(SESSION_STATE_NONE)
24+
TS_HELPER(SESSION_STATE_ENTER)
25+
TS_HELPER(SESSION_STATE_START_JOINING)
26+
TS_HELPER(SESSION_STATE_JOINING)
27+
TS_HELPER(SESSION_STATE_JOINED)
28+
TS_HELPER(SESSION_STATE_5)
29+
TS_HELPER(SESSION_STATE_6)
30+
TS_HELPER(SESSION_STATE_7)
31+
}
32+
33+
return va("%d", (int)hs);
34+
35+
#undef TS_HELPER
36+
}
37+
38+
#ifdef COMPILING_GTA_NET_RDR3
39+
#define GTA_NET_EXPORT DLL_EXPORT
40+
#else
41+
#define GTA_NET_EXPORT DLL_IMPORT
42+
#endif
43+
44+
// a1: new state
45+
// a2: old state
46+
extern GTA_NET_EXPORT fwEvent<HostState, HostState> OnHostStateTransition;

code/components/gta-net-rdr3/src/CoreNetworking.cpp

Lines changed: 148 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
NetLibrary* g_netLibrary;
1717

18+
#include <HostSystem.h>
19+
1820
// shared relay functions (from early rev. gta:net:five; do update!)
1921
#include <ws2tcpip.h>
2022

@@ -699,6 +701,148 @@ static int ReturnTrue()
699701
return true;
700702
}
701703

704+
705+
GTA_NET_EXPORT fwEvent<HostState, HostState> OnHostStateTransition;
706+
707+
struct HostStateHolder
708+
{
709+
HostState state;
710+
711+
inline bool operator==(HostState right)
712+
{
713+
return (state == right);
714+
}
715+
716+
inline HostState operator=(HostState right)
717+
{
718+
trace("SessionState transitioning from %s to %s\n", HostStateToString(state), HostStateToString(right));
719+
720+
AddCrashometry("hs_state", HostStateToString(right));
721+
722+
OnHostStateTransition(right, state);
723+
state = right;
724+
725+
return right;
726+
}
727+
};
728+
729+
struct
730+
{
731+
HostStateHolder state;
732+
int attempts;
733+
734+
std::string hostResult;
735+
736+
void handleHostResult(const std::string& str)
737+
{
738+
hostResult = str;
739+
}
740+
741+
void process()
742+
{
743+
ICoreGameInit* cgi = Instance<ICoreGameInit>::Get();
744+
745+
switch (state.state)
746+
{
747+
case SESSION_STATE_NONE:
748+
{
749+
// update presence
750+
_rlPresence_GamerPresence_Clear(rlPresence__m_GamerPresences);
751+
_rlPresence_refreshSigninState(0);
752+
_rlPresence_refreshNetworkStatus(0);
753+
754+
state = SESSION_STATE_ENTER;
755+
break;
756+
}
757+
case SESSION_STATE_ENTER:
758+
// wait for transition
759+
if (_getCurrentTransitionState() == 0)
760+
{
761+
state = SESSION_STATE_START_JOINING;
762+
}
763+
764+
break;
765+
766+
case SESSION_STATE_START_JOINING:
767+
{
768+
auto lastThread = rage::scrEngine::GetActiveThread();
769+
rage::scrEngine::SetActiveThread(fakeThread.GetThread());
770+
771+
// transition to mp
772+
_transitionToState(0x73040199);
773+
774+
rage::scrEngine::SetActiveThread(lastThread);
775+
776+
state = SESSION_STATE_JOINING;
777+
break;
778+
}
779+
case SESSION_STATE_JOINING:
780+
// wait for transition
781+
if (_getCurrentTransitionState() == 0x73040199) // MP MODE
782+
{
783+
state = SESSION_STATE_JOINED;
784+
}
785+
else if (_getCurrentTransitionState() == 0x1D94DE8C || _getCurrentTransitionState() == 0) // SP MODE
786+
{
787+
state = SESSION_STATE_START_JOINING;
788+
}
789+
790+
break;
791+
792+
case SESSION_STATE_JOINED:
793+
if (g_initedPlayer)
794+
{
795+
state = SESSION_STATE_5;
796+
}
797+
else if (_getCurrentTransitionState() == 0x1D94DE8C || _getCurrentTransitionState() == 0) // SP MODE
798+
{
799+
state = SESSION_STATE_START_JOINING;
800+
}
801+
802+
break;
803+
804+
case SESSION_STATE_5:
805+
if (cgi->OneSyncEnabled)
806+
{
807+
if (sync::IsWaitingForTimeSync())
808+
{
809+
return;
810+
}
811+
}
812+
813+
static char sessionIdPtr[48];
814+
memset(sessionIdPtr, 0, sizeof(sessionIdPtr));
815+
joinOrHost(1, nullptr, sessionIdPtr);
816+
817+
state = SESSION_STATE_6;
818+
819+
break;
820+
821+
case SESSION_STATE_6:
822+
struct
823+
{
824+
char* sessionMultiplayer;
825+
char pad[16];
826+
uint8_t networkInited;
827+
}* networkMgr;
828+
829+
networkMgr = *(decltype(networkMgr)*)g_networkMgrPtr;
830+
831+
if (networkMgr->networkInited)
832+
{
833+
auto networkState = *(BYTE*)(networkMgr->sessionMultiplayer + networkStateOffset);
834+
835+
if (networkState == 4)
836+
{
837+
state = SESSION_STATE_7;
838+
Instance<ICoreGameInit>::Get()->SetVariable("networkInited");
839+
}
840+
}
841+
break;
842+
}
843+
}
844+
} hostSystem;
845+
702846
static HookFunction hookFunction([]()
703847
{
704848
static ConsoleCommand quitCommand("quit", [](const std::string& message)
@@ -787,139 +931,28 @@ static HookFunction hookFunction([]()
787931
// pretend to have CGameScriptHandlerNetComponent always be host
788932
hook::jump(hook::get_pattern("33 DB 48 85 C0 74 17 48 8B 48 10 48 85 C9 74 0E", -10), ReturnTrue);
789933

790-
static LoggedInt tryHostStage = 0;
791-
792-
static bool gameLoaded;
793-
794-
Instance<ICoreGameInit>::Get()->OnGameFinalizeLoad.Connect([]()
795-
{
796-
gameLoaded = true;
797-
});
798-
799-
static ICoreGameInit* cgi = Instance<ICoreGameInit>::Get();
800-
801934
OnKillNetwork.Connect([](const char*)
802935
{
803-
gameLoaded = false;
804936
g_initedPlayer = false;
805937
});
806938

807939
OnMainGameFrame.Connect([]()
808940
{
809-
if (!gameLoaded)
941+
if (Instance<ICoreGameInit>::Get()->GetGameLoaded())
810942
{
811-
return;
943+
hostSystem.process();
812944
}
813945

814-
switch (tryHostStage)
815-
{
816-
case 0:
817-
{
818-
// update presence
819-
_rlPresence_GamerPresence_Clear(rlPresence__m_GamerPresences);
820-
_rlPresence_refreshSigninState(0);
821-
_rlPresence_refreshNetworkStatus(0);
822-
823-
tryHostStage = 1;
824-
break;
825-
}
826-
case 1:
827-
// wait for transition
828-
if (_getCurrentTransitionState() == 0)
829-
{
830-
tryHostStage = 2;
831-
}
832-
833-
break;
834-
835-
case 2:
836-
{
837-
auto lastThread = rage::scrEngine::GetActiveThread();
838-
rage::scrEngine::SetActiveThread(fakeThread.GetThread());
839-
840-
// transition to mp
841-
_transitionToState(0x73040199);
842-
843-
rage::scrEngine::SetActiveThread(lastThread);
844-
845-
tryHostStage = 3;
846-
break;
847-
}
848-
case 3:
849-
// wait for transition
850-
if (_getCurrentTransitionState() == 0x73040199)
851-
{
852-
tryHostStage = 4;
853-
}
854-
else if (_getCurrentTransitionState() == 0x1D94DE8C || _getCurrentTransitionState() == 0)
855-
{
856-
tryHostStage = 2;
857-
}
858-
859-
break;
860-
861-
case 4:
862-
if (g_initedPlayer)
863-
{
864-
tryHostStage = 5;
865-
}
866-
else if (_getCurrentTransitionState() == 0x1D94DE8C || _getCurrentTransitionState() == 0)
867-
{
868-
tryHostStage = 2;
869-
}
870-
871-
break;
872-
873-
case 5:
874-
if (cgi->OneSyncEnabled)
875-
{
876-
if (sync::IsWaitingForTimeSync())
877-
{
878-
return;
879-
}
880-
}
881-
882-
static char sessionIdPtr[48];
883-
memset(sessionIdPtr, 0, sizeof(sessionIdPtr));
884-
joinOrHost(1, nullptr, sessionIdPtr);
885-
886-
tryHostStage = 6;
887-
888-
break;
889-
890-
case 6:
891-
struct
892-
{
893-
char* sessionMultiplayer;
894-
char pad[16];
895-
uint8_t networkInited;
896-
}* networkMgr;
897-
898-
networkMgr = *(decltype(networkMgr)*)g_networkMgrPtr;
899-
900-
if (networkMgr->networkInited)
901-
{
902-
auto networkState = *(BYTE*)(networkMgr->sessionMultiplayer + networkStateOffset);
903-
904-
if (networkState == 4)
905-
{
906-
tryHostStage = 7;
907-
Instance<ICoreGameInit>::Get()->SetVariable("networkInited");
908-
}
909-
}
910-
911-
break;
912-
}
913946
});
914947

915948
static ConsoleCommand hhh("hhh", []()
916949
{
917-
tryHostStage = 0;
950+
hostSystem.state = SESSION_STATE_NONE;
918951
});
919952

920953
OnKillNetworkDone.Connect([]()
921954
{
922-
tryHostStage = 0;
955+
hostSystem.state = SESSION_STATE_NONE;
923956
});
924957

925958
// rlSession::InformPeersOfJoiner bugfix: reintroduce loop (as in, remove break; statement)

0 commit comments

Comments
 (0)