chore(generators): re-organise generated files

This commit is contained in:
roflmuffin
2025-11-06 13:47:52 +10:00
parent 0322548ebd
commit 0318713cbe
6 changed files with 9050 additions and 8868 deletions

View File

@@ -47,7 +47,7 @@
<PackageReference Include="Tomlyn" Version="0.19.0"/>
</ItemGroup>
<ItemGroup>
<Folder Include="Core\Schema\"/>
<Folder Include="Generated\Schema\" />
<Folder Include="Modules\Errors"/>
</ItemGroup>
<ItemGroup>

View File

@@ -212,7 +212,7 @@ internal static partial class Program
{
var outputPath =
args.FirstOrDefault() ??
"../CounterStrikeSharp.API/Core/Schema";
"../CounterStrikeSharp.API/Generated/Schema";
// Concat together all enums and classes
var allEnums = new SortedDictionary<string, SchemaEnum>();
@@ -407,20 +407,26 @@ internal static partial class Program
parentFields = GetAllParentFields(schemaClass, allClasses).ToArray();
}
if (schemaClass.Parent == null)
if (schemaClass.Parent == null && classNameCs != "CEntityInstance")
{
builder.Append($" : NativeObject");
}
else if (classNameCs == "CEntityInstance")
{
builder.Append($" : NativeEntity");
}
builder.AppendLine();
builder.AppendLine("{");
// All entity classes eventually derive from CEntityInstance,
// which is the root networkable class.
builder.AppendLine(
$" public {classNameCs} (IntPtr pointer) : base(pointer) {{}}");
builder.AppendLine();
if (classNameCs != "CEntityInstance")
{
builder.AppendLine(
$" public {classNameCs} (IntPtr pointer) : base(pointer) {{}}");
builder.AppendLine();
}
foreach (var field in schemaClass.Fields)
{

File diff suppressed because it is too large Load Diff

View File

@@ -11,6 +11,7 @@ public partial class Generators
{
Name = name;
}
public string Name { get; init; }
public string NamePascalCase => Name.ToPascalCase();
public List<GameEventKey> Keys { get; set; } = new();
@@ -23,6 +24,7 @@ public partial class Generators
Name = name;
Type = type;
}
public string Name { get; init; }
public string Type { get; init; }
public string NamePascalCase => Name.ToPascalCase();
@@ -71,7 +73,7 @@ public partial class Generators
var allGameEvents = new Dictionary<string, GameEvent>();
foreach (string url in GameEventFiles)
// foreach (string file in Directory.EnumerateFiles(pathToSearch, "*.gameevents", SearchOption.AllDirectories).OrderBy(Path.GetFileName))
// foreach (string file in Directory.EnumerateFiles(pathToSearch, "*.gameevents", SearchOption.AllDirectories).OrderBy(Path.GetFileName))
{
var file = await _httpClient.GetStringAsync($"{BaseUrl}/{url}");
var deserialized = VdfConvert.Deserialize(file);
@@ -133,7 +135,7 @@ public partial class Generators
// Remove the player_chat event as it's manually implemented
allGameEvents.RemoveAll(e => e.Name == "player_chat");
var gameEventsString = string.Join("\n", allGameEvents.OrderBy(x => x.NamePascalCase).Select(gameEvent =>
var events = allGameEvents.OrderBy(x => x.NamePascalCase).Select(gameEvent =>
{
var propertyDefinition = gameEvent.Keys.OrderBy(p => p.NamePascalCase).Select(key =>
{
@@ -142,43 +144,51 @@ public partial class Generators
? $"{key.NamePascalCase}Param"
: key.NamePascalCase;
return $@"
{(!string.IsNullOrEmpty(key.Comment) ? "// " + key.Comment : "")}
public {key.MappedType} {propertyName}
{{
get => {key.Getter};
set => {key.Setter};
}}";
return $@"{(!string.IsNullOrEmpty(key.Comment) ? "// " + key.Comment : "")}
public {key.MappedType} {propertyName}
{{
get => {key.Getter};
set => {key.Setter};
}}";
});
return $@"
[EventName(""{gameEvent.Name}"")]
public class Event{gameEvent.NamePascalCase} : GameEvent
{{
public Event{gameEvent.NamePascalCase}(IntPtr pointer) : base(pointer){{}}
public Event{gameEvent.NamePascalCase}(bool force) : base(""{gameEvent.Name}"", force){{}}
return (gameEvent, $@"
[EventName(""{gameEvent.Name}"")]
public class Event{gameEvent.NamePascalCase} : GameEvent
{{
public Event{gameEvent.NamePascalCase}(IntPtr pointer) : base(pointer){{}}
public Event{gameEvent.NamePascalCase}(bool force) : base(""{gameEvent.Name}"", force){{}}
{string.Join("\n", propertyDefinition)}
}}");
});
{string.Join("\n", propertyDefinition)}
}}";
}));
var result = $@"
#nullable enable
var template = $@"#nullable enable
using System;
using CounterStrikeSharp.API.Modules.Events;
using CounterStrikeSharp.API.Modules.Entities;
using CounterStrikeSharp.API.Core.Attributes;
namespace CounterStrikeSharp.API.Core
{{
{gameEventsString}
}}
namespace CounterStrikeSharp.API.Core;
<content>
#nullable restore
";
Console.WriteLine($"Generated C# bindings for {allGameEvents.Count} game events successfully.");
var outputPath = Path.Join(Helpers.GetRootDirectory(), "managed/CounterStrikeSharp.API/Generated/GameEvents");
File.WriteAllText(Path.Join(Helpers.GetRootDirectory(), "managed/CounterStrikeSharp.API/Core/GameEvents.g.cs"),
result);
// Clear output directory
if (Directory.Exists(outputPath))
{
string[] files = Directory.GetFiles(outputPath, "*", SearchOption.AllDirectories);
foreach (string file in files)
{
File.Delete(file);
}
}
foreach (var (gameEvent, definition) in events)
{
File.WriteAllText(Path.Join(outputPath, $"Event{gameEvent.NamePascalCase}.g.cs"), template.Replace("<content>", definition));
}
Console.WriteLine($"Generated C# bindings for {allGameEvents.Count} game events successfully.");
}
}

View File

@@ -1,216 +0,0 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace CodeGen.Natives.Scripts;
public partial class Generators
{
public class Class
{
[JsonPropertyName("class_name")] public string ClassName { get; set; }
[JsonPropertyName("class_size")] public int ClassSize { get; set; }
[JsonPropertyName("offsets")] public List<Offset> Offsets { get; set; }
[JsonPropertyName("metadata")] public List<Metadata>? Metadata { get; set; }
[JsonPropertyName("inherits")] public string Inherits { get; set; }
public List<Class> Subclasses { get; set; } = new List<Class>();
public string SchemaName { get; set; }
}
public class Enum
{
[JsonPropertyName("enum_name")] public string EnumName { get; set; }
[JsonPropertyName("enum_size")] public int EnumSize { get; set; }
[JsonPropertyName("memebers")] public List<Memeber> Members { get; set; }
}
public class Memeber
{
[JsonPropertyName("name")] public string Name { get; set; }
[JsonPropertyName("value")] public ulong Value { get; set; }
}
public class Metadata
{
[JsonPropertyName("type")] public string Type { get; set; }
[JsonPropertyName("name")] public string Name { get; set; }
[JsonPropertyName("var_name")] public string VarName { get; set; }
[JsonPropertyName("var_type")] public string VarType { get; set; }
}
public class Offset
{
[JsonPropertyName("field_name")] public string FieldName { get; set; }
[JsonPropertyName("field_type")] public string FieldType { get; set; }
[JsonPropertyName("field_ctype")] public string FieldCtype { get; set; }
[JsonPropertyName("offset")] public int OffsetSize { get; set; }
[JsonPropertyName("metadata")] public List<Metadata> Metadata { get; set; }
}
public class Root
{
[JsonPropertyName("schema_name")] public string SchemaName { get; set; }
[JsonPropertyName("classes")] public List<Class> Classes { get; set; }
[JsonPropertyName("enums")] public List<Enum>? Enums { get; set; }
}
private static string MapVarTypeToCSharpType(string value)
{
switch (value)
{
case "int32":
return "int";
case "int64":
return "long";
case "uint8":
return "sbyte";
case "float32":
return "float";
case "char":
return "string";
case "uint32":
return "uint";
case "uint64":
return "ulong";
}
if (CleanName(value).EndsWith("*"))
{
return $"PointerTo<{CleanName(value).Replace("*", "")}>";
}
return CleanName(value);
}
private static string CleanName(string value) => value.Replace("::", "__").Replace(" ", "");
record MemberRow(string VarType, string VarName, int? Offset);
public static void GenerateNativeObjects()
{
var jsonPath = Path.Join(Helpers.GetRootDirectory(), "tooling/CodeGen.Natives/cs2_schema.json");
var jsonString = File.ReadAllText(jsonPath);
var allSchemas = JsonSerializer.Deserialize<List<Root>>(jsonString);
var allClasses = allSchemas.Where(x => x.SchemaName != "client.dll").SelectMany(s =>
{
return s.Classes.Select(x =>
{
x.SchemaName = s.SchemaName;
return x;
});
});
var supportedTypes =
new HashSet<string>(new[] { "int", "int32", "float", "bool", "uint8", "float32", "char", "uint32", "uint64", "Vector" });
foreach (var name in allSchemas.SelectMany(x => x.Enums ?? Enumerable.Empty<Enum>()).DistinctBy(x => x.EnumName)
.Select(x => CleanName(x.EnumName)))
{
supportedTypes.Add(name);
}
foreach (var c in allClasses)
{
supportedTypes.Add(CleanName(c.ClassName));
supportedTypes.Add(CleanName(c.ClassName) + "*");
}
var addedMembers = new HashSet<string>();
var addedClasses = new HashSet<string>();
var allClassDefinitions = allClasses.Select(c =>
{
var className = c.ClassName.Replace("::", "__");
if (addedClasses.Contains(className)) return null;
var inheritedClassName = c.Inherits?.Split(new string[] { "::" }, StringSplitOptions.None).Last()
.Replace("::", "__");
var classDefinition = $@"
// {c.SchemaName}
public partial class {className} {(inheritedClassName != null ? $": {inheritedClassName}" : ": NativeObject")} {{
private const string ThisClassName = ""{className}"";
public {className} (IntPtr pointer) : base(pointer) {{}}
[[members]]
}}";
var networkVarMembers =
c.Metadata?.Where(x => x.Type != "Unknown").Select(x => new MemberRow(CleanName(x.VarType), x.VarName, null)) ??
Enumerable.Empty<MemberRow>();
// Currently disabled, but access to non network vars (aka not accessible via schema)
var offsetVarMembers = c.Offsets.Select(x => new MemberRow(CleanName(x.FieldCtype), x.FieldName, x.OffsetSize));
var members = networkVarMembers
// .Concat(offsetVarMembers)
.Where(x => supportedTypes.Contains(x.VarType) || x.VarType.StartsWith("CHandle"))
.Select(m =>
{
var mappedVarType = MapVarTypeToCSharpType(m.VarType);
var returnData = $@"
public {mappedVarType} {m.VarName}
{{
get => Schema.GetSchemaValue<{mappedVarType}>(this.Handle, ThisClassName, ""{m.VarName}"");
set => Schema.SetSchemaValue<{mappedVarType}>(this.Handle, ThisClassName, ""{m.VarName}"", value);
}}";
return returnData;
}).ToArray();
classDefinition = classDefinition.Replace("[[members]]", string.Join("\n", members));
addedClasses.Add(className);
return classDefinition;
}).Where(x => x != null).ToArray();
var result = $@"
using System;
using CounterStrikeSharp.API.Modules.Events;
using CounterStrikeSharp.API.Modules.Entities;
using CounterStrikeSharp.API.Core.Attributes;
using CounterStrikeSharp.API.Modules.Memory;
using CounterStrikeSharp.API.Modules.Utils;
namespace CounterStrikeSharp.API.Core
{{
[[template]]
}}
";
var allEnums = allSchemas.SelectMany(x => x.Enums ?? Enumerable.Empty<Enum>()).DistinctBy(x => x.EnumName)
.Select(e =>
{
return $@"
public enum {CleanName(e.EnumName)} : ulong {{
{string.Join(",\n\t\t", e.Members.Select(m => $"{m.Name} = {m.Value}"))}
}}";
});
File.WriteAllText(Path.Join(Helpers.GetRootDirectory(), "managed/CounterStrikeSharp.API/Core/Objects.g.cs"),
result.Replace("[[template]]", string.Join("\n", allClassDefinitions)));
Console.WriteLine($"Generated C# bindings for {allClassDefinitions.Length} native object classes successfully.");
File.WriteAllText(Path.Join(Helpers.GetRootDirectory(), "managed/CounterStrikeSharp.API/Core/Enums.g.cs"),
result.Replace("[[template]]", string.Join("\n", allEnums)));
}
}

View File

@@ -88,8 +88,7 @@ public partial class Generators
return returnStr.ToString();
}));
var result = $@"
using System;
var result = $@"using System;
using CounterStrikeSharp.API.Modules.Memory;
using CounterStrikeSharp.API.Modules.UserMessages;
using CounterStrikeSharp.API.Modules.Commands;
@@ -105,7 +104,7 @@ namespace CounterStrikeSharp.API.Core
Console.WriteLine($"Generated C# bindings for {natives.Count} methods successfully.");
File.WriteAllText(Path.Join(Helpers.GetRootDirectory(), "managed/CounterStrikeSharp.API/Core/API.cs"),
File.WriteAllText(Path.Join(Helpers.GetRootDirectory(), "managed/CounterStrikeSharp.API/Generated/Natives/API.cs"),
result);
}
}