aboutsummaryrefslogtreecommitdiff
path: root/NorthstarDLL/structs.h
diff options
context:
space:
mode:
authorEmma Miler <emma.pi@protonmail.com>2022-11-14 01:11:59 +0100
committerGitHub <noreply@github.com>2022-11-14 00:11:59 +0000
commit0c6d1f4e79d31de6fde4979a72afacdd6d13ca60 (patch)
tree06a9f21b76ac94d8ee11cf109ea3a32ac584982c /NorthstarDLL/structs.h
parent2139e0ec6d95ed7c5f673b53dec71f39a013dd93 (diff)
downloadNorthstarLauncher-0c6d1f4e79d31de6fde4979a72afacdd6d13ca60.tar.gz
NorthstarLauncher-0c6d1f4e79d31de6fde4979a72afacdd6d13ca60.zip
New syntax for reversed structs (#324)
* Initial commit Co-Authored-By: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> * Format change * Revert `VPKData` definition * Add `FIELDS` macro Co-authored-by: BobTheBob <32057864+BobTheBob9@users.noreply.github.com>
Diffstat (limited to 'NorthstarDLL/structs.h')
-rw-r--r--NorthstarDLL/structs.h63
1 files changed, 63 insertions, 0 deletions
diff --git a/NorthstarDLL/structs.h b/NorthstarDLL/structs.h
new file mode 100644
index 00000000..939fd302
--- /dev/null
+++ b/NorthstarDLL/structs.h
@@ -0,0 +1,63 @@
+#pragma once
+//clang-format off
+// About this file:
+// This file contains several macros used to define reversed structs
+// The reason we use these macros is to make it easier to update existing structs
+// when new fields are reversed
+// This means we dont have to manually add padding, and recalculate when updating
+
+// Technical note:
+// While functionally, these structs act like a regular struct, they are actually
+// defined as unions with anonymous structs in them.
+// This means that each field is essentially an offset into a union.
+// We acknowledge that this goes against C++'s active-member guideline for unions
+// However, this is not such a big deal here as these structs will not be constructed
+
+// Usage:
+// To use these macros, define a struct like so:
+/*
+OFFSET_STRUCT(Name)
+{
+ STRUCT_SIZE(0x100) // Total in-memory struct size
+ FIELD(0x0, int field) // offset, signature
+}
+*/
+
+#define OFFSET_STRUCT(name) union name
+#define STRUCT_SIZE(size) char __size[size];
+#define STRUCT_FIELD_OFFSET(offset, signature) \
+ struct \
+ { \
+ char CONCAT2(pad, __LINE__)[offset]; \
+ signature; \
+ };
+
+// Special case for a 0-offset field
+#define STRUCT_FIELD_NOOFFSET(offset, signature) signature;
+
+// Based on: https://stackoverflow.com/questions/11632219/c-preprocessor-macro-specialisation-based-on-an-argument
+// Yes, this is hacky, but it works quite well actually
+// This basically makes sure that when the offset is 0x0, no padding field gets generated
+#define OFFSET_0x0 ()
+
+#define IIF(c) CONCAT2(IIF_, c)
+#define IIF_0(t, ...) __VA_ARGS__
+#define IIF_1(t, ...) t
+
+#define PROBE(x) x, 1
+
+#define MSVC_VA_ARGS_WORKAROUND(define, args) define args
+#define CHECK(...) MSVC_VA_ARGS_WORKAROUND(CHECK_N, (__VA_ARGS__, 0))
+#define CHECK_N(x, n, ...) n
+
+#define DO_PROBE(offset) PROBE_PROXY(OFFSET_##offset) // concatenate prefix with offset
+#define PROBE_PROXY(...) PROBE_PRIMITIVE(__VA_ARGS__) // expand arguments
+#define PROBE_PRIMITIVE(x) PROBE_COMBINE_##x // merge
+#define PROBE_COMBINE_(...) PROBE(~) // if merge successful, expand to probe
+
+#define IS_0(offset) CHECK(DO_PROBE(offset))
+
+#define FIELD(offset, signature) IIF(IS_0(offset))(STRUCT_FIELD_NOOFFSET, STRUCT_FIELD_OFFSET)(offset, signature)
+#define FIELDS FIELD
+
+//clang-format on