Ahhh...
This commit is contained in:
@ -1,53 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal enum TimeStamp
|
||||
{
|
||||
AddPeds,
|
||||
PedTotal,
|
||||
AddVehicles,
|
||||
VehicleTotal,
|
||||
SendPed,
|
||||
SendPedState,
|
||||
SendVehicle,
|
||||
SendVehicleState,
|
||||
UpdatePed,
|
||||
UpdateVehicle,
|
||||
CheckProjectiles,
|
||||
GetAllEntities,
|
||||
Receive,
|
||||
|
||||
}
|
||||
internal static class Debug
|
||||
{
|
||||
public static Dictionary<TimeStamp, long> TimeStamps = new Dictionary<TimeStamp, long>();
|
||||
private static int _lastNfHandle;
|
||||
static Debug()
|
||||
{
|
||||
foreach(TimeStamp t in Enum.GetValues(typeof(TimeStamp)))
|
||||
{
|
||||
TimeStamps.Add(t, 0);
|
||||
}
|
||||
}
|
||||
public static string Dump(this Dictionary<TimeStamp, long> d)
|
||||
{
|
||||
string s = "";
|
||||
foreach(KeyValuePair<TimeStamp, long> kvp in d)
|
||||
{
|
||||
s+=kvp.Key+":"+kvp.Value+"\n";
|
||||
}
|
||||
return s;
|
||||
}
|
||||
public static void ShowTimeStamps()
|
||||
{
|
||||
GTA.UI.Notification.Hide(_lastNfHandle);
|
||||
_lastNfHandle=GTA.UI.Notification.Show(Debug.TimeStamps.Dump());
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -1,184 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using System.Threading;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal class DevTool:Script
|
||||
{
|
||||
public static Vehicle ToMark;
|
||||
public static bool UseSecondary=false;
|
||||
public static int Current = 0;
|
||||
public static int Secondary = 0;
|
||||
public static MuzzleDir Direction = MuzzleDir.Forward;
|
||||
public DevTool()
|
||||
{
|
||||
Tick+=OnTick;
|
||||
KeyDown+=OnKeyDown;
|
||||
}
|
||||
|
||||
private void OnKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (ToMark==null||(!ToMark.Exists())) { return; }
|
||||
if (DevToolMenu.Menu.SelectedItem==DevToolMenu.boneIndexItem) {
|
||||
|
||||
switch (e.KeyCode)
|
||||
{
|
||||
case Keys.Right:
|
||||
Current++;
|
||||
break;
|
||||
case Keys.Left:
|
||||
Current--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (DevToolMenu.Menu.SelectedItem==DevToolMenu.secondaryBoneIndexItem)
|
||||
{
|
||||
|
||||
switch (e.KeyCode)
|
||||
{
|
||||
case Keys.Right:
|
||||
Secondary++;
|
||||
break;
|
||||
case Keys.Left:
|
||||
Secondary--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Update();
|
||||
}
|
||||
private static void Update()
|
||||
{
|
||||
|
||||
if (Current>ToMark.Bones.Count-1)
|
||||
{
|
||||
Current=0;
|
||||
}
|
||||
else if (Current< 0)
|
||||
{
|
||||
Current=ToMark.Bones.Count-1;
|
||||
}
|
||||
DevToolMenu.boneIndexItem.AltTitle= Current.ToString();
|
||||
if (Secondary>ToMark.Bones.Count-1)
|
||||
{
|
||||
Secondary=0;
|
||||
}
|
||||
else if (Secondary< 0)
|
||||
{
|
||||
Secondary=ToMark.Bones.Count-1;
|
||||
}
|
||||
DevToolMenu.secondaryBoneIndexItem.AltTitle= Secondary.ToString();
|
||||
}
|
||||
private static void OnTick(object sender, EventArgs e)
|
||||
{
|
||||
if(ToMark == null || !ToMark.Exists()){ return;}
|
||||
Update();
|
||||
Draw(Current);
|
||||
if (UseSecondary)
|
||||
{
|
||||
Draw(Secondary);
|
||||
}
|
||||
|
||||
}
|
||||
private static void Draw(int boneindex)
|
||||
{
|
||||
var bone = ToMark.Bones[boneindex];
|
||||
World.DrawLine(bone.Position, bone.Position+2*bone.ForwardVector, Color.Blue);
|
||||
World.DrawLine(bone.Position, bone.Position+2*bone.UpVector, Color.Green);
|
||||
World.DrawLine(bone.Position, bone.Position+2*bone.RightVector, Color.Yellow);
|
||||
Vector3 todraw = bone.ForwardVector;
|
||||
switch ((byte)Direction)
|
||||
{
|
||||
case 0:
|
||||
todraw=bone.ForwardVector;
|
||||
break;
|
||||
case 1:
|
||||
todraw=bone.RightVector;
|
||||
break;
|
||||
case 2:
|
||||
todraw=bone.UpVector;
|
||||
break;
|
||||
case 3:
|
||||
todraw=bone.ForwardVector*-1;
|
||||
break;
|
||||
case 4:
|
||||
todraw=bone.RightVector*-1;
|
||||
break;
|
||||
case 5:
|
||||
todraw=bone.UpVector*-1;
|
||||
break;
|
||||
}
|
||||
World.DrawLine(bone.Position, bone.Position+10*todraw, Color.Red);
|
||||
}
|
||||
public static void CopyToClipboard(MuzzleDir dir)
|
||||
{
|
||||
|
||||
if (ToMark!=null)
|
||||
{
|
||||
string s;
|
||||
if (UseSecondary)
|
||||
{
|
||||
if ((byte)dir<3)
|
||||
{
|
||||
s=$@"
|
||||
// {ToMark.DisplayName}
|
||||
case {ToMark.Model.Hash}:
|
||||
i=BulletsShot%2==0 ? {Current} : {Secondary};
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].{dir}Vector);
|
||||
";
|
||||
}
|
||||
else
|
||||
{
|
||||
s=$@"
|
||||
// {ToMark.DisplayName}
|
||||
case {ToMark.Model.Hash}:
|
||||
i=BulletsShot%2==0 ? {Current} : {Secondary};
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].{((MuzzleDir)(dir-3)).ToString()}Vector*-1);
|
||||
";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((byte)dir<3)
|
||||
{
|
||||
s=$@"
|
||||
// {ToMark.DisplayName}
|
||||
case {ToMark.Model.Hash}:
|
||||
return new MuzzleInfo(v.Bones[{Current}].Position, v.Bones[{Current}].{dir}Vector);
|
||||
";
|
||||
}
|
||||
else
|
||||
{
|
||||
s=$@"
|
||||
// {ToMark.DisplayName}
|
||||
case {ToMark.Model.Hash}:
|
||||
return new MuzzleInfo(v.Bones[{Current}].Position, v.Bones[{Current}].{((MuzzleDir)(dir-3)).ToString()}Vector*-1);
|
||||
";
|
||||
}
|
||||
}
|
||||
Thread thread = new Thread(() => Clipboard.SetText(s));
|
||||
thread.SetApartmentState(ApartmentState.STA); //Set the thread to STA
|
||||
thread.Start();
|
||||
thread.Join();
|
||||
GTA.UI.Notification.Show("Copied to clipboard, please paste it on the GitHub issue page!");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
internal enum MuzzleDir:byte
|
||||
{
|
||||
Forward=0,
|
||||
Right = 1,
|
||||
Up=2,
|
||||
Backward=3,
|
||||
Left = 4,
|
||||
Down=5,
|
||||
}
|
||||
}
|
@ -1,391 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Threading;
|
||||
using System.Diagnostics;
|
||||
using RageCoop.Client.Menus;
|
||||
using RageCoop.Core;
|
||||
using GTA;
|
||||
using GTA.Native;
|
||||
using GTA.Math;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// Don't use it!
|
||||
/// </summary>
|
||||
internal class Main : Script
|
||||
{
|
||||
|
||||
private bool _gameLoaded = false;
|
||||
internal static readonly string CurrentVersion = "V0_5_0";
|
||||
|
||||
internal static int LocalPlayerID=0;
|
||||
|
||||
internal static RelationshipGroup SyncedPedsGroup;
|
||||
|
||||
internal static new Settings Settings = null;
|
||||
internal static Scripting.BaseScript BaseScript=new Scripting.BaseScript();
|
||||
|
||||
#if !NON_INTERACTIVE
|
||||
#endif
|
||||
internal static Chat MainChat = null;
|
||||
internal static Stopwatch Counter = new Stopwatch();
|
||||
internal static Logger Logger = null;
|
||||
|
||||
internal static ulong Ticked = 0;
|
||||
internal static Vector3 PlayerPosition;
|
||||
internal static Scripting.Resources Resources=null;
|
||||
private static List<Func<bool>> QueuedActions = new List<Func<bool>>();
|
||||
/// <summary>
|
||||
/// Don't use it!
|
||||
/// </summary>
|
||||
public Main()
|
||||
{
|
||||
try
|
||||
{
|
||||
Settings = Util.ReadSettings();
|
||||
}
|
||||
catch
|
||||
{
|
||||
GTA.UI.Notification.Show("Malformed configuration, overwriting with default values...");
|
||||
Settings=new Settings();
|
||||
Util.SaveSettings();
|
||||
}
|
||||
Directory.CreateDirectory(Settings.DataDirectory);
|
||||
Logger=new Logger()
|
||||
{
|
||||
LogPath=$"{Settings.DataDirectory}\\RageCoop.Client.log",
|
||||
UseConsole=false,
|
||||
#if DEBUG
|
||||
LogLevel = 0,
|
||||
#else
|
||||
LogLevel=Settings.LogLevel,
|
||||
#endif
|
||||
};
|
||||
Resources = new Scripting.Resources();
|
||||
if (Game.Version < GameVersion.v1_0_1290_1_Steam)
|
||||
{
|
||||
Tick += (object sender, EventArgs e) =>
|
||||
{
|
||||
if (Game.IsLoading)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!_gameLoaded)
|
||||
{
|
||||
GTA.UI.Notification.Show("~r~Please update your GTA5 to v1.0.1290 or newer!", true);
|
||||
_gameLoaded = true;
|
||||
}
|
||||
};
|
||||
return;
|
||||
}
|
||||
BaseScript.OnStart();
|
||||
SyncedPedsGroup=World.AddRelationshipGroup("SYNCPED");
|
||||
Game.Player.Character.RelationshipGroup.SetRelationshipBetweenGroups(SyncedPedsGroup, Relationship.Neutral, true);
|
||||
#if !NON_INTERACTIVE
|
||||
#endif
|
||||
MainChat = new Chat();
|
||||
Tick += OnTick;
|
||||
Tick += (s,e) => { Scripting.API.Events.InvokeTick(); };
|
||||
KeyDown += OnKeyDown;
|
||||
KeyDown+=(s, e) => { Scripting.API.Events.InvokeKeyDown(s, e); };
|
||||
KeyUp+=(s, e) => { Scripting.API.Events.InvokeKeyUp(s, e); };
|
||||
Aborted += (object sender, EventArgs e) => CleanUp();
|
||||
|
||||
Util.NativeMemory();
|
||||
Counter.Restart();
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
#endif
|
||||
private void OnTick(object sender, EventArgs e)
|
||||
{
|
||||
PlayerPosition=Game.Player.Character.Position;
|
||||
if (Game.IsLoading)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if (!_gameLoaded && (_gameLoaded = true))
|
||||
{
|
||||
#if !NON_INTERACTIVE
|
||||
GTA.UI.Notification.Show(GTA.UI.NotificationIcon.AllPlayersConf, "RAGECOOP","Welcome!", $"Press ~g~{Main.Settings.MenuKey}~s~ to open the menu.");
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !NON_INTERACTIVE
|
||||
CoopMenu.MenuPool.Process();
|
||||
#endif
|
||||
|
||||
DoQueuedActions();
|
||||
if (!Networking.IsOnServer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (Game.TimeScale!=1)
|
||||
{
|
||||
Game.TimeScale=1;
|
||||
}
|
||||
try
|
||||
{
|
||||
EntityPool.DoSync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Main.Logger.Error(ex);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if DEBUG
|
||||
if (Networking.ShowNetworkInfo)
|
||||
{
|
||||
|
||||
new LemonUI.Elements.ScaledText(new PointF(Screen.PrimaryScreen.Bounds.Width / 2, 0), $"L: {Networking.Latency * 1000:N0}ms", 0.5f) { Alignment = GTA.UI.Alignment.Center }.Draw();
|
||||
new LemonUI.Elements.ScaledText(new PointF(Screen.PrimaryScreen.Bounds.Width / 2, 30), $"R: {Lidgren.Network.NetUtility.ToHumanReadable(Statistics.BytesDownPerSecond)}/s", 0.5f) { Alignment = GTA.UI.Alignment.Center }.Draw();
|
||||
new LemonUI.Elements.ScaledText(new PointF(Screen.PrimaryScreen.Bounds.Width / 2, 60), $"S: {Lidgren.Network.NetUtility.ToHumanReadable(Statistics.BytesUpPerSecond)}/s", 0.5f) { Alignment = GTA.UI.Alignment.Center }.Draw();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
MainChat.Tick();
|
||||
PlayerList.Tick();
|
||||
if (!Scripting.API.Config.EnableAutoRespawn)
|
||||
{
|
||||
Function.Call(Hash.PAUSE_DEATH_ARREST_RESTART, true);
|
||||
Function.Call(Hash.IGNORE_NEXT_RESTART, true);
|
||||
Function.Call(Hash.FORCE_GAME_STATE_PLAYING);
|
||||
Function.Call(Hash.TERMINATE_ALL_SCRIPTS_WITH_THIS_NAME, "respawn_controller");
|
||||
|
||||
var P = Game.Player.Character;
|
||||
if (P.IsDead)
|
||||
{
|
||||
Function.Call(Hash.SET_FADE_OUT_AFTER_DEATH, false);
|
||||
|
||||
if (P.Health!=1)
|
||||
{
|
||||
P.Health=1;
|
||||
Game.Player.WantedLevel=0;
|
||||
Main.Logger.Debug("Player died.");
|
||||
}
|
||||
GTA.UI.Screen.StopEffects();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
Function.Call(Hash.DISPLAY_HUD, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Ticked++;
|
||||
}
|
||||
|
||||
private void OnKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (MainChat.Focused)
|
||||
{
|
||||
MainChat.OnKeyDown(e.KeyCode);
|
||||
return;
|
||||
}
|
||||
if (Networking.IsOnServer)
|
||||
{
|
||||
if (Game.IsControlPressed(GTA.Control.FrontendPause))
|
||||
{
|
||||
Function.Call(Hash.ACTIVATE_FRONTEND_MENU, Function.Call<int>(Hash.GET_HASH_KEY, "FE_MENU_VERSION_SP_PAUSE"), false, 0);
|
||||
return;
|
||||
}
|
||||
if (Game.IsControlPressed(GTA.Control.FrontendPauseAlternate)&&Settings.DisableAlternatePause)
|
||||
{
|
||||
Function.Call(Hash.ACTIVATE_FRONTEND_MENU, Function.Call<int>(Hash.GET_HASH_KEY, "FE_MENU_VERSION_SP_PAUSE"), false, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (e.KeyCode == Settings.MenuKey)
|
||||
{
|
||||
if (CoopMenu.MenuPool.AreAnyVisible)
|
||||
{
|
||||
CoopMenu.MenuPool.ForEach<LemonUI.Menus.NativeMenu>(x =>
|
||||
{
|
||||
if (x.Visible)
|
||||
{
|
||||
CoopMenu.LastMenu=x;
|
||||
x.Visible=false;
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
CoopMenu.LastMenu.Visible = true;
|
||||
}
|
||||
}
|
||||
else if (Game.IsControlJustPressed(GTA.Control.MultiplayerInfo))
|
||||
{
|
||||
if (Networking.IsOnServer)
|
||||
{
|
||||
ulong currentTimestamp = Util.GetTickCount64();
|
||||
PlayerList.Pressed = (currentTimestamp - PlayerList.Pressed) < 5000 ? (currentTimestamp - 6000) : currentTimestamp;
|
||||
}
|
||||
}
|
||||
else if (Game.IsControlJustPressed(GTA.Control.MpTextChatAll))
|
||||
{
|
||||
if (Networking.IsOnServer)
|
||||
{
|
||||
MainChat.Focused = true;
|
||||
}
|
||||
}
|
||||
else if (e.KeyCode==Settings.PassengerKey)
|
||||
{
|
||||
var P = Game.Player.Character;
|
||||
|
||||
if (!P.IsInVehicle())
|
||||
{
|
||||
if (P.IsTaskActive(TaskType.CTaskEnterVehicle))
|
||||
{
|
||||
P.Task.ClearAll();
|
||||
}
|
||||
else
|
||||
{
|
||||
var V = World.GetClosestVehicle(P.Position, 50);
|
||||
|
||||
if (V!=null)
|
||||
{
|
||||
var seat = P.GetNearestSeat(V);
|
||||
P.Task.EnterVehicle(V, seat);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public static void CleanUp()
|
||||
{
|
||||
MainChat.Clear();
|
||||
EntityPool.Cleanup();
|
||||
PlayerList.Cleanup();
|
||||
Main.LocalPlayerID=default;
|
||||
|
||||
}
|
||||
|
||||
internal static readonly Dictionary<ulong, byte> CheckNativeHash = new Dictionary<ulong, byte>()
|
||||
{
|
||||
{ 0xD49F9B0955C367DE, 1 }, // Entities
|
||||
{ 0xEF29A16337FACADB, 1 }, //
|
||||
{ 0xB4AC7D0CF06BFE8F, 1 }, //
|
||||
{ 0x9B62392B474F44A0, 1 }, //
|
||||
{ 0x7DD959874C1FD534, 1 }, //
|
||||
{ 0xAF35D0D2583051B0, 2 }, // Vehicles
|
||||
{ 0x63C6CCA8E68AE8C8, 2 }, //
|
||||
{ 0x509D5878EB39E842, 3 }, // Props
|
||||
{ 0x9A294B2138ABB884, 3 }, //
|
||||
{ 0x46818D79B1F7499A, 4 }, // Blips
|
||||
{ 0x5CDE92C702A8FCE7, 4 }, //
|
||||
{ 0xBE339365C863BD36, 4 }, //
|
||||
{ 0x5A039BB0BCA604B6, 4 }, //
|
||||
{ 0x0134F0835AB6BFCB, 5 } // Checkpoints
|
||||
};
|
||||
internal static Dictionary<int, byte> ServerItems = new Dictionary<int, byte>();
|
||||
internal static void CleanUpWorld()
|
||||
{
|
||||
if (ServerItems.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lock (ServerItems)
|
||||
{
|
||||
foreach (KeyValuePair<int, byte> item in ServerItems)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (item.Value)
|
||||
{
|
||||
case 1:
|
||||
World.GetAllEntities().FirstOrDefault(x => x.Handle == item.Key)?.Delete();
|
||||
break;
|
||||
case 2:
|
||||
World.GetAllVehicles().FirstOrDefault(x => x.Handle == item.Key)?.Delete();
|
||||
break;
|
||||
case 3:
|
||||
World.GetAllProps().FirstOrDefault(x => x.Handle == item.Key)?.Delete();
|
||||
break;
|
||||
case 4:
|
||||
Blip blip = new Blip(item.Key);
|
||||
if (blip.Exists())
|
||||
{
|
||||
blip.Delete();
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
Checkpoint checkpoint = new Checkpoint(item.Key);
|
||||
if (checkpoint.Exists())
|
||||
{
|
||||
checkpoint.Delete();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
GTA.UI.Notification.Show("~r~~h~CleanUpWorld() Error");
|
||||
Main.Logger.Error($"CleanUpWorld(): ~r~Item {item.Value} cannot be deleted!");
|
||||
}
|
||||
}
|
||||
ServerItems.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private static void DoQueuedActions()
|
||||
{
|
||||
lock (QueuedActions)
|
||||
{
|
||||
foreach (var action in QueuedActions.ToArray())
|
||||
{
|
||||
try
|
||||
{
|
||||
if (action())
|
||||
{
|
||||
QueuedActions.Remove(action);
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Logger.Error(ex);
|
||||
QueuedActions.Remove(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queue an action to be executed on next tick, allowing you to call scripting API from another thread.
|
||||
/// </summary>
|
||||
/// <param name="a"> An action to be executed with a return value indicating whether the action can be removed after execution.</param>
|
||||
internal static void QueueAction(Func<bool> a)
|
||||
{
|
||||
lock (QueuedActions)
|
||||
{
|
||||
QueuedActions.Add(a);
|
||||
}
|
||||
}
|
||||
internal static void QueueAction(Action a)
|
||||
{
|
||||
lock (QueuedActions)
|
||||
{
|
||||
QueuedActions.Add(() => { a(); return true; }) ;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Clears all queued actions
|
||||
/// </summary>
|
||||
internal static void ClearQueuedActions()
|
||||
{
|
||||
lock (QueuedActions) { QueuedActions.Clear(); }
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -1,168 +0,0 @@
|
||||
using GTA;
|
||||
|
||||
using System.Drawing;
|
||||
|
||||
using LemonUI;
|
||||
using LemonUI.Menus;
|
||||
using LemonUI.Scaleform;
|
||||
|
||||
namespace RageCoop.Client.Menus
|
||||
{
|
||||
/// <summary>
|
||||
/// Don't use it!
|
||||
/// </summary>
|
||||
internal static class CoopMenu
|
||||
{
|
||||
public static ObjectPool MenuPool = new ObjectPool();
|
||||
public static NativeMenu Menu = new NativeMenu("RAGECOOP", "MAIN")
|
||||
{
|
||||
UseMouse = false,
|
||||
Alignment = Main.Settings.FlipMenu ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left
|
||||
};
|
||||
public static PopUp PopUp=new PopUp()
|
||||
{
|
||||
Title="",
|
||||
Prompt="",
|
||||
Subtitle = "",
|
||||
Error="",
|
||||
ShowBackground = true,
|
||||
Visible=false,
|
||||
};
|
||||
public static NativeMenu LastMenu { get; set; } = Menu;
|
||||
#region ITEMS
|
||||
private static readonly NativeItem _usernameItem = new NativeItem("Username") { AltTitle = Main.Settings.Username };
|
||||
private static readonly NativeItem _passwordItem = new NativeItem("Password") { AltTitle = new string('*',Main.Settings.Password.Length) };
|
||||
|
||||
public static readonly NativeItem ServerIpItem = new NativeItem("Server IP") { AltTitle = Main.Settings.LastServerAddress };
|
||||
internal static readonly NativeItem _serverConnectItem = new NativeItem("Connect");
|
||||
private static readonly NativeItem _aboutItem = new NativeItem("About", "~y~SOURCE~s~~n~" +
|
||||
"https://github.com/RAGECOOP~n~" +
|
||||
"~y~VERSION~s~~n~" +
|
||||
Main.CurrentVersion.Replace("_", ".")) { LeftBadge = new LemonUI.Elements.ScaledTexture("commonmenu", "shop_new_star") };
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Don't use it!
|
||||
/// </summary>
|
||||
static CoopMenu()
|
||||
{
|
||||
|
||||
Menu.Banner.Color = Color.FromArgb(225, 0, 0, 0);
|
||||
Menu.Title.Color = Color.FromArgb(255, 165, 0);
|
||||
|
||||
_usernameItem.Activated += UsernameActivated;
|
||||
_passwordItem.Activated+=_passwordActivated;
|
||||
ServerIpItem.Activated += ServerIpActivated;
|
||||
_serverConnectItem.Activated += (sender, item) => { Networking.ToggleConnection(Main.Settings.LastServerAddress); };
|
||||
|
||||
|
||||
Menu.AddSubMenu(ServersMenu.Menu);
|
||||
|
||||
Menu.Add(_usernameItem);
|
||||
Menu.Add(_passwordItem);
|
||||
Menu.Add(ServerIpItem);
|
||||
Menu.Add(_serverConnectItem);
|
||||
|
||||
Menu.AddSubMenu(SettingsMenu.Menu);
|
||||
Menu.AddSubMenu(DevToolMenu.Menu);
|
||||
Menu.AddSubMenu(DebugMenu.Menu);
|
||||
Menu.AddSubMenu(UpdateMenu.Menu);
|
||||
|
||||
|
||||
MenuPool.Add(Menu);
|
||||
MenuPool.Add(SettingsMenu.Menu);
|
||||
MenuPool.Add(DevToolMenu.Menu);
|
||||
MenuPool.Add(DebugMenu.Menu);
|
||||
MenuPool.Add(DebugMenu.DiagnosticMenu);
|
||||
MenuPool.Add(ServersMenu.Menu);
|
||||
MenuPool.Add(UpdateMenu.Menu);
|
||||
MenuPool.Add(PopUp);
|
||||
|
||||
Menu.Add(_aboutItem);
|
||||
}
|
||||
|
||||
|
||||
public static bool ShowPopUp(string prompt, string title,string subtitle,string error,bool showbackground)
|
||||
{
|
||||
PopUp.Prompt=prompt;
|
||||
PopUp.Title=title;
|
||||
PopUp.Subtitle=subtitle;
|
||||
PopUp.Error=error;
|
||||
PopUp.ShowBackground=showbackground;
|
||||
PopUp.Visible=true;
|
||||
while (true)
|
||||
{
|
||||
Game.DisableAllControlsThisFrame();
|
||||
MenuPool.Process();
|
||||
if (Game.IsControlJustPressed(Control.FrontendAccept))
|
||||
{
|
||||
PopUp.Visible=false;
|
||||
return true;
|
||||
}
|
||||
else if (Game.IsControlJustPressed(Control.FrontendCancel))
|
||||
{
|
||||
PopUp.Visible = false;
|
||||
return false;
|
||||
}
|
||||
Script.Yield();
|
||||
}
|
||||
}
|
||||
public static void UsernameActivated(object a, System.EventArgs b)
|
||||
{
|
||||
string newUsername = Game.GetUserInput(WindowTitle.EnterMessage20, _usernameItem.AltTitle, 20);
|
||||
if (!string.IsNullOrWhiteSpace(newUsername))
|
||||
{
|
||||
Main.Settings.Username = newUsername;
|
||||
Util.SaveSettings();
|
||||
|
||||
_usernameItem.AltTitle = newUsername;
|
||||
}
|
||||
}
|
||||
|
||||
private static void _passwordActivated(object sender, System.EventArgs e)
|
||||
{
|
||||
string newPass = Game.GetUserInput(WindowTitle.EnterMessage20, "", 20);
|
||||
if (!string.IsNullOrWhiteSpace(newPass))
|
||||
{
|
||||
Main.Settings.Password = newPass;
|
||||
Util.SaveSettings();
|
||||
_passwordItem.AltTitle = new string('*', newPass.Length);
|
||||
}
|
||||
}
|
||||
public static void ServerIpActivated(object a, System.EventArgs b)
|
||||
{
|
||||
string newServerIp = Game.GetUserInput(WindowTitle.EnterMessage60, ServerIpItem.AltTitle, 60);
|
||||
if (!string.IsNullOrWhiteSpace(newServerIp) && newServerIp.Contains(":"))
|
||||
{
|
||||
Main.Settings.LastServerAddress = newServerIp;
|
||||
Util.SaveSettings();
|
||||
|
||||
ServerIpItem.AltTitle = newServerIp;
|
||||
}
|
||||
}
|
||||
|
||||
public static void InitiateConnectionMenuSetting()
|
||||
{
|
||||
_usernameItem.Enabled = false;
|
||||
ServerIpItem.Enabled = false;
|
||||
_serverConnectItem.Enabled = false;
|
||||
}
|
||||
|
||||
public static void ConnectedMenuSetting()
|
||||
{
|
||||
_serverConnectItem.Enabled = true;
|
||||
_serverConnectItem.Title = "Disconnect";
|
||||
Menu.Visible = false;
|
||||
}
|
||||
|
||||
public static void DisconnectedMenuSetting()
|
||||
{
|
||||
_usernameItem.Enabled = true;
|
||||
ServerIpItem.Enabled = true;
|
||||
_serverConnectItem.Enabled = true;
|
||||
_serverConnectItem.Title = "Connect";
|
||||
}
|
||||
}
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using LemonUI;
|
||||
using LemonUI.Menus;
|
||||
using GTA;
|
||||
using System.Drawing;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal static class DebugMenu
|
||||
{
|
||||
public static NativeMenu Menu = new NativeMenu("RAGECOOP", "Debug", "Debug settings") {
|
||||
UseMouse = false,
|
||||
Alignment = Main.Settings.FlipMenu ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left
|
||||
};
|
||||
public static NativeMenu DiagnosticMenu = new NativeMenu("RAGECOOP", "Diagnostic", "Performence and Diagnostic")
|
||||
{
|
||||
UseMouse = false,
|
||||
Alignment = Main.Settings.FlipMenu ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left
|
||||
};
|
||||
private static NativeItem d1=new NativeItem("PositionPrediction");
|
||||
static DebugMenu()
|
||||
{
|
||||
Menu.Banner.Color = Color.FromArgb(225, 0, 0, 0);
|
||||
Menu.Title.Color = Color.FromArgb(255, 165, 0);
|
||||
|
||||
d1.Activated+=(sender,e) =>
|
||||
{
|
||||
try{ SyncParameters.PositioinPredictionDefault =float.Parse(Game.GetUserInput(WindowTitle.EnterMessage20, SyncParameters.PositioinPredictionDefault.ToString(), 20));}
|
||||
catch { }
|
||||
Update();
|
||||
};
|
||||
|
||||
|
||||
Menu.Add(d1);
|
||||
Menu.AddSubMenu(DiagnosticMenu);
|
||||
Menu.Opening+=(sender, e) =>Update();
|
||||
DiagnosticMenu.Opening+=(sender, e) =>
|
||||
{
|
||||
DiagnosticMenu.Clear();
|
||||
DiagnosticMenu.Add(new NativeItem("EntityPool", EntityPool.DumpDebug()));
|
||||
foreach (var pair in Debug.TimeStamps)
|
||||
{
|
||||
DiagnosticMenu.Add(new NativeItem(pair.Key.ToString(), pair.Value.ToString(), pair.Value.ToString()));
|
||||
}
|
||||
};
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static void Update()
|
||||
{
|
||||
d1.AltTitle = SyncParameters.PositioinPredictionDefault.ToString();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using LemonUI.Menus;
|
||||
using GTA;
|
||||
using System.Drawing;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal static class DevToolMenu
|
||||
{
|
||||
public static NativeMenu Menu = new NativeMenu("RAGECOOP", "DevTool", "Help with the development")
|
||||
{
|
||||
UseMouse = false,
|
||||
Alignment = Main.Settings.FlipMenu ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left
|
||||
};
|
||||
private static NativeCheckboxItem enableItem = new NativeCheckboxItem("Enable");
|
||||
|
||||
private static NativeCheckboxItem enableSecondaryItem = new NativeCheckboxItem("Secondary","Enable if this vehicle have two muzzles");
|
||||
public static NativeItem boneIndexItem = new NativeItem("Current bone index");
|
||||
public static NativeItem secondaryBoneIndexItem = new NativeItem("Secondary bone index");
|
||||
public static NativeItem clipboardItem = new NativeItem("Copy to clipboard");
|
||||
public static NativeListItem<MuzzleDir> dirItem = new NativeListItem<MuzzleDir>("Direction");
|
||||
static DevToolMenu()
|
||||
{
|
||||
Menu.Banner.Color = Color.FromArgb(225, 0, 0, 0);
|
||||
Menu.Title.Color = Color.FromArgb(255, 165, 0);
|
||||
|
||||
enableItem.Activated+=enableItem_Activated;
|
||||
enableItem.Checked=false;
|
||||
enableSecondaryItem.CheckboxChanged+=EnableSecondaryItem_Changed;
|
||||
|
||||
secondaryBoneIndexItem.Enabled=false;
|
||||
clipboardItem.Activated+=ClipboardItem_Activated;
|
||||
dirItem.ItemChanged+=DirItem_ItemChanged;
|
||||
foreach (var d in Enum.GetValues(typeof(MuzzleDir)))
|
||||
{
|
||||
dirItem.Items.Add((MuzzleDir)d);
|
||||
}
|
||||
dirItem.SelectedIndex=0;
|
||||
|
||||
Menu.Add(enableItem);
|
||||
Menu.Add(boneIndexItem);
|
||||
Menu.Add(enableSecondaryItem);
|
||||
Menu.Add(secondaryBoneIndexItem);
|
||||
Menu.Add(dirItem);
|
||||
Menu.Add(clipboardItem);
|
||||
}
|
||||
|
||||
private static void EnableSecondaryItem_Changed(object sender, EventArgs e)
|
||||
{
|
||||
if (enableSecondaryItem.Checked)
|
||||
{
|
||||
DevTool.UseSecondary=true;
|
||||
secondaryBoneIndexItem.Enabled=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
DevTool.UseSecondary=false;
|
||||
secondaryBoneIndexItem.Enabled=false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void DirItem_ItemChanged(object sender, ItemChangedEventArgs<MuzzleDir> e)
|
||||
{
|
||||
DevTool.Direction=dirItem.SelectedItem;
|
||||
}
|
||||
|
||||
private static void ClipboardItem_Activated(object sender, EventArgs e)
|
||||
{
|
||||
DevTool.CopyToClipboard(dirItem.SelectedItem);
|
||||
}
|
||||
|
||||
private static void enableItem_Activated(object sender, EventArgs e)
|
||||
{
|
||||
if (enableItem.Checked)
|
||||
{
|
||||
DevTool.ToMark=Game.Player.Character.CurrentVehicle;
|
||||
}
|
||||
else
|
||||
{
|
||||
DevTool.ToMark=null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,148 +0,0 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Drawing;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
using LemonUI.Menus;
|
||||
using System.Threading;
|
||||
|
||||
namespace RageCoop.Client.Menus
|
||||
{
|
||||
internal class ServerListClass
|
||||
{
|
||||
[JsonProperty("address")]
|
||||
public string Address { get; set; }
|
||||
|
||||
[JsonProperty("port")]
|
||||
public string Port { get; set; }
|
||||
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("version")]
|
||||
public string Version { get; set; }
|
||||
|
||||
[JsonProperty("players")]
|
||||
public int Players { get; set; }
|
||||
|
||||
[JsonProperty("maxPlayers")]
|
||||
public int MaxPlayers { get; set; }
|
||||
|
||||
[JsonProperty("country")]
|
||||
public string Country { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Don't use it!
|
||||
/// </summary>
|
||||
internal static class ServersMenu
|
||||
{
|
||||
private static Thread GetServersThread;
|
||||
internal static NativeMenu Menu = new NativeMenu("RAGECOOP", "Servers", "Go to the server list")
|
||||
{
|
||||
UseMouse = false,
|
||||
Alignment = Main.Settings.FlipMenu ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left
|
||||
};
|
||||
internal static NativeItem ResultItem = null;
|
||||
|
||||
/// <summary>
|
||||
/// Don't use it!
|
||||
/// </summary>
|
||||
static ServersMenu()
|
||||
{
|
||||
Menu.Banner.Color = Color.FromArgb(225, 0, 0, 0);
|
||||
Menu.Title.Color = Color.FromArgb(255, 165, 0);
|
||||
|
||||
Menu.Opening += (object sender, System.ComponentModel.CancelEventArgs e) =>
|
||||
{
|
||||
CleanUpList();
|
||||
Menu.Add(ResultItem = new NativeItem("Loading..."));
|
||||
|
||||
// Prevent freezing
|
||||
GetServersThread=new Thread(()=> GetAllServers());
|
||||
GetServersThread.Start();
|
||||
};
|
||||
Menu.Closing += (object sender, System.ComponentModel.CancelEventArgs e) =>
|
||||
{
|
||||
CleanUpList();
|
||||
};
|
||||
}
|
||||
|
||||
private static void CleanUpList()
|
||||
{
|
||||
Menu.Clear();
|
||||
ResultItem = null;
|
||||
}
|
||||
|
||||
private static void GetAllServers()
|
||||
{
|
||||
List<ServerListClass> serverList = null;
|
||||
var realUrl = Main.Settings.MasterServer;
|
||||
serverList = JsonConvert.DeserializeObject<List<ServerListClass>>(DownloadString(realUrl));
|
||||
|
||||
// Need to be processed in main thread
|
||||
Main.QueueAction(() =>
|
||||
{
|
||||
if (serverList == null)
|
||||
{
|
||||
ResultItem.Title = "Something went wrong!";
|
||||
return;
|
||||
}
|
||||
if (serverList.Count == 0)
|
||||
{
|
||||
ResultItem.Title = "No server was found!";
|
||||
return;
|
||||
}
|
||||
CleanUpList();
|
||||
foreach (ServerListClass server in serverList)
|
||||
{
|
||||
string address = $"{server.Address}:{server.Port}";
|
||||
NativeItem tmpItem = new NativeItem($"[{server.Country}] {server.Name}", $"~b~{address}~s~~n~~g~Version {server.Version}.x~s~") { AltTitle = $"[{server.Players}/{server.MaxPlayers}]" };
|
||||
tmpItem.Activated += (object sender, EventArgs e) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Menu.Visible = false;
|
||||
|
||||
Networking.ToggleConnection(address);
|
||||
#if !NON_INTERACTIVE
|
||||
CoopMenu.ServerIpItem.AltTitle = address;
|
||||
|
||||
CoopMenu.Menu.Visible = true;
|
||||
#endif
|
||||
Main.Settings.LastServerAddress = address;
|
||||
Util.SaveSettings();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
GTA.UI.Notification.Show($"~r~{ex.Message}");
|
||||
}
|
||||
};
|
||||
Menu.Add(tmpItem);
|
||||
}
|
||||
});
|
||||
}
|
||||
private static string DownloadString(string url)
|
||||
{
|
||||
try
|
||||
{
|
||||
// TLS only
|
||||
ServicePointManager.Expect100Continue = true;
|
||||
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls13 | SecurityProtocolType.Tls12;
|
||||
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
|
||||
|
||||
WebClient client = new WebClient();
|
||||
return client.DownloadString(url);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Main.QueueAction(() =>
|
||||
{
|
||||
ResultItem.Title = "Download failed!";
|
||||
ResultItem.Description = ex.Message;
|
||||
});
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,123 +0,0 @@
|
||||
using System.Drawing;
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
using GTA;
|
||||
using LemonUI.Menus;
|
||||
|
||||
namespace RageCoop.Client.Menus
|
||||
{
|
||||
/// <summary>
|
||||
/// Don't use it!
|
||||
/// </summary>
|
||||
internal static class SettingsMenu
|
||||
{
|
||||
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 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 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());
|
||||
private static NativeItem _vehicleSoftLimit = new NativeItem("Vehicle limit (soft)", "The game won't spawn more NPC traffic if the limit is exceeded. \n-1 for unlimited (not recommended).",Main.Settings.WorldVehicleSoftLimit.ToString());
|
||||
|
||||
/// <summary>
|
||||
/// Don't use it!
|
||||
/// </summary>
|
||||
static SettingsMenu()
|
||||
{
|
||||
Menu.Banner.Color = Color.FromArgb(225, 0, 0, 0);
|
||||
Menu.Title.Color = Color.FromArgb(255, 165, 0);
|
||||
|
||||
_disableTrafficItem.CheckboxChanged += DisableTrafficCheckboxChanged;
|
||||
_disablePauseAlt.CheckboxChanged+=_disablePauseAlt_CheckboxChanged;
|
||||
_flipMenuItem.CheckboxChanged += FlipMenuCheckboxChanged;
|
||||
_showNetworkInfoItem.CheckboxChanged += ShowNetworkInfoCheckboxChanged;
|
||||
_menuKey.Activated+=ChaneMenuKey;
|
||||
_passengerKey.Activated+=ChangePassengerKey;
|
||||
_vehicleSoftLimit.Activated+=vehicleSoftLimit_Activated;
|
||||
|
||||
Menu.Add(_disableTrafficItem);
|
||||
Menu.Add(_disablePauseAlt);
|
||||
Menu.Add(_flipMenuItem);
|
||||
Menu.Add(_showNetworkInfoItem);
|
||||
Menu.Add(_menuKey);
|
||||
Menu.Add(_passengerKey);
|
||||
Menu.Add(_vehicleSoftLimit);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static void _disablePauseAlt_CheckboxChanged(object sender, EventArgs e)
|
||||
{
|
||||
Main.Settings.DisableAlternatePause=_disablePauseAlt.Checked;
|
||||
Util.SaveSettings();
|
||||
}
|
||||
private static void vehicleSoftLimit_Activated(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
Main.Settings.WorldVehicleSoftLimit =int.Parse(
|
||||
Game.GetUserInput(WindowTitle.EnterMessage20,
|
||||
Main.Settings.WorldVehicleSoftLimit.ToString(), 20));
|
||||
_menuKey.AltTitle=Main.Settings.WorldVehicleSoftLimit.ToString();
|
||||
Util.SaveSettings();
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
private static void ChaneMenuKey(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
Main.Settings.MenuKey =(Keys)Enum.Parse(
|
||||
typeof(Keys),
|
||||
Game.GetUserInput(WindowTitle.EnterMessage20,
|
||||
Main.Settings.MenuKey.ToString(), 20));
|
||||
_menuKey.AltTitle=Main.Settings.MenuKey.ToString();
|
||||
Util.SaveSettings();
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
private static void ChangePassengerKey(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
Main.Settings.PassengerKey =(Keys)Enum.Parse(
|
||||
typeof(Keys),
|
||||
Game.GetUserInput(WindowTitle.EnterMessage20,
|
||||
Main.Settings.PassengerKey.ToString(), 20));
|
||||
_passengerKey.AltTitle=Main.Settings.PassengerKey.ToString();
|
||||
Util.SaveSettings();
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
public static void DisableTrafficCheckboxChanged(object a, System.EventArgs b)
|
||||
{
|
||||
Main.Settings.DisableTraffic = _disableTrafficItem.Checked;
|
||||
Util.SaveSettings() ;
|
||||
}
|
||||
|
||||
public static void FlipMenuCheckboxChanged(object a, System.EventArgs b)
|
||||
{
|
||||
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 static void ShowNetworkInfoCheckboxChanged(object a, System.EventArgs b)
|
||||
{
|
||||
Networking.ShowNetworkInfo = _showNetworkInfoItem.Checked;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -1,101 +0,0 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using LemonUI.Menus;
|
||||
using System.Web;
|
||||
using System.Net;
|
||||
using System.IO;
|
||||
using ICSharpCode.SharpZipLib.Zip;
|
||||
|
||||
namespace RageCoop.Client.Menus
|
||||
{
|
||||
internal class UpdateMenu
|
||||
{
|
||||
public static bool IsUpdating { get; private set; } = false;
|
||||
private static NativeItem _updatingItem = new NativeItem("Updating...");
|
||||
private static NativeItem _downloadItem = new NativeItem("Download","Download and update to latest nightly");
|
||||
|
||||
private static string _downloadPath = Path.Combine(Main.Settings.DataDirectory, "RageCoop.Client.zip");
|
||||
public static NativeMenu Menu = new NativeMenu("Update", "Update", "Download and install latest nightly build from GitHub")
|
||||
{
|
||||
UseMouse = false,
|
||||
Alignment = Main.Settings.FlipMenu ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left
|
||||
};
|
||||
static UpdateMenu()
|
||||
{
|
||||
Menu.Banner.Color = Color.FromArgb(225, 0, 0, 0);
|
||||
Menu.Title.Color = Color.FromArgb(255, 165, 0);
|
||||
Menu.Opening+=Opening;
|
||||
_downloadItem.Activated+=StartUpdate;
|
||||
}
|
||||
|
||||
private static void StartUpdate(object sender, EventArgs e)
|
||||
{
|
||||
IsUpdating=true;
|
||||
Menu.Clear();
|
||||
Menu.Add(_updatingItem);
|
||||
Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (File.Exists(_downloadPath)) { File.Delete(_downloadPath); }
|
||||
WebClient client = new WebClient();
|
||||
|
||||
// TLS only
|
||||
ServicePointManager.Expect100Continue = true;
|
||||
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls13 | SecurityProtocolType.Tls12;
|
||||
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
|
||||
|
||||
client.DownloadProgressChanged += (s, e1) => { Main.QueueAction(() => { _updatingItem.AltTitle=$"{e1.ProgressPercentage}%"; }); };
|
||||
client.DownloadFileCompleted +=(s, e2) => { Install(); };
|
||||
client.DownloadFileAsync(new Uri("https://github.com/RAGECOOP/RAGECOOP-V/releases/download/nightly/RageCoop.Client.zip"), _downloadPath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Main.Logger.Error(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void Install()
|
||||
{
|
||||
try
|
||||
{
|
||||
Main.QueueAction(() =>
|
||||
{
|
||||
_updatingItem.AltTitle="Installing...";
|
||||
});
|
||||
new FastZip().ExtractZip(_downloadPath, "Scripts",FastZip.Overwrite.Always, null,null,null,true);
|
||||
Main.QueueAction(() =>
|
||||
{
|
||||
Util.Reload();
|
||||
IsUpdating=false;
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Main.Logger.Error(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static void Opening(object sender, System.ComponentModel.CancelEventArgs e)
|
||||
{
|
||||
Menu.Clear();
|
||||
if (Networking.IsOnServer)
|
||||
{
|
||||
Menu.Add(new NativeItem("Disconnect from the server first"));
|
||||
}
|
||||
else if (IsUpdating)
|
||||
{
|
||||
Menu.Add(_updatingItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
Menu.Add(_downloadItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,179 +0,0 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using RageCoop.Core;
|
||||
using GTA;
|
||||
using GTA.Native;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal class Chat
|
||||
{
|
||||
private readonly Scaleform MainScaleForm;
|
||||
|
||||
public string CurrentInput { get; set; }
|
||||
|
||||
private bool CurrentFocused { get; set; }
|
||||
public bool Focused
|
||||
{
|
||||
get { return CurrentFocused; }
|
||||
set
|
||||
{
|
||||
if (value && Hidden)
|
||||
{
|
||||
Hidden = false;
|
||||
}
|
||||
|
||||
MainScaleForm.CallFunction("SET_FOCUS", value ? 2 : 1, 2, "ALL");
|
||||
|
||||
CurrentFocused = value;
|
||||
}
|
||||
}
|
||||
|
||||
private ulong LastMessageTime { get; set; }
|
||||
|
||||
private bool CurrentHidden { get; set; }
|
||||
private bool Hidden
|
||||
{
|
||||
get { return CurrentHidden; }
|
||||
set
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
if (!CurrentHidden)
|
||||
{
|
||||
MainScaleForm.CallFunction("hide");
|
||||
}
|
||||
}
|
||||
else if (CurrentHidden)
|
||||
{
|
||||
MainScaleForm.CallFunction("showFeed");
|
||||
}
|
||||
|
||||
CurrentHidden = value;
|
||||
}
|
||||
}
|
||||
|
||||
public Chat()
|
||||
{
|
||||
MainScaleForm = new Scaleform("multiplayer_chat");
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
MainScaleForm.CallFunction("SET_FOCUS", 2, 2, "ALL");
|
||||
MainScaleForm.CallFunction("SET_FOCUS", 1, 2, "ALL");
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
MainScaleForm.CallFunction("RESET");
|
||||
}
|
||||
|
||||
public void Tick()
|
||||
{
|
||||
if ((Util.GetTickCount64() - LastMessageTime) > 15000 && !Focused && !Hidden)
|
||||
{
|
||||
Hidden = true;
|
||||
}
|
||||
|
||||
if (!Hidden)
|
||||
{
|
||||
MainScaleForm.Render2D();
|
||||
}
|
||||
|
||||
if (!CurrentFocused)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Function.Call(Hash.DISABLE_ALL_CONTROL_ACTIONS, 0);
|
||||
}
|
||||
|
||||
public void AddMessage(string sender, string msg)
|
||||
{
|
||||
MainScaleForm.CallFunction("ADD_MESSAGE", sender + ":", msg);
|
||||
LastMessageTime = Util.GetTickCount64();
|
||||
Hidden = false;
|
||||
}
|
||||
|
||||
public void OnKeyDown(Keys key)
|
||||
{
|
||||
if (key == Keys.Escape)
|
||||
{
|
||||
Focused = false;
|
||||
CurrentInput = "";
|
||||
return;
|
||||
}
|
||||
|
||||
if (key == Keys.PageUp)
|
||||
{
|
||||
MainScaleForm.CallFunction("PAGE_UP");
|
||||
}
|
||||
else if (key == Keys.PageDown)
|
||||
{
|
||||
MainScaleForm.CallFunction("PAGE_DOWN");
|
||||
}
|
||||
|
||||
string keyChar = GetCharFromKey(key, Game.IsKeyPressed(Keys.ShiftKey), false);
|
||||
|
||||
if (keyChar.Length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (keyChar[0])
|
||||
{
|
||||
case (char)8:
|
||||
if (CurrentInput?.Length > 0)
|
||||
{
|
||||
CurrentInput = CurrentInput.Remove(CurrentInput.Length - 1);
|
||||
MainScaleForm.CallFunction("DELETE_TEXT");
|
||||
}
|
||||
return;
|
||||
case (char)13:
|
||||
MainScaleForm.CallFunction("ADD_TEXT", "ENTER");
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(CurrentInput))
|
||||
{
|
||||
Networking.SendChatMessage(CurrentInput);
|
||||
}
|
||||
|
||||
Focused = false;
|
||||
CurrentInput = "";
|
||||
return;
|
||||
default:
|
||||
CurrentInput += keyChar;
|
||||
MainScaleForm.CallFunction("ADD_TEXT", keyChar);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern int ToUnicodeEx(uint virtualKeyCode, uint scanCode, byte[] keyboardState,
|
||||
[Out, MarshalAs(UnmanagedType.LPWStr, SizeConst = 64)]
|
||||
StringBuilder receivingBuffer,
|
||||
int bufferSize, uint flags, IntPtr kblayout);
|
||||
|
||||
public static string GetCharFromKey(Keys key, bool shift, bool altGr)
|
||||
{
|
||||
StringBuilder buf = new StringBuilder(256);
|
||||
byte[] keyboardState = new byte[256];
|
||||
|
||||
if (shift)
|
||||
{
|
||||
keyboardState[(int)Keys.ShiftKey] = 0xff;
|
||||
}
|
||||
|
||||
if (altGr)
|
||||
{
|
||||
keyboardState[(int)Keys.ControlKey] = 0xff;
|
||||
keyboardState[(int)Keys.Menu] = 0xff;
|
||||
}
|
||||
|
||||
ToUnicodeEx((uint)key, 0, keyboardState, buf, 256, 0, InputLanguage.CurrentInputLanguage.Handle);
|
||||
return buf.ToString();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,200 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using RageCoop.Core;
|
||||
using System;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal static class DownloadManager
|
||||
{
|
||||
static DownloadManager()
|
||||
{
|
||||
Networking.RequestHandlers.Add(PacketType.FileTransferRequest, (data) =>
|
||||
{
|
||||
var fr = new Packets.FileTransferRequest();
|
||||
fr.Unpack(data);
|
||||
if (fr.Name.EndsWith(".zip"))
|
||||
{
|
||||
_zips.Add(fr.Name);
|
||||
}
|
||||
return new Packets.FileTransferResponse()
|
||||
{
|
||||
ID= fr.ID,
|
||||
Response=AddFile(fr.ID,fr.Name,fr.FileLength) ? FileResponse.NeedToDownload : FileResponse.AlreadyExists
|
||||
};
|
||||
});
|
||||
Networking.RequestHandlers.Add(PacketType.FileTransferComplete, (data) =>
|
||||
{
|
||||
Packets.FileTransferComplete packet = new Packets.FileTransferComplete();
|
||||
packet.Unpack(data);
|
||||
|
||||
Main.Logger.Debug($"Finalizing download:{packet.ID}");
|
||||
Complete(packet.ID);
|
||||
|
||||
// Inform the server that the download is completed
|
||||
return new Packets.FileTransferResponse()
|
||||
{
|
||||
ID= packet.ID,
|
||||
Response=FileResponse.Completed
|
||||
};
|
||||
});
|
||||
Networking.RequestHandlers.Add(PacketType.AllResourcesSent, (data) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Main.Resources.Load(ResourceFolder,_zips.ToArray());
|
||||
return new Packets.FileTransferResponse() { ID=0, Response=FileResponse.Loaded };
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
|
||||
Main.Logger.Error("Error occurred when loading server resource:");
|
||||
Main.Logger.Error(ex);
|
||||
return new Packets.FileTransferResponse() { ID=0, Response=FileResponse.LoadFailed };
|
||||
}
|
||||
});
|
||||
}
|
||||
public static string ResourceFolder {
|
||||
get {
|
||||
return Path.Combine(Main.Settings.DataDirectory,"Resources", Main.Settings.LastServerAddress.Replace(":", "."));
|
||||
}
|
||||
}
|
||||
private static readonly Dictionary<int, DownloadFile> InProgressDownloads = new Dictionary<int, DownloadFile>();
|
||||
private static readonly List<string> _zips = new List<string>();
|
||||
public static bool AddFile(int id, string name, long length)
|
||||
{
|
||||
Main.Logger.Debug($"Downloading file to {ResourceFolder}\\{name} , id:{id}");
|
||||
if (!Directory.Exists(ResourceFolder))
|
||||
{
|
||||
Directory.CreateDirectory(ResourceFolder);
|
||||
}
|
||||
|
||||
if (FileAlreadyExists(ResourceFolder, name, length))
|
||||
{
|
||||
Main.Logger.Debug($"File already exists! canceling download:{name}");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!name.EndsWith(".zip"))
|
||||
{
|
||||
Main.Logger.Error($"File download blocked! [{name}]");
|
||||
return false;
|
||||
}
|
||||
lock (InProgressDownloads)
|
||||
{
|
||||
InProgressDownloads.Add(id, new DownloadFile()
|
||||
{
|
||||
FileID = id,
|
||||
FileName = name,
|
||||
FileLength = length,
|
||||
Stream = new FileStream($"{ResourceFolder}\\{name}", FileMode.CreateNew, FileAccess.Write, FileShare.ReadWrite)
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the file already exists and if the size correct otherwise delete this file
|
||||
/// </summary>
|
||||
/// <param name="folder"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <returns></returns>
|
||||
private static bool FileAlreadyExists(string folder, string name, long length)
|
||||
{
|
||||
string filePath = $"{folder}\\{name}";
|
||||
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
if (new FileInfo(filePath).Length == length)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Delete the file because the length is wrong (maybe the file was updated)
|
||||
File.Delete(filePath);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void Write(int id, byte[] chunk)
|
||||
{
|
||||
lock (InProgressDownloads)
|
||||
{
|
||||
DownloadFile file;
|
||||
if (InProgressDownloads.TryGetValue(id, out file))
|
||||
{
|
||||
|
||||
file.Stream.Write(chunk, 0, chunk.Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
Main.Logger.Trace($"Received unhandled file chunk:{id}");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void Complete(int id)
|
||||
{
|
||||
DownloadFile f;
|
||||
|
||||
if (InProgressDownloads.TryGetValue(id, out f))
|
||||
{
|
||||
InProgressDownloads.Remove(id);
|
||||
f.Dispose();
|
||||
if (f.FileName.EndsWith(".zip"))
|
||||
{
|
||||
_zips.Add(f.FileName);
|
||||
}
|
||||
Main.Logger.Info($"Download finished:{f.FileName}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Main.Logger.Error($"Download not found! {id}");
|
||||
}
|
||||
}
|
||||
|
||||
public static void Cleanup()
|
||||
{
|
||||
lock (InProgressDownloads)
|
||||
{
|
||||
foreach (var file in InProgressDownloads.Values)
|
||||
{
|
||||
file.Dispose();
|
||||
}
|
||||
InProgressDownloads.Clear();
|
||||
}
|
||||
if (Directory.Exists(ResourceFolder))
|
||||
{
|
||||
|
||||
foreach (var zip in Directory.GetDirectories(ResourceFolder, "*.zip"))
|
||||
{
|
||||
File.Delete(zip);
|
||||
}
|
||||
}
|
||||
_zips.Clear();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
internal class DownloadFile: IDisposable
|
||||
{
|
||||
public int FileID { get; set; } = 0;
|
||||
public string FileName { get; set; } = string.Empty;
|
||||
public long FileLength { get; set; } = 0;
|
||||
public long FileWritten { get; set; } = 0;
|
||||
public FileStream Stream { get; set; }
|
||||
public void Dispose()
|
||||
{
|
||||
if(Stream!= null)
|
||||
{
|
||||
Stream.Flush();
|
||||
Stream.Close();
|
||||
Stream.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,153 +0,0 @@
|
||||
using System;
|
||||
using Lidgren.Network;
|
||||
using RageCoop.Core;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using System.IO;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal static partial class Networking
|
||||
{
|
||||
public static NetClient Client;
|
||||
public static float Latency = 0;
|
||||
public static bool ShowNetworkInfo = false;
|
||||
public static Security Security;
|
||||
static Networking()
|
||||
{
|
||||
Security=new Security(Main.Logger);
|
||||
Task.Run(() =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (Client!=null)
|
||||
{
|
||||
ProcessMessage(Client.WaitMessage(200));
|
||||
Client.FlushSendQueue();
|
||||
}
|
||||
else
|
||||
{
|
||||
Thread.Sleep(20);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void ToggleConnection(string address,string username=null,string password=null)
|
||||
{
|
||||
if (IsOnServer)
|
||||
{
|
||||
Client.Disconnect("Bye!");
|
||||
}
|
||||
else
|
||||
{
|
||||
password = password ?? Main.Settings.Password;
|
||||
username=username ?? Main.Settings.Username;
|
||||
// 623c92c287cc392406e7aaaac1c0f3b0 = RAGECOOP
|
||||
NetPeerConfiguration config = new NetPeerConfiguration("623c92c287cc392406e7aaaac1c0f3b0")
|
||||
{
|
||||
AutoFlushSendQueue = true
|
||||
};
|
||||
|
||||
config.EnableMessageType(NetIncomingMessageType.ConnectionLatencyUpdated);
|
||||
config.EnableMessageType(NetIncomingMessageType.UnconnectedData);
|
||||
|
||||
|
||||
string[] ip = new string[2];
|
||||
|
||||
int idx = address.LastIndexOf(':');
|
||||
if (idx != -1)
|
||||
{
|
||||
ip[0] = address.Substring(0, idx);
|
||||
ip[1] = address.Substring(idx + 1);
|
||||
}
|
||||
|
||||
if (ip.Length != 2)
|
||||
{
|
||||
throw new Exception("Malformed URL");
|
||||
}
|
||||
|
||||
EntityPool.AddPlayer();
|
||||
Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
DownloadManager.Cleanup();
|
||||
Client = new NetClient(config);
|
||||
Client.Start();
|
||||
Main.QueueAction(() => { GTA.UI.Notification.Show($"~y~Trying to connect..."); });
|
||||
Menus.CoopMenu._serverConnectItem.Enabled=false;
|
||||
Security.Regen();
|
||||
if(!GetServerPublicKey(address))
|
||||
{
|
||||
Menus.CoopMenu._serverConnectItem.Enabled=true;
|
||||
throw new TimeoutException("Failed to retrive server's public key");
|
||||
}
|
||||
|
||||
// Send HandshakePacket
|
||||
NetOutgoingMessage outgoingMessage = Client.CreateMessage();
|
||||
var handshake = new Packets.Handshake()
|
||||
{
|
||||
PedID = Main.LocalPlayerID,
|
||||
Username =username,
|
||||
ModVersion = Main.CurrentVersion,
|
||||
PassHashEncrypted=Security.Encrypt(password.GetHash())
|
||||
};
|
||||
|
||||
Security.GetSymmetricKeysCrypted(out handshake.AesKeyCrypted, out handshake.AesIVCrypted);
|
||||
handshake.Pack(outgoingMessage);
|
||||
Client.Connect(ip[0], short.Parse(ip[1]), outgoingMessage);
|
||||
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Main.Logger.Error("Cannot connect to server: ", ex);
|
||||
Main.QueueAction(() => GTA.UI.Notification.Show("Cannot connect to server: "+ex.Message));
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
public static bool IsOnServer
|
||||
{
|
||||
get { return Client?.ConnectionStatus == NetConnectionStatus.Connected; }
|
||||
}
|
||||
|
||||
#region -- GET --
|
||||
#region -- PLAYER --
|
||||
private static void PlayerConnect(Packets.PlayerConnect packet)
|
||||
{
|
||||
var p = new PlayerData
|
||||
{
|
||||
PedID = packet.PedID,
|
||||
Username= packet.Username,
|
||||
};
|
||||
GTA.UI.Notification.Show($"{p.Username} connected.");
|
||||
PlayerList.SetPlayer(packet.PedID, packet.Username);
|
||||
|
||||
Main.Logger.Debug($"player connected:{p.Username}");
|
||||
}
|
||||
private static void PlayerDisconnect(Packets.PlayerDisconnect packet)
|
||||
{
|
||||
var name=PlayerList.GetPlayer(packet.PedID).Username;
|
||||
GTA.UI.Notification.Show($"{name} left.");
|
||||
PlayerList.RemovePlayer(packet.PedID);
|
||||
EntityPool.RemoveAllFromPlayer(packet.PedID);
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endregion // -- PLAYER --
|
||||
|
||||
private static bool GetServerPublicKey(string address,int timeout=10000)
|
||||
{
|
||||
var msg=Client.CreateMessage();
|
||||
new Packets.PublicKeyRequest().Pack(msg);
|
||||
var adds =address.Split(':');
|
||||
Client.SendUnconnectedMessage(msg,adds[0],int.Parse(adds[1]));
|
||||
return _publicKeyReceived.WaitOne(timeout);
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
@ -1,438 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Lidgren.Network;
|
||||
using RageCoop.Core;
|
||||
using GTA;
|
||||
using RageCoop.Client.Menus;
|
||||
using System.Threading;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal static partial class Networking
|
||||
{
|
||||
private static readonly Func<byte, BitReader, object> _resolveHandle = (t, reader) =>
|
||||
{
|
||||
switch (t)
|
||||
{
|
||||
case 50:
|
||||
return EntityPool.ServerProps[reader.ReadInt()].MainProp?.Handle;
|
||||
case 51:
|
||||
return EntityPool.GetPedByID(reader.ReadInt())?.MainPed?.Handle;
|
||||
case 52:
|
||||
return EntityPool.GetVehicleByID(reader.ReadInt())?.MainVehicle?.Handle;
|
||||
case 60:
|
||||
return EntityPool.ServerBlips[reader.ReadInt()].Handle;
|
||||
default:
|
||||
throw new ArgumentException("Cannot resolve server side argument: "+t);
|
||||
|
||||
}
|
||||
};
|
||||
private static readonly AutoResetEvent _publicKeyReceived=new AutoResetEvent(false);
|
||||
private static readonly Dictionary<int, Action<PacketType, byte[]>> PendingResponses = new Dictionary<int, Action<PacketType, byte[]>>();
|
||||
internal static readonly Dictionary<PacketType, Func< byte[], Packet>> RequestHandlers = new Dictionary<PacketType, Func< byte[], Packet>>();
|
||||
public static void ProcessMessage(NetIncomingMessage message)
|
||||
{
|
||||
if(message == null) { return; }
|
||||
|
||||
switch (message.MessageType)
|
||||
{
|
||||
case NetIncomingMessageType.StatusChanged:
|
||||
NetConnectionStatus status = (NetConnectionStatus)message.ReadByte();
|
||||
|
||||
string reason = message.ReadString();
|
||||
|
||||
switch (status)
|
||||
{
|
||||
case NetConnectionStatus.InitiatedConnect:
|
||||
#if !NON_INTERACTIVE
|
||||
CoopMenu.InitiateConnectionMenuSetting();
|
||||
#endif
|
||||
break;
|
||||
case NetConnectionStatus.Connected:
|
||||
Main.QueueAction(() => {
|
||||
CoopMenu.ConnectedMenuSetting();
|
||||
Main.MainChat.Init();
|
||||
PlayerList.Cleanup();
|
||||
GTA.UI.Notification.Show("~g~Connected!");
|
||||
});
|
||||
|
||||
Main.Logger.Info(">> Connected <<");
|
||||
break;
|
||||
case NetConnectionStatus.Disconnected:
|
||||
DownloadManager.Cleanup();
|
||||
|
||||
// Reset all values
|
||||
Latency = 0;
|
||||
|
||||
Main.QueueAction(() => Main.CleanUpWorld());
|
||||
|
||||
if (Main.MainChat.Focused)
|
||||
{
|
||||
Main.MainChat.Focused = false;
|
||||
}
|
||||
|
||||
Main.QueueAction(() => Main.CleanUp());
|
||||
|
||||
#if !NON_INTERACTIVE
|
||||
CoopMenu.DisconnectedMenuSetting();
|
||||
#endif
|
||||
Main.Logger.Info($">> Disconnected << reason: {reason}");
|
||||
Main.QueueAction(() =>
|
||||
GTA.UI.Notification.Show("~r~Disconnected: " + reason));
|
||||
Main.Resources.Unload();
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case NetIncomingMessageType.Data:
|
||||
{
|
||||
|
||||
if (message.LengthBytes==0) { break; }
|
||||
var packetType = PacketType.Unknown;
|
||||
try
|
||||
{
|
||||
|
||||
// Get packet type
|
||||
packetType = (PacketType)message.ReadByte();
|
||||
switch (packetType)
|
||||
{
|
||||
case PacketType.Response:
|
||||
{
|
||||
int id = message.ReadInt32();
|
||||
if (PendingResponses.TryGetValue(id, out var callback))
|
||||
{
|
||||
callback((PacketType)message.ReadByte(), message.ReadBytes(message.ReadInt32()));
|
||||
PendingResponses.Remove(id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PacketType.Request:
|
||||
{
|
||||
int id = message.ReadInt32();
|
||||
var realType = (PacketType)message.ReadByte();
|
||||
int len = message.ReadInt32();
|
||||
Main.Logger.Debug($"{id},{realType},{len}");
|
||||
if (RequestHandlers.TryGetValue(realType, out var handler))
|
||||
{
|
||||
var response = Client.CreateMessage();
|
||||
response.Write((byte)PacketType.Response);
|
||||
response.Write(id);
|
||||
handler(message.ReadBytes(len)).Pack(response);
|
||||
Client.SendMessage(response, NetDeliveryMethod.ReliableOrdered);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
byte[] data = message.ReadBytes(message.ReadInt32());
|
||||
|
||||
HandlePacket(packetType, data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Main.QueueAction(() => {
|
||||
GTA.UI.Notification.Show("~r~~h~Packet Error");
|
||||
return true;
|
||||
});
|
||||
Main.Logger.Error($"[{packetType}] {ex.Message}");
|
||||
Main.Logger.Error(ex);
|
||||
Client.Disconnect($"Packet Error [{packetType}]");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NetIncomingMessageType.ConnectionLatencyUpdated:
|
||||
Latency = message.ReadFloat();
|
||||
break;
|
||||
case NetIncomingMessageType.UnconnectedData:
|
||||
{
|
||||
var packetType = (PacketType)message.ReadByte();
|
||||
int len = message.ReadInt32();
|
||||
byte[] data = message.ReadBytes(len);
|
||||
if (packetType==PacketType.PublicKeyResponse)
|
||||
{
|
||||
var packet=new Packets.PublicKeyResponse();
|
||||
packet.Unpack(data);
|
||||
Security.SetServerPublicKey(packet.Modulus,packet.Exponent);
|
||||
_publicKeyReceived.Set();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case NetIncomingMessageType.DebugMessage:
|
||||
case NetIncomingMessageType.ErrorMessage:
|
||||
case NetIncomingMessageType.WarningMessage:
|
||||
case NetIncomingMessageType.VerboseDebugMessage:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Client.Recycle(message);
|
||||
}
|
||||
private static void HandlePacket(PacketType packetType, byte[] data)
|
||||
{
|
||||
|
||||
switch (packetType)
|
||||
{
|
||||
case PacketType.PlayerConnect:
|
||||
{
|
||||
|
||||
Packets.PlayerConnect packet = new Packets.PlayerConnect();
|
||||
packet.Unpack(data);
|
||||
|
||||
Main.QueueAction(() => PlayerConnect(packet));
|
||||
}
|
||||
break;
|
||||
case PacketType.PlayerDisconnect:
|
||||
{
|
||||
|
||||
Packets.PlayerDisconnect packet = new Packets.PlayerDisconnect();
|
||||
packet.Unpack(data);
|
||||
Main.QueueAction(() => PlayerDisconnect(packet));
|
||||
|
||||
}
|
||||
break;
|
||||
case PacketType.PlayerInfoUpdate:
|
||||
{
|
||||
var packet = new Packets.PlayerInfoUpdate();
|
||||
packet.Unpack(data);
|
||||
PlayerList.UpdatePlayer(packet);
|
||||
break;
|
||||
}
|
||||
#region ENTITY SYNC
|
||||
case PacketType.VehicleSync:
|
||||
{
|
||||
|
||||
Packets.VehicleSync packet = new Packets.VehicleSync();
|
||||
packet.Unpack(data);
|
||||
VehicleSync(packet);
|
||||
|
||||
}
|
||||
break;
|
||||
case PacketType.PedSync:
|
||||
{
|
||||
|
||||
Packets.PedSync packet = new Packets.PedSync();
|
||||
packet.Unpack(data);
|
||||
PedSync(packet);
|
||||
|
||||
}
|
||||
break;
|
||||
case PacketType.VehicleStateSync:
|
||||
{
|
||||
|
||||
Packets.VehicleStateSync packet = new Packets.VehicleStateSync();
|
||||
packet.Unpack(data);
|
||||
VehicleStateSync(packet);
|
||||
|
||||
}
|
||||
break;
|
||||
/*
|
||||
case PacketType.PedStateSync:
|
||||
{
|
||||
|
||||
|
||||
Packets.PedStateSync packet = new Packets.PedStateSync();
|
||||
packet.Unpack(data);
|
||||
PedStateSync(packet);
|
||||
|
||||
}
|
||||
break;
|
||||
*/
|
||||
case PacketType.ProjectileSync:
|
||||
{
|
||||
Packets.ProjectileSync packet = new Packets.ProjectileSync();
|
||||
packet.Unpack(data);
|
||||
ProjectileSync(packet);
|
||||
break;
|
||||
}
|
||||
#endregion
|
||||
case PacketType.ChatMessage:
|
||||
{
|
||||
|
||||
Packets.ChatMessage packet = new Packets.ChatMessage();
|
||||
packet.Unpack(data);
|
||||
|
||||
Main.QueueAction(() => { Main.MainChat.AddMessage(packet.Username, packet.Message); return true; });
|
||||
|
||||
|
||||
}
|
||||
break;
|
||||
case PacketType.CustomEvent:
|
||||
{
|
||||
Packets.CustomEvent packet = new Packets.CustomEvent(_resolveHandle);
|
||||
packet.Unpack(data);
|
||||
Scripting.API.Events.InvokeCustomEventReceived(packet);
|
||||
}
|
||||
break;
|
||||
case PacketType.CustomEventQueued:
|
||||
{
|
||||
Packets.CustomEvent packet = new Packets.CustomEvent(_resolveHandle);
|
||||
Main.QueueAction(() =>
|
||||
{
|
||||
packet.Unpack(data);
|
||||
Scripting.API.Events.InvokeCustomEventReceived(packet);
|
||||
});
|
||||
}
|
||||
break;
|
||||
case PacketType.FileTransferChunk:
|
||||
{
|
||||
Packets.FileTransferChunk packet = new Packets.FileTransferChunk();
|
||||
packet.Unpack(data);
|
||||
DownloadManager.Write(packet.ID, packet.FileChunk);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (packetType.IsSyncEvent())
|
||||
{
|
||||
// Dispatch to main thread
|
||||
Main.QueueAction(() => { SyncEvents.HandleEvent(packetType, data); return true; });
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void PedSync(Packets.PedSync packet)
|
||||
{
|
||||
SyncedPed c = EntityPool.GetPedByID(packet.ID);
|
||||
if (c==null)
|
||||
{
|
||||
// Main.Logger.Debug($"Creating character for incoming sync:{packet.ID}");
|
||||
EntityPool.ThreadSafe.Add(c=new SyncedPed(packet.ID));
|
||||
}
|
||||
PedDataFlags flags = packet.Flag;
|
||||
c.ID=packet.ID;
|
||||
c.OwnerID=packet.OwnerID;
|
||||
c.Health = packet.Health;
|
||||
c.Position = packet.Position;
|
||||
c.Rotation = packet.Rotation;
|
||||
c.Velocity = packet.Velocity;
|
||||
c.Speed = packet.Speed;
|
||||
c.CurrentWeaponHash = packet.CurrentWeaponHash;
|
||||
c.IsAiming = flags.HasPedFlag(PedDataFlags.IsAiming);
|
||||
c.IsReloading = flags.HasPedFlag(PedDataFlags.IsReloading);
|
||||
c.IsJumping = flags.HasPedFlag(PedDataFlags.IsJumping);
|
||||
c.IsRagdoll = flags.HasPedFlag(PedDataFlags.IsRagdoll);
|
||||
c.IsOnFire = flags.HasPedFlag(PedDataFlags.IsOnFire);
|
||||
c.IsInParachuteFreeFall = flags.HasPedFlag(PedDataFlags.IsInParachuteFreeFall);
|
||||
c.IsParachuteOpen = flags.HasPedFlag(PedDataFlags.IsParachuteOpen);
|
||||
c.IsOnLadder = flags.HasPedFlag(PedDataFlags.IsOnLadder);
|
||||
c.IsVaulting = flags.HasPedFlag(PedDataFlags.IsVaulting);
|
||||
c.IsInCover = flags.HasPedFlag(PedDataFlags.IsInCover);
|
||||
c.IsInStealthMode = flags.HasPedFlag(PedDataFlags.IsInStealthMode);
|
||||
c.Heading=packet.Heading;
|
||||
c.LastSynced = Main.Ticked;
|
||||
if (c.IsAiming)
|
||||
{
|
||||
c.AimCoords = packet.AimCoords;
|
||||
}
|
||||
if (packet.Flag.HasPedFlag(PedDataFlags.IsFullSync))
|
||||
{
|
||||
c.Clothes=packet.Clothes;
|
||||
c.WeaponComponents=packet.WeaponComponents;
|
||||
c.WeaponTint=packet.WeaponTint;
|
||||
c.Model=packet.ModelHash;
|
||||
c.BlipColor=packet.BlipColor;
|
||||
c.BlipSprite=packet.BlipSprite;
|
||||
c.BlipScale=packet.BlipScale;
|
||||
c.LastStateSynced = Main.Ticked;
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
private static void PedStateSync(Packets.PedStateSync packet)
|
||||
{
|
||||
SyncedPed c = EntityPool.GetPedByID(packet.ID);
|
||||
if (c==null) { return; }
|
||||
c.ID=packet.ID;
|
||||
c.OwnerID=packet.OwnerID;
|
||||
c.Clothes=packet.Clothes;
|
||||
c.WeaponComponents=packet.WeaponComponents;
|
||||
c.WeaponTint=packet.WeaponTint;
|
||||
c.Model=packet.ModelHash;
|
||||
c.BlipColor=packet.BlipColor;
|
||||
c.BlipSprite=packet.BlipSprite;
|
||||
c.BlipScale=packet.BlipScale;
|
||||
c.LastStateSynced = Main.Ticked;
|
||||
}
|
||||
*/
|
||||
private static void VehicleSync(Packets.VehicleSync packet)
|
||||
{
|
||||
SyncedVehicle v = EntityPool.GetVehicleByID(packet.ID);
|
||||
if (v==null)
|
||||
{
|
||||
EntityPool.ThreadSafe.Add(v=new SyncedVehicle(packet.ID));
|
||||
}
|
||||
if (v.IsLocal) { return; }
|
||||
v.ID= packet.ID;
|
||||
v.Position=packet.Position;
|
||||
v.Quaternion=packet.Quaternion;
|
||||
v.SteeringAngle=packet.SteeringAngle;
|
||||
v.ThrottlePower=packet.ThrottlePower;
|
||||
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)
|
||||
{
|
||||
SyncedVehicle v = EntityPool.GetVehicleByID(packet.ID);
|
||||
if (v==null||v.IsLocal) { return; }
|
||||
v.ID= packet.ID;
|
||||
v.OwnerID= packet.OwnerID;
|
||||
v.DamageModel=packet.DamageModel;
|
||||
v.EngineHealth=packet.EngineHealth;
|
||||
v.OwnerID=packet.OwnerID;
|
||||
v.Mods=packet.Mods;
|
||||
v.Model=packet.ModelHash;
|
||||
v.Colors=packet.Colors;
|
||||
v.LandingGear=packet.LandingGear;
|
||||
v.RoofState=(VehicleRoofState)packet.RoofState;
|
||||
v.EngineRunning = packet.Flag.HasVehFlag(VehicleDataFlags.IsEngineRunning);
|
||||
v.LightsOn = packet.Flag.HasVehFlag(VehicleDataFlags.AreLightsOn);
|
||||
v.BrakeLightsOn = packet.Flag.HasVehFlag(VehicleDataFlags.AreBrakeLightsOn);
|
||||
v.HighBeamsOn = packet.Flag.HasVehFlag(VehicleDataFlags.AreHighBeamsOn);
|
||||
v.SireneActive = packet.Flag.HasVehFlag(VehicleDataFlags.IsSirenActive);
|
||||
v.IsDead = packet.Flag.HasVehFlag(VehicleDataFlags.IsDead);
|
||||
v.HornActive = packet.Flag.HasVehFlag(VehicleDataFlags.IsHornActive);
|
||||
v.Transformed = packet.Flag.HasVehFlag(VehicleDataFlags.IsTransformed);
|
||||
v.Passengers=new Dictionary<VehicleSeat, SyncedPed>();
|
||||
v.LockStatus=packet.LockStatus;
|
||||
v.RadioStation=packet.RadioStation;
|
||||
v.LicensePlate=packet.LicensePlate;
|
||||
v.Livery=packet.Livery;
|
||||
v.Flags=packet.Flag;
|
||||
foreach (KeyValuePair<int, int> pair in packet.Passengers)
|
||||
{
|
||||
if (EntityPool.PedExists(pair.Value))
|
||||
{
|
||||
v.Passengers.Add((VehicleSeat)pair.Key, EntityPool.GetPedByID(pair.Value));
|
||||
}
|
||||
}
|
||||
v.LastStateSynced= Main.Ticked;
|
||||
|
||||
}
|
||||
private static void ProjectileSync(Packets.ProjectileSync packet)
|
||||
{
|
||||
var p = EntityPool.GetProjectileByID(packet.ID);
|
||||
if (p==null)
|
||||
{
|
||||
if (packet.Exploded) { return; }
|
||||
// Main.Logger.Debug($"Creating new projectile: {(WeaponHash)packet.WeaponHash}");
|
||||
EntityPool.ThreadSafe.Add(p=new SyncedProjectile(packet.ID));
|
||||
}
|
||||
p.Position=packet.Position;
|
||||
p.Rotation=packet.Rotation;
|
||||
p.Velocity=packet.Velocity;
|
||||
p.Hash=(WeaponHash)packet.WeaponHash;
|
||||
p.ShooterID=packet.ShooterID;
|
||||
p.Exploded=packet.Exploded;
|
||||
p.LastSynced=Main.Ticked;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,185 +0,0 @@
|
||||
using Lidgren.Network;
|
||||
using RageCoop.Core;
|
||||
using GTA;
|
||||
using GTA.Native;
|
||||
using GTA.Math;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal static partial class Networking
|
||||
{
|
||||
|
||||
|
||||
#region -- SEND --
|
||||
/// <summary>
|
||||
/// Pack the packet then send to server.
|
||||
/// </summary>
|
||||
/// <param name="p"></param>
|
||||
/// <param name="channel"></param>
|
||||
/// <param name="method"></param>
|
||||
public static void Send(Packet p, ConnectionChannel channel = ConnectionChannel.Default, NetDeliveryMethod method = NetDeliveryMethod.UnreliableSequenced)
|
||||
{
|
||||
NetOutgoingMessage outgoingMessage = Client.CreateMessage();
|
||||
p.Pack(outgoingMessage);
|
||||
Client.SendMessage(outgoingMessage, method, (int)channel);
|
||||
}
|
||||
|
||||
public static void SendPed(SyncedPed c,bool full)
|
||||
{
|
||||
Ped p = c.MainPed;
|
||||
var packet=new Packets.PedSync()
|
||||
{
|
||||
ID =c.ID,
|
||||
OwnerID=c.OwnerID,
|
||||
Health = p.Health,
|
||||
Position = p.Position,
|
||||
Rotation = p.Rotation,
|
||||
Velocity = p.Velocity,
|
||||
Speed = p.GetPedSpeed(),
|
||||
CurrentWeaponHash = (uint)p.Weapons.Current.Hash,
|
||||
Flag = p.GetPedFlags(),
|
||||
Heading=p.Heading,
|
||||
};
|
||||
if (packet.Flag.HasPedFlag(PedDataFlags.IsAiming))
|
||||
{
|
||||
packet.AimCoords = p.GetAimCoord();
|
||||
}
|
||||
if (full)
|
||||
{
|
||||
packet.Flag |= PedDataFlags.IsFullSync;
|
||||
packet.Clothes=p.GetPedClothes();
|
||||
packet.ModelHash=p.Model.Hash;
|
||||
packet.WeaponComponents=p.Weapons.Current.GetWeaponComponents();
|
||||
packet.WeaponTint=(byte)Function.Call<int>(Hash.GET_PED_WEAPON_TINT_INDEX, p, p.Weapons.Current.Hash);
|
||||
}
|
||||
Send(packet, ConnectionChannel.PedSync);
|
||||
}
|
||||
/*
|
||||
public static void SendPedState(SyncedPed c)
|
||||
{
|
||||
Ped p = c.MainPed;
|
||||
|
||||
var packet = new Packets.PedStateSync()
|
||||
{
|
||||
ID = c.ID,
|
||||
OwnerID=c.OwnerID,
|
||||
Clothes=p.GetPedClothes(),
|
||||
ModelHash=p.Model.Hash,
|
||||
WeaponComponents=p.Weapons.Current.GetWeaponComponents(),
|
||||
WeaponTint=(byte)Function.Call<int>(Hash.GET_PED_WEAPON_TINT_INDEX, p, p.Weapons.Current.Hash),
|
||||
};
|
||||
Blip b;
|
||||
if (c.IsPlayer)
|
||||
{
|
||||
packet.BlipColor=Scripting.API.Config.BlipColor;
|
||||
packet.BlipSprite=Scripting.API.Config.BlipSprite;
|
||||
packet.BlipScale=Scripting.API.Config.BlipScale;
|
||||
}
|
||||
else if ((b = p.AttachedBlip) !=null)
|
||||
{
|
||||
packet.BlipColor=b.Color;
|
||||
packet.BlipSprite=b.Sprite;
|
||||
|
||||
if (packet.BlipSprite==BlipSprite.PoliceOfficer || packet.BlipSprite==BlipSprite.PoliceOfficer2)
|
||||
{
|
||||
packet.BlipScale=0.5f;
|
||||
}
|
||||
}
|
||||
Send(packet, ConnectionChannel.PedSync);
|
||||
}
|
||||
*/
|
||||
public static void SendVehicle(SyncedVehicle v)
|
||||
{
|
||||
Vehicle veh = v.MainVehicle;
|
||||
var packet = new Packets.VehicleSync()
|
||||
{
|
||||
ID =v.ID,
|
||||
SteeringAngle = veh.SteeringAngle,
|
||||
Position = veh.PredictPosition(),
|
||||
Quaternion=veh.Quaternion,
|
||||
// Rotation = veh.Rotation,
|
||||
Velocity = veh.Velocity,
|
||||
RotationVelocity=veh.RotationVelocity,
|
||||
ThrottlePower = veh.ThrottlePower,
|
||||
BrakePower = veh.BrakePower,
|
||||
};
|
||||
if (v.MainVehicle.Model.Hash==1483171323) { packet.DeluxoWingRatio=v.MainVehicle.GetDeluxoWingRatio(); }
|
||||
Send(packet,ConnectionChannel.VehicleSync);
|
||||
}
|
||||
public static void SendVehicleState(SyncedVehicle v)
|
||||
{
|
||||
Vehicle veh = v.MainVehicle;
|
||||
byte primaryColor = 0;
|
||||
byte secondaryColor = 0;
|
||||
unsafe
|
||||
{
|
||||
Function.Call<byte>(Hash.GET_VEHICLE_COLOURS, veh, &primaryColor, &secondaryColor);
|
||||
}
|
||||
var packet = new Packets.VehicleStateSync()
|
||||
{
|
||||
ID =v.ID,
|
||||
OwnerID = v.OwnerID,
|
||||
Flag = veh.GetVehicleFlags(),
|
||||
Colors=new byte[] { primaryColor, secondaryColor },
|
||||
DamageModel=veh.GetVehicleDamageModel(),
|
||||
LandingGear = veh.IsAircraft ? (byte)veh.LandingGearState : (byte)0,
|
||||
RoofState=(byte)veh.RoofState,
|
||||
Mods = veh.Mods.GetVehicleMods(),
|
||||
ModelHash=veh.Model.Hash,
|
||||
EngineHealth=veh.EngineHealth,
|
||||
Passengers=veh.GetPassengers(),
|
||||
LockStatus=veh.LockStatus,
|
||||
LicensePlate=Function.Call<string>(Hash.GET_VEHICLE_NUMBER_PLATE_TEXT, veh),
|
||||
Livery=Function.Call<int>(Hash.GET_VEHICLE_LIVERY, veh)
|
||||
};
|
||||
if (v.MainVehicle==Game.Player.LastVehicle)
|
||||
{
|
||||
packet.RadioStation=Util.GetPlayerRadioIndex();
|
||||
}
|
||||
Send(packet, ConnectionChannel.VehicleSync);
|
||||
}
|
||||
public static void SendProjectile(SyncedProjectile sp)
|
||||
{
|
||||
var p = sp.MainProjectile;
|
||||
var packet = new Packets.ProjectileSync()
|
||||
{
|
||||
ID =sp.ID,
|
||||
ShooterID=sp.ShooterID,
|
||||
Position=p.Position,
|
||||
Rotation=p.Rotation,
|
||||
Velocity=p.Velocity,
|
||||
WeaponHash=(uint)p.WeaponHash,
|
||||
Exploded=p.IsDead
|
||||
};
|
||||
if (p.IsDead) { EntityPool.RemoveProjectile(sp.ID,"Dead"); }
|
||||
Send(packet, ConnectionChannel.ProjectileSync);
|
||||
}
|
||||
|
||||
|
||||
#region SYNC EVENTS
|
||||
public static void SendBulletShot(Vector3 start,Vector3 end,uint weapon,int ownerID)
|
||||
{
|
||||
Send(new Packets.BulletShot()
|
||||
{
|
||||
StartPosition = start,
|
||||
EndPosition = end,
|
||||
OwnerID = ownerID,
|
||||
WeaponHash=weapon,
|
||||
}, ConnectionChannel.SyncEvents);
|
||||
}
|
||||
#endregion
|
||||
public static void SendChatMessage(string message)
|
||||
{
|
||||
NetOutgoingMessage outgoingMessage = Client.CreateMessage();
|
||||
|
||||
new Packets.ChatMessage() { Username = Main.Settings.Username, Message = message }.Pack(outgoingMessage);
|
||||
|
||||
Client.SendMessage(outgoingMessage, NetDeliveryMethod.ReliableOrdered, (byte)ConnectionChannel.Chat);
|
||||
Client.FlushSendQueue();
|
||||
|
||||
#if DEBUG
|
||||
#endif
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal static class Statistics
|
||||
{
|
||||
public static int BytesDownPerSecond{ get; private set; }
|
||||
public static int BytesUpPerSecond { get; private set; }
|
||||
static Statistics()
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
var bu=Networking.Client.Statistics.SentBytes;
|
||||
var bd = Networking.Client.Statistics.ReceivedBytes;
|
||||
Thread.Sleep(1000);
|
||||
BytesUpPerSecond=Networking.Client.Statistics.SentBytes-bu;
|
||||
BytesDownPerSecond=Networking.Client.Statistics.ReceivedBytes-bd;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,134 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
using RageCoop.Core;
|
||||
using GTA.Native;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal static class PlayerList
|
||||
{
|
||||
private const float LEFT_POSITION = 0.122f;
|
||||
private const float RIGHT_POSITION = 0.9f;
|
||||
private static readonly Scaleform _mainScaleform = new Scaleform("mp_mm_card_freemode");
|
||||
private static ulong _lastUpdate = Util.GetTickCount64();
|
||||
public static ulong Pressed { get; set; }
|
||||
|
||||
public static bool LeftAlign = true;
|
||||
public static Dictionary<int,PlayerData> Players=new Dictionary<int, PlayerData> { };
|
||||
public static void Tick()
|
||||
{
|
||||
if (!Networking.IsOnServer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ((Util.GetTickCount64() - _lastUpdate) >= 1000)
|
||||
{
|
||||
Update( Main.Settings.Username);
|
||||
}
|
||||
|
||||
if ((Util.GetTickCount64() - Pressed) < 5000 && !Main.MainChat.Focused
|
||||
#if !NON_INTERACTIVE
|
||||
&& !Menus.CoopMenu.MenuPool.AreAnyVisible
|
||||
#endif
|
||||
)
|
||||
{
|
||||
Function.Call(Hash.DRAW_SCALEFORM_MOVIE, _mainScaleform.Handle,
|
||||
LeftAlign ? LEFT_POSITION : RIGHT_POSITION, 0.3f,
|
||||
0.28f, 0.6f,
|
||||
255, 255, 255, 255, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private static void Update( string localUsername)
|
||||
{
|
||||
_lastUpdate = Util.GetTickCount64();
|
||||
|
||||
_mainScaleform.CallFunction("SET_DATA_SLOT_EMPTY", 0);
|
||||
_mainScaleform.CallFunction("SET_DATA_SLOT", 0, $"{Networking.Latency * 1000:N0}ms", localUsername, 116, 0, 0, "", "", 2, "", "", ' ');
|
||||
|
||||
int i = 1;
|
||||
|
||||
foreach (var player in Players)
|
||||
{
|
||||
_mainScaleform.CallFunction("SET_DATA_SLOT", i++, $"{player.Value.Latency * 1000:N0}ms", player.Value.Username, 116, 0, i - 1, "", "", 2, "", "", ' ');
|
||||
}
|
||||
|
||||
_mainScaleform.CallFunction("SET_TITLE", "Player list", $"{Players.Count+1} players");
|
||||
_mainScaleform.CallFunction("DISPLAY_VIEW");
|
||||
}
|
||||
public static void SetPlayer(int id, string username,float latency=0)
|
||||
{
|
||||
|
||||
PlayerData p;
|
||||
if (Players.TryGetValue(id,out p))
|
||||
{
|
||||
p.Username=username;
|
||||
p.PedID=id;
|
||||
p.Latency=latency;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = new PlayerData { PedID=id, Username=username,Latency=latency };
|
||||
Players.Add(id,p);
|
||||
}
|
||||
}
|
||||
public static void UpdatePlayer(Packets.PlayerInfoUpdate packet)
|
||||
{
|
||||
var p = GetPlayer(packet.PedID);
|
||||
if(p?.Character != null)
|
||||
{
|
||||
p.Latency= packet.Latency;
|
||||
}
|
||||
}
|
||||
public static PlayerData GetPlayer(int id)
|
||||
{
|
||||
PlayerData p;
|
||||
Players.TryGetValue(id, out p);
|
||||
return p;
|
||||
}
|
||||
public static PlayerData GetPlayer(SyncedPed p)
|
||||
{
|
||||
var player = GetPlayer(p.ID);
|
||||
if (player!=null)
|
||||
{
|
||||
player.Character=p;
|
||||
}
|
||||
return player;
|
||||
}
|
||||
public static void RemovePlayer(int id)
|
||||
{
|
||||
if (Players.ContainsKey(id))
|
||||
{
|
||||
Players.Remove(id);
|
||||
}
|
||||
}
|
||||
public static void Cleanup()
|
||||
{
|
||||
Players=new Dictionary<int, PlayerData>{ };
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
internal class PlayerData
|
||||
{
|
||||
public string Username { get; internal set; }
|
||||
/// <summary>
|
||||
/// Universal character ID.
|
||||
/// </summary>
|
||||
public int PedID
|
||||
{
|
||||
get; internal set;
|
||||
}
|
||||
public SyncedPed Character { get; set; }
|
||||
/// <summary>
|
||||
/// Player Latency in second.
|
||||
/// </summary>
|
||||
public float Latency { get; set; }
|
||||
|
||||
public bool DisplayNameTag { get; set; } = true;
|
||||
}
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<UseWindowsForms>True</UseWindowsForms>
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
<ProduceReferenceAssembly>True</ProduceReferenceAssembly>
|
||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||
<DocumentationFile></DocumentationFile>
|
||||
<DebugType>portable</DebugType>
|
||||
<AssemblyVersion>0.5.0</AssemblyVersion>
|
||||
<FileVersion>0.5.0</FileVersion>
|
||||
<Version>0.5.0</Version>
|
||||
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
|
||||
<Authors>RAGECOOP</Authors>
|
||||
<Description>An API reference for developing client-side resource for RAGECOOP</Description>
|
||||
<PackageProjectUrl>https://ragecoop.online/</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/RAGECOOP/RAGECOOP-V</RepositoryUrl>
|
||||
<ApplicationIcon>icon.ico</ApplicationIcon>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
|
||||
<DefineConstants>SHVDN3</DefineConstants>
|
||||
<TargetFrameworks>net48</TargetFrameworks>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
|
||||
<OutDir>..\bin\Debug\Client</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
|
||||
<OutDir>..\bin\Release\Client</OutDir>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="icon.ico" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SharpZipLib" Version="1.3.3" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\RageCoop.Core\RageCoop.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="LemonUI.SHVDN3">
|
||||
<HintPath>..\libs\LemonUI.SHVDN3.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Lidgren.Network">
|
||||
<HintPath>..\libs\Lidgren.Network.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<HintPath>..\libs\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ScriptHookVDotNet">
|
||||
<HintPath>..\libs\ScriptHookVDotNet.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ScriptHookVDotNet3">
|
||||
<HintPath>..\libs\ScriptHookVDotNet3.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<_LastSelectedProfileId>M:\SandBox-Shared\repo\RageCoop\RageCoop-V\RageCoop.Client\Properties\PublishProfiles\FolderProfile.pubxml</_LastSelectedProfileId>
|
||||
</PropertyGroup>
|
||||
</Project>
|
@ -1,284 +0,0 @@
|
||||
#undef DEBUG
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using RageCoop.Core;
|
||||
using System.Windows.Forms;
|
||||
using GTA;
|
||||
|
||||
namespace RageCoop.Client.Scripting
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class CustomEventReceivedArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// The event hash
|
||||
/// </summary>
|
||||
public int Hash { get; set; }
|
||||
/// <summary>
|
||||
/// Supported types: byte, short, ushort, int, uint, long, ulong, float, bool, string, Vector3, Quaternion
|
||||
/// </summary>
|
||||
public object[] Args { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Provides vital functionality to interact with RAGECOOP
|
||||
/// </summary>
|
||||
public static class API
|
||||
{
|
||||
#region INTERNAL
|
||||
internal static Dictionary<int, List<Action<CustomEventReceivedArgs>>> CustomEventHandlers = new Dictionary<int, List<Action<CustomEventReceivedArgs>>>();
|
||||
#endregion
|
||||
/// <summary>
|
||||
/// Client configuration, this will conflict with server-side config.
|
||||
/// </summary>
|
||||
public static class Config
|
||||
{
|
||||
/// <summary>
|
||||
/// Get or set local player's username, set won't be effective if already connected to a server.
|
||||
/// </summary>
|
||||
public static string Username
|
||||
{
|
||||
get { return Main.Settings.Username; }
|
||||
set
|
||||
{
|
||||
if (Networking.IsOnServer || string.IsNullOrEmpty(value))
|
||||
{
|
||||
return;
|
||||
}
|
||||
Main.Settings.Username = value;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Enable automatic respawn for this player.
|
||||
/// </summary>
|
||||
public static bool EnableAutoRespawn { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Get or set player's blip color
|
||||
/// </summary>
|
||||
public static BlipColor BlipColor { get; set; } = BlipColor.White;
|
||||
|
||||
/// <summary>
|
||||
/// Get or set player's blip sprite
|
||||
/// </summary>
|
||||
public static BlipSprite BlipSprite { get; set; } = BlipSprite.Standard;
|
||||
|
||||
/// <summary>
|
||||
/// Get or set scale of player's blip
|
||||
/// </summary>
|
||||
public static float BlipScale { get; set; } = 1;
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// Base events for RageCoop
|
||||
/// </summary>
|
||||
public static class Events
|
||||
{
|
||||
#region DELEGATES
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public delegate void EmptyEvent();
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="hash"></param>
|
||||
/// <param name="args"></param>
|
||||
public delegate void CustomEvent(int hash, List<object> args);
|
||||
#endregion
|
||||
/// <summary>
|
||||
/// The local player is dead
|
||||
/// </summary>
|
||||
public static event EmptyEvent OnPlayerDied;
|
||||
|
||||
/// <summary>
|
||||
/// A local vehicle is spawned
|
||||
/// </summary>
|
||||
public static event EventHandler<SyncedVehicle> OnVehicleSpawned;
|
||||
|
||||
/// <summary>
|
||||
/// A local vehicle is deleted
|
||||
/// </summary>
|
||||
public static event EventHandler<SyncedVehicle> OnVehicleDeleted;
|
||||
|
||||
/// <summary>
|
||||
/// A local ped is spawned
|
||||
/// </summary>
|
||||
public static event EventHandler<SyncedPed> OnPedSpawned;
|
||||
|
||||
/// <summary>
|
||||
/// A local ped is deleted
|
||||
/// </summary>
|
||||
public static event EventHandler<SyncedPed> OnPedDeleted;
|
||||
|
||||
/// <summary>
|
||||
/// This is equivalent of <see cref="GTA.Script.Tick"/>.
|
||||
/// </summary>
|
||||
public static event EmptyEvent OnTick;
|
||||
|
||||
/// <summary>
|
||||
/// This is equivalent of <see cref="Script.KeyDown"/>
|
||||
/// </summary>
|
||||
public static KeyEventHandler OnKeyDown;
|
||||
|
||||
/// <summary>
|
||||
/// This is equivalent of <see cref="Script.KeyUp"/>
|
||||
/// </summary>
|
||||
public static KeyEventHandler OnKeyUp;
|
||||
|
||||
#region INVOKE
|
||||
internal static void InvokeVehicleSpawned(SyncedVehicle v) { OnVehicleSpawned?.Invoke(null, v); }
|
||||
internal static void InvokeVehicleDeleted(SyncedVehicle v) { OnVehicleDeleted?.Invoke(null, v); }
|
||||
internal static void InvokePedSpawned(SyncedPed p) { OnPedSpawned?.Invoke(null, p); }
|
||||
internal static void InvokePedDeleted(SyncedPed p) { OnPedDeleted?.Invoke(null, p); }
|
||||
internal static void InvokePlayerDied() { OnPlayerDied?.Invoke(); }
|
||||
internal static void InvokeTick() { OnTick?.Invoke(); }
|
||||
|
||||
internal static void InvokeKeyDown(object s,KeyEventArgs e) { OnKeyDown?.Invoke(s,e); }
|
||||
|
||||
internal static void InvokeKeyUp(object s, KeyEventArgs e) { OnKeyUp?.Invoke(s, e); }
|
||||
|
||||
internal static void InvokeCustomEventReceived(Packets.CustomEvent p)
|
||||
{
|
||||
var args = new CustomEventReceivedArgs() { Hash=p.Hash, Args=p.Args};
|
||||
|
||||
// Main.Logger.Debug($"CustomEvent:\n"+args.Args.DumpWithType());
|
||||
|
||||
List<Action<CustomEventReceivedArgs>> handlers;
|
||||
if (CustomEventHandlers.TryGetValue(p.Hash, out handlers))
|
||||
{
|
||||
handlers.ForEach((x) => { x.Invoke(args); });
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
#region PROPERTIES
|
||||
|
||||
/// <summary>
|
||||
/// Get the local player's ID
|
||||
/// </summary>
|
||||
/// <returns>PlayerID</returns>
|
||||
public static int LocalPlayerID
|
||||
{
|
||||
get { return Main.LocalPlayerID; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if a RAGECOOP menu is visible
|
||||
/// </summary>
|
||||
public static bool IsMenuVisible
|
||||
{
|
||||
get { return Menus.CoopMenu.MenuPool.AreAnyVisible; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the RAGECOOP chat is visible
|
||||
/// </summary>
|
||||
public static bool IsChatFocused
|
||||
{
|
||||
get { return Main.MainChat.Focused; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the RAGECOOP list of players is visible
|
||||
/// </summary>
|
||||
public static bool IsPlayerListVisible
|
||||
{
|
||||
get { return Util.GetTickCount64() - PlayerList.Pressed < 5000; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the version of RAGECOOP
|
||||
/// </summary>
|
||||
public static string CurrentVersion
|
||||
{
|
||||
get { return Main.CurrentVersion; }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get a <see cref="Core.Logger"/> that RAGECOOP is currently using.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static Logger Logger
|
||||
{
|
||||
get
|
||||
{
|
||||
return Main.Logger;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region FUNCTIONS
|
||||
/// <summary>
|
||||
/// Send a local chat message to this player
|
||||
/// </summary>
|
||||
/// <param name="from">Name of the sender</param>
|
||||
/// <param name="message">The player's message</param>
|
||||
public static void LocalChatMessage(string from, string message)
|
||||
{
|
||||
Main.MainChat.AddMessage(from, message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queue an action to be executed on next tick.
|
||||
/// </summary>
|
||||
/// <param name="a"></param>
|
||||
public static void QueueAction(Action a)
|
||||
{
|
||||
Main.QueueAction(a);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queue an action to be executed on next tick, allowing you to call scripting API from another thread.
|
||||
/// </summary>
|
||||
/// <param name="a"> An action to be executed with a return value indicating whether the action can be removed after execution.</param>
|
||||
public static void QueueAction(Func<bool> a)
|
||||
{
|
||||
Main.QueueAction(a);
|
||||
}
|
||||
/// <summary>
|
||||
/// Disconnect from the server
|
||||
/// </summary>
|
||||
public static void Disconnect()
|
||||
{
|
||||
Networking.ToggleConnection(null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send an event and data to the server.
|
||||
/// </summary>
|
||||
/// <param name="eventHash">An unique identifier of the event</param>
|
||||
/// <param name="args">The objects conataing your data, see <see cref="CustomEventReceivedArgs"/> for a list of supported types</param>
|
||||
public static void SendCustomEvent(int eventHash, params object[] args)
|
||||
{
|
||||
var p = new Packets.CustomEvent()
|
||||
{
|
||||
Args=args,
|
||||
Hash=eventHash
|
||||
};
|
||||
Networking.Send(p, ConnectionChannel.Event, Lidgren.Network.NetDeliveryMethod.ReliableOrdered);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register an handler to the specifed event hash, one event can have multiple handlers. This will be invoked from backgound thread, use <see cref="QueueAction(Action)"/> in the handler to dispatch code to script thread.
|
||||
/// </summary>
|
||||
/// <param name="hash">An unique identifier of the event, you can hash your event name with <see cref="Core.Scripting.CustomEvents.Hash(string)"/></param>
|
||||
/// <param name="handler">An handler to be invoked when the event is received from the server. </param>
|
||||
public static void RegisterCustomEventHandler(int hash, Action<CustomEventReceivedArgs> handler)
|
||||
{
|
||||
lock (CustomEventHandlers)
|
||||
{
|
||||
if (!CustomEventHandlers.TryGetValue(hash, out List<Action<CustomEventReceivedArgs>> handlers))
|
||||
{
|
||||
CustomEventHandlers.Add(hash, handlers = new List<Action<CustomEventReceivedArgs>>());
|
||||
}
|
||||
handlers.Add(handler);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -1,305 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using GTA.Native;
|
||||
using GTA.Math;
|
||||
using GTA;
|
||||
using RageCoop.Core;
|
||||
using RageCoop.Core.Scripting;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
|
||||
namespace RageCoop.Client.Scripting
|
||||
{
|
||||
internal class BaseScript : ClientScript
|
||||
{
|
||||
private bool _isHost=false;
|
||||
public override void OnStart()
|
||||
{
|
||||
API.Events.OnPedDeleted+=(s, p) => { API.SendCustomEvent(CustomEvents.OnPedDeleted, p.ID); };
|
||||
API.Events.OnVehicleDeleted+=(s, p) => { API.SendCustomEvent(CustomEvents.OnVehicleDeleted, p.ID); };
|
||||
|
||||
API.RegisterCustomEventHandler(CustomEvents.SetAutoRespawn,SetAutoRespawn);
|
||||
API.RegisterCustomEventHandler(CustomEvents.SetDisplayNameTag,SetDisplayNameTag);
|
||||
API.RegisterCustomEventHandler(CustomEvents.NativeCall,NativeCall);
|
||||
API.RegisterCustomEventHandler(CustomEvents.ServerPropSync, ServerObjectSync);
|
||||
API.RegisterCustomEventHandler(CustomEvents.DeleteServerProp, DeleteServerProp);
|
||||
API.RegisterCustomEventHandler(CustomEvents.DeleteEntity, DeleteEntity);
|
||||
API.RegisterCustomEventHandler(CustomEvents.SetDisplayNameTag, SetNameTag);
|
||||
API.RegisterCustomEventHandler(CustomEvents.ServerBlipSync, ServerBlipSync);
|
||||
API.RegisterCustomEventHandler(CustomEvents.DeleteServerBlip, DeleteServerBlip);
|
||||
API.RegisterCustomEventHandler(CustomEvents.CreateVehicle, CreateVehicle);
|
||||
API.RegisterCustomEventHandler(CustomEvents.UpdatePedBlip, UpdatePedBlip);
|
||||
API.RegisterCustomEventHandler(CustomEvents.IsHost, (e) => { _isHost=(bool)e.Args[0]; });
|
||||
API.RegisterCustomEventHandler(CustomEvents.WeatherTimeSync, WeatherTimeSync);
|
||||
Task.Run(() =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (_isHost)
|
||||
{
|
||||
API.QueueAction(() =>
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
var time = World.CurrentTimeOfDay;
|
||||
int weather1 = default(int);
|
||||
int weather2 = default(int);
|
||||
float percent2 = default(float);
|
||||
Function.Call(Hash._GET_WEATHER_TYPE_TRANSITION, &weather1, &weather2, &percent2);
|
||||
API.SendCustomEvent(CustomEvents.WeatherTimeSync, time.Hours, time.Minutes, time.Seconds, weather1, weather2, percent2);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void WeatherTimeSync(CustomEventReceivedArgs e)
|
||||
{
|
||||
World.CurrentTimeOfDay=new TimeSpan((int)e.Args[0], (int)e.Args[1], (int)e.Args[2]);
|
||||
Function.Call(Hash._SET_WEATHER_TYPE_TRANSITION, (int)e.Args[3], (int)e.Args[4], (float)e.Args[5]);
|
||||
}
|
||||
|
||||
private void SetDisplayNameTag(CustomEventReceivedArgs e)
|
||||
{
|
||||
var p = PlayerList.GetPlayer((int)e.Args[0]);
|
||||
if(p != null) { p.DisplayNameTag=(bool)e.Args[1]; }
|
||||
}
|
||||
|
||||
private void UpdatePedBlip(CustomEventReceivedArgs e)
|
||||
{
|
||||
var p = Entity.FromHandle((int)e.Args[0]);
|
||||
if (p == null) { return; }
|
||||
if (p.Handle==Game.Player.Character.Handle)
|
||||
{
|
||||
API.Config.BlipColor=(BlipColor)(byte)e.Args[1];
|
||||
API.Config.BlipSprite=(BlipSprite)(ushort)e.Args[2];
|
||||
API.Config.BlipScale=(float)e.Args[3];
|
||||
}
|
||||
else
|
||||
{
|
||||
var b = p.AttachedBlip;
|
||||
if (b == null) { b=p.AddBlip(); }
|
||||
b.Color=(BlipColor)(byte)e.Args[1];
|
||||
b.Sprite=(BlipSprite)(ushort)e.Args[2];
|
||||
b.Scale=(float)e.Args[3];
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateVehicle(CustomEventReceivedArgs e)
|
||||
{
|
||||
var vehicleModel = (Model)e.Args[1];
|
||||
vehicleModel.Request(1000);
|
||||
Vehicle veh= World.CreateVehicle(vehicleModel, (Vector3)e.Args[2], (float)e.Args[3]);
|
||||
while (veh==null)
|
||||
{
|
||||
veh = World.CreateVehicle(vehicleModel, (Vector3)e.Args[2], (float)e.Args[3]);
|
||||
Thread.Sleep(10);
|
||||
}
|
||||
veh.CanPretendOccupants=false;
|
||||
var v = new SyncedVehicle()
|
||||
{
|
||||
ID=(int)e.Args[0],
|
||||
MainVehicle=veh,
|
||||
OwnerID=Main.LocalPlayerID,
|
||||
};
|
||||
EntityPool.Add(v);
|
||||
}
|
||||
|
||||
private void DeleteServerBlip(CustomEventReceivedArgs e)
|
||||
{
|
||||
if (EntityPool.ServerBlips.TryGetValue((int)e.Args[0], out var blip))
|
||||
{
|
||||
EntityPool.ServerBlips.Remove((int)e.Args[0]);
|
||||
blip?.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
private void ServerBlipSync(CustomEventReceivedArgs obj)
|
||||
{
|
||||
int id= (int)obj.Args[0];
|
||||
var sprite=(BlipSprite)(ushort)obj.Args[1];
|
||||
var color = (BlipColor)(byte)obj.Args[2];
|
||||
var scale=(float)obj.Args[3];
|
||||
var pos=(Vector3)obj.Args[4];
|
||||
int rot= (int)obj.Args[5];
|
||||
var name=(string)obj.Args[6];
|
||||
Blip blip;
|
||||
if (!EntityPool.ServerBlips.TryGetValue(id, out blip))
|
||||
{
|
||||
EntityPool.ServerBlips.Add(id, blip=World.CreateBlip(pos));
|
||||
}
|
||||
blip.Sprite = sprite;
|
||||
blip.Color = color;
|
||||
blip.Scale = scale;
|
||||
blip.Position = pos;
|
||||
blip.Rotation = rot;
|
||||
blip.Name = name;
|
||||
}
|
||||
|
||||
|
||||
private void DeleteEntity(CustomEventReceivedArgs e)
|
||||
{
|
||||
Entity.FromHandle((int)e.Args[0])?.Delete();
|
||||
}
|
||||
|
||||
public override void OnStop()
|
||||
{
|
||||
}
|
||||
private void SetNameTag(CustomEventReceivedArgs e)
|
||||
{
|
||||
var p =PlayerList.GetPlayer((int)e.Args[0]);
|
||||
if(p!= null)
|
||||
{
|
||||
p.DisplayNameTag=(bool)e.Args[1];
|
||||
}
|
||||
}
|
||||
private void SetAutoRespawn(CustomEventReceivedArgs args)
|
||||
{
|
||||
API.Config.EnableAutoRespawn=(bool)args.Args[0];
|
||||
}
|
||||
private void DeleteServerProp(CustomEventReceivedArgs e)
|
||||
{
|
||||
var id = (int)e.Args[0];
|
||||
if (EntityPool.ServerProps.TryGetValue(id, out var prop))
|
||||
{
|
||||
EntityPool.ServerProps.Remove(id);
|
||||
prop?.MainProp?.Delete();
|
||||
}
|
||||
|
||||
}
|
||||
private void ServerObjectSync(CustomEventReceivedArgs e)
|
||||
{
|
||||
SyncedProp prop;
|
||||
var id = (int)e.Args[0];
|
||||
lock (EntityPool.PropsLock)
|
||||
{
|
||||
if (!EntityPool.ServerProps.TryGetValue(id, out prop))
|
||||
{
|
||||
EntityPool.ServerProps.Add(id, prop=new SyncedProp(id));
|
||||
}
|
||||
}
|
||||
prop.LastSynced=Main.Ticked+1;
|
||||
prop.Model= (Model)e.Args[1];
|
||||
prop.Position=(Vector3)e.Args[2];
|
||||
prop.Rotation=(Vector3)e.Args[3];
|
||||
prop.Update();
|
||||
}
|
||||
private void NativeCall(CustomEventReceivedArgs e)
|
||||
{
|
||||
List<InputArgument> arguments = new List<InputArgument>();
|
||||
int i;
|
||||
var ty = (byte)e.Args[0];
|
||||
TypeCode returnType=(TypeCode)ty;
|
||||
i = returnType==TypeCode.Empty ? 1 : 2;
|
||||
var hash = (Hash)e.Args[i++];
|
||||
for(; i<e.Args.Length;i++)
|
||||
{
|
||||
arguments.Add(GetInputArgument(e.Args[i]));
|
||||
}
|
||||
|
||||
if (returnType==TypeCode.Empty)
|
||||
{
|
||||
Function.Call(hash, arguments.ToArray());
|
||||
return;
|
||||
}
|
||||
var t = returnType;
|
||||
int id = (int)e.Args[1];
|
||||
|
||||
|
||||
switch (returnType)
|
||||
{
|
||||
case TypeCode.Boolean:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new object[] { id, Function.Call<bool>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
case TypeCode.Byte:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new object[] { id, Function.Call<byte>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
case TypeCode.Char:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new object[] { id, Function.Call<char>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
|
||||
case TypeCode.Single:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new object[] { id, Function.Call<float>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
|
||||
case TypeCode.Double:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new object[] { id, Function.Call<double>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
|
||||
case TypeCode.Int16:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new object[] { id, Function.Call<short>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
|
||||
case TypeCode.Int32:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new object[] { id, Function.Call<int>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
|
||||
case TypeCode.Int64:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new object[] { id, Function.Call<long>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
|
||||
case TypeCode.String:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new object[] { id, Function.Call<string>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
|
||||
case TypeCode.UInt16:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new object[] { id, Function.Call<ushort>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
|
||||
case TypeCode.UInt32:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new object[] { id, Function.Call<uint>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
|
||||
case TypeCode.UInt64:
|
||||
API.SendCustomEvent(CustomEvents.NativeResponse,
|
||||
new object[] { id, Function.Call<ulong>(hash, arguments.ToArray()) });
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
private InputArgument GetInputArgument(object obj)
|
||||
{
|
||||
// Implicit conversion
|
||||
switch (obj)
|
||||
{
|
||||
case byte _:
|
||||
return (byte)obj;
|
||||
case short _:
|
||||
return (short)obj;
|
||||
case ushort _:
|
||||
return (ushort)obj;
|
||||
case int _:
|
||||
return (int)obj;
|
||||
case uint _:
|
||||
return (uint)obj;
|
||||
case long _:
|
||||
return (long)obj;
|
||||
case ulong _:
|
||||
return (ulong)obj;
|
||||
case float _:
|
||||
return (float)obj;
|
||||
case bool _:
|
||||
return (bool)obj;
|
||||
case string _:
|
||||
return (obj as string);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
using RageCoop.Core.Scripting;
|
||||
|
||||
namespace RageCoop.Client.Scripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Inherit from this class, constructor will be called automatically, but other scripts might have yet been loaded, you should use <see cref="OnStart"/>. to initiate your script.
|
||||
/// </summary>
|
||||
public abstract class ClientScript
|
||||
{
|
||||
/// <summary>
|
||||
/// This method would be called from background thread, call <see cref="API.QueueAction(System.Action)"/> to dispatch it to main thread.
|
||||
/// </summary>
|
||||
public abstract void OnStart();
|
||||
|
||||
/// <summary>
|
||||
/// This method would be called from background thread when the client disconnected from the server, you MUST terminate all background jobs/threads in this method.
|
||||
/// </summary>
|
||||
public abstract void OnStop();
|
||||
|
||||
/// <summary>
|
||||
/// Get the <see cref="ResourceFile"/> instance where this script is loaded from.
|
||||
/// </summary>
|
||||
public ResourceFile CurrentFile { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Get the <see cref="ClientResource"/> that this script belongs to.
|
||||
/// </summary>
|
||||
public ClientResource CurrentResource { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Eqivalent of <see cref="ClientResource.Logger"/> in <see cref="CurrentResource"/>
|
||||
/// </summary>
|
||||
public Core.Logger Logger { get { return CurrentResource.Logger; } }
|
||||
|
||||
}
|
||||
}
|
@ -1,291 +0,0 @@
|
||||
using System.IO;
|
||||
using RageCoop.Core.Scripting;
|
||||
using RageCoop.Core;
|
||||
using ICSharpCode.SharpZipLib.Zip;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace RageCoop.Client.Scripting
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class ClientResource
|
||||
{
|
||||
/// <summary>
|
||||
/// Name of the resource
|
||||
/// </summary>
|
||||
public string Name { get; internal set; }
|
||||
/// <summary>
|
||||
/// A resource-specific folder that can be used to store your files.
|
||||
/// </summary>
|
||||
public string DataFolder { get; internal set; }
|
||||
/// <summary>
|
||||
/// Get all <see cref="ClientScript"/> instance in this resource.
|
||||
/// </summary>
|
||||
public List<ClientScript> Scripts { get; internal set; } = new List<ClientScript>();
|
||||
/// <summary>
|
||||
/// Get the <see cref="ResourceFile"/> where this script is loaded from.
|
||||
/// </summary>
|
||||
public Dictionary<string, ResourceFile> Files { get; internal set; } = new Dictionary<string, ResourceFile>();
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="Core.Logger"/> instance that can be used to debug your resource.
|
||||
/// </summary>
|
||||
public Logger Logger { get; internal set; }
|
||||
}
|
||||
internal class Resources
|
||||
{
|
||||
public Resources(){
|
||||
BaseScriptType = "RageCoop.Client.Scripting.ClientScript";
|
||||
Logger = Main.Logger;
|
||||
}
|
||||
private void StartAll()
|
||||
{
|
||||
lock (LoadedResources)
|
||||
{
|
||||
foreach (var d in LoadedResources)
|
||||
{
|
||||
foreach (var s in d.Scripts)
|
||||
{
|
||||
try
|
||||
{
|
||||
s.OnStart();
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Logger.Error("Error occurred when starting script:"+s.GetType().FullName);
|
||||
Logger?.Error(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private void StopAll()
|
||||
{
|
||||
lock (LoadedResources)
|
||||
{
|
||||
foreach (var d in LoadedResources)
|
||||
{
|
||||
foreach (var s in d.Scripts)
|
||||
{
|
||||
try
|
||||
{
|
||||
s.OnStop();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error("Error occurred when stopping script:"+s.GetType().FullName);
|
||||
Logger?.Error(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public void Load(string path,string[] zips)
|
||||
{
|
||||
foreach (var zip in zips)
|
||||
{
|
||||
var zipPath=Path.Combine(path, zip);
|
||||
Logger?.Info($"Loading resource: {Path.GetFileNameWithoutExtension(zip)}");
|
||||
LoadResource(new ZipFile(zipPath),Path.Combine(path,"data"));
|
||||
}
|
||||
StartAll();
|
||||
}
|
||||
public void Unload()
|
||||
{
|
||||
StopAll();
|
||||
if (LoadedResources.Count > 0)
|
||||
{
|
||||
API.QueueAction(()=>Util.Reload());
|
||||
}
|
||||
LoadedResources.Clear();
|
||||
}
|
||||
private List<string> ToIgnore = new List<string>
|
||||
{
|
||||
"RageCoop.Client.dll",
|
||||
"RageCoop.Core.dll",
|
||||
"RageCoop.Server.dll",
|
||||
"ScriptHookVDotNet3.dll"
|
||||
};
|
||||
private List<ClientResource> LoadedResources = new List<ClientResource>();
|
||||
private string BaseScriptType;
|
||||
public Logger Logger { get; set; }
|
||||
|
||||
private void LoadResource(ZipFile file, string dataFolderRoot)
|
||||
{
|
||||
var r = new ClientResource()
|
||||
{
|
||||
Scripts = new List<ClientScript>(),
|
||||
Name=Path.GetFileNameWithoutExtension(file.Name),
|
||||
DataFolder=Path.Combine(dataFolderRoot, Path.GetFileNameWithoutExtension(file.Name))
|
||||
};
|
||||
Directory.CreateDirectory(r.DataFolder);
|
||||
|
||||
foreach (ZipEntry entry in file)
|
||||
{
|
||||
ResourceFile rFile;
|
||||
r.Files.Add(entry.Name, rFile=new ResourceFile()
|
||||
{
|
||||
Name=entry.Name,
|
||||
IsDirectory=entry.IsDirectory,
|
||||
});
|
||||
if (!entry.IsDirectory)
|
||||
{
|
||||
rFile.GetStream=() => { return file.GetInputStream(entry); };
|
||||
if (entry.Name.EndsWith(".dll"))
|
||||
{
|
||||
var tmp = Path.GetTempFileName();
|
||||
var f = File.OpenWrite(tmp);
|
||||
rFile.GetStream().CopyTo(f);
|
||||
f.Close();
|
||||
LoadScriptsFromAssembly(rFile, tmp, r, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
LoadedResources.Add(r);
|
||||
file.Close();
|
||||
}
|
||||
private bool LoadScriptsFromAssembly(ResourceFile file, string path, ClientResource resource, bool shadowCopy = true)
|
||||
{
|
||||
lock (LoadedResources)
|
||||
{
|
||||
if (!IsManagedAssembly(path)) { return false; }
|
||||
if (ToIgnore.Contains(file.Name)) { try { File.Delete(path); } catch { }; return false; }
|
||||
|
||||
Logger?.Debug($"Loading assembly {file.Name} ...");
|
||||
|
||||
Assembly assembly;
|
||||
|
||||
try
|
||||
{
|
||||
if (shadowCopy)
|
||||
{
|
||||
var temp = Path.GetTempFileName();
|
||||
File.Copy(path, temp, true);
|
||||
assembly = Assembly.LoadFrom(temp);
|
||||
}
|
||||
else
|
||||
{
|
||||
assembly = Assembly.LoadFrom(path);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger?.Error("Unable to load "+file.Name);
|
||||
Logger?.Error(ex);
|
||||
return false;
|
||||
}
|
||||
|
||||
return LoadScriptsFromAssembly(file, assembly, path, resource);
|
||||
}
|
||||
}
|
||||
private bool LoadScriptsFromAssembly(ResourceFile rfile, Assembly assembly, string filename, ClientResource toload)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
try
|
||||
{
|
||||
// Find all script types in the assembly
|
||||
foreach (var type in assembly.GetTypes().Where(x => IsSubclassOf(x, BaseScriptType)))
|
||||
{
|
||||
ConstructorInfo constructor = type.GetConstructor(System.Type.EmptyTypes);
|
||||
if (constructor != null && constructor.IsPublic)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Invoke script constructor
|
||||
var script = constructor.Invoke(null) as ClientScript;
|
||||
// script.CurrentResource = toload;
|
||||
script.CurrentFile=rfile;
|
||||
script.CurrentResource=toload;
|
||||
toload.Scripts.Add(script);
|
||||
count++;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger?.Error($"Error occurred when loading script: {type.FullName}.");
|
||||
Logger?.Error(ex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger?.Error($"Script {type.FullName} has an invalid contructor.");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ReflectionTypeLoadException ex)
|
||||
{
|
||||
Logger?.Error($"Failed to load assembly {rfile.Name}: ");
|
||||
Logger?.Error(ex);
|
||||
foreach (var e in ex.LoaderExceptions)
|
||||
{
|
||||
Logger?.Error(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Logger?.Info($"Loaded {count} script(s) in {rfile.Name}");
|
||||
return count != 0;
|
||||
}
|
||||
private bool IsManagedAssembly(string filename)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (Stream file = new FileStream(filename, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
if (file.Length < 64)
|
||||
return false;
|
||||
|
||||
using (BinaryReader bin = new BinaryReader(file))
|
||||
{
|
||||
// PE header starts at offset 0x3C (60). Its a 4 byte header.
|
||||
file.Position = 0x3C;
|
||||
uint offset = bin.ReadUInt32();
|
||||
if (offset == 0)
|
||||
offset = 0x80;
|
||||
|
||||
// Ensure there is at least enough room for the following structures:
|
||||
// 24 byte PE Signature & Header
|
||||
// 28 byte Standard Fields (24 bytes for PE32+)
|
||||
// 68 byte NT Fields (88 bytes for PE32+)
|
||||
// >= 128 byte Data Dictionary Table
|
||||
if (offset > file.Length - 256)
|
||||
return false;
|
||||
|
||||
// Check the PE signature. Should equal 'PE\0\0'.
|
||||
file.Position = offset;
|
||||
if (bin.ReadUInt32() != 0x00004550)
|
||||
return false;
|
||||
|
||||
// Read PE magic number from Standard Fields to determine format.
|
||||
file.Position += 20;
|
||||
var peFormat = bin.ReadUInt16();
|
||||
if (peFormat != 0x10b /* PE32 */ && peFormat != 0x20b /* PE32Plus */)
|
||||
return false;
|
||||
|
||||
// Read the 15th Data Dictionary RVA field which contains the CLI header RVA.
|
||||
// When this is non-zero then the file contains CLI data otherwise not.
|
||||
file.Position = offset + (peFormat == 0x10b ? 232 : 248);
|
||||
return bin.ReadUInt32() != 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// This is likely not a valid assembly if any IO exceptions occur during reading
|
||||
return false;
|
||||
}
|
||||
}
|
||||
private bool IsSubclassOf(Type type, string baseTypeName)
|
||||
{
|
||||
for (Type t = type.BaseType; t != null; t = t.BaseType)
|
||||
if (t.FullName == baseTypeName)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Security.Cryptography;
|
||||
using System.IO;
|
||||
using RageCoop.Core;
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal class Security
|
||||
{
|
||||
public RSA ServerRSA { get; set; }
|
||||
public Aes ClientAes { get; set; }=Aes.Create();
|
||||
private Logger Logger;
|
||||
public Security(Logger logger)
|
||||
{
|
||||
Logger = logger;
|
||||
ClientAes.GenerateKey();
|
||||
ClientAes.GenerateIV();
|
||||
}
|
||||
public void GetSymmetricKeysCrypted(out byte[] cryptedKey,out byte[] cryptedIV)
|
||||
{
|
||||
// Logger?.Debug($"Aes.Key:{ClientAes.Key.Dump()}, Aes.IV:{ClientAes.IV.Dump()}");
|
||||
cryptedKey =ServerRSA.Encrypt(ClientAes.Key, RSAEncryptionPadding.Pkcs1);
|
||||
cryptedIV =ServerRSA.Encrypt(ClientAes.IV,RSAEncryptionPadding.Pkcs1);
|
||||
}
|
||||
public byte[] Encrypt(byte[] data)
|
||||
{
|
||||
return new CryptoStream(new MemoryStream(data), ClientAes.CreateEncryptor(), CryptoStreamMode.Read).ReadToEnd();
|
||||
}
|
||||
public void SetServerPublicKey(byte[] modulus,byte[] exponent)
|
||||
{
|
||||
var para = new RSAParameters();
|
||||
para.Modulus = modulus;
|
||||
para.Exponent = exponent;
|
||||
ServerRSA=RSA.Create(para);
|
||||
}
|
||||
public void Regen()
|
||||
{
|
||||
ClientAes=Aes.Create();
|
||||
ClientAes.GenerateKey();
|
||||
ClientAes.GenerateIV();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
#undef DEBUG
|
||||
using System.Windows.Forms;
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// Don't use it!
|
||||
/// </summary>
|
||||
public class Settings
|
||||
{
|
||||
/// <summary>
|
||||
/// Don't use it!
|
||||
/// </summary>
|
||||
public string Username { get; set; } = "Player";
|
||||
/// <summary>
|
||||
/// The password used to authenticate when connecting to a server.
|
||||
/// </summary>
|
||||
public string Password { get; set; } = "";
|
||||
/// <summary>
|
||||
/// Don't use it!
|
||||
/// </summary>
|
||||
public string LastServerAddress { get; set; } = "127.0.0.1:4499";
|
||||
/// <summary>
|
||||
/// Don't use it!
|
||||
/// </summary>
|
||||
public string MasterServer { get; set; } = "https://masterserver.ragecoop.online/";
|
||||
/// <summary>
|
||||
/// Don't use it!
|
||||
/// </summary>
|
||||
public bool FlipMenu { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// LogLevel for RageCoop.
|
||||
/// 0:Trace, 1:Debug, 2:Info, 3:Warning, 4:Error
|
||||
/// </summary>
|
||||
public int LogLevel = 2;
|
||||
|
||||
/// <summary>
|
||||
/// The key to open menu
|
||||
/// </summary>
|
||||
public Keys MenuKey { get; set; } = Keys.F9;
|
||||
|
||||
/// <summary>
|
||||
/// The key to enter a vehicle as passenger.
|
||||
/// </summary>
|
||||
public Keys PassengerKey { get; set; }=Keys.G;
|
||||
|
||||
/// <summary>
|
||||
/// Disable world NPC traffic, mission entities won't be affected
|
||||
/// </summary>
|
||||
public bool DisableTraffic { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Bring up pause menu but don't freeze time when FrontEndPauseAlternate(Esc) is pressed.
|
||||
/// </summary>
|
||||
public bool DisableAlternatePause { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// The game won't spawn more NPC traffic if the limit is exceeded. -1 for unlimited (not recommended).
|
||||
/// </summary>
|
||||
public int WorldVehicleSoftLimit { get; set; } = 20;
|
||||
|
||||
/// <summary>
|
||||
/// The game won't spawn more NPC traffic if the limit is exceeded. -1 for unlimited (not recommended).
|
||||
/// </summary>
|
||||
public int WorldPedSoftLimit { get; set; } = 30;
|
||||
/// <summary>
|
||||
/// The directory where log and resources downloaded from server will be placed.
|
||||
/// </summary>
|
||||
public string DataDirectory { get; set; } = "Scripts\\RageCoop\\Data";
|
||||
}
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public abstract class SyncedEntity
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the current player is responsible for syncing this entity.
|
||||
/// </summary>
|
||||
public bool IsLocal
|
||||
{
|
||||
get
|
||||
{
|
||||
return OwnerID==Main.LocalPlayerID;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Network ID for this entity
|
||||
/// </summary>
|
||||
public int ID { get;internal set; }
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public int OwnerID { get; internal set; }
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public bool IsOutOfSync
|
||||
{
|
||||
get
|
||||
{
|
||||
return Main.Ticked-LastSynced>200 && ID!=0;
|
||||
}
|
||||
}
|
||||
internal bool IsReady
|
||||
{
|
||||
get {return (LastSynced>0||LastStateSynced==0);}
|
||||
}
|
||||
internal bool IsInvincible { get; set; } = false;
|
||||
internal bool NeedUpdate
|
||||
{
|
||||
get { return LastSynced>LastUpdated; }
|
||||
}
|
||||
#region LAST STATE
|
||||
/// <summary>
|
||||
/// Last time a new sync message arrived.
|
||||
/// </summary>
|
||||
public ulong LastSynced { get; set; } = 0;
|
||||
/// <summary>
|
||||
/// Last time a new sync message arrived.
|
||||
/// </summary>
|
||||
public ulong LastStateSynced { get; internal set; } = 0;
|
||||
/// <summary>
|
||||
/// Last time the local entity has been updated,
|
||||
/// </summary>
|
||||
public ulong LastUpdated { get; set; } = 0;
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
internal protected bool _lastFrozen=false;
|
||||
internal Model Model { get; set; }
|
||||
internal Vector3 Position { get; set; }
|
||||
internal Vector3 Rotation { get; set; }
|
||||
internal Quaternion Quaternion { get; set; }
|
||||
internal Vector3 Velocity { get; set; }
|
||||
internal abstract void Update();
|
||||
internal void PauseUpdate(ulong frames)
|
||||
{
|
||||
LastUpdated=Main.Ticked+frames;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,746 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Drawing;
|
||||
using System.Collections.Generic;
|
||||
using RageCoop.Core;
|
||||
using GTA;
|
||||
using GTA.Native;
|
||||
using GTA.Math;
|
||||
using LemonUI.Elements;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// </summary>
|
||||
public class SyncedPed:SyncedEntity
|
||||
{
|
||||
#region CONSTRUCTORS
|
||||
|
||||
/// <summary>
|
||||
/// Create a local entity (outgoing sync)
|
||||
/// </summary>
|
||||
/// <param name="p"></param>
|
||||
internal SyncedPed(Ped p)
|
||||
{
|
||||
ID=EntityPool.RequestNewID();
|
||||
p.CanWrithe=false;
|
||||
p.IsOnlyDamagedByPlayer=false;
|
||||
MainPed=p;
|
||||
OwnerID=Main.LocalPlayerID;
|
||||
|
||||
Function.Call(Hash._SET_PED_CAN_PLAY_INJURED_ANIMS, false);
|
||||
MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DisableHurt, true);
|
||||
// MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DisableMelee, true);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an empty character with ID
|
||||
/// </summary>
|
||||
internal SyncedPed(int id)
|
||||
{
|
||||
ID=id;
|
||||
LastSynced=Main.Ticked;
|
||||
}
|
||||
#endregion
|
||||
#region PLAYER -- ONLY
|
||||
internal Blip PedBlip = null;
|
||||
internal BlipColor BlipColor = (BlipColor)255;
|
||||
internal BlipSprite BlipSprite = (BlipSprite)0;
|
||||
internal float BlipScale=1;
|
||||
internal PlayerData Player;
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether this ped is a player
|
||||
/// </summary>
|
||||
public bool IsPlayer { get { return (OwnerID==ID)&&(ID!=0); } }
|
||||
/// <summary>
|
||||
/// real entity
|
||||
/// </summary>
|
||||
public Ped MainPed { get; internal set; }
|
||||
internal int Health { get; set; }
|
||||
internal bool IsInStealthMode { get; set; }
|
||||
internal byte WeaponTint { get; set; }
|
||||
internal bool _lastEnteringVehicle=false;
|
||||
internal bool _lastSittingInVehicle=false;
|
||||
private bool _lastRagdoll=false;
|
||||
private ulong _lastRagdollTime=0;
|
||||
private bool _lastInCover = false;
|
||||
private byte[] _lastClothes = null;
|
||||
internal byte[] Clothes { get; set; }
|
||||
|
||||
internal float Heading { get; set; }
|
||||
// internal Vector3 RotationVelocity { get; set; }
|
||||
internal Vector3 AimCoords { get; set; }
|
||||
|
||||
private WeaponAsset WeaponAsset { get; set; }
|
||||
|
||||
|
||||
internal override void Update()
|
||||
{
|
||||
if (IsPlayer)
|
||||
{
|
||||
if (Player==null)
|
||||
{
|
||||
Player = PlayerList.GetPlayer(this);
|
||||
return;
|
||||
}
|
||||
RenderNameTag();
|
||||
}
|
||||
|
||||
// Check if all data avalible
|
||||
if (!IsReady) { return; }
|
||||
|
||||
// Skip update if no new sync message has arrived.
|
||||
if (!NeedUpdate)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (MainPed == null || !MainPed.Exists())
|
||||
{
|
||||
if (!CreateCharacter())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (((byte)BlipColor==255) && (PedBlip!=null))
|
||||
{
|
||||
PedBlip.Delete();
|
||||
PedBlip=null;
|
||||
}
|
||||
else if (((byte)BlipColor != 255) && PedBlip==null)
|
||||
{
|
||||
PedBlip=MainPed.AddBlip();
|
||||
|
||||
if (IsPlayer)
|
||||
{
|
||||
Main.Logger.Debug("blip:"+Player.Username);
|
||||
PedBlip.Name=Player.Username;
|
||||
}
|
||||
PedBlip.Color=BlipColor;
|
||||
PedBlip.Sprite=BlipSprite;
|
||||
PedBlip.Scale=BlipScale;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Need to update state
|
||||
if (LastStateSynced>=LastUpdated)
|
||||
{
|
||||
|
||||
if (MainPed!=null&& (Model != MainPed.Model.Hash))
|
||||
{
|
||||
if (!CreateCharacter())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!Clothes.SequenceEqual(_lastClothes))
|
||||
{
|
||||
SetClothes();
|
||||
}
|
||||
var b = MainPed.AttachedBlip;
|
||||
if (b==null || b.Color!=BlipColor || b.Sprite!=BlipSprite)
|
||||
{
|
||||
PedBlip?.Delete();
|
||||
PedBlip=MainPed.AddBlip();
|
||||
PedBlip.Color=BlipColor;
|
||||
PedBlip.Sprite =BlipSprite;
|
||||
if (IsPlayer)
|
||||
{
|
||||
Main.Logger.Debug("blip:"+Player.Username);
|
||||
b.Name=Player.Username;
|
||||
}
|
||||
}
|
||||
|
||||
CheckCurrentWeapon();
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (MainPed.IsDead)
|
||||
{
|
||||
if (Health>0)
|
||||
{
|
||||
if (IsPlayer)
|
||||
{
|
||||
MainPed.Resurrect();
|
||||
}
|
||||
else
|
||||
{
|
||||
SyncEvents.TriggerPedKilled(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (IsPlayer&&(MainPed.Health != Health))
|
||||
{
|
||||
MainPed.Health = Health;
|
||||
|
||||
if (Health <= 0 && !MainPed.IsDead)
|
||||
{
|
||||
MainPed.IsInvincible = false;
|
||||
MainPed.Kill();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (MainPed.IsInVehicle()||MainPed.IsGettingIntoVehicle)
|
||||
{
|
||||
DisplayInVehicle();
|
||||
}
|
||||
else
|
||||
{
|
||||
DisplayOnFoot();
|
||||
}
|
||||
LastUpdated=Main.Ticked;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
private void RenderNameTag()
|
||||
{
|
||||
if (!Player.DisplayNameTag || (MainPed==null) || !MainPed.IsVisible || !MainPed.IsInRange(Game.Player.Character.Position, 40f))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3 targetPos = MainPed.Bones[Bone.IKHead].Position;
|
||||
Point toDraw=default;
|
||||
if (Util.WorldToScreen(targetPos, ref toDraw))
|
||||
{
|
||||
toDraw.Y-=100;
|
||||
new ScaledText(toDraw, Player.Username, 0.4f, GTA.UI.Font.ChaletLondon)
|
||||
{
|
||||
Outline = true,
|
||||
Alignment = GTA.UI.Alignment.Center
|
||||
}.Draw();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private bool CreateCharacter()
|
||||
{
|
||||
if (MainPed != null)
|
||||
{
|
||||
if (MainPed.Exists())
|
||||
{
|
||||
Main.Logger.Debug($"Removing ped {ID}. Reason:CreateCharacter");
|
||||
MainPed.Kill();
|
||||
MainPed.MarkAsNoLongerNeeded();
|
||||
MainPed.Delete();
|
||||
}
|
||||
|
||||
MainPed = null;
|
||||
}
|
||||
|
||||
if (PedBlip != null && PedBlip.Exists())
|
||||
{
|
||||
PedBlip.Delete();
|
||||
PedBlip = null;
|
||||
}
|
||||
if (!Model.IsLoaded)
|
||||
{
|
||||
Model.Request();
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((MainPed = Util.CreatePed(Model, Position)) == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Model.MarkAsNoLongerNeeded();
|
||||
|
||||
|
||||
MainPed.BlockPermanentEvents = true;
|
||||
MainPed.CanWrithe=false;
|
||||
MainPed.CanBeDraggedOutOfVehicle = true;
|
||||
MainPed.IsOnlyDamagedByPlayer = false;
|
||||
MainPed.RelationshipGroup=Main.SyncedPedsGroup;
|
||||
MainPed.IsFireProof=false;
|
||||
MainPed.IsExplosionProof=false;
|
||||
|
||||
Function.Call(Hash.SET_PED_DROPS_WEAPONS_WHEN_DEAD, MainPed.Handle, false);
|
||||
Function.Call(Hash.SET_PED_CAN_BE_TARGETTED, MainPed.Handle, true);
|
||||
Function.Call(Hash.SET_PED_CAN_BE_TARGETTED_BY_PLAYER, MainPed.Handle, Game.Player, true);
|
||||
Function.Call(Hash.SET_PED_GET_OUT_UPSIDE_DOWN_VEHICLE, MainPed.Handle, false);
|
||||
Function.Call(Hash.SET_CAN_ATTACK_FRIENDLY, MainPed.Handle, true, true);
|
||||
Function.Call(Hash._SET_PED_CAN_PLAY_INJURED_ANIMS, false);
|
||||
Function.Call(Hash.SET_PED_CAN_EVASIVE_DIVE, MainPed.Handle, false);
|
||||
|
||||
|
||||
MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DrownsInWater,false);
|
||||
MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DisableHurt, true);
|
||||
MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DisableExplosionReactions, true);
|
||||
MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_AvoidTearGas, false);
|
||||
MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DisableShockingEvents, true);
|
||||
MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DisableHurt, true);
|
||||
|
||||
SetClothes();
|
||||
|
||||
if (IsPlayer)
|
||||
{
|
||||
MainPed.IsInvincible=true;
|
||||
}
|
||||
if (IsInvincible) { MainPed.IsInvincible=true; }
|
||||
|
||||
lock (EntityPool.PedsLock)
|
||||
{
|
||||
// Add to EntityPool so this Character can be accessed by handle.
|
||||
EntityPool.Add(this);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void SetClothes()
|
||||
{
|
||||
for (byte i = 0; i < 12; i++)
|
||||
{
|
||||
Function.Call(Hash.SET_PED_COMPONENT_VARIATION, MainPed.Handle, i, (int)Clothes[i], (int)Clothes[i+12], (int)Clothes[i+24]);
|
||||
}
|
||||
_lastClothes = Clothes;
|
||||
}
|
||||
#region ONFOOT
|
||||
#region -- VARIABLES --
|
||||
/// <summary>
|
||||
/// The latest character rotation (may not have been applied yet)
|
||||
/// </summary>
|
||||
public byte Speed { get; set; }
|
||||
private bool _lastIsJumping = false;
|
||||
internal bool IsJumping { get; set; }
|
||||
internal bool IsOnLadder { get; set; }
|
||||
internal bool IsVaulting { get; set; }
|
||||
internal bool IsInParachuteFreeFall { get; set; }
|
||||
internal bool IsParachuteOpen { get; set; }
|
||||
internal Prop ParachuteProp { get; set; } = null;
|
||||
internal bool IsRagdoll { get; set; }
|
||||
internal bool IsOnFire { get; set; }
|
||||
internal bool IsAiming { get; set; }
|
||||
internal bool IsReloading { get; set; }
|
||||
internal bool IsInCover { get; set; }
|
||||
internal uint CurrentWeaponHash { get; set; }
|
||||
private Dictionary<uint, bool> _lastWeaponComponents = null;
|
||||
internal Dictionary<uint, bool> WeaponComponents { get; set; } = null;
|
||||
private int _lastWeaponObj = 0;
|
||||
#endregion
|
||||
|
||||
private string[] _currentAnimation = new string[2] { "", "" };
|
||||
|
||||
private void DisplayOnFoot()
|
||||
{
|
||||
if (IsInParachuteFreeFall)
|
||||
{
|
||||
MainPed.PositionNoOffset = Vector3.Lerp(MainPed.Position, Position + Velocity, 0.5f);
|
||||
MainPed.Quaternion = Rotation.ToQuaternion();
|
||||
|
||||
if (!Function.Call<bool>(Hash.IS_ENTITY_PLAYING_ANIM, MainPed.Handle, "skydive@base", "free_idle", 3))
|
||||
{
|
||||
Function.Call(Hash.TASK_PLAY_ANIM, MainPed.Handle, LoadAnim("skydive@base"), "free_idle", 8f, 10f, -1, 0, -8f, 1, 1, 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsParachuteOpen)
|
||||
{
|
||||
if (ParachuteProp == null)
|
||||
{
|
||||
Model model = 1740193300;
|
||||
model.Request(1000);
|
||||
if (model != null)
|
||||
{
|
||||
ParachuteProp = World.CreateProp(model, MainPed.Position, MainPed.Rotation, false, false);
|
||||
model.MarkAsNoLongerNeeded();
|
||||
ParachuteProp.IsPositionFrozen = true;
|
||||
ParachuteProp.IsCollisionEnabled = false;
|
||||
|
||||
ParachuteProp.AttachTo(MainPed.Bones[Bone.SkelSpine2], new Vector3(3.6f, 0f, 0f), new Vector3(0f, 90f, 0f));
|
||||
}
|
||||
MainPed.Task.ClearAllImmediately();
|
||||
MainPed.Task.ClearSecondary();
|
||||
}
|
||||
|
||||
MainPed.PositionNoOffset = Vector3.Lerp(MainPed.Position, Position + Velocity, 0.5f);
|
||||
MainPed.Quaternion = Rotation.ToQuaternion();
|
||||
|
||||
if (!Function.Call<bool>(Hash.IS_ENTITY_PLAYING_ANIM, MainPed.Handle, "skydive@parachute@first_person", "chute_idle_right", 3))
|
||||
{
|
||||
Function.Call(Hash.TASK_PLAY_ANIM, MainPed, LoadAnim("skydive@parachute@first_person"), "chute_idle_right", 8f, 10f, -1, 0, -8f, 1, 1, 1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
if (ParachuteProp != null)
|
||||
{
|
||||
if (ParachuteProp.Exists())
|
||||
{
|
||||
ParachuteProp.Delete();
|
||||
}
|
||||
ParachuteProp = null;
|
||||
}
|
||||
|
||||
if (IsOnLadder)
|
||||
{
|
||||
if (Velocity.Z < 0)
|
||||
{
|
||||
string anim = Velocity.Z < -2f ? "slide_climb_down" : "climb_down";
|
||||
if (_currentAnimation[1] != anim)
|
||||
{
|
||||
MainPed.Task.ClearAllImmediately();
|
||||
_currentAnimation[1] = anim;
|
||||
}
|
||||
|
||||
if (!Function.Call<bool>(Hash.IS_ENTITY_PLAYING_ANIM, MainPed.Handle, "laddersbase", anim, 3))
|
||||
{
|
||||
MainPed.Task.PlayAnimation("laddersbase", anim, 8f, -1, AnimationFlags.Loop);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Math.Abs(Velocity.Z) < 0.5)
|
||||
{
|
||||
if (_currentAnimation[1] != "base_left_hand_up")
|
||||
{
|
||||
MainPed.Task.ClearAllImmediately();
|
||||
_currentAnimation[1] = "base_left_hand_up";
|
||||
}
|
||||
|
||||
if (!Function.Call<bool>(Hash.IS_ENTITY_PLAYING_ANIM, MainPed.Handle, "laddersbase", "base_left_hand_up", 3))
|
||||
{
|
||||
MainPed.Task.PlayAnimation("laddersbase", "base_left_hand_up", 8f, -1, AnimationFlags.Loop);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_currentAnimation[1] != "climb_up")
|
||||
{
|
||||
MainPed.Task.ClearAllImmediately();
|
||||
_currentAnimation[1] = "climb_up";
|
||||
}
|
||||
|
||||
if (!Function.Call<bool>(Hash.IS_ENTITY_PLAYING_ANIM, MainPed.Handle, "laddersbase", "climb_up", 3))
|
||||
{
|
||||
MainPed.Task.PlayAnimation("laddersbase", "climb_up", 8f, -1, AnimationFlags.Loop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SmoothTransition();
|
||||
return;
|
||||
}
|
||||
if (!IsOnLadder && MainPed.IsTaskActive(TaskType.CTaskGoToAndClimbLadder))
|
||||
{
|
||||
MainPed.Task.ClearAllImmediately();
|
||||
_currentAnimation[1] = "";
|
||||
}
|
||||
|
||||
if (IsVaulting)
|
||||
{
|
||||
if (!MainPed.IsVaulting)
|
||||
{
|
||||
MainPed.Task.Climb();
|
||||
}
|
||||
|
||||
SmoothTransition();
|
||||
|
||||
return;
|
||||
}
|
||||
if (!IsVaulting && MainPed.IsVaulting)
|
||||
{
|
||||
MainPed.Task.ClearAllImmediately();
|
||||
}
|
||||
|
||||
if (IsOnFire && !MainPed.IsOnFire)
|
||||
{
|
||||
|
||||
MainPed.SetOnFire(true);
|
||||
}
|
||||
else if (!IsOnFire && MainPed.IsOnFire)
|
||||
{
|
||||
MainPed.SetOnFire(false);
|
||||
}
|
||||
|
||||
if (IsJumping)
|
||||
{
|
||||
if (!_lastIsJumping)
|
||||
{
|
||||
_lastIsJumping = true;
|
||||
MainPed.Task.Jump();
|
||||
}
|
||||
|
||||
SmoothTransition();
|
||||
return;
|
||||
}
|
||||
_lastIsJumping = false;
|
||||
|
||||
if (IsRagdoll || Health==0)
|
||||
{
|
||||
if (!MainPed.IsRagdoll)
|
||||
{
|
||||
MainPed.Ragdoll();
|
||||
}
|
||||
|
||||
SmoothTransition();
|
||||
if (!_lastRagdoll)
|
||||
{
|
||||
_lastRagdoll = true;
|
||||
_lastRagdollTime=Main.Ticked;
|
||||
}
|
||||
/*
|
||||
if((Main.Ticked-_lastRagdollTime>30)&&((Position.DistanceTo(MainPed.Position)>2)||MainPed.Velocity.Length()<3f))
|
||||
{
|
||||
MainPed.ApplyForce((Position-MainPed.Position)*0.2f, (RotationVelocity-MainPed.RotationVelocity)*0.1f);
|
||||
|
||||
}*/
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (MainPed.IsRagdoll)
|
||||
{
|
||||
if (Speed==0)
|
||||
{
|
||||
MainPed.CancelRagdoll();
|
||||
}
|
||||
else
|
||||
{
|
||||
MainPed.Task.ClearAllImmediately();
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
_lastRagdoll = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (IsReloading)
|
||||
{
|
||||
if (!MainPed.IsTaskActive(TaskType.CTaskReloadGun))
|
||||
{
|
||||
MainPed.Task.ReloadWeapon();
|
||||
}
|
||||
/*
|
||||
if (!_isPlayingAnimation)
|
||||
{
|
||||
string[] reloadingAnim = MainPed.GetReloadingAnimation();
|
||||
if (reloadingAnim != null)
|
||||
{
|
||||
_isPlayingAnimation = true;
|
||||
_currentAnimation = reloadingAnim;
|
||||
MainPed.Task.PlayAnimation(_currentAnimation[0], _currentAnimation[1], 8f, -1, AnimationFlags.AllowRotation | AnimationFlags.UpperBodyOnly);
|
||||
}
|
||||
}
|
||||
*/
|
||||
SmoothTransition();
|
||||
}
|
||||
else if (IsInCover)
|
||||
{
|
||||
|
||||
|
||||
if (!_lastInCover)
|
||||
{
|
||||
Function.Call(Hash.TASK_STAY_IN_COVER, MainPed.Handle);
|
||||
}
|
||||
|
||||
_lastInCover=true;
|
||||
if (IsAiming)
|
||||
{
|
||||
DisplayAiming();
|
||||
_lastInCover=false;
|
||||
}
|
||||
else if (MainPed.IsInCover)
|
||||
{
|
||||
SmoothTransition();
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (_lastInCover)
|
||||
{
|
||||
MainPed.Task.ClearAllImmediately();
|
||||
_lastInCover=false;
|
||||
}
|
||||
else if (IsAiming)
|
||||
{
|
||||
DisplayAiming();
|
||||
}
|
||||
else if (MainPed.IsShooting)
|
||||
{
|
||||
MainPed.Task.ClearAllImmediately();
|
||||
}
|
||||
else
|
||||
{
|
||||
WalkTo();
|
||||
}
|
||||
}
|
||||
|
||||
#region WEAPON
|
||||
private void CheckCurrentWeapon()
|
||||
{
|
||||
if (MainPed.Weapons.Current.Hash != (WeaponHash)CurrentWeaponHash || !WeaponComponents.Compare(_lastWeaponComponents))
|
||||
{
|
||||
if (WeaponAsset!=null) { WeaponAsset.MarkAsNoLongerNeeded(); }
|
||||
WeaponAsset=new WeaponAsset(CurrentWeaponHash);
|
||||
if (!WeaponAsset.IsLoaded) { WeaponAsset.Request(); }
|
||||
MainPed.Weapons.RemoveAll();
|
||||
_lastWeaponObj = Function.Call<int>(Hash.CREATE_WEAPON_OBJECT, CurrentWeaponHash, -1, Position.X, Position.Y, Position.Z, true, 0, 0);
|
||||
|
||||
if (CurrentWeaponHash != (uint)WeaponHash.Unarmed)
|
||||
{
|
||||
if (WeaponComponents != null && WeaponComponents.Count != 0)
|
||||
{
|
||||
foreach (KeyValuePair<uint, bool> comp in WeaponComponents)
|
||||
{
|
||||
|
||||
if (comp.Value)
|
||||
{
|
||||
Function.Call(Hash.GIVE_WEAPON_COMPONENT_TO_WEAPON_OBJECT, _lastWeaponObj, comp.Key);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Function.Call(Hash.GIVE_WEAPON_OBJECT_TO_PED, _lastWeaponObj, MainPed.Handle);
|
||||
|
||||
}
|
||||
_lastWeaponComponents = WeaponComponents;
|
||||
}
|
||||
if (Function.Call<int>(Hash.GET_PED_WEAPON_TINT_INDEX,MainPed,CurrentWeaponHash)!=WeaponTint)
|
||||
{
|
||||
Function.Call<int>(Hash.SET_PED_WEAPON_TINT_INDEX, MainPed, CurrentWeaponHash, WeaponTint);
|
||||
}
|
||||
}
|
||||
|
||||
private void DisplayAiming()
|
||||
{
|
||||
if (Velocity==default)
|
||||
{
|
||||
MainPed.Task.AimAt(AimCoords,1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
Function.Call(Hash.TASK_GO_TO_COORD_WHILE_AIMING_AT_COORD, MainPed.Handle,
|
||||
Position.X+Velocity.X, Position.Y+Velocity.Y, Position.Z+Velocity.Z,
|
||||
AimCoords.X, AimCoords.Y, AimCoords.Z, 3f, false, 0x3F000000, 0x40800000, false, 512, false, 0);
|
||||
|
||||
}
|
||||
SmoothTransition();
|
||||
}
|
||||
#endregion
|
||||
|
||||
private bool LastMoving;
|
||||
private void WalkTo()
|
||||
{
|
||||
Vector3 predictPosition = Position + (Position - MainPed.Position) + Velocity * 0.5f;
|
||||
float range = predictPosition.DistanceToSquared(MainPed.Position);
|
||||
|
||||
switch (Speed)
|
||||
{
|
||||
case 1:
|
||||
if (!MainPed.IsWalking || range > 0.25f)
|
||||
{
|
||||
float nrange = range * 2;
|
||||
if (nrange > 1.0f)
|
||||
{
|
||||
nrange = 1.0f;
|
||||
}
|
||||
|
||||
MainPed.Task.GoStraightTo(predictPosition);
|
||||
Function.Call(Hash.SET_PED_DESIRED_MOVE_BLEND_RATIO, MainPed.Handle, nrange);
|
||||
}
|
||||
LastMoving = true;
|
||||
break;
|
||||
case 2:
|
||||
if (!MainPed.IsRunning || range > 0.50f)
|
||||
{
|
||||
MainPed.Task.RunTo(predictPosition, true);
|
||||
Function.Call(Hash.SET_PED_DESIRED_MOVE_BLEND_RATIO, MainPed.Handle, 1.0f);
|
||||
}
|
||||
LastMoving = true;
|
||||
break;
|
||||
case 3:
|
||||
if (!MainPed.IsSprinting || range > 0.75f)
|
||||
{
|
||||
Function.Call(Hash.TASK_GO_STRAIGHT_TO_COORD, MainPed.Handle, predictPosition.X, predictPosition.Y, predictPosition.Z, 3.0f, -1, 0.0f, 0.0f);
|
||||
Function.Call(Hash.SET_RUN_SPRINT_MULTIPLIER_FOR_PLAYER, MainPed.Handle, 1.49f);
|
||||
Function.Call(Hash.SET_PED_DESIRED_MOVE_BLEND_RATIO, MainPed.Handle, 1.0f);
|
||||
}
|
||||
LastMoving = true;
|
||||
break;
|
||||
default:
|
||||
if (LastMoving)
|
||||
{
|
||||
MainPed.Task.StandStill(2000);
|
||||
LastMoving = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
SmoothTransition();
|
||||
}
|
||||
|
||||
private void SmoothTransition()
|
||||
{
|
||||
var localRagdoll = MainPed.IsRagdoll;
|
||||
var dist = Position.DistanceTo(MainPed.Position);
|
||||
if (dist>3)
|
||||
{
|
||||
MainPed.PositionNoOffset=Position;
|
||||
return;
|
||||
}
|
||||
var f = dist*(Position+SyncParameters.PositioinPredictionDefault*Velocity-MainPed.Position)+(Velocity-MainPed.Velocity)*0.2f;
|
||||
if (!localRagdoll) { f*=5; }
|
||||
if (!(localRagdoll|| MainPed.IsDead))
|
||||
{
|
||||
MainPed.Rotation=Rotation;
|
||||
if (MainPed.Speed<0.05) { f*=10; MainPed.Heading=Heading; }
|
||||
}
|
||||
else if (Main.Ticked-_lastRagdollTime<10)
|
||||
{
|
||||
return;
|
||||
}
|
||||
MainPed.ApplyForce(f);
|
||||
}
|
||||
private string LoadAnim(string anim)
|
||||
{
|
||||
ulong startTime = Util.GetTickCount64();
|
||||
|
||||
while (!Function.Call<bool>(Hash.HAS_ANIM_DICT_LOADED, anim))
|
||||
{
|
||||
Script.Yield();
|
||||
Function.Call(Hash.REQUEST_ANIM_DICT, anim);
|
||||
if (Util.GetTickCount64() - startTime >= 1000)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return anim;
|
||||
}
|
||||
#endregion
|
||||
|
||||
private void DisplayInVehicle()
|
||||
{
|
||||
if (MainPed.IsOnTurretSeat())
|
||||
{
|
||||
Function.Call(Hash.SET_VEHICLE_TURRET_SPEED_THIS_FRAME, MainPed.CurrentVehicle, 100);
|
||||
Function.Call(Hash.TASK_VEHICLE_AIM_AT_COORD, MainPed.Handle, AimCoords.X, AimCoords.Y, AimCoords.Z);
|
||||
}
|
||||
/*
|
||||
Function.Call(Hash.TASK_SWEEP_AIM_ENTITY,P, "random@paparazzi@pap_anims", "sweep_low", "sweep_med", "sweep_high", -1,V, 1.57f, 0.25f);
|
||||
Function.Call(Hash.SET_PED_STEALTH_MOVEMENT, P,true, 0);
|
||||
return Function.Call<bool>(Hash.GET_PED_STEALTH_MOVEMENT, P);
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
@ -1,98 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
using RageCoop.Core;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal class SyncedProjectile : SyncedEntity
|
||||
{
|
||||
public SyncedProjectile(Projectile p)
|
||||
{
|
||||
ID=EntityPool.RequestNewID();
|
||||
MainProjectile = p;
|
||||
Origin=p.Position;
|
||||
var shooter = EntityPool.GetPedByHandle((p.Owner?.Handle).GetValueOrDefault());
|
||||
if (shooter==null)
|
||||
{
|
||||
// Owner will be the vehicle if projectile is shot with a vehicle
|
||||
var shooterVeh = EntityPool.GetVehicleByHandle((p.Owner?.Handle).GetValueOrDefault());
|
||||
if (shooterVeh!=null && shooterVeh.MainVehicle.Driver!=null)
|
||||
{
|
||||
shooter=shooterVeh.MainVehicle.Driver?.GetSyncEntity();
|
||||
}
|
||||
else
|
||||
{
|
||||
Main.Logger.Warning($"Could not find owner for projectile:{Hash}");
|
||||
}
|
||||
}
|
||||
if(shooter != null)
|
||||
{
|
||||
if (shooter.MainPed!=null && (p.AttachedEntity==shooter.MainPed.Weapons.CurrentWeaponObject || p.AttachedEntity== shooter.MainPed))
|
||||
{
|
||||
// Reloading
|
||||
IsValid=false;
|
||||
}
|
||||
ShooterID=shooter.ID;
|
||||
IsLocal=shooter.IsLocal;
|
||||
}
|
||||
|
||||
}
|
||||
public SyncedProjectile(int id)
|
||||
{
|
||||
ID= id;
|
||||
IsLocal=false;
|
||||
}
|
||||
public bool IsValid { get; private set; } = true;
|
||||
public new bool IsLocal { get; private set; } = false;
|
||||
public bool Exploded { get; set; } = false;
|
||||
public Projectile MainProjectile { get; set; }
|
||||
public int ShooterID { get; set; }
|
||||
private SyncedPed Shooter { get;set; }
|
||||
public Vector3 Origin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Invalid property for projectile.
|
||||
/// </summary>
|
||||
private new int OwnerID{ set { } }
|
||||
public WeaponHash Hash { get; set; }
|
||||
private WeaponAsset Asset { get; set; }
|
||||
internal override void Update()
|
||||
{
|
||||
|
||||
// Skip update if no new sync message has arrived.
|
||||
if (!NeedUpdate){ return; }
|
||||
|
||||
if (MainProjectile == null || !MainProjectile.Exists())
|
||||
{
|
||||
CreateProjectile();
|
||||
return;
|
||||
}
|
||||
MainProjectile.Velocity=Velocity+(Position+Networking.Latency*Velocity-MainProjectile.Position);
|
||||
MainProjectile.Rotation=Rotation;
|
||||
LastUpdated=Main.Ticked;
|
||||
}
|
||||
|
||||
private void CreateProjectile()
|
||||
{
|
||||
Asset=new WeaponAsset(Hash);
|
||||
if (!Asset.IsLoaded) { Asset.Request(); }
|
||||
World.ShootBullet(Position,Position+Velocity,(Shooter=EntityPool.GetPedByID(ShooterID))?.MainPed,Asset,0);
|
||||
var ps = World.GetAllProjectiles();
|
||||
MainProjectile=ps[ps.Length-1];
|
||||
if (Hash==(WeaponHash)VehicleWeaponHash.Tank)
|
||||
{
|
||||
var v = Shooter?.MainPed?.CurrentVehicle;
|
||||
if (v!=null)
|
||||
{
|
||||
World.CreateParticleEffectNonLooped(SyncEvents.CorePFXAsset, "muz_tank", v.GetMuzzleInfo().Position, v.Bones[35].ForwardVector.ToEulerRotation(v.Bones[35].UpVector), 1);
|
||||
}
|
||||
}
|
||||
EntityPool.Add(this);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using GTA.Native;
|
||||
using GTA;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// Synchronized prop, mostly owned by server
|
||||
/// </summary>
|
||||
public class SyncedProp : SyncedEntity
|
||||
{
|
||||
internal SyncedProp(int id)
|
||||
{
|
||||
ID= id;
|
||||
}
|
||||
/// <summary>
|
||||
/// The real entity
|
||||
/// </summary>
|
||||
public Prop MainProp { get; set; }
|
||||
internal new int OwnerID { get
|
||||
{
|
||||
// alwayse owned by server
|
||||
return 0;
|
||||
} }
|
||||
internal override void Update()
|
||||
{
|
||||
|
||||
if (!NeedUpdate) { return; }
|
||||
if (MainProp== null || !MainProp.Exists())
|
||||
{
|
||||
MainProp=World.CreateProp(Model,Position,Rotation,false,false);
|
||||
MainProp.IsInvincible=true;
|
||||
}
|
||||
MainProp.Position=Position;
|
||||
MainProp.Rotation=Rotation;
|
||||
MainProp.SetFrozen(true);
|
||||
LastUpdated=Main.Ticked;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,433 +0,0 @@
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using GTA;
|
||||
using GTA.Native;
|
||||
using GTA.Math;
|
||||
using RageCoop.Core;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// A synchronized vehicle instance
|
||||
/// </summary>
|
||||
public class SyncedVehicle : SyncedEntity
|
||||
{
|
||||
|
||||
#region -- CONSTRUCTORS --
|
||||
|
||||
/// <summary>
|
||||
/// Create a local entity (outgoing sync)
|
||||
/// </summary>
|
||||
/// <param name="v"></param>
|
||||
internal SyncedVehicle(Vehicle v)
|
||||
{
|
||||
|
||||
ID=EntityPool.RequestNewID();
|
||||
MainVehicle=v;
|
||||
MainVehicle.CanPretendOccupants=false;
|
||||
OwnerID=Main.LocalPlayerID;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an empty VehicleEntity
|
||||
/// </summary>
|
||||
internal SyncedVehicle()
|
||||
{
|
||||
|
||||
}
|
||||
internal SyncedVehicle(int id)
|
||||
{
|
||||
ID=id;
|
||||
LastSynced=Main.Ticked;
|
||||
}
|
||||
#endregion
|
||||
/// <summary>
|
||||
/// VehicleSeat,ID
|
||||
/// </summary>
|
||||
public Vehicle MainVehicle { get;internal set; }
|
||||
|
||||
|
||||
#region LAST STATE
|
||||
|
||||
|
||||
private byte[] _lastVehicleColors = new byte[] { 0, 0 };
|
||||
private Dictionary<int, int> _lastVehicleMods = new Dictionary<int, int>();
|
||||
|
||||
#endregion
|
||||
|
||||
#region -- CRITICAL STUFF --
|
||||
internal Vector3 RotationVelocity { get; set; }
|
||||
internal float SteeringAngle { get; set; }
|
||||
internal float ThrottlePower { get; set; }
|
||||
internal float BrakePower { get; set; }
|
||||
internal float DeluxoWingRatio { get; set; } = -1;
|
||||
internal bool IsFlipped
|
||||
{
|
||||
get
|
||||
{
|
||||
return (Quaternion*Vector3.RelativeTop).Z <(Quaternion*Vector3.RelativeBottom).Z;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region -- VEHICLE STATE --
|
||||
internal VehicleDataFlags Flags { get; set; }
|
||||
internal bool EngineRunning { get; set; }
|
||||
private bool _lastTransformed = false;
|
||||
internal bool Transformed { get; set; }
|
||||
private bool _lastHornActive = false;
|
||||
internal bool HornActive { get; set; }
|
||||
internal bool LightsOn { get; set; }
|
||||
internal bool BrakeLightsOn { get; set; } = false;
|
||||
internal bool HighBeamsOn { get; set; }
|
||||
internal byte LandingGear { get; set; }
|
||||
internal VehicleRoofState RoofState { get; set; }
|
||||
internal bool SireneActive { get; set; }
|
||||
internal VehicleDamageModel DamageModel { get; set; }
|
||||
internal byte[] Colors { get; set; }
|
||||
internal Dictionary<int, int> Mods { get; set; }
|
||||
internal bool IsDead { get; set; }
|
||||
internal float EngineHealth { get; set; }
|
||||
internal VehicleLockStatus LockStatus{get;set;}
|
||||
/// <summary>
|
||||
/// VehicleSeat,PedID
|
||||
/// </summary>
|
||||
internal Dictionary<VehicleSeat, SyncedPed> Passengers { get; set; }
|
||||
internal byte RadioStation = 255;
|
||||
internal string LicensePlate { get; set; }
|
||||
internal int _lastLivery = -1;
|
||||
internal int Livery { get; set; } = -1;
|
||||
internal bool _checkSeat { get; set; } = true;
|
||||
|
||||
#endregion
|
||||
internal override void Update()
|
||||
{
|
||||
|
||||
#region -- INITIAL CHECK --
|
||||
|
||||
// Check if all data avalible
|
||||
if(!IsReady) { return; }
|
||||
// Skip update if no new sync message has arrived.
|
||||
if (!NeedUpdate) { return; }
|
||||
#endregion
|
||||
#region -- CHECK EXISTENCE --
|
||||
if ((MainVehicle == null) || (!MainVehicle.Exists()) || (MainVehicle.Model.Hash != Model))
|
||||
{
|
||||
if (!CreateVehicle())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region -- SYNC CRITICAL --
|
||||
if (SteeringAngle != MainVehicle.SteeringAngle)
|
||||
{
|
||||
MainVehicle.CustomSteeringAngle((float)(Math.PI / 180) * SteeringAngle);
|
||||
}
|
||||
MainVehicle.ThrottlePower=ThrottlePower;
|
||||
MainVehicle.BrakePower=BrakePower;
|
||||
|
||||
if (MainVehicle.Position.DistanceTo(Position)<5)
|
||||
{
|
||||
MainVehicle.Velocity = Velocity+5*(Position+Velocity*SyncParameters.PositioinPredictionDefault - MainVehicle.Position);
|
||||
if (IsFlipped)
|
||||
{
|
||||
MainVehicle.Quaternion=Quaternion.Slerp(MainVehicle.Quaternion, Quaternion, 0.5f);
|
||||
MainVehicle.RotationVelocity=RotationVelocity;
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector3 cali = GetCalibrationRotation();
|
||||
if (cali.Length()<50)
|
||||
{
|
||||
MainVehicle.RotationVelocity = RotationVelocity+cali*0.2f;
|
||||
}
|
||||
else
|
||||
{
|
||||
MainVehicle.Quaternion=Quaternion;
|
||||
MainVehicle.RotationVelocity=RotationVelocity;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MainVehicle.Position=Position;
|
||||
MainVehicle.Velocity=Velocity;
|
||||
MainVehicle.Quaternion=Quaternion;
|
||||
}
|
||||
if (DeluxoWingRatio!=-1)
|
||||
{
|
||||
MainVehicle.SetDeluxoWingRatio(DeluxoWingRatio);
|
||||
}
|
||||
#endregion
|
||||
if (LastStateSynced>LastUpdated)
|
||||
{
|
||||
#region -- SYNC STATE --
|
||||
#region -- PASSENGER SYNC --
|
||||
|
||||
// check passengers (and driver).
|
||||
if (_checkSeat)
|
||||
{
|
||||
|
||||
var currentPassengers = MainVehicle.GetPassengers();
|
||||
|
||||
lock (Passengers)
|
||||
{
|
||||
for (int i = -1; i<MainVehicle.PassengerCapacity; i++)
|
||||
{
|
||||
VehicleSeat seat = (VehicleSeat)i;
|
||||
if (Passengers.ContainsKey(seat))
|
||||
{
|
||||
|
||||
SyncedPed c = Passengers[seat];
|
||||
if (c?.ID==Main.LocalPlayerID && (RadioStation!=Function.Call<int>(Hash.GET_PLAYER_RADIO_STATION_INDEX)))
|
||||
{
|
||||
Util.SetPlayerRadioIndex(RadioStation);
|
||||
}
|
||||
if (c?.MainPed!=null&&(!currentPassengers.ContainsKey(i))&&(!c.MainPed.IsBeingJacked)&&(!c.MainPed.IsTaskActive(TaskType.CTaskExitVehicleSeat)))
|
||||
{
|
||||
Passengers[seat].MainPed.SetIntoVehicle(MainVehicle, seat);
|
||||
}
|
||||
}
|
||||
else if (!MainVehicle.IsSeatFree(seat))
|
||||
{
|
||||
var p = MainVehicle.Occupants.Where(x => x.SeatIndex==seat).FirstOrDefault();
|
||||
if ((p!=null)&& !p.IsTaskActive(TaskType.CTaskLeaveAnyCar))
|
||||
{
|
||||
p.Task.WarpOutOfVehicle(MainVehicle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
if (Colors != null && Colors != _lastVehicleColors)
|
||||
{
|
||||
Function.Call(Hash.SET_VEHICLE_COLOURS, MainVehicle, Colors[0], Colors[1]);
|
||||
|
||||
_lastVehicleColors = Colors;
|
||||
}
|
||||
MainVehicle.EngineHealth=EngineHealth;
|
||||
if (Mods != null && !Mods.Compare(_lastVehicleMods))
|
||||
{
|
||||
Function.Call(Hash.SET_VEHICLE_MOD_KIT, MainVehicle, 0);
|
||||
|
||||
foreach (KeyValuePair<int, int> mod in Mods)
|
||||
{
|
||||
MainVehicle.Mods[(VehicleModType)mod.Key].Index = mod.Value;
|
||||
}
|
||||
|
||||
_lastVehicleMods = Mods;
|
||||
}
|
||||
|
||||
|
||||
if (IsDead)
|
||||
{
|
||||
if (MainVehicle.IsDead)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
MainVehicle.Explode();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (MainVehicle.IsDead)
|
||||
{
|
||||
MainVehicle.Repair();
|
||||
}
|
||||
}
|
||||
|
||||
if (EngineRunning != MainVehicle.IsEngineRunning)
|
||||
{
|
||||
MainVehicle.IsEngineRunning = EngineRunning;
|
||||
}
|
||||
|
||||
if (LightsOn != MainVehicle.AreLightsOn)
|
||||
{
|
||||
MainVehicle.AreLightsOn = LightsOn;
|
||||
}
|
||||
|
||||
if (HighBeamsOn != MainVehicle.AreHighBeamsOn)
|
||||
{
|
||||
MainVehicle.AreHighBeamsOn = HighBeamsOn;
|
||||
}
|
||||
|
||||
if (MainVehicle.IsSubmarineCar)
|
||||
{
|
||||
if (Transformed)
|
||||
{
|
||||
if (!_lastTransformed)
|
||||
{
|
||||
_lastTransformed = true;
|
||||
Function.Call(Hash._TRANSFORM_VEHICLE_TO_SUBMARINE, MainVehicle.Handle, false);
|
||||
}
|
||||
}
|
||||
else if (_lastTransformed)
|
||||
{
|
||||
_lastTransformed = false;
|
||||
Function.Call(Hash._TRANSFORM_SUBMARINE_TO_VEHICLE, MainVehicle.Handle, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (MainVehicle.IsAircraft)
|
||||
{
|
||||
if (LandingGear != (byte)MainVehicle.LandingGearState)
|
||||
{
|
||||
MainVehicle.LandingGearState = (VehicleLandingGearState)LandingGear;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (MainVehicle.HasSiren && SireneActive != MainVehicle.IsSirenActive)
|
||||
{
|
||||
MainVehicle.IsSirenActive = SireneActive;
|
||||
}
|
||||
|
||||
if (HornActive)
|
||||
{
|
||||
if (!_lastHornActive)
|
||||
{
|
||||
_lastHornActive = true;
|
||||
MainVehicle.SoundHorn(99999);
|
||||
}
|
||||
}
|
||||
else if (_lastHornActive)
|
||||
{
|
||||
_lastHornActive = false;
|
||||
MainVehicle.SoundHorn(1);
|
||||
}
|
||||
|
||||
if (MainVehicle.HasRoof && MainVehicle.RoofState!=RoofState)
|
||||
{
|
||||
MainVehicle.RoofState=RoofState;
|
||||
}
|
||||
|
||||
Function.Call(Hash.SET_VEHICLE_BRAKE_LIGHTS, MainVehicle.Handle, BrakeLightsOn);
|
||||
MainVehicle.SetDamageModel(DamageModel);
|
||||
|
||||
}
|
||||
MainVehicle.LockStatus=LockStatus;
|
||||
if (Flags.HasVehFlag(VehicleDataFlags.IsDeluxoHovering))
|
||||
{
|
||||
if (!MainVehicle.IsDeluxoHovering())
|
||||
{
|
||||
MainVehicle.SetDeluxoHoverState(true);
|
||||
}
|
||||
}
|
||||
else if(Model==1483171323)
|
||||
{
|
||||
if (MainVehicle.IsDeluxoHovering())
|
||||
{
|
||||
MainVehicle.SetDeluxoHoverState(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (Function.Call<string>(Hash.GET_VEHICLE_NUMBER_PLATE_TEXT, MainVehicle)!=LicensePlate)
|
||||
{
|
||||
Function.Call(Hash.SET_VEHICLE_NUMBER_PLATE_TEXT,MainVehicle,LicensePlate);
|
||||
}
|
||||
|
||||
if (_lastLivery!=Livery)
|
||||
{
|
||||
Function.Call(Hash.SET_VEHICLE_LIVERY, MainVehicle, Livery);
|
||||
_lastLivery=Livery;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
LastUpdated=Main.Ticked;
|
||||
}
|
||||
private Vector3 GetCalibrationRotation()
|
||||
{
|
||||
var rot=Quaternion.LookRotation(Quaternion*Vector3.RelativeFront, Quaternion*Vector3.RelativeTop).ToEulerAngles();
|
||||
var curRot=Quaternion.LookRotation(MainVehicle.Quaternion*Vector3.RelativeFront, MainVehicle.Quaternion*Vector3.RelativeTop).ToEulerAngles();
|
||||
|
||||
var r = (rot-curRot).ToDegree();
|
||||
if (r.X>180) { r.X=r.X-360; }
|
||||
else if(r.X<-180) { r.X=360+r.X; }
|
||||
|
||||
if (r.Y>180) { r.Y=r.Y-360; }
|
||||
else if (r.Y<-180) { r.Y=360+r.Y; }
|
||||
|
||||
if (r.Z>180) { r.Z=r.Z-360; }
|
||||
else if (r.Z<-180) { r.Z=360+r.Z; }
|
||||
return r;
|
||||
|
||||
}
|
||||
private bool CreateVehicle()
|
||||
{
|
||||
MainVehicle?.Delete();
|
||||
MainVehicle = Util.CreateVehicle(Model, Position);
|
||||
if (!Model.IsInCdImage)
|
||||
{
|
||||
// GTA.UI.Notification.Show($"~r~(Vehicle)Model ({CurrentVehicleModelHash}) cannot be loaded!");
|
||||
return false;
|
||||
}
|
||||
else if (MainVehicle==null)
|
||||
{
|
||||
Model.Request();
|
||||
return false;
|
||||
}
|
||||
lock (EntityPool.VehiclesLock)
|
||||
{
|
||||
EntityPool.Add(this);
|
||||
}
|
||||
MainVehicle.Quaternion = Quaternion;
|
||||
if (MainVehicle.HasRoof)
|
||||
{
|
||||
MainVehicle.RoofState=RoofState;
|
||||
}
|
||||
if (IsInvincible) { MainVehicle.IsInvincible=true; }
|
||||
Model.MarkAsNoLongerNeeded();
|
||||
return true;
|
||||
}
|
||||
#region -- PEDALING --
|
||||
/*
|
||||
* Thanks to @oldnapalm.
|
||||
*/
|
||||
|
||||
private string PedalingAnimDict()
|
||||
{
|
||||
switch ((VehicleHash)Model)
|
||||
{
|
||||
case VehicleHash.Bmx:
|
||||
return "veh@bicycle@bmx@front@base";
|
||||
case VehicleHash.Cruiser:
|
||||
return "veh@bicycle@cruiserfront@base";
|
||||
case VehicleHash.Scorcher:
|
||||
return "veh@bicycle@mountainfront@base";
|
||||
default:
|
||||
return "veh@bicycle@roadfront@base";
|
||||
}
|
||||
}
|
||||
|
||||
private string PedalingAnimName(bool fast)
|
||||
{
|
||||
return fast ? "fast_pedal_char" : "cruise_pedal_char";
|
||||
}
|
||||
|
||||
private void StartPedalingAnim(bool fast)
|
||||
{
|
||||
MainVehicle.Driver?.Task.PlayAnimation(PedalingAnimDict(), PedalingAnimName(fast), 8.0f, -8.0f, -1, AnimationFlags.Loop | AnimationFlags.AllowRotation, 1.0f);
|
||||
|
||||
}
|
||||
|
||||
private void StopPedalingAnim(bool fast)
|
||||
{
|
||||
MainVehicle.Driver.Task.ClearAnimation(PedalingAnimDict(), PedalingAnimName(fast));
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region OUTGOING
|
||||
internal float LastNozzleAngle { get; set; }
|
||||
#endregion
|
||||
}
|
||||
|
||||
}
|
@ -1,654 +0,0 @@
|
||||
|
||||
using System;
|
||||
using GTA;
|
||||
using GTA.Native;
|
||||
using RageCoop.Core;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using RageCoop.Client.Scripting;
|
||||
using System.Text;
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal class EntityPool
|
||||
{
|
||||
private static bool _trafficSpawning=true;
|
||||
public static object PedsLock = new object();
|
||||
private static Dictionary<int, SyncedPed> ID_Peds = new Dictionary<int, SyncedPed>();
|
||||
public static int CharactersCount { get { return ID_Peds.Count; } }
|
||||
#if BENCHMARK
|
||||
private static Stopwatch PerfCounter=new Stopwatch();
|
||||
private static Stopwatch PerfCounter2=Stopwatch.StartNew();
|
||||
#endif
|
||||
/// <summary>
|
||||
/// Faster access to Character with Handle, but values may not equal to <see cref="ID_Peds"/> since Ped might not have been created.
|
||||
/// </summary>
|
||||
private static Dictionary<int, SyncedPed> Handle_Peds = new Dictionary<int, SyncedPed>();
|
||||
|
||||
|
||||
public static object VehiclesLock = new object();
|
||||
private static Dictionary<int, SyncedVehicle> ID_Vehicles = new Dictionary<int, SyncedVehicle>();
|
||||
private static Dictionary<int, SyncedVehicle> Handle_Vehicles = new Dictionary<int, SyncedVehicle>();
|
||||
|
||||
public static object ProjectilesLock = new object();
|
||||
private static Dictionary<int, SyncedProjectile> ID_Projectiles = new Dictionary<int, SyncedProjectile>();
|
||||
private static Dictionary<int, SyncedProjectile> Handle_Projectiles = new Dictionary<int, SyncedProjectile>();
|
||||
|
||||
public static object PropsLock=new object();
|
||||
public static Dictionary<int,SyncedProp> ServerProps=new Dictionary<int,SyncedProp>();
|
||||
|
||||
public static object BlipsLock = new object();
|
||||
public static Dictionary<int, Blip> ServerBlips = new Dictionary<int, Blip>();
|
||||
|
||||
|
||||
public static void Cleanup(bool keepPlayer=true,bool keepMine=true)
|
||||
{
|
||||
foreach(int id in new List<int>(ID_Peds.Keys))
|
||||
{
|
||||
if (keepPlayer&&(id==Main.LocalPlayerID)) { continue; }
|
||||
if (keepMine&&(ID_Peds[id].OwnerID==Main.LocalPlayerID)) { continue; }
|
||||
RemovePed(id);
|
||||
}
|
||||
ID_Peds.Clear();
|
||||
Handle_Peds.Clear();
|
||||
|
||||
foreach (int id in new List<int>(ID_Vehicles.Keys))
|
||||
{
|
||||
if (keepMine&&(ID_Vehicles[id].OwnerID==Main.LocalPlayerID)) { continue; }
|
||||
RemoveVehicle(id);
|
||||
}
|
||||
ID_Vehicles.Clear();
|
||||
Handle_Vehicles.Clear();
|
||||
|
||||
foreach(var p in ID_Projectiles.Values)
|
||||
{
|
||||
if (p.ShooterID!=Main.LocalPlayerID && p.MainProjectile!=null && p.MainProjectile.Exists())
|
||||
{
|
||||
p.MainProjectile.Delete();
|
||||
}
|
||||
}
|
||||
ID_Projectiles.Clear();
|
||||
Handle_Projectiles.Clear();
|
||||
|
||||
foreach(var p in ServerProps.Values)
|
||||
{
|
||||
p?.MainProp?.Delete();
|
||||
}
|
||||
ServerProps.Clear();
|
||||
|
||||
foreach(var b in ServerBlips.Values)
|
||||
{
|
||||
if (b.Exists())
|
||||
{
|
||||
b.Delete();
|
||||
}
|
||||
}
|
||||
ServerBlips.Clear();
|
||||
}
|
||||
|
||||
#region PEDS
|
||||
public static SyncedPed GetPedByID(int id)
|
||||
{
|
||||
return ID_Peds.ContainsKey(id) ? ID_Peds[id] : null;
|
||||
}
|
||||
public static SyncedPed GetPedByHandle(int handle)
|
||||
{
|
||||
return Handle_Peds.ContainsKey(handle) ? Handle_Peds[handle] : null;
|
||||
}
|
||||
public static List<int> GetPedIDs()
|
||||
{
|
||||
return new List<int>(ID_Peds.Keys);
|
||||
}
|
||||
public static bool AddPlayer()
|
||||
{
|
||||
Ped p = Game.Player.Character;
|
||||
SyncedPed player = GetPedByID(Main.LocalPlayerID);
|
||||
if (player!=null)
|
||||
{
|
||||
if (player.MainPed!=p)
|
||||
{
|
||||
// Player model changed
|
||||
player.MainPed = p;
|
||||
|
||||
// Remove it from Handle_Characters
|
||||
var pairs=Handle_Peds.Where(x=>x.Value==player);
|
||||
if (pairs.Any())
|
||||
{
|
||||
var pair=pairs.First();
|
||||
|
||||
// Re-add
|
||||
Handle_Peds.Remove(pair.Key);
|
||||
if (Handle_Peds.ContainsKey(p.Handle))
|
||||
{
|
||||
RemovePed(Handle_Peds[p.Handle].ID);
|
||||
}
|
||||
Handle_Peds.Add(p.Handle, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Main.Logger.Debug($"Creating SyncEntity for player, handle:{p.Handle}");
|
||||
SyncedPed c = new SyncedPed(p);
|
||||
Main.LocalPlayerID=c.OwnerID=c.ID;
|
||||
Add(c);
|
||||
Main.Logger.Debug($"Local player ID is:{c.ID}");
|
||||
PlayerList.SetPlayer(c.ID, Main.Settings.Username );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public static void Add(SyncedPed c)
|
||||
{
|
||||
if (ID_Peds.ContainsKey(c.ID))
|
||||
{
|
||||
ID_Peds[c.ID]=c;
|
||||
}
|
||||
else
|
||||
{
|
||||
ID_Peds.Add(c.ID, c);
|
||||
}
|
||||
if (c.MainPed==null) { return; }
|
||||
if (Handle_Peds.ContainsKey(c.MainPed.Handle))
|
||||
{
|
||||
Handle_Peds[c.MainPed.Handle]=c;
|
||||
}
|
||||
else
|
||||
{
|
||||
Handle_Peds.Add(c.MainPed.Handle, c);
|
||||
}
|
||||
if (c.IsLocal)
|
||||
{
|
||||
API.Events.InvokePedSpawned(c);
|
||||
}
|
||||
}
|
||||
public static void RemovePed(int id,string reason="Cleanup")
|
||||
{
|
||||
if (ID_Peds.ContainsKey(id))
|
||||
{
|
||||
SyncedPed c = ID_Peds[id];
|
||||
var p = c.MainPed;
|
||||
if (p!=null)
|
||||
{
|
||||
if (Handle_Peds.ContainsKey(p.Handle))
|
||||
{
|
||||
Handle_Peds.Remove(p.Handle);
|
||||
}
|
||||
// Main.Logger.Debug($"Removing ped {c.ID}. Reason:{reason}");
|
||||
p.AttachedBlip?.Delete();
|
||||
p.Kill();
|
||||
p.MarkAsNoLongerNeeded();
|
||||
p.Delete();
|
||||
}
|
||||
c.PedBlip?.Delete();
|
||||
c.ParachuteProp?.Delete();
|
||||
ID_Peds.Remove(id);
|
||||
if (c.IsLocal)
|
||||
{
|
||||
API.Events.InvokePedDeleted(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region VEHICLES
|
||||
public static SyncedVehicle GetVehicleByID(int id)
|
||||
{
|
||||
return ID_Vehicles.ContainsKey(id) ? ID_Vehicles[id] : null;
|
||||
}
|
||||
public static SyncedVehicle GetVehicleByHandle(int handle)
|
||||
{
|
||||
return Handle_Vehicles.ContainsKey(handle) ? Handle_Vehicles[handle] : null;
|
||||
}
|
||||
public static List<int> GetVehicleIDs()
|
||||
{
|
||||
return new List<int>(ID_Vehicles.Keys);
|
||||
}
|
||||
public static void Add(SyncedVehicle v)
|
||||
{
|
||||
if (ID_Vehicles.ContainsKey(v.ID))
|
||||
{
|
||||
ID_Vehicles[v.ID]=v;
|
||||
}
|
||||
else
|
||||
{
|
||||
ID_Vehicles.Add(v.ID, v);
|
||||
}
|
||||
if (v.MainVehicle==null) { return; }
|
||||
if (Handle_Vehicles.ContainsKey(v.MainVehicle.Handle))
|
||||
{
|
||||
Handle_Vehicles[v.MainVehicle.Handle]=v;
|
||||
}
|
||||
else
|
||||
{
|
||||
Handle_Vehicles.Add(v.MainVehicle.Handle, v);
|
||||
}
|
||||
if (v.IsLocal)
|
||||
{
|
||||
API.Events.InvokeVehicleSpawned(v);
|
||||
}
|
||||
}
|
||||
public static void RemoveVehicle(int id,string reason = "Cleanup")
|
||||
{
|
||||
if (ID_Vehicles.ContainsKey(id))
|
||||
{
|
||||
SyncedVehicle v = ID_Vehicles[id];
|
||||
var veh = v.MainVehicle;
|
||||
if (veh!=null)
|
||||
{
|
||||
if (Handle_Vehicles.ContainsKey(veh.Handle))
|
||||
{
|
||||
Handle_Vehicles.Remove(veh.Handle);
|
||||
}
|
||||
// Main.Logger.Debug($"Removing vehicle {v.ID}. Reason:{reason}");
|
||||
veh.AttachedBlip?.Delete();
|
||||
veh.MarkAsNoLongerNeeded();
|
||||
veh.Delete();
|
||||
}
|
||||
ID_Vehicles.Remove(id);
|
||||
if (v.IsLocal) { API.Events.InvokeVehicleDeleted(v); }
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region PROJECTILES
|
||||
public static SyncedProjectile GetProjectileByID(int id)
|
||||
{
|
||||
return ID_Projectiles.ContainsKey(id) ? ID_Projectiles[id] : null;
|
||||
}
|
||||
public static void Add(SyncedProjectile p)
|
||||
{
|
||||
if (!p.IsValid) { return; }
|
||||
if (ID_Projectiles.ContainsKey(p.ID))
|
||||
{
|
||||
ID_Projectiles[p.ID]=p;
|
||||
}
|
||||
else
|
||||
{
|
||||
ID_Projectiles.Add(p.ID, p);
|
||||
}
|
||||
if (p.MainProjectile==null) { return; }
|
||||
if (Handle_Projectiles.ContainsKey(p.MainProjectile.Handle))
|
||||
{
|
||||
Handle_Projectiles[p.MainProjectile.Handle]=p;
|
||||
}
|
||||
else
|
||||
{
|
||||
Handle_Projectiles.Add(p.MainProjectile.Handle, p);
|
||||
}
|
||||
}
|
||||
public static void RemoveProjectile(int id, string reason)
|
||||
{
|
||||
if (ID_Projectiles.ContainsKey(id))
|
||||
{
|
||||
SyncedProjectile sp = ID_Projectiles[id];
|
||||
var p = sp.MainProjectile;
|
||||
if (p!=null)
|
||||
{
|
||||
if (Handle_Projectiles.ContainsKey(p.Handle))
|
||||
{
|
||||
Handle_Projectiles.Remove(p.Handle);
|
||||
}
|
||||
Main.Logger.Debug($"Removing projectile {sp.ID}. Reason:{reason}");
|
||||
p.Explode();
|
||||
}
|
||||
ID_Projectiles.Remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool PedExists(int id)
|
||||
{
|
||||
return ID_Peds.ContainsKey(id);
|
||||
}
|
||||
public static bool VehicleExists(int id)
|
||||
{
|
||||
return ID_Vehicles.ContainsKey(id);
|
||||
}
|
||||
public static bool ProjectileExists(int id)
|
||||
{
|
||||
return ID_Projectiles.ContainsKey(id);
|
||||
}
|
||||
#endregion
|
||||
static int vehStateIndex;
|
||||
static int pedStateIndex;
|
||||
static int vehStatesPerFrame;
|
||||
static int pedStatesPerFrame;
|
||||
static int i;
|
||||
public static Ped[] allPeds=new Ped[0];
|
||||
public static Vehicle[] allVehicles=new Vehicle[0];
|
||||
public static Projectile[] allProjectiles=new Projectile[0];
|
||||
|
||||
public static void DoSync()
|
||||
{
|
||||
#if BENCHMARK
|
||||
PerfCounter.Restart();
|
||||
Debug.TimeStamps[TimeStamp.CheckProjectiles]=PerfCounter.ElapsedTicks;
|
||||
#endif
|
||||
allPeds = World.GetAllPeds();
|
||||
allVehicles=World.GetAllVehicles();
|
||||
allProjectiles=World.GetAllProjectiles();
|
||||
vehStatesPerFrame=allVehicles.Length*2/(int)Game.FPS+1;
|
||||
pedStatesPerFrame=allPeds.Length*2/(int)Game.FPS+1;
|
||||
/*
|
||||
if (Main.Ticked%50==0)
|
||||
{
|
||||
bool flag1 = allVehicles.Length>Main.Settings.WorldVehicleSoftLimit && Main.Settings.WorldVehicleSoftLimit>-1;
|
||||
bool flag2 = allPeds.Length>Main.Settings.WorldPedSoftLimit && Main.Settings.WorldPedSoftLimit>-1;
|
||||
if ((flag1||flag2) && _trafficSpawning)
|
||||
{ SetBudget(0); _trafficSpawning=false; }
|
||||
else if(!_trafficSpawning)
|
||||
{ SetBudget(1); _trafficSpawning=true; }
|
||||
}
|
||||
*/
|
||||
#if BENCHMARK
|
||||
|
||||
Debug.TimeStamps[TimeStamp.GetAllEntities]=PerfCounter.ElapsedTicks;
|
||||
#endif
|
||||
|
||||
lock (ProjectilesLock)
|
||||
{
|
||||
|
||||
foreach (Projectile p in allProjectiles)
|
||||
{
|
||||
if (!Handle_Projectiles.ContainsKey(p.Handle))
|
||||
{
|
||||
Add(new SyncedProjectile(p));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
foreach (SyncedProjectile p in ID_Projectiles.Values.ToArray())
|
||||
{
|
||||
|
||||
// Outgoing sync
|
||||
if (p.IsLocal)
|
||||
{
|
||||
if (p.MainProjectile.AttachedEntity==null)
|
||||
{
|
||||
|
||||
// Prevent projectiles from exploding next to vehicle
|
||||
if (WeaponUtil.VehicleProjectileWeapons.Contains((VehicleWeaponHash)p.MainProjectile.WeaponHash))
|
||||
{
|
||||
if (p.MainProjectile.WeaponHash!=(WeaponHash)VehicleWeaponHash.Tank && p.Origin.DistanceTo(p.MainProjectile.Position)<2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Networking.SendProjectile(p);
|
||||
}
|
||||
}
|
||||
else // Incoming sync
|
||||
{
|
||||
if (p.Exploded || p.IsOutOfSync)
|
||||
{
|
||||
RemoveProjectile(p.ID, "OutOfSync | Exploded");
|
||||
}
|
||||
else
|
||||
{
|
||||
p.Update();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
i=-1;
|
||||
|
||||
lock (PedsLock)
|
||||
{
|
||||
EntityPool.AddPlayer();
|
||||
|
||||
foreach (Ped p in allPeds)
|
||||
{
|
||||
SyncedPed c = EntityPool.GetPedByHandle(p.Handle);
|
||||
if (c==null && (p!=Game.Player.Character))
|
||||
{
|
||||
if (allPeds.Length>Main.Settings.WorldPedSoftLimit)
|
||||
{
|
||||
if (p.PopulationType!=EntityPopulationType.RandomAmbient)
|
||||
{
|
||||
p.Delete();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Main.Logger.Trace($"Creating SyncEntity for ped, handle:{p.Handle}");
|
||||
c=new SyncedPed(p);
|
||||
|
||||
EntityPool.Add(c);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
#if BENCHMARK
|
||||
|
||||
Debug.TimeStamps[TimeStamp.AddPeds]=PerfCounter.ElapsedTicks;
|
||||
#endif
|
||||
var ps = ID_Peds.Values.ToArray();
|
||||
pedStateIndex+=pedStatesPerFrame;
|
||||
if (pedStateIndex>=ps.Length)
|
||||
{
|
||||
pedStateIndex=0;
|
||||
}
|
||||
foreach (SyncedPed c in ps)
|
||||
{
|
||||
i++;
|
||||
if ((c.MainPed!=null)&&(!c.MainPed.Exists()))
|
||||
{
|
||||
EntityPool.RemovePed(c.ID, "non-existent");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Outgoing sync
|
||||
if (c.IsLocal)
|
||||
{
|
||||
#if BENCHMARK
|
||||
var start = PerfCounter2.ElapsedTicks;
|
||||
#endif
|
||||
// event check
|
||||
SyncEvents.Check(c);
|
||||
|
||||
Networking.SendPed(c, (i-pedStateIndex)<pedStatesPerFrame);
|
||||
#if BENCHMARK
|
||||
|
||||
Debug.TimeStamps[TimeStamp.SendPed]=PerfCounter2.ElapsedTicks-start;
|
||||
#endif
|
||||
}
|
||||
else // Incoming sync
|
||||
{
|
||||
#if BENCHMARK
|
||||
var start = PerfCounter2.ElapsedTicks;
|
||||
#endif
|
||||
c.Update();
|
||||
if (c.IsOutOfSync)
|
||||
{
|
||||
RemovePed(c.ID, "OutOfSync");
|
||||
}
|
||||
#if BENCHMARK
|
||||
|
||||
Debug.TimeStamps[TimeStamp.UpdatePed]=PerfCounter2.ElapsedTicks-start;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#if BENCHMARK
|
||||
|
||||
Debug.TimeStamps[TimeStamp.PedTotal]=PerfCounter.ElapsedTicks;
|
||||
#endif
|
||||
}
|
||||
|
||||
i=-1;
|
||||
|
||||
lock (VehiclesLock)
|
||||
{
|
||||
|
||||
foreach (Vehicle veh in allVehicles)
|
||||
{
|
||||
if (!Handle_Vehicles.ContainsKey(veh.Handle))
|
||||
{
|
||||
if (allVehicles.Length>Main.Settings.WorldVehicleSoftLimit)
|
||||
{
|
||||
var type = veh.PopulationType;
|
||||
if (type==EntityPopulationType.RandomAmbient || type==EntityPopulationType.RandomParked)
|
||||
{
|
||||
foreach(var p in veh.Occupants)
|
||||
{
|
||||
p.Delete();
|
||||
var c = EntityPool.GetPedByHandle(p.Handle);
|
||||
if (c!=null)
|
||||
{
|
||||
EntityPool.RemovePed(c.ID,"ThrottleTraffic");
|
||||
}
|
||||
}
|
||||
veh.Delete();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Main.Logger.Debug($"Creating SyncEntity for vehicle, handle:{veh.Handle}");
|
||||
|
||||
EntityPool.Add(new SyncedVehicle(veh));
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
#if BENCHMARK
|
||||
|
||||
Debug.TimeStamps[TimeStamp.AddVehicles]=PerfCounter.ElapsedTicks;
|
||||
#endif
|
||||
var vs = ID_Vehicles.Values.ToArray();
|
||||
vehStateIndex+=vehStatesPerFrame;
|
||||
if (vehStateIndex>=vs.Length)
|
||||
{
|
||||
vehStateIndex=0;
|
||||
}
|
||||
foreach (SyncedVehicle v in vs)
|
||||
{
|
||||
i++;
|
||||
if ((v.MainVehicle!=null)&&(!v.MainVehicle.Exists()))
|
||||
{
|
||||
EntityPool.RemoveVehicle(v.ID,"non-existent");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Outgoing sync
|
||||
if (v.IsLocal)
|
||||
{
|
||||
if (!v.MainVehicle.IsVisible) { continue; }
|
||||
SyncEvents.Check(v);
|
||||
|
||||
Networking.SendVehicle(v);
|
||||
|
||||
// Send state
|
||||
if ((i-vehStateIndex)<vehStatesPerFrame)
|
||||
{
|
||||
Networking.SendVehicleState(v);
|
||||
}
|
||||
|
||||
}
|
||||
else // Incoming sync
|
||||
{
|
||||
|
||||
|
||||
v.Update();
|
||||
if (v.IsOutOfSync)
|
||||
{
|
||||
RemoveVehicle(v.ID, "OutOfSync");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if BENCHMARK
|
||||
Debug.TimeStamps[TimeStamp.VehicleTotal]=PerfCounter.ElapsedTicks;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static void RemoveAllFromPlayer(int playerPedId)
|
||||
{
|
||||
foreach(SyncedPed p in ID_Peds.Values.ToArray())
|
||||
{
|
||||
if (p.OwnerID==playerPedId)
|
||||
{
|
||||
RemovePed(p.ID);
|
||||
}
|
||||
}
|
||||
foreach (SyncedVehicle v in ID_Vehicles.Values.ToArray())
|
||||
{
|
||||
if (v.OwnerID==playerPedId)
|
||||
{
|
||||
RemoveVehicle(v.ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int RequestNewID()
|
||||
{
|
||||
int ID=0;
|
||||
while ((ID==0)
|
||||
|| ID_Peds.ContainsKey(ID)
|
||||
|| ID_Vehicles.ContainsKey(ID)
|
||||
|| ID_Projectiles.ContainsKey(ID))
|
||||
{
|
||||
byte[] rngBytes = new byte[4];
|
||||
|
||||
RandomNumberGenerator.Create().GetBytes(rngBytes);
|
||||
|
||||
// Convert the bytes into an integer
|
||||
ID = BitConverter.ToInt32(rngBytes, 0);
|
||||
}
|
||||
return ID;
|
||||
}
|
||||
private static void SetBudget(int b)
|
||||
{
|
||||
Function.Call(Hash.SET_PED_POPULATION_BUDGET, b); // 0 - 3
|
||||
Function.Call(Hash.SET_VEHICLE_POPULATION_BUDGET, b); // 0 - 3
|
||||
}
|
||||
public static string DumpDebug()
|
||||
{
|
||||
string s= "";
|
||||
s+="\nID_Peds: "+ID_Peds.Count;
|
||||
s+="\nHandle_Peds: "+Handle_Peds.Count;
|
||||
s+="\nID_Vehicles: "+ID_Vehicles.Count;
|
||||
s+="\nHandle_Vehicles: "+Handle_Vehicles.Count;
|
||||
s+="\nID_Projectiles: "+ID_Projectiles.Count;
|
||||
s+="\nHandle_Projectiles: "+Handle_Projectiles.Count;
|
||||
s+="\npedStatesPerFrame:"+pedStatesPerFrame;
|
||||
s+="\nvehStatesPerFrame:"+vehStatesPerFrame;
|
||||
return s;
|
||||
}
|
||||
public static class ThreadSafe
|
||||
{
|
||||
public static void Add(SyncedVehicle v)
|
||||
{
|
||||
lock (EntityPool.VehiclesLock)
|
||||
{
|
||||
EntityPool.Add(v);
|
||||
}
|
||||
}
|
||||
public static void Add(SyncedPed p)
|
||||
{
|
||||
lock (EntityPool.PedsLock)
|
||||
{
|
||||
EntityPool.Add(p);
|
||||
}
|
||||
}
|
||||
public static void Add(SyncedProjectile sp)
|
||||
{
|
||||
lock (EntityPool.ProjectilesLock)
|
||||
{
|
||||
EntityPool.Add(sp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,412 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
using RageCoop.Core;
|
||||
using GTA.Native;
|
||||
using System.Threading;
|
||||
|
||||
namespace RageCoop.Client {
|
||||
internal static class SyncEvents
|
||||
{
|
||||
#region TRIGGER
|
||||
public static void TriggerPedKilled(SyncedPed victim)
|
||||
{
|
||||
Networking.Send(new Packets.PedKilled() { VictimID=victim.ID},ConnectionChannel.SyncEvents);
|
||||
}
|
||||
|
||||
public static void TriggerEnteringVehicle(SyncedPed c,SyncedVehicle veh, VehicleSeat seat)
|
||||
{
|
||||
Networking.
|
||||
Send(new Packets.EnteringVehicle()
|
||||
{
|
||||
PedID=c.ID,
|
||||
VehicleID= veh.ID,
|
||||
VehicleSeat=(short)seat,
|
||||
}, ConnectionChannel.SyncEvents);
|
||||
}
|
||||
|
||||
public static void TriggerEnteredVehicle(SyncedPed c, SyncedVehicle veh, VehicleSeat seat)
|
||||
{
|
||||
if (seat==VehicleSeat.Driver)
|
||||
{
|
||||
veh.OwnerID=Main.LocalPlayerID;
|
||||
veh.LastSynced=Main.Ticked;
|
||||
TriggerChangeOwner(veh, c.ID);
|
||||
}
|
||||
Networking.Send(new Packets.EnteredVehicle()
|
||||
{
|
||||
VehicleSeat=(short)seat,
|
||||
PedID=c.ID,
|
||||
VehicleID=veh.ID
|
||||
},ConnectionChannel.SyncEvents);
|
||||
}
|
||||
|
||||
public static void TriggerChangeOwner(SyncedVehicle c, int newOwnerID)
|
||||
{
|
||||
|
||||
Networking.Send(new Packets.OwnerChanged()
|
||||
{
|
||||
ID= c.ID,
|
||||
NewOwnerID= newOwnerID,
|
||||
}, ConnectionChannel.SyncEvents);
|
||||
|
||||
}
|
||||
|
||||
public static void TriggerBulletShot(uint hash,SyncedPed owner,Vector3 impactPosition)
|
||||
{
|
||||
// Main.Logger.Trace($"bullet shot:{(WeaponHash)hash}");
|
||||
|
||||
|
||||
var start = owner.MainPed.GetMuzzlePosition();
|
||||
if (owner.MainPed.IsOnTurretSeat()) { start=owner.MainPed.Bones[Bone.SkelHead].Position; }
|
||||
if (start.DistanceTo(impactPosition)>10)
|
||||
{
|
||||
// Reduce latency
|
||||
start=impactPosition-(impactPosition-start).Normalized*10;
|
||||
}
|
||||
Networking.SendBulletShot(start, impactPosition, hash, owner.ID);
|
||||
}
|
||||
public static void TriggerLeaveVehicle(int id)
|
||||
{
|
||||
Networking.
|
||||
Send(new Packets.LeaveVehicle()
|
||||
{
|
||||
ID=id
|
||||
}, ConnectionChannel.SyncEvents);
|
||||
}
|
||||
|
||||
public static void TriggerVehBulletShot(uint hash, Vehicle veh, SyncedPed owner)
|
||||
{
|
||||
// ANNIHL
|
||||
if (veh.Model.Hash==837858166)
|
||||
{
|
||||
Networking.SendBulletShot(veh.Bones[35].Position, veh.Bones[35].Position+veh.Bones[35].ForwardVector,hash,owner.ID);
|
||||
Networking.SendBulletShot(veh.Bones[36].Position, veh.Bones[36].Position+veh.Bones[36].ForwardVector,hash, owner.ID);
|
||||
Networking.SendBulletShot(veh.Bones[37].Position, veh.Bones[37].Position+veh.Bones[37].ForwardVector,hash, owner.ID);
|
||||
Networking.SendBulletShot(veh.Bones[38].Position, veh.Bones[38].Position+veh.Bones[38].ForwardVector,hash, owner.ID);
|
||||
return;
|
||||
}
|
||||
|
||||
var info = veh.GetMuzzleInfo();
|
||||
if (info==null) { Main.Logger.Warning($"Failed to get muzzle info for vehicle:{veh.DisplayName}");return; }
|
||||
Networking.SendBulletShot(info.Position,info.Position+info.ForawardVector,hash,owner.ID);
|
||||
}
|
||||
public static void TriggerNozzleTransform(int vehID,bool hover)
|
||||
{
|
||||
Networking.Send(new Packets.NozzleTransform() { VehicleID=vehID, Hover=hover }, ConnectionChannel.SyncEvents);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region HANDLE
|
||||
|
||||
public static ParticleEffectAsset CorePFXAsset = new ParticleEffectAsset("core");
|
||||
|
||||
static WeaponAsset _weaponAsset = default;
|
||||
static uint _lastWeaponHash;
|
||||
|
||||
private static void HandleLeaveVehicle(Packets.LeaveVehicle p)
|
||||
{
|
||||
var ped = EntityPool.GetPedByID(p.ID);
|
||||
var veh = ped.MainPed.CurrentVehicle.GetSyncEntity();
|
||||
veh._checkSeat=false;
|
||||
var flag = LeaveVehicleFlags.None;
|
||||
if (ped.MainPed?.CurrentVehicle==null) { return; }
|
||||
// Bail out
|
||||
if (ped.MainPed.CurrentVehicle.Speed>5) { flag|=LeaveVehicleFlags.BailOut;}
|
||||
// ped.PauseUpdate((ulong)Game.FPS*2);
|
||||
ped.MainPed.Task.LeaveVehicle(flag) ;
|
||||
Task.Run(() =>
|
||||
{
|
||||
Thread.Sleep(1000);
|
||||
veh._checkSeat=true;
|
||||
});
|
||||
}
|
||||
private static void HandlePedKilled(Packets.PedKilled p)
|
||||
{
|
||||
EntityPool.GetPedByID(p.VictimID)?.MainPed?.Kill();
|
||||
}
|
||||
private static void HandleEnteringVehicle(SyncedPed c, SyncedVehicle veh, VehicleSeat seat)
|
||||
{
|
||||
c.MainPed?.Task.EnterVehicle(veh.MainVehicle, seat,-1,2,EnterVehicleFlags.WarpToDoor|EnterVehicleFlags.AllowJacking);
|
||||
}
|
||||
private static void HandleEnteredVehicle(int pedId, int vehId, VehicleSeat seat)
|
||||
{
|
||||
var v = EntityPool.GetVehicleByID(vehId);
|
||||
var p = EntityPool.GetPedByID(pedId)?.MainPed;
|
||||
if (v==null||p==null) { return; }
|
||||
if (!v.MainVehicle.IsSeatFree(seat))
|
||||
{
|
||||
if (v.MainVehicle.GetPedOnSeat(seat)!=p)
|
||||
{
|
||||
v.MainVehicle.GetPedOnSeat(seat).Task.WarpOutOfVehicle(v.MainVehicle);
|
||||
}
|
||||
}
|
||||
p.SetIntoVehicle(v.MainVehicle, seat);
|
||||
}
|
||||
private static void HandleOwnerChanged(Packets.OwnerChanged p)
|
||||
{
|
||||
var v = EntityPool.GetVehicleByID(p.ID);
|
||||
if (v==null) { return; }
|
||||
v.OwnerID=p.NewOwnerID;
|
||||
|
||||
v.Model=v.MainVehicle.Model;
|
||||
v.LastSynced=Main.Ticked;
|
||||
// So this vehicle doesn's get re-spawned
|
||||
}
|
||||
private static void HandleNozzleTransform(Packets.NozzleTransform p)
|
||||
{
|
||||
EntityPool.GetVehicleByID(p.VehicleID)?.MainVehicle?.SetNozzleAngel(p.Hover ? 1 : 0);
|
||||
}
|
||||
private static void HandleBulletShot(Vector3 start, Vector3 end, uint weaponHash, int ownerID)
|
||||
{
|
||||
switch (weaponHash)
|
||||
{
|
||||
// Minigun, not working for some reason
|
||||
case (uint)WeaponHash.Minigun:
|
||||
weaponHash=1176362416;
|
||||
break;
|
||||
|
||||
// Valkyire, not working for some reason
|
||||
case 2756787765:
|
||||
weaponHash=1176362416;
|
||||
break;
|
||||
|
||||
// Tampa3, not working for some reason
|
||||
case 3670375085:
|
||||
weaponHash=1176362416;
|
||||
break;
|
||||
|
||||
// Ruiner2, not working for some reason
|
||||
case 50118905:
|
||||
weaponHash=1176362416;
|
||||
break;
|
||||
|
||||
// SAVAGE
|
||||
case 1638077257:
|
||||
weaponHash=(uint)VehicleWeaponHash.PlayerLazer;
|
||||
break;
|
||||
|
||||
case (uint)VehicleWeaponHash.PlayerBuzzard:
|
||||
weaponHash=1176362416;
|
||||
break ;
|
||||
}
|
||||
|
||||
var p = EntityPool.GetPedByID(ownerID)?.MainPed;
|
||||
if (p == null) { p=Game.Player.Character; Main.Logger.Warning("Failed to find owner for bullet"); }
|
||||
if (!CorePFXAsset.IsLoaded) { CorePFXAsset.Request(); }
|
||||
if (_lastWeaponHash!=weaponHash)
|
||||
{
|
||||
_weaponAsset.MarkAsNoLongerNeeded();
|
||||
_weaponAsset=new WeaponAsset(weaponHash);
|
||||
_lastWeaponHash=weaponHash;
|
||||
}
|
||||
if (!_weaponAsset.IsLoaded) { _weaponAsset.Request(); }
|
||||
World.ShootBullet(start, end, p, _weaponAsset, (int)p.GetWeaponDamage(weaponHash));
|
||||
Prop w;
|
||||
if(((w = p.Weapons.CurrentWeaponObject) != null)&&(p.VehicleWeapon==VehicleWeaponHash.Invalid))
|
||||
{
|
||||
if (p.Weapons.Current.Components.GetSuppressorComponent().Active)
|
||||
{
|
||||
World.CreateParticleEffectNonLooped(CorePFXAsset, "muz_pistol_silencer", p.GetMuzzlePosition(), w.Rotation, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
World.CreateParticleEffectNonLooped(CorePFXAsset, "muz_assault_rifle", p.GetMuzzlePosition(), w.Rotation, 1);
|
||||
}
|
||||
|
||||
}
|
||||
else if (p.VehicleWeapon!=VehicleWeaponHash.Invalid)
|
||||
{
|
||||
if (p.VehicleWeapon==VehicleWeaponHash.Tank)
|
||||
{
|
||||
World.CreateParticleEffectNonLooped(CorePFXAsset, "muz_tank", p.CurrentVehicle.GetMuzzleInfo().Position, p.CurrentVehicle.Bones[35].ForwardVector.ToEulerRotation(p.CurrentVehicle.Bones[35].UpVector), 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
public static void HandleEvent(PacketType type,byte[] data)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case PacketType.BulletShot:
|
||||
{
|
||||
Packets.BulletShot p = new Packets.BulletShot();
|
||||
p.Unpack(data);
|
||||
HandleBulletShot(p.StartPosition, p.EndPosition, p.WeaponHash, p.OwnerID);
|
||||
break;
|
||||
}
|
||||
case PacketType.EnteringVehicle:
|
||||
{
|
||||
Packets.EnteringVehicle p = new Packets.EnteringVehicle();
|
||||
p.Unpack(data);
|
||||
HandleEnteringVehicle(EntityPool.GetPedByID(p.PedID), EntityPool.GetVehicleByID(p.VehicleID), (VehicleSeat)p.VehicleSeat);
|
||||
|
||||
|
||||
}
|
||||
break;
|
||||
case PacketType.LeaveVehicle:
|
||||
{
|
||||
Packets.LeaveVehicle packet = new Packets.LeaveVehicle();
|
||||
packet.Unpack(data);
|
||||
HandleLeaveVehicle(packet);
|
||||
}
|
||||
break;
|
||||
case PacketType.OwnerChanged:
|
||||
{
|
||||
Packets.OwnerChanged packet = new Packets.OwnerChanged();
|
||||
packet.Unpack(data);
|
||||
HandleOwnerChanged(packet);
|
||||
}
|
||||
break;
|
||||
case PacketType.PedKilled:
|
||||
{
|
||||
var packet = new Packets.PedKilled();
|
||||
packet.Unpack(data);
|
||||
HandlePedKilled(packet);
|
||||
}
|
||||
break;
|
||||
case PacketType.EnteredVehicle:
|
||||
{
|
||||
var packet = new Packets.EnteredVehicle();
|
||||
packet.Unpack(data);
|
||||
HandleEnteredVehicle(packet.PedID,packet.VehicleID,(VehicleSeat)packet.VehicleSeat);
|
||||
break;
|
||||
}
|
||||
case PacketType.NozzleTransform:
|
||||
{
|
||||
var packet = new Packets.NozzleTransform();
|
||||
packet.Unpack(data);
|
||||
HandleNozzleTransform(packet);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region CHECK EVENTS
|
||||
|
||||
|
||||
public static void Check(SyncedPed c)
|
||||
{
|
||||
Ped subject = c.MainPed;
|
||||
|
||||
// Check bullets
|
||||
if (subject.IsShooting)
|
||||
{
|
||||
if (!subject.IsUsingProjectileWeapon())
|
||||
{
|
||||
int i = 0;
|
||||
Func<bool> getBulletImpact = (() =>
|
||||
{
|
||||
Vector3 endPos = subject.LastWeaponImpactPosition;
|
||||
if (endPos==default)
|
||||
{
|
||||
if (i>5)
|
||||
{
|
||||
endPos=subject.GetAimCoord();
|
||||
if (subject.IsInVehicle() && subject.VehicleWeapon!=VehicleWeaponHash.Invalid)
|
||||
{
|
||||
if (subject.IsOnTurretSeat())
|
||||
{
|
||||
TriggerBulletShot((uint)subject.VehicleWeapon, subject.GetSyncEntity(), endPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
TriggerVehBulletShot((uint)subject.VehicleWeapon, subject.CurrentVehicle,c);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TriggerBulletShot((uint)subject.Weapons.Current.Hash, subject.GetSyncEntity(), endPos);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
i++;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (subject.IsInVehicle() && subject.VehicleWeapon!=VehicleWeaponHash.Invalid)
|
||||
{
|
||||
if (subject.IsOnTurretSeat())
|
||||
{
|
||||
TriggerBulletShot((uint)subject.VehicleWeapon, subject.GetSyncEntity(), endPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
TriggerVehBulletShot((uint)subject.VehicleWeapon, subject.CurrentVehicle,c);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TriggerBulletShot((uint)subject.Weapons.Current.Hash, subject.GetSyncEntity(), endPos);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
if (!getBulletImpact())
|
||||
{
|
||||
Main.QueueAction(getBulletImpact);
|
||||
}
|
||||
}
|
||||
else if (subject.VehicleWeapon==VehicleWeaponHash.Tank && subject.LastWeaponImpactPosition!=default)
|
||||
{
|
||||
TriggerBulletShot((uint)VehicleWeaponHash.Tank, subject.GetSyncEntity(),subject.LastWeaponImpactPosition);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Vehicles
|
||||
var g = subject.IsGettingIntoVehicle;
|
||||
if ( g && (!c._lastEnteringVehicle))
|
||||
{
|
||||
var v = subject.VehicleTryingToEnter.GetSyncEntity();
|
||||
TriggerEnteringVehicle(c, v, subject.GetSeatTryingToEnter());
|
||||
}
|
||||
var currentSitting= subject.IsSittingInVehicle();
|
||||
if (c._lastSittingInVehicle)
|
||||
{
|
||||
if (!currentSitting)
|
||||
{
|
||||
var veh = subject.CurrentVehicle;
|
||||
if (veh!=null)
|
||||
{
|
||||
var v = veh.GetSyncEntity();
|
||||
TriggerLeaveVehicle(c.ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (currentSitting)
|
||||
{
|
||||
TriggerEnteredVehicle(c, subject.CurrentVehicle.GetSyncEntity(), subject.SeatIndex);
|
||||
}
|
||||
c._lastSittingInVehicle=currentSitting;
|
||||
c._lastEnteringVehicle=g;
|
||||
}
|
||||
|
||||
public static void Check(SyncedVehicle v)
|
||||
{
|
||||
if (v.MainVehicle!=null&&v.MainVehicle.HasNozzle())
|
||||
{
|
||||
if((v.LastNozzleAngle==1) && (v.MainVehicle.GetNozzleAngel()!=1))
|
||||
{
|
||||
TriggerNozzleTransform(v.ID,false);
|
||||
}
|
||||
else if((v.LastNozzleAngle==0) && (v.MainVehicle.GetNozzleAngel()!=0))
|
||||
{
|
||||
TriggerNozzleTransform(v.ID,true);
|
||||
}
|
||||
v.LastNozzleAngle=v.MainVehicle.GetNozzleAngel();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal class SyncParameters
|
||||
{
|
||||
public static float PositioinPredictionDefault = 0.01f;
|
||||
}
|
||||
}
|
@ -1,471 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
// Potential names and hash collisions included as comments
|
||||
internal enum PedConfigFlags
|
||||
{
|
||||
_0x67D1A445 = 0,
|
||||
_0xC63DE95E = 1,
|
||||
CPED_CONFIG_FLAG_NoCriticalHits = 2,
|
||||
CPED_CONFIG_FLAG_DrownsInWater = 3,
|
||||
CPED_CONFIG_FLAG_DisableReticuleFixedLockon = 4,
|
||||
_0x37D196F4 = 5,
|
||||
_0xE2462399 = 6,
|
||||
CPED_CONFIG_FLAG_UpperBodyDamageAnimsOnly = 7,
|
||||
_0xEDDEB838 = 8,
|
||||
_0xB398B6FD = 9,
|
||||
_0xF6664E68 = 10,
|
||||
_0xA05E7CA3 = 11,
|
||||
_0xCE394045 = 12,
|
||||
CPED_CONFIG_FLAG_NeverLeavesGroup = 13,
|
||||
_0xCD8D1411 = 14,
|
||||
_0xB031F1A9 = 15,
|
||||
_0xFE65BEE3 = 16,
|
||||
CPED_CONFIG_FLAG_BlockNonTemporaryEvents = 17,
|
||||
_0x380165BD = 18,
|
||||
_0x07C045C7 = 19,
|
||||
_0x583B5E2D = 20,
|
||||
_0x475EDA58 = 21,
|
||||
_0x8629D05B = 22,
|
||||
_0x1522968B = 23,
|
||||
CPED_CONFIG_FLAG_IgnoreSeenMelee = 24,
|
||||
_0x4CC09C4B = 25,
|
||||
_0x034F3053 = 26,
|
||||
_0xD91BA7CC = 27,
|
||||
_0x5C8DC66E = 28,
|
||||
_0x8902EAA0 = 29,
|
||||
_0x6580B9D2 = 30,
|
||||
_0x0EF7A297 = 31,
|
||||
_0x6BF86E5B = 32,
|
||||
CPED_CONFIG_FLAG_DieWhenRagdoll = 33,
|
||||
CPED_CONFIG_FLAG_HasHelmet = 34,
|
||||
CPED_CONFIG_FLAG_UseHelmet = 35,
|
||||
_0xEEB3D630 = 36,
|
||||
_0xB130D17B = 37,
|
||||
_0x5F071200 = 38,
|
||||
CPED_CONFIG_FLAG_DisableEvasiveDives = 39,
|
||||
_0xC287AAFF = 40,
|
||||
_0x203328CC = 41,
|
||||
CPED_CONFIG_FLAG_DontInfluenceWantedLevel = 42,
|
||||
CPED_CONFIG_FLAG_DisablePlayerLockon = 43,
|
||||
CPED_CONFIG_FLAG_DisableLockonToRandomPeds = 44,
|
||||
_0xEC4A8ACF = 45,
|
||||
_0xDB115BFA = 46,
|
||||
CPED_CONFIG_FLAG_PedBeingDeleted = 47,
|
||||
CPED_CONFIG_FLAG_BlockWeaponSwitching = 48,
|
||||
_0xF8E99565 = 49,
|
||||
_0xDD17FEE6 = 50,
|
||||
_0x7ED9B2C9 = 51,
|
||||
_0x655E8618 = 52,
|
||||
_0x5A6C1F6E = 53,
|
||||
_0xD749FC41 = 54,
|
||||
_0x357F63F3 = 55,
|
||||
_0xC5E60961 = 56,
|
||||
_0x29275C3E = 57,
|
||||
CPED_CONFIG_FLAG_IsFiring = 58,
|
||||
CPED_CONFIG_FLAG_WasFiring = 59,
|
||||
CPED_CONFIG_FLAG_IsStanding = 60,
|
||||
CPED_CONFIG_FLAG_WasStanding = 61,
|
||||
CPED_CONFIG_FLAG_InVehicle = 62,
|
||||
CPED_CONFIG_FLAG_OnMount = 63,
|
||||
CPED_CONFIG_FLAG_AttachedToVehicle = 64,
|
||||
CPED_CONFIG_FLAG_IsSwimming = 65,
|
||||
CPED_CONFIG_FLAG_WasSwimming = 66,
|
||||
CPED_CONFIG_FLAG_IsSkiing = 67,
|
||||
CPED_CONFIG_FLAG_IsSitting = 68,
|
||||
CPED_CONFIG_FLAG_KilledByStealth = 69,
|
||||
CPED_CONFIG_FLAG_KilledByTakedown = 70,
|
||||
CPED_CONFIG_FLAG_Knockedout = 71,
|
||||
_0x3E3C4560 = 72,
|
||||
_0x2994C7B7 = 73,
|
||||
_0x6D59D275 = 74,
|
||||
CPED_CONFIG_FLAG_UsingCoverPoint = 75,
|
||||
CPED_CONFIG_FLAG_IsInTheAir = 76,
|
||||
_0x2D493FB7 = 77,
|
||||
CPED_CONFIG_FLAG_IsAimingGun = 78,
|
||||
_0x14D69875 = 79,
|
||||
_0x40B05311 = 80,
|
||||
_0x8B230BC5 = 81,
|
||||
_0xC74E5842 = 82,
|
||||
_0x9EA86147 = 83,
|
||||
_0x674C746C = 84,
|
||||
_0x3E56A8C2 = 85,
|
||||
_0xC144A1EF = 86,
|
||||
_0x0548512D = 87,
|
||||
_0x31C93909 = 88,
|
||||
_0xA0269315 = 89,
|
||||
_0xD4D59D4D = 90,
|
||||
_0x411D4420 = 91,
|
||||
_0xDF4AEF0D = 92,
|
||||
CPED_CONFIG_FLAG_ForcePedLoadCover = 93,
|
||||
_0x300E4CD3 = 94,
|
||||
_0xF1C5BF04 = 95,
|
||||
_0x89C2EF13 = 96,
|
||||
CPED_CONFIG_FLAG_VaultFromCover = 97,
|
||||
_0x02A852C8 = 98,
|
||||
_0x3D9407F1 = 99,
|
||||
_0x319B4558 = 100,
|
||||
CPED_CONFIG_FLAG_ForcedAim = 101,
|
||||
_0xB942D71A = 102,
|
||||
_0xD26C55A8 = 103,
|
||||
_0xB89E703B = 104,
|
||||
CPED_CONFIG_FLAG_ForceReload = 105,
|
||||
_0xD9E73DA2 = 106,
|
||||
_0xFF71DC2C = 107,
|
||||
_0x1E27E8D8 = 108,
|
||||
_0xF2C53966 = 109,
|
||||
_0xC4DBE247 = 110,
|
||||
_0x83C0A4BF = 111,
|
||||
_0x0E0FAF8C = 112,
|
||||
_0x26616660 = 113,
|
||||
_0x43B80B79 = 114,
|
||||
_0x0D2A9309 = 115,
|
||||
_0x12C1C983 = 116,
|
||||
CPED_CONFIG_FLAG_BumpedByPlayer = 117,
|
||||
_0xE586D504 = 118,
|
||||
_0x52374204 = 119,
|
||||
CPED_CONFIG_FLAG_IsHandCuffed = 120,
|
||||
CPED_CONFIG_FLAG_IsAnkleCuffed = 121,
|
||||
CPED_CONFIG_FLAG_DisableMelee = 122,
|
||||
_0xFE714397 = 123,
|
||||
_0xB3E660BD = 124,
|
||||
_0x5FED6BFD = 125,
|
||||
_0xC9D6F66F = 126,
|
||||
_0x519BC986 = 127,
|
||||
CPED_CONFIG_FLAG_CanBeAgitated = 128,
|
||||
_0x9A4B617C = 129, // CPED_CONFIG_FLAG_FaceDirInsult
|
||||
_0xDAB70E9F = 130,
|
||||
_0xE569438A = 131,
|
||||
_0xBBC77D6D = 132,
|
||||
_0xCB59EF0F = 133,
|
||||
_0x8C5EA971 = 134,
|
||||
CPED_CONFIG_FLAG_IsScuba = 135,
|
||||
CPED_CONFIG_FLAG_WillArrestRatherThanJack = 136,
|
||||
_0xDCE59B58 = 137,
|
||||
CPED_CONFIG_FLAG_RidingTrain = 138,
|
||||
CPED_CONFIG_FLAG_ArrestResult = 139,
|
||||
CPED_CONFIG_FLAG_CanAttackFriendly = 140,
|
||||
_0x98A4BE43 = 141,
|
||||
_0x6901E731 = 142,
|
||||
_0x9EC9BF6C = 143,
|
||||
_0x42841A8F = 144,
|
||||
CPED_CONFIG_FLAG_ShootingAnimFlag = 145,
|
||||
CPED_CONFIG_FLAG_DisableLadderClimbing = 146,
|
||||
CPED_CONFIG_FLAG_StairsDetected = 147,
|
||||
CPED_CONFIG_FLAG_SlopeDetected = 148,
|
||||
_0x1A15670B = 149,
|
||||
_0x61786EE5 = 150,
|
||||
_0xCB9186BD = 151,
|
||||
_0xF0710152 = 152,
|
||||
_0x43DFE310 = 153,
|
||||
_0xC43C624E = 154,
|
||||
CPED_CONFIG_FLAG_CanPerformArrest = 155,
|
||||
CPED_CONFIG_FLAG_CanPerformUncuff = 156,
|
||||
CPED_CONFIG_FLAG_CanBeArrested = 157,
|
||||
_0xF7960FF5 = 158,
|
||||
_0x59564113 = 159,
|
||||
_0x0C6C3099 = 160,
|
||||
_0x645F927A = 161,
|
||||
_0xA86549B9 = 162,
|
||||
_0x8AAF337A = 163,
|
||||
_0x13BAA6E7 = 164,
|
||||
_0x5FB9D1F5 = 165,
|
||||
CPED_CONFIG_FLAG_IsInjured = 166,
|
||||
_0x6398A20B = 167,
|
||||
_0xD8072639 = 168,
|
||||
_0xA05B1845 = 169,
|
||||
_0x83F6D220 = 170,
|
||||
_0xD8430331 = 171,
|
||||
_0x4B547520 = 172,
|
||||
_0xE66E1406 = 173,
|
||||
_0x1C4BFE0C = 174,
|
||||
_0x90008BFA = 175,
|
||||
_0x07C7A910 = 176,
|
||||
_0xF15F8191 = 177,
|
||||
_0xCE4E8BE2 = 178,
|
||||
_0x1D46E4F2 = 179,
|
||||
CPED_CONFIG_FLAG_IsInCustody = 180,
|
||||
_0xE4FD9B3A = 181,
|
||||
_0x67AE0812 = 182,
|
||||
CPED_CONFIG_FLAG_IsAgitated = 183,
|
||||
CPED_CONFIG_FLAG_PreventAutoShuffleToDriversSeat = 184,
|
||||
_0x7B2D325E = 185,
|
||||
CPED_CONFIG_FLAG_EnableWeaponBlocking = 186,
|
||||
CPED_CONFIG_FLAG_HasHurtStarted = 187,
|
||||
CPED_CONFIG_FLAG_DisableHurt = 188,
|
||||
CPED_CONFIG_FLAG_PlayerIsWeird = 189,
|
||||
_0x32FC208B = 190,
|
||||
_0x0C296E5A = 191,
|
||||
_0xE63B73EC = 192,
|
||||
_0x04E9CC80 = 193,
|
||||
CPED_CONFIG_FLAG_UsingScenario = 194,
|
||||
CPED_CONFIG_FLAG_VisibleOnScreen = 195,
|
||||
_0xD88C58A1 = 196,
|
||||
_0x5A3DCF43 = 197, // CPED_CONFIG_FLAG_AvoidUnderSide
|
||||
_0xEA02B420 = 198,
|
||||
_0x3F559CFF = 199,
|
||||
_0x8C55D029 = 200,
|
||||
_0x5E6466F6 = 201,
|
||||
_0xEB5AD706 = 202,
|
||||
_0x0EDDDDE7 = 203,
|
||||
_0xA64F7B1D = 204,
|
||||
_0x48532CBA = 205,
|
||||
_0xAA25A9E7 = 206,
|
||||
_0x415B26B9 = 207,
|
||||
CPED_CONFIG_FLAG_DisableExplosionReactions = 208,
|
||||
CPED_CONFIG_FLAG_DodgedPlayer = 209,
|
||||
_0x67405504 = 210,
|
||||
_0x75DDD68C = 211,
|
||||
_0x2AD879B4 = 212,
|
||||
_0x51486F91 = 213,
|
||||
_0x32F79E21 = 214,
|
||||
_0xBF099213 = 215,
|
||||
_0x054AC8E2 = 216,
|
||||
_0x14E495CC = 217,
|
||||
_0x3C7DF9DF = 218,
|
||||
_0x848FFEF2 = 219,
|
||||
CPED_CONFIG_FLAG_DontEnterLeadersVehicle = 220,
|
||||
_0x2618E1CF = 221,
|
||||
_0x84F722FA = 222,
|
||||
_0xD1B87B1F = 223,
|
||||
_0x728AA918 = 224,
|
||||
CPED_CONFIG_FLAG_DisablePotentialToBeWalkedIntoResponse = 225,
|
||||
CPED_CONFIG_FLAG_DisablePedAvoidance = 226,
|
||||
_0x59E91185 = 227,
|
||||
_0x1EA7225F = 228,
|
||||
CPED_CONFIG_FLAG_DisablePanicInVehicle = 229,
|
||||
_0x6DCA7D88 = 230,
|
||||
_0xFC3E572D = 231,
|
||||
_0x08E9F9CF = 232,
|
||||
_0x2D3BA52D = 233,
|
||||
_0xFD2F53EA = 234,
|
||||
_0x31A1B03B = 235,
|
||||
CPED_CONFIG_FLAG_IsHoldingProp = 236,
|
||||
_0x82ED0A66 = 237, // CPED_CONFIG_FLAG_BlocksPathingWhenDead
|
||||
_0xCE57C9A3 = 238,
|
||||
_0x26149198 = 239,
|
||||
_0x1B33B598 = 240,
|
||||
_0x719B6E87 = 241,
|
||||
_0x13E8E8E8 = 242,
|
||||
_0xF29739AE = 243,
|
||||
_0xABEA8A74 = 244,
|
||||
_0xB60EA2BA = 245,
|
||||
_0x536B0950 = 246,
|
||||
_0x0C754ACA = 247,
|
||||
CPED_CONFIG_FLAG_DisableVehicleSeatRandomAnimations = 248,
|
||||
_0x12659168 = 249,
|
||||
_0x1BDF2F04 = 250,
|
||||
_0x7728FAA3 = 251,
|
||||
_0x6A807ED8 = 252,
|
||||
CPED_CONFIG_FLAG_OnStairs = 253,
|
||||
_0xE1A2F73F = 254,
|
||||
_0x5B3697C8 = 255,
|
||||
_0xF1EB20A9 = 256,
|
||||
_0x8B7DF407 = 257,
|
||||
_0x329DCF1A = 258,
|
||||
_0x8D90DD1B = 259,
|
||||
_0xB8A292B7 = 260,
|
||||
_0x8374B087 = 261,
|
||||
_0x2AF558F0 = 262,
|
||||
_0x82251455 = 263,
|
||||
_0x30CF498B = 264,
|
||||
_0xE1CD50AF = 265,
|
||||
_0x72E4AE48 = 266,
|
||||
_0xC2657EA1 = 267,
|
||||
_0x29FF6030 = 268,
|
||||
_0x8248A5EC = 269,
|
||||
CPED_CONFIG_FLAG_OnStairSlope = 270,
|
||||
_0xA0897933 = 271,
|
||||
CPED_CONFIG_FLAG_DontBlipCop = 272,
|
||||
CPED_CONFIG_FLAG_ClimbedShiftedFence = 273,
|
||||
_0xF7823618 = 274,
|
||||
_0xDC305CCE = 275, // CPED_CONFIG_FLAG_KillWhenTrapped
|
||||
CPED_CONFIG_FLAG_EdgeDetected = 276,
|
||||
_0x92B67896 = 277,
|
||||
_0xCAD677C9 = 278,
|
||||
CPED_CONFIG_FLAG_AvoidTearGas = 279,
|
||||
_0x5276AC7B = 280,
|
||||
_0x1032692A = 281,
|
||||
_0xDA23E7F1 = 282,
|
||||
_0x9139724D = 283,
|
||||
_0xA1457461 = 284,
|
||||
_0x4186E095 = 285,
|
||||
_0xAC68E2EB = 286,
|
||||
CPED_CONFIG_FLAG_RagdollingOnBoat = 287,
|
||||
CPED_CONFIG_FLAG_HasBrandishedWeapon = 288,
|
||||
_0x1B9EE8A1 = 289,
|
||||
_0xF3F5758C = 290,
|
||||
_0x2A9307F1 = 291,
|
||||
_0x7403D216 = 292,
|
||||
_0xA06A3C6C = 293,
|
||||
CPED_CONFIG_FLAG_DisableShockingEvents = 294,
|
||||
_0xF8DA25A5 = 295,
|
||||
_0x7EF55802 = 296,
|
||||
_0xB31F1187 = 297,
|
||||
_0x84315402 = 298,
|
||||
_0x0FD69867 = 299,
|
||||
_0xC7829B67 = 300,
|
||||
CPED_CONFIG_FLAG_DisablePedConstraints = 301,
|
||||
_0x6D23CF25 = 302,
|
||||
_0x2ADA871B = 303,
|
||||
_0x47BC8A58 = 304,
|
||||
_0xEB692FA5 = 305,
|
||||
_0x4A133C50 = 306,
|
||||
_0xC58099C3 = 307,
|
||||
_0xF3D76D41 = 308,
|
||||
_0xB0EEE9F2 = 309,
|
||||
CPED_CONFIG_FLAG_IsInCluster = 310,
|
||||
_0x0FA153EF = 311,
|
||||
_0xD73F5CD3 = 312,
|
||||
_0xD4136C22 = 313,
|
||||
_0xE404CA6B = 314,
|
||||
_0xB9597446 = 315,
|
||||
_0xD5C98277 = 316,
|
||||
_0xD5060A9C = 317,
|
||||
_0x3E5F1CBB = 318,
|
||||
_0xD8BE1D54 = 319,
|
||||
_0x0B1F191F = 320,
|
||||
_0xC995167A = 321,
|
||||
CPED_CONFIG_FLAG_HasHighHeels = 322,
|
||||
_0x86B01E54 = 323,
|
||||
_0x3A56FE15 = 324,
|
||||
_0xC03B736C = 325, // CPED_CONFIG_FLAG_SpawnedAtScenario
|
||||
_0xBBF47729 = 326,
|
||||
_0x22B668A8 = 327,
|
||||
_0x2624D4D4 = 328,
|
||||
CPED_CONFIG_FLAG_DisableTalkTo = 329,
|
||||
CPED_CONFIG_FLAG_DontBlip = 330,
|
||||
CPED_CONFIG_FLAG_IsSwitchingWeapon = 331,
|
||||
_0x630F55F3 = 332,
|
||||
_0x150468FD = 333,
|
||||
_0x914EBD6B = 334,
|
||||
_0x79AF3B6D = 335,
|
||||
_0x75C7A632 = 336,
|
||||
_0x52D530E2 = 337,
|
||||
_0xDB2A90E0 = 338,
|
||||
_0x5922763D = 339,
|
||||
_0x12ADB567 = 340,
|
||||
_0x105C8518 = 341,
|
||||
_0x106F703D = 342,
|
||||
_0xED152C3E = 343,
|
||||
_0xA0EFE6A8 = 344,
|
||||
_0xBF348C82 = 345,
|
||||
_0xCDDFE830 = 346,
|
||||
_0x7B59BD9B = 347,
|
||||
_0x0124C788 = 348,
|
||||
CPED_CONFIG_FLAG_EquipJetpack = 349,
|
||||
_0x08D361A5 = 350,
|
||||
_0xE13D1F7C = 351,
|
||||
_0x40E25FB9 = 352,
|
||||
_0x930629D9 = 353,
|
||||
_0xECCF0C7F = 354,
|
||||
_0xB6E9613B = 355,
|
||||
_0x490C0478 = 356,
|
||||
_0xE8865BEA = 357,
|
||||
_0xF3C34A29 = 358,
|
||||
CPED_CONFIG_FLAG_IsDuckingInVehicle = 359,
|
||||
_0xF660E115 = 360,
|
||||
_0xAB0E6DED = 361,
|
||||
CPED_CONFIG_FLAG_HasReserveParachute = 362,
|
||||
CPED_CONFIG_FLAG_UseReserveParachute = 363,
|
||||
_0x5C5D9CD3 = 364,
|
||||
_0x8F7701F3 = 365,
|
||||
_0xBC4436AD = 366,
|
||||
_0xD7E07D37 = 367,
|
||||
_0x03C4FD24 = 368,
|
||||
_0x7675789A = 369,
|
||||
_0xB7288A88 = 370,
|
||||
_0xC06B6291 = 371,
|
||||
_0x95A4A805 = 372,
|
||||
_0xA8E9A042 = 373,
|
||||
CPED_CONFIG_FLAG_NeverLeaveTrain = 374,
|
||||
_0xBAC674B3 = 375,
|
||||
_0x147F1FFB = 376,
|
||||
_0x4376DD79 = 377,
|
||||
_0xCD3DB518 = 378,
|
||||
_0xFE4BA4B6 = 379,
|
||||
_0x5DF03A55 = 380,
|
||||
_0xBCD816CD = 381,
|
||||
_0xCF02DD69 = 382,
|
||||
_0xF73AFA2E = 383,
|
||||
_0x80B9A9D0 = 384,
|
||||
_0xF601F7EE = 385,
|
||||
_0xA91350FC = 386,
|
||||
_0x3AB23B96 = 387,
|
||||
CPED_CONFIG_FLAG_IsClimbingLadder = 388,
|
||||
CPED_CONFIG_FLAG_HasBareFeet = 389,
|
||||
_0xB4B1CD4C = 390,
|
||||
_0x5459AFB8 = 391,
|
||||
_0x54F27667 = 392,
|
||||
_0xC11D3E8F = 393,
|
||||
_0x5419EB3E = 394,
|
||||
_0x82D8DBB4 = 395,
|
||||
_0x33B02D2F = 396,
|
||||
_0xAE66176D = 397,
|
||||
_0xA2692593 = 398,
|
||||
_0x714C7E31 = 399,
|
||||
_0xEC488AC7 = 400,
|
||||
_0xAE398504 = 401,
|
||||
_0xABC58D72 = 402,
|
||||
_0x5E5B9591 = 403,
|
||||
_0x6BA1091E = 404,
|
||||
_0x77840177 = 405,
|
||||
_0x1C7ACAC4 = 406,
|
||||
_0x124420E9 = 407,
|
||||
_0x75A65587 = 408,
|
||||
_0xDFD2D55B = 409,
|
||||
_0xBDD39919 = 410,
|
||||
_0x43DEC267 = 411,
|
||||
_0xE42B7797 = 412,
|
||||
CPED_CONFIG_FLAG_IsHolsteringWeapon = 413,
|
||||
_0x4F8149F5 = 414,
|
||||
_0xDD9ECA7A = 415,
|
||||
_0x9E7EF9D2 = 416,
|
||||
_0x2C6ED942 = 417,
|
||||
CPED_CONFIG_FLAG_IsSwitchingHelmetVisor = 418,
|
||||
_0xA488727D = 419,
|
||||
_0xCFF5F6DE = 420,
|
||||
_0x6D614599 = 421,
|
||||
CPED_CONFIG_FLAG_DisableVehicleCombat = 422,
|
||||
_0xFE401D26 = 423,
|
||||
CPED_CONFIG_FLAG_FallsLikeAircraft = 424,
|
||||
_0x2B42AE82 = 425,
|
||||
_0x7A95734F = 426,
|
||||
_0xDF4D8617 = 427,
|
||||
_0x578F1F14 = 428,
|
||||
CPED_CONFIG_FLAG_DisableStartEngine = 429,
|
||||
CPED_CONFIG_FLAG_IgnoreBeingOnFire = 430,
|
||||
_0x153C9500 = 431,
|
||||
_0xCB7A632E = 432,
|
||||
_0xDE727981 = 433,
|
||||
CPED_CONFIG_FLAG_DisableHomingMissileLockon = 434,
|
||||
_0x12BBB935 = 435,
|
||||
_0xAD0A1277 = 436,
|
||||
_0xEA6AA46A = 437,
|
||||
CPED_CONFIG_FLAG_DisableHelmetArmor = 438,
|
||||
_0xCB7F3A1E = 439,
|
||||
_0x50178878 = 440,
|
||||
_0x051B4F0D = 441,
|
||||
_0x2FC3DECC = 442,
|
||||
_0xC0030B0B = 443,
|
||||
_0xBBDAF1E9 = 444,
|
||||
_0x944FE59C = 445,
|
||||
_0x506FBA39 = 446,
|
||||
_0xDD45FE84 = 447,
|
||||
_0xE698AE75 = 448,
|
||||
_0x199633F8 = 449,
|
||||
CPED_CONFIG_FLAG_PedIsArresting = 450,
|
||||
CPED_CONFIG_FLAG_IsDecoyPed = 451,
|
||||
_0x3A251D83 = 452,
|
||||
_0xA56F6986 = 453,
|
||||
_0x1D19C622 = 454,
|
||||
_0xB68D3EAB = 455,
|
||||
CPED_CONFIG_FLAG_CanBeIncapacitated = 456,
|
||||
_0x4BD5EBAD = 457,
|
||||
}
|
||||
}
|
@ -1,399 +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
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
// Not sure whether component will always be lesser than 255, whatever...
|
||||
public static byte[] GetPedClothes(this Ped ped)
|
||||
{
|
||||
var result = new byte[36];
|
||||
for (byte i = 0; i < 12; i++)
|
||||
{
|
||||
result[i]=(byte)Function.Call<short>(Hash.GET_PED_DRAWABLE_VARIATION, ped.Handle, i);
|
||||
result[i+12]=(byte)Function.Call<short>(Hash.GET_PED_TEXTURE_VARIATION, ped.Handle, i);
|
||||
result[i+24]=(byte)Function.Call<short>(Hash.GET_PED_PALETTE_VARIATION, ped.Handle, i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static PedDataFlags GetPedFlags(this Ped ped)
|
||||
{
|
||||
PedDataFlags flags = PedDataFlags.None;
|
||||
|
||||
if (ped.IsAiming || ped.IsOnTurretSeat())
|
||||
{
|
||||
flags |= PedDataFlags.IsAiming;
|
||||
}
|
||||
|
||||
|
||||
if (ped.IsReloading)
|
||||
{
|
||||
flags |= PedDataFlags.IsReloading;
|
||||
}
|
||||
|
||||
if (ped.IsJumping)
|
||||
{
|
||||
flags |= PedDataFlags.IsJumping;
|
||||
}
|
||||
|
||||
// Fake death
|
||||
if (ped.IsRagdoll || (ped.Health==1 && ped.IsPlayer))
|
||||
{
|
||||
flags |= PedDataFlags.IsRagdoll;
|
||||
}
|
||||
|
||||
if (ped.IsOnFire)
|
||||
{
|
||||
flags |= PedDataFlags.IsOnFire;
|
||||
}
|
||||
|
||||
if (ped.IsInParachuteFreeFall)
|
||||
{
|
||||
flags |= PedDataFlags.IsInParachuteFreeFall;
|
||||
}
|
||||
|
||||
if (ped.ParachuteState == ParachuteState.Gliding)
|
||||
{
|
||||
flags |= PedDataFlags.IsParachuteOpen;
|
||||
}
|
||||
|
||||
bool climbingLadder = ped.IsTaskActive(TaskType.CTaskGoToAndClimbLadder);
|
||||
if (climbingLadder)
|
||||
{
|
||||
flags |= PedDataFlags.IsOnLadder;
|
||||
}
|
||||
|
||||
if (ped.IsVaulting && !climbingLadder)
|
||||
{
|
||||
flags |= PedDataFlags.IsVaulting;
|
||||
}
|
||||
|
||||
if (ped.IsInCover || ped.IsGoingIntoCover)
|
||||
{
|
||||
flags |=PedDataFlags.IsInCover;
|
||||
}
|
||||
|
||||
if(Function.Call<bool>(Hash.GET_PED_STEALTH_MOVEMENT, ped))
|
||||
{
|
||||
flags |= PedDataFlags.IsInStealthMode;
|
||||
}
|
||||
|
||||
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
|
||||
|| (VehicleHash)veh.Model.Hash==VehicleHash.Dune3;
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -1,438 +0,0 @@
|
||||
// WARNING: values can change after a game update
|
||||
// if R* adds in the middle!
|
||||
// This is up-to-date for b2372
|
||||
internal enum TaskType
|
||||
{
|
||||
CTaskHandsUp = 0,
|
||||
CTaskClimbLadder = 1,
|
||||
CTaskExitVehicle = 2,
|
||||
CTaskCombatRoll = 3,
|
||||
CTaskAimGunOnFoot = 4,
|
||||
CTaskMovePlayer = 5,
|
||||
CTaskPlayerOnFoot = 6,
|
||||
CTaskWeapon = 8,
|
||||
CTaskPlayerWeapon = 9,
|
||||
CTaskPlayerIdles = 10,
|
||||
CTaskAimGun = 12,
|
||||
CTaskComplex = 12,
|
||||
CTaskFSMClone = 12,
|
||||
CTaskMotionBase = 12,
|
||||
CTaskMove = 12,
|
||||
CTaskMoveBase = 12,
|
||||
CTaskNMBehaviour = 12,
|
||||
CTaskNavBase = 12,
|
||||
CTaskScenario = 12,
|
||||
CTaskSearchBase = 12,
|
||||
CTaskSearchInVehicleBase = 12,
|
||||
CTaskShockingEvent = 12,
|
||||
CTaskTrainBase = 12,
|
||||
CTaskVehicleFSM = 12,
|
||||
CTaskVehicleGoTo = 12,
|
||||
CTaskVehicleMissionBase = 12,
|
||||
CTaskVehicleTempAction = 12,
|
||||
CTaskPause = 14,
|
||||
CTaskDoNothing = 15,
|
||||
CTaskGetUp = 16,
|
||||
CTaskGetUpAndStandStill = 17,
|
||||
CTaskFallOver = 18,
|
||||
CTaskFallAndGetUp = 19,
|
||||
CTaskCrawl = 20,
|
||||
CTaskComplexOnFire = 25,
|
||||
CTaskDamageElectric = 26,
|
||||
CTaskTriggerLookAt = 28,
|
||||
CTaskClearLookAt = 29,
|
||||
CTaskSetCharDecisionMaker = 30,
|
||||
CTaskSetPedDefensiveArea = 31,
|
||||
CTaskUseSequence = 32,
|
||||
CTaskMoveStandStill = 34,
|
||||
CTaskComplexControlMovement = 35,
|
||||
CTaskMoveSequence = 36,
|
||||
CTaskAmbientClips = 38,
|
||||
CTaskMoveInAir = 39,
|
||||
CTaskNetworkClone = 40,
|
||||
CTaskUseClimbOnRoute = 41,
|
||||
CTaskUseDropDownOnRoute = 42,
|
||||
CTaskUseLadderOnRoute = 43,
|
||||
CTaskSetBlockingOfNonTemporaryEvents = 44,
|
||||
CTaskForceMotionState = 45,
|
||||
CTaskSlopeScramble = 46,
|
||||
CTaskGoToAndClimbLadder = 47,
|
||||
CTaskClimbLadderFully = 48,
|
||||
CTaskRappel = 49,
|
||||
CTaskVault = 50,
|
||||
CTaskDropDown = 51,
|
||||
CTaskAffectSecondaryBehaviour = 52,
|
||||
CTaskAmbientLookAtEvent = 53,
|
||||
CTaskOpenDoor = 54,
|
||||
CTaskShovePed = 55,
|
||||
CTaskSwapWeapon = 56,
|
||||
CTaskGeneralSweep = 57,
|
||||
CTaskPolice = 58,
|
||||
CTaskPoliceOrderResponse = 59,
|
||||
CTaskPursueCriminal = 60,
|
||||
CTaskArrestPed = 62,
|
||||
CTaskArrestPed2 = 63,
|
||||
CTaskBusted = 64,
|
||||
CTaskFirePatrol = 65,
|
||||
CTaskHeliOrderResponse = 66,
|
||||
CTaskHeliPassengerRappel = 67,
|
||||
CTaskAmbulancePatrol = 68,
|
||||
CTaskPoliceWantedResponse = 69,
|
||||
CTaskSwat = 70,
|
||||
CTaskSwatWantedResponse = 72,
|
||||
CTaskSwatOrderResponse = 73,
|
||||
CTaskSwatGoToStagingArea = 74,
|
||||
CTaskSwatFollowInLine = 75,
|
||||
CTaskWitness = 76,
|
||||
CTaskGangPatrol = 77,
|
||||
CTaskArmy = 78,
|
||||
CTaskShockingEventWatch = 80,
|
||||
CTaskShockingEventGoto = 82,
|
||||
CTaskShockingEventHurryAway = 83,
|
||||
CTaskShockingEventReactToAircraft = 84,
|
||||
CTaskShockingEventReact = 85,
|
||||
CTaskShockingEventBackAway = 86,
|
||||
CTaskShockingPoliceInvestigate = 87,
|
||||
CTaskShockingEventStopAndStare = 88,
|
||||
CTaskShockingNiceCarPicture = 89,
|
||||
CTaskShockingEventThreatResponse = 90,
|
||||
CTaskTakeOffHelmet = 92,
|
||||
CTaskCarReactToVehicleCollision = 93,
|
||||
CTaskCarReactToVehicleCollisionGetOut = 95,
|
||||
CTaskDyingDead = 97,
|
||||
CTaskWanderingScenario = 100,
|
||||
CTaskWanderingInRadiusScenario = 101,
|
||||
CTaskMoveBetweenPointsScenario = 103,
|
||||
CTaskChatScenario = 104,
|
||||
CTaskCowerScenario = 106,
|
||||
CTaskDeadBodyScenario = 107,
|
||||
CTaskSayAudio = 114,
|
||||
CTaskWaitForSteppingOut = 116,
|
||||
CTaskCoupleScenario = 117,
|
||||
CTaskUseScenario = 118,
|
||||
CTaskUseVehicleScenario = 119,
|
||||
CTaskUnalerted = 120,
|
||||
CTaskStealVehicle = 121,
|
||||
CTaskReactToPursuit = 122,
|
||||
CTaskHitWall = 125,
|
||||
CTaskCower = 126,
|
||||
CTaskCrouch = 127,
|
||||
CTaskMelee = 128,
|
||||
CTaskMoveMeleeMovement = 129,
|
||||
CTaskMeleeActionResult = 130,
|
||||
CTaskMeleeUpperbodyAnims = 131,
|
||||
CTaskMoVEScripted = 133,
|
||||
CTaskScriptedAnimation = 134,
|
||||
CTaskSynchronizedScene = 135,
|
||||
CTaskComplexEvasiveStep = 137,
|
||||
CTaskWalkRoundCarWhileWandering = 138,
|
||||
CTaskComplexStuckInAir = 140,
|
||||
CTaskWalkRoundEntity = 141,
|
||||
CTaskMoveWalkRoundVehicle = 142,
|
||||
CTaskReactToGunAimedAt = 144,
|
||||
CTaskDuckAndCover = 146,
|
||||
CTaskAggressiveRubberneck = 147,
|
||||
CTaskInVehicleBasic = 150,
|
||||
CTaskCarDriveWander = 151,
|
||||
CTaskLeaveAnyCar = 152,
|
||||
CTaskComplexGetOffBoat = 153,
|
||||
CTaskCarSetTempAction = 155,
|
||||
CTaskBringVehicleToHalt = 156,
|
||||
CTaskCarDrive = 157,
|
||||
CTaskPlayerDrive = 159,
|
||||
CTaskEnterVehicle = 160,
|
||||
CTaskEnterVehicleAlign = 161,
|
||||
CTaskOpenVehicleDoorFromOutside = 162,
|
||||
CTaskEnterVehicleSeat = 163,
|
||||
CTaskCloseVehicleDoorFromInside = 164,
|
||||
CTaskInVehicleSeatShuffle = 165,
|
||||
CTaskExitVehicleSeat = 167,
|
||||
CTaskCloseVehicleDoorFromOutside = 168,
|
||||
CTaskControlVehicle = 169,
|
||||
CTaskMotionInAutomobile = 170,
|
||||
CTaskMotionOnBicycle = 171,
|
||||
CTaskMotionOnBicycleController = 172,
|
||||
CTaskMotionInVehicle = 173,
|
||||
CTaskMotionInTurret = 174,
|
||||
CTaskReactToBeingJacked = 175,
|
||||
CTaskReactToBeingAskedToLeaveVehicle = 176,
|
||||
CTaskTryToGrabVehicleDoor = 177,
|
||||
CTaskGetOnTrain = 178,
|
||||
CTaskGetOffTrain = 179,
|
||||
CTaskRideTrain = 180,
|
||||
CTaskMountThrowProjectile = 190,
|
||||
CTaskGoToCarDoorAndStandStill = 195,
|
||||
CTaskMoveGoToVehicleDoor = 196,
|
||||
CTaskSetPedInVehicle = 197,
|
||||
CTaskSetPedOutOfVehicle = 198,
|
||||
CTaskVehicleMountedWeapon = 199,
|
||||
CTaskVehicleGun = 200,
|
||||
CTaskVehicleProjectile = 201,
|
||||
CTaskSmashCarWindow = 204,
|
||||
CTaskMoveGoToPoint = 205,
|
||||
CTaskMoveAchieveHeading = 206,
|
||||
CTaskMoveFaceTarget = 207,
|
||||
CTaskComplexGoToPointAndStandStillTimed = 208,
|
||||
CTaskMoveGoToPointAndStandStill = 208,
|
||||
CTaskMoveFollowPointRoute = 209,
|
||||
CTaskMoveSeekEntity_CEntitySeekPosCalculatorStandard = 210,
|
||||
CTaskMoveSeekEntity_CEntitySeekPosCalculatorLastNavMeshIntersection = 211,
|
||||
CTaskMoveSeekEntity_CEntitySeekPosCalculatorLastNavMeshIntersection2 = 212,
|
||||
CTaskMoveSeekEntity_CEntitySeekPosCalculatorXYOffsetFixed = 213,
|
||||
CTaskMoveSeekEntity_CEntitySeekPosCalculatorXYOffsetFixed2 = 214,
|
||||
CTaskExhaustedFlee = 215,
|
||||
CTaskGrowlAndFlee = 216,
|
||||
CTaskScenarioFlee = 217,
|
||||
CTaskSmartFlee = 218,
|
||||
CTaskFlyAway = 219,
|
||||
CTaskWalkAway = 220,
|
||||
CTaskWander = 221,
|
||||
CTaskWanderInArea = 222,
|
||||
CTaskFollowLeaderInFormation = 223,
|
||||
CTaskGoToPointAnyMeans = 224,
|
||||
CTaskTurnToFaceEntityOrCoord = 225,
|
||||
CTaskFollowLeaderAnyMeans = 226,
|
||||
CTaskFlyToPoint = 228,
|
||||
CTaskFlyingWander = 229,
|
||||
CTaskGoToPointAiming = 230,
|
||||
CTaskGoToScenario = 231,
|
||||
CTaskSeekEntityAiming = 233,
|
||||
CTaskSlideToCoord = 234,
|
||||
CTaskSwimmingWander = 235,
|
||||
CTaskMoveTrackingEntity = 237,
|
||||
CTaskMoveFollowNavMesh = 238,
|
||||
CTaskMoveGoToPointOnRoute = 239,
|
||||
CTaskEscapeBlast = 240,
|
||||
CTaskMoveWander = 241,
|
||||
CTaskMoveBeInFormation = 242,
|
||||
CTaskMoveCrowdAroundLocation = 243,
|
||||
CTaskMoveCrossRoadAtTrafficLights = 244,
|
||||
CTaskMoveWaitForTraffic = 245,
|
||||
CTaskMoveGoToPointStandStillAchieveHeading = 246,
|
||||
CTaskMoveGetOntoMainNavMesh = 251,
|
||||
CTaskMoveSlideToCoord = 252,
|
||||
CTaskMoveGoToPointRelativeToEntityAndStandStill = 253,
|
||||
CTaskHelicopterStrafe = 254,
|
||||
CTaskGetOutOfWater = 256,
|
||||
CTaskMoveFollowEntityOffset = 259,
|
||||
CTaskFollowWaypointRecording = 261,
|
||||
CTaskMotionPed = 264,
|
||||
CTaskMotionPedLowLod = 265,
|
||||
CTaskHumanLocomotion = 268,
|
||||
CTaskMotionBasicLocomotionLowLod = 269,
|
||||
CTaskMotionStrafing = 270,
|
||||
CTaskMotionTennis = 271,
|
||||
CTaskMotionAiming = 272,
|
||||
CTaskBirdLocomotion = 273,
|
||||
CTaskFlightlessBirdLocomotion = 274,
|
||||
CTaskFishLocomotion = 278,
|
||||
CTaskQuadLocomotion = 279,
|
||||
CTaskMotionDiving = 280,
|
||||
CTaskMotionSwimming = 281,
|
||||
CTaskMotionParachuting = 282,
|
||||
CTaskMotionDrunk = 283,
|
||||
CTaskRepositionMove = 284,
|
||||
CTaskMotionAimingTransition = 285,
|
||||
CTaskThrowProjectile = 286,
|
||||
CTaskCover = 287,
|
||||
CTaskMotionInCover = 288,
|
||||
CTaskAimAndThrowProjectile = 289,
|
||||
CTaskGun = 290,
|
||||
CTaskAimFromGround = 291,
|
||||
CTaskAimGunVehicleDriveBy = 295,
|
||||
CTaskAimGunScripted = 296,
|
||||
CTaskReloadGun = 298,
|
||||
CTaskWeaponBlocked = 299,
|
||||
CTaskEnterCover = 300,
|
||||
CTaskExitCover = 301,
|
||||
CTaskAimGunFromCoverIntro = 302,
|
||||
CTaskAimGunFromCoverOutro = 303,
|
||||
CTaskAimGunBlindFire = 304,
|
||||
CTaskCombatClosestTargetInArea = 307,
|
||||
CTaskCombatAdditionalTask = 308,
|
||||
CTaskInCover = 309,
|
||||
CTaskAimSweep = 313,
|
||||
CTaskSharkCircle = 319,
|
||||
CTaskSharkAttack = 320,
|
||||
CTaskAgitated = 321,
|
||||
CTaskAgitatedAction = 322,
|
||||
CTaskConfront = 323,
|
||||
CTaskIntimidate = 324,
|
||||
CTaskShove = 325,
|
||||
CTaskShoved = 326,
|
||||
CTaskCrouchToggle = 328,
|
||||
CTaskRevive = 329,
|
||||
CTaskParachute = 335,
|
||||
CTaskParachuteObject = 336,
|
||||
CTaskTakeOffPedVariation = 337,
|
||||
CTaskCombatSeekCover = 340,
|
||||
CTaskCombatFlank = 342,
|
||||
CTaskCombat = 343,
|
||||
CTaskCombatMounted = 344,
|
||||
CTaskMoveCircle = 345,
|
||||
CTaskMoveCombatMounted = 346,
|
||||
CTaskSearch = 347,
|
||||
CTaskSearchOnFoot = 348,
|
||||
CTaskSearchInAutomobile = 349,
|
||||
CTaskSearchInBoat = 350,
|
||||
CTaskSearchInHeli = 351,
|
||||
CTaskThreatResponse = 352,
|
||||
CTaskInvestigate = 353,
|
||||
CTaskStandGuardFSM = 354,
|
||||
CTaskPatrol = 355,
|
||||
CTaskShootAtTarget = 356,
|
||||
CTaskSetAndGuardArea = 357,
|
||||
CTaskStandGuard = 358,
|
||||
CTaskSeparate = 359,
|
||||
CTaskStayInCover = 360,
|
||||
CTaskVehicleCombat = 361,
|
||||
CTaskVehiclePersuit = 362,
|
||||
CTaskVehicleChase = 363,
|
||||
CTaskDraggingToSafety = 364,
|
||||
CTaskDraggedToSafety = 365,
|
||||
CTaskVariedAimPose = 366,
|
||||
CTaskMoveWithinAttackWindow = 367,
|
||||
CTaskMoveWithinDefensiveArea = 368,
|
||||
CTaskShootOutTire = 369,
|
||||
CTaskShellShocked = 370,
|
||||
CTaskBoatChase = 371,
|
||||
CTaskBoatCombat = 372,
|
||||
CTaskBoatStrafe = 373,
|
||||
CTaskHeliChase = 374,
|
||||
CTaskHeliCombat = 375,
|
||||
CTaskSubmarineCombat = 376,
|
||||
CTaskSubmarineChase = 377,
|
||||
CTaskPlaneChase = 378,
|
||||
CTaskTargetUnreachable = 379,
|
||||
CTaskTargetUnreachableInInterior = 380,
|
||||
CTaskTargetUnreachableInExterior = 381,
|
||||
CTaskStealthKill = 382,
|
||||
CTaskWrithe = 383,
|
||||
CTaskAdvance = 384,
|
||||
CTaskCharge = 385,
|
||||
CTaskMoveToTacticalPoint = 386,
|
||||
CTaskToHurtTransit = 387,
|
||||
CTaskAnimatedHitByExplosion = 388,
|
||||
CTaskNMRelax = 389,
|
||||
CTaskNMPose = 391,
|
||||
CTaskNMBrace = 392,
|
||||
CTaskNMBuoyancy = 393,
|
||||
CTaskNMInjuredOnGround = 394,
|
||||
CTaskNMShot = 395,
|
||||
CTaskNMHighFall = 396,
|
||||
CTaskNMBalance = 397,
|
||||
CTaskNMElectrocute = 398,
|
||||
CTaskNMPrototype = 399,
|
||||
CTaskNMExplosion = 400,
|
||||
CTaskNMOnFire = 401,
|
||||
CTaskNMScriptControl = 402,
|
||||
CTaskNMJumpRollFromRoadVehicle = 403,
|
||||
CTaskNMFlinch = 404,
|
||||
CTaskNMSit = 405,
|
||||
CTaskNMFallDown = 406,
|
||||
CTaskBlendFromNM = 407,
|
||||
CTaskNMControl = 408,
|
||||
CTaskNMDangle = 409,
|
||||
CTaskNMGenericAttach = 412,
|
||||
CTaskNMDraggingToSafety = 414,
|
||||
CTaskNMThroughWindscreen = 415,
|
||||
CTaskNMRiverRapids = 416,
|
||||
CTaskNMSimple = 417,
|
||||
CTaskRageRagdoll = 418,
|
||||
CTaskJumpVault = 421,
|
||||
CTaskJump = 422,
|
||||
CTaskFall = 423,
|
||||
CTaskReactAimWeapon = 425,
|
||||
CTaskChat = 426,
|
||||
CTaskMobilePhone = 427,
|
||||
CTaskReactToDeadPed = 428,
|
||||
CTaskSearchForUnknownThreat = 430,
|
||||
CTaskBomb = 432,
|
||||
CTaskDetonator = 433,
|
||||
CTaskAnimatedAttach = 435,
|
||||
CTaskCutScene = 441,
|
||||
CTaskReactToExplosion = 442,
|
||||
CTaskReactToImminentExplosion = 443,
|
||||
CTaskDiveToGround = 444,
|
||||
CTaskReactAndFlee = 445,
|
||||
CTaskSidestep = 446,
|
||||
CTaskCallPolice = 447,
|
||||
CTaskReactInDirection = 448,
|
||||
CTaskReactToBuddyShot = 449,
|
||||
CTaskVehicleGoToAutomobileNew = 454,
|
||||
CTaskVehicleGoToPlane = 455,
|
||||
CTaskVehicleGoToHelicopter = 456,
|
||||
CTaskVehicleGoToSubmarine = 457,
|
||||
CTaskVehicleGoToBoat = 458,
|
||||
CTaskVehicleGoToPointAutomobile = 459,
|
||||
CTaskVehicleGoToPointWithAvoidanceAutomobile = 460,
|
||||
CTaskVehiclePursue = 461,
|
||||
CTaskVehicleRam = 462,
|
||||
CTaskVehicleSpinOut = 463,
|
||||
CTaskVehicleApproach = 464,
|
||||
CTaskVehicleThreePointTurn = 465,
|
||||
CTaskVehicleDeadDriver = 466,
|
||||
CTaskVehicleCruiseNew = 467,
|
||||
CTaskVehicleCruiseBoat = 468,
|
||||
CTaskVehicleStop = 469,
|
||||
CTaskVehiclePullOver = 470,
|
||||
CTaskVehiclePassengerExit = 471,
|
||||
CTaskVehicleFlee = 472,
|
||||
CTaskVehicleFleeAirborne = 473,
|
||||
CTaskVehicleFleeBoat = 474,
|
||||
CTaskVehicleFollowRecording = 475,
|
||||
CTaskVehicleFollow = 476,
|
||||
CTaskVehicleBlock = 477,
|
||||
CTaskVehicleBlockCruiseInFront = 478,
|
||||
CTaskVehicleBlockBrakeInFront = 479,
|
||||
CTaskVehicleBlockBackAndForth = 478,
|
||||
CTaskVehicleCrash = 481,
|
||||
CTaskVehicleLand = 482,
|
||||
CTaskVehicleLandPlane = 483,
|
||||
CTaskVehicleHover = 484,
|
||||
CTaskVehicleAttack = 485,
|
||||
CTaskVehicleAttackTank = 486,
|
||||
CTaskVehicleCircle = 487,
|
||||
CTaskVehiclePoliceBehaviour = 488,
|
||||
CTaskVehiclePoliceBehaviourHelicopter = 489,
|
||||
CTaskVehiclePoliceBehaviourBoat = 490,
|
||||
CTaskVehicleEscort = 491,
|
||||
CTaskVehicleHeliProtect = 492,
|
||||
CTaskVehiclePlayerDriveAutomobile = 494,
|
||||
CTaskVehiclePlayerDriveBike = 495,
|
||||
CTaskVehiclePlayerDriveBoat = 496,
|
||||
CTaskVehiclePlayerDriveSubmarine = 497,
|
||||
CTaskVehiclePlayerDriveSubmarineCar = 498,
|
||||
CTaskVehiclePlayerDriveAmphibiousAutomobile = 499,
|
||||
CTaskVehiclePlayerDrivePlane = 500,
|
||||
CTaskVehiclePlayerDriveHeli = 501,
|
||||
CTaskVehiclePlayerDriveAutogyro = 502,
|
||||
CTaskVehiclePlayerDriveDiggerArm = 503,
|
||||
CTaskVehiclePlayerDriveTrain = 504,
|
||||
CTaskVehiclePlaneChase = 505,
|
||||
CTaskVehicleNoDriver = 506,
|
||||
CTaskVehicleAnimation = 507,
|
||||
CTaskVehicleConvertibleRoof = 508,
|
||||
CTaskVehicleParkNew = 509,
|
||||
CTaskVehicleFollowWaypointRecording = 510,
|
||||
CTaskVehicleGoToNavmesh = 511,
|
||||
CTaskVehicleReactToCopSiren = 512,
|
||||
CTaskVehicleGotoLongRange = 513,
|
||||
CTaskVehicleWait = 514,
|
||||
CTaskVehicleReverse = 515,
|
||||
CTaskVehicleBrake = 516,
|
||||
CTaskVehicleHandBrake = 517,
|
||||
CTaskVehicleTurn = 518,
|
||||
CTaskVehicleGoForward = 519,
|
||||
CTaskVehicleSwerve = 520,
|
||||
CTaskVehicleFlyDirection = 521,
|
||||
CTaskVehicleHeadonCollision = 522,
|
||||
CTaskVehicleBoostUseSteeringAngle = 523,
|
||||
CTaskVehicleShotTire = 524,
|
||||
CTaskVehicleBurnout = 525,
|
||||
CTaskVehicleRevEngine = 526,
|
||||
CTaskVehicleSurfaceInSubmarine = 527,
|
||||
CTaskVehiclePullAlongside = 528,
|
||||
CTaskVehicleTransformToSubmarine = 529,
|
||||
CTaskAnimatedFallback = 530
|
||||
};
|
@ -1,293 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using GTA.Math;
|
||||
using System.Drawing;
|
||||
using GTA;
|
||||
using RageCoop.Core;
|
||||
using GTA.Native;
|
||||
using System.IO;
|
||||
using System.Xml.Serialization;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal static class Util
|
||||
{
|
||||
public static SizeF ResolutionMaintainRatio
|
||||
{
|
||||
get
|
||||
{
|
||||
// Get the game width and height
|
||||
int screenw = GTA.UI.Screen.Resolution.Width;
|
||||
int screenh = GTA.UI.Screen.Resolution.Height;
|
||||
// Calculate the ratio
|
||||
float ratio = (float)screenw / screenh;
|
||||
// And the width with that ratio
|
||||
float width = 1080f * ratio;
|
||||
// Finally, return a SizeF
|
||||
return new SizeF(width, 1080f);
|
||||
}
|
||||
}
|
||||
public static bool WorldToScreen(Vector3 pos, ref Point screenPos)
|
||||
{
|
||||
float x, y;
|
||||
unsafe
|
||||
{
|
||||
var res = ResolutionMaintainRatio;
|
||||
if (Function.Call<bool>(Hash.GET_SCREEN_COORD_FROM_WORLD_COORD, pos.X, pos.Y, pos.Z, &x, &y))
|
||||
{
|
||||
screenPos =new Point((int)(res.Width*x), (int)(y*1080));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
#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 string SettingsPath= "Scripts\\RageCoop\\Data\\RageCoop.Client.Settings.xml";
|
||||
public static Settings ReadSettings()
|
||||
{
|
||||
XmlSerializer ser = new XmlSerializer(typeof(Settings));
|
||||
|
||||
string path = SettingsPath;
|
||||
Directory.CreateDirectory(Directory.GetParent(path).FullName);
|
||||
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 = SettingsPath ;
|
||||
Directory.CreateDirectory(Directory.GetParent(path).FullName);
|
||||
|
||||
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 Vector3 PredictPosition(this Entity e, bool applyDefault = true)
|
||||
{
|
||||
return e.Position+e.Velocity*((applyDefault ? SyncParameters.PositioinPredictionDefault : 0)+Networking.Latency);
|
||||
}
|
||||
|
||||
public static Vehicle CreateVehicle(Model model, Vector3 position, float heading = 0f)
|
||||
{
|
||||
if (!model.IsLoaded) { return null; }
|
||||
return (Vehicle)Entity.FromHandle(Function.Call<int>(Hash.CREATE_VEHICLE, model.Hash, position.X, position.Y, position.Z, heading, false, false));
|
||||
}
|
||||
public static Ped CreatePed(Model model, Vector3 position, float heading = 0f)
|
||||
{
|
||||
if (!model.IsLoaded) { return null; }
|
||||
return (Ped)Entity.FromHandle(Function.Call<int>(Hash.CREATE_PED, 26, model.Hash, position.X, position.Y, position.Z, heading, false, false));
|
||||
}
|
||||
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 void SetFrozen(this Entity e,bool toggle)
|
||||
{
|
||||
Function.Call(Hash.FREEZE_ENTITY_POSITION, e, toggle);
|
||||
}
|
||||
|
||||
public static SyncedPed GetSyncEntity(this Ped p)
|
||||
{
|
||||
if (p == null) { return null; }
|
||||
var c = EntityPool.GetPedByHandle(p.Handle);
|
||||
if (c==null) { EntityPool.Add(c=new SyncedPed(p)); }
|
||||
return c;
|
||||
}
|
||||
|
||||
public static SyncedVehicle GetSyncEntity(this Vehicle veh)
|
||||
{
|
||||
if (veh == null) { return null; }
|
||||
var v = EntityPool.GetVehicleByHandle(veh.Handle);
|
||||
if (v==null) { EntityPool.Add(v=new SyncedVehicle(veh)); }
|
||||
return v;
|
||||
}
|
||||
|
||||
public static byte GetPlayerRadioIndex()
|
||||
{
|
||||
return (byte)Function.Call<int>(Hash.GET_PLAYER_RADIO_STATION_INDEX);
|
||||
}
|
||||
public static void SetPlayerRadioIndex(int index)
|
||||
{
|
||||
Function.Call(Hash.SET_RADIO_TO_STATION_INDEX, index);
|
||||
}
|
||||
public static byte[] GetHash(this string inputString)
|
||||
{
|
||||
using (HashAlgorithm algorithm = SHA256.Create())
|
||||
return algorithm.ComputeHash(Encoding.UTF8.GetBytes(inputString));
|
||||
}
|
||||
|
||||
#region WIN32
|
||||
|
||||
const UInt32 WM_KEYDOWN = 0x0100;
|
||||
public static void Reload()
|
||||
{
|
||||
string reloadKey="None";
|
||||
var lines = File.ReadAllLines("ScriptHookVDotNet.ini");
|
||||
foreach (var l in lines)
|
||||
{
|
||||
var ss = l.Split('=');
|
||||
if(ss.Length > 0 && ss[0]=="ReloadKey")
|
||||
{
|
||||
reloadKey = ss[1];
|
||||
}
|
||||
}
|
||||
var lineList = lines.ToList();
|
||||
if (reloadKey=="None")
|
||||
{
|
||||
foreach (var l in lines)
|
||||
{
|
||||
var ss = l.Split('=');
|
||||
if (ss.Length > 0 && ss[0]=="ReloadKey")
|
||||
{
|
||||
reloadKey = ss[1];
|
||||
lineList.Remove(l);
|
||||
}
|
||||
}
|
||||
lineList.Add("ReloadKey=Insert");
|
||||
File.WriteAllLines("ScriptHookVDotNet.ini",lineList.ToArray());
|
||||
}
|
||||
Keys key = (Keys)Enum.Parse(typeof(Keys), reloadKey, true);
|
||||
|
||||
// Move log file so it doesn't get deleted
|
||||
Main.Logger.Dispose();
|
||||
|
||||
var path = Main.Logger.LogPath+".last.log";
|
||||
try
|
||||
{
|
||||
if (File.Exists(path)) { File.Delete(path); }
|
||||
if (File.Exists(Main.Logger.LogPath)) { File.Move(Main.Logger.LogPath, path); }
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
GTA.UI.Notification.Show(ex.Message);
|
||||
}
|
||||
|
||||
PostMessage(System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle, WM_KEYDOWN, (int)key, 0);
|
||||
}
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
static extern bool PostMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);
|
||||
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern ulong GetTickCount64();
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -1,274 +0,0 @@
|
||||
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;
|
||||
}
|
||||
if (veh.HasRoof)
|
||||
{
|
||||
flags|=VehicleDataFlags.HasRoof;
|
||||
}
|
||||
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
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 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)
|
||||
{
|
||||
if (!door.IsBroken)
|
||||
{
|
||||
door.Break(leavedoors);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
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 Dictionary<int, int> GetPassengers(this Vehicle veh)
|
||||
{
|
||||
Dictionary<int, int> ps = new Dictionary<int, int>();
|
||||
var d = veh.Driver;
|
||||
if (d!=null&&d.IsSittingInVehicle())
|
||||
{
|
||||
ps.Add(-1, d.GetSyncEntity().ID);
|
||||
}
|
||||
foreach (Ped p in veh.Passengers)
|
||||
{
|
||||
if (p.IsSittingInVehicle())
|
||||
{
|
||||
ps.Add((int)p.SeatIndex, (int)p.GetSyncEntity().ID);
|
||||
}
|
||||
}
|
||||
return ps;
|
||||
}
|
||||
|
||||
|
||||
public static void SetDeluxoHoverState(this Vehicle deluxo, bool hover)
|
||||
{
|
||||
Function.Call(Hash._SET_VEHICLE_HOVER_TRANSFORM_PERCENTAGE, deluxo, hover ? 1f : 0f);
|
||||
}
|
||||
public static bool IsDeluxoHovering(this Vehicle deluxo)
|
||||
{
|
||||
return Math.Abs(deluxo.Bones[27].ForwardVector.GetCosTheta(deluxo.ForwardVector)-1)>0.05;
|
||||
}
|
||||
public static void SetDeluxoWingRatio(this Vehicle v, float ratio)
|
||||
{
|
||||
Function.Call(Hash._SET_SPECIALFLIGHT_WING_RATIO, v, ratio);
|
||||
}
|
||||
public static float GetDeluxoWingRatio(this Vehicle v)
|
||||
{
|
||||
return v.Bones[99].Position.DistanceTo(v.Bones[92].Position)-1.43f;
|
||||
}
|
||||
public static float GetNozzleAngel(this Vehicle plane)
|
||||
{
|
||||
return Function.Call<float>(Hash._GET_VEHICLE_FLIGHT_NOZZLE_POSITION, plane);
|
||||
}
|
||||
public static bool HasNozzle(this Vehicle v)
|
||||
{
|
||||
|
||||
switch (v.Model.Hash)
|
||||
{
|
||||
// Hydra
|
||||
case 970385471:
|
||||
return true;
|
||||
|
||||
// Avenger
|
||||
case -2118308144:
|
||||
return true;
|
||||
|
||||
// Tula
|
||||
case 1043222410:
|
||||
return true;
|
||||
|
||||
// Avenger
|
||||
case 408970549:
|
||||
return true;
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public static void SetNozzleAngel(this Vehicle plane, float ratio)
|
||||
{
|
||||
Function.Call(Hash.SET_VEHICLE_FLIGHT_NOZZLE_POSITION, plane, ratio);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -1,323 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using GTA;
|
||||
using GTA.Native;
|
||||
using GTA.Math;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal class MuzzleInfo
|
||||
{
|
||||
public MuzzleInfo(Vector3 pos,Vector3 forward)
|
||||
{
|
||||
Position = pos;
|
||||
ForawardVector=forward;
|
||||
}
|
||||
public Vector3 Position;
|
||||
public Vector3 ForawardVector;
|
||||
}
|
||||
internal static class WeaponUtil
|
||||
{
|
||||
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 Vector3 GetMuzzlePosition(this Ped p)
|
||||
{
|
||||
var w = p.Weapons.CurrentWeaponObject;
|
||||
if (w!=null)
|
||||
{
|
||||
var hash = p.Weapons.Current.Hash;
|
||||
if (MuzzleBoneIndexes.ContainsKey(hash)) { return w.Bones[MuzzleBoneIndexes[hash]].Position; }
|
||||
return w.Position;
|
||||
}
|
||||
return p.Bones[Bone.SkelRightHand].Position;
|
||||
}
|
||||
static long BulletsShot=0;
|
||||
|
||||
public static float GetWeaponDamage(this Ped P, uint hash)
|
||||
{
|
||||
var comp = P.Weapons.Current.Components.GetSuppressorComponent();
|
||||
return Function.Call<float>(Hash.GET_WEAPON_DAMAGE, hash, comp.Active ? comp.ComponentHash : WeaponComponentHash.Invalid);
|
||||
|
||||
/*
|
||||
if (P.IsInVehicle() && (hash!=(uint)P.Weapons.Current.Hash))
|
||||
{
|
||||
// This is a vehicle weapon
|
||||
P.VehicleWeapon=(VehicleWeaponHash)hash;
|
||||
return 100;
|
||||
}
|
||||
switch (P.Weapons.Current.Group)
|
||||
{
|
||||
case WeaponGroup.Pistol: return 30;
|
||||
case WeaponGroup.AssaultRifle: return 30;
|
||||
case WeaponGroup.SMG: return 20;
|
||||
case WeaponGroup.MG: return 40;
|
||||
case WeaponGroup.Shotgun: return 30;
|
||||
case WeaponGroup.Sniper: return 200;
|
||||
case WeaponGroup.Heavy: return 30;
|
||||
}
|
||||
return 0;
|
||||
*/
|
||||
}
|
||||
|
||||
public static MuzzleInfo GetMuzzleInfo(this Vehicle v)
|
||||
{
|
||||
BulletsShot++;
|
||||
int i;
|
||||
switch (v.Model.Hash)
|
||||
{
|
||||
// JB7002
|
||||
case 394110044:
|
||||
i=BulletsShot%2==0 ? 54 : 53;
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
|
||||
|
||||
// DOMINATOR5
|
||||
case -1375060657:
|
||||
i=BulletsShot%2==0 ? 35 : 36;
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
|
||||
|
||||
|
||||
|
||||
// IMPALER3
|
||||
case -1924800695:
|
||||
i=BulletsShot%2==0 ? 75 : 76;
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
|
||||
|
||||
|
||||
|
||||
// IMPERATOR2
|
||||
case 1637620610:
|
||||
i=BulletsShot%2==0 ? 97 : 99;
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
|
||||
|
||||
|
||||
|
||||
// SLAMVAN5
|
||||
case 373261600:
|
||||
i=BulletsShot%2==0 ? 51 : 53;
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
|
||||
|
||||
// RUINER2
|
||||
case 941494461:
|
||||
i=BulletsShot%2==0 ? 65 : 66;
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
|
||||
|
||||
// TAMPA3
|
||||
case -1210451983:
|
||||
return new MuzzleInfo(v.Bones[87].Position, v.Bones[87].ForwardVector);
|
||||
|
||||
// SCRAMJET
|
||||
case -638562243:
|
||||
i=BulletsShot%2==0 ? 44 : 45;
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
|
||||
|
||||
// VIGILANTE
|
||||
case -1242608589:
|
||||
i=BulletsShot%2==0 ? 42 : 43;
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
|
||||
|
||||
// ZR380
|
||||
case 540101442:
|
||||
i=BulletsShot%2==0 ? 57 : 63;
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
|
||||
|
||||
// ZR3802
|
||||
case -1106120762:
|
||||
i=BulletsShot%2==0 ? 57 : 63;
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
|
||||
|
||||
// ZR3803
|
||||
case -1478704292:
|
||||
i=BulletsShot%2==0 ? 53 : 59;
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
|
||||
|
||||
// STROMBERG
|
||||
case 886810209:
|
||||
i=BulletsShot%2==0 ? 85 : 84;
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
|
||||
|
||||
// SLAMVAN4
|
||||
case -2061049099:
|
||||
i=BulletsShot%2==0 ? 76 : 78;
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
|
||||
|
||||
// IMPERATOR
|
||||
case 444994115:
|
||||
i=BulletsShot%2==0 ? 88 : 86;
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
|
||||
|
||||
// IMPALER2
|
||||
case 1009171724:
|
||||
i=BulletsShot%2==0 ? 63 : 64;
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
|
||||
|
||||
// DOMINATOR4
|
||||
case -688189648:
|
||||
i=BulletsShot%2==0 ? 59 : 60;
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
|
||||
|
||||
// SAVAGE
|
||||
case -82626025:
|
||||
return new MuzzleInfo(v.Bones[30].Position, v.Bones[30].ForwardVector);
|
||||
|
||||
// BUZZARD
|
||||
case 788747387:
|
||||
i=BulletsShot%2==0 ? 28 : 23;
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
|
||||
|
||||
// ANNIHL
|
||||
case 837858166:
|
||||
i=(int)BulletsShot%4+35;
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
|
||||
|
||||
// HYDRA
|
||||
case 970385471:
|
||||
i=BulletsShot%2==0 ? 29 : 28;
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
|
||||
|
||||
// STARLING
|
||||
case -1700874274:
|
||||
i=BulletsShot%2==0 ? 24 : 12;
|
||||
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
|
||||
|
||||
// RHINO
|
||||
case 782665360:
|
||||
return new MuzzleInfo(v.Bones[35].Position,v.Bones[35].ForwardVector);
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsUsingProjectileWeapon(this Ped p)
|
||||
{
|
||||
var vp = p.VehicleWeapon;
|
||||
var type = Function.Call<int>(Hash.GET_WEAPON_DAMAGE_TYPE, vp);
|
||||
if (vp!=VehicleWeaponHash.Invalid)
|
||||
{
|
||||
if(type==3)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return VehicleProjectileWeapons.Contains(vp) || (type==5 && !ExplosiveBullets.Contains((uint)vp));
|
||||
}
|
||||
else
|
||||
{
|
||||
var w = p.Weapons.Current;
|
||||
return w.Group==WeaponGroup.Thrown || ProjectileWeapons.Contains(w.Hash);
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly HashSet<uint> ExplosiveBullets = new HashSet<uint>
|
||||
{
|
||||
(uint)VehicleWeaponHash.PlayerLazer,
|
||||
(uint)WeaponHash.Railgun,
|
||||
1638077257
|
||||
};
|
||||
|
||||
public static readonly Dictionary<WeaponHash, int> MuzzleBoneIndexes = new Dictionary<WeaponHash, int>
|
||||
{
|
||||
{WeaponHash.HeavySniper,6},
|
||||
{WeaponHash.MarksmanRifle,9},
|
||||
{WeaponHash.SniperRifle,9},
|
||||
{WeaponHash.AdvancedRifle,5},
|
||||
{WeaponHash.SpecialCarbine,9},
|
||||
{WeaponHash.BullpupRifle,7},
|
||||
{WeaponHash.AssaultRifle,9},
|
||||
{WeaponHash.CarbineRifle,6},
|
||||
{WeaponHash.MachinePistol,5},
|
||||
{WeaponHash.SMG,5},
|
||||
{WeaponHash.AssaultSMG,6},
|
||||
{WeaponHash.CombatPDW,5},
|
||||
{WeaponHash.MG,6},
|
||||
{WeaponHash.CombatMG,7},
|
||||
{WeaponHash.Gusenberg,7},
|
||||
{WeaponHash.MicroSMG,10},
|
||||
{WeaponHash.APPistol,8},
|
||||
{WeaponHash.StunGun,4},
|
||||
{WeaponHash.Pistol,8},
|
||||
{WeaponHash.CombatPistol,8},
|
||||
{WeaponHash.Pistol50,7},
|
||||
{WeaponHash.SNSPistol,8},
|
||||
{WeaponHash.HeavyPistol,8},
|
||||
{WeaponHash.VintagePistol,8},
|
||||
{WeaponHash.Railgun,9},
|
||||
{WeaponHash.Minigun,5},
|
||||
{WeaponHash.Musket,3},
|
||||
{WeaponHash.HeavyShotgun,10},
|
||||
{WeaponHash.PumpShotgun,11},
|
||||
{WeaponHash.SawnOffShotgun,8},
|
||||
{WeaponHash.BullpupShotgun,8},
|
||||
{WeaponHash.AssaultShotgun,9},
|
||||
{WeaponHash.HeavySniperMk2,11},
|
||||
{WeaponHash.MarksmanRifleMk2,9},
|
||||
{WeaponHash.CarbineRifleMk2,13},
|
||||
{WeaponHash.SpecialCarbineMk2,16},
|
||||
{WeaponHash.BullpupRifleMk2,8},
|
||||
{WeaponHash.CompactRifle,7},
|
||||
{WeaponHash.MilitaryRifle,11},
|
||||
{WeaponHash.AssaultrifleMk2,17},
|
||||
{WeaponHash.MiniSMG,5},
|
||||
{WeaponHash.SMGMk2,6},
|
||||
{WeaponHash.CombatMGMk2,16},
|
||||
{WeaponHash.UnholyHellbringer,4},
|
||||
{WeaponHash.PistolMk2,12},
|
||||
{WeaponHash.SNSPistolMk2,15},
|
||||
{WeaponHash.CeramicPistol,10},
|
||||
{WeaponHash.MarksmanPistol,4},
|
||||
{WeaponHash.Revolver,7},
|
||||
{WeaponHash.RevolverMk2,7},
|
||||
{WeaponHash.DoubleActionRevolver,7},
|
||||
{WeaponHash.NavyRevolver,7},
|
||||
{WeaponHash.PericoPistol,4},
|
||||
{WeaponHash.FlareGun,4},
|
||||
{WeaponHash.UpNAtomizer,4},
|
||||
{WeaponHash.HomingLauncher,5},
|
||||
{WeaponHash.CompactGrenadeLauncher,8},
|
||||
{WeaponHash.Widowmaker,6},
|
||||
{WeaponHash.GrenadeLauncher,3},
|
||||
{WeaponHash.RPG,9},
|
||||
{WeaponHash.DoubleBarrelShotgun,8},
|
||||
{WeaponHash.SweeperShotgun,7},
|
||||
{WeaponHash.CombatShotgun,7},
|
||||
{WeaponHash.PumpShotgunMk2,7},
|
||||
|
||||
};
|
||||
|
||||
|
||||
public static readonly HashSet<WeaponHash> ProjectileWeapons = new HashSet<WeaponHash> {
|
||||
WeaponHash.HomingLauncher,
|
||||
WeaponHash.RPG,
|
||||
WeaponHash.Firework,
|
||||
WeaponHash.UpNAtomizer,
|
||||
WeaponHash.GrenadeLauncher,
|
||||
WeaponHash.GrenadeLauncherSmoke,
|
||||
WeaponHash.CompactGrenadeLauncher,
|
||||
WeaponHash.FlareGun,
|
||||
};
|
||||
public static readonly HashSet<VehicleWeaponHash> VehicleProjectileWeapons = new HashSet<VehicleWeaponHash> {
|
||||
VehicleWeaponHash.PlaneRocket,
|
||||
VehicleWeaponHash.SpaceRocket,
|
||||
VehicleWeaponHash.Tank,
|
||||
(VehicleWeaponHash)3565779982, // STROMBERG missiles
|
||||
(VehicleWeaponHash)3169388763, // SCRAMJET missiles
|
||||
};
|
||||
}
|
||||
}
|
@ -1,144 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using RageCoop.Core;
|
||||
using GTA;
|
||||
using GTA.Native;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// Don't use it!
|
||||
/// </summary>
|
||||
public class WorldThread : Script
|
||||
{
|
||||
private static bool _lastDisableTraffic = false;
|
||||
|
||||
/// <summary>
|
||||
/// Don't use it!
|
||||
/// </summary>
|
||||
public WorldThread()
|
||||
{
|
||||
Tick += OnTick;
|
||||
Aborted += (sender, e) =>
|
||||
{
|
||||
if (_lastDisableTraffic)
|
||||
{
|
||||
Traffic(true);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void OnTick(object sender, EventArgs e)
|
||||
{
|
||||
if (Game.IsLoading)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Networking.IsOnServer)
|
||||
{
|
||||
return ;
|
||||
}
|
||||
Game.DisableControlThisFrame(Control.FrontendPause);
|
||||
if (Main.Settings.DisableAlternatePause)
|
||||
{
|
||||
Game.DisableControlThisFrame(Control.FrontendPauseAlternate);
|
||||
}
|
||||
|
||||
// Sets a value that determines how aggressive the ocean waves will be.
|
||||
// Values of 2.0 or more make for very aggressive waves like you see during a thunderstorm.
|
||||
Function.Call(Hash.SET_DEEP_OCEAN_SCALER, 0.0f); // Works only ~200 meters around the player
|
||||
|
||||
// Function.Call(Hash.SET_CAN_ATTACK_FRIENDLY, Game.Player.Character.Handle, true, false);
|
||||
if (Main.Settings==null) { return; }
|
||||
if (Main.Settings.DisableTraffic)
|
||||
{
|
||||
if (!_lastDisableTraffic)
|
||||
{
|
||||
Traffic(false);
|
||||
}
|
||||
|
||||
Function.Call(Hash.SET_VEHICLE_POPULATION_BUDGET, 0);
|
||||
Function.Call(Hash.SET_PED_POPULATION_BUDGET, 0);
|
||||
Function.Call(Hash.SET_VEHICLE_DENSITY_MULTIPLIER_THIS_FRAME, 0f);
|
||||
Function.Call(Hash.SET_RANDOM_VEHICLE_DENSITY_MULTIPLIER_THIS_FRAME, 0f);
|
||||
Function.Call(Hash.SET_PARKED_VEHICLE_DENSITY_MULTIPLIER_THIS_FRAME, 0f);
|
||||
Function.Call(Hash.SUPPRESS_SHOCKING_EVENTS_NEXT_FRAME);
|
||||
Function.Call(Hash.SUPPRESS_AGITATION_EVENTS_NEXT_FRAME);
|
||||
}
|
||||
else if (_lastDisableTraffic)
|
||||
{
|
||||
Traffic(true);
|
||||
}
|
||||
|
||||
_lastDisableTraffic = Main.Settings.DisableTraffic;
|
||||
}
|
||||
|
||||
private void Traffic(bool enable)
|
||||
{
|
||||
if (enable)
|
||||
{
|
||||
Function.Call(Hash.REMOVE_SCENARIO_BLOCKING_AREAS);
|
||||
Function.Call(Hash.SET_CREATE_RANDOM_COPS, true);
|
||||
Function.Call(Hash.SET_RANDOM_TRAINS, true);
|
||||
Function.Call(Hash.SET_RANDOM_BOATS, true);
|
||||
Function.Call(Hash.SET_GARBAGE_TRUCKS, true);
|
||||
Function.Call(Hash.SET_PED_POPULATION_BUDGET, 1); // 0 - 3
|
||||
Function.Call(Hash.SET_VEHICLE_POPULATION_BUDGET, 1); // 0 - 3
|
||||
Function.Call(Hash.SET_ALL_VEHICLE_GENERATORS_ACTIVE);
|
||||
Function.Call(Hash.SET_ALL_LOW_PRIORITY_VEHICLE_GENERATORS_ACTIVE, true);
|
||||
Function.Call(Hash.SET_NUMBER_OF_PARKED_VEHICLES, -1);
|
||||
Function.Call(Hash.SET_DISTANT_CARS_ENABLED, true);
|
||||
Function.Call(Hash.DISABLE_VEHICLE_DISTANTLIGHTS, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
Function.Call(Hash.ADD_SCENARIO_BLOCKING_AREA, -10000.0f, -10000.0f, -1000.0f, 10000.0f, 10000.0f, 1000.0f, 0, 1, 1, 1);
|
||||
Function.Call(Hash.SET_CREATE_RANDOM_COPS, false);
|
||||
Function.Call(Hash.SET_RANDOM_TRAINS, false);
|
||||
Function.Call(Hash.SET_RANDOM_BOATS, false);
|
||||
Function.Call(Hash.SET_GARBAGE_TRUCKS, false);
|
||||
Function.Call(Hash.DELETE_ALL_TRAINS);
|
||||
Function.Call(Hash.SET_PED_POPULATION_BUDGET, 3);
|
||||
Function.Call(Hash.SET_VEHICLE_POPULATION_BUDGET, 3);
|
||||
Function.Call(Hash.SET_ALL_LOW_PRIORITY_VEHICLE_GENERATORS_ACTIVE, false);
|
||||
Function.Call(Hash.SET_FAR_DRAW_VEHICLES, false);
|
||||
Function.Call(Hash.SET_NUMBER_OF_PARKED_VEHICLES, 0);
|
||||
Function.Call(Hash.SET_DISTANT_CARS_ENABLED, false);
|
||||
Function.Call(Hash.DISABLE_VEHICLE_DISTANTLIGHTS, true);
|
||||
|
||||
|
||||
foreach (Ped ped in World.GetAllPeds())
|
||||
{
|
||||
SyncedPed c = EntityPool.GetPedByHandle(ped.Handle);
|
||||
if ((c==null) || (c.IsLocal && (ped.Handle!=Game.Player.Character.Handle)&&ped.PopulationType!=EntityPopulationType.Mission))
|
||||
{
|
||||
if (ped.Handle==Game.Player.Character.Handle) { continue; }
|
||||
|
||||
Main.Logger.Trace($"Removing ped {ped.Handle}. Reason:RemoveTraffic");
|
||||
ped.CurrentVehicle?.Delete();
|
||||
ped.Kill();
|
||||
ped.Delete();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
foreach (Vehicle veh in World.GetAllVehicles())
|
||||
{
|
||||
SyncedVehicle v = veh.GetSyncEntity();
|
||||
if (v.MainVehicle==Game.Player.LastVehicle)
|
||||
{
|
||||
// Don't delete player's vehicle
|
||||
continue;
|
||||
}
|
||||
if((v== null) || (v.IsLocal&&veh.PopulationType!=EntityPopulationType.Mission))
|
||||
{
|
||||
Main.Logger.Debug($"Removing Vehicle {veh.Handle}. Reason:ClearTraffic");
|
||||
|
||||
veh.Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 13 KiB |
Reference in New Issue
Block a user