Skip to content
This repository was archived by the owner on Jan 19, 2025. It is now read-only.

Commit 8e59c29

Browse files
NaoUnderscoreNaoUnderscorexNexusACS
authored
Modules and API Revamp (#2779)
* fix docs typos * remote debugging * Call me god bb (breaking changes lmao) * Probably fixed null refs on CI * Initialize all dispatchers * Fixed and changed all the tracking logic and structure * Items and Pickups are ready to use. Added `TrackablesGC` and fixed Tracker. * Fixed custom roles and role assigners. * Commands fixes and adjustments * fixed typos * Update programs.yml * Fixed all configs related issues * stylecop fixes * Added `DynamicTypeGenerator` * Fix stylecop * Improved `ConfigSubsystem`, implemented by `ConfigManager::LoadConfigSubsystem`, adding standalone configs, adding support for multiple individual configs in the same path with other configs, such as `ModulePointer` and module configs. * Useless code * Removed unused using directive * Optimized attachments generation * Added more methods to type generator * `ConfigSubsystem` revamp and improvements, implemented new configs for `PlayerState` objects. Configs will rely on classes marked as `ConfigAttribute`, if a class doesn't exist or the `PlayerState::Config` is null or not initialized and no suitable class is found, a dynamic type will be generated along with the relative configuration file named as the type of the `PlayerState` + a "-Config" suffix, placed in the CustomModule's instance config directory, and will be (de)serialized by generating the relative dynamic time each time until the `PlayerState::Config` gets initialized from the user/dev. This adds support for uninitialized configs and handles the exception in the best manner. * stylecop brr * I was kidding * Removed useless warnings * Removed debug log * And another one * Added more descriptions to serializable properties. * More descriptions added * [Trackables Fix] Custom Modules Commands (#2780) * Starting New Custom Modules commands * Finish all gamemode commands * Starting Custom Teams * Custom Team Commands finished * Custom Escape Commands * Parent Commands Desc Change * Fixed `ImplementConfigs` and `ApplyConfig` methods. Made some adjustments to modules commands. * bump --------- Co-authored-by: NaoUnderscore <[email protected]> Co-authored-by: xNexusACS <[email protected]>
1 parent e0385b2 commit 8e59c29

File tree

141 files changed

+5052
-2201
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

141 files changed

+5052
-2201
lines changed

.github/workflows/programs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ jobs:
3232
run: dotnet publish ${{ matrix.proj_name }} -r ${{ matrix.target }} -c release -o builds/${{ matrix.target }} --self-contained true
3333

3434
- name: Upload ${{ matrix.proj_name }}@${{ matrix.target }} build
35-
uses: actions/upload-artifact@v2
35+
uses: actions/upload-artifact@v3
3636
with:
3737
name: ${{ matrix.proj_name }}-${{ matrix.target }}
3838
path: builds/${{ matrix.target }}

EXILED.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
<PropertyGroup>
1717
<!-- This is the global version and is used for all projects that don't have a version -->
18-
<Version Condition="$(Version) == ''">9.0.0-beta.2</Version>
18+
<Version Condition="$(Version) == ''">9.0.0-beta.3</Version>
1919
<!-- Enables public beta warning via the PUBLIC_BETA constant -->
2020
<PublicBeta>false</PublicBeta>
2121

Exiled.API/Extensions/ItemExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ public static IEnumerable<AttachmentIdentifier> GetAttachmentIdentifiers(this Fi
268268
if (type.GetBaseCode() > code)
269269
code = type.GetBaseCode();
270270

271-
if (!Firearm.ItemTypeToFirearmInstance.TryGetValue(type, out Firearm firearm))
271+
if (Item.Create(type.GetItemType()) is not Firearm firearm)
272272
throw new ArgumentException($"Couldn't find a Firearm instance matching the ItemType value: {type}.");
273273

274274
firearm.Base.ApplyAttachmentsCode(code, true);

Exiled.API/Extensions/ReflectionExtensions.cs

Lines changed: 82 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@
88
namespace Exiled.API.Extensions
99
{
1010
using System;
11+
using System.Collections.Generic;
1112
using System.Reflection;
1213

1314
using HarmonyLib;
14-
1515
using LiteNetLib.Utils;
1616

1717
/// <summary>
@@ -51,19 +51,96 @@ public static void InvokeStaticEvent(this Type type, string eventName, object[]
5151
}
5252

5353
/// <summary>
54-
/// Copy all properties from the source class to the target one.
54+
/// Copies all properties from the source object to the target object, performing a deep copy if necessary.
5555
/// </summary>
56-
/// <param name="target">The target object.</param>
56+
/// <param name="target">The target object to copy properties to.</param>
5757
/// <param name="source">The source object to copy properties from.</param>
58-
public static void CopyProperties(this object target, object source)
58+
/// <param name="deepCopy">Indicates whether to perform a deep copy of properties that are of class type.</param>
59+
/// <exception cref="InvalidTypeException">Thrown when the target and source types do not match.</exception>
60+
public static void CopyProperties(this object target, object source, bool deepCopy = false)
5961
{
6062
Type type = target.GetType();
6163

6264
if (type != source.GetType())
6365
throw new InvalidTypeException("Target and source type mismatch!");
6466

6567
foreach (PropertyInfo sourceProperty in type.GetProperties())
66-
type.GetProperty(sourceProperty.Name)?.SetValue(target, sourceProperty.GetValue(source, null), null);
68+
{
69+
if (sourceProperty.CanWrite)
70+
{
71+
object value = sourceProperty.GetValue(source, null);
72+
73+
if (deepCopy && value is not null && sourceProperty.PropertyType.IsClass &&
74+
sourceProperty.PropertyType != typeof(string))
75+
{
76+
object targetValue = Activator.CreateInstance(sourceProperty.PropertyType);
77+
CopyProperties(targetValue, value, true);
78+
sourceProperty.SetValue(target, targetValue, null);
79+
}
80+
else
81+
{
82+
sourceProperty.SetValue(target, value, null);
83+
}
84+
}
85+
}
86+
}
87+
88+
/// <summary>
89+
/// Removes the generic type suffix (e.g., '`1' from `List`1`) from a type name if it exists.
90+
/// </summary>
91+
/// <param name="typeName">The name of the type, which may include a generic suffix.</param>
92+
/// <returns>The type name without the generic suffix if it was present; otherwise, returns the original type name.</returns>
93+
public static string RemoveGenericSuffix(this string typeName)
94+
{
95+
int indexOfBacktick = typeName.IndexOf('`');
96+
return indexOfBacktick >= 0 ? typeName.Substring(0, indexOfBacktick) : typeName;
97+
}
98+
99+
/// <summary>
100+
/// Gets the first non-generic base type of a given type.
101+
/// </summary>
102+
/// <param name="type">The type for which to find the first non-generic base type.</param>
103+
/// <returns>The first non-generic base type, or null if none is found.</returns>
104+
public static Type GetFirstNonGenericBaseType(this Type type)
105+
{
106+
Type baseType = type.BaseType;
107+
108+
while (baseType != null && baseType.IsGenericType)
109+
baseType = baseType.BaseType;
110+
111+
return baseType;
112+
}
113+
114+
/// <summary>
115+
/// Retrieves the names and values of all properties of an object based on the specified binding flags.
116+
/// </summary>
117+
/// <param name="obj">The object whose properties are to be retrieved.</param>
118+
/// <param name="bindingFlags">Optional. Specifies the binding flags to use for retrieving properties. Default is <see cref="BindingFlags.Instance"/> and <see cref="BindingFlags.Public"/>.</param>
119+
/// <returns>A dictionary containing property names as keys and their respective values as values.</returns>
120+
public static Dictionary<string, object> GetPropertiesWithValue(this object obj, BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public)
121+
{
122+
Dictionary<string, object> propertyValues = new();
123+
124+
obj.GetType().GetProperties(bindingFlags)
125+
.ForEach(property => propertyValues.Add(property.Name, property.GetValue(obj, null)));
126+
127+
return propertyValues;
128+
}
129+
130+
/// <summary>
131+
/// Retrieves the names and values of all fields of an object based on the specified binding flags.
132+
/// </summary>
133+
/// <param name="obj">The object whose fields are to be retrieved.</param>
134+
/// <param name="bindingFlags">Optional. Specifies the binding flags to use for retrieving fields. Default is <see cref="BindingFlags.Instance"/> and <see cref="BindingFlags.Public"/>.</param>
135+
/// <returns>A dictionary containing field names as keys and their respective values as values.</returns>
136+
public static Dictionary<string, object> GetFieldsWithValue(this object obj, BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public)
137+
{
138+
Dictionary<string, object> propertyValues = new();
139+
140+
obj.GetType().GetFields(bindingFlags)
141+
.ForEach(field => propertyValues.Add(field.Name, field.GetValue(obj)));
142+
143+
return propertyValues;
67144
}
68145
}
69146
}

Exiled.API/Extensions/StringExtensions.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,13 @@ public static string ToSnakeCase(this string str, bool shouldReplaceSpecialChars
9292
return shouldReplaceSpecialChars ? Regex.Replace(snakeCaseString, @"[^0-9a-zA-Z_]+", string.Empty) : snakeCaseString;
9393
}
9494

95+
/// <summary>
96+
/// Converts a <see cref="string"/> to kebab case convention.
97+
/// </summary>
98+
/// <param name="input">Input string.</param>
99+
/// <returns>A string converted to kebab case.</returns>
100+
public static string ToKebabCase(this string input) => Regex.Replace(input, "([a-z])([A-Z])", "$1_$2").ToLower();
101+
95102
/// <summary>
96103
/// Converts a <see cref="string"/> from snake_case convention.
97104
/// </summary>
@@ -204,5 +211,23 @@ public static string GetHashedUserId(this string userId)
204211
byte[] hash = Sha256.ComputeHash(textData);
205212
return BitConverter.ToString(hash).Replace("-", string.Empty);
206213
}
214+
215+
/// <summary>
216+
/// Encrypts a value using SHA-256 and returns a hexadecimal hash string.
217+
/// </summary>
218+
/// <param name="value">The value to encrypt.</param>
219+
/// <returns>A hexadecimal hash string of the encrypted value.</returns>
220+
public static string GetHashedValue(this string value)
221+
{
222+
byte[] bytes = Encoding.UTF8.GetBytes(value);
223+
byte[] hashBytes = Sha256.ComputeHash(bytes);
224+
225+
StringBuilder hashStringBuilder = new();
226+
227+
foreach (byte b in hashBytes)
228+
hashStringBuilder.Append(b.ToString("x2"));
229+
230+
return hashStringBuilder.ToString();
231+
}
207232
}
208233
}

Exiled.API/Features/Attributes/ConfigAttribute.cs

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,29 +10,39 @@ namespace Exiled.API.Features.Attributes
1010
using System;
1111

1212
/// <summary>
13-
/// This attribute determines whether the class which is being applied to should be treated as <see cref="EConfig"/>.
13+
/// This attribute determines whether the class which is being applied to should be treated as <see cref="ConfigSubsystem"/>.
1414
/// </summary>
1515
[AttributeUsage(AttributeTargets.Class)]
1616
public class ConfigAttribute : Attribute
1717
{
1818
/// <summary>
1919
/// Initializes a new instance of the <see cref="ConfigAttribute"/> class.
2020
/// </summary>
21-
public ConfigAttribute()
22-
{
23-
}
24-
25-
/// <summary>
26-
/// Initializes a new instance of the <see cref="ConfigAttribute"/> class.
27-
/// </summary>
28-
/// <param name="folder"><inheritdoc cref="Folder"/></param>
29-
/// <param name="name"><inheritdoc cref="Name"/></param>
30-
/// <param name="isParent"><inheritdoc cref="IsParent"/></param>
31-
public ConfigAttribute(string folder, string name, bool isParent = false)
21+
/// <param name="folder">
22+
/// The folder where the config file is stored.
23+
/// This value is used to determine the path of the configuration file.
24+
/// </param>
25+
/// <param name="name">
26+
/// The name of the configuration file.
27+
/// This is the unique name used to identify the configuration file.
28+
/// </param>
29+
/// <param name="isParent">
30+
/// A value indicating whether this configuration acts as a parent config.
31+
/// If <see langword="true"/>, this config will manage child configurations.
32+
/// </param>
33+
/// <param name="isStandAlone">
34+
/// A value indicating whether this configuration is stand-alone and should not manage or be managed from other configurations.
35+
/// </param>
36+
public ConfigAttribute(
37+
string folder = null,
38+
string name = null,
39+
bool isParent = false,
40+
bool isStandAlone = false)
3241
{
3342
Folder = folder;
3443
Name = name;
3544
IsParent = isParent;
45+
IsStandAlone = isStandAlone;
3646
}
3747

3848
/// <summary>
@@ -46,8 +56,13 @@ public ConfigAttribute(string folder, string name, bool isParent = false)
4656
public string Name { get; }
4757

4858
/// <summary>
49-
/// Gets a value indicating whether the class on which this attribute is being applied to should be treated as parent <see cref="EConfig"/>.
59+
/// Gets a value indicating whether the class on which this attribute is being applied to should be treated as parent <see cref="ConfigSubsystem"/>.
5060
/// </summary>
5161
public bool IsParent { get; }
62+
63+
/// <summary>
64+
/// Gets a value indicating whether the config is individual.
65+
/// </summary>
66+
public bool IsStandAlone { get; }
5267
}
5368
}

0 commit comments

Comments
 (0)