49 Commits
0.3a ... 0.4.1a

Author SHA1 Message Date
2c0b7d4d64 Update version 2022-06-04 12:31:45 +08:00
62dc98f4a7 Remove unnecessary packages 2022-06-04 12:25:01 +08:00
d061b5ecbe Fix NullReferenceException on start. 2022-06-04 12:04:02 +08:00
546f4b16f4 No, 0.5 is better. 2022-06-03 17:56:36 +08:00
5a455d0487 Auto fetch master server address 2022-06-03 16:28:02 +08:00
11d178498f Back to old rotation calculation. 2022-06-03 14:40:41 +08:00
88a51cc154 Add radio station sync. 2022-06-03 13:11:17 +08:00
291ba5691b Request WeaponAsset before swapping weapon. 2022-06-02 16:40:38 +08:00
de63cd1271 Add Tank muzzle flash 2022-06-02 15:51:58 +08:00
8479502d75 Fix scramjet 2022-06-02 14:10:29 +08:00
051b496021 Two muzzles fix 2022-06-02 13:52:18 +08:00
2c6f0dbe3d Don't delete player's vehicle 2022-06-02 13:11:01 +08:00
ffb73c1ce4 Fix savage 2022-06-02 13:09:13 +08:00
c941ca96fc Projectile and stromberg fix. 2022-06-02 12:44:05 +08:00
e2d4ce2159 Weapon fix 2022-06-02 10:34:33 +08:00
a500a4eeed closes #4, add scramjet. 2022-06-02 09:27:39 +08:00
603e8af746 closes #5, add Vigilante. 2022-06-02 09:26:53 +08:00
0ae4e1c122 closes #6, add Apocalypse 380Z 2022-06-02 09:25:23 +08:00
83f260048d closes #7, add Future Shock 380Z. 2022-06-02 09:24:37 +08:00
9b79956c71 closes #8, add Nightmare 380Z 2022-06-02 09:23:44 +08:00
82c6dab4c4 add stromberg 2022-06-02 09:21:46 +08:00
6611ecac18 closes #10, add apocalypse 2022-06-02 09:17:19 +08:00
3fa62f1a69 closes #3, add savage 2022-06-02 09:15:18 +08:00
ad3031ef59 Logger fix 2022-06-02 08:53:01 +08:00
42d057e2c5 Latency update and threading fixes. 2022-06-01 19:05:45 +08:00
87b9a67d0b Update assemby version 2022-06-01 18:01:38 +08:00
4fca28f0e0 Ah~ 2022-06-01 17:57:54 +08:00
8ebf03ca99 Hmm... 2022-06-01 17:57:27 +08:00
f2760b1533 Merge branch 'main' of https://github.com/RAGECOOP/RageCoop-V 2022-06-01 17:56:02 +08:00
7eec12486f country road, take me home... 2022-06-01 17:55:38 +08:00
d789e4cb0b Update README.md 2022-06-01 16:27:50 +08:00
485497286f Update README.md
some shit
2022-06-01 16:27:10 +08:00
a305fb349f Update README.md 2022-06-01 16:06:02 +08:00
7aa41a6e0c Master server is back! 2022-05-31 23:12:32 -08:00
9d9d421671 Small fix 2022-05-31 19:46:40 -08:00
a8a16fac61 Scripting? 2022-05-31 19:35:01 -08:00
b863b7037a Added ability to disable automatic respawn
Prepare for client side scripting.
2022-05-31 02:16:12 -08:00
a33f839004 opt 2022-05-31 10:11:06 +08:00
a48170fec8 EnterVehicle fix, reduce NPC 2022-05-31 09:55:54 +08:00
2181a52d6c Add Tula 2022-05-31 09:24:28 +08:00
b96d349e4a Lots of sh*t
API cleanup
Complete deluxo transformation sync
blahblahblah
2022-05-31 09:14:30 +08:00
ad698a656d Removed LVector, LQuaternion.
Server side optimization.
Nework optimization (streaming distance).
2022-05-30 14:32:38 +08:00
aefea337f1 Some optimization. 2022-05-30 11:11:40 +08:00
811e7df14e fix for changing owner. 2022-05-29 18:27:07 +08:00
5cc63e688f Merge branch 'main' of https://github.com/RAGECOOP/RageCoop-V 2022-05-29 18:16:44 +08:00
08aa1370de Add nozzle and deluxo transformation sync. 2022-05-29 18:16:32 +08:00
5d6b99442b Update README.md 2022-05-27 17:08:40 +08:00
65b695cb78 Update README.md 2022-05-27 17:06:41 +08:00
ce94a9c7af Update README.md 2022-05-27 17:01:31 +08:00
63 changed files with 2871 additions and 2077 deletions

View File

@ -11,14 +11,15 @@ namespace RageCoop.Client
/// </summary> /// </summary>
public static class COOPAPI public static class COOPAPI
{ {
#region DELEGATES #region DELEGATES
/// <summary> /// <summary>
/// ? /// ?
/// </summary> /// </summary>
/// <param name="connected"></param> /// <param name="connected"></param>
/// <param name="from">The Lidgren-Network net handle</param> /// <param name="from">The player's id</param>
/// <param name="reason"></param> /// <param name="reason"></param>
public delegate void ConnectEvent(bool connected, long from, string reason = null); public delegate void ConnectEvent(bool connected, int from, string reason = null);
/// <summary> /// <summary>
/// ? /// ?
/// </summary> /// </summary>
@ -45,10 +46,6 @@ namespace RageCoop.Client
/// ? /// ?
/// </summary> /// </summary>
public static event ChatMessage OnChatMessage; public static event ChatMessage OnChatMessage;
/// <summary>
/// ?
/// </summary>
public static event ModEvent OnModPacketReceived;
public static void Connected() public static void Connected()
{ {
@ -60,19 +57,14 @@ namespace RageCoop.Client
OnConnection?.Invoke(false, GetPlayerID(), reason); OnConnection?.Invoke(false, GetPlayerID(), reason);
} }
public static void Connected(long netHandle) public static void Connected(int playerID)
{ {
OnConnection?.Invoke(true, netHandle); OnConnection?.Invoke(true, playerID);
} }
public static void Disconnected(long netHandle) public static void Disconnected(int playerID)
{ {
OnConnection?.Invoke(false, netHandle); OnConnection?.Invoke(false, playerID);
}
public static void ModPacketReceived(long from, string mod, byte customID, byte[] bytes)
{
OnModPacketReceived?.Invoke(from, mod, customID, bytes);
} }
public static bool ChatMessageReceived(string from, string message) public static bool ChatMessageReceived(string from, string message)
@ -99,7 +91,7 @@ namespace RageCoop.Client
/// <param name="serverAddress">The server address to connect. Example: 127.0.0.1:4499</param> /// <param name="serverAddress">The server address to connect. Example: 127.0.0.1:4499</param>
public static void Connect(string serverAddress) public static void Connect(string serverAddress)
{ {
Networking.DisConnectFromServer(serverAddress); Networking.ToggleConnection(serverAddress);
} }
/// <summary> /// <summary>
@ -107,7 +99,7 @@ namespace RageCoop.Client
/// </summary> /// </summary>
public static void Disconnect() public static void Disconnect()
{ {
Networking.DisConnectFromServer(null); Networking.ToggleConnection(null);
} }
/// <summary> /// <summary>
@ -122,25 +114,11 @@ namespace RageCoop.Client
/// Get the local player's ID /// Get the local player's ID
/// </summary> /// </summary>
/// <returns>PlayerID</returns> /// <returns>PlayerID</returns>
public static long GetPlayerID() public static int GetPlayerID()
{ {
return Main.LocalPlayerID; return Main.LocalPlayerID;
} }
/*
/// <summary>
/// Get a player using their Lidgren Network net handle
/// </summary>
/// <param name="handle">Lidgren-Network net handle</param>
public static CharacterEntity GetPed(int ID)
{
lock (Main.Characters)
{
return Main.Characters.ContainsKey(ID) ? Main.Characters[ID] : null;
}
}
*/
/// <summary> /// <summary>
/// Check if a RAGECOOP menu is visible /// Check if a RAGECOOP menu is visible
/// </summary> /// </summary>
@ -149,7 +127,7 @@ namespace RageCoop.Client
#if NON_INTERACTIVE #if NON_INTERACTIVE
return false; return false;
#else #else
return Main.MainMenu.MenuPool.AreAnyVisible; return Menus.CoopMenu.MenuPool.AreAnyVisible;
#endif #endif
} }
@ -177,40 +155,6 @@ namespace RageCoop.Client
return Main.CurrentVersion; return Main.CurrentVersion;
} }
/// <summary>
/// Send any data (bytes) to the server
/// </summary>
/// <param name="modName">The name of this modification (script)</param>
/// <param name="customID">The ID to know what the data is</param>
/// <param name="bytes">Your class, structure or whatever in bytes</param>
public static void SendDataToServer(string modName, byte customID, byte[] bytes)
{
Networking.SendModData(-1, modName, customID, bytes);
}
/// <summary>
/// Send any data (bytes) to the all player
/// </summary>
/// <param name="modName">The name of this modification (script)</param>
/// <param name="customID">The ID to know what the data is</param>
/// <param name="bytes">Your class, structure or whatever in bytes</param>
public static void SendDataToAll(string modName, byte customID, byte[] bytes)
{
Networking.SendModData(0, modName, customID, bytes);
}
/// <summary>
/// Send any data (bytes) to a player
/// </summary>
/// <param name="netHandle">The Lidgren Network net handle that receives the data</param>
/// <param name="modName">The name of this modification (script)</param>
/// <param name="customID">The ID to know what the data is</param>
/// <param name="bytes">Your class, structure or whatever in bytes</param>
public static void SendDataToPlayer(long netHandle, string modName, byte customID, byte[] bytes)
{
Networking.SendModData(netHandle, modName, customID, bytes);
}
/// <summary> /// <summary>
/// Get that player's local username /// Get that player's local username
/// </summary> /// </summary>
@ -236,35 +180,13 @@ namespace RageCoop.Client
return true; return true;
} }
/// <summary> /// <summary>
/// Enable or disable the local traffic for this player /// Get or set the client's settings.
/// </summary> /// </summary>
/// <param name="enable">true to disable traffic</param> /// <returns>The client's settings, you should NEVER change settings without notifying the player.</returns>
public static void SetLocalTraffic(bool enable) public static Settings Settings()
{ {
Main.Settings.DisableTraffic = !enable; return Main.Settings;
} }
/// <summary>
/// Sets the alignment for the player list, if set to true it will align left,
/// otherwise it will align right
/// </summary>
/// <param name="leftAlign">true to move the player list to the left</param>
public static void SetPlayerListLeftAlign(bool leftAlign)
{
PlayerList.LeftAlign = leftAlign;
}
#if DEBUG
/// <summary>
/// ?
/// </summary>
/// <param name="value"></param>
public static void SetDebug(bool value)
{
Main.UseDebug = value;
}
#endif
} }
} }

View File

@ -130,7 +130,7 @@ namespace RageCoop.Client
s=$@" s=$@"
// {ToMark.DisplayName} // {ToMark.DisplayName}
case {ToMark.Model.Hash}: case {ToMark.Model.Hash}:
i=Main.Ticked%2==0 ? {Current} : {Secondary}; i=BulletsShot%2==0 ? {Current} : {Secondary};
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].{dir}Vector); return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].{dir}Vector);
"; ";
} }
@ -139,7 +139,7 @@ namespace RageCoop.Client
s=$@" s=$@"
// {ToMark.DisplayName} // {ToMark.DisplayName}
case {ToMark.Model.Hash}: case {ToMark.Model.Hash}:
i=Main.Ticked%2==0 ? {Current} : {Secondary}; i=BulletsShot%2==0 ? {Current} : {Secondary};
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].{((MuzzleDir)(dir-3)).ToString()}Vector*-1); return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].{((MuzzleDir)(dir-3)).ToString()}Vector*-1);
"; ";
} }

View File

@ -21,25 +21,22 @@ namespace RageCoop.Client
{ {
private bool _gameLoaded = false; private bool _gameLoaded = false;
private static bool _isGoingToCar = false; private bool _lastDead = false;
public static readonly string CurrentVersion = "V0_4_1";
public static readonly string CurrentVersion = "V0_2";
public static int LocalPlayerID=0; public static int LocalPlayerID=0;
public static bool NPCsAllowed = false;
internal static RelationshipGroup SyncedPedsGroup; internal static RelationshipGroup SyncedPedsGroup;
public static new Settings Settings = null; public static new Settings Settings = null;
#if !NON_INTERACTIVE #if !NON_INTERACTIVE
public static RageCoopMenu MainMenu = null;
#endif #endif
public static Chat MainChat = null; public static Chat MainChat = null;
public static Stopwatch Counter = new Stopwatch(); public static Stopwatch Counter = new Stopwatch();
public static Core.Logging.Logger Logger = null;
public static ulong Ticked = 0; public static ulong Ticked = 0;
public static Loggger Logger=new Loggger("Scripts\\RageCoop\\RageCoop.Client.log");
private static List<Func<bool>> QueuedActions = new List<Func<bool>>(); private static List<Func<bool>> QueuedActions = new List<Func<bool>>();
/// <summary> /// <summary>
@ -47,7 +44,17 @@ namespace RageCoop.Client
/// </summary> /// </summary>
public Main() public Main()
{ {
Settings = Util.ReadSettings();
Logger=new Core.Logging.Logger()
{
LogPath="Scripts\\RageCoop\\RageCoop.Client.log",
UseConsole=false,
#if DEBUG
LogLevel = 0,
#else
LogLevel=Settings.LogLevel,
#endif
};
// Required for some synchronization! // Required for some synchronization!
/*if (Game.Version < GameVersion.v1_0_1290_1_Steam) /*if (Game.Version < GameVersion.v1_0_1290_1_Steam)
{ {
@ -68,17 +75,10 @@ namespace RageCoop.Client
}*/ }*/
SyncedPedsGroup=World.AddRelationshipGroup("SYNCPED"); SyncedPedsGroup=World.AddRelationshipGroup("SYNCPED");
Game.Player.Character.RelationshipGroup.SetRelationshipBetweenGroups(SyncedPedsGroup, Relationship.Neutral, true); Game.Player.Character.RelationshipGroup.SetRelationshipBetweenGroups(SyncedPedsGroup, Relationship.Neutral, true);
Settings = Util.ReadSettings();
Networking.Start(); Networking.Start();
#if !NON_INTERACTIVE #if !NON_INTERACTIVE
MainMenu = new RageCoopMenu();
#endif #endif
MainChat = new Chat(); MainChat = new Chat();
#if DEBUG
Logger.LogLevel = 0;
#else
Logger.LogLevel=Settings.LogLevel;
#endif
Tick += OnTick; Tick += OnTick;
KeyDown += OnKeyDown; KeyDown += OnKeyDown;
@ -107,14 +107,9 @@ namespace RageCoop.Client
} }
#if !NON_INTERACTIVE #if !NON_INTERACTIVE
MainMenu.MenuPool.Process(); CoopMenu.MenuPool.Process();
#endif #endif
if (_isGoingToCar && Game.Player.Character.IsInVehicle())
{
_isGoingToCar = false;
}
DoQueuedActions(); DoQueuedActions();
if (!Networking.IsOnServer) if (!Networking.IsOnServer)
{ {
@ -130,7 +125,7 @@ namespace RageCoop.Client
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Error(ex); Main.Logger.Error(ex);
} }
if (!DownloadManager.DownloadComplete) if (!DownloadManager.DownloadComplete)
@ -164,9 +159,32 @@ namespace RageCoop.Client
MainChat.Tick(); MainChat.Tick();
PlayerList.Tick(); PlayerList.Tick();
if (Settings.DisableAutoRespawn)
{
Function.Call(Hash.PAUSE_DEATH_ARREST_RESTART, true);
Function.Call(Hash.FORCE_GAME_STATE_PLAYING);
var P = Game.Player.Character;
if (P.IsDead)
{
Function.Call(Hash.TERMINATE_ALL_SCRIPTS_WITH_THIS_NAME, "respawn_controller");
Function.Call(Hash.SET_FADE_OUT_AFTER_DEATH, false);
if (P.Health!=1)
{
P.Health=1;
Game.Player.WantedLevel=0;
Main.Logger.Debug("Player died.");
}
GTA.UI.Screen.StopEffects();
}
else
{
Function.Call(Hash.DISPLAY_HUD, true);
}
_lastDead=P.IsDead;
}
Ticked++; Ticked++;
} }
@ -193,14 +211,20 @@ namespace RageCoop.Client
} }
if (e.KeyCode == Settings.MenuKey) if (e.KeyCode == Settings.MenuKey)
{ {
if (MainMenu.MenuPool.AreAnyVisible) if (CoopMenu.MenuPool.AreAnyVisible)
{ {
MainMenu.MainMenu.Visible = false; CoopMenu.MenuPool.ForEach<LemonUI.Menus.NativeMenu>(x =>
MainMenu.SubSettings.Menu.Visible = false; {
if (x.Visible)
{
CoopMenu.LastMenu=x;
x.Visible=false;
}
});
} }
else else
{ {
MainMenu.MainMenu.Visible = true; CoopMenu.LastMenu.Visible = true;
} }
} }
else if (Game.IsControlJustPressed(GTA.Control.MultiplayerInfo)) else if (Game.IsControlJustPressed(GTA.Control.MultiplayerInfo))
@ -234,7 +258,7 @@ namespace RageCoop.Client
if (V!=null) if (V!=null)
{ {
var seat = Util.GetNearestSeat(P, V); var seat = P.GetNearestSeat(V);
P.Task.EnterVehicle(V, seat); P.Task.EnterVehicle(V, seat);
} }
} }
@ -311,7 +335,7 @@ namespace RageCoop.Client
catch catch
{ {
GTA.UI.Notification.Show("~r~~h~CleanUpWorld() Error"); GTA.UI.Notification.Show("~r~~h~CleanUpWorld() Error");
Logger.Error($"CleanUpWorld(): ~r~Item {item.Value} cannot be deleted!"); Main.Logger.Error($"CleanUpWorld(): ~r~Item {item.Value} cannot be deleted!");
} }
} }
@ -379,7 +403,7 @@ namespace RageCoop.Client
// s+=$"\r\n{c.IsAiming} {c.IsJumping} {c.IsOnFire} {c.IsOnLadder} {c.IsRagdoll} {c.IsReloading} {c.IsShooting} {c.Speed}"; // s+=$"\r\n{c.IsAiming} {c.IsJumping} {c.IsOnFire} {c.IsOnLadder} {c.IsRagdoll} {c.IsReloading} {c.IsShooting} {c.Speed}";
} }
} }
Logger.Trace(s); Main.Logger.Trace(s);
return s; return s;
} }
public static string DumpPlayers() public static string DumpPlayers()
@ -390,7 +414,7 @@ namespace RageCoop.Client
s+=$"\r\nID:{p.PedID} Username:{p.Username}"; s+=$"\r\nID:{p.PedID} Username:{p.Username}";
} }
Logger.Trace(s); Main.Logger.Trace(s);
return s; return s;
} }

114
Client/Menus/CoopMenu.cs Normal file
View File

@ -0,0 +1,114 @@
using GTA;
using System.Drawing;
using LemonUI;
using LemonUI.Menus;
namespace RageCoop.Client.Menus
{
/// <summary>
/// Don't use it!
/// </summary>
internal static class CoopMenu
{
public static ObjectPool MenuPool = new ObjectPool();
public static NativeMenu Menu = new NativeMenu("RAGECOOP", "MAIN")
{
UseMouse = false,
Alignment = Main.Settings.FlipMenu ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left
};
public static NativeMenu LastMenu { get; set; } = Menu;
#region ITEMS
private static readonly NativeItem _usernameItem = new NativeItem("Username") { AltTitle = Main.Settings.Username };
public static readonly NativeItem ServerIpItem = new NativeItem("Server IP") { AltTitle = Main.Settings.LastServerAddress };
private static readonly NativeItem _serverConnectItem = new NativeItem("Connect");
private static readonly NativeItem _aboutItem = new NativeItem("About", "~y~SOURCE~s~~n~" +
"https://github.com/RAGECOOP~n~" +
"~y~VERSION~s~~n~" +
Main.CurrentVersion.Replace("_", ".")) { LeftBadge = new LemonUI.Elements.ScaledTexture("commonmenu", "shop_new_star") };
#endregion
/// <summary>
/// Don't use it!
/// </summary>
static CoopMenu()
{
Menu.Banner.Color = Color.FromArgb(225, 0, 0, 0);
Menu.Title.Color = Color.FromArgb(255, 165, 0);
_usernameItem.Activated += UsernameActivated;
ServerIpItem.Activated += ServerIpActivated;
_serverConnectItem.Activated += (sender, item) => { Networking.ToggleConnection(Main.Settings.LastServerAddress); };
Menu.AddSubMenu(ServersMenu.Menu);
Menu.Add(_usernameItem);
Menu.Add(ServerIpItem);
Menu.Add(_serverConnectItem);
Menu.AddSubMenu(SettingsMenu.Menu);
Menu.AddSubMenu(DevToolMenu.Menu);
Menu.AddSubMenu(DebugMenu.Menu);
MenuPool.Add(Menu);
MenuPool.Add(SettingsMenu.Menu);
MenuPool.Add(DevToolMenu.Menu);
MenuPool.Add(DebugMenu.Menu);
MenuPool.Add(DebugMenu.DiagnosticMenu);
MenuPool.Add(ServersMenu.Menu);
Menu.Add(_aboutItem);
}
public static void UsernameActivated(object a, System.EventArgs b)
{
string newUsername = Game.GetUserInput(WindowTitle.EnterMessage20, _usernameItem.AltTitle, 20);
if (!string.IsNullOrWhiteSpace(newUsername))
{
Main.Settings.Username = newUsername;
Util.SaveSettings();
_usernameItem.AltTitle = newUsername;
}
}
public static void ServerIpActivated(object a, System.EventArgs b)
{
string newServerIp = Game.GetUserInput(WindowTitle.EnterMessage60, ServerIpItem.AltTitle, 60);
if (!string.IsNullOrWhiteSpace(newServerIp) && newServerIp.Contains(":"))
{
Main.Settings.LastServerAddress = newServerIp;
Util.SaveSettings();
ServerIpItem.AltTitle = newServerIp;
}
}
public static void InitiateConnectionMenuSetting()
{
_usernameItem.Enabled = false;
ServerIpItem.Enabled = false;
_serverConnectItem.Enabled = false;
}
public static void ConnectedMenuSetting()
{
_serverConnectItem.Enabled = true;
_serverConnectItem.Title = "Disconnect";
Menu.Visible = false;
}
public static void DisconnectedMenuSetting()
{
_usernameItem.Enabled = true;
ServerIpItem.Enabled = true;
_serverConnectItem.Enabled = true;
_serverConnectItem.Title = "Connect";
}
}
}

View File

@ -1,115 +0,0 @@
using GTA;
using System.Drawing;
using LemonUI;
using LemonUI.Menus;
namespace RageCoop.Client.Menus
{
/// <summary>
/// Don't use it!
/// </summary>
public class RageCoopMenu
{
public ObjectPool MenuPool = new ObjectPool();
public NativeMenu MainMenu = new NativeMenu("RAGECOOP", "MAIN")
{
UseMouse = false,
Alignment = Main.Settings.FlipMenu ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left
};
#region SUB
public Sub.SettingsMenu SubSettings = new Sub.SettingsMenu();
#endregion
#region ITEMS
private readonly NativeItem _usernameItem = new NativeItem("Username") { AltTitle = Main.Settings.Username };
public readonly NativeItem ServerIpItem = new NativeItem("Server IP") { AltTitle = Main.Settings.LastServerAddress };
private readonly NativeItem _serverConnectItem = new NativeItem("Connect");
private readonly NativeItem _aboutItem = new NativeItem("About", "~y~SOURCE~s~~n~" +
"https://github.com/RAGECOOP~n~" +
"~y~VERSION~s~~n~" +
Main.CurrentVersion.Replace("_", ".")) { LeftBadge = new LemonUI.Elements.ScaledTexture("commonmenu", "shop_new_star") };
#endregion
/// <summary>
/// Don't use it!
/// </summary>
public RageCoopMenu()
{
MainMenu.Banner.Color = Color.FromArgb(225, 0, 0, 0);
MainMenu.Title.Color = Color.FromArgb(255, 165, 0);
_usernameItem.Activated += UsernameActivated;
ServerIpItem.Activated += ServerIpActivated;
_serverConnectItem.Activated += (sender, item) => { Networking.DisConnectFromServer(Main.Settings.LastServerAddress); };
MainMenu.Add(_usernameItem);
MainMenu.Add(ServerIpItem);
MainMenu.Add(_serverConnectItem);
MainMenu.Add(_aboutItem);
MainMenu.AddSubMenu(SubSettings.Menu);
MainMenu.AddSubMenu(DevToolMenu.Menu);
MainMenu.AddSubMenu(DebugMenu.Menu);
MenuPool.Add(MainMenu);
MenuPool.Add(SubSettings.Menu);
MenuPool.Add(DevToolMenu.Menu);
MenuPool.Add(DebugMenu.Menu);
MenuPool.Add(DebugMenu.DiagnosticMenu);
}
public void UsernameActivated(object a, System.EventArgs b)
{
string newUsername = Game.GetUserInput(WindowTitle.EnterMessage20, _usernameItem.AltTitle, 20);
if (!string.IsNullOrWhiteSpace(newUsername))
{
Main.Settings.Username = newUsername;
Util.SaveSettings();
_usernameItem.AltTitle = newUsername;
}
}
public void ServerIpActivated(object a, System.EventArgs b)
{
string newServerIp = Game.GetUserInput(WindowTitle.EnterMessage60, ServerIpItem.AltTitle, 60);
if (!string.IsNullOrWhiteSpace(newServerIp) && newServerIp.Contains(":"))
{
Main.Settings.LastServerAddress = newServerIp;
Util.SaveSettings();
ServerIpItem.AltTitle = newServerIp;
}
}
public void InitiateConnectionMenuSetting()
{
MainMenu.Items[0].Enabled = false;
MainMenu.Items[1].Enabled = false;
MainMenu.Items[2].Enabled = false;
}
public void ConnectedMenuSetting()
{
MainMenu.Items[2].Enabled = true;
MainMenu.Items[2].Title = "Disconnect";
MainMenu.Visible = false;
}
public void DisconnectedMenuSetting()
{
MainMenu.Items[0].Enabled = true;
MainMenu.Items[1].Enabled = true;
MainMenu.Items[2].Enabled = true;
MainMenu.Items[2].Title = "Connect";
SubSettings.Menu.Items[1].Enabled = false;
}
}
}

View File

@ -29,7 +29,7 @@ namespace RageCoop.Client
d1.Activated+=(sender,e) => d1.Activated+=(sender,e) =>
{ {
try{ SyncParameters.PositioinPrediction =float.Parse(Game.GetUserInput(WindowTitle.EnterMessage20, SyncParameters.PositioinPrediction.ToString(), 20));} try{ SyncParameters.PositioinPredictionDefault =float.Parse(Game.GetUserInput(WindowTitle.EnterMessage20, SyncParameters.PositioinPredictionDefault.ToString(), 20));}
catch { } catch { }
Update(); Update();
}; };
@ -55,7 +55,7 @@ namespace RageCoop.Client
private static void Update() private static void Update()
{ {
d1.AltTitle = SyncParameters.PositioinPrediction.ToString(); d1.AltTitle = SyncParameters.PositioinPredictionDefault.ToString();
} }
} }
} }

View File

@ -9,7 +9,7 @@ using System.Drawing;
namespace RageCoop.Client namespace RageCoop.Client
{ {
internal class DevToolMenu internal static class DevToolMenu
{ {
public static NativeMenu Menu = new NativeMenu("RAGECOOP", "DevTool", "Help with the development") public static NativeMenu Menu = new NativeMenu("RAGECOOP", "DevTool", "Help with the development")
{ {

View File

@ -0,0 +1,148 @@
using System;
using System.Net;
using System.Drawing;
using System.Collections.Generic;
using Newtonsoft.Json;
using LemonUI.Menus;
using System.Threading;
namespace RageCoop.Client.Menus
{
internal class ServerListClass
{
[JsonProperty("address")]
public string Address { get; set; }
[JsonProperty("port")]
public string Port { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("version")]
public string Version { get; set; }
[JsonProperty("players")]
public int Players { get; set; }
[JsonProperty("maxPlayers")]
public int MaxPlayers { get; set; }
[JsonProperty("country")]
public string Country { get; set; }
}
/// <summary>
/// Don't use it!
/// </summary>
internal static class ServersMenu
{
private static Thread GetServersThread;
internal static NativeMenu Menu = new NativeMenu("RAGECOOP", "Servers", "Go to the server list")
{
UseMouse = false,
Alignment = Main.Settings.FlipMenu ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left
};
internal static NativeItem ResultItem = null;
/// <summary>
/// Don't use it!
/// </summary>
static ServersMenu()
{
Menu.Banner.Color = Color.FromArgb(225, 0, 0, 0);
Menu.Title.Color = Color.FromArgb(255, 165, 0);
Menu.Opening += (object sender, System.ComponentModel.CancelEventArgs e) =>
{
CleanUpList();
Menu.Add(ResultItem = new NativeItem("Loading..."));
// Prevent freezing
GetServersThread=new Thread(()=> GetAllServers());
GetServersThread.Start();
};
Menu.Closing += (object sender, System.ComponentModel.CancelEventArgs e) =>
{
CleanUpList();
};
}
private static void CleanUpList()
{
Menu.Clear();
ResultItem = null;
}
private static void GetAllServers()
{
List<ServerListClass> serverList = null;
var realUrl = Main.Settings.MasterServer=="[AUTO]" ? DownloadString("https://ragecoop.online/stuff/masterserver") : Main.Settings.MasterServer;
serverList = JsonConvert.DeserializeObject<List<ServerListClass>>(DownloadString(realUrl));
// Need to be processed in main thread
Main.QueueAction(() =>
{
if (serverList == null)
{
ResultItem.Title = "Something went wrong!";
return;
}
if (serverList.Count == 0)
{
ResultItem.Title = "No server was found!";
return;
}
CleanUpList();
foreach (ServerListClass server in serverList)
{
string address = $"{server.Address}:{server.Port}";
NativeItem tmpItem = new NativeItem($"[{server.Country}] {server.Name}", $"~b~{address}~s~~n~~g~Version {server.Version}.x~s~") { AltTitle = $"[{server.Players}/{server.MaxPlayers}]" };
tmpItem.Activated += (object sender, EventArgs e) =>
{
try
{
Menu.Visible = false;
Networking.ToggleConnection(address);
#if !NON_INTERACTIVE
CoopMenu.ServerIpItem.AltTitle = address;
CoopMenu.Menu.Visible = true;
#endif
Main.Settings.LastServerAddress = address;
Util.SaveSettings();
}
catch (Exception ex)
{
GTA.UI.Notification.Show($"~r~{ex.Message}");
}
};
Menu.Add(tmpItem);
}
});
}
private static string DownloadString(string url)
{
try
{
// TLS only
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls13 | SecurityProtocolType.Tls12;
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
WebClient client = new WebClient();
return client.DownloadString(url);
}
catch (Exception ex)
{
Main.QueueAction(() =>
{
ResultItem.Title = "Download failed!";
ResultItem.Description = ex.Message;
});
return "";
}
}
}
}

View File

@ -4,24 +4,24 @@ using System.Windows.Forms;
using GTA; using GTA;
using LemonUI.Menus; using LemonUI.Menus;
namespace RageCoop.Client.Menus.Sub namespace RageCoop.Client.Menus
{ {
/// <summary> /// <summary>
/// Don't use it! /// Don't use it!
/// </summary> /// </summary>
public class SettingsMenu internal static class SettingsMenu
{ {
public NativeMenu Menu = new NativeMenu("RAGECOOP", "Settings", "Go to the settings") public static NativeMenu Menu = new NativeMenu("RAGECOOP", "Settings", "Go to the settings")
{ {
UseMouse = false, UseMouse = false,
Alignment = Main.Settings.FlipMenu ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left Alignment = Main.Settings.FlipMenu ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left
}; };
private readonly NativeCheckboxItem _disableTrafficItem = new NativeCheckboxItem("Disable Traffic (NPCs/Vehicles)", "Local traffic only", Main.Settings.DisableTraffic); private static readonly NativeCheckboxItem _disableTrafficItem = new NativeCheckboxItem("Disable Traffic (NPCs/Vehicles)", "Local traffic only", Main.Settings.DisableTraffic);
private readonly NativeCheckboxItem _flipMenuItem = new NativeCheckboxItem("Flip menu", Main.Settings.FlipMenu); private static readonly NativeCheckboxItem _flipMenuItem = new NativeCheckboxItem("Flip menu", Main.Settings.FlipMenu);
private readonly NativeCheckboxItem _disablePauseAlt = new NativeCheckboxItem("Disable Alternate Pause", "Don't freeze game time when Esc pressed", Main.Settings.DisableTraffic); private static readonly NativeCheckboxItem _disablePauseAlt = new NativeCheckboxItem("Disable Alternate Pause", "Don't freeze game time when Esc pressed", Main.Settings.DisableTraffic);
private readonly NativeCheckboxItem _showNetworkInfoItem = new NativeCheckboxItem("Show Network Info", Networking.ShowNetworkInfo); private static readonly NativeCheckboxItem _showNetworkInfoItem = new NativeCheckboxItem("Show Network Info", Networking.ShowNetworkInfo);
private static NativeItem _menuKey = new NativeItem("Menu Key","The key to open menu", Main.Settings.MenuKey.ToString()); private static NativeItem _menuKey = new NativeItem("Menu Key","The key to open menu", Main.Settings.MenuKey.ToString());
private static NativeItem _passengerKey = new NativeItem("Passenger Key", "The key to enter a vehicle as passenger", Main.Settings.PassengerKey.ToString()); private static NativeItem _passengerKey = new NativeItem("Passenger Key", "The key to enter a vehicle as passenger", Main.Settings.PassengerKey.ToString());
@ -30,7 +30,7 @@ namespace RageCoop.Client.Menus.Sub
/// <summary> /// <summary>
/// Don't use it! /// Don't use it!
/// </summary> /// </summary>
public SettingsMenu() static SettingsMenu()
{ {
Menu.Banner.Color = Color.FromArgb(225, 0, 0, 0); Menu.Banner.Color = Color.FromArgb(225, 0, 0, 0);
Menu.Title.Color = Color.FromArgb(255, 165, 0); Menu.Title.Color = Color.FromArgb(255, 165, 0);
@ -54,12 +54,12 @@ namespace RageCoop.Client.Menus.Sub
private void _disablePauseAlt_CheckboxChanged(object sender, EventArgs e) private static void _disablePauseAlt_CheckboxChanged(object sender, EventArgs e)
{ {
Main.Settings.DisableAlternatePause=_disablePauseAlt.Checked; Main.Settings.DisableAlternatePause=_disablePauseAlt.Checked;
Util.SaveSettings(); Util.SaveSettings();
} }
private void vehicleSoftLimit_Activated(object sender, EventArgs e) private static void vehicleSoftLimit_Activated(object sender, EventArgs e)
{ {
try try
{ {
@ -71,7 +71,7 @@ namespace RageCoop.Client.Menus.Sub
} }
catch { } catch { }
} }
private void ChaneMenuKey(object sender, EventArgs e) private static void ChaneMenuKey(object sender, EventArgs e)
{ {
try try
{ {
@ -85,7 +85,7 @@ namespace RageCoop.Client.Menus.Sub
catch { } catch { }
} }
private void ChangePassengerKey(object sender, EventArgs e) private static void ChangePassengerKey(object sender, EventArgs e)
{ {
try try
{ {
@ -99,22 +99,22 @@ namespace RageCoop.Client.Menus.Sub
catch { } catch { }
} }
public void DisableTrafficCheckboxChanged(object a, System.EventArgs b) public static void DisableTrafficCheckboxChanged(object a, System.EventArgs b)
{ {
Main.Settings.DisableTraffic = _disableTrafficItem.Checked; Main.Settings.DisableTraffic = _disableTrafficItem.Checked;
Util.SaveSettings() ; Util.SaveSettings() ;
} }
public void FlipMenuCheckboxChanged(object a, System.EventArgs b) public static void FlipMenuCheckboxChanged(object a, System.EventArgs b)
{ {
Main.MainMenu.MainMenu.Alignment = _flipMenuItem.Checked ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left; CoopMenu.Menu.Alignment = _flipMenuItem.Checked ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left;
Menu.Alignment = _flipMenuItem.Checked ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left; Menu.Alignment = _flipMenuItem.Checked ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left;
Main.Settings.FlipMenu = _flipMenuItem.Checked; Main.Settings.FlipMenu = _flipMenuItem.Checked;
Util.SaveSettings(); Util.SaveSettings();
} }
public void ShowNetworkInfoCheckboxChanged(object a, System.EventArgs b) public static void ShowNetworkInfoCheckboxChanged(object a, System.EventArgs b)
{ {
Networking.ShowNetworkInfo = _showNetworkInfoItem.Checked; Networking.ShowNetworkInfo = _showNetworkInfoItem.Checked;

View File

@ -1,903 +0,0 @@
using System;
using System.IO;
using System.Xml.Serialization;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using RageCoop.Core;
using GTA;
using GTA.Native;
using GTA.Math;
using System.Linq;
using System.Diagnostics;
namespace RageCoop.Client
{
/// <summary>
///
/// </summary>
internal static partial class Util
{
#region -- POINTER --
private static int _steeringAngleOffset { get; set; }
public static unsafe void NativeMemory()
{
IntPtr address;
address = Game.FindPattern("\x74\x0A\xF3\x0F\x11\xB3\x1C\x09\x00\x00\xEB\x25", "xxxxxx????xx");
if (address != IntPtr.Zero)
{
_steeringAngleOffset = *(int*)(address + 6) + 8;
}
// breaks some stuff.
/*
address = Game.FindPattern("\x32\xc0\xf3\x0f\x11\x09", "xxxxxx"); // Weapon / Radio slowdown
if (address != IntPtr.Zero)
{
for (int i = 0; i < 6; i++)
{
*(byte*)(address + i).ToPointer() = 0x90;
}
}
*/
}
public static unsafe void CustomSteeringAngle(this Vehicle veh, float value)
{
IntPtr address = new IntPtr((long)veh.MemoryAddress);
if (address == IntPtr.Zero || _steeringAngleOffset == 0)
{
return;
}
*(float*)(address + _steeringAngleOffset).ToPointer() = value;
}
#endregion
public static Settings ReadSettings()
{
XmlSerializer ser = new XmlSerializer(typeof(Settings));
string path = Directory.GetCurrentDirectory() + "\\Scripts\\RageCoop\\RageCoop.Client.Settings.xml";
Settings settings = null;
if (File.Exists(path))
{
using (FileStream stream = File.OpenRead(path))
{
settings = (RageCoop.Client.Settings)ser.Deserialize(stream);
}
using (FileStream stream = new FileStream(path, FileMode.Truncate, FileAccess.ReadWrite))
{
ser.Serialize(stream, settings);
}
}
else
{
using (FileStream stream = File.OpenWrite(path))
{
ser.Serialize(stream, settings = new Settings());
}
}
return settings;
}
public static void SaveSettings()
{
try
{
string path = Directory.GetCurrentDirectory() + "\\Scripts\\RageCoop\\RageCoop.Client.Settings.xml";
using (FileStream stream = new FileStream(path, File.Exists(path) ? FileMode.Truncate : FileMode.Create, FileAccess.ReadWrite))
{
XmlSerializer ser = new XmlSerializer(typeof(Settings));
ser.Serialize(stream, Main.Settings);
}
}
catch (Exception ex)
{
GTA.UI.Notification.Show("Error saving player settings: " + ex.Message);
}
}
public static bool IsBetween<T>(this T item, T start, T end)
{
return Comparer<T>.Default.Compare(item, start) >= 0 && Comparer<T>.Default.Compare(item, end) <= 0;
}
public static bool Compare<T, Y>(this Dictionary<T, Y> item, Dictionary<T, Y> item2)
{
if (item == null || item2 == null || item.Count != item2.Count)
{
return false;
}
foreach (KeyValuePair<T, Y> pair in item)
{
if (item2.TryGetValue(pair.Key, out Y value) && Equals(value, pair.Value))
{
continue;
}
// TryGetValue() or Equals failed
return false;
}
// No difference between item and item2
return true;
}
#region MATH
public static Vector3 LinearVectorLerp(Vector3 start, Vector3 end, ulong currentTime, int duration)
{
return new Vector3()
{
X = LinearFloatLerp(start.X, end.X, currentTime, duration),
Y = LinearFloatLerp(start.Y, end.Y, currentTime, duration),
Z = LinearFloatLerp(start.Z, end.Z, currentTime, duration),
};
}
public static float LinearFloatLerp(float start, float end, ulong currentTime, int duration)
{
return (end - start) * currentTime / duration + start;
}
public static float Lerp(float from, float to, float fAlpha)
{
return (from * (1.0f - fAlpha)) + (to * fAlpha); //from + (to - from) * fAlpha
}
public static Vector3 RotationToDirection(Vector3 rotation)
{
double z = DegToRad(rotation.Z);
double x = DegToRad(rotation.X);
double num = Math.Abs(Math.Cos(x));
return new Vector3
{
X = (float)(-Math.Sin(z) * num),
Y = (float)(Math.Cos(z) * num),
Z = (float)Math.Sin(x)
};
}
#endregion
public static Model ModelRequest(this int hash)
{
Model model = new Model(hash);
if (!model.IsValid)
{
//GTA.UI.Notification.Show("~y~Not valid!");
return null;
}
if (!model.IsLoaded)
{
return model.Request(1000) ? model : null;
}
return model;
}
#region PED
public static byte GetPedSpeed(this Ped ped)
{
if (ped.IsSprinting)
{
return 3;
}
if (ped.IsRunning)
{
return 2;
}
if (ped.IsWalking)
{
return 1;
}
return 0;
}
public static Dictionary<byte, short> GetPedClothes(this Ped ped)
{
Dictionary<byte, short> result = new Dictionary<byte, short>();
for (byte i = 0; i < 11; i++)
{
short mod = Function.Call<short>(Hash.GET_PED_DRAWABLE_VARIATION, ped.Handle, i);
result.Add(i, mod);
}
return result;
}
public static PedDataFlags GetPedFlags(this Ped ped)
{
PedDataFlags flags = PedDataFlags.None;
if (ped.IsAiming || ped.IsOnTurretSeat())
{
flags |= PedDataFlags.IsAiming;
}
if (ped.IsReloading)
{
flags |= PedDataFlags.IsReloading;
}
if (ped.IsJumping)
{
flags |= PedDataFlags.IsJumping;
}
if (ped.IsRagdoll)
{
flags |= PedDataFlags.IsRagdoll;
}
if (ped.IsOnFire)
{
flags |= PedDataFlags.IsOnFire;
}
if (ped.IsInParachuteFreeFall)
{
flags |= PedDataFlags.IsInParachuteFreeFall;
}
if (ped.ParachuteState == ParachuteState.Gliding)
{
flags |= PedDataFlags.IsParachuteOpen;
}
bool climbingLadder = ped.IsTaskActive(TaskType.CTaskGoToAndClimbLadder);
if (climbingLadder)
{
flags |= PedDataFlags.IsOnLadder;
}
if (ped.IsVaulting && !climbingLadder)
{
flags |= PedDataFlags.IsVaulting;
}
if (ped.IsInCover || ped.IsGoingIntoCover)
{
flags |=PedDataFlags.IsInCover;
}
return flags;
}
public static string[] GetReloadingAnimation(this Ped ped)
{
switch (ped.Weapons.Current.Hash)
{
case WeaponHash.Revolver:
case WeaponHash.RevolverMk2:
case WeaponHash.DoubleActionRevolver:
case WeaponHash.NavyRevolver:
return new string[2] { "anim@weapons@pistol@revolver_str", "reload_aim" };
case WeaponHash.APPistol:
return new string[2] { "weapons@pistol@ap_pistol_str", "reload_aim" };
case WeaponHash.Pistol50:
return new string[2] { "weapons@pistol@pistol_50_str", "reload_aim" };
case WeaponHash.Pistol:
case WeaponHash.PistolMk2:
case WeaponHash.PericoPistol:
case WeaponHash.SNSPistol:
case WeaponHash.SNSPistolMk2:
case WeaponHash.HeavyPistol:
case WeaponHash.VintagePistol:
case WeaponHash.CeramicPistol:
case WeaponHash.MachinePistol:
return new string[2] { "weapons@pistol@pistol_str", "reload_aim" };
case WeaponHash.AssaultRifle:
case WeaponHash.AssaultrifleMk2:
return new string[2] { "weapons@rifle@hi@assault_rifle_str", "reload_aim" };
case WeaponHash.SniperRifle:
return new string[2] { "weapons@rifle@hi@sniper_rifle_str", "reload_aim" };
case WeaponHash.HeavySniper:
case WeaponHash.HeavySniperMk2:
return new string[2] { "weapons@rifle@lo@sniper_heavy_str", "reload_aim" };
case WeaponHash.PumpShotgun:
case WeaponHash.PumpShotgunMk2:
return new string[2] { "weapons@rifle@pump_str", "reload_aim" };
case WeaponHash.Railgun:
return new string[2] { "weapons@rifle@lo@rail_gun_str", "reload_aim" };
case WeaponHash.SawnOffShotgun:
return new string[2] { "weapons@rifle@lo@sawnoff_str", "reload_aim" };
case WeaponHash.AssaultShotgun:
return new string[2] { "weapons@rifle@lo@shotgun_assault_str", "reload_aim" };
case WeaponHash.BullpupShotgun:
return new string[2] { "weapons@rifle@lo@shotgun_bullpup_str", "reload_aim" };
case WeaponHash.AdvancedRifle:
return new string[2] { "weapons@submg@advanced_rifle_str", "reload_aim" };
case WeaponHash.CarbineRifle:
case WeaponHash.CarbineRifleMk2:
case WeaponHash.CompactRifle:
return new string[2] { "weapons@rifle@lo@carbine_str", "reload_aim" };
case WeaponHash.Gusenberg:
return new string[2] { "anim@weapons@machinegun@gusenberg_str", "reload_aim" };
case WeaponHash.Musket:
return new string[2] { "anim@weapons@musket@musket_str", "reload_aim" };
case WeaponHash.FlareGun:
return new string[2] { "anim@weapons@pistol@flare_str", "reload_aim" };
case WeaponHash.SpecialCarbine:
case WeaponHash.SpecialCarbineMk2:
return new string[2] { "anim@weapons@rifle@lo@spcarbine_str", "reload_aim" };
case WeaponHash.CombatPDW:
return new string[2] { "anim@weapons@rifle@lo@pdw_str", "reload_aim" };
case WeaponHash.BullpupRifle:
case WeaponHash.BullpupRifleMk2:
return new string[2] { "anim@weapons@submg@bullpup_rifle_str", "reload_aim" };
case WeaponHash.AssaultSMG:
return new string[2] { "weapons@submg@assault_smg_str", "reload_aim" };
case WeaponHash.MicroSMG:
case WeaponHash.MiniSMG:
return new string[2] { "weapons@submg@lo@micro_smg_str", "reload_aim" };
case WeaponHash.SMG:
case WeaponHash.SMGMk2:
return new string[2] { "weapons@rifle@smg_str", "reload_aim" };
case WeaponHash.GrenadeLauncher:
case WeaponHash.GrenadeLauncherSmoke:
case WeaponHash.CompactGrenadeLauncher:
return new string[2] { "weapons@heavy@grenade_launcher_str", "reload_aim" };
case WeaponHash.RPG:
case WeaponHash.Firework:
return new string[2] { "weapons@heavy@rpg_str", "reload_aim" };
case WeaponHash.CombatMG:
case WeaponHash.CombatMGMk2:
return new string[2] { "weapons@machinegun@combat_mg_str", "reload_aim" };
case WeaponHash.MG:
return new string[2] { "weapons@machinegun@mg_str", "reload_aim" };
default:
Main.Logger.Warning($"~r~Reloading failed! Weapon ~g~[{ped.Weapons.Current.Hash}]~r~ could not be found!");
return null;
}
}
public static VehicleSeat GetNearestSeat(Ped ped, Vehicle veh, float distanceToignoreDoors = 50f)
{
float num = 99f;
int result = -2;
Dictionary<string, int> dictionary = new Dictionary<string, int>();
dictionary.Add("door_dside_f", -1);
dictionary.Add("door_pside_f", 0);
dictionary.Add("door_dside_r", 1);
dictionary.Add("door_pside_r", 2);
foreach (string text in dictionary.Keys)
{
bool flag = veh.Bones[text].Position != Vector3.Zero;
if (flag)
{
float num2 = ped.Position.DistanceTo(Function.Call<Vector3>(Hash.GET_WORLD_POSITION_OF_ENTITY_BONE, new InputArgument[]
{
veh,
veh.Bones[text].Index
}));
bool flag2 = (num2 < distanceToignoreDoors) && (num2 < num)&& IsSeatUsableByPed(ped, veh, dictionary[text]);
if (flag2)
{
num = num2;
result = dictionary[text];
}
}
}
return (VehicleSeat)result;
}
public static bool IsSeatUsableByPed(Ped ped, Vehicle veh, int _seat)
{
VehicleSeat seat = (VehicleSeat)_seat;
bool result = false;
bool flag = veh.IsSeatFree(seat);
if (flag)
{
result = true;
}
else
{
bool isDead = veh.GetPedOnSeat(seat).IsDead;
if (isDead)
{
result = true;
}
else
{
int num = Function.Call<int>(Hash.GET_RELATIONSHIP_BETWEEN_PEDS, new InputArgument[]
{
ped,
veh.GetPedOnSeat(seat)
});
bool flag2 = num > 2;
if (flag2)
{
result = true;
}
}
}
return result;
}
public static bool IsTaskActive(this Ped p,TaskType task)
{
return Function.Call<bool>(Hash.GET_IS_TASK_ACTIVE, p.Handle, task);
}
public static Vector3 GetAimCoord(this Ped p)
{
var weapon = p.Weapons.CurrentWeaponObject;
var v = p.CurrentVehicle;
// Rhino
if (v!=null && v.Model.Hash==782665360)
{
return v.Bones[35].Position+v.Bones[35].ForwardVector*100;
}
if (p.IsOnTurretSeat()) { return p.GetLookingCoord(); }
if (weapon!=null)
{
// Not very accurate, but doesn't matter
Vector3 dir = weapon.RightVector;
return weapon.Position+dir*20;
}
return GetLookingCoord(p);
}
public static Vector3 GetLookingCoord(this Ped p)
{
EntityBone b = p.Bones[Bone.FacialForehead];
Vector3 v = b.UpVector.Normalized;
return b.Position+200*v;
}
public static void StayInCover(this Ped p)
{
Function.Call(Hash.TASK_STAY_IN_COVER, p);
}
public static VehicleSeat GetSeatTryingToEnter(this Ped p)
{
return (VehicleSeat)Function.Call<int>(Hash.GET_SEAT_PED_IS_TRYING_TO_ENTER, p);
}
#endregion
#region VEHICLE
public static VehicleDataFlags GetVehicleFlags(this Vehicle veh)
{
VehicleDataFlags flags = 0;
if (veh.IsEngineRunning)
{
flags |= VehicleDataFlags.IsEngineRunning;
}
if (veh.AreLightsOn)
{
flags |= VehicleDataFlags.AreLightsOn;
}
if (veh.BrakePower >= 0.01f)
{
flags |= VehicleDataFlags.AreBrakeLightsOn;
}
if (veh.AreHighBeamsOn)
{
flags |= VehicleDataFlags.AreHighBeamsOn;
}
if (veh.IsSirenActive)
{
flags |= VehicleDataFlags.IsSirenActive;
}
if (veh.IsDead)
{
flags |= VehicleDataFlags.IsDead;
}
if (Function.Call<bool>(Hash.IS_HORN_ACTIVE, veh.Handle))
{
flags |= VehicleDataFlags.IsHornActive;
}
if (veh.IsSubmarineCar && Function.Call<bool>(Hash._GET_IS_SUBMARINE_VEHICLE_TRANSFORMED, veh.Handle))
{
flags |= VehicleDataFlags.IsTransformed;
}
if (veh.HasRoof && (veh.RoofState == VehicleRoofState.Opened || veh.RoofState == VehicleRoofState.Opening))
{
flags |= VehicleDataFlags.RoofOpened;
}
if (veh.IsAircraft)
{
flags |= VehicleDataFlags.IsAircraft;
}
return flags;
}
public static bool HasFlag(this PedDataFlags flagToCheck,PedDataFlags flag)
{
return (flagToCheck & flag)!=0;
}
public static bool HasFlag(this VehicleDataFlags flagToCheck, VehicleDataFlags flag)
{
return (flagToCheck & flag)!=0;
}
public static Dictionary<uint, bool> GetWeaponComponents(this Weapon weapon)
{
Dictionary<uint, bool> result = null;
if (weapon.Components.Count > 0)
{
result = new Dictionary<uint, bool>();
foreach (var comp in weapon.Components)
{
result.Add((uint)comp.ComponentHash, comp.Active);
}
}
return result;
}
public static Dictionary<int, int> GetVehicleMods(this VehicleModCollection mods)
{
Dictionary<int, int> result = new Dictionary<int, int>();
foreach (VehicleMod mod in mods.ToArray())
{
result.Add((int)mod.Type, mod.Index);
}
return result;
}
public static VehicleDamageModel GetVehicleDamageModel(this Vehicle veh)
{
// Broken windows
byte brokenWindows = 0;
for (int i = 0; i < 8; i++)
{
if (!veh.Windows[(VehicleWindowIndex)i].IsIntact)
{
brokenWindows |= (byte)(1 << i);
}
}
// Broken doors
byte brokenDoors = 0;
byte openedDoors = 0;
foreach (VehicleDoor door in veh.Doors)
{
if (door.IsBroken)
{
brokenDoors |= (byte)(1 << (byte)door.Index);
}
else if (door.IsOpen)
{
openedDoors |= (byte)(1 << (byte)door.Index);
}
}
// Bursted tires
short burstedTires = 0;
foreach (VehicleWheel wheel in veh.Wheels.GetAllWheels())
{
if (wheel.IsBursted)
{
burstedTires |= (short)(1 << (int)wheel.BoneId);
}
}
return new VehicleDamageModel()
{
BrokenDoors = brokenDoors,
OpenedDoors = openedDoors,
BrokenWindows = brokenWindows,
BurstedTires = burstedTires,
LeftHeadLightBroken = (byte)(veh.IsLeftHeadLightBroken ? 1 : 0),
RightHeadLightBroken = (byte)(veh.IsRightHeadLightBroken ? 1 : 0)
};
}
public static Dictionary<int,int> GetPassengers(this Vehicle veh)
{
Dictionary<int,int> ps=new Dictionary<int, int>();
var d = veh.Driver;
if (d!=null&&d.IsSittingInVehicle())
{
ps.Add(-1, d.GetSyncEntity().ID);
}
foreach(Ped p in veh.Passengers)
{
if (p.IsSittingInVehicle())
{
ps.Add((int)p.SeatIndex, (int)p.GetSyncEntity().ID);
}
}
return ps;
}
public static void SetDamageModel(this Vehicle veh, VehicleDamageModel model, bool leavedoors = true)
{
for (int i = 0; i < 8; i++)
{
var door = veh.Doors[(VehicleDoorIndex)i];
if ((model.BrokenDoors & (byte)(1 << i)) != 0)
{
door.Break(leavedoors);
}
else if (door.IsBroken)
{
// The vehicle can only fix a door if the vehicle was completely fixed
veh.Repair();
return;
}
if ((model.OpenedDoors & (byte)(1 << i)) != 0)
{
if ((!door.IsOpen)&&(!door.IsBroken))
{
door.Open();
}
}
else if (door.IsOpen)
{
if (!door.IsBroken) { door.Close(); }
}
if ((model.BrokenWindows & (byte)(1 << i)) != 0)
{
veh.Windows[(VehicleWindowIndex)i].Smash();
}
else if (!veh.Windows[(VehicleWindowIndex)i].IsIntact)
{
veh.Windows[(VehicleWindowIndex)i].Repair();
}
}
foreach (VehicleWheel wheel in veh.Wheels)
{
if ((model.BurstedTires & (short)(1 << (int)wheel.BoneId)) != 0)
{
if (!wheel.IsBursted)
{
wheel.Puncture();
wheel.Burst();
}
}
else if (wheel.IsBursted)
{
wheel.Fix();
}
}
veh.IsLeftHeadLightBroken = model.LeftHeadLightBroken > 0;
veh.IsRightHeadLightBroken = model.RightHeadLightBroken > 0;
}
#endregion
public static void SetOnFire(this Entity e,bool toggle)
{
if (toggle)
{
Function.Call(Hash.START_ENTITY_FIRE, e.Handle);
}
else
{
Function.Call(Hash.STOP_ENTITY_FIRE, e.Handle);
}
}
public static SyncedPed GetSyncEntity(this Ped p)
{
if(p == null) { return null; }
var c = EntityPool.GetPedByHandle(p.Handle);
if(c==null) { EntityPool.Add(c=new SyncedPed(p)); }
return c;
}
public static SyncedVehicle GetSyncEntity(this Vehicle veh)
{
if(veh == null) { return null; }
var v=EntityPool.GetVehicleByHandle(veh.Handle);
if (v==null) { EntityPool.Add(v=new SyncedVehicle(veh)); }
return v;
}
public static double DegToRad(double deg)
{
return deg * Math.PI / 180.0;
}
public static bool IsTurretSeat(this Vehicle veh, int seat)
{
if (!Function.Call<bool>(Hash.DOES_VEHICLE_HAVE_WEAPONS, veh.Handle))
{
return false;
}
switch (seat)
{
case -1:
return (VehicleHash)veh.Model.Hash == VehicleHash.Rhino
|| (VehicleHash)veh.Model.Hash == VehicleHash.Khanjari
|| (VehicleHash)veh.Model.Hash == VehicleHash.FireTruck
|| (VehicleHash)veh.Model.Hash == VehicleHash.Riot2
|| (VehicleHash)veh.Model.Hash == VehicleHash.Cerberus
|| (VehicleHash)veh.Model.Hash == VehicleHash.Cerberus2
|| (VehicleHash)veh.Model.Hash == VehicleHash.Cerberus3;
case 0:
return (VehicleHash)veh.Model.Hash == VehicleHash.Apc;
case 1:
return (VehicleHash)veh.Model.Hash == VehicleHash.Valkyrie
|| (VehicleHash)veh.Model.Hash == VehicleHash.Valkyrie2
|| (VehicleHash)veh.Model.Hash == VehicleHash.Technical
|| (VehicleHash)veh.Model.Hash == VehicleHash.Technical2
|| (VehicleHash)veh.Model.Hash == VehicleHash.Technical3
|| (VehicleHash)veh.Model.Hash == VehicleHash.HalfTrack
|| (VehicleHash)veh.Model.Hash == VehicleHash.Barrage;
case 2:
return (VehicleHash)veh.Model.Hash == VehicleHash.Valkyrie
|| (VehicleHash)veh.Model.Hash == VehicleHash.Valkyrie2
|| (VehicleHash)veh.Model.Hash == VehicleHash.Barrage;
case 3:
return (VehicleHash)veh.Model.Hash == VehicleHash.Limo2
|| (VehicleHash)veh.Model.Hash == VehicleHash.Dinghy5;
case 7:
return (VehicleHash)veh.Model.Hash == VehicleHash.Insurgent;
}
return false;
}
public static bool IsOnTurretSeat(this Ped P)
{
if (P.CurrentVehicle == null) { return false; }
return IsTurretSeat(P.CurrentVehicle, (int)P.SeatIndex);
}
[DllImport("kernel32.dll")]
public static extern ulong GetTickCount64();
}
/// <summary>
///
/// </summary>
public static class VectorExtensions
{
/// <summary>
///
/// </summary>
public static Vector3 ToVector(this Quaternion vec)
{
return new Vector3()
{
X = vec.X,
Y = vec.Y,
Z = vec.Z
};
}
/// <summary>
///
/// </summary>
public static Quaternion ToQuaternion(this Vector3 vec, float vW = 0.0f)
{
return new Quaternion()
{
X = vec.X,
Y = vec.Y,
Z = vec.Z,
W = vW
};
}
public static float Denormalize(this float h)
{
return h < 0f ? h + 360f : h;
}
public static float ToRadians(this float val)
{
return (float)(Math.PI / 180) * val;
}
public static Vector3 ToRadians(this Vector3 i)
{
return new Vector3()
{
X = ToRadians(i.X),
Y = ToRadians(i.Y),
Z = ToRadians(i.Z),
};
}
public static Quaternion ToQuaternion(this Vector3 vect)
{
vect = new Vector3()
{
X = vect.X.Denormalize() * -1,
Y = vect.Y.Denormalize() - 180f,
Z = vect.Z.Denormalize() - 180f,
};
vect = vect.ToRadians();
float rollOver2 = vect.Z * 0.5f;
float sinRollOver2 = (float)Math.Sin((double)rollOver2);
float cosRollOver2 = (float)Math.Cos((double)rollOver2);
float pitchOver2 = vect.Y * 0.5f;
float sinPitchOver2 = (float)Math.Sin((double)pitchOver2);
float cosPitchOver2 = (float)Math.Cos((double)pitchOver2);
float yawOver2 = vect.X * 0.5f; // pitch
float sinYawOver2 = (float)Math.Sin((double)yawOver2);
float cosYawOver2 = (float)Math.Cos((double)yawOver2);
Quaternion result = new Quaternion()
{
X = cosYawOver2 * cosPitchOver2 * cosRollOver2 + sinYawOver2 * sinPitchOver2 * sinRollOver2,
Y = cosYawOver2 * cosPitchOver2 * sinRollOver2 - sinYawOver2 * sinPitchOver2 * cosRollOver2,
Z = cosYawOver2 * sinPitchOver2 * cosRollOver2 + sinYawOver2 * cosPitchOver2 * sinRollOver2,
W = sinYawOver2 * cosPitchOver2 * cosRollOver2 - cosYawOver2 * sinPitchOver2 * sinRollOver2
};
return result;
}
/// <summary>
///
/// </summary>
public static LVector3 ToLVector(this Vector3 vec)
{
return new LVector3()
{
X = vec.X,
Y = vec.Y,
Z = vec.Z
};
}
/// <summary>
///
/// </summary>
public static LQuaternion ToLQuaternion(this Quaternion vec)
{
return new LQuaternion()
{
X = vec.X,
Y = vec.Y,
Z = vec.Z,
W = vec.W
};
}
}
}

View File

@ -8,7 +8,7 @@ using GTA.Native;
namespace RageCoop.Client namespace RageCoop.Client
{ {
public class Chat internal class Chat
{ {
private readonly Scaleform MainScaleForm; private readonly Scaleform MainScaleForm;

View File

@ -4,7 +4,7 @@ using System.Collections.Generic;
namespace RageCoop.Client namespace RageCoop.Client
{ {
public static class DownloadManager internal static class DownloadManager
{ {
private static readonly List<DownloadFile> _downloadFiles = new List<DownloadFile>(); private static readonly List<DownloadFile> _downloadFiles = new List<DownloadFile>();
private static readonly Dictionary<byte, FileStream> _streams = new Dictionary<byte, FileStream>(); private static readonly Dictionary<byte, FileStream> _streams = new Dictionary<byte, FileStream>();

View File

@ -6,7 +6,7 @@ using Lidgren.Network;
using RageCoop.Core; using RageCoop.Core;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Threading; using System.Threading;
using GTA; using GTA.Math;
using GTA.Native; using GTA.Native;
namespace RageCoop.Client namespace RageCoop.Client
@ -20,7 +20,7 @@ namespace RageCoop.Client
public static int BytesSend = 0; public static int BytesSend = 0;
private static Thread ReceiveThread; private static Thread ReceiveThread;
public static void DisConnectFromServer(string address) public static void ToggleConnection(string address)
{ {
if (IsOnServer) if (IsOnServer)
{ {
@ -31,7 +31,7 @@ namespace RageCoop.Client
// 623c92c287cc392406e7aaaac1c0f3b0 = RAGECOOP // 623c92c287cc392406e7aaaac1c0f3b0 = RAGECOOP
NetPeerConfiguration config = new NetPeerConfiguration("623c92c287cc392406e7aaaac1c0f3b0") NetPeerConfiguration config = new NetPeerConfiguration("623c92c287cc392406e7aaaac1c0f3b0")
{ {
AutoFlushSendQueue = true AutoFlushSendQueue = false
}; };
config.EnableMessageType(NetIncomingMessageType.ConnectionLatencyUpdated); config.EnableMessageType(NetIncomingMessageType.ConnectionLatencyUpdated);
@ -62,7 +62,6 @@ namespace RageCoop.Client
PedID = Main.LocalPlayerID, PedID = Main.LocalPlayerID,
Username = Main.Settings.Username, Username = Main.Settings.Username,
ModVersion = Main.CurrentVersion, ModVersion = Main.CurrentVersion,
NPCsAllowed = false
}.Pack(outgoingMessage); }.Pack(outgoingMessage);
Client.Connect(ip[0], short.Parse(ip[1]), outgoingMessage); Client.Connect(ip[0], short.Parse(ip[1]), outgoingMessage);
@ -80,7 +79,11 @@ namespace RageCoop.Client
{ {
try try
{ {
ReceiveMessages(); if (Client!=null)
{
Client.FlushSendQueue();
ReceiveMessages();
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -144,8 +147,8 @@ namespace RageCoop.Client
case string _: case string _:
arguments.Add((string)x); arguments.Add((string)x);
break; break;
case LVector3 _: case Vector3 _:
LVector3 vector = (LVector3)x; Vector3 vector = (Vector3)x;
arguments.Add((float)vector.X); arguments.Add((float)vector.X);
arguments.Add((float)vector.Y); arguments.Add((float)vector.Y);
arguments.Add((float)vector.Z); arguments.Add((float)vector.Z);
@ -173,7 +176,7 @@ namespace RageCoop.Client
case 0x03: // string case 0x03: // string
return Function.Call<string>((Hash)hash, arguments.ToArray()); return Function.Call<string>((Hash)hash, arguments.ToArray());
case 0x04: // vector3 case 0x04: // vector3
return Function.Call<GTA.Math.Vector3>((Hash)hash, arguments.ToArray()).ToLVector(); return Function.Call<Vector3>((Hash)hash, arguments.ToArray());
default: default:
GTA.UI.Notification.Show("[DecodeNativeCall][" + hash + "]: Type of return not found!"); GTA.UI.Notification.Show("[DecodeNativeCall][" + hash + "]: Type of return not found!");
return null; return null;

View File

@ -5,6 +5,7 @@ using System.Diagnostics;
using Lidgren.Network; using Lidgren.Network;
using RageCoop.Core; using RageCoop.Core;
using GTA; using GTA;
using RageCoop.Client.Menus;
using GTA.Math; using GTA.Math;
using GTA.Native; using GTA.Native;
@ -36,7 +37,7 @@ namespace RageCoop.Client
{ {
case NetConnectionStatus.InitiatedConnect: case NetConnectionStatus.InitiatedConnect:
#if !NON_INTERACTIVE #if !NON_INTERACTIVE
Main.MainMenu.InitiateConnectionMenuSetting(); CoopMenu.InitiateConnectionMenuSetting();
#endif #endif
Main.QueueAction(() => { GTA.UI.Notification.Show("~y~Trying to connect..."); return true; }); Main.QueueAction(() => { GTA.UI.Notification.Show("~y~Trying to connect..."); return true; });
break; break;
@ -53,17 +54,13 @@ namespace RageCoop.Client
Packets.Handshake handshakePacket = new Packets.Handshake(); Packets.Handshake handshakePacket = new Packets.Handshake();
handshakePacket.Unpack(data); handshakePacket.Unpack(data);
// Main.LocalNetHandle = handshakePacket.NetHandle;
Main.NPCsAllowed = handshakePacket.NPCsAllowed;
#if !NON_INTERACTIVE #if !NON_INTERACTIVE
#endif #endif
COOPAPI.Connected(); COOPAPI.Connected();
Main.QueueAction(() => { Main.QueueAction(() => {
Main.MainMenu.ConnectedMenuSetting(); CoopMenu.ConnectedMenuSetting();
Main.MainChat.Init(); Main.MainChat.Init();
PlayerList.Cleanup(); PlayerList.Cleanup();
GTA.UI.Notification.Show("~g~Connected!"); GTA.UI.Notification.Show("~g~Connected!");
@ -78,9 +75,7 @@ namespace RageCoop.Client
// Reset all values // Reset all values
Latency = 0; Latency = 0;
Main.QueueAction(() => { Main.CleanUpWorld();}); Main.QueueAction(() => Main.CleanUpWorld());
Main.NPCsAllowed = false;
if (Main.MainChat.Focused) if (Main.MainChat.Focused)
{ {
@ -90,7 +85,7 @@ namespace RageCoop.Client
Main.QueueAction(() => Main.CleanUp()); Main.QueueAction(() => Main.CleanUp());
#if !NON_INTERACTIVE #if !NON_INTERACTIVE
Main.MainMenu.DisconnectedMenuSetting(); CoopMenu.DisconnectedMenuSetting();
#endif #endif
COOPAPI.Disconnected(reason); COOPAPI.Disconnected(reason);
@ -227,8 +222,7 @@ namespace RageCoop.Client
{ {
Packets.Mod packet = new Packets.Mod(); Packets.Mod packet = new Packets.Mod();
packet.Unpack(data); packet.Unpack(data);
COOPAPI.ModPacketReceived(packet.NetHandle, packet.Name, packet.CustomPacketID, packet.Bytes); // Need to do some stuff here
} }
break; break;
case PacketTypes.FileTransferTick: case PacketTypes.FileTransferTick:
@ -307,20 +301,19 @@ namespace RageCoop.Client
private static void PedSync(Packets.PedSync packet) private static void PedSync(Packets.PedSync packet)
{ {
if (!EntityPool.PedExists(packet.ID)) SyncedPed c = EntityPool.GetPedByID(packet.ID);
if (c==null)
{ {
Main.Logger.Debug($"Creating character for incoming sync:{packet.ID}"); Main.Logger.Debug($"Creating character for incoming sync:{packet.ID}");
EntityPool.ThreadSafe.Add(c=new SyncedPed(packet.ID));
EntityPool.ThreadSafe.Add(new SyncedPed(packet.ID));
} }
PedDataFlags flags = packet.Flag; PedDataFlags flags = packet.Flag;
SyncedPed c = EntityPool.GetPedByID(packet.ID);
c.ID=packet.ID; c.ID=packet.ID;
//c.OwnerID=packet.OwnerID; //c.OwnerID=packet.OwnerID;
c.Health = packet.Health; c.Health = packet.Health;
c.Position = packet.Position.ToVector(); c.Position = packet.Position;
c.Rotation = packet.Rotation.ToVector(); c.Rotation = packet.Rotation;
c.Velocity = packet.Velocity.ToVector(); c.Velocity = packet.Velocity;
c.Speed = packet.Speed; c.Speed = packet.Speed;
c.CurrentWeaponHash = packet.CurrentWeaponHash; c.CurrentWeaponHash = packet.CurrentWeaponHash;
c.IsAiming = flags.HasFlag(PedDataFlags.IsAiming); c.IsAiming = flags.HasFlag(PedDataFlags.IsAiming);
@ -337,53 +330,47 @@ namespace RageCoop.Client
c.LastSynced = Main.Ticked; c.LastSynced = Main.Ticked;
if (c.IsAiming) if (c.IsAiming)
{ {
c.AimCoords = packet.AimCoords.ToVector(); c.AimCoords = packet.AimCoords;
} }
if (c.IsRagdoll) if (c.IsRagdoll)
{ {
c.RotationVelocity=packet.RotationVelocity.ToVector(); c.RotationVelocity=packet.RotationVelocity;
} }
} }
private static void PedStateSync(Packets.PedStateSync packet) private static void PedStateSync(Packets.PedStateSync packet)
{ {
if (!EntityPool.PedExists(packet.ID))
{
Main.Logger.Debug($"Creating character for incoming sync:{packet.ID}");
EntityPool.ThreadSafe.Add(new SyncedPed(packet.ID));
}
SyncedPed c = EntityPool.GetPedByID(packet.ID); SyncedPed c = EntityPool.GetPedByID(packet.ID);
if (c==null) { return; }
c.ID=packet.ID; c.ID=packet.ID;
c.OwnerID=packet.OwnerID; c.OwnerID=packet.OwnerID;
c.Clothes=packet.Clothes; c.Clothes=packet.Clothes;
c.WeaponComponents=packet.WeaponComponents; c.WeaponComponents=packet.WeaponComponents;
c.ModelHash=packet.ModelHash; c.ModelHash=packet.ModelHash;
c.LastSynced=c.LastStateSynced = Main.Ticked; c.LastStateSynced = Main.Ticked;
} }
private static void VehicleSync(Packets.VehicleSync packet) private static void VehicleSync(Packets.VehicleSync packet)
{ {
if (!EntityPool.VehicleExists(packet.ID))
{
EntityPool.ThreadSafe.Add(new SyncedVehicle(packet.ID));
}
SyncedVehicle v = EntityPool.GetVehicleByID(packet.ID); SyncedVehicle v = EntityPool.GetVehicleByID(packet.ID);
if (v==null)
{
EntityPool.ThreadSafe.Add(v=new SyncedVehicle(packet.ID));
}
if (v.IsMine) { return; }
v.ID= packet.ID; v.ID= packet.ID;
v.Position=packet.Position.ToVector(); v.Position=packet.Position;
v.Rotation=packet.Rotation.ToVector(); v.Quaternion=packet.Quaternion;
v.SteeringAngle=packet.SteeringAngle; v.SteeringAngle=packet.SteeringAngle;
v.ThrottlePower=packet.ThrottlePower; v.ThrottlePower=packet.ThrottlePower;
v.BrakePower=packet.BrakePower; v.BrakePower=packet.BrakePower;
v.Velocity=packet.Velocity.ToVector(); v.Velocity=packet.Velocity;
v.RotationVelocity=packet.RotationVelocity.ToVector(); v.RotationVelocity=packet.RotationVelocity;
v.DeluxoWingRatio=packet.DeluxoWingRatio;
v.LastSynced=Main.Ticked; v.LastSynced=Main.Ticked;
} }
private static void VehicleStateSync(Packets.VehicleStateSync packet) private static void VehicleStateSync(Packets.VehicleStateSync packet)
{ {
if (!EntityPool.VehicleExists(packet.ID))
{
EntityPool.ThreadSafe.Add(new SyncedVehicle(packet.ID));
}
SyncedVehicle v = EntityPool.GetVehicleByID(packet.ID); SyncedVehicle v = EntityPool.GetVehicleByID(packet.ID);
if (v==null||v.IsMine) { return; }
v.ID= packet.ID; v.ID= packet.ID;
v.OwnerID= packet.OwnerID; v.OwnerID= packet.OwnerID;
v.DamageModel=packet.DamageModel; v.DamageModel=packet.DamageModel;
@ -403,6 +390,8 @@ namespace RageCoop.Client
v.Transformed = packet.Flag.HasFlag(VehicleDataFlags.IsTransformed); v.Transformed = packet.Flag.HasFlag(VehicleDataFlags.IsTransformed);
v.Passengers=new Dictionary<VehicleSeat, SyncedPed>(); v.Passengers=new Dictionary<VehicleSeat, SyncedPed>();
v.LockStatus=packet.LockStatus; v.LockStatus=packet.LockStatus;
v.RadioStation=packet.RadioStation;
v.Flags=packet.Flag;
foreach (KeyValuePair<int, int> pair in packet.Passengers) foreach (KeyValuePair<int, int> pair in packet.Passengers)
{ {
if (EntityPool.PedExists(pair.Value)) if (EntityPool.PedExists(pair.Value))
@ -410,7 +399,7 @@ namespace RageCoop.Client
v.Passengers.Add((VehicleSeat)pair.Key, EntityPool.GetPedByID(pair.Value)); v.Passengers.Add((VehicleSeat)pair.Key, EntityPool.GetPedByID(pair.Value));
} }
} }
v.LastStateSynced=v.LastSynced= Main.Ticked; v.LastStateSynced= Main.Ticked;
} }
private static void ProjectileSync(Packets.ProjectileSync packet) private static void ProjectileSync(Packets.ProjectileSync packet)
@ -422,9 +411,9 @@ namespace RageCoop.Client
Main.Logger.Debug($"Creating new projectile: {(WeaponHash)packet.WeaponHash}"); Main.Logger.Debug($"Creating new projectile: {(WeaponHash)packet.WeaponHash}");
EntityPool.ThreadSafe.Add(p=new SyncedProjectile(packet.ID)); EntityPool.ThreadSafe.Add(p=new SyncedProjectile(packet.ID));
} }
p.Position=packet.Position.ToVector(); p.Position=packet.Position;
p.Rotation=packet.Rotation.ToVector(); p.Rotation=packet.Rotation;
p.Velocity=packet.Velocity.ToVector(); p.Velocity=packet.Velocity;
p.Hash=(WeaponHash)packet.WeaponHash; p.Hash=(WeaponHash)packet.WeaponHash;
p.ShooterID=packet.ShooterID; p.ShooterID=packet.ShooterID;
p.Exploded=packet.Exploded; p.Exploded=packet.Exploded;

View File

@ -36,9 +36,9 @@ namespace RageCoop.Client
{ {
ID =c.ID, ID =c.ID,
Health = p.Health, Health = p.Health,
Position = p.Position.ToLVector(), Position = p.Position,
Rotation = p.Rotation.ToLVector(), Rotation = p.Rotation,
Velocity = p.Velocity.ToLVector(), Velocity = p.Velocity,
Speed = p.GetPedSpeed(), Speed = p.GetPedSpeed(),
CurrentWeaponHash = (uint)p.Weapons.Current.Hash, CurrentWeaponHash = (uint)p.Weapons.Current.Hash,
Flag = p.GetPedFlags(), Flag = p.GetPedFlags(),
@ -46,11 +46,11 @@ namespace RageCoop.Client
}; };
if (packet.Flag.HasFlag(PedDataFlags.IsAiming)) if (packet.Flag.HasFlag(PedDataFlags.IsAiming))
{ {
packet.AimCoords = p.GetAimCoord().ToLVector(); packet.AimCoords = p.GetAimCoord();
} }
if (packet.Flag.HasFlag(PedDataFlags.IsRagdoll)) if (packet.Flag.HasFlag(PedDataFlags.IsRagdoll))
{ {
packet.RotationVelocity=p.RotationVelocity.ToLVector(); packet.RotationVelocity=p.RotationVelocity;
} }
Send(packet, ConnectionChannel.PedSync); Send(packet, ConnectionChannel.PedSync);
} }
@ -76,13 +76,15 @@ namespace RageCoop.Client
{ {
ID =v.ID, ID =v.ID,
SteeringAngle = veh.SteeringAngle, SteeringAngle = veh.SteeringAngle,
Position = veh.Position.ToLVector(), Position = veh.PredictPosition(),
Rotation = veh.Rotation.ToLVector(), Quaternion=veh.Quaternion,
Velocity = veh.Velocity.ToLVector(), // Rotation = veh.Rotation,
RotationVelocity=veh.RotationVelocity.ToLVector(), Velocity = veh.Velocity,
RotationVelocity=veh.RotationVelocity,
ThrottlePower = veh.ThrottlePower, ThrottlePower = veh.ThrottlePower,
BrakePower = veh.BrakePower, BrakePower = veh.BrakePower,
}; };
if (v.MainVehicle.Model.Hash==1483171323) { packet.DeluxoWingRatio=v.MainVehicle.GetDeluxoWingRatio(); }
Send(packet,ConnectionChannel.VehicleSync); Send(packet,ConnectionChannel.VehicleSync);
} }
public static void SendVehicleState(SyncedVehicle v) public static void SendVehicleState(SyncedVehicle v)
@ -108,6 +110,10 @@ namespace RageCoop.Client
Passengers=veh.GetPassengers(), Passengers=veh.GetPassengers(),
LockStatus=veh.LockStatus, LockStatus=veh.LockStatus,
}; };
if (v.MainVehicle==Game.Player.LastVehicle)
{
packet.RadioStation=Util.GetPlayerRadioIndex();
}
Send(packet, ConnectionChannel.VehicleSync); Send(packet, ConnectionChannel.VehicleSync);
} }
public static void SendProjectile(SyncedProjectile sp) public static void SendProjectile(SyncedProjectile sp)
@ -117,9 +123,9 @@ namespace RageCoop.Client
{ {
ID =sp.ID, ID =sp.ID,
ShooterID=sp.ShooterID, ShooterID=sp.ShooterID,
Position=p.Position.ToLVector(), Position=p.Position,
Rotation=p.Rotation.ToLVector(), Rotation=p.Rotation,
Velocity=p.Velocity.ToLVector(), Velocity=p.Velocity,
WeaponHash=(uint)p.WeaponHash, WeaponHash=(uint)p.WeaponHash,
Exploded=p.IsDead Exploded=p.IsDead
}; };
@ -133,8 +139,8 @@ namespace RageCoop.Client
{ {
Send(new Packets.BulletShot() Send(new Packets.BulletShot()
{ {
StartPosition = start.ToLVector(), StartPosition = start,
EndPosition = end.ToLVector(), EndPosition = end,
OwnerID = ownerID, OwnerID = ownerID,
WeaponHash=weapon, WeaponHash=weapon,
}, ConnectionChannel.SyncEvents); }, ConnectionChannel.SyncEvents);
@ -149,27 +155,6 @@ namespace RageCoop.Client
Client.SendMessage(outgoingMessage, NetDeliveryMethod.ReliableOrdered, (byte)ConnectionChannel.Chat); Client.SendMessage(outgoingMessage, NetDeliveryMethod.ReliableOrdered, (byte)ConnectionChannel.Chat);
Client.FlushSendQueue(); Client.FlushSendQueue();
#if DEBUG
if (ShowNetworkInfo)
{
BytesSend += outgoingMessage.LengthBytes;
}
#endif
}
public static void SendModData(long target, string modName, byte customID, byte[] bytes)
{
NetOutgoingMessage outgoingMessage = Client.CreateMessage();
new Packets.Mod()
{
// NetHandle = Main.LocalNetHandle,
Target = target,
Name = modName,
CustomPacketID = customID,
Bytes = bytes
}.Pack(outgoingMessage);
Client.SendMessage(outgoingMessage, NetDeliveryMethod.ReliableOrdered, (byte)ConnectionChannel.Mod);
Client.FlushSendQueue();
#if DEBUG #if DEBUG
if (ShowNetworkInfo) if (ShowNetworkInfo)
{ {
@ -193,19 +178,6 @@ namespace RageCoop.Client
} }
#endif #endif
} }
public static void SendTriggerEvent(string eventName, params object[] args)
{
NetOutgoingMessage outgoingMessage = Client.CreateMessage();
new Packets.ServerClientEvent()
{
EventName = eventName,
Args = new List<object>(args)
}.Pack(outgoingMessage);
Client.SendMessage(outgoingMessage, NetDeliveryMethod.ReliableUnordered, (byte)ConnectionChannel.Event);
Client.FlushSendQueue();
}
#endregion #endregion
} }
} }

View File

@ -30,7 +30,7 @@ namespace RageCoop.Client
if ((Util.GetTickCount64() - Pressed) < 5000 && !Main.MainChat.Focused if ((Util.GetTickCount64() - Pressed) < 5000 && !Main.MainChat.Focused
#if !NON_INTERACTIVE #if !NON_INTERACTIVE
&& !Main.MainMenu.MenuPool.AreAnyVisible && !Menus.CoopMenu.MenuPool.AreAnyVisible
#endif #endif
) )
{ {
@ -55,7 +55,7 @@ namespace RageCoop.Client
_mainScaleform.CallFunction("SET_DATA_SLOT", i++, $"{player.Latency * 1000:N0}ms", player.Username, 116, 0, i - 1, "", "", 2, "", "", ' '); _mainScaleform.CallFunction("SET_DATA_SLOT", i++, $"{player.Latency * 1000:N0}ms", player.Username, 116, 0, i - 1, "", "", 2, "", "", ' ');
} }
_mainScaleform.CallFunction("SET_TITLE", "Player list", (Players.Count) + " players"); _mainScaleform.CallFunction("SET_TITLE", "Player list", $"{Players.Count+1} players");
_mainScaleform.CallFunction("DISPLAY_VIEW"); _mainScaleform.CallFunction("DISPLAY_VIEW");
} }
public static void SetPlayer(int id, string username,float latency=0) public static void SetPlayer(int id, string username,float latency=0)

View File

@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers // You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("0.2.0.0")] [assembly: AssemblyVersion("0.4.1.0")]
[assembly: AssemblyFileVersion("0.2.0.0")] [assembly: AssemblyFileVersion("0.4.1.0")]

View File

@ -43,14 +43,6 @@
</DocumentationFile> </DocumentationFile>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="ClearScript.Core, Version=7.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\Libs\Release\scripts\ClearScript.Core.dll</HintPath>
</Reference>
<Reference Include="ClearScript.V8, Version=7.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\Libs\Release\scripts\ClearScript.V8.dll</HintPath>
</Reference>
<Reference Include="LemonUI.SHVDN3, Version=1.5.1.0, Culture=neutral, processorArchitecture=AMD64"> <Reference Include="LemonUI.SHVDN3, Version=1.5.1.0, Culture=neutral, processorArchitecture=AMD64">
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>..\Libs\Release\scripts\LemonUI.SHVDN3.dll</HintPath> <HintPath>..\Libs\Release\scripts\LemonUI.SHVDN3.dll</HintPath>
@ -59,21 +51,6 @@
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>..\Libs\Release\scripts\Lidgren.Network.dll</HintPath> <HintPath>..\Libs\Release\scripts\Lidgren.Network.dll</HintPath>
</Reference> </Reference>
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=6.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.6.0.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.DependencyInjection, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.DependencyInjection.6.0.0\lib\net461\Microsoft.Extensions.DependencyInjection.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.6.0.0\lib\net461\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Options, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Options.6.0.0\lib\net461\Microsoft.Extensions.Options.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Primitives, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Primitives.6.0.0\lib\net461\Microsoft.Extensions.Primitives.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> <Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>..\Libs\Release\scripts\Newtonsoft.Json.dll</HintPath> <HintPath>..\Libs\Release\scripts\Newtonsoft.Json.dll</HintPath>
@ -83,35 +60,14 @@
<HintPath>..\Libs\Release\ScriptHookVDotNet3.dll</HintPath> <HintPath>..\Libs\Release\ScriptHookVDotNet3.dll</HintPath>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
</Reference>
<Reference Include="System.ComponentModel.DataAnnotations" /> <Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Configuration" /> <Reference Include="System.Configuration" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
<Reference Include="System.Diagnostics.DiagnosticSource, Version=6.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Diagnostics.DiagnosticSource.6.0.0\lib\net461\System.Diagnostics.DiagnosticSource.dll</HintPath>
</Reference>
<Reference Include="System.Drawing" /> <Reference Include="System.Drawing" />
<Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll</HintPath>
</Reference>
<Reference Include="System.Numerics" /> <Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.Serialization" /> <Reference Include="System.Runtime.Serialization" />
<Reference Include="System.Security" /> <Reference Include="System.Security" />
<Reference Include="System.ServiceModel" /> <Reference Include="System.ServiceModel" />
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
<Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll</HintPath>
</Reference>
<Reference Include="System.Windows.Forms" /> <Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" /> <Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" /> <Reference Include="System.Data.DataSetExtensions" />
@ -123,18 +79,24 @@
<ItemGroup> <ItemGroup>
<Compile Include="DevTools\DevTool.cs" /> <Compile Include="DevTools\DevTool.cs" />
<Compile Include="Menus\Sub\DevToolMenu.cs" /> <Compile Include="Menus\Sub\DevToolMenu.cs" />
<Compile Include="Misc\WeaponUtil.cs" /> <Compile Include="Menus\Sub\ServersMenu.cs" />
<Compile Include="Scripting\ClientScript.cs" />
<Compile Include="Scripting\Engine.cs" />
<Compile Include="Util\MathExtensions.cs" />
<Compile Include="Util\PedConfigFlags.cs" />
<Compile Include="Util\Util.cs" />
<Compile Include="Util\VehicleExtensions.cs" />
<Compile Include="Util\WeaponUtil.cs" />
<Compile Include="Networking\Chat.cs" /> <Compile Include="Networking\Chat.cs" />
<Compile Include="COOPAPI.cs" /> <Compile Include="COOPAPI.cs" />
<Compile Include="Debug.cs" /> <Compile Include="Debug.cs" />
<Compile Include="Networking\DownloadManager.cs" /> <Compile Include="Networking\DownloadManager.cs" />
<Compile Include="Misc\TaskType.cs" /> <Compile Include="Util\TaskType.cs" />
<Compile Include="Menus\Sub\DebugMenu.cs" /> <Compile Include="Menus\Sub\DebugMenu.cs" />
<Compile Include="Networking\Receive.cs" /> <Compile Include="Networking\Receive.cs" />
<Compile Include="Networking\Send.cs" /> <Compile Include="Networking\Send.cs" />
<Compile Include="Sync\Entities\SyncedPed.cs" /> <Compile Include="Sync\Entities\SyncedPed.cs" />
<None Include="app.config" /> <None Include="app.config" />
<None Include="packages.config" />
<Compile Include="Sync\Entities\SyncedProjectile.cs" /> <Compile Include="Sync\Entities\SyncedProjectile.cs" />
<Compile Include="Sync\EntityPool.cs" /> <Compile Include="Sync\EntityPool.cs" />
<Compile Include="Sync\SyncEvents.cs" /> <Compile Include="Sync\SyncEvents.cs" />
@ -142,13 +104,13 @@
<Compile Include="Sync\Entities\SyncedVehicle.cs" /> <Compile Include="Sync\Entities\SyncedVehicle.cs" />
<Compile Include="Main.cs" /> <Compile Include="Main.cs" />
<Compile Include="Networking\MapLoader.cs" /> <Compile Include="Networking\MapLoader.cs" />
<Compile Include="Menus\RageCoopMenu.cs" /> <Compile Include="Menus\CoopMenu.cs" />
<Compile Include="Menus\Sub\SettingsMenu.cs" /> <Compile Include="Menus\Sub\SettingsMenu.cs" />
<Compile Include="Networking\Networking.cs" /> <Compile Include="Networking\Networking.cs" />
<Compile Include="PlayerList.cs" /> <Compile Include="PlayerList.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Sync\SyncParameters.cs" /> <Compile Include="Sync\SyncParameters.cs" />
<Compile Include="Misc\Util.cs" /> <Compile Include="Util\PedExtensions.cs" />
<Compile Include="WorldThread.cs" /> <Compile Include="WorldThread.cs" />
<Compile Include="Settings.cs" /> <Compile Include="Settings.cs" />
</ItemGroup> </ItemGroup>

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RageCoop.Client.Scripting
{
/// <summary>
/// Inherit from this class, constructor will be called when the script is loaded.
/// </summary>
public abstract class ClientScript
{
}
}

View File

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using System.IO;
using System.CodeDom.Compiler;
namespace RageCoop.Client.Scripting
{
internal class Engine : Core.Scripting.ScriptingEngine
{
public Engine() : base(typeof(ClientScript), Main.Logger) { }
}
}

View File

@ -18,7 +18,7 @@ namespace RageCoop.Client
/// <summary> /// <summary>
/// Don't use it! /// Don't use it!
/// </summary> /// </summary>
public string MasterServer { get; set; } = "https://ragecoop.online/gtav/servers"; public string MasterServer { get; set; } = "[AUTO]";
/// <summary> /// <summary>
/// Don't use it! /// Don't use it!
/// </summary> /// </summary>
@ -55,6 +55,9 @@ namespace RageCoop.Client
/// </summary> /// </summary>
public int WorldVehicleSoftLimit { get; set; } = 35; public int WorldVehicleSoftLimit { get; set; } = 35;
/// <summary>
/// Disable automatic respawn.
/// </summary>
public bool DisableAutoRespawn { get; set; } = false;
} }
} }

View File

@ -8,7 +8,7 @@ using GTA.Math;
namespace RageCoop.Client namespace RageCoop.Client
{ {
public abstract class SyncedEntity internal abstract class SyncedEntity
{ {
/// <summary> /// <summary>
@ -56,8 +56,13 @@ namespace RageCoop.Client
public Vector3 Position { get; set; } public Vector3 Position { get; set; }
public Vector3 Rotation { get; set; } public Vector3 Rotation { get; set; }
public Quaternion Quaternion { get; set; }
public Vector3 Velocity { get; set; } public Vector3 Velocity { get; set; }
public abstract void Update(); public abstract void Update();
public void PauseUpdate(ulong frames)
{
LastUpdated=Main.Ticked+frames;
}
} }
} }

View File

@ -14,7 +14,7 @@ namespace RageCoop.Client
/// <summary> /// <summary>
/// ? /// ?
/// </summary> /// </summary>
public partial class SyncedPed:SyncedEntity internal class SyncedPed:SyncedEntity
{ {
#region CONSTRUCTORS #region CONSTRUCTORS
@ -30,6 +30,10 @@ namespace RageCoop.Client
MainPed=p; MainPed=p;
OwnerID=Main.LocalPlayerID; OwnerID=Main.LocalPlayerID;
Function.Call(Hash._SET_PED_CAN_PLAY_INJURED_ANIMS, false);
MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DisableHurt, true);
MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DisableMelee, true);
} }
/// <summary> /// <summary>
@ -77,6 +81,7 @@ namespace RageCoop.Client
public Vector3 RotationVelocity { get; set; } public Vector3 RotationVelocity { get; set; }
public Vector3 AimCoords { get; set; } public Vector3 AimCoords { get; set; }
private WeaponAsset WeaponAsset { get; set; }
public override void Update() public override void Update()
@ -246,16 +251,25 @@ namespace RageCoop.Client
Function.Call(Hash.SET_PED_CAN_BE_TARGETTED_BY_PLAYER, MainPed.Handle, Game.Player, true); Function.Call(Hash.SET_PED_CAN_BE_TARGETTED_BY_PLAYER, MainPed.Handle, Game.Player, true);
Function.Call(Hash.SET_PED_GET_OUT_UPSIDE_DOWN_VEHICLE, MainPed.Handle, false); Function.Call(Hash.SET_PED_GET_OUT_UPSIDE_DOWN_VEHICLE, MainPed.Handle, false);
Function.Call(Hash.SET_CAN_ATTACK_FRIENDLY, MainPed.Handle, true, true); Function.Call(Hash.SET_CAN_ATTACK_FRIENDLY, MainPed.Handle, true, true);
Function.Call(Hash._SET_PED_CAN_PLAY_INJURED_ANIMS, false);
MainPed.BlockPermanentEvents = true; MainPed.BlockPermanentEvents = true;
MainPed.CanWrithe=false; MainPed.CanWrithe=false;
MainPed.CanBeDraggedOutOfVehicle = true; MainPed.CanBeDraggedOutOfVehicle = true;
MainPed.IsOnlyDamagedByPlayer = false; MainPed.IsOnlyDamagedByPlayer = false;
MainPed.RelationshipGroup=Main.SyncedPedsGroup; MainPed.RelationshipGroup=Main.SyncedPedsGroup;
if (IsPlayer) MainPed.IsFireProof=false;
{ MainPed.IsExplosionProof=false;
MainPed.IsInvincible=true;
} MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DrownsInWater,false);
MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DisableMelee, true);
MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DisableHurt, true);
MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DisableExplosionReactions, true);
MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_AvoidTearGas, false);
MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DisableShockingEvents, true);
MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DisableHurt, true);
SetClothes(); SetClothes();
if (IsPlayer) if (IsPlayer)
@ -266,6 +280,7 @@ namespace RageCoop.Client
MainPed.AttachedBlip.Scale = 0.8f; MainPed.AttachedBlip.Scale = 0.8f;
MainPed.AttachedBlip.Name =Username; MainPed.AttachedBlip.Name =Username;
MainPed.IsInvincible=true;
} }
// Add to EntityPool so this Character can be accessed by handle. // Add to EntityPool so this Character can be accessed by handle.
@ -304,7 +319,6 @@ namespace RageCoop.Client
private int _lastWeaponObj = 0; private int _lastWeaponObj = 0;
#endregion #endregion
private bool _isPlayingAnimation = false;
private string[] _currentAnimation = new string[2] { "", "" }; private string[] _currentAnimation = new string[2] { "", "" };
private void DisplayOnFoot() private void DisplayOnFoot()
@ -514,12 +528,6 @@ namespace RageCoop.Client
*/ */
SmoothTransition(); SmoothTransition();
} }
else if (_currentAnimation[1] == "reload_aim")
{
MainPed.Task.ClearAnimation(_currentAnimation[0], _currentAnimation[1]);
_isPlayingAnimation = false;
_currentAnimation = new string[2] { "", "" };
}
else if (IsInCover) else if (IsInCover)
{ {
@ -569,11 +577,13 @@ namespace RageCoop.Client
} }
#region WEAPON #region WEAPON
WeaponHash appliedWeaponhash = WeaponHash.Unarmed;
private void CheckCurrentWeapon() private void CheckCurrentWeapon()
{ {
if (MainPed.Weapons.Current.Hash != (WeaponHash)CurrentWeaponHash || !WeaponComponents.Compare(_lastWeaponComponents)) if (MainPed.Weapons.Current.Hash != (WeaponHash)CurrentWeaponHash || !WeaponComponents.Compare(_lastWeaponComponents))
{ {
if (WeaponAsset!=null) { WeaponAsset.MarkAsNoLongerNeeded(); }
WeaponAsset=new WeaponAsset(CurrentWeaponHash);
if (!WeaponAsset.IsLoaded) { WeaponAsset.Request(); }
MainPed.Weapons.RemoveAll(); MainPed.Weapons.RemoveAll();
_lastWeaponObj = Function.Call<int>(Hash.CREATE_WEAPON_OBJECT, CurrentWeaponHash, -1, Position.X, Position.Y, Position.Z, true, 0, 0); _lastWeaponObj = Function.Call<int>(Hash.CREATE_WEAPON_OBJECT, CurrentWeaponHash, -1, Position.X, Position.Y, Position.Z, true, 0, 0);
@ -676,7 +686,7 @@ namespace RageCoop.Client
MainPed.PositionNoOffset=Position; MainPed.PositionNoOffset=Position;
return; return;
} }
var f = dist*(Position+SyncParameters.PositioinPrediction*Velocity-MainPed.Position)+(Velocity-MainPed.Velocity)*0.2f; var f = dist*(Position+SyncParameters.PositioinPredictionDefault*Velocity-MainPed.Position)+(Velocity-MainPed.Velocity)*0.2f;
if (!localRagdoll) { f*=5; } if (!localRagdoll) { f*=5; }
if (!(localRagdoll|| MainPed.IsDead)) if (!(localRagdoll|| MainPed.IsDead))
{ {

View File

@ -16,7 +16,7 @@ namespace RageCoop.Client
IsMine=true; IsMine=true;
MainProjectile = p; MainProjectile = p;
Origin=p.Position; Origin=p.Position;
var shooter = EntityPool.GetPedByHandle(p.Owner.Handle); var shooter = EntityPool.GetPedByHandle((p.Owner?.Handle).GetValueOrDefault());
if(shooter != null) if(shooter != null)
{ {
ShooterID=shooter.ID; ShooterID=shooter.ID;
@ -24,14 +24,14 @@ namespace RageCoop.Client
else else
{ {
// Owner will be the vehicle if projectile is shot with a vehicle // Owner will be the vehicle if projectile is shot with a vehicle
var shooterVeh = EntityPool.GetVehicleByHandle(p.Owner.Handle); var shooterVeh = EntityPool.GetVehicleByHandle((p.Owner?.Handle).GetValueOrDefault());
if (shooterVeh!=null && shooterVeh.MainVehicle.Driver!=null) if (shooterVeh!=null && shooterVeh.MainVehicle.Driver!=null)
{ {
ShooterID=shooterVeh.MainVehicle.Driver.GetSyncEntity().ID; ShooterID=shooterVeh.MainVehicle.Driver.GetSyncEntity().ID;
} }
else else
{ {
Main.Logger.Warning($"Could not find owner for projectile, owner handle:{p.Owner.Handle}"); Main.Logger.Warning($"Could not find owner for projectile:{Hash}");
} }
} }
@ -45,7 +45,7 @@ namespace RageCoop.Client
public bool Exploded { get; set; } = false; public bool Exploded { get; set; } = false;
public Projectile MainProjectile { get; set; } public Projectile MainProjectile { get; set; }
public int ShooterID { get; set; } public int ShooterID { get; set; }
private SyncedPed Shooter { get;set; }
public Vector3 Origin { get; set; } public Vector3 Origin { get; set; }
/// <summary> /// <summary>
@ -75,9 +75,17 @@ namespace RageCoop.Client
{ {
Asset=new WeaponAsset(Hash); Asset=new WeaponAsset(Hash);
if (!Asset.IsLoaded) { Asset.Request(); } if (!Asset.IsLoaded) { Asset.Request(); }
World.ShootBullet(Position,Position+Velocity,EntityPool.GetPedByID(ShooterID)?.MainPed,Asset,0); World.ShootBullet(Position,Position+Velocity,(Shooter=EntityPool.GetPedByID(ShooterID))?.MainPed,Asset,0);
var ps = World.GetAllProjectiles(); var ps = World.GetAllProjectiles();
MainProjectile=ps[ps.Length-1]; MainProjectile=ps[ps.Length-1];
if (Hash==(WeaponHash)VehicleWeaponHash.Tank)
{
var v = Shooter?.MainPed?.CurrentVehicle;
if (v!=null)
{
World.CreateParticleEffectNonLooped(SyncEvents.CorePFXAsset, "muz_tank", v.GetMuzzleInfo().Position, v.Bones[35].ForwardVector.ToEulerRotation(v.Bones[35].UpVector), 1);
}
}
EntityPool.Add(this); EntityPool.Add(this);
} }
} }

View File

@ -11,7 +11,7 @@ using RageCoop.Core;
namespace RageCoop.Client namespace RageCoop.Client
{ {
public class SyncedVehicle : SyncedEntity internal class SyncedVehicle : SyncedEntity
{ {
#region -- CONSTRUCTORS -- #region -- CONSTRUCTORS --
@ -52,10 +52,9 @@ namespace RageCoop.Client
#region LAST STATE STORE #region LAST STATE STORE
private ulong _vehicleStopTime { get; set; }
private byte[] _lastVehicleColors = new byte[] { 0, 0 }; private byte[] _lastVehicleColors = new byte[] { 0, 0 };
private Dictionary<int, int> _lastVehicleMods = new Dictionary<int, int>(); private Dictionary<int, int> _lastVehicleMods = new Dictionary<int, int>();
private byte _lastRadioIndex=255;
#endregion #endregion
#region -- CRITICAL STUFF -- #region -- CRITICAL STUFF --
@ -63,9 +62,11 @@ namespace RageCoop.Client
public float SteeringAngle { get; set; } public float SteeringAngle { get; set; }
public float ThrottlePower { get; set; } public float ThrottlePower { get; set; }
public float BrakePower { get; set; } public float BrakePower { get; set; }
public float DeluxoWingRatio { get; set; } = -1;
#endregion #endregion
#region -- VEHICLE STATE -- #region -- VEHICLE STATE --
public VehicleDataFlags Flags { get; set; }
public bool EngineRunning { get; set; } public bool EngineRunning { get; set; }
private bool _lastTransformed = false; private bool _lastTransformed = false;
public bool Transformed { get; set; } public bool Transformed { get; set; }
@ -88,7 +89,7 @@ namespace RageCoop.Client
/// VehicleSeat,PedID /// VehicleSeat,PedID
/// </summary> /// </summary>
public Dictionary<VehicleSeat, SyncedPed> Passengers { get; set; } public Dictionary<VehicleSeat, SyncedPed> Passengers { get; set; }
public byte RadioStation = 255;
private long _lastPositionCalibrated { get; set; } private long _lastPositionCalibrated { get; set; }
#endregion #endregion
@ -99,10 +100,8 @@ namespace RageCoop.Client
// Check if all data avalible // Check if all data avalible
if(!IsReady) { return; } if(!IsReady) { return; }
// Skip update if no new sync message has arrived. // Skip update if no new sync message has arrived.
if (!NeedUpdate) { return; } if (!NeedUpdate) { return; }
#endregion #endregion
#region -- CHECK EXISTENCE -- #region -- CHECK EXISTENCE --
if ((MainVehicle == null) || (!MainVehicle.Exists()) || (MainVehicle.Model.Hash != ModelHash)) if ((MainVehicle == null) || (!MainVehicle.Exists()) || (MainVehicle.Model.Hash != ModelHash))
@ -129,27 +128,22 @@ namespace RageCoop.Client
} }
if (MainVehicle.Position.DistanceTo(Position)<5) if (MainVehicle.Position.DistanceTo(Position)<5)
{ {
MainVehicle.Velocity = Velocity+5*(Position+Velocity*SyncParameters.PositioinPrediction - MainVehicle.Position); MainVehicle.Velocity = Velocity+5*(Position+Velocity*SyncParameters.PositioinPredictionDefault - MainVehicle.Position);
_lastPositionCalibrated=Main.Counter.ElapsedMilliseconds; MainVehicle.Quaternion=Quaternion.Slerp(MainVehicle.Quaternion, Quaternion, 0.5f);
} }
else else
{ {
MainVehicle.Position=Position; MainVehicle.Position=Position;
MainVehicle.Velocity=Velocity; MainVehicle.Velocity=Velocity;
MainVehicle.Quaternion=Quaternion;
} }
Vector3 r = GetCalibrationRotation(); // Vector3 r = GetCalibrationRotation();
if (r.Length() < 20f) MainVehicle.RotationVelocity = RotationVelocity;
if (DeluxoWingRatio!=-1)
{ {
MainVehicle.RotationVelocity = r * 0.15f + RotationVelocity; MainVehicle.SetDeluxoWingRatio(DeluxoWingRatio);
} }
else
{
MainVehicle.Rotation = Rotation;
MainVehicle.RotationVelocity = RotationVelocity;
}
_vehicleStopTime = Util.GetTickCount64();
#endregion #endregion
if (LastStateSynced>LastUpdated) if (LastStateSynced>LastUpdated)
{ {
#region -- SYNC STATE -- #region -- SYNC STATE --
@ -168,7 +162,11 @@ namespace RageCoop.Client
{ {
SyncedPed c = Passengers[seat]; SyncedPed c = Passengers[seat];
if ((c!=null)&&c.MainPed!=null&&(!currentPassengers.ContainsKey(i))&&(!c.MainPed.IsBeingJacked)) { if (c?.ID==Main.LocalPlayerID && (RadioStation!=_lastRadioIndex))
{
Util.SetPlayerRadioIndex(RadioStation);
}
if (c?.MainPed!=null&&(!currentPassengers.ContainsKey(i))&&(!c.MainPed.IsBeingJacked)&&(!c.MainPed.IsTaskActive(TaskType.CTaskExitVehicleSeat))) {
Passengers[seat].MainPed.SetIntoVehicle(MainVehicle, seat); Passengers[seat].MainPed.SetIntoVehicle(MainVehicle, seat);
} }
} }
@ -303,7 +301,20 @@ namespace RageCoop.Client
} }
MainVehicle.LockStatus=LockStatus; MainVehicle.LockStatus=LockStatus;
if (Flags.HasFlag(VehicleDataFlags.IsDeluxoHovering))
{
if (!MainVehicle.IsDeluxoHovering())
{
MainVehicle.SetDeluxoHoverState(true);
}
}
else if(ModelHash==1483171323)
{
if (MainVehicle.IsDeluxoHovering())
{
MainVehicle.SetDeluxoHoverState(false);
}
}
#endregion #endregion
} }
@ -311,6 +322,8 @@ namespace RageCoop.Client
} }
private Vector3 GetCalibrationRotation() private Vector3 GetCalibrationRotation()
{ {
return (Quaternion-MainVehicle.Quaternion).ToEulerAngles().ToDegree();
/*
var r = Rotation-MainVehicle.Rotation; var r = Rotation-MainVehicle.Rotation;
if (r.X>180) { r.X=r.X-360; } if (r.X>180) { r.X=r.X-360; }
else if(r.X<-180) { r.X=360+r.X; } else if(r.X<-180) { r.X=360+r.X; }
@ -321,6 +334,7 @@ namespace RageCoop.Client
if (r.Z>180) { r.Z=r.Z-360; } if (r.Z>180) { r.Z=r.Z-360; }
else if (r.Z<-180) { r.Z=360+r.Z; } else if (r.Z<-180) { r.Z=360+r.Z; }
return r; return r;
*/
} }
private void CreateVehicle() private void CreateVehicle()
{ {
@ -336,7 +350,7 @@ namespace RageCoop.Client
{ {
EntityPool.Add( this); EntityPool.Add( this);
} }
MainVehicle.Rotation = Rotation; MainVehicle.Quaternion = Quaternion;
if (MainVehicle.HasRoof) if (MainVehicle.HasRoof)
{ {
@ -385,7 +399,9 @@ namespace RageCoop.Client
} }
#endregion #endregion
#region OUTGOING
public float LastNozzleAngle { get; set; }
#endregion
} }
} }

View File

@ -388,6 +388,7 @@ namespace RageCoop.Client
if (Main.Ticked%20==0) if (Main.Ticked%20==0)
{ {
Networking.SendPed(c);
Networking.SendPedState(c); Networking.SendPedState(c);
} }
else else
@ -449,10 +450,11 @@ namespace RageCoop.Client
// Outgoing sync // Outgoing sync
if (v.IsMine) if (v.IsMine)
{ {
SyncEvents.Check(v);
if (Main.Ticked%20==0) if (Main.Ticked%20==0)
{ {
Networking.SendVehicle(v);
Networking.SendVehicleState(v); Networking.SendVehicleState(v);
} }
else else
{ {

View File

@ -12,7 +12,6 @@ using System.Threading;
namespace RageCoop.Client { namespace RageCoop.Client {
internal static class SyncEvents internal static class SyncEvents
{ {
#region TRIGGER #region TRIGGER
public static void TriggerPedKilled(SyncedPed victim) public static void TriggerPedKilled(SyncedPed victim)
{ {
@ -34,9 +33,9 @@ namespace RageCoop.Client {
{ {
if (seat==VehicleSeat.Driver) if (seat==VehicleSeat.Driver)
{ {
TriggerChangeOwner(veh, c.ID);
veh.OwnerID=Main.LocalPlayerID; veh.OwnerID=Main.LocalPlayerID;
veh.LastSynced=Main.Ticked; veh.LastSynced=Main.Ticked;
TriggerChangeOwner(veh, c.ID);
} }
Networking.Send(new Packets.EnteredVehicle() Networking.Send(new Packets.EnteredVehicle()
{ {
@ -61,13 +60,6 @@ namespace RageCoop.Client {
{ {
Main.Logger.Trace($"bullet shot:{(WeaponHash)hash}"); Main.Logger.Trace($"bullet shot:{(WeaponHash)hash}");
// Minigun, not working for some reason
if (hash==(uint)WeaponHash.Minigun)
{
hash=(uint)WeaponHash.HeavyRifle;
}
// Valkyire, not working for some reason
if (hash==2756787765) { hash=(uint)WeaponHash.HeavyRifle; }
var start = owner.MainPed.GetMuzzlePosition(); var start = owner.MainPed.GetMuzzlePosition();
if (owner.MainPed.IsOnTurretSeat()) { start=owner.MainPed.Bones[Bone.SkelHead].Position; } if (owner.MainPed.IsOnTurretSeat()) { start=owner.MainPed.Bones[Bone.SkelHead].Position; }
@ -89,10 +81,6 @@ namespace RageCoop.Client {
public static void TriggerVehBulletShot(uint hash, Vehicle veh, SyncedPed owner) public static void TriggerVehBulletShot(uint hash, Vehicle veh, SyncedPed owner)
{ {
if (hash==(uint)VehicleWeaponHash.PlayerBuzzard)
{
hash=(uint)WeaponHash.HeavyRifle;
}
// ANNIHL // ANNIHL
if (veh.Model.Hash==837858166) if (veh.Model.Hash==837858166)
{ {
@ -107,19 +95,29 @@ namespace RageCoop.Client {
if (info==null) { Main.Logger.Warning($"Failed to get muzzle info for vehicle:{veh.DisplayName}");return; } if (info==null) { Main.Logger.Warning($"Failed to get muzzle info for vehicle:{veh.DisplayName}");return; }
Networking.SendBulletShot(info.Position,info.Position+info.ForawardVector,hash,owner.ID); Networking.SendBulletShot(info.Position,info.Position+info.ForawardVector,hash,owner.ID);
} }
public static void TriggerNozzleTransform(int vehID,bool hover)
{
Networking.Send(new Packets.NozzleTransform() { VehicleID=vehID, Hover=hover }, ConnectionChannel.SyncEvents);
}
#endregion #endregion
#region HANDLE #region HANDLE
public static ParticleEffectAsset CorePFXAsset = new ParticleEffectAsset("core");
static WeaponAsset _weaponAsset = default;
static uint _lastWeaponHash;
private static void HandleLeaveVehicle(Packets.LeaveVehicle p) private static void HandleLeaveVehicle(Packets.LeaveVehicle p)
{ {
var ped = EntityPool.GetPedByID(p.ID)?.MainPed; var ped = EntityPool.GetPedByID(p.ID);
var flag = LeaveVehicleFlags.None; var flag = LeaveVehicleFlags.None;
if (ped.MainPed?.CurrentVehicle==null) { return; }
// Bail out // Bail out
if (ped?.CurrentVehicle==null) { return; } if (ped.MainPed.CurrentVehicle.Speed>5) { flag|=LeaveVehicleFlags.BailOut;}
if (ped.CurrentVehicle.Speed>5) { flag|=LeaveVehicleFlags.BailOut;} ped.PauseUpdate((ulong)Game.FPS*2);
ped.Task.LeaveVehicle(flag) ; ped.MainPed.Task.LeaveVehicle(flag) ;
} }
private static void HandlePedKilled(Packets.PedKilled p) private static void HandlePedKilled(Packets.PedKilled p)
{ {
@ -150,30 +148,50 @@ namespace RageCoop.Client {
v.OwnerID=p.NewOwnerID; v.OwnerID=p.NewOwnerID;
v.ModelHash=v.MainVehicle.Model; v.ModelHash=v.MainVehicle.Model;
v.LastSynced=Main.Ticked;
// So this vehicle doesn's get re-spawned // So this vehicle doesn's get re-spawned
} }
private static void HandleNozzleTransform(Packets.NozzleTransform p)
private static ParticleEffectAsset CorePFXAsset = default; {
EntityPool.GetVehicleByID(p.VehicleID)?.MainVehicle?.SetNozzleAngel(p.Hover ? 1 : 0);
static WeaponAsset _weaponAsset = default; }
static uint _lastWeaponHash;
private static void HandleBulletShot(Vector3 start, Vector3 end, uint weaponHash, int ownerID) private static void HandleBulletShot(Vector3 start, Vector3 end, uint weaponHash, int ownerID)
{ {
if (CorePFXAsset==default) { switch (weaponHash)
CorePFXAsset= new ParticleEffectAsset("core"); {
// Minigun, not working for some reason
case (uint)WeaponHash.Minigun:
weaponHash=1176362416;
break;
// Valkyire, not working for some reason
case 2756787765:
weaponHash=1176362416;
break;
// SAVAGE
case 1638077257:
weaponHash=(uint)VehicleWeaponHash.PlayerLazer;
break;
case (uint)VehicleWeaponHash.PlayerBuzzard:
weaponHash=1176362416;
break ;
} }
if (!CorePFXAsset.IsLoaded) { CorePFXAsset.Request(); }
var p = EntityPool.GetPedByID(ownerID)?.MainPed; var p = EntityPool.GetPedByID(ownerID)?.MainPed;
if (p == null) { p=Game.Player.Character; Main.Logger.Warning("Failed to find owner for bullet"); } if (p == null) { p=Game.Player.Character; Main.Logger.Warning("Failed to find owner for bullet"); }
if (!CorePFXAsset.IsLoaded) { CorePFXAsset.Request(); }
if (_lastWeaponHash!=weaponHash) if (_lastWeaponHash!=weaponHash)
{ {
_weaponAsset.MarkAsNoLongerNeeded();
_weaponAsset=new WeaponAsset(weaponHash); _weaponAsset=new WeaponAsset(weaponHash);
_lastWeaponHash=weaponHash; _lastWeaponHash=weaponHash;
} }
if (!_weaponAsset.IsLoaded) { _weaponAsset.Request(); } if (!_weaponAsset.IsLoaded) { _weaponAsset.Request(); }
World.ShootBullet(start, end, p, _weaponAsset, p.GetWeaponDamage()); World.ShootBullet(start, end, p, _weaponAsset, p.GetWeaponDamage(weaponHash));
var w = p.Weapons.CurrentWeaponObject; Prop w;
if(w != null) if(((w = p.Weapons.CurrentWeaponObject) != null)&&(p.VehicleWeapon==VehicleWeaponHash.Invalid))
{ {
if (p.Weapons.Current.Components.GetSuppressorComponent().Active) if (p.Weapons.Current.Components.GetSuppressorComponent().Active)
{ {
@ -185,6 +203,13 @@ namespace RageCoop.Client {
} }
} }
else if (p.VehicleWeapon!=VehicleWeaponHash.Invalid)
{
if (p.VehicleWeapon==VehicleWeaponHash.Tank)
{
World.CreateParticleEffectNonLooped(CorePFXAsset, "muz_tank", p.CurrentVehicle.GetMuzzleInfo().Position, p.CurrentVehicle.Bones[35].ForwardVector.ToEulerRotation(p.CurrentVehicle.Bones[35].UpVector), 1);
}
}
} }
public static void HandleEvent(PacketTypes type,byte[] data) public static void HandleEvent(PacketTypes type,byte[] data)
{ {
@ -194,7 +219,7 @@ namespace RageCoop.Client {
{ {
Packets.BulletShot p = new Packets.BulletShot(); Packets.BulletShot p = new Packets.BulletShot();
p.Unpack(data); p.Unpack(data);
HandleBulletShot(p.StartPosition.ToVector(), p.EndPosition.ToVector(), p.WeaponHash, p.OwnerID); HandleBulletShot(p.StartPosition, p.EndPosition, p.WeaponHash, p.OwnerID);
break; break;
} }
case PacketTypes.EnteringVehicle: case PacketTypes.EnteringVehicle:
@ -234,13 +259,22 @@ namespace RageCoop.Client {
HandleEnteredVehicle(packet.PedID,packet.VehicleID,(VehicleSeat)packet.VehicleSeat); HandleEnteredVehicle(packet.PedID,packet.VehicleID,(VehicleSeat)packet.VehicleSeat);
break; break;
} }
case PacketTypes.NozzleTransform:
{
var packet = new Packets.NozzleTransform();
packet.Unpack(data);
HandleNozzleTransform(packet);
break;
}
} }
} }
public static int GetWeaponDamage(this Ped p) public static int GetWeaponDamage(this Ped p,uint hash)
{ {
if (p.VehicleWeapon!=VehicleWeaponHash.Invalid) if(p.IsInVehicle() && (hash!=(uint)p.Weapons.Current.Hash))
{ {
return 30; // This is a vehicle weapon
p.VehicleWeapon=(VehicleWeaponHash)hash;
return 100;
} }
switch (p.Weapons.Current.Group) switch (p.Weapons.Current.Group)
{ {
@ -264,6 +298,8 @@ namespace RageCoop.Client {
public static void Check(SyncedPed c) public static void Check(SyncedPed c)
{ {
Ped subject = c.MainPed; Ped subject = c.MainPed;
// Check bullets
if (subject.IsShooting) if (subject.IsShooting)
{ {
if (!subject.IsUsingProjectileWeapon()) if (!subject.IsUsingProjectileWeapon())
@ -360,7 +396,21 @@ namespace RageCoop.Client {
c._lastEnteringVehicle=g; c._lastEnteringVehicle=g;
} }
public static void Check(SyncedVehicle v)
{
if (v.MainVehicle!=null&&v.MainVehicle.HasNozzle())
{
if((v.LastNozzleAngle==1) && (v.MainVehicle.GetNozzleAngel()!=1))
{
TriggerNozzleTransform(v.ID,false);
}
else if((v.LastNozzleAngle==0) && (v.MainVehicle.GetNozzleAngel()!=0))
{
TriggerNozzleTransform(v.ID,true);
}
v.LastNozzleAngle=v.MainVehicle.GetNozzleAngel();
}
}
#endregion #endregion
} }
} }

View File

@ -8,6 +8,6 @@ namespace RageCoop.Client
{ {
internal class SyncParameters internal class SyncParameters
{ {
public static float PositioinPrediction = 0.03f; public static float PositioinPredictionDefault = 0.01f;
} }
} }

View File

@ -0,0 +1,149 @@
using System;
using GTA.Math;
namespace RageCoop.Client
{
internal static class MathExtensions
{
/// <summary>
///
/// </summary>
public static Vector3 ToVector(this Quaternion vec)
{
return new Vector3()
{
X = vec.X,
Y = vec.Y,
Z = vec.Z
};
}
/// <summary>
///
/// </summary>
public static Quaternion ToQuaternion(this Vector3 vec, float vW = 0.0f)
{
return new Quaternion()
{
X = vec.X,
Y = vec.Y,
Z = vec.Z,
W = vW
};
}
public static float Denormalize(this float h)
{
return h < 0f ? h + 360f : h;
}
public static float ToRadians(this float val)
{
return (float)(Math.PI / 180) * val;
}
public static Vector3 ToRadians(this Vector3 i)
{
return new Vector3()
{
X = ToRadians(i.X),
Y = ToRadians(i.Y),
Z = ToRadians(i.Z),
};
}
public static Quaternion ToQuaternion(this Vector3 vect)
{
vect = new Vector3()
{
X = vect.X.Denormalize() * -1,
Y = vect.Y.Denormalize() - 180f,
Z = vect.Z.Denormalize() - 180f,
};
vect = vect.ToRadians();
float rollOver2 = vect.Z * 0.5f;
float sinRollOver2 = (float)Math.Sin((double)rollOver2);
float cosRollOver2 = (float)Math.Cos((double)rollOver2);
float pitchOver2 = vect.Y * 0.5f;
float sinPitchOver2 = (float)Math.Sin((double)pitchOver2);
float cosPitchOver2 = (float)Math.Cos((double)pitchOver2);
float yawOver2 = vect.X * 0.5f; // pitch
float sinYawOver2 = (float)Math.Sin((double)yawOver2);
float cosYawOver2 = (float)Math.Cos((double)yawOver2);
Quaternion result = new Quaternion()
{
X = cosYawOver2 * cosPitchOver2 * cosRollOver2 + sinYawOver2 * sinPitchOver2 * sinRollOver2,
Y = cosYawOver2 * cosPitchOver2 * sinRollOver2 - sinYawOver2 * sinPitchOver2 * cosRollOver2,
Z = cosYawOver2 * sinPitchOver2 * cosRollOver2 + sinYawOver2 * cosPitchOver2 * sinRollOver2,
W = sinYawOver2 * cosPitchOver2 * cosRollOver2 - cosYawOver2 * sinPitchOver2 * sinRollOver2
};
return result;
}
public static double DegToRad(double deg)
{
return deg * Math.PI / 180.0;
}
public static Vector3 ToEulerRotation(this Vector3 dir, Vector3 up)
{
var rot = Quaternion.LookRotation(dir.Normalized, up).ToEulerAngles().ToDegree();
return rot;
}
public static Vector3 ToDegree(this Vector3 radian)
{
return radian*(float)(180/Math.PI);
}
public static Vector3 ToEulerAngles(this Quaternion q)
{
Vector3 angles = new Vector3();
// roll / x
double sinr_cosp = 2 * (q.W * q.X + q.Y * q.Z);
double cosr_cosp = 1 - 2 * (q.X * q.X + q.Y * q.Y);
angles.X = (float)Math.Atan2(sinr_cosp, cosr_cosp);
// pitch / y
double sinp = 2 * (q.W * q.Y - q.Z * q.X);
if (Math.Abs(sinp) >= 1)
{
angles.Y = CopySign(Math.PI / 2, sinp);
}
else
{
angles.Y = (float)Math.Asin(sinp);
}
// yaw / z
double siny_cosp = 2 * (q.W * q.Z + q.X * q.Y);
double cosy_cosp = 1 - 2 * (q.Y * q.Y + q.Z * q.Z);
angles.Z = (float)Math.Atan2(siny_cosp, cosy_cosp);
return angles;
}
private static float CopySign(double x, double y)
{
bool isPositive = y>=0;
if (isPositive)
{
if (x>=0) { return (float)x; } else { return (float)-x; }
}
else
{
if (x>=0) { return (float)-x; } else { return (float)x; }
}
}
public static double AngelTo(this Vector3 v1, Vector3 v2)
{
return Math.Acos(v1.GetCosTheta(v2));
}
public static float GetCosTheta(this Vector3 v1, Vector3 v2)
{
return Vector3.Dot(v1, v2)/(v1.Length()*v2.Length());
}
}
}

View File

@ -0,0 +1,471 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RageCoop.Client
{
// Potential names and hash collisions included as comments
public enum PedConfigFlags
{
_0x67D1A445 = 0,
_0xC63DE95E = 1,
CPED_CONFIG_FLAG_NoCriticalHits = 2,
CPED_CONFIG_FLAG_DrownsInWater = 3,
CPED_CONFIG_FLAG_DisableReticuleFixedLockon = 4,
_0x37D196F4 = 5,
_0xE2462399 = 6,
CPED_CONFIG_FLAG_UpperBodyDamageAnimsOnly = 7,
_0xEDDEB838 = 8,
_0xB398B6FD = 9,
_0xF6664E68 = 10,
_0xA05E7CA3 = 11,
_0xCE394045 = 12,
CPED_CONFIG_FLAG_NeverLeavesGroup = 13,
_0xCD8D1411 = 14,
_0xB031F1A9 = 15,
_0xFE65BEE3 = 16,
CPED_CONFIG_FLAG_BlockNonTemporaryEvents = 17,
_0x380165BD = 18,
_0x07C045C7 = 19,
_0x583B5E2D = 20,
_0x475EDA58 = 21,
_0x8629D05B = 22,
_0x1522968B = 23,
CPED_CONFIG_FLAG_IgnoreSeenMelee = 24,
_0x4CC09C4B = 25,
_0x034F3053 = 26,
_0xD91BA7CC = 27,
_0x5C8DC66E = 28,
_0x8902EAA0 = 29,
_0x6580B9D2 = 30,
_0x0EF7A297 = 31,
_0x6BF86E5B = 32,
CPED_CONFIG_FLAG_DieWhenRagdoll = 33,
CPED_CONFIG_FLAG_HasHelmet = 34,
CPED_CONFIG_FLAG_UseHelmet = 35,
_0xEEB3D630 = 36,
_0xB130D17B = 37,
_0x5F071200 = 38,
CPED_CONFIG_FLAG_DisableEvasiveDives = 39,
_0xC287AAFF = 40,
_0x203328CC = 41,
CPED_CONFIG_FLAG_DontInfluenceWantedLevel = 42,
CPED_CONFIG_FLAG_DisablePlayerLockon = 43,
CPED_CONFIG_FLAG_DisableLockonToRandomPeds = 44,
_0xEC4A8ACF = 45,
_0xDB115BFA = 46,
CPED_CONFIG_FLAG_PedBeingDeleted = 47,
CPED_CONFIG_FLAG_BlockWeaponSwitching = 48,
_0xF8E99565 = 49,
_0xDD17FEE6 = 50,
_0x7ED9B2C9 = 51,
_0x655E8618 = 52,
_0x5A6C1F6E = 53,
_0xD749FC41 = 54,
_0x357F63F3 = 55,
_0xC5E60961 = 56,
_0x29275C3E = 57,
CPED_CONFIG_FLAG_IsFiring = 58,
CPED_CONFIG_FLAG_WasFiring = 59,
CPED_CONFIG_FLAG_IsStanding = 60,
CPED_CONFIG_FLAG_WasStanding = 61,
CPED_CONFIG_FLAG_InVehicle = 62,
CPED_CONFIG_FLAG_OnMount = 63,
CPED_CONFIG_FLAG_AttachedToVehicle = 64,
CPED_CONFIG_FLAG_IsSwimming = 65,
CPED_CONFIG_FLAG_WasSwimming = 66,
CPED_CONFIG_FLAG_IsSkiing = 67,
CPED_CONFIG_FLAG_IsSitting = 68,
CPED_CONFIG_FLAG_KilledByStealth = 69,
CPED_CONFIG_FLAG_KilledByTakedown = 70,
CPED_CONFIG_FLAG_Knockedout = 71,
_0x3E3C4560 = 72,
_0x2994C7B7 = 73,
_0x6D59D275 = 74,
CPED_CONFIG_FLAG_UsingCoverPoint = 75,
CPED_CONFIG_FLAG_IsInTheAir = 76,
_0x2D493FB7 = 77,
CPED_CONFIG_FLAG_IsAimingGun = 78,
_0x14D69875 = 79,
_0x40B05311 = 80,
_0x8B230BC5 = 81,
_0xC74E5842 = 82,
_0x9EA86147 = 83,
_0x674C746C = 84,
_0x3E56A8C2 = 85,
_0xC144A1EF = 86,
_0x0548512D = 87,
_0x31C93909 = 88,
_0xA0269315 = 89,
_0xD4D59D4D = 90,
_0x411D4420 = 91,
_0xDF4AEF0D = 92,
CPED_CONFIG_FLAG_ForcePedLoadCover = 93,
_0x300E4CD3 = 94,
_0xF1C5BF04 = 95,
_0x89C2EF13 = 96,
CPED_CONFIG_FLAG_VaultFromCover = 97,
_0x02A852C8 = 98,
_0x3D9407F1 = 99,
_0x319B4558 = 100,
CPED_CONFIG_FLAG_ForcedAim = 101,
_0xB942D71A = 102,
_0xD26C55A8 = 103,
_0xB89E703B = 104,
CPED_CONFIG_FLAG_ForceReload = 105,
_0xD9E73DA2 = 106,
_0xFF71DC2C = 107,
_0x1E27E8D8 = 108,
_0xF2C53966 = 109,
_0xC4DBE247 = 110,
_0x83C0A4BF = 111,
_0x0E0FAF8C = 112,
_0x26616660 = 113,
_0x43B80B79 = 114,
_0x0D2A9309 = 115,
_0x12C1C983 = 116,
CPED_CONFIG_FLAG_BumpedByPlayer = 117,
_0xE586D504 = 118,
_0x52374204 = 119,
CPED_CONFIG_FLAG_IsHandCuffed = 120,
CPED_CONFIG_FLAG_IsAnkleCuffed = 121,
CPED_CONFIG_FLAG_DisableMelee = 122,
_0xFE714397 = 123,
_0xB3E660BD = 124,
_0x5FED6BFD = 125,
_0xC9D6F66F = 126,
_0x519BC986 = 127,
CPED_CONFIG_FLAG_CanBeAgitated = 128,
_0x9A4B617C = 129, // CPED_CONFIG_FLAG_FaceDirInsult
_0xDAB70E9F = 130,
_0xE569438A = 131,
_0xBBC77D6D = 132,
_0xCB59EF0F = 133,
_0x8C5EA971 = 134,
CPED_CONFIG_FLAG_IsScuba = 135,
CPED_CONFIG_FLAG_WillArrestRatherThanJack = 136,
_0xDCE59B58 = 137,
CPED_CONFIG_FLAG_RidingTrain = 138,
CPED_CONFIG_FLAG_ArrestResult = 139,
CPED_CONFIG_FLAG_CanAttackFriendly = 140,
_0x98A4BE43 = 141,
_0x6901E731 = 142,
_0x9EC9BF6C = 143,
_0x42841A8F = 144,
CPED_CONFIG_FLAG_ShootingAnimFlag = 145,
CPED_CONFIG_FLAG_DisableLadderClimbing = 146,
CPED_CONFIG_FLAG_StairsDetected = 147,
CPED_CONFIG_FLAG_SlopeDetected = 148,
_0x1A15670B = 149,
_0x61786EE5 = 150,
_0xCB9186BD = 151,
_0xF0710152 = 152,
_0x43DFE310 = 153,
_0xC43C624E = 154,
CPED_CONFIG_FLAG_CanPerformArrest = 155,
CPED_CONFIG_FLAG_CanPerformUncuff = 156,
CPED_CONFIG_FLAG_CanBeArrested = 157,
_0xF7960FF5 = 158,
_0x59564113 = 159,
_0x0C6C3099 = 160,
_0x645F927A = 161,
_0xA86549B9 = 162,
_0x8AAF337A = 163,
_0x13BAA6E7 = 164,
_0x5FB9D1F5 = 165,
CPED_CONFIG_FLAG_IsInjured = 166,
_0x6398A20B = 167,
_0xD8072639 = 168,
_0xA05B1845 = 169,
_0x83F6D220 = 170,
_0xD8430331 = 171,
_0x4B547520 = 172,
_0xE66E1406 = 173,
_0x1C4BFE0C = 174,
_0x90008BFA = 175,
_0x07C7A910 = 176,
_0xF15F8191 = 177,
_0xCE4E8BE2 = 178,
_0x1D46E4F2 = 179,
CPED_CONFIG_FLAG_IsInCustody = 180,
_0xE4FD9B3A = 181,
_0x67AE0812 = 182,
CPED_CONFIG_FLAG_IsAgitated = 183,
CPED_CONFIG_FLAG_PreventAutoShuffleToDriversSeat = 184,
_0x7B2D325E = 185,
CPED_CONFIG_FLAG_EnableWeaponBlocking = 186,
CPED_CONFIG_FLAG_HasHurtStarted = 187,
CPED_CONFIG_FLAG_DisableHurt = 188,
CPED_CONFIG_FLAG_PlayerIsWeird = 189,
_0x32FC208B = 190,
_0x0C296E5A = 191,
_0xE63B73EC = 192,
_0x04E9CC80 = 193,
CPED_CONFIG_FLAG_UsingScenario = 194,
CPED_CONFIG_FLAG_VisibleOnScreen = 195,
_0xD88C58A1 = 196,
_0x5A3DCF43 = 197, // CPED_CONFIG_FLAG_AvoidUnderSide
_0xEA02B420 = 198,
_0x3F559CFF = 199,
_0x8C55D029 = 200,
_0x5E6466F6 = 201,
_0xEB5AD706 = 202,
_0x0EDDDDE7 = 203,
_0xA64F7B1D = 204,
_0x48532CBA = 205,
_0xAA25A9E7 = 206,
_0x415B26B9 = 207,
CPED_CONFIG_FLAG_DisableExplosionReactions = 208,
CPED_CONFIG_FLAG_DodgedPlayer = 209,
_0x67405504 = 210,
_0x75DDD68C = 211,
_0x2AD879B4 = 212,
_0x51486F91 = 213,
_0x32F79E21 = 214,
_0xBF099213 = 215,
_0x054AC8E2 = 216,
_0x14E495CC = 217,
_0x3C7DF9DF = 218,
_0x848FFEF2 = 219,
CPED_CONFIG_FLAG_DontEnterLeadersVehicle = 220,
_0x2618E1CF = 221,
_0x84F722FA = 222,
_0xD1B87B1F = 223,
_0x728AA918 = 224,
CPED_CONFIG_FLAG_DisablePotentialToBeWalkedIntoResponse = 225,
CPED_CONFIG_FLAG_DisablePedAvoidance = 226,
_0x59E91185 = 227,
_0x1EA7225F = 228,
CPED_CONFIG_FLAG_DisablePanicInVehicle = 229,
_0x6DCA7D88 = 230,
_0xFC3E572D = 231,
_0x08E9F9CF = 232,
_0x2D3BA52D = 233,
_0xFD2F53EA = 234,
_0x31A1B03B = 235,
CPED_CONFIG_FLAG_IsHoldingProp = 236,
_0x82ED0A66 = 237, // CPED_CONFIG_FLAG_BlocksPathingWhenDead
_0xCE57C9A3 = 238,
_0x26149198 = 239,
_0x1B33B598 = 240,
_0x719B6E87 = 241,
_0x13E8E8E8 = 242,
_0xF29739AE = 243,
_0xABEA8A74 = 244,
_0xB60EA2BA = 245,
_0x536B0950 = 246,
_0x0C754ACA = 247,
CPED_CONFIG_FLAG_DisableVehicleSeatRandomAnimations = 248,
_0x12659168 = 249,
_0x1BDF2F04 = 250,
_0x7728FAA3 = 251,
_0x6A807ED8 = 252,
CPED_CONFIG_FLAG_OnStairs = 253,
_0xE1A2F73F = 254,
_0x5B3697C8 = 255,
_0xF1EB20A9 = 256,
_0x8B7DF407 = 257,
_0x329DCF1A = 258,
_0x8D90DD1B = 259,
_0xB8A292B7 = 260,
_0x8374B087 = 261,
_0x2AF558F0 = 262,
_0x82251455 = 263,
_0x30CF498B = 264,
_0xE1CD50AF = 265,
_0x72E4AE48 = 266,
_0xC2657EA1 = 267,
_0x29FF6030 = 268,
_0x8248A5EC = 269,
CPED_CONFIG_FLAG_OnStairSlope = 270,
_0xA0897933 = 271,
CPED_CONFIG_FLAG_DontBlipCop = 272,
CPED_CONFIG_FLAG_ClimbedShiftedFence = 273,
_0xF7823618 = 274,
_0xDC305CCE = 275, // CPED_CONFIG_FLAG_KillWhenTrapped
CPED_CONFIG_FLAG_EdgeDetected = 276,
_0x92B67896 = 277,
_0xCAD677C9 = 278,
CPED_CONFIG_FLAG_AvoidTearGas = 279,
_0x5276AC7B = 280,
_0x1032692A = 281,
_0xDA23E7F1 = 282,
_0x9139724D = 283,
_0xA1457461 = 284,
_0x4186E095 = 285,
_0xAC68E2EB = 286,
CPED_CONFIG_FLAG_RagdollingOnBoat = 287,
CPED_CONFIG_FLAG_HasBrandishedWeapon = 288,
_0x1B9EE8A1 = 289,
_0xF3F5758C = 290,
_0x2A9307F1 = 291,
_0x7403D216 = 292,
_0xA06A3C6C = 293,
CPED_CONFIG_FLAG_DisableShockingEvents = 294,
_0xF8DA25A5 = 295,
_0x7EF55802 = 296,
_0xB31F1187 = 297,
_0x84315402 = 298,
_0x0FD69867 = 299,
_0xC7829B67 = 300,
CPED_CONFIG_FLAG_DisablePedConstraints = 301,
_0x6D23CF25 = 302,
_0x2ADA871B = 303,
_0x47BC8A58 = 304,
_0xEB692FA5 = 305,
_0x4A133C50 = 306,
_0xC58099C3 = 307,
_0xF3D76D41 = 308,
_0xB0EEE9F2 = 309,
CPED_CONFIG_FLAG_IsInCluster = 310,
_0x0FA153EF = 311,
_0xD73F5CD3 = 312,
_0xD4136C22 = 313,
_0xE404CA6B = 314,
_0xB9597446 = 315,
_0xD5C98277 = 316,
_0xD5060A9C = 317,
_0x3E5F1CBB = 318,
_0xD8BE1D54 = 319,
_0x0B1F191F = 320,
_0xC995167A = 321,
CPED_CONFIG_FLAG_HasHighHeels = 322,
_0x86B01E54 = 323,
_0x3A56FE15 = 324,
_0xC03B736C = 325, // CPED_CONFIG_FLAG_SpawnedAtScenario
_0xBBF47729 = 326,
_0x22B668A8 = 327,
_0x2624D4D4 = 328,
CPED_CONFIG_FLAG_DisableTalkTo = 329,
CPED_CONFIG_FLAG_DontBlip = 330,
CPED_CONFIG_FLAG_IsSwitchingWeapon = 331,
_0x630F55F3 = 332,
_0x150468FD = 333,
_0x914EBD6B = 334,
_0x79AF3B6D = 335,
_0x75C7A632 = 336,
_0x52D530E2 = 337,
_0xDB2A90E0 = 338,
_0x5922763D = 339,
_0x12ADB567 = 340,
_0x105C8518 = 341,
_0x106F703D = 342,
_0xED152C3E = 343,
_0xA0EFE6A8 = 344,
_0xBF348C82 = 345,
_0xCDDFE830 = 346,
_0x7B59BD9B = 347,
_0x0124C788 = 348,
CPED_CONFIG_FLAG_EquipJetpack = 349,
_0x08D361A5 = 350,
_0xE13D1F7C = 351,
_0x40E25FB9 = 352,
_0x930629D9 = 353,
_0xECCF0C7F = 354,
_0xB6E9613B = 355,
_0x490C0478 = 356,
_0xE8865BEA = 357,
_0xF3C34A29 = 358,
CPED_CONFIG_FLAG_IsDuckingInVehicle = 359,
_0xF660E115 = 360,
_0xAB0E6DED = 361,
CPED_CONFIG_FLAG_HasReserveParachute = 362,
CPED_CONFIG_FLAG_UseReserveParachute = 363,
_0x5C5D9CD3 = 364,
_0x8F7701F3 = 365,
_0xBC4436AD = 366,
_0xD7E07D37 = 367,
_0x03C4FD24 = 368,
_0x7675789A = 369,
_0xB7288A88 = 370,
_0xC06B6291 = 371,
_0x95A4A805 = 372,
_0xA8E9A042 = 373,
CPED_CONFIG_FLAG_NeverLeaveTrain = 374,
_0xBAC674B3 = 375,
_0x147F1FFB = 376,
_0x4376DD79 = 377,
_0xCD3DB518 = 378,
_0xFE4BA4B6 = 379,
_0x5DF03A55 = 380,
_0xBCD816CD = 381,
_0xCF02DD69 = 382,
_0xF73AFA2E = 383,
_0x80B9A9D0 = 384,
_0xF601F7EE = 385,
_0xA91350FC = 386,
_0x3AB23B96 = 387,
CPED_CONFIG_FLAG_IsClimbingLadder = 388,
CPED_CONFIG_FLAG_HasBareFeet = 389,
_0xB4B1CD4C = 390,
_0x5459AFB8 = 391,
_0x54F27667 = 392,
_0xC11D3E8F = 393,
_0x5419EB3E = 394,
_0x82D8DBB4 = 395,
_0x33B02D2F = 396,
_0xAE66176D = 397,
_0xA2692593 = 398,
_0x714C7E31 = 399,
_0xEC488AC7 = 400,
_0xAE398504 = 401,
_0xABC58D72 = 402,
_0x5E5B9591 = 403,
_0x6BA1091E = 404,
_0x77840177 = 405,
_0x1C7ACAC4 = 406,
_0x124420E9 = 407,
_0x75A65587 = 408,
_0xDFD2D55B = 409,
_0xBDD39919 = 410,
_0x43DEC267 = 411,
_0xE42B7797 = 412,
CPED_CONFIG_FLAG_IsHolsteringWeapon = 413,
_0x4F8149F5 = 414,
_0xDD9ECA7A = 415,
_0x9E7EF9D2 = 416,
_0x2C6ED942 = 417,
CPED_CONFIG_FLAG_IsSwitchingHelmetVisor = 418,
_0xA488727D = 419,
_0xCFF5F6DE = 420,
_0x6D614599 = 421,
CPED_CONFIG_FLAG_DisableVehicleCombat = 422,
_0xFE401D26 = 423,
CPED_CONFIG_FLAG_FallsLikeAircraft = 424,
_0x2B42AE82 = 425,
_0x7A95734F = 426,
_0xDF4D8617 = 427,
_0x578F1F14 = 428,
CPED_CONFIG_FLAG_DisableStartEngine = 429,
CPED_CONFIG_FLAG_IgnoreBeingOnFire = 430,
_0x153C9500 = 431,
_0xCB7A632E = 432,
_0xDE727981 = 433,
CPED_CONFIG_FLAG_DisableHomingMissileLockon = 434,
_0x12BBB935 = 435,
_0xAD0A1277 = 436,
_0xEA6AA46A = 437,
CPED_CONFIG_FLAG_DisableHelmetArmor = 438,
_0xCB7F3A1E = 439,
_0x50178878 = 440,
_0x051B4F0D = 441,
_0x2FC3DECC = 442,
_0xC0030B0B = 443,
_0xBBDAF1E9 = 444,
_0x944FE59C = 445,
_0x506FBA39 = 446,
_0xDD45FE84 = 447,
_0xE698AE75 = 448,
_0x199633F8 = 449,
CPED_CONFIG_FLAG_PedIsArresting = 450,
CPED_CONFIG_FLAG_IsDecoyPed = 451,
_0x3A251D83 = 452,
_0xA56F6986 = 453,
_0x1D19C622 = 454,
_0xB68D3EAB = 455,
CPED_CONFIG_FLAG_CanBeIncapacitated = 456,
_0x4BD5EBAD = 457,
}
}

View File

@ -0,0 +1,390 @@
using System;
using System.IO;
using System.Xml.Serialization;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using RageCoop.Core;
using GTA;
using GTA.Native;
using GTA.Math;
using System.Linq;
using System.Diagnostics;
namespace RageCoop.Client
{
internal static partial class PedExtensions
{
public static bool IsBetween<T>(this T item, T start, T end)
{
return Comparer<T>.Default.Compare(item, start) >= 0 && Comparer<T>.Default.Compare(item, end) <= 0;
}
public static bool Compare<T, Y>(this Dictionary<T, Y> item, Dictionary<T, Y> item2)
{
if (item == null || item2 == null || item.Count != item2.Count)
{
return false;
}
foreach (KeyValuePair<T, Y> pair in item)
{
if (item2.TryGetValue(pair.Key, out Y value) && Equals(value, pair.Value))
{
continue;
}
// TryGetValue() or Equals failed
return false;
}
// No difference between item and item2
return true;
}
#region PED
public static byte GetPedSpeed(this Ped ped)
{
if (ped.IsSprinting)
{
return 3;
}
if (ped.IsRunning)
{
return 2;
}
if (ped.IsWalking)
{
return 1;
}
return 0;
}
public static Dictionary<byte, short> GetPedClothes(this Ped ped)
{
Dictionary<byte, short> result = new Dictionary<byte, short>();
for (byte i = 0; i < 11; i++)
{
short mod = Function.Call<short>(Hash.GET_PED_DRAWABLE_VARIATION, ped.Handle, i);
result.Add(i, mod);
}
return result;
}
public static PedDataFlags GetPedFlags(this Ped ped)
{
PedDataFlags flags = PedDataFlags.None;
if (ped.IsAiming || ped.IsOnTurretSeat())
{
flags |= PedDataFlags.IsAiming;
}
if (ped.IsReloading)
{
flags |= PedDataFlags.IsReloading;
}
if (ped.IsJumping)
{
flags |= PedDataFlags.IsJumping;
}
// Fake death
if (ped.IsRagdoll || (ped.Health==1 && ped.IsPlayer))
{
flags |= PedDataFlags.IsRagdoll;
}
if (ped.IsOnFire)
{
flags |= PedDataFlags.IsOnFire;
}
if (ped.IsInParachuteFreeFall)
{
flags |= PedDataFlags.IsInParachuteFreeFall;
}
if (ped.ParachuteState == ParachuteState.Gliding)
{
flags |= PedDataFlags.IsParachuteOpen;
}
bool climbingLadder = ped.IsTaskActive(TaskType.CTaskGoToAndClimbLadder);
if (climbingLadder)
{
flags |= PedDataFlags.IsOnLadder;
}
if (ped.IsVaulting && !climbingLadder)
{
flags |= PedDataFlags.IsVaulting;
}
if (ped.IsInCover || ped.IsGoingIntoCover)
{
flags |=PedDataFlags.IsInCover;
}
return flags;
}
public static string[] GetReloadingAnimation(this Ped ped)
{
switch (ped.Weapons.Current.Hash)
{
case WeaponHash.Revolver:
case WeaponHash.RevolverMk2:
case WeaponHash.DoubleActionRevolver:
case WeaponHash.NavyRevolver:
return new string[2] { "anim@weapons@pistol@revolver_str", "reload_aim" };
case WeaponHash.APPistol:
return new string[2] { "weapons@pistol@ap_pistol_str", "reload_aim" };
case WeaponHash.Pistol50:
return new string[2] { "weapons@pistol@pistol_50_str", "reload_aim" };
case WeaponHash.Pistol:
case WeaponHash.PistolMk2:
case WeaponHash.PericoPistol:
case WeaponHash.SNSPistol:
case WeaponHash.SNSPistolMk2:
case WeaponHash.HeavyPistol:
case WeaponHash.VintagePistol:
case WeaponHash.CeramicPistol:
case WeaponHash.MachinePistol:
return new string[2] { "weapons@pistol@pistol_str", "reload_aim" };
case WeaponHash.AssaultRifle:
case WeaponHash.AssaultrifleMk2:
return new string[2] { "weapons@rifle@hi@assault_rifle_str", "reload_aim" };
case WeaponHash.SniperRifle:
return new string[2] { "weapons@rifle@hi@sniper_rifle_str", "reload_aim" };
case WeaponHash.HeavySniper:
case WeaponHash.HeavySniperMk2:
return new string[2] { "weapons@rifle@lo@sniper_heavy_str", "reload_aim" };
case WeaponHash.PumpShotgun:
case WeaponHash.PumpShotgunMk2:
return new string[2] { "weapons@rifle@pump_str", "reload_aim" };
case WeaponHash.Railgun:
return new string[2] { "weapons@rifle@lo@rail_gun_str", "reload_aim" };
case WeaponHash.SawnOffShotgun:
return new string[2] { "weapons@rifle@lo@sawnoff_str", "reload_aim" };
case WeaponHash.AssaultShotgun:
return new string[2] { "weapons@rifle@lo@shotgun_assault_str", "reload_aim" };
case WeaponHash.BullpupShotgun:
return new string[2] { "weapons@rifle@lo@shotgun_bullpup_str", "reload_aim" };
case WeaponHash.AdvancedRifle:
return new string[2] { "weapons@submg@advanced_rifle_str", "reload_aim" };
case WeaponHash.CarbineRifle:
case WeaponHash.CarbineRifleMk2:
case WeaponHash.CompactRifle:
return new string[2] { "weapons@rifle@lo@carbine_str", "reload_aim" };
case WeaponHash.Gusenberg:
return new string[2] { "anim@weapons@machinegun@gusenberg_str", "reload_aim" };
case WeaponHash.Musket:
return new string[2] { "anim@weapons@musket@musket_str", "reload_aim" };
case WeaponHash.FlareGun:
return new string[2] { "anim@weapons@pistol@flare_str", "reload_aim" };
case WeaponHash.SpecialCarbine:
case WeaponHash.SpecialCarbineMk2:
return new string[2] { "anim@weapons@rifle@lo@spcarbine_str", "reload_aim" };
case WeaponHash.CombatPDW:
return new string[2] { "anim@weapons@rifle@lo@pdw_str", "reload_aim" };
case WeaponHash.BullpupRifle:
case WeaponHash.BullpupRifleMk2:
return new string[2] { "anim@weapons@submg@bullpup_rifle_str", "reload_aim" };
case WeaponHash.AssaultSMG:
return new string[2] { "weapons@submg@assault_smg_str", "reload_aim" };
case WeaponHash.MicroSMG:
case WeaponHash.MiniSMG:
return new string[2] { "weapons@submg@lo@micro_smg_str", "reload_aim" };
case WeaponHash.SMG:
case WeaponHash.SMGMk2:
return new string[2] { "weapons@rifle@smg_str", "reload_aim" };
case WeaponHash.GrenadeLauncher:
case WeaponHash.GrenadeLauncherSmoke:
case WeaponHash.CompactGrenadeLauncher:
return new string[2] { "weapons@heavy@grenade_launcher_str", "reload_aim" };
case WeaponHash.RPG:
case WeaponHash.Firework:
return new string[2] { "weapons@heavy@rpg_str", "reload_aim" };
case WeaponHash.CombatMG:
case WeaponHash.CombatMGMk2:
return new string[2] { "weapons@machinegun@combat_mg_str", "reload_aim" };
case WeaponHash.MG:
return new string[2] { "weapons@machinegun@mg_str", "reload_aim" };
default:
Main.Logger.Warning($"~r~Reloading failed! Weapon ~g~[{ped.Weapons.Current.Hash}]~r~ could not be found!");
return null;
}
}
public static VehicleSeat GetNearestSeat(this Ped ped, Vehicle veh, float distanceToignoreDoors = 50f)
{
float num = 99f;
int result = -2;
Dictionary<string, int> dictionary = new Dictionary<string, int>();
dictionary.Add("door_dside_f", -1);
dictionary.Add("door_pside_f", 0);
dictionary.Add("door_dside_r", 1);
dictionary.Add("door_pside_r", 2);
foreach (string text in dictionary.Keys)
{
bool flag = veh.Bones[text].Position != Vector3.Zero;
if (flag)
{
float num2 = ped.Position.DistanceTo(Function.Call<Vector3>(Hash.GET_WORLD_POSITION_OF_ENTITY_BONE, new InputArgument[]
{
veh,
veh.Bones[text].Index
}));
bool flag2 = (num2 < distanceToignoreDoors) && (num2 < num)&& IsSeatUsableByPed(ped, veh, dictionary[text]);
if (flag2)
{
num = num2;
result = dictionary[text];
}
}
}
return (VehicleSeat)result;
}
public static bool IsSeatUsableByPed(Ped ped, Vehicle veh, int _seat)
{
VehicleSeat seat = (VehicleSeat)_seat;
bool result = false;
bool flag = veh.IsSeatFree(seat);
if (flag)
{
result = true;
}
else
{
bool isDead = veh.GetPedOnSeat(seat).IsDead;
if (isDead)
{
result = true;
}
else
{
int num = Function.Call<int>(Hash.GET_RELATIONSHIP_BETWEEN_PEDS, new InputArgument[]
{
ped,
veh.GetPedOnSeat(seat)
});
bool flag2 = num > 2;
if (flag2)
{
result = true;
}
}
}
return result;
}
public static bool IsTaskActive(this Ped p,TaskType task)
{
return Function.Call<bool>(Hash.GET_IS_TASK_ACTIVE, p.Handle, task);
}
public static Vector3 GetAimCoord(this Ped p)
{
var weapon = p.Weapons.CurrentWeaponObject;
var v = p.CurrentVehicle;
// Rhino
if (v!=null && v.Model.Hash==782665360)
{
return v.Bones[35].Position+v.Bones[35].ForwardVector*100;
}
if (p.IsOnTurretSeat()) { return p.GetLookingCoord(); }
if (weapon!=null)
{
// Not very accurate, but doesn't matter
Vector3 dir = weapon.RightVector;
return weapon.Position+dir*20;
}
return GetLookingCoord(p);
}
public static Vector3 GetLookingCoord(this Ped p)
{
EntityBone b = p.Bones[Bone.FacialForehead];
Vector3 v = b.UpVector.Normalized;
return b.Position+200*v;
}
public static void StayInCover(this Ped p)
{
Function.Call(Hash.TASK_STAY_IN_COVER, p);
}
public static VehicleSeat GetSeatTryingToEnter(this Ped p)
{
return (VehicleSeat)Function.Call<int>(Hash.GET_SEAT_PED_IS_TRYING_TO_ENTER, p);
}
#endregion
public static bool IsTurretSeat(this Vehicle veh, int seat)
{
if (!Function.Call<bool>(Hash.DOES_VEHICLE_HAVE_WEAPONS, veh.Handle))
{
return false;
}
switch (seat)
{
case -1:
return (VehicleHash)veh.Model.Hash == VehicleHash.Rhino
|| (VehicleHash)veh.Model.Hash == VehicleHash.Khanjari
|| (VehicleHash)veh.Model.Hash == VehicleHash.FireTruck
|| (VehicleHash)veh.Model.Hash == VehicleHash.Riot2
|| (VehicleHash)veh.Model.Hash == VehicleHash.Cerberus
|| (VehicleHash)veh.Model.Hash == VehicleHash.Cerberus2
|| (VehicleHash)veh.Model.Hash == VehicleHash.Cerberus3;
case 0:
return (VehicleHash)veh.Model.Hash == VehicleHash.Apc;
case 1:
return (VehicleHash)veh.Model.Hash == VehicleHash.Valkyrie
|| (VehicleHash)veh.Model.Hash == VehicleHash.Valkyrie2
|| (VehicleHash)veh.Model.Hash == VehicleHash.Technical
|| (VehicleHash)veh.Model.Hash == VehicleHash.Technical2
|| (VehicleHash)veh.Model.Hash == VehicleHash.Technical3
|| (VehicleHash)veh.Model.Hash == VehicleHash.HalfTrack
|| (VehicleHash)veh.Model.Hash == VehicleHash.Barrage;
case 2:
return (VehicleHash)veh.Model.Hash == VehicleHash.Valkyrie
|| (VehicleHash)veh.Model.Hash == VehicleHash.Valkyrie2
|| (VehicleHash)veh.Model.Hash == VehicleHash.Barrage;
case 3:
return (VehicleHash)veh.Model.Hash == VehicleHash.Limo2
|| (VehicleHash)veh.Model.Hash == VehicleHash.Dinghy5;
case 7:
return (VehicleHash)veh.Model.Hash == VehicleHash.Insurgent;
}
return false;
}
public static bool IsOnTurretSeat(this Ped P)
{
if (P.CurrentVehicle == null) { return false; }
return IsTurretSeat(P.CurrentVehicle, (int)P.SeatIndex);
}
}
}

200
Client/Util/Util.cs Normal file
View File

@ -0,0 +1,200 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GTA.Math;
using GTA;
using GTA.Native;
using System.IO;
using System.Xml.Serialization;
using System.Runtime.InteropServices;
namespace RageCoop.Client
{
internal static class Util
{
#region -- POINTER --
private static int _steeringAngleOffset { get; set; }
public static unsafe void NativeMemory()
{
IntPtr address;
address = Game.FindPattern("\x74\x0A\xF3\x0F\x11\xB3\x1C\x09\x00\x00\xEB\x25", "xxxxxx????xx");
if (address != IntPtr.Zero)
{
_steeringAngleOffset = *(int*)(address + 6) + 8;
}
// breaks some stuff.
/*
address = Game.FindPattern("\x32\xc0\xf3\x0f\x11\x09", "xxxxxx"); // Weapon / Radio slowdown
if (address != IntPtr.Zero)
{
for (int i = 0; i < 6; i++)
{
*(byte*)(address + i).ToPointer() = 0x90;
}
}
*/
}
public static unsafe void CustomSteeringAngle(this Vehicle veh, float value)
{
IntPtr address = new IntPtr((long)veh.MemoryAddress);
if (address == IntPtr.Zero || _steeringAngleOffset == 0)
{
return;
}
*(float*)(address + _steeringAngleOffset).ToPointer() = value;
}
#endregion
#region MATH
public static Vector3 LinearVectorLerp(Vector3 start, Vector3 end, ulong currentTime, int duration)
{
return new Vector3()
{
X = LinearFloatLerp(start.X, end.X, currentTime, duration),
Y = LinearFloatLerp(start.Y, end.Y, currentTime, duration),
Z = LinearFloatLerp(start.Z, end.Z, currentTime, duration),
};
}
public static float LinearFloatLerp(float start, float end, ulong currentTime, int duration)
{
return (end - start) * currentTime / duration + start;
}
public static float Lerp(float from, float to, float fAlpha)
{
return (from * (1.0f - fAlpha)) + (to * fAlpha); //from + (to - from) * fAlpha
}
public static Vector3 RotationToDirection(Vector3 rotation)
{
double z = MathExtensions.DegToRad(rotation.Z);
double x = MathExtensions.DegToRad(rotation.X);
double num = Math.Abs(Math.Cos(x));
return new Vector3
{
X = (float)(-Math.Sin(z) * num),
Y = (float)(Math.Cos(z) * num),
Z = (float)Math.Sin(x)
};
}
#endregion
public static Settings ReadSettings()
{
XmlSerializer ser = new XmlSerializer(typeof(Settings));
string path = Directory.GetCurrentDirectory() + "\\Scripts\\RageCoop\\RageCoop.Client.Settings.xml";
Settings settings = null;
if (File.Exists(path))
{
using (FileStream stream = File.OpenRead(path))
{
settings = (RageCoop.Client.Settings)ser.Deserialize(stream);
}
using (FileStream stream = new FileStream(path, FileMode.Truncate, FileAccess.ReadWrite))
{
ser.Serialize(stream, settings);
}
}
else
{
using (FileStream stream = File.OpenWrite(path))
{
ser.Serialize(stream, settings = new Settings());
}
}
return settings;
}
public static void SaveSettings()
{
try
{
string path = Directory.GetCurrentDirectory() + "\\Scripts\\RageCoop\\RageCoop.Client.Settings.xml";
using (FileStream stream = new FileStream(path, File.Exists(path) ? FileMode.Truncate : FileMode.Create, FileAccess.ReadWrite))
{
XmlSerializer ser = new XmlSerializer(typeof(Settings));
ser.Serialize(stream, Main.Settings);
}
}
catch (Exception ex)
{
GTA.UI.Notification.Show("Error saving player settings: " + ex.Message);
}
}
[DllImport("kernel32.dll")]
public static extern ulong GetTickCount64();
public static Vector3 PredictPosition(this Entity e, bool applyDefault = true)
{
return e.Position+e.Velocity*((applyDefault ? SyncParameters.PositioinPredictionDefault : 0)+Networking.Latency);
}
public static Model ModelRequest(this int hash)
{
Model model = new Model(hash);
if (!model.IsValid)
{
//GTA.UI.Notification.Show("~y~Not valid!");
return null;
}
if (!model.IsLoaded)
{
return model.Request(1000) ? model : null;
}
return model;
}
public static void SetOnFire(this Entity e, bool toggle)
{
if (toggle)
{
Function.Call(Hash.START_ENTITY_FIRE, e.Handle);
}
else
{
Function.Call(Hash.STOP_ENTITY_FIRE, e.Handle);
}
}
public static SyncedPed GetSyncEntity(this Ped p)
{
if (p == null) { return null; }
var c = EntityPool.GetPedByHandle(p.Handle);
if (c==null) { EntityPool.Add(c=new SyncedPed(p)); }
return c;
}
public static SyncedVehicle GetSyncEntity(this Vehicle veh)
{
if (veh == null) { return null; }
var v = EntityPool.GetVehicleByHandle(veh.Handle);
if (v==null) { EntityPool.Add(v=new SyncedVehicle(veh)); }
return v;
}
public static byte GetPlayerRadioIndex()
{
return (byte)Function.Call<int>(Hash.GET_PLAYER_RADIO_STATION_INDEX);
}
public static void SetPlayerRadioIndex(int index)
{
Function.Call(Hash.SET_RADIO_TO_STATION_INDEX, index);
}
}
}

View File

@ -0,0 +1,293 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GTA;
using GTA.Native;
using RageCoop.Core;
using GTA.Math;
namespace RageCoop.Client
{
internal static class VehicleExtensions
{
#region VEHICLE
public static VehicleDataFlags GetVehicleFlags(this Vehicle veh)
{
VehicleDataFlags flags = 0;
if (veh.IsEngineRunning)
{
flags |= VehicleDataFlags.IsEngineRunning;
}
if (veh.AreLightsOn)
{
flags |= VehicleDataFlags.AreLightsOn;
}
if (veh.BrakePower >= 0.01f)
{
flags |= VehicleDataFlags.AreBrakeLightsOn;
}
if (veh.AreHighBeamsOn)
{
flags |= VehicleDataFlags.AreHighBeamsOn;
}
if (veh.IsSirenActive)
{
flags |= VehicleDataFlags.IsSirenActive;
}
if (veh.IsDead)
{
flags |= VehicleDataFlags.IsDead;
}
if (Function.Call<bool>(Hash.IS_HORN_ACTIVE, veh.Handle))
{
flags |= VehicleDataFlags.IsHornActive;
}
if (veh.IsSubmarineCar && Function.Call<bool>(Hash._GET_IS_SUBMARINE_VEHICLE_TRANSFORMED, veh.Handle))
{
flags |= VehicleDataFlags.IsTransformed;
}
if (veh.HasRoof && (veh.RoofState == VehicleRoofState.Opened || veh.RoofState == VehicleRoofState.Opening))
{
flags |= VehicleDataFlags.RoofOpened;
}
if (veh.IsAircraft)
{
flags |= VehicleDataFlags.IsAircraft;
}
if (veh.Model.Hash==1483171323 && veh.IsDeluxoHovering())
{
flags|= VehicleDataFlags.IsDeluxoHovering;
}
return flags;
}
public static bool HasFlag(this PedDataFlags flagToCheck, PedDataFlags flag)
{
return (flagToCheck & flag)!=0;
}
public static bool HasFlag(this VehicleDataFlags flagToCheck, VehicleDataFlags flag)
{
return (flagToCheck & flag)!=0;
}
public static Dictionary<uint, bool> GetWeaponComponents(this Weapon weapon)
{
Dictionary<uint, bool> result = null;
if (weapon.Components.Count > 0)
{
result = new Dictionary<uint, bool>();
foreach (var comp in weapon.Components)
{
result.Add((uint)comp.ComponentHash, comp.Active);
}
}
return result;
}
public static Dictionary<int, int> GetVehicleMods(this VehicleModCollection mods)
{
Dictionary<int, int> result = new Dictionary<int, int>();
foreach (VehicleMod mod in mods.ToArray())
{
result.Add((int)mod.Type, mod.Index);
}
return result;
}
public static VehicleDamageModel GetVehicleDamageModel(this Vehicle veh)
{
// Broken windows
byte brokenWindows = 0;
for (int i = 0; i < 8; i++)
{
if (!veh.Windows[(VehicleWindowIndex)i].IsIntact)
{
brokenWindows |= (byte)(1 << i);
}
}
// Broken doors
byte brokenDoors = 0;
byte openedDoors = 0;
foreach (VehicleDoor door in veh.Doors)
{
if (door.IsBroken)
{
brokenDoors |= (byte)(1 << (byte)door.Index);
}
else if (door.IsOpen)
{
openedDoors |= (byte)(1 << (byte)door.Index);
}
}
// Bursted tires
short burstedTires = 0;
foreach (VehicleWheel wheel in veh.Wheels.GetAllWheels())
{
if (wheel.IsBursted)
{
burstedTires |= (short)(1 << (int)wheel.BoneId);
}
}
return new VehicleDamageModel()
{
BrokenDoors = brokenDoors,
OpenedDoors = openedDoors,
BrokenWindows = brokenWindows,
BurstedTires = burstedTires,
LeftHeadLightBroken = (byte)(veh.IsLeftHeadLightBroken ? 1 : 0),
RightHeadLightBroken = (byte)(veh.IsRightHeadLightBroken ? 1 : 0)
};
}
public static Dictionary<int, int> GetPassengers(this Vehicle veh)
{
Dictionary<int, int> ps = new Dictionary<int, int>();
var d = veh.Driver;
if (d!=null&&d.IsSittingInVehicle())
{
ps.Add(-1, d.GetSyncEntity().ID);
}
foreach (Ped p in veh.Passengers)
{
if (p.IsSittingInVehicle())
{
ps.Add((int)p.SeatIndex, (int)p.GetSyncEntity().ID);
}
}
return ps;
}
public static void SetDeluxoHoverState(this Vehicle deluxo, bool hover)
{
Function.Call(Hash._SET_VEHICLE_HOVER_TRANSFORM_PERCENTAGE, deluxo, hover ? 1f : 0f);
}
public static bool IsDeluxoHovering(this Vehicle deluxo)
{
return Math.Abs(deluxo.Bones[27].ForwardVector.GetCosTheta(deluxo.ForwardVector)-1)>0.05;
}
public static void SetDeluxoWingRatio(this Vehicle v, float ratio)
{
Function.Call(Hash._SET_SPECIALFLIGHT_WING_RATIO, v, ratio);
}
public static float GetDeluxoWingRatio(this Vehicle v)
{
return v.Bones[99].Position.DistanceTo(v.Bones[92].Position)-1.43f;
}
public static float GetNozzleAngel(this Vehicle plane)
{
return Function.Call<float>(Hash._GET_VEHICLE_FLIGHT_NOZZLE_POSITION, plane);
}
public static bool HasNozzle(this Vehicle v)
{
switch (v.Model.Hash)
{
// Hydra
case 970385471:
return true;
// Avenger
case -2118308144:
return true;
// Tula
case 1043222410:
return true;
// Avenger
case 408970549:
return true;
}
return false;
}
public static void SetNozzleAngel(this Vehicle plane, float ratio)
{
Function.Call(Hash.SET_VEHICLE_FLIGHT_NOZZLE_POSITION, plane, ratio);
}
public static void SetDamageModel(this Vehicle veh, VehicleDamageModel model, bool leavedoors = true)
{
for (int i = 0; i < 8; i++)
{
var door = veh.Doors[(VehicleDoorIndex)i];
if ((model.BrokenDoors & (byte)(1 << i)) != 0)
{
door.Break(leavedoors);
}
else if (door.IsBroken)
{
// The vehicle can only fix a door if the vehicle was completely fixed
veh.Repair();
return;
}
if ((model.OpenedDoors & (byte)(1 << i)) != 0)
{
if ((!door.IsOpen)&&(!door.IsBroken))
{
door.Open();
}
}
else if (door.IsOpen)
{
if (!door.IsBroken) { door.Close(); }
}
if ((model.BrokenWindows & (byte)(1 << i)) != 0)
{
veh.Windows[(VehicleWindowIndex)i].Smash();
}
else if (!veh.Windows[(VehicleWindowIndex)i].IsIntact)
{
veh.Windows[(VehicleWindowIndex)i].Repair();
}
}
foreach (VehicleWheel wheel in veh.Wheels)
{
if ((model.BurstedTires & (short)(1 << (int)wheel.BoneId)) != 0)
{
if (!wheel.IsBursted)
{
wheel.Puncture();
wheel.Burst();
}
}
else if (wheel.IsBursted)
{
wheel.Fix();
}
}
veh.IsLeftHeadLightBroken = model.LeftHeadLightBroken > 0;
veh.IsRightHeadLightBroken = model.RightHeadLightBroken > 0;
}
#endregion
}
}

View File

@ -31,29 +31,85 @@ namespace RageCoop.Client
} }
return p.Bones[Bone.SkelRightHand].Position; return p.Bones[Bone.SkelRightHand].Position;
} }
static long BulletsShot=0;
public static MuzzleInfo GetMuzzleInfo(this Vehicle v) public static MuzzleInfo GetMuzzleInfo(this Vehicle v)
{ {
BulletsShot++;
int i; int i;
switch (v.Model.Hash) switch (v.Model.Hash)
{ {
// SCRAMJET
case -638562243:
i=BulletsShot%2==0 ? 44 : 45;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
// VIGILANTE
case -1242608589:
i=BulletsShot%2==0 ? 42 : 43;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
// ZR380
case 540101442:
i=BulletsShot%2==0 ? 57 : 63;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
// ZR3802
case -1106120762:
i=BulletsShot%2==0 ? 57 : 63;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
// ZR3803
case -1478704292:
i=BulletsShot%2==0 ? 53 : 59;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
// STROMBERG
case 886810209:
i=BulletsShot%2==0 ? 85 : 84;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
// SLAMVAN4
case -2061049099:
i=BulletsShot%2==0 ? 76 : 78;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
// IMPERATOR
case 444994115:
i=BulletsShot%2==0 ? 88 : 86;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
// IMPALER2
case 1009171724:
i=BulletsShot%2==0 ? 63 : 64;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
// DOMINATOR4
case -688189648:
i=BulletsShot%2==0 ? 59 : 60;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
// SAVAGE
case -82626025:
return new MuzzleInfo(v.Bones[30].Position, v.Bones[30].ForwardVector);
// BUZZARD // BUZZARD
case 788747387: case 788747387:
i=Main.Ticked%2==0 ? 28 : 23; i=BulletsShot%2==0 ? 28 : 23;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector); return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
// ANNIHL // ANNIHL
case 837858166: case 837858166:
i=(int)Main.Ticked%4+35; i=(int)BulletsShot%4+35;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector); return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
// HYDRA // HYDRA
case 970385471: case 970385471:
i=Main.Ticked%2==0 ? 29 : 28; i=BulletsShot%2==0 ? 29 : 28;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector); return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
// STARLING // STARLING
case -1700874274: case -1700874274:
i=Main.Ticked%2==0 ? 24 : 12; i=BulletsShot%2==0 ? 24 : 12;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector); return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
// RHINO // RHINO
@ -79,24 +135,6 @@ namespace RageCoop.Client
} }
} }
public static int GetDamage(this Weapon w)
{
int damage = 0;
switch (w.Group)
{
case WeaponGroup.AssaultRifle: damage=30; break;
case WeaponGroup.Heavy: damage=30; break;
case WeaponGroup.MG: damage=30; break;
case WeaponGroup.PetrolCan: damage=0; break;
case WeaponGroup.Pistol: damage=30; break;
case WeaponGroup.Shotgun: damage=30; break;
case WeaponGroup.SMG: damage=20; break;
case WeaponGroup.Sniper: damage=100; break;
case WeaponGroup.Thrown: damage=0; break;
case WeaponGroup.Unarmed: damage=0; break;
}
return damage;
}
public static readonly Dictionary<WeaponHash, int> MuzzleBoneIndexes = new Dictionary<WeaponHash, int> public static readonly Dictionary<WeaponHash, int> MuzzleBoneIndexes = new Dictionary<WeaponHash, int>
{ {
{WeaponHash.HeavySniper,6}, {WeaponHash.HeavySniper,6},
@ -181,6 +219,8 @@ namespace RageCoop.Client
VehicleWeaponHash.PlaneRocket, VehicleWeaponHash.PlaneRocket,
VehicleWeaponHash.SpaceRocket, VehicleWeaponHash.SpaceRocket,
VehicleWeaponHash.Tank, VehicleWeaponHash.Tank,
(VehicleWeaponHash)3565779982, // STROMBERG missiles
(VehicleWeaponHash)3169388763, // SCRAMJET missiles
}; };
} }
} }

View File

@ -49,7 +49,7 @@ namespace RageCoop.Client
// Values of 2.0 or more make for very aggressive waves like you see during a thunderstorm. // Values of 2.0 or more make for very aggressive waves like you see during a thunderstorm.
Function.Call(Hash.SET_DEEP_OCEAN_SCALER, 0.0f); // Works only ~200 meters around the player Function.Call(Hash.SET_DEEP_OCEAN_SCALER, 0.0f); // Works only ~200 meters around the player
Function.Call(Hash.SET_CAN_ATTACK_FRIENDLY, Game.Player.Character.Handle, true, false); // Function.Call(Hash.SET_CAN_ATTACK_FRIENDLY, Game.Player.Character.Handle, true, false);
if (Main.Settings==null) { return; } if (Main.Settings==null) { return; }
if (Main.Settings.DisableTraffic) if (Main.Settings.DisableTraffic)
{ {
@ -99,8 +99,8 @@ namespace RageCoop.Client
Function.Call(Hash.SET_RANDOM_BOATS, false); Function.Call(Hash.SET_RANDOM_BOATS, false);
Function.Call(Hash.SET_GARBAGE_TRUCKS, false); Function.Call(Hash.SET_GARBAGE_TRUCKS, false);
Function.Call(Hash.DELETE_ALL_TRAINS); Function.Call(Hash.DELETE_ALL_TRAINS);
Function.Call(Hash.SET_PED_POPULATION_BUDGET, 0); Function.Call(Hash.SET_PED_POPULATION_BUDGET, 3);
Function.Call(Hash.SET_VEHICLE_POPULATION_BUDGET, 0); Function.Call(Hash.SET_VEHICLE_POPULATION_BUDGET, 3);
Function.Call(Hash.SET_ALL_LOW_PRIORITY_VEHICLE_GENERATORS_ACTIVE, false); Function.Call(Hash.SET_ALL_LOW_PRIORITY_VEHICLE_GENERATORS_ACTIVE, false);
Function.Call(Hash.SET_FAR_DRAW_VEHICLES, false); Function.Call(Hash.SET_FAR_DRAW_VEHICLES, false);
Function.Call(Hash.SET_NUMBER_OF_PARKED_VEHICLES, 0); Function.Call(Hash.SET_NUMBER_OF_PARKED_VEHICLES, 0);
@ -126,6 +126,11 @@ namespace RageCoop.Client
foreach (Vehicle veh in World.GetAllVehicles()) foreach (Vehicle veh in World.GetAllVehicles())
{ {
SyncedVehicle v = veh.GetSyncEntity(); SyncedVehicle v = veh.GetSyncEntity();
if (v.MainVehicle==Game.Player.LastVehicle)
{
// Don't delete player's vehicle
continue;
}
if((v== null) || (v.IsMine&&veh.PopulationType!=EntityPopulationType.Mission)) if((v== null) || (v.IsMine&&veh.PopulationType!=EntityPopulationType.Mission))
{ {
Main.Logger.Debug($"Removing Vehicle {veh.Handle}. Reason:ClearTraffic"); Main.Logger.Debug($"Removing Vehicle {veh.Handle}. Reason:ClearTraffic");

View File

@ -1,15 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Bcl.AsyncInterfaces" version="6.0.0" targetFramework="net48" />
<package id="Microsoft.Extensions.DependencyInjection" version="6.0.0" targetFramework="net48" />
<package id="Microsoft.Extensions.DependencyInjection.Abstractions" version="6.0.0" targetFramework="net48" />
<package id="Microsoft.Extensions.Options" version="6.0.0" targetFramework="net48" />
<package id="Microsoft.Extensions.Primitives" version="6.0.0" targetFramework="net48" />
<package id="System.Buffers" version="4.5.1" targetFramework="net48" />
<package id="System.Diagnostics.DiagnosticSource" version="6.0.0" targetFramework="net48" />
<package id="System.Memory" version="4.5.4" targetFramework="net48" />
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net48" />
<package id="System.Runtime.CompilerServices.Unsafe" version="6.0.0" targetFramework="net48" />
<package id="System.Threading.Tasks.Extensions" version="4.5.4" targetFramework="net48" />
<package id="System.ValueTuple" version="4.5.0" targetFramework="net48" />
</packages>

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Text; using System.Text;
using System.Linq; using System.Linq;
using GTA.Math;
namespace RageCoop.Core namespace RageCoop.Core
{ {
@ -103,18 +104,18 @@ namespace RageCoop.Core
return value; return value;
} }
public LVector3 ReadLVector3() public Vector3 ReadVector3()
{ {
return new LVector3() return new Vector3()
{ {
X = ReadFloat(), X = ReadFloat(),
Y = ReadFloat(), Y = ReadFloat(),
Z = ReadFloat() Z = ReadFloat()
}; };
} }
public LQuaternion ReadLQuaternion() public Quaternion ReadQuaternion()
{ {
return new LQuaternion() return new Quaternion()
{ {
X = ReadFloat(), X = ReadFloat(),
Y = ReadFloat(), Y = ReadFloat(),

View File

@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using GTA.Math;
using System.Net;
namespace RageCoop.Core namespace RageCoop.Core
{ {
public class CoreUtils public class CoreUtils
@ -34,16 +36,17 @@ namespace RageCoop.Core
return (0x0, null); return (0x0, null);
} }
} }
} }
public static class Extensions public static class Extensions
{ {
public static void AddLVector3(this List<byte> bytes, LVector3 vec3) public static void AddVector3(this List<byte> bytes, Vector3 vec3)
{ {
bytes.AddRange(BitConverter.GetBytes(vec3.X)); bytes.AddRange(BitConverter.GetBytes(vec3.X));
bytes.AddRange(BitConverter.GetBytes(vec3.Y)); bytes.AddRange(BitConverter.GetBytes(vec3.Y));
bytes.AddRange(BitConverter.GetBytes(vec3.Z)); bytes.AddRange(BitConverter.GetBytes(vec3.Z));
} }
public static void AddLQuaternion(this List<byte> bytes, LQuaternion quat) public static void AddQuaternion(this List<byte> bytes, Quaternion quat)
{ {
bytes.AddRange(BitConverter.GetBytes(quat.X)); bytes.AddRange(BitConverter.GetBytes(quat.X));
bytes.AddRange(BitConverter.GetBytes(quat.Y)); bytes.AddRange(BitConverter.GetBytes(quat.Y));

View File

@ -5,48 +5,35 @@ using System.Threading.Tasks;
using System.Threading; using System.Threading;
using System.Diagnostics; using System.Diagnostics;
namespace RageCoop.Core namespace RageCoop.Core.Logging
{ {
public class Loggger public class Logger :IDisposable
{ {
public string LogPath;
private StreamWriter logWriter;
private bool UseConsole=false;
/// <summary> /// <summary>
/// 0:Trace, 1:Debug, 2:Info, 3:Warning, 4:Error /// 0:Trace, 1:Debug, 2:Info, 3:Warning, 4:Error
/// </summary> /// </summary>
public int LogLevel = 0; public int LogLevel = 0;
public string LogPath;
public bool UseConsole = false;
private static StreamWriter logWriter;
private string Buffer=""; private string Buffer="";
private Thread LoggerThread;
private bool Stopping=false;
public Loggger(string path,bool overwrite=true) public Logger(bool overwrite=true)
{ {
if (File.Exists(LogPath)&&overwrite) { File.Delete(LogPath); }
LoggerThread=new Thread(() =>
LogPath=path;
if (File.Exists(path)&&overwrite) { File.Delete(path); }
Task.Run(() =>
{ {
while (true) while (!Stopping)
{
Flush();
Thread.Sleep(1000);
}
});
}
public Loggger()
{
UseConsole=true;
Task.Run(() =>
{
while (true)
{ {
Flush(); Flush();
Thread.Sleep(1000); Thread.Sleep(1000);
} }
}); });
LoggerThread.Start();
} }
public void Info(string message) public void Info(string message)
@ -146,5 +133,10 @@ namespace RageCoop.Core
} }
} }
public void Dispose()
{
Stopping=true;
LoggerThread?.Join();
}
} }
} }

View File

@ -7,6 +7,7 @@ using GTA.Math;
namespace RageCoop.Core namespace RageCoop.Core
{ {
/*
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
@ -111,7 +112,7 @@ namespace RageCoop.Core
/// </summary> /// </summary>
public float W { get; set; } public float W { get; set; }
} }
*/
public enum PacketTypes:byte public enum PacketTypes:byte
{ {
Handshake=0, Handshake=0,
@ -148,6 +149,7 @@ namespace RageCoop.Core
EnteredVehicle=34, EnteredVehicle=34,
OwnerChanged=35, OwnerChanged=35,
VehicleBulletShot = 36, VehicleBulletShot = 36,
NozzleTransform=37,
#endregion #endregion
@ -205,7 +207,7 @@ namespace RageCoop.Core
RoofOpened = 1 << 8, RoofOpened = 1 << 8,
OnTurretSeat = 1 << 9, OnTurretSeat = 1 << 9,
IsAircraft = 1 << 10, IsAircraft = 1 << 10,
IsHandBrakeOn=1<<11, IsDeluxoHovering=1 << 11,
} }
@ -236,10 +238,6 @@ namespace RageCoop.Core
{ {
public class Mod : Packet public class Mod : Packet
{ {
public long NetHandle { get; set; }
public long Target { get; set; }
public string Name { get; set; } public string Name { get; set; }
public byte CustomPacketID { get; set; } public byte CustomPacketID { get; set; }
@ -253,12 +251,6 @@ namespace RageCoop.Core
List<byte> byteArray = new List<byte>(); List<byte> byteArray = new List<byte>();
// Write NetHandle
byteArray.AddRange(BitConverter.GetBytes(NetHandle));
// Write Target
byteArray.AddRange(BitConverter.GetBytes(Target));
// Write Name // Write Name
byte[] nameBytes = Encoding.UTF8.GetBytes(Name); byte[] nameBytes = Encoding.UTF8.GetBytes(Name);
byteArray.AddRange(BitConverter.GetBytes(nameBytes.Length)); byteArray.AddRange(BitConverter.GetBytes(nameBytes.Length));
@ -283,12 +275,6 @@ namespace RageCoop.Core
#region NetIncomingMessageToPacket #region NetIncomingMessageToPacket
BitReader reader = new BitReader(array); BitReader reader = new BitReader(array);
// Read NetHandle
NetHandle = reader.ReadLong();
// Read Target
Target = reader.ReadLong();
// Read Name // Read Name
int nameLength = reader.ReadInt(); int nameLength = reader.ReadInt();
Name = reader.ReadString(nameLength); Name = reader.ReadString(nameLength);
@ -492,10 +478,10 @@ namespace RageCoop.Core
byteArray.AddRange(BitConverter.GetBytes(stringBytes.Length)); byteArray.AddRange(BitConverter.GetBytes(stringBytes.Length));
byteArray.AddRange(stringBytes); byteArray.AddRange(stringBytes);
} }
else if (type == typeof(LVector3)) else if (type == typeof(Vector3))
{ {
byteArray.Add(0x04); byteArray.Add(0x04);
LVector3 vector = (LVector3)x; Vector3 vector = (Vector3)x;
byteArray.AddRange(BitConverter.GetBytes(vector.X)); byteArray.AddRange(BitConverter.GetBytes(vector.X));
byteArray.AddRange(BitConverter.GetBytes(vector.Y)); byteArray.AddRange(BitConverter.GetBytes(vector.Y));
byteArray.AddRange(BitConverter.GetBytes(vector.Z)); byteArray.AddRange(BitConverter.GetBytes(vector.Z));
@ -539,7 +525,7 @@ namespace RageCoop.Core
Args.Add(reader.ReadString(stringLength)); Args.Add(reader.ReadString(stringLength));
break; break;
case 0x04: case 0x04:
Args.Add(new LVector3() Args.Add(new Vector3()
{ {
X = reader.ReadFloat(), X = reader.ReadFloat(),
Y = reader.ReadFloat(), Y = reader.ReadFloat(),
@ -602,10 +588,10 @@ namespace RageCoop.Core
byteArray.AddRange(BitConverter.GetBytes(stringBytes.Length)); byteArray.AddRange(BitConverter.GetBytes(stringBytes.Length));
byteArray.AddRange(stringBytes); byteArray.AddRange(stringBytes);
} }
else if (type == typeof(LVector3)) else if (type == typeof(Vector3))
{ {
byteArray.Add(0x04); byteArray.Add(0x04);
LVector3 vector = (LVector3)x; Vector3 vector = (Vector3)x;
byteArray.AddRange(BitConverter.GetBytes(vector.X)); byteArray.AddRange(BitConverter.GetBytes(vector.X));
byteArray.AddRange(BitConverter.GetBytes(vector.Y)); byteArray.AddRange(BitConverter.GetBytes(vector.Y));
byteArray.AddRange(BitConverter.GetBytes(vector.Z)); byteArray.AddRange(BitConverter.GetBytes(vector.Z));
@ -657,7 +643,7 @@ namespace RageCoop.Core
Args.Add(reader.ReadString(stringLength)); Args.Add(reader.ReadString(stringLength));
break; break;
case 0x04: case 0x04:
Args.Add(new LVector3() Args.Add(new Vector3()
{ {
X = reader.ReadFloat(), X = reader.ReadFloat(),
Y = reader.ReadFloat(), Y = reader.ReadFloat(),
@ -680,9 +666,6 @@ namespace RageCoop.Core
#endregion // ===== NATIVECALL ===== #endregion // ===== NATIVECALL =====
} }
/// <summary>
/// ?
/// </summary>
public static class CoopSerializer public static class CoopSerializer
{ {
/// <summary> /// <summary>

View File

@ -1,7 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using GTA.Math;
using Lidgren.Network; using Lidgren.Network;
namespace RageCoop.Core namespace RageCoop.Core
@ -126,17 +126,17 @@ namespace RageCoop.Core
public int Health { get; set; } public int Health { get; set; }
public LVector3 Position { get; set; } public Vector3 Position { get; set; }
public LVector3 Rotation { get; set; } public Vector3 Rotation { get; set; }
public LVector3 Velocity { get; set; } public Vector3 Velocity { get; set; }
public LVector3 RotationVelocity { get; set; } public Vector3 RotationVelocity { get; set; }
public byte Speed { get; set; } public byte Speed { get; set; }
public LVector3 AimCoords { get; set; } public Vector3 AimCoords { get; set; }
public uint CurrentWeaponHash { get; set; } public uint CurrentWeaponHash { get; set; }
@ -160,17 +160,17 @@ namespace RageCoop.Core
byteArray.AddRange(BitConverter.GetBytes(Health)); byteArray.AddRange(BitConverter.GetBytes(Health));
// Write ped position // Write ped position
byteArray.AddLVector3(Position); byteArray.AddVector3(Position);
// Write ped rotation // Write ped rotation
byteArray.AddLVector3(Rotation); byteArray.AddVector3(Rotation);
// Write ped velocity // Write ped velocity
byteArray.AddLVector3(Velocity); byteArray.AddVector3(Velocity);
if (Flag.HasFlag(PedDataFlags.IsRagdoll)) if (Flag.HasFlag(PedDataFlags.IsRagdoll))
{ {
byteArray.AddLVector3(RotationVelocity); byteArray.AddVector3(RotationVelocity);
} }
// Write ped speed // Write ped speed
@ -182,7 +182,7 @@ namespace RageCoop.Core
if (Flag.HasFlag(PedDataFlags.IsAiming)) if (Flag.HasFlag(PedDataFlags.IsAiming))
{ {
// Write ped aim coords // Write ped aim coords
byteArray.AddLVector3(AimCoords); byteArray.AddVector3(AimCoords);
} }
byteArray.AddFloat(Heading); byteArray.AddFloat(Heading);
@ -209,18 +209,18 @@ namespace RageCoop.Core
Health = reader.ReadInt(); Health = reader.ReadInt();
// Read player position // Read player position
Position = reader.ReadLVector3(); Position = reader.ReadVector3();
// Read player rotation // Read player rotation
Rotation = reader.ReadLVector3(); Rotation = reader.ReadVector3();
// Read player velocity // Read player velocity
Velocity = reader.ReadLVector3(); Velocity = reader.ReadVector3();
// Read rotation velocity if in ragdoll // Read rotation velocity if in ragdoll
if (Flag.HasFlag(PedDataFlags.IsRagdoll)) if (Flag.HasFlag(PedDataFlags.IsRagdoll))
{ {
RotationVelocity=reader.ReadLVector3(); RotationVelocity=reader.ReadVector3();
} }
// Read player speed // Read player speed
@ -233,7 +233,7 @@ namespace RageCoop.Core
if (Flag.HasFlag(PedDataFlags.IsAiming)) if (Flag.HasFlag(PedDataFlags.IsAiming))
{ {
// Read player aim coords // Read player aim coords
AimCoords = reader.ReadLVector3(); AimCoords = reader.ReadVector3();
} }
Heading=reader.ReadFloat(); Heading=reader.ReadFloat();

View File

@ -16,8 +16,6 @@ namespace RageCoop.Core
public string ModVersion { get; set; } public string ModVersion { get; set; }
public bool NPCsAllowed { get; set; }
public override void Pack(NetOutgoingMessage message) public override void Pack(NetOutgoingMessage message)
{ {
#region PacketToNetOutGoingMessage #region PacketToNetOutGoingMessage
@ -38,9 +36,6 @@ namespace RageCoop.Core
byteArray.AddRange(BitConverter.GetBytes(modVersionBytes.Length)); byteArray.AddRange(BitConverter.GetBytes(modVersionBytes.Length));
byteArray.AddRange(modVersionBytes); byteArray.AddRange(modVersionBytes);
// Write NpcsAllowed
byteArray.Add(NPCsAllowed ? (byte)0x01 : (byte)0x00);
byte[] result = byteArray.ToArray(); byte[] result = byteArray.ToArray();
message.Write(result.Length); message.Write(result.Length);
@ -63,9 +58,6 @@ namespace RageCoop.Core
// Read ModVersion // Read ModVersion
int modVersionLength = reader.ReadInt(); int modVersionLength = reader.ReadInt();
ModVersion = reader.ReadString(modVersionLength); ModVersion = reader.ReadString(modVersionLength);
// Read NPCsAllowed
NPCsAllowed = reader.ReadBool();
#endregion #endregion
} }
} }

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using GTA.Math;
using Lidgren.Network; using Lidgren.Network;
namespace RageCoop.Core namespace RageCoop.Core
@ -15,11 +16,11 @@ namespace RageCoop.Core
public int ShooterID { get; set; } public int ShooterID { get; set; }
public uint WeaponHash { get; set; } public uint WeaponHash { get; set; }
public LVector3 Position { get; set; } public Vector3 Position { get; set; }
public LVector3 Rotation { get; set; } public Vector3 Rotation { get; set; }
public LVector3 Velocity { get; set; } public Vector3 Velocity { get; set; }
public bool Exploded { get; set; } public bool Exploded { get; set; }
@ -41,14 +42,14 @@ namespace RageCoop.Core
byteArray.AddUint(WeaponHash); byteArray.AddUint(WeaponHash);
// Write position // Write position
byteArray.AddLVector3(Position); byteArray.AddVector3(Position);
// Write rotation // Write rotation
byteArray.AddLVector3(Rotation); byteArray.AddVector3(Rotation);
// Write velocity // Write velocity
byteArray.AddLVector3(Velocity); byteArray.AddVector3(Velocity);
if (Exploded) { byteArray.Add(1); } if (Exploded) { byteArray.Add(1); }
@ -73,13 +74,13 @@ namespace RageCoop.Core
WeaponHash= reader.ReadUInt(); WeaponHash= reader.ReadUInt();
// Read position // Read position
Position = reader.ReadLVector3(); Position = reader.ReadVector3();
// Read rotation // Read rotation
Rotation = reader.ReadLVector3(); Rotation = reader.ReadVector3();
// Read velocity // Read velocity
Velocity =reader.ReadLVector3(); Velocity =reader.ReadVector3();
if (reader.CanRead(1)) if (reader.CanRead(1))
{ {

View File

@ -1,7 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using GTA.Math;
using Lidgren.Network; using Lidgren.Network;
namespace RageCoop.Core namespace RageCoop.Core
@ -15,8 +15,8 @@ namespace RageCoop.Core
public uint WeaponHash { get; set; } public uint WeaponHash { get; set; }
public LVector3 StartPosition { get; set; } public Vector3 StartPosition { get; set; }
public LVector3 EndPosition { get; set; } public Vector3 EndPosition { get; set; }
public override void Pack(NetOutgoingMessage message) public override void Pack(NetOutgoingMessage message)
{ {
@ -32,10 +32,10 @@ namespace RageCoop.Core
byteArray.AddRange(BitConverter.GetBytes(WeaponHash)); byteArray.AddRange(BitConverter.GetBytes(WeaponHash));
// Write StartPosition // Write StartPosition
byteArray.AddLVector3(StartPosition); byteArray.AddVector3(StartPosition);
// Write EndPosition // Write EndPosition
byteArray.AddLVector3(EndPosition); byteArray.AddVector3(EndPosition);
byte[] result = byteArray.ToArray(); byte[] result = byteArray.ToArray();
@ -57,10 +57,10 @@ namespace RageCoop.Core
WeaponHash=reader.ReadUInt(); WeaponHash=reader.ReadUInt();
// Read StartPosition // Read StartPosition
StartPosition=reader.ReadLVector3(); StartPosition=reader.ReadVector3();
// Read EndPosition // Read EndPosition
EndPosition=reader.ReadLVector3(); EndPosition=reader.ReadVector3();
#endregion #endregion
} }
} }

View File

@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Text;
using Lidgren.Network;
namespace RageCoop.Core
{
public partial class Packets
{
public class NozzleTransform : Packet
{
public int VehicleID { get; set; }
public bool Hover { get; set; }
public override void Pack(NetOutgoingMessage message)
{
#region PacketToNetOutGoingMessage
message.Write((byte)PacketTypes.NozzleTransform);
List<byte> byteArray = new List<byte>();
byteArray.AddInt(VehicleID);
if (Hover) { byteArray.Add(1); }
byte[] result = byteArray.ToArray();
message.Write(result.Length);
message.Write(result);
#endregion
}
public override void Unpack(byte[] array)
{
#region NetIncomingMessageToPacket
BitReader reader = new BitReader(array);
VehicleID=reader.ReadInt();
Hover=reader.CanRead(1);
#endregion
}
}
}
}

View File

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using GTA; using GTA;
using GTA.Math;
using Lidgren.Network; using Lidgren.Network;
namespace RageCoop.Core namespace RageCoop.Core
@ -40,6 +41,7 @@ namespace RageCoop.Core
/// </summary> /// </summary>
public Dictionary<int, int> Passengers { get; set; } public Dictionary<int, int> Passengers { get; set; }
public byte RadioStation { get; set; } = 255;
public override void Pack(NetOutgoingMessage message) public override void Pack(NetOutgoingMessage message)
{ {
#region PacketToNetOutGoingMessage #region PacketToNetOutGoingMessage
@ -117,6 +119,9 @@ namespace RageCoop.Core
// Write LockStatus // Write LockStatus
byteArray.Add((byte)LockStatus); byteArray.Add((byte)LockStatus);
// Write RadioStation
byteArray.Add(RadioStation);
byte[] result = byteArray.ToArray(); byte[] result = byteArray.ToArray();
message.Write(result.Length); message.Write(result.Length);
@ -199,6 +204,9 @@ namespace RageCoop.Core
// Read LockStatus // Read LockStatus
LockStatus=(VehicleLockStatus)reader.ReadByte(); LockStatus=(VehicleLockStatus)reader.ReadByte();
// Read RadioStation
RadioStation=reader.ReadByte();
#endregion #endregion
} }
} }
@ -207,18 +215,19 @@ namespace RageCoop.Core
{ {
public int ID { get; set; } public int ID { get; set; }
public LVector3 Position { get; set; } public Vector3 Position { get; set; }
public LVector3 Rotation { get; set; } public Quaternion Quaternion { get; set; }
// public Vector3 Rotation { get; set; }
public LVector3 Velocity { get; set; } public Vector3 Velocity { get; set; }
public LVector3 RotationVelocity { get; set; } public Vector3 RotationVelocity { get; set; }
public float ThrottlePower { get; set; } public float ThrottlePower { get; set; }
public float BrakePower { get; set; } public float BrakePower { get; set; }
public float SteeringAngle { get; set; } public float SteeringAngle { get; set; }
public float DeluxoWingRatio { get; set; } = -1;
public override void Pack(NetOutgoingMessage message) public override void Pack(NetOutgoingMessage message)
{ {
@ -231,17 +240,18 @@ namespace RageCoop.Core
byteArray.AddInt(ID); byteArray.AddInt(ID);
// Write position // Write position
byteArray.AddLVector3(Position); byteArray.AddVector3(Position);
// Write rotation // Write quaternion
byteArray.AddLVector3(Rotation); //byteArray.AddVector3(Rotation);
byteArray.AddQuaternion(Quaternion);
// Write velocity // Write velocity
byteArray.AddLVector3(Velocity); byteArray.AddVector3(Velocity);
// Write rotation velocity // Write rotation velocity
byteArray.AddLVector3(RotationVelocity); byteArray.AddVector3(RotationVelocity);
byteArray.AddFloat(ThrottlePower); byteArray.AddFloat(ThrottlePower);
@ -251,6 +261,11 @@ namespace RageCoop.Core
// Write vehicle steering angle // Write vehicle steering angle
byteArray.AddFloat(SteeringAngle); byteArray.AddFloat(SteeringAngle);
if (DeluxoWingRatio!=-1)
{
byteArray.AddFloat(DeluxoWingRatio);
}
byte[] result = byteArray.ToArray(); byte[] result = byteArray.ToArray();
@ -268,16 +283,17 @@ namespace RageCoop.Core
ID = reader.ReadInt(); ID = reader.ReadInt();
// Read position // Read position
Position = reader.ReadLVector3(); Position = reader.ReadVector3();
// Read rotation // Read quaternion
Rotation = reader.ReadLVector3(); // Rotation = reader.ReadVector3();
Quaternion=reader.ReadQuaternion();
// Read velocity // Read velocity
Velocity =reader.ReadLVector3(); Velocity =reader.ReadVector3();
// Read rotation velocity // Read rotation velocity
RotationVelocity=reader.ReadLVector3(); RotationVelocity=reader.ReadVector3();
// Read throttle power // Read throttle power
ThrottlePower=reader.ReadFloat(); ThrottlePower=reader.ReadFloat();
@ -288,6 +304,11 @@ namespace RageCoop.Core
// Read steering angle // Read steering angle
SteeringAngle = reader.ReadFloat(); SteeringAngle = reader.ReadFloat();
if (reader.CanRead(4))
{
DeluxoWingRatio= reader.ReadFloat();
}
#endregion #endregion
} }
} }

View File

@ -1,34 +1,33 @@
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices;
using GTA.Math;
[assembly: InternalsVisibleTo("RageCoop.Server")]
[assembly: InternalsVisibleTo("RageCoop.Client")]
namespace RageCoop.Core namespace RageCoop.Core
{ {
public class PlayerData public class PlayerData
{ {
public string Username { get; set; } public string Username { get; internal set; }
/// <summary> /// <summary>
/// Universal character ID. /// Universal character ID.
/// </summary> /// </summary>
public int PedID public int PedID
{ {
get; set; get; internal set;
} }
/// <summary> /// <summary>
/// Universal vehicle ID. /// The ID of player's last vehicle.
/// </summary> /// </summary>
public int VehicleID { get; set; } public int VehicleID { get; internal set; }
public bool IsInVehicle { get; internal set; } public Vector3 Position { get;internal set; }
public LVector3 Position { get; set; }
/// <summary> /// <summary>
/// Player Latency in second. /// Player Latency in second.
/// </summary> /// </summary>
public float Latency { get; set; } public float Latency { get; internal set; }
public int Health { get; set; } public int Health { get; internal set; }
public bool IsInRangeOf(LVector3 position, float distance)
{
return LVector3.Subtract(Position, position).Length() < distance;
}
} }
} }

View File

@ -0,0 +1,153 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Linq;
[assembly: InternalsVisibleTo("RageCoop.Server")]
[assembly: InternalsVisibleTo("RageCoop.Client")]
namespace RageCoop.Core.Scripting
{
internal class ScriptingEngine
{
private Type BaseScriptType;
public Logging.Logger Logger { get; set; }
public ScriptingEngine(Type baseScriptType, Logging.Logger logger)
{
BaseScriptType = baseScriptType;
Logger = logger;
}
/// <summary>
/// Loads scripts from the specified assembly file.
/// </summary>
/// <param name="filename">The path to the assembly file to load.</param>
/// <returns><see langword="true" /> on success, <see langword="false" /> otherwise</returns>
private bool LoadScriptsFromAssembly(string filename)
{
if (!IsManagedAssembly(filename))
return false;
Logger?.Debug($"Loading assembly {Path.GetFileName(filename)} ...");
Assembly assembly;
try
{
assembly = Assembly.LoadFrom(filename);
}
catch (Exception ex)
{
Logger?.Error( "Unable to load "+Path.GetFileName(filename));
Logger?.Error(ex);
return false;
}
return LoadScriptsFromAssembly(assembly, filename);
}
/// <summary>
/// Loads scripts from the specified assembly object.
/// </summary>
/// <param name="filename">The path to the file associated with this assembly.</param>
/// <param name="assembly">The assembly to load.</param>
/// <returns><see langword="true" /> on success, <see langword="false" /> otherwise</returns>
private bool LoadScriptsFromAssembly(Assembly assembly, string filename)
{
int count = 0;
try
{
// Find all script types in the assembly
foreach (var type in assembly.GetTypes().Where(x => IsSubclassOf(x,nameof(BaseScriptType))))
{
ConstructorInfo constructor = type.GetConstructor(System.Type.EmptyTypes);
if (constructor != null && constructor.IsPublic)
{
try
{
// Invoke script constructor
constructor.Invoke(null);
count++;
}
catch (Exception ex)
{
Logger?.Error($"Error occurred when loading script: {type.FullName}.");
Logger?.Error(ex);
}
}
else
{
Logger?.Error($"Script {type.FullName} has an invalid contructor.");
}
}
}
catch (ReflectionTypeLoadException ex)
{
Logger?.Error($"Failed to load assembly {Path.GetFileName(filename)}: ");
Logger?.Error(ex);
return false;
}
Logger?.Info($"Loaded {count.ToString()} script(s) in {Path.GetFileName(filename)}");
return count != 0;
}
private bool IsManagedAssembly(string filename)
{
try
{
using (Stream file = new FileStream(filename, FileMode.Open, FileAccess.Read))
{
if (file.Length < 64)
return false;
using (BinaryReader bin = new BinaryReader(file))
{
// PE header starts at offset 0x3C (60). Its a 4 byte header.
file.Position = 0x3C;
uint offset = bin.ReadUInt32();
if (offset == 0)
offset = 0x80;
// Ensure there is at least enough room for the following structures:
// 24 byte PE Signature & Header
// 28 byte Standard Fields (24 bytes for PE32+)
// 68 byte NT Fields (88 bytes for PE32+)
// >= 128 byte Data Dictionary Table
if (offset > file.Length - 256)
return false;
// Check the PE signature. Should equal 'PE\0\0'.
file.Position = offset;
if (bin.ReadUInt32() != 0x00004550)
return false;
// Read PE magic number from Standard Fields to determine format.
file.Position += 20;
var peFormat = bin.ReadUInt16();
if (peFormat != 0x10b /* PE32 */ && peFormat != 0x20b /* PE32Plus */)
return false;
// Read the 15th Data Dictionary RVA field which contains the CLI header RVA.
// When this is non-zero then the file contains CLI data otherwise not.
file.Position = offset + (peFormat == 0x10b ? 232 : 248);
return bin.ReadUInt32() != 0;
}
}
}
catch
{
// This is likely not a valid assembly if any IO exceptions occur during reading
return false;
}
}
private bool IsSubclassOf(Type type, string baseTypeName)
{
for (Type t = type.BaseType; t != null; t = t.BaseType)
if (t.FullName == baseTypeName)
return true;
return false;
}
}
}

View File

@ -1,57 +1,94 @@
# 🌐 RAGECOOP # 🌐 RAGECOOP
[![Contributors][contributors-shield]][contributors-url]
[![Forks][forks-shield]][forks-url]
[![Stargazers][stars-shield]][stars-url]
[![Issues][issues-shield]][issues-url]
# Disclaimer
The original author of this project is @EntenKoeniq. The original author of this project is @EntenKoeniq.
The project has been reworked and is currently maintained by @Sardelka9515. The project has been reworked and is currently maintained by @Sardelka9515.
# **Help to survive the project** # 🧠 That's it
RAGECOOP is a multiplayer mod to play story mode or some mods made for RAGECOOP or just drive around with your buddy.
#### The project is in active development as for now but may get discontinued if user's support is not present! _Old name: GTACOOP:R_
## if you are a developer...
Please **CONTRIBUTE** to the project and make RAGECOOP better together!
## otherwise...
**[Become a patreon](https://www.patreon.com/Sardelka)** to help keep the project alive and get exclusive support to individual issues.
<br><br><br>
# 📋 Requirements
- Visual Studio 2022
- .NET 6.0
- .NET Framework 4.8
# 📚 Libraries
- [ScriptHookVDotNet3](https://github.com/crosire/scripthookvdotnet/releases/tag/v3.4.0)
- [LemonUI.SHVDN3](https://github.com/justalemon/LemonUI/releases/tag/v1.6)
- Lidgren Network Custom (***PRIVATE***)
- - No new features (only improvements)
- [Newtonsoft.Json](https://www.nuget.org/packages/Newtonsoft.Json/13.0.1)
- [ClearScript](https://github.com/microsoft/ClearScript)
# Features # Features
1. Synchronized bullets 1. Synchronized bullets
2. Synchronized vehicle/player/NPC 2. Synchronized vehicle/player/NPC
3. Synchronized Projectile 3. Synchronized projectiles
4. Basic ragdoll sync 4. Simple ragdoll sync
5. Smoother vehicle/ped movement. 5. Smoother vehicle/ped movement.
6. Ownership based sync logic, carjacking is now working properly. 6. Ownership based sync logic, carjacking is now working properly.
7. Introduced SyncEvents. 7. Introduced SyncEvents.
8. Code refactoring and namespace cleanup 8. Code refactoring and namespace cleanup
9. Synchronized vehicle doors, brake and throttle. 9. Synchronized vehicle doors, brake and throttle.
10. Other improvements 10. Weaponized vehicle sync(WIP).
11. Other improvements
# Known issues # Known issues
1. Weapon sounds are missing. 1. Weapon sounds are missing.
2. Cover sync is still buggy. 2. Cover sync is still buggy.
3. Weaponized vehicle doen't work currently 3. Framerate drop with high number of synchronized entities.
4. Framerate drop with high number of synchronized entities.
5. Scripting API is screwed.(will be rewritten in the future) 5. Scripting API is screwed.(will be rewritten in the future)
# Installation
## Client ## Installation
### Client
Download latest release, remove old version of the mod. Extract the zip and put `RageCoop` in `Grand Theft Auto V/Scripts`. Download latest release, remove old version of the mod. Extract the zip and put `RageCoop` in `Grand Theft Auto V/Scripts`.
## Server ### Server
Download latest release for your OS, then extract and run. Download latest release for your OS, then extract and run.
# Downloads # Downloads
Download latest release [here](https://github.com/RAGECOOP/RAGECOOP-V/releases/latest)
Old release can be downloaded [here](https://gitlab.com/justasausage/RageCOOP-V/-/tree/main/Release)
Please note that this is incompatible with all previous versions of ragecoop, remove old files before installing. Please note that this is incompatible with all previous versions of ragecoop, remove old files before installing.
# Support us
<a href="https://patreon.com/Sardelka"><img src="https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fshieldsio-patreon.vercel.app%2Fapi%3Fusername%3DSardelka%26type%3Dpatrons&style=for-the-badge" /></a>
# 🦆 Special thanks to
- [Makinolo](https://github.com/Makinolo), [oldnapalm](https://github.com/oldnapalm)
- - For testing, ideas, contributions and the first modification with the API
- [crosire](https://github.com/crosire)
- - For the extensive work in ScriptHookVDotNet
- [justalemon](https://github.com/justalemon)
- - For the extensive work in LemonUI
# 📝 License
This project is licensed under [MIT license](https://github.com/RAGECOOP/RAGECOOP-V/blob/main/LICENSE)
[contributors-shield]: https://img.shields.io/github/contributors/RAGECOOP/RAGECOOP-V.svg?style=for-the-badge
[contributors-url]: https://github.com/RAGECOOP/RAGECOOP-V/graphs/contributors
[forks-shield]: https://img.shields.io/github/forks/RAGECOOP/RAGECOOP-V.svg?style=for-the-badge
[forks-url]: https://github.com/RAGECOOP/RAGECOOP-V/network/members
[stars-shield]: https://img.shields.io/github/stars/RAGECOOP/RAGECOOP-V.svg?style=for-the-badge
[stars-url]: https://github.com/RAGECOOP/RAGECOOP-V/stargazers
[issues-shield]: https://img.shields.io/github/issues/RAGECOOP/RAGECOOP-V.svg?style=for-the-badge
[issues-url]: https://github.com/RAGECOOP/RAGECOOP-V/issues

View File

@ -1,9 +1 @@
using System.Collections.Generic; using System.Collections.Generic;
namespace RageCoop.Server
{
public class Allowlist
{
public List<string> Username { get; set; } = new();
}
}

View File

@ -2,23 +2,25 @@
using System.Collections.Generic; using System.Collections.Generic;
using RageCoop.Core; using RageCoop.Core;
using Lidgren.Network; using Lidgren.Network;
using GTA.Math;
namespace RageCoop.Server namespace RageCoop.Server
{ {
public class Client public class Client
{ {
public long ClientID = 0; public long NetID = 0;
private float _currentLatency = 0f; private float _currentLatency = 0f;
public NetConnection Connection { get; set; }
public float Latency public float Latency
{ {
get => _currentLatency; get => _currentLatency;
set internal set
{ {
_currentLatency = value; _currentLatency = value;
if ((value * 1000f) > Server.MainSettings.MaxLatency) if ((value * 1000f) > Server.MainSettings.MaxLatency)
{ {
Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == ClientID)?.Disconnect($"Too high latency [{value * 1000f}/{(float)Server.MainSettings.MaxLatency}]"); Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == NetID)?.Disconnect($"Too high latency [{value * 1000f}/{(float)Server.MainSettings.MaxLatency}]");
} }
} }
} }
@ -26,7 +28,7 @@ namespace RageCoop.Server
private readonly Dictionary<string, object> _customData = new(); private readonly Dictionary<string, object> _customData = new();
private long _callbacksCount = 0; private long _callbacksCount = 0;
public readonly Dictionary<long, Action<object>> Callbacks = new(); public readonly Dictionary<long, Action<object>> Callbacks = new();
public bool FilesReceived { get; set; } = false; public bool FilesReceived { get;internal set; } = false;
public bool FilesSent = false; public bool FilesSent = false;
#region CUSTOMDATA FUNCTIONS #region CUSTOMDATA FUNCTIONS
@ -64,7 +66,7 @@ namespace RageCoop.Server
#region FUNCTIONS #region FUNCTIONS
public void Kick(string reason) public void Kick(string reason)
{ {
Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == ClientID)?.Disconnect(reason); Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == NetID)?.Disconnect(reason);
} }
public void Kick(string[] reason) public void Kick(string[] reason)
{ {
@ -75,7 +77,7 @@ namespace RageCoop.Server
{ {
try try
{ {
NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == ClientID); NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == NetID);
if (userConnection == null) if (userConnection == null)
{ {
return; return;
@ -85,7 +87,7 @@ namespace RageCoop.Server
} }
catch (Exception e) catch (Exception e)
{ {
Logging.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<"); Program.Logger.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<");
} }
} }
@ -93,16 +95,16 @@ namespace RageCoop.Server
{ {
try try
{ {
NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == ClientID); NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == NetID);
if (userConnection == null) if (userConnection == null)
{ {
Logging.Error($"[Client->SendNativeCall(ulong hash, params object[] args)]: Connection \"{ClientID}\" not found!"); Program.Logger.Error($"[Client->SendNativeCall(ulong hash, params object[] args)]: Connection \"{NetID}\" not found!");
return; return;
} }
if (args != null && args.Length == 0) if (args != null && args.Length == 0)
{ {
Logging.Error($"[Client->SendNativeCall(ulong hash, Dictionary<string, object> args)]: Missing arguments!"); Program.Logger.Error($"[Client->SendNativeCall(ulong hash, Dictionary<string, object> args)]: Missing arguments!");
return; return;
} }
@ -118,7 +120,7 @@ namespace RageCoop.Server
} }
catch (Exception e) catch (Exception e)
{ {
Logging.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<"); Program.Logger.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<");
} }
} }
@ -126,16 +128,16 @@ namespace RageCoop.Server
{ {
try try
{ {
NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == ClientID); NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == NetID);
if (userConnection == null) if (userConnection == null)
{ {
Logging.Error($"[Client->SendNativeResponse(Action<object> callback, ulong hash, Type type, params object[] args)]: Connection \"{ClientID}\" not found!"); Program.Logger.Error($"[Client->SendNativeResponse(Action<object> callback, ulong hash, Type type, params object[] args)]: Connection \"{NetID}\" not found!");
return; return;
} }
if (args != null && args.Length == 0) if (args != null && args.Length == 0)
{ {
Logging.Error($"[Client->SendNativeCall(ulong hash, Dictionary<string, object> args)]: Missing arguments!"); Program.Logger.Error($"[Client->SendNativeCall(ulong hash, Dictionary<string, object> args)]: Missing arguments!");
return; return;
} }
@ -159,13 +161,13 @@ namespace RageCoop.Server
{ {
returnTypeValue = 0x03; returnTypeValue = 0x03;
} }
else if (returnType == typeof(LVector3)) else if (returnType == typeof(Vector3))
{ {
returnTypeValue = 0x04; returnTypeValue = 0x04;
} }
else else
{ {
Logging.Error($"[Client->SendNativeCall(ulong hash, Dictionary<string, object> args)]: Missing return type!"); Program.Logger.Error($"[Client->SendNativeCall(ulong hash, Dictionary<string, object> args)]: Missing return type!");
return; return;
} }
@ -181,16 +183,16 @@ namespace RageCoop.Server
} }
catch (Exception e) catch (Exception e)
{ {
Logging.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<"); Program.Logger.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<");
} }
} }
public void SendCleanUpWorld() public void SendCleanUpWorld()
{ {
NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == ClientID); NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == NetID);
if (userConnection == null) if (userConnection == null)
{ {
Logging.Error($"[Client->SendCleanUpWorld()]: Connection \"{ClientID}\" not found!"); Program.Logger.Error($"[Client->SendCleanUpWorld()]: Connection \"{NetID}\" not found!");
return; return;
} }
@ -203,7 +205,7 @@ namespace RageCoop.Server
{ {
try try
{ {
NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == ClientID); NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == NetID);
if (userConnection == null) if (userConnection == null)
{ {
return; return;
@ -212,8 +214,6 @@ namespace RageCoop.Server
NetOutgoingMessage outgoingMessage = Server.MainNetServer.CreateMessage(); NetOutgoingMessage outgoingMessage = Server.MainNetServer.CreateMessage();
new Packets.Mod() new Packets.Mod()
{ {
NetHandle = 0,
Target = 0,
Name = modName, Name = modName,
CustomPacketID = customID, CustomPacketID = customID,
Bytes = bytes Bytes = bytes
@ -223,7 +223,7 @@ namespace RageCoop.Server
} }
catch (Exception e) catch (Exception e)
{ {
Logging.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<"); Program.Logger.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<");
} }
} }
@ -231,13 +231,13 @@ namespace RageCoop.Server
{ {
if (!FilesReceived) if (!FilesReceived)
{ {
Logging.Warning($"Player \"{Player.Username}\" doesn't have all the files yet!"); Program.Logger.Warning($"Player \"{Player.Username}\" doesn't have all the files yet!");
return; return;
} }
try try
{ {
NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == ClientID); NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == NetID);
if (userConnection == null) if (userConnection == null)
{ {
return; return;
@ -254,7 +254,7 @@ namespace RageCoop.Server
} }
catch (Exception e) catch (Exception e)
{ {
Logging.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<"); Program.Logger.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<");
} }
} }
#endregion #endregion

View File

@ -43,7 +43,7 @@ namespace RageCoop.Server
// ONLY JAVASCRIPT AND JSON FILES! // ONLY JAVASCRIPT AND JSON FILES!
if (!new string[] { ".js", ".xml" }.Any(x => x == fileInfo.Extension)) if (!new string[] { ".js", ".xml" }.Any(x => x == fileInfo.Extension))
{ {
Logging.Warning("Only files with \"*.js\" and \"*.xml\" can be sent!"); Program.Logger.Warning("Only files with \"*.js\" and \"*.xml\" can be sent!");
continue; continue;
} }
@ -105,7 +105,7 @@ namespace RageCoop.Server
{ {
lock (Server.Clients) lock (Server.Clients)
{ {
Client x = Server.Clients.FirstOrDefault(x => x.ClientID == client.NetHandle); Client x = Util.GetClientByID(client.NetHandle);
if (x != null) if (x != null)
{ {
x.FilesReceived = true; x.FilesReceived = true;

View File

@ -1,79 +0,0 @@
using System;
using System.IO;
namespace RageCoop.Server
{
public class Logging
{
private static readonly object _lock = new();
public static void Info(string message)
{
lock (_lock)
{
string msg = string.Format("[{0}] [INFO] {1}", Date(), message);
Console.ForegroundColor = ConsoleColor.Gray;
Console.WriteLine(msg);
Console.ResetColor();
using StreamWriter sw = new("log.txt", true);
sw.WriteLine(msg);
}
}
public static void Warning(string message)
{
lock (_lock)
{
string msg = string.Format("[{0}] [WARNING] {1}", Date(), message);
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine(msg);
Console.ResetColor();
using StreamWriter sw = new("log.txt", true);
sw.WriteLine(msg);
}
}
public static void Error(string message)
{
lock (_lock)
{
string msg = string.Format("[{0}] [ERROR] {1}", Date(), message);
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(msg);
Console.ResetColor();
using StreamWriter sw = new("log.txt", true);
sw.WriteLine(msg);
}
}
public static void Debug(string message)
{
if (!Server.MainSettings.DebugMode)
{
return;
}
lock (_lock)
{
string msg = string.Format("[{0}] [DEBUG] {1}", Date(), message);
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine(msg);
Console.ResetColor();
using StreamWriter sw = new("log.txt", true);
sw.WriteLine(msg);
}
}
private static string Date()
{
return DateTime.Now.ToString();
}
}
}

View File

@ -9,8 +9,14 @@ namespace RageCoop.Server
class Program class Program
{ {
public static bool ReadyToStop = false; public static bool ReadyToStop = false;
public static Core.Logging.Logger Logger;
static void Main(string[] args) static void Main(string[] args)
{ {
Logger=new Core.Logging.Logger()
{
LogPath="RageCoop.Server.log",
UseConsole=true,
};
try try
{ {
#if DEBUG #if DEBUG
@ -45,7 +51,7 @@ namespace RageCoop.Server
} }
catch (Exception e) catch (Exception e)
{ {
Logging.Error(e.InnerException?.Message ?? e.Message); Program.Logger.Error(e.InnerException?.Message ?? e.Message);
Console.ReadLine(); Console.ReadLine();
} }
} }

View File

@ -6,10 +6,10 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<PropertyGroup> <PropertyGroup>
<Configuration>Release</Configuration> <Configuration>Release</Configuration>
<Platform>Any CPU</Platform> <Platform>Any CPU</Platform>
<PublishDir>bin\Release\net6.0\publish\osx-x64\</PublishDir> <PublishDir>bin\Release\net6.0\publish\linux-arm\</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol> <PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<RuntimeIdentifier>osx-x64</RuntimeIdentifier> <RuntimeIdentifier>linux-arm</RuntimeIdentifier>
<SelfContained>true</SelfContained> <SelfContained>true</SelfContained>
<PublishSingleFile>True</PublishSingleFile> <PublishSingleFile>True</PublishSingleFile>
<PublishTrimmed>True</PublishTrimmed> <PublishTrimmed>True</PublishTrimmed>

View File

@ -4,6 +4,6 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
--> -->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup> <PropertyGroup>
<History>True|2022-05-25T02:30:00.0927959Z;True|2022-05-25T10:26:50.6739643+08:00;True|2022-05-25T10:20:36.6658425+08:00;True|2022-05-25T10:19:47.8333108+08:00;True|2022-05-24T11:00:13.3617113+08:00;True|2022-05-22T16:56:31.0481188+08:00;True|2022-05-18T13:35:57.1402751+08:00;True|2022-05-18T13:10:28.4995253+08:00;True|2022-05-01T18:35:01.9624101+08:00;True|2022-05-01T12:32:20.8671319+08:00;False|2022-05-01T12:30:25.4596227+08:00;</History> <History>True|2022-06-03T08:41:45.9403306Z;True|2022-06-03T16:41:27.9643943+08:00;True|2022-06-03T16:41:03.3149741+08:00;True|2022-06-03T16:40:25.3605097+08:00;True|2022-06-03T16:40:05.4510168+08:00;True|2022-06-02T13:21:10.3456459+08:00;True|2022-06-02T13:20:52.1088278+08:00;True|2022-06-02T13:20:25.6889167+08:00;True|2022-06-02T13:19:06.3089340+08:00;True|2022-06-01T18:47:39.6707493+08:00;True|2022-06-01T18:04:32.2932367+08:00;True|2022-06-01T18:03:17.8871227+08:00;True|2022-05-27T15:20:25.7264350+08:00;True|2022-05-27T15:20:04.2362276+08:00;True|2022-05-27T15:19:21.4852644+08:00;True|2022-05-27T15:18:36.0857345+08:00;True|2022-05-25T10:30:00.0927959+08:00;True|2022-05-25T10:26:50.6739643+08:00;True|2022-05-25T10:20:36.6658425+08:00;True|2022-05-25T10:19:47.8333108+08:00;True|2022-05-24T11:00:13.3617113+08:00;True|2022-05-22T16:56:31.0481188+08:00;True|2022-05-18T13:35:57.1402751+08:00;True|2022-05-18T13:10:28.4995253+08:00;True|2022-05-01T18:35:01.9624101+08:00;True|2022-05-01T12:32:20.8671319+08:00;False|2022-05-01T12:30:25.4596227+08:00;</History>
</PropertyGroup> </PropertyGroup>
</Project> </Project>

View File

@ -3,8 +3,8 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AssemblyVersion>0.2</AssemblyVersion> <AssemblyVersion>0.4</AssemblyVersion>
<FileVersion>0.2</FileVersion> <FileVersion>0.4</FileVersion>
<RepositoryUrl>https://github.com/RAGECOOP/RAGECOOP-V</RepositoryUrl> <RepositoryUrl>https://github.com/RAGECOOP/RAGECOOP-V</RepositoryUrl>
<PackageProjectUrl>https://ragecoop.online/</PackageProjectUrl> <PackageProjectUrl>https://ragecoop.online/</PackageProjectUrl>
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance> <PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
@ -12,7 +12,7 @@
<Product>$(AssemblyName)-V</Product> <Product>$(AssemblyName)-V</Product>
<PackageId>RAGECOOP-V</PackageId> <PackageId>RAGECOOP-V</PackageId>
<Authors>RAGECOOP</Authors> <Authors>RAGECOOP</Authors>
<Version>0.2</Version> <Version>0.4</Version>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
@ -32,6 +32,9 @@
<Reference Include="Newtonsoft.Json"> <Reference Include="Newtonsoft.Json">
<HintPath>..\Libs\Release\scripts\Newtonsoft.Json.dll</HintPath> <HintPath>..\Libs\Release\scripts\Newtonsoft.Json.dll</HintPath>
</Reference> </Reference>
<Reference Include="ScriptHookVDotNet3">
<HintPath>..\Libs\Release\ScriptHookVDotNet3.dll</HintPath>
</Reference>
</ItemGroup> </ItemGroup>

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RageCoop.Core.Scripting;
namespace RageCoop.Server.Scripting
{
internal class Engine:ScriptingEngine
{
public Engine() : base(typeof(ServerScript), Program.Logger)
{
}
public static void Load()
{
}
}
}

View File

@ -55,8 +55,8 @@ namespace RageCoop.Server
(localQueue.Dequeue() as Action)?.Invoke(); (localQueue.Dequeue() as Action)?.Invoke();
} }
// 16 milliseconds to sleep to reduce CPU usage // 15 milliseconds to sleep to reduce CPU usage
Thread.Sleep(1000 / 60); Thread.Sleep(15);
} }
_script.API.InvokeStop(); _script.API.InvokeStop();
@ -105,13 +105,6 @@ namespace RageCoop.Server
return task.Result; return task.Result;
} }
public void InvokePlayerPositionUpdate(string username)
{
lock (_actionQueue.SyncRoot)
{
_actionQueue.Enqueue(new Action(() => _script.API.InvokePlayerPositionUpdate(username)));
}
}
public void InvokePlayerUpdate(Client client) public void InvokePlayerUpdate(Client client)
{ {
@ -121,29 +114,6 @@ namespace RageCoop.Server
} }
} }
public void InvokePlayerHealthUpdate(string username)
{
lock (_actionQueue.SyncRoot)
{
_actionQueue.Enqueue(new Action(() => _script.API.InvokePlayerHealthUpdate(username)));
}
}
public void InvokePlayerPedHandleUpdate(string username)
{
lock (_actionQueue.SyncRoot)
{
_actionQueue.Enqueue(new Action(() => _script.API.InvokePlayerPedHandleUpdate(username)));
}
}
public void InvokePlayerVehicleHandleUpdate(string username)
{
lock (_actionQueue.SyncRoot)
{
_actionQueue.Enqueue(new Action(() => _script.API.InvokePlayerVehicleHandleUpdate(username)));
}
}
public void InvokeTick(long tick) public void InvokeTick(long tick)
{ {
@ -197,25 +167,6 @@ namespace RageCoop.Server
/// Called when a new player sends data like health /// Called when a new player sends data like health
/// </summary> /// </summary>
public event PlayerEvent OnPlayerUpdate; public event PlayerEvent OnPlayerUpdate;
/// <summary>
/// Called when a player has a new health value
/// </summary>
public event PlayerEvent OnPlayerHealthUpdate;
/// <summary>
/// Called when a player has a new position
/// </summary>
public event PlayerEvent OnPlayerPositionUpdate;
/// <summary>
/// Called when a player has a new position
/// </summary>
public event PlayerEvent OnPlayerPedHandleUpdate;
/// <summary>
/// Called when a player has a new position
/// </summary>
public event PlayerEvent OnPlayerVehicleHandleUpdate;
/// <summary>
/// Called when a player sends a packet from another modification
/// </summary>
public event ModEvent OnModPacketReceived; public event ModEvent OnModPacketReceived;
public void InvokeTick(long tick) public void InvokeTick(long tick)
@ -253,11 +204,6 @@ namespace RageCoop.Server
OnPlayerUpdate?.Invoke(client); OnPlayerUpdate?.Invoke(client);
} }
public void InvokePlayerHealthUpdate(string username)
{
OnPlayerHealthUpdate?.Invoke(Server.Clients.FirstOrDefault(x => x.Player.Username == username));
}
public bool InvokeChatMessage(string username, string message) public bool InvokeChatMessage(string username, string message)
{ {
CancelEventArgs args = new(false); CancelEventArgs args = new(false);
@ -265,21 +211,6 @@ namespace RageCoop.Server
return args.Cancel; return args.Cancel;
} }
public void InvokePlayerPositionUpdate(string username)
{
OnPlayerPositionUpdate?.Invoke(Server.Clients.FirstOrDefault(x => x.Player.Username == username));
}
public void InvokePlayerPedHandleUpdate(string username)
{
OnPlayerPedHandleUpdate?.Invoke(Server.Clients.FirstOrDefault(x => x.Player.Username == username));
}
public void InvokePlayerVehicleHandleUpdate(string username)
{
OnPlayerVehicleHandleUpdate?.Invoke(Server.Clients.FirstOrDefault(x => x.Player.Username == username));
}
public bool InvokeModPacketReceived(long from, long target, string modName, byte customID, byte[] bytes) public bool InvokeModPacketReceived(long from, long target, string modName, byte customID, byte[] bytes)
{ {
CancelEventArgs args = new(false); CancelEventArgs args = new(false);
@ -295,35 +226,39 @@ namespace RageCoop.Server
/// <param name="modName">The name of the modification that will receive the data</param> /// <param name="modName">The name of the modification that will receive the data</param>
/// <param name="customID">The ID to check what this data is</param> /// <param name="customID">The ID to check what this data is</param>
/// <param name="bytes">The serialized data</param> /// <param name="bytes">The serialized data</param>
/// <param name="netHandleList">The list of connections (players) that will receive the data</param> /// <param name="playerList">The list of player ID (PedID) that will receive the data</param>
public static void SendModPacketToAll(string modName, byte customID, byte[] bytes, List<long> netHandleList = null) public static void SendModPacketToAll(string modName, byte customID, byte[] bytes, List<int> playerList = null)
{ {
try try
{ {// A resource can be calling this function on disconnect of the last player in the server and we will
List<NetConnection> connections = netHandleList == null
? Server.MainNetServer.Connections
: Server.MainNetServer.Connections.FindAll(c => netHandleList.Contains(c.RemoteUniqueIdentifier));
// A resource can be calling this function on disconnect of the last player in the server and we will
// get an empty connection list, make sure connections has at least one handle in it // get an empty connection list, make sure connections has at least one handle in it
if (connections.Count > 0) NetOutgoingMessage outgoingMessage = Server.MainNetServer.CreateMessage();
new Packets.Mod()
{ {
NetOutgoingMessage outgoingMessage = Server.MainNetServer.CreateMessage(); Name = modName,
new Packets.Mod() CustomPacketID = customID,
{ Bytes = bytes
NetHandle = 0, }.Pack(outgoingMessage);
Target = 0, if (playerList==null)
Name = modName, {
CustomPacketID = customID, Server.MainNetServer.SendMessage(outgoingMessage, Server.MainNetServer.Connections, NetDeliveryMethod.ReliableOrdered, (byte)ConnectionChannel.Mod);
Bytes = bytes
}.Pack(outgoingMessage);
Logging.Debug($"SendModPacketToAll recipients list {connections.Count}");
Server.MainNetServer.SendMessage(outgoingMessage, connections, NetDeliveryMethod.ReliableOrdered, (byte)ConnectionChannel.Mod);
Server.MainNetServer.FlushSendQueue();
} }
else
{
foreach(var c in Server.Clients.Values)
{
if (playerList.Contains(c.Player.PedID))
{
Server.MainNetServer.SendMessage(outgoingMessage, c.Connection, NetDeliveryMethod.ReliableOrdered, (byte)ConnectionChannel.Mod);
}
}
}
Server.MainNetServer.FlushSendQueue();
} }
catch (Exception e) catch (Exception e)
{ {
Logging.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<"); Program.Logger.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<");
} }
} }
@ -344,7 +279,7 @@ namespace RageCoop.Server
if (args != null && args.Length == 0) if (args != null && args.Length == 0)
{ {
Logging.Error($"[ServerScript->SendNativeCallToAll(ulong hash, params object[] args)]: args is not null!"); Program.Logger.Error($"[ServerScript->SendNativeCallToAll(ulong hash, params object[] args)]: args is not null!");
return; return;
} }
@ -360,37 +295,15 @@ namespace RageCoop.Server
} }
catch (Exception e) catch (Exception e)
{ {
Logging.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<"); Program.Logger.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<");
} }
} }
/// <summary>
/// Get all connections as a list of NetHandle(long)
/// </summary>
/// <returns>All connections(NetHandle) as a List</returns>
public static List<long> GetAllConnections()
{
List<long> result = new();
Server.MainNetServer.Connections.ForEach(x => result.Add(x.RemoteUniqueIdentifier));
return result;
}
/// <summary>
/// Get the count of all connections
/// </summary>
/// <returns>The count of all connections as an integer</returns>
public static int GetAllClientsCount()
{
return Server.Clients.Count;
}
/// <summary> /// <summary>
/// Get a list of all Clients /// Get a list of all Clients
/// </summary> /// </summary>
/// <returns>All Clients as a List</returns> /// <returns>All clients as a dictionary indexed by NetID</returns>
public static List<Client> GetAllClients() public static Dictionary<long,Client> GetAllClients()
{ {
return Server.Clients; return Server.Clients;
} }
@ -402,7 +315,7 @@ namespace RageCoop.Server
/// <returns>The Client from this user or null</returns> /// <returns>The Client from this user or null</returns>
public static Client GetClientByUsername(string username) public static Client GetClientByUsername(string username)
{ {
return Server.Clients.FirstOrDefault(x => x.Player.Username.ToLower() == username.ToLower()); return Server.Clients.Values.FirstOrDefault(x => x.Player.Username.ToLower() == username.ToLower());
} }
/// <summary> /// <summary>
@ -428,7 +341,7 @@ namespace RageCoop.Server
} }
catch (Exception e) catch (Exception e)
{ {
Logging.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<"); Program.Logger.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<");
} }
} }

View File

@ -11,6 +11,7 @@ using RageCoop.Core;
using Newtonsoft.Json; using Newtonsoft.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
using Lidgren.Network; using Lidgren.Network;
using System.Timers;
namespace RageCoop.Server namespace RageCoop.Server
{ {
@ -22,29 +23,26 @@ namespace RageCoop.Server
public class Server public class Server
{ {
private static readonly string _compatibleVersion = "V0_2"; private static readonly string _compatibleVersion = "V0_4";
private static long _currentTick = 0; private static long _currentTick = 0;
public static readonly Settings MainSettings = Util.Read<Settings>("Settings.xml"); public static readonly Settings MainSettings = Util.Read<Settings>("Settings.xml");
private readonly Blocklist _mainBlocklist = Util.Read<Blocklist>("Blocklist.xml"); private readonly Blocklist _mainBlocklist = Util.Read<Blocklist>("Blocklist.xml");
private readonly Allowlist _mainAllowlist = Util.Read<Allowlist>("Allowlist.xml");
public static NetServer MainNetServer; public static NetServer MainNetServer;
public static Resource RunningResource = null; public static Resource RunningResource = null;
public static readonly Dictionary<Command, Action<CommandContext>> Commands = new(); public static readonly Dictionary<Command, Action<CommandContext>> Commands = new();
public static readonly Dictionary<TriggerEvent, Action<EventContext>> TriggerEvents = new(); public static readonly Dictionary<TriggerEvent, Action<EventContext>> TriggerEvents = new();
private static Thread BackgroundThread;
public static readonly List<Client> Clients = new();
public static readonly Dictionary<long,Client> Clients = new();
private static System.Timers.Timer SendLatencyTimer = new System.Timers.Timer(5000);
public Server() public Server()
{ {
Logging.Info("================"); Program.Logger.Info("================");
Logging.Info($"Server bound to: 0.0.0.0:{MainSettings.Port}"); Program.Logger.Info($"Server bound to: 0.0.0.0:{MainSettings.Port}");
Logging.Info($"Server version: {Assembly.GetCallingAssembly().GetName().Version}"); Program.Logger.Info($"Server version: {Assembly.GetCallingAssembly().GetName().Version}");
Logging.Info($"Compatible RAGECOOP versions: {_compatibleVersion.Replace('_', '.')}.x"); Program.Logger.Info($"Compatible RAGECOOP versions: {_compatibleVersion.Replace('_', '.')}.x");
Logging.Info("================"); Program.Logger.Info("================");
// 623c92c287cc392406e7aaaac1c0f3b0 = RAGECOOP // 623c92c287cc392406e7aaaac1c0f3b0 = RAGECOOP
NetPeerConfiguration config = new("623c92c287cc392406e7aaaac1c0f3b0") NetPeerConfiguration config = new("623c92c287cc392406e7aaaac1c0f3b0")
@ -59,27 +57,28 @@ namespace RageCoop.Server
MainNetServer = new NetServer(config); MainNetServer = new NetServer(config);
MainNetServer.Start(); MainNetServer.Start();
SendLatencyTimer.Elapsed+=((s,e) => { SendLatency(); });
Logging.Info(string.Format("Server listening on {0}:{1}", config.LocalAddress.ToString(), config.Port)); SendLatencyTimer.AutoReset=true;
SendLatencyTimer.Enabled=true;
Program.Logger.Info(string.Format("Server listening on {0}:{1}", config.LocalAddress.ToString(), config.Port));
if (MainSettings.UPnP) if (MainSettings.UPnP)
{ {
Logging.Info(string.Format("Attempting to forward port {0}", MainSettings.Port)); Program.Logger.Info(string.Format("Attempting to forward port {0}", MainSettings.Port));
if (MainNetServer.UPnP.ForwardPort(MainSettings.Port, "RAGECOOP server")) if (MainNetServer.UPnP.ForwardPort(MainSettings.Port, "RAGECOOP server"))
{ {
Logging.Info(string.Format("Server available on {0}:{1}", MainNetServer.UPnP.GetExternalIP().ToString(), config.Port)); Program.Logger.Info(string.Format("Server available on {0}:{1}", MainNetServer.UPnP.GetExternalIP().ToString(), config.Port));
} }
else else
{ {
Logging.Error("Port forwarding failed! Your router may not support UPnP."); Program.Logger.Warning("Port forwarding failed! Your router may not support UPnP.");
Logging.Warning("If you and your friends can join this server, please ignore this error or set UPnP in Settings.xml to false!"); Program.Logger.Info("If you and your friends can join this server, please ignore this error or set UPnP in Settings.xml to false!");
} }
} }
if (MainSettings.AnnounceSelf) if (MainSettings.AnnounceSelf)
{ {
Logging.Info("Announcing to master server...");
#region -- MASTERSERVER -- #region -- MASTERSERVER --
new Thread(async () => new Thread(async () =>
@ -104,13 +103,14 @@ namespace RageCoop.Server
string content = await response.Content.ReadAsStringAsync(); string content = await response.Content.ReadAsStringAsync();
info = JsonConvert.DeserializeObject<IpInfo>(content); info = JsonConvert.DeserializeObject<IpInfo>(content);
Program.Logger.Info($"Your public IP is {info.Address}, announcing to master server...");
} }
catch (Exception ex) catch (Exception ex)
{ {
Logging.Error(ex.InnerException?.Message ?? ex.Message); Program.Logger.Error(ex.InnerException?.Message ?? ex.Message);
return; return;
} }
var realMaster = MainSettings.MasterServer=="[AUTO]" ? Util.DownloadString("https://ragecoop.online/stuff/masterserver") : MainSettings.MasterServer;
while (!Program.ReadyToStop) while (!Program.ReadyToStop)
{ {
string msg = string msg =
@ -120,20 +120,16 @@ namespace RageCoop.Server
"\"name\": \"" + MainSettings.Name + "\", " + "\"name\": \"" + MainSettings.Name + "\", " +
"\"version\": \"" + _compatibleVersion.Replace("_", ".") + "\", " + "\"version\": \"" + _compatibleVersion.Replace("_", ".") + "\", " +
"\"players\": \"" + MainNetServer.ConnectionsCount + "\", " + "\"players\": \"" + MainNetServer.ConnectionsCount + "\", " +
"\"maxPlayers\": \"" + MainSettings.MaxPlayers + "\", " + "\"maxPlayers\": \"" + MainSettings.MaxPlayers + "\"" +
"\"allowlist\": \"" + _mainAllowlist.Username.Any() + "\", " +
"\"mods\": \"" + MainSettings.ModsAllowed + "\", " +
"\"npcs\": \"" + MainSettings.NpcsAllowed + "\"" +
" }"; " }";
HttpResponseMessage response = null; HttpResponseMessage response = null;
try try
{ {
response = await httpClient.PostAsync(MainSettings.MasterServer, new StringContent(msg, Encoding.UTF8, "application/json")); response = await httpClient.PostAsync(realMaster, new StringContent(msg, Encoding.UTF8, "application/json"));
} }
catch (Exception ex) catch (Exception ex)
{ {
Logging.Error($"MasterServer: {ex.Message}"); Program.Logger.Error($"MasterServer: {ex.Message}");
// Sleep for 5s // Sleep for 5s
Thread.Sleep(5000); Thread.Sleep(5000);
@ -142,18 +138,19 @@ namespace RageCoop.Server
if (response == null) if (response == null)
{ {
Logging.Error("MasterServer: Something went wrong!"); Program.Logger.Error("MasterServer: Something went wrong!");
} }
else if (response.StatusCode != HttpStatusCode.OK) else if (response.StatusCode != HttpStatusCode.OK)
{ {
if (response.StatusCode == HttpStatusCode.BadRequest) if (response.StatusCode == HttpStatusCode.BadRequest)
{ {
string requestContent = await response.Content.ReadAsStringAsync(); string requestContent = await response.Content.ReadAsStringAsync();
Logging.Error($"MasterServer: [{(int)response.StatusCode}], {requestContent}"); Program.Logger.Error($"MasterServer: [{(int)response.StatusCode}], {requestContent}");
} }
else else
{ {
Logging.Error($"MasterServer: [{(int)response.StatusCode}]"); Program.Logger.Error($"MasterServer: [{(int)response.StatusCode}]");
Program.Logger.Error($"MasterServer: [{await response.Content.ReadAsStringAsync()}]");
} }
} }
@ -163,11 +160,11 @@ namespace RageCoop.Server
} }
catch (HttpRequestException ex) catch (HttpRequestException ex)
{ {
Logging.Error($"MasterServer: {ex.InnerException.Message}"); Program.Logger.Error($"MasterServer: {ex.InnerException.Message}");
} }
catch (Exception ex) catch (Exception ex)
{ {
Logging.Error($"MasterServer: {ex.Message}"); Program.Logger.Error($"MasterServer: {ex.Message}");
} }
}).Start(); }).Start();
#endregion #endregion
@ -178,7 +175,7 @@ namespace RageCoop.Server
try try
{ {
string resourcepath = AppDomain.CurrentDomain.BaseDirectory + "resources" + Path.DirectorySeparatorChar + MainSettings.Resource + ".dll"; string resourcepath = AppDomain.CurrentDomain.BaseDirectory + "resources" + Path.DirectorySeparatorChar + MainSettings.Resource + ".dll";
Logging.Info($"Loading resource \"{MainSettings.Resource}.dll\"..."); Program.Logger.Info($"Loading resource \"{MainSettings.Resource}.dll\"...");
Assembly asm = Assembly.LoadFrom(resourcepath); Assembly asm = Assembly.LoadFrom(resourcepath);
Type[] types = asm.GetExportedTypes(); Type[] types = asm.GetExportedTypes();
@ -187,7 +184,7 @@ namespace RageCoop.Server
if (!enumerable.Any()) if (!enumerable.Any())
{ {
Logging.Error("ERROR: No classes that inherit from ServerScript have been found in the assembly. Starting freeroam."); Program.Logger.Error("ERROR: No classes that inherit from ServerScript have been found in the assembly. Starting freeroam.");
} }
else else
{ {
@ -197,28 +194,26 @@ namespace RageCoop.Server
} }
else else
{ {
Logging.Warning("Could not create resource: it is null."); Program.Logger.Warning("Could not create resource: it is null.");
} }
} }
} }
catch (Exception e) catch (Exception e)
{ {
Logging.Error(e.InnerException.Message); Program.Logger.Error(e.InnerException.Message);
} }
} }
Program.Logger.Info("Searching for client-side files...");
Logging.Info("Searching for client-side files...");
DownloadManager.CheckForDirectoryAndFiles(); DownloadManager.CheckForDirectoryAndFiles();
Listen();
BackgroundThread=new Thread(() => Background()); Listen();
} }
private void Listen() private void Listen()
{ {
Logging.Info("Listening for clients"); Program.Logger.Info("Listening for clients");
Logging.Info("Please use CTRL + C if you want to stop the server!"); Program.Logger.Info("Please use CTRL + C if you want to stop the server!");
while (!Program.ReadyToStop) while (!Program.ReadyToStop)
{ {
@ -232,11 +227,11 @@ namespace RageCoop.Server
{ {
lock (Clients) lock (Clients)
{ {
Clients.ForEach(client => Clients.Values.ToList().ForEach(client =>
{ {
if (!client.FilesSent) if (!client.FilesSent)
{ {
DownloadManager.InsertClient(client.ClientID); DownloadManager.InsertClient(client.NetID);
client.FilesSent = true; client.FilesSent = true;
} }
}); });
@ -253,10 +248,10 @@ namespace RageCoop.Server
{ {
case NetIncomingMessageType.ConnectionApproval: case NetIncomingMessageType.ConnectionApproval:
{ {
Logging.Info($"New incoming connection from: [{message.SenderConnection.RemoteEndPoint}]"); Program.Logger.Info($"New incoming connection from: [{message.SenderConnection.RemoteEndPoint}]");
if (message.ReadByte() != (byte)PacketTypes.Handshake) if (message.ReadByte() != (byte)PacketTypes.Handshake)
{ {
Logging.Info($"IP [{message.SenderConnection.RemoteEndPoint.Address}] was blocked, reason: Wrong packet!"); Program.Logger.Info($"IP [{message.SenderConnection.RemoteEndPoint.Address}] was blocked, reason: Wrong packet!");
message.SenderConnection.Deny("Wrong packet!"); message.SenderConnection.Deny("Wrong packet!");
} }
else else
@ -273,7 +268,7 @@ namespace RageCoop.Server
} }
catch (Exception e) catch (Exception e)
{ {
Logging.Info($"IP [{message.SenderConnection.RemoteEndPoint.Address}] was blocked, reason: {e.Message}"); Program.Logger.Info($"IP [{message.SenderConnection.RemoteEndPoint.Address}] was blocked, reason: {e.Message}");
message.SenderConnection.Deny(e.Message); message.SenderConnection.Deny(e.Message);
} }
} }
@ -317,7 +312,7 @@ namespace RageCoop.Server
Packets.PedStateSync packet = new(); Packets.PedStateSync packet = new();
packet.Unpack(data); packet.Unpack(data);
CharacterStateSync(packet, message.SenderConnection.RemoteUniqueIdentifier); PedStateSync(packet, message.SenderConnection.RemoteUniqueIdentifier);
} }
catch (Exception e) catch (Exception e)
{ {
@ -353,7 +348,7 @@ namespace RageCoop.Server
Packets.PedSync packet = new(); Packets.PedSync packet = new();
packet.Unpack(data); packet.Unpack(data);
CharacterSync(packet, message.SenderConnection.RemoteUniqueIdentifier); PedSync(packet, message.SenderConnection.RemoteUniqueIdentifier);
} }
catch (Exception e) catch (Exception e)
{ {
@ -429,7 +424,7 @@ namespace RageCoop.Server
Packets.NativeResponse packet = new(); Packets.NativeResponse packet = new();
packet.Unpack(data); packet.Unpack(data);
Client client = Clients.Find(x => x.ClientID == message.SenderConnection.RemoteUniqueIdentifier); Client client = Util.GetClientByID(message.SenderConnection.RemoteUniqueIdentifier);
if (client != null) if (client != null)
{ {
if (client.Callbacks.ContainsKey(packet.ID)) if (client.Callbacks.ContainsKey(packet.ID))
@ -445,63 +440,6 @@ namespace RageCoop.Server
} }
} }
break; break;
case PacketTypes.Mod:
{
if (MainSettings.ModsAllowed)
{
try
{
int len = message.ReadInt32();
byte[] data = message.ReadBytes(len);
Packets.Mod packet = new Packets.Mod();
packet.Unpack(data);
bool resourceResult = false;
if (RunningResource != null)
{
if (RunningResource.InvokeModPacketReceived(packet.NetHandle, packet.Target, packet.Name, packet.CustomPacketID, packet.Bytes))
{
resourceResult = true;
}
}
if (!resourceResult && packet.Target != -1)
{
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
packet.Pack(outgoingMessage);
if (packet.Target != 0)
{
NetConnection target = MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == packet.Target);
if (target == null)
{
Logging.Error($"[ModPacket] target \"{packet.Target}\" not found!");
}
else
{
// Send back to target
MainNetServer.SendMessage(outgoingMessage, target, NetDeliveryMethod.ReliableOrdered, (byte)ConnectionChannel.Mod);
}
}
else
{
// Send back to all players
MainNetServer.SendMessage(outgoingMessage, MainNetServer.Connections, NetDeliveryMethod.ReliableOrdered, (byte)ConnectionChannel.Mod);
}
}
}
catch (Exception e)
{
DisconnectAndLog(message.SenderConnection, type, e);
}
}
else
{
message.SenderConnection.Disconnect("Mods are not allowed!");
}
}
break;
case PacketTypes.FileTransferComplete: case PacketTypes.FileTransferComplete:
{ {
try try
@ -514,10 +452,10 @@ namespace RageCoop.Server
Packets.FileTransferComplete packet = new(); Packets.FileTransferComplete packet = new();
packet.Unpack(data); packet.Unpack(data);
Client client = Clients.Find(x => x.ClientID == message.SenderConnection.RemoteUniqueIdentifier); Client client = Util.GetClientByID(message.SenderConnection.RemoteUniqueIdentifier);
if (client != null && !client.FilesReceived) if (client != null && !client.FilesReceived)
{ {
DownloadManager.TryToRemoveClient(client.ClientID, packet.ID); DownloadManager.TryToRemoveClient(client.NetID, packet.ID);
} }
} }
} }
@ -558,7 +496,7 @@ namespace RageCoop.Server
} }
else else
{ {
Logging.Warning($"Player \"{client.Player.Username}\" attempted to trigger an unknown event! [{packet.EventName}]"); Program.Logger.Warning($"Player \"{client.Player.Username}\" attempted to trigger an unknown event! [{packet.EventName}]");
} }
} }
} }
@ -594,14 +532,14 @@ namespace RageCoop.Server
} }
else else
{ {
Logging.Error("Unhandled Data / Packet type"); Program.Logger.Error("Unhandled Data / Packet type");
} }
break; break;
} }
break; break;
case NetIncomingMessageType.ConnectionLatencyUpdated: case NetIncomingMessageType.ConnectionLatencyUpdated:
{ {
Client client = Clients.Find(x => x.ClientID == message.SenderConnection.RemoteUniqueIdentifier); Client client = Util.GetClientByID(message.SenderConnection.RemoteUniqueIdentifier);
if (client != null) if (client != null)
{ {
client.Latency = message.ReadFloat(); client.Latency = message.ReadFloat();
@ -609,28 +547,28 @@ namespace RageCoop.Server
} }
break; break;
case NetIncomingMessageType.ErrorMessage: case NetIncomingMessageType.ErrorMessage:
Logging.Error(message.ReadString()); Program.Logger.Error(message.ReadString());
break; break;
case NetIncomingMessageType.WarningMessage: case NetIncomingMessageType.WarningMessage:
Logging.Warning(message.ReadString()); Program.Logger.Warning(message.ReadString());
break; break;
case NetIncomingMessageType.DebugMessage: case NetIncomingMessageType.DebugMessage:
case NetIncomingMessageType.VerboseDebugMessage: case NetIncomingMessageType.VerboseDebugMessage:
Logging.Debug(message.ReadString()); Program.Logger.Debug(message.ReadString());
break; break;
default: default:
Logging.Error(string.Format("Unhandled type: {0} {1} bytes {2} | {3}", message.MessageType, message.LengthBytes, message.DeliveryMethod, message.SequenceChannel)); Program.Logger.Error(string.Format("Unhandled type: {0} {1} bytes {2} | {3}", message.MessageType, message.LengthBytes, message.DeliveryMethod, message.SequenceChannel));
break; break;
} }
MainNetServer.Recycle(message); MainNetServer.Recycle(message);
} }
// 16 milliseconds to sleep to reduce CPU usage // 3 milliseconds to sleep to reduce CPU usage
Thread.Sleep(1000 / 60); Thread.Sleep(3);
} }
Logging.Warning("Server is shutting down!"); Program.Logger.Warning("Server is shutting down!");
if (RunningResource != null) if (RunningResource != null)
{ {
// Waiting for resource... // Waiting for resource...
@ -648,36 +586,32 @@ namespace RageCoop.Server
// Sleep for 1 second // Sleep for 1 second
Thread.Sleep(1000); Thread.Sleep(1000);
} }
Program.Logger.Dispose();
} }
private void Background() private void SendLatency()
{ {
while (true) foreach (Client c in Clients.Values)
{ {
foreach(Client c in Clients) MainNetServer.Connections.FindAll(x => x.RemoteUniqueIdentifier != c.NetID).ForEach(x =>
{ {
MainNetServer.Connections.FindAll(x => x.RemoteUniqueIdentifier != c.ClientID).ForEach(x => NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
new Packets.PlayerInfoUpdate()
{ {
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage(); PedID=c.Player.PedID,
new Packets.PlayerInfoUpdate() Username=c.Player.Username,
{ Latency=c.Player.Latency=c.Latency,
PedID=c.Player.PedID, }.Pack(outgoingMessage);
Username=c.Player.Username, MainNetServer.SendMessage(outgoingMessage, x, NetDeliveryMethod.ReliableSequenced, (byte)ConnectionChannel.Default);
Latency=c.Player.Latency=c.Latency, });
}.Pack(outgoingMessage);
MainNetServer.SendMessage(outgoingMessage, x, NetDeliveryMethod.ReliableSequenced, (byte)ConnectionChannel.Default);
});
}
// Update Latency every 20 seconds.
Thread.Sleep(1000*20);
} }
} }
private void DisconnectAndLog(NetConnection senderConnection,PacketTypes type, Exception e) private void DisconnectAndLog(NetConnection senderConnection,PacketTypes type, Exception e)
{ {
Logging.Error($"Error receiving a packet of type {type}"); Program.Logger.Error($"Error receiving a packet of type {type}");
Logging.Error(e.Message); Program.Logger.Error(e.Message);
Logging.Error(e.StackTrace); Program.Logger.Error(e.StackTrace);
senderConnection.Disconnect(e.Message); senderConnection.Disconnect(e.Message);
} }
@ -685,7 +619,7 @@ namespace RageCoop.Server
// Before we approve the connection, we must shake hands // Before we approve the connection, we must shake hands
private void GetHandshake(NetConnection local, Packets.Handshake packet) private void GetHandshake(NetConnection local, Packets.Handshake packet)
{ {
Logging.Debug("New handshake from: [Name: " + packet.Username + " | Address: " + local.RemoteEndPoint.Address.ToString() + "]"); Program.Logger.Debug("New handshake from: [Name: " + packet.Username + " | Address: " + local.RemoteEndPoint.Address.ToString() + "]");
if (!packet.ModVersion.StartsWith(_compatibleVersion)) if (!packet.ModVersion.StartsWith(_compatibleVersion))
{ {
@ -702,11 +636,6 @@ namespace RageCoop.Server
local.Deny("Username contains special chars!"); local.Deny("Username contains special chars!");
return; return;
} }
if (_mainAllowlist.Username.Any() && !_mainAllowlist.Username.Contains(packet.Username.ToLower()))
{
local.Deny("This Username is not on the allow list!");
return;
}
if (_mainBlocklist.Username.Contains(packet.Username.ToLower())) if (_mainBlocklist.Username.Contains(packet.Username.ToLower()))
{ {
local.Deny("This Username has been blocked by this server!"); local.Deny("This Username has been blocked by this server!");
@ -717,7 +646,7 @@ namespace RageCoop.Server
local.Deny("This IP was blocked by this server!"); local.Deny("This IP was blocked by this server!");
return; return;
} }
if (Clients.Any(x => x.Player.Username.ToLower() == packet.Username.ToLower())) if (Clients.Values.Any(x => x.Player.Username.ToLower() == packet.Username.ToLower()))
{ {
local.Deny("Username is already taken!"); local.Deny("Username is already taken!");
return; return;
@ -730,19 +659,20 @@ namespace RageCoop.Server
// Add the player to Players // Add the player to Players
lock (Clients) lock (Clients)
{ {
Clients.Add( Clients.Add(local.RemoteUniqueIdentifier,
tmpClient = new Client() tmpClient = new Client()
{ {
ClientID = local.RemoteUniqueIdentifier, NetID = local.RemoteUniqueIdentifier,
Connection=local,
Player = new() Player = new()
{ {
Username = packet.Username, Username = packet.Username,
PedID=packet.PedID PedID=packet.PedID,
} }
} }
);; );;
} }
Logging.Info($"HandShake sucess, Player:{packet.Username} PedID:{packet.PedID}"); Program.Logger.Info($"Handshake sucess, Player:{packet.Username} PedID:{packet.PedID}");
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage(); NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
// Create a new handshake packet // Create a new handshake packet
@ -751,7 +681,6 @@ namespace RageCoop.Server
PedID = packet.PedID, PedID = packet.PedID,
Username = string.Empty, Username = string.Empty,
ModVersion = string.Empty, ModVersion = string.Empty,
NPCsAllowed = MainSettings.NpcsAllowed
}.Pack(outgoingMessage); }.Pack(outgoingMessage);
// Accept the connection and send back a new handshake packet with the connection ID // Accept the connection and send back a new handshake packet with the connection ID
@ -766,7 +695,7 @@ namespace RageCoop.Server
// The connection has been approved, now we need to send all other players to the new player and the new player to all players // The connection has been approved, now we need to send all other players to the new player and the new player to all players
private static void SendPlayerConnectPacket(NetConnection local) private static void SendPlayerConnectPacket(NetConnection local)
{ {
Client localClient = Clients.Find(x => x.ClientID == local.RemoteUniqueIdentifier); Client localClient = Util.GetClientByID(local.RemoteUniqueIdentifier);
if (localClient == null) if (localClient == null)
{ {
local.Disconnect("No data found!"); local.Disconnect("No data found!");
@ -781,7 +710,7 @@ namespace RageCoop.Server
{ {
long targetNetHandle = targetPlayer.RemoteUniqueIdentifier; long targetNetHandle = targetPlayer.RemoteUniqueIdentifier;
Client targetClient = Clients.Find(x => x.ClientID == targetNetHandle); Client targetClient = Util.GetClientByID(targetNetHandle);
if (targetClient != null) if (targetClient != null)
{ {
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage(); NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
@ -813,7 +742,7 @@ namespace RageCoop.Server
} }
else else
{ {
Logging.Info($"Player {localClient.Player.Username} connected!"); Program.Logger.Info($"Player {localClient.Player.Username} connected!");
} }
if (!string.IsNullOrEmpty(MainSettings.WelcomeMessage)) if (!string.IsNullOrEmpty(MainSettings.WelcomeMessage))
@ -826,7 +755,7 @@ namespace RageCoop.Server
private static void SendPlayerDisconnectPacket(long nethandle) private static void SendPlayerDisconnectPacket(long nethandle)
{ {
List<NetConnection> clients = MainNetServer.Connections.FindAll(x => x.RemoteUniqueIdentifier != nethandle); List<NetConnection> clients = MainNetServer.Connections.FindAll(x => x.RemoteUniqueIdentifier != nethandle);
int playerPedID = Clients.Where(x => x.ClientID==nethandle).First().Player.PedID; int playerPedID = Clients[nethandle].Player.PedID;
if (clients.Count > 0) if (clients.Count > 0)
{ {
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage(); NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
@ -838,13 +767,13 @@ namespace RageCoop.Server
MainNetServer.SendMessage(outgoingMessage, clients, NetDeliveryMethod.ReliableOrdered, 0); MainNetServer.SendMessage(outgoingMessage, clients, NetDeliveryMethod.ReliableOrdered, 0);
} }
Client localClient = Clients.FirstOrDefault(x => x.ClientID == nethandle); Client localClient = Util.GetClientByID( nethandle);
if (localClient == null) if (localClient == null)
{ {
return; return;
} }
Clients.Remove(localClient); Clients.Remove(localClient.NetID);
if (RunningResource != null) if (RunningResource != null)
{ {
@ -852,12 +781,12 @@ namespace RageCoop.Server
} }
else else
{ {
Logging.Info($"Player {localClient.Player.Username} disconnected! ID:{playerPedID}"); Program.Logger.Info($"Player {localClient.Player.Username} disconnected! ID:{playerPedID}");
} }
} }
#region SyncEntities #region SyncEntities
private static void CharacterStateSync(Packets.PedStateSync packet,long ClientID) private static void PedStateSync(Packets.PedStateSync packet,long ClientID)
{ {
@ -868,15 +797,13 @@ namespace RageCoop.Server
} }
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
MainNetServer.Connections.FindAll(x => x.RemoteUniqueIdentifier != ClientID).ForEach(x => packet.Pack(outgoingMessage);
foreach (var c in Clients.Values)
{ {
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage(); if (c.NetID==client.NetID) { continue; }
packet.Pack(outgoingMessage); MainNetServer.SendMessage(outgoingMessage, c.Connection, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.PedSync);
MainNetServer.SendMessage(outgoingMessage, x, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.PedSync); }
});
if (RunningResource != null && packet.ID==client.Player.PedID) if (RunningResource != null && packet.ID==client.Player.PedID)
{ {
RunningResource.InvokePlayerUpdate(client); RunningResource.InvokePlayerUpdate(client);
@ -896,33 +823,47 @@ namespace RageCoop.Server
client.Player.VehicleID = packet.ID; client.Player.VehicleID = packet.ID;
} }
MainNetServer.Connections.FindAll(x => x.RemoteUniqueIdentifier != ClientID).ForEach(x => foreach (var c in Clients.Values)
{ {
if (c.NetID==client.NetID) { continue; }
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage(); NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
packet.Pack(outgoingMessage); packet.Pack(outgoingMessage);
MainNetServer.SendMessage(outgoingMessage, x, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.VehicleSync); MainNetServer.SendMessage(outgoingMessage, c.Connection, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.PedSync);
}
});
} }
private static void CharacterSync(Packets.PedSync packet, long ClientID) private static void PedSync(Packets.PedSync packet, long ClientID)
{ {
Client client = Util.GetClientByID(ClientID); Client client = Util.GetClientByID(ClientID);
if (client == null) if (client == null)
{ {
return; return;
} }
bool isPlayer = packet.ID==client.Player.PedID;
if (isPlayer) { client.Player.Position=packet.Position; }
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
MainNetServer.Connections.FindAll(x => x.RemoteUniqueIdentifier != ClientID).ForEach(x => packet.Pack(outgoingMessage);
foreach (var c in Clients.Values)
{ {
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
packet.Pack(outgoingMessage);
MainNetServer.SendMessage(outgoingMessage, x, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.PedSync);
}); // Don't send data back
if (c.NetID==client.NetID) { continue; }
if (RunningResource != null && packet.ID==client.Player.PedID) // Check streaming distance
if (isPlayer)
{
if ((MainSettings.PlayerStreamingDistance!=-1)&&(packet.Position.DistanceTo(c.Player.Position)>MainSettings.PlayerStreamingDistance))
{
continue;
}
}
else if ((MainSettings.NpcStreamingDistance!=-1)&&(packet.Position.DistanceTo(c.Player.Position)>MainSettings.NpcStreamingDistance))
{
continue;
}
MainNetServer.SendMessage(outgoingMessage,c.Connection, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.PedSync);
}
if (RunningResource != null && isPlayer)
{ {
RunningResource.InvokePlayerUpdate(client); RunningResource.InvokePlayerUpdate(client);
} }
@ -934,43 +875,27 @@ namespace RageCoop.Server
{ {
return; return;
} }
bool isPlayer = packet.ID==client.Player.VehicleID;
MainNetServer.Connections.FindAll(x => x.RemoteUniqueIdentifier != ClientID).ForEach(x => foreach (var c in Clients.Values)
{ {
if (c.NetID==client.NetID) { continue; }
if (isPlayer)
{
// Player's vehicle
if ((MainSettings.PlayerStreamingDistance!=-1)&&(packet.Position.DistanceTo(c.Player.Position)>MainSettings.PlayerStreamingDistance))
{
continue;
}
}
else if((MainSettings.NpcStreamingDistance!=-1)&&(packet.Position.DistanceTo(c.Player.Position)>MainSettings.NpcStreamingDistance))
{
continue;
}
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage(); NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
packet.Pack(outgoingMessage); packet.Pack(outgoingMessage);
MainNetServer.SendMessage(outgoingMessage, x, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.VehicleSync); MainNetServer.SendMessage(outgoingMessage, c.Connection, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.PedSync);
});
/*
Client client = Util.GetClientByID(ClientID);
if (client == null)
{
return;
} }
// Save the new data
client.Player.PedHandle = packet.PedHandle;
client.Player.VehicleHandle = packet.VehicleHandle;
client.Player.IsInVehicle = true;
client.Player.Position = packet.Position;
client.Player.Health = packet.Health;
// Override the latency
packet.Latency = client.Latency;
MainNetServer.Connections.FindAll(x => x.RemoteUniqueIdentifier != ClientID).ForEach(x =>
{
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
packet.PacketToNetOutGoingMessage(outgoingMessage);
MainNetServer.SendMessage(outgoingMessage, x, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.PlayerFull);
});
if (RunningResource != null)
{
RunningResource.InvokePlayerUpdate(client);
}
*/
} }
private static void ProjectileSync(Packets.ProjectileSync packet, long ClientID) private static void ProjectileSync(Packets.ProjectileSync packet, long ClientID)
{ {
@ -980,12 +905,13 @@ namespace RageCoop.Server
return; return;
} }
MainNetServer.Connections.FindAll(x => x.RemoteUniqueIdentifier != ClientID).ForEach(x => foreach (var c in Clients.Values)
{ {
if (c.NetID==client.NetID) { continue; }
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage(); NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
packet.Pack(outgoingMessage); packet.Pack(outgoingMessage);
MainNetServer.SendMessage(outgoingMessage, x, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.ProjectileSync); MainNetServer.SendMessage(outgoingMessage, c.Connection, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.PedSync);
}); }
} }
#endregion #endregion
@ -1004,7 +930,7 @@ namespace RageCoop.Server
CommandContext ctx = new() CommandContext ctx = new()
{ {
Client = Clients.Find(x => x.Player.Username == packet.Username), Client = Clients.Values.Where(x => x.Player.Username == packet.Username).FirstOrDefault(),
Args = argsWithoutCmd Args = argsWithoutCmd
}; };
@ -1048,7 +974,7 @@ namespace RageCoop.Server
SendChatMessage(packet.Username, packet.Message, targets); SendChatMessage(packet.Username, packet.Message, targets);
Logging.Info(packet.Username + ": " + packet.Message); Program.Logger.Info(packet.Username + ": " + packet.Message);
} }
public static void SendChatMessage(string username, string message, List<NetConnection> targets = null) public static void SendChatMessage(string username, string message, List<NetConnection> targets = null)

View File

@ -3,16 +3,22 @@
public class Settings public class Settings
{ {
public int Port { get; set; } = 4499; public int Port { get; set; } = 4499;
public int MaxPlayers { get; set; } = 16; public int MaxPlayers { get; set; } = 32;
public int MaxLatency { get; set; } = 300; public int MaxLatency { get; set; } = 500;
public string Name { get; set; } = "RAGECOOP server"; public string Name { get; set; } = "RAGECOOP server";
public string WelcomeMessage { get; set; } = "Welcome on this server :)"; public string WelcomeMessage { get; set; } = "Welcome on this server :)";
public string Resource { get; set; } = ""; public string Resource { get; set; } = "";
public bool NpcsAllowed { get; set; } = true;
public bool ModsAllowed { get; set; } = false;
public bool UPnP { get; set; } = true; public bool UPnP { get; set; } = true;
public bool AnnounceSelf { get; set; } = false; public bool AnnounceSelf { get; set; } = false;
public string MasterServer { get; set; } = "https://ragecoop.online/gtav/servers"; public string MasterServer { get; set; } = "[AUTO]";
public bool DebugMode { get; set; } = false; public bool DebugMode { get; set; } = false;
/// <summary>
/// NPC data won't be sent to a player if their distance is greater than this value. -1 for unlimited.
/// </summary>
public float NpcStreamingDistance { get; set; } = 1000;
/// <summary>
/// Player's data won't be sent to another player if their distance is greater than this value. -1 for unlimited.
/// </summary>
public float PlayerStreamingDistance { get; set; } = -1;
} }
} }

View File

@ -6,11 +6,30 @@ using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
using RageCoop.Core; using RageCoop.Core;
using Lidgren.Network; using Lidgren.Network;
using System.Net;
namespace RageCoop.Server namespace RageCoop.Server
{ {
static partial class Util static partial class Util
{ {
public static string DownloadString(string url)
{
try
{
// TLS only
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls13 | SecurityProtocolType.Tls12;
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
WebClient client = new();
return client.DownloadString(url);
}
catch
{
return "";
}
}
public static (byte, byte[]) GetBytesFromObject(object obj) public static (byte, byte[]) GetBytesFromObject(object obj)
{ {
return obj switch return obj switch
@ -30,7 +49,8 @@ namespace RageCoop.Server
public static Client GetClientByID(long id) public static Client GetClientByID(long id)
{ {
Client result = Server.Clients.Find(x => x.ClientID == id); Client result = null;
Server.Clients.TryGetValue(id,out result);
if (result == null) if (result == null)
{ {
NetConnection localConn = Server.MainNetServer.Connections.Find(x => id == x.RemoteUniqueIdentifier); NetConnection localConn = Server.MainNetServer.Connections.Find(x => id == x.RemoteUniqueIdentifier);
@ -46,13 +66,13 @@ namespace RageCoop.Server
public static NetConnection GetConnectionByUsername(string username) public static NetConnection GetConnectionByUsername(string username)
{ {
Client client = Server.Clients.Find(x => x.Player.Username.ToLower() == username.ToLower()); Client client = Server.Clients.Values.ToList().Find(x => x.Player.Username.ToLower() == username.ToLower());
if (client == null) if (client == null)
{ {
return null; return null;
} }
return Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == client.ClientID); return Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == client.NetID);
} }
// Return a list of all connections but not the local connection // Return a list of all connections but not the local connection
@ -65,25 +85,6 @@ namespace RageCoop.Server
return new(Server.MainNetServer.Connections.Where(e => e.RemoteUniqueIdentifier != local)); return new(Server.MainNetServer.Connections.Where(e => e.RemoteUniqueIdentifier != local));
} }
// Return a list of players within range of ...
public static List<NetConnection> GetAllInRange(LVector3 position, float range)
{
return new(Server.MainNetServer.Connections.FindAll(e =>
{
Client client = Server.Clients.First(x => x.ClientID == e.RemoteUniqueIdentifier);
return client != null && client.Player.IsInRangeOf(position, range);
}));
}
// Return a list of players within range of ... but not the local one
public static List<NetConnection> GetAllInRange(LVector3 position, float range, NetConnection local)
{
return new(Server.MainNetServer.Connections.Where(e =>
{
Client client = Server.Clients.First(x => x.ClientID == e.RemoteUniqueIdentifier);
return e != local && client != null && client.Player.IsInRangeOf(position, range);
}));
}
public static T Read<T>(string file) where T : new() public static T Read<T>(string file) where T : new()
{ {
XmlSerializer ser = new(typeof(T)); XmlSerializer ser = new(typeof(T));