From 19f47b7f70b07bcdcbc0f188013746051f2cf821 Mon Sep 17 00:00:00 2001
From: Ricky Merc <65817116+RickyB505@users.noreply.github.com>
Date: Mon, 6 Apr 2026 14:42:30 -0400
Subject: [PATCH 1/5] fix(vehicle): fixes bug with underglow colour grabbing
---
vMenu/menus/VehicleOptions.cs | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/vMenu/menus/VehicleOptions.cs b/vMenu/menus/VehicleOptions.cs
index 17da329b..e9f755aa 100644
--- a/vMenu/menus/VehicleOptions.cs
+++ b/vMenu/menus/VehicleOptions.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Drawing;
using System.Linq;
using CitizenFX.Core;
@@ -2541,7 +2542,7 @@ internal static int GetHeadlightsColorForVehicle(Vehicle vehicle)
///
///
///
- private System.Drawing.Color GetColorFromIndex(int index)
+ private static System.Drawing.Color GetColorFromIndex(int index)
{
if (index is >= 0 and < 13)
{
@@ -2807,9 +2808,10 @@ public static void CreateCustomColourMenu(Menu menu, RGBType type = RGBType.prim
}
else if (type == RGBType.underglow)
{
- int red = vehicle.Mods.TireSmokeColor.R;
- int green = vehicle.Mods.NeonLightsColor.G;
- int blue = vehicle.Mods.NeonLightsColor.B;
+ Color underglow = GetColorFromIndex(newIndex);
+ int red = underglow.R;
+ int green = underglow.G;
+ int blue = underglow.B;
redColour.BarColor = System.Drawing.Color.FromArgb(255, red, green, blue);
greenColour.BarColor = System.Drawing.Color.FromArgb(255, red, green, blue);
From 26b1db7c6b494b9034e025043717d8d062389406 Mon Sep 17 00:00:00 2001
From: Ricky Merc <65817116+RickyB505@users.noreply.github.com>
Date: Mon, 6 Apr 2026 14:49:36 -0400
Subject: [PATCH 2/5] fix(vehicle): headlight index going out of range
---
vMenu/menus/VehicleOptions.cs | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/vMenu/menus/VehicleOptions.cs b/vMenu/menus/VehicleOptions.cs
index e9f755aa..cc4ba398 100644
--- a/vMenu/menus/VehicleOptions.cs
+++ b/vMenu/menus/VehicleOptions.cs
@@ -2723,9 +2723,10 @@ public static void CreateCustomColourMenu(Menu menu, RGBType type = RGBType.prim
{
if (IsToggleModOn(vehicle.Handle, 22))
{
- r = VehicleData.NeonLightColors[GetHeadlightsColorForVehicle(vehicle)][0];
- g = VehicleData.NeonLightColors[GetHeadlightsColorForVehicle(vehicle)][1];
- b = VehicleData.NeonLightColors[GetHeadlightsColorForVehicle(vehicle)][2];
+ int headlight = GetHeadlightsColorForVehicle(vehicle) < 0 ? 0 : GetHeadlightsColorForVehicle(vehicle);
+ r = VehicleData.NeonLightColors[headlight][0];
+ g = VehicleData.NeonLightColors[headlight][1];
+ b = VehicleData.NeonLightColors[headlight][2];
}
}
@@ -2828,10 +2829,10 @@ public static void CreateCustomColourMenu(Menu menu, RGBType type = RGBType.prim
}
else if (type == RGBType.headlight)
{
-
- int red = VehicleData.NeonLightColors[GetHeadlightsColorForVehicle(vehicle)][0];
- int green = VehicleData.NeonLightColors[GetHeadlightsColorForVehicle(vehicle)][1];
- int blue = VehicleData.NeonLightColors[GetHeadlightsColorForVehicle(vehicle)][2];
+ int headlight = GetHeadlightsColorForVehicle(vehicle) < 0 ? 0 : GetHeadlightsColorForVehicle(vehicle);
+ int red = VehicleData.NeonLightColors[headlight][0];
+ int green = VehicleData.NeonLightColors[headlight][1];
+ int blue = VehicleData.NeonLightColors[headlight][2];
redColour.BarColor = System.Drawing.Color.FromArgb(255, red, green, blue);
From 09acff53de697166b50a6806c15bd50e56eb8b95 Mon Sep 17 00:00:00 2001
From: Ricky Merc <65817116+RickyB505@users.noreply.github.com>
Date: Mon, 6 Apr 2026 14:57:14 -0400
Subject: [PATCH 3/5] fix(vehicle): fixes bugs related to spelling, and missing
text fields
---
vMenu/menus/VehicleOptions.cs | 57 ++++++++++++++++++-----------------
1 file changed, 29 insertions(+), 28 deletions(-)
diff --git a/vMenu/menus/VehicleOptions.cs b/vMenu/menus/VehicleOptions.cs
index cc4ba398..6c89be7f 100644
--- a/vMenu/menus/VehicleOptions.cs
+++ b/vMenu/menus/VehicleOptions.cs
@@ -2153,7 +2153,7 @@ public void UpdateMods(int selectedIndex = 0)
}
var headlightsButton = new MenuItem("Headlights");
- var headlightsMenu = new Menu("Headlights");
+ var headlightsMenu = new Menu("Headlights", "headlights");
var xenonHeadlights = new MenuCheckboxItem("Xenon Headlights", "Enable or disable ~b~xenon ~s~headlights.", IsToggleModOn(veh.Handle, 22));
headlightsMenu.AddMenuItem(xenonHeadlights);
var currentHeadlightColor = GetHeadlightsColorForVehicle(veh);
@@ -2215,7 +2215,7 @@ public void UpdateMods(int selectedIndex = 0)
}
var tireSmokeButton = new MenuItem("Tire Smoke");
- var tireSmokeMenu = new Menu("Tire Smoke");
+ var tireSmokeMenu = new Menu("Tire Smoke", "Tire Smoke");
// Create a list of tire smoke options.
var tireSmokes = new List() { "Red", "Orange", "Yellow", "Gold", "Light Green", "Dark Green", "Light Blue", "Dark Blue", "Purple", "Pink", "Black" };
var tireSmokeColors = new Dictionary()
@@ -2587,22 +2587,22 @@ public enum RGBType
public static void CreateCustomColourMenu(Menu menu, RGBType type = RGBType.primaryPaint)
{
- var hexColour = new MenuItem("Hex Colour Code");
+ var hexColour = new MenuItem("Hex Color Code");
var typeList = new MenuListItem("Paint Finish", Enum.GetNames(typeof(Colour_Types)).ToList(), 0);
int r = 0, g = 0, b = 0;
- var redColour = new MenuSliderItem("Red Colour", 0, 255, 128, true)
+ var redColour = new MenuSliderItem("Red Color", 0, 255, 128, true)
{
BarColor = System.Drawing.Color.FromArgb(155, 0, 0, 0),
BackgroundColor = System.Drawing.Color.FromArgb(200, 79, 79, 79),
};
- var greenColour = new MenuSliderItem("Green Colour", 0, 255, 128, true)
+ var greenColour = new MenuSliderItem("Green Color", 0, 255, 128, true)
{
BarColor = System.Drawing.Color.FromArgb(155, 0, 0, 0),
BackgroundColor = System.Drawing.Color.FromArgb(200, 79, 79, 79),
};
- var blueColour = new MenuSliderItem("Blue Colour", 0, 255, 128, true)
+ var blueColour = new MenuSliderItem("Blue Color", 0, 255, 128, true)
{
BarColor = System.Drawing.Color.FromArgb(155, 0, 0, 0),
BackgroundColor = System.Drawing.Color.FromArgb(200, 79, 79, 79),
@@ -2635,9 +2635,10 @@ public static void CreateCustomColourMenu(Menu menu, RGBType type = RGBType.prim
{
if (IsToggleModOn(vehicle.Handle, 22))
{
- r = VehicleData.NeonLightColors[GetHeadlightsColorForVehicle(vehicle)][0];
- g = VehicleData.NeonLightColors[GetHeadlightsColorForVehicle(vehicle)][1];
- b = VehicleData.NeonLightColors[GetHeadlightsColorForVehicle(vehicle)][2];
+ int headlight = GetHeadlightsColorForVehicle(vehicle) < 0 ? 0 : GetHeadlightsColorForVehicle(vehicle);
+ r = VehicleData.NeonLightColors[headlight][0];
+ g = VehicleData.NeonLightColors[headlight][1];
+ b = VehicleData.NeonLightColors[headlight][2];
}
}
@@ -2646,13 +2647,13 @@ public static void CreateCustomColourMenu(Menu menu, RGBType type = RGBType.prim
GetVehicleTyreSmokeColor(vehicle.Handle, ref r, ref g, ref b);
- redColour.Text = $"Red Colour ({r})";
+ redColour.Text = $"Red Color ({r})";
redColour.Position = r;
- greenColour.Text = $"Green Colour ({g})";
+ greenColour.Text = $"Green Color ({g})";
greenColour.Position = g;
- blueColour.Text = $"Blue Colour ({b})";
+ blueColour.Text = $"Blue Color ({b})";
blueColour.Position = b;
redColour.BarColor = System.Drawing.Color.FromArgb(255, redColour.Position, greenColour.Position, blueColour.Position);
@@ -2666,7 +2667,7 @@ public static void CreateCustomColourMenu(Menu menu, RGBType type = RGBType.prim
if (item == hexColour)
{
string hexValue = redColour.Position.ToString("X2") + greenColour.Position.ToString("X2") + blueColour.Position.ToString("X2");
- var result = await GetUserInput(windowTitle: "Enter Colour Hex", defaultText: (hexValue).Replace("#", ""), maxInputLength: 6);
+ var result = await GetUserInput(windowTitle: "Enter Color Hex", defaultText: (hexValue).Replace("#", ""), maxInputLength: 6);
if (!string.IsNullOrEmpty(result))
{
if (IsHex(result))
@@ -2691,13 +2692,13 @@ public static void CreateCustomColourMenu(Menu menu, RGBType type = RGBType.prim
greenColour.BarColor = System.Drawing.Color.FromArgb(255, red, green, blue);
blueColour.BarColor = System.Drawing.Color.FromArgb(255, red, green, blue);
- redColour.Text = $"Red Colour ({red})";
+ redColour.Text = $"Red Color ({red})";
redColour.Position = red;
- greenColour.Text = $"Green Colour ({green})";
+ greenColour.Text = $"Green Color ({green})";
greenColour.Position = green;
- blueColour.Text = $"Blue Colour ({blue})";
+ blueColour.Text = $"Blue Color ({blue})";
blueColour.Position = blue;
}
}
@@ -2748,7 +2749,7 @@ public static void CreateCustomColourMenu(Menu menu, RGBType type = RGBType.prim
else if (type == RGBType.tiresmoke)
vehicle.Mods.TireSmokeColor = System.Drawing.Color.FromArgb(255, newPosition, g, b);
- redColour.Text = $"Red Colour ({newPosition})";
+ redColour.Text = $"Red Color ({newPosition})";
}
if (sliderItem == greenColour)
{
@@ -2763,7 +2764,7 @@ public static void CreateCustomColourMenu(Menu menu, RGBType type = RGBType.prim
else if (type == RGBType.tiresmoke)
vehicle.Mods.TireSmokeColor = System.Drawing.Color.FromArgb(255, r, newPosition, b);
- greenColour.Text = $"Green Colour ({newPosition})";
+ greenColour.Text = $"Green Color ({newPosition})";
}
if (sliderItem == blueColour)
{
@@ -2778,7 +2779,7 @@ public static void CreateCustomColourMenu(Menu menu, RGBType type = RGBType.prim
else if (type == RGBType.tiresmoke)
vehicle.Mods.TireSmokeColor = System.Drawing.Color.FromArgb(255, r, g, newPosition);
- blueColour.Text = $"Blue Colour ({newPosition})";
+ blueColour.Text = $"Blue Color ({newPosition})";
}
redColour.BarColor = System.Drawing.Color.FromArgb(255, redColour.Position, greenColour.Position, blueColour.Position);
greenColour.BarColor = System.Drawing.Color.FromArgb(255, redColour.Position, greenColour.Position, blueColour.Position);
@@ -2818,13 +2819,13 @@ public static void CreateCustomColourMenu(Menu menu, RGBType type = RGBType.prim
greenColour.BarColor = System.Drawing.Color.FromArgb(255, red, green, blue);
blueColour.BarColor = System.Drawing.Color.FromArgb(255, red, green, blue);
- redColour.Text = $"Red Colour ({red})";
+ redColour.Text = $"Red Color ({red})";
redColour.Position = red;
- greenColour.Text = $"Green Colour ({green})";
+ greenColour.Text = $"Green Color ({green})";
greenColour.Position = green;
- blueColour.Text = $"Blue Colour ({blue})";
+ blueColour.Text = $"Blue Color ({blue})";
blueColour.Position = blue;
}
else if (type == RGBType.headlight)
@@ -2839,13 +2840,13 @@ public static void CreateCustomColourMenu(Menu menu, RGBType type = RGBType.prim
greenColour.BarColor = System.Drawing.Color.FromArgb(255, red, green, blue);
blueColour.BarColor = System.Drawing.Color.FromArgb(255, red, green, blue);
- redColour.Text = $"Red Colour ({red})";
+ redColour.Text = $"Red Color ({red})";
redColour.Position = red;
- greenColour.Text = $"Green Colour ({green})";
+ greenColour.Text = $"Green Color ({green})";
greenColour.Position = green;
- blueColour.Text = $"Blue Colour ({blue})";
+ blueColour.Text = $"Blue Color ({blue})";
blueColour.Position = blue;
}
else if (type == RGBType.tiresmoke)
@@ -2858,13 +2859,13 @@ public static void CreateCustomColourMenu(Menu menu, RGBType type = RGBType.prim
greenColour.BarColor = System.Drawing.Color.FromArgb(255, red, green, blue);
blueColour.BarColor = System.Drawing.Color.FromArgb(255, red, green, blue);
- redColour.Text = $"Red Colour ({red})";
+ redColour.Text = $"Red Color ({red})";
redColour.Position = red;
- greenColour.Text = $"Green Colour ({green})";
+ greenColour.Text = $"Green Color ({green})";
greenColour.Position = green;
- blueColour.Text = $"Blue Colour ({blue})";
+ blueColour.Text = $"Blue Color ({blue})";
blueColour.Position = blue;
}
From ee278e9ebe9feb0b6a9f25c6f4c596e376bd0a73 Mon Sep 17 00:00:00 2001
From: Tom Grobbe
Date: Sat, 18 Apr 2026 19:08:26 +0200
Subject: [PATCH 4/5] Gitignore update
---
.gitignore | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/.gitignore b/.gitignore
index fdc8383c..61d26fcf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -267,4 +267,6 @@ external/
*.cmd.bak
# VS Build Output
-build/
\ No newline at end of file
+build/
+
+*.lscache
\ No newline at end of file
From b6a8bbe60889186452d6a4b619fbc6a36bec44ae Mon Sep 17 00:00:00 2001
From: Tom <31419184+TomGrobbe@users.noreply.github.com>
Date: Fri, 5 Jun 2026 15:35:35 +0200
Subject: [PATCH 5/5] Supplemental permissions pilot (#619)
* feat/fix: addon permissions/updating outdated function (#610)
* feat/fix: addon permissions/updating outdated function
added individual permissions to addon vehicles/weapons/peds, and added a whitelist to regular vehicles/ped. changed (uint)GetHashKey() to Game.GenerateHashASCII() for better optimization
* fix: updated what was requested
* fix: typo
* fix: fixed what needed changing
* fix: fixed controller controls and permissions for weapons (#613)
* New features and fixes (#614)
* vehicle spawning ratelimit
* fix: move setting the vehicle speed inside where we check if they spawn inside
* feat: add command "vMenu:DV"
* feat: add back smooth time transitions
* fix: fixes server sided permissions so it checks the parent permissions
* fix: disable post build command on non windows machines
* fix: Changes and fixes requested
---------
Co-authored-by: Ricky Merc <65817116+RickyB505@users.noreply.github.com>
---
SharedClasses/ConfigManager.cs | 19 +-
SharedClasses/PermissionsManager.cs | 4 +-
.../SupplementaryPermissionManager.cs | 240 ++++++++++++++++++
vMenu/CommonFunctions.cs | 184 +++++++++++---
vMenu/EntitySpawner.cs | 2 +-
vMenu/EventManager.cs | 79 +++++-
vMenu/FunctionsController.cs | 198 +++++++++------
vMenu/MainMenu.cs | 43 +++-
vMenu/data/BlipInfo.cs | 105 ++++----
vMenu/data/PedModels.cs | 87 +++----
vMenu/data/ValidAddonWeapon.cs | 4 +-
vMenu/data/ValidWeapon.cs | 4 +-
vMenu/menus/MpPedCustomization.cs | 34 +--
vMenu/menus/PlayerAppearance.cs | 29 ++-
vMenu/menus/PlayerOptions.cs | 2 +-
vMenu/menus/Recording.cs | 2 +-
vMenu/menus/VehicleOptions.cs | 21 +-
vMenu/menus/VehicleSpawner.cs | 34 ++-
vMenu/menus/WeaponOptions.cs | 19 +-
vMenu/vMenuClient.csproj | 5 +-
vMenuServer/MainServer.cs | 132 ++++++++--
vMenuServer/config/model-whitelists.json | 23 ++
vMenuServer/config/permissions.cfg | 8 +
vMenuServer/vMenuServer.csproj | 6 +-
24 files changed, 962 insertions(+), 322 deletions(-)
create mode 100644 SharedClasses/SupplementaryPermissionManager.cs
create mode 100644 vMenuServer/config/model-whitelists.json
diff --git a/SharedClasses/ConfigManager.cs b/SharedClasses/ConfigManager.cs
index c8b07fe7..5f212c2d 100644
--- a/SharedClasses/ConfigManager.cs
+++ b/SharedClasses/ConfigManager.cs
@@ -34,8 +34,10 @@ public enum Setting
vmenu_disable_entity_outlines_tool,
vmenu_disable_player_stats_setup,
- // Vehicle Chameleon Colours
+ // Vehicle Settings
vmenu_using_chameleon_colours,
+ vmenu_vehicle_spawn_delay,
+ vmenu_delete_vehicle_distance,
// Prevent Extras Abuse
vmenu_prevent_extras_when_damaged,
@@ -61,6 +63,7 @@ public enum Setting
vmenu_vehicle_blackout_enabled,
vmenu_weather_change_duration,
vmenu_enable_snow,
+ vmenu_smooth_time_transitions,
// Time settings
vmenu_enable_time_sync,
@@ -92,12 +95,12 @@ public static bool GetSettingsBool(Setting setting)
///
///
///
- public static int GetSettingsInt(Setting setting)
+ public static int GetSettingsInt(Setting setting, int defaultValue = -1)
{
- var convarInt = GetConvarInt(setting.ToString(), -1);
- if (convarInt == -1)
+ var convarInt = GetConvarInt(setting.ToString(), defaultValue);
+ if (convarInt == defaultValue)
{
- if (int.TryParse(GetConvar(setting.ToString(), "-1"), out var convarIntAlt))
+ if (int.TryParse(GetConvar(setting.ToString(), defaultValue.ToString()), out var convarIntAlt))
{
return convarIntAlt;
}
@@ -110,13 +113,13 @@ public static int GetSettingsInt(Setting setting)
///
///
///
- public static float GetSettingsFloat(Setting setting)
+ public static float GetSettingsFloat(Setting setting, float defaultValue = -1f)
{
- if (float.TryParse(GetConvar(setting.ToString(), "-1.0"), out var result))
+ if (float.TryParse(GetConvar(setting.ToString(), defaultValue.ToString()), out var result))
{
return result;
}
- return -1f;
+ return defaultValue;
}
///
diff --git a/SharedClasses/PermissionsManager.cs b/SharedClasses/PermissionsManager.cs
index f3240bc6..d5826c73 100644
--- a/SharedClasses/PermissionsManager.cs
+++ b/SharedClasses/PermissionsManager.cs
@@ -113,6 +113,7 @@ public enum Permission
#region vehicle spawner
VSMenu,
VSAll,
+ VSBypassRateLimit,
VSDisableReplacePrevious,
VSSpawnByName,
VSAddon,
@@ -481,8 +482,7 @@ private static bool IsAllowedServer(Permission permission, string playerHandle)
{
return false;
}
-
- return IsPlayerAceAllowed(playerHandle, GetAceName(permission));
+ return GetPermissionAndParentPermissions(permission).Any(p => IsPlayerAceAllowed(playerHandle, GetAceName(p)));
}
#endif
diff --git a/SharedClasses/SupplementaryPermissionManager.cs b/SharedClasses/SupplementaryPermissionManager.cs
new file mode 100644
index 00000000..8ef9944c
--- /dev/null
+++ b/SharedClasses/SupplementaryPermissionManager.cs
@@ -0,0 +1,240 @@
+using System;
+
+using System.Collections.Generic;
+using System.Linq;
+
+using CitizenFX.Core;
+
+using static CitizenFX.Core.Native.API;
+using CitizenFX.Core.Native;
+
+namespace vMenuShared
+{
+ public static class SupplementaryPermissionManager
+ {
+ public static List Permission = new()
+ {
+ "VWAll",
+ "PWAll",
+ "WWAll",
+ };
+
+ public static Dictionary Permissions { get; private set; } = new Dictionary();
+ public static bool ArePermissionsSetup { get; set; } = false;
+
+
+#if SERVER
+ ///
+ /// Public function to check if a permission is allowed.
+ ///
+ ///
+ ///
+ ///
+ public static bool IsAllowed(string permission, Player source) => IsAllowedServer(permission, source);
+
+ ///
+ /// Public function to check if a permission is allowed.
+ ///
+ ///
+ ///
+ ///
+ public static bool IsAllowed(string permission, string playerHandle) => IsAllowedServer(permission, playerHandle);
+#endif
+
+#if CLIENT
+ ///
+ /// Public function to check if a permission is allowed.
+ ///
+ ///
+ /// if true, then the permissions will be checked even if they aren't setup yet.
+ ///
+ public static bool IsAllowed(string permission, bool checkAnyway = false) => IsAllowedClient(permission, checkAnyway);
+
+ private static readonly Dictionary allowedPerms = new();
+ ///
+ /// Private function that handles client side permission requests.
+ ///
+ ///
+ ///
+ private static bool IsAllowedClient(string permission, bool checkAnyway)
+ {
+ if (ArePermissionsSetup || checkAnyway)
+ {
+ if (allowedPerms.ContainsKey(permission) && allowedPerms[permission])
+ {
+ return true;
+ }
+ else if (!allowedPerms.ContainsKey(permission))
+ {
+ allowedPerms[permission] = false;
+ }
+
+ // Get a list of all permissions that are (parents) of the current permission, including the current permission.
+ var permissionsToCheck = GetPermissionAndParentPermissions(permission);
+
+ // Check if any of those permissions is allowed, if so, return true.
+ if (permissionsToCheck.Any(p => Permissions.ContainsKey(p) && Permissions[p]))
+ {
+ allowedPerms[permission] = true;
+ return true;
+ }
+ }
+ switch (permission.Substring(0, 2))
+ {
+ case "VW":
+ allowedPerms[permission] = PermissionsManager.IsAllowed(PermissionsManager.Permission.VSAll);
+ return PermissionsManager.IsAllowed(PermissionsManager.Permission.VSAll);
+ case "PW":
+ allowedPerms[permission] = PermissionsManager.IsAllowed(PermissionsManager.Permission.PAAll);
+ return PermissionsManager.IsAllowed(PermissionsManager.Permission.PAAll);
+ case "WW":
+ allowedPerms[permission] = PermissionsManager.IsAllowed(PermissionsManager.Permission.WPAll);
+ return PermissionsManager.IsAllowed(PermissionsManager.Permission.WPAll);
+ }
+ return false;
+ }
+#endif
+#if SERVER
+ ///
+ /// Checks if the player is allowed that specific permission.
+ ///
+ ///
+ ///
+ ///
+ private static bool IsAllowedServer(string permission, Player source)
+ {
+ if (source == null)
+ {
+ return false;
+ }
+
+ return IsAllowedServer(permission, source.Handle);
+ }
+
+ ///
+ /// Checks if the player is allowed that specific permission.
+ ///
+ ///
+ ///
+ ///
+ private static bool IsAllowedServer(string permission, string playerHandle)
+ {
+ if (!DoesPlayerExist(playerHandle))
+ {
+ return false;
+ }
+
+ return GetPermissionAndParentPermissions(permission).Any(p => IsPlayerAceAllowed(playerHandle, GetAceName(p)));
+ }
+#endif
+
+ private static readonly Dictionary> parentPermissions = new();
+
+ ///
+ /// Gets the current permission and all parent permissions.
+ ///
+ ///
+ ///
+ public static List GetPermissionAndParentPermissions(string permission)
+ {
+ if (parentPermissions.ContainsKey(permission))
+ {
+ return parentPermissions[permission];
+ }
+ else
+ {
+ var list = new List() { "Everything", permission };
+
+ // if the first 2 characters are both uppercase
+ if (permission.Substring(0, 2).ToUpper() == permission.Substring(0, 2))
+ {
+ if (permission.Substring(2) is not "All")
+ {
+ list.AddRange(Permission.Where(a => a.ToString() == permission.Substring(0, 2) + "All"));
+ }
+ }
+ //else // it's one of the .Everything, .DontKickMe, DontBanMe, NoClip, Staff, etc perms that are not menu specific.
+ //{
+ // // do nothing
+ //}
+ parentPermissions[permission] = list;
+ return list;
+ }
+ }
+
+#if SERVER
+
+
+ ///
+ /// Sets the permissions for a specific player (checks server side, sends event to client side).
+ ///
+ ///
+ public static void SetPermissionsForPlayer([FromSource] Player player)
+ {
+ if (player == null)
+ {
+ return;
+ }
+
+ var perms = new Dictionary();
+
+ // Loop through all permissions and check if they're allowed.
+ foreach (string permission in Permission)
+ {
+ if (!perms.ContainsKey(permission))
+ {
+ perms.Add(permission, IsAllowed(permission, player)); // triggers IsAllowedServer
+ }
+ }
+ // Send the permissions to the client.
+ player.TriggerEvent("vMenu:SetSupplementaryPermissions", Newtonsoft.Json.JsonConvert.SerializeObject(perms));
+ }
+#endif
+#if CLIENT
+ ///
+ /// Sets the permission (client side event handler).
+ ///
+ ///
+ public static void SetPermissions(string permissions)
+ {
+ Permissions = Newtonsoft.Json.JsonConvert.DeserializeObject>(permissions);
+
+ // if debug logging.
+ if (GetResourceMetadata(GetCurrentResourceName(), "client_debug_mode", 0) == "true")
+ {
+ Debug.WriteLine("[vMenu] [Permissions] " + Newtonsoft.Json.JsonConvert.SerializeObject(Permissions, Newtonsoft.Json.Formatting.None));
+ }
+ }
+#endif
+#if SERVER
+ ///
+ /// Gets the full permission ace name for the specific enum.
+ ///
+ ///
+ ///
+ public static string GetAceName(string permission)
+ {
+ var name = permission.ToString();
+
+ var prefix = "vMenu.";
+
+ switch (name.Substring(0, 2))
+ {
+ case "VW":
+ prefix += "VehicleSpawner.WhitelistedModels";
+ break;
+ case "PW":
+ prefix += "PlayerAppearance.WhitelistedModels";
+ break;
+ case "WW":
+ prefix += "WeaponOptions.WhitelistedModels";
+ break;
+ default:
+ return prefix + name;
+ }
+
+ return prefix + "." + name.Substring(2);
+ }
+#endif
+ }
+}
diff --git a/vMenu/CommonFunctions.cs b/vMenu/CommonFunctions.cs
index 3dc95ebd..cbf2e802 100644
--- a/vMenu/CommonFunctions.cs
+++ b/vMenu/CommonFunctions.cs
@@ -4,6 +4,7 @@
using System.Threading.Tasks;
using CitizenFX.Core;
+using static CitizenFX.Core.Native.API;
using MenuAPI;
@@ -12,9 +13,9 @@
using vMenuClient.data;
using vMenuClient.menus;
-using static CitizenFX.Core.Native.API;
using static CitizenFX.Core.UI.Screen;
using static vMenuShared.PermissionsManager;
+using vMenuShared;
namespace vMenuClient
{
@@ -23,7 +24,6 @@ public static class CommonFunctions
#region Variables
private static string _currentScenario = "";
private static Vehicle _previousVehicle;
-
internal static bool DriveToWpTaskActive = false;
internal static bool DriveWanderTaskActive = false;
#endregion
@@ -121,7 +121,7 @@ public static async void LockOrUnlockDoors(Vehicle veh, bool lockDoors)
///
///
///
- public static string GetVehDisplayNameFromModel(string name) => GetLabelText(GetDisplayNameFromVehicleModel((uint)GetHashKey(name)));
+ public static string GetVehDisplayNameFromModel(string name) => GetLabelText(GetDisplayNameFromVehicleModel(Game.GenerateHashASCII(name)));
#endregion
#region DoesModelExist
@@ -130,7 +130,7 @@ public static async void LockOrUnlockDoors(Vehicle veh, bool lockDoors)
///
/// The model name
///
- public static bool DoesModelExist(string modelName) => DoesModelExist((uint)GetHashKey(modelName));
+ public static bool DoesModelExist(string modelName) => DoesModelExist(Game.GenerateHashASCII(modelName));
///
/// Does this model exist?
@@ -213,7 +213,7 @@ public static Vehicle GetVehicle(Player player, bool lastVehicle = false)
///
/// Entity/vehicle.
/// Returns the (uint) model hash from a (vehicle) entity.
- public static uint GetVehicleModel(int vehicle) => (uint)GetHashKey(GetEntityModel(vehicle).ToString());
+ public static uint GetVehicleModel(int vehicle) => Game.GenerateHashASCII(GetEntityModel(vehicle).ToString());
#endregion
#region Is ped pointing
@@ -873,35 +873,35 @@ public static async void CommitSuicide()
if (Game.PlayerPed.Weapons.HasWeapon(WeaponHash.PistolMk2))
{
- weaponHash = (uint)GetHashKey("WEAPON_PISTOL_MK2");
+ weaponHash = Game.GenerateHashASCII("WEAPON_PISTOL_MK2");
}
else if (Game.PlayerPed.Weapons.HasWeapon(WeaponHash.CombatPistol))
{
- weaponHash = (uint)GetHashKey("WEAPON_COMBATPISTOL");
+ weaponHash = Game.GenerateHashASCII("WEAPON_COMBATPISTOL");
}
else if (Game.PlayerPed.Weapons.HasWeapon(WeaponHash.Pistol))
{
- weaponHash = (uint)GetHashKey("WEAPON_PISTOL");
+ weaponHash = Game.GenerateHashASCII("WEAPON_PISTOL");
}
- else if (Game.PlayerPed.Weapons.HasWeapon((WeaponHash)(uint)GetHashKey("WEAPON_SNSPISTOL_MK2")))
+ else if (Game.PlayerPed.Weapons.HasWeapon((WeaponHash)Game.GenerateHashASCII("WEAPON_SNSPISTOL_MK2")))
{
- weaponHash = (uint)GetHashKey("WEAPON_SNSPISTOL_MK2");
+ weaponHash = Game.GenerateHashASCII("WEAPON_SNSPISTOL_MK2");
}
else if (Game.PlayerPed.Weapons.HasWeapon(WeaponHash.SNSPistol))
{
- weaponHash = (uint)GetHashKey("WEAPON_SNSPISTOL");
+ weaponHash = Game.GenerateHashASCII("WEAPON_SNSPISTOL");
}
else if (Game.PlayerPed.Weapons.HasWeapon(WeaponHash.Pistol50))
{
- weaponHash = (uint)GetHashKey("WEAPON_PISTOL50");
+ weaponHash = Game.GenerateHashASCII("WEAPON_PISTOL50");
}
else if (Game.PlayerPed.Weapons.HasWeapon(WeaponHash.HeavyPistol))
{
- weaponHash = (uint)GetHashKey("WEAPON_HEAVYPISTOL");
+ weaponHash = Game.GenerateHashASCII("WEAPON_HEAVYPISTOL");
}
else if (Game.PlayerPed.Weapons.HasWeapon(WeaponHash.VintagePistol))
{
- weaponHash = (uint)GetHashKey("WEAPON_VINTAGEPISTOL");
+ weaponHash = Game.GenerateHashASCII("WEAPON_VINTAGEPISTOL");
}
else
{
@@ -912,7 +912,7 @@ public static async void CommitSuicide()
// If we take the pill, remove any weapons in our hands.
if (takePill)
{
- SetCurrentPedWeapon(Game.PlayerPed.Handle, (uint)GetHashKey("weapon_unarmed"), true);
+ SetCurrentPedWeapon(Game.PlayerPed.Handle, Game.GenerateHashASCII("weapon_unarmed"), true);
}
// Otherwise, give the ped a gun.
else if (weaponHash != null)
@@ -922,8 +922,8 @@ public static async void CommitSuicide()
}
else
{
- GiveWeaponToPed(Game.PlayerPed.Handle, (uint)GetHashKey("weapon_pistol_mk2"), 1, false, true);
- SetCurrentPedWeapon(Game.PlayerPed.Handle, (uint)GetHashKey("weapon_pistol_mk2"), true);
+ GiveWeaponToPed(Game.PlayerPed.Handle, Game.GenerateHashASCII("weapon_pistol_mk2"), 1, false, true);
+ SetCurrentPedWeapon(Game.PlayerPed.Handle, Game.GenerateHashASCII("weapon_pistol_mk2"), true);
SetPedDropsWeaponsWhenDead(Game.PlayerPed.Handle, true);
}
@@ -935,7 +935,7 @@ public static async void CommitSuicide()
while (true)
{
var time = GetEntityAnimCurrentTime(Game.PlayerPed.Handle, "MP_SUICIDE", takePill ? "pill" : "pistol");
- if (HasAnimEventFired(Game.PlayerPed.Handle, (uint)GetHashKey("Fire")) && !shot) // shoot the gun if the animation event is triggered.
+ if (HasAnimEventFired(Game.PlayerPed.Handle, Game.GenerateHashASCII("Fire")) && !shot) // shoot the gun if the animation event is triggered.
{
ClearEntityLastDamageEntity(Game.PlayerPed.Handle);
SetPedShootsAtCoord(Game.PlayerPed.Handle, 0f, 0f, 0f, false);
@@ -1209,7 +1209,7 @@ public static async Task SpawnVehicle(string vehicleName = "custom", bool s
if (!string.IsNullOrEmpty(result))
{
// Convert it into a model hash.
- var model = (uint)GetHashKey(result);
+ var model = Game.GenerateHashASCII(result);
return await SpawnVehicle(vehicleHash: model, spawnInside: spawnInside, replacePrevious: replacePrevious, skipLoad: false, vehicleInfo: new VehicleInfo(),
saveName: null);
}
@@ -1220,12 +1220,14 @@ public static async Task SpawnVehicle(string vehicleName = "custom", bool s
return 0;
}
}
- return await SpawnVehicle(vehicleHash: (uint)GetHashKey(vehicleName), spawnInside: spawnInside, replacePrevious: replacePrevious, skipLoad: false,
+ return await SpawnVehicle(vehicleHash: Game.GenerateHashASCII(vehicleName), spawnInside: spawnInside, replacePrevious: replacePrevious, skipLoad: false,
vehicleInfo: new VehicleInfo(), saveName: null);
}
#endregion
#region Main Spawn Vehicle Function
+ public static int lastSpawnTime = 0;
+ public static int spawnTime = ConfigManager.GetSettingsInt(ConfigManager.Setting.vmenu_vehicle_spawn_delay, 5) * 1000;
///
/// Spawns a vehicle.
///
@@ -1252,6 +1254,27 @@ public static async Task SpawnVehicle(uint vehicleHash, bool spawnInside, b
Notify.Alert("You are not allowed to spawn this vehicle, because it belongs to a category which is restricted by the server owner.");
return 0;
}
+
+ if (VehicleSpawner.WhitelistVehicles.Values.Contains(vehicleHash))
+ {
+ if (!vMenuShared.SupplementaryPermissionManager.IsAllowed("VW" + VehicleSpawner.WhitelistVehicles.FirstOrDefault(x => x.Value == vehicleHash).Key.ToLower()))
+ {
+ Notify.Alert("You are not allowed to spawn this vehicle, because it is restricted by the server owner.");
+ return 0;
+ }
+ }
+
+ int gameTime = GetGameTimer();
+ if (!IsAllowed(Permission.VSBypassRateLimit))
+ {
+ if (lastSpawnTime + spawnTime > gameTime)
+ {
+ Notify.Error($"You are spawning vehicles too quickly. Please wait {Math.Ceiling((double)(lastSpawnTime + spawnTime - gameTime)/1000)} second(s) before trying again.");
+ return 0;
+ }
+ }
+
+ lastSpawnTime = gameTime;
if (!skipLoad)
{
@@ -1366,6 +1389,13 @@ public static async Task SpawnVehicle(uint vehicleHash, bool spawnInside, b
{
vehicle.PlaceOnGround();
}
+
+ if (!vehicle.Model.IsTrain) // to be extra fucking safe
+ {
+ // workaround of retarded feature above:
+ SetVehicleForwardSpeed(vehicle.Handle, speed);
+ }
+ vehicle.CurrentRPM = rpm;
}
// If mod info about the vehicle was specified, check if it's not null.
@@ -1376,13 +1406,6 @@ public static async Task SpawnVehicle(uint vehicleHash, bool spawnInside, b
// Set the previous vehicle to the new vehicle.
_previousVehicle = vehicle;
- //vehicle.Speed = speed; // retarded feature that randomly breaks for no fucking reason
- if (!vehicle.Model.IsTrain) // to be extra fucking safe
- {
- // workaround of retarded feature above:
- SetVehicleForwardSpeed(vehicle.Handle, speed);
- }
- vehicle.CurrentRPM = rpm;
int vehicleDefaultRadio = UserDefaults.VehicleDefaultRadio;
@@ -2132,7 +2155,7 @@ public static void UpdateServerTime(int hours, int minutes)
{
realMinutes = 0;
}
- TriggerServerEvent("vMenu:UpdateServerTime", realHours, realMinutes);
+ TriggerServerEvent("vMenu:UpdateServerTime", realHours, realMinutes, EventManager.IsServerTimeFrozen);
}
///
@@ -2245,7 +2268,7 @@ public struct PedInfo
/// Sets the player's model to the provided modelName.
///
/// The model name.
- public static async Task SetPlayerSkin(string modelName, PedInfo pedCustomizationOptions, bool keepWeapons = true) => await SetPlayerSkin((uint)GetHashKey(modelName), pedCustomizationOptions, keepWeapons);
+ public static async Task SetPlayerSkin(string modelName, PedInfo pedCustomizationOptions, bool keepWeapons = true) => await SetPlayerSkin(Game.GenerateHashASCII(modelName), pedCustomizationOptions, keepWeapons);
///
/// Sets the player's model to the provided modelHash.
@@ -2255,6 +2278,14 @@ public static async Task SetPlayerSkin(uint modelHash, PedInfo pedCustomizationO
{
if (IsModelInCdimage(modelHash))
{
+ if (PlayerAppearance.WhitelistedPeds.Values.Contains(modelHash))
+ {
+ if (!vMenuShared.SupplementaryPermissionManager.IsAllowed("PW" + PlayerAppearance.WhitelistedPeds.FirstOrDefault(x => x.Value == modelHash).Key.ToLower()))
+ {
+ Notify.Alert("You are not allowed to spawn this ped, because it is restricted by the server owner.");
+ return;
+ }
+ }
if (keepWeapons)
{
SaveWeaponLoadout("vmenu_temp_weapons_loadout_before_respawn");
@@ -2265,7 +2296,6 @@ public static async Task SetPlayerSkin(uint modelHash, PedInfo pedCustomizationO
{
await Delay(0);
}
-
if ((uint)GetEntityModel(Game.PlayerPed.Handle) != modelHash) // only change skins if the player is not yet using the new skin.
{
// check if the ped is in a vehicle.
@@ -2348,7 +2378,7 @@ public static async Task SetPlayerSkin(uint modelHash, PedInfo pedCustomizationO
{
await SpawnWeaponLoadoutAsync("vmenu_temp_weapons_loadout_before_respawn", false, true, false);
}
- if (modelHash == (uint)GetHashKey("mp_f_freemode_01") || modelHash == (uint)GetHashKey("mp_m_freemode_01"))
+ if (modelHash == Game.GenerateHashASCII("mp_f_freemode_01") || modelHash == Game.GenerateHashASCII("mp_m_freemode_01"))
{
//var headBlendData = Game.PlayerPed.GetHeadBlendData();
if (pedCustomizationOptions.version == -1)
@@ -2376,7 +2406,7 @@ public static async void SpawnPedByName()
var input = await GetUserInput(windowTitle: "Enter Ped Model Name", maxInputLength: 30);
if (!string.IsNullOrEmpty(input))
{
- await SetPlayerSkin((uint)GetHashKey(input), new PedInfo() { version = -1 });
+ await SetPlayerSkin(Game.GenerateHashASCII(input), new PedInfo() { version = -1 });
}
else
{
@@ -2438,7 +2468,7 @@ public static async Task SavePed(string forceName = null, bool overrideExi
data.props = props;
data.propTextures = propTextures;
- data.isMpPed = model == (uint)GetHashKey("mp_f_freemode_01") || model == (uint)GetHashKey("mp_m_freemode_01");
+ data.isMpPed = model == Game.GenerateHashASCII("mp_f_freemode_01") || model == Game.GenerateHashASCII("mp_m_freemode_01");
if (data.isMpPed)
{
Notify.Alert("Note, you should probably use the MP Character creator if you want more advanced features. Saving Multiplayer characters with this function does NOT save a lot of the online peds customization.");
@@ -2707,7 +2737,7 @@ public static async void SpawnCustomWeapon()
}
}
- var model = (uint)GetHashKey(inputName.ToUpper());
+ var model = Game.GenerateHashASCII(inputName.ToUpper());
if (IsWeaponValid(model))
{
@@ -2872,7 +2902,7 @@ public static async Task SpawnWeaponLoadoutAsync(string saveName, bool appendWea
}
// Set the current weapon to 'unarmed'.
- SetCurrentPedWeapon(Game.PlayerPed.Handle, (uint)GetHashKey("weapon_unarmed"), true);
+ SetCurrentPedWeapon(Game.PlayerPed.Handle, Game.GenerateHashASCII("weapon_unarmed"), true);
if (!(saveName == "vmenu_temp_weapons_loadout_before_respawn" || dontNotify))
{
@@ -2990,9 +3020,9 @@ public static bool SaveWeaponLoadout(string saveName)
///
public static async void SetWalkingStyle(string walkingStyle)
{
- if (IsPedModel(Game.PlayerPed.Handle, (uint)GetHashKey("mp_f_freemode_01")) || IsPedModel(Game.PlayerPed.Handle, (uint)GetHashKey("mp_m_freemode_01")))
+ if (IsPedModel(Game.PlayerPed.Handle, Game.GenerateHashASCII("mp_f_freemode_01")) || IsPedModel(Game.PlayerPed.Handle, Game.GenerateHashASCII("mp_m_freemode_01")))
{
- var isPedMale = IsPedModel(Game.PlayerPed.Handle, (uint)GetHashKey("mp_m_freemode_01"));
+ var isPedMale = IsPedModel(Game.PlayerPed.Handle, Game.GenerateHashASCII("mp_m_freemode_01"));
ClearPedAlternateMovementAnim(Game.PlayerPed.Handle, 0, 1f);
ClearPedAlternateMovementAnim(Game.PlayerPed.Handle, 1, 1f);
ClearPedAlternateMovementAnim(Game.PlayerPed.Handle, 2, 1f);
@@ -3444,7 +3474,7 @@ public static async void PressKeyFob(Vehicle veh)
var player = Game.Player;
if (player != null && !player.IsDead && !player.Character.IsInVehicle())
{
- var KeyFobHashKey = (uint)GetHashKey("p_car_keys_01");
+ var KeyFobHashKey = Game.GenerateHashASCII("p_car_keys_01");
RequestModel(KeyFobHashKey);
while (!HasModelLoaded(KeyFobHashKey))
{
@@ -3456,7 +3486,7 @@ public static async void PressKeyFob(Vehicle veh)
SetModelAsNoLongerNeeded(KeyFobHashKey); // cleanup model from memory
ClearPedTasks(player.Character.Handle);
- SetCurrentPedWeapon(Game.PlayerPed.Handle, (uint)GetHashKey("WEAPON_UNARMED"), true);
+ SetCurrentPedWeapon(Game.PlayerPed.Handle, Game.GenerateHashASCII("WEAPON_UNARMED"), true);
//if (player.Character.Weapons.Current.Hash != WeaponHash.Unarmed)
//{
// player.Character.Weapons.Give(WeaponHash.Unarmed, 1, true, true);
@@ -3599,5 +3629,81 @@ .. Enum.GetValues(typeof(VehicleData.ModType))
];
}
#endregion
+
+ #region Delete vehicle function
+
+ public async static void DeleteVehicle()
+ {
+ var player = Game.PlayerPed;
+
+ if (!player.IsAlive)
+ return;
+
+ if (player.IsInVehicle())
+ {
+ var veh = GetVehicle();
+
+ if (veh != null && veh.Exists() && veh.Driver == player)
+ {
+ SetVehicleHasBeenOwnedByPlayer(veh.Handle, false);
+ SetEntityAsMissionEntity(veh.Handle, false, false);
+ veh.Delete();
+ }
+ else
+ {
+ Notify.Error("This vehicle does not exist (somehow) or you need to be the driver of this vehicle to delete it!");
+ }
+
+ return;
+ }
+
+ float distance = ConfigManager.GetSettingsFloat(ConfigManager.Setting.vmenu_delete_vehicle_distance, 5.0f);
+ int maxDeleteTries = 5;
+ int maxHitTries = 5;
+
+ var forward = GetOffsetFromEntityInWorldCoords(player.Handle, 0f, distance, 0f);
+ var ray = StartShapeTestCapsule(player.Position.X, player.Position.Y, player.Position.Z, forward.X, forward.Y, forward.Z, 5f, 10, player.Handle, 7);
+
+ bool hit = false;
+ Vector3 endCoords = Vector3.Zero;
+ Vector3 surfaceNormal = Vector3.Zero;
+ int entity = 0;
+
+ for (int i = 0; i < maxHitTries; i++)
+ {
+ GetShapeTestResult(ray, ref hit, ref endCoords, ref surfaceNormal, ref entity);
+ if (hit) break;
+ await Task.FromResult(0);
+ }
+
+ if (!hit || !DoesEntityExist(entity) || !IsEntityAVehicle(entity))
+ {
+ Notify.Error("No vehicle found in front of you to delete!");
+ return;
+ }
+
+ var hitVeh = new Vehicle(entity);
+
+ for (int i = 0; i <= maxDeleteTries && DoesEntityExist(entity); i++)
+ {
+ NetworkRequestControlOfEntity(entity);
+ SetVehicleHasBeenOwnedByPlayer(entity, false);
+ SetEntityAsMissionEntity(entity, false, false);
+ hitVeh.Delete();
+ await Task.FromResult(0);
+ }
+
+ if (DoesEntityExist(entity))
+ {
+ Notify.Error("Failed to delete the vehicle in front of you. Try again or ask an admin for help.");
+ }
+ else
+ {
+ Notify.Success("Vehicle deleted successfully.");
+ }
+ }
+
+
+ #endregion
}
}
diff --git a/vMenu/EntitySpawner.cs b/vMenu/EntitySpawner.cs
index 0401f9b7..c3719ab8 100644
--- a/vMenu/EntitySpawner.cs
+++ b/vMenu/EntitySpawner.cs
@@ -47,7 +47,7 @@ public EntitySpawner()
/// true spawn was succesful
public static void SpawnEntity(string model, Vector3 coords)
{
- SpawnEntity((uint)GetHashKey(model), coords);
+ SpawnEntity(Game.GenerateHashASCII(model), coords);
}
///
diff --git a/vMenu/EventManager.cs b/vMenu/EventManager.cs
index 3a57dafc..682c6825 100644
--- a/vMenu/EventManager.cs
+++ b/vMenu/EventManager.cs
@@ -41,6 +41,7 @@ public EventManager()
EventHandlers.Add("vMenu:SetAddons", new Action(SetConfigOptions)); // DEPRECATED: Backwards-compatible event handler; use 'vMenu:SetConfigOptions' instead
EventHandlers.Add("vMenu:SetConfigOptions", new Action(SetConfigOptions));
EventHandlers.Add("vMenu:SetPermissions", new Action(MainMenu.SetPermissions));
+ EventHandlers.Add("vMenu:SetSupplementaryPermissions", new Action(MainMenu.SetSupplementaryPermissions));
EventHandlers.Add("vMenu:KillMe", new Action(KillMe));
EventHandlers.Add("vMenu:Notify", new Action(NotifyPlayer));
EventHandlers.Add("vMenu:SetClouds", new Action(SetClouds));
@@ -98,6 +99,7 @@ private async void SetAppearanceOnFirstSpawn()
private void SetConfigOptions()
{
SetAddons();
+ SetWhiteLists();
SetExtras();
SetTattoos();
@@ -128,7 +130,7 @@ private void SetAddons()
{
if (!VehicleSpawner.AddonVehicles.ContainsKey(addon))
{
- VehicleSpawner.AddonVehicles.Add(addon, (uint)GetHashKey(addon));
+ VehicleSpawner.AddonVehicles.Add(addon, Game.GenerateHashASCII(addon));
}
else
{
@@ -144,7 +146,7 @@ private void SetAddons()
{
if (!WeaponOptions.AddonWeapons.ContainsKey(addon))
{
- WeaponOptions.AddonWeapons.Add(addon, (uint)GetHashKey(addon));
+ WeaponOptions.AddonWeapons.Add(addon, Game.GenerateHashASCII(addon));
}
else
{
@@ -160,7 +162,7 @@ private void SetAddons()
{
if (!PlayerAppearance.AddonPeds.ContainsKey(addon))
{
- PlayerAppearance.AddonPeds.Add(addon, (uint)GetHashKey(addon));
+ PlayerAppearance.AddonPeds.Add(addon, Game.GenerateHashASCII(addon));
}
else
{
@@ -190,6 +192,75 @@ private void SetAddons()
}
}
+ ///
+ /// Sets the addon models from the addons.json file.
+ ///
+ private void SetWhiteLists()
+ {
+ // reset addons
+ VehicleSpawner.WhitelistVehicles = new Dictionary();
+ PlayerAppearance.WhitelistedPeds = new Dictionary();
+ WeaponOptions.WeaponWhitelist = new Dictionary();
+
+ var jsonData = LoadResourceFile(GetCurrentResourceName(), "config/model-whitelists.json") ?? "{}";
+ try
+ {
+ // load new addons.
+ var whitelists = JsonConvert.DeserializeObject>>(jsonData);
+
+ // load whitelist vehicles
+ if (whitelists.ContainsKey("whitelistedvehicle"))
+ {
+ foreach (var whitelist in whitelists["whitelistedvehicle"])
+ {
+ if (!VehicleSpawner.WhitelistVehicles.ContainsKey(whitelist))
+ {
+ VehicleSpawner.WhitelistVehicles.Add(whitelist, Game.GenerateHashASCII(whitelist));
+ }
+ else
+ {
+ Debug.WriteLine($"[vMenu] [Error] Your model-whitelists.json file contains 2 or more entries with the same vehicle name! ({whitelist}) Please remove duplicate lines!");
+ }
+ }
+ }
+
+ // load whitelisted peds.
+ if (whitelists.ContainsKey("whitelistedpeds"))
+ {
+ foreach (var whitelist in whitelists["whitelistedpeds"])
+ {
+ if (!PlayerAppearance.WhitelistedPeds.ContainsKey(whitelist))
+ {
+ PlayerAppearance.WhitelistedPeds.Add(whitelist, Game.GenerateHashASCII(whitelist));
+ }
+ else
+ {
+ Debug.WriteLine($"[vMenu] [Error] Your model-whitelists.json file contains 2 or more entries with the same ped name! ({whitelist}) Please remove duplicate lines!");
+ }
+ }
+ }
+
+ // load whitelisted weapon.
+ if (whitelists.ContainsKey("whitelistedweapons"))
+ {
+ foreach (var whitelist in whitelists["whitelistedweapons"])
+ {
+ if (!WeaponOptions.WeaponWhitelist.ContainsKey(whitelist))
+ {
+ WeaponOptions.WeaponWhitelist.Add(whitelist, Game.GenerateHashASCII(whitelist));
+ }
+ else
+ {
+ Debug.WriteLine($"[vMenu] [Error] Your model-whitelists.json file contains 2 or more entries with the same ped name! ({whitelist}) Please remove duplicate lines!");
+ }
+ }
+ }
+ }
+ catch (JsonReaderException ex)
+ {
+ Debug.WriteLine($"\n\n^1[vMenu] [ERROR] ^7Your model-whitelists.json file contains a problem! Error details: {ex.Message}\n\n");
+ }
+ }
///
/// Sets the extras labels from the extras.json file.
///
@@ -207,7 +278,7 @@ private void SetExtras()
foreach (string model in extras.Keys)
{
- uint modelHash = (uint)GetHashKey(model);
+ uint modelHash = Game.GenerateHashASCII(model);
if (extras[model] != null && extras[model].Count > 0)
{
diff --git a/vMenu/FunctionsController.cs b/vMenu/FunctionsController.cs
index 12dbc85e..a584fc02 100644
--- a/vMenu/FunctionsController.cs
+++ b/vMenu/FunctionsController.cs
@@ -51,7 +51,7 @@ class FunctionsController : BaseScript
private const string snowball_anim_dict = "anim@mp_snowball";
private const string snowball_anim_name = "pickup_snowball";
- private readonly uint snowball_hash = (uint)GetHashKey("weapon_snowball");
+ private readonly uint snowball_hash = Game.GenerateHashASCII("weapon_snowball");
private bool showSnowballInfo = false;
private bool stopPropsLoop = false;
@@ -76,6 +76,7 @@ public void SetupTickFunctions()
Tick += MiscSettings;
Tick += GeneralTasks;
Tick += GcTick;
+ Tick += ControllerTick;
if (GetSettingsBool(Setting.keep_player_head_props))
{
@@ -214,6 +215,36 @@ private async Task GcTick()
}
#endregion
+ #region Controller tick and functions
+ private async Task ControllerTick()
+ {
+ if (!Game.IsPaused && !IsPauseMenuRestarting() && IsScreenFadedIn() && !IsPlayerSwitchInProgress() && !Game.Player.IsDead && !MenuController.DisableMenuButtons)
+ {
+ if (Game.CurrentInputMode == InputMode.GamePad)
+ {
+ await HandleMenuToggleKeyForController();
+ }
+ }
+ await Task.FromResult(0);
+ }
+ private async Task HandleMenuToggleKeyForController()
+ {
+ int tmpTimer = GetGameTimer();
+ while ((Game.IsControlPressed(0, Control.InteractionMenu) || Game.IsDisabledControlPressed(0, Control.InteractionMenu)) && !Game.IsPaused && IsScreenFadedIn() && !Game.Player.IsDead && !IsPlayerSwitchInProgress() && !MenuController.DontOpenAnyMenu)
+ {
+ if (GetGameTimer() - tmpTimer > 400)
+ {
+ if (MainMenu.Menu != null)
+ {
+ MainMenu.Menu.OpenMenu();
+ }
+ break;
+ }
+ await Delay(0);
+ }
+ }
+ #endregion
+
#region General Tasks
///
/// All general tasks that run every 1 game ticks (and are not (sub)menu specific).
@@ -590,7 +621,6 @@ private async Task VehicleOptions()
var subMenus = new List