2022-07-20 17:50:01 +08:00
using GTA ;
using GTA.Math ;
using GTA.Native ;
using RageCoop.Client.Menus ;
using RageCoop.Core ;
using System ;
using System.Collections.Generic ;
using System.Diagnostics ;
2022-08-02 17:43:18 +08:00
using System.Drawing ;
2022-09-06 21:46:35 +08:00
using System.IO ;
2022-07-21 22:42:29 +08:00
using System.Threading ;
2022-09-06 21:46:35 +08:00
using System.Threading.Tasks ;
using System.Windows.Forms ;
2021-07-07 13:36:25 +02:00
2022-05-22 15:55:26 +08:00
namespace RageCoop.Client
2021-07-07 13:36:25 +02:00
{
2021-12-03 20:30:00 +01:00
/// <summary>
/// Don't use it!
/// </summary>
2022-05-23 11:10:11 +08:00
internal class Main : Script
2021-07-07 13:36:25 +02:00
{
2022-04-10 14:34:55 +02:00
private bool _gameLoaded = false ;
2022-09-06 21:46:35 +08:00
internal static Version Version = typeof ( Main ) . Assembly . GetName ( ) . Version ;
2021-07-07 13:36:25 +02:00
2022-07-20 17:50:01 +08:00
internal static int LocalPlayerID = 0 ;
2022-05-31 09:14:30 +08:00
2022-05-23 11:10:11 +08:00
internal static RelationshipGroup SyncedPedsGroup ;
2021-07-07 13:36:25 +02:00
2022-06-12 15:39:32 +08:00
internal static new Settings Settings = null ;
2022-07-20 17:50:01 +08:00
internal static Scripting . BaseScript BaseScript = new Scripting . BaseScript ( ) ;
2021-08-18 11:47:59 +02:00
2021-09-26 20:52:23 -06:00
#if ! NON_INTERACTIVE
#endif
2022-06-12 15:39:32 +08:00
internal static Chat MainChat = null ;
internal static Stopwatch Counter = new Stopwatch ( ) ;
2022-06-22 08:58:36 +08:00
internal static Logger Logger = null ;
2022-07-20 17:50:01 +08:00
2022-06-12 15:39:32 +08:00
internal static ulong Ticked = 0 ;
2022-07-17 11:15:02 +08:00
internal static Vector3 PlayerPosition ;
2022-07-20 17:50:01 +08:00
internal static Scripting . Resources Resources = null ;
2022-09-06 21:46:35 +08:00
private static readonly List < Func < bool > > QueuedActions = new List < Func < bool > > ( ) ;
2022-08-08 17:03:41 +08:00
public static Worker Worker ;
2022-08-14 13:04:39 +08:00
2021-12-03 20:30:00 +01:00
/// <summary>
/// Don't use it!
/// </summary>
2021-07-07 13:36:25 +02:00
public Main ( )
2022-08-27 14:23:28 +08:00
{
2022-08-08 17:03:41 +08:00
Worker = new Worker ( "RageCoop.Client.Main.Worker" , Logger ) ;
2022-07-14 17:59:41 +08:00
try
{
Settings = Util . ReadSettings ( ) ;
}
catch
{
2024-06-30 05:17:35 -03:00
GTA . UI . Notification . PostTicker ( "Malformed configuration, overwriting with default values..." , false ) ;
2022-09-06 21:46:35 +08:00
Settings = new Settings ( ) ;
2022-07-14 17:59:41 +08:00
Util . SaveSettings ( ) ;
}
2022-07-02 13:53:14 +08:00
Directory . CreateDirectory ( Settings . DataDirectory ) ;
2022-09-06 21:46:35 +08:00
Logger = new Logger ( )
2022-05-31 19:35:01 -08:00
{
2022-09-06 21:46:35 +08:00
LogPath = $"{Settings.DataDirectory}\\RageCoop.Client.log" ,
UseConsole = false ,
2022-05-31 19:35:01 -08:00
#if DEBUG
LogLevel = 0 ,
#else
2022-06-02 08:53:01 +08:00
LogLevel = Settings . LogLevel ,
2022-05-31 19:35:01 -08:00
#endif
} ;
2022-06-12 17:11:14 +08:00
Resources = new Scripting . Resources ( ) ;
2022-06-22 14:18:20 +08:00
if ( Game . Version < GameVersion . v1_0_1290_1_Steam )
2021-12-14 14:20:41 +01:00
{
Tick + = ( object sender , EventArgs e ) = >
{
if ( Game . IsLoading )
{
return ;
}
2022-04-10 14:34:55 +02:00
if ( ! _gameLoaded )
2021-12-14 14:20:41 +01:00
{
2024-06-30 05:17:35 -03:00
GTA . UI . Notification . PostTicker ( "~r~Please update your GTA5 to v1.0.1290 or newer!" , true ) ;
2022-04-10 14:34:55 +02:00
_gameLoaded = true ;
2021-12-14 14:20:41 +01:00
}
} ;
return ;
2022-06-22 14:18:20 +08:00
}
BaseScript . OnStart ( ) ;
2022-09-06 21:46:35 +08:00
SyncedPedsGroup = World . AddRelationshipGroup ( "SYNCPED" ) ;
2022-05-22 15:55:26 +08:00
Game . Player . Character . RelationshipGroup . SetRelationshipBetweenGroups ( SyncedPedsGroup , Relationship . Neutral , true ) ;
2021-12-14 20:24:03 -07:00
#if ! NON_INTERACTIVE
#endif
2021-12-14 14:20:41 +01:00
MainChat = new Chat ( ) ;
2021-07-07 13:36:25 +02:00
Tick + = OnTick ;
2022-07-20 17:50:01 +08:00
Tick + = ( s , e ) = > { Scripting . API . Events . InvokeTick ( ) ; } ;
2021-07-07 13:36:25 +02:00
KeyDown + = OnKeyDown ;
2022-09-06 21:46:35 +08:00
KeyDown + = ( s , e ) = > { Scripting . API . Events . InvokeKeyDown ( s , e ) ; } ;
KeyUp + = ( s , e ) = > { Scripting . API . Events . InvokeKeyUp ( s , e ) ; } ;
Aborted + = ( object sender , EventArgs e ) = > Disconnected ( "Abort" ) ;
2022-07-20 17:50:01 +08:00
2021-07-13 16:32:45 +02:00
Util . NativeMemory ( ) ;
2022-05-22 15:55:26 +08:00
Counter . Restart ( ) ;
2021-07-07 13:36:25 +02:00
}
2022-08-14 13:04:39 +08:00
2022-07-20 17:50:01 +08:00
public static Ped P ;
public static float FPS ;
2022-07-21 08:41:05 +08:00
private bool _lastDead ;
2021-07-07 13:36:25 +02:00
private void OnTick ( object sender , EventArgs e )
{
2022-09-06 21:46:35 +08:00
P = Game . Player . Character ;
PlayerPosition = P . ReadPosition ( ) ;
FPS = Game . FPS ;
2021-07-07 13:36:25 +02:00
if ( Game . IsLoading )
{
return ;
}
2022-04-10 14:34:55 +02:00
else if ( ! _gameLoaded & & ( _gameLoaded = true ) )
2021-07-07 13:36:25 +02:00
{
2021-12-07 22:14:15 -07:00
#if ! NON_INTERACTIVE
2024-06-30 05:17:35 -03:00
GTA . UI . Notification . PostMessageText ( $"Press ~g~{Settings.MenuKey}~s~ to open the menu." , new GTA . Graphics . TextureAsset ( "CHAR_ALL_PLAYERS_CONF" , "CHAR_ALL_PLAYERS_CONF" ) , false , GTA . UI . FeedTextIcon . Message , "RAGECOOP" , "Welcome!" ) ;
2021-12-07 22:14:15 -07:00
#endif
2021-07-07 13:36:25 +02:00
}
2021-09-26 20:52:23 -06:00
#if ! NON_INTERACTIVE
2022-05-31 09:14:30 +08:00
CoopMenu . MenuPool . Process ( ) ;
2021-09-26 20:52:23 -06:00
#endif
2022-07-20 17:50:01 +08:00
2022-08-13 11:28:35 +08:00
2022-05-22 15:55:26 +08:00
DoQueuedActions ( ) ;
2022-05-25 11:32:34 +08:00
if ( ! Networking . IsOnServer )
2021-07-07 13:36:25 +02:00
{
return ;
}
2022-09-06 21:46:35 +08:00
if ( Game . TimeScale ! = 1 )
2022-04-11 15:10:27 +02:00
{
2022-09-06 21:46:35 +08:00
Game . TimeScale = 1 ;
2022-04-11 15:10:27 +02:00
}
2022-05-22 15:55:26 +08:00
try
2022-04-11 13:07:46 +02:00
{
2022-06-11 18:41:10 +08:00
EntityPool . DoSync ( ) ;
2022-05-22 15:55:26 +08:00
}
catch ( Exception ex )
{
2023-07-24 10:40:33 -03:00
#if DEBUG
2022-05-31 19:35:01 -08:00
Main . Logger . Error ( ex ) ;
2023-07-24 10:40:33 -03:00
#endif
2022-05-22 15:55:26 +08:00
}
2022-07-20 17:50:01 +08:00
2022-05-23 16:59:49 +08:00
if ( Networking . ShowNetworkInfo )
2021-08-18 11:47:59 +02:00
{
2022-05-23 16:59:49 +08:00
new LemonUI . Elements . ScaledText ( new PointF ( Screen . PrimaryScreen . Bounds . Width / 2 , 0 ) , $"L: {Networking.Latency * 1000:N0}ms" , 0.5f ) { Alignment = GTA . UI . Alignment . Center } . Draw ( ) ;
2022-07-06 01:03:18 +08:00
new LemonUI . Elements . ScaledText ( new PointF ( Screen . PrimaryScreen . Bounds . Width / 2 , 30 ) , $"R: {Lidgren.Network.NetUtility.ToHumanReadable(Statistics.BytesDownPerSecond)}/s" , 0.5f ) { Alignment = GTA . UI . Alignment . Center } . Draw ( ) ;
new LemonUI . Elements . ScaledText ( new PointF ( Screen . PrimaryScreen . Bounds . Width / 2 , 60 ) , $"S: {Lidgren.Network.NetUtility.ToHumanReadable(Statistics.BytesUpPerSecond)}/s" , 0.5f ) { Alignment = GTA . UI . Alignment . Center } . Draw ( ) ;
2021-08-18 11:47:59 +02:00
}
2022-05-22 15:55:26 +08:00
2021-07-07 13:36:25 +02:00
MainChat . Tick ( ) ;
2022-05-23 16:59:49 +08:00
PlayerList . Tick ( ) ;
2022-06-11 18:41:10 +08:00
if ( ! Scripting . API . Config . EnableAutoRespawn )
2022-05-31 02:16:12 -08:00
{
Function . Call ( Hash . PAUSE_DEATH_ARREST_RESTART , true ) ;
2022-06-22 14:18:20 +08:00
Function . Call ( Hash . IGNORE_NEXT_RESTART , true ) ;
2022-07-20 17:50:01 +08:00
Function . Call ( Hash . FORCE_GAME_STATE_PLAYING ) ;
2022-06-22 14:18:20 +08:00
Function . Call ( Hash . TERMINATE_ALL_SCRIPTS_WITH_THIS_NAME , "respawn_controller" ) ;
2022-05-31 02:16:12 -08:00
if ( P . IsDead )
{
Function . Call ( Hash . SET_FADE_OUT_AFTER_DEATH , false ) ;
2022-07-20 17:50:01 +08:00
2022-09-06 21:46:35 +08:00
if ( P . Health ! = 1 )
2022-05-31 02:16:12 -08:00
{
2022-09-06 21:46:35 +08:00
P . Health = 1 ;
Game . Player . WantedLevel = 0 ;
2022-05-31 02:16:12 -08:00
Main . Logger . Debug ( "Player died." ) ;
2023-10-06 23:46:08 -03:00
Scripting . API . Events . InvokePlayerDied ( KillMessage ( ) ) ;
2022-05-31 02:16:12 -08:00
}
GTA . UI . Screen . StopEffects ( ) ;
}
else
{
Function . Call ( Hash . DISPLAY_HUD , true ) ;
}
}
2022-07-21 08:41:05 +08:00
else if ( P . IsDead & & ! _lastDead )
{
2023-10-06 23:46:08 -03:00
Scripting . API . Events . InvokePlayerDied ( KillMessage ( ) ) ;
2022-07-21 08:41:05 +08:00
}
2022-09-06 21:46:35 +08:00
_lastDead = P . IsDead ;
2022-05-22 15:55:26 +08:00
Ticked + + ;
2021-07-07 13:36:25 +02:00
}
private void OnKeyDown ( object sender , KeyEventArgs e )
{
2022-08-13 02:19:40 +02:00
if ( MainChat . Focused )
{
MainChat . OnKeyDown ( e . KeyCode ) ;
return ;
}
if ( Networking . IsOnServer )
2022-08-13 00:52:34 +02:00
{
2022-08-15 16:13:53 +08:00
if ( Voice . WasInitialized ( ) )
2022-08-13 00:52:34 +02:00
{
2022-08-13 03:39:11 +02:00
if ( Game . IsControlPressed ( GTA . Control . PushToTalk ) )
{
2022-08-15 16:13:53 +08:00
Voice . StartRecording ( ) ;
2022-08-13 03:39:11 +02:00
return ;
}
2022-08-15 16:13:53 +08:00
else if ( Voice . IsRecording ( ) )
2022-08-13 03:39:11 +02:00
{
2022-08-15 16:13:53 +08:00
Voice . StopRecording ( ) ;
2022-08-13 03:39:11 +02:00
return ;
}
2022-08-13 00:52:34 +02:00
}
2022-09-06 21:46:35 +08:00
2022-05-25 21:54:25 +08:00
if ( Game . IsControlPressed ( GTA . Control . FrontendPause ) )
{
Function . Call ( Hash . ACTIVATE_FRONTEND_MENU , Function . Call < int > ( Hash . GET_HASH_KEY , "FE_MENU_VERSION_SP_PAUSE" ) , false , 0 ) ;
return ;
}
2022-09-06 21:46:35 +08:00
if ( Game . IsControlPressed ( GTA . Control . FrontendPauseAlternate ) & & Settings . DisableAlternatePause )
2022-05-25 21:54:25 +08:00
{
Function . Call ( Hash . ACTIVATE_FRONTEND_MENU , Function . Call < int > ( Hash . GET_HASH_KEY , "FE_MENU_VERSION_SP_PAUSE" ) , false , 0 ) ;
return ;
}
2022-05-25 11:32:34 +08:00
}
if ( e . KeyCode = = Settings . MenuKey )
2022-05-22 15:55:26 +08:00
{
2022-05-31 09:14:30 +08:00
if ( CoopMenu . MenuPool . AreAnyVisible )
2022-05-23 11:10:11 +08:00
{
2022-05-31 09:14:30 +08:00
CoopMenu . MenuPool . ForEach < LemonUI . Menus . NativeMenu > ( x = >
{
if ( x . Visible )
{
2022-09-06 21:46:35 +08:00
CoopMenu . LastMenu = x ;
x . Visible = false ;
2022-05-31 09:14:30 +08:00
}
} ) ;
2022-05-23 11:10:11 +08:00
}
else
{
2022-05-31 09:14:30 +08:00
CoopMenu . LastMenu . Visible = true ;
2022-05-23 11:10:11 +08:00
}
2022-05-22 15:55:26 +08:00
}
2022-08-16 22:16:18 +08:00
else if ( Game . IsControlJustPressed ( GTA . Control . MpTextChatAll ) )
{
if ( Networking . IsOnServer )
{
MainChat . Focused = true ;
}
}
2022-08-16 22:23:32 +08:00
else if ( MainChat . Focused ) { return ; }
else if ( Game . IsControlJustPressed ( GTA . Control . MultiplayerInfo ) )
2022-05-22 15:55:26 +08:00
{
2022-05-25 11:32:34 +08:00
if ( Networking . IsOnServer )
2022-05-23 11:10:11 +08:00
{
ulong currentTimestamp = Util . GetTickCount64 ( ) ;
2022-05-23 16:59:49 +08:00
PlayerList . Pressed = ( currentTimestamp - PlayerList . Pressed ) < 5000 ? ( currentTimestamp - 6000 ) : currentTimestamp ;
2022-05-23 11:10:11 +08:00
}
2022-05-22 15:55:26 +08:00
}
2022-09-06 21:46:35 +08:00
else if ( e . KeyCode = = Settings . PassengerKey )
2022-05-22 15:55:26 +08:00
{
var P = Game . Player . Character ;
2022-07-20 17:50:01 +08:00
2022-05-23 11:10:11 +08:00
if ( ! P . IsInVehicle ( ) )
2022-05-22 15:55:26 +08:00
{
2022-05-23 13:02:28 +08:00
if ( P . IsTaskActive ( TaskType . CTaskEnterVehicle ) )
2022-05-22 15:55:26 +08:00
{
2022-05-23 11:10:11 +08:00
P . Task . ClearAll ( ) ;
2022-05-22 15:55:26 +08:00
}
2022-05-23 11:10:11 +08:00
else
2022-05-22 15:55:26 +08:00
{
2022-07-23 23:45:20 +08:00
var V = World . GetClosestVehicle ( P . ReadPosition ( ) , 50 ) ;
2022-05-23 11:10:11 +08:00
2022-09-06 21:46:35 +08:00
if ( V ! = null )
2022-05-23 11:10:11 +08:00
{
2022-05-31 09:14:30 +08:00
var seat = P . GetNearestSeat ( V ) ;
2022-08-21 14:12:44 +08:00
var p = V . GetPedOnSeat ( seat ) ;
if ( p ! = null & & ! p . IsDead )
{
2022-09-06 21:46:35 +08:00
for ( int i = - 1 ; i < V . PassengerCapacity ; i + + )
2022-08-21 14:12:44 +08:00
{
seat = ( VehicleSeat ) i ;
p = V . GetPedOnSeat ( seat ) ;
if ( p = = null | | p . IsDead )
{
break ;
}
}
}
2022-09-06 21:46:35 +08:00
P . Task . EnterVehicle ( V , seat , - 1 , 5 , EnterVehicleFlags . None ) ;
2022-05-23 11:10:11 +08:00
}
2022-05-22 15:55:26 +08:00
}
}
}
2021-07-07 13:36:25 +02:00
}
2022-09-06 21:46:35 +08:00
internal static void Connected ( )
{
Memory . ApplyPatches ( ) ;
if ( Settings . Voice & & ! Voice . WasInitialized ( ) )
{
Voice . Init ( ) ;
}
QueueAction ( ( ) = >
{
WorldThread . Traffic ( ! Settings . DisableTraffic ) ;
Function . Call ( Hash . SET_ENABLE_VEHICLE_SLIPSTREAMING , true ) ;
CoopMenu . ConnectedMenuSetting ( ) ;
MainChat . Init ( ) ;
2024-06-30 05:17:35 -03:00
GTA . UI . Notification . PostTicker ( "~g~Connected!" , false ) ;
2022-09-06 21:46:35 +08:00
} ) ;
Logger . Info ( ">> Connected <<" ) ;
}
public static void Disconnected ( string reason )
2021-08-06 12:31:25 +02:00
{
2022-09-06 21:46:35 +08:00
Logger . Info ( $">> Disconnected << reason: {reason}" ) ;
QueueAction ( ( ) = >
{
if ( MainChat . Focused )
{
MainChat . Focused = false ;
}
2022-09-07 09:52:40 +08:00
PlayerList . Cleanup ( ) ;
2022-09-06 21:46:35 +08:00
MainChat . Clear ( ) ;
EntityPool . Cleanup ( ) ;
WorldThread . Traffic ( true ) ;
Function . Call ( Hash . SET_ENABLE_VEHICLE_SLIPSTREAMING , false ) ;
CoopMenu . DisconnectedMenuSetting ( ) ;
2023-10-22 17:14:50 -03:00
if ( reason ! = "Abort" )
2024-06-30 05:17:35 -03:00
GTA . UI . Notification . PostTicker ( "~r~Disconnected: " + reason , false ) ;
2022-09-07 09:52:40 +08:00
LocalPlayerID = default ;
2022-09-06 21:46:35 +08:00
} ) ;
2022-09-07 09:52:40 +08:00
Memory . RestorePatches ( ) ;
DownloadManager . Cleanup ( ) ;
Voice . ClearAll ( ) ;
2022-09-06 21:46:35 +08:00
Resources . Unload ( ) ;
2021-08-05 20:30:27 -03:00
}
2022-05-22 15:55:26 +08:00
private static void DoQueuedActions ( )
{
lock ( QueuedActions )
{
foreach ( var action in QueuedActions . ToArray ( ) )
{
try
{
if ( action ( ) )
{
QueuedActions . Remove ( action ) ;
}
}
2022-07-20 17:50:01 +08:00
catch ( Exception ex )
2022-05-22 15:55:26 +08:00
{
2023-07-24 10:40:33 -03:00
#if DEBUG
2022-06-18 12:06:22 +08:00
Logger . Error ( ex ) ;
2023-07-24 10:40:33 -03:00
#endif
2022-05-22 15:55:26 +08:00
QueuedActions . Remove ( action ) ;
}
}
}
}
/// <summary>
2022-07-14 18:50:15 +08:00
/// Queue an action to be executed on next tick, allowing you to call scripting API from another thread.
2022-05-22 15:55:26 +08:00
/// </summary>
2022-07-14 18:50:15 +08:00
/// <param name="a"> An action to be executed with a return value indicating whether the action can be removed after execution.</param>
2022-06-12 15:39:32 +08:00
internal static void QueueAction ( Func < bool > a )
2022-05-22 15:55:26 +08:00
{
lock ( QueuedActions )
{
QueuedActions . Add ( a ) ;
}
}
2022-06-12 15:39:32 +08:00
internal static void QueueAction ( Action a )
2022-05-22 15:55:26 +08:00
{
lock ( QueuedActions )
{
2022-07-20 17:50:01 +08:00
QueuedActions . Add ( ( ) = > { a ( ) ; return true ; } ) ;
2022-05-22 15:55:26 +08:00
}
}
/// <summary>
/// Clears all queued actions
/// </summary>
2022-06-12 15:39:32 +08:00
internal static void ClearQueuedActions ( )
2022-05-22 15:55:26 +08:00
{
lock ( QueuedActions ) { QueuedActions . Clear ( ) ; }
}
2022-07-21 22:42:29 +08:00
public static void Delay ( Action a , int time )
{
Task . Run ( ( ) = >
{
Thread . Sleep ( time ) ;
QueueAction ( a ) ;
} ) ;
}
2022-09-06 21:46:35 +08:00
2023-10-06 23:46:08 -03:00
private string KillMessage ( )
2023-10-06 16:36:49 -03:00
{
if ( P . Killer ! = null )
{
var killer = EntityPool . GetPedByHandle ( P . Killer . Handle ) ;
if ( killer ! = null & & killer . ID = = killer . Owner . ID )
2023-10-06 23:46:08 -03:00
return $"~h~{PlayerList.GetPlayer(LocalPlayerID).Username}~h~ was killed by ~h~{killer.Owner.Username}~h~ ({P.CauseOfDeath})" ;
2023-10-06 16:36:49 -03:00
}
2023-10-06 23:46:08 -03:00
return $"~h~{PlayerList.GetPlayer(LocalPlayerID).Username}~h~ died" ;
2023-10-06 16:36:49 -03:00
}
2021-07-07 13:36:25 +02:00
}
}