Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/SampSharp.OpenMp.Entities/SAMP/Components/Actor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class Actor : WorldEntity
/// <summary>
/// Initializes a new instance of the <see cref="Actor" /> class.
/// </summary>
protected Actor(IActorsComponent actors, IActor actor) : base((IEntity)actor)
protected Actor(IActorsComponent actors, IActor actor) : base(actor.HasValue ? (IEntity)actor : default)
{
_actors = actors;
Resource = actor;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public abstract class BaseGangZone : IdProvider
/// <summary>
/// Initializes a new instance of the <see cref="BaseGangZone" /> class.
/// </summary>
protected BaseGangZone(IOmpEntityProvider entityProvider, IGangZonesComponent gangZones, IGangZone gangZone) : base((IIDProvider)gangZone)
protected BaseGangZone(IOmpEntityProvider entityProvider, IGangZonesComponent gangZones, IGangZone gangZone) : base(gangZone.HasValue ? (IIDProvider)gangZone : default)
{
_entityProvider = entityProvider;
Resource = gangZone;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public abstract class BasePickup : WorldEntity
/// <summary>
/// Initializes a new instance of the <see cref="BasePickup" /> class.
/// </summary>
protected BasePickup(IPickupsComponent pickups, IPickup pickup) : base((IEntity)pickup)
protected BasePickup(IPickupsComponent pickups, IPickup pickup) : base(pickup.HasValue ? (IEntity)pickup : default)
{
_pickups = pickups;
Resource = pickup;
Expand Down
2 changes: 1 addition & 1 deletion src/SampSharp.OpenMp.Entities/SAMP/Components/Class.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class Class : IdProvider
/// <summary>
/// Initializes a new instance of the <see cref="Class" /> class.
/// </summary>
protected Class(IClassesComponent classes, IClass playerClass) : base((IIDProvider)playerClass)
protected Class(IClassesComponent classes, IClass playerClass) : base(playerClass.HasValue ? (IIDProvider)playerClass : default)
{
_classes = classes;
Resource = playerClass;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class GlobalObject : WorldEntity
/// <summary>
/// Initializes a new instance of the <see cref="GlobalObject" /> class.
/// </summary>
protected GlobalObject(IOmpEntityProvider entityProvider, IObjectsComponent objects, IObject @object) : base((IEntity)@object)
protected GlobalObject(IOmpEntityProvider entityProvider, IObjectsComponent objects, IObject @object) : base(@object.HasValue ? (IEntity)@object : default)
{
_entityProvider = entityProvider;
_objects = objects;
Expand Down
14 changes: 11 additions & 3 deletions src/SampSharp.OpenMp.Entities/SAMP/Components/IdProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,25 @@ namespace SampSharp.Entities.SAMP;
/// <summary>
/// Represents a component which provides an identifier.
/// </summary>
/// <param name="idProvider">The open.mp id provider this component represents.</param>
public abstract class IdProvider(IIDProvider idProvider) : Component
public abstract class IdProvider : Component
{
/// <summary>
/// Initializes a new instance of the <see cref="IdProvider" /> class.
/// </summary>
/// <param name="idProvider">The open.mp id provider this component represents.</param>
protected IdProvider(IIDProvider idProvider)
{
Resource = idProvider;
}

private IIDProvider Resource
{
get
{
ObjectDisposedException.ThrowIf(!IsComponentAlive, typeof(IdProvider));
return field;
}
} = idProvider;
}

/// <summary>
/// Gets the identifier of this component.
Expand Down
2 changes: 1 addition & 1 deletion src/SampSharp.OpenMp.Entities/SAMP/Components/Menu.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class Menu : IdProvider
/// <summary>
/// Initializes a new instance of the <see cref="Menu" /> class.
/// </summary>
protected Menu(IMenusComponent menus, IMenu menu, string title) : base((IIDProvider)menu)
protected Menu(IMenusComponent menus, IMenu menu, string title) : base(menu.HasValue ? (IIDProvider)menu : default)
{
_menus = menus;
Resource = menu;
Expand Down
2 changes: 1 addition & 1 deletion src/SampSharp.OpenMp.Entities/SAMP/Components/Npc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public class Npc : IdProvider
/// <summary>
/// Initializes a new instance of the <see cref="Npc" /> class.
/// </summary>
protected Npc(INPCComponent npcs, INPC npc) : base((IIDProvider)npc)
protected Npc(INPCComponent npcs, INPC npc) : base(npc.HasValue ? (IIDProvider)npc : default)
{
_npcs = npcs;
Resource = npc;
Expand Down
2 changes: 1 addition & 1 deletion src/SampSharp.OpenMp.Entities/SAMP/Components/Player.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public class Player : WorldEntity
/// <summary>
/// Constructs an instance of <see cref="Player" />, should be used internally.
/// </summary>
protected Player(IOmpEntityProvider entityProvider, IPlayer player) : base((IEntity)player)
protected Player(IOmpEntityProvider entityProvider, IPlayer player) : base(player.HasValue ? (IEntity)player : default)
{
_entityProvider = entityProvider;
Resource = player;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ public class PlayerObject : WorldEntity
/// <summary>
/// Initializes a new instance of the <see cref="PlayerObject" /> class.
/// </summary>
protected PlayerObject(IOmpEntityProvider entityProvider, IPlayerObjectData playerObjects, IPlayerObject playerObject) : base((IEntity)playerObject)
protected PlayerObject(IOmpEntityProvider entityProvider, IPlayerObjectData playerObjects, IPlayerObject playerObject) : base(playerObject.HasValue
? (IEntity)playerObject
: default)
{
_entityProvider = entityProvider;
_playerObjects = playerObjects;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class PlayerTextDraw : IdProvider
/// <summary>
/// Initializes a new instance of the <see cref="PlayerTextDraw" /> class.
/// </summary>
protected PlayerTextDraw(IPlayerTextDrawData playerTextDraws, IPlayerTextDraw playerTextDraw) : base((IIDProvider)playerTextDraw)
protected PlayerTextDraw(IPlayerTextDrawData playerTextDraws, IPlayerTextDraw playerTextDraw) : base(playerTextDraw.HasValue ? (IIDProvider)playerTextDraw : default)
{
_playerTextDraws = playerTextDraws;
Resource = playerTextDraw;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class PlayerTextLabel : WorldEntity
/// <summary>
/// Initializes a new instance of the <see cref="PlayerTextLabel" /> class.
/// </summary>
protected PlayerTextLabel(IOmpEntityProvider entityProvider, IPlayerTextLabelData playerTextLabels, IPlayerTextLabel playerTextLabel) : base((IEntity)playerTextLabel)
protected PlayerTextLabel(IOmpEntityProvider entityProvider, IPlayerTextLabelData playerTextLabels, IPlayerTextLabel playerTextLabel) : base(playerTextLabel.HasValue ? (IEntity)playerTextLabel : default)
{
_entityProvider = entityProvider;
_playerTextLabels = playerTextLabels;
Expand Down
2 changes: 1 addition & 1 deletion src/SampSharp.OpenMp.Entities/SAMP/Components/TextDraw.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class TextDraw : IdProvider
/// <summary>
/// Initializes a new instance of the <see cref="TextDraw" /> class.
/// </summary>
protected TextDraw(ITextDrawsComponent textDraws, ITextDraw textDraw) : base((IIDProvider)textDraw)
protected TextDraw(ITextDrawsComponent textDraws, ITextDraw textDraw) : base(textDraw.HasValue ? (IIDProvider)textDraw : default)
{
_textDraws = textDraws;
Resource = textDraw;
Expand Down
2 changes: 1 addition & 1 deletion src/SampSharp.OpenMp.Entities/SAMP/Components/TextLabel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class TextLabel : WorldEntity
/// <summary>
/// Initializes a new instance of the <see cref="TextLabel" /> class.
/// </summary>
protected TextLabel(IOmpEntityProvider entityProvider, ITextLabelsComponent textLabels, ITextLabel textLabel) : base((IEntity)textLabel)
protected TextLabel(IOmpEntityProvider entityProvider, ITextLabelsComponent textLabels, ITextLabel textLabel) : base(textLabel.HasValue ? (IEntity)textLabel : default)
{
_entityProvider = entityProvider;
_textLabels = textLabels;
Expand Down
2 changes: 1 addition & 1 deletion src/SampSharp.OpenMp.Entities/SAMP/Components/Vehicle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class Vehicle : WorldEntity
/// <summary>
/// Initializes a new instance of the <see cref="Vehicle" /> class.
/// </summary>
protected Vehicle(IOmpEntityProvider entityProvider, IVehiclesComponent vehicles, IVehicle vehicle) : base((IEntity)vehicle)
protected Vehicle(IOmpEntityProvider entityProvider, IVehiclesComponent vehicles, IVehicle vehicle) : base(vehicle.HasValue ? (IEntity)vehicle : default)
{
_entityProvider = entityProvider;
_vehicles = vehicles;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public abstract class WorldEntity : IdProvider
/// Initializes a new instance of the <see cref="WorldEntity" /> class.
/// </summary>
/// <param name="entity">The open.mp entity this component represents.</param>
protected WorldEntity(IEntity entity) : base((IIDProvider)entity)
protected WorldEntity(IEntity entity) : base(entity.HasValue ? (IIDProvider)entity : default)
{
Resource = entity;
}
Expand Down
1 change: 0 additions & 1 deletion src/sampsharp-component/compat.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

#pragma once

#include <coreclr_delegates.h>
Expand Down
72 changes: 72 additions & 0 deletions src/sampsharp-component/sampsharp-api.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#pragma once

// This header defines the API for the SampSharp managed components. Through this API the managed component is provided
// with access to the open.mp infrastructure and ties the managed component to the lifecycle of this unmanaged component.
// This API is implemented by the SampSharp.Sdk/SampSharp.OpenMp.Core packages.
#include <coreclr_delegates.h>
#include <sdk.hpp>

#include "platform.hpp"

// Provides version information about the SampSharp component and the hosted API. This is used to check for version
// mismatches that would cause launch failure.
struct SampSharpInfo
{
SampSharpInfo(int api_version, SemanticVersion version) :
size(sizeof(SampSharpInfo)),
api_version(api_version),
version(version)
{
}

// sizeof(SampSharpInfo) for backwards compatibility
size_t size;
// version of SampSharp component <> hosted API. Version mismatch will cause launch failure.
int api_version;
// version of the SampSharp component
SemanticVersion version;
};

// Delegate type for the cleanup callback, called when the component is unloaded during shutdown.
typedef void(API_CALLTYPE* on_cleanup_fn)();

// Delegate type for the on_free_component callback, called when a component is freed.
typedef void(API_CALLTYPE* on_free_component_fn)(IComponent* component);

// Delegate type for the configure callback function, used to set the on_cleanup and on_free_component callbacks.
typedef void(API_CALLTYPE* configure_callback_fn)(void** cb);

// Parameters for initializing the managed component, passed to the on_init callback.
// This is a struct instead of parameters for backwards compatibility, so parameters can be added without breaking the
// API. The size field is used to check which version of the struct is being used, so new fields should only be added
// at the end.
struct SampSharpInitParams
{
SampSharpInitParams(ICore* core, IComponentList* componentList, SampSharpInfo* info,
configure_callback_fn setOnCleanup, configure_callback_fn setOnFreeComponent) :
size(sizeof(SampSharpInitParams)),
info(info),
core(core),
componentList(componentList),
setOnCleanup(setOnCleanup),
setOnFreeComponent(setOnFreeComponent)
{
}

// sizeof(SampSharpInitParams) for backwards compatibility
size_t size;
// Version info about the SampSharp component
SampSharpInfo* info;
// Pointer to open.mp ICore
ICore* core;
// Pointer to open.mp IComponentList
IComponentList* componentList;
// Function to configure a cleanup callback. Callback should have signature on_cleanup_fn.
configure_callback_fn setOnCleanup;
// Function to configure a onFreeComponent callback. Callback should have signature configure_callback_fn.
configure_callback_fn setOnFreeComponent;
};

// Delegate type for the on_init callback, called when the component is loaded. The callback should initialize the
// managed component and optionally set the on_cleanup and on_free_component callbacks.
typedef void(CORECLR_DELEGATE_CALLTYPE* on_init_fn)(SampSharpInitParams);
15 changes: 12 additions & 3 deletions src/sampsharp-component/sampsharp-component.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ void SampSharpComponent::onInit(IComponentList* components)

const char* error = nullptr;

// 1) Load hostfxr: The .NET host framework resolver provides functionality for resolving and loading the correct
// .NET runtime version based on the runtime configuration provided for the gamemode assembly. Hostfxr is part of
// the .NET runtime and is loaded from the installation directory of the runtime.
// The path to hostfxr is resolved using the thin nethost static library we include in our component.
if (!managed_host_.initialize(&error))
{
core_->logLn(Error,
Expand All @@ -86,16 +90,21 @@ void SampSharpComponent::onInit(IComponentList* components)
return;
}

// 2) Load .NET runtime: Load the .NET runtime using hostfxr using the .runtimeconfig.json of the gamemode assembly.
if (!managed_host_.loadFor(directory, assembly, &error))
{
core_->logLn(Error,
"Failed to initialize the .NET runtime for '%s/%s'. Is the '*.runtimeconfig.json' file available? "
"Is the .NET runtime available?",
"Failed to initialize the .NET runtime for '%s/%s'. "
"This may happen when the configured gamemode assembly or directory is incorrect, when the runtime"
" configuration file (.runtimeconfig.json) for the gamemode assembly cannot be found or when the "
"required .NET runtime version ins not installed. ",
directory.to_string().c_str(), assembly.to_string().c_str());
core_->logLn(Error, "Error message: %s", error);
core_->logLn(Error, "Error message returned by the .NET host framework resolver: %s", error);
return;
}

// 3) Load gamemode: Load the gamemode assembly and locate our SampSharp entrypoint. A function pointer to the
// managed entry point is retrieved.
on_init_fn on_init;
if (!managed_host_.getEntryPoint(full_entry_point, entry_point_method, reinterpret_cast<void**>(&on_init), &error))
{
Expand Down
48 changes: 1 addition & 47 deletions src/sampsharp-component/sampsharp-component.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,53 +3,7 @@
#include <sdk.hpp>

#include "managed-host.hpp"
#include "platform.hpp"

struct SampSharpInfo
{
SampSharpInfo(int api_version, SemanticVersion version) :
size(sizeof(SampSharpInfo)),
api_version(api_version),
version(version)
{
}

// sizeof(SampSharpInfo) for backwards compatibility
size_t size;
// version of SampSharp component <> hosted API. Version mismatch will cause launch failure.
int api_version;
// version of the SampSharp component
SemanticVersion version;
};

typedef void(API_CALLTYPE* on_cleanup_fn)();
typedef void(API_CALLTYPE* on_free_component_fn)(IComponent* component);

typedef void(API_CALLTYPE* configure_callback_fn)(void** cb);

struct SampSharpInitParams
{
SampSharpInitParams(ICore* core, IComponentList* componentList, SampSharpInfo* info,
configure_callback_fn setOnCleanup, configure_callback_fn setOnFreeComponent) :
size(sizeof(SampSharpInitParams)),
info(info),
core(core),
componentList(componentList),
setOnCleanup(setOnCleanup),
setOnFreeComponent(setOnFreeComponent)
{
}

// sizeof(SampSharpInitParams) for backwards compatibility
size_t size;
SampSharpInfo* info;
ICore* core;
IComponentList* componentList;
configure_callback_fn setOnCleanup;
configure_callback_fn setOnFreeComponent;
};

typedef void(CORECLR_DELEGATE_CALLTYPE* on_init_fn)(SampSharpInitParams);
#include "sampsharp-api.hpp"

struct ISampSharpComponent : IComponent
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,4 @@ public static void ShouldHaveCount<TKey, TValue>(this IReadOnlyDictionary<TKey,
{
dict.Count.ShouldBe(expectedCount);
}
}
}
Loading