SampSharp.MapObjects
1.0.0-preview.2
See the version list below for details.
dotnet add package SampSharp.MapObjects --version 1.0.0-preview.2
NuGet\Install-Package SampSharp.MapObjects -Version 1.0.0-preview.2
<PackageReference Include="SampSharp.MapObjects" Version="1.0.0-preview.2" />
<PackageVersion Include="SampSharp.MapObjects" Version="1.0.0-preview.2" />
<PackageReference Include="SampSharp.MapObjects" />
paket add SampSharp.MapObjects --version 1.0.0-preview.2
#r "nuget: SampSharp.MapObjects, 1.0.0-preview.2"
#:package SampSharp.MapObjects@1.0.0-preview.2
#addin nuget:?package=SampSharp.MapObjects&version=1.0.0-preview.2&prerelease
#tool nuget:?package=SampSharp.MapObjects&version=1.0.0-preview.2&prerelease
SampSharp.MapObjects
A .NET library for SampSharp that implements object maps as regular C# classes instead of Pawn filterscripts.
It is designed for open.mp (Open Multiplayer, a multiplayer mod for GTA San Andreas) game modes where a single map is active at a time, allowing maps to be loaded and unloaded directly from code without relying on RCON commands.
Why this library exists
This library was originally developed for the Capture the Flag game mode for open.mp, where maps are loaded and unloaded dynamically throughout the match.
For many years, every map was implemented as an individual Pawn filterscript. The game mode itself was written in C# using SampSharp, but every time the active map changed it had to ask open.mp to load or unload a filterscript through an RCON command.
The object maps looked like this:
#include <open.mp>
#define FILTER_SCRIPT_NAME "Aim_Headshot"
#include "objects"
public OnFilterScriptInit()
{
new objectId;
CreateObject(6989, -166.94000, 138.17999, -79.50000, 0.00000, 0.00000, -17.46000);
CreateObject(6989, -272.32999, 67.31000, -79.50000, 0.00000, 0.00000, 72.72000);
CreateObject(6989, -320.23999, -86.67000, -79.50000, 0.00000, 0.00000, 72.72000);
objectId = CreateObject(3885, -152.15030, 52.53920, 2.75850, 0.00000, 0.00000, 146.00000);
SetObjectMaterial(objectId, 0, 10357, "tvtower_sfs", "ws_transmit_red", 0xFFFFFFFF);
return 1;
}
Whenever the map rotation changed, the C# game mode, built with SampSharp, still had to communicate with open.mp through RCON commands in order to load or unload Pawn filterscripts:
serverService.SendRconCommand($"loadfs {nextMap.Name}");
or
serverService.SendRconCommand($"unloadfs {currentMap.Name}");
This approach is very common in open.mp game modes where only one map is active at a time, and it worked reliably for years.
Eventually, however, it became clear that there was no reason to keep object maps in Pawn. The game mode was already written in C#, yet it still depended on Pawn filterscripts and RCON commands just to create and destroy objects.
The solution
This library replaces Pawn filterscripts with native C# map definitions.
Instead of compiling and loading filterscripts, maps are implemented as regular C# classes and registered in an IServiceCollection using the standard Microsoft dependency injection container. They can then be loaded and unloaded directly from code without relying on loadfs, unloadfs, or SendRconCommand.
This provides several advantages:
- Eliminates the dependency on Pawn for object maps.
- Removes the need to communicate with open.mp through RCON commands.
- Keeps map definitions in the same language and ecosystem as the rest of the game mode.
- Makes the same map definitions reusable across multiple SampSharp game modes.
Although this library was originally developed for the Capture the Flag game mode built with SampSharp for open.mp, it can be reused by any SampSharp game mode that loads and unloads maps dynamically, including:
- Gun Game
- Counter-Strike Team Deathmatch
- Capture the Flag
- Any game mode that activates one map at a time
The library is intentionally designed around this use case: a single active map that can be loaded and unloaded on demand.
Installation
Install the required packages:
dotnet add package SampSharp.MapObjects.Abstractions
dotnet add package SampSharp.MapObjects
Registering services
Register the object map services during application startup:
services.AddMapObjects();
This registers the infrastructure required to manage object maps, including the IMapObjectService implementation and all built-in map definitions.
The library currently includes 40 built-in map definitions, including:
- Aim_Headshot
- Area51
- de_dust2
- fy_iceworld
- WarZone
- ZM_Italy
- ...and many more.
Custom map definitions can be registered alongside the built-in maps:
services
.AddMapObjects()
.AddMapDefinition<MyMap>();
Creating a map
If you already have existing Pawn map filterscripts, such as this one, you don't need to rewrite them manually.
PawnMapTranslator can automatically convert supported object creation code into C# MapDefinition classes, like the one shown in the example below. The translator currently supports CreateObject and SetObjectMaterial.
The following class was generated from the Aim_Headshot Pawn filterscript and can be further customized using regular C# code:
public class Aim_Headshot : MapDefinition
{
public override string Name => "Aim_Headshot";
protected override void OnLoad()
{
CreateObject(modelId: 6989, position: new Vector3(-166.94000f, 138.17999f, -79.50000f), rotation: new Vector3(0.00000f, 0.00000f, -17.46000f));
CreateObject(modelId: 6989, position: new Vector3(-272.32999f, 67.31000f, -79.50000f), rotation: new Vector3(0.00000f, 0.00000f, 72.72000f));
CreateObject(modelId: 6989, position: new Vector3(-320.23999f, -86.67000f, -79.50000f), rotation: new Vector3(0.00000f, 0.00000f, 72.72000f));
CreateObject(modelId: 6989, position: new Vector3(-236.36000f, -150.46001f, -79.50000f), rotation: new Vector3(0.00000f, 0.00000f, 162.78000f));
CreateObject(modelId: 6989, position: new Vector3(-110.30000f, 21.05000f, -79.50000f), rotation: new Vector3(0.00000f, 0.00000f, 249.66000f));
CreateObject(modelId: 6989, position: new Vector3(-166.24001f, -130.03999f, -79.52000f), rotation: new Vector3(0.00000f, 0.00000f, 249.66000f));
CreateObject(modelId: 6388, position: new Vector3(-246.37000f, -69.28000f, -11.84000f), rotation: new Vector3(0.00000f, 0.00000f, -17.70000f));
CreateObject(modelId: 6388, position: new Vector3(-160.59000f, 67.49000f, -11.84000f), rotation: new Vector3(0.00000f, 0.00000f, 162.00000f));
CreateObject(modelId: 2934, position: new Vector3(-201.84000f, 75.71000f, 3.24000f), rotation: new Vector3(0.00000f, 0.00000f, 75.66000f));
CreateObject(modelId: 2934, position: new Vector3(-210.97000f, 78.84000f, 3.25000f), rotation: new Vector3(0.00000f, 0.00000f, 64.56000f));
CreateObject(modelId: 2934, position: new Vector3(-218.19000f, 81.28000f, 2.73000f), rotation: new Vector3(0.00000f, 0.00000f, 65.58000f));
CreateObject(modelId: 2934, position: new Vector3(-235.96001f, 83.86000f, 2.49000f), rotation: new Vector3(0.00000f, 0.00000f, 119.22000f));
CreateObject(modelId: 2934, position: new Vector3(-207.37000f, 75.83000f, 6.14000f), rotation: new Vector3(0.00000f, 0.00000f, 69.24000f));
CreateObject(modelId: 2932, position: new Vector3(-205.71001f, -77.41000f, 3.43000f), rotation: new Vector3(0.00000f, 0.00000f, -104.76000f));
CreateObject(modelId: 2932, position: new Vector3(-197.41000f, -80.80000f, 3.44000f), rotation: new Vector3(0.00000f, 0.00000f, -121.14000f));
CreateObject(modelId: 2932, position: new Vector3(-190.30000f, -84.02000f, 3.44000f), rotation: new Vector3(0.00000f, 0.00000f, -109.02000f));
CreateObject(modelId: 2932, position: new Vector3(-177.84000f, -84.31000f, 3.44000f), rotation: new Vector3(0.00000f, 0.00000f, -52.02000f));
CreateObject(modelId: 2932, position: new Vector3(-200.48000f, -77.53000f, 6.33000f), rotation: new Vector3(0.00000f, 0.00000f, -112.50000f));
CreateObject(modelId: 2934, position: new Vector3(-165.21001f, 90.02000f, 3.50000f), rotation: new Vector3(0.00000f, 0.00000f, 72.24000f));
CreateObject(modelId: 2932, position: new Vector3(-241.75000f, -91.92000f, 3.40000f), rotation: new Vector3(0.00000f, 0.00000f, 72.18000f));
CreateObject(modelId: 2935, position: new Vector3(-205.25000f, -1.99000f, 3.49000f), rotation: new Vector3(0.00000f, 0.00000f, 71.70000f));
CreateObject(modelId: 16061, position: new Vector3(-239.14999f, -119.39000f, 1.88000f), rotation: new Vector3(0.00000f, 0.00000f, 73.32000f));
CreateObject(modelId: 16061, position: new Vector3(-219.09000f, 106.20000f, -9.92000f), rotation: new Vector3(0.00000f, 0.00000f, 240.24001f));
CreateObject(modelId: 16061, position: new Vector3(-188.72000f, -101.70000f, -9.92000f), rotation: new Vector3(0.00000f, 0.00000f, 85.74000f));
CreateObject(modelId: 16061, position: new Vector3(-175.15781f, 113.35090f, 1.95000f), rotation: new Vector3(0.00000f, 0.00000f, 250.56000f));
CreateObject(modelId: 16061, position: new Vector3(-148.36000f, -10.28000f, 2.59000f), rotation: new Vector3(0.00000f, 0.00000f, 156.84000f));
CreateObject(modelId: 16061, position: new Vector3(-258.48001f, 27.26000f, 1.40000f), rotation: new Vector3(0.00000f, 0.00000f, 340.01999f));
GlobalObject object0 = CreateObject(modelId: 3885, position: new Vector3(-152.15030f, 52.53920f, 2.75850f), rotation: new Vector3(0.00000f, 0.00000f, 146.00000f));
object0.SetMaterial(materialIndex: 0, modelId: 10357, txdName: "tvtower_sfs", textureName: "ws_transmit_red", materialColor: new Color(0xFFFFFFFF));
GlobalObject object1 = CreateObject(modelId: 3885, position: new Vector3(-247.57410f, -55.88480f, 2.77900f), rotation: new Vector3(0.00000f, 0.00000f, -38.00000f));
object1.SetMaterial(materialIndex: 0, modelId: 6328, txdName: "sunset04_law2", textureName: "LAbluewall", materialColor: new Color(0xFFFFFFFF));
CreateObject(modelId: 18257, position: new Vector3(-142.27528f, 54.97489f, 6.50410f), rotation: new Vector3(0.00000f, 0.00000f, -18.00000f));
CreateObject(modelId: 18257, position: new Vector3(-156.45602f, 59.57191f, 6.50410f), rotation: new Vector3(0.00000f, 0.00000f, -18.00000f));
CreateObject(modelId: 18257, position: new Vector3(-168.30475f, 63.68726f, 6.50410f), rotation: new Vector3(0.00000f, 0.00000f, -18.00000f));
CreateObject(modelId: 2991, position: new Vector3(-180.94998f, 68.02634f, 7.09530f), rotation: new Vector3(0.00000f, 0.00000f, -18.00000f));
CreateObject(modelId: 2991, position: new Vector3(-180.95000f, 68.02630f, 8.27530f), rotation: new Vector3(0.00000f, 0.00000f, -18.00000f));
CreateObject(modelId: 18257, position: new Vector3(-225.18930f, -72.35310f, 6.50580f), rotation: new Vector3(0.00000f, 0.00000f, -20.00000f));
CreateObject(modelId: 18257, position: new Vector3(-237.63338f, -68.80544f, 6.50580f), rotation: new Vector3(0.00000f, 0.00000f, -20.00000f));
CreateObject(modelId: 18257, position: new Vector3(-250.39244f, -64.32850f, 6.50580f), rotation: new Vector3(0.00000f, 0.00000f, -20.00000f));
CreateObject(modelId: 2991, position: new Vector3(-262.21289f, -58.01108f, 7.07080f), rotation: new Vector3(0.00000f, 0.00000f, -18.00000f));
CreateObject(modelId: 2991, position: new Vector3(-262.21289f, -58.01110f, 8.25080f), rotation: new Vector3(0.00000f, 0.00000f, -18.00000f));
}
}
Loading maps
Inject IMapObjectService into the service responsible for your game mode's map rotation:
public class MapRotationService(IMapObjectService mapObjects)
{
// ...
}
Load a map by its registered name:
mapObjects.Load("Aim_Headshot");
or, if your game mode already keeps track of the current rotation:
mapObjects.Load(nextMap.Name);
If the specified map name is not registered, the call is ignored.
Unloading maps
When the current map is no longer needed, unload it:
mapObjects.Unload();
All objects created through CreateObject are automatically destroyed when the map is unloaded.
Design constraints
SampSharp.MapObjects is designed around game modes where only one object map can be active at a time.
Because of this, IMapObjectService enforces the following constraints:
- Calling
Loadwhile another map is already loaded throws anInvalidOperationException. - Calling
Unloadwhen no map is currently loaded throws anInvalidOperationException. - Calling
Loadwith an unregistered map name is ignored. - All objects created through
CreateObjectare automatically destroyed when the current map is unloaded.
This design matches game modes where maps rotate sequentially, such as Capture the Flag, Gun Game, Counter-Strike Team Deathmatch, or any mode that activates a single map at a time.
Contribution
Contributions of all kinds are welcome! You can help by improving the code, documentation, or tests.
To contribute:
- Fork the repository.
- Create a feature branch (
git checkout -b my-new-change). - Commit your changes (
git commit -am "Add some change"). - Push to your branch (
git push origin my-new-change). - Open a Pull Request.
License
This project is licensed under the MIT License. See the LICENSE file for details.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.8)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.8)
- SampSharp.MapObjects.Abstractions (>= 1.0.0-preview.2)
- SampSharp.OpenMp.Entities (>= 1.0.0-prerelease2)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 82 | 7/20/2026 |
| 1.0.0-preview.3 | 45 | 7/20/2026 |
| 1.0.0-preview.2 | 41 | 7/20/2026 |
| 1.0.0-preview.1 | 43 | 7/19/2026 |