0.0.1
This commit is contained in:
@@ -0,0 +1,415 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using CitizenFX.Core;
|
||||
using static CitizenFX.Core.Native.API;
|
||||
|
||||
namespace RvWorldCleanup.Client
|
||||
{
|
||||
public class WorldCleanupClient : BaseScript
|
||||
{
|
||||
private static readonly string[] BlockedScenarioTypes =
|
||||
{
|
||||
"WORLD_HUMAN_AA_COFFEE",
|
||||
"WORLD_HUMAN_AA_SMOKE",
|
||||
"WORLD_HUMAN_BINOCULARS",
|
||||
"WORLD_HUMAN_CLIPBOARD",
|
||||
"WORLD_HUMAN_DRINKING",
|
||||
"WORLD_HUMAN_GUARD_STAND",
|
||||
"WORLD_HUMAN_HANG_OUT_STREET",
|
||||
"WORLD_HUMAN_SMOKING",
|
||||
"WORLD_HUMAN_STAND_IMPATIENT",
|
||||
"PROP_HUMAN_SEAT_BENCH",
|
||||
"PROP_HUMAN_SEAT_CHAIR",
|
||||
"WORLD_VEHICLE_ATTRACTOR",
|
||||
"WORLD_VEHICLE_BICYCLE_BMX",
|
||||
"WORLD_VEHICLE_EMPTY",
|
||||
"WORLD_VEHICLE_POLICE_CAR",
|
||||
"WORLD_VEHICLE_POLICE_NEXT_TO_CAR"
|
||||
};
|
||||
|
||||
private CleanupSettings _settings;
|
||||
private int _nextConfigRefreshAt;
|
||||
private int _nextCleanupAt;
|
||||
|
||||
public WorldCleanupClient()
|
||||
{
|
||||
_settings = CleanupSettings.Load();
|
||||
ApplyPersistentToggles();
|
||||
|
||||
EventHandlers["onClientResourceStart"] += new Action<string>(OnClientResourceStart);
|
||||
EventHandlers["onClientResourceStop"] += new Action<string>(OnClientResourceStop);
|
||||
|
||||
Tick += OnTick;
|
||||
}
|
||||
|
||||
private void OnClientResourceStart(string resourceName)
|
||||
{
|
||||
if (resourceName != GetCurrentResourceName())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_settings = CleanupSettings.Load();
|
||||
ApplyPersistentToggles();
|
||||
|
||||
Debug.WriteLine(string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
"[{0}] Ambient cleanup aktiv. Radius={1:0.##}, Intervall={2}ms",
|
||||
GetCurrentResourceName(),
|
||||
_settings.ClearRadius,
|
||||
_settings.ClearIntervalMs));
|
||||
}
|
||||
|
||||
private void OnClientResourceStop(string resourceName)
|
||||
{
|
||||
if (resourceName != GetCurrentResourceName())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RestorePersistentToggles();
|
||||
}
|
||||
|
||||
private async Task OnTick()
|
||||
{
|
||||
var now = GetGameTimer();
|
||||
|
||||
if (now >= _nextConfigRefreshAt)
|
||||
{
|
||||
_settings = CleanupSettings.Load();
|
||||
ApplyPersistentToggles();
|
||||
_nextConfigRefreshAt = now + _settings.ConfigRefreshMs;
|
||||
}
|
||||
|
||||
if (!_settings.Enabled)
|
||||
{
|
||||
await Delay(1000);
|
||||
return;
|
||||
}
|
||||
|
||||
ApplyFrameSuppression();
|
||||
|
||||
if (_settings.DisableScenarioActions)
|
||||
{
|
||||
ApplyScenarioSuppression();
|
||||
}
|
||||
|
||||
if (now >= _nextCleanupAt)
|
||||
{
|
||||
CleanupNearbyWorld();
|
||||
_nextCleanupAt = now + _settings.ClearIntervalMs;
|
||||
}
|
||||
|
||||
await Delay(0);
|
||||
}
|
||||
|
||||
private void ApplyPersistentToggles()
|
||||
{
|
||||
SetRandomBoats(!_settings.DisableRandomBoats);
|
||||
SetGarbageTrucks(!_settings.DisableGarbageTrucks);
|
||||
|
||||
var allowRandomCops = !_settings.DisableRandomCops;
|
||||
SetCreateRandomCops(allowRandomCops);
|
||||
SetCreateRandomCopsOnScenarios(allowRandomCops);
|
||||
SetCreateRandomCopsNotOnScenarios(allowRandomCops);
|
||||
|
||||
var allowDispatch = !_settings.DisableDispatchServices;
|
||||
|
||||
for (var service = 1; service <= 15; service++)
|
||||
{
|
||||
EnableDispatchService(service, allowDispatch);
|
||||
}
|
||||
|
||||
SetMaxWantedLevel(_settings.DisableDispatchServices ? 0 : 5);
|
||||
}
|
||||
|
||||
private void RestorePersistentToggles()
|
||||
{
|
||||
SetRandomBoats(true);
|
||||
SetGarbageTrucks(true);
|
||||
SetCreateRandomCops(true);
|
||||
SetCreateRandomCopsOnScenarios(true);
|
||||
SetCreateRandomCopsNotOnScenarios(true);
|
||||
|
||||
for (var service = 1; service <= 15; service++)
|
||||
{
|
||||
EnableDispatchService(service, true);
|
||||
}
|
||||
|
||||
SetMaxWantedLevel(5);
|
||||
}
|
||||
|
||||
private void ApplyFrameSuppression()
|
||||
{
|
||||
SetPedPopulationBudget(_settings.DisableAmbientPeds ? 0 : 3);
|
||||
SetVehiclePopulationBudget(_settings.DisableAmbientVehicles ? 0 : 3);
|
||||
|
||||
SetPedDensityMultiplierThisFrame(_settings.DisableAmbientPeds ? 0.0f : 1.0f);
|
||||
SetScenarioPedDensityMultiplierThisFrame(
|
||||
_settings.DisableScenarioPeds ? 0.0f : 1.0f,
|
||||
_settings.DisableScenarioPeds ? 0.0f : 1.0f);
|
||||
SetVehicleDensityMultiplierThisFrame(_settings.DisableAmbientVehicles ? 0.0f : 1.0f);
|
||||
SetRandomVehicleDensityMultiplierThisFrame(_settings.DisableAmbientVehicles ? 0.0f : 1.0f);
|
||||
SetParkedVehicleDensityMultiplierThisFrame(_settings.DisableParkedVehicles ? 0.0f : 1.0f);
|
||||
}
|
||||
|
||||
private void ApplyScenarioSuppression()
|
||||
{
|
||||
SuppressShockingEventsNextFrame();
|
||||
|
||||
foreach (var scenarioType in BlockedScenarioTypes)
|
||||
{
|
||||
SetScenarioTypeEnabled(scenarioType, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void CleanupNearbyWorld()
|
||||
{
|
||||
var playerPed = PlayerPedId();
|
||||
|
||||
if (playerPed == 0 || !DoesEntityExist(playerPed))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var playerCoords = GetEntityCoords(playerPed, true);
|
||||
var radius = _settings.ClearRadius;
|
||||
|
||||
if (_settings.DisableAmbientVehicles || _settings.DisableParkedVehicles)
|
||||
{
|
||||
RemoveVehiclesFromGeneratorsInArea(
|
||||
playerCoords.X - radius,
|
||||
playerCoords.Y - radius,
|
||||
playerCoords.Z - 10.0f,
|
||||
playerCoords.X + radius,
|
||||
playerCoords.Y + radius,
|
||||
playerCoords.Z + 10.0f);
|
||||
}
|
||||
|
||||
if (_settings.DeleteExistingPeds)
|
||||
{
|
||||
CleanupPeds(playerCoords, radius, playerPed);
|
||||
}
|
||||
|
||||
if (_settings.DeleteExistingVehicles)
|
||||
{
|
||||
CleanupVehicles(playerCoords, radius, playerPed);
|
||||
}
|
||||
}
|
||||
|
||||
private void CleanupPeds(Vector3 origin, float radius, int playerPed)
|
||||
{
|
||||
var iterator = FindFirstPed(ref playerPed);
|
||||
|
||||
try
|
||||
{
|
||||
if (iterator == -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var ped = playerPed;
|
||||
|
||||
do
|
||||
{
|
||||
if (!CanDeletePed(ped, playerPed, origin, radius))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
SetEntityAsMissionEntity(ped, true, true);
|
||||
DeletePed(ref ped);
|
||||
}
|
||||
while (FindNextPed(iterator, ref ped));
|
||||
}
|
||||
finally
|
||||
{
|
||||
EndFindPed(iterator);
|
||||
}
|
||||
}
|
||||
|
||||
private void CleanupVehicles(Vector3 origin, float radius, int playerPed)
|
||||
{
|
||||
var vehicle = 0;
|
||||
var iterator = FindFirstVehicle(ref vehicle);
|
||||
|
||||
try
|
||||
{
|
||||
if (iterator == -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
if (!CanDeleteVehicle(vehicle, playerPed, origin, radius))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
SetEntityAsMissionEntity(vehicle, true, true);
|
||||
DeleteVehicle(ref vehicle);
|
||||
}
|
||||
while (FindNextVehicle(iterator, ref vehicle));
|
||||
}
|
||||
finally
|
||||
{
|
||||
EndFindVehicle(iterator);
|
||||
}
|
||||
}
|
||||
|
||||
private bool CanDeletePed(int ped, int playerPed, Vector3 origin, float radius)
|
||||
{
|
||||
if (ped == 0 || ped == playerPed || !DoesEntityExist(ped))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsPedAPlayer(ped))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_settings.PreserveMissionEntities && IsEntityAMissionEntity(ped))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_settings.PreserveNetworkedEntities && NetworkGetEntityIsNetworked(ped))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsPedInAnyVehicle(ped, false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return IsInsideRadius(origin, GetEntityCoords(ped, true), radius);
|
||||
}
|
||||
|
||||
private bool CanDeleteVehicle(int vehicle, int playerPed, Vector3 origin, float radius)
|
||||
{
|
||||
if (vehicle == 0 || !DoesEntityExist(vehicle))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var currentPlayerVehicle = GetVehiclePedIsIn(playerPed, false);
|
||||
|
||||
if (vehicle == currentPlayerVehicle)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_settings.PreserveMissionEntities && IsEntityAMissionEntity(vehicle))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_settings.PreserveNetworkedEntities && NetworkGetEntityIsNetworked(vehicle))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_settings.PreserveOccupiedVehicles && !IsVehicleSeatFree(vehicle, -1))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return IsInsideRadius(origin, GetEntityCoords(vehicle, true), radius);
|
||||
}
|
||||
|
||||
private static bool IsInsideRadius(Vector3 origin, Vector3 target, float radius)
|
||||
{
|
||||
var distanceX = origin.X - target.X;
|
||||
var distanceY = origin.Y - target.Y;
|
||||
var distanceZ = origin.Z - target.Z;
|
||||
|
||||
return (distanceX * distanceX) + (distanceY * distanceY) + (distanceZ * distanceZ) <= radius * radius;
|
||||
}
|
||||
|
||||
private sealed class CleanupSettings
|
||||
{
|
||||
public bool Enabled { get; private set; }
|
||||
public bool DisableAmbientPeds { get; private set; }
|
||||
public bool DisableScenarioPeds { get; private set; }
|
||||
public bool DisableAmbientVehicles { get; private set; }
|
||||
public bool DisableParkedVehicles { get; private set; }
|
||||
public bool DisableDispatchServices { get; private set; }
|
||||
public bool DisableRandomCops { get; private set; }
|
||||
public bool DisableGarbageTrucks { get; private set; }
|
||||
public bool DisableRandomBoats { get; private set; }
|
||||
public bool DisableScenarioActions { get; private set; }
|
||||
public bool DeleteExistingPeds { get; private set; }
|
||||
public bool DeleteExistingVehicles { get; private set; }
|
||||
public bool PreserveMissionEntities { get; private set; }
|
||||
public bool PreserveNetworkedEntities { get; private set; }
|
||||
public bool PreserveOccupiedVehicles { get; private set; }
|
||||
public float ClearRadius { get; private set; }
|
||||
public int ClearIntervalMs { get; private set; }
|
||||
public int ConfigRefreshMs { get; private set; }
|
||||
|
||||
public static CleanupSettings Load()
|
||||
{
|
||||
return new CleanupSettings
|
||||
{
|
||||
Enabled = ReadBool("rv_cleanup_enable", true),
|
||||
DisableAmbientPeds = ReadBool("rv_cleanup_disable_ambient_peds", true),
|
||||
DisableScenarioPeds = ReadBool("rv_cleanup_disable_scenario_peds", true),
|
||||
DisableAmbientVehicles = ReadBool("rv_cleanup_disable_ambient_vehicles", true),
|
||||
DisableParkedVehicles = ReadBool("rv_cleanup_disable_parked_vehicles", true),
|
||||
DisableDispatchServices = ReadBool("rv_cleanup_disable_dispatch_services", true),
|
||||
DisableRandomCops = ReadBool("rv_cleanup_disable_random_cops", true),
|
||||
DisableGarbageTrucks = ReadBool("rv_cleanup_disable_garbage_trucks", true),
|
||||
DisableRandomBoats = ReadBool("rv_cleanup_disable_random_boats", true),
|
||||
DisableScenarioActions = ReadBool("rv_cleanup_disable_scenario_actions", true),
|
||||
DeleteExistingPeds = ReadBool("rv_cleanup_delete_existing_peds", true),
|
||||
DeleteExistingVehicles = ReadBool("rv_cleanup_delete_existing_vehicles", true),
|
||||
PreserveMissionEntities = ReadBool("rv_cleanup_preserve_mission_entities", true),
|
||||
PreserveNetworkedEntities = ReadBool("rv_cleanup_preserve_networked_entities", true),
|
||||
PreserveOccupiedVehicles = ReadBool("rv_cleanup_preserve_occupied_vehicles", true),
|
||||
ClearRadius = ReadFloat("rv_cleanup_clear_radius", 175.0f),
|
||||
ClearIntervalMs = ReadInt("rv_cleanup_clear_interval_ms", 10000),
|
||||
ConfigRefreshMs = ReadInt("rv_cleanup_config_refresh_ms", 5000)
|
||||
};
|
||||
}
|
||||
|
||||
private static bool ReadBool(string convarName, bool defaultValue)
|
||||
{
|
||||
var defaultText = defaultValue ? "true" : "false";
|
||||
var value = GetConvar(convarName, defaultText);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
value = value.Trim().ToLowerInvariant();
|
||||
|
||||
return value == "1" || value == "true" || value == "yes" || value == "on";
|
||||
}
|
||||
|
||||
private static int ReadInt(string convarName, int defaultValue)
|
||||
{
|
||||
var value = GetConvarInt(convarName, defaultValue);
|
||||
return value > 0 ? value : defaultValue;
|
||||
}
|
||||
|
||||
private static float ReadFloat(string convarName, float defaultValue)
|
||||
{
|
||||
var rawValue = GetConvar(convarName, defaultValue.ToString(CultureInfo.InvariantCulture));
|
||||
float parsedValue;
|
||||
|
||||
if (float.TryParse(rawValue, NumberStyles.Float, CultureInfo.InvariantCulture, out parsedValue) && parsedValue > 0.0f)
|
||||
{
|
||||
return parsedValue;
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<Project Sdk="CitizenFX.Sdk.Client/0.2.3">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net452</TargetFramework>
|
||||
<AssemblyName>rv_world_cleanup.Client</AssemblyName>
|
||||
<RootNamespace>RvWorldCleanup.Client</RootNamespace>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<OutputPath>..\dist\client\</OutputPath>
|
||||
<PublishDir>..\dist\client\</PublishDir>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
20
resources/[standalone]/rv_world_cleanup/README.md
Normal file
20
resources/[standalone]/rv_world_cleanup/README.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# rv_world_cleanup
|
||||
|
||||
Ambient-World-Cleanup als FiveM-C#-Resource für ESX.
|
||||
|
||||
## Build
|
||||
|
||||
Dieses Resource wurde absichtlich nicht lokal gebaut.
|
||||
|
||||
Zum Build auf deinem Server oder Build-System:
|
||||
|
||||
```bat
|
||||
cd /d resources\[standalone]\rv_world_cleanup
|
||||
build.cmd
|
||||
```
|
||||
|
||||
Danach liegt die DLL unter `dist/client/`.
|
||||
|
||||
## Config
|
||||
|
||||
Die Schalter liegen direkt in der `server.cfg` und werden als `setr rv_cleanup_* ...` gelesen.
|
||||
2
resources/[standalone]/rv_world_cleanup/build.cmd
Normal file
2
resources/[standalone]/rv_world_cleanup/build.cmd
Normal file
@@ -0,0 +1,2 @@
|
||||
@echo off
|
||||
dotnet publish Client\rv_world_cleanup.Client.csproj --configuration Release
|
||||
36
resources/[standalone]/rv_world_cleanup/fxmanifest.lua
Normal file
36
resources/[standalone]/rv_world_cleanup/fxmanifest.lua
Normal file
@@ -0,0 +1,36 @@
|
||||
fx_version 'cerulean'
|
||||
game 'gta5'
|
||||
|
||||
name 'rv_world_cleanup'
|
||||
author 'OpenAI'
|
||||
description 'Configurable ambient world cleanup for ESX servers'
|
||||
version '1.0.0'
|
||||
|
||||
client_script 'dist/client/rv_world_cleanup.Client.net.dll'
|
||||
|
||||
files {
|
||||
'dist/client/*.dll'
|
||||
}
|
||||
|
||||
convar_category 'RV World Cleanup' {
|
||||
'Steuert Ambient-NPCs, Fahrzeuge und Szenarien direkt über server.cfg.',
|
||||
{
|
||||
{'System aktivieren', '$rv_cleanup_enable', 'CV_BOOL', true},
|
||||
{'Ambient-NPCs deaktivieren', '$rv_cleanup_disable_ambient_peds', 'CV_BOOL', true},
|
||||
{'Szenario-NPCs deaktivieren', '$rv_cleanup_disable_scenario_peds', 'CV_BOOL', true},
|
||||
{'Ambient-Fahrzeuge deaktivieren', '$rv_cleanup_disable_ambient_vehicles', 'CV_BOOL', true},
|
||||
{'Geparkte Fahrzeuge deaktivieren', '$rv_cleanup_disable_parked_vehicles', 'CV_BOOL', true},
|
||||
{'Dispatch/Wanted deaktivieren', '$rv_cleanup_disable_dispatch_services', 'CV_BOOL', true},
|
||||
{'Zufalls-Cops deaktivieren', '$rv_cleanup_disable_random_cops', 'CV_BOOL', true},
|
||||
{'Müllwagen deaktivieren', '$rv_cleanup_disable_garbage_trucks', 'CV_BOOL', true},
|
||||
{'Zufalls-Boote deaktivieren', '$rv_cleanup_disable_random_boats', 'CV_BOOL', true},
|
||||
{'Welt-Szenarien unterdrücken', '$rv_cleanup_disable_scenario_actions', 'CV_BOOL', true},
|
||||
{'Bestehende Ambient-NPCs löschen', '$rv_cleanup_delete_existing_peds', 'CV_BOOL', true},
|
||||
{'Bestehende Ambient-Fahrzeuge löschen', '$rv_cleanup_delete_existing_vehicles', 'CV_BOOL', true},
|
||||
{'Radius für Bereinigung', '$rv_cleanup_clear_radius', 'CV_COMBI', 175, 25, 500},
|
||||
{'Intervall in Millisekunden', '$rv_cleanup_clear_interval_ms', 'CV_COMBI', 10000, 1000, 60000}
|
||||
}
|
||||
}
|
||||
|
||||
fxdk_watch_command 'dotnet' { 'watch', '--project', 'Client/rv_world_cleanup.Client.csproj', 'publish', '--configuration', 'Release' }
|
||||
fxdk_build_command 'dotnet' { 'publish', 'Client/rv_world_cleanup.Client.csproj', '--configuration', 'Release' }
|
||||
Reference in New Issue
Block a user