private static void OnTick(int counter, EventArgs args)
        {
            if (processHandle == IntPtr.Zero)                                              //if we still don't have a handle to the process
            {
                var wndHnd = Memory.FindWindowClassName("UnityWndClass");                  //try finding the window of the process (check if it's spawned and loaded)
                if (wndHnd != IntPtr.Zero)                                                 //if it exists
                {
                    var calcPid = Memory.GetPIDFromHWND(wndHnd);                           //get the PID of that same process
                    if (calcPid > 0)                                                       //if we got the PID
                    {
                        processHandle = Memory.ZwOpenProcess(PROCESS_ALL_ACCESS, calcPid); //get full access to the process so we can use it later
                        if (processHandle != IntPtr.Zero)
                        {
                            //if we got access to the game, check if it's x64 bit, this is needed when reading pointers, since their size is 4 for x86 and 8 for x64
                            isWow64Process = Memory.IsProcess64Bit(processHandle);
                            //here you can scan for signatures and stuff, it happens only once on "attach"
                        }
                    }
                }
            }
            else //else we have a handle, lets check if we should close it, or use it
            {
                var wndHnd = Memory.FindWindowClassName("UnityWndClass");
                if (wndHnd != IntPtr.Zero) //window still exists, so handle should be valid? let's keep using it
                {
                    //the lines of code below execute every 33ms outside of the renderer thread, heavy code can be put here if it's not render dependant
                    gameProcessExists = true;
                    isGameOnTop       = Renderer.IsGameOnTop(wndHnd);
                    isOverlayOnTop    = Overlay.IsOnTop();

                    if (GameAssembly_dll == IntPtr.Zero)
                    {
                        GameAssembly_dll = Memory.ZwGetModule(processHandle, "GameAssembly.dll", isWow64Process);
                        Console.WriteLine($"Found GameAssembly.dll: {GameAssembly_dll.ToString("X")}");
                    }
                    //since we're not drawing, the rest of the code can be put here.
                    if (characterPtr == IntPtr.Zero)
                    {
                        //characterPtr = Memory.ZwFindSignatureBase(processHandle, IntPtr.Zero, IntPtr.Zero, "00 00 18 41 00 00 18 41 00 00 E0 40 CD CC 4C 3E 00 00 A0 40 00 00 E0 40 00 00 00 41 00 00 00 41 00"); //just to get the base of the character allocation data
                        //9.50 9.50 7.00 0.20 5.00 7.00 8.00 or ... 41180000 41180000 40E00000 3E4CCCCD 40A00000 40E00000 41000000
                        characterPtr = SDKUtil.ZwReadPointerChain(processHandle, (IntPtr)(GameAssembly_dll.ToInt64() + 0x028F1F40), isWow64Process, 0xB58, 0x88);
                        if (characterPtr != IntPtr.Zero)
                        {
                            Console.WriteLine($"FOUND Character Base Ptr: {characterPtr.ToString("X")}");
                        }
                        else
                        {
                            if (lastTime + 1000 < Memory.TickCount)
                            {
                                lastTime = Memory.TickCount;
                                Console.WriteLine("FAILED TO FIND Character Base Ptr :(");
                            }
                        }
                    }
                    else
                    {
                        //we are in game and got char ptr ... continue with menu modifications every tick

                        IntPtr timeToRunNextCharacterControllerDataCheckPTR = SDKUtil.ZwReadPointerChain(processHandle, (IntPtr)(GameAssembly_dll.ToInt64() + 0x2C2AD28), isWow64Process, 0xB8, 0x0, 0xC8, 0x10, 0x30, 0x1D8);
                        //Console.WriteLine(timeToRunNextCharacterControllerDataCheck.ToString("X"));
                        if (timeToRunNextCharacterControllerDataCheckPTR != IntPtr.Zero)
                        {
                            var timeToRunNextCharacterControllerDataCheck = Memory.ZwReadFloat(processHandle, (IntPtr)timeToRunNextCharacterControllerDataCheckPTR.ToInt64() + 0x10);
                            if ((timeToRunNextCharacterControllerDataCheck > 0) && (timeToRunNextCharacterControllerDataCheck < 100000000.0f))
                            {
                                Memory.ZwWriteFloat(processHandle, (IntPtr)(timeToRunNextCharacterControllerDataCheckPTR.ToInt64() + 0x10), 100000000.0f);
                            }
                            else
                            {
                                var doublecheck = Memory.ZwReadFloat(processHandle, (IntPtr)timeToRunNextCharacterControllerDataCheckPTR.ToInt64() + 0x10);
                                if (doublecheck == 100000000.0f)
                                {
                                    //DelayAction.Queue(() => writeCheatosz(processHandle, characterPtr), 5000.0f);
                                    writeCheatos(processHandle, characterPtr, false);
                                }
                            }
                        }
                        else
                        {
                            //writeCheatos(processHandle, characterPtr, true);
                        }
                    }
                }
                else //else most likely the process is dead, clean up
                {
                    Memory.CloseHandle(processHandle); //close the handle to avoid leaks
                    processHandle     = IntPtr.Zero; //set it like this just in case for C# logic
                    gameProcessExists = false;
                    characterPtr      = IntPtr.Zero;
                    GameAssembly_dll  = IntPtr.Zero;
                }
            }
        }