This commit is contained in:
2026-07-07 21:08:52 +02:00
commit 4c20cfc716
2613 changed files with 318021 additions and 0 deletions

View File

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

View File

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

View 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.

View File

@@ -0,0 +1,2 @@
@echo off
dotnet publish Client\rv_world_cleanup.Client.csproj --configuration Release

View 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' }