proof-of-concept code. Attempt to run x64 .NET code with an up-to-date well supported runtime as an open.mp component.
The goal of this project is to create a ready-for-production concept that can be easily used to generate a bridge between .NET and the open.mp component/data structure.
The current implementation works but requires several quality improvements and bug fixes. I'm currently working on
improving the source generation to allow the unmanaged -> managed transition to perform marshalling of arguments. This
would happen during the initial native-to-managed delegate implementation as generated by
OpenMpEventHandlerSourceGenerator
.
The current EventHandler/EventDispatcher also requires some changes to allow a single type to implement multiple event handler interfaces. There is currently an issue where the default implementations of the event handler interfaces are conflicting.
The project consists of several parts:
- The open.mp component written in c++ which hosts the dotnet runtime (x64) and provides C declarations for all C++ functions using very simple proxy functions. The component also contains some small C++ class implementations required for registering event handlers which can be created and deleted using declared C functions. open.mp uses the robin hood library for hash tables which are exposed in the open.mp API. Therefore we also provide proxy functions for a subset of functions exposed in its API. The component is currently fully functional on Windows, but lacks Linux support.
- The source generator generates various structures. The source generator generates the following code structures:
- Implementations of event handler infastructure (registration/unregistration) using the
[OpenMpEventHandler]
attribute - P/Invokes + marshalling of functions exposed in the open.mp api using the
[OpenMpApi]
attribute - (TODO) An
OnInit
entry point for the open.mp to invoke. The entry point should have a fixed namespace, class and method name and should wire up the communication between the open.mp component and the .NET portion of SampSharp. It should also generate aMain
entry point. This entry point should either be empty or provide a consosle message that the game mode should be launched through open.mp. TheMain
entry point is r eqquire in order for .NET to write a runtimeconfig which we need to run the gamemode. The entry point generator has not be implemented yet. A manually written entry point currrently resides in theInterop
class.
- Implementations of event handler infastructure (registration/unregistration) using the
- (TODO) The analyzer provides useful diagnostics for helping writing proper SampSharp code that interfaces with open.mp. It should provide warnings/errors when the written code cannot be marshalled or no P/Invoke can be generated.
- The SampSharp.OpenMp.Core provides the open.mp API and data structures in .NET. These APIs are usable but not as user-friendly as we'd like to see in SampSharp.
- (TODO) Lastly we need a user-friendly library which allows the user to easily write game modes in .NET. It will be based on the ECS library SampSharp.Entities. Since the ECS framework seems more flexible and performant due to the way events propagate I'll not be rewriting SampSharp.GameMode for open.mp. Maintaining two versions of SampSharp greatly increases the amount of effort required from maintainers. When the open.mp version of SampSharp is ready, the old SampSharp will go into maintenance mode and only receive critical bug fixes.
There are a number of key differences between the libraries in this repo and the libraries in the main SampSharp repo:
- We use the open.mp API instead of the the Pawn scripting API for communicating between .NET and the SA-MP server backend. Aside from the big performance benefit this change provides, we also gain an increased flexibility due to getting access to the entire server API instead of the subset exposed to Pawn.
- We build x64 binaries instead of x86. While open.mp does not yet ship their x64 server binaries from the releases page, daily builds are available for x64 (https://github.com/openmultiplayer/open.mp/actions/workflows/build.yml?query=branch%3Amaster). .NET does however not provide x86 binaries for Linux (they do for Windows). While 3rd party x86 .NET binaries are available, these are not supported by MS and may have stability issues.
- The bridge between the .NET API and server API are generated at compile-time instead of at run-time. This means that the initial performance of the server should be better, it easier to diagnose issues in generated code and easier to improve the generated code since we generate c# code instead of itermediate code (IL).
On Windows, the following software is required to build the project
- Install CMake 3.19 +
- Visual Studio 2022
- Install the Development to desktop with .NET
- Install the Development to desktop with C++
- Open.MP Server x64
- Find and click in the last sucessfully run in
master
branch - Scroll to the bottom of the page and download the
open.mp-win-x64-v*
file for windows oropen.mp-linux-x86_64-v*
for linux
- Find and click in the last sucessfully run in
- Clone the repository including all submodules:
git clone https://github.com/SampSharp/openmp-sampsharp-x64-poc --recursive
- NOTE* If you forgot to clone the submodules (directories in
external/sdk
empty), you can do it after cloning the repository:git submodule update --init --recursive
cmake -S . -B build -A x64 -T ClangCL
cmake --build build --config RelWithDebInfo
After building, copy the built library (build/src/sampsharp-component/RelWithDebInfo/SampSharp.dll
) to the components directory of your open.mp server
cmake -S . -B build
cmake --build build
After building, copy the built library (build/src/sampsharp-component/libSampSharp.so
) to the components directory of your open.mp server
dotnet build SampSharp.sln
- Setup the launchSettings.json:
- Navigate to
src/SampSharp.OpenMp.Core/Properties/launchSettings.json
. - Replace the content with te following configuration and replace the
executablePath
andworkingDirectory
values:
- Navigate to
{
"profiles": {
"SampSharp.OpenMp.Core": {
"commandName": "Project"
},
"open.mp": {
"commandName": "Executable",
"executablePath": "C:\\path\\to\\openmp_x64_server\\omp-server.exe",
"workingDirectory": "C:\\path\\to\\openmp_x64_server\\",
"commandLineArgs": "-c sampsharp.folder=$(TargetDir) -c sampsharp.assembly=\"$(TargetName)\""
}
}
}
- Build the dotnet project and run the open.mp server
- Open the
<root>/SampSharp.sln
file with the Visual Studio - Run the
open.mp
profile on VS
- Open the