diff --git a/pkNX.Structures/Scripts/AmxError.cs b/pkNX.Structures/Scripts/AmxError.cs
new file mode 100644
index 00000000..d95b24eb
--- /dev/null
+++ b/pkNX.Structures/Scripts/AmxError.cs
@@ -0,0 +1,35 @@
+namespace pkNX.Structures
+{
+ public enum AmxError
+ {
+ AMX_ERR_NONE,
+ /* reserve the first 15 error codes for exit codes of the abstract machine */
+ EXIT, /* forced exit */
+ ASSERT, /* assertion failed */
+ STACKERR, /* stack/heap collision */
+ BOUNDS, /* index out of bounds */
+ MEMACCESS, /* invalid memory access */
+ INVINSTR, /* invalid instruction */
+ STACKLOW, /* stack underflow */
+ HEAPLOW, /* heap underflow */
+ CALLBACK, /* no callback, or invalid callback */
+ NATIVE, /* native function failed */
+ DIVIDE, /* divide by zero */
+ SLEEP, /* go into sleepmode - code can be restarted */
+ INVSTATE, /* no implementation for this state, no fall-back */
+
+ MEMORY = 16, /* out of memory */
+ FORMAT, /* invalid file format */
+ VERSION, /* file is for a newer version of the AMX */
+ NOTFOUND, /* function not found */
+ INDEX, /* invalid index parameter (bad entry point) */
+ DEBUG, /* debugger cannot run */
+ INIT, /* AMX not initialized (or doubly initialized) */
+ USERDATA, /* unable to set user data field (table full) */
+ INIT_JIT, /* cannot initialize the JIT */
+ PARAMS, /* parameter error */
+ DOMAIN, /* domain error, expression result does not fit in range */
+ GENERAL, /* general error (unknown or unspecific error) */
+ OVERLAY, /* overlays are unsupported (JIT) or uninitialized */
+ }
+}
\ No newline at end of file
diff --git a/pkNX.Structures/Scripts/AmxFlags.cs b/pkNX.Structures/Scripts/AmxFlags.cs
new file mode 100644
index 00000000..5a2134ad
--- /dev/null
+++ b/pkNX.Structures/Scripts/AmxFlags.cs
@@ -0,0 +1,57 @@
+using System;
+
+namespace pkNX.Structures
+{
+ ///
+ /// Feature flags for the
+ ///
+ ///
+ /// Flag version listed here is for CUR_FILE_VERSION = 10, circa 2008
+ ///
+ [Flags]
+ public enum AmxFlags : short
+ {
+ NONE,
+
+ /// All function calls use overlays
+ OVERLAY = 0x01,
+
+ /// Symbolic info is available
+ DEBUG = 0x02,
+
+ /// Compact encoding
+ COMPACT = 0x04,
+
+ /// Script uses the sleep instruction (possible re-entry or power-down mode)
+ SLEEP = 0x08,
+
+ /// No array bounds checking; no BREAK opcodes
+ NOCHECKS = 0x10,
+
+ /// Data section is explicitly initialized
+ DSEG_INIT = 0x20,
+
+ /// Script new (optimized) version of SYSREQ opcode
+ SYSREQN = 0x800,
+
+ /// All native functions are registered
+ NTVREG = 0x1000,
+
+ /// Abstract machine is JIT compiled
+ JITC = 0x2000,
+
+ /// Busy verifying P-code
+ VERIFY = 0x4000,
+
+ /// AMX has been initialized
+ INIT = 8000
+ }
+
+ public static class AmxFlagsExtensions
+ {
+ public static bool HasFlagFast(this AmxFlags value, AmxFlags flag)
+ {
+ return (value & flag) != 0;
+ }
+ }
+}
\ No newline at end of file
diff --git a/pkNX.Structures/Scripts/AmxHeader.cs b/pkNX.Structures/Scripts/AmxHeader.cs
new file mode 100644
index 00000000..62131459
--- /dev/null
+++ b/pkNX.Structures/Scripts/AmxHeader.cs
@@ -0,0 +1,82 @@
+using System.Runtime.InteropServices;
+
+namespace pkNX.Structures
+{
+ [StructLayout(LayoutKind.Sequential)]
+ public class AmxHeader
+ {
+ // Cell Size magic verification
+ public const ushort MAGIC_32 = 0xf1e0;
+ public const ushort MAGIC_64 = 0xf1e1;
+ public const ushort MAGIC_16 = 0xf1e2;
+
+ /// Size of the "file"
+ public int Size; // 0x00
+
+ /// Signature
+ public ushort Magic; // 0x04
+
+ /// File format version
+ public byte FileVersion; // 0x06
+
+ /// Required version of the AMX
+ public byte AMXVersion; // 0x07
+
+ /// Feature flags
+ public AmxFlags Flags; // 0x08
+
+ /// Size of a definition record
+ public short DefinitionSize; // 0x0A
+
+ /// Initial value of COD - code block
+ public int COD; // 0x0C
+
+ /// initial value of DAT - data block
+ public int Data; // 0x10
+
+ /// Initial value of HEA - start of the heap
+ public int Heap; // 0x14
+
+ /// Initial value of STP - stack top
+ public int StackTop; // 0x18
+
+ /// Initial value of CIP - the instruction pointer
+ public int CurrentInstructionPointer; // 0x20
+
+ /// Offset to the "public functions" table
+ public int Publics; // 0x24
+
+ /// Offset to the "native functions" table
+ public int Natives; // 0x28
+
+ /// Offset to the table of libraries
+ public int Libraries; // 0x2C
+
+ /// Offset to the "public variables" table
+ public int PublicVars; // 0x30
+
+ /// Offset to the "public tagnames" table
+ public int Tags; // 0x34
+
+ /// Offset to the name table
+ public int NameTable; // 0x38
+
+ /// Offset to the overlay table
+ public int Overlays; // 0x3C
+ }
+
+/* File format version
+ * 0 original version
+ * 1 opcodes JUMP.pri, SWITCH and CASETBL
+ * 2 compressed files
+ * 3 public variables
+ * 4 opcodes SWAP.pri/alt and PUSHADDR
+ * 5 tagnames table
+ * 6 reformatted header
+ * 7 name table, opcodes SYMTAG & SYSREQ.D
+ * 8 opcode BREAK, renewed debug interface
+ * 9 macro opcodes
+ * 10 position-independent code, overlays, packed instructions
+ * 11 relocating instructions for the native interface, reorganized instruction set
+ */
+}
diff --git a/pkNX.Structures/Scripts/AmxOpCode.cs b/pkNX.Structures/Scripts/AmxOpCode.cs
new file mode 100644
index 00000000..a320424e
--- /dev/null
+++ b/pkNX.Structures/Scripts/AmxOpCode.cs
@@ -0,0 +1,226 @@
+namespace pkNX.Structures
+{
+ // https://github.com/gameswop/mtasa-resources/blob/d557a72fefef57ac34780a76edf16383d3dff0e8/%5Bgamemodes%5D/%5Bamx%5D/amx-deps/src/amx/amx.c#L143
+ public enum AmxOpCode
+ {
+ NONE, /* invalid opcode */
+ LOAD_PRI,
+ LOAD_ALT,
+ LOAD_S_PRI,
+ LOAD_S_ALT,
+ LREF_PRI,
+ LREF_ALT,
+ LREF_S_PRI,
+ LREF_S_ALT,
+ LOAD_I,
+ LODB_I,
+ CONST_PRI,
+ CONST_ALT,
+ ADDR_PRI,
+ ADDR_ALT,
+ STOR_PRI,
+ STOR_ALT,
+ STOR_S_PRI,
+ STOR_S_ALT,
+ SREF_PRI,
+ SREF_ALT,
+ SREF_S_PRI,
+ SREF_S_ALT,
+ STOR_I,
+ STRB_I,
+ LIDX,
+ LIDX_B,
+ IDXADDR,
+ IDXADDR_B,
+ ALIGN_PRI,
+ ALIGN_ALT,
+ LCTRL,
+ SCTRL,
+ MOVE_PRI,
+ MOVE_ALT,
+ XCHG,
+ PUSH_PRI,
+ PUSH_ALT,
+ PICK,
+ PUSH_C,
+ PUSH,
+ PUSH_S,
+ PPRI,
+ PALT,
+ STACK,
+ HEAP,
+ PROC,
+ RET,
+ RETN,
+ CALL,
+ CALL_PRI,
+ JUMP,
+ JREL, /* obsolete */
+ JZER,
+ JNZ,
+ JEQ,
+ JNEQ,
+ JLESS,
+ JLEQ,
+ JGRTR,
+ JGEQ,
+ JSLESS,
+ JSLEQ,
+ JSGRTR,
+ JSGEQ,
+ SHL,
+ SHR,
+ SSHR,
+ SHL_C_PRI,
+ SHL_C_ALT,
+ SHR_C_PRI,
+ SHR_C_ALT,
+ SMUL,
+ SDIV,
+ SDIV_ALT,
+ UMUL,
+ UDIV,
+ UDIV_ALT,
+ ADD,
+ SUB,
+ SUB_ALT,
+ AND,
+ OR,
+ XOR,
+ NOT,
+ NEG,
+ INVERT,
+ ADD_C,
+ SMUL_C,
+ ZERO_PRI,
+ ZERO_ALT,
+ ZERO,
+ ZERO_S,
+ SIGN_PRI,
+ SIGN_ALT,
+ EQ,
+ NEQ,
+ LESS,
+ LEQ,
+ GRTR,
+ GEQ,
+ SLESS,
+ SLEQ,
+ SGRTR,
+ SGEQ,
+ EQ_C_PRI,
+ EQ_C_ALT,
+ INC_PRI,
+ INC_ALT,
+ INC,
+ INC_S,
+ INC_I,
+ DEC_PRI,
+ DEC_ALT,
+ DEC,
+ DEC_S,
+ DEC_I,
+ MOVS,
+ CMPS,
+ FILL,
+ HALT,
+ BOUNDS,
+ SYSREQ_PRI,
+ SYSREQ_C,
+ FILE, /* obsolete */
+ LINE, /* obsolete */
+ SYMBOL, /* obsolete */
+ SRANGE, /* obsolete */
+ JUMP_PRI,
+ SWITCH,
+ CASETBL,
+ SWAP_PRI,
+ SWAP_ALT,
+ PUSH_ADR,
+ NOP,
+ SYSREQ_N,
+ SYMTAG, /* obsolete */
+ BREAK, /* macro instructions */
+ PUSH2_C,
+ PUSH2,
+ PUSH2_S,
+ PUSH2_ADR,
+ PUSH3_C,
+ PUSH3,
+ PUSH3_S,
+ PUSH3_ADR,
+ PUSH4_C,
+ PUSH4,
+ PUSH4_S,
+ PUSH4_ADR,
+ PUSH5_C,
+ PUSH5,
+ PUSH5_S,
+ PUSH5_ADR,
+ LOAD_BOTH,
+ LOAD_S_BOTH,
+ CONST,
+ CONST_S, /* overlay instructions */
+ ICALL,
+ IRETN,
+ ISWITCH,
+ ICASETBL, /* packed instructions */
+#if !AMX_NO_PACKED_OPC
+ LOAD_P_PRI,
+ LOAD_P_ALT,
+ LOAD_P_S_PRI,
+ LOAD_P_S_ALT,
+ LREF_P_PRI,
+ LREF_P_ALT,
+ LREF_P_S_PRI,
+ LREF_P_S_ALT,
+ LODB_P_I,
+ CONST_P_PRI,
+ CONST_P_ALT,
+ ADDR_P_PRI,
+ ADDR_P_ALT,
+ STOR_P_PRI,
+ STOR_P_ALT,
+ STOR_P_S_PRI,
+ STOR_P_S_ALT,
+ SREF_P_PRI,
+ SREF_P_ALT,
+ SREF_P_S_PRI,
+ SREF_P_S_ALT,
+ STRB_P_I,
+ LIDX_P_B,
+ IDXADDR_P_B,
+ ALIGN_P_PRI,
+ ALIGN_P_ALT,
+ PUSH_P_C,
+ PUSH_P,
+ PUSH_P_S,
+ STACK_P,
+ HEAP_P,
+ SHL_P_C_PRI,
+ SHL_P_C_ALT,
+ SHR_P_C_PRI,
+ SHR_P_C_ALT,
+ ADD_P_C,
+ SMUL_P_C,
+ ZERO_P,
+ ZERO_P_S,
+ EQ_P_C_PRI,
+ EQ_P_C_ALT,
+ INC_P,
+ INC_P_S,
+ DEC_P,
+ DEC_P_S,
+ MOVS_P,
+ CMPS_P,
+ FILL_P,
+ HALT_P,
+ BOUNDS_P,
+ PUSH_P_ADR,
+#endif
+ /* ----- */
+ SYSREQ_D,
+ SYSREQ_ND, /* ----- */
+ NUM_OPCODES
+ }
+}
diff --git a/pkNX.Structures/Scripts/Script.cs b/pkNX.Structures/Scripts/Script.cs
index 0035fe6d..3cb9485c 100644
--- a/pkNX.Structures/Scripts/Script.cs
+++ b/pkNX.Structures/Scripts/Script.cs
@@ -9,11 +9,12 @@ namespace pkNX.Structures
/// https://github.com/compuphase/pawn
public class Script
{
- public int Length => BitConverter.ToInt32(Raw, 0x00);
- public uint Magic => BitConverter.ToUInt32(Raw, 0x04);
+ public AmxHeader Header;
+ public int Length => Header.Size;
+ public uint Magic => Header.Magic;
// case 0x0A0AF1E0: code = read_code_block(f); break;
// case 0x0A0AF1EF: debug = read_debug_block(f); break;
- public bool Debug => Magic == 0x0A0AF1EF;
+ public bool Debug => Header.Flags.HasFlagFast(AmxFlags.DEBUG);
public ushort PtrOffset => BitConverter.ToUInt16(Raw, 0x08);
public ushort PtrCount => BitConverter.ToUInt16(Raw, 0x0A);
@@ -48,9 +49,10 @@ public class Script
public Script(byte[] data = null)
{
Raw = data ?? Array.Empty();
+ Header = data.ToClass();
// sub_51AAFC
- if ((Raw[8] & 1) != 0)
+ if (Header.Flags.HasFlagFast(AmxFlags.OVERLAY))
throw new ArgumentException("Multi-environment script!?");
}