mirror of
https://github.com/AHA705/Monopoly-Poker-Helper.git
synced 2026-10-07 22:56:34 +01:00
306 lines
8.0 KiB
Markdown
306 lines
8.0 KiB
Markdown
# 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 6`
|
|
- `BepInEx IL2CPP`
|
|
- `dnSpy` (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.
|
|
- `dnSpy` may need a fix for loading certain assemblies.
|
|
- You can use `BepInEx.ConfigurationManager` if you want an in-game configuration UI.
|
|
|
|
## Setup
|
|
|
|
1. Open the solution in Visual Studio.
|
|
2. Ensure the project targets `.NET 6` and references the game assembly as needed.
|
|
3. Build the helper project.
|
|
4. 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](https://github.com/sinai-dev/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 <TargetFrameworkVersion> and as well as not including _TargetFrameworkVersionWithoutV. To fix this:
|
|
|
|
1. Open the .csproj file in a text editor.
|
|
2. Near the top you'll see these two lines:
|
|
```xml
|
|
<TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
|
|
<TargetFrameworkIdentifier>.NETCoreApp</TargetFrameworkIdentifier>
|
|
```
|
|
|
|
Modify the first line (remove the "v"), and insert the second line, so it looks like this:
|
|
|
|
```xml
|
|
<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.
|
|
|
|
[Source](https://www.clearhat.org/post/how-fix-numeric-comparison-was-attempted-_targetframeworkversionwithoutv-evaluates-instead-number-condition-targetframeworkidentifier-netcoreapp)
|
|
|
|
### 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
|
|
|
|
```csharp
|
|
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
|
|
|
|
```csharp
|
|
// Most game managers use the Singleton pattern
|
|
var instance = ManagerType.GetProperty("Instance").GetValue(null);
|
|
```
|
|
|
|
### Pattern: Safe Reflection
|
|
|
|
```csharp
|
|
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
|
|
|
|
```csharp
|
|
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:
|
|
|
|
```csharp
|
|
// 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:
|
|
|
|
```csharp
|
|
// 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:
|
|
|
|
```csharp
|
|
// Use full namespace
|
|
FindType("YoudaGames.MonopolyPoker.Popups.RollingOffersPopup");
|
|
```
|
|
|
|
### 4. **Harmony Patch Failures**
|
|
|
|
Methods might not exist or load later:
|
|
|
|
```csharp
|
|
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:
|
|
|
|
1. **Auto Claimer** - Automatically collect daily rewards (you have this!)
|
|
2. **Speed Hack** - Patch animation methods to speed up gameplay
|
|
3. **UI Remover** - Block annoying popups (you have this!)
|
|
4. **Unlimited Resources** - Modify currency values via reflection
|
|
5. **Auto Player** - Hook game actions and make decisions automatically
|
|
6. **Visual Tweaks** - Modify Unity UI elements at runtime
|
|
|
|
---
|
|
|
|
## 🐛 Debugging Tips
|
|
|
|
### View Logs
|
|
|
|
```
|
|
<Game Dir>/BepInEx/LogOutput.log
|
|
```
|
|
|
|
### Enable Debug Logging
|
|
|
|
In your plugin:
|
|
|
|
```csharp
|
|
Log.LogDebug("Debug message"); // Will show if debug level enabled
|
|
```
|
|
|
|
In `BepInEx/config/BepInEx.cfg`:
|
|
|
|
```ini
|
|
[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. |