Queue action in WorldThread

This commit is contained in:
sardelka9515
2022-10-09 11:15:09 +08:00
parent 5585876005
commit 1606d25fed
12 changed files with 92 additions and 80 deletions

View File

@ -42,7 +42,6 @@ namespace RageCoop.Client
internal static Vector3 PlayerPosition;
internal static Resources Resources = null;
private static readonly ConcurrentQueue<Action> TaskQueue = new ConcurrentQueue<Action>();
private static readonly List<Func<bool>> QueuedActions = new List<Func<bool>>();
public static Worker Worker;
internal static SHVDN.Console Console => AppDomain.CurrentDomain.GetData("Console") as SHVDN.Console;
/// <summary>
@ -179,7 +178,6 @@ namespace RageCoop.Client
#endif
DoQueuedActions();
if (!Networking.IsOnServer)
{
return;
@ -349,7 +347,7 @@ namespace RageCoop.Client
{
Voice.Init();
}
QueueAction(() =>
API.QueueAction(() =>
{
WorldThread.Traffic(!Settings.DisableTraffic);
Function.Call(Hash.SET_ENABLE_VEHICLE_SLIPSTREAMING, true);
@ -365,7 +363,7 @@ namespace RageCoop.Client
Logger.Info($">> Disconnected << reason: {reason}");
QueueAction(() =>
API.QueueAction(() =>
{
if (MainChat.Focused)
{
@ -385,62 +383,7 @@ namespace RageCoop.Client
Voice.ClearAll();
Resources.Unload();
}
private static void DoQueuedActions()
{
lock (QueuedActions)
{
foreach (var action in QueuedActions.ToArray())
{
try
{
if (action())
{
QueuedActions.Remove(action);
}
}
catch (Exception ex)
{
Logger.Error(ex);
QueuedActions.Remove(action);
}
}
}
}
/// <summary>
/// Queue an action to be executed on next tick, allowing you to call scripting API from another thread.
/// </summary>
/// <param name="a"> An action to be executed with a return value indicating whether the action can be removed after execution.</param>
internal static void QueueAction(Func<bool> a)
{
lock (QueuedActions)
{
QueuedActions.Add(a);
}
}
internal static void QueueAction(Action a)
{
lock (QueuedActions)
{
QueuedActions.Add(() => { a(); return true; });
}
}
/// <summary>
/// Clears all queued actions
/// </summary>
internal static void ClearQueuedActions()
{
lock (QueuedActions) { QueuedActions.Clear(); }
}
public static void Delay(Action a, int time)
{
Task.Run(() =>
{
Thread.Sleep(time);
QueueAction(a);
});
}
}
}

View File

@ -1,6 +1,7 @@
using GTA.UI;
using LemonUI.Menus;
using Newtonsoft.Json;
using RageCoop.Client.Scripting;
using RageCoop.Core;
using System;
using System.Collections.Generic;
@ -16,6 +17,7 @@ namespace RageCoop.Client.Menus
/// </summary>
internal static class ServersMenu
{
static API API = Main.API;
private static Thread GetServersThread;
internal static NativeMenu Menu = new NativeMenu("RAGECOOP", "Servers", "Go to the server list")
{
@ -60,7 +62,7 @@ namespace RageCoop.Client.Menus
serverList = JsonConvert.DeserializeObject<List<ServerInfo>>(DownloadString(realUrl));
// Need to be processed in main thread
Main.QueueAction(() =>
API.QueueAction(() =>
{
if (serverList == null)
{
@ -127,7 +129,7 @@ namespace RageCoop.Client.Menus
}
catch (Exception ex)
{
Main.QueueAction(() =>
API.QueueAction(() =>
{
ResultItem.Title = "Download failed!";
ResultItem.Description = ex.Message;

View File

@ -1,5 +1,6 @@
using ICSharpCode.SharpZipLib.Zip;
using LemonUI.Menus;
using RageCoop.Client.Scripting;
using System;
using System.Drawing;
using System.IO;
@ -10,6 +11,7 @@ namespace RageCoop.Client.Menus
{
internal class UpdateMenu
{
static readonly API API = Main.API;
public static bool IsUpdating { get; private set; } = false;
private static readonly NativeItem _updatingItem = new NativeItem("Updating...");
private static readonly NativeItem _downloadItem = new NativeItem("Download", "Download and update to latest nightly");
@ -45,7 +47,7 @@ namespace RageCoop.Client.Menus
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls13 | SecurityProtocolType.Tls12;
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
client.DownloadProgressChanged += (s, e1) => { Main.QueueAction(() => { _updatingItem.AltTitle = $"{e1.ProgressPercentage}%"; }); };
client.DownloadProgressChanged += (s, e1) => { API.QueueAction(() => { _updatingItem.AltTitle = $"{e1.ProgressPercentage}%"; }); };
client.DownloadFileCompleted += (s, e2) => { Install(); };
client.DownloadFileAsync(new Uri("https://github.com/RAGECOOP/RAGECOOP-V/releases/download/nightly/RageCoop.Client.zip"), _downloadPath);
}
@ -60,7 +62,7 @@ namespace RageCoop.Client.Menus
{
try
{
Main.QueueAction(() =>
API.QueueAction(() =>
{
_updatingItem.AltTitle = "Installing...";
});
@ -73,7 +75,7 @@ namespace RageCoop.Client.Menus
new FastZip().ExtractZip(_downloadPath, "Scripts", FastZip.Overwrite.Always, null, null, null, true);
try { File.Delete(_downloadPath); } catch { }
try { File.Delete(Path.Combine("Scripts", "RageCoop.Client.Installer.exe")); } catch { }
Main.QueueAction(() =>
API.QueueAction(() =>
{
Util.Reload();
IsUpdating = false;

View File

@ -101,7 +101,7 @@ namespace RageCoop.Client
try { ProcessMessage(m); }
catch (Exception ex) { Main.Logger.Error(ex); }
};
Main.QueueAction(() => { Notification.Show($"~y~Trying to connect..."); });
API.QueueAction(() => { Notification.Show($"~y~Trying to connect..."); });
Menus.CoopMenu._serverConnectItem.Enabled = false;
Security.Regen();
if (publicKey == null)
@ -136,7 +136,7 @@ namespace RageCoop.Client
catch (Exception ex)
{
Main.Logger.Error("Cannot connect to server: ", ex);
Main.QueueAction(() => Notification.Show("Cannot connect to server: " + ex.Message));
API.QueueAction(() => Notification.Show("Cannot connect to server: " + ex.Message));
}
IsConnecting = false;
});
@ -155,7 +155,7 @@ namespace RageCoop.Client
PlayerList.SetPlayer(packet.PedID, packet.Username);
Main.Logger.Debug($"player connected:{p.Username}");
Main.QueueAction(() =>
API.QueueAction(() =>
GTA.UI.Notification.Show($"~h~{p.Username}~h~ connected."));
}
private static void PlayerDisconnect(Packets.PlayerDisconnect packet)
@ -163,7 +163,7 @@ namespace RageCoop.Client
var player = PlayerList.GetPlayer(packet.PedID);
if (player == null) { return; }
PlayerList.RemovePlayer(packet.PedID);
Main.QueueAction(() =>
API.QueueAction(() =>
{
EntityPool.RemoveAllFromPlayer(packet.PedID);
GTA.UI.Notification.Show($"~h~{player.Username}~h~ left.");

View File

@ -149,7 +149,7 @@ namespace RageCoop.Client
}
catch (Exception ex)
{
Main.QueueAction(() =>
API.QueueAction(() =>
{
GTA.UI.Notification.Show($"~r~~h~Packet Error {ex.Message}");
return true;
@ -236,7 +236,7 @@ namespace RageCoop.Client
Packets.ChatMessage packet = new Packets.ChatMessage((b) => Security.Decrypt(b));
packet.Deserialize(msg);
Main.QueueAction(() => { Main.MainChat.AddMessage(packet.Username, packet.Message); return true; });
API.QueueAction(() => { Main.MainChat.AddMessage(packet.Username, packet.Message); return true; });
}
break;
@ -264,7 +264,7 @@ namespace RageCoop.Client
if (packet.Flags.HasEventFlag(Core.Scripting.CustomEventFlags.Queued))
{
recycle = false;
Main.QueueAction(() =>
API.QueueAction(() =>
{
API.Events.InvokeCustomEventReceived(packet);
Peer.Recycle(msg);
@ -290,7 +290,7 @@ namespace RageCoop.Client
{
recycle = false;
// Dispatch to script thread
Main.QueueAction(() => { SyncEvents.HandleEvent(packetType, msg); Peer.Recycle(msg); return true; });
API.QueueAction(() => { SyncEvents.HandleEvent(packetType, msg); Peer.Recycle(msg); return true; });
}
break;
}

View File

@ -85,7 +85,7 @@ namespace RageCoop.Client
p._latencyToServer = packet.Latency;
p.Position = packet.Position;
p.IsHost = packet.IsHost;
Main.QueueAction(() =>
API.QueueAction(() =>
{
if (p.FakeBlip?.Exists() != true)
{
@ -126,7 +126,7 @@ namespace RageCoop.Client
if (Players.TryGetValue(id, out var player))
{
Players.Remove(id);
Main.QueueAction(() => player.FakeBlip?.Delete());
API.QueueAction(() => player.FakeBlip?.Delete());
}
}
public static void Cleanup()

View File

@ -16,7 +16,7 @@ using System.Resources;
// Version informationr(
[assembly: AssemblyVersion("1.5.4.141")]
[assembly: AssemblyFileVersion("1.5.4.141")]
[assembly: AssemblyVersion("1.5.4.146")]
[assembly: AssemblyFileVersion("1.5.4.146")]
[assembly: NeutralResourcesLanguageAttribute( "en-US" )]

View File

@ -292,7 +292,7 @@ namespace RageCoop.Client.Scripting
/// <param name="a"></param>
public void QueueAction(Action a)
{
Main.QueueAction(a);
WorldThread.QueueAction(a);
}
/// <summary>
@ -301,7 +301,7 @@ namespace RageCoop.Client.Scripting
/// <param name="a"> An <see cref="Func{T, TResult}"/> to be executed with a return value indicating whether it can be removed after execution.</param>
public void QueueAction(Func<bool> a)
{
Main.QueueAction(a);
WorldThread.QueueAction(a);
}
/// <summary>

View File

@ -27,6 +27,7 @@ namespace RageCoop.Client
{
if (!NeedUpdate) { return; }
if (!Model.IsLoaded) { Model.Request(); return; }
if (MainProp == null || !MainProp.Exists())
{
MainProp = World.CreateProp(Model, Position, Rotation, false, false);

View File

@ -113,7 +113,7 @@ namespace RageCoop.Client
{
if (MainVehicle.IsDead)
{
Main.Delay(() =>
WorldThread.Delay(() =>
{
if (MainVehicle.IsDead && !IsDead)
{

View File

@ -8,6 +8,9 @@ namespace RageCoop.Client
{
internal static class SyncEvents
{
static readonly Scripting.API API = Main.API;
#region TRIGGER
public static void TriggerPedKilled(SyncedPed victim)
{
@ -256,7 +259,7 @@ namespace RageCoop.Client
if (!getBulletImpact())
{
Main.QueueAction(getBulletImpact);
API.QueueAction(getBulletImpact);
}
}
else if (subject.VehicleWeapon == VehicleWeaponHash.Tank && subject.LastWeaponImpactPosition != default)

View File

@ -1,7 +1,11 @@
using GTA;
using GTA.Native;
using RageCoop.Client.Scripting;
using RageCoop.Core;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Threading;
namespace RageCoop.Client
{
@ -10,7 +14,63 @@ namespace RageCoop.Client
/// </summary>
internal class WorldThread : Script
{
private static readonly List<Func<bool>> QueuedActions = new List<Func<bool>>();
public static void Delay(Action a, int time)
{
Task.Run(() =>
{
Thread.Sleep(time);
QueueAction(a);
});
}
private static void DoQueuedActions()
{
lock (QueuedActions)
{
foreach (var action in QueuedActions.ToArray())
{
try
{
if (action())
{
QueuedActions.Remove(action);
}
}
catch (Exception ex)
{
Main.Logger.Error(ex);
QueuedActions.Remove(action);
}
}
}
}
/// <summary>
/// Queue an action to be executed on next tick, allowing you to call scripting API from another thread.
/// </summary>
/// <param name="a"> An action to be executed with a return value indicating whether the action can be removed after execution.</param>
internal static void QueueAction(Func<bool> a)
{
lock (QueuedActions)
{
QueuedActions.Add(a);
}
}
internal static void QueueAction(Action a)
{
lock (QueuedActions)
{
QueuedActions.Add(() => { a(); return true; });
}
}
/// <summary>
/// Clears all queued actions
/// </summary>
internal static void ClearQueuedActions()
{
lock (QueuedActions) { QueuedActions.Clear(); }
}
/// <summary>
/// Don't use it!
/// </summary>
@ -27,6 +87,7 @@ namespace RageCoop.Client
private static bool _trafficEnabled;
private void OnTick(object sender, EventArgs e)
{
DoQueuedActions();
if (Game.IsLoading || !Networking.IsOnServer)
{
return;