Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Review #2764

Open
wants to merge 19 commits into
base: dev
Choose a base branch
from
Open

Review #2764

Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Exiled.API/Features/Core/Components/TickComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public sealed class TickComponent : EObject
/// The default fixed tick rate (60 per second).
/// </summary>
#pragma warning disable SA1310
public const float DEFAULT_FIXED_TICK_RATE = 0.016f;
public const float DEFAULT_FIXED_TICK_RATE = 1f / 60f;
warquys marked this conversation as resolved.
Show resolved Hide resolved
#pragma warning restore SA1310

private readonly HashSet<CoroutineHandle> boundHandles;
Expand Down
3 changes: 2 additions & 1 deletion Exiled.API/Features/Core/ConstProperty.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// <copyright file="ConstProperty.cs" company="Exiled Team">
// Copyright (c) Exiled Team. All rights reserved.
// Licensed under the CC BY-SA 3.0 license.
Expand Down Expand Up @@ -48,6 +48,7 @@ public ConstProperty(T constantValue, Type[] typesToPatch, MethodInfo[] skipMeth
/// </summary>
~ConstProperty()
{
// @Nao Never be call, it need to remove it reference from List beffor the dtor call
List.Remove(this);

foreach (MethodInfo methodInfo in PatchedMethods)
Expand Down
5 changes: 0 additions & 5 deletions Exiled.API/Features/Core/GameEntity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,6 @@ protected GameEntity(GameObject gameObject)
// List.Add(this);
}

/// <summary>
/// Finalizes an instance of the <see cref="GameEntity"/> class.
/// </summary>
~GameEntity() => List.Remove(this);

warquys marked this conversation as resolved.
Show resolved Hide resolved
/// <summary>
/// Gets all active <see cref="GameEntity"/> instances.
/// <para/>
Expand Down
2 changes: 2 additions & 0 deletions Exiled.API/Features/Core/Generic/EBehaviour.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ protected EBehaviour()
/// </remarks>
protected virtual void FindOwner()
{
// @Nao T is a GameEntity, why not add in inisde of it the method a abstract.
warquys marked this conversation as resolved.
Show resolved Hide resolved
// Or create an specific Interaface requesting to implement this method
MethodInfo method = typeof(T).GetMethod("Get", BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(GameObject) }, null);

if (method != null)
Expand Down
17 changes: 10 additions & 7 deletions Exiled.API/Features/Core/Generic/Singleton.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ namespace Exiled.API.Features.Core.Generic
public sealed class Singleton<T> : TypeCastObject<T>
where T : class
{
// @Nao, this is not realy a singleton if you have mutliple value.
warquys marked this conversation as resolved.
Show resolved Hide resolved
// NB: each Singleton<T> ave a new instance of dictionary.
// exemple Singleton<int>.Instance is not the same Singleton<bool>.Instance
private static readonly Dictionary<T, Singleton<T>> Instances = new();

/// <summary>
Expand All @@ -35,6 +38,8 @@ public Singleton(T value)
/// <summary>
/// Finalizes an instance of the <see cref="Singleton{T}"/> class.
/// </summary>
// @Nao Probably never call, it self reference. Maybe an future issue doing memory leek
warquys marked this conversation as resolved.
Show resolved Hide resolved
// it will get call only after the instance get remove form Instances
~Singleton() => Instances.Remove(Value);

/// <summary>
Expand All @@ -59,6 +64,10 @@ public Singleton(T value)
/// <typeparam name="TObject">The type of the object.</typeparam>
/// <param name="instance">The object instance.</param>
/// <returns><see langword="true"/> if the object instance is not null and can be casted as the specified type; otherwise, <see langword="false"/>.</returns>
// @nao It will return the Instance.
// But with this curent class definition you can register derived class of T.
// They can be registred but not retrived. Also why make this method generic if this not to get
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was high writing most of this code

// other value than the instance.
public static bool TryGet<TObject>(out TObject instance)
where TObject : class => (instance = Instance as TObject) is not null;

Expand All @@ -72,13 +81,7 @@ public static bool TryGet<TObject>(out TObject instance)
/// <returns><see langword="true"/> if the instance was destroyed; otherwise, <see langword="false"/>.</returns>
public static bool Destroy(T @object)
{
if (Instances.TryGetValue(@object, out Singleton<T> _))
{
Instances[@object] = null;
return Instances.Remove(@object);
}

return false;
return Instances.Remove(@object);
warquys marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
9 changes: 8 additions & 1 deletion Exiled.API/Features/Core/Generic/UniqueUnmanagedEnumClass.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ public UniqueUnmanagedEnumClass()
values ??= new();
TypeCode code = Convert.GetTypeCode(typeof(TSource).GetField("MinValue").GetValue(null));

// @Nao If the value is not an Uxxxxx it will get an overflow. Like if it use an Int16, Byte or SByte
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right

// Maybe use a long for nextValue and do "nextValue = typeof(TSource).GetField("MinValue").GetValue(null)"
// it also be a struct containing only unmanged struct. The best solution is proably to
// look for upper version of the framwork to resolve this with the new numeric interfaces.
if (code is TypeCode.UInt16 or TypeCode.UInt32 or TypeCode.UInt64)
nextValue = 0;

Expand All @@ -53,6 +57,9 @@ public UniqueUnmanagedEnumClass()
while (values.ContainsKey(value));

Value = value;

// @nao If the value is register when a new instance is created.
// Maybe put the ctor in protected to avoid exteranal code (outisde the enum) to create new values
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

internal protected can be cool if Exiled need to create dedicated new instance in an helper class

values.Add(value, (TObject)this);
}
}
Expand Down Expand Up @@ -285,7 +292,7 @@ public int CompareTo(object obj) =>
/// </returns>
public int Compare(TObject x, TObject y) => x == null ? -1 : y == null ? 1 : x.Value.CompareTo(y.Value);

/// <inheritdoc/>
/// <inheritdoc/>
TypeCode IConvertible.GetTypeCode() => Value.GetTypeCode();

/// <inheritdoc/>
Expand Down
4 changes: 4 additions & 0 deletions Exiled.API/Features/Core/Generic/UnmanagedEnumClass.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ namespace Exiled.API.Features.Core.Generic
/// </summary>
/// <typeparam name="TSource">The type of the <see langword="unmanaged"/> source object to handle the instance of.</typeparam>
/// <typeparam name="TObject">The type of the child object to handle the instance of.</typeparam>
// @Nao you can use Comparer<NonComparable>.Default, it will result as using the IComparable<TObject>.Compare
public abstract class UnmanagedEnumClass<TSource, TObject> : IComparable, IEquatable<TObject>, IComparable<TObject>, IComparer<TObject>, IConvertible, IEnumClass
where TSource : unmanaged, IComparable, IFormattable, IConvertible, IComparable<TSource>, IEquatable<TSource>
where TObject : UnmanagedEnumClass<TSource, TObject>
Expand Down Expand Up @@ -253,6 +254,7 @@ public override bool Equals(object obj) =>
/// Zero This instance occurs in the same position in the sort order as other.
/// Greater than zero This instance follows other in the sort order.
/// </returns>
// @Nao if x and y is null it should return, 0.
public int CompareTo(object obj) =>
obj == null ? -1 : obj is TSource value ? Value.CompareTo(value) : obj is TObject derived ? Value.CompareTo(derived.Value) : -1;

Expand All @@ -269,6 +271,8 @@ public int CompareTo(object obj) =>
/// Zero This instance occurs in the same position in the sort order as other.
/// Greater than zero This instance follows other in the sort order.
/// </returns>
// @Nao if x and y is equal to null it should return, 0.
// Maybe use the default comparator, it handle it by default and if needed it can be replaced by a custom one.
public int Compare(TObject x, TObject y) => x == null ? -1 : y == null ? 1 : x.Value.CompareTo(y.Value);

/// <inheritdoc/>
Expand Down
1 change: 1 addition & 0 deletions Exiled.API/Features/Player.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4066,6 +4066,7 @@ public void PlayCassieAnnouncement(string words, bool makeHold = false, bool mak
/// <param name="makeHold">Same on <see cref="Cassie.MessageTranslated(string, string, bool, bool, bool)"/>'s isHeld.</param>
/// <param name="makeNoise">Same on <see cref="Cassie.MessageTranslated(string, string, bool, bool, bool)"/>'s isNoisy.</param>
/// <param name="isSubtitles">Same on <see cref="Cassie.MessageTranslated(string, string, bool, bool, bool)"/>'s isSubtitles.</param>
// @Nao, why not inherit the documentation for the param ?
public void SendCassieAnnouncement(string words, string translation, bool makeHold = false, bool makeNoise = true, bool isSubtitles = true)
{
StringBuilder announcement = StringBuilderPool.Pool.Get();
Expand Down
7 changes: 5 additions & 2 deletions Exiled.API/Features/Respawn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ namespace Exiled.API.Features
/// </summary>
public static class Respawn
{
private const string MtfChopperGameObjectName = "Chopper";
private const string ChaosVanGameObjectName = "CIVanArrive";
warquys marked this conversation as resolved.
Show resolved Hide resolved

private static GameObject ntfHelicopterGameObject;
private static GameObject chaosCarGameObject;

Expand All @@ -34,7 +37,7 @@ public static GameObject NtfHelicopter
get
{
if (ntfHelicopterGameObject == null)
ntfHelicopterGameObject = GameObject.Find("Chopper");
ntfHelicopterGameObject = GameObject.Find(MtfChopperGameObjectName);

return ntfHelicopterGameObject;
}
Expand All @@ -48,7 +51,7 @@ public static GameObject ChaosVan
get
{
if (chaosCarGameObject == null)
chaosCarGameObject = GameObject.Find("CIVanArrive");
chaosCarGameObject = GameObject.Find(ChaosVanGameObjectName);

return chaosCarGameObject;
}
Expand Down
2 changes: 1 addition & 1 deletion Exiled.API/Features/VirtualAssemblies/VirtualPlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ public static IEnumerable<VirtualPlugin> EnableAll()
continue;

VirtualPlugin vp = Activator.CreateInstance(type) as VirtualPlugin;
vp.TryRegister(type.GetCustomAttribute(typeof(VirtualPluginAttribute)) as VirtualPluginAttribute);
vp.TryRegister(type.GetCustomAttribute<VirtualPluginAttribute>());
vps.Add(vp);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public EscapeSettings(
Role = role;
CustomRole = CustomRole.Get(customRole);
Position = position == default ? DefaultPosition : position;
DistanceThreshold = distanceThreshold == DefaultMaxDistanceTolerance ? DefaultMaxDistanceTolerance : distanceThreshold;
DistanceThreshold = distanceThreshold;
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ public class GameModeSettings : TypeCastObject<GameModeSettings>, IAdditivePrope
public virtual uint[] NonSpawnableCustomRoles { get; set; }

/// <summary>
/// Gets or sets a <see cref="UUCustomTeamType"/>[] containing all non spawnable custom teams.
/// Gets or sets a <see cref="SpawnableTeamType"/>[] containing all non spawnable custom teams.
/// <para/>
/// If not empty, all undefined teams will be able to spawn.
/// <br/>
Expand Down
3 changes: 1 addition & 2 deletions Exiled.CustomModules/API/Features/CustomRoles/CustomRole.cs
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,7 @@ public virtual bool EvaluateConditions
{
if (pawn.Role == RequiredRoleToSpawn)
{
if ((RoleExtensions.GetTeam(RequiredRoleToSpawn) is Team.SCPs && !pawn.IsScp) ||
(RoleExtensions.GetTeam(RequiredRoleToSpawn) is not Team.SCPs && pawn.IsScp))
if ((RoleExtensions.GetTeam(RequiredRoleToSpawn) is Team.SCPs) != pawn.IsScp)
continue;

return true;
Expand Down
11 changes: 7 additions & 4 deletions Exiled.CustomModules/API/Features/CustomRoles/CustomTeam.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ namespace Exiled.CustomModules.API.Features.CustomRoles
/// </remarks>
public abstract class CustomTeam : CustomModule
{
private const string VanilaConfigMtfMinTime = "minimum_MTF_time_to_spawn";
private const string VanilaConfigMtfMaxTime = "maximum_MTF_time_to_spawn";

warquys marked this conversation as resolved.
Show resolved Hide resolved
private static readonly Dictionary<Player, CustomTeam> PlayersValue = new();
private static readonly List<CustomTeam> Registered = new();
private static readonly Dictionary<Type, CustomTeam> TypeLookupTable = new();
Expand Down Expand Up @@ -111,17 +114,18 @@ public abstract class CustomTeam : CustomModule
/// This property provides access to a curated collection of <see cref="uint"/> objects, encapsulating all available custom role within the context of units.
/// <br/>The collection is designed to be both queried and modified as needed to accommodate dynamic scenarios within the game architecture.
/// </remarks>
// @Nao, adding the possiblity to have custom roles
public virtual IEnumerable<uint> Units { get; set; } = new uint[] { };

/// <summary>
/// Gets or sets the minimum amount time after which any team will be allowed to spawn.
/// </summary>
public virtual float MinNextSequenceTime { get; set; } = GameCore.ConfigFile.ServerConfig.GetFloat("minimum_MTF_time_to_spawn", 280f);
public virtual float MinNextSequenceTime { get; set; } = GameCore.ConfigFile.ServerConfig.GetFloat(VanilaConfigMtfMinTime, 280f);

/// <summary>
/// Gets or sets the maximum amount time after which any team will be spawned.
/// </summary>
public virtual float MaxNextSequenceTime { get; set; } = GameCore.ConfigFile.ServerConfig.GetFloat("maximum_MTF_time_to_spawn", 350f);
public virtual float MaxNextSequenceTime { get; set; } = GameCore.ConfigFile.ServerConfig.GetFloat(VanilaConfigMtfMaxTime, 350f);

/// <summary>
/// Gets or sets the relative spawn probability of the <see cref="CustomTeam"/>.
Expand Down Expand Up @@ -226,8 +230,7 @@ public virtual bool EvaluateConditions
{
if (pawn.Role == RequiredRoleToSpawn)
{
if ((RoleExtensions.GetTeam(RequiredRoleToSpawn) is Team.SCPs && !pawn.IsScp) ||
(RoleExtensions.GetTeam(RequiredRoleToSpawn) is not Team.SCPs && pawn.IsScp))
if ((RoleExtensions.GetTeam(RequiredRoleToSpawn) is Team.SCPs) != pawn.IsScp)
continue;

return true;
Expand Down
66 changes: 39 additions & 27 deletions Exiled.CustomModules/API/Features/CustomRoles/RoleBehaviour.cs
Original file line number Diff line number Diff line change
Expand Up @@ -178,37 +178,49 @@ protected virtual RoleTypeId FakeAppearance
/// <summary>
/// Evaluates the specified conditions affecting the round's ending conditions.
/// </summary>
/// <returns>The corresponding evaluation.</returns>
/// <returns>
/// <see langword="false"/> if the round should continue.
/// <br/>Otherwise, <see langword="true"/> if the round can end.
/// All other condition need to be <see langword="true"/> to end the round.
/// </returns>
public virtual bool EvaluateEndingConditions()
{
if (CustomRole.TeamsOwnership.Length == 1)
return true;

SummaryInfo summaryInfo = World.Get().SummaryInfo;

if (CustomRole.TeamsOwnership.Contains(Team.SCPs) && summaryInfo.FoundationForces <= 0 && summaryInfo.ChaosInsurgency <= 0)
return true;

if (CustomRole.TeamsOwnership.Any(team => team is Team.ClassD or Team.ChaosInsurgency) && summaryInfo.FoundationForces <= 0 && summaryInfo.Anomalies <= 0)
return true;

if (CustomRole.TeamsOwnership.Any(team => team is Team.FoundationForces or Team.Scientists) && summaryInfo.ChaosInsurgency <= 0 && summaryInfo.Anomalies <= 0)
return true;

if (CustomRole.TeamsOwnership.IsEmpty())
SummaryInfo summaryInfo;
switch (CustomRole.TeamsOwnership.Length)
{
int uniqueFaction = 0;
if (summaryInfo.FoundationForces > 0)
++uniqueFaction;
if (summaryInfo.ChaosInsurgency > 0)
++uniqueFaction;
if (summaryInfo.Anomalies > 0)
++uniqueFaction;

return uniqueFaction <= 1;
}
case 0:
summaryInfo = World.Get().SummaryInfo;
int uniqueFaction = 0;
if (summaryInfo.FoundationForces > 0)
++uniqueFaction;
if (summaryInfo.ChaosInsurgency > 0)
++uniqueFaction;
if (summaryInfo.Anomalies > 0)
++uniqueFaction;
return uniqueFaction <= 1;

case 1: return true;

default:
// @Nao, i mouve repeted code here to see better
// For me this following condition are always true.
// Expete if it existe a case where there is -1 Chaos
summaryInfo = World.Get().SummaryInfo;

bool hasChaos = summaryInfo.ChaosInsurgency <= 0;
bool hasFondtion = summaryInfo.FoundationForces <= 0;
bool hasScp = summaryInfo.ChaosInsurgency <= 0;

if (CustomRole.TeamsOwnership.Contains(Team.SCPs) && hasFondtion && hasChaos)
return true; // @Nao Why true, that mean the round can end, but if there is some fondation left, the round should not end...

if (CustomRole.TeamsOwnership.Any(team => team is Team.ClassD or Team.ChaosInsurgency) && hasFondtion && hasScp)
return true;

return false;
if (CustomRole.TeamsOwnership.Any(team => team is Team.FoundationForces or Team.Scientists) && hasChaos && hasScp)
return true;
return false;
}
}

/// <inheritdoc/>
Expand Down
9 changes: 6 additions & 3 deletions Exiled.CustomModules/API/Features/RespawnManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -174,21 +174,24 @@ private void OnPreRespawningTeam(PreRespawningTeamEventArgs ev)
{
PreviousKnownTeam = NextKnownTeam;

// @Nao are you sur that is "or SpawnableTeamType" and not "or not SpawnableTeamType"
warquys marked this conversation as resolved.
Show resolved Hide resolved
if (NextKnownTeam is null or SpawnableTeamType)
return;

CustomTeam customTeam = CustomTeam.Get((uint)NextKnownTeam);
if (customTeam is null)
return;

if (customTeam.TeamsOwnership.Any(t =>
t == (ev.NextKnownTeam is SpawnableTeamType.ChaosInsurgency ?
Team.ChaosInsurgency : Team.FoundationForces)))
if (customTeam.TeamsOwnership.Any(t => t == (Team)ev.NextKnownTeam))
{
ev.MaxWaveSize = customTeam.Size;
return;
}

// @Nao, it cool to use the event system for this. But if an other plugin
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right

// allready say "ev.IsAllowed = false". it will get ignore
// and the team will still spawn...
// And post event shoold be here to spawn. Or an EventHandler handling last
ev.IsAllowed = false;
Spawn();
Respawning.RespawnManager.Singleton?.RestartSequence();
Expand Down
Loading