Skip to content

Commit

Permalink
Improved string marshalling:
Browse files Browse the repository at this point in the history
 - Added StrPtrType enum to specify how strings are marshalled as an alternative to using the separate boolean flags
 - OmsiStrArrayPtrAttribute now supports pascal strings
 - Fixed bug when reading wide pascal strings
 - Fixed some struct definitions
  • Loading branch information
space928 committed Oct 24, 2023
1 parent 775ae45 commit 2f6febd
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 49 deletions.
5 changes: 2 additions & 3 deletions OmsiExtensionsCLI/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,8 @@ static void Main(string[] args)
Console.WriteLine($"{omsi.Globals.PlayerVehicle.PAI_LastBrake} {omsi.Globals.PlayerVehicle.Bremspedal}".PadRight(Console.WindowWidth - 1));
Console.WriteLine($"{omsi.Globals.Time.Day}/{omsi.Globals.Time.Month}/{omsi.Globals.Time.Year} - {omsi.Globals.Time.Hour}:{omsi.Globals.Time.Minute}:{omsi.Globals.Time.Second:F2}");
Console.WriteLine($"Camera data: x:{omsi.Globals.Camera.Pos.x:F3} y:{omsi.Globals.Camera.Pos.y:F3} z:{omsi.Globals.Camera.Pos.z:F3} ".PadRight(Console.WindowWidth - 1));
/*Console.WriteLine(($"Camera2 data: x:{omsi.Globals.Camera2.Pos.x:F3} y:{omsi.Globals.Camera2.Pos.y:F3} z:{omsi.Globals.Camera2.Pos.z:F3} ").PadRight(Console.WindowWidth - 1));
Console.WriteLine(($"Camera3 data: x:{omsi.Globals.Camera3.Pos.x:F3} y:{omsi.Globals.Camera3.Pos.y:F3} z:{omsi.Globals.Camera3.Pos.z:F3} ").PadRight(Console.WindowWidth - 1));
Console.WriteLine(($"Camera4 data: x:{omsi.Globals.Camera4.Pos.x:F3} y:{omsi.Globals.Camera4.Pos.y:F3} z:{omsi.Globals.Camera4.Pos.z:F3} ").PadRight(Console.WindowWidth - 1));*/
Console.WriteLine($"{omsi.Globals.Drivers}".PadRight(Console.WindowWidth - 1));

Console.WriteLine("".PadRight(Console.WindowWidth-1));
try
{
Expand Down
76 changes: 71 additions & 5 deletions OmsiHook/CustomAttributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,24 +57,37 @@ sealed class OmsiStrPtrAttribute : OmsiMarshallerAttribute
// http://go.microsoft.com/fwlink/?LinkId=85236
readonly bool wide;
readonly bool raw;
readonly bool lengthPrefixed;
readonly bool pascal;

/// <summary>
///
/// </summary>
/// <param name="wide">Whether or not to decode the string as UTF-16.</param>
/// <param name="raw">Treat the address as a pointer to the first character
/// (<c>char *</c>) rather than a pointer to a pointer.</param>
public OmsiStrPtrAttribute(bool wide = false, bool raw = false, bool lengthPrefixed = false)
/// <param name="pascal">Whether the string can be treated as a length prefixed (pascal)
/// string, which is much faster to read</param>
public OmsiStrPtrAttribute(bool wide = false, bool raw = false, bool pascal = true)
{
this.wide = wide;
this.raw = raw;
this.lengthPrefixed = lengthPrefixed;
this.pascal = pascal;
}

/// <summary>
///
/// </summary>
/// <param name="strType">Flags specifying how to decode the string.</param>
public OmsiStrPtrAttribute(StrPtrType strType)
{
this.wide = (strType & StrPtrType.Wide) != 0;
this.raw = (strType & StrPtrType.Raw) != 0;
this.pascal = (strType & StrPtrType.Pascal) != 0;
}

public bool Wide => wide;
public bool Raw => raw;
public bool LengthPrefixed => lengthPrefixed;
public bool Pascal => pascal;
}

/// <summary>
Expand Down Expand Up @@ -221,20 +234,73 @@ sealed class OmsiStrArrayPtrAttribute : OmsiMarshallerAttribute
// http://go.microsoft.com/fwlink/?LinkId=85236
readonly bool wide;
readonly bool raw;
readonly bool pascal;

/// <summary>
///
/// </summary>
/// <param name="wide"></param>
/// <param name="raw">If <see langword="true"/>, treat the <c>address</c> as the pointer to the first element
/// of the array instead of as a pointer to the array.</param>
public OmsiStrArrayPtrAttribute(bool wide = false, bool raw = false)
/// <param name="pascal">Whether the string can be treated as a length prefixed (pascal)
/// string, which is much faster to read</param>
public OmsiStrArrayPtrAttribute(bool wide = false, bool raw = false, bool pascal = false)
{
this.wide = wide;
this.raw = raw;
this.pascal = pascal;
}

/// <summary>
///
/// </summary>
/// <param name="strType">Flags specifying how to decode the string.</param>
public OmsiStrArrayPtrAttribute(StrPtrType strType)
{
this.wide = (strType & StrPtrType.Wide) != 0;
this.raw = (strType & StrPtrType.Raw) != 0;
this.pascal = (strType & StrPtrType.Pascal) != 0;
}

public bool Wide => wide;
public bool Raw => raw;
public bool Pascal => pascal;
}

/// <summary>
/// An enum specifying how a string pointer should be marshalled.
/// </summary>
[Flags]
public enum StrPtrType
{
/// <summary>
/// Indicates the value points to a standard UTF-8/System code page, null-terminated string
/// </summary>
PCStr = 0,
/// <summary>
/// Indicates the string is encoded in UTF-16
/// </summary>
Wide = 1 << 0,
/// <summary>
/// Indicates the value points directly to start of the string (as opposed to being a pointer to a pointer).
/// </summary>
Raw = 1 << 1,
/// <summary>
/// Indicates the string is
/// </summary>
Pascal = 1 << 2,

/// <summary>
/// The default for most strings in Omsi.
/// </summary>
DelphiString = Wide | Pascal,
/// <summary>
/// The default for most AnsiStrings in Omsi.
/// </summary>
DelphiAnsiString = Pascal,
/// <summary>
/// The default for most strings in arrays in Omsi.
/// </summary>
RawDelphiString = Wide | Pascal | Raw,
}
}
28 changes: 24 additions & 4 deletions OmsiHook/Memory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -387,12 +387,28 @@ public T ReadMemory<T>(int address) where T : unmanaged
return ByteArrayToStructure<T>(readBuffer);
}

/// <summary>
/// Returns the value of a null terminated/length prefixed string at a given address.
/// </summary>
/// <param name="address">The address to read from</param>
/// <param name="strType">Flags specifying how to decode the string.</param>
/// <returns>The value of the string at the given address.</returns>
public string ReadMemoryString(int address, StrPtrType strType)
{
return ReadMemoryString(address,
(strType & StrPtrType.Wide) != 0,
(strType & StrPtrType.Raw) != 0,
(strType & StrPtrType.Pascal) != 0);
}

/// <summary>
/// Returns the value of a null terminated/length prefixed string at a given address.
/// </summary>
/// <param name="address">The address to read from</param>
/// <param name="raw">Treat the address as a pointer to the first character
/// (<c>char *</c>) rather than a pointer to a pointer.</param>
/// <param name="pascalString">Whether the string can be treated as a length prefixed (pascal)
/// string, which is much faster to read</param>
/// <returns>The value of the string at the given address.</returns>
public string ReadMemoryString(int address, bool wide = false, bool raw = false, bool pascalString = true)
{
Expand All @@ -407,6 +423,8 @@ public string ReadMemoryString(int address, bool wide = false, bool raw = false,
if (pascalString)
{
int strLen = ReadMemory<int>(i - 4);
if(wide)
strLen *= 2;
var bytes = ReadMemory(i, strLen, readBuffer);
sb.Append(wide ? Encoding.Unicode.GetString(bytes) : Encoding.ASCII.GetString(bytes));
}
Expand Down Expand Up @@ -619,8 +637,10 @@ public T[] ReadMemoryStructPtrArray<T>(int address) where T : unmanaged
/// <param name="address">The address of the array to read from</param>
/// <param name="raw">If <see langword="true"/>, treat the <c>address</c> as the pointer to the first element
/// of the array instead of as a pointer to the array.</param>
/// <param name="pascal">Whether the string can be treated as a length prefixed (pascal)
/// string, which is much faster to read</param>
/// <returns>The parsed array of strings.</returns>
public string[] ReadMemoryStringArray(int address, bool wide = false, bool raw = false)
public string[] ReadMemoryStringArray(int address, bool wide = false, bool raw = false, bool pascal = true)
{
int arr = address;
if (!raw)
Expand All @@ -630,7 +650,7 @@ public string[] ReadMemoryStringArray(int address, bool wide = false, bool raw =
int len = ReadMemory<int>(arr - 4);
string[] ret = new string[len];
for (int i = 0; i < len; i++)
ret[i] = ReadMemoryString(arr + i * 4, wide);
ret[i] = ReadMemoryString(arr + i * 4, wide, raw:false, pascal);

return ret;
}
Expand Down Expand Up @@ -716,7 +736,7 @@ public OutStruct MarshalStruct<OutStruct, InStruct>(InStruct obj)
break;

case OmsiStrPtrAttribute a:
val = ReadMemoryString((int)val, a.Wide, a.Raw, a.LengthPrefixed);
val = ReadMemoryString((int)val, a.Wide, a.Raw, a.Pascal);
break;

case OmsiPtrAttribute:
Expand Down Expand Up @@ -766,7 +786,7 @@ public OutStruct MarshalStruct<OutStruct, InStruct>(InStruct obj)
break;

case OmsiStrArrayPtrAttribute a:
val = ReadMemoryStringArray((int)val, a.Wide, a.Raw);
val = ReadMemoryStringArray((int)val, a.Wide, a.Raw, a.Pascal);
break;

case OmsiMarshallerAttribute a:
Expand Down
78 changes: 41 additions & 37 deletions OmsiHook/OmsiStructs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -349,8 +349,8 @@ internal struct OmsiTicketPackInternal
{
[OmsiStrPtr(raw:true)] public int filename;
[OmsiStrPtr(true, raw:true)] public int voicepath;
//[OmsiStructArrayPtr(typeof(OmsiTicket), typeof(OmsiTicketInternal))]
[OmsiPtr]
[OmsiStructArrayPtr(typeof(OmsiTicket), typeof(OmsiTicketInternal))]
//[OmsiPtr]
public int tickets;
public float stamper_prop;
public float ticketBuy_prop;
Expand All @@ -362,25 +362,29 @@ public struct OmsiTicketPack
{
public string filename;
public string voicepath;
//public OmsiTicket[] tickets;
public IntPtr tickets;
public OmsiTicket[] tickets;
//public IntPtr tickets;
public float stamper_prop;
public float ticketBuy_prop;
public float chattiness;
public float whinge_prop;
}

[StructLayout(LayoutKind.Explicit, Size = 0x2c)]
internal struct OmsiTicketInternal
{
//TODO: I don't think these are decoding correctly (I saw nothing when I looked), check this actually works.
[OmsiStrPtr(raw:true)] 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;
[FieldOffset(0x0)] [OmsiStrPtr(StrPtrType.Raw)] public int name;
[FieldOffset(0x4)] [OmsiStrPtr(StrPtrType.Raw)] public int name_english;
[FieldOffset(0x8)] [OmsiStrPtr(StrPtrType.Raw)] public int name_display;
[FieldOffset(0xc)] public int max_stations;
[FieldOffset(0x10)] public int age_min;
[FieldOffset(0x14)] public int age_max;
[FieldOffset(0x18)] public float value;
[FieldOffset(0x1c)] public bool dayTicket;
[FieldOffset(0x20)] public float propability;
[FieldOffset(0x24)] [OmsiObjPtr(typeof(D3DMeshFileObject))] public int mesh_block;
[FieldOffset(0x28)] [OmsiObjPtr(typeof(D3DMeshFileObject))] public int mesh_single;
}

public struct OmsiTicket
Expand Down Expand Up @@ -584,7 +588,7 @@ public struct OmsiAIGroupTypeNumber
internal struct OmsiHolidayInternal
{
public int date;
[OmsiStrPtr] public int name;
[OmsiStrPtr(StrPtrType.DelphiString)] public int name;
}

public struct OmsiHoliday
Expand All @@ -596,7 +600,7 @@ public struct OmsiHoliday
internal struct OmsiHolidaysInternal
{
public int start, ende;
[OmsiStrPtr] public int name;
[OmsiStrPtr(StrPtrType.DelphiString)] public int name;
}

public struct OmsiHolidays
Expand Down Expand Up @@ -1277,7 +1281,7 @@ public struct OmsiPerbus
}
internal struct OmsiPerbusInternal
{
[OmsiStrPtr] public int busname;
[OmsiStrPtr(StrPtrType.PCStr)] public int busname;
public uint hektometer;
}

Expand Down Expand Up @@ -1306,30 +1310,30 @@ public struct OmsiDriver
public OmsiPerbus[] perbus;
}

[StructLayout(LayoutKind.Explicit, Size = 0x68)]
internal struct OmsiDriverInternal
{
[OmsiStrPtr] public int filename;
[OmsiStrPtr] public int name;
public bool gender;
public double birthday;
public double dateOfHire;
public uint cnt_busstop_all;
public uint cnt_busstop_late;
public uint cnt_busstop_early;
public uint hektometer_all;
public uint cnt_crashs;
public uint cnt_hitandrun;
public uint cnt_hitandrun_heavy;
public uint crashes_ped;
public double bew_fahrstill; // These look like driver raitings
public uint bew_passcomfort;
public uint bew_ticket_count;
public uint bew_ticket_points;
public uint passCount;
public uint ticket_cnt;
public float tickets_cash;
[OmsiStructArrayPtr(typeof(OmsiPerbus),typeof(OmsiPerbusInternal))] public int perbus;

[FieldOffset(0x0)][OmsiStrPtr(StrPtrType.RawDelphiString)] public int filename;
[FieldOffset(0x4)][OmsiStrPtr(StrPtrType.RawDelphiString)] public int name;
[FieldOffset(0x8)] public bool gender;
[FieldOffset(0x10)] public double birthday;
[FieldOffset(0x18)] public double dateOfHire;
[FieldOffset(0x20)] public uint cnt_busstop_all;
[FieldOffset(0x24)] public uint cnt_busstop_late;
[FieldOffset(0x28)] public uint cnt_busstop_early;
[FieldOffset(0x2c)] public uint hektometer_all;
[FieldOffset(0x30)] public uint cnt_crashs;
[FieldOffset(0x34)] public uint cnt_hitandrun;
[FieldOffset(0x38)] public uint cnt_hitandrun_heavy;
[FieldOffset(0x3c)] public uint crashes_ped;
[FieldOffset(0x40)] public double bew_fahrstill; // These look like driver raitings
[FieldOffset(0x48)] public uint bew_passcomfort;
[FieldOffset(0x4c)] public uint bew_ticket_count;
[FieldOffset(0x50)] public uint bew_ticket_points;
[FieldOffset(0x54)] public uint passCount;
[FieldOffset(0x58)] public uint ticket_cnt;
[FieldOffset(0x5c)] public float tickets_cash;
[FieldOffset(0x60)][OmsiStructArrayPtr(typeof(OmsiPerbus),typeof(OmsiPerbusInternal))] public int perbus;
}
public struct OmsiTTLogDetailed
{
Expand Down

0 comments on commit 2f6febd

Please sign in to comment.