From 9a36dd58ff0d76cd11c0271d2005d6f231a46d44 Mon Sep 17 00:00:00 2001 From: Garry Newman Date: Wed, 12 Feb 2020 14:55:36 +0000 Subject: [PATCH] New parser, no code skimming --- Generator/CodeParser/CodeParser.cs | 153 ------------------------ Generator/CodeWriter/ClassVTable.cs | 38 +++--- Generator/CodeWriter/CodeWriter.cs | 38 ++---- Generator/CodeWriter/Constants.cs | 2 + Generator/CodeWriter/GlobalFunctions.cs | 4 + Generator/CodeWriter/Struct.cs | 6 +- Generator/Generator.csproj | 1 - Generator/Program.cs | 12 +- Generator/SteamApiDefinition.cs | 99 ++++++++------- 9 files changed, 93 insertions(+), 260 deletions(-) delete mode 100644 Generator/CodeParser/CodeParser.cs diff --git a/Generator/CodeParser/CodeParser.cs b/Generator/CodeParser/CodeParser.cs deleted file mode 100644 index 425572b..0000000 --- a/Generator/CodeParser/CodeParser.cs +++ /dev/null @@ -1,153 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; - -namespace Generator -{ - public partial class CodeParser - { - public string Content; - - public CodeParser( string folder ) - { - foreach ( var file in System.IO.Directory.GetFiles( folder, "*.h", System.IO.SearchOption.AllDirectories ) ) - { - Content += System.IO.File.ReadAllText( file ); - } - - Content = Content.Replace( "\r\n", "\n" ); - Content = Content.Replace( "\n\r", "\n" ); - } - - internal void ExtendDefinition( SteamApiDefinition def ) - { - // - // Get a list of CallbackIds - // - def.CallbackIds = new Dictionary(); - - //v1 - { - var r = new Regex( @"enum { (k_[i|I](?:.+)) = ([0-9]+) };" ); - var ma = r.Matches( Content ); - - foreach ( Match m in ma ) - { - def.CallbackIds.Add( m.Groups[1].Value.Substring( 3 ).Replace( "Callbacks", "" ), int.Parse( m.Groups[2].Value ) ); - } - } - - // - // Associate callbackIds with structs - // - foreach ( var t in def.structs ) - { - if ( !string.IsNullOrEmpty( t.CallbackId ) ) continue; - - // Standard style - { - var r = new Regex( @"struct "+t.Name+@"\n{ ?\n(?:.)+enum { k_iCallback = (?:(.+) \+ ([0-9]+)|(.+)) };", RegexOptions.Multiline | RegexOptions.IgnoreCase ); - var m = r.Match( Content ); - if ( m.Success ) - { - var kName = m.Groups[1].Value; - var num = m.Groups[2].Value; - - if ( string.IsNullOrEmpty( kName ) ) - { - kName = m.Groups[3].Value; - num = "0"; - } - - kName = "CallbackIdentifiers." + kName.Substring( 3 ).Replace( "Callbacks", "" ); - - t.CallbackId = $"{kName} + {num}"; - } - } - - // New style - { - var r = new Regex( @"DEFINE_CALLBACK\( "+t.Name+@", (.+) \+ ([0-9]+) \)" ); - var m = r.Match( Content ); - if ( m.Success ) - { - var kName = m.Groups[1].Value; - var num = m.Groups[2].Value; - - //kName = kName.Replace( "k_i", "CallbackIdentifiers." ).Replace( "Callbacks", "" ); - kName = "CallbackIdentifiers." + kName.Substring( 3 ).Replace( "Callbacks", "" ); - - t.CallbackId = $"{kName} + {num}"; - } - } - - // Even Newer Style - { - var r = new Regex( @"STEAM_CALLBACK_BEGIN\( " + t.Name + @", (.+) \+ ([0-9]+) \)" ); - var m = r.Match( Content ); - if ( m.Success ) - { - var kName = m.Groups[1].Value; - var num = m.Groups[2].Value; - - //kName = kName.Replace( "k_i", "CallbackIdentifiers." ).Replace( "Callbacks", "" ); - kName = "CallbackIdentifiers." + kName.Substring( 3 ).Replace( "Callbacks", "" ); - - t.CallbackId = $"{kName} + {num}"; - } - } - } - - // - // Find defines - // - def.Defines = new Dictionary(); - { - var r = new Regex( @"#define ([a-zA-Z_]+) ""(.+)""" ); - var ma = r.Matches( Content ); - - foreach ( Match m in ma ) - { - def.Defines.Add( m.Groups[1].Value.Replace( "Callbacks", "" ), m.Groups[2].Value ); - } - } - - // - // Find missing structs - // - { - var r = new Regex( @"struct ([a-zA-Z]+_t)" ); - var ma = r.Matches( Content ); - - foreach ( Match m in ma ) - { - var s = def.structs.SingleOrDefault( x => x.Name == m.Groups[1].Value ); - if ( s == null ) - { - Console.WriteLine( "Missing Struct: " + m.Groups[1].Value ); - } - } - - //Console.ReadKey(); - } - - // - // Change all struct bool fields to bytes (they're technically bytes anyway, and it helps with marshalling) - // - { - foreach ( var s in def.structs ) - { - foreach ( var f in s.Fields ) - { - if ( f.Type == "bool" ) - f.Type = "byte"; - } - } - } - - } - } -} diff --git a/Generator/CodeWriter/ClassVTable.cs b/Generator/CodeWriter/ClassVTable.cs index d2fd8e4..bb5e8fb 100644 --- a/Generator/CodeWriter/ClassVTable.cs +++ b/Generator/CodeWriter/ClassVTable.cs @@ -8,7 +8,7 @@ namespace Generator { public partial class CodeWriter { - public void GenerateVTableClass( string className, string filename ) + public void GenerateVTableClass( SteamApiDefinition.Interface iface, string folder ) { sb = new StringBuilder(); @@ -23,26 +23,24 @@ namespace Generator StartBlock( $"namespace Steamworks" ); { - StartBlock( $"internal class {className} : SteamInterface" ); + StartBlock( $"internal class {iface.Name} : SteamInterface" ); { - WriteLine( $"public override IntPtr GetInterfacePointer() => GetApi.{className.Substring( 1 )}();" ); + WriteLine( $"public override IntPtr GetInterfacePointer() => GetApi.{iface.Name.Substring( 1 )}();" ); WriteLine(); WriteLine(); - StartBlock( $"internal {className}()" ); + StartBlock( $"internal {iface.Name}()" ); { WriteLine( $"SetupInterface();" ); } EndBlock(); WriteLine(); - var functions = def.methods.Where( x => x.ClassName == className ); - - foreach ( var func in functions ) + foreach ( var func in iface.Methods ) { - if ( Cleanup.IsDeprecated( $"{func.ClassName}.{func.Name}" ) ) + if ( Cleanup.IsDeprecated( $"{iface.Name}.{func.Name}" ) ) continue; - WriteFunction( func ); + WriteFunction( iface, func ); WriteLine(); } @@ -51,19 +49,19 @@ namespace Generator } EndBlock(); - System.IO.File.WriteAllText( $"{filename}", sb.ToString() ); + System.IO.File.WriteAllText( $"{folder}{iface.Name}.cs", sb.ToString() ); } - private void WriteFunction( SteamApiDefinition.MethodDef func ) + private void WriteFunction( SteamApiDefinition.Interface iface, SteamApiDefinition.Interface.Method func ) { - var returnType = BaseType.Parse( func.ReturnType, null, func.CallResult ); + var returnType = BaseType.Parse( func.ReturnType, null ); returnType.Func = func.Name; if ( func.Params == null ) - func.Params = new SteamApiDefinition.MethodDef.ParamType[0]; + func.Params = new SteamApiDefinition.Interface.Method.Param[0]; var args = func.Params.Select( x => { - var bt = BaseType.Parse( x.Type, x.Name ); + var bt = BaseType.Parse( x.ParamType, x.ParamName ); bt.Func = func.Name; return bt; } ).ToArray(); @@ -89,16 +87,16 @@ namespace Generator var argstr = string.Join( ", ", args.Where( x => !x.ShouldSkipAsArgument ).Select( x => x.AsArgument() ) ); ; var delegateargstr = string.Join( ", ", args.Select( x => x.AsNativeArgument() ) ); - if ( returnType is SteamApiCallType sap ) - { - sap.CallResult = func.CallResult; + //if ( returnType is SteamApiCallType sap ) + // { + // sap.CallResult = func.CallResult; - argstr = string.Join( ", ", args.Select( x => x.AsArgument().Replace( "ref ", " /* ref */ " ) ) ); - } + // argstr = string.Join( ", ", args.Select( x => x.AsArgument().Replace( "ref ", " /* ref */ " ) ) ); + // } WriteLine( $"#region FunctionMeta" ); - WriteLine( $"[DllImport( Platform.LibraryName, EntryPoint = \"SteamAPI_{func.ClassName}_{func.Name}\")]" ); + WriteLine( $"[DllImport( Platform.LibraryName, EntryPoint = \"{func.FlatName}\")]" ); if ( returnType.ReturnAttribute != null ) WriteLine( returnType.ReturnAttribute ); diff --git a/Generator/CodeWriter/CodeWriter.cs b/Generator/CodeWriter/CodeWriter.cs index f1c8c23..f716959 100644 --- a/Generator/CodeWriter/CodeWriter.cs +++ b/Generator/CodeWriter/CodeWriter.cs @@ -11,12 +11,9 @@ namespace Generator public partial class CodeWriter { private SteamApiDefinition def; - public CodeParser Parser; - public CodeWriter( CodeParser parser, SteamApiDefinition def ) + public CodeWriter( SteamApiDefinition def ) { - Parser = parser; - this.def = def; WorkoutTypes(); } @@ -56,34 +53,15 @@ namespace Generator } { - GenerateGlobalFunctions( "SteamAPI", $"{folder}../Generated/SteamAPI.cs" ); - GenerateGlobalFunctions( "SteamGameServer", $"{folder}../Generated/SteamGameServer.cs" ); - GenerateGlobalFunctions( "SteamInternal", $"{folder}../Generated/SteamInternal.cs" ); + // GenerateGlobalFunctions( "SteamAPI", $"{folder}../Generated/SteamAPI.cs" ); + // GenerateGlobalFunctions( "SteamGameServer", $"{folder}../Generated/SteamGameServer.cs" ); + // GenerateGlobalFunctions( "SteamInternal", $"{folder}../Generated/SteamInternal.cs" ); } - { - GenerateVTableClass( "ISteamApps", $"{folder}../Generated/Interfaces/ISteamApps.cs" ); - GenerateVTableClass( "ISteamUtils", $"{folder}../Generated/Interfaces/ISteamUtils.cs" ); - GenerateVTableClass( "ISteamParentalSettings", $"{folder}../Generated/Interfaces/ISteamParentalSettings.cs" ); - GenerateVTableClass( "ISteamMusic", $"{folder}../Generated/Interfaces/ISteamMusic.cs" ); - GenerateVTableClass( "ISteamVideo", $"{folder}../Generated/Interfaces/ISteamVideo.cs" ); - GenerateVTableClass( "ISteamUser", $"{folder}../Generated/Interfaces/ISteamUser.cs" ); - GenerateVTableClass( "ISteamMatchmakingServers", $"{folder}../Generated/Interfaces/ISteamMatchmakingServers.cs" ); - GenerateVTableClass( "ISteamFriends", $"{folder}../Generated/Interfaces/ISteamFriends.cs" ); - GenerateVTableClass( "ISteamGameServer", $"{folder}../Generated/Interfaces/ISteamGameServer.cs" ); - GenerateVTableClass( "ISteamScreenshots", $"{folder}../Generated/Interfaces/ISteamScreenshots.cs" ); - GenerateVTableClass( "ISteamUserStats", $"{folder}../Generated/Interfaces/ISteamUserStats.cs" ); - GenerateVTableClass( "ISteamUGC", $"{folder}../Generated/Interfaces/ISteamUGC.cs" ); - GenerateVTableClass( "ISteamRemoteStorage", $"{folder}../Generated/Interfaces/ISteamRemoteStorage.cs" ); - GenerateVTableClass( "ISteamInventory", $"{folder}../Generated/Interfaces/ISteamInventory.cs" ); - GenerateVTableClass( "ISteamNetworking", $"{folder}../Generated/Interfaces/ISteamNetworking.cs" ); - GenerateVTableClass( "ISteamMatchmaking", $"{folder}../Generated/Interfaces/ISteamMatchmaking.cs" ); - GenerateVTableClass( "ISteamParties", $"{folder}../Generated/Interfaces/ISteamParties.cs" ); - GenerateVTableClass( "ISteamNetworkingUtils", $"{folder}../Generated/Interfaces/ISteamNetworkingUtils.cs" ); - GenerateVTableClass( "ISteamNetworkingSockets", $"{folder}../Generated/Interfaces/ISteamNetworkingSockets.cs" ); - GenerateVTableClass( "ISteamGameServerStats", $"{folder}../Generated/Interfaces/ISteamGameServerStats.cs" ); - GenerateVTableClass( "ISteamInput", $"{folder}../Generated/Interfaces/ISteamInput.cs" ); - } + foreach ( var iface in def.Interfaces ) + { + GenerateVTableClass( iface, $"{folder}../Generated/Interfaces/" ); + } } void WorkoutTypes() diff --git a/Generator/CodeWriter/Constants.cs b/Generator/CodeWriter/Constants.cs index 3f31841..253809c 100644 --- a/Generator/CodeWriter/Constants.cs +++ b/Generator/CodeWriter/Constants.cs @@ -10,6 +10,7 @@ namespace Generator { private void Constants() { + /* StartBlock( "internal static class CallbackIdentifiers" ); foreach ( var o in def.CallbackIds ) { @@ -23,6 +24,7 @@ namespace Generator WriteLine( $"internal const string {o.Key} = \"{o.Value}\";" ); } EndBlock(); + */ } } } \ No newline at end of file diff --git a/Generator/CodeWriter/GlobalFunctions.cs b/Generator/CodeWriter/GlobalFunctions.cs index 3f4224f..0f074e0 100644 --- a/Generator/CodeWriter/GlobalFunctions.cs +++ b/Generator/CodeWriter/GlobalFunctions.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; namespace Generator { + /* public partial class CodeWriter { public void GenerateGlobalFunctions( string startingWith, string filename ) @@ -124,5 +125,8 @@ namespace Generator WriteLine( $"public static extern {(returnType.IsReturnedWeird ? "void" : returnType.TypeNameFrom)} {func.Name}( {delegateargstr} );" ); WriteLine(); } + + } + */ } diff --git a/Generator/CodeWriter/Struct.cs b/Generator/CodeWriter/Struct.cs index 6306aff..ad389b0 100644 --- a/Generator/CodeWriter/Struct.cs +++ b/Generator/CodeWriter/Struct.cs @@ -40,7 +40,7 @@ namespace Generator { var callbackList = new List(); - foreach ( var c in def.structs ) + foreach ( var c in def.callback_structs ) { var name = Cleanup.ConvertType( c.Name ); @@ -55,7 +55,7 @@ namespace Generator int defaultPack = c.IsPack4OnWindows ? 4 : 8; - var isCallback = !string.IsNullOrEmpty( c.CallbackId ); + var isCallback = true; var iface = ""; if ( isCallback ) iface = " : ICallbackData"; @@ -117,7 +117,7 @@ namespace Generator WriteLine( "#endregion" ); } - if ( !string.IsNullOrEmpty( c.CallbackId ) ) + // if ( c.CallbackId ) ) { callbackList.Add( c ); } diff --git a/Generator/Generator.csproj b/Generator/Generator.csproj index 70745ff..f35f646 100644 --- a/Generator/Generator.csproj +++ b/Generator/Generator.csproj @@ -47,7 +47,6 @@ - diff --git a/Generator/Program.cs b/Generator/Program.cs index 3dad0c5..94efa3f 100644 --- a/Generator/Program.cs +++ b/Generator/Program.cs @@ -13,18 +13,14 @@ namespace Generator static void Main( string[] args ) { - var content = System.IO.File.ReadAllText( "steam_sdk/steam_api.json" ); + var content = System.IO.File.ReadAllText( "steam_api.json" ); var def = Newtonsoft.Json.JsonConvert.DeserializeObject( content ); - AddMissing( def ); - - var parser = new CodeParser( @"steam_sdk" ); - - parser.ExtendDefinition( def ); + // AddMissing( def ); Definitions = def; - var generator = new CodeWriter( parser, def ); + var generator = new CodeWriter( def ); generator.ToFolder( "../Facepunch.Steamworks/Generated/" ); } @@ -35,7 +31,7 @@ namespace Generator var missing = Newtonsoft.Json.JsonConvert.DeserializeObject( content ); output.structs.AddRange( missing.structs ); - output.methods.AddRange( missing.methods ); + // output.methods.AddRange( missing.methods ); foreach ( var s in output.structs ) { diff --git a/Generator/SteamApiDefinition.cs b/Generator/SteamApiDefinition.cs index dd61a92..2580407 100644 --- a/Generator/SteamApiDefinition.cs +++ b/Generator/SteamApiDefinition.cs @@ -9,15 +9,38 @@ namespace Generator { public class SteamApiDefinition { - public class TypeDef + public class Interface { - [JsonProperty( PropertyName = "typedef" )] + [JsonProperty( PropertyName = "classname" )] public string Name { get; set; } - [JsonProperty( PropertyName = "type" )] - public string Type { get; set; } + + [JsonProperty( PropertyName = "version_string" )] + public string VersionString { get; set; } + + public class Method + { + public string ReturnType { get; set; } + + public class Param + { + public string ParamType { get; set; } + public string ParamName { get; set; } + } + + public Param[] Params { get; set; } + [JsonProperty( PropertyName = "methodname" )] + public string Name { get; set; } + [JsonProperty( PropertyName = "flat_name" )] + public string FlatName { get; set; } + + } + + public Method[] Methods { get; set; } + } - public List typedefs { get; set; } + public Interface[] Interfaces { get; set; } + public class EnumDef { @@ -37,6 +60,17 @@ namespace Generator public EnumDef[] enums { get; set; } + + public class TypeDef + { + [JsonProperty( PropertyName = "typedef" )] + public string Name { get; set; } + [JsonProperty( PropertyName = "type" )] + public string Type { get; set; } + } + + public List typedefs { get; set; } + public class StructDef { public class StructFields @@ -52,55 +86,30 @@ namespace Generator [JsonProperty( PropertyName = "fields" )] public StructFields[] Fields { get; set; } - public string CallbackId { get; set; } + public bool IsPack4OnWindows + { + get + { + // 4/8 packing is irrevant to these classes + if ( Name.Contains( "MatchMakingKeyValuePair_t" ) ) return true; - public bool IsPack4OnWindows - { - get - { - // 4/8 packing is irrevant to these classes - if ( Name.Contains( "MatchMakingKeyValuePair_t" ) ) return true; + if ( Fields.Any( x => x.Type.Contains( "CSteamID" ) ) ) + return true; - if ( Fields.Any( x => x.Type.Contains( "CSteamID" ) ) ) - return true; - - return false; - } - } + return false; + } + } } public List structs { get; set; } - public class MethodDef + public class CallbackStructDef : StructDef { - public class ParamType - { - [JsonProperty( PropertyName = "paramname" )] - public string Name { get; set; } - [JsonProperty( PropertyName = "paramtype" )] - public string Type { get; set; } - } - - [JsonProperty( PropertyName = "classname" )] - public string ClassName { get; set; } - [JsonProperty( PropertyName = "methodname" )] - public string Name { get; set; } - [JsonProperty( PropertyName = "returntype" )] - public string ReturnType { get; set; } - [JsonProperty( PropertyName = "params" )] - public ParamType[] Params { get; set; } - - [JsonProperty( PropertyName = "callresult" )] - public string CallResult { get; set; } - - public bool NeedsSelfPointer = true; + [JsonProperty( PropertyName = "callback_id" )] + public int CallbackId { get; set; } } - public List methods { get; set; } - - - public Dictionary CallbackIds { get; internal set; } - public Dictionary Defines { get; internal set; } + public List callback_structs { get; set; } } }