Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

+ Added custom marshalling for pointers to OmsiObject and arrays of … #4

Merged
merged 1 commit into from
Apr 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion OmsiExtensionsCLI/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ static void Main(string[] args)
var pos = omsi.PlayerVehicle.Position;
var map = omsi.Map;
var weather = omsi.Weather;
var water = map.Water_Matl;
var ticketPack = omsi.TicketPack;

Console.WriteLine($"Read data: x:{pos.x:F3}\ty:{pos.y:F3}\tz:{pos.z:F3}\t\t" +
$"tile:{0}\trow45:{0:F3}\trow47:{0:F3}");
Expand Down
84 changes: 84 additions & 0 deletions OmsiHook/CustomAttributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,88 @@ sealed class OmsiPtrAttribute : Attribute
{

}

/// <summary>
/// Marks a field to be converted from an int to an OmsiObject.<para/>
/// Used by Memory.MarshalStruct()
/// </summary>
[System.AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
sealed class OmsiObjPtrAttribute : Attribute
{
// See the attribute guidelines at
// http://go.microsoft.com/fwlink/?LinkId=85236
readonly Type objType;

// This is a positional argument
public OmsiObjPtrAttribute(Type objType)
{
if (!objType.IsSubclassOf(typeof(OmsiObject)))
throw new ArgumentException("OmsiObjPtr must be a pointer to an object deriving from " + nameof(OmsiObject) + "!");

this.objType = objType;
}

public Type ObjType => objType;
}

/// <summary>
/// Marks a field to be converted from an int to an OmsiObject[].<para/>
/// Used by Memory.MarshalStruct()
/// </summary>
[System.AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
sealed class OmsiObjArrayPtrAttribute : Attribute
{
// See the attribute guidelines at
// http://go.microsoft.com/fwlink/?LinkId=85236
readonly Type objType;

// This is a positional argument
public OmsiObjArrayPtrAttribute(Type objType)
{
if (objType.IsSubclassOf(typeof(OmsiObject)))
throw new ArgumentException("OmsiObjArrayPtr must be a pointer to an object deriving from " + nameof(OmsiObject) + "!");

this.objType = objType;
}

public Type ObjType => objType;
}

/// <summary>
/// Marks a field to be converted from an int to an OmsiObject[].<para/>
/// Used by Memory.MarshalStruct()
/// </summary>
[System.AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
sealed class OmsiStructArrayPtrAttribute : Attribute
{
// See the attribute guidelines at
// http://go.microsoft.com/fwlink/?LinkId=85236
readonly Type objType;
readonly Type internalType;
readonly bool requiresExtraMarshalling;

// This is a positional argument
/// <summary>
///
/// </summary>
/// <param name="objType">The type of the object to convert to</param>
/// <param name="internalType">The intermidiate type to convert through
/// (in case Marshal.PtrToStruct doesn't support all the fields in objType).
/// Leave null to default to objType</param>
public OmsiStructArrayPtrAttribute(Type objType, Type internalType = null)
{
if (!objType.IsValueType)
throw new ArgumentException("OmsiStructArrayPtr must be a pointer to a struct/value!");
if ((!internalType?.IsValueType) ?? false)
throw new ArgumentException("OmsiStructArrayPtr must be a pointer to a struct/value!");

this.objType = objType;
this.requiresExtraMarshalling = internalType != null;
this.internalType = internalType ?? objType;
}

public Type ObjType => objType;
public Type InternalType => internalType;
public bool RequiresExtraMarshalling => requiresExtraMarshalling;
}
}
8 changes: 8 additions & 0 deletions OmsiHook/D3DMeshFileObject.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace OmsiHook
{
public class D3DMeshFileObject : D3DMeshObject
{
internal D3DMeshFileObject(Memory omsiMemory, int baseAddress) : base(omsiMemory, baseAddress) { }
internal D3DMeshFileObject() : base() { }
}
}
8 changes: 8 additions & 0 deletions OmsiHook/D3DMeshObject.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace OmsiHook
{
public class D3DMeshObject : D3DTransformObject
{
internal D3DMeshObject(Memory omsiMemory, int baseAddress) : base(omsiMemory, baseAddress) { }
internal D3DMeshObject() : base() { }
}
}
8 changes: 8 additions & 0 deletions OmsiHook/D3DObject.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace OmsiHook
{
public class D3DObject : OmsiObject
{
internal D3DObject(Memory omsiMemory, int baseAddress) : base(omsiMemory, baseAddress) { }
internal D3DObject() : base() { }
}
}
8 changes: 8 additions & 0 deletions OmsiHook/D3DTransformObject.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace OmsiHook
{
public class D3DTransformObject : D3DObject
{
internal D3DTransformObject(Memory omsiMemory, int baseAddress) : base(omsiMemory, baseAddress) { }
internal D3DTransformObject() : base() { }
}
}
36 changes: 31 additions & 5 deletions OmsiHook/Memory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -223,19 +223,45 @@ public OutStruct MarshalStruct<OutStruct, InStruct>(InStruct obj)
foreach (var field in obj.GetType().GetFields())
{
object val = field.GetValue(obj);
foreach (var attr in field.CustomAttributes)
foreach (var attr in field.GetCustomAttributes(false))
{
switch (attr.AttributeType.Name)
// Based on which kind of attribute the field has, perform special marshalling operations
switch (attr)
{
case nameof(OmsiStrPtrAttribute):
val = ReadMemoryString((int)val, (bool)attr.ConstructorArguments[0].Value);
case OmsiStrPtrAttribute a:
val = ReadMemoryString((int)val, a.Wide);
break;
case nameof(OmsiPtrAttribute):

case OmsiPtrAttribute:
val = new IntPtr((int)val);
break;

case OmsiObjPtrAttribute a:
int addr = (int)val;
val = Activator.CreateInstance(a.ObjType, true);
((OmsiObject)val).InitObject(this, addr);
break;

case OmsiStructArrayPtrAttribute a:
val = typeof(Memory).GetMethod(nameof(ReadMemoryStructArray))
.MakeGenericMethod(a.InternalType)
.Invoke(this, new object[] { val });
// Perform extra marshalling if needed
if(a.RequiresExtraMarshalling)
val = typeof(Memory).GetMethod(nameof(MarshalStructs))
.MakeGenericMethod(a.ObjType, a.InternalType)
.Invoke(this, new object[] { val });
break;

case OmsiObjArrayPtrAttribute a:
val = typeof(Memory).GetMethod(nameof(ReadMemoryObjArray))
.MakeGenericMethod(a.ObjType)
.Invoke(this, new object[] { val });
break;
}
}

// Match fields by name, setting the destination fields to the corresponding source fields
typeof(OutStruct).GetField(field.Name).SetValue(ret, val);
}

Expand Down
2 changes: 2 additions & 0 deletions OmsiHook/OmsiHook.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ public class OmsiHook
public int PlayerVehicleIndex => omsiMemory.ReadMemory<int>(0x00861740);
public OmsiWeather Weather => new(omsiMemory, omsiMemory.ReadMemory<int>(0x008617D0));
public OmsiMap Map => new(omsiMemory, omsiMemory.ReadMemory<int>(0x861588));
public OmsiTicketPack TicketPack => omsiMemory.MarshalStruct<OmsiTicketPack, OmsiTicketPackInternal>(
omsiMemory.ReadMemory<OmsiTicketPackInternal>(0x008611fc));

/// <summary>
/// Attaches the hooking application to OMSI.exe.
Expand Down
18 changes: 17 additions & 1 deletion OmsiHook/OmsiMap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,22 @@ public bool Tile_Aerial_Visible
set => Memory.WriteMemory(Address + 0x184, value);
}

//TODO: Many more...
public int GridTexture
{
get => Memory.ReadMemory<int>(Address + 0x188);
set => Memory.WriteMemory(Address + 0x188, value);
}

public float WellenAnimation
{
get => Memory.ReadMemory<float>(Address + 0x18c);
set => Memory.WriteMemory(Address + 0x18c, value);
}

/*public float[] WellenAnimation_P
{
get => Memory.ReadMemoryStructArray<float>(Address + 0x184);
set => Memory.WriteMemory(Address + 0x184, value);
}*/
}
}
52 changes: 50 additions & 2 deletions OmsiHook/OmsiStructs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -279,15 +279,15 @@ public struct OmsiWeatherProp
public bool schneeAufStrassen;
}

internal struct CloudTypeInternal
internal struct OmsiCloudTypeInternal
{
[OmsiStrPtr] public int name; // ANSI String
[OmsiStrPtr] public int texFile; // ANSI String
public float texSize;
public bool ovc;
}

public struct CloudType
public struct OmsiCloudType
{
public string name; // ANSI String
public string texFile; // ANSI String
Expand All @@ -297,4 +297,52 @@ public struct CloudType
/// </summary>
public bool ovc;
}

public struct OmsiTicketPackInternal
{
[OmsiStrPtr] public int filename;
[OmsiStrPtr(true)] public int voicepath;
[OmsiStructArrayPtr(typeof(OmsiTicket), typeof(OmsiTicketInternal))]
public int tickets;
public float stamper_prop;
public float ticketBuy_prop;
public float chattiness;
public float whinge_prop;
}

public struct OmsiTicketPack
{
public string filename;
public string voicepath;
public OmsiTicket[] tickets;
public float stamper_prop;
public float ticketBuy_prop;
public float chattiness;
public float whinge_prop;
}

public struct OmsiTicketInternal
{
//TODO: I don't think these are decoding correctly (I saw nothing when I looked), check this actually works.
[OmsiStrPtr] public int name, name_english, name_display;
public int max_stations;
public int age_min, age_max;
public float value;
public bool dayTicket;
public float propability;
[OmsiObjPtr(typeof(D3DMeshFileObject))] public int mesh_block;
[OmsiObjPtr(typeof(D3DMeshFileObject))] public int mesh_single;
}

public struct OmsiTicket
{
public string name, name_english, name_display;
public int max_stations;
public int age_min, age_max;
public float value;
public bool dayTicket;
public float propability;
public D3DMeshFileObject mesh_block;
public D3DMeshFileObject mesh_single;
}
}