2022-10-23 19:02:39 +08:00
|
|
|
|
using System;
|
2022-10-09 11:15:09 +08:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Threading;
|
2022-10-15 17:06:19 +08:00
|
|
|
|
using System.Threading.Tasks;
|
2022-10-23 19:02:39 +08:00
|
|
|
|
using GTA;
|
|
|
|
|
using GTA.Native;
|
|
|
|
|
using GTA.UI;
|
2022-11-30 19:08:52 +08:00
|
|
|
|
using RageCoop.Client.Menus;
|
2021-07-07 13:36:25 +02:00
|
|
|
|
|
2022-05-22 15:55:26 +08:00
|
|
|
|
namespace RageCoop.Client
|
2021-07-07 13:36:25 +02:00
|
|
|
|
{
|
2021-12-03 20:30:00 +01:00
|
|
|
|
/// <summary>
|
2022-10-23 19:02:39 +08:00
|
|
|
|
/// Don't use it!
|
2021-12-03 20:30:00 +01:00
|
|
|
|
/// </summary>
|
2023-01-28 20:51:29 +08:00
|
|
|
|
[ScriptAttributes(Author = "RageCoop", SupportURL = "https://github.com/RAGECOOP/RAGECOOP-V")]
|
2022-10-08 23:49:48 +08:00
|
|
|
|
internal class WorldThread : Script
|
2021-07-07 13:36:25 +02:00
|
|
|
|
{
|
2022-10-09 22:07:52 +08:00
|
|
|
|
public static Script Instance;
|
2022-10-09 11:15:09 +08:00
|
|
|
|
private static readonly List<Func<bool>> QueuedActions = new List<Func<bool>>();
|
2022-10-23 19:02:39 +08:00
|
|
|
|
|
|
|
|
|
private static bool _trafficEnabled;
|
|
|
|
|
|
2021-12-03 20:30:00 +01:00
|
|
|
|
/// <summary>
|
2022-10-23 19:02:39 +08:00
|
|
|
|
/// Don't use it!
|
2021-12-03 20:30:00 +01:00
|
|
|
|
/// </summary>
|
2021-07-07 13:36:25 +02:00
|
|
|
|
public WorldThread()
|
|
|
|
|
{
|
2022-10-15 17:06:19 +08:00
|
|
|
|
Instance = this;
|
2023-01-28 20:51:29 +08:00
|
|
|
|
Aborted += (e) => { DoQueuedActions(); ChangeTraffic(true); };
|
2021-07-07 13:36:25 +02:00
|
|
|
|
}
|
2023-01-28 20:51:29 +08:00
|
|
|
|
protected override void OnStart()
|
|
|
|
|
{
|
|
|
|
|
base.OnStart();
|
2023-03-26 15:36:15 +08:00
|
|
|
|
while (Game.IsLoading)
|
|
|
|
|
Yield();
|
2022-09-06 21:46:35 +08:00
|
|
|
|
|
2023-01-28 20:51:29 +08:00
|
|
|
|
Notification.Show(NotificationIcon.AllPlayersConf, "RAGECOOP", "Welcome!",
|
2023-02-13 20:44:50 +08:00
|
|
|
|
$"Press ~g~{Settings.MenuKey}~s~ to open the menu.");
|
2023-01-28 20:51:29 +08:00
|
|
|
|
}
|
|
|
|
|
protected override void OnTick()
|
2021-07-07 13:36:25 +02:00
|
|
|
|
{
|
2023-01-28 20:51:29 +08:00
|
|
|
|
base.OnTick();
|
|
|
|
|
|
2023-03-26 15:36:15 +08:00
|
|
|
|
if (_sleeping)
|
|
|
|
|
{
|
|
|
|
|
Game.Pause(true);
|
|
|
|
|
while (_sleeping)
|
|
|
|
|
{
|
|
|
|
|
// Don't wait longer than 5 seconds or the game will crash
|
|
|
|
|
Thread.Sleep(4500);
|
|
|
|
|
Yield();
|
|
|
|
|
}
|
|
|
|
|
Game.Pause(false);
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-30 19:08:52 +08:00
|
|
|
|
if (Game.IsLoading) return;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
CoopMenu.MenuPool.Process();
|
|
|
|
|
DoQueuedActions();
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
2023-02-13 17:51:18 +08:00
|
|
|
|
Log.Error(ex);
|
2022-11-30 19:08:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!Networking.IsOnServer) return;
|
2021-07-07 13:36:25 +02:00
|
|
|
|
|
2022-05-27 14:33:33 +08:00
|
|
|
|
Game.DisableControlThisFrame(Control.FrontendPause);
|
2022-08-13 16:59:09 +08:00
|
|
|
|
|
2023-02-13 20:44:50 +08:00
|
|
|
|
if (Settings.DisableAlternatePause) Game.DisableControlThisFrame(Control.FrontendPauseAlternate);
|
2022-04-18 21:54:34 +02:00
|
|
|
|
// 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.
|
2023-01-28 20:51:29 +08:00
|
|
|
|
Call(SET_DEEP_OCEAN_SCALER, 0.0f); // Works only ~200 meters around the player
|
2022-08-23 17:43:24 +08:00
|
|
|
|
|
2023-02-13 20:44:50 +08:00
|
|
|
|
if (Settings.ShowEntityOwnerName)
|
2022-08-23 17:43:24 +08:00
|
|
|
|
unsafe
|
|
|
|
|
{
|
|
|
|
|
int handle;
|
2023-01-28 20:51:29 +08:00
|
|
|
|
if (Call<bool>(GET_ENTITY_PLAYER_IS_FREE_AIMING_AT, 0, &handle))
|
2022-08-23 17:43:24 +08:00
|
|
|
|
{
|
|
|
|
|
var entity = Entity.FromHandle(handle);
|
|
|
|
|
if (entity != null)
|
|
|
|
|
{
|
|
|
|
|
var owner = "invalid";
|
|
|
|
|
if (entity.EntityType == EntityType.Vehicle)
|
|
|
|
|
owner = (entity as Vehicle).GetSyncEntity()?.Owner?.Username ?? "unknown";
|
|
|
|
|
if (entity.EntityType == EntityType.Ped)
|
|
|
|
|
owner = (entity as Ped).GetSyncEntity()?.Owner?.Username ?? "unknown";
|
2022-10-23 19:02:39 +08:00
|
|
|
|
Screen.ShowHelpTextThisFrame("Entity owner: " + owner);
|
2022-08-23 17:43:24 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-10-23 19:02:39 +08:00
|
|
|
|
|
2022-08-24 18:47:59 +08:00
|
|
|
|
if (!_trafficEnabled)
|
|
|
|
|
{
|
2023-01-28 20:51:29 +08:00
|
|
|
|
Call(SET_VEHICLE_POPULATION_BUDGET, 0);
|
|
|
|
|
Call(SET_PED_POPULATION_BUDGET, 0);
|
|
|
|
|
Call(SET_VEHICLE_DENSITY_MULTIPLIER_THIS_FRAME, 0f);
|
|
|
|
|
Call(SET_RANDOM_VEHICLE_DENSITY_MULTIPLIER_THIS_FRAME, 0f);
|
|
|
|
|
Call(SET_PARKED_VEHICLE_DENSITY_MULTIPLIER_THIS_FRAME, 0f);
|
|
|
|
|
Call(SUPPRESS_SHOCKING_EVENTS_NEXT_FRAME);
|
|
|
|
|
Call(SUPPRESS_AGITATION_EVENTS_NEXT_FRAME);
|
2022-08-24 18:47:59 +08:00
|
|
|
|
}
|
2021-08-18 11:47:59 +02:00
|
|
|
|
}
|
2022-10-23 19:02:39 +08:00
|
|
|
|
|
2022-08-14 10:35:59 +08:00
|
|
|
|
public static void Traffic(bool enable)
|
2022-08-22 21:59:01 +08:00
|
|
|
|
{
|
|
|
|
|
ChangeTraffic(enable);
|
|
|
|
|
_trafficEnabled = enable;
|
|
|
|
|
}
|
2022-10-23 19:02:39 +08:00
|
|
|
|
|
2022-08-22 21:59:01 +08:00
|
|
|
|
private static void ChangeTraffic(bool enable)
|
2021-08-18 11:47:59 +02:00
|
|
|
|
{
|
|
|
|
|
if (enable)
|
|
|
|
|
{
|
2023-01-28 20:51:29 +08:00
|
|
|
|
Call(REMOVE_SCENARIO_BLOCKING_AREAS);
|
|
|
|
|
Call(SET_CREATE_RANDOM_COPS, true);
|
|
|
|
|
Call(SET_RANDOM_TRAINS, true);
|
|
|
|
|
Call(SET_RANDOM_BOATS, true);
|
|
|
|
|
Call(SET_GARBAGE_TRUCKS, true);
|
|
|
|
|
Call(SET_PED_POPULATION_BUDGET, 3); // 0 - 3
|
|
|
|
|
Call(SET_VEHICLE_POPULATION_BUDGET, 3); // 0 - 3
|
|
|
|
|
Call(SET_ALL_VEHICLE_GENERATORS_ACTIVE);
|
|
|
|
|
Call(SET_ALL_LOW_PRIORITY_VEHICLE_GENERATORS_ACTIVE, true);
|
|
|
|
|
Call(SET_NUMBER_OF_PARKED_VEHICLES, -1);
|
|
|
|
|
Call(SET_DISTANT_CARS_ENABLED, true);
|
|
|
|
|
Call(DISABLE_VEHICLE_DISTANTLIGHTS, false);
|
2021-08-18 11:47:59 +02:00
|
|
|
|
}
|
2022-09-06 21:46:35 +08:00
|
|
|
|
else if (Networking.IsOnServer)
|
2021-08-18 11:47:59 +02:00
|
|
|
|
{
|
2023-01-28 20:51:29 +08:00
|
|
|
|
Call(ADD_SCENARIO_BLOCKING_AREA, -10000.0f, -10000.0f, -1000.0f, 10000.0f, 10000.0f,
|
2022-10-23 19:02:39 +08:00
|
|
|
|
1000.0f, 0, 1, 1, 1);
|
2023-01-28 20:51:29 +08:00
|
|
|
|
Call(SET_CREATE_RANDOM_COPS, false);
|
|
|
|
|
Call(SET_RANDOM_TRAINS, false);
|
|
|
|
|
Call(SET_RANDOM_BOATS, false);
|
|
|
|
|
Call(SET_GARBAGE_TRUCKS, false);
|
|
|
|
|
Call(DELETE_ALL_TRAINS);
|
|
|
|
|
Call(SET_PED_POPULATION_BUDGET, 0);
|
|
|
|
|
Call(SET_VEHICLE_POPULATION_BUDGET, 0);
|
|
|
|
|
Call(SET_ALL_LOW_PRIORITY_VEHICLE_GENERATORS_ACTIVE, false);
|
|
|
|
|
Call(SET_FAR_DRAW_VEHICLES, false);
|
|
|
|
|
Call(SET_NUMBER_OF_PARKED_VEHICLES, 0);
|
|
|
|
|
Call(SET_DISTANT_CARS_ENABLED, false);
|
|
|
|
|
Call(DISABLE_VEHICLE_DISTANTLIGHTS, true);
|
2022-10-23 19:02:39 +08:00
|
|
|
|
foreach (var ped in World.GetAllPeds())
|
2021-08-18 11:47:59 +02:00
|
|
|
|
{
|
2022-10-23 19:02:39 +08:00
|
|
|
|
if (ped == Game.Player.Character) continue;
|
|
|
|
|
var c = EntityPool.GetPedByHandle(ped.Handle);
|
|
|
|
|
if (c == null || (c.IsLocal && ped.Handle != Game.Player.Character.Handle &&
|
|
|
|
|
ped.PopulationType != EntityPopulationType.Mission))
|
2022-05-22 15:55:26 +08:00
|
|
|
|
{
|
2023-02-13 17:51:18 +08:00
|
|
|
|
Log.Trace($"Removing ped {ped.Handle}. Reason:RemoveTraffic");
|
2022-08-27 14:17:10 +08:00
|
|
|
|
ped.CurrentVehicle?.Delete();
|
|
|
|
|
ped.Kill();
|
|
|
|
|
ped.Delete();
|
2022-05-22 15:55:26 +08:00
|
|
|
|
}
|
2022-08-22 21:59:01 +08:00
|
|
|
|
}
|
2022-08-27 14:17:10 +08:00
|
|
|
|
|
2022-10-23 19:02:39 +08:00
|
|
|
|
foreach (var veh in World.GetAllVehicles())
|
2021-08-18 11:47:59 +02:00
|
|
|
|
{
|
2022-10-23 19:02:39 +08:00
|
|
|
|
var v = veh.GetSyncEntity();
|
|
|
|
|
if (v.MainVehicle == Game.Player.LastVehicle ||
|
|
|
|
|
v.MainVehicle == Game.Player.Character.CurrentVehicle)
|
2022-08-27 14:17:10 +08:00
|
|
|
|
// Don't delete player's vehicle
|
|
|
|
|
continue;
|
2022-10-23 19:02:39 +08:00
|
|
|
|
if (v == null || (v.IsLocal && veh.PopulationType != EntityPopulationType.Mission))
|
2023-02-13 17:51:18 +08:00
|
|
|
|
// Log.Debug($"Removing Vehicle {veh.Handle}. Reason:ClearTraffic");
|
2022-05-22 15:55:26 +08:00
|
|
|
|
|
2022-08-27 14:17:10 +08:00
|
|
|
|
veh.Delete();
|
2021-08-18 11:47:59 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2021-07-07 13:36:25 +02:00
|
|
|
|
}
|
2022-10-09 22:07:52 +08:00
|
|
|
|
|
|
|
|
|
public static void Delay(Action a, int time)
|
|
|
|
|
{
|
|
|
|
|
Task.Run(() =>
|
|
|
|
|
{
|
|
|
|
|
Thread.Sleep(time);
|
|
|
|
|
QueueAction(a);
|
|
|
|
|
});
|
|
|
|
|
}
|
2022-10-23 19:02:39 +08:00
|
|
|
|
|
2022-10-09 22:07:52 +08:00
|
|
|
|
internal static void DoQueuedActions()
|
|
|
|
|
{
|
|
|
|
|
lock (QueuedActions)
|
|
|
|
|
{
|
|
|
|
|
foreach (var action in QueuedActions.ToArray())
|
|
|
|
|
try
|
|
|
|
|
{
|
2022-10-23 19:02:39 +08:00
|
|
|
|
if (action()) QueuedActions.Remove(action);
|
2022-10-09 22:07:52 +08:00
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
2023-02-13 17:51:18 +08:00
|
|
|
|
Log.Error(ex);
|
2022-10-09 22:07:52 +08:00
|
|
|
|
QueuedActions.Remove(action);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2022-10-23 19:02:39 +08:00
|
|
|
|
/// Queue an action to be executed on next tick, allowing you to call scripting API from another thread.
|
2022-10-09 22:07:52 +08:00
|
|
|
|
/// </summary>
|
2022-10-23 19:02:39 +08:00
|
|
|
|
/// <param name="a">
|
|
|
|
|
/// An action to be executed with a return value indicating whether the action can be removed after
|
|
|
|
|
/// execution.
|
|
|
|
|
/// </param>
|
2022-10-09 22:07:52 +08:00
|
|
|
|
internal static void QueueAction(Func<bool> a)
|
|
|
|
|
{
|
|
|
|
|
lock (QueuedActions)
|
|
|
|
|
{
|
|
|
|
|
QueuedActions.Add(a);
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-10-23 19:02:39 +08:00
|
|
|
|
|
2022-10-09 22:07:52 +08:00
|
|
|
|
internal static void QueueAction(Action a)
|
|
|
|
|
{
|
|
|
|
|
lock (QueuedActions)
|
|
|
|
|
{
|
2022-10-23 19:02:39 +08:00
|
|
|
|
QueuedActions.Add(() =>
|
|
|
|
|
{
|
|
|
|
|
a();
|
|
|
|
|
return true;
|
|
|
|
|
});
|
2022-10-09 22:07:52 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-10-23 19:02:39 +08:00
|
|
|
|
|
2022-10-09 22:07:52 +08:00
|
|
|
|
/// <summary>
|
2022-10-23 19:02:39 +08:00
|
|
|
|
/// Clears all queued actions
|
2022-10-09 22:07:52 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
internal static void ClearQueuedActions()
|
|
|
|
|
{
|
2022-10-23 19:02:39 +08:00
|
|
|
|
lock (QueuedActions)
|
|
|
|
|
{
|
|
|
|
|
QueuedActions.Clear();
|
|
|
|
|
}
|
2022-10-09 22:07:52 +08:00
|
|
|
|
}
|
2023-03-26 15:36:15 +08:00
|
|
|
|
private static bool _sleeping;
|
|
|
|
|
[ConsoleCommand("Put the game to sleep state by blocking main thread, press any key in the debug console to resume")]
|
|
|
|
|
public static void Sleep()
|
|
|
|
|
{
|
|
|
|
|
if (_sleeping)
|
|
|
|
|
throw new InvalidOperationException("Already in sleep state");
|
|
|
|
|
|
|
|
|
|
_sleeping = true;
|
|
|
|
|
Task.Run(() =>
|
|
|
|
|
{
|
|
|
|
|
System.Console.WriteLine("Press any key to put the game out of sleep state");
|
|
|
|
|
System.Console.ReadKey();
|
|
|
|
|
System.Console.WriteLine("Game resumed");
|
|
|
|
|
_sleeping = false;
|
|
|
|
|
});
|
|
|
|
|
}
|
2021-07-07 13:36:25 +02:00
|
|
|
|
}
|
2022-10-23 19:02:39 +08:00
|
|
|
|
}
|