/// <summary>
        /// Creates the wrapper function that wraps a native function with our own defined or custom calling convention,
        /// into a regular X64 Microsoft Calling Convention function that is natively supported by the C# programming language.
        ///
        /// This allows us to call non-standard "usercall" game functions, such as for example functions that take values
        /// in registers as parameters instead of using the stack, functions which take paremeters in a mixture of both stack
        /// and registers as well as functions which varying return parameters, either caller or callee cleaned up.
        /// </summary>
        /// <param name="functionAddress">The address of the function to create a wrapper for.</param>
        /// <param name="reloadedFunction">Structure containing the details of the actual function in question.</param>
        /// <returns>Pointer to the new X64 Microsoft Calling Convention function address to call from C# code to invoke our game function.</returns>
        private static IntPtr CreateWrapperFunctionInternal <TFunction>(IntPtr functionAddress, X64ReloadedFunctionAttribute reloadedFunction)
        {
            // Retrieve number of parameters.
            int numberOfParameters    = FunctionCommon.GetNumberofParametersWithoutFloats(typeof(TFunction));
            int nonRegisterParameters = numberOfParameters - reloadedFunction.SourceRegisters.Length;

            // List of ASM Instructions to be Compiled
            List <string> assemblyCode = new List <string> {
                "use64"
            };

            // Backup Stack Frame
            assemblyCode.Add("push rbp");       // Backup old call frame
            assemblyCode.Add("mov rbp, rsp");   // Setup new call frame

            // Setup Function Parameters
            if (numberOfParameters > 0)
            {
                assemblyCode.AddRange(AssembleFunctionParameters(numberOfParameters, reloadedFunction.SourceRegisters));
            }

            // Make Shadow Space if necessary.
            if (reloadedFunction.ShadowSpace)
            {
                assemblyCode.Add("sub rsp, 32");   // Setup new call frame
            }
            // Assemble the call to the game function in question.
            assemblyCode.AddRange(HookCommon.X64AssembleAbsoluteCallMnemonics(functionAddress, reloadedFunction));

            // Move return register back if necessary.
            if (reloadedFunction.ReturnRegister != X64ReloadedFunctionAttribute.Register.rax)
            {
                assemblyCode.Add("mov rax, " + reloadedFunction.ReturnRegister);
            }

            // Restore the stack pointer from the Shadow Space
            // 8 = IntPtr.Size
            // 32 = Shadow Space
            if (reloadedFunction.ShadowSpace)
            {
                assemblyCode.Add("add rsp, " + ((nonRegisterParameters * 8) + 32));
            }
            else
            {
                assemblyCode.Add("add rsp, " + (nonRegisterParameters * 8));
            }

            // Restore Stack Frame and Return
            assemblyCode.Add("pop rbp");
            assemblyCode.Add("ret");

            // Write function to buffer and return pointer.
            byte[] assembledMnemonics = Assembler.Assembler.Assemble(assemblyCode.ToArray());
            return(MemoryBufferManager.Add(assembledMnemonics));
        }
        /// <summary>
        /// Creates the wrapper function for redirecting program flow to our C# function.
        /// </summary>
        /// <param name="reloadedFunction">Structure containing the details of the actual function in question.</param>
        /// <param name="functionAddress">The address of the function to create a wrapper for.</param>
        /// <returns></returns>
        internal static IntPtr CreateX64WrapperFunctionInternal <TFunction>(IntPtr functionAddress, X64ReloadedFunctionAttribute reloadedFunction)
        {
            // Retrieve number of parameters.
            int numberOfParameters    = FunctionCommon.GetNumberofParametersWithoutFloats(typeof(TFunction));
            int nonRegisterParameters = numberOfParameters - reloadedFunction.SourceRegisters.Length;

            // List of ASM Instructions to be Compiled
            List <string> assemblyCode = new List <string> {
                "use64"
            };

            // If the attribute is Microsoft Call Convention, take fast path!
            if (reloadedFunction.Equals(new X64ReloadedFunctionAttribute(X64CallingConventions.Microsoft)))
            {
                // Backup old call frame
                assemblyCode.AddRange(HookCommon.X64AssembleAbsoluteJumpMnemonics(functionAddress, reloadedFunction));
            }
            else
            {
                // Backup Stack Frame
                assemblyCode.Add("push rbp");       // Backup old call frame
                assemblyCode.Add("mov rbp, rsp");   // Setup new call frame

                // We assume that we are stack aligned in usercall/custom calling conventions, if we are not, game over for now.
                // Our stack frame alignment is off by 8 here, we must also consider non-register parameters.
                // Note to self: In the case you forget, dummy. Your stack needs to be 16 byte aligned.

                // Calculate the bytes our wrapper parameters take on the stack in total.
                // The stack frame backup, push rbp and CALL negate themselves so it's down to this.
                // Then our misalignment to the stack.
                int stackBytesTotal   = (nonRegisterParameters * 8);
                int stackMisalignment = (stackBytesTotal % 16);

                // Prealign stack
                assemblyCode.Add($"sub rbp, {stackMisalignment}");   // Setup new call frame

                // Setup the registers for our C# method.
                assemblyCode.AddRange(AssembleFunctionParameters(numberOfParameters, reloadedFunction, stackMisalignment));

                // And now we add the shadow space for C# method's Microsoft Call Convention.
                assemblyCode.Add("sub rsp, 32");   // Setup new call frame

                // Assemble the Call to C# Function Pointer.
                assemblyCode.AddRange(HookCommon.X64AssembleAbsoluteCallMnemonics(functionAddress, reloadedFunction));

                // MOV our own return register, EAX into the register expected by the calling convention
                assemblyCode.Add($"mov {reloadedFunction.ReturnRegister}, rax");

                // Restore stack pointer (this is always the same, our function is Microsoft Call Convention Compliant)
                assemblyCode.Add("add rsp, " + ((nonRegisterParameters * 8) + 32));

                // Restore stack alignment
                assemblyCode.Add($"add rbp, {stackMisalignment}");

                // Restore Stack Frame and Return
                assemblyCode.Add("pop rbp");
                assemblyCode.Add("ret");
            }

            // Assemble and return pointer to code
            byte[] assembledMnemonics = Assembler.Assembler.Assemble(assemblyCode.ToArray());
            return(MemoryBufferManager.Add(assembledMnemonics));
        }