Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
91c0328
a lot of changes, primarily insect spawner
kwadukathole Jan 7, 2026
a892d14
a lot of changes, primarily insect spawner v2
kwadukathole Jan 7, 2026
94fa42e
Merge branch 'master' of https://github.com/RedShyGuy/Vapecord-ACNL-P…
kwadukathole Jan 7, 2026
b02c07c
Structure research
kwadukathole Jan 7, 2026
e000d0e
Structure research
kwadukathole Jan 8, 2026
b739fb0
a few unfinished things, insect spawner almost done, custom buttons a…
RedShyGuy Jan 13, 2026
c37cd83
added lots of struct research
RedShyGuy Jan 14, 2026
9024025
struct research
RedShyGuy Jan 18, 2026
a6ed449
struct research
RedShyGuy Jan 19, 2026
7ed0177
bug fixes, new cheat, etc
RedShyGuy Jan 26, 2026
8cdfb96
langauge system revamped
RedShyGuy Jan 28, 2026
e88c009
new OSD System with systemfont for notify
RedShyGuy Jan 30, 2026
dcd7a8b
new pipeline test
RedShyGuy Feb 1, 2026
db8e7db
new pipeline test
RedShyGuy Feb 1, 2026
7cf8ccb
new pipeline test
RedShyGuy Feb 1, 2026
0f6e769
new pipeline test
RedShyGuy Feb 1, 2026
c7deae1
new pipeline test
RedShyGuy Feb 1, 2026
efe53c0
new pipeline test
RedShyGuy Feb 1, 2026
5d3351f
fix chat commands
FoofooTheGuy Feb 4, 2026
656d67a
pipeline edits, other improvements
RedShyGuy Feb 9, 2026
ea514f0
Merge pull request #220 from RedShyGuy/fix-chat-commands
RedShyGuy Feb 9, 2026
d5616d8
finished mostly everything for release, porting addresses still needs…
RedShyGuy Feb 9, 2026
4ae4210
ported few addresses, still a few missing
RedShyGuy Feb 9, 2026
f304e03
ported all offsets
RedShyGuy Feb 10, 2026
3af109c
finished release
RedShyGuy Feb 10, 2026
6adf805
Run language python script before building plugin for newest textid.hpp
RedShyGuy Feb 10, 2026
5c5db70
Revise README for clarity and updated build instructions
RedShyGuy Feb 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 23 additions & 15 deletions .github/workflows/c-cpp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ on:
branches: ["master"]
pull_request:
branches: ["master"]
workflow_dispatch:

jobs:
build:
Expand All @@ -14,30 +15,27 @@ jobs:
steps:
- uses: actions/checkout@v4

- name: Download libctrpf
run: |
wget -O libctrpf.tar.bz2 "https://gitlab.com/-/project/35748837/uploads/8d2a3dc282f32b6a75d5f6abaeafe88f/libctrpf-0.8.0.tar.bz2"
tar -xjf libctrpf.tar.bz2

- name: Install libctrpf
run: |
mkdir -p /opt/devkitpro/libctrpf/include
mkdir -p /opt/devkitpro/libctrpf/lib
cp -r include/* /opt/devkitpro/libctrpf/include/
cp -r lib/* /opt/devkitpro/libctrpf/lib/

- name: Download 3gxtool
run: |
wget -O 3gxtool "https://gitlab.com/-/project/35893975/uploads/7cf27fcdc26921d9a6c5505c1e5bbcaa/3gxtool"
chmod +x 3gxtool
cp 3gxtool /opt/devkitpro/tools/bin/3gxtool

- name: Build Plugin
run: make
- name: Clone libctrpf (develop)
run: |
git clone --depth=1 --branch develop https://gitlab.com/thepixellizeross/ctrpluginframework.git libctrpf

- name: Build & Install libctrpf
run: |
cd libctrpf
make

- name: Run Language Python Script
run: python3 LanguageBinCreator/json_to_bin.py

- name: Build Plugin
run: make

- name: Package Plugin
run: |
mkdir -p package/Vapecord/Data/
Expand All @@ -51,12 +49,18 @@ jobs:
cp -r Files/snd/* package/luma/plugins/$folder/snd/
done

- name: Upload Artifacts
- name: Upload Package Artifact
uses: actions/upload-artifact@v4
with:
name: Vapecord.Public
path: package/

- name: Upload ELF Artifact
uses: actions/upload-artifact@v4
with:
name: Vapecord.Public.elf
path: Vapecord_Public.elf

- name: Check For Unused Text
run: python3 CheckForUnusedText.py

Expand All @@ -66,5 +70,9 @@ jobs:
- name: Check If Text Is Translated
run: python3 CheckIfTextIsTranslated.py

- name: Check For Unused Addresses
run: python3 CheckForUnusedAddresses.py




2 changes: 1 addition & 1 deletion .vscode/c_cpp_properties.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"databaseFilename": ""
},
"cStandard": "c11",
"cppStandard": "gnu++20",
"cppStandard": "c++11",
"intelliSenseMode": "gcc-arm"
}
],
Expand Down
100 changes: 100 additions & 0 deletions CheckForUnusedAddresses.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import os
import re
import sys
from pathlib import Path

SCRIPT_DIR = Path(__file__).parent
ADDRESSES_HEADER = SCRIPT_DIR / "Includes/Address/Addresses.hpp"

address_usage_pattern = re.compile(
r"\bAddress(?:\s+\w+)?\s*\(\s*(0x[0-9A-Fa-f]+)\s*\)"
)

array_pattern = re.compile(
r"\{\s*(0x[0-9A-Fa-f]+)\s*,"
)


# --- comment stripping ---

def strip_block_comments(text: str) -> str:
return re.sub(r"/\*.*?\*/", "", text, flags=re.DOTALL)


def strip_all_comments(text: str) -> str:
text = re.sub(r"/\*.*?\*/", "", text, flags=re.DOTALL)
text = re.sub(r"//.*", "", text)
return text


# --- header scan ---

def collect_addresses_from_header():
addresses = set()

if not ADDRESSES_HEADER.exists():
print(f"ERROR: {ADDRESSES_HEADER} not found!")
return addresses

with open(ADDRESSES_HEADER, "r", encoding="utf-8", errors="ignore") as f:
content = strip_block_comments(f.read())

for match in array_pattern.finditer(content):
addresses.add(match.group(1).lower())

return addresses


# --- code scan ---

def collect_used_addresses():
used = set()

for root, _, files in os.walk("."):
for file in files:
if not file.endswith((".cpp", ".hpp", ".h")):
continue

path = Path(root) / file

if path.resolve() == ADDRESSES_HEADER.resolve():
continue

with open(path, "r", encoding="utf-8", errors="ignore") as f:
content = strip_all_comments(f.read())

for match in address_usage_pattern.finditer(content):
used.add(match.group(1).lower())

return used


# --- main ---

def main():
print("Scanning for unused addresses...")

header_addresses = collect_addresses_from_header()
used_addresses = collect_used_addresses()

unused = sorted(header_addresses - used_addresses)

print(f"Total in header: {len(header_addresses)}")
print(f"Used in code: {len(used_addresses)}")
print(f"Unused: {len(unused)}")

if unused:
print("\nUnused addresses:")
for addr in unused:
print(f" {addr}")
exit_code = 1
else:
print("\nNo unused addresses found!")
exit_code = 0

sys.exit(exit_code)


if __name__ == "__main__":
main()

32 changes: 11 additions & 21 deletions CheckForUnusedText.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,16 @@
import json
from pathlib import Path
import re
import sys

# Config
PROJECT_ROOT = Path(__file__).parent
LANG_JSON_DIR = PROJECT_ROOT / "LanguageBinCreator" / "languages"

# Regex: match anything inside get("...") or get('...')
LANG_PATTERN = re.compile(r'Language::getInstance\(\)->get\(\s*["\'](.+?)["\']\s*\)')
# Regex: match anything like TextID::KEY
TEXTID_PATTERN = re.compile(r'TextID::([A-Z0-9_]+)')

# MenuFolderExtras
MENUFOLDER_PATTERN = re.compile(r'MenuFolderExtras\(\s*["\'](.+?)["\']')

# MenuEntryExtras
MENUENTRY_PATTERN = re.compile(r'MenuEntryExtras\((.*?)\)')

# HotkeyExtras
HOTKEY_PATTERN = re.compile(r'HotkeyExtras\([^,]+,\s*["\'](.+?)["\']\s*\)')

# Scan code files for keys
# Scan code files for enum keys
keys_used = set()

for file_path in PROJECT_ROOT.rglob("*"):
Expand All @@ -29,16 +21,11 @@
print(f"[WARNING] Could not read {file_path}: {e}")
continue

matches = MENUFOLDER_PATTERN.findall(content) + \
HOTKEY_PATTERN.findall(content) + \
LANG_PATTERN.findall(content)

matches = TEXTID_PATTERN.findall(content)
keys_used.update(matches)

params = MENUENTRY_PATTERN.findall(content)
for param_str in params:
string_keys = re.findall(r'["\'](.+?)["\']', param_str)
keys_used.update(string_keys)
# Ignore TextID::NONE
keys_used.discard("NONE")

# Load all JSON entries
json_files = list(LANG_JSON_DIR.glob("*.json"))
Expand All @@ -63,12 +50,15 @@
# Print results
if not unused_keys_report:
print("All language keys in JSON files are used in the code!")
exit_code = 0
else:
print(f"Unused language keys found ({sum(len(v) for v in unused_keys_report.values())}):")
for json_name, keys in sorted(unused_keys_report.items()):
print(f"\n{json_name} ({len(keys)} unused keys):")
for key in sorted(keys):
print(f" - {key}")
exit_code = 1

print(f"\nTotal keys used in code: {len(keys_used)}")
print(f"\nTotal TextID keys used in code: {len(keys_used)}")
print(f"JSON files scanned: {len(json_files)}")
sys.exit(exit_code)
5 changes: 5 additions & 0 deletions CheckIfAddressesArePorted.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import os
import re
import sys
from pathlib import Path

# CONFIG
Expand Down Expand Up @@ -67,8 +68,12 @@ def main():
print(f"\n{file}:")
for line, val in entries:
print(f" Line {line}: {val}")
exit_code = 1
else:
print("\nAll Address-Entries are ported!")
exit_code = 0

sys.exit(exit_code)

if __name__ == "__main__":
main()
42 changes: 17 additions & 25 deletions CheckIfTextIsTranslated.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,17 @@
import json
from pathlib import Path
import re
import sys

# Config
PROJECT_ROOT = Path(__file__).parent
LANG_JSON_DIR = PROJECT_ROOT / "LanguageBinCreator" / "languages"
TEXTID_ENUM_FILE = PROJECT_ROOT.parent / "Includes" / "TextID.hpp"

# Regex: match anything inside get("...") or get('...')
LANG_PATTERN = re.compile(r'Language::getInstance\(\)->get\(\s*["\'](.+?)["\']\s*\)')
# Regex: match anything like TextID::SOME_KEY
TEXTID_PATTERN = re.compile(r'TextID::([A-Z0-9_]+)')

# MenuFolderExtras: first parameter
MENUFOLDER_PATTERN = re.compile(r'MenuFolderExtras\(\s*["\'](.+?)["\']')

# MenuEntryExtras: last string parameter

MENUENTRY_PATTERN = re.compile(r'MenuEntryExtras\((.*?)\)')

# HotkeyExtras: second parameter
HOTKEY_PATTERN = re.compile(r'HotkeyExtras\([^,]+,\s*["\'](.+?)["\']\s*\)')

# Scan code files for keys
# Scan code files for enum keys
keys_used = set()

for file_path in PROJECT_ROOT.rglob("*"):
Expand All @@ -28,20 +20,16 @@
content = file_path.read_text(encoding="utf-8")
except Exception as e:
print(f"[WARNING] Could not read {file_path}: {e}")
exit_code = 1
continue

matches = MENUFOLDER_PATTERN.findall(content) + \
HOTKEY_PATTERN.findall(content) + \
LANG_PATTERN.findall(content)

matches = TEXTID_PATTERN.findall(content)
keys_used.update(matches)

params = MENUENTRY_PATTERN.findall(content)
for param_str in params:
string_keys = re.findall(r'["\'](.+?)["\']', param_str)
keys_used.update(string_keys)
# Ignore NONE
keys_used.discard("NONE")

# Load all JSON entries
# Load all JSON entries (master_keys)
json_files = list(LANG_JSON_DIR.glob("*.json"))
json_entries_per_file = {}

Expand All @@ -52,6 +40,7 @@
json_entries_per_file[json_file.name] = entries
except Exception as e:
print(f"[WARNING] Could not parse {json_file}: {e}")
exit_code = 1

# Check each key in every JSON
missing_keys_report = {}
Expand All @@ -66,11 +55,14 @@

# Print results
if not missing_keys_report:
print("All language keys exist in every JSON file!")
print("All TextID keys exist in every JSON file!")
exit_code = 0
else:
print(f"Some language keys are missing in JSON files ({len(missing_keys_report)}):")
print(f"Some TextID keys are missing in JSON files ({len(missing_keys_report)}):")
for key, missing_files in sorted(missing_keys_report.items()):
print(f" - {key} missing in: {', '.join(missing_files)}")
exit_code = 1

print(f"\nTotal keys found in code: {len(keys_used)}")
print(f"\nTotal TextID keys found in code: {len(keys_used)}")
print(f"JSON files scanned: {len(json_files)}")
sys.exit(exit_code)
Loading