-
Notifications
You must be signed in to change notification settings - Fork 7
Add plugin auto-build and hot reload for dev #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
billsonnn
merged 1 commit into
nitrodevco:main
from
Diddyy:feature/plugin-dev-autoreload
Feb 8, 2026
+570
−95
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| # Turbo Cloud | ||
|
|
||
| A Habbo Hotel emulator built with C# and [Orleans](https://learn.microsoft.com/en-us/dotnet/orleans/). | ||
|
|
||
| ## Plugin Development | ||
|
|
||
| Turbo Cloud uses a plugin system where game features are implemented as loadable plugins. During development, plugins are hot-reloaded in-process when you rebuild them - no server restart needed. | ||
|
|
||
| ### Prerequisites | ||
|
|
||
| - .NET 9 SDK | ||
| - A plugin project that references `Turbo.Contracts` | ||
|
|
||
| ### Plugin Project Setup | ||
|
|
||
| Your plugin's `.csproj` must copy `manifest.json` to the build output: | ||
|
|
||
| ```xml | ||
| <ItemGroup> | ||
| <Content Include="manifest.json"> | ||
| <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | ||
| </Content> | ||
| </ItemGroup> | ||
| ``` | ||
|
|
||
| ### Emulator Configuration | ||
|
|
||
| In `appsettings.Development.json`, point `DevPluginPaths` at your plugin's build output directory: | ||
|
|
||
| ```json | ||
| { | ||
| "Turbo": { | ||
| "Plugin": { | ||
| "DevPluginPaths": [ | ||
| "C:/path/to/your-plugin/bin/Debug/net9.0" | ||
| ] | ||
| } | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| You can list multiple plugin paths if you're developing several plugins at once. | ||
|
|
||
| ### Dev Workflow | ||
|
|
||
| Open two terminals: | ||
|
|
||
| **Terminal 1** - Run the emulator: | ||
| ``` | ||
| dotnet run --project Turbo.Main | ||
| ``` | ||
|
|
||
| **Terminal 2** - Watch your plugin for changes: | ||
| ``` | ||
| cd C:/path/to/your-plugin | ||
| dotnet watch build | ||
| ``` | ||
|
|
||
| Now when you edit a `.cs` file and save, `dotnet watch` rebuilds the plugin automatically. The emulator detects the new DLL and hot-reloads the plugin in-process. Message handlers and services are swapped live - connected clients stay connected. | ||
|
|
||
| ### How It Works | ||
|
|
||
| 1. You edit a `.cs` file in your plugin project | ||
| 2. `dotnet watch build` detects the change and rebuilds | ||
| 3. The new DLL lands in your plugin's `bin/Debug/net9.0/` | ||
| 4. The emulator's file watcher detects the DLL change | ||
| 5. The plugin is unloaded and reloaded with the new assembly | ||
| 6. Message handlers and services are swapped atomically | ||
|
|
||
| ### Released Plugins | ||
|
|
||
| For production/released plugins, place them in the `plugins/` directory inside the emulator's output folder. Each plugin should be in its own subdirectory with a `manifest.json`: | ||
|
|
||
| ``` | ||
| plugins/ | ||
| MyPlugin/ | ||
| manifest.json | ||
| MyPlugin.dll | ||
| ``` | ||
|
|
||
| During development, `DevPluginPaths` takes precedence - if the same plugin key exists in both `plugins/` and a dev path, the dev version is loaded. | ||
|
|
||
| ### Limitations | ||
|
|
||
| - **Grain types cannot be hot-reloaded.** Orleans requires grain types to be registered at silo startup. If your plugin adds new grain types, a server restart is needed. | ||
| - **Memory may grow over many reloads.** Assembly unloading relies on .NET's `AssemblyLoadContext` which may not fully release memory if type references are retained. Restart the emulator periodically during long dev sessions if memory grows. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.