API cleanup, prepare for CustomEvent, fix server not shutting down

This commit is contained in:
Sardelka
2022-06-12 15:39:32 +08:00
parent 88a4f046d4
commit 45c3ff83cf
63 changed files with 440 additions and 8498 deletions

View File

@ -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());
}
}
}

View File

@ -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!");
}
}
}
public enum MuzzleDir:byte
{
Forward=0,
Right = 1,
Up=2,
Backward=3,
Left = 4,
Down=5,
}
}

View File

@ -1,415 +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;
public static readonly string CurrentVersion = "V0_4_1";
public static int LocalPlayerID=0;
internal static RelationshipGroup SyncedPedsGroup;
public static new Settings Settings = null;
#if !NON_INTERACTIVE
#endif
public static Chat MainChat = null;
public static Stopwatch Counter = new Stopwatch();
public static Core.Logging.Logger Logger = null;
public static ulong Ticked = 0;
private static List<Func<bool>> QueuedActions = new List<Func<bool>>();
/// <summary>
/// Don't use it!
/// </summary>
public Main()
{
Settings = Util.ReadSettings();
Logger=new Core.Logging.Logger()
{
LogPath=$"RageCoop\\RageCoop.Client.log",
UseConsole=false,
#if DEBUG
LogLevel = 0,
#else
LogLevel=Settings.LogLevel,
#endif
};
// Required for some synchronization!
/*if (Game.Version < GameVersion.v1_0_1290_1_Steam)
{
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;
}*/
SyncedPedsGroup=World.AddRelationshipGroup("SYNCPED");
Game.Player.Character.RelationshipGroup.SetRelationshipBetweenGroups(SyncedPedsGroup, Relationship.Neutral, true);
#if !NON_INTERACTIVE
#endif
MainChat = new Chat();
Tick += OnTick;
KeyDown += OnKeyDown;
Aborted += (object sender, EventArgs e) => CleanUp();
Util.NativeMemory();
Counter.Restart();
}
#if DEBUG
private ulong _lastDebugData;
private int _debugBytesSend;
private int _debugBytesReceived;
#endif
private void OnTick(object sender, EventArgs e)
{
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);
}
MapLoader.LoadAll();
#if DEBUG
if (Networking.ShowNetworkInfo)
{
ulong time = Util.GetTickCount64();
if (time - _lastDebugData > 1000)
{
_lastDebugData = time;
_debugBytesReceived = Networking.BytesReceived;
Networking.BytesReceived = 0;
_debugBytesSend = Networking.BytesSend;
Networking.BytesSend = 0;
}
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(_debugBytesReceived)}/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(_debugBytesSend)}/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.FORCE_GAME_STATE_PLAYING);
var P = Game.Player.Character;
if (P.IsDead)
{
Function.Call(Hash.TERMINATE_ALL_SCRIPTS_WITH_THIS_NAME, "respawn_controller");
Function.Call(Hash.SET_FADE_OUT_AFTER_DEATH, false);
if (P.Health!=1)
{
P.Health=1;
Game.Player.WantedLevel=0;
Main.Logger.Debug("Player died.");
}
GTA.UI.Screen.StopEffects();
}
else
{
Function.Call(Hash.DISPLAY_HUD, true);
}
}
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;
}
public 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
};
public static Dictionary<int, byte> ServerItems = new Dictionary<int, byte>();
public 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)
{
GTA.UI.Screen.ShowSubtitle(ex.ToString());
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"> The action to be executed, must return a bool indicating whether the action cane be removed after execution.</param>
public static void QueueAction(Func<bool> a)
{
lock (QueuedActions)
{
QueuedActions.Add(a);
}
}
public static void QueueAction(Action a)
{
lock (QueuedActions)
{
QueuedActions.Add(() => { a(); return true; }) ;
}
}
/// <summary>
/// Clears all queued actions
/// </summary>
public static void ClearQueuedActions()
{
lock (QueuedActions) { QueuedActions.Clear(); }
}
public static string DumpCharacters()
{
string s = "Characters:";
lock (EntityPool.PedsLock)
{
foreach (int id in EntityPool.GetPedIDs())
{
var c = EntityPool.GetPedByID(id);
s+=$"\r\nID:{c.ID} Owner:{c.OwnerID} LastUpdated:{c.LastUpdated} LastSynced:{c.LastSynced} LastStateSynced:{c.LastStateSynced}";
// s+=$"\r\n{c.IsAiming} {c.IsJumping} {c.IsOnFire} {c.IsOnLadder} {c.IsRagdoll} {c.IsReloading} {c.IsShooting} {c.Speed}";
}
}
Main.Logger.Trace(s);
return s;
}
public static string DumpPlayers()
{
string s = "Players:";
foreach (PlayerData p in PlayerList.Players)
{
s+=$"\r\nID:{p.PedID} Username:{p.Username}";
}
Main.Logger.Trace(s);
return s;
}
}
}

View File

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

View File

@ -1,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();
}
}
}

View File

@ -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;
}
}
}
}

View File

@ -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=="[AUTO]" ? DownloadString("https://ragecoop.online/stuff/masterserver") : Main.Settings.MasterServer;
serverList = JsonConvert.DeserializeObject<List<ServerListClass>>(DownloadString(realUrl));
// Need to be processed in main thread
Main.QueueAction(() =>
{
if (serverList == null)
{
ResultItem.Title = "Something went wrong!";
return;
}
if (serverList.Count == 0)
{
ResultItem.Title = "No server was found!";
return;
}
CleanUpList();
foreach (ServerListClass server in serverList)
{
string address = $"{server.Address}:{server.Port}";
NativeItem tmpItem = new NativeItem($"[{server.Country}] {server.Name}", $"~b~{address}~s~~n~~g~Version {server.Version}.x~s~") { AltTitle = $"[{server.Players}/{server.MaxPlayers}]" };
tmpItem.Activated += (object sender, EventArgs e) =>
{
try
{
Menu.Visible = false;
Networking.ToggleConnection(address);
#if !NON_INTERACTIVE
CoopMenu.ServerIpItem.AltTitle = address;
CoopMenu.Menu.Visible = true;
#endif
Main.Settings.LastServerAddress = address;
Util.SaveSettings();
}
catch (Exception ex)
{
GTA.UI.Notification.Show($"~r~{ex.Message}");
}
};
Menu.Add(tmpItem);
}
});
}
private static string DownloadString(string url)
{
try
{
// TLS only
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls13 | SecurityProtocolType.Tls12;
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
WebClient client = new WebClient();
return client.DownloadString(url);
}
catch (Exception ex)
{
Main.QueueAction(() =>
{
ResultItem.Title = "Download failed!";
ResultItem.Description = ex.Message;
});
return "";
}
}
}
}

View File

@ -1,128 +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;
if (!Networking.ShowNetworkInfo)
{
Networking.BytesReceived = 0;
Networking.BytesSend = 0;
}
}
}
}

View File

@ -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();
}
}
}

View File

@ -1,169 +0,0 @@
using System.IO;
using System.Linq;
using System.Collections.Generic;
namespace RageCoop.Client
{
internal static class DownloadManager
{
static string downloadFolder = $"RageCoop\\Resources\\{Main.Settings.LastServerAddress.Replace(":", ".")}";
private static readonly Dictionary<int, DownloadFile> InProgressDownloads = new Dictionary<int, DownloadFile>();
public static void AddFile(int id, string name, long length)
{
Main.Logger.Debug($"Downloading file to {downloadFolder}\\{name} , id:{id}");
if (!Directory.Exists(downloadFolder))
{
Directory.CreateDirectory(downloadFolder);
}
if (FileAlreadyExists(downloadFolder, name, length))
{
Main.Logger.Debug($"File already exists! canceling download:{name}");
Cancel(id);
if (name=="Resources.zip")
{
Main.Logger.Debug("Loading resources...");
Resources.Load(Path.Combine(downloadFolder));
}
return;
}
if (!name.EndsWith(".zip"))
{
Cancel(id);
GTA.UI.Notification.Show($"The download of a file from the server was blocked! [{name}]", true);
Main.Logger.Error($"The download of a file from the server was blocked! [{name}]");
return;
}
lock (InProgressDownloads)
{
InProgressDownloads.Add(id, new DownloadFile()
{
FileID = id,
FileName = name,
FileLength = length,
Stream = new FileStream($"{downloadFolder}\\{name}", FileMode.CreateNew, FileAccess.Write, FileShare.ReadWrite)
});
}
}
/// <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}");
return;
}
}
}
public static void Cancel(int id)
{
Main.Logger.Debug($"Canceling download:{id}");
// Tell the server to stop sending chunks
Networking.SendDownloadFinish(id);
DownloadFile file;
lock (InProgressDownloads)
{
if (InProgressDownloads.TryGetValue(id, out file))
{
InProgressDownloads.Remove(id);
file.Dispose();
}
}
}
public static void Complete(int id)
{
DownloadFile f;
if (InProgressDownloads.TryGetValue(id, out f))
{
lock (InProgressDownloads)
{
InProgressDownloads.Remove(id);
f.Dispose();
Main.Logger.Info($"Download finished:{f.FileName}");
if (f.FileName=="Resources.zip")
{
Main.Logger.Debug("Loading resources...");
Resources.Load(Path.Combine(downloadFolder));
}
Networking.SendDownloadFinish(id);
}
}
else
{
Main.Logger.Error($"Download not found! {id}");
}
}
public static void Cleanup()
{
lock (InProgressDownloads)
{
foreach (var file in InProgressDownloads.Values)
{
file.Dispose();
}
InProgressDownloads.Clear();
}
}
}
public class DownloadFile: System.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();
}
}
}
}

View File

@ -1,180 +0,0 @@
using System;
using System.IO;
using System.Linq;
using System.Xml.Serialization;
using System.Collections.Generic;
using RageCoop.Core;
using GTA;
using GTA.Math;
using GTA.Native;
namespace RageCoop.Client
{
/// <summary>
///
/// </summary>
[XmlRoot(ElementName = "Map")]
public class CoopMap
{
/// <summary>
///
/// </summary>
[XmlArray("Props")]
[XmlArrayItem("Prop")]
public List<CoopProp> Props { get; set; } = new List<CoopProp>();
}
/// <summary>
///
/// </summary>
public struct CoopProp
{
/// <summary>
///
/// </summary>
public Vector3 Position { get; set; }
/// <summary>
///
/// </summary>
public Vector3 Rotation { get; set; }
/// <summary>
///
/// </summary>
public int Hash { get; set; }
/// <summary>
///
/// </summary>
public bool Dynamic { get; set; }
/// <summary>
///
/// </summary>
public int Texture { get; set; }
}
public static class MapLoader
{
// string = file name
private static readonly Dictionary<string, CoopMap> _maps = new Dictionary<string, CoopMap>();
private static readonly List<int> _createdObjects = new List<int>();
public static void LoadAll()
{
string downloadFolder = $"RageCoop\\Resources\\{Main.Settings.LastServerAddress.Replace(":", ".")}";
if (!Directory.Exists(downloadFolder))
{
try
{
Directory.CreateDirectory(downloadFolder);
}
catch (Exception ex)
{
Main.Logger.Error(ex.Message);
// Without the directory we can't do the other stuff
return;
}
}
string[] files = Directory.GetFiles(downloadFolder, "*.xml");
lock (_maps)
{
for (int i = 0; i < files.Length; i++)
{
string filePath = files[i];
string fileName = Path.GetFileName(filePath);
XmlSerializer serializer = new XmlSerializer(typeof(CoopMap));
CoopMap map;
using (var stream = new FileStream(filePath, FileMode.Open))
{
try
{
map = (CoopMap)serializer.Deserialize(stream);
}
catch (Exception ex)
{
Main.Logger.Error($"The map with the name \"{fileName}\" couldn't be added!");
Main.Logger.Error($"{ex.Message}");
continue;
}
}
_maps.Add(fileName, map);
}
}
}
public static void LoadMap(string name)
{
lock (_maps) lock (_createdObjects)
{
if (!_maps.ContainsKey(name) || _createdObjects.Count != 0)
{
GTA.UI.Notification.Show($"The map with the name \"{name}\" couldn't be loaded!");
Main.Logger.Error($"The map with the name \"{name}\" couldn't be loaded!");
return;
}
CoopMap map = _maps[name];
foreach (CoopProp prop in map.Props)
{
Model model = prop.Hash.ModelRequest();
if (model == null)
{
Main.Logger.Error($"Model for object \"{model.Hash}\" couldn't be loaded!");
continue;
}
int handle = Function.Call<int>(Hash.CREATE_OBJECT, model.Hash, prop.Position.X, prop.Position.Y, prop.Position.Z, 1, 1, prop.Dynamic);
model.MarkAsNoLongerNeeded();
if (handle == 0)
{
Main.Logger.Error($"Object \"{prop.Hash}\" couldn't be created!");
continue;
}
_createdObjects.Add(handle);
if (prop.Texture > 0 && prop.Texture < 16)
{
Function.Call(Hash._SET_OBJECT_TEXTURE_VARIATION, handle, prop.Texture);
}
}
}
}
public static bool AnyMapLoaded()
{
lock (_createdObjects) return _createdObjects.Any();
}
public static void UnloadMap()
{
lock (_createdObjects)
{
foreach (int handle in _createdObjects)
{
unsafe
{
int tmpHandle = handle;
Function.Call(Hash.DELETE_OBJECT, &tmpHandle);
}
}
_createdObjects.Clear();
}
}
public static void DeleteAll()
{
UnloadMap();
lock (_maps)
{
_maps.Clear();
}
}
}
}

View File

@ -1,213 +0,0 @@
using System;
using System.Linq;
using System.Collections.Generic;
using System.Diagnostics;
using Lidgren.Network;
using RageCoop.Core;
using System.Threading.Tasks;
using System.Threading;
using GTA.Math;
using GTA.Native;
namespace RageCoop.Client
{
internal static partial class Networking
{
public static NetClient Client;
public static float Latency = 0;
public static bool ShowNetworkInfo = false;
public static int BytesReceived = 0;
public static int BytesSend = 0;
static Networking()
{
Task.Run(() =>
{
while (true)
{
if (Client!=null)
{
ProcessMessage(Client.WaitMessage(200));
Client.FlushSendQueue();
}
else
{
Thread.Sleep(20);
}
}
});
}
public static void ToggleConnection(string address)
{
if (IsOnServer)
{
Client.Disconnect("Bye!");
}
else
{
// 623c92c287cc392406e7aaaac1c0f3b0 = RAGECOOP
NetPeerConfiguration config = new NetPeerConfiguration("623c92c287cc392406e7aaaac1c0f3b0")
{
AutoFlushSendQueue = true
};
config.EnableMessageType(NetIncomingMessageType.ConnectionLatencyUpdated);
Client = new NetClient(config);
Client.Start();
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();
// Send HandshakePacket
NetOutgoingMessage outgoingMessage = Client.CreateMessage();
new Packets.Handshake()
{
PedID = Main.LocalPlayerID,
Username = Main.Settings.Username,
ModVersion = Main.CurrentVersion,
}.Pack(outgoingMessage);
Client.Connect(ip[0], short.Parse(ip[1]), outgoingMessage);
}
}
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}");
Main.DumpCharacters();
}
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);
}
private static object DecodeNativeCall(ulong hash, List<object> args, bool returnValue, byte? returnType = null)
{
List<InputArgument> arguments = new List<InputArgument>();
if (args == null || args.Count == 0)
{
return null;
}
for (ushort i = 0; i < args.Count; i++)
{
object x = args.ElementAt(i);
switch (x)
{
case int _:
arguments.Add((int)x);
break;
case bool _:
arguments.Add((bool)x);
break;
case float _:
arguments.Add((float)x);
break;
case string _:
arguments.Add((string)x);
break;
case Vector3 _:
Vector3 vector = (Vector3)x;
arguments.Add((float)vector.X);
arguments.Add((float)vector.Y);
arguments.Add((float)vector.Z);
break;
default:
GTA.UI.Notification.Show("[DecodeNativeCall][" + hash + "]: Type of argument not found!");
return null;
}
}
if (!returnValue)
{
Function.Call((Hash)hash, arguments.ToArray());
return null;
}
switch (returnType.Value)
{
case 0x00: // int
return Function.Call<int>((Hash)hash, arguments.ToArray());
case 0x01: // bool
return Function.Call<bool>((Hash)hash, arguments.ToArray());
case 0x02: // float
return Function.Call<float>((Hash)hash, arguments.ToArray());
case 0x03: // string
return Function.Call<string>((Hash)hash, arguments.ToArray());
case 0x04: // vector3
return Function.Call<Vector3>((Hash)hash, arguments.ToArray());
default:
GTA.UI.Notification.Show("[DecodeNativeCall][" + hash + "]: Type of return not found!");
return null;
}
}
private static void DecodeNativeResponse(Packets.NativeResponse packet)
{
object result = DecodeNativeCall(packet.Hash, packet.Args, true, packet.ResultType);
if (Main.CheckNativeHash.ContainsKey(packet.Hash))
{
foreach (KeyValuePair<ulong, byte> hash in Main.CheckNativeHash)
{
if (hash.Key == packet.Hash)
{
lock (Main.ServerItems)
{
Main.ServerItems.Add((int)result, hash.Value);
}
break;
}
}
}
NetOutgoingMessage outgoingMessage = Client.CreateMessage();
new Packets.NativeResponse()
{
Hash = 0,
Args = new List<object>() { result },
ID = packet.ID
}.Pack(outgoingMessage);
Client.SendMessage(outgoingMessage, NetDeliveryMethod.ReliableOrdered, (byte)ConnectionChannel.Native);
Client.FlushSendQueue();
}
#endregion // -- PLAYER --
#endregion
}
}

View File

@ -1,402 +0,0 @@
using System;
using System.Linq;
using System.Collections.Generic;
using System.Diagnostics;
using Lidgren.Network;
using RageCoop.Core;
using GTA;
using RageCoop.Client.Menus;
using GTA.Math;
using GTA.Native;
namespace RageCoop.Client
{
internal static partial class Networking
{
public static void ProcessMessage(NetIncomingMessage message)
{
if(message == null) { return; }
BytesReceived += message.LengthBytes;
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
Main.QueueAction(() => { GTA.UI.Notification.Show("~y~Trying to connect..."); return true; });
break;
case NetConnectionStatus.Connected:
if (message.SenderConnection.RemoteHailMessage.ReadByte() != (byte)PacketTypes.Handshake)
{
Client.Disconnect("Wrong packet!");
}
else
{
int len = message.SenderConnection.RemoteHailMessage.ReadInt32();
byte[] data = message.SenderConnection.RemoteHailMessage.ReadBytes(len);
Packets.Handshake handshakePacket = new Packets.Handshake();
handshakePacket.Unpack(data);
#if !NON_INTERACTIVE
#endif
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.QueueAction(() =>
GTA.UI.Notification.Show("~r~Disconnected: " + reason));
MapLoader.DeleteAll();
Resources.UnloadAll();
Main.Logger.Info($">> Disconnected << reason: {reason}");
break;
}
break;
case NetIncomingMessageType.Data:
if (message.LengthBytes==0) { break; }
var packetType = (PacketTypes)message.ReadByte();
try
{
int len = message.ReadInt32();
byte[] data = message.ReadBytes(len);
switch (packetType)
{
case PacketTypes.CleanUpWorld:
{
Main.QueueAction(() => { Main.CleanUpWorld(); return true; });
}
break;
case PacketTypes.PlayerConnect:
{
Packets.PlayerConnect packet = new Packets.PlayerConnect();
packet.Unpack(data);
Main.QueueAction(() => PlayerConnect(packet));
}
break;
case PacketTypes.PlayerDisconnect:
{
Packets.PlayerDisconnect packet = new Packets.PlayerDisconnect();
packet.Unpack(data);
Main.QueueAction(() => PlayerDisconnect(packet));
}
break;
case PacketTypes.PlayerInfoUpdate:
{
var packet = new Packets.PlayerInfoUpdate();
packet.Unpack(data);
PlayerList.SetPlayer(packet.PedID, packet.Username, packet.Latency);
break;
}
#region ENTITY SYNC
case PacketTypes.VehicleSync:
{
Packets.VehicleSync packet = new Packets.VehicleSync();
packet.Unpack(data);
VehicleSync(packet);
}
break;
case PacketTypes.PedSync:
{
Packets.PedSync packet = new Packets.PedSync();
packet.Unpack(data);
PedSync(packet);
}
break;
case PacketTypes.VehicleStateSync:
{
Packets.VehicleStateSync packet = new Packets.VehicleStateSync();
packet.Unpack(data);
VehicleStateSync(packet);
}
break;
case PacketTypes.PedStateSync:
{
Packets.PedStateSync packet = new Packets.PedStateSync();
packet.Unpack(data);
PedStateSync(packet);
}
break;
case PacketTypes.ProjectileSync:
{
Packets.ProjectileSync packet = new Packets.ProjectileSync();
packet.Unpack(data);
ProjectileSync(packet);
break;
}
#endregion
case PacketTypes.ChatMessage:
{
Packets.ChatMessage packet = new Packets.ChatMessage();
packet.Unpack(data);
Main.QueueAction(() => { Main.MainChat.AddMessage(packet.Username, packet.Message); return true; });
}
break;
case PacketTypes.NativeCall:
{
Packets.NativeCall packet = new Packets.NativeCall();
packet.Unpack(data);
DecodeNativeCall(packet.Hash, packet.Args, false);
}
break;
case PacketTypes.NativeResponse:
{
Packets.NativeResponse packet = new Packets.NativeResponse();
packet.Unpack(data);
DecodeNativeResponse(packet);
}
break;
case PacketTypes.FileTransferChunk:
{
Packets.FileTransferChunk packet = new Packets.FileTransferChunk();
packet.Unpack(data);
DownloadManager.Write(packet.ID, packet.FileChunk);
}
break;
case PacketTypes.FileTransferRequest:
{
Packets.FileTransferRequest packet = new Packets.FileTransferRequest();
packet.Unpack(data);
DownloadManager.AddFile(packet.ID, packet.Name, packet.FileLength);
}
break;
case PacketTypes.FileTransferComplete:
{
Packets.FileTransferComplete packet = new Packets.FileTransferComplete();
packet.Unpack(data);
Main.Logger.Debug($"Finalizing download:{packet.ID}");
DownloadManager.Complete(packet.ID);
}
break;
case PacketTypes.ServerClientEvent:
{
Packets.ServerClientEvent packet = new Packets.ServerClientEvent();
packet.Unpack(data);
}
break;
default:
if (packetType.IsSyncEvent())
{
// Dispatch to main thread
Main.QueueAction(() => { SyncEvents.HandleEvent(packetType, data); return true; });
}
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.DebugMessage:
case NetIncomingMessageType.ErrorMessage:
case NetIncomingMessageType.WarningMessage:
case NetIncomingMessageType.VerboseDebugMessage:
break;
default:
break;
}
Client.Recycle(message);
}
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.HasFlag(PedDataFlags.IsAiming);
c.IsReloading = flags.HasFlag(PedDataFlags.IsReloading);
c.IsJumping = flags.HasFlag(PedDataFlags.IsJumping);
c.IsRagdoll = flags.HasFlag(PedDataFlags.IsRagdoll);
c.IsOnFire = flags.HasFlag(PedDataFlags.IsOnFire);
c.IsInParachuteFreeFall = flags.HasFlag(PedDataFlags.IsInParachuteFreeFall);
c.IsParachuteOpen = flags.HasFlag(PedDataFlags.IsParachuteOpen);
c.IsOnLadder = flags.HasFlag(PedDataFlags.IsOnLadder);
c.IsVaulting = flags.HasFlag(PedDataFlags.IsVaulting);
c.IsInCover = flags.HasFlag(PedDataFlags.IsInCover);
c.Heading=packet.Heading;
c.LastSynced = Main.Ticked;
if (c.IsAiming)
{
c.AimCoords = packet.AimCoords;
}
if (c.IsRagdoll)
{
c.RotationVelocity=packet.RotationVelocity;
}
}
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.ModelHash=packet.ModelHash;
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.IsMine) { 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.IsMine) { 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.ModelHash=packet.ModelHash;
v.Colors=packet.Colors;
v.LandingGear=packet.LandingGear;
v.EngineRunning = packet.Flag.HasFlag(VehicleDataFlags.IsEngineRunning);
v.LightsOn = packet.Flag.HasFlag(VehicleDataFlags.AreLightsOn);
v.BrakeLightsOn = packet.Flag.HasFlag(VehicleDataFlags.AreBrakeLightsOn);
v.HighBeamsOn = packet.Flag.HasFlag(VehicleDataFlags.AreHighBeamsOn);
v.SireneActive = packet.Flag.HasFlag(VehicleDataFlags.IsSirenActive);
v.IsDead = packet.Flag.HasFlag(VehicleDataFlags.IsDead);
v.HornActive = packet.Flag.HasFlag(VehicleDataFlags.IsHornActive);
v.Transformed = packet.Flag.HasFlag(VehicleDataFlags.IsTransformed);
v.Passengers=new Dictionary<VehicleSeat, SyncedPed>();
v.LockStatus=packet.LockStatus;
v.RadioStation=packet.RadioStation;
v.Flags=packet.Flag;
foreach (KeyValuePair<int, int> pair in packet.Passengers)
{
if (EntityPool.PedExists(pair.Value))
{
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;
}
}
}

View File

@ -1,183 +0,0 @@
using System;
using System.Linq;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
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)
{
Ped p = c.MainPed;
var packet=new Packets.PedSync()
{
ID =c.ID,
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.HasFlag(PedDataFlags.IsAiming))
{
packet.AimCoords = p.GetAimCoord();
}
if (packet.Flag.HasFlag(PedDataFlags.IsRagdoll))
{
packet.RotationVelocity=p.RotationVelocity;
}
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(),
};
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,
Mods = veh.Mods.GetVehicleMods(),
ModelHash=veh.Model.Hash,
EngineHealth=veh.EngineHealth,
Passengers=veh.GetPassengers(),
LockStatus=veh.LockStatus,
};
if (v.MainVehicle==Game.Player.LastVehicle)
{
packet.RadioStation=Util.GetPlayerRadioIndex();
}
Send(packet, ConnectionChannel.VehicleSync);
}
public static void SendProjectile(SyncedProjectile sp)
{
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
if (ShowNetworkInfo)
{
BytesSend += outgoingMessage.LengthBytes;
}
#endif
}
public static void SendDownloadFinish(int id)
{
NetOutgoingMessage outgoingMessage = Client.CreateMessage();
new Packets.FileTransferComplete() { ID = id }.Pack(outgoingMessage);
Client.SendMessage(outgoingMessage, NetDeliveryMethod.ReliableOrdered, (byte)ConnectionChannel.File);
Client.FlushSendQueue();
#if DEBUG
if (ShowNetworkInfo)
{
BytesSend += outgoingMessage.LengthBytes;
}
#endif
}
#endregion
}
}

View File

@ -1,96 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using RageCoop.Core;
using GTA;
using GTA.Native;
namespace RageCoop.Client
{
public 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 List<PlayerData> Players=new List<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.Latency * 1000:N0}ms", player.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)
{
var toset = Players.Where(x => x.PedID==id);
if (toset.Any())
{
var p=toset.First();
p.Username=username;
p.PedID=id;
p.Latency=latency;
}
else
{
PlayerData p = new PlayerData { PedID=id, Username=username,Latency=latency };
Players.Add(p);
}
}
public static PlayerData GetPlayer(int id)
{
return Players.Find(x => x.PedID==id);
}
public static void RemovePlayer(int id)
{
var p = Players.Where(x => x.PedID==id);
if (p.Any())
{
Players.Remove(p.First());
}
}
public static void Cleanup()
{
Players=new List<PlayerData> { };
}
}
}

View File

@ -1,36 +0,0 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("RageCoop.Client")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("RageCoop.Client")]
[assembly: AssemblyCopyright("Copyright © 2021")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("ef56d109-1f22-43e0-9dff-cfcfb94e0681")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("0.4.1.0")]
[assembly: AssemblyFileVersion("0.4.1.0")]

View File

@ -1,125 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{EF56D109-1F22-43E0-9DFF-CFCFB94E0681}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>RageCoop.Client</RootNamespace>
<AssemblyName>RageCoop.Client</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
<TargetFrameworkProfile />
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>D:\Games\Grand Theft Auto V\Scripts\RageCoop\</OutputPath>
<DefineConstants>TRACE;DEBUG</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x64</PlatformTarget>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
<DocumentationFile>
</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
<DocumentationFile>
</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="DotNetZip, Version=1.16.0.0, Culture=neutral, PublicKeyToken=6583c7c814667745, processorArchitecture=MSIL">
<HintPath>..\packages\DotNetZip.1.16.0\lib\net40\DotNetZip.dll</HintPath>
</Reference>
<Reference Include="LemonUI.SHVDN3, Version=1.5.1.0, Culture=neutral, processorArchitecture=AMD64">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\Libs\Release\scripts\LemonUI.SHVDN3.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\Libs\Release\scripts\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="ScriptHookVDotNet3, Version=3.3.2.0, Culture=neutral, processorArchitecture=AMD64">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\Libs\Release\ScriptHookVDotNet3.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Numerics" />
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.Security" />
<Reference Include="System.ServiceModel" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="DevTools\DevTool.cs" />
<Compile Include="Menus\Sub\DevToolMenu.cs" />
<Compile Include="Menus\Sub\ServersMenu.cs" />
<Compile Include="Resources.cs" />
<Compile Include="Scripting\ClientScript.cs" />
<Compile Include="Scripting\Engine.cs" />
<Compile Include="Util\MathExtensions.cs" />
<Compile Include="Util\PedConfigFlags.cs" />
<Compile Include="Util\Util.cs" />
<Compile Include="Util\VehicleExtensions.cs" />
<Compile Include="Util\WeaponUtil.cs" />
<Compile Include="Networking\Chat.cs" />
<Compile Include="Scripting\API.cs" />
<Compile Include="Debug.cs" />
<Compile Include="Networking\DownloadManager.cs" />
<Compile Include="Util\TaskType.cs" />
<Compile Include="Menus\Sub\DebugMenu.cs" />
<Compile Include="Networking\Receive.cs" />
<Compile Include="Networking\Send.cs" />
<Compile Include="Sync\Entities\SyncedPed.cs" />
<None Include="app.config" />
<Compile Include="Sync\Entities\SyncedProjectile.cs" />
<Compile Include="Sync\EntityPool.cs" />
<Compile Include="Sync\SyncEvents.cs" />
<Compile Include="Sync\Entities\SyncedEntity.cs" />
<Compile Include="Sync\Entities\SyncedVehicle.cs" />
<Compile Include="Main.cs" />
<Compile Include="Networking\MapLoader.cs" />
<Compile Include="Menus\CoopMenu.cs" />
<Compile Include="Menus\Sub\SettingsMenu.cs" />
<Compile Include="Networking\Networking.cs" />
<Compile Include="PlayerList.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Sync\SyncParameters.cs" />
<Compile Include="Util\PedExtensions.cs" />
<Compile Include="WorldThread.cs" />
<Compile Include="Settings.cs" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\RageCoop.Core\RageCoop.Core.csproj">
<Project>{cc2e8102-e568-4524-aa1f-f8e0f1cfe58a}</Project>
<Name>RageCoop.Core</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@ -1,36 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Ionic.Zip;
using System.IO;
namespace RageCoop.Client
{
internal static class Resources
{
static Scripting.Engine ScriptingEngine = new Scripting.Engine();
/// <summary>
/// Load all resources from a server
/// </summary>
/// <param name="path">The path to the directory containing the resources.</param>
public static void Load(string path)
{
ScriptingEngine.StopAll();
foreach(var d in Directory.GetDirectories(path))
{
Directory.Delete(d, true);
}
using (var zip = ZipFile.Read(Path.Combine(path, "Resources.zip")))
{
zip.ExtractAll(path, ExtractExistingFileAction.OverwriteSilently);
}
ScriptingEngine.LoadAll(path);
}
public static void UnloadAll()
{
ScriptingEngine.StopAll();
}
}
}

View File

@ -1,147 +0,0 @@
#undef DEBUG
using System.Collections.Generic;
using System;
using System.Linq;
using RageCoop.Core;
namespace RageCoop.Client.Scripting
{
/// <summary>
/// ?
/// </summary>
public static class API
{
public static class Config
{
/// <summary>
/// Enable automatic respawn for this player.
/// </summary>
public static bool EnableAutoRespawn { get; set; } = true;
}
public static class Events
{
public delegate void EmptyEvent();
/// <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;
public static event EventHandler<SyncedPed> OnPedSpawned;
public static event EventHandler<SyncedPed> OnPedDeleted;
#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(); }
#endregion
}
/// <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);
}
public static Core.Logging.Logger GetLogger()
{
return Main.Logger;
}
/// <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>
/// Disconnect from the server
/// </summary>
public static void Disconnect()
{
Networking.ToggleConnection(null);
}
/// <summary>
/// Check if the player is already on a server
/// </summary>
public static bool IsOnServer
{
get { return Networking.IsOnServer; }
}
/// <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 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 (IsOnServer || string.IsNullOrEmpty(value))
{
return;
}
Main.Settings.Username = value;
}
}
}
}

View File

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

View File

@ -1,234 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using System.IO;
using RageCoop.Core;
using RageCoop.Core.Scripting;
namespace RageCoop.Client.Scripting
{
internal class Engine : MarshalByRefObject
{
protected List<string> ToIgnore = new List<string>
{
"RageCoop.Client.dll",
"RageCoop.Core.dll",
"RageCoop.Server.dll",
"ScriptHookVDotNet3.dll"
};
internal class Resource
{
public string Name { get; set; }
public List<IScriptable> Scripts { get; set; }
}
protected List<Resource> LoadedResources = new List<Resource>();
private string BaseScriptType;
public Core.Logging.Logger Logger { get; set; }
public Engine()
{
BaseScriptType = "RageCoop.Client.Scripting.ClientScript";
Logger = Main.Logger;
}
/// <summary>
/// Load all assemblies inside this directory and create a new domain.
/// </summary>
/// <param name="path">Path of the directory.</param>
protected void LoadFromDirectory(string path)
{
var name = Path.GetDirectoryName(path);
var r = new Resource()
{
Scripts = new List<IScriptable>(),
Name=name,
};
foreach (var f in Directory.GetFiles(path, "*.dll", SearchOption.AllDirectories))
{
LoadScriptsFromAssembly(f, r);
}
LoadedResources.Add(r);
}
/// <summary>
/// Loads scripts from the specified assembly file.
/// </summary>
/// <param name="path">The path to the assembly file to load.</param>
/// <returns><see langword="true" /> on success, <see langword="false" /> otherwise</returns>
protected bool LoadScriptsFromAssembly(string path, Resource domain)
{
lock (LoadedResources)
{
if (!IsManagedAssembly(path)) { return false; }
if (ToIgnore.Contains(Path.GetFileName(path))) { return false; }
Logger?.Debug($"Loading assembly {Path.GetFileName(path)} ...");
Assembly assembly;
try
{
var temp= Path.GetTempFileName();
File.Copy(path,temp,true);
assembly = Assembly.LoadFrom(temp);
}
catch (Exception ex)
{
Logger?.Error("Unable to load "+Path.GetFileName(path));
Logger?.Error(ex);
return false;
}
return LoadScriptsFromAssembly(assembly, path, domain);
}
}
/// <summary>
/// Loads scripts from the specified assembly object.
/// </summary>
/// <param name="filename">The path to the file associated with this assembly.</param>
/// <param name="assembly">The assembly to load.</param>
/// <returns><see langword="true" /> on success, <see langword="false" /> otherwise</returns>
private bool LoadScriptsFromAssembly(Assembly assembly, string filename, Resource 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
toload.Scripts.Add(constructor.Invoke(null) as IScriptable);
count++;
}
catch (Exception ex)
{
Logger?.Error($"Error occurred when loading script: {type.FullName}.");
Logger?.Error(ex);
}
}
else
{
Logger?.Error($"Script {type.FullName} has an invalid contructor.");
}
}
}
catch (ReflectionTypeLoadException ex)
{
Logger?.Error($"Failed to load assembly {Path.GetFileName(filename)}: ");
Logger?.Error(ex);
foreach(var e in ex.LoaderExceptions)
{
Logger?.Error(e);
}
return false;
}
Logger?.Info($"Loaded {count} script(s) in {Path.GetFileName(filename)}");
return count != 0;
}
private bool IsManagedAssembly(string filename)
{
try
{
using (Stream file = new FileStream(filename, FileMode.Open, FileAccess.Read))
{
if (file.Length < 64)
return false;
using (BinaryReader bin = new BinaryReader(file))
{
// PE header starts at offset 0x3C (60). Its a 4 byte header.
file.Position = 0x3C;
uint offset = bin.ReadUInt32();
if (offset == 0)
offset = 0x80;
// Ensure there is at least enough room for the following structures:
// 24 byte PE Signature & Header
// 28 byte Standard Fields (24 bytes for PE32+)
// 68 byte NT Fields (88 bytes for PE32+)
// >= 128 byte Data Dictionary Table
if (offset > file.Length - 256)
return false;
// Check the PE signature. Should equal 'PE\0\0'.
file.Position = offset;
if (bin.ReadUInt32() != 0x00004550)
return false;
// Read PE magic number from Standard Fields to determine format.
file.Position += 20;
var peFormat = bin.ReadUInt16();
if (peFormat != 0x10b /* PE32 */ && peFormat != 0x20b /* PE32Plus */)
return false;
// Read the 15th Data Dictionary RVA field which contains the CLI header RVA.
// When this is non-zero then the file contains CLI data otherwise not.
file.Position = offset + (peFormat == 0x10b ? 232 : 248);
return bin.ReadUInt32() != 0;
}
}
}
catch
{
// This is likely not a valid assembly if any IO exceptions occur during reading
return false;
}
}
private bool IsSubclassOf(Type type, string baseTypeName)
{
for (Type t = type.BaseType; t != null; t = t.BaseType)
if (t.FullName == baseTypeName)
return true;
return false;
}
protected void StartAll()
{
lock (LoadedResources)
{
foreach (var d in LoadedResources)
{
foreach (var s in d.Scripts)
{
Main.QueueAction(() => s.OnStart());
}
}
}
}
public void StopAll()
{
lock (LoadedResources)
{
foreach (var d in LoadedResources)
{
foreach (var s in d.Scripts)
{
Main.QueueAction(() => s.OnStop());
}
}
}
LoadedResources.Clear();
}
/// <summary>
/// Load all resources inside the directory.
/// </summary>
/// <param name="path">Path of the directory.</param>
public void LoadAll(string path)
{
Directory.CreateDirectory(path);
foreach (var resource in Directory.GetDirectories(path))
{
Logger.Info($"Loading resource: {Path.GetFileName(resource)}");
LoadFromDirectory(resource);
}
StartAll();
}
}
}

View File

@ -1,58 +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>
/// 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; } = "[AUTO]";
/// <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; } = 35;
}
}

View File

@ -1,68 +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
{
public abstract class SyncedEntity
{
/// <summary>
/// Indicates whether the current player is responsible for syncing this entity.
/// </summary>
public bool IsMine
{
get
{
return OwnerID==Main.LocalPlayerID;
}
}
public int ID { get;internal set; }
public int OwnerID { get; internal set; }
public bool IsOutOfSync
{
get
{
return Main.Ticked-LastSynced>200;
}
}
internal bool IsReady
{
get {return !(LastSynced==0||LastStateSynced==0);}
}
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
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;
}
}
}

View File

@ -1,722 +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
public string Username = "N/A";
internal Blip PedBlip = null;
internal bool DisplayBlip { get; set; }
internal bool DisplayNameTag { get; set; }
#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 _lastEnteringVehicle=false;
internal bool _lastSittingInVehicle=false;
private bool _lastRagdoll=false;
private ulong _lastRagdollTime=0;
private bool _lastInCover = false;
internal int ModelHash
{
get;set;
}
private Dictionary<byte, short> _lastClothes = null;
internal Dictionary<byte, short> 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 (Username=="N/A")
{
var p = PlayerList.GetPlayer(ID);
if (p!=null)
{
Username=p.Username;
if (PedBlip!=null)
{
PedBlip.Name=Username;
}
}
}
if((!DisplayBlip) && (PedBlip!=null))
{
PedBlip.Delete();
PedBlip=null;
}
RenderNameTag();
}
// Check if all data avalible
if (!IsReady) { return; }
// Skip update if no new sync message has arrived.
if (!NeedUpdate)
{
return;
}
bool characterExist = (MainPed != null) && MainPed.Exists();
if (!characterExist)
{
CreateCharacter();
return;
}
// Need to update state
if (LastStateSynced>=LastUpdated)
{
if (MainPed!=null&& (ModelHash != MainPed.Model.Hash))
{
CreateCharacter();
return;
}
if (!Clothes.Compare(_lastClothes))
{
SetClothes();
}
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 (DisplayNameTag || (MainPed==null) || !MainPed.IsVisible || !MainPed.IsInRange(Game.Player.Character.Position, 20f))
{
return;
}
string renderText = IsOutOfSync ? "~r~AFK" : Username;
Vector3 targetPos = MainPed.Bones[Bone.IKHead].Position + new Vector3(0, 0, 0.35f);
Function.Call(Hash.SET_DRAW_ORIGIN, targetPos.X, targetPos.Y, targetPos.Z, 0);
float dist = (GameplayCamera.Position - MainPed.Position).Length();
var sizeOffset = Math.Max(1f - (dist / 30f), 0.3f);
new ScaledText(new PointF(0, 0), renderText, 0.4f * sizeOffset, GTA.UI.Font.ChaletLondon)
{
Outline = true,
Alignment = GTA.UI.Alignment.Center
}.Draw();
Function.Call(Hash.CLEAR_DRAW_ORIGIN);
}
private void 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;
}
Model characterModel = ModelHash.ModelRequest();
if (characterModel == null)
{
return;
}
MainPed = World.CreatePed(characterModel, Position);
characterModel.MarkAsNoLongerNeeded();
if (MainPed == null)
{
return;
}
Function.Call(Hash.SET_PED_CAN_EVASIVE_DIVE, MainPed.Handle, 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);
MainPed.BlockPermanentEvents = true;
MainPed.CanWrithe=false;
MainPed.CanBeDraggedOutOfVehicle = true;
MainPed.IsOnlyDamagedByPlayer = false;
MainPed.RelationshipGroup=Main.SyncedPedsGroup;
MainPed.IsFireProof=false;
MainPed.IsExplosionProof=false;
MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DrownsInWater,false);
MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DisableMelee, true);
MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DisableHurt, true);
MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DisableExplosionReactions, true);
MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_AvoidTearGas, false);
MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DisableShockingEvents, true);
MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DisableHurt, true);
SetClothes();
if (IsPlayer)
{
if (DisplayBlip)
{
// Add a new blip for the ped
PedBlip=MainPed.AddBlip();
MainPed.AttachedBlip.Color = BlipColor.White;
MainPed.AttachedBlip.Scale = 0.8f;
MainPed.AttachedBlip.Name =Username;
}
MainPed.IsInvincible=true;
}
// Add to EntityPool so this Character can be accessed by handle.
EntityPool.Add(this);
}
private void SetClothes()
{
foreach (KeyValuePair<byte, short> cloth in Clothes)
{
Function.Call(Hash.SET_PED_COMPONENT_VARIATION, MainPed.Handle, cloth.Key, cloth.Value, 0, 0);
}
_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.ModelRequest();
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;
}
}
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);
}
}
}
}

View File

@ -1,92 +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
{
internal class SyncedProjectile : SyncedEntity
{
public SyncedProjectile(Projectile p)
{
ID=EntityPool.RequestNewID();
IsMine=true;
MainProjectile = p;
Origin=p.Position;
var shooter = EntityPool.GetPedByHandle((p.Owner?.Handle).GetValueOrDefault());
if(shooter != null)
{
ShooterID=shooter.ID;
}
else
{
// 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)
{
ShooterID=shooterVeh.MainVehicle.Driver.GetSyncEntity().ID;
}
else
{
Main.Logger.Warning($"Could not find owner for projectile:{Hash}");
}
}
}
public SyncedProjectile(int id)
{
ID= id;
IsMine=false;
}
public new bool IsMine { get; private set; }
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.PositionNoOffset=Position+Velocity*Networking.Latency;
MainProjectile.Velocity=Velocity;
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);
}
}
}

View File

@ -1,406 +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
{
public class SyncedVehicle : SyncedEntity
{
#region -- CONSTRUCTORS --
/// <summary>
/// Create a local entity (outgoing sync)
/// </summary>
/// <param name="p"></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>();
private byte _lastRadioIndex=255;
#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;
#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 bool RoofOpened { get; set; }
internal bool SireneActive { get; set; }
internal VehicleDamageModel DamageModel { get; set; }
internal int ModelHash { 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;
#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 != ModelHash))
{
CreateVehicle();
return;
}
#endregion
#region -- SYNC CRITICAL --
if (SteeringAngle != MainVehicle.SteeringAngle)
{
MainVehicle.CustomSteeringAngle((float)(Math.PI / 180) * SteeringAngle);
}
if (MainVehicle.ThrottlePower!=ThrottlePower)
{
MainVehicle.ThrottlePower=ThrottlePower;
}
if (MainVehicle.BrakePower!=BrakePower)
{
MainVehicle.BrakePower=BrakePower;
}
if (MainVehicle.Position.DistanceTo(Position)<5)
{
MainVehicle.Velocity = Velocity+5*(Position+Velocity*SyncParameters.PositioinPredictionDefault - MainVehicle.Position);
MainVehicle.Quaternion=Quaternion.Slerp(MainVehicle.Quaternion, Quaternion, 0.5f);
}
else
{
MainVehicle.Position=Position;
MainVehicle.Velocity=Velocity;
MainVehicle.Quaternion=Quaternion;
}
// Vector3 r = GetCalibrationRotation();
MainVehicle.RotationVelocity = RotationVelocity;
if (DeluxoWingRatio!=-1)
{
MainVehicle.SetDeluxoWingRatio(DeluxoWingRatio);
}
#endregion
if (LastStateSynced>LastUpdated)
{
#region -- SYNC STATE --
#region -- PASSENGER SYNC --
// check passengers (and driver).
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!=_lastRadioIndex))
{
Util.SetPlayerRadioIndex(RadioStation);
}
if (c?.MainPed!=null&&(!currentPassengers.ContainsKey(i))&&(!c.MainPed.IsBeingJacked)&&(!c.MainPed.IsTaskActive(TaskType.CTaskExitVehicleSeat))) {
Passengers[seat].MainPed.SetIntoVehicle(MainVehicle, seat);
}
}
else if (!MainVehicle.IsSeatFree(seat))
{
if (seat==VehicleSeat.Driver &&MainVehicle.Driver.IsSittingInVehicle())
{
MainVehicle.Driver.Task.WarpOutOfVehicle(MainVehicle);
}
else
{
var p = MainVehicle.Passengers.Where(x => x.SeatIndex==seat).FirstOrDefault();
if ((p!=null)&&p.IsSittingInVehicle())
{
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)
{
bool roofOpened = MainVehicle.RoofState == VehicleRoofState.Opened || MainVehicle.RoofState == VehicleRoofState.Opening;
if (roofOpened != RoofOpened)
{
MainVehicle.RoofState = RoofOpened ? VehicleRoofState.Opening : VehicleRoofState.Closing;
}
}
Function.Call(Hash.SET_VEHICLE_BRAKE_LIGHTS, MainVehicle.Handle, BrakeLightsOn);
MainVehicle.SetDamageModel(DamageModel);
}
MainVehicle.LockStatus=LockStatus;
if (Flags.HasFlag(VehicleDataFlags.IsDeluxoHovering))
{
if (!MainVehicle.IsDeluxoHovering())
{
MainVehicle.SetDeluxoHoverState(true);
}
}
else if(ModelHash==1483171323)
{
if (MainVehicle.IsDeluxoHovering())
{
MainVehicle.SetDeluxoHoverState(false);
}
}
#endregion
}
LastUpdated=Main.Ticked;
}
private Vector3 GetCalibrationRotation()
{
return (Quaternion-MainVehicle.Quaternion).ToEulerAngles().ToDegree();
/*
var r = Rotation-MainVehicle.Rotation;
if (r.X>180) { r.X=r.X-360; }
else if(r.X<-180) { r.X=360+r.X; }
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 void CreateVehicle()
{
MainVehicle?.Delete();
Model vehicleModel = ModelHash.ModelRequest();
if (vehicleModel == null)
{
//GTA.UI.Notification.Show($"~r~(Vehicle)Model ({CurrentVehicleModelHash}) cannot be loaded!");
return;
}
MainVehicle = World.CreateVehicle(vehicleModel, Position);
lock (EntityPool.VehiclesLock)
{
EntityPool.Add( this);
}
MainVehicle.Quaternion = Quaternion;
if (MainVehicle.HasRoof)
{
bool roofOpened = MainVehicle.RoofState == VehicleRoofState.Opened || MainVehicle.RoofState == VehicleRoofState.Opening;
if (roofOpened != RoofOpened)
{
MainVehicle.RoofState = RoofOpened ? VehicleRoofState.Opened : VehicleRoofState.Closed;
}
}
vehicleModel.MarkAsNoLongerNeeded();
}
#region -- PEDALING --
/*
* Thanks to @oldnapalm.
*/
private string PedalingAnimDict()
{
switch ((VehicleHash)ModelHash)
{
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
}
}

View File

@ -1,561 +0,0 @@

using System;
using GTA;
using GTA.Native;
using RageCoop.Core;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Security.Cryptography;
namespace RageCoop.Client
{
internal class EntityPool
{
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 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();
}
#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($"My 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);
}
}
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);
}
}
#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);
}
}
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);
}
}
#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 (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
public static void DoSync()
{
#if BENCHMARK
PerfCounter.Restart();
Debug.TimeStamps[TimeStamp.CheckProjectiles]=PerfCounter.ElapsedTicks;
#endif
var allPeds = World.GetAllPeds();
var allVehicles=World.GetAllVehicles();
var allProjectiles=World.GetAllProjectiles();
if (Main.Settings.WorldVehicleSoftLimit>-1)
{
if (Main.Ticked%100==0) { if (allVehicles.Length>Main.Settings.WorldVehicleSoftLimit) { SetBudget(0); } else { SetBudget(1); } }
}
#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.IsMine)
{
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();
}
}
}
}
lock (PedsLock)
{
EntityPool.AddPlayer();
foreach (Ped p in allPeds)
{
SyncedPed c = EntityPool.GetPedByHandle(p.Handle);
if (c==null && (p!=Game.Player.Character))
{
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
foreach (SyncedPed c in ID_Peds.Values.ToArray())
{
if ((c.MainPed!=null)&&(!c.MainPed.Exists()))
{
EntityPool.RemovePed(c.ID, "non-existent");
continue;
}
// Outgoing sync
if (c.IsMine)
{
#if BENCHMARK
var start = PerfCounter2.ElapsedTicks;
#endif
// event check
SyncEvents.Check(c);
if (Main.Ticked%20==0)
{
Networking.SendPed(c);
Networking.SendPedState(c);
}
else
{
Networking.SendPed(c);
}
#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
}
lock (VehiclesLock)
{
foreach (Vehicle veh in allVehicles)
{
if (!Handle_Vehicles.ContainsKey(veh.Handle))
{
Main.Logger.Debug($"Creating SyncEntity for vehicle, handle:{veh.Handle}");
EntityPool.Add(new SyncedVehicle(veh));
}
}
#if BENCHMARK
Debug.TimeStamps[TimeStamp.AddVehicles]=PerfCounter.ElapsedTicks;
#endif
foreach (SyncedVehicle v in ID_Vehicles.Values.ToArray())
{
if ((v.MainVehicle!=null)&&(!v.MainVehicle.Exists()))
{
EntityPool.RemoveVehicle(v.ID,"non-existent");
continue;
}
// Outgoing sync
if (v.IsMine)
{
SyncEvents.Check(v);
if (Main.Ticked%20==0)
{
Networking.SendVehicle(v);
Networking.SendVehicleState(v);
}
else
{
Networking.SendVehicle(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;
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);
}
}
}
}
}

View File

@ -1,416 +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 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) ;
}
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.ModelHash=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;
// 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, 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(PacketTypes type,byte[] data)
{
switch (type)
{
case PacketTypes.BulletShot:
{
Packets.BulletShot p = new Packets.BulletShot();
p.Unpack(data);
HandleBulletShot(p.StartPosition, p.EndPosition, p.WeaponHash, p.OwnerID);
break;
}
case PacketTypes.EnteringVehicle:
{
Packets.EnteringVehicle p = new Packets.EnteringVehicle();
p.Unpack(data);
HandleEnteringVehicle(EntityPool.GetPedByID(p.PedID), EntityPool.GetVehicleByID(p.VehicleID), (VehicleSeat)p.VehicleSeat);
}
break;
case PacketTypes.LeaveVehicle:
{
Packets.LeaveVehicle packet = new Packets.LeaveVehicle();
packet.Unpack(data);
HandleLeaveVehicle(packet);
}
break;
case PacketTypes.OwnerChanged:
{
Packets.OwnerChanged packet = new Packets.OwnerChanged();
packet.Unpack(data);
HandleOwnerChanged(packet);
}
break;
case PacketTypes.PedKilled:
{
var packet = new Packets.PedKilled();
packet.Unpack(data);
HandlePedKilled(packet);
}
break;
case PacketTypes.EnteredVehicle:
{
var packet = new Packets.EnteredVehicle();
packet.Unpack(data);
HandleEnteredVehicle(packet.PedID,packet.VehicleID,(VehicleSeat)packet.VehicleSeat);
break;
}
case PacketTypes.NozzleTransform:
{
var packet = new Packets.NozzleTransform();
packet.Unpack(data);
HandleNozzleTransform(packet);
break;
}
}
}
public static int GetWeaponDamage(this Ped p,uint hash)
{
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;
}
#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
}
}

View File

@ -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;
}
}

View File

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

View File

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

View File

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

View File

@ -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
public 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
};

View File

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

View File

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

View File

@ -1,226 +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
{
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 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 MuzzleInfo GetMuzzleInfo(this Vehicle v)
{
BulletsShot++;
int i;
switch (v.Model.Hash)
{
// SCRAMJET
case -638562243:
i=BulletsShot%2==0 ? 44 : 45;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
// VIGILANTE
case -1242608589:
i=BulletsShot%2==0 ? 42 : 43;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
// ZR380
case 540101442:
i=BulletsShot%2==0 ? 57 : 63;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
// ZR3802
case -1106120762:
i=BulletsShot%2==0 ? 57 : 63;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
// ZR3803
case -1478704292:
i=BulletsShot%2==0 ? 53 : 59;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
// STROMBERG
case 886810209:
i=BulletsShot%2==0 ? 85 : 84;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
// SLAMVAN4
case -2061049099:
i=BulletsShot%2==0 ? 76 : 78;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
// IMPERATOR
case 444994115:
i=BulletsShot%2==0 ? 88 : 86;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
// IMPALER2
case 1009171724:
i=BulletsShot%2==0 ? 63 : 64;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
// DOMINATOR4
case -688189648:
i=BulletsShot%2==0 ? 59 : 60;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
// SAVAGE
case -82626025:
return new MuzzleInfo(v.Bones[30].Position, v.Bones[30].ForwardVector);
// BUZZARD
case 788747387:
i=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;
if (vp!=VehicleWeaponHash.Invalid)
{
return VehicleProjectileWeapons.Contains(vp);
}
else
{
var w = p.Weapons.Current;
return w.Group==WeaponGroup.Thrown || ProjectileWeapons.Contains(w.Hash);
}
}
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
};
}
}

View File

@ -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.IsMine && (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.IsMine&&veh.PopulationType!=EntityPopulationType.Mission))
{
Main.Logger.Debug($"Removing Vehicle {veh.Handle}. Reason:ClearTraffic");
veh.Delete();
}
}
}
}
}
}

View File

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

View File

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="DotNetZip" version="1.16.0" targetFramework="net48" />
</packages>

View File

@ -21,23 +21,23 @@ namespace RageCoop.Client
{
private bool _gameLoaded = false;
public static readonly string CurrentVersion = "V0_4_1";
internal static readonly string CurrentVersion = "V0_4_1";
public static int LocalPlayerID=0;
internal static int LocalPlayerID=0;
internal static RelationshipGroup SyncedPedsGroup;
public static new Settings Settings = null;
internal static new Settings Settings = null;
#if !NON_INTERACTIVE
#endif
public static Chat MainChat = null;
public static Stopwatch Counter = new Stopwatch();
public static Core.Logging.Logger Logger = null;
public static ulong Ticked = 0;
internal static Chat MainChat = null;
internal static Stopwatch Counter = new Stopwatch();
internal static Core.Logging.Logger Logger = null;
internal static ulong Ticked = 0;
internal static Scripting.Resources Resources = new Scripting.Resources();
private static List<Func<bool>> QueuedActions = new List<Func<bool>>();
/// <summary>
/// Don't use it!
/// </summary>
@ -79,6 +79,7 @@ namespace RageCoop.Client
MainChat = new Chat();
Tick += OnTick;
Tick += (s,e) => { Scripting.API.Events.InvokeTick(); };
KeyDown += OnKeyDown;
Aborted += (object sender, EventArgs e) => CleanUp();
@ -267,7 +268,7 @@ namespace RageCoop.Client
}
public static readonly Dictionary<ulong, byte> CheckNativeHash = new Dictionary<ulong, byte>()
internal static readonly Dictionary<ulong, byte> CheckNativeHash = new Dictionary<ulong, byte>()
{
{ 0xD49F9B0955C367DE, 1 }, // Entities
{ 0xEF29A16337FACADB, 1 }, //
@ -284,8 +285,8 @@ namespace RageCoop.Client
{ 0x5A039BB0BCA604B6, 4 }, //
{ 0x0134F0835AB6BFCB, 5 } // Checkpoints
};
public static Dictionary<int, byte> ServerItems = new Dictionary<int, byte>();
public static void CleanUpWorld()
internal static Dictionary<int, byte> ServerItems = new Dictionary<int, byte>();
internal static void CleanUpWorld()
{
if (ServerItems.Count == 0)
{
@ -362,14 +363,14 @@ namespace RageCoop.Client
/// Queue an action to be executed on next tick, allowing you to call scripting API from another thread.
/// </summary>
/// <param name="a"> The action to be executed, must return a bool indicating whether the action cane be removed after execution.</param>
public static void QueueAction(Func<bool> a)
internal static void QueueAction(Func<bool> a)
{
lock (QueuedActions)
{
QueuedActions.Add(a);
}
}
public static void QueueAction(Action a)
internal static void QueueAction(Action a)
{
lock (QueuedActions)
{
@ -379,37 +380,11 @@ namespace RageCoop.Client
/// <summary>
/// Clears all queued actions
/// </summary>
public static void ClearQueuedActions()
internal static void ClearQueuedActions()
{
lock (QueuedActions) { QueuedActions.Clear(); }
}
public static string DumpCharacters()
{
string s = "Characters:";
lock (EntityPool.PedsLock)
{
foreach (int id in EntityPool.GetPedIDs())
{
var c = EntityPool.GetPedByID(id);
s+=$"\r\nID:{c.ID} Owner:{c.OwnerID} LastUpdated:{c.LastUpdated} LastSynced:{c.LastSynced} LastStateSynced:{c.LastStateSynced}";
// s+=$"\r\n{c.IsAiming} {c.IsJumping} {c.IsOnFire} {c.IsOnLadder} {c.IsRagdoll} {c.IsReloading} {c.IsShooting} {c.Speed}";
}
}
Main.Logger.Trace(s);
return s;
}
public static string DumpPlayers()
{
string s = "Players:";
foreach (PlayerData p in PlayerList.Players)
{
s+=$"\r\nID:{p.PedID} Username:{p.Username}";
}
Main.Logger.Trace(s);
return s;
}
}
}

View File

@ -24,7 +24,7 @@ namespace RageCoop.Client
if (name=="Resources.zip")
{
Main.Logger.Debug("Loading resources...");
Resources.Load(Path.Combine(downloadFolder));
Main.Resources.Load(Path.Combine(downloadFolder));
}
return;
}
@ -124,7 +124,7 @@ namespace RageCoop.Client
if (f.FileName=="Resources.zip")
{
Main.Logger.Debug("Loading resources...");
Resources.Load(Path.Combine(downloadFolder));
Main.Resources.Load(Path.Combine(downloadFolder));
}
Networking.SendDownloadFinish(id);
}

View File

@ -103,7 +103,6 @@ namespace RageCoop.Client
PlayerList.SetPlayer(packet.PedID, packet.Username);
Main.Logger.Debug($"player connected:{p.Username}");
Main.DumpCharacters();
}
private static void PlayerDisconnect(Packets.PlayerDisconnect packet)
{

View File

@ -84,7 +84,7 @@ namespace RageCoop.Client
GTA.UI.Notification.Show("~r~Disconnected: " + reason));
MapLoader.DeleteAll();
Resources.UnloadAll();
Main.Resources.Unload();
Main.Logger.Info($">> Disconnected << reason: {reason}");
break;
@ -236,9 +236,9 @@ namespace RageCoop.Client
}
break;
case PacketTypes.ServerClientEvent:
case PacketTypes.CustomEvent:
{
Packets.ServerClientEvent packet = new Packets.ServerClientEvent();
Packets.CustomEvent packet = new Packets.CustomEvent();
packet.Unpack(data);
}
break;

View File

@ -6,7 +6,7 @@ using GTA.Native;
namespace RageCoop.Client
{
public static class PlayerList
internal static class PlayerList
{
private const float LEFT_POSITION = 0.122f;
private const float RIGHT_POSITION = 0.9f;

View File

@ -6,6 +6,9 @@
<OutputPath>D:\Games\Grand Theft Auto V\Scripts\RageCoop</OutputPath>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<ProduceReferenceAssembly>False</ProduceReferenceAssembly>
<GenerateDocumentationFile>False</GenerateDocumentationFile>
<DocumentationFile></DocumentationFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DotNetZip" Version="1.16.0" />

View File

@ -1,36 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Ionic.Zip;
using System.IO;
namespace RageCoop.Client
{
internal static class Resources
{
static Scripting.Engine ScriptingEngine = new Scripting.Engine();
/// <summary>
/// Load all resources from a server
/// </summary>
/// <param name="path">The path to the directory containing the resources.</param>
public static void Load(string path)
{
ScriptingEngine.StopAll();
foreach(var d in Directory.GetDirectories(path))
{
Directory.Delete(d, true);
}
using (var zip = ZipFile.Read(Path.Combine(path, "Resources.zip")))
{
zip.ExtractAll(path, ExtractExistingFileAction.OverwriteSilently);
}
ScriptingEngine.LoadAll(path);
}
public static void UnloadAll()
{
ScriptingEngine.StopAll();
}
}
}

View File

@ -7,20 +7,43 @@ using RageCoop.Core;
namespace RageCoop.Client.Scripting
{
/// <summary>
/// ?
/// Provides vital functionality to interact with RAGECOOP
/// </summary>
public static class API
{
/// <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 (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>
/// Base events for RageCoop
/// </summary>
public static class Events
{
/// <summary>
/// Empty delegate
/// </summary>
public delegate void EmptyEvent();
/// <summary>
@ -38,15 +61,27 @@ namespace RageCoop.Client.Scripting
/// </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;
#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 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(); }
#endregion
}
/// <summary>
@ -59,6 +94,10 @@ namespace RageCoop.Client.Scripting
Main.MainChat.AddMessage(from, message);
}
/// <summary>
/// Get a <see cref="Core.Logging.Logger"/> that RAGECOOP is currently using.
/// </summary>
/// <returns></returns>
public static Core.Logging.Logger GetLogger()
{
return Main.Logger;
@ -128,20 +167,5 @@ namespace RageCoop.Client.Scripting
get { return Main.CurrentVersion; }
}
/// <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 (IsOnServer || string.IsNullOrEmpty(value))
{
return;
}
Main.Settings.Username = value;
}
}
}
}

View File

@ -1,17 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RageCoop.Client.Scripting
namespace RageCoop.Client.Scripting
{
/// <summary>
/// Inherit from this class, constructor will be called when the script is loaded.
/// 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:Core.Scripting.IScriptable
{
/// <summary>
/// This method would be called from main thread shortly after all scripts have been loaded.
/// </summary>
public abstract void OnStart();
/// <summary>
/// This method would be called from main 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 resource directory this script belongs to, beware that this directory should not be used to store any client-specific information since it'll get deleted every time the resource is loaded.
/// </summary>
public string CurrentDirectory { get;internal set; }
}
}

View File

@ -0,0 +1,66 @@
using System.IO;
using RageCoop.Core.Scripting;
using Ionic.Zip;
namespace RageCoop.Client.Scripting
{
internal class Resources:ResourceLoader
{
public Resources() : base(typeof(ClientScript), Main.Logger) { }
private void StartAll()
{
lock (LoadedResources)
{
foreach (var d in LoadedResources)
{
foreach (var s in d.Scripts)
{
Main.QueueAction(() => s.OnStart());
}
}
}
}
private void StopAll()
{
lock (LoadedResources)
{
foreach (var d in LoadedResources)
{
foreach (var s in d.Scripts)
{
Main.QueueAction(() => s.OnStop());
}
}
}
}
/// <summary>
/// Load all resources from the server
/// </summary>
/// <param name="path">The path to the directory containing the resources.</param>
public void Load(string path)
{
Unload();
foreach (var d in Directory.GetDirectories(path))
{
Directory.Delete(d, true);
}
using (var zip = ZipFile.Read(Path.Combine(path, "Resources.zip")))
{
zip.ExtractAll(path, ExtractExistingFileAction.OverwriteSilently);
}
Directory.CreateDirectory(path);
foreach (var resource in Directory.GetDirectories(path))
{
Logger.Info($"Loading resource: {Path.GetFileName(resource)}");
LoadResource(resource);
}
StartAll();
}
public void Unload()
{
StopAll();
LoadedResources.Clear();
}
}
}

View File

@ -65,7 +65,7 @@ namespace RageCoop.Client
CreateProjectile();
return;
}
MainProjectile.Velocity=Velocity+0.2f*((Position+Velocity*Networking.Latency)-MainProjectile.Position);
MainProjectile.Velocity=Velocity+0.2f*(Position+Velocity*Networking.Latency-MainProjectile.Position);
MainProjectile.Rotation=Rotation;
LastUpdated=Main.Ticked;
}

View File

@ -7,7 +7,7 @@ using System.Threading.Tasks;
namespace RageCoop.Client
{
// Potential names and hash collisions included as comments
public enum PedConfigFlags
internal enum PedConfigFlags
{
_0x67D1A445 = 0,
_0xC63DE95E = 1,

View File

@ -1,7 +1,7 @@
// WARNING: values can change after a game update
// if R* adds in the middle!
// This is up-to-date for b2372
public enum TaskType
internal enum TaskType
{
CTaskHandsUp = 0,
CTaskClimbLadder = 1,

View File

@ -130,7 +130,8 @@ namespace RageCoop.Core
FileTransferRequest=16,
FileTransferComplete=17,
ServerClientEvent = 18,
CustomEvent = 18,
InvokeCustomEvent=19,
#region Sync
#region INTERVAL
@ -289,99 +290,86 @@ namespace RageCoop.Core
}
}
public class ServerClientEvent : Packet
public class CustomEvent : Packet
{
public string EventName { get; set; }
public List<object> Args { get; set; }
public int Hash { get; set; }
public byte[] Data { get; set; }
public override void Pack(NetOutgoingMessage message)
{
#region PacketToNetOutGoingMessage
message.Write((byte)PacketTypes.ServerClientEvent);
message.Write((byte)PacketTypes.CustomEvent);
List<byte> byteArray = new List<byte>();
byte[] eventNameBytes = Encoding.UTF8.GetBytes(EventName);
// Write event name
byteArray.AddRange(BitConverter.GetBytes(eventNameBytes.Length));
byteArray.AddRange(eventNameBytes);
// Write hash
byteArray.AddInt(Hash);
// Write args
byteArray.AddRange(BitConverter.GetBytes(Args.Count));
foreach (object arg in Args)
{
var test = CoreUtils.GetBytesFromObject(arg);
if (test.Item1 == 0x0)
{
// Logger.Write("Can't get type of an object!", Logger.LogLevel.Server);
byteArray.Add(0x0);
}
else
{
byteArray.Add(test.Item1);
byteArray.AddRange(test.Item2);
}
}
// Write data
byteArray.AddRange(Data);
byte[] result = byteArray.ToArray();
message.Write(result.Length);
message.Write(result);
#endregion
}
public override void Unpack(byte[] array)
{
#region NetIncomingMessageToPacket
BitReader reader = new BitReader(array);
// Read event name
int eventNameBytes = reader.ReadInt();
EventName = reader.ReadString(eventNameBytes);
Hash = reader.ReadInt();
// Read args
Args = new List<object>();
int argsCount = reader.ReadInt();
for (int i = 0; i < argsCount; i++)
{
byte argType = reader.ReadByte();
switch (argType)
{
case 0x01:
Args.Add(reader.ReadByte());
break;
case 0x02:
Args.Add(reader.ReadShort());
break;
case 0x03:
Args.Add(reader.ReadUShort());
break;
case 0x04:
Args.Add(reader.ReadInt());
break;
case 0x05:
Args.Add(reader.ReadUInt());
break;
case 0x06:
Args.Add(reader.ReadLong());
break;
case 0x07:
Args.Add(reader.ReadULong());
break;
case 0x08:
Args.Add(reader.ReadFloat());
break;
case 0x09:
Args.Add(reader.ReadBool());
break;
}
}
#endregion
Data=reader.ReadByteArray(array.Length-4);
}
}
public class InvokeCustomEvent : Packet
{
public int Hash { get; set; }
public int[] Targets { get; set; }
public byte[] Data { get; set; }
public override void Pack(NetOutgoingMessage message)
{
message.Write((byte)PacketTypes.InvokeCustomEvent);
List<byte> byteArray = new List<byte>();
// Write hash
byteArray.AddInt(Hash);
// Write targets
byteArray.AddInt(Targets.Length);
foreach (var target in Targets)
{
byteArray.AddInt(target);
}
// Write data
byteArray.AddRange(Data);
byte[] result = byteArray.ToArray();
message.Write(result.Length);
message.Write(result);
}
public override void Unpack(byte[] array)
{
BitReader reader = new BitReader(array);
Hash = reader.ReadInt();
Targets = new int[reader.ReadInt()];
for(int i = 0; i < Targets.Length; i++)
{
Targets[i]=reader.ReadInt();
}
Data=reader.ReadByteArray(array.Length-4);
}
}
#region ===== NATIVECALL =====
public class NativeCall : Packet
{

View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace RageCoop.Core.Scripting.Events
{
public class OnVehicleSpawned:CustomEvent
{
public int VehicleID { get; set; }
public override int EventID { get; set; } = Hasher.Hash("RageCoop.OnVehicleSpawned");
public override byte[] Serialize()
{
return BitConverter.GetBytes(VehicleID);
}
public override void Deserialize(byte[] data)
{
VehicleID= BitConverter.ToInt32(data, 0);
}
}
}

View File

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
namespace RageCoop.Core.Scripting.Events
{
public interface ICustomEvent
{
int EventID { get; set; }
byte[] Serialize();
void Deserialize(byte[] data);
}
public abstract class CustomEvent:ICustomEvent
{
public abstract int EventID { get; set; }
public abstract byte[] Serialize();
public abstract void Deserialize(byte[] data);
}
public static class Hasher
{
public static int Hash(string s)
{
MD5 md5Hasher = MD5.Create();
var hashed = md5Hasher.ComputeHash(Encoding.UTF8.GetBytes(s));
return BitConverter.ToInt32(hashed, 0);
}
}
}

View File

@ -1,17 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using System.IO;
using RageCoop.Core;
using RageCoop.Core.Scripting;
using System.Linq;
namespace RageCoop.Client.Scripting
namespace RageCoop.Core.Scripting
{
internal class Engine : MarshalByRefObject
internal class Resource
{
public string Name { get; set; }
public string Directory { get; set; }
public List<IScriptable> Scripts { get; set; }
}
internal class ResourceLoader
{
protected List<string> ToIgnore = new List<string>
{
"RageCoop.Client.dll",
@ -19,30 +22,25 @@ namespace RageCoop.Client.Scripting
"RageCoop.Server.dll",
"ScriptHookVDotNet3.dll"
};
internal class Resource
{
public string Name { get; set; }
public List<IScriptable> Scripts { get; set; }
}
protected List<Resource> LoadedResources = new List<Resource>();
private string BaseScriptType;
public Core.Logging.Logger Logger { get; set; }
public Engine()
public Logging.Logger Logger { get; set; }
public ResourceLoader(Type basetype,Logging.Logger logger)
{
BaseScriptType = "RageCoop.Client.Scripting.ClientScript";
Logger = Main.Logger;
BaseScriptType = basetype.GetType().FullName;
Logger = logger;
}
/// <summary>
/// Load all assemblies inside this directory and create a new domain.
/// Load all assemblies inside the resource directory.
/// </summary>
/// <param name="path">Path of the directory.</param>
protected void LoadFromDirectory(string path)
protected void LoadResource(string path)
{
var name = Path.GetDirectoryName(path);
var r = new Resource()
{
Scripts = new List<IScriptable>(),
Name=name,
Name=Path.GetDirectoryName(path),
Directory=path,
};
foreach (var f in Directory.GetFiles(path, "*.dll", SearchOption.AllDirectories))
{
@ -68,8 +66,8 @@ namespace RageCoop.Client.Scripting
try
{
var temp= Path.GetTempFileName();
File.Copy(path,temp,true);
var temp = Path.GetTempFileName();
File.Copy(path, temp, true);
assembly = Assembly.LoadFrom(temp);
}
catch (Exception ex)
@ -122,10 +120,10 @@ namespace RageCoop.Client.Scripting
{
Logger?.Error($"Failed to load assembly {Path.GetFileName(filename)}: ");
Logger?.Error(ex);
foreach(var e in ex.LoaderExceptions)
{
foreach (var e in ex.LoaderExceptions)
{
Logger?.Error(e);
}
}
return false;
}
@ -188,47 +186,5 @@ namespace RageCoop.Client.Scripting
return true;
return false;
}
protected void StartAll()
{
lock (LoadedResources)
{
foreach (var d in LoadedResources)
{
foreach (var s in d.Scripts)
{
Main.QueueAction(() => s.OnStart());
}
}
}
}
public void StopAll()
{
lock (LoadedResources)
{
foreach (var d in LoadedResources)
{
foreach (var s in d.Scripts)
{
Main.QueueAction(() => s.OnStop());
}
}
}
LoadedResources.Clear();
}
/// <summary>
/// Load all resources inside the directory.
/// </summary>
/// <param name="path">Path of the directory.</param>
public void LoadAll(string path)
{
Directory.CreateDirectory(path);
foreach (var resource in Directory.GetDirectories(path))
{
Logger.Info($"Loading resource: {Path.GetFileName(resource)}");
LoadFromDirectory(resource);
}
StartAll();
}
}
}

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using RageCoop.Core;
using Lidgren.Network;
using GTA.Math;
using RageCoop.Core.Scripting.Events;
namespace RageCoop.Server
{
@ -185,7 +186,7 @@ namespace RageCoop.Server
Server.MainNetServer.SendMessage(outgoingMessage, userConnection, NetDeliveryMethod.ReliableOrdered, (byte)ConnectionChannel.Default);
}
public void SendTriggerEvent(string eventName, params object[] args)
public void SendCustomEvent(int id,byte[] data)
{
if (!IsReady)
{
@ -195,24 +196,19 @@ namespace RageCoop.Server
try
{
NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == NetID);
if (userConnection == null)
{
return;
}
NetOutgoingMessage outgoingMessage = Server.MainNetServer.CreateMessage();
new Packets.ServerClientEvent()
new Packets.CustomEvent()
{
EventName = eventName,
Args = new List<object>(args)
Hash=id,
Data=data
}.Pack(outgoingMessage);
Server.MainNetServer.SendMessage(outgoingMessage, userConnection, NetDeliveryMethod.ReliableOrdered, (byte)ConnectionChannel.Event);
Server.MainNetServer.SendMessage(outgoingMessage, Connection, NetDeliveryMethod.ReliableOrdered, (byte)ConnectionChannel.Event);
}
catch (Exception e)
catch (Exception ex)
{
Program.Logger.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<");
Program.Logger.Error(ex);
}
}
#endregion

View File

@ -1,72 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RageCoop.Server.Scripting;
using System.IO;
using Ionic.Zip;
namespace RageCoop.Server
{
internal static class Resources
{
public static readonly ScriptingEngine Engine = new();
/// <summary>
/// Pack client-side resources as a zip file
/// </summary>
public static bool HasClientResources=false;
public static void LoadAll()
{
var path = Path.Combine("Resources", "Client");
Directory.CreateDirectory(path);
var clientResources = Directory.GetDirectories(path);
if (clientResources.Length!=0)
{
// Pack client side resources as a zip file
Program.Logger.Info("Packing client-side resources");
try
{
var zippath = Path.Combine(path, "Resources.zip");
if (File.Exists(zippath))
{
File.Delete(zippath);
}
using (ZipFile zip = new ZipFile())
{
zip.AddDirectory(path);
zip.Save(zippath);
}
HasClientResources=true;
}
catch(Exception ex)
{
Program.Logger.Error("Failed to pack client resources");
Program.Logger.Error(ex);
}
}
Engine.LoadAll();
}
public static void UnloadAll()
{
Engine.StopAll();
}
public static void SendTo(Client client)
{
string path;
if (HasClientResources && File.Exists(path = Path.Combine("Resources", "Client", "Resources.zip")))
{
Task.Run(() =>
{
Program.Logger.Info($"Sending resources to client:{client.Player.Username}");
Server.SendFile(path, "Resources.zip", client);
Program.Logger.Info($"Resources sent to:{client.Player.Username}");
});
}
}
}
}

View File

@ -5,6 +5,7 @@ using System.Text;
using System.Threading.Tasks;
using Lidgren.Network;
using RageCoop.Core;
using RageCoop.Core.Scripting.Events;
using System.Net;
namespace RageCoop.Server.Scripting
@ -55,9 +56,7 @@ namespace RageCoop.Server.Scripting
internal static void InvokePlayerDisconnected(Client client)
{ OnPlayerDisconnected?.Invoke(client); }
internal static void InvokePlayerHandshake(HandshakeEventArgs args)
{
OnPlayerHandshake?.Invoke(null, args);
}
{ OnPlayerHandshake?.Invoke(null, args); }
#endregion
}
@ -194,13 +193,28 @@ namespace RageCoop.Server.Scripting
Server.RegisterCommands<T>();
}
/// <summary>
/// Register a class of events
/// </summary>
/// <typeparam name="T">The name of your class with functions</typeparam>
public static void RegisterEvents<T>()
public static void SendCustomEvent(int eventID, byte[] data, IEnumerable<Client> recepients)
{
Server.RegisterEvents<T>();
foreach(var c in recepients)
{
c.SendCustomEvent(eventID,data);
}
}
public static void SendCustomEvent(CustomEvent e, Client[] recepients)
{
SendCustomEvent(e.EventID, e.Serialize(), recepients);
}
public static void SendCustomEvent(int eventID, byte[] data, int[] recepients)
{
if (recepients.Length==0)
{
SendCustomEvent(eventID,data,Server.Clients.Values);
}
else
{
SendCustomEvent(eventID,data, Server.Clients.Values.Where(x => recepients.Contains(x.Player.PedID)).ToArray());
}
}
#endregion
}

View File

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

View File

@ -0,0 +1,103 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RageCoop.Core.Scripting;
using System.IO;
using Ionic.Zip;
using System.Reflection;
namespace RageCoop.Server.Scripting
{
internal class Resources : ResourceLoader
{
public Resources() : base(typeof(ServerScript), Program.Logger) { }
public static bool HasClientResources = false;
public void LoadAll()
{
#region CLIENT
var path = Path.Combine("Resources", "Client");
Directory.CreateDirectory(path);
var clientResources = Directory.GetDirectories(path);
if (clientResources.Length!=0)
{
// Pack client side resources as a zip file
Logger.Info("Packing client-side resources");
try
{
var zippath = Path.Combine(path, "Resources.zip");
if (File.Exists(zippath))
{
File.Delete(zippath);
}
using (ZipFile zip = new ZipFile())
{
zip.AddDirectory(path);
zip.Save(zippath);
}
HasClientResources=true;
}
catch (Exception ex)
{
Logger.Error("Failed to pack client resources");
Logger.Error(ex);
}
}
#endregion
#region SERVER
path = Path.Combine("Resources", "Server");
Directory.CreateDirectory(path);
foreach (var resource in Directory.GetDirectories(path))
{
Logger.Info($"Loading resource: {Path.GetFileName(resource)}");
LoadResource(resource);
}
// Start scripts
lock (LoadedResources)
{
foreach (var d in LoadedResources)
{
foreach (var s in d.Scripts)
{
(s as ServerScript).CurrentDirectory = d.Directory;
s.OnStart();
}
}
}
#endregion
}
public void StopAll()
{
lock (LoadedResources)
{
foreach (var d in LoadedResources)
{
foreach (var s in d.Scripts)
{
s.OnStop();
}
}
}
}
public void SendTo(Client client)
{
string path;
if (HasClientResources && File.Exists(path = Path.Combine("Resources", "Client", "Resources.zip")))
{
Task.Run(() =>
{
Logger.Info($"Sending resources to client:{client.Player.Username}");
Server.SendFile(path, "Resources.zip", client);
Logger.Info($"Resources sent to:{client.Player.Username}");
});
}
}
}
}

View File

@ -1,43 +1,26 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using RageCoop.Core;
using Lidgren.Network;
namespace RageCoop.Server.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 ServerScript :Core.Scripting.IScriptable
{
/// <summary>
/// This method would be called from main thread after all scripts have been loaded.
/// </summary>
public abstract void OnStart();
/// <summary>
/// This method would be called from main thread when the server is shutting down, you MUST terminate all background jobs/threads in this method.
/// </summary>
public abstract void OnStop();
}
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
public class TriggerEvent : Attribute
{
public string EventName { get; set; }
public TriggerEvent(string eventName)
{
EventName = eventName;
}
}
public class EventContext
{
/// <summary>
/// Gets the client which executed the command
/// </summary>
public Client Client { get; internal set; }
/// <summary>
/// Arguments (all standard but no string!)
/// Get the resource directory this script belongs to.
/// </summary>
public object[] Args { get; internal set; }
public string CurrentDirectory { get; internal set; }
}
[AttributeUsage(AttributeTargets.Method, Inherited = false)]

View File

@ -32,12 +32,11 @@ namespace RageCoop.Server
public static NetServer MainNetServer;
public static readonly Dictionary<Command, Action<CommandContext>> Commands = new();
public static readonly Dictionary<TriggerEvent, Action<EventContext>> TriggerEvents = new();
public static readonly Dictionary<long,Client> Clients = new();
private static System.Timers.Timer SendLatencyTimer = new System.Timers.Timer(5000);
private static Dictionary<int,FileTransfer> InProgressFileTransfers=new();
private static Resources Resources = new Resources();
public Server()
{
Program.Logger.Info("================");
@ -169,16 +168,14 @@ namespace RageCoop.Server
while (!Program.ReadyToStop)
{
while (true)
{
ProcessMessage(MainNetServer.WaitMessage(10));
MainNetServer.FlushSendQueue();
}
ProcessMessage(MainNetServer.WaitMessage(10));
MainNetServer.FlushSendQueue();
}
Program.Logger.Warning("Server is shutting down!");
Resources.UnloadAll();
MainNetServer.Shutdown("Server is shutting down!");
Program.Logger.Info("Waiting for resources to stop...");
Resources.StopAll();
Program.Logger.Dispose();
}
@ -332,35 +329,11 @@ namespace RageCoop.Server
}
}
break;
case PacketTypes.ServerClientEvent:
case PacketTypes.InvokeCustomEvent:
{
Packets.ServerClientEvent packet = new Packets.ServerClientEvent();
packet.Unpack(data);
long senderNetHandle = message.SenderConnection.RemoteUniqueIdentifier;
Client client = null;
lock (Clients)
{
client = Util.GetClientByNetID(senderNetHandle);
}
if (client != null)
{
if (TriggerEvents.Any(x => x.Key.EventName == packet.EventName))
{
EventContext ctx = new()
{
Client = client,
Args = packet.Args.ToArray()
};
TriggerEvents.FirstOrDefault(x => x.Key.EventName == packet.EventName).Value?.Invoke(ctx);
}
else
{
Program.Logger.Warning($"Player \"{client.Player.Username}\" attempted to trigger an unknown event! [{packet.EventName}]");
}
}
var p = new Packets.InvokeCustomEvent();
p.Unpack(data);
API.SendCustomEvent(p.Hash,p.Data,p.Targets);
}
break;
case PacketTypes.FileTransferComplete:
@ -855,28 +828,6 @@ namespace RageCoop.Server
}
}
public static void RegisterEvent(string eventName, Action<EventContext> callback)
{
TriggerEvent ev = new(eventName);
if (TriggerEvents.ContainsKey(ev))
{
throw new Exception("TriggerEvent \"" + ev.EventName + "\" was already been registered!");
}
TriggerEvents.Add(ev, callback);
}
public static void RegisterEvents<T>()
{
IEnumerable<MethodInfo> events = typeof(T).GetMethods().Where(method => method.GetCustomAttributes(typeof(TriggerEvent), false).Any());
foreach (MethodInfo method in events)
{
TriggerEvent attribute = method.GetCustomAttribute<TriggerEvent>(true);
RegisterEvent(attribute.EventName, (Action<EventContext>)Delegate.CreateDelegate(typeof(Action<EventContext>), method));
}
}
public static void SendFile(string path,string name,Client client,Action<float> updateCallback=null)
{
int id = RequestFileID();
@ -937,7 +888,7 @@ namespace RageCoop.Server
Program.Logger.Debug($"All file chunks sent:{name}");
InProgressFileTransfers.Remove(id);
}
public static int RequestFileID()
private static int RequestFileID()
{
int ID = 0;
while ((ID==0)