Lots of sh*t
API cleanup Complete deluxo transformation sync blahblahblah
This commit is contained in:
parent
ad698a656d
commit
b96d349e4a
@ -45,10 +45,6 @@ namespace RageCoop.Client
|
||||
/// ?
|
||||
/// </summary>
|
||||
public static event ChatMessage OnChatMessage;
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// </summary>
|
||||
public static event ModEvent OnModPacketReceived;
|
||||
|
||||
public static void Connected()
|
||||
{
|
||||
@ -60,9 +56,9 @@ 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)
|
||||
@ -70,11 +66,6 @@ namespace RageCoop.Client
|
||||
OnConnection?.Invoke(false, netHandle);
|
||||
}
|
||||
|
||||
public static void ModPacketReceived(long from, string mod, byte customID, byte[] bytes)
|
||||
{
|
||||
OnModPacketReceived?.Invoke(from, mod, customID, bytes);
|
||||
}
|
||||
|
||||
public static bool ChatMessageReceived(string from, string message)
|
||||
{
|
||||
CancelEventArgs args = new CancelEventArgs(false);
|
||||
@ -127,20 +118,6 @@ namespace RageCoop.Client
|
||||
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 +126,7 @@ namespace RageCoop.Client
|
||||
#if NON_INTERACTIVE
|
||||
return false;
|
||||
#else
|
||||
return Main.MainMenu.MenuPool.AreAnyVisible;
|
||||
return Menus.CoopMenu.MenuPool.AreAnyVisible;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -177,40 +154,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 +179,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
|
||||
}
|
||||
}
|
||||
|
@ -26,13 +26,12 @@ namespace RageCoop.Client
|
||||
public static readonly string CurrentVersion = "V0_3";
|
||||
|
||||
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();
|
||||
@ -71,7 +70,6 @@ namespace RageCoop.Client
|
||||
Settings = Util.ReadSettings();
|
||||
Networking.Start();
|
||||
#if !NON_INTERACTIVE
|
||||
MainMenu = new RageCoopMenu();
|
||||
#endif
|
||||
MainChat = new Chat();
|
||||
#if DEBUG
|
||||
@ -107,7 +105,7 @@ namespace RageCoop.Client
|
||||
}
|
||||
|
||||
#if !NON_INTERACTIVE
|
||||
MainMenu.MenuPool.Process();
|
||||
CoopMenu.MenuPool.Process();
|
||||
#endif
|
||||
|
||||
|
||||
@ -193,14 +191,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 +238,7 @@ namespace RageCoop.Client
|
||||
|
||||
if (V!=null)
|
||||
{
|
||||
var seat = Util.GetNearestSeat(P, V);
|
||||
var seat = P.GetNearestSeat(V);
|
||||
P.Task.EnterVehicle(V, seat);
|
||||
}
|
||||
}
|
||||
|
@ -10,24 +10,20 @@ namespace RageCoop.Client.Menus
|
||||
/// <summary>
|
||||
/// Don't use it!
|
||||
/// </summary>
|
||||
public class RageCoopMenu
|
||||
internal static class CoopMenu
|
||||
{
|
||||
public ObjectPool MenuPool = new ObjectPool();
|
||||
|
||||
public NativeMenu MainMenu = new NativeMenu("RAGECOOP", "MAIN")
|
||||
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
|
||||
};
|
||||
#region SUB
|
||||
public SettingsMenu SubSettings = new SettingsMenu();
|
||||
#endregion
|
||||
|
||||
public static NativeMenu LastMenu { get; set; } = Menu;
|
||||
#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~" +
|
||||
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") };
|
||||
@ -38,35 +34,35 @@ namespace RageCoop.Client.Menus
|
||||
/// <summary>
|
||||
/// Don't use it!
|
||||
/// </summary>
|
||||
public RageCoopMenu()
|
||||
static CoopMenu()
|
||||
{
|
||||
MainMenu.Banner.Color = Color.FromArgb(225, 0, 0, 0);
|
||||
MainMenu.Title.Color = Color.FromArgb(255, 165, 0);
|
||||
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.DisConnectFromServer(Main.Settings.LastServerAddress); };
|
||||
|
||||
|
||||
MainMenu.Add(_usernameItem);
|
||||
MainMenu.Add(ServerIpItem);
|
||||
MainMenu.Add(_serverConnectItem);
|
||||
Menu.Add(_usernameItem);
|
||||
Menu.Add(ServerIpItem);
|
||||
Menu.Add(_serverConnectItem);
|
||||
|
||||
MainMenu.AddSubMenu(SubSettings.Menu);
|
||||
MainMenu.AddSubMenu(DevToolMenu.Menu);
|
||||
MainMenu.AddSubMenu(DebugMenu.Menu);
|
||||
Menu.AddSubMenu(SettingsMenu.Menu);
|
||||
Menu.AddSubMenu(DevToolMenu.Menu);
|
||||
Menu.AddSubMenu(DebugMenu.Menu);
|
||||
|
||||
|
||||
MenuPool.Add(MainMenu);
|
||||
MenuPool.Add(SubSettings.Menu);
|
||||
MenuPool.Add(Menu);
|
||||
MenuPool.Add(SettingsMenu.Menu);
|
||||
MenuPool.Add(DevToolMenu.Menu);
|
||||
MenuPool.Add(DebugMenu.Menu);
|
||||
MenuPool.Add(DebugMenu.DiagnosticMenu);
|
||||
|
||||
MainMenu.Add(_aboutItem);
|
||||
Menu.Add(_aboutItem);
|
||||
}
|
||||
|
||||
public void UsernameActivated(object a, System.EventArgs b)
|
||||
public static void UsernameActivated(object a, System.EventArgs b)
|
||||
{
|
||||
string newUsername = Game.GetUserInput(WindowTitle.EnterMessage20, _usernameItem.AltTitle, 20);
|
||||
if (!string.IsNullOrWhiteSpace(newUsername))
|
||||
@ -78,7 +74,7 @@ namespace RageCoop.Client.Menus
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerIpActivated(object a, System.EventArgs b)
|
||||
public static void ServerIpActivated(object a, System.EventArgs b)
|
||||
{
|
||||
string newServerIp = Game.GetUserInput(WindowTitle.EnterMessage60, ServerIpItem.AltTitle, 60);
|
||||
if (!string.IsNullOrWhiteSpace(newServerIp) && newServerIp.Contains(":"))
|
||||
@ -90,21 +86,21 @@ namespace RageCoop.Client.Menus
|
||||
}
|
||||
}
|
||||
|
||||
public void InitiateConnectionMenuSetting()
|
||||
public static void InitiateConnectionMenuSetting()
|
||||
{
|
||||
_usernameItem.Enabled = false;
|
||||
ServerIpItem.Enabled = false;
|
||||
_serverConnectItem.Enabled = false;
|
||||
}
|
||||
|
||||
public void ConnectedMenuSetting()
|
||||
public static void ConnectedMenuSetting()
|
||||
{
|
||||
_serverConnectItem.Enabled = true;
|
||||
_serverConnectItem.Title = "Disconnect";
|
||||
MainMenu.Visible = false;
|
||||
Menu.Visible = false;
|
||||
}
|
||||
|
||||
public void DisconnectedMenuSetting()
|
||||
public static void DisconnectedMenuSetting()
|
||||
{
|
||||
_usernameItem.Enabled = true;
|
||||
ServerIpItem.Enabled = true;
|
@ -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")
|
||||
{
|
||||
|
@ -9,19 +9,19 @@ 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
|
||||
/// <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
|
||||
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
|
||||
}
|
||||
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
|
||||
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
|
||||
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,982 +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 = 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 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;
|
||||
}
|
||||
if (ped.IsPlayer)
|
||||
{
|
||||
flags|=PedDataFlags.IsPlayer;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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 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;
|
||||
|
||||
// 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;
|
||||
}
|
||||
public static Vector3 PredictPosition(this Entity e,bool applyDefault=true)
|
||||
{
|
||||
return e.Position+e.Velocity*((applyDefault?SyncParameters.PositioinPredictionDefault:0)+Networking.Latency);
|
||||
}
|
||||
|
||||
#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 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 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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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>();
|
||||
|
@ -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,6 +79,7 @@ namespace RageCoop.Client
|
||||
{
|
||||
try
|
||||
{
|
||||
Client.FlushSendQueue();
|
||||
ReceiveMessages();
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -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:
|
||||
@ -370,6 +364,7 @@ namespace RageCoop.Client
|
||||
v.BrakePower=packet.BrakePower;
|
||||
v.Velocity=packet.Velocity;
|
||||
v.RotationVelocity=packet.RotationVelocity;
|
||||
v.DeluxoWingRatio=packet.DeluxoWingRatio;
|
||||
v.LastSynced=Main.Ticked;
|
||||
}
|
||||
private static void VehicleStateSync(Packets.VehicleStateSync packet)
|
||||
|
@ -83,6 +83,7 @@ namespace RageCoop.Client
|
||||
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)
|
||||
@ -149,27 +150,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 +173,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
|
||||
)
|
||||
{
|
||||
|
@ -123,12 +123,15 @@
|
||||
<ItemGroup>
|
||||
<Compile Include="DevTools\DevTool.cs" />
|
||||
<Compile Include="Menus\Sub\DevToolMenu.cs" />
|
||||
<Compile Include="Misc\WeaponUtil.cs" />
|
||||
<Compile Include="Util\MathExtensions.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 +145,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>
|
||||
|
@ -8,7 +8,7 @@ using GTA.Math;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
public abstract class SyncedEntity
|
||||
internal abstract class SyncedEntity
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
|
@ -14,7 +14,7 @@ namespace RageCoop.Client
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// </summary>
|
||||
public partial class SyncedPed:SyncedEntity
|
||||
internal class SyncedPed:SyncedEntity
|
||||
{
|
||||
#region CONSTRUCTORS
|
||||
|
||||
|
@ -11,7 +11,7 @@ using RageCoop.Core;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
public class SyncedVehicle : SyncedEntity
|
||||
internal class SyncedVehicle : SyncedEntity
|
||||
{
|
||||
|
||||
#region -- CONSTRUCTORS --
|
||||
@ -89,7 +89,7 @@ namespace RageCoop.Client
|
||||
/// VehicleSeat,PedID
|
||||
/// </summary>
|
||||
public Dictionary<VehicleSeat, SyncedPed> Passengers { get; set; }
|
||||
|
||||
public float DeluxoWingRatio { get; set; } = -1;
|
||||
private long _lastPositionCalibrated { get; set; }
|
||||
|
||||
#endregion
|
||||
@ -148,9 +148,11 @@ namespace RageCoop.Client
|
||||
MainVehicle.Rotation = Rotation;
|
||||
MainVehicle.RotationVelocity = RotationVelocity;
|
||||
}
|
||||
_vehicleStopTime = Util.GetTickCount64();
|
||||
if (DeluxoWingRatio!=-1)
|
||||
{
|
||||
MainVehicle.SetDeluxoWingRatio(DeluxoWingRatio);
|
||||
}
|
||||
#endregion
|
||||
|
||||
if (LastStateSynced>LastUpdated)
|
||||
{
|
||||
#region -- SYNC STATE --
|
||||
|
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());
|
||||
}
|
||||
}
|
||||
}
|
389
Client/Util/PedExtensions.cs
Normal file
389
Client/Util/PedExtensions.cs
Normal file
@ -0,0 +1,389 @@
|
||||
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;
|
||||
}
|
||||
|
||||
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(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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
190
Client/Util/Util.cs
Normal file
190
Client/Util/Util.cs
Normal file
@ -0,0 +1,190 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
289
Client/Util/VehicleExtensions.cs
Normal file
289
Client/Util/VehicleExtensions.cs
Normal file
@ -0,0 +1,289 @@
|
||||
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;
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
@ -191,7 +191,6 @@ namespace RageCoop.Core
|
||||
IsOnLadder = 1 << 8,
|
||||
IsVaulting = 1 << 9,
|
||||
IsInCover=1<< 10,
|
||||
IsPlayer=1<<11,
|
||||
}
|
||||
|
||||
#region ===== VEHICLE DATA =====
|
||||
@ -239,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; }
|
||||
@ -256,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));
|
||||
@ -286,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);
|
||||
@ -683,9 +666,6 @@ namespace RageCoop.Core
|
||||
#endregion // ===== NATIVECALL =====
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// </summary>
|
||||
public static class CoopSerializer
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -219,7 +219,7 @@ namespace RageCoop.Core
|
||||
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)
|
||||
{
|
||||
@ -252,6 +252,10 @@ namespace RageCoop.Core
|
||||
// Write vehicle steering angle
|
||||
byteArray.AddFloat(SteeringAngle);
|
||||
|
||||
if (DeluxoWingRatio!=-1)
|
||||
{
|
||||
byteArray.AddFloat(DeluxoWingRatio);
|
||||
}
|
||||
|
||||
byte[] result = byteArray.ToArray();
|
||||
|
||||
@ -289,6 +293,10 @@ namespace RageCoop.Core
|
||||
// Read steering angle
|
||||
SteeringAngle = reader.ReadFloat();
|
||||
|
||||
if (reader.CanRead(4))
|
||||
{
|
||||
DeluxoWingRatio= reader.ReadFloat();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
@ -1,30 +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 Vector3 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 float Latency { get; internal set; }
|
||||
public int Health { get; internal set; }
|
||||
}
|
||||
}
|
||||
|
@ -8,19 +8,19 @@ 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}]");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -28,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
|
||||
@ -66,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)
|
||||
{
|
||||
@ -77,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;
|
||||
@ -95,10 +95,10 @@ 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!");
|
||||
Logging.Error($"[Client->SendNativeCall(ulong hash, params object[] args)]: Connection \"{NetID}\" not found!");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -128,10 +128,10 @@ 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!");
|
||||
Logging.Error($"[Client->SendNativeResponse(Action<object> callback, ulong hash, Type type, params object[] args)]: Connection \"{NetID}\" not found!");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -189,10 +189,10 @@ namespace RageCoop.Server
|
||||
|
||||
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!");
|
||||
Logging.Error($"[Client->SendCleanUpWorld()]: Connection \"{NetID}\" not found!");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -205,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;
|
||||
@ -214,8 +214,6 @@ namespace RageCoop.Server
|
||||
NetOutgoingMessage outgoingMessage = Server.MainNetServer.CreateMessage();
|
||||
new Packets.Mod()
|
||||
{
|
||||
NetHandle = 0,
|
||||
Target = 0,
|
||||
Name = modName,
|
||||
CustomPacketID = customID,
|
||||
Bytes = bytes
|
||||
@ -239,7 +237,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;
|
||||
|
@ -122,8 +122,6 @@ namespace RageCoop.Server
|
||||
"\"players\": \"" + MainNetServer.ConnectionsCount + "\", " +
|
||||
"\"maxPlayers\": \"" + MainSettings.MaxPlayers + "\", " +
|
||||
"\"allowlist\": \"" + _mainAllowlist.Username.Any() + "\", " +
|
||||
"\"mods\": \"" + MainSettings.ModsAllowed + "\", " +
|
||||
"\"npcs\": \"" + MainSettings.NpcsAllowed + "\"" +
|
||||
" }";
|
||||
|
||||
HttpResponseMessage response = null;
|
||||
@ -237,7 +235,7 @@ namespace RageCoop.Server
|
||||
{
|
||||
if (!client.FilesSent)
|
||||
{
|
||||
DownloadManager.InsertClient(client.ClientID);
|
||||
DownloadManager.InsertClient(client.NetID);
|
||||
client.FilesSent = true;
|
||||
}
|
||||
});
|
||||
@ -446,63 +444,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
|
||||
@ -518,7 +459,7 @@ namespace RageCoop.Server
|
||||
Client client = Util.GetClientByID(message.SenderConnection.RemoteUniqueIdentifier);
|
||||
if (client != null && !client.FilesReceived)
|
||||
{
|
||||
DownloadManager.TryToRemoveClient(client.ClientID, packet.ID);
|
||||
DownloadManager.TryToRemoveClient(client.NetID, packet.ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -656,7 +597,7 @@ namespace RageCoop.Server
|
||||
{
|
||||
foreach(Client c in Clients.Values)
|
||||
{
|
||||
MainNetServer.Connections.FindAll(x => x.RemoteUniqueIdentifier != c.ClientID).ForEach(x =>
|
||||
MainNetServer.Connections.FindAll(x => x.RemoteUniqueIdentifier != c.NetID).ForEach(x =>
|
||||
{
|
||||
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
||||
new Packets.PlayerInfoUpdate()
|
||||
@ -734,7 +675,7 @@ namespace RageCoop.Server
|
||||
Clients.Add(local.RemoteUniqueIdentifier,
|
||||
tmpClient = new Client()
|
||||
{
|
||||
ClientID = local.RemoteUniqueIdentifier,
|
||||
NetID = local.RemoteUniqueIdentifier,
|
||||
Connection=local,
|
||||
Player = new()
|
||||
{
|
||||
@ -753,7 +694,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
|
||||
@ -846,7 +786,7 @@ namespace RageCoop.Server
|
||||
return;
|
||||
}
|
||||
|
||||
Clients.Remove(localClient.ClientID);
|
||||
Clients.Remove(localClient.NetID);
|
||||
|
||||
if (RunningResource != null)
|
||||
{
|
||||
@ -870,14 +810,13 @@ namespace RageCoop.Server
|
||||
}
|
||||
|
||||
|
||||
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
||||
packet.Pack(outgoingMessage);
|
||||
foreach (var c in Clients.Values)
|
||||
{
|
||||
if (c.ClientID==client.ClientID) { continue; }
|
||||
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
||||
packet.Pack(outgoingMessage);
|
||||
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);
|
||||
@ -899,7 +838,7 @@ namespace RageCoop.Server
|
||||
|
||||
foreach (var c in Clients.Values)
|
||||
{
|
||||
if (c.ClientID==client.ClientID) { continue; }
|
||||
if (c.NetID==client.NetID) { continue; }
|
||||
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
||||
packet.Pack(outgoingMessage);
|
||||
MainNetServer.SendMessage(outgoingMessage, c.Connection, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.PedSync);
|
||||
@ -912,13 +851,15 @@ namespace RageCoop.Server
|
||||
{
|
||||
return;
|
||||
}
|
||||
bool isPlayer = packet.Flag.HasFlag(PedDataFlags.IsPlayer);
|
||||
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)
|
||||
{
|
||||
|
||||
// Don't send data back
|
||||
if (c.ClientID==client.ClientID) { continue; }
|
||||
if (c.NetID==client.NetID) { continue; }
|
||||
|
||||
// Check streaming distance
|
||||
if (isPlayer)
|
||||
@ -932,12 +873,10 @@ namespace RageCoop.Server
|
||||
{
|
||||
continue;
|
||||
}
|
||||
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
||||
packet.Pack(outgoingMessage);
|
||||
MainNetServer.SendMessage(outgoingMessage,c.Connection, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.PedSync);
|
||||
}
|
||||
|
||||
if (RunningResource != null && packet.ID==client.Player.PedID)
|
||||
if (RunningResource != null && isPlayer)
|
||||
{
|
||||
RunningResource.InvokePlayerUpdate(client);
|
||||
}
|
||||
@ -952,7 +891,7 @@ namespace RageCoop.Server
|
||||
bool isPlayer = packet.ID==client.Player.VehicleID;
|
||||
foreach (var c in Clients.Values)
|
||||
{
|
||||
if (c.ClientID==client.ClientID) { continue; }
|
||||
if (c.NetID==client.NetID) { continue; }
|
||||
if (isPlayer)
|
||||
{
|
||||
// Player's vehicle
|
||||
@ -981,7 +920,7 @@ namespace RageCoop.Server
|
||||
|
||||
foreach (var c in Clients.Values)
|
||||
{
|
||||
if (c.ClientID==client.ClientID) { continue; }
|
||||
if (c.NetID==client.NetID) { continue; }
|
||||
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
||||
packet.Pack(outgoingMessage);
|
||||
MainNetServer.SendMessage(outgoingMessage, c.Connection, NetDeliveryMethod.UnreliableSequenced, (byte)ConnectionChannel.PedSync);
|
||||
|
@ -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();
|
||||
@ -167,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)
|
||||
@ -245,31 +226,35 @@ 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)
|
||||
{
|
||||
@ -314,32 +299,10 @@ namespace RageCoop.Server
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 dictionary indexed by ClientID</returns>
|
||||
/// <returns>All clients as a dictionary indexed by NetID</returns>
|
||||
public static Dictionary<long,Client> GetAllClients()
|
||||
{
|
||||
return Server.Clients;
|
||||
|
@ -8,8 +8,6 @@
|
||||
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";
|
||||
|
@ -53,7 +53,7 @@ namespace RageCoop.Server
|
||||
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
|
||||
|
Loading…
x
Reference in New Issue
Block a user