Thank you for your interest in making Phoenix Wright: Ace Attorney Trilogy more accessible. This guide will help you get started.
- Visual Studio 2019+, Visual Studio Code, or another compatible IDE with .NET support
- .NET Framework 3.5 targeting pack
- Phoenix Wright: Ace Attorney Trilogy (Steam)
- MelonLoader v0.7.1 installed in the game directory
cd AccessibilityMod
dotnet build -c ReleaseThe build output is automatically copied to the game's Mods folder.
- Build the mod
- Launch the game through Steam
- Check
[Game Directory]/MelonLoader/Latest.logfor debug output
Use AccessibilityMod.Logger.Msg() to add debug logging.
To create Harmony patches, you'll need to inspect the game's code. Use ILSpy, dnSpy, or a similar .NET decompiler to examine the game assemblies in [Game Directory]/PWAAT_Data/Managed/. Key assemblies:
Assembly-CSharp.dll- Main game code (dialogue, menus, minigames)
AccessibilityMod/
├── Core/ # Main mod entry point and managers
├── Patches/ # Harmony patches for game hooks
├── Services/ # Localization, character names, etc.
├── Navigators/ # Mode-specific navigation (hotspots, evidence, etc.)
└── Data/ # Default configuration files
The mod targets .NET 3.5 to match MelonLoader. Avoid modern C# features:
- Use
Net35Extensions.IsNullOrWhiteSpace()instead ofstring.IsNullOrWhiteSpace() - Use
sb.Length = 0instead ofStringBuilder.Clear() - Use
.ToArray()beforestring.Join()on enumerables
- Verify method names exist in the decompiled code before patching
- Game methods often use lowercase names (
arrow,board,name_plate) - Use
[HarmonyPostfix]unless you need to intercept before the original runs
- Find the target method in the decompiled code
- Create a patch class in
Patches/ - Use
[HarmonyPatch]attributes with exact method signatures - Test thoroughly - incorrect patches can crash the game
For new game modes, follow the existing navigator structure:
public static class MyNavigator {
private static List<ItemInfo> _items;
private static int _currentIndex;
public static bool IsActive() { /* check game state */ }
public static void Update() { /* called each frame */ }
public static void NavigateNext() { /* [ key */ }
public static void NavigatePrevious() { /* ] key */ }
public static void AnnounceHint() { /* H key */ }
}Register the navigator in InputManager with appropriate priority.
- Use
L.Get("key")for all user-facing strings - Add new strings to
Data/en/strings.json - Use placeholders like
{0},{1}for dynamic values
- Fork the repository
- Create a feature branch (
git checkout -b feature/my-feature) - Make your changes
- Test with the game
- Submit a pull request
- Use clear, descriptive commit messages
- Start with a verb (Add, Fix, Update, Remove)
- Reference issues if applicable
- Describe what the change does and why
- Include testing steps
- Keep changes focused - one feature or fix per PR
When reporting bugs, include:
- Game version and episode/case where the issue occurs
- Steps to reproduce
- Expected vs actual behavior
- Relevant log output from
MelonLoader/Latest.log
Open an issue for questions about contributing or the codebase.