8.0 KiB
Monopoly Poker Mod Helper
This repository contains helper code, notes, and logs for modding Monopoly Poker.
Overview
Monopoly Poker is an Unity IL2CPP game on Steam, so mods should be built for IL2CPP. BepInEx IL2CPP is used in this project.
This repo is focused on reverse engineering game behavior, finding useful types through reflection, and automating helper actions.
Requirements
- Visual Studio
.NET 6BepInEx IL2CPPdnSpy(for inspecting game assemblies and objects)
Repository Structure
MonopolyPokerHelper/
Main mod/helper project code.
Example files:
ClaimMissionHandler.cs- discovers and claims missions through reflection
Assembly-CSharp
This is a dnSpy dump of the game's main assembly, used for reference and exploration. It is not meant to be built or modified directly.
What This Project Is For
- Uses reflection to inspect game objects and types
- Automates helper actions inside the game
- Stores notes and logs for reverse engineering work
Notes
- The dash character
—may display incorrectly in the BepInEx console. dnSpymay need a fix for loading certain assemblies.- You can use
BepInEx.ConfigurationManagerif you want an in-game configuration UI.
Setup
- Open the solution in Visual Studio.
- Ensure the project targets
.NET 6and references the game assembly as needed. - Build the helper project.
- Deploy the output into the BepInEx plugin folder.
Useful References
- BepInEx IL2CPP: https://github.com/BepInEx/BepInEx
- Configuration Manager: https://github.com/BepInEx/BepInEx.ConfigurationManager/releases/tag/v18.4.1
- UnityExplorer (for browsing game assets and types during runtime)
- BepInEx Docs: https://docs.bepinex.dev/
- Harmony Docs: https://harmony.pardeike.net/
Note UnityExplorer is archived, need to use a fork.
Known Issues
dnSpy Import Project
When trying to load a disassembled project that was then reassembled with dnSpy into Visual Studio you'll encounter the error:
A numeric comparison was attempted on "$(_TargetFrameworkVersionWithoutV)" that evaluates to "" instead of a number, in condition "('$(TargetFrameworkIdentifier)' != '.NETCoreApp'
This is because the project file generated by dnSpy is adding a v to and as well as not including _TargetFrameworkVersionWithoutV. To fix this:
- Open the .csproj file in a text editor.
- Near the top you'll see these two lines:
<TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
<TargetFrameworkIdentifier>.NETCoreApp</TargetFrameworkIdentifier>
Modify the first line (remove the "v"), and insert the second line, so it looks like this:
<TargetFrameworkVersion>5.0</TargetFrameworkVersion>
<_TargetFrameworkVersionWithoutV>5.0</_TargetFrameworkVersionWithoutV>
<TargetFrameworkIdentifier>.NETCoreApp</TargetFrameworkIdentifier>
Load the project as you were, and it should work.
Mileage may vary with different versions of Visual Studio and .NET SDK, but this is the general fix for the issue.
Encoding issues in BepInEx Console
"—" always shows as ΓòÉ on BepInEx Console. Use the regular hyphen "-" instead.
How to Extend This README
Add new sections when needed:
- setup and build instructions
- file-by-file descriptions
- known issues
- update history
Git Stash Reminder
to git stash staged changes, you can use the following command:
git stash push --staged -m "message"
Modding Guide
Tech Stack
What is BepInEx?
BepInEx (Bepis Injector Extendable) is a plugin/mod loader for Unity games. It:
- Injects itself into the game when it launches
- Loads your plugin DLLs automatically from
BepInEx/plugins/ - Provides logging, configuration, and modding APIs
- Handles IL2CPP games (compiled to native C++ code, harder to mod than Mono)
What is Harmony?
Harmony is a runtime patching library that lets you modify game methods without changing the original game files:
- Prefix: Run your code BEFORE the original method (can block the original)
- Postfix: Run your code AFTER the original method
- Transpiler: Modify the method's IL code directly (advanced)
You patch methods by their type and method name - no compile-time references needed!
📋 Common Patterns
Pattern: Periodic Timer
private static float _timer;
private const float INTERVAL = 10f;
private static void UpdatePostfix()
{
_timer += UnityEngine.Time.deltaTime;
if (_timer < INTERVAL) return;
_timer = 0f;
// Do something every 10 seconds
}
Pattern: Singleton Access
// Most game managers use the Singleton pattern
var instance = ManagerType.GetProperty("Instance").GetValue(null);
Pattern: Safe Reflection
try
{
var method = type.GetMethod("MethodName");
if (method == null)
{
Log.LogWarning("Method not found!");
return;
}
method.Invoke(instance, args);
}
catch (Exception ex)
{
Log.LogError($"Reflection error: {ex.Message}");
}
Pattern: Patch All Overloads
var methods = targetType.GetMethods(BindingFlags.Public | BindingFlags.Instance);
foreach (var method in methods)
{
if (method.Name == "TargetMethod")
{
_harmony.Patch(method, prefix: myPrefix);
}
}
⚠️ Common Pitfalls
1. IL2CPP Array Indexing
IL2CPP arrays need special handling:
// DON'T: arr[0]
// DO:
var getMethod = array.GetType().GetMethod("get_Item");
var value = getMethod.Invoke(array, new object[] { 0 });
2. Timing Issues
Game managers may not be loaded immediately:
// Wait before trying to access managers
if (!_initialDelayDone)
{
_elapsed += deltaTime;
if (_elapsed < 30f) return; // wait 30 seconds
_initialDelayDone = true;
}
3. Type Name Collisions
Multiple assemblies may have classes with the same name:
// Use full namespace
FindType("YoudaGames.MonopolyPoker.Popups.RollingOffersPopup");
4. Harmony Patch Failures
Methods might not exist or load later:
try
{
_harmony.Patch(method, prefix);
}
catch (Exception ex)
{
Log.LogWarning($"Patch failed: {ex.Message}");
// Method may load later - try again or check name
}
🎉 Example Mod Ideas
Now that you understand the basics, try creating:
- Auto Claimer - Automatically collect daily rewards (you have this!)
- Speed Hack - Patch animation methods to speed up gameplay
- UI Remover - Block annoying popups (you have this!)
- Unlimited Resources - Modify currency values via reflection
- Auto Player - Hook game actions and make decisions automatically
- Visual Tweaks - Modify Unity UI elements at runtime
🐛 Debugging Tips
View Logs
<Game Dir>/BepInEx/LogOutput.log
Enable Debug Logging
In your plugin:
Log.LogDebug("Debug message"); // Will show if debug level enabled
In BepInEx/config/BepInEx.cfg:
[Logging.Console]
LogLevels = Fatal, Error, Warning, Message, Info, Debug
UnityExplorer Console Snippets
Dumping GameObject Information
Replace the type with the one you need, e.g., YoudaGames.MonopolyPoker.Popups.BoardwalkJackpotRollPopup.
var instances = UnityEngine.Object.FindObjectsOfType<YoudaGames.MonopolyPoker.Popups.BoardwalkJackpotRollPopup>();
foreach (var popup in instances)
{
Console.WriteLine($"--- Begin for instance {popup} ---");
var type = popup.GetType();
foreach (var prop in type.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance))
{
Console.WriteLine($"{prop.Name}: {prop.GetValue(popup)}");
}
Console.WriteLine("--- End ---");
}
TODO: Perhaps seperate this README into a docs folder and link to it from the main README, to keep the main README concise and focused on project overview and setup.