[
  {
    "path": ".github/workflows/main.yml",
    "content": "name: Release\n\non:\n  workflow_dispatch:\n    inputs:\n      branch:\n        description: 'Branch to run on'\n        required: true\n        default: 'main'\n\njobs:\n  build_and_release:\n    name: Build and release\n    runs-on: ubuntu-22.04\n    container: devkitpro/devkita64:20250728\n    steps:\n      - name: Update packages\n        run: |\n          sudo -n apt-get update\n          sudo -n apt-get install -y build-essential zip python3 python3-pip python3-lz4\n        shell: bash\n      - name: Update latest libnx\n        run: |\n          git config --global --add safe.directory \"*\"\n          git clone --recurse-submodules https://github.com/switchbrew/libnx.git\n          cd libnx\n          make install -j$(nproc)\n        shell: bash\n      - name: Checkout latest code\n        uses: actions/checkout@v5.0.0\n        with:\n          ref: main\n          clean: true\n          fetch-depth: 0\n          fetch-tags: true\n          submodules: recursive\n      - name: Setup ENV parameters\n        run: |\n          VER_FILE=Makefile\n          VERSION=$(awk '/^APP_VERSION/{print $3}' $VER_FILE)\n          echo \"TAG=${VERSION}\" >> \"${GITHUB_ENV}\"\n          echo \"RELEASE_NAME=${VERSION}\" >> \"${GITHUB_ENV}\"\n          echo \"RELEASE=1\" >> \"${GITHUB_ENV}\"\n        shell: bash\n      - name: Replace Tesla Colors\n        run: |\n          sed -i '/constexpr Color ColorHighlight/c\\            constexpr Color ColorHighlight        = { 0x0, 0xC, 0xF, 0xF };   ///< Greenish highlight color' ./libs/libultrahand/libtesla/include/tesla.hpp\n          sed -i '/static Color onTextColor/c\\    static Color onTextColor = RGB888(\"00CCFF\");' ./libs/libultrahand/libtesla/include/tesla.hpp\n          sed -i '/static Color trackBarFullColor/c\\    static Color trackBarFullColor = RGB888(\"00CCFF\");' ./libs/libultrahand/libtesla/include/tesla.hpp\n        shell: bash\n      - name: Build\n        run: |\n          export DEVKITPRO=/opt/devkitpro\n          make all\n        shell: bash\n      - name: Upload Release Asset\n        uses: softprops/action-gh-release@v2.4.1\n        with:\n          name: ${{ env.RELEASE_NAME }}\n          tag_name: ${{ env.TAG }}\n          draft: false\n          prerelease: false\n          generate_release_notes: yes\n          make_latest: true\n          files: |\n            ./SdOut/EdiZon-Overlay.zip\n            ./SdOut/switch/.overlays/ovlEdiZon.ovl"
  },
  {
    "path": ".gitignore",
    "content": "###################\n#.gitignore       #\n###################\n\n#\n# Visual Studio Code\n#\n.settings/\n.classpath\n.factorypath\n.project\n.vscode/\n\n#\n# CMAKE\n#\nbuild/\nout/\n*.lst\n\n#\n# Custom\n#\nSdOut/\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"libs/libultrahand\"]\n\tpath = libs/libultrahand\n\turl = https://github.com/ppkantorski/libultrahand\n"
  },
  {
    "path": "Makefile",
    "content": "#---------------------------------------------------------------------------------\n.SUFFIXES:\n#---------------------------------------------------------------------------------\n\nifeq ($(strip $(DEVKITPRO)),)\n$(error \"Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro\")\nendif\n\nTOPDIR ?= $(CURDIR)\ninclude $(DEVKITPRO)/libnx/switch_rules\n\nAPP_TITLE\t\t:=\tEdiZon\nAPP_FILENAME\t:=  ovlEdiZon\nAPP_AUTHOR\t\t:=\tWerWolv, proferabg, and ppkantorski\nAPP_VERSION\t\t:=\tv1.0.14\n\nifeq ($(RELEASE), 1)\n\tAPP_VERSION\t:=\t$(APP_VERSION)-$(shell git describe --always)\nendif\n\nTARGET\t\t\t:=\t$(APP_TITLE)\nOUTDIR\t\t\t:=\tout\nBUILD\t\t\t:=\tbuild\nSOURCES_TOP\t\t:=\tsource\nSOURCES\t\t\t+=  $(foreach dir,$(SOURCES_TOP),$(shell find $(dir) -type d 2>/dev/null))\nINCLUDES\t\t:=\tinclude\n#EXCLUDES\t\t:=  dmntcht.c\nDATA\t\t\t:=\tdata\n\n# This location should reflect where you place the libultrahand directory (lib can vary between projects).\ninclude ${TOPDIR}/libs/libultrahand/ultrahand.mk\n\n#---------------------------------------------------------------------------------\n# options for code generation\n#---------------------------------------------------------------------------------\nnull      \t:=\nSPACE     \t:=  $(null) $(null)\n\nARCH\t:=\t-march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE\n\nCFLAGS\t:= -g -Wall -O3 -ffunction-sections -fdata-sections -flto -ffast-math -fomit-frame-pointer \\\n\t\t\t\t\t-fuse-linker-plugin -finline-small-functions -fno-strict-aliasing -frename-registers -falign-functions=16 \\\n\t\t\t\t\t$(ARCH) $(DEFINES) -DVERSION_STRING=\\\"$(subst $(SPACE),\\$(SPACE),${APP_VERSION})\\\"\n\n\nCFLAGS\t+=\t$(INCLUDE) -D__SWITCH__ -D__OVERLAY__ -I$(PORTLIBS)/include/freetype2 $(pkg-config --cflags --libs python3) -Wno-deprecated-declarations \nCFLAGS\t+=\t-DAPP_VERSION=\\\"$(APP_VERSION)\\\" -DAPP_TITLE=\\\"$(APP_TITLE)\\\" -DAPP_AUTHOR=\\\"\"$(APP_AUTHOR)\"\\\"\n\nCXXFLAGS\t:= $(CFLAGS) -fexceptions -std=c++26\n\nASFLAGS\t:=\t-g $(ARCH)\nLDFLAGS\t=\t-specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)\n\nLIBS\t:= -lnx\n\n#---------------------------------------------------------------------------------\n# list of directories containing libraries, this must be the top level containing\n# include and lib\n#---------------------------------------------------------------------------------\nLIBDIRS\t:= $(CURDIR)/libs/nxpy $(PORTLIBS) $(LIBNX)\n\n\n#---------------------------------------------------------------------------------\n# no real need to edit anything past this point unless you need to add additional\n# rules for different file extensions\n#---------------------------------------------------------------------------------\nifneq ($(BUILD),$(notdir $(CURDIR)))\n#---------------------------------------------------------------------------------\n\nexport OUTPUT\t:=\t$(CURDIR)/$(OUTDIR)/$(APP_FILENAME)\nexport TOPDIR\t:=\t$(CURDIR)\n\nexport VPATH\t:=\t$(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \\\n\t\t\t\t\t$(foreach dir,$(DATA),$(CURDIR)/$(dir))\n\nexport DEPSDIR\t:=\t$(CURDIR)/$(BUILD)\n\n\nCFILES\t\t\t:=\t$(filter-out $(EXCLUDES),$(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))))\nCPPFILES\t\t:=\t$(filter-out $(EXCLUDES),$(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))))\nSFILES\t\t\t:=\t$(filter-out $(EXCLUDES),$(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))))\nBINFILES\t\t:=\t$(filter-out $(EXCLUDES),$(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))))\n\n#---------------------------------------------------------------------------------\n# use CXX for linking C++ projects, CC for standard C\n#---------------------------------------------------------------------------------\nifeq ($(strip $(CPPFILES)),)\n#---------------------------------------------------------------------------------\n\texport LD\t:=\t$(CC)\n#---------------------------------------------------------------------------------\nelse\n#---------------------------------------------------------------------------------\n\texport LD\t:=\t$(CXX)\n#---------------------------------------------------------------------------------\nendif\n#---------------------------------------------------------------------------------\n\nexport OFILES_BIN\t:=\t$(addsuffix .o,$(BINFILES))\nexport OFILES_SRC\t:=\t$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)\nexport OFILES \t\t:=\t$(OFILES_BIN) $(OFILES_SRC)\nexport HFILES_BIN\t:=\t$(addsuffix .h,$(subst .,_,$(BINFILES)))\n\nexport INCLUDE\t:=\t$(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \\\n\t\t\t$(foreach dir,$(LIBDIRS),-I$(dir)/include) \\\n\t\t\t-I$(CURDIR)/$(BUILD)\n\nexport LIBPATHS\t:=\t$(foreach dir,$(LIBDIRS),-L$(dir)/lib)\n\nifeq ($(strip $(CONFIG_JSON)),)\n\tjsons := $(wildcard *.json)\n\tifneq (,$(findstring $(TARGET).json,$(jsons)))\n\t\texport APP_JSON := $(TOPDIR)/$(TARGET).json\n\telse\n\t\tifneq (,$(findstring config.json,$(jsons)))\n\t\t\texport APP_JSON := $(TOPDIR)/config.json\n\t\tendif\n\tendif\nelse\n\texport APP_JSON := $(TOPDIR)/$(CONFIG_JSON)\nendif\n\nifeq ($(strip $(ICON)),)\n\ticons := $(wildcard *.jpg)\n\tifneq (,$(findstring $(TARGET).jpg,$(icons)))\n\t\texport APP_ICON := $(TOPDIR)/$(TARGET).jpg\n\telse\n\t\tifneq (,$(findstring icon.jpg,$(icons)))\n\t\t\texport APP_ICON := $(TOPDIR)/icon.jpg\n\t\tendif\n\tendif\nelse\n\texport APP_ICON := $(TOPDIR)/$(ICON)\nendif\n\nifeq ($(strip $(NO_ICON)),)\n\texport NROFLAGS += --icon=$(APP_ICON)\nendif\n\nifeq ($(strip $(NO_NACP)),)\n\texport NROFLAGS += --nacp=$(OUTPUT).nacp\nendif\n\nifneq ($(APP_TITLEID),)\n\texport NACPFLAGS += --titleid=$(APP_TITLEID)\nendif\n\nifneq ($(ROMFS),)\n\texport NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS)\nendif\n\n.PHONY: $(BUILD) clean all install\n\n#---------------------------------------------------------------------------------\nall: $(BUILD)\n\n$(BUILD):\n\t@[ -d $@ ] || mkdir -p $@ $(BUILD) $(OUTDIR)\n\t@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile\n\t@rm -rf SdOut\n\t@mkdir -p SdOut/switch/.overlays\n\t@cp -rf $(OUTPUT).ovl SdOut/switch/.overlays/\n\t@cd $(CURDIR)/SdOut; zip -r -q -9 $(APP_TITLE)-Overlay.zip switch; cd $(CURDIR)\n\n#---------------------------------------------------------------------------------\nclean:\n\t@echo \" RM   \" $(BUILD) $(OUTDIR) SdOut\n\t@rm -fr $(BUILD) $(OUTDIR) SdOut\n\n#---------------------------------------------------------------------------------\ninstall: all\n\t@echo \" LFTP \" $@\n\t@lftp -e \"put -O /switch/.overlays ./out/$(APP_FILENAME).ovl;bye\" $(IP)\n\n#---------------------------------------------------------------------------------\nelse\n.PHONY:\tall\n\nDEPENDS\t:=\t$(OFILES:.o=.d)\n\n#---------------------------------------------------------------------------------\n# main targets\n#---------------------------------------------------------------------------------\nall\t:  $(OUTPUT).ovl\n\n$(OUTPUT).ovl\t:\t$(OUTPUT).nro\n\t@cp $(OUTPUT).nro $(OUTPUT).ovl\n\t@printf 'ULTR' >> $(OUTPUT).ovl\n\t@echo \"Ultrahand signature has been added.\"\n\n$(OUTPUT).nsp\t:\t$(OUTPUT).nso $(OUTPUT).npdm\n\n$(OUTPUT).nso\t:\t$(OUTPUT).elf\n\n$(OUTPUT).nro\t:\t$(OUTPUT).nso $(OUTPUT).nacp\n\n$(OUTPUT).elf\t:\t$(OFILES)\n\n$(OFILES_SRC)\t: $(HFILES_BIN)\n\n#---------------------------------------------------------------------------------\n# you need a rule like this for each extension you use as binary data\n#---------------------------------------------------------------------------------\n%.bin.o\t%_bin.h :\t%.bin\n\t@echo \" BIN  \" $@\n\t@$(bin2o)\n\n%.ttf.o\t%_ttf.h :\t%.ttf\n\t@echo \" BIN  \" $@\n\t@$(bin2o)\n\n-include $(DEPENDS)\n\n#---------------------------------------------------------------------------------------\nendif\n#---------------------------------------------------------------------------------------\n"
  },
  {
    "path": "README.md",
    "content": "# EdiZon-Overlay [![Github All Releases](https://img.shields.io/github/downloads/proferabg/EdiZon-Overlay/total.svg)]()\n\nOriginally by [@WerWolv](https://www.github.com/WerWolv)\n\nContinued Support by proferabg & ppkantorski\n<br />\n<br />\n\n# Latest Changelog - v1.0.14\n    Update libultrahand to v2.2.0\n<br />\n\n# How To Use Submenus\n\nIn your cheat text document, you can add submenus by using these 2 tags\n\n    [--SectionStart:<Section Name>--]\n    [--SectionEnd:<Section Name>--]\n\nExample:\n\n    [--SectionStart:Item Codes--]\n    00000000 00000000 00000000    \n\n    [Items x999]\n    040A0000 01DB2A08 52807CE0\n\n    [--SectionEnd:Item Codes--]\n    00000000 00000000 00000000\n\nThis will create a submenu called ***Item Codes*** with ***Items x999*** being a cheat in that submenu.\n\nYou can also disable the submenu feature (skips submenu items in cheat file).\nTo do so, insert the following at the very top of the file.\n\n    [--DisableSubmenus--]\n    00000000 00000000 00000000\n\nWarning: Having too many cheats at once can lead to stability issues and can crash.\n<br />\n\n# How To Enable Cheats by Default on Overlay Open\n\nIn your cheat text document, you can have cheats turn on by default on opening of the overlay.\nTo do this, simply find the cheat you want to enable by default and add ***:ENABLED*** onto the end of the name.\n\nExample:\n\n    [60 FPS Mod:ENABLED]\n    00000000 00000000 00000000\n\nWarning: This will turn the cheat on every time the overlay is relaunched. Also, turning the cheat off in the menu and relaunching the overlay will turn the cheat back on.\n"
  },
  {
    "path": "include/cheat.hpp",
    "content": "/**\n * Copyright (C) 2019 - 2020 WerWolv\n * \n * This file is part of EdiZon.\n * \n * EdiZon is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n * \n * EdiZon is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with EdiZon.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#pragma once\n\n#include \"dmntcht.h\"\n#include \"cheat_engine_types.hpp\"\n#include \"result.hpp\"\n#include \"results.hpp\"\n\n#include <string>\n#include <vector>\n\nnamespace edz::cheat {\n\n    // Work around for EResult madness\n    bool Succeeded(Result res);\n\n    #define EDIZON_CHEATS_DIR EDIZON_DIR \"/cheats\"\n    #define EMPTY_RESPONSE { }\n\n    class Cheat {\n    public:\n        Cheat(DmntCheatEntry cheatEntry);\n\n        std::string getName();\n        u32 getID();\n\n        bool toggle();\n        bool setState(bool state);\n        bool isEnabled();\n\n    private:\n        std::string m_name;\n        u32 m_id;\n    };\n\n    class FrozenAddress {\n    public:\n        FrozenAddress(DmntFrozenAddressEntry);\n        FrozenAddress(u64 address, u8 width, u64 value);\n        FrozenAddress(u64 address, u8 width);\n\n        u64 getAddress();\n        u8 getWidth();\n        u64 getValue();\n        u64 setValue(u64 value, u8 width);\n\n        bool toggle();\n        bool isFrozen();\n\n    private:\n        DmntFrozenAddressEntry m_frozenAddressEntry;\n        bool m_frozen;\n    };\n\n\n    class CheatManager {\n    public:\n        static Result initialize();\n        static void exit();\n\n        static bool isCheatServiceAvailable();\n\n        static Result forceAttach();\n        static bool hasCheatProcess();\n\n        static u64 getTitleID();\n        static u64 getProcessID();\n        static u64 getBuildID();\n\n        static types::Region getBaseRegion();\n        static types::Region getHeapRegion();\n        static types::Region getMainRegion();\n        static types::Region getAliasRegion();\n\n        //static EResultVal<std::string> getCheatFile();\n\n        //static EResultVal<u32> addCheat(DmntCheatDefinition cheatDefinition, bool enabled);\n        static Result removeCheat(u32 cheatID);\n\n        static std::vector<Cheat*>& getCheats();\n        static std::vector<FrozenAddress*>& getFrozenAddresses();\n\n        static MemoryInfo queryMemory(u64 address);\n        static std::vector<MemoryInfo> getMemoryRegions();\n\n        static Result readMemory(u64 address, void *buffer, size_t bufferSize);\n        static Result writeMemory(u64 address, const void *buffer, size_t bufferSize);\n\n        static Result reload();\n\n    private:\n        static inline std::vector<Cheat*> s_cheats;\n        static inline std::vector<FrozenAddress*> s_frozenAddresses;\n\n        static inline DmntCheatProcessMetadata s_processMetadata;\n    };\n\n} "
  },
  {
    "path": "include/cheat_engine_types.hpp",
    "content": "/**\n * Copyright (C) 2019 - 2020 WerWolv\n * \n * This file is part of EdiZon.\n * \n * EdiZon is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n * \n * EdiZon is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with EdiZon.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#pragma once\n\n#include <cstring>\n#include <vector>\n\nnamespace edz::cheat::types {\n\n    struct Region {\n        u64 baseAddress;\n        u64 size;\n\n        bool contains(u64 addr) {\n            return addr >= baseAddress && addr < (baseAddress + size);\n        }\n    };\n\n    enum class Signedness {\n        Unsigned,\n        Signed\n    };\n\n    class Pattern {\n    public:\n        Pattern() : m_pattern(nullptr), m_size(0) { }\n        Pattern(u8 *pattern, std::size_t size) : m_pattern(pattern), m_size(size) {}\n\n        void setPattern(u8 *pattern) { this->m_pattern = pattern; }\n        void setSize(std::size_t size) { this->m_size = size; }\n        void setSignedness(Signedness signedness) { this->m_signedness = signedness; }\n\n        bool operator==(Pattern& other) {\n            if (this->m_size != other.m_size) return false;\n\n            return std::memcmp(this->m_pattern, other.m_pattern, this->m_size) == 0;\n        }\n\n        bool operator!=(Pattern& other) {\n            return !operator==(other);\n        }\n\n        bool operator>(Pattern& other) {\n            if (this->m_size != other.m_size) return false;\n\n            if (this->m_signedness == Signedness::Signed) {\n                if ((reinterpret_cast<u8*>(this->m_pattern)[this->m_size - 1] & 0x80) > (reinterpret_cast<u8*>(other.m_pattern)[this->m_size - 1] & 0x80))\n                    return false;\n\n                for (s8 i = this->m_size - 1; i >= 0; i--)\n                    if (reinterpret_cast<u8*>(this->m_pattern)[i] > reinterpret_cast<u8*>(other.m_pattern)[i])\n                        return true;\n            } else {\n                for (s8 i = this->m_size - 1; i >= 0; i--) {\n                    if (reinterpret_cast<u8*>(this->m_pattern)[i] > reinterpret_cast<u8*>(other.m_pattern)[i])\n                        return true;\n                }\n            }\n\n            return false;\n        }\n\n        bool operator<(Pattern& other) {\n            if (this->m_size != other.m_size) return false;\n\n            if (this->m_signedness == Signedness::Signed) {\n                if ((reinterpret_cast<u8*>(this->m_pattern)[this->m_size - 1] & 0x80) < (reinterpret_cast<u8*>(other.m_pattern)[this->m_size - 1] & 0x80))\n                    return false;\n\n                for (s8 i = 0; i < this->m_size; i++)\n                    if (reinterpret_cast<u8*>(this->m_pattern)[i] < reinterpret_cast<u8*>(other.m_pattern)[i])\n                        return true;\n            } else {\n                for (s8 i = 0; i < this->m_size; i++) {\n                    if (reinterpret_cast<u8*>(this->m_pattern)[i] < reinterpret_cast<u8*>(other.m_pattern)[i])\n                        return true;\n                }\n            }\n\n            return false;\n        }\n\n    private:\n        u8 *m_pattern;\n        ssize_t m_size;\n        Signedness m_signedness;\n    };\n\n\n    using Operation = bool(Pattern::*)(Pattern&);\n    #define STRATEGY(operation) &edz::cheat::types::Pattern::operator operation\n\n}"
  },
  {
    "path": "include/dmntcht.h",
    "content": "/*\n * Copyright (c) Atmosphère-NX\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#pragma once\n#include <switch.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct {\n    u64 base;\n    u64 size;\n} DmntMemoryRegionExtents;\n\ntypedef struct {\n    u64 process_id;\n    u64 title_id;\n    DmntMemoryRegionExtents main_nso_extents;\n    DmntMemoryRegionExtents heap_extents;\n    DmntMemoryRegionExtents alias_extents;\n    DmntMemoryRegionExtents address_space_extents;\n    u8 main_nso_build_id[0x20];\n} DmntCheatProcessMetadata;\n\ntypedef struct {\n    char readable_name[0x40];\n    uint32_t num_opcodes;\n    uint32_t opcodes[0x100];\n} DmntCheatDefinition;\n\ntypedef struct {\n    bool enabled;\n    uint32_t cheat_id;\n    DmntCheatDefinition definition;\n} DmntCheatEntry;\n\ntypedef struct {\n    u64 value;\n    u8 width;\n} DmntFrozenAddressValue;\n\ntypedef struct {\n    u64 address;\n    DmntFrozenAddressValue value;\n} DmntFrozenAddressEntry;\n\nResult dmntchtInitialize(void);\nvoid dmntchtExit(void);\nService* dmntchtGetServiceSession(void);\n\nResult dmntchtHasCheatProcess(bool *out);\nResult dmntchtGetCheatProcessEvent(Event *event);\nResult dmntchtGetCheatProcessMetadata(DmntCheatProcessMetadata *out_metadata);\nResult dmntchtForceOpenCheatProcess(void);\nResult dmntchtForceCloseCheatProcess(void);\n\nResult dmntchtGetCheatProcessMappingCount(u64 *out_count);\nResult dmntchtGetCheatProcessMappings(MemoryInfo *buffer, u64 max_count, u64 offset, u64 *out_count);\nResult dmntchtReadCheatProcessMemory(u64 address, void *buffer, size_t size);\nResult dmntchtWriteCheatProcessMemory(u64 address, const void *buffer, size_t size);\nResult dmntchtQueryCheatProcessMemory(MemoryInfo *mem_info, u64 address);\nResult dmntchtPauseCheatProcess(void);\nResult dmntchtResumeCheatProcess(void);\n\nResult dmntchtGetCheatCount(u64 *out_count);\nResult dmntchtGetCheats(DmntCheatEntry *buffer, u64 max_count, u64 offset, u64 *out_count);\nResult dmntchtGetCheatById(DmntCheatEntry *out_cheat, u32 cheat_id);\nResult dmntchtToggleCheat(u32 cheat_id);\nResult dmntchtAddCheat(DmntCheatDefinition *cheat, bool enabled, u32 *out_cheat_id);\nResult dmntchtRemoveCheat(u32 cheat_id);\nResult dmntchtReadStaticRegister(u64 *out, u8 which);\nResult dmntchtWriteStaticRegister(u8 which, u64 value);\nResult dmntchtResetStaticRegisters();\nResult dmntchtSetMasterCheat(DmntCheatDefinition *cheat);\n\nResult dmntchtGetFrozenAddressCount(u64 *out_count);\nResult dmntchtGetFrozenAddresses(DmntFrozenAddressEntry *buffer, u64 max_count, u64 offset, u64 *out_count);\nResult dmntchtGetFrozenAddress(DmntFrozenAddressEntry *out, u64 address);\nResult dmntchtEnableFrozenAddress(u64 address, u64 width, u64 *out_value);\nResult dmntchtDisableFrozenAddress(u64 address);\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "include/result.hpp",
    "content": "/**\n * Copyright (C) 2019 - 2020 WerWolv\n * \n * This file is part of EdiZon.\n * \n * EdiZon is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n * \n * EdiZon is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with EdiZon.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#pragma once\n\n#include <switch.h>\n#include <string>\n\n#define MODULE_EDIZONHB  337\n#define MODULE_EDIZONSYS 338\n\nnamespace edz {\n\n    class EResult {\n    public:\n        constexpr EResult() : m_module(0), m_desc(0) {}\n\n        constexpr EResult(u32 module, u32 desc) : m_module(module), m_desc(desc) {}\n\n        constexpr EResult(Result result) : m_module(static_cast<u32>(R_MODULE(result))), m_desc(static_cast<u32>(R_DESCRIPTION(result))) {}\n\n        constexpr u32 getModule() {\n            return this->m_module;\n        }\n\n        constexpr u32 getDescription() {\n            return this->m_desc;\n        }\n\n        std::string getString() {\n            char buffer[0x20];\n            sprintf(buffer, \"2%03d-%04d (0x%x)\", this->getModule(), this->getDescription(), static_cast<u32>(*this));\n\n            return buffer;\n        }\n\n\n        constexpr bool operator==(EResult &other) {\n            return this->getDescription() == other.getDescription();\n        }\n\n        constexpr bool operator!=(EResult &other) {\n            return this->getDescription() != other.getDescription();\n        }\n\n        constexpr bool operator==(Result &other) {\n            return this->getDescription() == EResult(other).getDescription() && this->getDescription() == EResult(other).getModule();\n        }\n\n        constexpr bool operator!=(Result &other) {\n            return this->getDescription() != EResult(other).getDescription() || this->getDescription() != EResult(other).getModule();\n        }\n\n        constexpr EResult operator=(u32 &other) {\n            return Result(other);\n        }\n\n        constexpr EResult operator=(EResult &other) {\n            return EResult(other.getDescription());\n        }\n\n        constexpr EResult operator=(Result other) {\n            return EResult(static_cast<u32>(other));\n        }\n\n        constexpr operator u32() const { \n            return MAKERESULT(this->m_module, this->m_desc);\n        }\n\n        constexpr bool succeeded() {\n            return this->m_module == 0 && this->m_desc == 0;\n        }\n\n        constexpr bool failed() {\n            return !this->succeeded();\n        }\n\n    private:\n        const u32 m_module, m_desc;\n    };\n\n    template<typename T>\n    using EResultVal = std::pair<EResult, T>;\n    \n}"
  },
  {
    "path": "include/results.hpp",
    "content": "/**\n * Copyright (C) 2019 - 2020 WerWolv\n * \n * This file is part of EdiZon.\n * \n * EdiZon is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n * \n * EdiZon is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with EdiZon.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#pragma once\n\n#include <switch.h>\n#include \"result.hpp\"\n\nnamespace edz {\n\n    #define EDZHBRES(desc)  MAKERESULT(MODULE_EDIZONHB, desc)\n    #define EDZSYSRES(desc) MAKERESULT(MODULE_EDIZONSYS, desc)\n\n    /* Common error codes */\n    constexpr EResult ResultSuccess                          = MAKERESULT(0, 0);\n\n    /* Homebrew error codes */\n    constexpr EResult ResultEdzBorealisInitFailed            = EDZHBRES(1);\n    constexpr EResult ResultEdzCurlInitFailed                = EDZHBRES(2);\n    constexpr EResult ResultEdzNotYetImplemented             = EDZHBRES(3);\n    constexpr EResult ResultEdzErrorDuringErrorHandling      = EDZHBRES(4);\n    constexpr EResult ResultEdzNotFound                      = EDZHBRES(5);\n    constexpr EResult ResultEdzOperationFailed               = EDZHBRES(6);\n\n    constexpr EResult ResultEdzSysmoduleAlreadyRunning       = EDZHBRES(101);\n    constexpr EResult ResultEdzSysmoduleNotRunning           = EDZHBRES(102);\n    constexpr EResult ResultEdzSysmoduleLaunchFailed         = EDZHBRES(103);\n    constexpr EResult ResultEdzSysmoduleTerminationFailed    = EDZHBRES(104);\n\n    constexpr EResult ResultEdzEditorNoConfigFound           = EDZHBRES(201);\n    constexpr EResult ResultEdzEditorNoScriptFound           = EDZHBRES(202);\n    constexpr EResult ResultEdzEditorConfigOutdated          = EDZHBRES(203);\n    constexpr EResult ResultEdzEditorScriptSyntaxError       = EDZHBRES(204);\n    constexpr EResult ResultEdzEditorTooManyRedirects        = EDZHBRES(205);\n    constexpr EResult ResultEdzEditorAlreadyLoaded           = EDZHBRES(206);\n    constexpr EResult ResultEdzEditorNotLoaded               = EDZHBRES(207);\n    constexpr EResult ResultEdzEditorLoadFailed              = EDZHBRES(208);\n    constexpr EResult ResultEdzEditorStoreFailed             = EDZHBRES(209);\n\n    constexpr EResult ResultEdzScriptRuntimeError            = EDZHBRES(301);\n    constexpr EResult ResultEdzScriptInvalidArgument         = EDZHBRES(302);\n\n    constexpr EResult ResultEdzCurlError                     = EDZHBRES(401);\n    constexpr EResult ResultEdzAPIError                      = EDZHBRES(402);\n\n    constexpr EResult ResultEdzSaveNoSaveFS                  = EDZHBRES(501);\n    constexpr EResult ResultEdzSaveNoSuchBackup              = EDZHBRES(502);\n    constexpr EResult ResultEdzSaveInvalidArgument           = EDZHBRES(503);\n\n    constexpr EResult ResultEdzCheatParsingFailed            = EDZHBRES(601);\n    constexpr EResult ResultEdzCheatServiceNotAvailable      = EDZHBRES(602);\n\n    constexpr EResult ResultEdzMemoryReadFailed              = EDZHBRES(701);\n    constexpr EResult ResultEdzMemoryOverflow                = EDZHBRES(702);\n    constexpr EResult ResultEdzOutOfRange                    = EDZHBRES(703);\n    constexpr EResult ResultEdzNoValuesFound                 = EDZHBRES(704);\n    constexpr EResult ResultEdzInvalidOperation              = EDZHBRES(705);\n\n    /* SysmoduEle error codes */\n    constexpr EResult ResultEdzAlreadyRegistered              = EDZSYSRES(1);\n    constexpr EResult ResultEdzUnknownButtonID                = EDZSYSRES(2);\n    constexpr EResult ResultEdzInvalidButtonCombination       = EDZSYSRES(3);\n    constexpr EResult ResultEdzAttachFailed                   = EDZSYSRES(4);\n    constexpr EResult ResultEdzDetachFailed                   = EDZSYSRES(5);\n    constexpr EResult ResultEdzInvalidBuffer                  = EDZSYSRES(6);\n\n    constexpr EResult ResultEdzTCPInitFailed                  = EDZSYSRES(101);\n    constexpr EResult ResultEdzUSBInitFailed                  = EDZSYSRES(102);\n    constexpr EResult ResultEdzScreenInitFailed               = EDZSYSRES(103);\n    constexpr EResult ResultEdzFontInitFailed                 = EDZSYSRES(104);\n\n    constexpr EResult ResultEdzSocketInitFailed               = EDZSYSRES(201);\n\n    constexpr EResult ResultEdzAbortFailed                    = EDZSYSRES(301);\n}"
  },
  {
    "path": "include/service_guard.h",
    "content": "#pragma once\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <switch/types.h>\n#include <switch/result.h>\n#include <switch/kernel/mutex.h>\n#include <switch/sf/service.h>\n#include <switch/services/sm.h>\n\ntypedef struct ServiceGuard {\n    Mutex mutex;\n    u32 refCount;\n} ServiceGuard;\n\nNX_INLINE bool serviceGuardBeginInit(ServiceGuard* g)\n{\n    mutexLock(&g->mutex);\n    return (g->refCount++) == 0;\n}\n\nNX_INLINE Result serviceGuardEndInit(ServiceGuard* g, Result rc, void (*cleanupFunc)(void))\n{\n    if (R_FAILED(rc)) {\n        cleanupFunc();\n        --g->refCount;\n    }\n    mutexUnlock(&g->mutex);\n    return rc;\n}\n\nNX_INLINE void serviceGuardExit(ServiceGuard* g, void (*cleanupFunc)(void))\n{\n    mutexLock(&g->mutex);\n    if (g->refCount && (--g->refCount) == 0)\n        cleanupFunc();\n    mutexUnlock(&g->mutex);\n}\n\n#define NX_GENERATE_SERVICE_GUARD_PARAMS(name, _paramdecl, _parampass) \\\n\\\nstatic ServiceGuard g_##name##Guard; \\\nNX_INLINE Result _##name##Initialize _paramdecl; \\\nstatic void _##name##Cleanup(void); \\\n\\\nResult name##Initialize _paramdecl \\\n{ \\\n    Result rc = 0; \\\n    if (serviceGuardBeginInit(&g_##name##Guard)) \\\n        rc = _##name##Initialize _parampass; \\\n    return serviceGuardEndInit(&g_##name##Guard, rc, _##name##Cleanup); \\\n} \\\n\\\nvoid name##Exit(void) \\\n{ \\\n    serviceGuardExit(&g_##name##Guard, _##name##Cleanup); \\\n}\n\n#define NX_GENERATE_SERVICE_GUARD(name) NX_GENERATE_SERVICE_GUARD_PARAMS(name, (void), ())\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "include/utils.hpp",
    "content": "#pragma once\n\n#include <string>\n#include <sstream>\n#include <iomanip>\n#include <cstring>\n\n/* C++ style sprintf */\ntemplate <typename ...Args>\nstd::string formatString(const std::string& format, Args && ...args) {\n    auto size = std::snprintf(nullptr, 0, format.c_str(), args...);\n    char output[size + 1];\n    std::memset(output, ' ', sizeof(output));\n    std::sprintf(output, format.c_str(), args...);\n\n    return output;\n}"
  },
  {
    "path": "source/cheat.cpp",
    "content": "/**\n * Copyright (C) 2019 - 2020 WerWolv\n * \n * This file is part of EdiZon.\n * \n * EdiZon is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n * \n * EdiZon is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with EdiZon.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include \"cheat.hpp\"\n\n#include <cstring>\n\nnamespace edz::cheat {\n\n    bool Succeeded(Result res){\n        return (R_MODULE(res) == 0 && R_DESCRIPTION(res) == 0);\n    }\n\n    /////// Cheat Type ///////\n\n    Cheat::Cheat(DmntCheatEntry cheatEntry) : m_name(cheatEntry.definition.readable_name), m_id(cheatEntry.cheat_id) {\n\n    }\n\n    std::string Cheat::getName() {\n        return this->m_name;\n    }\n\n    u32 Cheat::getID() {\n        return this->m_id;\n    }\n\n    bool Cheat::toggle() {\n        dmntchtToggleCheat(getID());\n\n        return isEnabled();\n    }\n\n    bool Cheat::setState(bool state) {\n        bool ret = state;\n        if (isEnabled() != state)\n            ret = this->toggle();\n        \n        return ret;\n    }\n\n    bool Cheat::isEnabled() {\n        DmntCheatEntry cheatEntry;\n\n        if (!Succeeded(dmntchtGetCheatById(&cheatEntry, getID()))) {\n            return false;\n        }\n\n        return cheatEntry.enabled;\n    }\n\n\n    /////// FrozenAddress Type ///////\n\n    FrozenAddress::FrozenAddress(DmntFrozenAddressEntry frozenAddressEntry) : m_frozenAddressEntry(frozenAddressEntry), m_frozen(true) {\n\n    }\n\n    FrozenAddress::FrozenAddress(u64 address, u8 width, u64 value) : m_frozen(false) {\n        this->m_frozenAddressEntry.address        = address;\n        this->m_frozenAddressEntry.value.width    = width;\n        this->m_frozenAddressEntry.value.value    = value;\n    }\n\n    FrozenAddress::FrozenAddress(u64 address, u8 width) : m_frozen(false) {\n        this->m_frozenAddressEntry.address        = address;\n        this->m_frozenAddressEntry.value.width    = width;\n    }\n\n\n    u64 FrozenAddress::getAddress() {\n        return this->m_frozenAddressEntry.address;\n    }\n\n    u8 FrozenAddress::getWidth() {\n        return this->m_frozenAddressEntry.value.width;\n    }\n\n    u64 FrozenAddress::getValue() {\n        return this->m_frozenAddressEntry.value.value;\n    }\n\n    u64 FrozenAddress::setValue(u64 value, u8 width) {\n        bool wasFrozen = isFrozen();\n        u64 newValue = 0;\n\n        dmntchtDisableFrozenAddress(getAddress());\n\n        dmntchtWriteCheatProcessMemory(getAddress(), &value, width);\n\n        if (wasFrozen) {\n            if (Succeeded(dmntchtEnableFrozenAddress(getAddress(), getWidth(), &newValue)))\n                return -1;\n        }\n\n        // Check if the value was set correctly\n        if (std::memcmp(&value, &newValue, width) == 0) {\n            this->m_frozenAddressEntry.value.value = newValue;\n            this->m_frozenAddressEntry.value.width = width;\n                    \n            return newValue;\n        }\n\n        return -1;\n    }\n\n\n    bool FrozenAddress::toggle() {\n        if (isFrozen()) {\n            if (Succeeded(dmntchtDisableFrozenAddress(getAddress())))\n                this->m_frozen = false;\n        }\n        else {\n            if (Succeeded(dmntchtEnableFrozenAddress(getAddress(), getWidth(), &m_frozenAddressEntry.value.value)))\n                this->m_frozen = true;\n        }\n\n        return isFrozen();\n    }\n\n    bool FrozenAddress::isFrozen() {\n        return this->m_frozen;\n    }\n\n\n    /////// FrozenAddress Type ///////\n\n    Result CheatManager::initialize() {\n        dmntchtInitialize();\n        return CheatManager::reload();\n    }   \n\n    void CheatManager::exit() {\n        dmntchtExit();\n        for (auto &cheat : CheatManager::s_cheats)\n            delete cheat;\n        CheatManager::s_cheats.clear();\n\n        for (auto &frozenAddress : CheatManager::s_frozenAddresses)\n            delete frozenAddress;\n        CheatManager::s_frozenAddresses.clear();\n    }\n\n\n    bool CheatManager::isCheatServiceAvailable() {\n        static s8 running = -1;\n        if (running == -1){\n            Handle handle;\n            SmServiceName service_name = smEncodeName(\"dmnt:cht\");\n            running = R_FAILED(smRegisterService(&handle, service_name, false, 1));\n\n            svcCloseHandle(handle);\n\n            if (!running)\n                smUnregisterService(service_name);\n        }\n        return !!running; \n    }\n\n    Result CheatManager::forceAttach() {\n        if (!CheatManager::isCheatServiceAvailable())\n            return ResultEdzCheatServiceNotAvailable;\n\n        uint64_t PID = 0;\n        for(int i = 0; i < 10; i++) {\n            if (R_SUCCEEDED(pmdmntGetApplicationProcessId(&PID))) {\n                return dmntchtForceOpenCheatProcess();\n            }\n        }\n        return ResultEdzAttachFailed;\n    }\n\n    bool CheatManager::hasCheatProcess() {\n        if (R_FAILED(CheatManager::forceAttach()))\n            return false;\n\n        bool hasCheatProcess;\n\n        dmntchtHasCheatProcess(&hasCheatProcess);\n\n        return hasCheatProcess;\n    }\n\n\n    u64 CheatManager::getTitleID() {\n        return CheatManager::s_processMetadata.title_id;\n    }\n\n    u64 CheatManager::getProcessID() {\n        return CheatManager::s_processMetadata.process_id;\n    }\n\n    u64 CheatManager::getBuildID() {\n        u64 buildid = 0;\n\n        std::memcpy(&buildid, CheatManager::s_processMetadata.main_nso_build_id, sizeof(u64));\n        \n        return __builtin_bswap64(buildid);;\n    }\n\n\n    types::Region CheatManager::getBaseRegion() {\n        if (!CheatManager::isCheatServiceAvailable())\n            return { };\n\n        return types::Region{ CheatManager::s_processMetadata.address_space_extents.base, CheatManager::s_processMetadata.address_space_extents.size };\n    }\n\n    types::Region CheatManager::getHeapRegion() {\n        if (!CheatManager::isCheatServiceAvailable())\n            return { };\n\n        return types::Region{ CheatManager::s_processMetadata.heap_extents.base, CheatManager::s_processMetadata.heap_extents.size };\n    }\n\n    types::Region CheatManager::getMainRegion() {\n        if (!CheatManager::isCheatServiceAvailable())\n            return { };\n\n        return types::Region{ CheatManager::s_processMetadata.main_nso_extents.base, CheatManager::s_processMetadata.main_nso_extents.size };\n    }\n\n    types::Region CheatManager::getAliasRegion() {\n        if (!CheatManager::isCheatServiceAvailable())\n            return { };\n\n        return types::Region{ CheatManager::s_processMetadata.alias_extents.base, CheatManager::s_processMetadata.alias_extents.size };\n    }\n\n\n    /*EResultVal<std::string> CheatManager::getCheatFile() {\n        if (!CheatManager::isCheatServiceAvailable())\n            return { ResultEdzCheatServiceNotAvailable, \"\" };\n        \n        std::string expectedFileName = hlp::toHexString(CheatManager::getBuildID()) + \".txt\";\n\n        for (auto &[fileName, file] : hlp::Folder(EDIZON_CHEATS_DIR).getFiles()) {\n            if (strcasecmp(expectedFileName.c_str(), fileName.c_str()) == 0)\n                return { ResultSuccess, fileName };\n        }\n            \n        return { ResultEdzNotFound, \"\" }; \n    }\n\n\n    EResultVal<u32> CheatManager::addCheat(DmntCheatDefinition cheatDefinition, bool enabled) {\n        if (!CheatManager::isCheatServiceAvailable())\n            return { ResultEdzCheatServiceNotAvailable, 0 };\n\n        u32 cheatID = 0;\n        Result res;\n        \n        if (res = dmntchtAddCheat(&cheatDefinition, enabled, &cheatID); !Succeeded(res))\n            return { res, 0 };\n\n        if (res = CheatManager::reload(); !Succeeded(res))\n            return { res, 0 };\n\n        return { res, cheatID };\n    }*/\n\n    Result CheatManager::removeCheat(u32 cheatID) {\n        if (!CheatManager::isCheatServiceAvailable())\n            return ResultEdzCheatServiceNotAvailable;\n\n        Result res;\n\n        if (res = dmntchtRemoveCheat(cheatID); !Succeeded(res))\n            return res;\n\n        return CheatManager::reload();\n    }\n\n\n    std::vector<Cheat*>& CheatManager::getCheats() {\n        return CheatManager::s_cheats;\n    }\n\n    std::vector<FrozenAddress*>& CheatManager::getFrozenAddresses() {\n        return CheatManager::s_frozenAddresses;\n    }\n\n\n    MemoryInfo CheatManager::queryMemory(u64 address) {\n        if (!CheatManager::isCheatServiceAvailable())\n            return { 0 };\n\n        MemoryInfo memInfo = { 0 };\n\n        dmntchtQueryCheatProcessMemory(&memInfo, address);\n\n        return memInfo;\n    }\n\n    std::vector<MemoryInfo> CheatManager::getMemoryRegions() {\n        if (!CheatManager::isCheatServiceAvailable())\n            return EMPTY_RESPONSE;\n\n        MemoryInfo memInfo = { 0 };\n        std::vector<MemoryInfo> memInfos;\n\n        u64 lastAddress = 0;\n\n        do {\n            lastAddress = memInfo.addr;\n\n            memInfo = queryMemory(memInfo.addr + memInfo.size);\n            memInfos.push_back(memInfo);\n        } while (lastAddress < (memInfo.addr + memInfo.size));\n\n        return memInfos;\n    }\n\n\n    Result CheatManager::readMemory(u64 address, void *buffer, size_t bufferSize) {\n        if (!CheatManager::isCheatServiceAvailable())\n            return ResultEdzCheatServiceNotAvailable;\n\n        return dmntchtReadCheatProcessMemory(address, buffer, bufferSize);\n    }\n\n    Result CheatManager::writeMemory(u64 address, const void *buffer, size_t bufferSize) {\n        if (!CheatManager::isCheatServiceAvailable())\n            return ResultEdzCheatServiceNotAvailable;\n\n        return dmntchtWriteCheatProcessMemory(address, buffer, bufferSize);\n    }\n\n    Result CheatManager::reload() {\n        if (!CheatManager::isCheatServiceAvailable())\n            return ResultEdzCheatServiceNotAvailable;\n\n        Result res;\n\n        if (R_FAILED(res = CheatManager::forceAttach()))\n            return res;\n\n        // Delete local cheats copy if there are any\n        for (auto &cheat : CheatManager::s_cheats)\n            delete cheat;\n        CheatManager::s_cheats.clear();\n\n        // Delete local frozen addresses copy if there are any\n        for (auto &frozenAddress : CheatManager::s_frozenAddresses)\n            delete frozenAddress;\n        CheatManager::s_frozenAddresses.clear();\n\n        // Get process metadata\n        if (res = dmntchtGetCheatProcessMetadata(&CheatManager::s_processMetadata); !Succeeded(res))\n            return res;\n\n\n        // Get all loaded cheats\n        u64 cheatCnt = 0;\n        if (res = dmntchtGetCheatCount(&cheatCnt); !Succeeded(res))\n            return res;\n\n        DmntCheatEntry *cheatEntries = new DmntCheatEntry[cheatCnt];\n\n        if (res = dmntchtGetCheats(cheatEntries, cheatCnt, 0, &cheatCnt); !Succeeded(res))\n            return res;\n        \n        CheatManager::s_cheats.reserve(cheatCnt);\n        for (u32 i = 0; i < cheatCnt; i++)\n            CheatManager::s_cheats.push_back(new Cheat(cheatEntries[i]));\n\n\n        // Get all frozen addresses\n        u64 frozenAddressCnt = 0;\n        if (res = dmntchtGetFrozenAddressCount(&frozenAddressCnt); !Succeeded(res))\n            return res;\n\n        DmntFrozenAddressEntry frozenAddressEntries[frozenAddressCnt];\n        \n        if (res = dmntchtGetFrozenAddresses(frozenAddressEntries, frozenAddressCnt, 0, &frozenAddressCnt); !Succeeded(res))\n            return res;\n\n        CheatManager::s_frozenAddresses.reserve(frozenAddressCnt);\n        for (auto &frozenAddressEntry : frozenAddressEntries)\n            CheatManager::s_frozenAddresses.push_back(new FrozenAddress(frozenAddressEntry));\n\n        return res;\n    }\n\n}\n"
  },
  {
    "path": "source/dmntcht.c",
    "content": "/*\n * Copyright (c) Atmosphère-NX\n *\n * This program is free software; you can redistribute it and/or modify it\n * under the terms and conditions of the GNU General Public License,\n * version 2, as published by the Free Software Foundation.\n *\n * This program is distributed in the hope it will be useful, but WITHOUT\n * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\n * more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n#define NX_SERVICE_ASSUME_NON_DOMAIN\n#include \"service_guard.h\"\n#include \"dmntcht.h\"\n\nstatic Service g_dmntchtSrv;\n\nNX_GENERATE_SERVICE_GUARD(dmntcht);\n\nResult _dmntchtInitialize(void) {\n    return smGetService(&g_dmntchtSrv, \"dmnt:cht\");\n}\n\nvoid _dmntchtCleanup(void) {\n    serviceClose(&g_dmntchtSrv);\n}\n\nService* dmntchtGetServiceSession(void) {\n    return &g_dmntchtSrv;\n}\n\nResult dmntchtHasCheatProcess(bool *out) {\n    u8 tmp;\n    Result rc = serviceDispatchOut(&g_dmntchtSrv, 65000, tmp);\n    if (R_SUCCEEDED(rc) && out) *out = tmp & 1;\n    return rc;\n}\n\nResult dmntchtGetCheatProcessEvent(Event *event) {\n    Handle evt_handle;\n    Result rc = serviceDispatch(&g_dmntchtSrv, 65001,\n        .out_handle_attrs = { SfOutHandleAttr_HipcCopy },\n        .out_handles = &evt_handle,\n    );\n\n    if (R_SUCCEEDED(rc)) {\n        eventLoadRemote(event, evt_handle, true);\n    }\n\n    return rc;\n}\n\nResult dmntchtGetCheatProcessMetadata(DmntCheatProcessMetadata *out_metadata) {\n    return serviceDispatchOut(&g_dmntchtSrv, 65002, *out_metadata);\n}\n\nstatic Result _dmntchtCmdVoid(Service* srv, u32 cmd_id) {\n    return serviceDispatch(srv, cmd_id);\n}\n\nResult dmntchtForceOpenCheatProcess(void) {\n    return _dmntchtCmdVoid(&g_dmntchtSrv, 65003);\n}\n\nResult dmntchtPauseCheatProcess(void) {\n    return _dmntchtCmdVoid(&g_dmntchtSrv, 65004);\n}\n\nResult dmntchtResumeCheatProcess(void) {\n    return _dmntchtCmdVoid(&g_dmntchtSrv, 65005);\n}\n\nResult dmntchtForceCloseCheatProcess(void) {\n    return _dmntchtCmdVoid(&g_dmntchtSrv, 65006);\n}\n\nstatic Result _dmntchtGetCount(u64 *out_count, u32 cmd_id) {\n    return serviceDispatchOut(&g_dmntchtSrv, cmd_id, *out_count);\n}\n\nstatic Result _dmntchtGetEntries(void *buffer, u64 buffer_size, u64 offset, u64 *out_count, u32 cmd_id) {\n    return serviceDispatchInOut(&g_dmntchtSrv, cmd_id, offset, *out_count,\n        .buffer_attrs = { SfBufferAttr_Out | SfBufferAttr_HipcMapAlias },\n        .buffers = { { buffer, buffer_size } },\n    );\n}\n\nstatic Result _dmntchtCmdInU32NoOut(u32 in, u32 cmd_id) {\n    return serviceDispatchIn(&g_dmntchtSrv, cmd_id, in);\n}\n\nResult dmntchtGetCheatProcessMappingCount(u64 *out_count) {\n    return _dmntchtGetCount(out_count, 65100);\n}\n\nResult dmntchtGetCheatProcessMappings(MemoryInfo *buffer, u64 max_count, u64 offset, u64 *out_count) {\n    return _dmntchtGetEntries(buffer, sizeof(*buffer) * max_count, offset, out_count, 65101);\n}\n\nResult dmntchtReadCheatProcessMemory(u64 address, void *buffer, size_t size) {\n    const struct {\n        u64 address;\n        u64 size;\n    } in = { address, size };\n    return serviceDispatchIn(&g_dmntchtSrv, 65102, in,\n        .buffer_attrs = { SfBufferAttr_Out | SfBufferAttr_HipcMapAlias },\n        .buffers = { { buffer, size } },\n    );\n}\n\nResult dmntchtWriteCheatProcessMemory(u64 address, const void *buffer, size_t size) {\n    const struct {\n        u64 address;\n        u64 size;\n    } in = { address, size };\n    return serviceDispatchIn(&g_dmntchtSrv, 65103, in,\n        .buffer_attrs = { SfBufferAttr_In | SfBufferAttr_HipcMapAlias },\n        .buffers = { { buffer, size } },\n    );\n}\n\nResult dmntchtQueryCheatProcessMemory(MemoryInfo *mem_info, u64 address){\n    return serviceDispatchInOut(&g_dmntchtSrv, 65104, address, *mem_info);\n}\n\nResult dmntchtGetCheatCount(u64 *out_count) {\n    return _dmntchtGetCount(out_count, 65200);\n}\n\nResult dmntchtGetCheats(DmntCheatEntry *buffer, u64 max_count, u64 offset, u64 *out_count) {\n    return _dmntchtGetEntries(buffer, sizeof(*buffer) * max_count, offset, out_count, 65201);\n}\n\nResult dmntchtGetCheatById(DmntCheatEntry *out, u32 cheat_id) {\n    return serviceDispatchIn(&g_dmntchtSrv, 65202, cheat_id,\n        .buffer_attrs = { SfBufferAttr_Out | SfBufferAttr_HipcMapAlias | SfBufferAttr_FixedSize },\n        .buffers = { { out, sizeof(*out) } },\n    );\n}\n\nResult dmntchtToggleCheat(u32 cheat_id) {\n    return _dmntchtCmdInU32NoOut(cheat_id, 65203);\n}\n\nResult dmntchtAddCheat(DmntCheatDefinition *cheat_def, bool enabled, u32 *out_cheat_id) {\n    const u8 in = enabled != 0;\n    return serviceDispatchInOut(&g_dmntchtSrv, 65204, in, *out_cheat_id,\n        .buffer_attrs = { SfBufferAttr_In | SfBufferAttr_HipcMapAlias | SfBufferAttr_FixedSize },\n        .buffers = { { cheat_def, sizeof(*cheat_def) } },\n    );\n}\n\nResult dmntchtRemoveCheat(u32 cheat_id) {\n    return _dmntchtCmdInU32NoOut(cheat_id, 65205);\n}\n\nResult dmntchtReadStaticRegister(u64 *out, u8 which) {\n    return serviceDispatchInOut(&g_dmntchtSrv, 65206, which, *out);\n}\n\nResult dmntchtWriteStaticRegister(u8 which, u64 value) {\n    const struct {\n        u64 which;\n        u64 value;\n    } in = { which, value };\n\n    return serviceDispatchIn(&g_dmntchtSrv, 65207, in);\n}\n\nResult dmntchtResetStaticRegisters() {\n    return _dmntchtCmdVoid(&g_dmntchtSrv, 65208);\n}\n\nResult dmntchtSetMasterCheat(DmntCheatDefinition *cheat_def)  {\n    return serviceDispatch(&g_dmntchtSrv, 65209,\n        .buffer_attrs = { SfBufferAttr_In | SfBufferAttr_HipcMapAlias | SfBufferAttr_FixedSize },\n        .buffers = { { cheat_def, sizeof(*cheat_def) } },\n    );\n}\n\nResult dmntchtGetFrozenAddressCount(u64 *out_count) {\n    return _dmntchtGetCount(out_count, 65300);\n}\n\nResult dmntchtGetFrozenAddresses(DmntFrozenAddressEntry *buffer, u64 max_count, u64 offset, u64 *out_count) {\n    return _dmntchtGetEntries(buffer, sizeof(*buffer) * max_count, offset, out_count, 65301);\n}\n\nResult dmntchtGetFrozenAddress(DmntFrozenAddressEntry *out, u64 address) {\n    return serviceDispatchInOut(&g_dmntchtSrv, 65302, address, *out);\n}\n\nResult dmntchtEnableFrozenAddress(u64 address, u64 width, u64 *out_value) {\n    const struct {\n        u64 address;\n        u64 width;\n    } in = { address, width };\n    return serviceDispatchInOut(&g_dmntchtSrv, 65303, in, *out_value);\n}\n\nResult dmntchtDisableFrozenAddress(u64 address) {\n    return serviceDispatchIn(&g_dmntchtSrv, 65304, address);\n}\n"
  },
  {
    "path": "source/main.cpp",
    "content": "/**\n * Copyright (C) 2019 - 2020 WerWolv\n * \n * This file is part of EdiZon\n * \n * EdiZon is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n * \n * EdiZon is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with EdiZon.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#define TESLA_INIT_IMPL\n#include <tesla.hpp>\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <switch.h>\n\n#include <switch/nro.h>\n#include <switch/nacp.h>\n\n#include \"utils.hpp\"\n#include \"cheat.hpp\"\n\n#include <unistd.h>\n#include <netinet/in.h>\n\nclass GuiCheats;\n\nclass GuiStats;\n\nclass GuiMain : public tsl::Gui {\npublic:\n    GuiMain() { }\n\n    ~GuiMain() { }\n\n    virtual tsl::elm::Element* createUI() {\n        auto *rootFrame = new tsl::elm::HeaderOverlayFrame();\n        rootFrame->setHeader(new tsl::elm::CustomDrawer([this](tsl::gfx::Renderer *renderer, s32 x, s32 y, s32 w, s32 h) {\n            renderer->drawString(APP_TITLE, false, 20, 50, 32, (tsl::defaultOverlayColor));\n            renderer->drawString(APP_VERSION, false, 20, 52+23, 15, (tsl::bannerVersionTextColor));\n\n            if (edz::cheat::CheatManager::getProcessID() != 0) {\n                renderer->drawString(\"Program ID\", false, 150 +14, 40 -6, 15, (tsl::style::color::ColorText));\n                renderer->drawString(\"Build ID\", false, 150 +14, 60 -6, 15, (tsl::style::color::ColorText));\n                renderer->drawString(\"Process ID\", false, 150 +14, 80 -6, 15, (tsl::style::color::ColorText));\n                renderer->drawString(GuiMain::s_runningTitleIDString.c_str(), false, 250 +14, 40 -6, 15, (tsl::style::color::ColorHighlight));\n                renderer->drawString(GuiMain::s_runningBuildIDString.c_str(), false, 250 +14, 60 -6, 15, (tsl::style::color::ColorHighlight));\n                renderer->drawString(GuiMain::s_runningProcessIDString.c_str(), false, 250 +14, 80 -6, 15, (tsl::style::color::ColorHighlight));\n            }\n        }));\n\n        auto list = new tsl::elm::List();\n\n        if(edz::cheat::CheatManager::isCheatServiceAvailable()){\n            auto cheatsItem = new tsl::elm::ListItem(\"Cheats\");\n            cheatsItem->setClickListener([](s64 keys) {\n                if (keys & KEY_A) {\n                    tsl::changeTo<GuiCheats>(\"\");\n                    return true;\n                }\n                return false;\n            });\n            list->addItem(cheatsItem);\n        } else {\n            auto noDmntSvc = new tsl::elm::ListItem(\"Cheat Service Unavailable!\");\n            list->addItem(noDmntSvc);\n        }\n\n        auto statsItem  = new tsl::elm::ListItem(\"System Information\");\n        statsItem->setClickListener([](s64 keys) {\n            if (keys & KEY_A) {\n                tsl::changeTo<GuiStats>();\n                return true;\n            }\n            return false;\n        });\n        list->addItem(statsItem);\n\n        //list->disableCaching();\n        rootFrame->setContent(list);\n        return rootFrame;\n    }\n\n    virtual void update() { }\n\npublic:\n    static inline std::string s_runningTitleIDString;\n    static inline std::string s_runningProcessIDString;\n    static inline std::string s_runningBuildIDString;\n    static inline bool b_firstRun = true;\n};\n\n\nclass GuiCheats : public tsl::Gui {\npublic:\n    GuiCheats(std::string section) { \n        this->m_section = section;\n    }\n    ~GuiCheats() { }\n\n    virtual tsl::elm::Element* createUI() override {\n        auto rootFrame = new tsl::elm::HeaderOverlayFrame(97);\n\n        bool setOnce = true; // for ensuring header sync with frame caching for header overlayframe\n\n        rootFrame->setHeader(new tsl::elm::CustomDrawer([this, &setOnce](tsl::gfx::Renderer *renderer, s32 x, s32 y, s32 w, s32 h) {\n            renderer->drawString(APP_TITLE, false, 20, 50, 32, (tsl::defaultOverlayColor));\n\n            //static bool runOnce = true;\n            if (setOnce) {\n                renderer->drawString(APP_VERSION, false, 20, 52+23, 15, (tsl::bannerVersionTextColor));\n                setOnce = false;\n            } else {\n                renderer->drawString(\"Cheats\", false, 20, 52+23, 15, (tsl::bannerVersionTextColor));\n            }\n            \n\n            if (edz::cheat::CheatManager::getProcessID() != 0) {\n                renderer->drawString(\"Program ID\", false, 150 +14, 40 -6, 15, (tsl::style::color::ColorText));\n                renderer->drawString(\"Build ID\", false, 150 +14, 60 -6, 15, (tsl::style::color::ColorText));\n                renderer->drawString(\"Process ID\", false, 150 +14, 80 -6, 15, (tsl::style::color::ColorText));\n                renderer->drawString(GuiMain::s_runningTitleIDString.c_str(), false, 250 +14, 40 -6, 15, (tsl::style::color::ColorHighlight));\n                renderer->drawString(GuiMain::s_runningBuildIDString.c_str(), false, 250 +14, 60 -6, 15, (tsl::style::color::ColorHighlight));\n                renderer->drawString(GuiMain::s_runningProcessIDString.c_str(), false, 250 +14, 80 -6, 15, (tsl::style::color::ColorHighlight));\n            }\n        }));\n\n        if (edz::cheat::CheatManager::getCheats().size() == 0) {\n            auto warning = new tsl::elm::CustomDrawer([](tsl::gfx::Renderer *renderer, u16 x, u16 y, u16 w, u16 h){\n                renderer->drawString(\"\\uE150\", false, 180, 274, 90, (0xFFFF));\n                renderer->drawString(\"No Cheats loaded!\", false, 110, 360, 25, (0xFFFF));\n            });\n\n            rootFrame->setContent(warning);\n\n        } else {\n            auto list = new tsl::elm::List();\n            std::string head = \"Section: \" + this->m_section;\n\n            if(m_section.length() > 0) list->addItem(new tsl::elm::CategoryHeader(head));\n            else list->addItem(new tsl::elm::CategoryHeader(\"Available cheats\"));\n\n            bool skip = false, inSection = false, submenus = true;\n            std::string skipUntil = \"\";\n\n            for (auto &cheat : edz::cheat::CheatManager::getCheats()) {\n                if(cheat->getID() == 1 && cheat->getName().find(\"--DisableSubmenus--\") != std::string::npos)\n                    submenus = false;\n\n                if(submenus){\n                    // Find section start and end\n                    if(this->m_section.length() > 0 && !inSection && cheat->getName().find(\"--SectionStart:\" + this->m_section + \"--\") == std::string::npos) continue;\n                    else if(cheat->getName().find(\"--SectionStart:\" + this->m_section + \"--\") != std::string::npos) { inSection = true; continue; }\n                    else if(inSection && cheat->getName().find(\"--SectionEnd:\" + this->m_section + \"--\") != std::string::npos) break;\n\n                    // new section\n                    if(!skip && cheat->getName().find(\"--SectionStart:\") != std::string::npos){\n\n                        //remove formatting\n                        std::string name = cheat->getName();\n                        replaceAll(name, \"--\", \"\");\n                        replaceAll(name, \"SectionStart:\", \"\");\n\n                        //create submenu button\n                        auto cheatsSubmenu = new tsl::elm::ListItem(name);\n                        cheatsSubmenu->setClickListener([name = name](s64 keys) {\n                            if (keys & KEY_A) {\n                                tsl::changeTo<GuiCheats>(name);\n                                return true;\n                            }\n                            return false;\n                        });\n                        list->addItem(cheatsSubmenu);\n                        this->m_numCheats++;\n\n                        //skip over items in section\n                        skip = true;\n                        skipUntil = \"--SectionEnd:\" + name + \"--\";\n                    }\n                    // found end of child section\n                    else if (skip && cheat->getName().compare(skipUntil) == 0){\n                        skip = false;\n                        skipUntil = \"\";\n                    }\n                    // items to add to section\n                    else if(!skip && (inSection || this->m_section.length() < 1)) {\n                        std::string cheatNameCheck = cheat->getName();\n                        replaceAll(cheatNameCheck, \":ENABLED\", \"\");\n\n                        auto cheatToggleItem = new tsl::elm::ToggleListItem(/*formatString(\"%d:%s: %s\", cheat->getID(), (cheat->isEnabled() ? \"y\" : \"n\"),*/ cheatNameCheck/*.c_str()).c_str()*/, cheat->isEnabled());\n                        cheatToggleItem->setStateChangedListener([&cheat](bool state) { cheat->setState(state); });\n\n                        this->m_cheatToggleItems.insert({cheat->getID(), cheatToggleItem});\n                        list->addItem(cheatToggleItem);\n                        this->m_numCheats++;\n                    }\n                } else {\n                    if(cheat->getName().find(\"--SectionStart:\") != std::string::npos || cheat->getName().find(\"--SectionEnd:\") != std::string::npos || cheat->getName().find(\"--DisableSubmenus--\") != std::string::npos)\n                        continue;\n\n                    std::string cheatNameCheck = cheat->getName();\n                    replaceAll(cheatNameCheck, \":ENABLED\", \"\");\n\n                    auto cheatToggleItem = new tsl::elm::ToggleListItem(cheatNameCheck, cheat->isEnabled());\n                    cheatToggleItem->setStateChangedListener([&cheat](bool state) { cheat->setState(state); });\n\n                    this->m_cheatToggleItems.insert({cheat->getID(), cheatToggleItem});\n                    list->addItem(cheatToggleItem);\n                    this->m_numCheats++;\n                }\n            }\n\n            //list->disableCaching();\n\n            // display if no cheats in submenu\n            if(this->m_numCheats < 1){\n                auto warning = new tsl::elm::CustomDrawer([](tsl::gfx::Renderer *renderer, u16 x, u16 y, u16 w, u16 h){\n                    renderer->drawString(\"\\uE150\", false, 180, 250, 90, (0xFFFF));\n                    renderer->drawString(\"No Cheats in Submenu!\", false, 110, 340, 25, (0xFFFF));\n                });\n\n                rootFrame->setContent(warning);\n            } else rootFrame->setContent(list);\n        }\n\n        return rootFrame;\n    }\n\n    void replaceAll(std::string& str, const std::string& from, const std::string& to) {\n        if(from.empty())\n            return;\n        size_t start_pos = 0;\n        while((start_pos = str.find(from, start_pos)) != std::string::npos) {\n            str.replace(start_pos, from.length(), to);\n            start_pos += to.length();\n        }\n    }\n\n    virtual void update() override {\n        for (auto const& [cheatId, toggleElem] : this->m_cheatToggleItems)\n            for(auto &cheat : edz::cheat::CheatManager::getCheats())\n                if(cheat->getID() == cheatId)\n                    toggleElem->setState(cheat->isEnabled());\n    }\n\nprivate:\n    int m_numCheats = 0;\n    std::string m_section;\n    std::map<u32, tsl::elm::ToggleListItem*> m_cheatToggleItems;\n};\n\nclass GuiStats : public tsl::Gui {\npublic:\n    GuiStats() { \n        if (hosversionAtLeast(8,0,0)) {\n            clkrstOpenSession(&this->m_clkrstSessionCpu, PcvModuleId_CpuBus, 3);\n            clkrstOpenSession(&this->m_clkrstSessionGpu, PcvModuleId_GPU, 3);\n            clkrstOpenSession(&this->m_clkrstSessionMem, PcvModuleId_EMC, 3);\n        }\n\n        tsl::hlp::doWithSmSession([this]{\n            nifmGetCurrentIpAddress(&this->m_ipAddress);\n            this->m_ipAddressString = formatString(\"%d.%d.%d.%d\", this->m_ipAddress & 0xFF, (this->m_ipAddress >> 8) & 0xFF, (this->m_ipAddress >> 16) & 0xFF, (this->m_ipAddress >> 24) & 0xFF);\n        });\n\n    }\n    ~GuiStats() {\n        if (hosversionAtLeast(8,0,0)) {\n            clkrstCloseSession(&this->m_clkrstSessionCpu);\n            clkrstCloseSession(&this->m_clkrstSessionGpu);\n            clkrstCloseSession(&this->m_clkrstSessionMem);\n        }\n     }\n            \n    virtual tsl::elm::Element* createUI() override {\n        auto rootFrame = new tsl::elm::OverlayFrame(APP_TITLE, \"System Information\");\n    \n        auto infos = new tsl::elm::CustomDrawer([this](tsl::gfx::Renderer *renderer, u16 x, u16 y, u16 w, u16 h){\n    \n            renderer->drawString(\"CPU Temperature:\", false, 63, 200, 18, (tsl::style::color::ColorText));\n            renderer->drawString(\"PCB Temperature:\", false, 63, 230, 18, (tsl::style::color::ColorText));\n    \n            renderer->drawRect(x, 243, w, 1, renderer->a(tsl::style::color::ColorFrame));\n            renderer->drawString(\"CPU Clock:\", false, 63, 270, 18, (tsl::style::color::ColorText));\n            renderer->drawString(\"GPU Clock:\", false, 63, 300, 18, (tsl::style::color::ColorText));\n            renderer->drawString(\"MEM Clock:\", false, 63, 330, 18, (tsl::style::color::ColorText));\n    \n            renderer->drawRect(x, 343, w, 1, renderer->a(tsl::style::color::ColorFrame));\n            renderer->drawString(\"Local IP:\", false, 63, 370, 18, (tsl::style::color::ColorText));\n    \n    \n            // Draw temperatures and battery percentage\n            static char PCB_temperatureStr[10];\n            static char SOC_temperatureStr[10];\n            \n            // Use temporary float variables to receive the temperature values\n            static float tempSOC = 0.0f;\n            static float tempPCB = 0.0f;\n\n            ult::ReadSocTemperature(&tempSOC, false);\n            ult::ReadPcbTemperature(&tempPCB, false);\n    \n            snprintf(SOC_temperatureStr, sizeof(SOC_temperatureStr) - 1, \"%.1f °C\", static_cast<double>(tempSOC));\n            snprintf(PCB_temperatureStr, sizeof(PCB_temperatureStr) - 1, \"%.1f °C\", static_cast<double>(tempPCB));\n            \n            renderer->drawString(SOC_temperatureStr, false, 258, 200, 18, (tsl::style::color::ColorHighlight));\n            renderer->drawString(PCB_temperatureStr, false, 258, 230, 18, (tsl::style::color::ColorHighlight));\n            \n            static u32 cpuClock = 0, gpuClock = 0, memClock = 0;\n    \n            if (hosversionAtLeast(8,0,0)) {\n                clkrstGetClockRate(&this->m_clkrstSessionCpu, &cpuClock);\n                clkrstGetClockRate(&this->m_clkrstSessionGpu, &gpuClock);\n                clkrstGetClockRate(&this->m_clkrstSessionMem, &memClock);\n            } else {\n                pcvGetClockRate(PcvModule_CpuBus, &cpuClock);\n                pcvGetClockRate(PcvModule_GPU, &gpuClock);\n                pcvGetClockRate(PcvModule_EMC, &memClock);\n            }\n    \n            renderer->drawString(formatString(\"%.01f MHz\", cpuClock / 1'000'000.0F).c_str(), false, 258, 270, 18, (tsl::style::color::ColorHighlight));\n            renderer->drawString(formatString(\"%.01f MHz\", gpuClock / 1'000'000.0F).c_str(), false, 258, 300, 18, (tsl::style::color::ColorHighlight));\n            renderer->drawString(formatString(\"%.01f MHz\", memClock / 1'000'000.0F).c_str(), false, 258, 330, 18, (tsl::style::color::ColorHighlight));\n    \n            if (this->m_ipAddressString ==  \"0.0.0.0\")\n                renderer->drawString(\"Offline\", false, 258, 370, 18, (tsl::style::color::ColorHighlight));\n            else \n                renderer->drawString(this->m_ipAddressString.c_str(), false, 258, 370, 18, (tsl::style::color::ColorHighlight));\n    \n            if(hosversionAtLeast(15,0,0)){\n                NifmInternetConnectionType conType;\n                u32 wifiStrength;\n                NifmInternetConnectionStatus conStatus;\n                nifmGetInternetConnectionStatus(&conType, &wifiStrength, &conStatus);\n                renderer->drawString(\"Connection:\", false, 63, 400, 18, (tsl::style::color::ColorText));\n                if(conStatus == NifmInternetConnectionStatus_Connected && conType == NifmInternetConnectionType_WiFi) {\n                    std::string wifiStrengthStr = \"(Strong)\";\n                    tsl::Color color = tsl::Color(0x0, 0xF, 0x0, 0xF);\n                    if(wifiStrength == 2){\n                        wifiStrengthStr = \"(Fair)\";\n                        color = tsl::Color(0xE, 0xE, 0x2, 0xF);\n                    } else if(wifiStrength <= 1){\n                        wifiStrengthStr = \"(Poor)\";\n                        color = tsl::Color(0xF, 0x0, 0x0, 0xF);\n                    }\n                    renderer->drawString(\"WiFi\", false, 258, 400, 18, (tsl::style::color::ColorHighlight));\n                    renderer->drawString(wifiStrengthStr.c_str(), false, 303, 400, 18, (color));\n                } else if(conStatus == NifmInternetConnectionStatus_Connected && conType == NifmInternetConnectionType_Ethernet){\n                    renderer->drawString(\"Ethernet\", false, 258, 400, 18, (tsl::style::color::ColorHighlight));\n                } else {\n                    renderer->drawString(\"Disconnected\", false, 258, 400, 18, (tsl::style::color::ColorHighlight));\n                }\n            } else {\n                s32 signalStrength = 0;\n                wlaninfGetRSSI(&signalStrength);\n    \n                renderer->drawString(\"WiFi Signal:\", false, 63, 400, 18, (tsl::style::color::ColorText));\n                renderer->drawString(formatString(\"%d dBm\", signalStrength).c_str(), false, 258, 400, 18, (tsl::style::color::ColorHighlight)); \n            }\n            renderer->drawString(\"Credits:\", false, 63, 600, 18, (tsl::style::color::ColorText));\n            renderer->drawString(APP_AUTHOR, false, 75, 630, 18, (tsl::style::color::ColorHighlight)); \n        });\n        rootFrame->setContent(infos);\n    \n        return rootFrame;\n    }\n\n    virtual void update() { }\n\nprivate:\n    ClkrstSession m_clkrstSessionCpu, m_clkrstSessionGpu, m_clkrstSessionMem;\n    u32 m_ipAddress;\n    std::string m_ipAddressString;\n};\n\n\n\n\nclass EdiZonOverlay : public tsl::Overlay {\npublic:\n    EdiZonOverlay() { }\n    ~EdiZonOverlay() { }\n\n    void initServices() override {\n        // GDB Check & Saved Cheat Enabling\n        if(edz::cheat::CheatManager::isCheatServiceAvailable()){\n            edz::cheat::CheatManager::initialize();\n            for (auto &cheat : edz::cheat::CheatManager::getCheats()) {\n                if(cheat->getName().find(\":ENABLED\") != std::string::npos){\n                    cheat->setState(true);\n                }\n            }\n        }\n        clkrstInitialize();\n        pcvInitialize();\n        \n        i2cInitialize();\n        nifmInitialize(NifmServiceType_User);\n    } \n\n    virtual void exitServices() override {\n        if (edz::cheat::CheatManager::isCheatServiceAvailable())\n            edz::cheat::CheatManager::exit();\n        nifmExit();\n        i2cExit();\n        wlaninfExit();\n        nifmExit();\n        clkrstExit();\n        pcvExit();\n\n    }\n\n    virtual void onShow() override {\n        edz::cheat::CheatManager::reload();\n        GuiMain::s_runningTitleIDString     = formatString(\"%016lX\", edz::cheat::CheatManager::getTitleID());\n        GuiMain::s_runningBuildIDString     = formatString(\"%016lX\", edz::cheat::CheatManager::getBuildID());\n        GuiMain::s_runningProcessIDString   = formatString(\"%lu\", edz::cheat::CheatManager::getProcessID());\n    }\n\n    std::unique_ptr<tsl::Gui> loadInitialGui() override {\n        return initially<GuiMain>();\n    }\n\n    \n};\n\n\nint main(int argc, char **argv) {\n    return tsl::loop<EdiZonOverlay>(argc, argv);\n}\n"
  }
]