Compare commits
45 Commits
Author | SHA1 | Date | |
---|---|---|---|
5a455d0487 | |||
11d178498f | |||
88a51cc154 | |||
291ba5691b | |||
de63cd1271 | |||
8479502d75 | |||
051b496021 | |||
2c6f0dbe3d | |||
ffb73c1ce4 | |||
c941ca96fc | |||
e2d4ce2159 | |||
a500a4eeed | |||
603e8af746 | |||
0ae4e1c122 | |||
83f260048d | |||
9b79956c71 | |||
82c6dab4c4 | |||
6611ecac18 | |||
3fa62f1a69 | |||
ad3031ef59 | |||
42d057e2c5 | |||
87b9a67d0b | |||
4fca28f0e0 | |||
8ebf03ca99 | |||
f2760b1533 | |||
7eec12486f | |||
d789e4cb0b | |||
485497286f | |||
a305fb349f | |||
7aa41a6e0c | |||
9d9d421671 | |||
a8a16fac61 | |||
b863b7037a | |||
a33f839004 | |||
a48170fec8 | |||
2181a52d6c | |||
b96d349e4a | |||
ad698a656d | |||
aefea337f1 | |||
811e7df14e | |||
5cc63e688f | |||
08aa1370de | |||
5d6b99442b | |||
65b695cb78 | |||
ce94a9c7af |
@ -11,14 +11,15 @@ namespace RageCoop.Client
|
||||
/// </summary>
|
||||
public static class COOPAPI
|
||||
{
|
||||
|
||||
#region DELEGATES
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// </summary>
|
||||
/// <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>
|
||||
public delegate void ConnectEvent(bool connected, long from, string reason = null);
|
||||
public delegate void ConnectEvent(bool connected, int from, string reason = null);
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// </summary>
|
||||
@ -45,10 +46,6 @@ namespace RageCoop.Client
|
||||
/// ?
|
||||
/// </summary>
|
||||
public static event ChatMessage OnChatMessage;
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// </summary>
|
||||
public static event ModEvent OnModPacketReceived;
|
||||
|
||||
public static void Connected()
|
||||
{
|
||||
@ -60,19 +57,14 @@ namespace RageCoop.Client
|
||||
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);
|
||||
}
|
||||
|
||||
public static void ModPacketReceived(long from, string mod, byte customID, byte[] bytes)
|
||||
{
|
||||
OnModPacketReceived?.Invoke(from, mod, customID, bytes);
|
||||
OnConnection?.Invoke(false, playerID);
|
||||
}
|
||||
|
||||
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>
|
||||
public static void Connect(string serverAddress)
|
||||
{
|
||||
Networking.DisConnectFromServer(serverAddress);
|
||||
Networking.ToggleConnection(serverAddress);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -107,7 +99,7 @@ namespace RageCoop.Client
|
||||
/// </summary>
|
||||
public static void Disconnect()
|
||||
{
|
||||
Networking.DisConnectFromServer(null);
|
||||
Networking.ToggleConnection(null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -122,25 +114,11 @@ namespace RageCoop.Client
|
||||
/// Get the local player's ID
|
||||
/// </summary>
|
||||
/// <returns>PlayerID</returns>
|
||||
public static long GetPlayerID()
|
||||
public static int GetPlayerID()
|
||||
{
|
||||
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>
|
||||
/// Check if a RAGECOOP menu is visible
|
||||
/// </summary>
|
||||
@ -149,7 +127,7 @@ namespace RageCoop.Client
|
||||
#if NON_INTERACTIVE
|
||||
return false;
|
||||
#else
|
||||
return Main.MainMenu.MenuPool.AreAnyVisible;
|
||||
return Menus.CoopMenu.MenuPool.AreAnyVisible;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -177,40 +155,6 @@ namespace RageCoop.Client
|
||||
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>
|
||||
/// Get that player's local username
|
||||
/// </summary>
|
||||
@ -236,35 +180,13 @@ namespace RageCoop.Client
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Enable or disable the local traffic for this player
|
||||
/// Get or set the client's settings.
|
||||
/// </summary>
|
||||
/// <param name="enable">true to disable traffic</param>
|
||||
public static void SetLocalTraffic(bool enable)
|
||||
/// <returns>The client's settings, you should NEVER change settings without notifying the player.</returns>
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -130,7 +130,7 @@ namespace RageCoop.Client
|
||||
s=$@"
|
||||
// {ToMark.DisplayName}
|
||||
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);
|
||||
";
|
||||
}
|
||||
@ -139,7 +139,7 @@ namespace RageCoop.Client
|
||||
s=$@"
|
||||
// {ToMark.DisplayName}
|
||||
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);
|
||||
";
|
||||
}
|
||||
|
@ -21,25 +21,22 @@ namespace RageCoop.Client
|
||||
{
|
||||
|
||||
private bool _gameLoaded = false;
|
||||
private static bool _isGoingToCar = false;
|
||||
|
||||
public static readonly string CurrentVersion = "V0_2";
|
||||
private bool _lastDead = false;
|
||||
public static readonly string CurrentVersion = "V0_4";
|
||||
|
||||
public static int LocalPlayerID=0;
|
||||
public static bool NPCsAllowed = false;
|
||||
|
||||
internal static RelationshipGroup SyncedPedsGroup;
|
||||
|
||||
public static new Settings Settings = null;
|
||||
|
||||
#if !NON_INTERACTIVE
|
||||
public static RageCoopMenu MainMenu = null;
|
||||
#endif
|
||||
public static Chat MainChat = null;
|
||||
public static Stopwatch Counter = new Stopwatch();
|
||||
public static Core.Logging.Logger Logger = null;
|
||||
|
||||
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>>();
|
||||
|
||||
/// <summary>
|
||||
@ -47,7 +44,16 @@ namespace RageCoop.Client
|
||||
/// </summary>
|
||||
public Main()
|
||||
{
|
||||
|
||||
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!
|
||||
/*if (Game.Version < GameVersion.v1_0_1290_1_Steam)
|
||||
{
|
||||
@ -57,7 +63,7 @@ namespace RageCoop.Client
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!_gameLoaded)
|
||||
{
|
||||
GTA.UI.Notification.Show("~r~Please update your GTA5 to v1.0.1290 or newer!", true);
|
||||
@ -71,14 +77,8 @@ namespace RageCoop.Client
|
||||
Settings = Util.ReadSettings();
|
||||
Networking.Start();
|
||||
#if !NON_INTERACTIVE
|
||||
MainMenu = new RageCoopMenu();
|
||||
#endif
|
||||
MainChat = new Chat();
|
||||
#if DEBUG
|
||||
Logger.LogLevel = 0;
|
||||
#else
|
||||
Logger.LogLevel=Settings.LogLevel;
|
||||
#endif
|
||||
|
||||
Tick += OnTick;
|
||||
KeyDown += OnKeyDown;
|
||||
@ -107,14 +107,9 @@ namespace RageCoop.Client
|
||||
}
|
||||
|
||||
#if !NON_INTERACTIVE
|
||||
MainMenu.MenuPool.Process();
|
||||
CoopMenu.MenuPool.Process();
|
||||
#endif
|
||||
|
||||
|
||||
if (_isGoingToCar && Game.Player.Character.IsInVehicle())
|
||||
{
|
||||
_isGoingToCar = false;
|
||||
}
|
||||
DoQueuedActions();
|
||||
if (!Networking.IsOnServer)
|
||||
{
|
||||
@ -130,7 +125,7 @@ namespace RageCoop.Client
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error(ex);
|
||||
Main.Logger.Error(ex);
|
||||
}
|
||||
|
||||
if (!DownloadManager.DownloadComplete)
|
||||
@ -164,9 +159,32 @@ namespace RageCoop.Client
|
||||
|
||||
MainChat.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++;
|
||||
}
|
||||
@ -193,14 +211,20 @@ namespace RageCoop.Client
|
||||
}
|
||||
if (e.KeyCode == Settings.MenuKey)
|
||||
{
|
||||
if (MainMenu.MenuPool.AreAnyVisible)
|
||||
if (CoopMenu.MenuPool.AreAnyVisible)
|
||||
{
|
||||
MainMenu.MainMenu.Visible = false;
|
||||
MainMenu.SubSettings.Menu.Visible = false;
|
||||
CoopMenu.MenuPool.ForEach<LemonUI.Menus.NativeMenu>(x =>
|
||||
{
|
||||
if (x.Visible)
|
||||
{
|
||||
CoopMenu.LastMenu=x;
|
||||
x.Visible=false;
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
MainMenu.MainMenu.Visible = true;
|
||||
CoopMenu.LastMenu.Visible = true;
|
||||
}
|
||||
}
|
||||
else if (Game.IsControlJustPressed(GTA.Control.MultiplayerInfo))
|
||||
@ -234,7 +258,7 @@ namespace RageCoop.Client
|
||||
|
||||
if (V!=null)
|
||||
{
|
||||
var seat = Util.GetNearestSeat(P, V);
|
||||
var seat = P.GetNearestSeat(V);
|
||||
P.Task.EnterVehicle(V, seat);
|
||||
}
|
||||
}
|
||||
@ -311,7 +335,7 @@ namespace RageCoop.Client
|
||||
catch
|
||||
{
|
||||
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}";
|
||||
}
|
||||
}
|
||||
Logger.Trace(s);
|
||||
Main.Logger.Trace(s);
|
||||
return s;
|
||||
}
|
||||
public static string DumpPlayers()
|
||||
@ -390,7 +414,7 @@ namespace RageCoop.Client
|
||||
|
||||
s+=$"\r\nID:{p.PedID} Username:{p.Username}";
|
||||
}
|
||||
Logger.Trace(s);
|
||||
Main.Logger.Trace(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
114
Client/Menus/CoopMenu.cs
Normal file
114
Client/Menus/CoopMenu.cs
Normal 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";
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -29,7 +29,7 @@ namespace RageCoop.Client
|
||||
|
||||
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 { }
|
||||
Update();
|
||||
};
|
||||
@ -55,7 +55,7 @@ namespace RageCoop.Client
|
||||
|
||||
private static void Update()
|
||||
{
|
||||
d1.AltTitle = SyncParameters.PositioinPrediction.ToString();
|
||||
d1.AltTitle = SyncParameters.PositioinPredictionDefault.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ using System.Drawing;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal class DevToolMenu
|
||||
internal static class DevToolMenu
|
||||
{
|
||||
public static NativeMenu Menu = new NativeMenu("RAGECOOP", "DevTool", "Help with the development")
|
||||
{
|
||||
|
148
Client/Menus/Sub/ServersMenu.cs
Normal file
148
Client/Menus/Sub/ServersMenu.cs
Normal 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 "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -4,24 +4,24 @@ using System.Windows.Forms;
|
||||
using GTA;
|
||||
using LemonUI.Menus;
|
||||
|
||||
namespace RageCoop.Client.Menus.Sub
|
||||
namespace RageCoop.Client.Menus
|
||||
{
|
||||
/// <summary>
|
||||
/// Don't use it!
|
||||
/// </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,
|
||||
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 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 _disableTrafficItem = new NativeCheckboxItem("Disable Traffic (NPCs/Vehicles)", "Local traffic only", Main.Settings.DisableTraffic);
|
||||
private static readonly NativeCheckboxItem _flipMenuItem = new NativeCheckboxItem("Flip menu", Main.Settings.FlipMenu);
|
||||
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 _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>
|
||||
/// Don't use it!
|
||||
/// </summary>
|
||||
public SettingsMenu()
|
||||
static SettingsMenu()
|
||||
{
|
||||
Menu.Banner.Color = Color.FromArgb(225, 0, 0, 0);
|
||||
Menu.Title.Color = Color.FromArgb(255, 165, 0);
|
||||
@ -52,14 +52,14 @@ namespace RageCoop.Client.Menus.Sub
|
||||
Menu.Add(_vehicleSoftLimit);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void _disablePauseAlt_CheckboxChanged(object sender, EventArgs e)
|
||||
|
||||
private static void _disablePauseAlt_CheckboxChanged(object sender, EventArgs e)
|
||||
{
|
||||
Main.Settings.DisableAlternatePause=_disablePauseAlt.Checked;
|
||||
Util.SaveSettings();
|
||||
}
|
||||
private void vehicleSoftLimit_Activated(object sender, EventArgs e)
|
||||
private static void vehicleSoftLimit_Activated(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -71,7 +71,7 @@ namespace RageCoop.Client.Menus.Sub
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
private void ChaneMenuKey(object sender, EventArgs e)
|
||||
private static void ChaneMenuKey(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -85,7 +85,7 @@ namespace RageCoop.Client.Menus.Sub
|
||||
catch { }
|
||||
}
|
||||
|
||||
private void ChangePassengerKey(object sender, EventArgs e)
|
||||
private static void ChangePassengerKey(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -99,22 +99,22 @@ namespace RageCoop.Client.Menus.Sub
|
||||
catch { }
|
||||
}
|
||||
|
||||
public void DisableTrafficCheckboxChanged(object a, System.EventArgs b)
|
||||
public static void DisableTrafficCheckboxChanged(object a, System.EventArgs b)
|
||||
{
|
||||
Main.Settings.DisableTraffic = _disableTrafficItem.Checked;
|
||||
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;
|
||||
Main.Settings.FlipMenu = _flipMenuItem.Checked;
|
||||
Util.SaveSettings();
|
||||
}
|
||||
|
||||
public void ShowNetworkInfoCheckboxChanged(object a, System.EventArgs b)
|
||||
public static void ShowNetworkInfoCheckboxChanged(object a, System.EventArgs b)
|
||||
{
|
||||
Networking.ShowNetworkInfo = _showNetworkInfoItem.Checked;
|
||||
|
||||
|
@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -8,7 +8,7 @@ using GTA.Native;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
public class Chat
|
||||
internal class Chat
|
||||
{
|
||||
private readonly Scaleform MainScaleForm;
|
||||
|
||||
|
@ -4,7 +4,7 @@ using System.Collections.Generic;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
public static class DownloadManager
|
||||
internal static class DownloadManager
|
||||
{
|
||||
private static readonly List<DownloadFile> _downloadFiles = new List<DownloadFile>();
|
||||
private static readonly Dictionary<byte, FileStream> _streams = new Dictionary<byte, FileStream>();
|
||||
|
@ -6,7 +6,7 @@ using Lidgren.Network;
|
||||
using RageCoop.Core;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
using GTA.Native;
|
||||
|
||||
namespace RageCoop.Client
|
||||
@ -20,7 +20,7 @@ namespace RageCoop.Client
|
||||
public static int BytesSend = 0;
|
||||
private static Thread ReceiveThread;
|
||||
|
||||
public static void DisConnectFromServer(string address)
|
||||
public static void ToggleConnection(string address)
|
||||
{
|
||||
if (IsOnServer)
|
||||
{
|
||||
@ -31,7 +31,7 @@ namespace RageCoop.Client
|
||||
// 623c92c287cc392406e7aaaac1c0f3b0 = RAGECOOP
|
||||
NetPeerConfiguration config = new NetPeerConfiguration("623c92c287cc392406e7aaaac1c0f3b0")
|
||||
{
|
||||
AutoFlushSendQueue = true
|
||||
AutoFlushSendQueue = false
|
||||
};
|
||||
|
||||
config.EnableMessageType(NetIncomingMessageType.ConnectionLatencyUpdated);
|
||||
@ -62,7 +62,6 @@ namespace RageCoop.Client
|
||||
PedID = Main.LocalPlayerID,
|
||||
Username = Main.Settings.Username,
|
||||
ModVersion = Main.CurrentVersion,
|
||||
NPCsAllowed = false
|
||||
}.Pack(outgoingMessage);
|
||||
|
||||
Client.Connect(ip[0], short.Parse(ip[1]), outgoingMessage);
|
||||
@ -80,7 +79,11 @@ namespace RageCoop.Client
|
||||
{
|
||||
try
|
||||
{
|
||||
ReceiveMessages();
|
||||
if (Client!=null)
|
||||
{
|
||||
Client.FlushSendQueue();
|
||||
ReceiveMessages();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -144,8 +147,8 @@ namespace RageCoop.Client
|
||||
case string _:
|
||||
arguments.Add((string)x);
|
||||
break;
|
||||
case LVector3 _:
|
||||
LVector3 vector = (LVector3)x;
|
||||
case Vector3 _:
|
||||
Vector3 vector = (Vector3)x;
|
||||
arguments.Add((float)vector.X);
|
||||
arguments.Add((float)vector.Y);
|
||||
arguments.Add((float)vector.Z);
|
||||
@ -173,7 +176,7 @@ namespace RageCoop.Client
|
||||
case 0x03: // string
|
||||
return Function.Call<string>((Hash)hash, arguments.ToArray());
|
||||
case 0x04: // vector3
|
||||
return Function.Call<GTA.Math.Vector3>((Hash)hash, arguments.ToArray()).ToLVector();
|
||||
return Function.Call<Vector3>((Hash)hash, arguments.ToArray());
|
||||
default:
|
||||
GTA.UI.Notification.Show("[DecodeNativeCall][" + hash + "]: Type of return not found!");
|
||||
return null;
|
||||
|
@ -5,6 +5,7 @@ using System.Diagnostics;
|
||||
using Lidgren.Network;
|
||||
using RageCoop.Core;
|
||||
using GTA;
|
||||
using RageCoop.Client.Menus;
|
||||
using GTA.Math;
|
||||
using GTA.Native;
|
||||
|
||||
@ -36,7 +37,7 @@ namespace RageCoop.Client
|
||||
{
|
||||
case NetConnectionStatus.InitiatedConnect:
|
||||
#if !NON_INTERACTIVE
|
||||
Main.MainMenu.InitiateConnectionMenuSetting();
|
||||
CoopMenu.InitiateConnectionMenuSetting();
|
||||
#endif
|
||||
Main.QueueAction(() => { GTA.UI.Notification.Show("~y~Trying to connect..."); return true; });
|
||||
break;
|
||||
@ -53,17 +54,13 @@ namespace RageCoop.Client
|
||||
Packets.Handshake handshakePacket = new Packets.Handshake();
|
||||
handshakePacket.Unpack(data);
|
||||
|
||||
// Main.LocalNetHandle = handshakePacket.NetHandle;
|
||||
Main.NPCsAllowed = handshakePacket.NPCsAllowed;
|
||||
|
||||
|
||||
#if !NON_INTERACTIVE
|
||||
|
||||
#endif
|
||||
|
||||
COOPAPI.Connected();
|
||||
Main.QueueAction(() => {
|
||||
Main.MainMenu.ConnectedMenuSetting();
|
||||
CoopMenu.ConnectedMenuSetting();
|
||||
Main.MainChat.Init();
|
||||
PlayerList.Cleanup();
|
||||
GTA.UI.Notification.Show("~g~Connected!");
|
||||
@ -78,9 +75,7 @@ namespace RageCoop.Client
|
||||
// Reset all values
|
||||
Latency = 0;
|
||||
|
||||
Main.QueueAction(() => { Main.CleanUpWorld();});
|
||||
|
||||
Main.NPCsAllowed = false;
|
||||
Main.QueueAction(() => Main.CleanUpWorld());
|
||||
|
||||
if (Main.MainChat.Focused)
|
||||
{
|
||||
@ -90,7 +85,7 @@ namespace RageCoop.Client
|
||||
Main.QueueAction(() => Main.CleanUp());
|
||||
|
||||
#if !NON_INTERACTIVE
|
||||
Main.MainMenu.DisconnectedMenuSetting();
|
||||
CoopMenu.DisconnectedMenuSetting();
|
||||
#endif
|
||||
|
||||
COOPAPI.Disconnected(reason);
|
||||
@ -227,8 +222,7 @@ namespace RageCoop.Client
|
||||
{
|
||||
Packets.Mod packet = new Packets.Mod();
|
||||
packet.Unpack(data);
|
||||
COOPAPI.ModPacketReceived(packet.NetHandle, packet.Name, packet.CustomPacketID, packet.Bytes);
|
||||
|
||||
// Need to do some stuff here
|
||||
}
|
||||
break;
|
||||
case PacketTypes.FileTransferTick:
|
||||
@ -307,20 +301,19 @@ namespace RageCoop.Client
|
||||
|
||||
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}");
|
||||
|
||||
EntityPool.ThreadSafe.Add(new SyncedPed(packet.ID));
|
||||
EntityPool.ThreadSafe.Add(c=new SyncedPed(packet.ID));
|
||||
}
|
||||
PedDataFlags flags = packet.Flag;
|
||||
SyncedPed c = EntityPool.GetPedByID(packet.ID);
|
||||
c.ID=packet.ID;
|
||||
//c.OwnerID=packet.OwnerID;
|
||||
c.Health = packet.Health;
|
||||
c.Position = packet.Position.ToVector();
|
||||
c.Rotation = packet.Rotation.ToVector();
|
||||
c.Velocity = packet.Velocity.ToVector();
|
||||
c.Position = packet.Position;
|
||||
c.Rotation = packet.Rotation;
|
||||
c.Velocity = packet.Velocity;
|
||||
c.Speed = packet.Speed;
|
||||
c.CurrentWeaponHash = packet.CurrentWeaponHash;
|
||||
c.IsAiming = flags.HasFlag(PedDataFlags.IsAiming);
|
||||
@ -337,53 +330,47 @@ namespace RageCoop.Client
|
||||
c.LastSynced = Main.Ticked;
|
||||
if (c.IsAiming)
|
||||
{
|
||||
c.AimCoords = packet.AimCoords.ToVector();
|
||||
c.AimCoords = packet.AimCoords;
|
||||
}
|
||||
if (c.IsRagdoll)
|
||||
{
|
||||
c.RotationVelocity=packet.RotationVelocity.ToVector();
|
||||
c.RotationVelocity=packet.RotationVelocity;
|
||||
}
|
||||
}
|
||||
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);
|
||||
if (c==null) { return; }
|
||||
c.ID=packet.ID;
|
||||
c.OwnerID=packet.OwnerID;
|
||||
c.Clothes=packet.Clothes;
|
||||
c.WeaponComponents=packet.WeaponComponents;
|
||||
c.ModelHash=packet.ModelHash;
|
||||
c.LastSynced=c.LastStateSynced = Main.Ticked;
|
||||
c.LastStateSynced = Main.Ticked;
|
||||
}
|
||||
private static void VehicleSync(Packets.VehicleSync packet)
|
||||
{
|
||||
if (!EntityPool.VehicleExists(packet.ID))
|
||||
SyncedVehicle v = EntityPool.GetVehicleByID(packet.ID);
|
||||
if (v==null)
|
||||
{
|
||||
EntityPool.ThreadSafe.Add(new SyncedVehicle(packet.ID));
|
||||
EntityPool.ThreadSafe.Add(v=new SyncedVehicle(packet.ID));
|
||||
}
|
||||
SyncedVehicle v = EntityPool.GetVehicleByID(packet.ID);
|
||||
if (v.IsMine) { return; }
|
||||
v.ID= packet.ID;
|
||||
v.Position=packet.Position.ToVector();
|
||||
v.Rotation=packet.Rotation.ToVector();
|
||||
v.Position=packet.Position;
|
||||
v.Quaternion=packet.Quaternion;
|
||||
v.SteeringAngle=packet.SteeringAngle;
|
||||
v.ThrottlePower=packet.ThrottlePower;
|
||||
v.BrakePower=packet.BrakePower;
|
||||
v.Velocity=packet.Velocity.ToVector();
|
||||
v.RotationVelocity=packet.RotationVelocity.ToVector();
|
||||
v.Velocity=packet.Velocity;
|
||||
v.RotationVelocity=packet.RotationVelocity;
|
||||
v.DeluxoWingRatio=packet.DeluxoWingRatio;
|
||||
v.LastSynced=Main.Ticked;
|
||||
}
|
||||
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);
|
||||
if (v==null||v.IsMine) { return; }
|
||||
v.ID= packet.ID;
|
||||
v.OwnerID= packet.OwnerID;
|
||||
v.DamageModel=packet.DamageModel;
|
||||
@ -403,6 +390,8 @@ namespace RageCoop.Client
|
||||
v.Transformed = packet.Flag.HasFlag(VehicleDataFlags.IsTransformed);
|
||||
v.Passengers=new Dictionary<VehicleSeat, SyncedPed>();
|
||||
v.LockStatus=packet.LockStatus;
|
||||
v.RadioStation=packet.RadioStation;
|
||||
v.Flags=packet.Flag;
|
||||
foreach (KeyValuePair<int, int> pair in packet.Passengers)
|
||||
{
|
||||
if (EntityPool.PedExists(pair.Value))
|
||||
@ -410,7 +399,7 @@ namespace RageCoop.Client
|
||||
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)
|
||||
@ -422,9 +411,9 @@ namespace RageCoop.Client
|
||||
Main.Logger.Debug($"Creating new projectile: {(WeaponHash)packet.WeaponHash}");
|
||||
EntityPool.ThreadSafe.Add(p=new SyncedProjectile(packet.ID));
|
||||
}
|
||||
p.Position=packet.Position.ToVector();
|
||||
p.Rotation=packet.Rotation.ToVector();
|
||||
p.Velocity=packet.Velocity.ToVector();
|
||||
p.Position=packet.Position;
|
||||
p.Rotation=packet.Rotation;
|
||||
p.Velocity=packet.Velocity;
|
||||
p.Hash=(WeaponHash)packet.WeaponHash;
|
||||
p.ShooterID=packet.ShooterID;
|
||||
p.Exploded=packet.Exploded;
|
||||
|
@ -36,9 +36,9 @@ namespace RageCoop.Client
|
||||
{
|
||||
ID =c.ID,
|
||||
Health = p.Health,
|
||||
Position = p.Position.ToLVector(),
|
||||
Rotation = p.Rotation.ToLVector(),
|
||||
Velocity = p.Velocity.ToLVector(),
|
||||
Position = p.Position,
|
||||
Rotation = p.Rotation,
|
||||
Velocity = p.Velocity,
|
||||
Speed = p.GetPedSpeed(),
|
||||
CurrentWeaponHash = (uint)p.Weapons.Current.Hash,
|
||||
Flag = p.GetPedFlags(),
|
||||
@ -46,11 +46,11 @@ namespace RageCoop.Client
|
||||
};
|
||||
if (packet.Flag.HasFlag(PedDataFlags.IsAiming))
|
||||
{
|
||||
packet.AimCoords = p.GetAimCoord().ToLVector();
|
||||
packet.AimCoords = p.GetAimCoord();
|
||||
}
|
||||
if (packet.Flag.HasFlag(PedDataFlags.IsRagdoll))
|
||||
{
|
||||
packet.RotationVelocity=p.RotationVelocity.ToLVector();
|
||||
packet.RotationVelocity=p.RotationVelocity;
|
||||
}
|
||||
Send(packet, ConnectionChannel.PedSync);
|
||||
}
|
||||
@ -76,13 +76,15 @@ namespace RageCoop.Client
|
||||
{
|
||||
ID =v.ID,
|
||||
SteeringAngle = veh.SteeringAngle,
|
||||
Position = veh.Position.ToLVector(),
|
||||
Rotation = veh.Rotation.ToLVector(),
|
||||
Velocity = veh.Velocity.ToLVector(),
|
||||
RotationVelocity=veh.RotationVelocity.ToLVector(),
|
||||
Position = veh.PredictPosition(),
|
||||
Quaternion=veh.Quaternion,
|
||||
// Rotation = veh.Rotation,
|
||||
Velocity = veh.Velocity,
|
||||
RotationVelocity=veh.RotationVelocity,
|
||||
ThrottlePower = veh.ThrottlePower,
|
||||
BrakePower = veh.BrakePower,
|
||||
};
|
||||
if (v.MainVehicle.Model.Hash==1483171323) { packet.DeluxoWingRatio=v.MainVehicle.GetDeluxoWingRatio(); }
|
||||
Send(packet,ConnectionChannel.VehicleSync);
|
||||
}
|
||||
public static void SendVehicleState(SyncedVehicle v)
|
||||
@ -108,6 +110,10 @@ namespace RageCoop.Client
|
||||
Passengers=veh.GetPassengers(),
|
||||
LockStatus=veh.LockStatus,
|
||||
};
|
||||
if (v.MainVehicle==Game.Player.LastVehicle)
|
||||
{
|
||||
packet.RadioStation=Util.GetPlayerRadioIndex();
|
||||
}
|
||||
Send(packet, ConnectionChannel.VehicleSync);
|
||||
}
|
||||
public static void SendProjectile(SyncedProjectile sp)
|
||||
@ -117,9 +123,9 @@ namespace RageCoop.Client
|
||||
{
|
||||
ID =sp.ID,
|
||||
ShooterID=sp.ShooterID,
|
||||
Position=p.Position.ToLVector(),
|
||||
Rotation=p.Rotation.ToLVector(),
|
||||
Velocity=p.Velocity.ToLVector(),
|
||||
Position=p.Position,
|
||||
Rotation=p.Rotation,
|
||||
Velocity=p.Velocity,
|
||||
WeaponHash=(uint)p.WeaponHash,
|
||||
Exploded=p.IsDead
|
||||
};
|
||||
@ -133,8 +139,8 @@ namespace RageCoop.Client
|
||||
{
|
||||
Send(new Packets.BulletShot()
|
||||
{
|
||||
StartPosition = start.ToLVector(),
|
||||
EndPosition = end.ToLVector(),
|
||||
StartPosition = start,
|
||||
EndPosition = end,
|
||||
OwnerID = ownerID,
|
||||
WeaponHash=weapon,
|
||||
}, ConnectionChannel.SyncEvents);
|
||||
@ -149,27 +155,6 @@ namespace RageCoop.Client
|
||||
Client.SendMessage(outgoingMessage, NetDeliveryMethod.ReliableOrdered, (byte)ConnectionChannel.Chat);
|
||||
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 (ShowNetworkInfo)
|
||||
{
|
||||
@ -193,19 +178,6 @@ namespace RageCoop.Client
|
||||
}
|
||||
#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
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ namespace RageCoop.Client
|
||||
|
||||
if ((Util.GetTickCount64() - Pressed) < 5000 && !Main.MainChat.Focused
|
||||
#if !NON_INTERACTIVE
|
||||
&& !Main.MainMenu.MenuPool.AreAnyVisible
|
||||
&& !Menus.CoopMenu.MenuPool.AreAnyVisible
|
||||
#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_TITLE", "Player list", (Players.Count) + " players");
|
||||
_mainScaleform.CallFunction("SET_TITLE", "Player list", $"{Players.Count+1} players");
|
||||
_mainScaleform.CallFunction("DISPLAY_VIEW");
|
||||
}
|
||||
public static void SetPlayer(int id, string username,float latency=0)
|
||||
|
@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("0.2.0.0")]
|
||||
[assembly: AssemblyFileVersion("0.2.0.0")]
|
||||
[assembly: AssemblyVersion("0.4.0.0")]
|
||||
[assembly: AssemblyFileVersion("0.4.0.0")]
|
||||
|
@ -123,12 +123,19 @@
|
||||
<ItemGroup>
|
||||
<Compile Include="DevTools\DevTool.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="COOPAPI.cs" />
|
||||
<Compile Include="Debug.cs" />
|
||||
<Compile Include="Networking\DownloadManager.cs" />
|
||||
<Compile Include="Misc\TaskType.cs" />
|
||||
<Compile Include="Util\TaskType.cs" />
|
||||
<Compile Include="Menus\Sub\DebugMenu.cs" />
|
||||
<Compile Include="Networking\Receive.cs" />
|
||||
<Compile Include="Networking\Send.cs" />
|
||||
@ -142,13 +149,13 @@
|
||||
<Compile Include="Sync\Entities\SyncedVehicle.cs" />
|
||||
<Compile Include="Main.cs" />
|
||||
<Compile Include="Networking\MapLoader.cs" />
|
||||
<Compile Include="Menus\RageCoopMenu.cs" />
|
||||
<Compile Include="Menus\CoopMenu.cs" />
|
||||
<Compile Include="Menus\Sub\SettingsMenu.cs" />
|
||||
<Compile Include="Networking\Networking.cs" />
|
||||
<Compile Include="PlayerList.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Sync\SyncParameters.cs" />
|
||||
<Compile Include="Misc\Util.cs" />
|
||||
<Compile Include="Util\PedExtensions.cs" />
|
||||
<Compile Include="WorldThread.cs" />
|
||||
<Compile Include="Settings.cs" />
|
||||
</ItemGroup>
|
||||
|
15
Client/Scripting/ClientScript.cs
Normal file
15
Client/Scripting/ClientScript.cs
Normal 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
|
||||
{
|
||||
}
|
||||
}
|
19
Client/Scripting/Engine.cs
Normal file
19
Client/Scripting/Engine.cs
Normal file
@ -0,0 +1,19 @@
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -18,7 +18,7 @@ namespace RageCoop.Client
|
||||
/// <summary>
|
||||
/// Don't use it!
|
||||
/// </summary>
|
||||
public string MasterServer { get; set; } = "https://ragecoop.online/gtav/servers";
|
||||
public string MasterServer { get; set; } = "[AUTO]";
|
||||
/// <summary>
|
||||
/// Don't use it!
|
||||
/// </summary>
|
||||
@ -54,7 +54,10 @@ namespace RageCoop.Client
|
||||
/// The game won't spawn more NPC traffic if the limit is exceeded. -1 for unlimited (not recommended).
|
||||
/// </summary>
|
||||
public int WorldVehicleSoftLimit { get; set; } = 35;
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Disable automatic respawn.
|
||||
/// </summary>
|
||||
public bool DisableAutoRespawn { get; set; } = false;
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ using GTA.Math;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
public abstract class SyncedEntity
|
||||
internal abstract class SyncedEntity
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
@ -56,8 +56,13 @@ namespace RageCoop.Client
|
||||
|
||||
public Vector3 Position { get; set; }
|
||||
public Vector3 Rotation { get; set; }
|
||||
public Quaternion Quaternion { get; set; }
|
||||
public Vector3 Velocity { get; set; }
|
||||
public abstract void Update();
|
||||
public void PauseUpdate(ulong frames)
|
||||
{
|
||||
LastUpdated=Main.Ticked+frames;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ namespace RageCoop.Client
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// </summary>
|
||||
public partial class SyncedPed:SyncedEntity
|
||||
internal class SyncedPed:SyncedEntity
|
||||
{
|
||||
#region CONSTRUCTORS
|
||||
|
||||
@ -30,6 +30,10 @@ namespace RageCoop.Client
|
||||
MainPed=p;
|
||||
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>
|
||||
@ -77,6 +81,7 @@ namespace RageCoop.Client
|
||||
public Vector3 RotationVelocity { get; set; }
|
||||
public Vector3 AimCoords { get; set; }
|
||||
|
||||
private WeaponAsset WeaponAsset { get; set; }
|
||||
|
||||
|
||||
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_GET_OUT_UPSIDE_DOWN_VEHICLE, MainPed.Handle, false);
|
||||
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.CanWrithe=false;
|
||||
MainPed.CanBeDraggedOutOfVehicle = true;
|
||||
MainPed.IsOnlyDamagedByPlayer = false;
|
||||
MainPed.RelationshipGroup=Main.SyncedPedsGroup;
|
||||
if (IsPlayer)
|
||||
{
|
||||
MainPed.IsInvincible=true;
|
||||
}
|
||||
MainPed.IsFireProof=false;
|
||||
MainPed.IsExplosionProof=false;
|
||||
|
||||
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();
|
||||
|
||||
if (IsPlayer)
|
||||
@ -265,7 +279,8 @@ namespace RageCoop.Client
|
||||
MainPed.AttachedBlip.Color = BlipColor.White;
|
||||
MainPed.AttachedBlip.Scale = 0.8f;
|
||||
MainPed.AttachedBlip.Name =Username;
|
||||
|
||||
|
||||
MainPed.IsInvincible=true;
|
||||
}
|
||||
|
||||
// Add to EntityPool so this Character can be accessed by handle.
|
||||
@ -304,7 +319,6 @@ namespace RageCoop.Client
|
||||
private int _lastWeaponObj = 0;
|
||||
#endregion
|
||||
|
||||
private bool _isPlayingAnimation = false;
|
||||
private string[] _currentAnimation = new string[2] { "", "" };
|
||||
|
||||
private void DisplayOnFoot()
|
||||
@ -514,12 +528,6 @@ namespace RageCoop.Client
|
||||
*/
|
||||
SmoothTransition();
|
||||
}
|
||||
else if (_currentAnimation[1] == "reload_aim")
|
||||
{
|
||||
MainPed.Task.ClearAnimation(_currentAnimation[0], _currentAnimation[1]);
|
||||
_isPlayingAnimation = false;
|
||||
_currentAnimation = new string[2] { "", "" };
|
||||
}
|
||||
else if (IsInCover)
|
||||
{
|
||||
|
||||
@ -569,11 +577,13 @@ namespace RageCoop.Client
|
||||
}
|
||||
|
||||
#region WEAPON
|
||||
WeaponHash appliedWeaponhash = WeaponHash.Unarmed;
|
||||
private void CheckCurrentWeapon()
|
||||
{
|
||||
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();
|
||||
_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;
|
||||
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|| MainPed.IsDead))
|
||||
{
|
||||
|
@ -16,7 +16,7 @@ namespace RageCoop.Client
|
||||
IsMine=true;
|
||||
MainProjectile = p;
|
||||
Origin=p.Position;
|
||||
var shooter = EntityPool.GetPedByHandle(p.Owner.Handle);
|
||||
var shooter = EntityPool.GetPedByHandle((p.Owner?.Handle).GetValueOrDefault());
|
||||
if(shooter != null)
|
||||
{
|
||||
ShooterID=shooter.ID;
|
||||
@ -24,14 +24,14 @@ namespace RageCoop.Client
|
||||
else
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
ShooterID=shooterVeh.MainVehicle.Driver.GetSyncEntity().ID;
|
||||
}
|
||||
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 Projectile MainProjectile { get; set; }
|
||||
public int ShooterID { get; set; }
|
||||
|
||||
private SyncedPed Shooter { get;set; }
|
||||
public Vector3 Origin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@ -75,9 +75,17 @@ namespace RageCoop.Client
|
||||
{
|
||||
Asset=new WeaponAsset(Hash);
|
||||
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();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ using RageCoop.Core;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
public class SyncedVehicle : SyncedEntity
|
||||
internal class SyncedVehicle : SyncedEntity
|
||||
{
|
||||
|
||||
#region -- CONSTRUCTORS --
|
||||
@ -52,10 +52,9 @@ namespace RageCoop.Client
|
||||
#region LAST STATE STORE
|
||||
|
||||
|
||||
private ulong _vehicleStopTime { get; set; }
|
||||
private byte[] _lastVehicleColors = new byte[] { 0, 0 };
|
||||
private Dictionary<int, int> _lastVehicleMods = new Dictionary<int, int>();
|
||||
|
||||
private byte _lastRadioIndex=255;
|
||||
#endregion
|
||||
|
||||
#region -- CRITICAL STUFF --
|
||||
@ -63,9 +62,11 @@ namespace RageCoop.Client
|
||||
public float SteeringAngle { get; set; }
|
||||
public float ThrottlePower { get; set; }
|
||||
public float BrakePower { get; set; }
|
||||
public float DeluxoWingRatio { get; set; } = -1;
|
||||
#endregion
|
||||
|
||||
#region -- VEHICLE STATE --
|
||||
public VehicleDataFlags Flags { get; set; }
|
||||
public bool EngineRunning { get; set; }
|
||||
private bool _lastTransformed = false;
|
||||
public bool Transformed { get; set; }
|
||||
@ -88,7 +89,7 @@ namespace RageCoop.Client
|
||||
/// VehicleSeat,PedID
|
||||
/// </summary>
|
||||
public Dictionary<VehicleSeat, SyncedPed> Passengers { get; set; }
|
||||
|
||||
public byte RadioStation = 255;
|
||||
private long _lastPositionCalibrated { get; set; }
|
||||
|
||||
#endregion
|
||||
@ -99,10 +100,8 @@ namespace RageCoop.Client
|
||||
|
||||
// Check if all data avalible
|
||||
if(!IsReady) { return; }
|
||||
|
||||
// Skip update if no new sync message has arrived.
|
||||
if (!NeedUpdate) { return; }
|
||||
|
||||
#endregion
|
||||
#region -- CHECK EXISTENCE --
|
||||
if ((MainVehicle == null) || (!MainVehicle.Exists()) || (MainVehicle.Model.Hash != ModelHash))
|
||||
@ -129,27 +128,22 @@ namespace RageCoop.Client
|
||||
}
|
||||
if (MainVehicle.Position.DistanceTo(Position)<5)
|
||||
{
|
||||
MainVehicle.Velocity = Velocity+5*(Position+Velocity*SyncParameters.PositioinPrediction - MainVehicle.Position);
|
||||
_lastPositionCalibrated=Main.Counter.ElapsedMilliseconds;
|
||||
MainVehicle.Velocity = Velocity+5*(Position+Velocity*SyncParameters.PositioinPredictionDefault - MainVehicle.Position);
|
||||
MainVehicle.Quaternion=Quaternion.Slerp(MainVehicle.Quaternion, Quaternion, 0.35f);
|
||||
}
|
||||
else
|
||||
{
|
||||
MainVehicle.Position=Position;
|
||||
MainVehicle.Velocity=Velocity;
|
||||
MainVehicle.Quaternion=Quaternion;
|
||||
}
|
||||
Vector3 r = GetCalibrationRotation();
|
||||
if (r.Length() < 20f)
|
||||
// Vector3 r = GetCalibrationRotation();
|
||||
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
|
||||
|
||||
if (LastStateSynced>LastUpdated)
|
||||
{
|
||||
#region -- SYNC STATE --
|
||||
@ -168,7 +162,11 @@ namespace RageCoop.Client
|
||||
{
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -303,7 +301,20 @@ namespace RageCoop.Client
|
||||
|
||||
}
|
||||
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
|
||||
}
|
||||
@ -311,6 +322,8 @@ namespace RageCoop.Client
|
||||
}
|
||||
private Vector3 GetCalibrationRotation()
|
||||
{
|
||||
return (Quaternion-MainVehicle.Quaternion).ToEulerAngles().ToDegree();
|
||||
/*
|
||||
var r = Rotation-MainVehicle.Rotation;
|
||||
if (r.X>180) { r.X=r.X-360; }
|
||||
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; }
|
||||
else if (r.Z<-180) { r.Z=360+r.Z; }
|
||||
return r;
|
||||
*/
|
||||
}
|
||||
private void CreateVehicle()
|
||||
{
|
||||
@ -336,7 +350,7 @@ namespace RageCoop.Client
|
||||
{
|
||||
EntityPool.Add( this);
|
||||
}
|
||||
MainVehicle.Rotation = Rotation;
|
||||
MainVehicle.Quaternion = Quaternion;
|
||||
|
||||
if (MainVehicle.HasRoof)
|
||||
{
|
||||
@ -385,7 +399,9 @@ namespace RageCoop.Client
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region OUTGOING
|
||||
public float LastNozzleAngle { get; set; }
|
||||
#endregion
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -388,6 +388,7 @@ namespace RageCoop.Client
|
||||
|
||||
if (Main.Ticked%20==0)
|
||||
{
|
||||
Networking.SendPed(c);
|
||||
Networking.SendPedState(c);
|
||||
}
|
||||
else
|
||||
@ -449,10 +450,11 @@ namespace RageCoop.Client
|
||||
// Outgoing sync
|
||||
if (v.IsMine)
|
||||
{
|
||||
SyncEvents.Check(v);
|
||||
if (Main.Ticked%20==0)
|
||||
{
|
||||
Networking.SendVehicle(v);
|
||||
Networking.SendVehicleState(v);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -12,7 +12,6 @@ using System.Threading;
|
||||
namespace RageCoop.Client {
|
||||
internal static class SyncEvents
|
||||
{
|
||||
|
||||
#region TRIGGER
|
||||
public static void TriggerPedKilled(SyncedPed victim)
|
||||
{
|
||||
@ -34,9 +33,9 @@ namespace RageCoop.Client {
|
||||
{
|
||||
if (seat==VehicleSeat.Driver)
|
||||
{
|
||||
TriggerChangeOwner(veh, c.ID);
|
||||
veh.OwnerID=Main.LocalPlayerID;
|
||||
veh.LastSynced=Main.Ticked;
|
||||
TriggerChangeOwner(veh, c.ID);
|
||||
}
|
||||
Networking.Send(new Packets.EnteredVehicle()
|
||||
{
|
||||
@ -61,13 +60,6 @@ namespace RageCoop.Client {
|
||||
{
|
||||
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();
|
||||
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)
|
||||
{
|
||||
if (hash==(uint)VehicleWeaponHash.PlayerBuzzard)
|
||||
{
|
||||
hash=(uint)WeaponHash.HeavyRifle;
|
||||
}
|
||||
// ANNIHL
|
||||
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; }
|
||||
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
|
||||
|
||||
#region HANDLE
|
||||
|
||||
public static ParticleEffectAsset CorePFXAsset = new ParticleEffectAsset("core");
|
||||
|
||||
static WeaponAsset _weaponAsset = default;
|
||||
static uint _lastWeaponHash;
|
||||
|
||||
private static void HandleLeaveVehicle(Packets.LeaveVehicle p)
|
||||
{
|
||||
var ped = EntityPool.GetPedByID(p.ID)?.MainPed;
|
||||
var ped = EntityPool.GetPedByID(p.ID);
|
||||
var flag = LeaveVehicleFlags.None;
|
||||
if (ped.MainPed?.CurrentVehicle==null) { return; }
|
||||
// Bail out
|
||||
if (ped?.CurrentVehicle==null) { return; }
|
||||
if (ped.CurrentVehicle.Speed>5) { flag|=LeaveVehicleFlags.BailOut;}
|
||||
ped.Task.LeaveVehicle(flag) ;
|
||||
if (ped.MainPed.CurrentVehicle.Speed>5) { flag|=LeaveVehicleFlags.BailOut;}
|
||||
ped.PauseUpdate((ulong)Game.FPS*2);
|
||||
ped.MainPed.Task.LeaveVehicle(flag) ;
|
||||
}
|
||||
private static void HandlePedKilled(Packets.PedKilled p)
|
||||
{
|
||||
@ -150,30 +148,50 @@ namespace RageCoop.Client {
|
||||
v.OwnerID=p.NewOwnerID;
|
||||
|
||||
v.ModelHash=v.MainVehicle.Model;
|
||||
v.LastSynced=Main.Ticked;
|
||||
// So this vehicle doesn's get re-spawned
|
||||
}
|
||||
|
||||
private static ParticleEffectAsset CorePFXAsset = default;
|
||||
|
||||
static WeaponAsset _weaponAsset = default;
|
||||
static uint _lastWeaponHash;
|
||||
private static void HandleNozzleTransform(Packets.NozzleTransform p)
|
||||
{
|
||||
EntityPool.GetVehicleByID(p.VehicleID)?.MainVehicle?.SetNozzleAngel(p.Hover ? 1 : 0);
|
||||
}
|
||||
private static void HandleBulletShot(Vector3 start, Vector3 end, uint weaponHash, int ownerID)
|
||||
{
|
||||
if (CorePFXAsset==default) {
|
||||
CorePFXAsset= new ParticleEffectAsset("core");
|
||||
switch (weaponHash)
|
||||
{
|
||||
// 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;
|
||||
if (p == null) { p=Game.Player.Character; Main.Logger.Warning("Failed to find owner for bullet"); }
|
||||
if (!CorePFXAsset.IsLoaded) { CorePFXAsset.Request(); }
|
||||
if (_lastWeaponHash!=weaponHash)
|
||||
{
|
||||
_weaponAsset.MarkAsNoLongerNeeded();
|
||||
_weaponAsset=new WeaponAsset(weaponHash);
|
||||
_lastWeaponHash=weaponHash;
|
||||
}
|
||||
if (!_weaponAsset.IsLoaded) { _weaponAsset.Request(); }
|
||||
World.ShootBullet(start, end, p, _weaponAsset, p.GetWeaponDamage());
|
||||
var w = p.Weapons.CurrentWeaponObject;
|
||||
if(w != null)
|
||||
World.ShootBullet(start, end, p, _weaponAsset, p.GetWeaponDamage(weaponHash));
|
||||
Prop w;
|
||||
if(((w = p.Weapons.CurrentWeaponObject) != null)&&(p.VehicleWeapon==VehicleWeaponHash.Invalid))
|
||||
{
|
||||
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)
|
||||
{
|
||||
@ -194,7 +219,7 @@ namespace RageCoop.Client {
|
||||
{
|
||||
Packets.BulletShot p = new Packets.BulletShot();
|
||||
p.Unpack(data);
|
||||
HandleBulletShot(p.StartPosition.ToVector(), p.EndPosition.ToVector(), p.WeaponHash, p.OwnerID);
|
||||
HandleBulletShot(p.StartPosition, p.EndPosition, p.WeaponHash, p.OwnerID);
|
||||
break;
|
||||
}
|
||||
case PacketTypes.EnteringVehicle:
|
||||
@ -234,13 +259,22 @@ namespace RageCoop.Client {
|
||||
HandleEnteredVehicle(packet.PedID,packet.VehicleID,(VehicleSeat)packet.VehicleSeat);
|
||||
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)
|
||||
{
|
||||
@ -264,6 +298,8 @@ namespace RageCoop.Client {
|
||||
public static void Check(SyncedPed c)
|
||||
{
|
||||
Ped subject = c.MainPed;
|
||||
|
||||
// Check bullets
|
||||
if (subject.IsShooting)
|
||||
{
|
||||
if (!subject.IsUsingProjectileWeapon())
|
||||
@ -360,7 +396,21 @@ namespace RageCoop.Client {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,6 @@ namespace RageCoop.Client
|
||||
{
|
||||
internal class SyncParameters
|
||||
{
|
||||
public static float PositioinPrediction = 0.03f;
|
||||
public static float PositioinPredictionDefault = 0.01f;
|
||||
}
|
||||
}
|
||||
|
149
Client/Util/MathExtensions.cs
Normal file
149
Client/Util/MathExtensions.cs
Normal 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());
|
||||
}
|
||||
}
|
||||
}
|
471
Client/Util/PedConfigFlags.cs
Normal file
471
Client/Util/PedConfigFlags.cs
Normal 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,
|
||||
}
|
||||
}
|
390
Client/Util/PedExtensions.cs
Normal file
390
Client/Util/PedExtensions.cs
Normal 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
200
Client/Util/Util.cs
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
293
Client/Util/VehicleExtensions.cs
Normal file
293
Client/Util/VehicleExtensions.cs
Normal 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
|
||||
}
|
||||
}
|
@ -31,29 +31,85 @@ namespace RageCoop.Client
|
||||
}
|
||||
return p.Bones[Bone.SkelRightHand].Position;
|
||||
}
|
||||
static long BulletsShot=0;
|
||||
public static MuzzleInfo GetMuzzleInfo(this Vehicle v)
|
||||
{
|
||||
BulletsShot++;
|
||||
int i;
|
||||
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
|
||||
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);
|
||||
|
||||
// ANNIHL
|
||||
case 837858166:
|
||||
i=(int)Main.Ticked%4+35;
|
||||
i=(int)BulletsShot%4+35;
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
|
||||
|
||||
// HYDRA
|
||||
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);
|
||||
|
||||
// STARLING
|
||||
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);
|
||||
|
||||
// RHINO
|
||||
@ -78,25 +134,7 @@ namespace RageCoop.Client
|
||||
return w.Group==WeaponGroup.Thrown || ProjectileWeapons.Contains(w.Hash);
|
||||
}
|
||||
}
|
||||
|
||||
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>
|
||||
{
|
||||
{WeaponHash.HeavySniper,6},
|
||||
@ -181,6 +219,8 @@ namespace RageCoop.Client
|
||||
VehicleWeaponHash.PlaneRocket,
|
||||
VehicleWeaponHash.SpaceRocket,
|
||||
VehicleWeaponHash.Tank,
|
||||
(VehicleWeaponHash)3565779982, // STROMBERG missiles
|
||||
(VehicleWeaponHash)3169388763, // SCRAMJET missiles
|
||||
};
|
||||
}
|
||||
}
|
@ -49,7 +49,7 @@ namespace RageCoop.Client
|
||||
// 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_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.DisableTraffic)
|
||||
{
|
||||
@ -99,8 +99,8 @@ namespace RageCoop.Client
|
||||
Function.Call(Hash.SET_RANDOM_BOATS, false);
|
||||
Function.Call(Hash.SET_GARBAGE_TRUCKS, false);
|
||||
Function.Call(Hash.DELETE_ALL_TRAINS);
|
||||
Function.Call(Hash.SET_PED_POPULATION_BUDGET, 0);
|
||||
Function.Call(Hash.SET_VEHICLE_POPULATION_BUDGET, 0);
|
||||
Function.Call(Hash.SET_PED_POPULATION_BUDGET, 3);
|
||||
Function.Call(Hash.SET_VEHICLE_POPULATION_BUDGET, 3);
|
||||
Function.Call(Hash.SET_ALL_LOW_PRIORITY_VEHICLE_GENERATORS_ACTIVE, false);
|
||||
Function.Call(Hash.SET_FAR_DRAW_VEHICLES, false);
|
||||
Function.Call(Hash.SET_NUMBER_OF_PARKED_VEHICLES, 0);
|
||||
@ -126,6 +126,11 @@ namespace RageCoop.Client
|
||||
foreach (Vehicle veh in World.GetAllVehicles())
|
||||
{
|
||||
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))
|
||||
{
|
||||
Main.Logger.Debug($"Removing Vehicle {veh.Handle}. Reason:ClearTraffic");
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
using GTA.Math;
|
||||
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
@ -103,18 +104,18 @@ namespace RageCoop.Core
|
||||
return value;
|
||||
}
|
||||
|
||||
public LVector3 ReadLVector3()
|
||||
public Vector3 ReadVector3()
|
||||
{
|
||||
return new LVector3()
|
||||
return new Vector3()
|
||||
{
|
||||
X = ReadFloat(),
|
||||
Y = ReadFloat(),
|
||||
Z = ReadFloat()
|
||||
};
|
||||
}
|
||||
public LQuaternion ReadLQuaternion()
|
||||
public Quaternion ReadQuaternion()
|
||||
{
|
||||
return new LQuaternion()
|
||||
return new Quaternion()
|
||||
{
|
||||
X = ReadFloat(),
|
||||
Y = ReadFloat(),
|
||||
|
@ -3,6 +3,8 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using GTA.Math;
|
||||
using System.Net;
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
public class CoreUtils
|
||||
@ -34,16 +36,17 @@ namespace RageCoop.Core
|
||||
return (0x0, null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
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.Y));
|
||||
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.Y));
|
||||
|
@ -5,48 +5,35 @@ using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
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>
|
||||
/// 0:Trace, 1:Debug, 2:Info, 3:Warning, 4:Error
|
||||
/// </summary>
|
||||
public int LogLevel = 0;
|
||||
public string LogPath;
|
||||
public bool UseConsole = false;
|
||||
private static StreamWriter logWriter;
|
||||
|
||||
private string Buffer="";
|
||||
private Thread LoggerThread;
|
||||
private bool Stopping=false;
|
||||
|
||||
public Loggger(string path,bool overwrite=true)
|
||||
public Logger(bool overwrite=true)
|
||||
{
|
||||
|
||||
|
||||
LogPath=path;
|
||||
if (File.Exists(path)&&overwrite) { File.Delete(path); }
|
||||
Task.Run(() =>
|
||||
if (File.Exists(LogPath)&&overwrite) { File.Delete(LogPath); }
|
||||
LoggerThread=new Thread(() =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
Flush();
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
public Loggger()
|
||||
{
|
||||
UseConsole=true;
|
||||
Task.Run(() =>
|
||||
{
|
||||
while (true)
|
||||
while (!Stopping)
|
||||
{
|
||||
Flush();
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
});
|
||||
LoggerThread.Start();
|
||||
}
|
||||
|
||||
public void Info(string message)
|
||||
@ -146,5 +133,10 @@ namespace RageCoop.Core
|
||||
|
||||
}
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
Stopping=true;
|
||||
LoggerThread?.Join();
|
||||
}
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@ using GTA.Math;
|
||||
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
/*
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
@ -111,7 +112,7 @@ namespace RageCoop.Core
|
||||
/// </summary>
|
||||
public float W { get; set; }
|
||||
}
|
||||
|
||||
*/
|
||||
public enum PacketTypes:byte
|
||||
{
|
||||
Handshake=0,
|
||||
@ -148,6 +149,7 @@ namespace RageCoop.Core
|
||||
EnteredVehicle=34,
|
||||
OwnerChanged=35,
|
||||
VehicleBulletShot = 36,
|
||||
NozzleTransform=37,
|
||||
|
||||
#endregion
|
||||
|
||||
@ -205,7 +207,7 @@ namespace RageCoop.Core
|
||||
RoofOpened = 1 << 8,
|
||||
OnTurretSeat = 1 << 9,
|
||||
IsAircraft = 1 << 10,
|
||||
IsHandBrakeOn=1<<11,
|
||||
IsDeluxoHovering=1 << 11,
|
||||
}
|
||||
|
||||
|
||||
@ -236,10 +238,6 @@ namespace RageCoop.Core
|
||||
{
|
||||
public class Mod : Packet
|
||||
{
|
||||
public long NetHandle { get; set; }
|
||||
|
||||
public long Target { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public byte CustomPacketID { get; set; }
|
||||
@ -253,12 +251,6 @@ namespace RageCoop.Core
|
||||
|
||||
List<byte> byteArray = new List<byte>();
|
||||
|
||||
// Write NetHandle
|
||||
byteArray.AddRange(BitConverter.GetBytes(NetHandle));
|
||||
|
||||
// Write Target
|
||||
byteArray.AddRange(BitConverter.GetBytes(Target));
|
||||
|
||||
// Write Name
|
||||
byte[] nameBytes = Encoding.UTF8.GetBytes(Name);
|
||||
byteArray.AddRange(BitConverter.GetBytes(nameBytes.Length));
|
||||
@ -283,12 +275,6 @@ namespace RageCoop.Core
|
||||
#region NetIncomingMessageToPacket
|
||||
BitReader reader = new BitReader(array);
|
||||
|
||||
// Read NetHandle
|
||||
NetHandle = reader.ReadLong();
|
||||
|
||||
// Read Target
|
||||
Target = reader.ReadLong();
|
||||
|
||||
// Read Name
|
||||
int nameLength = reader.ReadInt();
|
||||
Name = reader.ReadString(nameLength);
|
||||
@ -492,10 +478,10 @@ namespace RageCoop.Core
|
||||
byteArray.AddRange(BitConverter.GetBytes(stringBytes.Length));
|
||||
byteArray.AddRange(stringBytes);
|
||||
}
|
||||
else if (type == typeof(LVector3))
|
||||
else if (type == typeof(Vector3))
|
||||
{
|
||||
byteArray.Add(0x04);
|
||||
LVector3 vector = (LVector3)x;
|
||||
Vector3 vector = (Vector3)x;
|
||||
byteArray.AddRange(BitConverter.GetBytes(vector.X));
|
||||
byteArray.AddRange(BitConverter.GetBytes(vector.Y));
|
||||
byteArray.AddRange(BitConverter.GetBytes(vector.Z));
|
||||
@ -539,7 +525,7 @@ namespace RageCoop.Core
|
||||
Args.Add(reader.ReadString(stringLength));
|
||||
break;
|
||||
case 0x04:
|
||||
Args.Add(new LVector3()
|
||||
Args.Add(new Vector3()
|
||||
{
|
||||
X = reader.ReadFloat(),
|
||||
Y = reader.ReadFloat(),
|
||||
@ -602,10 +588,10 @@ namespace RageCoop.Core
|
||||
byteArray.AddRange(BitConverter.GetBytes(stringBytes.Length));
|
||||
byteArray.AddRange(stringBytes);
|
||||
}
|
||||
else if (type == typeof(LVector3))
|
||||
else if (type == typeof(Vector3))
|
||||
{
|
||||
byteArray.Add(0x04);
|
||||
LVector3 vector = (LVector3)x;
|
||||
Vector3 vector = (Vector3)x;
|
||||
byteArray.AddRange(BitConverter.GetBytes(vector.X));
|
||||
byteArray.AddRange(BitConverter.GetBytes(vector.Y));
|
||||
byteArray.AddRange(BitConverter.GetBytes(vector.Z));
|
||||
@ -657,7 +643,7 @@ namespace RageCoop.Core
|
||||
Args.Add(reader.ReadString(stringLength));
|
||||
break;
|
||||
case 0x04:
|
||||
Args.Add(new LVector3()
|
||||
Args.Add(new Vector3()
|
||||
{
|
||||
X = reader.ReadFloat(),
|
||||
Y = reader.ReadFloat(),
|
||||
@ -680,9 +666,6 @@ namespace RageCoop.Core
|
||||
#endregion // ===== NATIVECALL =====
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// </summary>
|
||||
public static class CoopSerializer
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
using GTA.Math;
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace RageCoop.Core
|
||||
@ -126,17 +126,17 @@ namespace RageCoop.Core
|
||||
|
||||
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 LVector3 AimCoords { get; set; }
|
||||
public Vector3 AimCoords { get; set; }
|
||||
|
||||
public uint CurrentWeaponHash { get; set; }
|
||||
|
||||
@ -160,17 +160,17 @@ namespace RageCoop.Core
|
||||
byteArray.AddRange(BitConverter.GetBytes(Health));
|
||||
|
||||
// Write ped position
|
||||
byteArray.AddLVector3(Position);
|
||||
byteArray.AddVector3(Position);
|
||||
|
||||
// Write ped rotation
|
||||
byteArray.AddLVector3(Rotation);
|
||||
byteArray.AddVector3(Rotation);
|
||||
|
||||
// Write ped velocity
|
||||
byteArray.AddLVector3(Velocity);
|
||||
byteArray.AddVector3(Velocity);
|
||||
|
||||
if (Flag.HasFlag(PedDataFlags.IsRagdoll))
|
||||
{
|
||||
byteArray.AddLVector3(RotationVelocity);
|
||||
byteArray.AddVector3(RotationVelocity);
|
||||
}
|
||||
|
||||
// Write ped speed
|
||||
@ -182,7 +182,7 @@ namespace RageCoop.Core
|
||||
if (Flag.HasFlag(PedDataFlags.IsAiming))
|
||||
{
|
||||
// Write ped aim coords
|
||||
byteArray.AddLVector3(AimCoords);
|
||||
byteArray.AddVector3(AimCoords);
|
||||
}
|
||||
|
||||
byteArray.AddFloat(Heading);
|
||||
@ -209,18 +209,18 @@ namespace RageCoop.Core
|
||||
Health = reader.ReadInt();
|
||||
|
||||
// Read player position
|
||||
Position = reader.ReadLVector3();
|
||||
Position = reader.ReadVector3();
|
||||
|
||||
// Read player rotation
|
||||
Rotation = reader.ReadLVector3();
|
||||
Rotation = reader.ReadVector3();
|
||||
|
||||
// Read player velocity
|
||||
Velocity = reader.ReadLVector3();
|
||||
Velocity = reader.ReadVector3();
|
||||
|
||||
// Read rotation velocity if in ragdoll
|
||||
if (Flag.HasFlag(PedDataFlags.IsRagdoll))
|
||||
{
|
||||
RotationVelocity=reader.ReadLVector3();
|
||||
RotationVelocity=reader.ReadVector3();
|
||||
}
|
||||
|
||||
// Read player speed
|
||||
@ -233,7 +233,7 @@ namespace RageCoop.Core
|
||||
if (Flag.HasFlag(PedDataFlags.IsAiming))
|
||||
{
|
||||
// Read player aim coords
|
||||
AimCoords = reader.ReadLVector3();
|
||||
AimCoords = reader.ReadVector3();
|
||||
}
|
||||
|
||||
Heading=reader.ReadFloat();
|
||||
|
@ -16,8 +16,6 @@ namespace RageCoop.Core
|
||||
|
||||
public string ModVersion { get; set; }
|
||||
|
||||
public bool NPCsAllowed { get; set; }
|
||||
|
||||
public override void Pack(NetOutgoingMessage message)
|
||||
{
|
||||
#region PacketToNetOutGoingMessage
|
||||
@ -38,9 +36,6 @@ namespace RageCoop.Core
|
||||
byteArray.AddRange(BitConverter.GetBytes(modVersionBytes.Length));
|
||||
byteArray.AddRange(modVersionBytes);
|
||||
|
||||
// Write NpcsAllowed
|
||||
byteArray.Add(NPCsAllowed ? (byte)0x01 : (byte)0x00);
|
||||
|
||||
byte[] result = byteArray.ToArray();
|
||||
|
||||
message.Write(result.Length);
|
||||
@ -63,9 +58,6 @@ namespace RageCoop.Core
|
||||
// Read ModVersion
|
||||
int modVersionLength = reader.ReadInt();
|
||||
ModVersion = reader.ReadString(modVersionLength);
|
||||
|
||||
// Read NPCsAllowed
|
||||
NPCsAllowed = reader.ReadBool();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using GTA.Math;
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace RageCoop.Core
|
||||
@ -15,11 +16,11 @@ namespace RageCoop.Core
|
||||
public int ShooterID { 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; }
|
||||
|
||||
@ -41,14 +42,14 @@ namespace RageCoop.Core
|
||||
byteArray.AddUint(WeaponHash);
|
||||
|
||||
// Write position
|
||||
byteArray.AddLVector3(Position);
|
||||
byteArray.AddVector3(Position);
|
||||
|
||||
|
||||
// Write rotation
|
||||
byteArray.AddLVector3(Rotation);
|
||||
byteArray.AddVector3(Rotation);
|
||||
|
||||
// Write velocity
|
||||
byteArray.AddLVector3(Velocity);
|
||||
byteArray.AddVector3(Velocity);
|
||||
|
||||
if (Exploded) { byteArray.Add(1); }
|
||||
|
||||
@ -73,13 +74,13 @@ namespace RageCoop.Core
|
||||
WeaponHash= reader.ReadUInt();
|
||||
|
||||
// Read position
|
||||
Position = reader.ReadLVector3();
|
||||
Position = reader.ReadVector3();
|
||||
|
||||
// Read rotation
|
||||
Rotation = reader.ReadLVector3();
|
||||
Rotation = reader.ReadVector3();
|
||||
|
||||
// Read velocity
|
||||
Velocity =reader.ReadLVector3();
|
||||
Velocity =reader.ReadVector3();
|
||||
|
||||
if (reader.CanRead(1))
|
||||
{
|
||||
|
@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
using GTA.Math;
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace RageCoop.Core
|
||||
@ -15,8 +15,8 @@ namespace RageCoop.Core
|
||||
|
||||
public uint WeaponHash { get; set; }
|
||||
|
||||
public LVector3 StartPosition { get; set; }
|
||||
public LVector3 EndPosition { get; set; }
|
||||
public Vector3 StartPosition { get; set; }
|
||||
public Vector3 EndPosition { get; set; }
|
||||
|
||||
public override void Pack(NetOutgoingMessage message)
|
||||
{
|
||||
@ -32,10 +32,10 @@ namespace RageCoop.Core
|
||||
byteArray.AddRange(BitConverter.GetBytes(WeaponHash));
|
||||
|
||||
// Write StartPosition
|
||||
byteArray.AddLVector3(StartPosition);
|
||||
byteArray.AddVector3(StartPosition);
|
||||
|
||||
// Write EndPosition
|
||||
byteArray.AddLVector3(EndPosition);
|
||||
byteArray.AddVector3(EndPosition);
|
||||
|
||||
|
||||
byte[] result = byteArray.ToArray();
|
||||
@ -57,10 +57,10 @@ namespace RageCoop.Core
|
||||
WeaponHash=reader.ReadUInt();
|
||||
|
||||
// Read StartPosition
|
||||
StartPosition=reader.ReadLVector3();
|
||||
StartPosition=reader.ReadVector3();
|
||||
|
||||
// Read EndPosition
|
||||
EndPosition=reader.ReadLVector3();
|
||||
EndPosition=reader.ReadVector3();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
49
Core/Packets/SyncEvents/NozzleTransform.cs
Normal file
49
Core/Packets/SyncEvents/NozzleTransform.cs
Normal 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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace RageCoop.Core
|
||||
@ -40,6 +41,7 @@ namespace RageCoop.Core
|
||||
/// </summary>
|
||||
public Dictionary<int, int> Passengers { get; set; }
|
||||
|
||||
public byte RadioStation { get; set; } = 255;
|
||||
public override void Pack(NetOutgoingMessage message)
|
||||
{
|
||||
#region PacketToNetOutGoingMessage
|
||||
@ -117,6 +119,9 @@ namespace RageCoop.Core
|
||||
// Write LockStatus
|
||||
byteArray.Add((byte)LockStatus);
|
||||
|
||||
// Write RadioStation
|
||||
byteArray.Add(RadioStation);
|
||||
|
||||
byte[] result = byteArray.ToArray();
|
||||
|
||||
message.Write(result.Length);
|
||||
@ -199,6 +204,9 @@ namespace RageCoop.Core
|
||||
|
||||
// Read LockStatus
|
||||
LockStatus=(VehicleLockStatus)reader.ReadByte();
|
||||
|
||||
// Read RadioStation
|
||||
RadioStation=reader.ReadByte();
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -207,18 +215,19 @@ namespace RageCoop.Core
|
||||
{
|
||||
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 BrakePower { get; set; }
|
||||
public float SteeringAngle { get; set; }
|
||||
|
||||
public float DeluxoWingRatio { get; set; } = -1;
|
||||
|
||||
public override void Pack(NetOutgoingMessage message)
|
||||
{
|
||||
@ -231,17 +240,18 @@ namespace RageCoop.Core
|
||||
byteArray.AddInt(ID);
|
||||
|
||||
// Write position
|
||||
byteArray.AddLVector3(Position);
|
||||
byteArray.AddVector3(Position);
|
||||
|
||||
|
||||
// Write rotation
|
||||
byteArray.AddLVector3(Rotation);
|
||||
// Write quaternion
|
||||
//byteArray.AddVector3(Rotation);
|
||||
byteArray.AddQuaternion(Quaternion);
|
||||
|
||||
// Write velocity
|
||||
byteArray.AddLVector3(Velocity);
|
||||
byteArray.AddVector3(Velocity);
|
||||
|
||||
// Write rotation velocity
|
||||
byteArray.AddLVector3(RotationVelocity);
|
||||
byteArray.AddVector3(RotationVelocity);
|
||||
|
||||
|
||||
byteArray.AddFloat(ThrottlePower);
|
||||
@ -251,6 +261,11 @@ namespace RageCoop.Core
|
||||
// Write vehicle steering angle
|
||||
byteArray.AddFloat(SteeringAngle);
|
||||
|
||||
if (DeluxoWingRatio!=-1)
|
||||
{
|
||||
byteArray.AddFloat(DeluxoWingRatio);
|
||||
}
|
||||
|
||||
|
||||
byte[] result = byteArray.ToArray();
|
||||
|
||||
@ -268,16 +283,17 @@ namespace RageCoop.Core
|
||||
ID = reader.ReadInt();
|
||||
|
||||
// Read position
|
||||
Position = reader.ReadLVector3();
|
||||
Position = reader.ReadVector3();
|
||||
|
||||
// Read rotation
|
||||
Rotation = reader.ReadLVector3();
|
||||
// Read quaternion
|
||||
// Rotation = reader.ReadVector3();
|
||||
Quaternion=reader.ReadQuaternion();
|
||||
|
||||
// Read velocity
|
||||
Velocity =reader.ReadLVector3();
|
||||
Velocity =reader.ReadVector3();
|
||||
|
||||
// Read rotation velocity
|
||||
RotationVelocity=reader.ReadLVector3();
|
||||
RotationVelocity=reader.ReadVector3();
|
||||
|
||||
// Read throttle power
|
||||
ThrottlePower=reader.ReadFloat();
|
||||
@ -288,6 +304,11 @@ namespace RageCoop.Core
|
||||
// Read steering angle
|
||||
SteeringAngle = reader.ReadFloat();
|
||||
|
||||
|
||||
if (reader.CanRead(4))
|
||||
{
|
||||
DeluxoWingRatio= reader.ReadFloat();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
@ -1,34 +1,33 @@
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using GTA.Math;
|
||||
|
||||
[assembly: InternalsVisibleTo("RageCoop.Server")]
|
||||
[assembly: InternalsVisibleTo("RageCoop.Client")]
|
||||
namespace RageCoop.Core
|
||||
{
|
||||
public class PlayerData
|
||||
{
|
||||
public string Username { get; set; }
|
||||
public string Username { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Universal character ID.
|
||||
/// </summary>
|
||||
public int PedID
|
||||
{
|
||||
get; set;
|
||||
get; internal set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Universal vehicle ID.
|
||||
/// The ID of player's last vehicle.
|
||||
/// </summary>
|
||||
public int VehicleID { get; set; }
|
||||
public bool IsInVehicle { get; internal set; }
|
||||
public LVector3 Position { get; set; }
|
||||
public int VehicleID { get; internal set; }
|
||||
public Vector3 Position { get;internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Player Latency in second.
|
||||
/// </summary>
|
||||
public float Latency { get; set; }
|
||||
public int Health { get; set; }
|
||||
|
||||
public bool IsInRangeOf(LVector3 position, float distance)
|
||||
{
|
||||
return LVector3.Subtract(Position, position).Length() < distance;
|
||||
}
|
||||
public float Latency { get; internal set; }
|
||||
public int Health { get; internal set; }
|
||||
}
|
||||
}
|
||||
|
153
Core/Scripting/ScriptingEngine.cs
Normal file
153
Core/Scripting/ScriptingEngine.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
79
README.md
79
README.md
@ -1,57 +1,94 @@
|
||||
|
||||
|
||||
# 🌐 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 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!
|
||||
|
||||
## 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>
|
||||
_Old name: GTACOOP:R_
|
||||
|
||||
# 📋 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
|
||||
|
||||
1. Synchronized bullets
|
||||
2. Synchronized vehicle/player/NPC
|
||||
3. Synchronized Projectile
|
||||
4. Basic ragdoll sync
|
||||
3. Synchronized projectiles
|
||||
4. Simple ragdoll sync
|
||||
5. Smoother vehicle/ped movement.
|
||||
6. Ownership based sync logic, carjacking is now working properly.
|
||||
7. Introduced SyncEvents.
|
||||
8. Code refactoring and namespace cleanup
|
||||
9. Synchronized vehicle doors, brake and throttle.
|
||||
10. Other improvements
|
||||
10. Weaponized vehicle sync(WIP).
|
||||
11. Other improvements
|
||||
|
||||
# Known issues
|
||||
|
||||
1. Weapon sounds are missing.
|
||||
2. Cover sync is still buggy.
|
||||
3. Weaponized vehicle doen't work currently
|
||||
4. Framerate drop with high number of synchronized entities.
|
||||
3. Framerate drop with high number of synchronized entities.
|
||||
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`.
|
||||
|
||||
## Server
|
||||
### Server
|
||||
|
||||
Download latest release for your OS, then extract and run.
|
||||
|
||||
# Downloads
|
||||
|
||||
|
||||
Old release can be downloaded [here](https://gitlab.com/justasausage/RageCOOP-V/-/tree/main/Release)
|
||||
Download latest release [here](https://github.com/RAGECOOP/RAGECOOP-V/releases/latest)
|
||||
|
||||
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
|
||||
|
||||
|
@ -1,9 +1 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace RageCoop.Server
|
||||
{
|
||||
public class Allowlist
|
||||
{
|
||||
public List<string> Username { get; set; } = new();
|
||||
}
|
||||
}
|
||||
|
@ -2,23 +2,25 @@
|
||||
using System.Collections.Generic;
|
||||
using RageCoop.Core;
|
||||
using Lidgren.Network;
|
||||
using GTA.Math;
|
||||
|
||||
namespace RageCoop.Server
|
||||
{
|
||||
public class Client
|
||||
{
|
||||
public long ClientID = 0;
|
||||
public long NetID = 0;
|
||||
private float _currentLatency = 0f;
|
||||
public NetConnection Connection { get; set; }
|
||||
public float Latency
|
||||
{
|
||||
get => _currentLatency;
|
||||
set
|
||||
internal set
|
||||
{
|
||||
_currentLatency = value;
|
||||
|
||||
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 long _callbacksCount = 0;
|
||||
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;
|
||||
|
||||
#region CUSTOMDATA FUNCTIONS
|
||||
@ -64,7 +66,7 @@ namespace RageCoop.Server
|
||||
#region FUNCTIONS
|
||||
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)
|
||||
{
|
||||
@ -75,7 +77,7 @@ namespace RageCoop.Server
|
||||
{
|
||||
try
|
||||
{
|
||||
NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == ClientID);
|
||||
NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == NetID);
|
||||
if (userConnection == null)
|
||||
{
|
||||
return;
|
||||
@ -85,7 +87,7 @@ namespace RageCoop.Server
|
||||
}
|
||||
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
|
||||
{
|
||||
NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == ClientID);
|
||||
NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == NetID);
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -118,7 +120,7 @@ namespace RageCoop.Server
|
||||
}
|
||||
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
|
||||
{
|
||||
NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == ClientID);
|
||||
NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == NetID);
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -159,13 +161,13 @@ namespace RageCoop.Server
|
||||
{
|
||||
returnTypeValue = 0x03;
|
||||
}
|
||||
else if (returnType == typeof(LVector3))
|
||||
else if (returnType == typeof(Vector3))
|
||||
{
|
||||
returnTypeValue = 0x04;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@ -181,16 +183,16 @@ namespace RageCoop.Server
|
||||
}
|
||||
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()
|
||||
{
|
||||
NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == ClientID);
|
||||
NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == NetID);
|
||||
if (userConnection == null)
|
||||
{
|
||||
Logging.Error($"[Client->SendCleanUpWorld()]: Connection \"{ClientID}\" not found!");
|
||||
Program.Logger.Error($"[Client->SendCleanUpWorld()]: Connection \"{NetID}\" not found!");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -203,7 +205,7 @@ namespace RageCoop.Server
|
||||
{
|
||||
try
|
||||
{
|
||||
NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == ClientID);
|
||||
NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == NetID);
|
||||
if (userConnection == null)
|
||||
{
|
||||
return;
|
||||
@ -212,8 +214,6 @@ namespace RageCoop.Server
|
||||
NetOutgoingMessage outgoingMessage = Server.MainNetServer.CreateMessage();
|
||||
new Packets.Mod()
|
||||
{
|
||||
NetHandle = 0,
|
||||
Target = 0,
|
||||
Name = modName,
|
||||
CustomPacketID = customID,
|
||||
Bytes = bytes
|
||||
@ -223,7 +223,7 @@ namespace RageCoop.Server
|
||||
}
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == ClientID);
|
||||
NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == NetID);
|
||||
if (userConnection == null)
|
||||
{
|
||||
return;
|
||||
@ -254,7 +254,7 @@ namespace RageCoop.Server
|
||||
}
|
||||
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
|
||||
|
@ -43,7 +43,7 @@ namespace RageCoop.Server
|
||||
// ONLY JAVASCRIPT AND JSON FILES!
|
||||
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;
|
||||
}
|
||||
|
||||
@ -105,7 +105,7 @@ namespace RageCoop.Server
|
||||
{
|
||||
lock (Server.Clients)
|
||||
{
|
||||
Client x = Server.Clients.FirstOrDefault(x => x.ClientID == client.NetHandle);
|
||||
Client x = Util.GetClientByID(client.NetHandle);
|
||||
if (x != null)
|
||||
{
|
||||
x.FilesReceived = true;
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -9,8 +9,14 @@ namespace RageCoop.Server
|
||||
class Program
|
||||
{
|
||||
public static bool ReadyToStop = false;
|
||||
public static Core.Logging.Logger Logger;
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Logger=new Core.Logging.Logger()
|
||||
{
|
||||
LogPath="RageCoop.Server.log",
|
||||
UseConsole=true,
|
||||
};
|
||||
try
|
||||
{
|
||||
#if DEBUG
|
||||
@ -45,7 +51,7 @@ namespace RageCoop.Server
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Error(e.InnerException?.Message ?? e.Message);
|
||||
Program.Logger.Error(e.InnerException?.Message ?? e.Message);
|
||||
Console.ReadLine();
|
||||
}
|
||||
}
|
||||
|
@ -6,10 +6,10 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||
<PropertyGroup>
|
||||
<Configuration>Release</Configuration>
|
||||
<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>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<RuntimeIdentifier>osx-x64</RuntimeIdentifier>
|
||||
<RuntimeIdentifier>linux-arm</RuntimeIdentifier>
|
||||
<SelfContained>true</SelfContained>
|
||||
<PublishSingleFile>True</PublishSingleFile>
|
||||
<PublishTrimmed>True</PublishTrimmed>
|
||||
|
@ -4,6 +4,6 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||
-->
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<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-02T05:21:10.3456459Z;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>
|
||||
</Project>
|
@ -3,8 +3,8 @@
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<AssemblyVersion>0.2</AssemblyVersion>
|
||||
<FileVersion>0.2</FileVersion>
|
||||
<AssemblyVersion>0.4</AssemblyVersion>
|
||||
<FileVersion>0.4</FileVersion>
|
||||
<RepositoryUrl>https://github.com/RAGECOOP/RAGECOOP-V</RepositoryUrl>
|
||||
<PackageProjectUrl>https://ragecoop.online/</PackageProjectUrl>
|
||||
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
|
||||
@ -12,7 +12,7 @@
|
||||
<Product>$(AssemblyName)-V</Product>
|
||||
<PackageId>RAGECOOP-V</PackageId>
|
||||
<Authors>RAGECOOP</Authors>
|
||||
<Version>0.2</Version>
|
||||
<Version>0.4</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@ -32,6 +32,9 @@
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<HintPath>..\Libs\Release\scripts\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ScriptHookVDotNet3">
|
||||
<HintPath>..\Libs\Release\ScriptHookVDotNet3.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
363
Server/Server.cs
363
Server/Server.cs
@ -11,6 +11,7 @@ using RageCoop.Core;
|
||||
using Newtonsoft.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Lidgren.Network;
|
||||
using System.Timers;
|
||||
|
||||
namespace RageCoop.Server
|
||||
{
|
||||
@ -22,29 +23,26 @@ namespace RageCoop.Server
|
||||
|
||||
public class Server
|
||||
{
|
||||
private static readonly string _compatibleVersion = "V0_2";
|
||||
private static readonly string _compatibleVersion = "V0_4";
|
||||
private static long _currentTick = 0;
|
||||
|
||||
public static readonly Settings MainSettings = Util.Read<Settings>("Settings.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 Resource RunningResource = null;
|
||||
public static readonly Dictionary<Command, Action<CommandContext>> Commands = 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()
|
||||
{
|
||||
Logging.Info("================");
|
||||
Logging.Info($"Server bound to: 0.0.0.0:{MainSettings.Port}");
|
||||
Logging.Info($"Server version: {Assembly.GetCallingAssembly().GetName().Version}");
|
||||
Logging.Info($"Compatible RAGECOOP versions: {_compatibleVersion.Replace('_', '.')}.x");
|
||||
Logging.Info("================");
|
||||
Program.Logger.Info("================");
|
||||
Program.Logger.Info($"Server bound to: 0.0.0.0:{MainSettings.Port}");
|
||||
Program.Logger.Info($"Server version: {Assembly.GetCallingAssembly().GetName().Version}");
|
||||
Program.Logger.Info($"Compatible RAGECOOP versions: {_compatibleVersion.Replace('_', '.')}.x");
|
||||
Program.Logger.Info("================");
|
||||
|
||||
// 623c92c287cc392406e7aaaac1c0f3b0 = RAGECOOP
|
||||
NetPeerConfiguration config = new("623c92c287cc392406e7aaaac1c0f3b0")
|
||||
@ -59,27 +57,28 @@ namespace RageCoop.Server
|
||||
|
||||
MainNetServer = new NetServer(config);
|
||||
MainNetServer.Start();
|
||||
|
||||
Logging.Info(string.Format("Server listening on {0}:{1}", config.LocalAddress.ToString(), config.Port));
|
||||
SendLatencyTimer.Elapsed+=((s,e) => { SendLatency(); });
|
||||
SendLatencyTimer.AutoReset=true;
|
||||
SendLatencyTimer.Enabled=true;
|
||||
Program.Logger.Info(string.Format("Server listening on {0}:{1}", config.LocalAddress.ToString(), config.Port));
|
||||
|
||||
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"))
|
||||
{
|
||||
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
|
||||
{
|
||||
Logging.Error("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.Error("Port forwarding failed! Your router may not support UPnP.");
|
||||
Program.Logger.Warning("If you and your friends can join this server, please ignore this error or set UPnP in Settings.xml to false!");
|
||||
}
|
||||
}
|
||||
|
||||
if (MainSettings.AnnounceSelf)
|
||||
{
|
||||
Logging.Info("Announcing to master server...");
|
||||
|
||||
#region -- MASTERSERVER --
|
||||
new Thread(async () =>
|
||||
@ -104,13 +103,14 @@ namespace RageCoop.Server
|
||||
|
||||
string content = await response.Content.ReadAsStringAsync();
|
||||
info = JsonConvert.DeserializeObject<IpInfo>(content);
|
||||
Program.Logger.Info($"Your public IP is {info.Address}, announcing to master server...");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Error(ex.InnerException?.Message ?? ex.Message);
|
||||
Program.Logger.Error(ex.InnerException?.Message ?? ex.Message);
|
||||
return;
|
||||
}
|
||||
|
||||
var realMaster = MainSettings.MasterServer=="[AUTO]" ? Util.DownloadString("https://ragecoop.online/stuff/masterserver") : MainSettings.MasterServer;
|
||||
while (!Program.ReadyToStop)
|
||||
{
|
||||
string msg =
|
||||
@ -120,20 +120,16 @@ namespace RageCoop.Server
|
||||
"\"name\": \"" + MainSettings.Name + "\", " +
|
||||
"\"version\": \"" + _compatibleVersion.Replace("_", ".") + "\", " +
|
||||
"\"players\": \"" + MainNetServer.ConnectionsCount + "\", " +
|
||||
"\"maxPlayers\": \"" + MainSettings.MaxPlayers + "\", " +
|
||||
"\"allowlist\": \"" + _mainAllowlist.Username.Any() + "\", " +
|
||||
"\"mods\": \"" + MainSettings.ModsAllowed + "\", " +
|
||||
"\"npcs\": \"" + MainSettings.NpcsAllowed + "\"" +
|
||||
"\"maxPlayers\": \"" + MainSettings.MaxPlayers + "\"" +
|
||||
" }";
|
||||
|
||||
HttpResponseMessage response = null;
|
||||
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)
|
||||
{
|
||||
Logging.Error($"MasterServer: {ex.Message}");
|
||||
Program.Logger.Error($"MasterServer: {ex.Message}");
|
||||
|
||||
// Sleep for 5s
|
||||
Thread.Sleep(5000);
|
||||
@ -142,18 +138,19 @@ namespace RageCoop.Server
|
||||
|
||||
if (response == null)
|
||||
{
|
||||
Logging.Error("MasterServer: Something went wrong!");
|
||||
Program.Logger.Error("MasterServer: Something went wrong!");
|
||||
}
|
||||
else if (response.StatusCode != HttpStatusCode.OK)
|
||||
{
|
||||
if (response.StatusCode == HttpStatusCode.BadRequest)
|
||||
{
|
||||
string requestContent = await response.Content.ReadAsStringAsync();
|
||||
Logging.Error($"MasterServer: [{(int)response.StatusCode}], {requestContent}");
|
||||
Program.Logger.Error($"MasterServer: [{(int)response.StatusCode}], {requestContent}");
|
||||
}
|
||||
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)
|
||||
{
|
||||
Logging.Error($"MasterServer: {ex.InnerException.Message}");
|
||||
Program.Logger.Error($"MasterServer: {ex.InnerException.Message}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.Error($"MasterServer: {ex.Message}");
|
||||
Program.Logger.Error($"MasterServer: {ex.Message}");
|
||||
}
|
||||
}).Start();
|
||||
#endregion
|
||||
@ -178,7 +175,7 @@ namespace RageCoop.Server
|
||||
try
|
||||
{
|
||||
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);
|
||||
Type[] types = asm.GetExportedTypes();
|
||||
@ -187,7 +184,7 @@ namespace RageCoop.Server
|
||||
|
||||
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
|
||||
{
|
||||
@ -197,28 +194,27 @@ namespace RageCoop.Server
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Warning("Could not create resource: it is null.");
|
||||
Program.Logger.Warning("Could not create resource: it is null.");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logging.Error(e.InnerException.Message);
|
||||
Program.Logger.Error(e.InnerException.Message);
|
||||
}
|
||||
}
|
||||
|
||||
Logging.Info("Searching for client-side files...");
|
||||
Program.Logger.Info("Searching for client-side files...");
|
||||
DownloadManager.CheckForDirectoryAndFiles();
|
||||
|
||||
Listen();
|
||||
|
||||
BackgroundThread=new Thread(() => Background());
|
||||
Listen();
|
||||
}
|
||||
|
||||
private void Listen()
|
||||
{
|
||||
Logging.Info("Listening for clients");
|
||||
Logging.Info("Please use CTRL + C if you want to stop the server!");
|
||||
Program.Logger.Info("Listening for clients");
|
||||
Program.Logger.Info("Please use CTRL + C if you want to stop the server!");
|
||||
|
||||
while (!Program.ReadyToStop)
|
||||
{
|
||||
@ -232,11 +228,11 @@ namespace RageCoop.Server
|
||||
{
|
||||
lock (Clients)
|
||||
{
|
||||
Clients.ForEach(client =>
|
||||
Clients.Values.ToList().ForEach(client =>
|
||||
{
|
||||
if (!client.FilesSent)
|
||||
{
|
||||
DownloadManager.InsertClient(client.ClientID);
|
||||
DownloadManager.InsertClient(client.NetID);
|
||||
client.FilesSent = true;
|
||||
}
|
||||
});
|
||||
@ -253,10 +249,10 @@ namespace RageCoop.Server
|
||||
{
|
||||
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)
|
||||
{
|
||||
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!");
|
||||
}
|
||||
else
|
||||
@ -273,7 +269,7 @@ namespace RageCoop.Server
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -317,7 +313,7 @@ namespace RageCoop.Server
|
||||
Packets.PedStateSync packet = new();
|
||||
packet.Unpack(data);
|
||||
|
||||
CharacterStateSync(packet, message.SenderConnection.RemoteUniqueIdentifier);
|
||||
PedStateSync(packet, message.SenderConnection.RemoteUniqueIdentifier);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@ -353,7 +349,7 @@ namespace RageCoop.Server
|
||||
Packets.PedSync packet = new();
|
||||
packet.Unpack(data);
|
||||
|
||||
CharacterSync(packet, message.SenderConnection.RemoteUniqueIdentifier);
|
||||
PedSync(packet, message.SenderConnection.RemoteUniqueIdentifier);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@ -429,7 +425,7 @@ namespace RageCoop.Server
|
||||
Packets.NativeResponse packet = new();
|
||||
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.Callbacks.ContainsKey(packet.ID))
|
||||
@ -445,63 +441,6 @@ namespace RageCoop.Server
|
||||
}
|
||||
}
|
||||
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:
|
||||
{
|
||||
try
|
||||
@ -514,10 +453,10 @@ namespace RageCoop.Server
|
||||
Packets.FileTransferComplete packet = new();
|
||||
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)
|
||||
{
|
||||
DownloadManager.TryToRemoveClient(client.ClientID, packet.ID);
|
||||
DownloadManager.TryToRemoveClient(client.NetID, packet.ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -558,7 +497,7 @@ namespace RageCoop.Server
|
||||
}
|
||||
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 +533,14 @@ namespace RageCoop.Server
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Error("Unhandled Data / Packet type");
|
||||
Program.Logger.Error("Unhandled Data / Packet type");
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case NetIncomingMessageType.ConnectionLatencyUpdated:
|
||||
{
|
||||
Client client = Clients.Find(x => x.ClientID == message.SenderConnection.RemoteUniqueIdentifier);
|
||||
Client client = Util.GetClientByID(message.SenderConnection.RemoteUniqueIdentifier);
|
||||
if (client != null)
|
||||
{
|
||||
client.Latency = message.ReadFloat();
|
||||
@ -609,28 +548,28 @@ namespace RageCoop.Server
|
||||
}
|
||||
break;
|
||||
case NetIncomingMessageType.ErrorMessage:
|
||||
Logging.Error(message.ReadString());
|
||||
Program.Logger.Error(message.ReadString());
|
||||
break;
|
||||
case NetIncomingMessageType.WarningMessage:
|
||||
Logging.Warning(message.ReadString());
|
||||
Program.Logger.Warning(message.ReadString());
|
||||
break;
|
||||
case NetIncomingMessageType.DebugMessage:
|
||||
case NetIncomingMessageType.VerboseDebugMessage:
|
||||
Logging.Debug(message.ReadString());
|
||||
Program.Logger.Debug(message.ReadString());
|
||||
break;
|
||||
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;
|
||||
}
|
||||
|
||||
MainNetServer.Recycle(message);
|
||||
}
|
||||
|
||||
// 16 milliseconds to sleep to reduce CPU usage
|
||||
Thread.Sleep(1000 / 60);
|
||||
// 3 milliseconds to sleep to reduce CPU usage
|
||||
Thread.Sleep(3);
|
||||
}
|
||||
|
||||
Logging.Warning("Server is shutting down!");
|
||||
Program.Logger.Warning("Server is shutting down!");
|
||||
if (RunningResource != null)
|
||||
{
|
||||
// Waiting for resource...
|
||||
@ -648,36 +587,32 @@ namespace RageCoop.Server
|
||||
// Sleep for 1 second
|
||||
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();
|
||||
new Packets.PlayerInfoUpdate()
|
||||
{
|
||||
PedID=c.Player.PedID,
|
||||
Username=c.Player.Username,
|
||||
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);
|
||||
PedID=c.Player.PedID,
|
||||
Username=c.Player.Username,
|
||||
Latency=c.Player.Latency=c.Latency,
|
||||
}.Pack(outgoingMessage);
|
||||
MainNetServer.SendMessage(outgoingMessage, x, NetDeliveryMethod.ReliableSequenced, (byte)ConnectionChannel.Default);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void DisconnectAndLog(NetConnection senderConnection,PacketTypes type, Exception e)
|
||||
{
|
||||
Logging.Error($"Error receiving a packet of type {type}");
|
||||
Logging.Error(e.Message);
|
||||
Logging.Error(e.StackTrace);
|
||||
Program.Logger.Error($"Error receiving a packet of type {type}");
|
||||
Program.Logger.Error(e.Message);
|
||||
Program.Logger.Error(e.StackTrace);
|
||||
senderConnection.Disconnect(e.Message);
|
||||
}
|
||||
|
||||
@ -685,7 +620,7 @@ namespace RageCoop.Server
|
||||
// Before we approve the connection, we must shake hands
|
||||
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))
|
||||
{
|
||||
@ -702,11 +637,6 @@ namespace RageCoop.Server
|
||||
local.Deny("Username contains special chars!");
|
||||
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()))
|
||||
{
|
||||
local.Deny("This Username has been blocked by this server!");
|
||||
@ -717,7 +647,7 @@ namespace RageCoop.Server
|
||||
local.Deny("This IP was blocked by this server!");
|
||||
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!");
|
||||
return;
|
||||
@ -730,19 +660,20 @@ namespace RageCoop.Server
|
||||
// Add the player to Players
|
||||
lock (Clients)
|
||||
{
|
||||
Clients.Add(
|
||||
Clients.Add(local.RemoteUniqueIdentifier,
|
||||
tmpClient = new Client()
|
||||
{
|
||||
ClientID = local.RemoteUniqueIdentifier,
|
||||
NetID = local.RemoteUniqueIdentifier,
|
||||
Connection=local,
|
||||
Player = new()
|
||||
{
|
||||
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();
|
||||
|
||||
// Create a new handshake packet
|
||||
@ -751,7 +682,6 @@ namespace RageCoop.Server
|
||||
PedID = packet.PedID,
|
||||
Username = string.Empty,
|
||||
ModVersion = string.Empty,
|
||||
NPCsAllowed = MainSettings.NpcsAllowed
|
||||
}.Pack(outgoingMessage);
|
||||
|
||||
// Accept the connection and send back a new handshake packet with the connection ID
|
||||
@ -766,7 +696,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
|
||||
private static void SendPlayerConnectPacket(NetConnection local)
|
||||
{
|
||||
Client localClient = Clients.Find(x => x.ClientID == local.RemoteUniqueIdentifier);
|
||||
Client localClient = Util.GetClientByID(local.RemoteUniqueIdentifier);
|
||||
if (localClient == null)
|
||||
{
|
||||
local.Disconnect("No data found!");
|
||||
@ -781,7 +711,7 @@ namespace RageCoop.Server
|
||||
{
|
||||
long targetNetHandle = targetPlayer.RemoteUniqueIdentifier;
|
||||
|
||||
Client targetClient = Clients.Find(x => x.ClientID == targetNetHandle);
|
||||
Client targetClient = Util.GetClientByID(targetNetHandle);
|
||||
if (targetClient != null)
|
||||
{
|
||||
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
||||
@ -813,7 +743,7 @@ namespace RageCoop.Server
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Info($"Player {localClient.Player.Username} connected!");
|
||||
Program.Logger.Info($"Player {localClient.Player.Username} connected!");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(MainSettings.WelcomeMessage))
|
||||
@ -826,7 +756,7 @@ namespace RageCoop.Server
|
||||
private static void SendPlayerDisconnectPacket(long 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)
|
||||
{
|
||||
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
||||
@ -838,13 +768,13 @@ namespace RageCoop.Server
|
||||
MainNetServer.SendMessage(outgoingMessage, clients, NetDeliveryMethod.ReliableOrdered, 0);
|
||||
}
|
||||
|
||||
Client localClient = Clients.FirstOrDefault(x => x.ClientID == nethandle);
|
||||
Client localClient = Util.GetClientByID( nethandle);
|
||||
if (localClient == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Clients.Remove(localClient);
|
||||
Clients.Remove(localClient.NetID);
|
||||
|
||||
if (RunningResource != null)
|
||||
{
|
||||
@ -852,12 +782,12 @@ namespace RageCoop.Server
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Info($"Player {localClient.Player.Username} disconnected! ID:{playerPedID}");
|
||||
Program.Logger.Info($"Player {localClient.Player.Username} disconnected! ID:{playerPedID}");
|
||||
}
|
||||
}
|
||||
|
||||
#region SyncEntities
|
||||
private static void CharacterStateSync(Packets.PedStateSync packet,long ClientID)
|
||||
private static void PedStateSync(Packets.PedStateSync packet,long ClientID)
|
||||
{
|
||||
|
||||
|
||||
@ -868,15 +798,13 @@ namespace RageCoop.Server
|
||||
}
|
||||
|
||||
|
||||
|
||||
MainNetServer.Connections.FindAll(x => x.RemoteUniqueIdentifier != ClientID).ForEach(x =>
|
||||
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
||||
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);
|
||||
|
||||
});
|
||||
|
||||
if (c.NetID==client.NetID) { continue; }
|
||||
MainNetServer.SendMessage(outgoingMessage, c.Connection, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.PedSync);
|
||||
}
|
||||
if (RunningResource != null && packet.ID==client.Player.PedID)
|
||||
{
|
||||
RunningResource.InvokePlayerUpdate(client);
|
||||
@ -896,33 +824,47 @@ namespace RageCoop.Server
|
||||
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();
|
||||
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);
|
||||
if (client == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
MainNetServer.Connections.FindAll(x => x.RemoteUniqueIdentifier != ClientID).ForEach(x =>
|
||||
bool isPlayer = packet.ID==client.Player.PedID;
|
||||
if (isPlayer) { client.Player.Position=packet.Position; }
|
||||
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
||||
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);
|
||||
}
|
||||
@ -934,43 +876,27 @@ namespace RageCoop.Server
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MainNetServer.Connections.FindAll(x => x.RemoteUniqueIdentifier != ClientID).ForEach(x =>
|
||||
bool isPlayer = packet.ID==client.Player.VehicleID;
|
||||
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();
|
||||
packet.Pack(outgoingMessage);
|
||||
MainNetServer.SendMessage(outgoingMessage, x, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.VehicleSync);
|
||||
|
||||
});
|
||||
/*
|
||||
Client client = Util.GetClientByID(ClientID);
|
||||
if (client == null)
|
||||
{
|
||||
return;
|
||||
MainNetServer.SendMessage(outgoingMessage, c.Connection, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.PedSync);
|
||||
}
|
||||
// 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)
|
||||
{
|
||||
@ -980,12 +906,13 @@ namespace RageCoop.Server
|
||||
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();
|
||||
packet.Pack(outgoingMessage);
|
||||
MainNetServer.SendMessage(outgoingMessage, x, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.ProjectileSync);
|
||||
});
|
||||
MainNetServer.SendMessage(outgoingMessage, c.Connection, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.PedSync);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -1004,7 +931,7 @@ namespace RageCoop.Server
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
@ -1048,7 +975,7 @@ namespace RageCoop.Server
|
||||
|
||||
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)
|
||||
|
@ -55,8 +55,8 @@ namespace RageCoop.Server
|
||||
(localQueue.Dequeue() as Action)?.Invoke();
|
||||
}
|
||||
|
||||
// 16 milliseconds to sleep to reduce CPU usage
|
||||
Thread.Sleep(1000 / 60);
|
||||
// 15 milliseconds to sleep to reduce CPU usage
|
||||
Thread.Sleep(15);
|
||||
}
|
||||
|
||||
_script.API.InvokeStop();
|
||||
@ -105,13 +105,6 @@ namespace RageCoop.Server
|
||||
return task.Result;
|
||||
}
|
||||
|
||||
public void InvokePlayerPositionUpdate(string username)
|
||||
{
|
||||
lock (_actionQueue.SyncRoot)
|
||||
{
|
||||
_actionQueue.Enqueue(new Action(() => _script.API.InvokePlayerPositionUpdate(username)));
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@ -197,25 +167,6 @@ namespace RageCoop.Server
|
||||
/// Called when a new player sends data like health
|
||||
/// </summary>
|
||||
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 void InvokeTick(long tick)
|
||||
@ -253,11 +204,6 @@ namespace RageCoop.Server
|
||||
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)
|
||||
{
|
||||
CancelEventArgs args = new(false);
|
||||
@ -265,21 +211,6 @@ namespace RageCoop.Server
|
||||
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)
|
||||
{
|
||||
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="customID">The ID to check what this data is</param>
|
||||
/// <param name="bytes">The serialized data</param>
|
||||
/// <param name="netHandleList">The list of connections (players) that will receive the data</param>
|
||||
public static void SendModPacketToAll(string modName, byte customID, byte[] bytes, List<long> netHandleList = null)
|
||||
/// <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<int> playerList = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
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
|
||||
{// 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
|
||||
if (connections.Count > 0)
|
||||
NetOutgoingMessage outgoingMessage = Server.MainNetServer.CreateMessage();
|
||||
new Packets.Mod()
|
||||
{
|
||||
NetOutgoingMessage outgoingMessage = Server.MainNetServer.CreateMessage();
|
||||
new Packets.Mod()
|
||||
{
|
||||
NetHandle = 0,
|
||||
Target = 0,
|
||||
Name = modName,
|
||||
CustomPacketID = customID,
|
||||
Bytes = bytes
|
||||
}.Pack(outgoingMessage);
|
||||
Logging.Debug($"SendModPacketToAll recipients list {connections.Count}");
|
||||
Server.MainNetServer.SendMessage(outgoingMessage, connections, NetDeliveryMethod.ReliableOrdered, (byte)ConnectionChannel.Mod);
|
||||
Server.MainNetServer.FlushSendQueue();
|
||||
Name = modName,
|
||||
CustomPacketID = customID,
|
||||
Bytes = bytes
|
||||
}.Pack(outgoingMessage);
|
||||
if (playerList==null)
|
||||
{
|
||||
Server.MainNetServer.SendMessage(outgoingMessage, Server.MainNetServer.Connections, NetDeliveryMethod.ReliableOrdered, (byte)ConnectionChannel.Mod);
|
||||
}
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@ -360,37 +295,15 @@ namespace RageCoop.Server
|
||||
}
|
||||
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>
|
||||
/// Get a list of all Clients
|
||||
/// </summary>
|
||||
/// <returns>All Clients as a List</returns>
|
||||
public static List<Client> GetAllClients()
|
||||
/// <returns>All clients as a dictionary indexed by NetID</returns>
|
||||
public static Dictionary<long,Client> GetAllClients()
|
||||
{
|
||||
return Server.Clients;
|
||||
}
|
||||
@ -402,7 +315,7 @@ namespace RageCoop.Server
|
||||
/// <returns>The Client from this user or null</returns>
|
||||
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>
|
||||
@ -428,7 +341,7 @@ namespace RageCoop.Server
|
||||
}
|
||||
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} <<");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,16 +3,22 @@
|
||||
public class Settings
|
||||
{
|
||||
public int Port { get; set; } = 4499;
|
||||
public int MaxPlayers { get; set; } = 16;
|
||||
public int MaxLatency { get; set; } = 300;
|
||||
public int MaxPlayers { get; set; } = 32;
|
||||
public int MaxLatency { get; set; } = 500;
|
||||
public string Name { get; set; } = "RAGECOOP server";
|
||||
public string WelcomeMessage { get; set; } = "Welcome on this server :)";
|
||||
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 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;
|
||||
/// <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;
|
||||
}
|
||||
}
|
||||
|
@ -6,11 +6,30 @@ using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using RageCoop.Core;
|
||||
using Lidgren.Network;
|
||||
using System.Net;
|
||||
|
||||
namespace RageCoop.Server
|
||||
{
|
||||
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)
|
||||
{
|
||||
return obj switch
|
||||
@ -30,7 +49,8 @@ namespace RageCoop.Server
|
||||
|
||||
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)
|
||||
{
|
||||
NetConnection localConn = Server.MainNetServer.Connections.Find(x => id == x.RemoteUniqueIdentifier);
|
||||
@ -46,13 +66,13 @@ namespace RageCoop.Server
|
||||
|
||||
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)
|
||||
{
|
||||
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
|
||||
@ -65,25 +85,6 @@ namespace RageCoop.Server
|
||||
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()
|
||||
{
|
||||
XmlSerializer ser = new(typeof(T));
|
||||
|
Reference in New Issue
Block a user