This commit is contained in:
Garry Newman 2020-02-20 12:09:23 +00:00
parent 0ea03e1499
commit f562e65149
14 changed files with 268 additions and 161 deletions

View File

@ -104,7 +104,7 @@ internal void ReleaseRequest( HServerListRequest hServerListRequest )
internal gameserveritem_t GetServerDetails( HServerListRequest hRequest, int iServer )
{
var returnValue = _GetServerDetails( Self, hRequest, iServer );
return (gameserveritem_t) Marshal.PtrToStructure( returnValue, typeof( gameserveritem_t ) );
return returnValue.ToType<gameserveritem_t>();
}
#region FunctionMeta

View File

@ -28,7 +28,7 @@ internal ISteamNetworkingUtils( bool IsGameServer )
internal NetMsg AllocateMessage( int cbAllocateBuffer )
{
var returnValue = _AllocateMessage( Self, cbAllocateBuffer );
return (NetMsg) Marshal.PtrToStructure( returnValue, typeof( NetMsg ) );
return returnValue.ToType<NetMsg>();
}
#region FunctionMeta

View File

@ -144,5 +144,17 @@ internal static bool IsDeprecated( string name )
}
return false;
}
//
// If we start with E[Capital] then strip the E
// (makes us more C# like)
//
internal static string CleanEnum( string name )
{
if ( name[0] != 'E' ) return name;
if ( !char.IsUpper( name[1] ) ) return name;
return name.Substring( 1 );
}
}

View File

@ -10,11 +10,14 @@ namespace Generator
{
public partial class CodeWriter
{
public static CodeWriter Current { get; private set; }
private SteamApiDefinition def;
public CodeWriter( SteamApiDefinition def )
{
this.def = def;
Current = this;
WorkoutTypes();
}
@ -119,5 +122,37 @@ private void Footer()
{
EndBlock();
}
public bool IsStruct( string name )
{
if ( def.structs.Any( x => x.Name == name || Cleanup.ConvertType( x.Name ) == name ) )
return true;
return false;
}
public bool IsTypeDef( string name )
{
if ( def.typedefs.Any( x => x.Name == name || Cleanup.ConvertType( x.Name ) == name ) )
return true;
return false;
}
public bool IsCallback( string name )
{
if ( def.callback_structs.Any( x => x.Name == name || Cleanup.ConvertType( x.Name ) == name ) )
return true;
return false;
}
public bool IsEnum( string name )
{
if ( def.enums.Any( x => x.Name == name || Cleanup.ConvertType( x.Name ) == name ) )
return true;
return false;
}
}
}

View File

@ -96,13 +96,13 @@ private void WriteFunction( SteamApiDefinition.Interface iface, SteamApiDefiniti
for( int i=0; i<args.Length; i++ )
{
if ( args[i] is StringType )
if ( args[i] is FetchStringType )
{
if ( args[i + 1] is IntType || args[i + 1] is UIntType || args[i + 1] is UIntPtrType )
{
if ( args[i + 1].Ref == string.Empty )
{
args[i + 1] = new ConstValueType( args[i + 1], "(1024 * 32)" );
args[i + 1] = new LiteralType( args[i + 1], "(1024 * 32)" );
}
}
else
@ -150,7 +150,7 @@ private void WriteFunction( SteamApiDefinition.Interface iface, SteamApiDefiniti
//
foreach ( var arg in args )
{
if ( arg is StringType sb )
if ( arg is FetchStringType sb )
{
WriteLine( $"IntPtr mem{sb.VarName} = Helpers.TakeMemory();" );
}
@ -170,7 +170,7 @@ private void WriteFunction( SteamApiDefinition.Interface iface, SteamApiDefiniti
//
foreach ( var arg in args )
{
if ( arg is StringType sb )
if ( arg is FetchStringType sb )
{
WriteLine( $"{sb.VarName} = Helpers.MemoryToString( mem{sb.VarName} );" );
}

View File

@ -51,7 +51,14 @@
<Compile Include="CodeWriter\Constants.cs" />
<Compile Include="CodeWriter\CustomEnums.cs" />
<Compile Include="CodeWriter\StructCallbacks.cs" />
<Compile Include="CodeWriter\Types\BaseType.cs" />
<Compile Include="Types\FetchStringType.cs" />
<Compile Include="Types\ConstCharType.cs" />
<Compile Include="Types\LiteralType.cs" />
<Compile Include="Types\StructType.cs" />
<Compile Include="Types\BoolType.cs" />
<Compile Include="Types\VoidType.cs" />
<Compile Include="Types\SteamApiCallType.cs" />
<Compile Include="Types\BaseType.cs" />
<Compile Include="CodeWriter\Writing.cs" />
<Compile Include="CodeWriter\CodeWriter.cs" />
<Compile Include="CodeWriter\Enums.cs" />

View File

@ -13,8 +13,6 @@ internal class BaseType
public string Func;
public virtual bool WindowsSpecific => false;
public static BaseType Parse( string type, string varname = null, string callresult = null )
{
type = Cleanup.ConvertType( type );
@ -26,7 +24,7 @@ public static BaseType Parse( string type, string varname = null, string callres
if ( type == "void" ) return new VoidType { NativeType = type, VarName = varname };
if ( type.Replace( " ", "" ).StartsWith( "constchar*" ) ) return new ConstCharType { NativeType = type, VarName = varname };
if ( type == "char *" ) return new StringType { NativeType = type, VarName = varname };
if ( type == "char *" ) return new FetchStringType { NativeType = type, VarName = varname };
var basicType = type.Replace( "const ", "" ).Trim( ' ', '*', '&' );
@ -38,34 +36,39 @@ public static BaseType Parse( string type, string varname = null, string callres
if ( basicType == "uint8" ) return new UInt8Type { NativeType = type, VarName = varname };
if ( basicType == "uint16" ) return new UInt16Type { NativeType = type, VarName = varname };
if ( basicType == "unsigned short" ) return new UInt16Type { NativeType = type, VarName = varname };
if ( basicType == "SteamId" ) return new CSteamIdType { NativeType = type, VarName = varname };
if ( basicType == "size_t" ) return new UIntPtrType{ NativeType = type, VarName = varname };
// DANGER DANGER Danger
if ( basicType == "intptr_t" ) return new LongType { NativeType = type, VarName = varname };
if ( basicType == "ptrdiff_t" ) return new LongType { NativeType = type, VarName = varname };
if ( basicType == "size_t" ) return new UIntPtrType { NativeType = type, VarName = varname };
if ( basicType == "uint64" ) return new ULongType { NativeType = type, VarName = varname };
if ( basicType == "int64" ) return new LongType { NativeType = type, VarName = varname };
if ( basicType == "bool" ) return new BoolType { NativeType = type, VarName = varname };
if ( basicType == "InventoryItemId" ) return new StructType { NativeType = type, VarName = varname, StructName = basicType };
if ( basicType == "InventoryDefId" ) return new StructType { NativeType = type, VarName = varname, StructName = basicType };
if ( basicType == "PingLocation" ) return new StructType { NativeType = type, VarName = varname, StructName = basicType };
if ( basicType == "NetIdentity" ) return new StructType { NativeType = type, VarName = varname, StructName = basicType };
if ( basicType == "NetAddress" ) return new StructType { NativeType = type, VarName = varname, StructName = basicType };
if ( basicType == "ConnectionInfo" ) return new StructType { NativeType = type, VarName = varname, StructName = basicType };
if ( basicType == "DigitalState" ) return new StructType { NativeType = type, VarName = varname, StructName = basicType };
if ( basicType == "AnalogState" ) return new StructType { NativeType = type, VarName = varname, StructName = basicType };
if ( basicType == "MotionState" ) return new StructType { NativeType = type, VarName = varname, StructName = basicType };
if ( basicType == "NetMsg" ) return new StructType { NativeType = type, VarName = varname, StructName = basicType };
if ( basicType == "NetKeyValue" ) return new StructType { NativeType = type, VarName = varname, StructName = basicType };
if ( basicType == "SteamIPAddress" ) return new StructType { NativeType = type, VarName = varname, StructName = basicType };
if ( basicType.StartsWith( "E" ) && char.IsUpper( basicType[1] ) ) return new EnumType { NativeType = type.Substring( 1 ), VarName = varname };
if ( basicType.EndsWith( "_t" ) ) return new StructType { NativeType = type, VarName = varname, StructName = basicType };
//
// Enum types are handled in a generic way, but we do need to clean up the name
//
if ( Generator.CodeWriter.Current.IsEnum( basicType ) )
{
return new BaseType { NativeType = Cleanup.CleanEnum( type ), VarName = varname };
}
//
// Structs are generally sent as plain old data, but need marshalling if they're expected as a pointer
//
if ( Generator.CodeWriter.Current.IsStruct( basicType ) )
{
return new StructType { NativeType = type, VarName = varname, StructName = basicType };
}
//
// c# doesn't really have typerdefs, so we convert things like HSteamUser into structs
// which from a memory point of view behave in the same way.
//
if ( Generator.CodeWriter.Current.IsTypeDef( basicType ) )
{
return new StructType { NativeType = type, VarName = varname, StructName = basicType };
}
return new BaseType { NativeType = type, VarName = varname };
}
@ -123,85 +126,6 @@ public virtual bool IsVector
public virtual bool IsVoid => false;
public virtual bool IsReturnedWeird => false;
}
internal class BoolType : BaseType
{
public override string TypeName => $"bool";
public override string AsArgument() => $"[MarshalAs( UnmanagedType.U1 )] {Ref}{TypeName} {VarName}";
public override string ReturnAttribute => "[return: MarshalAs( UnmanagedType.I1 )]";
}
internal class StructType : BaseType
{
public string StructName;
public override string TypeName => StructName;
public override string TypeNameFrom => NativeType.EndsWith( "*" ) ? "IntPtr" : base.ReturnType;
public override string Return( string varname )
{
if ( NativeType.EndsWith( "*" ) )
{
return $"return ({TypeName}) Marshal.PtrToStructure( {varname}, typeof( {TypeName} ) );";
}
return base.Return( varname );
}
public override bool WindowsSpecific
{
get
{
var s = Generator.Program.Definitions.structs.FirstOrDefault( x => x.Name == StructName );
if ( s == null ) return false;
return !s.IsPack4OnWindows;
}
}
static string[] SpecialTypes = new string[]
{
"DigitalState",
"AnalogState",
"MotionState",
};
public override bool IsReturnedWeird => SpecialTypes.Contains( StructName );
}
internal class SteamApiCallType : BaseType
{
public string CallResult;
public override string TypeName => "SteamAPICall_t";
public override string Return( string varname )
{
if ( !string.IsNullOrEmpty( CallResult ) )
return $"return new CallResult<{CallResult}>( {varname} );";
return $"return new CallResult( {varname} );";
}
public override string ReturnType
{
get
{
if ( !string.IsNullOrEmpty( CallResult ) )
return $"CallResult<{CallResult}>";
return $"CallResult";
}
}
}
internal class CSteamIdType : BaseType
{
public override bool IsReturnedWeird => true;
}
internal class IntType : BaseType
@ -243,54 +167,3 @@ internal class LongType : BaseType
{
public override string TypeName => $"long";
}
internal class ConstCharType : BaseType
{
public override string TypeName => $"string";
public override string TypeNameFrom => $"Utf8StringPointer";
public override string AsArgument() => $"[MarshalAs( UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof( Utf8StringToNative ) )] {Ref}{TypeName} {VarName}";
public override string Ref => "";
}
internal class StringType : BaseType
{
public override string TypeName => $"string";
public override string AsArgument() => $"out string {VarName}";
public override string AsNativeArgument() => $"IntPtr {VarName}";
public override string AsCallArgument() => $"mem{VarName}";
public override string Ref => "";
}
internal class VoidType : BaseType
{
public override string TypeName => $"void";
public override string TypeNameFrom => $"void";
public override string Return( string varname ) => $"";
public override bool IsVoid => true;
}
internal class EnumType : BaseType
{
}
internal class ConstValueType : BaseType
{
private string Value;
BaseType basetype;
public ConstValueType( BaseType basetype, string value )
{
this.basetype = basetype;
this.Value = value;
}
public override bool ShouldSkipAsArgument => true;
public override string Ref => "";
public override bool IsVector => false;
public override string AsArgument() => basetype.AsArgument();
public override string AsCallArgument() => Value;
}

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
/// <summary>
/// Special care needs to be taken with bool types. Apparently BOOL in WINDOWS.H are 4 bytes.
/// But in reality and in native c++ they're 1 byte.
/// Of course marshalling by default expects them to be 4 bytes - because why not eh. So we have
/// to add a few attributes to make sure we don't get fucked over by bill gates again.
/// </summary>
internal class BoolType : BaseType
{
public override string TypeName => $"bool";
public override string AsArgument() => $"[MarshalAs( UnmanagedType.U1 )] {Ref}{TypeName} {VarName}";
public override string ReturnAttribute => "[return: MarshalAs( UnmanagedType.I1 )]";
}

View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
/// <summary>
/// To pass a string we use a custom marshaller (Utf8StringToNative) to convert it
/// from a utf8 string to a pointer. If we just pass it as a string it won't be utf8 encoded.
///
/// To receive we have a special struct called Utf8StringPointer which can implicitly change
/// the pointer to a utf8 string.
/// </summary>
internal class ConstCharType : BaseType
{
public override string TypeName => $"string";
public override string TypeNameFrom => $"Utf8StringPointer";
public override string AsArgument() => $"[MarshalAs( UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof( Utf8StringToNative ) )] {Ref}{TypeName} {VarName}";
public override string Ref => "";
}

View File

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
/// <summary>
/// Passes a pointer to a buffer as an argument, then converts
/// it into a string which is returned via an out param.
///
/// This is used of "char *" parameters which expect you to pass in
/// a buffer to retrieve the text. Usually \0 terminated.
/// </summary>
internal class FetchStringType : BaseType
{
public override string TypeName => $"string";
public override string AsArgument() => $"out string {VarName}";
public override string AsNativeArgument() => $"IntPtr {VarName}";
public override string AsCallArgument() => $"mem{VarName}";
public override string Ref => "";
}

View File

@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
/// <summary>
/// Used to replace a variable with a literal.
///
/// This is used when we can determine a parameter ourselves. For example
/// if you're passing a buffer and a paramter is the buffer length
/// </summary>
internal class LiteralType : BaseType
{
private string Value;
BaseType basetype;
public LiteralType( BaseType basetype, string value )
{
this.basetype = basetype;
this.Value = value;
}
public override bool ShouldSkipAsArgument => true;
public override string Ref => "";
public override bool IsVector => false;
public override string AsArgument() => basetype.AsArgument();
public override string AsCallArgument() => Value;
}

View File

@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
/// <summary>
/// Functions returning SteamAPICall_t are converted to be asyncronhous
/// and return a generic CallResult struct with the T of the result type.
/// </summary>
internal class SteamApiCallType : BaseType
{
public string CallResult;
public override string TypeName => "SteamAPICall_t";
public override string Return( string varname )
{
if ( !string.IsNullOrEmpty( CallResult ) )
return $"return new CallResult<{CallResult}>( {varname} );";
return $"return new CallResult( {varname} );";
}
public override string ReturnType
{
get
{
if ( !string.IsNullOrEmpty( CallResult ) )
return $"CallResult<{CallResult}>";
return $"CallResult";
}
}
}

View File

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
/// <summary>
/// The struct can be passed as a pointer or as plain old data.
/// If it's a pointer we need to marshal it back to our type
/// (this only happens in a couple of places in the sdk)
/// </summary>
internal class StructType : BaseType
{
public string StructName;
public override string TypeName => StructName;
public override string TypeNameFrom => NativeType.EndsWith( "*" ) ? "IntPtr" : base.ReturnType;
public override string Return( string varname )
{
if ( NativeType.EndsWith( "*" ) )
{
return $"return {varname}.ToType<{TypeName}>();";
}
return base.Return( varname );
}
}

View File

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
/// <summary>
/// Nothing - just priny void
/// </summary>
internal class VoidType : BaseType
{
public override string TypeName => $"void";
public override string TypeNameFrom => $"void";
public override string Return( string varname ) => "";
public override bool IsVoid => true;
}