Files
s&box team 71f266059a Open source release
This commit imports the C# engine code and game files, excluding C++ source code.

[Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
2025-11-24 09:05:18 +00:00

266 lines
7.2 KiB
C#

using Facepunch.InteropGen.Parsers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
namespace Facepunch.InteropGen;
public class Definition
{
[ThreadStatic]
public static Definition Current;
/// <summary>
/// The root folder
/// </summary>
public System.IO.DirectoryInfo Root { get; private set; }
public string Ident { get; internal set; } = "!!!NO IDENT!!!";
public string NativeDll { get; internal set; } = "!!!NO NativeDll!!!";
public string InitFrom { get; internal set; } = "Native";
public string StringTools { get; internal set; } = "Sandbox.Interop";
public string Filename { get; private set; }
public string ExceptionHandlerName { get; internal set; }
public string SaveFileCpp { get; internal set; }
public string SaveFileCppH { get; internal set; }
public string SaveFileCs { get; internal set; }
public string ManagedNamespace { get; internal set; } = "ManagedNamespace";
public string PrecompiledHeader { get; set; }
public string FullText { get; set; }
public int Hash { get; private set; }
public string CustomNamespace => SaveFileCs.Replace( ".cs", "Internal" ).Replace( ".", "" ).Replace( "/", "" );
public List<Class> Classes = [];
public List<Struct> Structs = [];
public List<string> Includes = [];
public List<string> CppIncludes = [];
public List<string> Externs = [];
public List<string> FunctionPointers = [];
public List<string> Delegates = [];
public List<Definition> IncludedDefinitions = [];
public List<Definition> SkipDefines = [];
public List<Definition> SkipAll = [];
public static Definition FromFile( string filename )
{
string folder = System.IO.Path.GetDirectoryName( filename );
if ( string.IsNullOrEmpty( folder ) )
{
folder = ".";
}
// Log.WriteLine( $"Reading {filename}" );
string text = System.IO.File.ReadAllText( filename );
Definition d = new()
{
Filename = System.IO.Path.GetFileName( filename ),
Root = new System.IO.DirectoryInfo( folder )
};
Current = d;
// Log.WriteLine( $"Parsing {filename}" );
d.ParseFrom( text );
// Log.WriteLine( $"Completing definition" );
d.CompleteDefinition();
// Log.WriteLine( $"Sorting" );
d.Sort();
// Log.WriteLine( $"Mangling" );
Mangler mangler = new();
mangler.Mangle( d.Classes );
d.GenerateHash();
return d;
}
private void ParseFrom( string text )
{
FullText = "";
GlobalParser parser = new();
parser.Parse( this, text, System.IO.Path.Combine( Root.FullName, Filename ) );
}
private void GenerateHash()
{
using MD5 md5 = MD5.Create();
md5.Initialize();
_ = md5.ComputeHash( Encoding.UTF8.GetBytes( FullText ) );
Hash = BitConverter.ToUInt16( md5.Hash, 0 );
}
private void CompleteDefinition()
{
foreach ( Class c in Classes )
{
c.ClassIdent = FastHash( c.ManagedNameWithNamespace );
//
// This class has a baseclass, find the actual class and set it.
//
if ( !string.IsNullOrWhiteSpace( c.BaseClassName ) )
{
c.BaseClass = Classes.FirstOrDefault( x => x.ManagedNameWithNamespace == c.BaseClassName );
c.BaseClass ??= Classes.SingleOrDefault( x => x.ManagedName == c.BaseClassName );
if ( c.BaseClass == null )
{
throw new Exception( $"{c.ManagedNameWithNamespace} has unknown baseclass: {c.BaseClassName}" );
}
}
Class baseclass = c.BaseClass;
while ( baseclass != null )
{
c.ClassDepth++;
c.Functions.AddRange( baseclass.Functions.Where( x => !x.Static ) );
baseclass = baseclass.BaseClass;
}
//
// Fix the functions up
//
foreach ( Function f in c.Functions )
{
try
{
f.Return = TryFixArg( f.Return );
for ( int i = 0; i < f.Parameters.Length; i++ )
{
f.Parameters[i] = TryFixArg( f.Parameters[i] );
}
}
catch ( System.Exception e )
{
Log.Warning( $"[{e.Message}] in {c.ManagedNameWithNamespace}.{f.Name}" );
throw new Exception( $"Unhandled Type [{e.Message}] in {c.ManagedNameWithNamespace}.{f.Name}" );
}
}
//
// Fix the variables up
//
foreach ( Variable f in c.Variables )
{
try
{
f.Return = TryFixArg( f.Return );
}
catch ( System.Exception e )
{
Log.Warning( $"[{e.Message}] in {c.ManagedNameWithNamespace}.{f.Name}" );
throw new Exception( "Unhandled Type" );
}
}
}
foreach ( Class c in Classes )
{
c.Functions = c.Functions.Distinct().Select( x => x.Copy() ).ToList();
c.Children = Classes.Where( x => x.DerivesFrom( c ) ).ToList();
}
}
private Arg TryFixArg( Arg arg )
{
if ( arg is ArgUnknown au )
{
Class c = Classes.SingleOrDefault( x => x.ManagedNameWithNamespace == au.Type );
if ( c != null && c.Native )
{
return ClassArgument( au, c );
}
if ( c != null && !c.Native )
{
return au.Wrap( new ArgManagedClass( c, au.Name, au.Flags ) );
}
Struct s = Structs.SingleOrDefault( x => x.ManagedNameWithNamespace == au.Type );
if ( s != null )
{
return au.Wrap( s.IsEnum ? new ArgEnum( s, au.Name ) : new ArgDefinedStruct( s, au.Name, au.Flags ) );
}
c = Classes.SingleOrDefault( x => x.ManagedName == au.Type );
if ( c != null && c.Native )
{
return ClassArgument( au, c );
}
if ( c != null && !c.Native )
{
return au.Wrap( new ArgManagedClass( c, au.Name, au.Flags ) );
}
s = Structs.SingleOrDefault( x => x.ManagedName == au.Type || x.NativeNameWithNamespace == au.Type || x.NativeName == au.Type );
return s != null
? au.Wrap( s.IsEnum ? new ArgEnum( s, au.Name ) : new ArgDefinedStruct( s, au.Name, au.Flags ) )
: FunctionPointers.Contains( au.Type )
? au.Wrap( new ArgFunctionPointer( au.Type, au.Name, au.Flags ) )
: Delegates.Contains( au.Type )
? au.Wrap( new ArgDelegate( au.Type, au.Name, au.Flags ) )
: throw new System.Exception( $"Unknown Type {au.Type}" );
}
return arg;
}
private Arg ClassArgument( ArgUnknown au, Class c )
{
return c.HasAttribute( "SharedDataPointer" )
? au.Wrap( new ArgSharedDataPointer( c, au.Name, au.Flags ) )
: au.Wrap( new ArgDefinedClass( c, au.Name, au.Flags ) );
}
private void Sort()
{
Structs = Structs.OrderBy( x => x.NativeName ).ToList();
Classes = Classes.OrderBy( x => x.NativeNameWithNamespace ).ToList();
foreach ( Class c in Classes )
{
c.Functions = c.Functions.OrderBy( x => x.MangledName ).ToList();
}
}
public bool IsIncluded( Class c )
{
return IncludedDefinitions.Any( x => x.Classes.Any( y => y.ManagedNameWithNamespace == c.ManagedNameWithNamespace && y.NativeNameWithNamespace == c.NativeNameWithNamespace ) );
}
public bool IsIncluded( Struct s )
{
return IncludedDefinitions.Any( x => x.Structs.Any( y => y.ManagedNameWithNamespace == s.ManagedNameWithNamespace && y.NativeNameWithNamespace == s.NativeNameWithNamespace ) );
}
public bool isRebind( Class c )
{
return SkipDefines.Any( x => x.Classes.Any( y => y.ManagedNameWithNamespace == c.ManagedNameWithNamespace && y.NativeNameWithNamespace == c.NativeNameWithNamespace ) );
}
public static int FastHash( string str )
{
// FNV-1a hash
uint hash = 0x811C9DC5;
byte[] data = Encoding.Unicode.GetBytes( str );
foreach ( byte b in data )
{
hash ^= b;
hash *= 0x1000193;
}
return unchecked((int)hash);
}
}