Intersect Engine is a complete 2D MMORPG game development suite built on MonoGame with .NET 8. It provides a client-server architecture with an integrated game editor, enabling developers to create multiplayer games without programming experience, while remaining extensible for advanced developers.
Key Facts:
- Language: C# (.NET 8)
- License: Split licensing (MIT for client/framework, GPLv3 for server/editor)
- Architecture: Client-Server with embedded single-player mode
- Primary Platforms: Windows (editor), Linux, macOS (client/server)
- Current Version: 0.8.0-beta
- Repository: https://github.com/AscensionGameDev/Intersect-Engine
- Codebase Architecture
- Project Structure
- Development Environment Setup
- Build System
- Git Workflow and Branching
- Code Conventions
- Development Workflows
- Testing
- Common Tasks
- Key Design Patterns
- Important File Locations
- Pull Request Guidelines
┌─────────────────────────────────────────────────────────┐
│ Application Layer │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Client.exe │ │ Server.exe │ │ Editor.exe │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ Implementation Layer │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Client.Core │ │ Server.Core │ │ Editor.Core │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ Framework Layer │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │Client.Frmwrk │ │Server.Frmwrk │ │ Network │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ Core Layer │
│ ┌──────────────┐ ┌──────────────────────────────────┐ │
│ │Intersect.Core│ │ Framework.Core (Game Objects) │ │
│ └──────────────┘ └──────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
| Project | License | Purpose | Key Dependencies |
|---|---|---|---|
| Intersect.Core | MIT | Application lifecycle, networking, plugins | - |
| Framework.Core | MIT | Game object definitions, shared types | Intersect.Core |
| Intersect.Network | MIT | LiteNetLib wrapper, encryption | Intersect.Core |
| Client.Framework | MIT | Client public API, graphics abstractions | Framework.Core |
| Client.Core | MIT | MonoGame rendering, UI (Gwen), input | Client.Framework |
| Client | MIT | Client executable | Client.Core |
| Server.Framework | GPLv3 | Server public API | Framework.Core |
| Server.Core | GPLv3 | Game logic, database (EF Core), entities | Server.Framework |
| Server | GPLv3 | Server executable, web dashboard | Server.Core |
| Editor | GPLv3 | Map/content editor (Windows/DirectX only) | Client.Framework, Server.Framework |
| SinglePlayer | MIT | Embedded server for offline play | Client.Core, Server.Core |
- Service-Oriented Architecture: Core application services (plugins, networking, database) managed through
IApplicationServicelifecycle - Factory Pattern:
FactoryRegistry<T>for dependency injection - Observer Pattern: Event-driven packet handling via
PacketDispatcher - Plugin Architecture: Dynamic plugin loading with isolated contexts
- Entity Component System: Inheritance-based entity hierarchy (Player, NPC, Projectile, Resource)
- Repository Pattern: Entity Framework Core for data access
- Command Pattern: Network packets as commands
- Template Method:
ApplicationServicebase class defines lifecycle
Intersect-Engine/
├── .github/ # GitHub Actions workflows
│ └── workflows/ # build.yml, pull_request.yml
├── Documentation/ # Extended features documentation
├── Examples/ # Plugin examples
│ ├── Plugin.Server/ # Server plugin example
│ ├── Plugin.Client/ # Client plugin example
│ └── Plugin.Multitarget/ # Multi-target plugin example
├── Framework/ # Shared framework layer
│ ├── Framework.Core/ # Game objects, packets, serialization
│ ├── Framework/ # Framework implementation
│ └── Framework.Multitarget/ # Cross-platform targeting
├── Intersect (Core)/ # Core infrastructure (note the space!)
│ ├── Core/ # Application lifecycle, services
│ ├── Network/ # Networking abstractions
│ ├── Plugins/ # Plugin system
│ └── Serialization/ # JSON/binary serialization
├── Intersect.Network/ # LiteNetLib implementation
├── Intersect.Client.Framework/ # Client API, graphics, UI (Gwen)
├── Intersect.Client.Core/ # Client implementation
├── Intersect.Client/ # Client executable
├── Intersect.Server.Framework/ # Server API
├── Intersect.Server.Core/ # Server implementation, database
├── Intersect.Server/ # Server executable, web UI
├── Intersect.Editor/ # Map/game editor
├── Intersect.SinglePlayer/ # Single-player mode
├── Intersect.Tests/ # Core tests
├── Intersect.Tests.*/ # Component-specific tests
├── Utilities/ # Helper tools (port checker)
├── assets/ # Submodule: Intersect-Assets
├── scripts/ # Build and maintenance scripts
├── targets/ # MSBuild target files
└── vendor/ # Third-party dependencies
Intersect.Core- Application runtime, services, networkingIntersect.Framework.Core- Game objects (Items, NPCs, Maps, Events, etc.)Intersect.Network- Network transport layerIntersect.Server.Core.Entities- Server-side entity implementationsIntersect.Server.Core.Database- Database models and migrationsIntersect.Client.Core.Entities- Client-side entity view modelsIntersect.Client.Framework.Gwen- UI frameworkIntersect.Client.Framework.Graphics- Rendering abstractionsIntersect.Plugins- Plugin infrastructure
-
.NET 8 SDK (tested with 8.0.405)
dotnet --version # Should be 8.0.x -
Git (for submodules)
git --version # Tested with 2.47.1 -
IDE (recommended):
- Visual Studio 2022+ (Windows)
- Visual Studio Code with C# extension
- JetBrains Rider
# Clone repository
git clone https://github.com/AscensionGameDev/Intersect-Engine.git
cd Intersect-Engine
# Initialize submodules (required for assets)
git submodule update --init --recursive# Apply patch to disable Windows-only projects (Editor)
git apply disable-windows-only.patch
# Before updating from upstream:
git apply -R disable-windows-only.patch # Revert patch first
git pull
git apply disable-windows-only.patch # Reapplydotnet restore Intersect.sln- Debug - Development builds, no single-file output
- Release - Production builds, single-file binaries
- DebugTests - Test-specific debug build
- DebugFull - Full debug symbols
- DebugPlugins - Plugin development debugging
dotnet build -p:Configuration=Debug \
-p:PackageVersion=0.8.0-beta \
-p:Version=0.8.0dotnet build -p:Configuration=Release \
-p:PackageVersion=0.8.0-beta \
-p:Version=0.8.0# Linux
dotnet publish -p:Configuration=Release \
-p:PackageVersion=0.8.0-beta \
-p:Version=0.8.0 \
-r linux-x64
# macOS
dotnet publish -r osx-x64 -p:Configuration=Release
# Windows
dotnet publish -r win-x64 -p:Configuration=Releaselinux-x64,linux-arm64osx-x64,osx-arm64win-x64
Key MSBuild properties (see Common.props, Intersect.props):
PackageVersion- NuGet package versionVersion- Assembly versionConfiguration- Build configurationTargetFramework- Alwaysnet8.0LangVersion- AlwayslatestNullable- AlwaysenableImplicitUsings- Alwaysenable
- Network Keys: Keys are generated during first build of
Intersect.Networkand cached inIntersect.Network/bin/Release/keys/ - Single-File Binaries: Only created in Release builds via
dotnet publish - Self-Contained: Use
--scflag for self-contained deployments (includes runtime)
| Branch | Version | Purpose | Allowed Changes |
|---|---|---|---|
main |
0.8.0.x | Stable releases | Bug fixes (non-breaking), markdown docs, GitHub automation |
prerelease |
0.7.x.y | Release candidates | Non-breaking fixes and features |
development |
0.8.x.y | Active development | Breaking changes permitted |
- Pattern:
<major>.<minor>.<patch>.<build> - Pre-1.0:
0.<major>.<minor>.<build> - Semantic Versioning: Breaking changes increment major/minor
- Breaking Changes: Any change that alters/removes field, property, method, or class signatures, or alters/deletes assemblies
- Required for
mainbranch: All commits MUST be GPG signed - Strongly recommended: Sign all commits on all branches
- Setup: https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits
Use lowercase except for names (classes, etc.):
feat: <what was added>
fix: <what is fixed>
chore: <what was done>
Examples:
feat: add server selection interfacefix: added null-check to prevent crashfix: removed outdated expectation in TestTryAddFriendchore: documented configuration optionschore: added tests for MathHelperchore: resolved null reference warnings
Do:
- Commit test code separately and after the feature code (same PR)
- Add documentation in the same commit as new code
- Commit immediately after renames, file creation/deletion
chore: renamed ClassA to ClassBchore: separated class declaration into separate file
- Commit immediately after running formatting tools (ensure it compiles first)
chore: formatting
Don't:
- Commit bug fix + new feature code together (separate commits)
- Commit multiple separate bug fixes in one commit
- Commit hand-modified + tool-modified code together
- C# files: 4 spaces
- XML files: 2 spaces
- JSON/YAML: 2 spaces
- Use spaces, not tabs for C# code
- LF (
\n) for all files - UTF-8 encoding
- PascalCase for constant fields
- No
this.qualification unless required for disambiguation - Prefer language keywords over BCL types (
intvsInt32)
- var preferred for built-in types when type is apparent
- Expression-bodied members for properties, indexers, accessors
- Block bodies for methods, constructors, operators
- Pattern matching over
iswith cast check - Braces always required for control flow
- New line before open brace (Allman style)
- New line before
else,catch,finally - Space after keywords in control flow statements
- Space around binary operators
- No space after cast
- File-scoped namespaces preferred (C# 10+)
- Nullable reference types enabled project-wide
- Implicit usings enabled
- Latest C# language version (
LangVersion: latest)
namespace Intersect.Server.Entities;
public class Player : Entity
{
private readonly List<Item> _inventory;
public string Name { get; set; }
public int Level => CalculateLevel();
public Player(Guid id)
{
_inventory = new List<Item>();
Id = id;
}
private int CalculateLevel()
{
if (Experience < 100)
{
return 1;
}
return (int)Math.Floor(Experience / 100.0) + 1;
}
}resharper_csharp_wrap_arguments_style = chop_if_longresharper_csharp_wrap_parameters_style = chop_if_longresharper_max_invocation_arguments_on_line = 5resharper_trailing_comma_in_multiline_lists = true
Location: Framework/Intersect.Framework.Core/Network/Packets/
-
Create packet class inheriting from
IntersectPacket[MessagePackObject] public class ExamplePacket : IntersectPacket { [Key(0)] public string Message { get; set; } [Key(1)] public int Value { get; set; } }
-
Register in plugin (if plugin-based):
context.Packet.TryRegisterPacketType<ExamplePacket>();
-
Create packet handler:
public class ExamplePacketHandler : IPacketHandler<ExamplePacket> { public void Handle(IConnection connection, ExamplePacket packet) { // Handle packet } }
-
Register handler:
context.Packet.TryRegisterPacketHandler<ExamplePacketHandler, ExamplePacket>();
Example Location: Examples/Intersect.Examples.Plugin.Server/
-
Create plugin entry class:
public class MyServerPlugin : ServerPluginEntry { public override void OnBootstrap(IPluginBootstrapContext context) { // Register packet types, configure services context.Logging.Application.Info("Plugin bootstrapping..."); } public override void OnStart(IServerPluginContext context) { // Start services, register handlers context.Logging.Plugin.Info("Plugin started!"); } public override void OnStop(IServerPluginContext context) { // Cleanup resources } }
-
Create manifest (plugin.json or implement
IManifestHelper):{ "Name": "My Plugin", "Key": "my-plugin", "Version": "1.0.0", "Authors": ["Your Name"], "Homepage": "https://example.com" } -
Build and deploy:
dotnet build -p:Configuration=Release # Copy output to resources/plugins/
Location: Intersect.Server.Core/Database/
-
Add/modify entity model in appropriate folder:
PlayerData/Players/- Player-related modelsPlayerData/Guilds/- Guild modelsGameData/- Static game data
-
Create migration:
dotnet ef migrations add YourMigrationName --project Intersect.Server.Core
-
Apply migration (automatic on server start, or manual):
dotnet ef database update --project Intersect.Server.Core
-
Thread safety: Use
DbInterface.Poolfor async database operations
Location: Intersect.Client.Framework/Gwen/
-
Create control inheriting from Gwen base:
public class MyCustomControl : Base { public MyCustomControl(Base parent) : base(parent) { // Initialize control } protected override void Render(SkinBase skin) { // Custom rendering } }
-
Use data binding:
var dataProvider = new DataProvider<string>(); dataProvider.Value = "Hello"; myLabel.SetDataBinding(dataProvider);
-
Load textures:
var texture = context.Content.Load<GameTexture>( ContentType.Texture, "path/to/texture.png", "texture-alias" );
Intersect.Tests- Core framework testsIntersect.Tests.Network- Network layer testsIntersect.Tests.Client- Client testsIntersect.Tests.Client.Framework- Client framework testsIntersect.Tests.Server- Server logic testsIntersect.Tests.Editor- Editor testsExamples/Plugin.Client.Tests- Plugin testing example
# Run all tests
dotnet test
# Run specific project tests
dotnet test Intersect.Tests.Server/Intersect.Tests.Server.csproj
# Run with coverage
dotnet test --collect:"XPlat Code Coverage"
# Run specific test
dotnet test --filter "FullyQualifiedName~TestMethodName"- Configuration:
DebugTestsfor test-specific builds - Framework: xUnit, NUnit, or MSTest (check individual projects)
- Mocking: Moq or NSubstitute where applicable
- Commit test code separately from feature code
- Commit after feature code in the same PR
- Test fixes can be merged to any relevant branch
- Test additions should target
prereleaseordevelopment
-
Define in Framework.Core:
Framework/Intersect.Framework.Core/GameObjects/[MessagePackObject] public class NewGameObject : IGameObject { [Key(0)] public Guid Id { get; set; } [Key(1)] public string Name { get; set; } }
-
Add database model (if persistent):
Intersect.Server.Core/Database/GameData/ -
Create migration:
dotnet ef migrations add AddNewGameObject -
Add editor support:
Intersect.Editor/UI and logic
-
Edit Options class:
Intersect (Core)/Configuration/Options.cs[JsonProperty] public NewOptionsSection NewSection { get; set; } = new();
-
Document in code comments for auto-generated docs
-
Default configuration created automatically on first run
-
Server-side: Inherit from
EntityinIntersect.Server.Core/Entities/public class CustomEntity : Entity { public override void Update(long timeMs) { base.Update(timeMs); // Custom update logic } }
-
Client-side: Create view model in
Intersect.Client.Core/Entities/ -
Synchronization: Add packet types for client-server sync
-
Define content type:
Intersect.Client.Framework/Content/ContentType.cs -
Update content manager: Support loading new type
-
Add asset organization: Update directory structure in
resources/
Base class for all services:
public abstract class ApplicationService<TInterface, TImpl> : IApplicationService
where TImpl : TInterface
{
public void Bootstrap(IApplicationContext context) { }
public void Start(IApplicationContext context) { }
public void Stop() { }
}Lifecycle: Bootstrap → Start → Run → Stop
FactoryRegistry<IPluginContext>.RegisterFactory(new ServerPluginContext.Factory());
var context = FactoryRegistry<IPluginContext>.Create();// Register handler
PacketDispatcher.RegisterHandler(typeof(MyPacket), HandleMyPacket);
// Dispatch
PacketDispatcher.Dispatch(connection, packet);- Packet events: Pre-process and post-process hooks
- Connection events: OnConnected, OnDisconnected
- Entity events: Update, Spawn, Destroy
- UI events: Data provider change notifications
- Editor Config:
.editorconfig- Code style rules - Build Properties:
Common.props,Directory.Build.props,Intersect.props - NuGet Config:
NuGet.Config - Git Attributes:
.gitattributes- Line ending rules - Git Ignore:
.gitignore - Submodules:
.gitmodules- Assets repository
- README:
README.md- Project overview - Contributing:
CONTRIBUTING.md- Contribution guidelines - Versioning:
VERSIONING.md- Version strategy - Security:
SECURITY.md- Security policies - Requirements:
REQUIREMENTS.md- Platform support matrix - Features:
Documentation/Features.md- Extended features - Authors:
AUTHORS.md- Contributors list - License:
LICENSE.md- License information
- GitHub Actions:
.github/workflows/build.yml,.github/workflows/pull_request.yml - Build Scripts:
scripts/ - MSBuild Targets:
targets/ - Bundles:
.github/bundles/- Package definitions
- Server Config:
Intersect.Server/appsettings.json - Network Keys:
Intersect.Network/bin/Release/keys/ - Game Assets:
assets/(submodule)
- Associate with issue: Start PR description with
Resolves #123 - Rebase on target branch: Keep PR up-to-date
- Resolve merge conflicts: Author's responsibility
- Test thoroughly: Provide screenshots/recordings
- Sign commits: GPG signing required for
main, recommended for all
- One PR addresses one issue (exceptions: refactors, code quality)
- Commit messages follow format (
feat:,fix:,chore:) - Commits are coherent chunks that compile
- Tests added/updated and passing
- Documentation updated if needed
- No backwards-compatibility hacks for removed code
- Author listed in
AUTHORS.md(first contribution) - Supplementary materials provided (screenshots, recordings, logs)
Same as commit messages, but precedence: feat > fix > chore
Examples:
feat: add guild alliance system (#456)fix: prevent crash when loading invalid map data (#789)chore: improve test coverage for packet handling (#123)
- Additive/Subtractive PRs: Squash merge (default)
- Promotion PRs: Rebase merge (branch promotions only)
- Reviews Required: 1 contributor + 1 maintainer minimum
- Checks: Must pass all CI/CD checks
- Features: →
developmentonly - Bug fixes: → any relevant branch
- Test additions: →
prereleaseordevelopment - Test fixes: → any relevant branch
- Documentation (code): →
developmentonly - Documentation (markdown): → any relevant branch
- Read before modifying: Always read files before editing them
- Respect licensing: Remember split licensing (MIT vs GPLv3)
- Follow editorconfig: Maintain code style consistency
- Test changes: Build and run tests after modifications
- Keep context: Note the directory name "Intersect (Core)" has a space
- Check platform: Some features are Windows-only (Editor)
- Use proper paths: Always use absolute paths for file operations
- Understand architecture: Review this document's architecture section
- Plugin first: Consider plugin-based solutions before core changes
- Backward compatibility: Avoid breaking changes on stable branches
- Don't modify
LICENSE.mdfiles without unanimous contributor consent - Don't create backwards-compatibility shims (rename unused vars, etc.)
- Don't add features to
mainbranch (bug fixes only) - Don't commit unsigned code to
main - Don't forget to update submodules after clone
- Don't apply Windows-only patch on Windows systems
- Don't use interactive git commands (
git rebase -i,git add -i) - Don't guess at configuration values - read existing config first
- Build output: Check
bin/Debug/orbin/Release/ - Network keys: Regenerate if missing: rebuild
Intersect.Network - Database issues: Check migrations in
Intersect.Server.Core/Migrations/ - Asset loading: Verify
assets/submodule is initialized - Platform errors: Ensure correct patch applied (non-Windows)
- Plugin issues: Check plugin manifest and bootstrap logging
# Full clean build
dotnet clean
dotnet restore
dotnet build
# Run specific project
dotnet run --project Intersect.Server/Intersect.Server.csproj
# Watch mode (auto-rebuild on changes)
dotnet watch --project Intersect.Server/Intersect.Server.csproj
# Format code
dotnet format
# List projects
dotnet sln list
# Dependency graph
dotnet list package --include-transitive- Official Website: https://freemmorpgmaker.com
- Documentation: https://docs.freemmorpgmaker.com
- Community Forums: https://ascensiongamedev.com
- Discord: https://discord.gg/Ggt3KJV
- Issue Tracker: https://github.com/AscensionGameDev/Intersect-Engine/issues
- Assets Repository: https://github.com/AscensionGameDev/Intersect-Assets
- Downloads: https://freemmorpgmaker.com/download
IPluginBootstrapContext- Bootstrap-phase contextIPluginContext/IServerPluginContext/IClientPluginContext- Runtime contextPluginEntry<TContext>- Base plugin entry classIManifestHelper- Plugin manifest metadata
IPacket- Base packet interfaceIntersectPacket- MessagePack-serialized packet baseIConnection- Network connection abstractionIPacketHandler<TPacket>- Packet handler interface
IApplicationService- Service lifecycle interfaceIApplicationContext- Application runtime containerApplicationService<TInterface, TImpl>- Service base class
IContentManager- Asset loading interfaceContentType- Asset type enumerationIGameTexture- Texture interface
IEntity- Entity interface (public API)Entity- Base entity implementation (server)Player,Npc,Projectile,Resource- Derived entity types
Document Version: 1.0 Last Updated: 2025-12-06 Intersect Version: 0.8.0-beta Maintained By: AI Assistant Documentation System
For questions or clarifications about this guide, refer to the community forums or Discord.