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
93 changes: 92 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,73 @@ jobs:
name: swiftlys2_windows_pdb
path: build/windows/x64/release/swiftlys2.pdb

linux_loader:
needs: versioning
runs-on: ubuntu-latest
container:
image: registry.gitlab.steamos.cloud/steamrt/sniper/sdk
steps:
- name: Install dependencies
run: |
apt-get update
apt install libreadline-dev
- name: Checkout repository and submodules
uses: actions/checkout@v4
with:
repository: swiftly-solution/swiftlys2-loader
submodules: recursive
fetch-depth: 0
- name: Setup xmake
uses: xmake-io/github-action-setup-xmake@v1
with:
xmake-version: latest
actions-cache-folder: '.xmake-cache'
actions-cache-key: xmake-loader-${{ runner.os }}
- name: Build
run: |
xmake f --cc=gcc-14 --cxx=g++-14 -y
xmake build -y
env:
SWIFTLY_VERSION: ${{ needs.versioning.outputs.semVer }}
- name: Upload plugin as artifact
uses: actions/upload-artifact@v4
with:
name: swiftlys2_loader_linux
path: build/package/addons

windows_loader:
needs: versioning
runs-on: windows-latest
steps:
- name: Checkout repository and submodules
uses: actions/checkout@v4
with:
repository: swiftly-solution/swiftlys2-loader
submodules: recursive
fetch-depth: 0
- name: Setup xmake
uses: xmake-io/github-action-setup-xmake@v1
with:
xmake-version: latest
actions-cache-key: xmake-loader-${{ runner.os }}
- name: Build
run: |
xmake build -y
env:
SWIFTLY_VERSION: ${{ needs.versioning.outputs.semVer }}
- name: Upload plugin as artifact
uses: actions/upload-artifact@v4
with:
name: swiftlys2_loader_windows
path: build/package/addons
- name: Upload PDB as artifact
uses: actions/upload-artifact@v4
with:
name: swiftlys2_loader_windows_pdb
path: build/windows/x64/release/server.pdb

packaging:
needs: [versioning, linux_core, windows_core, managed]
needs: [versioning, linux_core, windows_core, managed, linux_loader, windows_loader]
runs-on: ubuntu-latest
env:
LINUX_FOLDER: swiftlys2-linux-v${{ needs.versioning.outputs.semVer }}
Expand All @@ -130,11 +195,31 @@ jobs:
with:
name: swiftlys2_linux
path: ./${{ env.LINUX_FOLDER }}
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: swiftlys2_loader_linux
path: ./${{ env.LINUX_FOLDER }}-loader
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: swiftlys2_windows
path: ./${{ env.WINDOWS_FOLDER }}
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: swiftlys2_windows_pdb
path: ./swiftlys2.pdb
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: swiftlys2_loader_windows
path: ./${{ env.WINDOWS_FOLDER }}-loader
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: swiftlys2_loader_windows_pdb
path: ./server.pdb

- name: Download artifacts
uses: actions/download-artifact@v4
Expand All @@ -161,6 +246,12 @@ jobs:
cp -r managed/SwiftlyS2 ${{ env.LINUX_FOLDER }}/swiftlys2/bin/managed
cp -r managed/SwiftlyS2 ${{ env.WINDOWS_FOLDER }}/swiftlys2/bin/managed

cp -r ${{ env.LINUX_FOLDER }}-loader/* ${{ env.LINUX_FOLDER }}/
cp -r ${{ env.WINDOWS_FOLDER }}-loader/* ${{ env.WINDOWS_FOLDER }}/

cp -r ./swiftlys2.pdb/swiftlys2.pdb ${{ env.WINDOWS_FOLDER }}/swiftlys2/bin/win64/
cp -r ./server.pdb/server.pdb ${{ env.WINDOWS_FOLDER }}/swiftlys2/bin/win64/

mkdir -p ${{ env.LINUX_FOLDER }}/swiftlys2/plugins/
mkdir -p ${{ env.WINDOWS_FOLDER }}/swiftlys2/plugins/

Expand Down
1 change: 1 addition & 0 deletions managed/managed.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
<BaseOutputPath>build\</BaseOutputPath>
<OutputPath>$(BaseOutputPath)Release\SwiftlyS2</OutputPath>
<AssemblyName>SwiftlyS2.CS2</AssemblyName>
<DisableRuntimeMarshalling>true</DisableRuntimeMarshalling>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
<NoWarn>$(NoWarn);CS1591</NoWarn>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public CommandCallback(string commandName, bool registerRaw, ICommandService.Com

var args = argsString.Split('\x01');
var context = new CommandContext(playerId, args, commandNameString, prefixString, slient == 1);
if (string.IsNullOrWhiteSpace(_permissions) || _permissionManager.PlayerHasPermission(_playerManagerService.GetPlayer(playerId).SteamID, _permissions))
if (!context.IsSentByPlayer || string.IsNullOrWhiteSpace(_permissions) || _permissionManager.PlayerHasPermission(_playerManagerService.GetPlayer(playerId).SteamID, _permissions))
{
_handler(context);
}
Expand Down
6 changes: 6 additions & 0 deletions managed/src/SwiftlyS2.Core/Modules/Engine/EngineService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,10 @@ public bool IsMapValid(string map)
{
return NativeEngineHelpers.IsMapValid(map);
}

public nint? FindGameSystemByName(string name)
{
var handle = NativeEngineHelpers.FindGameSystemByName(name);
return handle == nint.Zero ? null : handle;
}
}
73 changes: 70 additions & 3 deletions managed/src/SwiftlyS2.Core/Modules/Plugins/PluginManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using McMaster.NETCore.Plugins;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using SwiftlyS2.Core.Natives;
using SwiftlyS2.Core.Modules.Plugins;
using SwiftlyS2.Core.Services;
using SwiftlyS2.Shared;
Expand All @@ -21,6 +22,7 @@ internal class PluginManager
private List<Type> _SharedTypes { get; set; } = new();

private DateTime lastRead = DateTime.MinValue;
private readonly HashSet<string> reloadingPlugins = new();

public PluginManager(
IServiceProvider provider,
Expand Down Expand Up @@ -77,7 +79,12 @@ public void HandlePluginChange(object sender, FileSystemEventArgs e)
{
try
{
// why i have to make a debounce here?
if (!NativeServerHelpers.UseAutoHotReload())
{
return;
}

// Windows FileSystemWatcher triggers multiple (open, write, close) events for a single file change
if (DateTime.Now - lastRead < TimeSpan.FromSeconds(1))
{
return;
Expand All @@ -91,10 +98,70 @@ public void HandlePluginChange(object sender, FileSystemEventArgs e)

foreach (var plugin in _Plugins)
{
if (plugin.Metadata?.Id == Path.GetFileName(directory))
if (Path.GetFileName(plugin?.PluginDirectory) == Path.GetFileName(directory))
{
var pluginId = plugin.Metadata?.Id;
if (string.IsNullOrWhiteSpace(pluginId))
{
break;
}

lock (reloadingPlugins)
{
if (reloadingPlugins.Contains(pluginId))
{
return;
}
reloadingPlugins.Add(pluginId);
}

lastRead = DateTime.Now;
ReloadPlugin(plugin.Metadata!.Id);

// meh, Idk why, but when using Mstsc to copy and overwrite files
// it sometimes triggers: "System.IO.IOException: The process cannot access the file because it is being used by another process."
// therefore, we use a retry mechanism
Task.Run(async () =>
{
try
{
await Task.Delay(500);

bool fileLockSuccess = false;
for (int attempt = 0; attempt < 3; attempt++)
{
try
{
using (var stream = File.Open(e.FullPath, FileMode.Open, FileAccess.Read, FileShare.None))
{
}
fileLockSuccess = true;
break;
}
catch (IOException) when (attempt < 1)
{
_Logger.LogWarning($"{Path.GetFileName(plugin?.PluginDirectory)} is locked, retrying in 500ms... (Attempt {attempt + 1}/3)");
await Task.Delay(500);
}
catch (IOException)
{
_Logger.LogError($"Failed to reload {Path.GetFileName(plugin?.PluginDirectory)} after 3 attempts");
}
}

if (fileLockSuccess)
{
ReloadPlugin(pluginId);
}
}
finally
{
lock (reloadingPlugins)
{
reloadingPlugins.Remove(pluginId);
}
}
});

break;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ public IPluginConfigurationService InitializeWithTemplate(string name, string te

var options = new JsonSerializerOptions {
WriteIndented = true,
IncludeFields = true,
PropertyNamingPolicy = null
};

Expand Down
7 changes: 7 additions & 0 deletions managed/src/SwiftlyS2.Generated/Natives/ServerHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,11 @@ public unsafe static bool IsFollowingServerGuidelines() {
var ret = _IsFollowingServerGuidelines();
return ret == 1;
}

private unsafe static delegate* unmanaged<byte> _UseAutoHotReload;

public unsafe static bool UseAutoHotReload() {
var ret = _UseAutoHotReload();
return ret == 1;
}
}
7 changes: 7 additions & 0 deletions managed/src/SwiftlyS2.Shared/Modules/Engine/IEngineService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,11 @@ public interface IEngineService
/// The number of simulation ticks that have occurred since the server started.
/// </summary>
int TickCount { get; }

/// <summary>
/// Find a game system by name.
/// </summary>
/// <param name="name">The name of the game system.</param>
/// <returns>The game system handle. Null if not found.</returns>
nint? FindGameSystemByName(string name);
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public void Dispose() {
_handle.Dispose();
}

internal nint Address => _handle.Address;
public nint Address => _handle.Address;

public void SetBool(string key, bool value) {
NativeCEntityKeyValues.SetBool(Address, key, value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
public nint Elements;

[StructLayout(LayoutKind.Sequential)]
public struct Iterator_t

Check warning on line 22 in managed/src/SwiftlyS2.Shared/Natives/Structs/CUtlLeanVector.cs

View workflow job for this annotation

GitHub Actions / managed

'CUtlLeanVector<T, I>.Iterator_t' defines operator == or operator != but does not override Object.GetHashCode()

Check warning on line 22 in managed/src/SwiftlyS2.Shared/Natives/Structs/CUtlLeanVector.cs

View workflow job for this annotation

GitHub Actions / managed

'CUtlLeanVector<T, I>.Iterator_t' overrides Object.Equals(object o) but does not override Object.GetHashCode()

Check warning on line 22 in managed/src/SwiftlyS2.Shared/Natives/Structs/CUtlLeanVector.cs

View workflow job for this annotation

GitHub Actions / managed

'CUtlLeanVector<T, I>.Iterator_t' defines operator == or operator != but does not override Object.GetHashCode()

Check warning on line 22 in managed/src/SwiftlyS2.Shared/Natives/Structs/CUtlLeanVector.cs

View workflow job for this annotation

GitHub Actions / managed

'CUtlLeanVector<T, I>.Iterator_t' overrides Object.Equals(object o) but does not override Object.GetHashCode()

Check warning on line 22 in managed/src/SwiftlyS2.Shared/Natives/Structs/CUtlLeanVector.cs

View workflow job for this annotation

GitHub Actions / nuget

'CUtlLeanVector<T, I>.Iterator_t' defines operator == or operator != but does not override Object.GetHashCode()

Check warning on line 22 in managed/src/SwiftlyS2.Shared/Natives/Structs/CUtlLeanVector.cs

View workflow job for this annotation

GitHub Actions / nuget

'CUtlLeanVector<T, I>.Iterator_t' overrides Object.Equals(object o) but does not override Object.GetHashCode()
{
public I Index;

Expand All @@ -40,13 +40,21 @@

private I ExternalBufferMarker => I.One << ((Marshal.SizeOf<I>() * 8) - 1);

/// <summary>
/// Please use <see cref="ManagedCUtlLeanVector{T, I}"/> instead to construct it.
/// If you really want to use this, you should call <see cref="Purge"/> after you are done with it.
/// </summary>
public CUtlLeanVector(I growSize, I initSize)
{
Count = (I)(object)0;
Allocated = (I)(object)0;
EnsureCapacity(int.CreateChecked(initSize), true);
}

/// <summary>
/// Please use <see cref="ManagedCUtlLeanVector{T, I}"/> instead to construct it.
/// If you really want to use this, you should call <see cref="Purge"/> after you are done with it.
/// </summary>
public CUtlLeanVector(nint memory, I allocationCount, I numElements)
{
Count = numElements;
Expand Down
15 changes: 9 additions & 6 deletions managed/src/SwiftlyS2.Shared/Natives/Structs/CUtlMemory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,18 @@ public enum BufferMarkers
}

[StructLayout(LayoutKind.Sequential)]
public struct CUtlMemory<T> : IDisposable
public struct CUtlMemory<T>
{
private nint _memory;
private uint _allocationCount;
private uint _growSize;

public int ElementSize => SchemaSize.Get<T>();

/// <summary>
/// Please use <see cref="ManagedCUtlMemory{T}"/> instead to construct it.
/// If you really want to use this, you should call <see cref="Purge"/> after you are done with it.
/// </summary>
public CUtlMemory(int growSize, int initSize)
{
_memory = 0;
Expand All @@ -30,6 +34,10 @@ public CUtlMemory(int growSize, int initSize)
Init(growSize, initSize);
}

/// <summary>
/// Please use <see cref="ManagedCUtlMemory{T}"/> instead to construct it.
/// If you really want to use this, you should call <see cref="Purge"/> after you are done with it.
/// </summary>
public CUtlMemory(nint memory, int numelements, bool readOnly)
{
_memory = 0;
Expand All @@ -38,11 +46,6 @@ public CUtlMemory(nint memory, int numelements, bool readOnly)
SetExternalBuffer(memory, numelements, readOnly);
}

public void Dispose()
{
Purge();
}

public void Init(int growSize, int initSize)
{
Purge();
Expand Down
Loading
Loading