#if FIVEM
using CitizenFX.Core;
using CitizenFX.Core.UI;
using CitizenFX.Core.Native;
#elif RAGEMP
using RAGE.Game;
using RAGE.NUI;
#elif RPH
using Rage;
using Rage.Native;
#elif SHVDN3
using GTA.Native;
using GTA.UI;
#endif
using System;
using System.Collections.Concurrent;
using System.Drawing;
namespace LemonUI
{
///
/// Represents the method that reports a Resolution change in the Game Settings.
///
/// The source of the event.
/// A containing the Previous and Current resolution.
public delegate void ResolutionChangedEventHandler(object sender, ResolutionChangedEventArgs e);
///
/// Represents the method that reports a Safe Zone change in the Game Settings.
///
/// The source of the event event.
/// A containing the Previous and Current Safe Zone.
public delegate void SafeZoneChangedEventHandler(object sender, SafeZoneChangedEventArgs e);
///
/// Represents the information after a Resolution Change in the game.
///
public class ResolutionChangedEventArgs
{
///
/// The Game Resolution before it was changed.
///
public SizeF Before { get; }
///
/// The Game Resolution after it was changed.
///
public SizeF After { get; }
internal ResolutionChangedEventArgs(SizeF before, SizeF after)
{
Before = before;
After = after;
}
}
///
/// Represents the information after a Safe Zone Change in the game.
///
public class SafeZoneChangedEventArgs
{
///
/// The raw Safezone size before the change.
///
public float Before { get; }
///
/// The Safezone size after the change.
///
public float After { get; }
internal SafeZoneChangedEventArgs(float before, float after)
{
Before = before;
After = after;
}
}
///
/// Manager for Menus and Items.
///
public class ObjectPool
{
#region Private Fields
///
/// The last known resolution by the object pool.
///
#if FIVEM
private SizeF lastKnownResolution = CitizenFX.Core.UI.Screen.Resolution;
#elif RAGEMP
private SizeF lastKnownResolution = new SizeF(Game.ScreenResolution.Width, Game.ScreenResolution.Height);
#elif RPH
private SizeF lastKnownResolution = Game.Resolution;
#elif SHVDN3
private SizeF lastKnownResolution = GTA.UI.Screen.Resolution;
#endif
///
/// The last know Safezone size.
///
#if FIVEM
private float lastKnownSafezone = API.GetSafeZoneSize();
#elif RAGEMP
private float lastKnownSafezone = Invoker.Invoke(Natives.GetSafeZoneSize);
#elif RPH
private float lastKnownSafezone = NativeFunction.CallByHash(0xBAF107B6BB2C97F0);
#elif SHVDN3
private float lastKnownSafezone = Function.Call(Hash.GET_SAFE_ZONE_SIZE);
#endif
///
/// The list of processable objects.
///
private readonly ConcurrentDictionary objects = new ConcurrentDictionary();
#endregion
#region Public Properties
///
/// Checks if there are objects visible on the screen.
///
public bool AreAnyVisible
{
get
{
// Iterate over the objects
foreach (IProcessable obj in objects.Values)
{
// If is visible return true
if (obj.Visible)
{
return true;
}
}
// If none were visible return false
return false;
}
}
#endregion
#region Events
///
/// Event triggered when the game resolution is changed.
///
public event ResolutionChangedEventHandler ResolutionChanged;
///
/// Event triggered when the Safezone size option in the Display settings is changed.
///
public event SafeZoneChangedEventHandler SafezoneChanged;
#endregion
#region Tools
///
/// Detects resolution changes by comparing the last known resolution and the current one.
///
private void DetectResolutionChanges()
{
// Get the current resolution
#if FIVEM
SizeF resolution = CitizenFX.Core.UI.Screen.Resolution;
#elif RAGEMP
ScreenResolutionType raw = Game.ScreenResolution;
SizeF resolution = new SizeF(raw.Width, raw.Height);
#elif RPH
SizeF resolution = Game.Resolution;
#elif SHVDN3
SizeF resolution = GTA.UI.Screen.Resolution;
#endif
// If the old res does not matches the current one
if (lastKnownResolution != resolution)
{
// Trigger the event
ResolutionChanged?.Invoke(this, new ResolutionChangedEventArgs(lastKnownResolution, resolution));
// Refresh everything
RefreshAll();
// And save the new resolution
lastKnownResolution = resolution;
}
}
///
/// Detects Safezone changes by comparing the last known value to the current one.
///
private void DetectSafezoneChanges()
{
// Get the current Safezone size
#if FIVEM
float safezone = API.GetSafeZoneSize();
#elif RAGEMP
float safezone = Invoker.Invoke(Natives.GetSafeZoneSize);
#elif RPH
float safezone = NativeFunction.CallByHash(0xBAF107B6BB2C97F0);
#elif SHVDN3
float safezone = Function.Call(Hash.GET_SAFE_ZONE_SIZE);
#endif
// If is not the same as the last one
if (lastKnownSafezone != safezone)
{
// Trigger the event
SafezoneChanged?.Invoke(this, new SafeZoneChangedEventArgs(lastKnownSafezone, safezone));
// Refresh everything
RefreshAll();
// And save the new safezone
lastKnownSafezone = safezone;
}
}
#endregion
#region Public Function
///
/// Adds the object into the pool.
///
/// The object to add.
public void Add(IProcessable obj)
{
// Make sure that the object is not null
if (obj == null)
{
throw new ArgumentNullException(nameof(obj));
}
int key = obj.GetHashCode();
// Otherwise, add it to the general pool
if (objects.ContainsKey(key))
{
throw new InvalidOperationException("The object is already part of this pool.");
}
objects.TryAdd(key, obj);
}
///
/// Removes the object from the pool.
///
/// The object to remove.
public void Remove(IProcessable obj)
{
objects.TryRemove(obj.GetHashCode(), out _);
}
///
/// Performs the specified action on each element that matches T.
///
/// The type to match.
/// The action delegate to perform on each T.
public void ForEach(Action action)
{
foreach (IProcessable obj in objects.Values)
{
if (obj is T conv)
{
action(conv);
}
}
}
///
/// Refreshes all of the items.
///
public void RefreshAll()
{
// Iterate over the objects and recalculate those possible
foreach (IProcessable obj in objects.Values)
{
if (obj is IRecalculable recal)
{
recal.Recalculate();
}
}
}
///
/// Hides all of the objects.
///
public void HideAll()
{
foreach (IProcessable obj in objects.Values)
{
obj.Visible = false;
}
}
///
/// Processes the objects and features in this pool.
/// This needs to be called every tick.
///
public void Process()
{
// See if there are resolution or safezone changes
DetectResolutionChanges();
DetectSafezoneChanges();
// And process the objects in the pool
foreach (IProcessable obj in objects.Values)
{
obj.Process();
}
}
#endregion
}
}