Add files via upload

This commit is contained in:
Dawid Bepierszcz
2025-07-17 21:37:57 +02:00
committed by GitHub
parent d965384025
commit 84d2197317
71 changed files with 5596 additions and 0 deletions

View File

@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>CS2_SimpleAdmin_PlayTimeModule</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CounterStrikeSharp.API" Version="1.0.316" />
<PackageReference Include="Dapper" Version="2.1.66" />
<PackageReference Include="MySqlConnector" Version="2.4.0" />
</ItemGroup>
<ItemGroup>
<Reference Include="CS2-SimpleAdminApi">
<HintPath>CS2-SimpleAdminApi.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,16 @@

Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CS2-SimpleAdmin_PlayTimeModule", "CS2-SimpleAdmin_PlayTimeModule.csproj", "{FEF949BC-C8AD-4ECB-ABA1-449AE685B31C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{FEF949BC-C8AD-4ECB-ABA1-449AE685B31C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FEF949BC-C8AD-4ECB-ABA1-449AE685B31C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FEF949BC-C8AD-4ECB-ABA1-449AE685B31C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FEF949BC-C8AD-4ECB-ABA1-449AE685B31C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,4 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/AddReferences/RecentPaths/=L_003A_005CGITHUB_005CCS2_002DSimpleAdmin_005CModules_005CCS2_002DSimpleAdmin_005FPlayTimeModule_005CCS2_002DSimpleAdminApi_002Edll/@EntryIndexedValue">True</s:Boolean>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AGameEvents_002Eg_002Ecs_002Fl_003AC_0021_003FUsers_003Fxdaff_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F7e129fe222b6d23f1a582a7dfdd9f730e7925c8ab8d2d5fb457fdf385e69_003FGameEvents_002Eg_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AICS2_005FSimpleAdminApi_002Ecs_002Fl_003AC_0021_003FUsers_003Fxdaff_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fa64168ca28114bbebf4c9d9298397d462200_003Fd2_003Fb9523498_003FICS2_005FSimpleAdminApi_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>

View File

@@ -0,0 +1,181 @@
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Capabilities;
using CS2_SimpleAdminApi;
using Microsoft.Extensions.Logging;
using CounterStrikeSharp.API.Core.Attributes.Registration;
using CounterStrikeSharp.API.Modules.Admin;
using CounterStrikeSharp.API.Modules.Commands;
using CounterStrikeSharp.API.Modules.Entities;
namespace CS2_SimpleAdmin_PlayTimeModule;
public sealed class CS2_SimpleAdmin_PlayTimeModule : BasePlugin
{
public override string ModuleName => "[CS2-SimpleAdmin] PlayTime Module";
public override string ModuleVersion => "1.0.0";
private static ICS2_SimpleAdminApi? _sharedApi;
private readonly PluginCapability<ICS2_SimpleAdminApi> _pluginCapability = new("simpleadmin:api");
private Database? _database;
private readonly Dictionary<ulong, PlayTimeModel> _playTimes = [];
public override void OnAllPluginsLoaded(bool hotReload)
{
_sharedApi = _pluginCapability.Get();
if (_sharedApi == null)
{
Logger.LogError("CS2-SimpleAdmin SharedApi not found");
Unload(false);
return;
}
AddCommandListener("jointeam", JoinTeamListener);
// ## Zrobic to na jointeam
_database = new Database(_sharedApi.GetConnectionString());
}
private HookResult JoinTeamListener(CCSPlayerController? player, CommandInfo commandinfo)
{
if (player == null || !player.IsValid || player.IsBot)
return HookResult.Continue;
int team = GetTeamNumber(commandinfo);
if (player.TeamNum == team)
return HookResult.Continue;
var steamId = player.SteamID;
if (!_playTimes.TryGetValue(steamId, out var playTimeModel)) return HookResult.Continue;
HandlePlayTimeUpdate(playTimeModel.OldTeam, team, playTimeModel, x => x.Teams[playTimeModel.OldTeam].JoinedTime, time => playTimeModel.Teams[playTimeModel.OldTeam].PlayTime += time);
playTimeModel.Teams[player.TeamNum].JoinedTime = DateTime.Now;
playTimeModel.OldTeam = team;
return HookResult.Continue;
}
[GameEventHandler]
public HookResult EventPlayerFullConnect(EventPlayerConnectFull @event, GameEventInfo _)
{
if (_sharedApi == null || _database == null)
return HookResult.Continue;
var player = @event.Userid;
if (player == null || !player.IsValid || player.IsBot)
return HookResult.Continue;
var steamId = player.SteamID;
Task.Run(async () =>
{
var playTimeModel = await _database.GetPlayTimeAsync(steamId, _sharedApi.GetServerId());
if (playTimeModel == null)
return;
_playTimes.Add(steamId, playTimeModel);
});
return HookResult.Continue;
}
[GameEventHandler(HookMode.Pre)]
public HookResult EventPlayerDisconnect(EventPlayerDisconnect @event, GameEventInfo _)
{
if (_sharedApi == null || _database == null)
return HookResult.Continue;
var player = @event.Userid;
if (player == null || !player.IsValid || player.IsBot)
return HookResult.Continue;
var steamId = player.SteamID;
if (!_playTimes.TryGetValue(steamId, out var playTimeModel)) return HookResult.Continue;
var totalPlayTime = (int)(DateTime.Now - playTimeModel.JoinedTime).TotalSeconds;
if (totalPlayTime <= 10) return HookResult.Continue;
playTimeModel.TotalPlayTime += totalPlayTime;
HandlePlayTimeUpdate(playTimeModel.OldTeam, playTimeModel.OldTeam, playTimeModel, x => x.Teams[playTimeModel.OldTeam].JoinedTime, time => playTimeModel.Teams[playTimeModel.OldTeam].PlayTime += time);
Task.Run(async () =>
{
await _database.UpdatePlayTimeAsync(steamId, playTimeModel, _sharedApi.GetServerId());
_playTimes.Remove(steamId);
});
return HookResult.Continue;
}
[GameEventHandler(HookMode.Pre)]
public HookResult EventPlayerChangeTeam(EventPlayerTeam @event, GameEventInfo _)
{
if (_sharedApi == null || _database == null)
return HookResult.Continue;
var player = @event.Userid;
if (player == null || !player.IsValid || player.IsBot)
return HookResult.Continue;
var steamId = player.SteamID;
if (!_playTimes.TryGetValue(steamId, out var playTimeModel)) return HookResult.Continue;
// Set the appropriate join time based on the team
playTimeModel.Teams[@event.Team].JoinedTime = DateTime.Now;
HandlePlayTimeUpdate(playTimeModel.OldTeam, @event.Team, playTimeModel, x => x.Teams[playTimeModel.OldTeam].JoinedTime, time => playTimeModel.Teams[playTimeModel.OldTeam].PlayTime += time);
playTimeModel.OldTeam = @event.Team;
return HookResult.Continue;
}
[GameEventHandler]
public HookResult EventPlayerSpawn(EventPlayerSpawn @event, GameEventInfo _)
{
if (_sharedApi == null || _database == null)
return HookResult.Continue;
var player = @event.Userid;
if (player == null || !player.IsValid || player.IsBot || player.Connected != PlayerConnectedState.PlayerConnected)
return HookResult.Continue;
var steamId = player.SteamID;
// if (AdminManager.PlayerHasPermissions(new SteamID(steamId)))
if (!_playTimes.TryGetValue(steamId, out var playTimeModel)) return HookResult.Continue;
if (playTimeModel.OldTeam != player.TeamNum)
{
HandlePlayTimeUpdate(playTimeModel.OldTeam, player.TeamNum, playTimeModel, x => x.Teams[playTimeModel.OldTeam].JoinedTime, time => playTimeModel.Teams[playTimeModel.OldTeam].PlayTime += time);
}
playTimeModel.OldTeam = player.TeamNum;
playTimeModel.Teams[player.TeamNum].JoinedTime = DateTime.Now;
return HookResult.Continue;
}
private static void HandlePlayTimeUpdate(int oldTeam, int newTeam, PlayTimeModel playTimeModel, Func<PlayTimeModel, DateTime?> getJoinTime, Action<int> updatePlayTime)
{
var joinedTime = getJoinTime(playTimeModel);
if (!joinedTime.HasValue) return;
// Add playtime to the appropriate team
var playTime = (int)(DateTime.Now - joinedTime.Value).TotalSeconds;
updatePlayTime(playTime); // Update playtime for the corresponding team
// Clear the join time after updating playtime
playTimeModel.Teams[oldTeam].JoinedTime = null;
}
private static int GetTeamNumber(CommandInfo info)
{
var startIndex = info.ArgByIndex(0).Equals("jointeam", StringComparison.CurrentCultureIgnoreCase) ? 1 : 0;
return info.ArgCount > startIndex && int.TryParse(info.ArgByIndex(startIndex), out var teamId) ? teamId : -1;
}
}

View File

@@ -0,0 +1,10 @@
using CounterStrikeSharp.API.Core;
namespace CS2_SimpleAdmin_PlayTimeModule;
public class Config : IBasePluginConfig
{
public int Version { get; set; } = 1;
public string AdminFlag { get; set; } = "@css/ban";
public int MinPlayers { get; set; } = 4;
}

View File

@@ -0,0 +1,115 @@
using Dapper;
using MySqlConnector;
namespace CS2_SimpleAdmin_PlayTimeModule;
public class Database(string dbConnectionString)
{
private async Task<MySqlConnection> GetConnectionAsync()
{
var connection = new MySqlConnection(dbConnectionString);
await connection.OpenAsync();
return connection;
}
public async Task<PlayTimeModel?> GetPlayTimeAsync(ulong steamId, int? serverId)
{
if (!serverId.HasValue)
return null;
try
{
await using var connection = await GetConnectionAsync();
const string query = """
SELECT total_playtime AS TotalPlayTime,
spec_playtime AS SpecPlayTime,
hidden_playtime AS HiddenPlayTime,
ct_playtime AS CtPlayTime,
tt_playtime AS TtPlayTime
FROM sa_playtime
WHERE steamid = @SteamId AND server_id = @ServerId
LIMIT 1;
""";
var rawResult = await connection.QueryFirstOrDefaultAsync(query, new { SteamId = steamId, ServerId = serverId });
var model = new PlayTimeModel();
if (rawResult != null)
{
model.TotalPlayTime = rawResult.TotalPlayTime;
model.Teams[0].PlayTime = rawResult.HiddenPlayTime;
model.Teams[1].PlayTime = rawResult.SpecPlayTime;
model.Teams[2].PlayTime = rawResult.TtPlayTime;
model.Teams[3].PlayTime = rawResult.CtPlayTime;
}
// var result = await connection.QueryFirstOrDefaultAsync<PlayTimeModel>(query, new { SteamId = steamId, ServerId = serverId })
// ?? new PlayTimeModel(totalPlayTime: 0);
model.JoinedTime = DateTime.Now;
return model;
}
catch (Exception ex)
{
Console.WriteLine($"Error retrieving playtime data for SteamId {steamId}: {ex.Message}");
return null;
}
}
public async Task UpdatePlayTimeAsync(ulong steamId, PlayTimeModel model, int? serverId)
{
if (!serverId.HasValue)
return;
try
{
const string checkQuery =
"SELECT EXISTS(SELECT 1 FROM sa_playtime WHERE steamid = @SteamId AND server_id = @ServerId LIMIT 1);";
const string insertQuery =
"INSERT INTO sa_playtime (steamid, server_id, total_playtime, spec_playtime, hidden_playtime, ct_playtime, tt_playtime) " +
"VALUES (@SteamId, @ServerId, @TotalPlayTime, @SpecPlayTime, @HiddenPlayTime, @CtPlayTime, @TtPlayTime);";
const string updateQuery =
"UPDATE sa_playtime " +
"SET total_playtime = @TotalPlayTime, spec_playtime = @SpecPlayTime, hidden_playtime = @HiddenPlayTime, ct_playtime = @CtPlayTime, tt_playtime = @TtPlayTime " +
"WHERE steamid = @SteamId AND server_id = @ServerId;";
await using var connection = await GetConnectionAsync();
var exists =
await connection.ExecuteScalarAsync<bool>(checkQuery, new { SteamId = steamId, ServerId = serverId });
if (exists)
{
await connection.ExecuteAsync(updateQuery, new
{
SteamId = steamId,
ServerId = serverId,
model.TotalPlayTime,
HiddenPlayTime = model.Teams[0].PlayTime,
SpecPlayTime = model.Teams[1].PlayTime,
TtPlayTime = model.Teams[2].PlayTime,
CtPlayTime = model.Teams[3].PlayTime
});
}
else
{
await connection.ExecuteAsync(insertQuery, new
{
SteamId = steamId,
ServerId = serverId,
model.TotalPlayTime,
HiddenPlayTime = model.Teams[0].PlayTime,
SpecPlayTime = model.Teams[1].PlayTime,
TtPlayTime = model.Teams[2].PlayTime,
CtPlayTime = model.Teams[3].PlayTime
});
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}

View File

@@ -0,0 +1,31 @@
namespace CS2_SimpleAdmin_PlayTimeModule;
public class PlayTimeModel
{
public PlayTimeModel()
{
}
public PlayTimeModel(int totalPlayTime)
{
TotalPlayTime = totalPlayTime;
}
public int TotalPlayTime { get; set; }
public DateTime JoinedTime { get; set; }
public int OldTeam { get; set; } = 1;
public Dictionary<int, PlayerTeamModel> Teams { get; set; } = new()
{
{ 0, new PlayerTeamModel() }, // Hidden
{ 1, new PlayerTeamModel() }, // Spec
{ 2, new PlayerTeamModel() }, // TT
{ 3, new PlayerTeamModel() }, // CT
};
}
public class PlayerTeamModel
{
public int PlayTime { get; set; }
public DateTime? JoinedTime { get; set; }
}

View File

@@ -0,0 +1,7 @@
{
"sdk": {
"version": "8.0.0",
"rollForward": "latestMinor",
"allowPrerelease": false
}
}