Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
9af0550
feat(game): Extend more shortcut in GameService
samyycX Apr 23, 2026
d478dca
chore(native): Cleanup
skuzzis Apr 23, 2026
066a502
chore(gamefuncs): Redundant
skuzzis Apr 23, 2026
e585562
update(vendor): NUKE METAMOD
skuzzis Apr 24, 2026
9f31c00
perf(natives): String returns
skuzzis Apr 24, 2026
1c67174
feat(gamedata): RevertPatch
skuzzis Apr 25, 2026
1bf0b1b
[skip ci] fix(managed): handle null TakeDamageResult (#303)
isMADAO Apr 25, 2026
da38a81
chore(TakeDamage): Make the object global
skuzzis Apr 25, 2026
be61305
feat(player/components): ToPlayer
skuzzis Apr 25, 2026
61b1ed9
fix(FindTargettedPlayers): NoMultipleTargets
skuzzis Apr 25, 2026
a7796ff
feat(perms): GetPlayerPermissions
skuzzis Apr 25, 2026
0a0f1f3
update(takedamage): More fields set
skuzzis Apr 25, 2026
528efe8
fix(managed): Fix console redirect
samyycX Apr 26, 2026
626f101
fix(log): Output encoding
samyycX Apr 26, 2026
e07d456
fix(netmsg): Fuck you valve
samyycX Apr 26, 2026
d1de3f1
fix(CTakeDamage): Safety check
skuzzis Apr 26, 2026
3379e4b
fix: game event params (#308)
isMADAO Apr 26, 2026
13cebe2
update(dotnet): Runtime
skuzzis Apr 27, 2026
4b330ed
fix(workflow): HostFXR fetch
skuzzis Apr 27, 2026
e79f584
feat(playermanager): MaxPlayers
skuzzis Apr 27, 2026
3346ca8
fix(allocator): null checks
skuzzis Apr 27, 2026
31d8b1d
update(Teleport): Use corresponding offset
skuzzis Apr 28, 2026
c801b41
fix(GetWorkshopId): Async
skuzzis Apr 29, 2026
81bd38e
fix(allocator): Return nullptr on size 0
skuzzis Apr 29, 2026
0c62966
feat(ag2): Some ag2 struct
samyycX Apr 30, 2026
97d3b8e
tryfix(convars): String Value reader
skuzzis Apr 30, 2026
1dd379b
update(schema): Update schema
samyycX May 1, 2026
e7b46ee
chore(translations): Explain
skuzzis May 2, 2026
73565e9
tryfix(scheduler): QueueOrNow -> OnTick
skuzzis May 2, 2026
de09f9c
[skip ci] update(templates): nuget pkg
skuzzis May 2, 2026
d0317f0
feat(crashreporter): Tracer level 2
skuzzis May 2, 2026
39898f6
fix(tracer): linux build
skuzzis May 2, 2026
02a0eef
feat(entitysystem): Make game rules safer
samyycX May 3, 2026
8ed574c
fix(sdk): Fix submodule
samyycX May 3, 2026
e21e9c6
perf(entities): Better
samyycX May 3, 2026
dfda15e
update(player): Some valid checks
skuzzis May 3, 2026
59f87c1
fix(console): Not outputting more than 2048 chars
skuzzis May 3, 2026
0f41f55
feat(colors): Allow case insensitive replacement
skuzzis May 3, 2026
ce72295
fix(player/lang): Use server as fallback
skuzzis May 3, 2026
e71a654
feat(player/targetting): UserID (#userid)
skuzzis May 4, 2026
2a4c86e
update(engine): WorkshopId sync only
skuzzis May 4, 2026
01db196
fix(pluginmanager): useless exception
skuzzis May 4, 2026
0266684
tryfix(allocator): Nuke locks
samyycX May 4, 2026
1f9a7bd
fix(crashreporter): memoryLoad
skuzzis May 5, 2026
a59e0c7
tryfix(db): Pooling
skuzzis May 5, 2026
121cef2
feat(sw/lists): Use pagination for tables
skuzzis May 5, 2026
59ce354
tryfix(player/msg): HLTV Support
skuzzis May 5, 2026
c858e4d
tryfix(db): Pooling casting
skuzzis May 5, 2026
bfc01c4
perf(db): Use smarter pooling cache
skuzzis May 5, 2026
671a09b
update(db): Refetch data on each factory call
skuzzis May 5, 2026
bf0d284
update(natives): Don't use static strings
skuzzis May 5, 2026
e46621c
fix(db): connection in constructor
skuzzis May 5, 2026
454f7e3
fix(db/connchecker): IsAlive
skuzzis May 5, 2026
cd35623
revert(db): pooling
skuzzis May 5, 2026
4145cb1
revert(player/msg): HLTV Support
skuzzis May 6, 2026
b76c12b
update(localizer): Return nonexistent key
skuzzis May 6, 2026
910e9c1
fix(translation): Empty localizer
skuzzis May 6, 2026
90e7e31
update(code): safer approaches
skuzzis May 6, 2026
b20b905
update(tracer): remove thread name tracking
skuzzis May 6, 2026
addc868
fix(console): Chunking
skuzzis May 6, 2026
4e4d6e8
feat(core): Add windows full dump
samyycX May 7, 2026
a2e0886
fix(menu/render): Invalid index
skuzzis May 7, 2026
67d4168
update(plugins/list): Remove website
skuzzis May 7, 2026
89f4fc9
update(entity/manager): useless try-catch
skuzzis May 8, 2026
ef34881
fix(takedamage): nullptr check
skuzzis May 8, 2026
1671e2d
revert(WorkshopId): Sync Only
skuzzis May 8, 2026
ef254ce
update(shared/ifacemanager): Exception message
skuzzis May 8, 2026
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
12 changes: 6 additions & 6 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -250,14 +250,14 @@ jobs:
run: |
mkdir -p ./linux-runtimes
cd ./linux-runtimes
wget https://builds.dotnet.microsoft.com/dotnet/Runtime/10.0.0/dotnet-runtime-10.0.0-linux-x64.tar.gz
wget https://builds.dotnet.microsoft.com/dotnet/Runtime/10.0.7/dotnet-runtime-10.0.7-linux-x64.tar.gz
mkdir -p content
tar -xzf dotnet-runtime-10.0.0-linux-x64.tar.gz -C content
tar -xzf dotnet-runtime-10.0.7-linux-x64.tar.gz -C content
cd ..
mkdir -p ./windows-runtimes
cd ./windows-runtimes
wget https://builds.dotnet.microsoft.com/dotnet/Runtime/10.0.0/dotnet-runtime-10.0.0-win-x64.zip
unzip dotnet-runtime-10.0.0-win-x64.zip -d content
wget https://builds.dotnet.microsoft.com/dotnet/Runtime/10.0.7/dotnet-runtime-10.0.7-win-x64.zip
unzip dotnet-runtime-10.0.7-win-x64.zip -d content
cd ..

- name: Create package
Expand All @@ -283,8 +283,8 @@ jobs:
cp -r linux-runtimes/content/ ${{ env.LINUX_FOLDER }}-with-runtimes/swiftlys2/bin/managed/dotnet
cp -r windows-runtimes/content/ ${{ env.WINDOWS_FOLDER }}-with-runtimes/swiftlys2/bin/managed/dotnet

cp linux-runtimes/content/host/fxr/10.0.0/libhostfxr.so ${{ env.LINUX_FOLDER }}-with-runtimes/swiftlys2/bin/linuxsteamrt64/libhostfxr.so
cp windows-runtimes/content/host/fxr/10.0.0/hostfxr.dll ${{ env.WINDOWS_FOLDER }}-with-runtimes/swiftlys2/bin/win64/hostfxr.dll
cp linux-runtimes/content/host/fxr/10.0.7/libhostfxr.so ${{ env.LINUX_FOLDER }}-with-runtimes/swiftlys2/bin/linuxsteamrt64/libhostfxr.so
cp windows-runtimes/content/host/fxr/10.0.7/hostfxr.dll ${{ env.WINDOWS_FOLDER }}-with-runtimes/swiftlys2/bin/win64/hostfxr.dll

mkdir -p ${{ env.LINUX_FOLDER }}/addons/
mkdir -p ${{ env.WINDOWS_FOLDER }}/addons/
Expand Down
3 changes: 0 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
[submodule "vendor/metamod"]
path = vendor/metamod
url = https://github.com/alliedmodders/metamod-source
[submodule "vendor/s2sdk"]
path = vendor/s2sdk
url = https://github.com/swiftly-solution/s2sdk
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<PackageId>SwiftlyS2.CS2.PluginTemplate</PackageId>
<Authors>SwiftlyS2 Team</Authors>
<Version>1.0.2</Version>
<Version>1.0.3</Version>
<Description>This is a template for creating a SwiftlyS2 plugin.</Description>
<PackageType>Template</PackageType>
<PackageIcon>icon.png</PackageIcon>
Expand Down
Binary file not shown.
2 changes: 1 addition & 1 deletion managed/SwiftlyS2.PluginTemplate/templates/PluginId.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="10.0.0" ExcludeAssets="runtime" PrivateAssets="all" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="10.0.0" ExcludeAssets="runtime" PrivateAssets="all" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="10.0.0" ExcludeAssets="runtime" PrivateAssets="all" />
<PackageReference Include="SwiftlyS2.CS2" Version="1.1.0" ExcludeAssets="runtime" PrivateAssets="all" />
<PackageReference Include="SwiftlyS2.CS2" Version="*" ExcludeAssets="runtime" PrivateAssets="all" />
</ItemGroup>

<ItemGroup>
Expand Down
8 changes: 8 additions & 0 deletions managed/src/SwiftlyS2.Core/Bootstrap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using SwiftlyS2.Core.Services;
using SwiftlyS2.Core.Translations;
using SwiftlyS2.Shared.SteamAPI;
using SwiftlyS2.Shared.Misc;

namespace SwiftlyS2.Core;

Expand Down Expand Up @@ -65,6 +66,13 @@ public static void Start( IntPtr nativeTable, int nativeTableSize, string basePa
GameFunctions.Initialize();
FileLogger.Initialize(logPath);

var redirector = new ConsoleRedirector();
Console.SetOut(redirector);
Console.SetError(redirector);
AnsiConsole.Console = AnsiConsole.Create(new AnsiConsoleSettings {
Out = new AnsiConsoleOutput(redirector)
});

AnsiConsole.Write(new FigletText("SwiftlyS2").LeftJustified().Color(Color.LightSteelBlue1));

sw2Host = Host.CreateDefaultBuilder()
Expand Down
2 changes: 1 addition & 1 deletion managed/src/SwiftlyS2.Core/Modules/Convars/ConVar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ public T GetValue()
{
unsafe
{
return Type != EConVarType.EConVarType_String ? Unsafe.Read<T>((void*)ValuePtr) : (T)(object)ValuePtr.AsRef<CUtlString>().Value;
return Type != EConVarType.EConVarType_String ? Unsafe.Read<T>((void*)ValuePtr) : (T)(object)ValueAsString;
}
}

Expand Down
29 changes: 16 additions & 13 deletions managed/src/SwiftlyS2.Core/Modules/Database/DatabaseService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,18 @@ static DatabaseService()
{
}

public DatabaseService( ILogger<DatabaseService> logger )
public DatabaseService(ILogger<DatabaseService> logger)
{
this.logger = logger;
this.connectionFactories.Clear();
}

private string ResolveConnectionName( string connectionName )
private string ResolveConnectionName(string connectionName)
{
return NativeDatabase.ConnectionExists(connectionName) ? connectionName : NativeDatabase.GetDefaultConnectionName();
}

private Func<IDbConnection> GetOrCreateConnectionFactory( string connectionName )
private Func<IDbConnection> GetOrCreateConnectionFactory(string connectionName)
{
var resolvedName = ResolveConnectionName(connectionName);

Expand All @@ -56,7 +56,7 @@ private Func<IDbConnection> GetOrCreateConnectionFactory( string connectionName
}
}

private static Func<IDbConnection> CreateConnectionFactory( string connectionName )
private static Func<IDbConnection> CreateConnectionFactory(string connectionName)
{
var driver = NativeDatabase.GetConnectionDriver(connectionName);
var host = NativeDatabase.GetConnectionHost(connectionName);
Expand All @@ -66,23 +66,25 @@ private static Func<IDbConnection> CreateConnectionFactory( string connectionNam
var timeout = NativeDatabase.GetConnectionTimeout(connectionName);
var port = NativeDatabase.GetConnectionPort(connectionName);

return driver switch {
return driver switch
{
"sqlite" => CreateSqliteFactory(database),
"mysql" => CreateMySqlFactory(host, port, database, user, pass, timeout),
"postgresql" => CreatePostgresFactory(host, port, database, user, pass, timeout),
_ => throw new NotSupportedException($"Unsupported database driver: {driver}")
};
}

private static Func<IDbConnection> CreateSqliteFactory( string database )
private static Func<IDbConnection> CreateSqliteFactory(string database)
{
var connStr = $"Data Source={database}";
return () => new SQLiteConnection(connStr);
}

private static Func<IDbConnection> CreateMySqlFactory( string host, ushort port, string database, string user, string pass, uint timeout )
private static Func<IDbConnection> CreateMySqlFactory(string host, ushort port, string database, string user, string pass, uint timeout)
{
var builder = new MySqlConnectionStringBuilder {
var builder = new MySqlConnectionStringBuilder
{
Server = host,
Port = port > 0 ? port : 3306u,
Database = database,
Expand All @@ -99,9 +101,10 @@ private static Func<IDbConnection> CreateMySqlFactory( string host, ushort port,
return () => new MySqlConnection(connStr);
}

private static Func<IDbConnection> CreatePostgresFactory( string host, ushort port, string database, string user, string pass, uint timeout )
private static Func<IDbConnection> CreatePostgresFactory(string host, ushort port, string database, string user, string pass, uint timeout)
{
var builder = new NpgsqlConnectionStringBuilder {
var builder = new NpgsqlConnectionStringBuilder
{
Host = host,
Port = port > 0 ? port : 5432,
Database = database,
Expand All @@ -118,12 +121,12 @@ private static Func<IDbConnection> CreatePostgresFactory( string host, ushort po
return () => new NpgsqlConnection(connStr);
}

public string GetConnectionString( string connectionName )
public string GetConnectionString(string connectionName)
{
return GetConnectionInfo(connectionName).ToString();
}

public DatabaseConnectionInfo GetConnectionInfo( string connectionName )
public DatabaseConnectionInfo GetConnectionInfo(string connectionName)
{
var resolvedName = ResolveConnectionName(connectionName);
return new DatabaseConnectionInfo(
Expand All @@ -138,7 +141,7 @@ public DatabaseConnectionInfo GetConnectionInfo( string connectionName )
);
}

public IDbConnection GetConnection( string connectionName )
public IDbConnection GetConnection(string connectionName)
{
return GetOrCreateConnectionFactory(connectionName)();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,20 @@ private void ProcessCommandEnd()
output = output.Append(line);
}

_ = Task.Run(() => command.Callback.Invoke(output.ToString()));
_ = Task.Run(() =>
{
try
{
command.Callback.Invoke(output.ToString());
} catch (Exception ex)
{
if (!GlobalExceptionHandler.Handle(ref ex))
{
return;
}
AnsiConsole.WriteException(ex);
}
});
}
}

Expand Down
27 changes: 10 additions & 17 deletions managed/src/SwiftlyS2.Core/Modules/EntitySystem/EntityManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ public static CEntityInstance OnEntityCreated( nint entityPtr )

_Dummy.DangerousSetHandle(entityPtr);
var index = _Dummy.Index;
var entity = ClassConvertor.ConvertEntityByDesignerName(entityPtr, _Dummy.DesignerName);
var designerName = _Dummy.DesignerName;
var entity = ClassConvertor.ConvertEntityByDesignerName(entityPtr, designerName);
lock (_lock)
{
try
Expand Down Expand Up @@ -52,21 +53,18 @@ public static CEntityInstance OnEntityCreated( nint entityPtr )

public static CEntityInstance? GetEntityByAddress( nint address )
{
if (address == 0) return null;

lock (_lock)
{
try
{
return !_PtrToIndex.TryGetValue(address, out var value) ? null : _Entities[value];
}
catch
{
return null;
}
return !_PtrToIndex.TryGetValue(address, out var value) ? null : _Entities[value];
}
}

public static void OnEntityDeleted( nint entityPtr )
{
if (entityPtr == 0) return;

lock (_lock)
{
try
Expand Down Expand Up @@ -102,16 +100,11 @@ public static IEnumerable<CEntityInstance> GetAllEntities()

public static bool IsAddressValid( nint address )
{
if (address == 0) return false;

lock (_lock)
{
try
{
return _PtrToIndex.ContainsKey(address);
}
catch
{
return false;
}
return _PtrToIndex.ContainsKey(address);
}
}

Expand Down
26 changes: 23 additions & 3 deletions managed/src/SwiftlyS2.Core/Modules/EntitySystem/EntitySystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ namespace SwiftlyS2.Core.EntitySystem;

internal class EntitySystemService : IEntitySystemService, IDisposable
{
private CCSGameRulesProxy? cachedGameRulesProxy;
private CCSGameRules? cachedGameRules;
private readonly IEventSubscriber eventSubscriber;

private readonly ConcurrentDictionary<Guid, EventDelegates.OnEntityFireOutputHookEvent> outputHooks = new();
private readonly ConcurrentDictionary<Guid, EventDelegates.OnEntityIdentityAcceptInputHook> inputHooks = new();
private CCSGameRulesImpl cachedGameRules = new(0);
private volatile bool disposed;

public EntitySystemService( IEventSubscriber eventSubscriber )
Expand Down Expand Up @@ -65,8 +66,27 @@ public CHandle<T> GetRefEHandle<T>( T entity ) where T : class, ISchemaClass<T>
public CCSGameRules? GetGameRules()
{
ThrowIfEntitySystemInvalid();
cachedGameRules.DangerousSetHandle(NativeEntitySystem.GetGameRules());
return cachedGameRules;
if (cachedGameRules != null)
{
if (cachedGameRulesProxy != null && cachedGameRulesProxy.IsValidEntity)
{
return cachedGameRules;
} else
{
cachedGameRules = null;
cachedGameRulesProxy = null;
return null;
}
} else
{
if (GetAllEntitiesByClass<CCSGameRulesProxy>().FirstOrDefault() is CCSGameRulesProxy proxy)
{
cachedGameRulesProxy = proxy;
cachedGameRules = cachedGameRulesProxy.GameRules;
return cachedGameRules;
}
}
return null;
}

public IEnumerable<CEntityInstance> GetAllEntities()
Expand Down
27 changes: 27 additions & 0 deletions managed/src/SwiftlyS2.Core/Modules/Events/EventPublisher.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Runtime.InteropServices;
using Spectre.Console;
using SwiftlyS2.Shared.Misc;
using SwiftlyS2.Shared.Natives;
using SwiftlyS2.Core.Natives;
using SwiftlyS2.Shared.Events;
using SwiftlyS2.Core.Scheduler;
Expand All @@ -16,6 +17,7 @@ internal static class EventPublisher
{
private static readonly List<EventSubscriber> subscribers = [];
private static readonly Lock subscribersLock = new();
private static CTakeDamageResult emptyTakeDamageResult = new();

public static void Subscribe( EventSubscriber subscriber )
{
Expand Down Expand Up @@ -637,6 +639,31 @@ public static byte OnEntityTakeDamage( nint entityPtr, nint takeDamageInfoPtr, n
{
unsafe
{
if (takeDamageResultPtr == 0 && takeDamageInfoPtr != 0)
{
var damageInfo = (CTakeDamageInfo*)takeDamageInfoPtr;

emptyTakeDamageResult.OriginatingInfo = damageInfo;
emptyTakeDamageResult.DestructibleHitGroupRequests = damageInfo->DestructiblePartDamageRequests;
emptyTakeDamageResult.HealthLost = (int)damageInfo->Damage;
emptyTakeDamageResult.DamageDealt = damageInfo->Damage;
emptyTakeDamageResult.PreModifiedDamage = damageInfo->Damage;
emptyTakeDamageResult.TotalledDamageDealt = damageInfo->Damage;
emptyTakeDamageResult.TotalledHealthLost = (int)damageInfo->Damage;
emptyTakeDamageResult.TotalledPreModifiedDamage = damageInfo->Damage;
emptyTakeDamageResult.DamageFlags = damageInfo->DamageFlags;
emptyTakeDamageResult.WasDamageSuppressed = (byte)(damageInfo->InTakeDamageFlow == 0 ? 1 : 0);
emptyTakeDamageResult.OverrideFlinchHitGroup = damageInfo->ActualHitGroup;
emptyTakeDamageResult.HealthBefore = 0;
emptyTakeDamageResult.NewDamageAccumulatorValue = 0;
emptyTakeDamageResult.SuppressFlinch = 0;

fixed (CTakeDamageResult* resultPtr = &emptyTakeDamageResult)
{
takeDamageResultPtr = (nint)resultPtr;
}
}

OnEntityTakeDamageEvent @event = new() {
Entity = EntityManager.GetEntityByAddress(entityPtr) ?? new CEntityInstanceImpl(entityPtr),
_infoPtr = takeDamageInfoPtr,
Expand Down
Loading
Loading