diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 56dcf408..711f2c4c 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -1,4 +1,4 @@ -name: Build and Publish C# Project +name: Build and Publish C# Project on: push: @@ -36,13 +36,13 @@ jobs: ${{ runner.os }}-dotnet- - name: Restore dependencies - run: dotnet restore SharpTimer.csproj + run: dotnet restore SharpTimer-main.sln - name: Build the project - run: dotnet build --configuration Release SharpTimer.csproj + run: dotnet build --configuration Release SharpTimer-main.sln - name: Publish the project - run: dotnet publish --configuration Release --output ./publish SharpTimer.csproj + run: dotnet publish --configuration Release --output ./publish src/SharpTimer.csproj - name: Move files run: | diff --git a/.gitignore b/.gitignore index 18b94464..c2859733 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,7 @@ CounterStrikeSharp.API.dll .vscode/ .vs/ /.idea +/src/SharpTimer.csproj.user +/src/Properties/PublishProfiles/FolderProfile.pubxml +/src/Properties/PublishProfiles/FolderProfile.pubxml.user +/Build \ No newline at end of file diff --git a/README.md b/README.md index 9ac8fdd5..7435b60f 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,10 @@ - -
- -![GitHub Repo stars](https://img.shields.io/github/stars/Letaryat/poor-sharptimer?style=for-the-badge) -![GitHub all releases](https://img.shields.io/github/downloads/Letaryat/poor-sharptimer/total?style=for-the-badge) -
+# SharpTimer +SharpTimer is a "simple" Surf/Bhop/MG/Deathrun/etc. CS2 Timer plugin using CounterStrikeSharp
> [!NOTE] -> The original creator of SharpTimer is [Dea](https://github.com/girlglock), who discontinued support for the project after version 0.2.6. This fork is now maintaned by the community, mainly [rcnoob](https://github.com/rcnoob). - - +> The original creator of SharpTimer is dea_bb, who discontinued support for the project after version 0.2.6. This fork is now maintaned by the community, mainly [rcnoob](https://github.com/rcnoob). -## **Join Our Discord For Support** - - +[**Discord**](https://discord.com/invite/SmQXeyMcny)
@@ -22,11 +14,6 @@ Badge

- -# SharpTimer -SharpTimer is a "simple" Surf/KZ/Bhop/MG/Deathrun/etc. CS2 Timer plugin using CounterStrikeSharp
- - ## Features
Timer, speedometer and key input with color customization @@ -51,10 +38,6 @@ SharpTimer is a "simple" Surf/KZ/Bhop/MG/Deathrun/etc. CS2 Timer plugin using Co Discord Webhook
-
- JumpStats -
-
Map CFGs
@@ -82,15 +65,13 @@ SharpTimer is a "simple" Surf/KZ/Bhop/MG/Deathrun/etc. CS2 Timer plugin using Co
- KZ Checkpoint system (disabled by default, check config) + Checkpoint system (disabled by default, check config)


-

( back to top )

- ## Dependencies [**MetaMod**](https://cs2.poggu.me/metamod/installation/) @@ -105,15 +86,17 @@ SharpTimer is a "simple" Surf/KZ/Bhop/MG/Deathrun/etc. CS2 Timer plugin using Co [**Web panel** *(optional but recommended)*](https://github.com/Letaryat/sharptimer-web-panel) +[**SharpTimer-WallLists** *(optional but recommended)*](https://github.com/M-archand/SharpTimer-WallLists) + [**CS2-TeleportAnglesFix** *(optional but recommended)*](https://github.com/M-archand/CS2-TeleportAnglesFix) [**STFixes** *(optional but recommended)*](https://github.com/rcnoob/STFixes) -[**Flashing HUD Fix** *(optional but recommended)*](https://github.com/M-archand/CS2FlashingHtmlHudFix) +[**CS#-Fixes** *(optional but recommended)*](https://github.com/CharlesBarone/CSSharp-Fixes) -[**SharpTimer-WallLists** *(optional)*](https://github.com/SharpTimer/WallLists) +[**Flashing HUD Fix** *(optional but recommended)*](https://github.com/deabb/CS2FlashingHtmlHudFix) -[**SharpTimer-Trails** *(optional)*](https://github.com/SharpTimer/Trails) +[**Flashing HUD Fix (alt)** *(optional but recommended)*](https://gitlab.com/dea_bb/FlashingXMLHintFix) ## Install @@ -142,7 +125,7 @@ SharpTimer is a "simple" Surf/KZ/Bhop/MG/Deathrun/etc. CS2 Timer plugin using Co - [x] Zones - [x] Hook common triggers by default - [x] Manual Zones - - [x] Hook Bonus Zones Triggers (KZ & Surf) + - [x] Hook Bonus Zones Triggers (Surf) - [x] Player PBs - [x] Save to Json - [x] Save to MySQL @@ -161,30 +144,19 @@ SharpTimer is a "simple" Surf/KZ/Bhop/MG/Deathrun/etc. CS2 Timer plugin using Co - [x] Player Server Stats - [x] Player Map Stats - [x] Replays -- [x] Jumpstats - - [x] Distance - - [x] Pre - - [x] Max - - [x] Height - - [x] Width - - [ ] Sync - - [ ] Jump Types - - [x] Long Jump - - [x] BunnyHop - - [x] MultiBunnyHop - - [x] Jump Bug - - [ ] Edge Bug - - [ ] Ladder Jump -- [X] Silly Stuff +- [ ] Silly Stuff - [x] Color customization - [x] Special Tester Gifs - [x] Custom Player Gifs - [x] Dioscord Webhook - - [X] Strafe Sync Bar on HUD + - [ ] Strafe Sync Bar on HUD + ## Authors: -[Deana](https://twitter.com/girlglock) +original creator: [DEA_BB](https://twitter.com/dea_bb) + +sharptimer team: [Letaryat](https://github.com/Letaryat) [rcnoob](https://github.com/rcnoob) - -

( back to top )

+[exkludera](https://github.com/exkludera) +[Marchand](https://github.com/M-archand) \ No newline at end of file diff --git a/SharpTimer-main.sln b/SharpTimer-main.sln index 8379e308..667b6ef9 100644 --- a/SharpTimer-main.sln +++ b/SharpTimer-main.sln @@ -3,7 +3,11 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.5.002.0 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharpTimer", "SharpTimer.csproj", "{8E786DDC-5BDE-462A-AC36-BB39D6D1560D}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpTimerAPI", "SharpTimerAPI\SharpTimerAPI.csproj", "{A950E141-B4D1-4338-9238-A1592AA42E1A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpTimer", "src\SharpTimer.csproj", "{09BD8C5E-A95F-4C42-9090-FD35ECEAF518}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpTimer-Example", "SharpTimerAPI-Example\SharpTimer-Example.csproj", "{FF468BD2-D94C-467F-A6FD-DE4CB4C71D69}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -11,10 +15,18 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {8E786DDC-5BDE-462A-AC36-BB39D6D1560D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8E786DDC-5BDE-462A-AC36-BB39D6D1560D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8E786DDC-5BDE-462A-AC36-BB39D6D1560D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8E786DDC-5BDE-462A-AC36-BB39D6D1560D}.Release|Any CPU.Build.0 = Release|Any CPU + {A950E141-B4D1-4338-9238-A1592AA42E1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A950E141-B4D1-4338-9238-A1592AA42E1A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A950E141-B4D1-4338-9238-A1592AA42E1A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A950E141-B4D1-4338-9238-A1592AA42E1A}.Release|Any CPU.Build.0 = Release|Any CPU + {09BD8C5E-A95F-4C42-9090-FD35ECEAF518}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {09BD8C5E-A95F-4C42-9090-FD35ECEAF518}.Debug|Any CPU.Build.0 = Debug|Any CPU + {09BD8C5E-A95F-4C42-9090-FD35ECEAF518}.Release|Any CPU.ActiveCfg = Release|Any CPU + {09BD8C5E-A95F-4C42-9090-FD35ECEAF518}.Release|Any CPU.Build.0 = Release|Any CPU + {FF468BD2-D94C-467F-A6FD-DE4CB4C71D69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FF468BD2-D94C-467F-A6FD-DE4CB4C71D69}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FF468BD2-D94C-467F-A6FD-DE4CB4C71D69}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FF468BD2-D94C-467F-A6FD-DE4CB4C71D69}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/SharpTimerAPI-Example/SharpTimer-Example.cs b/SharpTimerAPI-Example/SharpTimer-Example.cs new file mode 100644 index 00000000..452106a1 --- /dev/null +++ b/SharpTimerAPI-Example/SharpTimer-Example.cs @@ -0,0 +1,119 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Commands; +using CounterStrikeSharp.API.Modules.Utils; +using Microsoft.Extensions.Logging; +using SharpTimerAPI; + +public class SharpTimer_Example : BasePlugin +{ + public override string ModuleName => "SharpTimer API Example"; + public override string ModuleVersion => ""; + public override string ModuleAuthor => ""; + + public ISharpTimerEventSender? eventSender { get; set; } + public ISharpTimerManager? timerManager { get; set; } + public ISharpTimerDatabase? databaseManager { get; set; } + + public override void Load(bool hotReload) + { + AddCommand("css_SharpTimerAPI_TimerCheck", "", Command_API_TimerCheck); + AddCommand("css_SharpTimerAPI_ToggleTimer", "", Command_API_ToggleTimer); + AddCommand("css_SharpTimerAPI_GetSR", "", Command_API_GetSR); + + RegisterEventHandler(EventPlayerDeath); + } + + public override void Unload(bool hotReload) + { + RemoveCommand("css_SharpTimerAPI_TimerCheck", Command_API_TimerCheck); + RemoveCommand("css_SharpTimerAPI_ToggleTimer", Command_API_ToggleTimer); + RemoveCommand("css_SharpTimerAPI_GetSR", Command_API_GetSR); + + DeregisterEventHandler(EventPlayerDeath); + } + + public override void OnAllPluginsLoaded(bool hotReload) + { + eventSender = ISharpTimerEventSender.Capability.Get(); + timerManager = ISharpTimerManager.Capability.Get(); + databaseManager = ISharpTimerDatabase.Capability.Get(); + + if (eventSender == null || timerManager == null || databaseManager == null) + { + Logger.LogError("Error: Could not load SharpTimerAPI! Ensure everything is installed properly."); + return; + } + } + + public void Command_API_TimerCheck(CCSPlayerController? player, CommandInfo command) + { + if (player == null) + return; + + if (timerManager == null) + { + Logger.LogError("Error: ISharpTimerManager not loaded! Ensure everything is installed properly."); + return; + } + + command.ReplyToCommand($" {ChatColors.LightPurple}[SharpTimer-Example] {ChatColors.Grey}Timer: " + (timerManager.IsTimerOn(player) ? $"{ChatColors.Green}ON" : $"{ChatColors.Red}OFF")); + } + + public void Command_API_ToggleTimer(CCSPlayerController? player, CommandInfo command) + { + if (player == null) + return; + + if (timerManager == null) + { + Logger.LogError("Error: ISharpTimerManager not loaded! Ensure everything is installed properly."); + return; + } + + timerManager.ToggleTimer(player); + + command.ReplyToCommand($" {ChatColors.LightPurple}[SharpTimer-Example] {ChatColors.Grey}Timer has been toggeled: " + (timerManager.IsTimerOn(player) ? $"{ChatColors.Green}ON" : $"{ChatColors.Red}OFF")); + } + + public void Command_API_GetSR(CCSPlayerController? player, CommandInfo command) + { + if (player == null) + return; + + if (databaseManager == null) + { + Logger.LogError("Error: ISharpTimerDatabase not loaded! Ensure everything is installed properly."); + return; + } + + var record = databaseManager.GetSortedRecordsFromDatabase(1, 0, Server.MapName, 0).Result.FirstOrDefault().Value; + + string formattedTime; + + TimeSpan timeSpan = TimeSpan.FromSeconds(record.TimerTicks / 64.0); + string milliseconds = $"{record.TimerTicks % 64 * (1000.0 / 64.0):000}"; + int totalMinutes = (int)timeSpan.TotalMinutes; + + if (totalMinutes >= 60) + formattedTime = $"{totalMinutes / 60:D1}:{totalMinutes % 60:D2}:{timeSpan.Seconds:D2}.{milliseconds}"; + else + formattedTime = $"{totalMinutes:D1}:{timeSpan.Seconds:D2}.{milliseconds}"; + + command.ReplyToCommand($" {ChatColors.LightPurple}[SharpTimer-Example] {ChatColors.Grey}player: {ChatColors.White}{record.PlayerName} {ChatColors.Grey}has the SR on {ChatColors.White}{Server.MapName} {ChatColors.Grey}with time: {ChatColors.White}{formattedTime}"); + } + + + public HookResult EventPlayerDeath(EventPlayerDeath @event, GameEventInfo gameEventInfo) + { + var player = @event.Userid; + if (player == null || player.IsBot) + return HookResult.Continue; + + timerManager?.RestartTimer(player); + + player.PrintToChat($" {ChatColors.LightPurple}[SharpTimer-Example] {ChatColors.Red}Timer has been reset, because you died :("); + + return HookResult.Continue; + } +} \ No newline at end of file diff --git a/SharpTimerAPI-Example/SharpTimer-Example.csproj b/SharpTimerAPI-Example/SharpTimer-Example.csproj new file mode 100644 index 00000000..a139137a --- /dev/null +++ b/SharpTimerAPI-Example/SharpTimer-Example.csproj @@ -0,0 +1,20 @@ + + + net8.0 + enable + enable + false + $(ProjectDir)..\Build\plugins\SharpTimer-Example\ + false + + + + + + + + + + + + diff --git a/SharpTimerAPI/Events/FinishMapEvent.cs b/SharpTimerAPI/Events/FinishMapEvent.cs new file mode 100644 index 00000000..74a6282d --- /dev/null +++ b/SharpTimerAPI/Events/FinishMapEvent.cs @@ -0,0 +1,5 @@ +using CounterStrikeSharp.API.Core; + +namespace SharpTimerAPI.Events; + +public record FinishMapEvent(CCSPlayerController? Player, bool IsSr, bool IsPb, int Tier) : ISharpTimerPlayerEvent; \ No newline at end of file diff --git a/SharpTimerAPI/Events/ISharpTimerPlayerEvent.cs b/SharpTimerAPI/Events/ISharpTimerPlayerEvent.cs new file mode 100644 index 00000000..2fea410e --- /dev/null +++ b/SharpTimerAPI/Events/ISharpTimerPlayerEvent.cs @@ -0,0 +1,9 @@ +using CounterStrikeSharp.API.Core; + +namespace SharpTimerAPI.Events; +using CounterStrikeSharp; + +public interface ISharpTimerPlayerEvent +{ + public CCSPlayerController? Player { get;} +} \ No newline at end of file diff --git a/SharpTimerAPI/Events/StartTimerEvent.cs b/SharpTimerAPI/Events/StartTimerEvent.cs new file mode 100644 index 00000000..4572c73f --- /dev/null +++ b/SharpTimerAPI/Events/StartTimerEvent.cs @@ -0,0 +1,5 @@ +using CounterStrikeSharp.API.Core; + +namespace SharpTimerAPI.Events; + +public record StartTimerEvent(CCSPlayerController? Player) : ISharpTimerPlayerEvent; \ No newline at end of file diff --git a/SharpTimerAPI/ISharpTimerDatabase.cs b/SharpTimerAPI/ISharpTimerDatabase.cs new file mode 100644 index 00000000..148f90f7 --- /dev/null +++ b/SharpTimerAPI/ISharpTimerDatabase.cs @@ -0,0 +1,20 @@ +using CounterStrikeSharp.API.Core.Capabilities; + +namespace SharpTimerAPI; + +public interface ISharpTimerDatabase +{ + public static readonly PluginCapability Capability = new("sharptimer:database"); + + public class PlayerRecord + { + public int RecordID { get; set; } + public string? PlayerName { get; set; } + public string? SteamID { get; set; } + public string? MapName { get; set; } + public int TimerTicks { get; set; } + public bool Replay { get; set; } + } + public Task> GetSortedRecordsFromDatabase(int limit = 0, int bonusX = 0, string mapName = "", int style = 0); + public Task> GetAllSortedRecordsFromDatabase(int limit = 0, int bonusX = 0, int style = 0); +} \ No newline at end of file diff --git a/SharpTimerAPI/ISharpTimerEventSender.cs b/SharpTimerAPI/ISharpTimerEventSender.cs new file mode 100644 index 00000000..f0911863 --- /dev/null +++ b/SharpTimerAPI/ISharpTimerEventSender.cs @@ -0,0 +1,12 @@ +using CounterStrikeSharp.API.Core.Capabilities; +using SharpTimerAPI.Events; + +namespace SharpTimerAPI; + +public interface ISharpTimerEventSender +{ + public static readonly PluginCapability Capability = new("sharptimer:event_sender"); + + public event EventHandler STEventSender; + public void TriggerEvent(ISharpTimerPlayerEvent @event); +} \ No newline at end of file diff --git a/SharpTimerAPI/ISharpTimerManager.cs b/SharpTimerAPI/ISharpTimerManager.cs new file mode 100644 index 00000000..24f40ce6 --- /dev/null +++ b/SharpTimerAPI/ISharpTimerManager.cs @@ -0,0 +1,15 @@ +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Core.Capabilities; + +namespace SharpTimerAPI; + +public interface ISharpTimerManager +{ + public static readonly PluginCapability Capability = new("sharptimer:manager"); + + public void RestartTimer(CCSPlayerController player); + public bool IsTimerOn(CCSPlayerController player); + public void ToggleTimer(CCSPlayerController player); + public void BlockTimerCmd(CCSPlayerController player, bool block); + public void BlockRespawnCmd(CCSPlayerController player, bool block); +} \ No newline at end of file diff --git a/SharpTimerAPI/SharpTimerAPI.csproj b/SharpTimerAPI/SharpTimerAPI.csproj new file mode 100644 index 00000000..298f8d3c --- /dev/null +++ b/SharpTimerAPI/SharpTimerAPI.csproj @@ -0,0 +1,18 @@ + + + net8.0 + enable + enable + false + $(ProjectDir)..\Build\shared\SharpTimerAPI\ + false + + + + + + + + + + diff --git a/cfg/SharpTimer/MapData/MapExecs/bhop_.cfg b/cfg/SharpTimer/MapData/MapExecs/bhop_.cfg index add21e10..4726d4e7 100644 --- a/cfg/SharpTimer/MapData/MapExecs/bhop_.cfg +++ b/cfg/SharpTimer/MapData/MapExecs/bhop_.cfg @@ -37,7 +37,6 @@ sv_accelerate 5.000000 sv_maxvelocity 99999.000000 sv_air_max_wishspeed 30.000000 sv_gravity 800.000000 -sv_standable_normal 0.700000 sv_wateraccelerate 10.000000 //Team & Map Settings @@ -58,7 +57,7 @@ mp_friendlyfire false mp_limitteams 0 mp_randomspawn 0 mp_randomspawn_los false -mp_solid_teammates 2 +mp_solid_teammates 0 mp_spectators_max 64 mp_suicide_penalty true mp_team_timeout_max 1 @@ -77,7 +76,6 @@ mp_teamcashawards false mp_playercashawards false mp_weapons_allow_map_placed true mp_weapons_allow_zeus 2 -mp_weapons_glow_on_ground false sv_infinite_ammo 0 mp_ct_default_secondary weapon_hkp2000 mp_t_default_secondary weapon_glock @@ -102,11 +100,12 @@ sv_ignoregrenaderadio false sv_talk_enemy_dead true sv_talk_enemy_living true + //Misc -CS_WarnFriendlyDamageInterval 3 -sv_gameinstructor_enable false mp_disconnect_kills_players true -Bot Settings + + +// Bot Settings bot_controllable true bot_quota_mode fill bot_quota 0 @@ -130,6 +129,4 @@ sharptimer_rank_enabled true sharptimer_checkpoints_enabled true sharptimer_remove_checkpoints_restrictions true -sharptimer_checkpoints_only_when_timer_stopped true - -sharptimer_jumpstats_enabled false \ No newline at end of file +sharptimer_checkpoints_only_when_timer_stopped true \ No newline at end of file diff --git a/cfg/SharpTimer/MapData/MapExecs/de_example.cfg b/cfg/SharpTimer/MapData/MapExecs/de_example.cfg new file mode 100644 index 00000000..ad385b0c --- /dev/null +++ b/cfg/SharpTimer/MapData/MapExecs/de_example.cfg @@ -0,0 +1,4 @@ +//These Commands will exec whenever the server Loads the map "de_example" + +mp_timelimit 60 +sv_airaccelerate 100 \ No newline at end of file diff --git a/cfg/SharpTimer/MapData/MapExecs/kz_.cfg b/cfg/SharpTimer/MapData/MapExecs/kz_.cfg deleted file mode 100644 index f409f0eb..00000000 --- a/cfg/SharpTimer/MapData/MapExecs/kz_.cfg +++ /dev/null @@ -1,134 +0,0 @@ -// Round Settings -mp_roundtime 30 -mp_roundtime_defuse 30 -mp_roundtime_hostage 30 -mp_timelimit 30 -mp_maxrounds 0 -mp_freezetime 0 -mp_halftime false -mp_overtime_enable false -mp_round_restart_delay 0 -mp_team_intro_time 0 -mp_team_timeout_max 0 -mp_technical_timeout_per_team 0 -sv_warmup_to_freezetime_delay 0 -mp_buytime 0 -mp_ignore_round_win_conditions true -mp_respawn_immunitytime -1 -mp_respawn_on_death_ct true -mp_respawn_on_death_t true -mp_warmuptime 0 -mp_warmup_end - -sv_airaccelerate 100.000000 -sv_enablebunnyhopping false -sv_autobunnyhopping false -sv_falldamage_scale 0.000000 -sv_staminajumpcost 0.000000 -sv_staminalandcost 0.000000 -sv_timebetweenducks 0.000000 -sv_staminarecoveryrate 60.000000 -sv_staminamax 0.000000 -sv_ladder_scale_speed 1.000000 -sv_jump_impulse 301.993378 -sv_friction 5.000000 -sv_accelerate_use_weapon_speed false -sv_accelerate 6.500000 -sv_maxvelocity 2000.000000 -sv_air_max_wishspeed 30.000000 -sv_gravity 800.000000 -sv_standable_normal 0.700000 -sv_wateraccelerate 10.000000 - -ff_damage_reduction_bullets 0.000000 -ff_damage_reduction_grenade 0.000000 -ff_damage_reduction_grenade_self 0.000000 -ff_damage_reduction_other 0.000000 -mp_damage_headshot_only true -mp_damage_scale_ct_head 1.000000 -mp_damage_scale_t_head 1.000000 -mp_damage_scale_ct_body 1.000000 -mp_damage_scale_t_body 1.000000 -mp_autokick false -mp_autoteambalance true -mp_forcecamera 0 -mp_force_pick_time 15.000000 -mp_friendlyfire false -mp_limitteams 0 -mp_randomspawn 0 -mp_randomspawn_los false -mp_solid_teammates 2 -mp_spectators_max 64 -mp_suicide_penalty true -mp_team_timeout_max 1 -mp_teamname_1 "SHARPTIMER" -mp_teamname_2 "X.COM/DEAFPS_" -sv_falldamage_scale 0.000000 -sv_show_teammate_death_notification false -sv_disable_radar 1 - -mp_afterroundmoney 0 -mp_free_armor 1 -mp_maxmoney 0 -mp_startmoney 1000 -mp_teamcashawards false -mp_playercashawards false -mp_weapons_allow_map_placed true -mp_weapons_allow_zeus 2 -mp_weapons_glow_on_ground false -sv_infinite_ammo 0 -mp_ct_default_secondary weapon_hkp2000 -mp_t_default_secondary weapon_glock -mp_drop_knife_enable true -mp_weapons_allow_map_placed false -mp_death_drop_gun 0 - -sv_workshop_allow_other_maps true -mp_endmatch_votenextmap false -mp_endmatch_votenextmap_keepcurrent true -mp_match_end_changelevel false -mp_match_end_restart false -mp_match_restart_delay 10 -sv_allow_votes true - -sv_auto_full_alltalk_during_warmup_half_end false -sv_deadtalk true -sv_full_alltalk false -sv_ignoregrenaderadio false -sv_talk_enemy_dead true -sv_talk_enemy_living true - -CS_WarnFriendlyDamageInterval 99999 -sv_gameinstructor_enable false -mp_disconnect_kills_players true - -bot_controllable false -bot_quota_mode fill -bot_quota 1 - -// SharpTimer Settings -sharptimer_remove_legs true -sharptimer_remove_collision true -sharptimer_remove_damage true -sharptimer_kill_pointservercommand_entities true - -sharptimer_use2Dspeed_enabled false -sharptimer_disable_telehop true -sharptimer_max_start_speed_enabled true -sharptimer_max_start_speed 320 -sharptimer_force_knife_speed true -sharptimer_forced_player_speed 260 - -sharptimer_respawn_enabled true -sharptimer_top_enabled true -sharptimer_rank_enabled true - -sharptimer_checkpoints_enabled true -sharptimer_remove_checkpoints_restrictions false -sharptimer_checkpoints_only_when_timer_stopped false - -sharptimer_jumpstats_enabled true -sharptimer_jumpstats_min_distance 175.0 -sharptimer_jumpstats_max_vert 32.0 -sharptimer_jumpstats_movement_unlocker_cap true -sharptimer_jumpstats_movement_unlocker_cap_value 250.0 \ No newline at end of file diff --git a/cfg/SharpTimer/MapData/MapExecs/kz_example.cfg b/cfg/SharpTimer/MapData/MapExecs/kz_example.cfg deleted file mode 100644 index 93a7003a..00000000 --- a/cfg/SharpTimer/MapData/MapExecs/kz_example.cfg +++ /dev/null @@ -1,4 +0,0 @@ -//These Commands will exec whenever the server Loads the map "kz_example" - -mp_timelimit 60 -sv_airaccelerate 100 \ No newline at end of file diff --git a/cfg/SharpTimer/MapData/MapExecs/surf_.cfg b/cfg/SharpTimer/MapData/MapExecs/surf_.cfg index 7d9e323a..f24281fd 100644 --- a/cfg/SharpTimer/MapData/MapExecs/surf_.cfg +++ b/cfg/SharpTimer/MapData/MapExecs/surf_.cfg @@ -38,8 +38,8 @@ sv_accelerate 6.5 sv_maxvelocity 9876.0 sv_air_max_wishspeed 30.000000 sv_gravity 800.0 -sv_standable_normal 0.7 sv_wateraccelerate 10.0 +sv_jump_precision_enable false // Team & Map Settings @@ -60,12 +60,12 @@ mp_friendlyfire 0 mp_limitteams 0 mp_randomspawn 0 mp_randomspawn_los 0 -mp_solid_teammates 1 +mp_solid_teammates 0 mp_spectators_max 64 mp_suicide_penalty false mp_team_timeout_max 0 mp_teamname_1 "SHARPTIMER" -mp_teamname_2 "X.COM/DEAFPS_" +mp_teamname_2 "SHARPTIMER" sv_falldamage_scale 0 sv_show_teammate_death_notification 0 sv_disable_radar 1 @@ -110,10 +110,11 @@ sv_ignoregrenaderadio true sv_talk_enemy_dead true sv_talk_enemy_living true + // Misc -CS_WarnFriendlyDamageInterval 99999 mp_disconnect_kills_players true + // Bot Settings bot_controllable 0 bot_quota_mode fill @@ -139,5 +140,3 @@ sharptimer_rank_enabled true sharptimer_checkpoints_enabled true sharptimer_remove_checkpoints_restrictions true sharptimer_checkpoints_only_when_timer_stopped true - -sharptimer_jumpstats_enabled false diff --git a/cfg/SharpTimer/MapData/MapExecs/vnl_.cfg b/cfg/SharpTimer/MapData/MapExecs/vnl_.cfg index 3554a29e..a79d6606 100644 --- a/cfg/SharpTimer/MapData/MapExecs/vnl_.cfg +++ b/cfg/SharpTimer/MapData/MapExecs/vnl_.cfg @@ -39,7 +39,6 @@ sv_accelerate 5.500000 sv_maxvelocity 3500.000000 sv_air_max_wishspeed 30.000000 sv_gravity 800.000000 -sv_standable_normal 0.700000 sv_wateraccelerate 10.000000 @@ -61,7 +60,7 @@ mp_friendlyfire 0 mp_limitteams 0 mp_randomspawn 0 mp_randomspawn_los 0 -mp_solid_teammates 1 +mp_solid_teammates 0 mp_spectators_max 64 mp_suicide_penalty false mp_team_timeout_max 0 @@ -81,7 +80,6 @@ mp_teamcashawards false mp_playercashawards false mp_weapons_allow_map_placed false mp_weapons_allow_zeus 0 -mp_weapons_glow_on_ground 0 sv_infinite_ammo 2 mp_ct_default_secondary weapon_usp_silencer mp_t_default_secondary weapon_usp_silencer @@ -114,9 +112,7 @@ sv_talk_enemy_dead true sv_talk_enemy_living true -// Misc -CS_WarnFriendlyDamageInterval 99999 -sv_gameinstructor_enable 0 +// Misc mp_disconnect_kills_players true @@ -145,10 +141,4 @@ sharptimer_rank_enabled true sharptimer_checkpoints_enabled true sharptimer_remove_checkpoints_restrictions false -sharptimer_checkpoints_only_when_timer_stopped false - -sharptimer_jumpstats_enabled true -sharptimer_jumpstats_min_distance 175.0 -sharptimer_jumpstats_max_vert 32.0 -sharptimer_jumpstats_movement_unlocker_cap true -sharptimer_jumpstats_movement_unlocker_cap_value 250.0 \ No newline at end of file +sharptimer_checkpoints_only_when_timer_stopped false \ No newline at end of file diff --git a/cfg/SharpTimer/MapData/local_data/kz_.json b/cfg/SharpTimer/MapData/local_data/kz_.json deleted file mode 100644 index f8f50d84..00000000 --- a/cfg/SharpTimer/MapData/local_data/kz_.json +++ /dev/null @@ -1,2855 +0,0 @@ -{ - "kz_11342": { - "Tier": 1 - }, - "kz_11735": { - "Tier": 1 - }, - "kz_8b1_brickngrass": { - "Tier": 1 - }, - "kz_adeline": { - "Tier": 1 - }, - "kz_alt_cargo": { - "Tier": 1 - }, - "kz_autobadges": { - "Tier": 1 - }, - "kz_baxter": { - "Tier": 1 - }, - "kz_beanguy_v2": { - "Tier": 1 - }, - "kz_beginnerblock": { - "Tier": 1 - }, - "kz_blocks2006": { - "Tier": 1 - }, - "kz_boomblock": { - "Tier": 1 - }, - "kz_breezeblocks": { - "Tier": 1 - }, - "kz_brightblock": { - "Tier": 1 - }, - "kz_cartooncastle": { - "Tier": 1 - }, - "kz_caulis_v2": { - "Tier": 1 - }, - "kz_cellblock_go2": { - "Tier": 1 - }, - "kz_cheetos_fix": { - "Tier": 1 - }, - "kz_chessblock": { - "Tier": 1 - }, - "kz_chrysoprase": { - "Tier": 1 - }, - "kz_cliffhanger": { - "Tier": 1 - }, - "kz_conifer": { - "Tier": 1 - }, - "kz_cranking_the_hog": { - "Tier": 1 - }, - "kz_cratespeed": { - "Tier": 1 - }, - "kz_crate_delight": { - "Tier": 1 - }, - "kz_cybersand": { - "Tier": 1 - }, - "kz_dakow": { - "Tier": 1 - }, - "kz_dale": { - "Tier": 1 - }, - "kz_daniel": { - "Tier": 1 - }, - "kz_dark_fury": { - "Tier": 1 - }, - "kz_delphinium": { - "Tier": 1 - }, - "kz_de_bhop": { - "Tier": 1 - }, - "kz_ea_beneath": { - "Tier": 1 - }, - "kz_emblem_bonus": { - "Tier": 1 - }, - "kz_eros_v2": { - "Tier": 1 - }, - "kz_exoteric": { - "Tier": 1 - }, - "kz_fastmap": { - "Tier": 1 - }, - "kz_fikablock": { - "Tier": 1 - }, - "kz_flying_rabbits": { - "Tier": 1 - }, - "kz_forestrace": { - "Tier": 1 - }, - "kz_frozen": { - "Tier": 1 - }, - "kz_galaxy_go2": { - "Tier": 1 - }, - "kz_ghat": { - "Tier": 1 - }, - "kz_giantbean": { - "Tier": 1 - }, - "kz_gigablock": { - "Tier": 1 - }, - "kz_gkd_v2": { - "Tier": 1 - }, - "kz_haki_v2": { - "Tier": 1 - }, - "kz_hb_3kliksphilip": { - "Tier": 1 - }, - "kz_hillside": { - "Tier": 1 - }, - "kz_huber": { - "Tier": 1 - }, - "kz_hyroblock": { - "Tier": 1 - }, - "kz_intercourse!": { - "Tier": 1 - }, - "kz_j2s_westbl0ck": { - "Tier": 1 - }, - "kz_janpu_final_fix": { - "Tier": 1 - }, - "kz_kiwifactory": { - "Tier": 1 - }, - "kz_kzra_oddland": { - "Tier": 1 - }, - "kz_kzra_shortclimb_v2": { - "Tier": 1 - }, - "kz_kzra_suhu": { - "Tier": 1 - }, - "kz_kzro_2boxes1room": { - "Tier": 1 - }, - "kz_kzro_beknowater": { - "Tier": 1 - }, - "kz_kzro_darkhole": { - "Tier": 1 - }, - "kz_kzro_fastcliff": { - "Tier": 1 - }, - "kz_kzro_shima_v2": { - "Tier": 1 - }, - "kz_kzro_smallcanyon": { - "Tier": 1 - }, - "kz_kzro_speedcavescape": { - "Tier": 1 - }, - "kz_kzro_syotiles": { - "Tier": 1 - }, - "kz_kzro_yaruna": { - "Tier": 1 - }, - "kz_layercake": { - "Tier": 1 - }, - "kz_littlerock_v2": { - "Tier": 1 - }, - "kz_luonto": { - "Tier": 1 - }, - "kz_mac": { - "Tier": 1 - }, - "kz_man_everest_fix": { - "Tier": 1 - }, - "kz_megabhop_v2": { - "Tier": 1 - }, - "kz_micropenis": { - "Tier": 1 - }, - "kz_minimountain_f": { - "Tier": 1 - }, - "kz_morebricks_msq": { - "Tier": 1 - }, - "kz_mz": { - "Tier": 1 - }, - "kz_natureblock_scte": { - "Tier": 1 - }, - "kz_nature_remaster": { - "Tier": 1 - }, - "kz_obsidian": { - "Tier": 1 - }, - "kz_owtetad": { - "Tier": 1 - }, - "kz_phamous": { - "Tier": 1 - }, - "kz_pharos_fix": { - "Tier": 1 - }, - "kz_phaztec": { - "Tier": 1 - }, - "kz_piranha": { - "Tier": 1 - }, - "kz_prolific": { - "Tier": 1 - }, - "kz_quickshot": { - "Tier": 1 - }, - "kz_rainrun_kn_f": { - "Tier": 1 - }, - "kz_redline": { - "Tier": 1 - }, - "kz_rocks_global": { - "Tier": 1 - }, - "kz_rush2suck": { - "Tier": 1 - }, - "kz_sanctuary": { - "Tier": 1 - }, - "kz_sandstone_mq": { - "Tier": 1 - }, - "kz_simplicity_v2": { - "Tier": 1 - }, - "kz_sp1_kyuubisroom": { - "Tier": 1 - }, - "kz_spiritblockv2": { - "Tier": 1 - }, - "kz_sukblock_v2_fixed": { - "Tier": 1 - }, - "kz_summercliff2": { - "Tier": 1 - }, - "kz_terablock": { - "Tier": 1 - }, - "kz_tomb_fix": { - "Tier": 1 - }, - "kz_tradeblock": { - "Tier": 1 - }, - "kz_violet_fix": { - "Tier": 1 - }, - "kz_woodstock_v2": { - "Tier": 1 - }, - "kz_xand": { - "Tier": 1 - }, - "kz_xmas2008": { - "Tier": 1 - }, - "kz_xmas2009": { - "Tier": 1 - }, - "kz_za_tileblock": { - "Tier": 1 - }, - "skz_map": { - "Tier": 1 - }, - "vnl_whiterun": { - "Tier": 1 - }, - "xc_cliffjump_fix": { - "Tier": 1 - }, - "xc_dtt_nasty": { - "Tier": 1 - }, - "kz_kzro_justgrab": { - "Tier": 1 - }, - "kz_sloth": { - "Tier": 1 - }, - "kz_leto_v2": { - "Tier": 1 - }, - "kz_ronja": { - "Tier": 1 - }, - "bkz_kartrider": { - "Tier": 1 - }, - "kz_kiwimirific": { - "Tier": 1 - }, - "kz_smb": { - "Tier": 1 - }, - "kz_something": { - "Tier": 1 - }, - "kz_kays": { - "Tier": 1 - }, - "kz_ghs": { - "Tier": 1 - }, - "kz_lmn": { - "Tier": 1 - }, - "kz_apiisnotresponding": { - "Tier": 1 - }, - "kz_automata": { - "Tier": 1 - }, - "kz_grotto": { - "Tier": 2 - }, - "bkz_blackrockshooter_vzp": { - "Tier": 2 - }, - "bkz_bonus_z1": { - "Tier": 2 - }, - "bkz_cauz_final": { - "Tier": 2 - }, - "bkz_caves": { - "Tier": 2 - }, - "bkz_cg_coldbhop": { - "Tier": 2 - }, - "bkz_chillhop": { - "Tier": 2 - }, - "bkz_dydhop": { - "Tier": 2 - }, - "bkz_goldbhop": { - "Tier": 2 - }, - "bkz_goldbhop": { - "Tier": 2 - }, - "bkz_hellokitty_v2": { - "Tier": 2 - }, - "bkz_impulse": { - "Tier": 2 - }, - "bkz_itz_h25l": { - "Tier": 2 - }, - "bkz_levite_v2": { - "Tier": 2 - }, - "bkz_lewlysex": { - "Tier": 2 - }, - "bkz_measure": { - "Tier": 2 - }, - "bkz_measure2_b03": { - "Tier": 2 - }, - "bkz_nocturns_blue_gfix": { - "Tier": 2 - }, - "bkz_volcanohop": { - "Tier": 2 - }, - "kz_16pillars": { - "Tier": 2 - }, - "kz_420b": { - "Tier": 2 - }, - "kz_4u_nature": { - "Tier": 2 - }, - "kz_7in1": { - "Tier": 2 - }, - "kz_adventure_v2": { - "Tier": 2 - }, - "kz_after_agitation_easy_fix": { - "Tier": 2 - }, - "kz_akrh_warehouse_v3": { - "Tier": 2 - }, - "kz_alfama": { - "Tier": 2 - }, - "kz_alouette_fix": { - "Tier": 2 - }, - "kz_alt_aztec": { - "Tier": 2 - }, - "kz_ancient_v3": { - "Tier": 2 - }, - "kz_antigeneric": { - "Tier": 2 - }, - "kz_antiquity": { - "Tier": 2 - }, - "kz_anus": { - "Tier": 2 - }, - "kz_ashen": { - "Tier": 2 - }, - "kz_asphyxiate": { - "Tier": 2 - }, - "kz_asteroid_field": { - "Tier": 2 - }, - "kz_avalon": { - "Tier": 2 - }, - "kz_aztec": { - "Tier": 2 - }, - "kz_babycat_fix": { - "Tier": 2 - }, - "kz_basicnoon": { - "Tier": 2 - }, - "kz_betterdunjun": { - "Tier": 2 - }, - "kz_bhop_lego": { - "Tier": 2 - }, - "kz_bhop_lj": { - "Tier": 2 - }, - "kz_bhop_monsterjam": { - "Tier": 2 - }, - "kz_bhop_watertemple": { - "Tier": 2 - }, - "kz_bir_dont_fix": { - "Tier": 2 - }, - "kz_bluerace_v2": { - "Tier": 2 - }, - "kz_brickblock_v2": { - "Tier": 2 - }, - "kz_bridge17_fix": { - "Tier": 2 - }, - "kz_canyon": { - "Tier": 2 - }, - "kz_cargo": { - "Tier": 2 - }, - "kz_carp_v2": { - "Tier": 2 - }, - "kz_castlehops_v3": { - "Tier": 2 - }, - "kz_catharsis_global": { - "Tier": 2 - }, - "kz_cdr_myst": { - "Tier": 2 - }, - "kz_checkmate": { - "Tier": 2 - }, - "kz_cheese": { - "Tier": 2 - }, - "kz_christmas": { - "Tier": 2 - }, - "kz_chunky_peanut_butter": { - "Tier": 2 - }, - "kz_combobreaker": { - "Tier": 2 - }, - "kz_combohop_c02": { - "Tier": 2 - }, - "kz_comboya": { - "Tier": 2 - }, - "kz_complex": { - "Tier": 2 - }, - "kz_comp_global": { - "Tier": 2 - }, - "kz_concretejungle": { - "Tier": 2 - }, - "kz_construction": { - "Tier": 2 - }, - "kz_cousucks": { - "Tier": 2 - }, - "kz_cuberunfast": { - "Tier": 2 - }, - "kz_dimensions_v1": { - "Tier": 2 - }, - "kz_doubletake": { - "Tier": 2 - }, - "kz_doveen": { - "Tier": 2 - }, - "kz_dryness": { - "Tier": 2 - }, - "kz_dungeon": { - "Tier": 2 - }, - "kz_dvn_cube_fixed": { - "Tier": 2 - }, - "kz_dvn_dull": { - "Tier": 2 - }, - "kz_dvn_redcarpet": { - "Tier": 2 - }, - "kz_dzy_beyond_v2": { - "Tier": 2 - }, - "kz_echo": { - "Tier": 2 - }, - "kz_edp445": { - "Tier": 2 - }, - "kz_egyptmap": { - "Tier": 2 - }, - "kz_eimeristzurueck": { - "Tier": 2 - }, - "kz_emblem": { - "Tier": 2 - }, - "kz_ephemeral": { - "Tier": 2 - }, - "kz_epusbridge": { - "Tier": 2 - }, - "kz_erbajerb": { - "Tier": 2 - }, - "kz_excavate": { - "Tier": 2 - }, - "kz_experiment": { - "Tier": 2 - }, - "kz_ext_bblocks": { - "Tier": 2 - }, - "kz_fabrik": { - "Tier": 2 - }, - "kz_fas2map": { - "Tier": 2 - }, - "kz_fatigue_v2": { - "Tier": 2 - }, - "kz_final_ascension": { - "Tier": 2 - }, - "kz_floatingislands": { - "Tier": 2 - }, - "kz_foggywarehouse_v2": { - "Tier": 2 - }, - "kz_forgettable": { - "Tier": 2 - }, - "kz_freezing_ridge": { - "Tier": 2 - }, - "kz_fury": { - "Tier": 2 - }, - "kz_gary": { - "Tier": 2 - }, - "kz_generic": { - "Tier": 2 - }, - "kz_genesis": { - "Tier": 2 - }, - "kz_gfy_limit": { - "Tier": 2 - }, - "kz_ggurk": { - "Tier": 2 - }, - "kz_glassesospa_v1": { - "Tier": 2 - }, - "kz_glide": { - "Tier": 2 - }, - "kz_goldenroad": { - "Tier": 2 - }, - "kz_hate": { - "Tier": 2 - }, - "kz_hb_anduu": { - "Tier": 2 - }, - "kz_hb_bacon": { - "Tier": 2 - }, - "kz_hb_fyksen": { - "Tier": 2 - }, - "kz_highland": { - "Tier": 2 - }, - "kz_holdmyhand": { - "Tier": 2 - }, - "kz_holmu1": { - "Tier": 2 - }, - "kz_iluvprok_global": { - "Tier": 2 - }, - "kz_j2s_cupblock_fix2": { - "Tier": 2 - }, - "kz_j2s_tetris": { - "Tier": 2 - }, - "kz_johndoe": { - "Tier": 2 - }, - "kz_jump_n_run": { - "Tier": 2 - }, - "kz_kiwionerous": { - "Tier": 2 - }, - "kz_kiwitown": { - "Tier": 2 - }, - "kz_kohze_sucks": { - "Tier": 2 - }, - "kz_kzra_cliffy": { - "Tier": 2 - }, - "kz_kzra_fustcaves": { - "Tier": 2 - }, - "kz_kzra_greycliff": { - "Tier": 2 - }, - "kz_kzra_stonebhop": { - "Tier": 2 - }, - "kz_kzra_stoneishbhop": { - "Tier": 2 - }, - "kz_kzra_undercastle": { - "Tier": 2 - }, - "kz_kzro_basalt": { - "Tier": 2 - }, - "kz_kzro_brickstgrass_v2": { - "Tier": 2 - }, - "kz_kzro_bronea": { - "Tier": 2 - }, - "kz_kzro_cavernste_v2": { - "Tier": 2 - }, - "kz_kzro_cryscosrun": { - "Tier": 2 - }, - "kz_kzro_excitedbhop": { - "Tier": 2 - }, - "kz_kzro_gohome": { - "Tier": 2 - }, - "kz_kzro_greybrickbhop": { - "Tier": 2 - }, - "kz_kzro_jaashs": { - "Tier": 2 - }, - "kz_kzro_mountainbhop": { - "Tier": 2 - }, - "kz_kzro_mountainhaya": { - "Tier": 2 - }, - "kz_kzro_mountainsein": { - "Tier": 2 - }, - "kz_kzro_mountainsnow": { - "Tier": 2 - }, - "kz_kzro_sunmountainset": { - "Tier": 2 - }, - "kz_kzro_whiterock": { - "Tier": 2 - }, - "kz_kzse_aztectemple": { - "Tier": 2 - }, - "kz_lazy": { - "Tier": 2 - }, - "kz_lego": { - "Tier": 2 - }, - "kz_levels": { - "Tier": 2 - }, - "kz_lookout": { - "Tier": 2 - }, - "kz_machinery": { - "Tier": 2 - }, - "kz_matilda_np": { - "Tier": 2 - }, - "kz_memento": { - "Tier": 2 - }, - "kz_metalrun_global": { - "Tier": 2 - }, - "kz_mike_v4": { - "Tier": 2 - }, - "kz_minimalism": { - "Tier": 2 - }, - "kz_minimal_combo": { - "Tier": 2 - }, - "kz_moorerutan": { - "Tier": 2 - }, - "kz_msp_comatose": { - "Tier": 2 - }, - "kz_nassau": { - "Tier": 2 - }, - "kz_nb_final": { - "Tier": 2 - }, - "kz_nuclear": { - "Tier": 2 - }, - "kz_oldstuff": { - "Tier": 2 - }, - "kz_ominous2": { - "Tier": 2 - }, - "kz_overjoyed": { - "Tier": 2 - }, - "kz_paintball_tv_fix": { - "Tier": 2 - }, - "kz_paradise": { - "Tier": 2 - }, - "kz_peak_global": { - "Tier": 2 - }, - "kz_perfunctory": { - "Tier": 2 - }, - "kz_perf_darkcave": { - "Tier": 2 - }, - "kz_pharaoh": { - "Tier": 2 - }, - "kz_pianoclimb": { - "Tier": 2 - }, - "kz_plains": { - "Tier": 2 - }, - "kz_portal_fix": { - "Tier": 2 - }, - "kz_prima": { - "Tier": 2 - }, - "kz_prismus": { - "Tier": 2 - }, - "kz_project": { - "Tier": 2 - }, - "kz_psyk": { - "Tier": 2 - }, - "kz_psytime": { - "Tier": 2 - }, - "kz_quick7_v2": { - "Tier": 2 - }, - "kz_quicksand": { - "Tier": 2 - }, - "kz_rcn_impermanence": { - "Tier": 2 - }, - "kz_redemption": { - "Tier": 2 - }, - "kz_refract": { - "Tier": 2 - }, - "kz_remedy_v2": { - "Tier": 2 - }, - "kz_retreat": { - "Tier": 2 - }, - "kz_rockclimb": { - "Tier": 2 - }, - "kz_rumzor": { - "Tier": 2 - }, - "kz_serenity": { - "Tier": 2 - }, - "kz_shaft_fix": { - "Tier": 2 - }, - "kz_signs_v2": { - "Tier": 2 - }, - "kz_skyhotel": { - "Tier": 2 - }, - "kz_skytower": { - "Tier": 2 - }, - "kz_slumpfrageous": { - "Tier": 2 - }, - "kz_snowman_v2": { - "Tier": 2 - }, - "kz_sonder": { - "Tier": 2 - }, - "kz_sp1_aoirobhop": { - "Tier": 2 - }, - "kz_sp1_blueconcrete": { - "Tier": 2 - }, - "kz_sp1_candles": { - "Tier": 2 - }, - "kz_sp1_castaway": { - "Tier": 2 - }, - "kz_sp1_greyconcrete": { - "Tier": 2 - }, - "kz_sp1_inverseblocks": { - "Tier": 2 - }, - "kz_sp1_perf2win": { - "Tier": 2 - }, - "kz_sp1_redbrickbhop": { - "Tier": 2 - }, - "kz_sp1_redconcrete": { - "Tier": 2 - }, - "kz_sp1_siedlungclimb": { - "Tier": 2 - }, - "kz_sp1_whiteblocks": { - "Tier": 2 - }, - "kz_spaceladders_v2": { - "Tier": 2 - }, - "kz_spire": { - "Tier": 2 - }, - "kz_splifff": { - "Tier": 2 - }, - "kz_splopkopsc_loverick": { - "Tier": 2 - }, - "kz_sqrdsucks": { - "Tier": 2 - }, - "kz_streetblock": { - "Tier": 2 - }, - "kz_stuff_final": { - "Tier": 2 - }, - "kz_symmetry": { - "Tier": 2 - }, - "kz_thinkblock": { - "Tier": 2 - }, - "kz_toonadventure": { - "Tier": 2 - }, - "kz_toonrun_final": { - "Tier": 2 - }, - "kz_toughluck_fix": { - "Tier": 2 - }, - "kz_tour_de_nuke_rt": { - "Tier": 2 - }, - "kz_twiivo": { - "Tier": 2 - }, - "kz_unity_u01": { - "Tier": 2 - }, - "kz_unknownspace": { - "Tier": 2 - }, - "kz_vci_apprentice": { - "Tier": 2 - }, - "kz_warehouse": { - "Tier": 2 - }, - "kz_wasabi": { - "Tier": 2 - }, - "kz_weebfactory_censored": { - "Tier": 2 - }, - "kz_weightless": { - "Tier": 2 - }, - "kz_wetbricks": { - "Tier": 2 - }, - "kz_whereyoufrom": { - "Tier": 2 - }, - "kz_woodstonegrass_final": { - "Tier": 2 - }, - "kz_woodworld": { - "Tier": 2 - }, - "kz_xmas2020": { - "Tier": 2 - }, - "kz_xtremeblock_v2": { - "Tier": 2 - }, - "xc_lucid_global": { - "Tier": 2 - }, - "xc_minecraft3_global": { - "Tier": 2 - }, - "xc_minecraft4": { - "Tier": 2 - }, - "xc_powerblock_rc1": { - "Tier": 2 - }, - "xc_skycastle": { - "Tier": 2 - }, - "xc_supermario_gfix": { - "Tier": 2 - }, - "kz_kzro_wallblocks": { - "Tier": 2 - }, - "kz_sp1_greyhollowrock": { - "Tier": 2 - }, - "kz_sp1_kansopyon": { - "Tier": 2 - }, - "kz_sp1_parallelblocks": { - "Tier": 2 - }, - "kz_sp1_rockcanyonblocks": { - "Tier": 2 - }, - "kz_sunstone": { - "Tier": 2 - }, - "bkz_greed": { - "Tier": 2 - }, - "kz_lust": { - "Tier": 2 - }, - "kz_moorish": { - "Tier": 2 - }, - "kz_opus": { - "Tier": 2 - }, - "kz_souljaboy": { - "Tier": 2 - }, - "kz_communityblock": { - "Tier": 2 - }, - "kz_comp_2022": { - "Tier": 2 - }, - "kz_sp1_shouryokou": { - "Tier": 2 - }, - "kz_sp1_spreadblocks": { - "Tier": 2 - }, - "kz_sp1_uchuunookuheki": { - "Tier": 2 - }, - "kz_victoria": { - "Tier": 2 - }, - "bkz_canadaszn": { - "Tier": 2 - }, - "kz_bing": { - "Tier": 2 - }, - "kz_greyorgray": { - "Tier": 2 - }, - "kz_cajou": { - "Tier": 2 - }, - "kz_tranquillity": { - "Tier": 2 - }, - "kz_delirium": { - "Tier": 2 - }, - "kz_devon": { - "Tier": 2 - }, - "kz_cf_snakeskin": { - "Tier": 2 - }, - "kz_glow": { - "Tier": 2 - }, - "kz_xmas2022": { - "Tier": 2 - }, - "kz_igneous": { - "Tier": 2 - }, - "kz_acores": { - "Tier": 2 - }, - "kz_desolate": { - "Tier": 2 - }, - "kz_silk": { - "Tier": 2 - }, - "kz_ehcivec": { - "Tier": 2 - }, - "kz_eilrahc": { - "Tier": 2 - }, - "kz_frenzy": { - "Tier": 2 - }, - "kz_hypothermia": { - "Tier": 2 - }, - "kz_kogamaostry": { - "Tier": 2 - }, - "kz_tmnf_e05": { - "Tier": 2 - }, - "vnl_ll_nuke": { - "Tier": 2 - }, - "kz_cakewalk": { - "Tier": 3 - }, - "kz_dontstop": { - "Tier": 3 - }, - "kz_fapzor": { - "Tier": 3 - }, - "kz_pogo": { - "Tier": 3 - }, - "kz_sahara": { - "Tier": 3 - }, - "kz_uninspired_trash": { - "Tier": 3 - }, - "kz_zephyr_v2": { - "Tier": 3 - }, - "kzpro_justrun_sp": { - "Tier": 3 - }, - "kz_21loop_final_fix": { - "Tier": 3 - }, - "kz_2fast": { - "Tier": 3 - }, - "kz_2seasons_spring_final": { - "Tier": 3 - }, - "kz_abandoned": { - "Tier": 3 - }, - "kz_adv_cursedjourney": { - "Tier": 3 - }, - "kz_ahful": { - "Tier": 3 - }, - "kz_alice_fix": { - "Tier": 3 - }, - "kz_allure": { - "Tier": 3 - }, - "kz_amber_od": { - "Tier": 3 - }, - "kz_arbitrary_words": { - "Tier": 3 - }, - "kz_arcadium": { - "Tier": 3 - }, - "kz_arcturus": { - "Tier": 3 - }, - "kz_arrebol": { - "Tier": 3 - }, - "kz_athena": { - "Tier": 3 - }, - "kz_autumn_valley_fix": { - "Tier": 3 - }, - "kz_bacho": { - "Tier": 3 - }, - "kz_basics_b02": { - "Tier": 3 - }, - "kz_beyond_fix": { - "Tier": 3 - }, - "kz_bhop_mosaic_od2": { - "Tier": 3 - }, - "kz_bhop_sakura": { - "Tier": 3 - }, - "kz_bible_black": { - "Tier": 3 - }, - "kz_bigcastle": { - "Tier": 3 - }, - "kz_binseebak": { - "Tier": 3 - }, - "kz_bionic": { - "Tier": 3 - }, - "kz_blatherskite_v1": { - "Tier": 3 - }, - "kz_blindcity_easy_fix": { - "Tier": 3 - }, - "kz_blockhardy2k": { - "Tier": 3 - }, - "kz_bloodline": { - "Tier": 3 - }, - "kz_bombu": { - "Tier": 3 - }, - "kz_bored": { - "Tier": 3 - }, - "kz_buildings_final": { - "Tier": 3 - }, - "kz_burnished": { - "Tier": 3 - }, - "kz_byrem": { - "Tier": 3 - }, - "kz_camembert": { - "Tier": 3 - }, - "kz_cascade_v4": { - "Tier": 3 - }, - "kz_cataclysm": { - "Tier": 3 - }, - "kz_catalyst_gfix": { - "Tier": 3 - }, - "kz_celestial": { - "Tier": 3 - }, - "kz_cereal": { - "Tier": 3 - }, - "kz_cg_brick_rmk": { - "Tier": 3 - }, - "kz_cg_lighthops": { - "Tier": 3 - }, - "kz_chinablock": { - "Tier": 3 - }, - "kz_coastline_fix": { - "Tier": 3 - }, - "kz_colorcode": { - "Tier": 3 - }, - "kz_colors_v2": { - "Tier": 3 - }, - "kz_concept": { - "Tier": 3 - }, - "kz_conrun_scrub": { - "Tier": 3 - }, - "kz_conspiracy": { - "Tier": 3 - }, - "kz_coronado_fix": { - "Tier": 3 - }, - "kz_correguachin_reisido": { - "Tier": 3 - }, - "kz_crash_fix": { - "Tier": 3 - }, - "kz_crypt_final": { - "Tier": 3 - }, - "kz_crysis": { - "Tier": 3 - }, - "kz_cyb_adrenaline_fix": { - "Tier": 3 - }, - "kz_dank_stacks": { - "Tier": 3 - }, - "kz_date2": { - "Tier": 3 - }, - "kz_default": { - "Tier": 3 - }, - "kz_dejavu": { - "Tier": 3 - }, - "kz_depot": { - "Tier": 3 - }, - "kz_diajonal": { - "Tier": 3 - }, - "kz_district_d01": { - "Tier": 3 - }, - "kz_drops_od": { - "Tier": 3 - }, - "kz_duality_v2": { - "Tier": 3 - }, - "kz_dust": { - "Tier": 3 - }, - "kz_dzy_reach_v2": { - "Tier": 3 - }, - "kz_edifice": { - "Tier": 3 - }, - "kz_egyptianbox": { - "Tier": 3 - }, - "kz_emptiness": { - "Tier": 3 - }, - "kz_erinome": { - "Tier": 3 - }, - "kz_excape": { - "Tier": 3 - }, - "kz_exemplum_fix": { - "Tier": 3 - }, - "kz_exps_cursedjourney": { - "Tier": 3 - }, - "kz_farm_v2": { - "Tier": 3 - }, - "kz_fastcombomap": { - "Tier": 3 - }, - "kz_fastcombowombo_v2": { - "Tier": 3 - }, - "kz_forchi": { - "Tier": 3 - }, - "kz_fused": { - "Tier": 3 - }, - "kz_futureblock": { - "Tier": 3 - }, - "kz_gallus": { - "Tier": 3 - }, - "kz_comboking7k": { - "Tier": 3 - }, - "kz_goldentabby": { - "Tier": 3 - }, - "kz_gonbe": { - "Tier": 3 - }, - "kz_green": { - "Tier": 3 - }, - "kz_halicarnassus_fs": { - "Tier": 3 - }, - "kz_hammer": { - "Tier": 3 - }, - "kz_hb_smieszneznaczki": { - "Tier": 3 - }, - "kz_heatvents_mq": { - "Tier": 3 - }, - "kz_hek": { - "Tier": 3 - }, - "kz_hellinashop": { - "Tier": 3 - }, - "kz_hikari_od": { - "Tier": 3 - }, - "kz_holyspace": { - "Tier": 3 - }, - "kz_how2slide_fix": { - "Tier": 3 - }, - "kz_hydromancy": { - "Tier": 3 - }, - "kz_ickkck": { - "Tier": 3 - }, - "kz_illusion_gfix": { - "Tier": 3 - }, - "kz_innit": { - "Tier": 3 - }, - "kz_island": { - "Tier": 3 - }, - "kz_itz_transcendent": { - "Tier": 3 - }, - "kz_jg_ditch": { - "Tier": 3 - }, - "kz_kat_colorblind": { - "Tier": 3 - }, - "kz_kzinga_fixed": { - "Tier": 3 - }, - "kz_kzra_bars": { - "Tier": 3 - }, - "kz_kzra_coast": { - "Tier": 3 - }, - "kz_kzra_hohum": { - "Tier": 3 - }, - "kz_kzra_morath": { - "Tier": 3 - }, - "kz_kzra_rockloy": { - "Tier": 3 - }, - "kz_kzra_rocky": { - "Tier": 3 - }, - "kz_kzra_skaxis": { - "Tier": 3 - }, - "kz_kzra_voovblock": { - "Tier": 3 - }, - "kz_kzra_whitesquare": { - "Tier": 3 - }, - "kz_kzro_cavehole": { - "Tier": 3 - }, - "kz_kzro_sekiseibhop": { - "Tier": 3 - }, - "kz_kzro_slidesmear": { - "Tier": 3 - }, - "kz_lair": { - "Tier": 3 - }, - "kz_lavablock_global": { - "Tier": 3 - }, - "kz_legoland": { - "Tier": 3 - }, - "kz_lego_two_redux_v3": { - "Tier": 3 - }, - "kz_life_final": { - "Tier": 3 - }, - "kz_linoleum": { - "Tier": 3 - }, - "kz_loftroofs": { - "Tier": 3 - }, - "kz_longjumps_easy": { - "Tier": 3 - }, - "kz_lost_marketplace_gfix": { - "Tier": 3 - }, - "kz_magus": { - "Tier": 3 - }, - "kz_megalodon": { - "Tier": 3 - }, - "kz_microwave": { - "Tier": 3 - }, - "kz_milehigh": { - "Tier": 3 - }, - "kz_moonlight": { - "Tier": 3 - }, - "kz_morestairs_msq": { - "Tier": 3 - }, - "kz_motivated": { - "Tier": 3 - }, - "kz_nightfall": { - "Tier": 3 - }, - "kz_nightmare_v2": { - "Tier": 3 - }, - "kz_nyc_v1": { - "Tier": 3 - }, - "kz_oasis": { - "Tier": 3 - }, - "kz_olympus": { - "Tier": 3 - }, - "kz_openspace": { - "Tier": 3 - }, - "kz_orangejuice_v2": { - "Tier": 3 - }, - "kz_orbolution_v2": { - "Tier": 3 - }, - "kz_otakuroom": { - "Tier": 3 - }, - "kz_overgrowth": { - "Tier": 3 - }, - "kz_persona_is_a_dictator": { - "Tier": 3 - }, - "kz_pineforest_v2": { - "Tier": 3 - }, - "kz_pixelrun_v2": { - "Tier": 3 - }, - "kz_pollution": { - "Tier": 3 - }, - "kz_porridge": { - "Tier": 3 - }, - "kz_prekeeper": { - "Tier": 3 - }, - "kz_progressive": { - "Tier": 3 - }, - "kz_quadrablock": { - "Tier": 3 - }, - "kz_quadrant_fix": { - "Tier": 3 - }, - "kz_quixotic": { - "Tier": 3 - }, - "kz_railings": { - "Tier": 3 - }, - "kz_rcn_optimisery": { - "Tier": 3 - }, - "kz_reach_v2": { - "Tier": 3 - }, - "kz_refuge": { - "Tier": 3 - }, - "kz_research": { - "Tier": 3 - }, - "kz_rise": { - "Tier": 3 - }, - "kz_rockjungle_v2": { - "Tier": 3 - }, - "kz_roman": { - "Tier": 3 - }, - "kz_sandstorm_ez": { - "Tier": 3 - }, - "kz_sandyhill_hoc": { - "Tier": 3 - }, - "kz_shortcut_tx": { - "Tier": 3 - }, - "kz_skybridge": { - "Tier": 3 - }, - "kz_slate": { - "Tier": 3 - }, - "kz_slide_kissa": { - "Tier": 3 - }, - "kz_slide_koira": { - "Tier": 3 - }, - "kz_slide_or_dont": { - "Tier": 3 - }, - "kz_slide_pallokala": { - "Tier": 3 - }, - "kz_smallcastle": { - "Tier": 3 - }, - "kz_smallmap": { - "Tier": 3 - }, - "kz_sn_desert": { - "Tier": 3 - }, - "kz_solidarity_v2": { - "Tier": 3 - }, - "kz_sp1_behold": { - "Tier": 3 - }, - "kz_sp1_driedblocks": { - "Tier": 3 - }, - "kz_sp1_greenconcrete": { - "Tier": 3 - }, - "kz_sp1_hallwaybhop": { - "Tier": 3 - }, - "kz_sp1_purpose": { - "Tier": 3 - }, - "kz_spacus": { - "Tier": 3 - }, - "kz_stepblock": { - "Tier": 3 - }, - "kz_stepup": { - "Tier": 3 - }, - "kz_structures": { - "Tier": 3 - }, - "kz_strun_mq": { - "Tier": 3 - }, - "kz_superstructure": { - "Tier": 3 - }, - "kz_surf_ace": { - "Tier": 3 - }, - "kz_symbiosis_final": { - "Tier": 3 - }, - "kz_synergy_ez": { - "Tier": 3 - }, - "kz_synthesis_v2": { - "Tier": 3 - }, - "kz_sz_goldenbean": { - "Tier": 3 - }, - "kz_talltreeforest_v3": { - "Tier": 3 - }, - "kz_talmaniac": { - "Tier": 3 - }, - "kz_timescape_zero": { - "Tier": 3 - }, - "kz_tron_global": { - "Tier": 3 - }, - "kz_twilight_od": { - "Tier": 3 - }, - "kz_twister": { - "Tier": 3 - }, - "kz_unity_collab": { - "Tier": 3 - }, - "kz_verv3_gg": { - "Tier": 3 - }, - "kz_village": { - "Tier": 3 - }, - "kz_vittu_mika_persse": { - "Tier": 3 - }, - "kz_void": { - "Tier": 3 - }, - "kz_waterhole": { - "Tier": 3 - }, - "kz_whatever_v2": { - "Tier": 3 - }, - "kz_yes": { - "Tier": 3 - }, - "kz_zhop_son_fix": { - "Tier": 3 - }, - "kz_zxp_interstellar_v2": { - "Tier": 3 - }, - "vnl_slidegarden": { - "Tier": 3 - }, - "vnl_undefined": { - "Tier": 3 - }, - "xc_alt_nephilim": { - "Tier": 3 - }, - "xc_dreamland2": { - "Tier": 3 - }, - "xc_fox_shrine_japan_fr": { - "Tier": 3 - }, - "xc_karo4": { - "Tier": 3 - }, - "xc_minecraft2_global": { - "Tier": 3 - }, - "xc_nephilim": { - "Tier": 3 - }, - "xc_secret_valley_global_fix": { - "Tier": 3 - }, - "xc_umbrella_global": { - "Tier": 3 - }, - "kz_sp1_xmas2021": { - "Tier": 3 - }, - "kz_kzro_tamlair": { - "Tier": 3 - }, - "kz_maya": { - "Tier": 3 - }, - "kz_sp1_rengapyon": { - "Tier": 3 - }, - "skz_pride": { - "Tier": 3 - }, - "kz_invision": { - "Tier": 3 - }, - "kz_tq": { - "Tier": 3 - }, - "kz_difficultas_discendi": { - "Tier": 3 - }, - "kz_nebula": { - "Tier": 3 - }, - "kz_chillin": { - "Tier": 3 - }, - "kz_slide_bozo": { - "Tier": 3 - }, - "kz_bhop_proxy_null": { - "Tier": 3 - }, - "kz_slide_leto": { - "Tier": 3 - }, - "kz_lovesick": { - "Tier": 3 - }, - "kz_vnl_crimdaughter": { - "Tier": 3 - }, - "kz_hideous": { - "Tier": 3 - }, - "kz_vnl_crimstmas": { - "Tier": 3 - }, - "kz_cf_slide": { - "Tier": 3 - }, - "kz_tangent": { - "Tier": 3 - }, - "kz_cf_hestia": { - "Tier": 3 - }, - "kz_mediumcastle": { - "Tier": 3 - }, - "kz_pamehcilc": { - "Tier": 3 - }, - "kz_prefix_cliche": { - "Tier": 3 - }, - "vnl_lea": { - "Tier": 3 - }, - "bkz_cauz_short": { - "Tier": 4 - }, - "bkz_evanstep": { - "Tier": 4 - }, - "bkz_iota_v3": { - "Tier": 4 - }, - "kzpro_concrete_c02": { - "Tier": 4 - }, - "kz_2seasons_winter_final": { - "Tier": 4 - }, - "kz_aaaa": { - "Tier": 4 - }, - "kz_abstruse_od2": { - "Tier": 4 - }, - "kz_andromeda": { - "Tier": 4 - }, - "kz_another_climb_map": { - "Tier": 4 - }, - "kz_antimony": { - "Tier": 4 - }, - "kz_ascend_hv": { - "Tier": 4 - }, - "kz_atelectasis_sct": { - "Tier": 4 - }, - "kz_atlantis_od3": { - "Tier": 4 - }, - "kz_azure": { - "Tier": 4 - }, - "kz_banjo": { - "Tier": 4 - }, - "kz_betapmaps": { - "Tier": 4 - }, - "kz_bhop_badges3": { - "Tier": 4 - }, - "kz_bhop_benchmark": { - "Tier": 4 - }, - "kz_bhop_composure_f": { - "Tier": 4 - }, - "kz_bhop_dusk": { - "Tier": 4 - }, - "kz_bhop_essence": { - "Tier": 4 - }, - "kz_bhop_lucid": { - "Tier": 4 - }, - "kz_bhop_northface": { - "Tier": 4 - }, - "kz_bhop_nothing": { - "Tier": 4 - }, - "kz_bhop_rotebal3": { - "Tier": 4 - }, - "kz_bhop_skyworld": { - "Tier": 4 - }, - "kz_bhop_zenith": { - "Tier": 4 - }, - "kz_birrita_fix": { - "Tier": 4 - }, - "kz_blindcity_hard_final": { - "Tier": 4 - }, - "kz_bluehop_mq": { - "Tier": 4 - }, - "kz_bluuu": { - "Tier": 4 - }, - "kz_bounce": { - "Tier": 4 - }, - "kz_cabin_fix": { - "Tier": 4 - }, - "kz_carbon": { - "Tier": 4 - }, - "kz_cdr_rustenborg": { - "Tier": 4 - }, - "kz_cdr_slash_final": { - "Tier": 4 - }, - "kz_chopchop": { - "Tier": 4 - }, - "kz_citadel": { - "Tier": 4 - }, - "kz_civilizations": { - "Tier": 4 - }, - "kz_communityjump3": { - "Tier": 4 - }, - "kz_conrun_mq": { - "Tier": 4 - }, - "kz_divided": { - "Tier": 4 - }, - "kz_dontjump": { - "Tier": 4 - }, - "kz_dyd_ladderjumps": { - "Tier": 4 - }, - "kz_epiphany_v2": { - "Tier": 4 - }, - "kz_eudora": { - "Tier": 4 - }, - "kz_eventide": { - "Tier": 4 - }, - "kz_everything": { - "Tier": 4 - }, - "kz_evilcorp": { - "Tier": 4 - }, - "kz_flabbergast": { - "Tier": 4 - }, - "kz_forgotten": { - "Tier": 4 - }, - "kz_free_ahful": { - "Tier": 4 - }, - "kz_f_salted_banana": { - "Tier": 4 - }, - "kz_shark_gc": { - "Tier": 4 - }, - "kz_gfy_blueberry": { - "Tier": 4 - }, - "kz_gfy_devcastle": { - "Tier": 4 - }, - "kz_gfy_final": { - "Tier": 4 - }, - "kz_gfy_fortroca": { - "Tier": 4 - }, - "kz_gfy_strawberry_": { - "Tier": 4 - }, - "kz_gfy_tech": { - "Tier": 4 - }, - "kz_gitgud_final": { - "Tier": 4 - }, - "kz_gloom": { - "Tier": 4 - }, - "kz_gobbledygook": { - "Tier": 4 - }, - "kz_goodluck_p": { - "Tier": 4 - }, - "kz_grass_hard": { - "Tier": 4 - }, - "kz_gy_agitation": { - "Tier": 4 - }, - "kz_haste": { - "Tier": 4 - }, - "kz_hb_lowlita": { - "Tier": 4 - }, - "kz_hb_lrs": { - "Tier": 4 - }, - "kz_headbongo": { - "Tier": 4 - }, - "kz_heaven_od": { - "Tier": 4 - }, - "kz_insomnia_fix": { - "Tier": 4 - }, - "kz_inspired": { - "Tier": 4 - }, - "kz_internatus": { - "Tier": 4 - }, - "kz_kiwi_lars": { - "Tier": 4 - }, - "kz_kzra_slidely": { - "Tier": 4 - }, - "kz_kzra_slidepuf": { - "Tier": 4 - }, - "kz_kzro_chairs": { - "Tier": 4 - }, - "kz_ladderall": { - "Tier": 4 - }, - "kz_ladderhell_fix": { - "Tier": 4 - }, - "kz_lastwork_p1": { - "Tier": 4 - }, - "kz_loathe": { - "Tier": 4 - }, - "kz_longjumps_space": { - "Tier": 4 - }, - "kz_lume": { - "Tier": 4 - }, - "kz_luv_less": { - "Tier": 4 - }, - "kz_malignom_short": { - "Tier": 4 - }, - "kz_mandelbrot": { - "Tier": 4 - }, - "kz_meander": { - "Tier": 4 - }, - "kz_mescaline_f": { - "Tier": 4 - }, - "kz_module": { - "Tier": 4 - }, - "kz_mushrruption_v8": { - "Tier": 4 - }, - "kz_neon_portal": { - "Tier": 4 - }, - "kz_nieh": { - "Tier": 4 - }, - "kz_nightcastle": { - "Tier": 4 - }, - "kz_nymph": { - "Tier": 4 - }, - "kz_pamxul_wip": { - "Tier": 4 - }, - "kz_pantheism_p02": { - "Tier": 4 - }, - "kz_prototype": { - "Tier": 4 - }, - "kz_rectangle": { - "Tier": 4 - }, - "kz_return": { - "Tier": 4 - }, - "kz_reverse": { - "Tier": 4 - }, - "kz_rompenutrias_asheglado": { - "Tier": 4 - }, - "kz_rush2sk8": { - "Tier": 4 - }, - "kz_scum": { - "Tier": 4 - }, - "kz_sendhelp_final": { - "Tier": 4 - }, - "kz_simplejourney": { - "Tier": 4 - }, - "kz_sky_lake": { - "Tier": 4 - }, - "kz_slide_0x7_n1m0": { - "Tier": 4 - }, - "kz_slide_concrete": { - "Tier": 4 - }, - "kz_slide_dydanhomon": { - "Tier": 4 - }, - "kz_slide_pisauva": { - "Tier": 4 - }, - "kz_slide_svn_temple": { - "Tier": 4 - }, - "kz_slide_vaahtera": { - "Tier": 4 - }, - "kz_south": { - "Tier": 4 - }, - "kz_sp1_hiragana": { - "Tier": 4 - }, - "kz_stranded": { - "Tier": 4 - }, - "kz_suomi": { - "Tier": 4 - }, - "kz_surf_blue": { - "Tier": 4 - }, - "kz_surf_kim_hana_gl": { - "Tier": 4 - }, - "kz_swamped_v3": { - "Tier": 4 - }, - "kz_theaquila": { - "Tier": 4 - }, - "kz_trashsurf": { - "Tier": 4 - }, - "kz_trazodon_fix": { - "Tier": 4 - }, - "kz_tribute": { - "Tier": 4 - }, - "kz_variety_fix": { - "Tier": 4 - }, - "kz_why": { - "Tier": 4 - }, - "kz_yanse": { - "Tier": 4 - }, - "kz_yoink": { - "Tier": 4 - }, - "kz_zhop_freestyle": { - "Tier": 4 - }, - "kz_zhop_function3": { - "Tier": 4 - }, - "kz_ziggurath_final": { - "Tier": 4 - }, - "kz_zoomer_fix": { - "Tier": 4 - }, - "kz_zxp_final4": { - "Tier": 4 - }, - "kz_zxp_undia": { - "Tier": 4 - }, - "vnl_cat": { - "Tier": 4 - }, - "vnl_invasion": { - "Tier": 4 - }, - "kz_winterize": { - "Tier": 4 - }, - "kz_envy": { - "Tier": 4 - }, - "kz_gluttony": { - "Tier": 4 - }, - "kz_question": { - "Tier": 4 - }, - "kz_slide_cave": { - "Tier": 4 - }, - "kz_xiaobitu": { - "Tier": 4 - }, - "kz_bhop_horseshit_9": { - "Tier": 4 - }, - "kz_demonhours": { - "Tier": 4 - }, - "kz_slide_piss": { - "Tier": 4 - }, - "kz_nomibo": { - "Tier": 4 - }, - "kz_vnl_crimson": { - "Tier": 4 - }, - "kz_itz_updown": { - "Tier": 4 - }, - "kz_sxb_poi": { - "Tier": 4 - }, - "kz_bhop_exodus": { - "Tier": 4 - }, - "kz_euclide_illusionary": { - "Tier": 4 - }, - "kz_sp1_saishuu": { - "Tier": 4 - }, - "kz_vnl_crimdaddy": { - "Tier": 4 - }, - "vnl_caverun": { - "Tier": 4 - }, - "bkz_apricity_v3": { - "Tier": 5 - }, - "bkz_fear4": { - "Tier": 5 - }, - "bkz_underground_crypt_v3": { - "Tier": 5 - }, - "kzpro_gull_pidr_reborn": { - "Tier": 5 - }, - "kz_aether_fix": { - "Tier": 5 - }, - "kz_alfie": { - "Tier": 5 - }, - "kz_alpha": { - "Tier": 5 - }, - "kz_altum_od": { - "Tier": 5 - }, - "kz_antharas": { - "Tier": 5 - }, - "kz_armored_core": { - "Tier": 5 - }, - "kz_avoria": { - "Tier": 5 - }, - "kz_backwards": { - "Tier": 5 - }, - "kz_bananaysoda_v2": { - "Tier": 5 - }, - "kz_bhop_badges2": { - "Tier": 5 - }, - "kz_carpet": { - "Tier": 5 - }, - "kz_choka_fix": { - "Tier": 5 - }, - "kz_custos": { - "Tier": 5 - }, - "kz_dethroned": { - "Tier": 5 - }, - "kz_failed_fastrun_rt": { - "Tier": 5 - }, - "kz_hb_fafnir": { - "Tier": 5 - }, - "kz_high_socks": { - "Tier": 5 - }, - "kz_hitech": { - "Tier": 5 - }, - "kz_imaginary_final": { - "Tier": 5 - }, - "kz_kiwitech": { - "Tier": 5 - }, - "kz_kzro_hexonay": { - "Tier": 5 - }, - "kz_kzro_mountainroad": { - "Tier": 5 - }, - "kz_ladderdespair": { - "Tier": 5 - }, - "kz_list_gnida_v2": { - "Tier": 5 - }, - "kz_lovely": { - "Tier": 5 - }, - "kz_modernvomit": { - "Tier": 5 - }, - "kz_nix_od": { - "Tier": 5 - }, - "kz_noobfort": { - "Tier": 5 - }, - "kz_okaychamp": { - "Tier": 5 - }, - "kz_simple_sp": { - "Tier": 5 - }, - "kz_slide_isnt_kz": { - "Tier": 5 - }, - "kz_slide_purple_x": { - "Tier": 5 - }, - "kz_slide_rovod": { - "Tier": 5 - }, - "kz_sp1_icecave": { - "Tier": 5 - }, - "kz_sp1_katakana": { - "Tier": 5 - }, - "kz_strafehop_fix": { - "Tier": 5 - }, - "kz_synergy_x": { - "Tier": 5 - }, - "kz_technical_difficulties": { - "Tier": 5 - }, - "kz_techtonic_v2_ldr": { - "Tier": 5 - }, - "skz_bananaysoda_2": { - "Tier": 5 - }, - "skz_sati": { - "Tier": 5 - }, - "skz_sequence_shot": { - "Tier": 5 - }, - "kz_sp1_vines": { - "Tier": 5 - }, - "kz_bhop_mentalism": { - "Tier": 5 - }, - "kz_dishonest": { - "Tier": 5 - }, - "kz_mess": { - "Tier": 5 - }, - "kz_sc_collapse": { - "Tier": 5 - }, - "kz_sc_surf": { - "Tier": 5 - }, - "kz_unnamed": { - "Tier": 5 - }, - "vnl_simplebrickrooms": { - "Tier": 5 - }, - "kz_bhop_algetic": { - "Tier": 5 - }, - "kz_sc_ruins": { - "Tier": 5 - }, - "kz_auuughh": { - "Tier": 5 - }, - "kz_gus_sct2": { - "Tier": 5 - }, - "kz_slide_wasteland": { - "Tier": 5 - }, - "kz_kiwiqualia": { - "Tier": 5 - }, - "kz_simplyhard": { - "Tier": 5 - }, - "kz_slide_era": { - "Tier": 5 - }, - "kz_hoist_fix": { - "Tier": 5 - }, - "kz_persona_is_a_furry": { - "Tier": 5 - }, - "kz_ggsh": { - "Tier": 5 - }, - "vnl_farewell_fix": { - "Tier": 5 - }, - "kz_sxb_biewan": { - "Tier": 5 - }, - "kz_hope": { - "Tier": 5 - }, - "kz_rlk": { - "Tier": 5 - }, - "kz_sxb_despacito": { - "Tier": 5 - }, - "kz_sxb_remake": { - "Tier": 5 - }, - "kzpro_psilocybin": { - "Tier": 6 - }, - "kz_afterlife": { - "Tier": 6 - }, - "kz_alien_city": { - "Tier": 6 - }, - "kz_angina_final": { - "Tier": 6 - }, - "kz_bhop_koki_niwa": { - "Tier": 6 - }, - "kz_blackness": { - "Tier": 6 - }, - "kz_chloroplast": { - "Tier": 6 - }, - "kz_continuum": { - "Tier": 6 - }, - "kz_drunkards": { - "Tier": 6 - }, - "kz_erratum_v2": { - "Tier": 6 - }, - "kz_gemischte_gefuehlslagen": { - "Tier": 6 - }, - "kz_goquicklol_v2": { - "Tier": 6 - }, - "kz_kareful": { - "Tier": 6 - }, - "kz_kiwi_cod": { - "Tier": 6 - }, - "kz_kzro_hardvalley": { - "Tier": 6 - }, - "kz_kzro_skyrocks": { - "Tier": 6 - }, - "kz_lionheart": { - "Tier": 6 - }, - "kz_mieszaneuczucia": { - "Tier": 6 - }, - "kz_neoncity_z": { - "Tier": 6 - }, - "kz_oloramasa": { - "Tier": 6 - }, - "kz_p1": { - "Tier": 6 - }, - "kz_pendulum": { - "Tier": 6 - }, - "kz_portalclimb": { - "Tier": 6 - }, - "kz_procrastination_f": { - "Tier": 6 - }, - "kz_psychosomatic": { - "Tier": 6 - }, - "kz_purgatory": { - "Tier": 6 - }, - "kz_retribution_v2_final": { - "Tier": 6 - }, - "kz_shell": { - "Tier": 6 - }, - "kz_slidebober": { - "Tier": 6 - }, - "kz_slidemap_fix": { - "Tier": 6 - }, - "kz_slide_deee": { - "Tier": 6 - }, - "kz_slide_svn_extreme": { - "Tier": 6 - }, - "kz_slowrun_global_fix": { - "Tier": 6 - }, - "kz_sp1_bloodyljs_v2": { - "Tier": 6 - }, - "kz_spacemario_h": { - "Tier": 6 - }, - "kz_surf_larry": { - "Tier": 6 - }, - "kz_zaloopazxc": { - "Tier": 6 - }, - "skz_makalaka": { - "Tier": 6 - }, - "skz_odious_v2": { - "Tier": 6 - }, - "vnl_oy_lj": { - "Tier": 6 - }, - "kz_bhop_slide": { - "Tier": 6 - }, - "kz_func_detail_v2": { - "Tier": 6 - }, - "kz_dabitu_fix2": { - "Tier": 6 - }, - "kz_d_decompile": { - "Tier": 6 - }, - "kz_rarkovosis": { - "Tier": 6 - }, - "kz_bozo": { - "Tier": 6 - }, - "kz_cthulhu": { - "Tier": 6 - }, - "kz_kukkojapallokidutus": { - "Tier": 6 - }, - "kz_lastwork_p2": { - "Tier": 6 - }, - "kz_scicret": { - "Tier": 6 - }, - "kz_wafflehouse_easy": { - "Tier": 6 - }, - "kz_kiwimind": { - "Tier": 6 - }, - "kz_ltt": { - "Tier": 6 - }, - "kz_mazemerized": { - "Tier": 6 - }, - "kz_slide_red": { - "Tier": 6 - }, - "kz_surf_abaddon": { - "Tier": 6 - }, - "kz_sxb_makabaka": { - "Tier": 6 - }, - "kz_sxb_xbcmzl": { - "Tier": 6 - }, - "kz_climb": { - "Tier": 6 - }, - "kz_divert": { - "Tier": 6 - }, - "kz_dystopia_h": { - "Tier": 6 - }, - "kz_hemochromatosis": { - "Tier": 6 - }, - "kz_maxine": { - "Tier": 6 - }, - "kz_monstrosity": { - "Tier": 6 - }, - "kz_nbdy_maps": { - "Tier": 6 - }, - "kz_thrombosis": { - "Tier": 6 - }, - "kz_zhongbitu": { - "Tier": 6 - }, - "kz_unmake": { - "Tier": 7 - }, - "kzpro_wrath": { - "Tier": 7 - }, - "kz_kiwideath": { - "Tier": 7 - }, - "kz_spacemario_xt": { - "Tier": 7 - }, - "kz_sp1_strafechampion": { - "Tier": 7 - }, - "kz_ladderhorror": { - "Tier": 7 - }, - "kz_slowerrun": { - "Tier": 7 - }, - "kz_wafflehouse_hard": { - "Tier": 7 - }, - "kz_kiwipsychosis": { - "Tier": 7 - }, - "vnl_sewers": { - "Tier": 7 - }, - "kz_kiwislide": { - "Tier": 7 - }, - "kz_w1_holiday": { - "Tier": 7 - }, - "kz_tense": { - "Tier": 7 - }, - "kz_cf_foliage": { - "Tier": 7 - }, - "kz_kiwiexophoric": { - "Tier": 7 - }, - "kz_kiwi_hym": { - "Tier": 7 - }, - "kz_sandbox": { - "Tier": 7 - }, - "kz_wafflehouse_x": { - "Tier": 7 - } -} diff --git a/cfg/SharpTimer/MapData/local_data/surf_.json b/cfg/SharpTimer/MapData/local_data/surf_.json index ac69bd3d..0b8829e4 100644 --- a/cfg/SharpTimer/MapData/local_data/surf_.json +++ b/cfg/SharpTimer/MapData/local_data/surf_.json @@ -3491,4 +3491,4 @@ "Tier": 8, "Type": "Staged" } -} \ No newline at end of file +} diff --git a/cfg/SharpTimer/config.cfg b/cfg/SharpTimer/config.cfg index 7f20838d..6c6f90de 100644 --- a/cfg/SharpTimer/config.cfg +++ b/cfg/SharpTimer/config.cfg @@ -24,7 +24,7 @@ sharptimer_discordwebhook_print_pb true sharptimer_connectmsg_enabled true // Whether connect/disconnect messages are enabled by default or not. Default value : true sharptimer_connect_commands_msg_enabled true // Whether commands on join messages are enabled by default or not. Default value : true sharptimer_kill_pointservercommand_entities true // If "true" the plugin will kill all point_servercommand ents on map start (necessary to make xplay maps playable. 🖕 @xplay). Default value : true -sharptimer_custom_map_cfgs_enabled true // Whether Custom Map .cfg files should be executed for the corresponding maps (found in cfg/SharpTimer/MapData/MapExecs/kz_example.cfg). Default value : true +sharptimer_custom_map_cfgs_enabled true // Whether Custom Map .cfg files should be executed for the corresponding maps (found in cfg/SharpTimer/MapData/MapExecs/de_example.cfg). Default value : true sharptimer_command_spam_cooldown 0.5 // Defines the time in seconds between commands can be called. Default value : 0.5 sharptimer_remove_legs true // Whether Legs should be removed or not. Default value : true sharptimer_remove_collision true // Whether player collision should be removed or not. Default value : true @@ -32,9 +32,9 @@ sharptimer_remove_damage true sharptimer_remove_crouch_fatigue true // Whether the player should get no crouch fatigue or not. Default value : true sharptimer_bhop_block_ticks 16 // Ticks allowed on bhop_block. Default value : 16 sharptimer_spawn_on_respawnpos false // Teleports player to respawnpos on spawn. Default value : false -sharptimer_stage_times_enabled true // Whether stage time records are enabled by default or not. Default value : true sharptimer_enable_checkpoint_verification true // Enable or disable checkpoint verification system. Default value : true (set to false if experiencing "current checkpoint does not match final" issue) sharptimer_apply_infinite_ammo true // Enable or disable infinite ammo. Default value: true +sharptimer_print_start_speed true // Whether the start speed should be printed to chat when the player leaves the start zone. Default value: true sharptimer_stage_times_path csgo cfg SharpTimer PlayerStageData // Path to the stage times folder. Default value : csgo cfg SharpTimer PlayerStageData //PERFORMANCE @@ -45,12 +45,12 @@ sharptimer_hud_updates_per_second 64 //ZONES -sharptimer_zones_box false // Make Zone a 3D Box. Default value : false +sharptimer_zones_box false // Make Zone a 3D Box. Default value : false sharptimer_override_beam_colors_enabled false // Whether Trigger Beams should use the colors below or not. If false plugin uses sharptimer_hud_primary_color -sharptimer_start_beam_color #00FF00 // Start Zone color. Default Value : #00FF00 (green hex code) -sharptimer_end_beam_color #FF0000 // End Zone color. Default Value : #FF0000 (red hex code) +sharptimer_start_beam_color #00FF00 // Start Zone color. Default Value : #00FF00 (green hex code) +sharptimer_end_beam_color #FF0000 // End Zone color. Default Value : #FF0000 (red hex code) sharptimer_allow_startzone_jump true // Allow jumping in startzone. Default value : true (NEGATIVE PERFORMANCE IMPACT) -sharptimer_fake_zones_height 50 // Fake Zones height in units. Default value : 50 +sharptimer_fake_zones_height 50 // Fake Zones height in units. Default value : 50 //STYLES @@ -90,16 +90,16 @@ sharptimer_forced_player_speed 250 //HUD sharptimer_hud_primary_color #00FF00 // Primary Color for Timer HUD (you can use hex codes too). Default value : #00FF00 (green) sharptimer_hud_secondary_color #FFA500 // Secondary Color for Timer HUD (you can use hex codes too). Default value : #FFA500 (orange) -sharptimer_hud_secondary_color_dynamic false // False = Use the sharptimer_hud_secondary_color color. True = Use dynamic color based on player velocity (surf only). Default value: false +sharptimer_hud_secondary_color_dynamic False // False = Use the sharptimer_hud_secondary_color color. True = Use dynamic color based on player velocity (surf only). Default value: false sharptimer_hud_tertiary_color #FFFFFF // Tertiary Color for Timer HUD (you can use hex codes too). Default value : #FFFFFF (white) sharptimer_enable_timer_hud true // If Timer Hud should be globally enabled or not. Default value : true sharptimer_enable_keys_hud true // If Keys Hud should be globally enabled or not. Default value : true sharptimer_enable_rankicons_hud true // If Rank Icons Hud should be globally enabled or not. Default value : true sharptimer_enable_velocity_hud true // If Speed Velocity Hud should be globally enabled or not. Default value : true sharptimer_enable_strafesync_hud true // If Stafe Sync % Hud should be globally enabled or not. Default value : true -sharptimer_enable_map_tier_hud true // If Map Tier Hud should be globally enabled or not. Default value : true -sharptimer_enable_map_type_hud true // If Map Type Hud should be globally enabled or not. Default value : true -sharptimer_enable_map_name_hud true // If Map Name Hud should be globally enabled or not. Default value : true +sharptimer_enable_map_tier_hud true // If Map Tier Hud should be globally enabled or not. Default value : true +sharptimer_enable_map_type_hud true // If Map Type Hud should be globally enabled or not. Default value : true +sharptimer_enable_map_name_hud true // If Map Name Hud should be globally enabled or not. Default value : true //BASIC COMMANDS @@ -112,6 +112,7 @@ sharptimer_help_enabled true sharptimer_enable_noclip false // Whether !noclip/!nc is enabled by default or not. Default value : false sharptimer_rs_enabled_onlinear false // Whether !rs will reset players on linear maps. Default value : false + //GLOBAL RANK POINTS sharptimer_global_rank_points_enabled false // Whether the plugin should reward players with global points for completing maps. MySQL Requierd. Default value : false sharptimer_display_rank_tags_chat true // Whether the plugin should display rank tags infront of players names in chat or not. Default value : true @@ -147,12 +148,14 @@ sharptimer_global_rank_group3_percentile 12.5 sharptimer_global_rank_group4_percentile 25 // The top % of record holders in group no4. Default value : 25 sharptimer_global_rank_group5_percentile 50 // The top % of record holders in group no5. Default value : 50 + //REPLAYS -sharptimer_replays_enabled false // Whether replays should be enabled or not. This option might be performance taxing and use more ram & cpu. Default value: false -sharptimer_replay_max_length 300 // The maximum length for a Replay to be saved in seconds. Anything longer will be discarded Default value: 300 -sharptimer_replay_bot_enabled false // Whether a looping Server Record bot should be spawned in or not (requires navmesh fix). Default value: false -sharptimer_replay_bot_name SERVER RECORD REPLAY // What the name of the Replay Record bot should be. Default value: SERVER RECORD REPLAY -sharptimer_replay_data_directory csgo/cfg/SharpTimer/PlayerReplayData // Directory for replay data. Prepended with game dir. Default value: csgo cfg SharpTimer PlayerReplayData +sharptimer_replays_enabled false // Whether replays should be enabled or not. This option might be performance taxing and use more ram & cpu. Default value : false +sharptimer_replay_only_sr false // Only saves SR replay if true. Default value: false +sharptimer_replay_max_length 300 // The maximum length for a Replay to be saved in seconds. Anything longer will be discarded Default value : 300 +sharptimer_replay_bot_enabled false // Whether a looping Server Record bot should be spawned in or not (requires navmesh fix). Default value : false +sharptimer_replay_bot_name SERVER RECORD REPLAY // What the name of the Replay Record bot should be. Default value : SERVER RECORD REPLAY +sharptimer_replay_data_directory csgo/cfg/SharpTimer/PlayerReplayData // Directory for replay data. Prepended with game dir. Default value: csgo/cfg/SharpTimer/PlayerReplayData //CHECKPOINTS/SAVELOC @@ -161,22 +164,20 @@ sharptimer_remove_checkpoints_restrictions false sharptimer_checkpoints_only_when_timer_stopped false // Will only allow checkpoints/locs if timer is stopped using !timer -//JUMPSTATS (KZ) -sharptimer_jumpstats_enabled false // Whether JumpStats are enabled or not. Default value : false -sharptimer_jumpstats_min_distance 175.0 // Defines the minimum distance for a jumpstat to be printed to chat. Default value : 175.0 -sharptimer_jumpstats_max_vert 32.0 // Defines the max vertical distance for a jumpstat to not be printed to chat. Default value : 32.0 -sharptimer_jumpstats_movement_unlocker_cap true // Intended for taming movement unlocker, caps speed on the second tick of a player being on the ground. Default value : true -sharptimer_jumpstats_movement_unlocker_cap_value 250.0 // Speed cap value which will kick in on the second tick of the player being on the ground. Default value : 250.0 +//STAGES +sharptimer_stage_times_enabled true // Whether stage time records are enabled by default or not. Default value : true +sharptimer_stage_sr_enabled true // Whether stage time server records are enabled by default or not. Default value : true //SOUNDS -sharptimer_enable_sounds_by_default false // Whether to enable sounds for players by default. Default value : false -sharptimer_sound_timer sounds/ui/counter_beep.vsnd // Defines Timer sound. Default value : sounds/ui/counter_beep.vsnd (old: sounds/ui/csgo_ui_button_rollover_large.vsnd) -sharptimer_sound_respawn sounds/buttons/button9.vsnd // Defines Respawn sound. Default value : sounds/buttons/button9.vsnd (old: sounds/buttons/button8.vsnd) -sharptimer_sound_checkpoint sounds/ui/buttonclick.vsnd // Defines Checkpoint sound. Default value : sounds/ui/buttonclick.vsnd (old: sounds/ui/counter_beep.vsnd) -sharptimer_sound_checkpoint_error sounds/ui/weapon_cant_buy.vsnd // Defines Checkpoint Error sound. Default value : sounds/ui/weapon_cant_buy.vsnd -sharptimer_sound_teleport sounds/buttons/blip1.vsnd // Defines Teleport sound. Default value : sounds/buttons/blip1.vsnd (old: sounds/ui/buttonclick.vsnd) -sharptimer_sound_pb sounds/buttons/bell1.vsnd // Defines PB Sound. Default value : sounds/buttons/bell1.vsnd -sharptimer_sound_sr sounds/ui/panorama/round_report_round_won_01.vsnd // Defines SR Sound. Default value : sounds/ui/panorama/round_report_round_won_01.vsnd -sharptimer_sound_sr_all_players true // Whether to play SR sound for all players. Default value : true +sharptimer_enable_sounds_by_default false // Whether to enable sounds for players by default. Default value : false +sharptimer_sound_timer sounds/ui/counter_beep.vsnd // Defines Timer sound. Default value : sounds/ui/counter_beep.vsnd (old: sounds/ui/csgo_ui_button_rollover_large.vsnd) +sharptimer_sound_respawn sounds/buttons/button9.vsnd // Defines Respawn sound. Default value : sounds/buttons/button9.vsnd (old: sounds/buttons/button8.vsnd) +sharptimer_sound_checkpoint sounds/ui/buttonclick.vsnd // Defines Checkpoint sound. Default value : sounds/ui/buttonclick.vsnd (old: sounds/ui/counter_beep.vsnd) +sharptimer_sound_checkpoint_error sounds/ui/weapon_cant_buy.vsnd // Defines Checkpoint Error sound. Default value : sounds/ui/weapon_cant_buy.vsnd +sharptimer_sound_teleport sounds/buttons/blip1.vsnd // Defines Teleport sound. Default value : sounds/buttons/blip1.vsnd (old: sounds/ui/buttonclick.vsnd) +sharptimer_sound_pb sounds/buttons/bell1.vsnd // Defines PB Sound. Default value : sounds/buttons/bell1.vsnd +sharptimer_sound_sr sounds/ui/panorama/round_report_round_won_01.vsnd // Defines SR Sound. Default value : sounds/ui/panorama/round_report_round_won_01.vsnd +sharptimer_sound_sr_all_players true // Whether to play SR sound for all players. Default value : true sharptimer_sound_stage_all_players true // Whether to play stage record sound for all players. Default value : true +sharptimer_enable_soundevents false // When enabled it will play soundevents (not .vsnd files), recommended to keep disabled. Default value : false \ No newline at end of file diff --git a/cfg/SharpTimer/custom_exec.cfg b/cfg/SharpTimer/custom_exec.cfg index 1cf0b838..a895320a 100644 --- a/cfg/SharpTimer/custom_exec.cfg +++ b/cfg/SharpTimer/custom_exec.cfg @@ -1,4 +1,2 @@ //Add your desired server settings here -//Example KZ cfg: https://github.com/deafps/cs-cfg/blob/main/kz.cfg -//Example Surf cfg: https://github.com/deafps/cs-cfg/blob/main/surf.cfg //All commands here will be executed on Map Start \ No newline at end of file diff --git a/lang/en.json b/lang/en.json index fcd9f595..302abfd6 100644 --- a/lang/en.json +++ b/lang/en.json @@ -70,8 +70,6 @@ "hud_hidden": "Hud is now: {red}Hidden", "keys_shown": "Keys is now: {green}Shown", "keys_hidden": "Keys is now: {red}Hidden", - "jumpstats_shown": "Jump Stats are now: {green}Shown", - "jumpstats_hidden": "Jump Stats are now: {red}Hidden", "sounds_on": "Sounds are now: {green}ON", "sounds_off": "Sounds are now: {red}OFF", @@ -105,10 +103,6 @@ "goto_player": "Teleporting to {lime}{0}", "goto_player_not_found": "{lightred}Player name not found! If the name contains spaces please try {lime}!goto 'some name'", - //jumpstats - "js_msg1": "{lime}JS: {grey} {0}: {1}{2}{grey} | Pre: {lime}{3}{grey} | Max: {lime}{4}{grey} | Strafes: {lime}{5}", - "js_msg2": "{grey}Height: {lime}{0}{grey} | Width: {lime}{1}{grey} | WT: {lime}{2}{grey} | Sync: {lime}{3}%", - //ad messages "ad_see_all_commands": "{primary}Type !sthelp{default} to see all commands!", "ad_replay_pb": "Type {primary}!replaypb{default} to watch a replay of your personal best run!", @@ -131,7 +125,6 @@ "ad_hud": "Type {primary}!hud{default} to toggle timer hud!", "ad_keys": "Type {primary}!keys{default} to toggle hud keys!", "ad_styles": "Type {primary}!styles{default} to list all available styles!", - "ad_jumpstats": "Type {primaryChatColor}!jumpstats{default} to toggle JumpStats!", //other "command_cooldown": "Command is on cooldown. Chill...", @@ -144,12 +137,13 @@ "connected_message_first": "Player {red}{0} {default}connected for the first time!", "disconnect_message": "Player {red}{0} {default}disconnected!", "afk_message": "{red}You are about to be moved to AFK!", + "start_speed": "Start speed:", //Error "error_savingtime": "Error Saving Time: Player time is 0 ticks", - "error_stagenotmatchfinalone": "Error Saving Time: Player current stage does not match final one{0}", + "error_stagenotmatchfinalone": "Error Saving Time: Player current stage does not match final one", "error_checkpointnotmatchfinalone": "Error Saving Time: Player current checkpoint does not match final one{0}", - + //help console Localizer "Check_console": "Check your console for a list of available commands!", "console_r": "• !r (css_r) - Respawns you", @@ -179,8 +173,7 @@ "console_replaypb": "• !replaypb (css_replaypb) - Replay your pb for the current map", "console_replaybonus": "• !replaybonus / !replayb [1-10] [bonus stage] (css_replaybonus) - Replay a top 10 server bonus record", "console_replaybonuspb": "• !replaybonuspb / !replaybpb (css_replaybonuspb) - Replay your pb for a bonus", - "console_jumpstats": "• !jumpstats (css_jumpstats) - Toggles JumpStats", "console_hideweapon": "• !hideweapon (css_hideweapon) - Toggles weapon visibility", "console_spec": "• !spec (css_spec) - Moves you to Spectator or back to a team", "console_styles": "• !styles (css_styles) - List all styles" -} +} \ No newline at end of file diff --git a/lang/fi.json b/lang/fi.json index b09e54ce..f9012d72 100644 --- a/lang/fi.json +++ b/lang/fi.json @@ -36,6 +36,7 @@ "current_rank": "Sijoituksesi on nyt {0}{1}{lime}", "current_rank_points": "{default}({lime}{0}{default}) [{lime}{1}{default}]", "current_pb": "Ennätyksesi kentällä {lime}{0}{default}: {lime}{1}{default} [{lime}{2}{default}]", + "current_bonus_pb": "Ennätyksesi kentällä {lime}Boonus {0}{default}: {lime}{1}{default} [{lime}{2}{default}]", "current_sr": "Palvelin Ennätys kentällä {lime}{0}{white}:", "current_sr_player": "{lime}{0} {white}- {lime}{1}", "reached_max_free": "Olet saavuttanut maksimi ilmaiset piste palkintosi kentälle {lime}{0}{default}!", @@ -100,44 +101,49 @@ "error_occured": "{lightred}Tapahtui virhe.", "info_version": "Tällä palvelimella on käytössä SharpTimer v{0}", "info_os": "OS: {0}", - "info_runtime": "Runtime: {0}", - - // Error - "error_savingtime": "Virhe tallentaessa aikaa: Pelaajan aika on 0 tikkiä", - "error_stagenotmatchfinalone": "Virhe tallentaessa aikaa: Pelaajan nykyinen vaihe ei vastaa viimeistä vaihetta {0}", - "error_checkpointnotmatchfinalone": "Virhe tallentaessa aikaa: Pelaajan nykyinen tarkistuskohta ei vastaa viimeistä tarkistuspistettä {0}", + "info_runtime": "Suoritusaika: {0}", + "connect_message": "Pelaaja {red}{0} {default}yhdistyi!", + "connected_message": "Pelaaja {red}{0} {default}yhdistyi {1}. kerran!", + "connected_message_first": "Pelaaja {red}{0} {default}yhdistyi ensimmäistä kertaa!", + "disconnect_message": "Pelaaja {red}{0} {default}yhdistyi!", + "afk_message": "{red}Olet siirtymässä AFK-tilaan!", + "start_speed": "Aloitusnopeus:", - // help console Localizer - "Check_console": "Tarkista konsolisi saatavilla olevien komentojen luettelon!", - "console_r": "• !r (css_r) - Herättää sinut henkiin", - "console_rb": "• !rb <#> / !b <#> (css_rb / css_b) - Herättää sinut bonukseen", - "console_setresp": "• !setresp / !startpos (css_setresp / css_startpos) - Tallenna mukautettu herätyspiste aloitustunnisteen sisälle", - "console_top": "• !top (css_top) - Listaa kymmenen parasta tulosta tällä kartalla", - "console_topbonus": "• !topbonus <#> (css_topbonus) - Listaa kymmenen parasta bonus-tulosta", - "console_rank": "• !rank (css_rank) - Näyttää nykyisen tason ja parhaat tulokset", - "console_ranks": "• !ranks (css_ranks) - Näyttää serverin tasoluettelon", - "console_points": "• !points (css_points) - Tulostaa kymmenen parasta pistettä", - "console_goto": "• !goto (css_goto) - Teleporttaa sinut toiseen pelaajaan", - "console_stage": "• !stage <#> (css_stage) - Teleporttaa sinut vaiheeseen", - "console_sounds": "• !sounds (css_sounds) - Kytke ajastimen äänet päälle/pois!", - "console_hud": "• !hud (css_hud) - Kytke ajastimen HUD päälle/pois!", - "console_keys": "• !keys (css_keys) - Kytke HUD-näppäimet päälle/pois!", - "console_fov": "• !fov <0-140> (css_fov) - Muuta näkökenttääsi!", - "console_saveloc": "• !saveloc (css_saveloc) - Tallentaa sijainnin", - "console_loadloc": "• !loadloc (css_loadloc) - Teleporttaa sinut viimeiselle sijainnille", - "console_prevloc": "• !prevloc (css_prevloc) - Teleporttaa sinut edelliselle sijainnille", - "console_nextloc": "• !nextloc (css_nextloc) - Teleporttaa sinut seuraavalle sijainnille", - "console_cp": "• !cp (css_cp) - Asettaa tarkistuspisteen", - "console_tp": "• !tp (css_tp) - Teleporttaa sinut viimeiselle tarkistuspisteelle", - "console_prevcp": "• !prevcp (css_prevcp) - Teleporttaa sinut edelliselle tarkistuspisteelle", - "console_nextcp": "• !nextcp (css_nextcp) - Teleporttaa sinut seuraavalle tarkistuspisteelle", - "console_replay": "• !replay / !replaysr (css_replay / css_replaysr) - Toistaa nykyisen kartan serveritulos", - "console_replaytop": "• !replaytop [1-10] (css_replaytop) - Toistaa kymmenen parasta serverin kartan tulosta", - "console_replaypb": "• !replaypb (css_replaypb) - Toistaa sinun parhaat tuloksesi nykyiseltä kartalta", - "console_replaybonus": "• !replaybonus / !replayb [1-10] [bonus-vaihe] (css_replaybonus) - Toistaa kymmenen parasta serverin bonus-tulosta", - "console_replaybonuspb": "• !replaybonuspb / !replaybpb (css_replaybonuspb) - Toistaa sinun parhaat tuloksesi bonus-vaiheessa", - "console_jumpstats": "• !jumpstats (css_jumpstats) - Vaihtaa JumpStatsin päälle/pois", - "console_hideweapon": "• !hideweapon (css_hideweapon) - Vaihtaa aseen näkyvyyden päälle/pois", - "console_spec": "• !spec (css_spec) - Siirtää sinut katselijaksi tai takaisin tiimiin", - "console_styles": "• !styles (css_styles) - Listaa kaikki tyylit" + // Error + "error_savingtime": "Virhe tallentaessa aikaa: Pelaajan aika on 0 tikkiä", + "error_stagenotmatchfinalone": "Virhe tallentaessa aikaa: Pelaajan nykyinen vaihe ei vastaa viimeistä vaihetta", + "error_checkpointnotmatchfinalone": "Virhe tallentaessa aikaa: Pelaajan nykyinen tarkistuskohta ei vastaa viimeistä tarkistuspistettä {0}", + + // help console Localizer + "Check_console": "Tarkista konsolisi saatavilla olevien komentojen luettelon!", + "console_r": "• !r (css_r) - Herättää sinut henkiin", + "console_rb": "• !rb <#> / !b <#> (css_rb / css_b) - Herättää sinut bonukseen", + "console_setresp": "• !setresp / !startpos (css_setresp / css_startpos) - Tallenna mukautettu herätyspiste aloitustunnisteen sisälle", + "console_top": "• !top (css_top) - Listaa kymmenen parasta tulosta tällä kartalla", + "console_topbonus": "• !topbonus <#> (css_topbonus) - Listaa kymmenen parasta bonus-tulosta", + "console_rank": "• !rank (css_rank) - Näyttää nykyisen tason ja parhaat tulokset", + "console_ranks": "• !ranks (css_ranks) - Näyttää serverin tasoluettelon", + "console_points": "• !points (css_points) - Tulostaa kymmenen parasta pistettä", + "console_goto": "• !goto (css_goto) - Teleporttaa sinut toiseen pelaajaan", + "console_stage": "• !stage <#> (css_stage) - Teleporttaa sinut vaiheeseen", + "console_sounds": "• !sounds (css_sounds) - Kytke ajastimen äänet päälle/pois!", + "console_hud": "• !hud (css_hud) - Kytke ajastimen HUD päälle/pois!", + "console_keys": "• !keys (css_keys) - Kytke HUD-näppäimet päälle/pois!", + "console_fov": "• !fov <0-140> (css_fov) - Muuta näkökenttääsi!", + "console_saveloc": "• !saveloc (css_saveloc) - Tallentaa sijainnin", + "console_loadloc": "• !loadloc (css_loadloc) - Teleporttaa sinut viimeiselle sijainnille", + "console_prevloc": "• !prevloc (css_prevloc) - Teleporttaa sinut edelliselle sijainnille", + "console_nextloc": "• !nextloc (css_nextloc) - Teleporttaa sinut seuraavalle sijainnille", + "console_cp": "• !cp (css_cp) - Asettaa tarkistuspisteen", + "console_tp": "• !tp (css_tp) - Teleporttaa sinut viimeiselle tarkistuspisteelle", + "console_prevcp": "• !prevcp (css_prevcp) - Teleporttaa sinut edelliselle tarkistuspisteelle", + "console_nextcp": "• !nextcp (css_nextcp) - Teleporttaa sinut seuraavalle tarkistuspisteelle", + "console_replay": "• !replay / !replaysr (css_replay / css_replaysr) - Toistaa nykyisen kartan serveritulos", + "console_replaytop": "• !replaytop [1-10] (css_replaytop) - Toistaa kymmenen parasta serverin kartan tulosta", + "console_replaypb": "• !replaypb (css_replaypb) - Toistaa sinun parhaat tuloksesi nykyiseltä kartalta", + "console_replaybonus": "• !replaybonus / !replayb [1-10] [bonus-vaihe] (css_replaybonus) - Toistaa kymmenen parasta serverin bonus-tulosta", + "console_replaybonuspb": "• !replaybonuspb / !replaybpb (css_replaybonuspb) - Toistaa sinun parhaat tuloksesi bonus-vaiheessa", + "console_hideweapon": "• !hideweapon (css_hideweapon) - Vaihtaa aseen näkyvyyden päälle/pois", + "console_spec": "• !spec (css_spec) - Siirtää sinut katselijaksi tai takaisin tiimiin", + "console_styles": "• !styles (css_styles) - Listaa kaikki tyylit" } diff --git a/lang/fr.json b/lang/fr.json index 6d9b221b..c4a716b7 100644 --- a/lang/fr.json +++ b/lang/fr.json @@ -60,8 +60,6 @@ "hud_hidden": "L'Hud est maintenant: {red}Caché", "keys_shown": "Les touches sont maintenant: {green}Affiché", "keys_hidden": "Les touches sont maintenant: {red}Caché", - "jumpstats_shown": "Les statistiques de saut sont maintenant: {green}Affiché", - "jumpstats_hidden": "Les statistiques de saut sont maintenant: {red}Caché", "sounds_on": "Les sons sont maintenant: {green}Activé", "sounds_off": "Les sons sont maintenant: {red}Désactivé", @@ -94,10 +92,6 @@ "goto_player": "Téléportation vers {lime}{0}", "goto_player_not_found": "{lightred}Le nom du joueur n'a pas été trouvé ! Si le nom contient des espaces, essayez {lime}!goto 'joueur lambda'", - //jumpstats - "js_msg1": "{lime}JS: {grey} {0}: {1}{2}{grey} | Pre: {lime}{3}{grey} | Max: {lime}{4}{grey} | Strafes: {lime}{5}", - "js_msg2": "{grey}Hauteur: {lime}{0}{grey} | Largeur: {lime}{1}{grey} | WT: {lime}{2}{grey} | Sync: {lime}{3}%", - //other "command_cooldown": "La commande est en attente. Chill...", "error_occured": "{lightred}Une erreur s'est produite.", @@ -108,10 +102,12 @@ "connected_message": "Joueur {red}{0} {default}connecté pour la {1} fois!", "connected_message_first": "Le joueur {red}{0} {default} s'est connecté pour la première fois!", "disconnect_message": "Joueur {red}{0} {default}déconnecté!", + "afk_message": "{red}Vous allez être déplacé vers l'AFK !", + "start_speed": "Vitesse de départ:", // Error "error_savingtime": "Erreur de sauvegarde du temps : Le temps du joueur est de 0 ticks", - "error_stagenotmatchfinalone": "Erreur de sauvegarde du temps : Le niveau actuel du joueur ne correspond pas au dernier niveau {0}", + "error_stagenotmatchfinalone": "Erreur de sauvegarde du temps : Le niveau actuel du joueur ne correspond pas au dernier niveau", "error_checkpointnotmatchfinalone": "Erreur de sauvegarde du temps : Le point de contrôle actuel du joueur ne correspond pas au dernier point de contrôle {0}", // help console Localizer @@ -143,8 +139,7 @@ "console_replaypb": "• !replaypb (css_replaypb) - Rejoue votre meilleur temps pour la carte actuelle", "console_replaybonus": "• !replaybonus / !replayb [1-10] [bonus stage] (css_replaybonus) - Rejoue un des 10 meilleurs records de bonus sur le serveur", "console_replaybonuspb": "• !replaybonuspb / !replaybpb (css_replaybonuspb) - Rejoue votre meilleur temps pour un bonus", - "console_jumpstats": "• !jumpstats (css_jumpstats) - Active/désactive les statistiques de saut", "console_hideweapon": "• !hideweapon (css_hideweapon) - Active/désactive la visibilité de l'arme", "console_spec": "• !spec (css_spec) - Vous place en spectateur ou vous ramène dans une équipe", "console_styles": "• !styles (css_styles) - Liste tous les styles" -} +} \ No newline at end of file diff --git a/lang/ko.json b/lang/ko.json index 6debb2a4..dbb9512c 100644 --- a/lang/ko.json +++ b/lang/ko.json @@ -67,8 +67,6 @@ "hud_hidden": "HUD: {red}숨겨짐", "keys_shown": "키: {green}표시됨", "keys_hidden": "키: {red}숨겨짐", - "jumpstats_shown": "점프 통계: {green}표시됨", - "jumpstats_hidden": "점프 통계: {red}숨겨짐", "sounds_on": "소리: {green}켜짐", "sounds_off": "소리: {red}꺼짐", @@ -102,10 +100,6 @@ "goto_player": "{lime}{0}으로 이동 중", "goto_player_not_found": "{lightred}플레이어 이름을 찾을 수 없습니다! 이름에 공백이 포함된 경우 {lime}!goto '이름'을 시도해보세요", - // 점프 통계 - "js_msg1": "{lime}JS: {grey} {0}: {1}{2}{grey} | Pre: {lime}{3}{grey} | Max: {lime}{4}{grey} | Strafes: {lime}{5}", - "js_msg2": "{grey}높이: {lime}{0}{grey} | 폭: {lime}{1}{grey} | WT: {lime}{2}{grey} | 동기화: {lime}{3}%", - // 광고 메시지 "ad_see_all_commands": "{primary}!sthelp{default}를 입력하여 모든 명령어를 확인하세요!", "ad_replay_pb": "{primary}!replaypb{default}를 입력하여 자신의 최고 기록 리플레이를 시청하세요!", @@ -128,7 +122,6 @@ "ad_hud": "{primary}!hud{default}를 입력하여 타이머 HUD를 켜거나 끄세요!", "ad_keys": "{primary}!keys{default}를 입력하여 키 HUD를 켜거나 끄세요!", "ad_styles": "{primary}!styles{default}를 입력하여 사용 가능한 모든 스타일을 확인하세요!", - "ad_jumpstats": "{primaryChatColor}!jumpstats{default}를 입력하여 점프 통계를 켜거나 끄세요!", // 기타 "command_cooldown": "명령어 쿨다운 중입니다. 잠시 기다리세요...", @@ -139,10 +132,11 @@ "connect_message": "{red}{0} {default}플레이어가 연결되었습니다!", "disconnect_message": "{red}{0} {default}플레이어가 연결이 끊어졌습니다!", "afk_message": "{red}곧 AFK로 이동합니다!", + "start_speed": "시작 속도:", // 오류 "error_savingtime": "시간 저장 오류: 플레이어 시간이 0 틱입니다", - "error_stagenotmatchfinalone": "시간 저장 오류: 플레이어의 현재 스테이지가 마지막 스테이지와 일치하지 않습니다{0}", + "error_stagenotmatchfinalone": "시간 저장 오류: 플레이어의 현재 스테이지가 마지막 스테이지와 일치하지 않습니다", "error_checkpointnotmatchfinalone": "시간 저장 오류: 플레이어의 현재 체크포인트가 마지막 체크포인트와 일치하지 않습니다{0}", // 도움말 콘솔 지역화 @@ -174,7 +168,6 @@ "console_replaypb": "• !replaypb (css_replaypb) - 현재 맵의 PB를 재생합니다", "console_replaybonus": "• !replaybonus / !replayb [1-10] [보너스 스테이지] (css_replaybonus) - 서버 상위 10개 보너스 기록을 재생합니다", "console_replaybonuspb": "• !replaybonuspb / !replaybpb (css_replaybonuspb) - 보너스의 PB를 재생합니다", - "console_jumpstats": "• !jumpstats (css_jumpstats) - 점프 통계를 전환합니다", "console_hideweapon": "• !hideweapon (css_hideweapon) - 무기 가시성을 전환합니다", "console_spec": "• !spec (css_spec) - 관전자 모드로 이동하거나 팀으로 돌아갑니다", "console_styles": "• !styles (css_styles) - 모든 스타일을 나열합니다" diff --git a/lang/nb.json b/lang/nb.json index 9ab06885..0a1cb009 100644 --- a/lang/nb.json +++ b/lang/nb.json @@ -60,8 +60,6 @@ "hud_hidden": "Hud er nå: {red}Gjemt", "keys_shown": "Keys er nå: {green}Vist", "keys_hidden": "Keys er nå: {red}Gjemt", - "jumpstats_shown": "Hoppstatistikk er nå: {green}Vist", - "jumpstats_hidden": "Hoppstatistikk er nå: {red}Gjemt", "sounds_on": "Lyder er nå: {green}PÅ", "sounds_off": "Lyder er nå: {red}AV", @@ -93,10 +91,6 @@ "goto_player": "Teleporterer til {lime}{0}", "goto_player_not_found": "{lightred}Finner ikke spillernavnet! Hvis navnet inneholder mellomrom, prøv {lime}!goto 'et navn'", - - //jumpstats - "js_msg1": "{lime}JS: {grey} {0}: {1}{2}{grey} | Pre: {lime}{3}{grey} | Max: {lime}{4}{grey} | Strafes: {lime}{5}", - "js_msg2": "{grey}Høyde: {lime}{0}{grey} | Bredde: {lime}{1}{grey} | WT: {lime}{2}{grey} | Sync: {lime}{3}%", //ad messages "ad_see_all_commands": "{primary}Skriv !sthelp{default} for å se alle kommandoer!", @@ -120,8 +114,7 @@ "ad_hud": "Skriv {primary}!hud{default} for å veksle tidtaker hud!", "ad_keys": "Skriv {primary}!keys{default} for å veksle hud taster!", "ad_styles": "Skriv {primary}!styles{default} for å liste opp alle tilgjengelige stiler!", - "ad_jumpstats": "Skriv {primaryChatColor}!jumpstats{default} for å veksle JumpStats!", - + //other "command_cooldown": "Kommandoen er på nedkjøling. Chill...", "error_occured": "{lightred}Feil oppstod.", @@ -132,10 +125,12 @@ "connected_message": "Spiller {red}{0} {default}koblet til for den {1} gang!", "connected_message_first": "Spiller {red}{0} {default}koblet til for første gang!", "disconnect_message": "Spiller {red}{0} {default}frakoblet!", + "afk_message": "{red}Du er i ferd med å bli flyttet til AFK!", + "start_speed": "Startfart:", // Error "error_savingtime": "Feil ved lagring av tid: Spillerens tid er 0 ticks", - "error_stagenotmatchfinalone": "Feil ved lagring av tid: Spillerens nåværende nivå stemmer ikke overens med siste nivå {0}", + "error_stagenotmatchfinalone": "Feil ved lagring av tid: Spillerens nåværende nivå stemmer ikke overens med siste nivå", "error_checkpointnotmatchfinalone": "Feil ved lagring av tid: Spillerens nåværende sjekkpunkt stemmer ikke overens med siste sjekkpunkt {0}", // help console Localizer @@ -167,9 +162,8 @@ "console_replaypb": "• !replaypb (css_replaypb) - Spill av din PB for det nåværende kartet", "console_replaybonus": "• !replaybonus / !replayb [1-10] [bonus stage] (css_replaybonus) - Spill av et av de 10 beste bonus-rekordene på serveren", "console_replaybonuspb": "• !replaybonuspb / !replaybpb (css_replaybonuspb) - Spill av din PB for en bonus", - "console_jumpstats": "• !jumpstats (css_jumpstats) - Bytt JumpStats", "console_hideweapon": "• !hideweapon (css_hideweapon) - Bytt synligheten på våpen", "console_spec": "• !spec (css_spec) - Flytter deg til spekter eller tilbake til et lag", "console_styles": "• !styles (css_styles) - List alle stiler" -} +} \ No newline at end of file diff --git a/lang/pl.json b/lang/pl.json index 0fc635f2..dcc82734 100644 --- a/lang/pl.json +++ b/lang/pl.json @@ -60,8 +60,6 @@ "hud_hidden": "Hud zostal: {red}Ukryte", "keys_shown": "Klawisze sa teraz: {green}Pokazane", "keys_hidden": "Klawisze sa teraz: {red}Ukryte", - "jumpstats_shown": "Statystyki skokow zostaly: {green}Pokazane", - "jumpstats_hidden": "Statystyki skokow zostaly: {red}Ukryte", "sounds_on": "Dzwieki zostaly: {green}Wlaczone", "sounds_off": "Dzwieki zostaly: {red}Wylaczone", @@ -94,10 +92,6 @@ "goto_player": "Przeniesiono do {lime}{0}", "goto_player_not_found": "{lightred}Gracz pod dana nazwa nie zostal znaleziony. Jezeli nazwa posiada spacje sprobuj uzyc: {lime}!goto 'some name'", - //jumpstats - "js_msg1": "{lime}JS: {grey} {0}: {1}{2}{grey} | Pre: {lime}{3}{grey} | Max: {lime}{4}{grey} | Strafes: {lime}{5}", - "js_msg2": "{grey}Height: {lime}{0}{grey} | Width: {lime}{1}{grey} | WT: {lime}{2}{grey} | Sync: {lime}{3}%", - //other "command_cooldown": "Odczekaj zanim ponownie skorzystasz z komendy!", "error_occured": "{lightred}Wystapil blad.", @@ -108,10 +102,12 @@ "connected_message": "Gracz {red}{0} {default}połączył się {1} raz!", "connected_message_first": "Gracz {red}{0} {default}połączył się po raz pierwszy!", "disconnect_message": "Gracz {red}{0} {default}rozłączył się!", + "afk_message": "{red}Za chwilę zostaniesz przeniesiony do AFK!", + "start_speed": "Prędkość startowa:", - // Error + // Error "error_savingtime": "Błąd zapisywania czasu: Czas gracza wynosi 0 ticks", - "error_stagenotmatchfinalone": "Błąd zapisywania czasu: Aktualny etap gracza nie pasuje do ostatniego {0}", + "error_stagenotmatchfinalone": "Błąd zapisywania czasu: Aktualny etap gracza nie pasuje do ostatniego", "error_checkpointnotmatchfinalone": "Błąd zapisywania czasu: Aktualny punkt kontrolny gracza nie pasuje do ostatniego {0}", // help console Localizer @@ -143,8 +139,7 @@ "console_replaypb": "• !replaypb (css_replaypb) - Odtwarza twój PB na aktualnej mapie", "console_replaybonus": "• !replaybonus / !replayb [1-10] [bonus stage] (css_replaybonus) - Odtwarza jeden z 10 najlepszych rekordów bonusowych", "console_replaybonuspb": "• !replaybonuspb / !replaybpb (css_replaybonuspb) - Odtwarza twój PB na bonusie", - "console_jumpstats": "• !jumpstats (css_jumpstats) - Przełącza JumpStats", "console_hideweapon": "• !hideweapon (css_hideweapon) - Przełącza widoczność broni", "console_spec": "• !spec (css_spec) - Przenosi cię do widza lub z powrotem do drużyny", "console_styles": "• !styles (css_styles) - Wyświetla wszystkie style" -} +} \ No newline at end of file diff --git a/lang/sk.json b/lang/sk.json index 7759d322..3be1d518 100644 --- a/lang/sk.json +++ b/lang/sk.json @@ -1,110 +1,110 @@ { - "prefix": "{lime}SharpTimer ●{white}", + "prefix": "{lime}SharpTimer ●{white}", - //timer - "timer_time": "Čas: [{lime}{0}{default}] {1}", - "timer_style": "Štýl: [{lime}{0}{default}]", - "stop_using_timer": "Zastavte svoj časovač pomocou {lime}!timer{default} naprv!", - "timer_enabled": "Časovač: {green}Zapnutý", - "timer_disabled": "Časovač: {red}Vypnutý", - "timer_cancelled": "Časovač bol zrušený z dôvodu nelegálneho pokusu o preskočenie", - "timer_reset": "Resetovali ste sa kvôli nelegálnemu pokusu o preskočenie", + //timer + "timer_time": "Čas: [{lime}{0}{default}] {1}", + "timer_style": "Štýl: [{lime}{0}{default}]", + "stop_using_timer": "Zastavte svoj časovač pomocou {lime}!timer{default} naprv!", + "timer_enabled": "Časovač: {green}Zapnutý", + "timer_disabled": "Časovač: {red}Vypnutý", + "timer_cancelled": "Časovač bol zrušený z dôvodu nelegálneho pokusu o preskočenie", + "timer_reset": "Resetovali ste sa kvôli nelegálnemu pokusu o preskočenie", - //records - "no_records_available": "Pre {0} nie sú dostupné žiadne záznamy", - "no_records_available_bonus": "Pre bonus {0} dňa {1} nie sú k dispozícii žiadne záznamy", - "records_map": "#{0}: {lime}{1} {default}- {2} {lime}{3}", - "new_server_record": "{lime}{0} {white}nastavil nový serverový rekord!", - "new_server_record_bonus": "{lime}{0} {white}nastavil nový serverový rekord na mape {1} (Bonus)!", - "new_pb_record": "{lime}{0} {white}získal nový najlepší čas hráča!", - "new_pb_record_bonus": "{lime}{0} {white}získal nový nalepší čas hráča na mape {1} (Bonus)!", - "map_finish": "{lime}{0} {white}dokončil mapu!", - "map_finish_bonus": "{lime}{0} {white}dokončil Bonus {1}!", - "map_finish_rank": "Hodnosť: [{lime}{0}{default}] Dokončené: [{lime}{1}{default}]", - "top10_records": "Top 10 {0} rekordy pre {1}:", - "top10_records_bonus": "Top 10 {0} rekordy pre bonus {1} na {2}:", + //records + "no_records_available": "Pre {0} nie sú dostupné žiadne záznamy", + "no_records_available_bonus": "Pre bonus {0} dňa {1} nie sú k dispozícii žiadne záznamy", + "records_map": "#{0}: {lime}{1} {default}- {2} {lime}{3}", + "new_server_record": "{lime}{0} {white}nastavil nový serverový rekord!", + "new_server_record_bonus": "{lime}{0} {white}nastavil nový serverový rekord na mape {1} (Bonus)!", + "new_pb_record": "{lime}{0} {white}získal nový najlepší čas hráča!", + "new_pb_record_bonus": "{lime}{0} {white}získal nový nalepší čas hráča na mape {1} (Bonus)!", + "map_finish": "{lime}{0} {white}dokončil mapu!", + "map_finish_bonus": "{lime}{0} {white}dokončil Bonus {1}!", + "map_finish_rank": "Hodnosť: [{lime}{0}{default}] Dokončené: [{lime}{1}{default}]", + "top10_records": "Top 10 {0} rekordy pre {1}:", + "top10_records_bonus": "Top 10 {0} rekordy pre bonus {1} na {2}:", - //stages - "invalid_bonus_stage": "Zadajte platný bonusový stupeň, napr.: {lime}!topbonus 1", - "invalid_bonus_rb": "Zadajte platnú bonusovú fázu, napr.: {lime}!rb ", - "stages_unavalible": "Etapy nedostupné", - "stages_unavalible_respawnpos": "{lightred}Pre aktuálnu mapu sa nenašlo žiadne RespawnStagePos s indexom {0}!", - "stages_enter_valid": "Zadajte platnú fázu, napr.: {lime}!stage ", - "map_no_stages": "{lightred}Aktuálna mapa nemá žiadne fázy!", + //stages + "invalid_bonus_stage": "Zadajte platný bonusový stupeň, napr.: {lime}!topbonus 1", + "invalid_bonus_rb": "Zadajte platnú bonusovú fázu, napr.: {lime}!rb ", + "stages_unavalible": "Etapy nedostupné", + "stages_unavalible_respawnpos": "{lightred}Pre aktuálnu mapu sa nenašlo žiadne RespawnStagePos s indexom {0}!", + "stages_enter_valid": "Zadajte platnú fázu, napr.: {lime}!stage ", + "map_no_stages": "{lightred}Aktuálna mapa nemá žiadne fázy!", - //rank - "current_rank": "Momentálne ste {0}{1}{lime}", - "current_rank_points": "{default}({lime}{0}{default}) [{lime}{1}{default}]", - "current_pb": "Vaša aktuálna PB na {lime}{0}{default}: {lime}{1}{default} [{lime}{2}{default}]", - "current_bonus_pb": "Vaša aktuálna PB na {lime}Bonus {0}{default}: {lime}{1}{default} [{lime}{2}{default}]", - "current_sr": "Aktuálny záznam servera na {lime}{0}{white}:", - "current_sr_player": "{lime}{0} {white}- {lime}{1}", - "reached_max_free": "Dosiahli ste maximálny počet bezplatných odmien vo výške {lime}{0}{default}!", + //rank + "current_rank": "Momentálne ste {0}{1}{lime}", + "current_rank_points": "{default}({lime}{0}{default}) [{lime}{1}{default}]", + "current_pb": "Vaša aktuálna PB na {lime}{0}{default}: {lime}{1}{default} [{lime}{2}{default}]", + "current_bonus_pb": "Vaša aktuálna PB na {lime}Bonus {0}{default}: {lime}{1}{default} [{lime}{2}{default}]", + "current_sr": "Aktuálny záznam servera na {lime}{0}{white}:", + "current_sr_player": "{lime}{0} {white}- {lime}{1}", + "reached_max_free": "Dosiahli ste maximálny počet bezplatných odmien vo výške {lime}{0}{default}!", - //replay - "no_replay": "Momentálne sa neprehráva žiadne prehrávanie", - "end_your_replay": "Najprv ukončite svoje aktuálne prehrávanie {lime}!stopreplay", - "available_replay_cmds": "Dostupné replay príkazy: {lime}!replaypb{default} | {lime}!replaytop <1-10>{default} | {lime}!replaysr{predvolené}", - "no_sr_replay": "Žiadny záznam servera na prehratie!", - "replaying_server_top": "Prehrávanie Top Server Top {0} napíšte {lime}!stop alebo {lime}!stopreplay {default}, aby ste ukončili prehrávanie", - "replaying_pb": "Prehrávanie PB typu {lime}!stop alebo {lime}!stopreplay {default}, aby ste ukončili prehrávanie", - "ending_replay": "Ukončenie opakovaného prehrávania!", - "replay_corrupt": "Zdá sa, že požadované prehratie je poškodené", - "replay_dont_exist": "Požadované prehratie neexistuje", + //replay + "no_replay": "Momentálne sa neprehráva žiadne prehrávanie", + "end_your_replay": "Najprv ukončite svoje aktuálne prehrávanie {lime}!stopreplay", + "available_replay_cmds": "Dostupné replay príkazy: {lime}!replaypb{default} | {lime}!replaytop <1-10>{default} | {lime}!replaysr{predvolené}", + "no_sr_replay": "Žiadny záznam servera na prehratie!", + "replaying_server_top": "Prehrávanie Top Server Top {0} napíšte {lime}!stop alebo {lime}!stopreplay {default}, aby ste ukončili prehrávanie", + "replaying_pb": "Prehrávanie PB typu {lime}!stop alebo {lime}!stopreplay {default}, aby ste ukončili prehrávanie", + "ending_replay": "Ukončenie opakovaného prehrávania!", + "replay_corrupt": "Zdá sa, že požadované prehratie je poškodené", + "replay_dont_exist": "Požadované prehratie neexistuje", - //settings - "hud_shown": "Hud je práve: {green}Zobrazené", - "hud_hidden": "Hud je práve: {red}Skryté", - "keys_shown": "Keys je práve: {green}Zobrazené", - "keys_hidden": "Keys je práve: {red}Skryté", - "jumpstats_shown": "Jump Stats sú práve: {green}Zobrazené", - "jumpstats_hidden": "Jump Stats sú práve: {red}Skryté", - "sounds_on": "Zvuky sú práve: {green}Zapnuté", - "sounds_off": "Zvuky sú práve: {red}Vypnuté", + //settings + "hud_shown": "Hud je práve: {green}Zobrazené", + "hud_hidden": "Hud je práve: {red}Skryté", + "keys_shown": "Keys je práve: {green}Zobrazené", + "keys_hidden": "Keys je práve: {red}Skryté", + "sounds_on": "Zvuky sú práve: {green}Zapnuté", + "sounds_off": "Zvuky sú práve: {red}Vypnuté", - //zones - "no_respawnpos": "{lightred}Pre aktuálnu mapu sa nenašlo žiadne RespawnPos!", - "no_respawnpos_bonus": "{lightred}Pre aktuálnu mapu sa nenašlo žiadne RespawnBonusPos!", - "no_respawnpos_bonus_index": "{lightred}Pre aktuálnu mapu sa nenašlo žiadne RespawnBonusPos s indexom {0}!", - "no_endpos": "{lightred}Pre aktuálnu mapu sa nenašlo žiadne koncové miesto!", - "map_using_manual_zones": "Aktuálna mapa používa manuálne zóny", - "saved_custom_respawnpos": "Uložené vlastné RespawnPos počiatočnej zóny!", - "not_inside_startzone": "Nie ste v štartovacej zóne!", + //zones + "no_respawnpos": "{lightred}Pre aktuálnu mapu sa nenašlo žiadne RespawnPos!", + "no_respawnpos_bonus": "{lightred}Pre aktuálnu mapu sa nenašlo žiadne RespawnBonusPos!", + "no_respawnpos_bonus_index": "{lightred}Pre aktuálnu mapu sa nenašlo žiadne RespawnBonusPos s indexom {0}!", + "no_endpos": "{lightred}Pre aktuálnu mapu sa nenašlo žiadne koncové miesto!", + "map_using_manual_zones": "Aktuálna mapa používa manuálne zóny", + "saved_custom_respawnpos": "Uložené vlastné RespawnPos počiatočnej zóny!", + "not_inside_startzone": "Nie ste v štartovacej zóne!", - //styles - "styles_list": "Štýl {0}. {lime}{1}", - "style_example": "príklad: {lime}/style 1", - "style_set": "Štýl nastavený na: {lime}{0}", - "style_not_found": "Štýl {0} neexistuje", - "styles_disabled": "Štýly sú momentálne na tomto serveri zakázané", - "styles_not_supported": "Štýly momentálne nie sú podporované na miestnych záznamoch :(", + //styles + "styles_list": "Štýl {0}. {lime}{1}", + "style_example": "príklad: {lime}/style 1", + "style_set": "Štýl nastavený na: {lime}{0}", + "style_not_found": "Štýl {0} neexistuje", + "styles_disabled": "Štýly sú momentálne na tomto serveri zakázané", + "styles_not_supported": "Štýly momentálne nie sú podporované na miestnych záznamoch :(", - //checkpoints - "checkpoint_set": "{0} nastavené! {lime}#{1}", - "no_checkpoint_set": "Nič {0} nenastavené!", - "cant_use_checkpoint": "{lightred}Keď je časovač zapnutý, nemožno použiť {0}, použite {default}!timer", - "cant_use_checkpoint_in_air": "{lightred}Vo vzduchu nie je možné nastaviť {0}", - "used_checkpoint": "Teleportované do nasledujúceho {0}", - "used_recent_checkpoint": "Teleportované na najnovšie {0}", - "used_previous_checkpoint": "Teleportované do predchádzajúceho {0}", + //checkpoints + "checkpoint_set": "{0} nastavené! {lime}#{1}", + "no_checkpoint_set": "Nič {0} nenastavené!", + "cant_use_checkpoint": "{lightred}Keď je časovač zapnutý, nemožno použiť {0}, použite {default}!timer", + "cant_use_checkpoint_in_air": "{lightred}Vo vzduchu nie je možné nastaviť {0}", + "used_checkpoint": "Teleportované do nasledujúceho {0}", + "used_recent_checkpoint": "Teleportované na najnovšie {0}", + "used_previous_checkpoint": "Teleportované do predchádzajúceho {0}", - "goto_player": "Teleportuje sa do {lime}{0}", - "goto_player_not_found": "{lightred}Meno hráča sa nenašlo! Ak názov obsahuje medzery, skúste {lime}!goto 'nejaký názov'", + "goto_player": "Teleportuje sa do {lime}{0}", + "goto_player_not_found": "{lightred}Meno hráča sa nenašlo! Ak názov obsahuje medzery, skúste {lime}!goto 'nejaký názov'", - //jumpstats - "js_msg1": "{lime}JS: {grey} {0}: {1}{2}{grey} | Pre: {lime}{3}{grey} | Max: {lime}{4}{grey} | Strafes: {lime}{5}", - "js_msg2": "{grey}Výška: {lime}{0}{grey} | Šírka: {lime}{1}{grey} | WT: {lime}{2}{grey} | Synchronizácia: {lime}{3} %", + //other + "command_cooldown": "Príkaz je v režime cooldown. Kľud...", + "error_occured": "{lightred}Vyskytla sa chyba.", + "info_version": "Tento server používa SharpTimer v{0}", + "info_os": "OS: {0}", + "info_runtime": "Doba behu: {0}", + "connect_message": "Hráč {red}{0} {default}sa pripojil!", + "connected_message": "Hráč {red}{0} {default}sa pripojil po {1}. krát!", + "connected_message_first": "Hráč {red}{0} {default}sa pripojil po prvýkrát!", + "disconnect_message": "Hráč {red}{0} {default}sa odpojil!", + "afk_message": "{red}Čoskoro budete presunutý do AFK!", + "start_speed": "Počiatočná rýchlosť:", - //other - "command_cooldown": "Príkaz je v režime cooldown. Kľud...", - "error_occured": "{lightred}Vyskytla sa chyba.", - "info_version": "Tento server používa SharpTimer v{0}", - "info_os": "OS: {0}", - "info_runtime": "Runtime: {0}", - - // Error + // Error "error_savingtime": "Napaka pri shranjevanju časa: Čas igralca je 0 tics", - "error_stagenotmatchfinalone": "Napaka pri shranjevanju časa: Trenutna stopnja igralca se ne ujema z zadnjo {0}", + "error_stagenotmatchfinalone": "Napaka pri shranjevanju časa: Trenutna stopnja igralca se ne ujema z zadnjo", "error_checkpointnotmatchfinalone": "Napaka pri shranjevanju časa: Trenutna kontrolna točka igralca se ne ujema z zadnjo {0}", // help console Localizer @@ -136,8 +136,7 @@ "console_replaypb": "• !replaypb (css_replaypb) - Predvaja vaš PB za trenutni zemljevid", "console_replaybonus": "• !replaybonus / !replayb [1-10] [bonus stage] (css_replaybonus) - Predvaja enega izmed 10 najboljših bonusnih zapisov strežnika", "console_replaybonuspb": "• !replaybonuspb / !replaybpb (css_replaybonuspb) - Predvaja vaš PB za bonus", - "console_jumpstats": "• !jumpstats (css_jumpstats) - Preklopi JumpStats", "console_hideweapon": "• !hideweapon (css_hideweapon) - Preklopi vidnost orožja", "console_spec": "• !spec (css_spec) - Premakne vas v opazovalca ali nazaj v ekipo", "console_styles": "• !styles (css_styles) - Prikazuje vse sloge" -} +} \ No newline at end of file diff --git a/lang/sv.json b/lang/sv.json index d7746a23..d21eb7f6 100644 --- a/lang/sv.json +++ b/lang/sv.json @@ -60,8 +60,6 @@ "hud_hidden": "HUD är nu: {red}Gömd", "keys_shown": "Tangenter är nu: {green}Synliga", "keys_hidden": "Tangenter är nu: {red}Gömda", - "jumpstats_shown": "Jump Stats är nu: {green}Synliga", - "jumpstats_hidden": "Jump Stats är nu: {red}Gömda", "sounds_on": "Ljud är nu: {green}PÅ", "sounds_off": "Ljud är nu: {red}AV", @@ -94,10 +92,6 @@ "goto_player": "Teleporterar till {lime}{0}", "goto_player_not_found": "{lightred}Namnet på spelaren hittades inte! Om namnet innehåller mellanslag, försök {lime}!goto 'spelarens namn'", - //jumpstats - "js_msg1": "{lime}JS: {grey} {0}: {1}{2}{grey} | Pre: {lime}{3}{grey} | Max: {lime}{4}{grey} | Strafes: {lime}{5}", - "js_msg2": "{grey}Height: {lime}{0}{grey} | Width: {lime}{1}{grey} | WT: {lime}{2}{grey} | Sync: {lime}{3}%", - //other "command_cooldown": "Command är på cooldown. Chilla...", "error_occured": "{lightred}Fel uppstod.", @@ -108,43 +102,45 @@ "connected_message": "Spelare {red}{0} {default}ansluten för den {1} gången!", "connected_message_first": "Spleare {red}{0} {default}ansluten för första gången!", "disconnect_message": "Spelare {red}{0} {default}lämnade!", - - // Error - "error_savingtime": "Chyba pri ukladaní času: Čas hráča je 0 tics", - "error_stagenotmatchfinalone": "Chyba pri ukladaní času: Aktuálna fáza hráča sa nezhoduje s konečnou {0}", - "error_checkpointnotmatchfinalone": "Chyba pri ukladaní času: Aktuálna kontrolná bodka hráča sa nezhoduje s konečnou {0}", - // help console Localizer - "Check_console": "Skontrolujte svoju konzolu pre zoznam dostupných príkazov!", - "console_r": "• !r (css_r) - Ožije vás", - "console_rb": "• !rb <#> / !b <#> (css_rb / css_b) - Ožije vás na bonuse", - "console_setresp": "• !setresp / !startpos (css_setresp / css_startpos) - Uloží vlastný bod respawnu v štartovacom spúšťači", - "console_top": "• !top (css_top) - Zobrazí 10 najlepších rekordov na tejto mape", - "console_topbonus": "• !topbonus <#> (css_topbonus) - Zobrazí 10 najlepších bonusových rekordov", - "console_rank": "• !rank (css_rank) - Zobrazí váš aktuálny rank a PB", - "console_ranks": "• !ranks (css_ranks) - Zobrazí zoznam rankov servera", - "console_points": "• !points (css_points) - Zobrazí 10 najlepších bodov", - "console_goto": "• !goto (css_goto) - Teleportuje vás k hráčovi", - "console_stage": "• !stage <#> (css_stage) - Teleportuje vás na scénu", - "console_sounds": "• !sounds (css_sounds) - Prepnúť zvuky časovača!", - "console_hud": "• !hud (css_hud) - Prepnúť HUD časovača!", - "console_keys": "• !keys (css_keys) - Prepnúť tlačidlá HUD!", - "console_fov": "• !fov <0-140> (css_fov) - Zmeniť vaše zorné pole!", - "console_saveloc": "• !saveloc (css_saveloc) - Uloží lokalitu", - "console_loadloc": "• !loadloc (css_loadloc) - Teleportuje vás na poslednú lokalitu", - "console_prevloc": "• !prevloc (css_prevloc) - Teleportuje vás o jednu lokalitu späť", - "console_nextloc": "• !nextloc (css_nextloc) - Teleportuje vás o jednu lokalitu dopredu", - "console_cp": "• !cp (css_cp) - Nastaví kontrolný bod", - "console_tp": "• !tp (css_tp) - Teleportuje vás na posledný kontrolný bod", - "console_prevcp": "• !prevcp (css_prevcp) - Teleportuje vás o jeden kontrolný bod späť", - "console_nextcp": "• !nextcp (css_nextcp) - Teleportuje vás o jeden kontrolný bod dopredu", - "console_replay": "• !replay / !replaysr (css_replay / css_replaysr) - Prehrá aktuálny záznam serverovej mapy", - "console_replaytop": "• !replaytop [1-10] (css_replaytop) - Prehrá top 10 serverových rekordov mapy", - "console_replaypb": "• !replaypb (css_replaypb) - Prehrá váš PB pre aktuálnu mapu", - "console_replaybonus": "• !replaybonus / !replayb [1-10] [bonus stage] (css_replaybonus) - Prehrá top 10 serverových bonusových rekordov", - "console_replaybonuspb": "• !replaybonuspb / !replaybpb (css_replaybonuspb) - Prehrá váš PB pre bonus", - "console_jumpstats": "• !jumpstats (css_jumpstats) - Prepnúť JumpStats", - "console_hideweapon": "• !hideweapon (css_hideweapon) - Prepnúť viditeľnosť zbrane", - "console_spec": "• !spec (css_spec) - Presunie vás na diváka alebo späť do tímu", - "console_styles": "• !styles (css_styles) - Zobraziť všetky štýly" + "afk_message": "{red}Du är på väg att flyttas till AFK!", + "start_speed": "Startfart:", + + //Error + "error_savingtime": "Error Saving Time: Spelartiden är 0 tick", + "error_stagenotmatchfinalone": "Error Saving Time: Spelarens nuvarande stadium matchar inte det sista", + "error_checkpointnotmatchfinalone": "Error Saving Time: Spelarens aktuella checkpoint matchar inte den sista{0}", + + //help console Localizer + "Check_console": "Kolla din konsol för en lista över tillgängliga kommandon!", + "console_r": "• !r (css_r) - Respawnar dig", + "console_rb": "• !rb <#> / !b <#> (css_rb / css_b) - Respawnar dig till en bonus", + "console_setresp": "• !setresp / !startpos (css_setresp / css_startpos) - Spara en custom respawn plats inom start triggern", + "console_top": "• !top (css_top) - Listar topp 10 rekord på denna karta", + "console_topbonus": "• !topbonus <#> (css_topbonus) - Listar topp 10 rekord på en bonus", + "console_rank": "• !rank (css_rank) - Visar din nuvarande rank och pb", + "console_ranks": "• !ranks (css_ranks) - Visar en lista över serverrankningarna", + "console_points": "• !points (css_points) - Visa topp 10 poäng", + "console_goto": "• !goto (css_goto) - Teleporterar dig till en spelare", + "console_stage": "• !stage <#> (css_stage) - Teleporterar dig till en stage", + "console_sounds": "• !sounds (css_sounds) - Toggla timer ljud!", + "console_hud": "• !hud (css_hud) - Toggla timer hud!", + "console_keys": "• !keys (css_keys) - Toggla hud keys!", + "console_fov": "• !fov <0-140> (css_fov) - Ändra din field of view!", + "console_saveloc": "• !saveloc (css_saveloc) - Spara en Loc", + "console_loadloc": "• !loadloc (css_loadloc) - Teleporterar dig till det sista Loc", + "console_prevloc": "• !prevloc (css_prevloc) - Teleporterar dig en Loc tillbaka", + "console_nextloc": "• !nextloc (css_nextloc) - Teleporterar dig en Loc framåt", + "console_cp": "• !cp (css_cp) - Sätter en Checkpoint", + "console_tp": "• !tp (css_tp) - Teleporterar dig till din sista Checkpoint", + "console_prevcp": "• !prevcp (css_prevcp) - Teleporterar dig en Checkpoint bak", + "console_nextcp": "• !nextcp (css_nextcp) - Teleporterar dig en Checkpoint fram", + "console_replay": "• !replay / !replaysr (css_replay / css_replaysr) - Spela upp nuvarande kartas server rekord", + "console_replaytop": "• !replaytop [1-10] (css_replaytop) - Spela upp en topp 10 server karta rekord", + "console_replaypb": "• !replaypb (css_replaypb) - Spela om din pb för den aktuella kartan", + "console_replaybonus": "• !replaybonus / !replayb [1-10] [bonus stage] (css_replaybonus) - Spela om ett topp 10-serverbonusrekord", + "console_replaybonuspb": "• !replaybonuspb / !replaybpb (css_replaybonuspb) - Spela om din pb för en bonus", + "console_hideweapon": "• !hideweapon (css_hideweapon) - Toggla vapnets synlighet", + "console_spec": "• !spec (css_spec) - Flyttar dig till Spectator eller tillbaka till ett lag", + "console_styles": "• !styles (css_styles) - Lista alla styles" } diff --git a/lang/tr.json b/lang/tr.json index d7a53585..016a8647 100644 --- a/lang/tr.json +++ b/lang/tr.json @@ -64,8 +64,6 @@ "hud_hidden": "Hud şu anda: {red}Gizli", "keys_shown": "Tușlar şu anda: {green}Gösteriliyor", "keys_hidden": "Tușlar şu anda: {red}Gizli", - "jumpstats_shown": "Jump Stat'ları şu anda: {green}Gösteriliyor", - "jumpstats_hidden": "Jump Stat'ları şu anda: {red}Gizli", "sounds_on": "Sesler şu anda: {green}Açık", "sounds_off": "Sesler şu anda: {red}Kapalı", @@ -99,10 +97,6 @@ "goto_player": "Oyuncuya {lime}{0} ışınlanılıyor", "goto_player_not_found": "{lightred}Oyuncu adı bulunamadı! Eğer adı boşluk içeriyorsa {lime}!goto 'örnek kullanım' şeklinde deneyin", - //jumpstat mesajları - "js_msg1": "{lime}JS: {grey} {0}: {1}{2}{grey} | Pre: {lime}{3}{grey} | Max: {lime}{4}{grey} | Strafes: {lime}{5}", - "js_msg2": "{grey}Yükseklik: {lime}{0}{grey} | Genişlik: {lime}{1}{grey} | WT: {lime}{2}{grey} | Senkronizasyon: {lime}{3}%", - //Reklam mesajları "ad_see_all_commands": "{primary}Tüm komutları görmek için !sthelp yazın{default}", "ad_replay_pb": "Kişisel en iyi rekorunuzun replayını izlemek için {primary}!replaypb yazın{default}", @@ -125,7 +119,6 @@ "ad_hud": "Zamanlayıcı HUD'unu açmak/kapamak için {primary}!hud yazın{default}", "ad_keys": "HUD tuşlarını açmak/kapamak için {primary}!keys yazın{default}", "ad_styles": "Mevcut stilleri listelemek için {primary}!styles yazın{default}", - "ad_jumpstats": "JumpStats'ı açmak/kapamak için {primaryChatColor}!jumpstats yazın{default}", //Diğer "command_cooldown": "Komut bekleme süresinde. Sakin olun...", @@ -138,10 +131,11 @@ "connected_message_first": "Oyuncu {red}{0} {default} ilk kez bağlandı!", "disconnect_message": "Oyuncu {red}{0} {default}çıktı!", "afk_message": "{red}AFK'ya alınmak üzeresiniz!", + "start_speed": "Başlangıç hızı:", //Hata "error_savingtime": "Zaman kaydedilirken hata: Oyuncu zamanı 0 tick", - "error_stagenotmatchfinalone": "Zaman kaydedilirken hata: Oyuncunun geçerli stage'i son stage ile uyuşmuyor{0}", + "error_stagenotmatchfinalone": "Zaman kaydedilirken hata: Oyuncunun geçerli stage'i son stage ile uyuşmuyor", "error_checkpointnotmatchfinalone": "Zaman kaydedilirken hata: Oyuncunun geçerli kontrol noktası son kontrol noktası ile uyuşmuyor{0}", //Yardım konsolu Yerelleştirici @@ -173,7 +167,6 @@ "console_replaypb": "• !replaypb (css_replaypb) - Mevcut haritada kişisel en iyi zamanınızı tekrar oynatır", "console_replaybonus": "• !replaybonus / !replayb [1-10] [bonus numarası] (css_replaybonus) - Bonus bölgesindeki sunucu replayını tekrar oynatır", "console_replaybonuspb": "• !replaybonuspb / !replaybpb (css_replaybonuspb) - Bonus bölgesindeki kişisel en iyi zamanınızı tekrar oynatır", - "console_jumpstats": "• !jumpstats (css_jumpstats) - JumpStats'ı açar/kapar", "console_hideweapon": "• !hideweapon (css_hideweapon) - Silah görünürlüğünü açar/kapar", "console_spec": "• !spec (css_spec) - Sizi izleyiciye veya takıma geri taşır", "console_styles": "• !styles (css_styles) - Mevcut stilleri listeler" diff --git a/lang/zh-Hans.json b/lang/zh-Hans.json index 1449a970..4a1b85cc 100644 --- a/lang/zh-Hans.json +++ b/lang/zh-Hans.json @@ -52,8 +52,6 @@ "hud_hidden": "HUD : {red}隐藏", "keys_shown": "按键: {green}显示", "keys_hidden": "按键: {red}隐藏", - "jumpstats_shown": "跳跃统计: {green}显示", - "jumpstats_hidden": "跳跃统计: {red}隐藏", "sounds_on": "声音: {green}打开", "sounds_off": "声音: {red}关闭", "no_respawnpos": "{lightred}当前地图未找到重生位置!", @@ -78,8 +76,6 @@ "used_previous_checkpoint": "已传送至上一个 {0}", "goto_player": "正在传送到 {lime}{0}", "goto_player_not_found": "{lightred}未找到玩家名称!如果名称包含空格,请尝试 {lime}!goto '名称'", - "js_msg1": "{lime}跳跃统计: {grey} {0}: {1}{2}{grey} | 预跳: {lime}{3}{grey} | 最大: {lime}{4}{grey} | 滑动次数: {lime}{5}", - "js_msg2": "{grey}高度: {lime}{0}{grey} | 宽度: {lime}{1}{grey} | 滑动时间: {lime}{2}{grey} | 同步率: {lime}{3}%", "ad_see_all_commands": "{primary}输入 !sthelp{default} 查看所有命令!", "ad_replay_pb": "输入 {primary}!replaypb{default} 观看你个人最佳的重播!", "ad_replay_sr": "输入 {primary}!replay 或 {primary}!replaysr{default} 观看 {primary}{current_map}{default} 的服务器记录重播!", @@ -101,7 +97,6 @@ "ad_hud": "输入 {primary}!hud{default} 启用/禁用计时器 HUD!", "ad_keys": "输入 {primary}!keys{default} 启用/禁用 HUD 按键!", "ad_styles": "输入 {primary}!styles{default} 列出所有可用的风格!", - "ad_jumpstats": "输入 {primaryChatColor}!jumpstats{default} 启用/禁用跳跃统计!", "command_cooldown": "命令正在冷却中,请稍等...", "error_occured": "{lightred}发生错误。", "info_version": "此服务器运行 SharpTimer v{0}", @@ -112,10 +107,11 @@ "connected_message_first": "玩家 {red}{0} {default}首次进入服务器!", "disconnect_message": "玩家 {red}{0} {default}断开连接!", "afk_message": "{red}你即将到达 AFK 检测!", + "start_speed": "起始速度:", //报错 "error_savingtime": "保存时间错误:玩家时间为 0 ticks", - "error_stagenotmatchfinalone": "保存时间错误:玩家当前阶段与最终阶段不匹配{0}", + "error_stagenotmatchfinalone": "保存时间错误:玩家当前阶段与最终阶段不匹配", "error_checkpointnotmatchfinalone": "保存时间错误:玩家当前检查点与最终检查点不匹配{0}", //控制台项 @@ -147,8 +143,7 @@ "console_replaypb": "• !replaypb (css_replaypb) - 回放你在当前地图的个人最好成绩", "console_replaybonus": "• !replaybonus / !replayb [1-10] [bonus stage] (css_replaybonus) - 回放前 10 名的服务器奖励记录", "console_replaybonuspb": "• !replaybonuspb / !replaybpb (css_replaybonuspb) - 回放你在奖励关卡的个人最好成绩", - "console_jumpstats": "• !jumpstats (css_jumpstats) - 切换跳跃统计", "console_hideweapon": "• !hideweapon (css_hideweapon) - 切换武器可见性", "console_spec": "• !spec (css_spec) - 使你进入观战模式或返回队伍", "console_styles": "• !styles (css_styles) - 列出所有样式" -} +} \ No newline at end of file diff --git a/remote_data/kz_.json b/remote_data/kz_.json deleted file mode 100644 index f8f50d84..00000000 --- a/remote_data/kz_.json +++ /dev/null @@ -1,2855 +0,0 @@ -{ - "kz_11342": { - "Tier": 1 - }, - "kz_11735": { - "Tier": 1 - }, - "kz_8b1_brickngrass": { - "Tier": 1 - }, - "kz_adeline": { - "Tier": 1 - }, - "kz_alt_cargo": { - "Tier": 1 - }, - "kz_autobadges": { - "Tier": 1 - }, - "kz_baxter": { - "Tier": 1 - }, - "kz_beanguy_v2": { - "Tier": 1 - }, - "kz_beginnerblock": { - "Tier": 1 - }, - "kz_blocks2006": { - "Tier": 1 - }, - "kz_boomblock": { - "Tier": 1 - }, - "kz_breezeblocks": { - "Tier": 1 - }, - "kz_brightblock": { - "Tier": 1 - }, - "kz_cartooncastle": { - "Tier": 1 - }, - "kz_caulis_v2": { - "Tier": 1 - }, - "kz_cellblock_go2": { - "Tier": 1 - }, - "kz_cheetos_fix": { - "Tier": 1 - }, - "kz_chessblock": { - "Tier": 1 - }, - "kz_chrysoprase": { - "Tier": 1 - }, - "kz_cliffhanger": { - "Tier": 1 - }, - "kz_conifer": { - "Tier": 1 - }, - "kz_cranking_the_hog": { - "Tier": 1 - }, - "kz_cratespeed": { - "Tier": 1 - }, - "kz_crate_delight": { - "Tier": 1 - }, - "kz_cybersand": { - "Tier": 1 - }, - "kz_dakow": { - "Tier": 1 - }, - "kz_dale": { - "Tier": 1 - }, - "kz_daniel": { - "Tier": 1 - }, - "kz_dark_fury": { - "Tier": 1 - }, - "kz_delphinium": { - "Tier": 1 - }, - "kz_de_bhop": { - "Tier": 1 - }, - "kz_ea_beneath": { - "Tier": 1 - }, - "kz_emblem_bonus": { - "Tier": 1 - }, - "kz_eros_v2": { - "Tier": 1 - }, - "kz_exoteric": { - "Tier": 1 - }, - "kz_fastmap": { - "Tier": 1 - }, - "kz_fikablock": { - "Tier": 1 - }, - "kz_flying_rabbits": { - "Tier": 1 - }, - "kz_forestrace": { - "Tier": 1 - }, - "kz_frozen": { - "Tier": 1 - }, - "kz_galaxy_go2": { - "Tier": 1 - }, - "kz_ghat": { - "Tier": 1 - }, - "kz_giantbean": { - "Tier": 1 - }, - "kz_gigablock": { - "Tier": 1 - }, - "kz_gkd_v2": { - "Tier": 1 - }, - "kz_haki_v2": { - "Tier": 1 - }, - "kz_hb_3kliksphilip": { - "Tier": 1 - }, - "kz_hillside": { - "Tier": 1 - }, - "kz_huber": { - "Tier": 1 - }, - "kz_hyroblock": { - "Tier": 1 - }, - "kz_intercourse!": { - "Tier": 1 - }, - "kz_j2s_westbl0ck": { - "Tier": 1 - }, - "kz_janpu_final_fix": { - "Tier": 1 - }, - "kz_kiwifactory": { - "Tier": 1 - }, - "kz_kzra_oddland": { - "Tier": 1 - }, - "kz_kzra_shortclimb_v2": { - "Tier": 1 - }, - "kz_kzra_suhu": { - "Tier": 1 - }, - "kz_kzro_2boxes1room": { - "Tier": 1 - }, - "kz_kzro_beknowater": { - "Tier": 1 - }, - "kz_kzro_darkhole": { - "Tier": 1 - }, - "kz_kzro_fastcliff": { - "Tier": 1 - }, - "kz_kzro_shima_v2": { - "Tier": 1 - }, - "kz_kzro_smallcanyon": { - "Tier": 1 - }, - "kz_kzro_speedcavescape": { - "Tier": 1 - }, - "kz_kzro_syotiles": { - "Tier": 1 - }, - "kz_kzro_yaruna": { - "Tier": 1 - }, - "kz_layercake": { - "Tier": 1 - }, - "kz_littlerock_v2": { - "Tier": 1 - }, - "kz_luonto": { - "Tier": 1 - }, - "kz_mac": { - "Tier": 1 - }, - "kz_man_everest_fix": { - "Tier": 1 - }, - "kz_megabhop_v2": { - "Tier": 1 - }, - "kz_micropenis": { - "Tier": 1 - }, - "kz_minimountain_f": { - "Tier": 1 - }, - "kz_morebricks_msq": { - "Tier": 1 - }, - "kz_mz": { - "Tier": 1 - }, - "kz_natureblock_scte": { - "Tier": 1 - }, - "kz_nature_remaster": { - "Tier": 1 - }, - "kz_obsidian": { - "Tier": 1 - }, - "kz_owtetad": { - "Tier": 1 - }, - "kz_phamous": { - "Tier": 1 - }, - "kz_pharos_fix": { - "Tier": 1 - }, - "kz_phaztec": { - "Tier": 1 - }, - "kz_piranha": { - "Tier": 1 - }, - "kz_prolific": { - "Tier": 1 - }, - "kz_quickshot": { - "Tier": 1 - }, - "kz_rainrun_kn_f": { - "Tier": 1 - }, - "kz_redline": { - "Tier": 1 - }, - "kz_rocks_global": { - "Tier": 1 - }, - "kz_rush2suck": { - "Tier": 1 - }, - "kz_sanctuary": { - "Tier": 1 - }, - "kz_sandstone_mq": { - "Tier": 1 - }, - "kz_simplicity_v2": { - "Tier": 1 - }, - "kz_sp1_kyuubisroom": { - "Tier": 1 - }, - "kz_spiritblockv2": { - "Tier": 1 - }, - "kz_sukblock_v2_fixed": { - "Tier": 1 - }, - "kz_summercliff2": { - "Tier": 1 - }, - "kz_terablock": { - "Tier": 1 - }, - "kz_tomb_fix": { - "Tier": 1 - }, - "kz_tradeblock": { - "Tier": 1 - }, - "kz_violet_fix": { - "Tier": 1 - }, - "kz_woodstock_v2": { - "Tier": 1 - }, - "kz_xand": { - "Tier": 1 - }, - "kz_xmas2008": { - "Tier": 1 - }, - "kz_xmas2009": { - "Tier": 1 - }, - "kz_za_tileblock": { - "Tier": 1 - }, - "skz_map": { - "Tier": 1 - }, - "vnl_whiterun": { - "Tier": 1 - }, - "xc_cliffjump_fix": { - "Tier": 1 - }, - "xc_dtt_nasty": { - "Tier": 1 - }, - "kz_kzro_justgrab": { - "Tier": 1 - }, - "kz_sloth": { - "Tier": 1 - }, - "kz_leto_v2": { - "Tier": 1 - }, - "kz_ronja": { - "Tier": 1 - }, - "bkz_kartrider": { - "Tier": 1 - }, - "kz_kiwimirific": { - "Tier": 1 - }, - "kz_smb": { - "Tier": 1 - }, - "kz_something": { - "Tier": 1 - }, - "kz_kays": { - "Tier": 1 - }, - "kz_ghs": { - "Tier": 1 - }, - "kz_lmn": { - "Tier": 1 - }, - "kz_apiisnotresponding": { - "Tier": 1 - }, - "kz_automata": { - "Tier": 1 - }, - "kz_grotto": { - "Tier": 2 - }, - "bkz_blackrockshooter_vzp": { - "Tier": 2 - }, - "bkz_bonus_z1": { - "Tier": 2 - }, - "bkz_cauz_final": { - "Tier": 2 - }, - "bkz_caves": { - "Tier": 2 - }, - "bkz_cg_coldbhop": { - "Tier": 2 - }, - "bkz_chillhop": { - "Tier": 2 - }, - "bkz_dydhop": { - "Tier": 2 - }, - "bkz_goldbhop": { - "Tier": 2 - }, - "bkz_goldbhop": { - "Tier": 2 - }, - "bkz_hellokitty_v2": { - "Tier": 2 - }, - "bkz_impulse": { - "Tier": 2 - }, - "bkz_itz_h25l": { - "Tier": 2 - }, - "bkz_levite_v2": { - "Tier": 2 - }, - "bkz_lewlysex": { - "Tier": 2 - }, - "bkz_measure": { - "Tier": 2 - }, - "bkz_measure2_b03": { - "Tier": 2 - }, - "bkz_nocturns_blue_gfix": { - "Tier": 2 - }, - "bkz_volcanohop": { - "Tier": 2 - }, - "kz_16pillars": { - "Tier": 2 - }, - "kz_420b": { - "Tier": 2 - }, - "kz_4u_nature": { - "Tier": 2 - }, - "kz_7in1": { - "Tier": 2 - }, - "kz_adventure_v2": { - "Tier": 2 - }, - "kz_after_agitation_easy_fix": { - "Tier": 2 - }, - "kz_akrh_warehouse_v3": { - "Tier": 2 - }, - "kz_alfama": { - "Tier": 2 - }, - "kz_alouette_fix": { - "Tier": 2 - }, - "kz_alt_aztec": { - "Tier": 2 - }, - "kz_ancient_v3": { - "Tier": 2 - }, - "kz_antigeneric": { - "Tier": 2 - }, - "kz_antiquity": { - "Tier": 2 - }, - "kz_anus": { - "Tier": 2 - }, - "kz_ashen": { - "Tier": 2 - }, - "kz_asphyxiate": { - "Tier": 2 - }, - "kz_asteroid_field": { - "Tier": 2 - }, - "kz_avalon": { - "Tier": 2 - }, - "kz_aztec": { - "Tier": 2 - }, - "kz_babycat_fix": { - "Tier": 2 - }, - "kz_basicnoon": { - "Tier": 2 - }, - "kz_betterdunjun": { - "Tier": 2 - }, - "kz_bhop_lego": { - "Tier": 2 - }, - "kz_bhop_lj": { - "Tier": 2 - }, - "kz_bhop_monsterjam": { - "Tier": 2 - }, - "kz_bhop_watertemple": { - "Tier": 2 - }, - "kz_bir_dont_fix": { - "Tier": 2 - }, - "kz_bluerace_v2": { - "Tier": 2 - }, - "kz_brickblock_v2": { - "Tier": 2 - }, - "kz_bridge17_fix": { - "Tier": 2 - }, - "kz_canyon": { - "Tier": 2 - }, - "kz_cargo": { - "Tier": 2 - }, - "kz_carp_v2": { - "Tier": 2 - }, - "kz_castlehops_v3": { - "Tier": 2 - }, - "kz_catharsis_global": { - "Tier": 2 - }, - "kz_cdr_myst": { - "Tier": 2 - }, - "kz_checkmate": { - "Tier": 2 - }, - "kz_cheese": { - "Tier": 2 - }, - "kz_christmas": { - "Tier": 2 - }, - "kz_chunky_peanut_butter": { - "Tier": 2 - }, - "kz_combobreaker": { - "Tier": 2 - }, - "kz_combohop_c02": { - "Tier": 2 - }, - "kz_comboya": { - "Tier": 2 - }, - "kz_complex": { - "Tier": 2 - }, - "kz_comp_global": { - "Tier": 2 - }, - "kz_concretejungle": { - "Tier": 2 - }, - "kz_construction": { - "Tier": 2 - }, - "kz_cousucks": { - "Tier": 2 - }, - "kz_cuberunfast": { - "Tier": 2 - }, - "kz_dimensions_v1": { - "Tier": 2 - }, - "kz_doubletake": { - "Tier": 2 - }, - "kz_doveen": { - "Tier": 2 - }, - "kz_dryness": { - "Tier": 2 - }, - "kz_dungeon": { - "Tier": 2 - }, - "kz_dvn_cube_fixed": { - "Tier": 2 - }, - "kz_dvn_dull": { - "Tier": 2 - }, - "kz_dvn_redcarpet": { - "Tier": 2 - }, - "kz_dzy_beyond_v2": { - "Tier": 2 - }, - "kz_echo": { - "Tier": 2 - }, - "kz_edp445": { - "Tier": 2 - }, - "kz_egyptmap": { - "Tier": 2 - }, - "kz_eimeristzurueck": { - "Tier": 2 - }, - "kz_emblem": { - "Tier": 2 - }, - "kz_ephemeral": { - "Tier": 2 - }, - "kz_epusbridge": { - "Tier": 2 - }, - "kz_erbajerb": { - "Tier": 2 - }, - "kz_excavate": { - "Tier": 2 - }, - "kz_experiment": { - "Tier": 2 - }, - "kz_ext_bblocks": { - "Tier": 2 - }, - "kz_fabrik": { - "Tier": 2 - }, - "kz_fas2map": { - "Tier": 2 - }, - "kz_fatigue_v2": { - "Tier": 2 - }, - "kz_final_ascension": { - "Tier": 2 - }, - "kz_floatingislands": { - "Tier": 2 - }, - "kz_foggywarehouse_v2": { - "Tier": 2 - }, - "kz_forgettable": { - "Tier": 2 - }, - "kz_freezing_ridge": { - "Tier": 2 - }, - "kz_fury": { - "Tier": 2 - }, - "kz_gary": { - "Tier": 2 - }, - "kz_generic": { - "Tier": 2 - }, - "kz_genesis": { - "Tier": 2 - }, - "kz_gfy_limit": { - "Tier": 2 - }, - "kz_ggurk": { - "Tier": 2 - }, - "kz_glassesospa_v1": { - "Tier": 2 - }, - "kz_glide": { - "Tier": 2 - }, - "kz_goldenroad": { - "Tier": 2 - }, - "kz_hate": { - "Tier": 2 - }, - "kz_hb_anduu": { - "Tier": 2 - }, - "kz_hb_bacon": { - "Tier": 2 - }, - "kz_hb_fyksen": { - "Tier": 2 - }, - "kz_highland": { - "Tier": 2 - }, - "kz_holdmyhand": { - "Tier": 2 - }, - "kz_holmu1": { - "Tier": 2 - }, - "kz_iluvprok_global": { - "Tier": 2 - }, - "kz_j2s_cupblock_fix2": { - "Tier": 2 - }, - "kz_j2s_tetris": { - "Tier": 2 - }, - "kz_johndoe": { - "Tier": 2 - }, - "kz_jump_n_run": { - "Tier": 2 - }, - "kz_kiwionerous": { - "Tier": 2 - }, - "kz_kiwitown": { - "Tier": 2 - }, - "kz_kohze_sucks": { - "Tier": 2 - }, - "kz_kzra_cliffy": { - "Tier": 2 - }, - "kz_kzra_fustcaves": { - "Tier": 2 - }, - "kz_kzra_greycliff": { - "Tier": 2 - }, - "kz_kzra_stonebhop": { - "Tier": 2 - }, - "kz_kzra_stoneishbhop": { - "Tier": 2 - }, - "kz_kzra_undercastle": { - "Tier": 2 - }, - "kz_kzro_basalt": { - "Tier": 2 - }, - "kz_kzro_brickstgrass_v2": { - "Tier": 2 - }, - "kz_kzro_bronea": { - "Tier": 2 - }, - "kz_kzro_cavernste_v2": { - "Tier": 2 - }, - "kz_kzro_cryscosrun": { - "Tier": 2 - }, - "kz_kzro_excitedbhop": { - "Tier": 2 - }, - "kz_kzro_gohome": { - "Tier": 2 - }, - "kz_kzro_greybrickbhop": { - "Tier": 2 - }, - "kz_kzro_jaashs": { - "Tier": 2 - }, - "kz_kzro_mountainbhop": { - "Tier": 2 - }, - "kz_kzro_mountainhaya": { - "Tier": 2 - }, - "kz_kzro_mountainsein": { - "Tier": 2 - }, - "kz_kzro_mountainsnow": { - "Tier": 2 - }, - "kz_kzro_sunmountainset": { - "Tier": 2 - }, - "kz_kzro_whiterock": { - "Tier": 2 - }, - "kz_kzse_aztectemple": { - "Tier": 2 - }, - "kz_lazy": { - "Tier": 2 - }, - "kz_lego": { - "Tier": 2 - }, - "kz_levels": { - "Tier": 2 - }, - "kz_lookout": { - "Tier": 2 - }, - "kz_machinery": { - "Tier": 2 - }, - "kz_matilda_np": { - "Tier": 2 - }, - "kz_memento": { - "Tier": 2 - }, - "kz_metalrun_global": { - "Tier": 2 - }, - "kz_mike_v4": { - "Tier": 2 - }, - "kz_minimalism": { - "Tier": 2 - }, - "kz_minimal_combo": { - "Tier": 2 - }, - "kz_moorerutan": { - "Tier": 2 - }, - "kz_msp_comatose": { - "Tier": 2 - }, - "kz_nassau": { - "Tier": 2 - }, - "kz_nb_final": { - "Tier": 2 - }, - "kz_nuclear": { - "Tier": 2 - }, - "kz_oldstuff": { - "Tier": 2 - }, - "kz_ominous2": { - "Tier": 2 - }, - "kz_overjoyed": { - "Tier": 2 - }, - "kz_paintball_tv_fix": { - "Tier": 2 - }, - "kz_paradise": { - "Tier": 2 - }, - "kz_peak_global": { - "Tier": 2 - }, - "kz_perfunctory": { - "Tier": 2 - }, - "kz_perf_darkcave": { - "Tier": 2 - }, - "kz_pharaoh": { - "Tier": 2 - }, - "kz_pianoclimb": { - "Tier": 2 - }, - "kz_plains": { - "Tier": 2 - }, - "kz_portal_fix": { - "Tier": 2 - }, - "kz_prima": { - "Tier": 2 - }, - "kz_prismus": { - "Tier": 2 - }, - "kz_project": { - "Tier": 2 - }, - "kz_psyk": { - "Tier": 2 - }, - "kz_psytime": { - "Tier": 2 - }, - "kz_quick7_v2": { - "Tier": 2 - }, - "kz_quicksand": { - "Tier": 2 - }, - "kz_rcn_impermanence": { - "Tier": 2 - }, - "kz_redemption": { - "Tier": 2 - }, - "kz_refract": { - "Tier": 2 - }, - "kz_remedy_v2": { - "Tier": 2 - }, - "kz_retreat": { - "Tier": 2 - }, - "kz_rockclimb": { - "Tier": 2 - }, - "kz_rumzor": { - "Tier": 2 - }, - "kz_serenity": { - "Tier": 2 - }, - "kz_shaft_fix": { - "Tier": 2 - }, - "kz_signs_v2": { - "Tier": 2 - }, - "kz_skyhotel": { - "Tier": 2 - }, - "kz_skytower": { - "Tier": 2 - }, - "kz_slumpfrageous": { - "Tier": 2 - }, - "kz_snowman_v2": { - "Tier": 2 - }, - "kz_sonder": { - "Tier": 2 - }, - "kz_sp1_aoirobhop": { - "Tier": 2 - }, - "kz_sp1_blueconcrete": { - "Tier": 2 - }, - "kz_sp1_candles": { - "Tier": 2 - }, - "kz_sp1_castaway": { - "Tier": 2 - }, - "kz_sp1_greyconcrete": { - "Tier": 2 - }, - "kz_sp1_inverseblocks": { - "Tier": 2 - }, - "kz_sp1_perf2win": { - "Tier": 2 - }, - "kz_sp1_redbrickbhop": { - "Tier": 2 - }, - "kz_sp1_redconcrete": { - "Tier": 2 - }, - "kz_sp1_siedlungclimb": { - "Tier": 2 - }, - "kz_sp1_whiteblocks": { - "Tier": 2 - }, - "kz_spaceladders_v2": { - "Tier": 2 - }, - "kz_spire": { - "Tier": 2 - }, - "kz_splifff": { - "Tier": 2 - }, - "kz_splopkopsc_loverick": { - "Tier": 2 - }, - "kz_sqrdsucks": { - "Tier": 2 - }, - "kz_streetblock": { - "Tier": 2 - }, - "kz_stuff_final": { - "Tier": 2 - }, - "kz_symmetry": { - "Tier": 2 - }, - "kz_thinkblock": { - "Tier": 2 - }, - "kz_toonadventure": { - "Tier": 2 - }, - "kz_toonrun_final": { - "Tier": 2 - }, - "kz_toughluck_fix": { - "Tier": 2 - }, - "kz_tour_de_nuke_rt": { - "Tier": 2 - }, - "kz_twiivo": { - "Tier": 2 - }, - "kz_unity_u01": { - "Tier": 2 - }, - "kz_unknownspace": { - "Tier": 2 - }, - "kz_vci_apprentice": { - "Tier": 2 - }, - "kz_warehouse": { - "Tier": 2 - }, - "kz_wasabi": { - "Tier": 2 - }, - "kz_weebfactory_censored": { - "Tier": 2 - }, - "kz_weightless": { - "Tier": 2 - }, - "kz_wetbricks": { - "Tier": 2 - }, - "kz_whereyoufrom": { - "Tier": 2 - }, - "kz_woodstonegrass_final": { - "Tier": 2 - }, - "kz_woodworld": { - "Tier": 2 - }, - "kz_xmas2020": { - "Tier": 2 - }, - "kz_xtremeblock_v2": { - "Tier": 2 - }, - "xc_lucid_global": { - "Tier": 2 - }, - "xc_minecraft3_global": { - "Tier": 2 - }, - "xc_minecraft4": { - "Tier": 2 - }, - "xc_powerblock_rc1": { - "Tier": 2 - }, - "xc_skycastle": { - "Tier": 2 - }, - "xc_supermario_gfix": { - "Tier": 2 - }, - "kz_kzro_wallblocks": { - "Tier": 2 - }, - "kz_sp1_greyhollowrock": { - "Tier": 2 - }, - "kz_sp1_kansopyon": { - "Tier": 2 - }, - "kz_sp1_parallelblocks": { - "Tier": 2 - }, - "kz_sp1_rockcanyonblocks": { - "Tier": 2 - }, - "kz_sunstone": { - "Tier": 2 - }, - "bkz_greed": { - "Tier": 2 - }, - "kz_lust": { - "Tier": 2 - }, - "kz_moorish": { - "Tier": 2 - }, - "kz_opus": { - "Tier": 2 - }, - "kz_souljaboy": { - "Tier": 2 - }, - "kz_communityblock": { - "Tier": 2 - }, - "kz_comp_2022": { - "Tier": 2 - }, - "kz_sp1_shouryokou": { - "Tier": 2 - }, - "kz_sp1_spreadblocks": { - "Tier": 2 - }, - "kz_sp1_uchuunookuheki": { - "Tier": 2 - }, - "kz_victoria": { - "Tier": 2 - }, - "bkz_canadaszn": { - "Tier": 2 - }, - "kz_bing": { - "Tier": 2 - }, - "kz_greyorgray": { - "Tier": 2 - }, - "kz_cajou": { - "Tier": 2 - }, - "kz_tranquillity": { - "Tier": 2 - }, - "kz_delirium": { - "Tier": 2 - }, - "kz_devon": { - "Tier": 2 - }, - "kz_cf_snakeskin": { - "Tier": 2 - }, - "kz_glow": { - "Tier": 2 - }, - "kz_xmas2022": { - "Tier": 2 - }, - "kz_igneous": { - "Tier": 2 - }, - "kz_acores": { - "Tier": 2 - }, - "kz_desolate": { - "Tier": 2 - }, - "kz_silk": { - "Tier": 2 - }, - "kz_ehcivec": { - "Tier": 2 - }, - "kz_eilrahc": { - "Tier": 2 - }, - "kz_frenzy": { - "Tier": 2 - }, - "kz_hypothermia": { - "Tier": 2 - }, - "kz_kogamaostry": { - "Tier": 2 - }, - "kz_tmnf_e05": { - "Tier": 2 - }, - "vnl_ll_nuke": { - "Tier": 2 - }, - "kz_cakewalk": { - "Tier": 3 - }, - "kz_dontstop": { - "Tier": 3 - }, - "kz_fapzor": { - "Tier": 3 - }, - "kz_pogo": { - "Tier": 3 - }, - "kz_sahara": { - "Tier": 3 - }, - "kz_uninspired_trash": { - "Tier": 3 - }, - "kz_zephyr_v2": { - "Tier": 3 - }, - "kzpro_justrun_sp": { - "Tier": 3 - }, - "kz_21loop_final_fix": { - "Tier": 3 - }, - "kz_2fast": { - "Tier": 3 - }, - "kz_2seasons_spring_final": { - "Tier": 3 - }, - "kz_abandoned": { - "Tier": 3 - }, - "kz_adv_cursedjourney": { - "Tier": 3 - }, - "kz_ahful": { - "Tier": 3 - }, - "kz_alice_fix": { - "Tier": 3 - }, - "kz_allure": { - "Tier": 3 - }, - "kz_amber_od": { - "Tier": 3 - }, - "kz_arbitrary_words": { - "Tier": 3 - }, - "kz_arcadium": { - "Tier": 3 - }, - "kz_arcturus": { - "Tier": 3 - }, - "kz_arrebol": { - "Tier": 3 - }, - "kz_athena": { - "Tier": 3 - }, - "kz_autumn_valley_fix": { - "Tier": 3 - }, - "kz_bacho": { - "Tier": 3 - }, - "kz_basics_b02": { - "Tier": 3 - }, - "kz_beyond_fix": { - "Tier": 3 - }, - "kz_bhop_mosaic_od2": { - "Tier": 3 - }, - "kz_bhop_sakura": { - "Tier": 3 - }, - "kz_bible_black": { - "Tier": 3 - }, - "kz_bigcastle": { - "Tier": 3 - }, - "kz_binseebak": { - "Tier": 3 - }, - "kz_bionic": { - "Tier": 3 - }, - "kz_blatherskite_v1": { - "Tier": 3 - }, - "kz_blindcity_easy_fix": { - "Tier": 3 - }, - "kz_blockhardy2k": { - "Tier": 3 - }, - "kz_bloodline": { - "Tier": 3 - }, - "kz_bombu": { - "Tier": 3 - }, - "kz_bored": { - "Tier": 3 - }, - "kz_buildings_final": { - "Tier": 3 - }, - "kz_burnished": { - "Tier": 3 - }, - "kz_byrem": { - "Tier": 3 - }, - "kz_camembert": { - "Tier": 3 - }, - "kz_cascade_v4": { - "Tier": 3 - }, - "kz_cataclysm": { - "Tier": 3 - }, - "kz_catalyst_gfix": { - "Tier": 3 - }, - "kz_celestial": { - "Tier": 3 - }, - "kz_cereal": { - "Tier": 3 - }, - "kz_cg_brick_rmk": { - "Tier": 3 - }, - "kz_cg_lighthops": { - "Tier": 3 - }, - "kz_chinablock": { - "Tier": 3 - }, - "kz_coastline_fix": { - "Tier": 3 - }, - "kz_colorcode": { - "Tier": 3 - }, - "kz_colors_v2": { - "Tier": 3 - }, - "kz_concept": { - "Tier": 3 - }, - "kz_conrun_scrub": { - "Tier": 3 - }, - "kz_conspiracy": { - "Tier": 3 - }, - "kz_coronado_fix": { - "Tier": 3 - }, - "kz_correguachin_reisido": { - "Tier": 3 - }, - "kz_crash_fix": { - "Tier": 3 - }, - "kz_crypt_final": { - "Tier": 3 - }, - "kz_crysis": { - "Tier": 3 - }, - "kz_cyb_adrenaline_fix": { - "Tier": 3 - }, - "kz_dank_stacks": { - "Tier": 3 - }, - "kz_date2": { - "Tier": 3 - }, - "kz_default": { - "Tier": 3 - }, - "kz_dejavu": { - "Tier": 3 - }, - "kz_depot": { - "Tier": 3 - }, - "kz_diajonal": { - "Tier": 3 - }, - "kz_district_d01": { - "Tier": 3 - }, - "kz_drops_od": { - "Tier": 3 - }, - "kz_duality_v2": { - "Tier": 3 - }, - "kz_dust": { - "Tier": 3 - }, - "kz_dzy_reach_v2": { - "Tier": 3 - }, - "kz_edifice": { - "Tier": 3 - }, - "kz_egyptianbox": { - "Tier": 3 - }, - "kz_emptiness": { - "Tier": 3 - }, - "kz_erinome": { - "Tier": 3 - }, - "kz_excape": { - "Tier": 3 - }, - "kz_exemplum_fix": { - "Tier": 3 - }, - "kz_exps_cursedjourney": { - "Tier": 3 - }, - "kz_farm_v2": { - "Tier": 3 - }, - "kz_fastcombomap": { - "Tier": 3 - }, - "kz_fastcombowombo_v2": { - "Tier": 3 - }, - "kz_forchi": { - "Tier": 3 - }, - "kz_fused": { - "Tier": 3 - }, - "kz_futureblock": { - "Tier": 3 - }, - "kz_gallus": { - "Tier": 3 - }, - "kz_comboking7k": { - "Tier": 3 - }, - "kz_goldentabby": { - "Tier": 3 - }, - "kz_gonbe": { - "Tier": 3 - }, - "kz_green": { - "Tier": 3 - }, - "kz_halicarnassus_fs": { - "Tier": 3 - }, - "kz_hammer": { - "Tier": 3 - }, - "kz_hb_smieszneznaczki": { - "Tier": 3 - }, - "kz_heatvents_mq": { - "Tier": 3 - }, - "kz_hek": { - "Tier": 3 - }, - "kz_hellinashop": { - "Tier": 3 - }, - "kz_hikari_od": { - "Tier": 3 - }, - "kz_holyspace": { - "Tier": 3 - }, - "kz_how2slide_fix": { - "Tier": 3 - }, - "kz_hydromancy": { - "Tier": 3 - }, - "kz_ickkck": { - "Tier": 3 - }, - "kz_illusion_gfix": { - "Tier": 3 - }, - "kz_innit": { - "Tier": 3 - }, - "kz_island": { - "Tier": 3 - }, - "kz_itz_transcendent": { - "Tier": 3 - }, - "kz_jg_ditch": { - "Tier": 3 - }, - "kz_kat_colorblind": { - "Tier": 3 - }, - "kz_kzinga_fixed": { - "Tier": 3 - }, - "kz_kzra_bars": { - "Tier": 3 - }, - "kz_kzra_coast": { - "Tier": 3 - }, - "kz_kzra_hohum": { - "Tier": 3 - }, - "kz_kzra_morath": { - "Tier": 3 - }, - "kz_kzra_rockloy": { - "Tier": 3 - }, - "kz_kzra_rocky": { - "Tier": 3 - }, - "kz_kzra_skaxis": { - "Tier": 3 - }, - "kz_kzra_voovblock": { - "Tier": 3 - }, - "kz_kzra_whitesquare": { - "Tier": 3 - }, - "kz_kzro_cavehole": { - "Tier": 3 - }, - "kz_kzro_sekiseibhop": { - "Tier": 3 - }, - "kz_kzro_slidesmear": { - "Tier": 3 - }, - "kz_lair": { - "Tier": 3 - }, - "kz_lavablock_global": { - "Tier": 3 - }, - "kz_legoland": { - "Tier": 3 - }, - "kz_lego_two_redux_v3": { - "Tier": 3 - }, - "kz_life_final": { - "Tier": 3 - }, - "kz_linoleum": { - "Tier": 3 - }, - "kz_loftroofs": { - "Tier": 3 - }, - "kz_longjumps_easy": { - "Tier": 3 - }, - "kz_lost_marketplace_gfix": { - "Tier": 3 - }, - "kz_magus": { - "Tier": 3 - }, - "kz_megalodon": { - "Tier": 3 - }, - "kz_microwave": { - "Tier": 3 - }, - "kz_milehigh": { - "Tier": 3 - }, - "kz_moonlight": { - "Tier": 3 - }, - "kz_morestairs_msq": { - "Tier": 3 - }, - "kz_motivated": { - "Tier": 3 - }, - "kz_nightfall": { - "Tier": 3 - }, - "kz_nightmare_v2": { - "Tier": 3 - }, - "kz_nyc_v1": { - "Tier": 3 - }, - "kz_oasis": { - "Tier": 3 - }, - "kz_olympus": { - "Tier": 3 - }, - "kz_openspace": { - "Tier": 3 - }, - "kz_orangejuice_v2": { - "Tier": 3 - }, - "kz_orbolution_v2": { - "Tier": 3 - }, - "kz_otakuroom": { - "Tier": 3 - }, - "kz_overgrowth": { - "Tier": 3 - }, - "kz_persona_is_a_dictator": { - "Tier": 3 - }, - "kz_pineforest_v2": { - "Tier": 3 - }, - "kz_pixelrun_v2": { - "Tier": 3 - }, - "kz_pollution": { - "Tier": 3 - }, - "kz_porridge": { - "Tier": 3 - }, - "kz_prekeeper": { - "Tier": 3 - }, - "kz_progressive": { - "Tier": 3 - }, - "kz_quadrablock": { - "Tier": 3 - }, - "kz_quadrant_fix": { - "Tier": 3 - }, - "kz_quixotic": { - "Tier": 3 - }, - "kz_railings": { - "Tier": 3 - }, - "kz_rcn_optimisery": { - "Tier": 3 - }, - "kz_reach_v2": { - "Tier": 3 - }, - "kz_refuge": { - "Tier": 3 - }, - "kz_research": { - "Tier": 3 - }, - "kz_rise": { - "Tier": 3 - }, - "kz_rockjungle_v2": { - "Tier": 3 - }, - "kz_roman": { - "Tier": 3 - }, - "kz_sandstorm_ez": { - "Tier": 3 - }, - "kz_sandyhill_hoc": { - "Tier": 3 - }, - "kz_shortcut_tx": { - "Tier": 3 - }, - "kz_skybridge": { - "Tier": 3 - }, - "kz_slate": { - "Tier": 3 - }, - "kz_slide_kissa": { - "Tier": 3 - }, - "kz_slide_koira": { - "Tier": 3 - }, - "kz_slide_or_dont": { - "Tier": 3 - }, - "kz_slide_pallokala": { - "Tier": 3 - }, - "kz_smallcastle": { - "Tier": 3 - }, - "kz_smallmap": { - "Tier": 3 - }, - "kz_sn_desert": { - "Tier": 3 - }, - "kz_solidarity_v2": { - "Tier": 3 - }, - "kz_sp1_behold": { - "Tier": 3 - }, - "kz_sp1_driedblocks": { - "Tier": 3 - }, - "kz_sp1_greenconcrete": { - "Tier": 3 - }, - "kz_sp1_hallwaybhop": { - "Tier": 3 - }, - "kz_sp1_purpose": { - "Tier": 3 - }, - "kz_spacus": { - "Tier": 3 - }, - "kz_stepblock": { - "Tier": 3 - }, - "kz_stepup": { - "Tier": 3 - }, - "kz_structures": { - "Tier": 3 - }, - "kz_strun_mq": { - "Tier": 3 - }, - "kz_superstructure": { - "Tier": 3 - }, - "kz_surf_ace": { - "Tier": 3 - }, - "kz_symbiosis_final": { - "Tier": 3 - }, - "kz_synergy_ez": { - "Tier": 3 - }, - "kz_synthesis_v2": { - "Tier": 3 - }, - "kz_sz_goldenbean": { - "Tier": 3 - }, - "kz_talltreeforest_v3": { - "Tier": 3 - }, - "kz_talmaniac": { - "Tier": 3 - }, - "kz_timescape_zero": { - "Tier": 3 - }, - "kz_tron_global": { - "Tier": 3 - }, - "kz_twilight_od": { - "Tier": 3 - }, - "kz_twister": { - "Tier": 3 - }, - "kz_unity_collab": { - "Tier": 3 - }, - "kz_verv3_gg": { - "Tier": 3 - }, - "kz_village": { - "Tier": 3 - }, - "kz_vittu_mika_persse": { - "Tier": 3 - }, - "kz_void": { - "Tier": 3 - }, - "kz_waterhole": { - "Tier": 3 - }, - "kz_whatever_v2": { - "Tier": 3 - }, - "kz_yes": { - "Tier": 3 - }, - "kz_zhop_son_fix": { - "Tier": 3 - }, - "kz_zxp_interstellar_v2": { - "Tier": 3 - }, - "vnl_slidegarden": { - "Tier": 3 - }, - "vnl_undefined": { - "Tier": 3 - }, - "xc_alt_nephilim": { - "Tier": 3 - }, - "xc_dreamland2": { - "Tier": 3 - }, - "xc_fox_shrine_japan_fr": { - "Tier": 3 - }, - "xc_karo4": { - "Tier": 3 - }, - "xc_minecraft2_global": { - "Tier": 3 - }, - "xc_nephilim": { - "Tier": 3 - }, - "xc_secret_valley_global_fix": { - "Tier": 3 - }, - "xc_umbrella_global": { - "Tier": 3 - }, - "kz_sp1_xmas2021": { - "Tier": 3 - }, - "kz_kzro_tamlair": { - "Tier": 3 - }, - "kz_maya": { - "Tier": 3 - }, - "kz_sp1_rengapyon": { - "Tier": 3 - }, - "skz_pride": { - "Tier": 3 - }, - "kz_invision": { - "Tier": 3 - }, - "kz_tq": { - "Tier": 3 - }, - "kz_difficultas_discendi": { - "Tier": 3 - }, - "kz_nebula": { - "Tier": 3 - }, - "kz_chillin": { - "Tier": 3 - }, - "kz_slide_bozo": { - "Tier": 3 - }, - "kz_bhop_proxy_null": { - "Tier": 3 - }, - "kz_slide_leto": { - "Tier": 3 - }, - "kz_lovesick": { - "Tier": 3 - }, - "kz_vnl_crimdaughter": { - "Tier": 3 - }, - "kz_hideous": { - "Tier": 3 - }, - "kz_vnl_crimstmas": { - "Tier": 3 - }, - "kz_cf_slide": { - "Tier": 3 - }, - "kz_tangent": { - "Tier": 3 - }, - "kz_cf_hestia": { - "Tier": 3 - }, - "kz_mediumcastle": { - "Tier": 3 - }, - "kz_pamehcilc": { - "Tier": 3 - }, - "kz_prefix_cliche": { - "Tier": 3 - }, - "vnl_lea": { - "Tier": 3 - }, - "bkz_cauz_short": { - "Tier": 4 - }, - "bkz_evanstep": { - "Tier": 4 - }, - "bkz_iota_v3": { - "Tier": 4 - }, - "kzpro_concrete_c02": { - "Tier": 4 - }, - "kz_2seasons_winter_final": { - "Tier": 4 - }, - "kz_aaaa": { - "Tier": 4 - }, - "kz_abstruse_od2": { - "Tier": 4 - }, - "kz_andromeda": { - "Tier": 4 - }, - "kz_another_climb_map": { - "Tier": 4 - }, - "kz_antimony": { - "Tier": 4 - }, - "kz_ascend_hv": { - "Tier": 4 - }, - "kz_atelectasis_sct": { - "Tier": 4 - }, - "kz_atlantis_od3": { - "Tier": 4 - }, - "kz_azure": { - "Tier": 4 - }, - "kz_banjo": { - "Tier": 4 - }, - "kz_betapmaps": { - "Tier": 4 - }, - "kz_bhop_badges3": { - "Tier": 4 - }, - "kz_bhop_benchmark": { - "Tier": 4 - }, - "kz_bhop_composure_f": { - "Tier": 4 - }, - "kz_bhop_dusk": { - "Tier": 4 - }, - "kz_bhop_essence": { - "Tier": 4 - }, - "kz_bhop_lucid": { - "Tier": 4 - }, - "kz_bhop_northface": { - "Tier": 4 - }, - "kz_bhop_nothing": { - "Tier": 4 - }, - "kz_bhop_rotebal3": { - "Tier": 4 - }, - "kz_bhop_skyworld": { - "Tier": 4 - }, - "kz_bhop_zenith": { - "Tier": 4 - }, - "kz_birrita_fix": { - "Tier": 4 - }, - "kz_blindcity_hard_final": { - "Tier": 4 - }, - "kz_bluehop_mq": { - "Tier": 4 - }, - "kz_bluuu": { - "Tier": 4 - }, - "kz_bounce": { - "Tier": 4 - }, - "kz_cabin_fix": { - "Tier": 4 - }, - "kz_carbon": { - "Tier": 4 - }, - "kz_cdr_rustenborg": { - "Tier": 4 - }, - "kz_cdr_slash_final": { - "Tier": 4 - }, - "kz_chopchop": { - "Tier": 4 - }, - "kz_citadel": { - "Tier": 4 - }, - "kz_civilizations": { - "Tier": 4 - }, - "kz_communityjump3": { - "Tier": 4 - }, - "kz_conrun_mq": { - "Tier": 4 - }, - "kz_divided": { - "Tier": 4 - }, - "kz_dontjump": { - "Tier": 4 - }, - "kz_dyd_ladderjumps": { - "Tier": 4 - }, - "kz_epiphany_v2": { - "Tier": 4 - }, - "kz_eudora": { - "Tier": 4 - }, - "kz_eventide": { - "Tier": 4 - }, - "kz_everything": { - "Tier": 4 - }, - "kz_evilcorp": { - "Tier": 4 - }, - "kz_flabbergast": { - "Tier": 4 - }, - "kz_forgotten": { - "Tier": 4 - }, - "kz_free_ahful": { - "Tier": 4 - }, - "kz_f_salted_banana": { - "Tier": 4 - }, - "kz_shark_gc": { - "Tier": 4 - }, - "kz_gfy_blueberry": { - "Tier": 4 - }, - "kz_gfy_devcastle": { - "Tier": 4 - }, - "kz_gfy_final": { - "Tier": 4 - }, - "kz_gfy_fortroca": { - "Tier": 4 - }, - "kz_gfy_strawberry_": { - "Tier": 4 - }, - "kz_gfy_tech": { - "Tier": 4 - }, - "kz_gitgud_final": { - "Tier": 4 - }, - "kz_gloom": { - "Tier": 4 - }, - "kz_gobbledygook": { - "Tier": 4 - }, - "kz_goodluck_p": { - "Tier": 4 - }, - "kz_grass_hard": { - "Tier": 4 - }, - "kz_gy_agitation": { - "Tier": 4 - }, - "kz_haste": { - "Tier": 4 - }, - "kz_hb_lowlita": { - "Tier": 4 - }, - "kz_hb_lrs": { - "Tier": 4 - }, - "kz_headbongo": { - "Tier": 4 - }, - "kz_heaven_od": { - "Tier": 4 - }, - "kz_insomnia_fix": { - "Tier": 4 - }, - "kz_inspired": { - "Tier": 4 - }, - "kz_internatus": { - "Tier": 4 - }, - "kz_kiwi_lars": { - "Tier": 4 - }, - "kz_kzra_slidely": { - "Tier": 4 - }, - "kz_kzra_slidepuf": { - "Tier": 4 - }, - "kz_kzro_chairs": { - "Tier": 4 - }, - "kz_ladderall": { - "Tier": 4 - }, - "kz_ladderhell_fix": { - "Tier": 4 - }, - "kz_lastwork_p1": { - "Tier": 4 - }, - "kz_loathe": { - "Tier": 4 - }, - "kz_longjumps_space": { - "Tier": 4 - }, - "kz_lume": { - "Tier": 4 - }, - "kz_luv_less": { - "Tier": 4 - }, - "kz_malignom_short": { - "Tier": 4 - }, - "kz_mandelbrot": { - "Tier": 4 - }, - "kz_meander": { - "Tier": 4 - }, - "kz_mescaline_f": { - "Tier": 4 - }, - "kz_module": { - "Tier": 4 - }, - "kz_mushrruption_v8": { - "Tier": 4 - }, - "kz_neon_portal": { - "Tier": 4 - }, - "kz_nieh": { - "Tier": 4 - }, - "kz_nightcastle": { - "Tier": 4 - }, - "kz_nymph": { - "Tier": 4 - }, - "kz_pamxul_wip": { - "Tier": 4 - }, - "kz_pantheism_p02": { - "Tier": 4 - }, - "kz_prototype": { - "Tier": 4 - }, - "kz_rectangle": { - "Tier": 4 - }, - "kz_return": { - "Tier": 4 - }, - "kz_reverse": { - "Tier": 4 - }, - "kz_rompenutrias_asheglado": { - "Tier": 4 - }, - "kz_rush2sk8": { - "Tier": 4 - }, - "kz_scum": { - "Tier": 4 - }, - "kz_sendhelp_final": { - "Tier": 4 - }, - "kz_simplejourney": { - "Tier": 4 - }, - "kz_sky_lake": { - "Tier": 4 - }, - "kz_slide_0x7_n1m0": { - "Tier": 4 - }, - "kz_slide_concrete": { - "Tier": 4 - }, - "kz_slide_dydanhomon": { - "Tier": 4 - }, - "kz_slide_pisauva": { - "Tier": 4 - }, - "kz_slide_svn_temple": { - "Tier": 4 - }, - "kz_slide_vaahtera": { - "Tier": 4 - }, - "kz_south": { - "Tier": 4 - }, - "kz_sp1_hiragana": { - "Tier": 4 - }, - "kz_stranded": { - "Tier": 4 - }, - "kz_suomi": { - "Tier": 4 - }, - "kz_surf_blue": { - "Tier": 4 - }, - "kz_surf_kim_hana_gl": { - "Tier": 4 - }, - "kz_swamped_v3": { - "Tier": 4 - }, - "kz_theaquila": { - "Tier": 4 - }, - "kz_trashsurf": { - "Tier": 4 - }, - "kz_trazodon_fix": { - "Tier": 4 - }, - "kz_tribute": { - "Tier": 4 - }, - "kz_variety_fix": { - "Tier": 4 - }, - "kz_why": { - "Tier": 4 - }, - "kz_yanse": { - "Tier": 4 - }, - "kz_yoink": { - "Tier": 4 - }, - "kz_zhop_freestyle": { - "Tier": 4 - }, - "kz_zhop_function3": { - "Tier": 4 - }, - "kz_ziggurath_final": { - "Tier": 4 - }, - "kz_zoomer_fix": { - "Tier": 4 - }, - "kz_zxp_final4": { - "Tier": 4 - }, - "kz_zxp_undia": { - "Tier": 4 - }, - "vnl_cat": { - "Tier": 4 - }, - "vnl_invasion": { - "Tier": 4 - }, - "kz_winterize": { - "Tier": 4 - }, - "kz_envy": { - "Tier": 4 - }, - "kz_gluttony": { - "Tier": 4 - }, - "kz_question": { - "Tier": 4 - }, - "kz_slide_cave": { - "Tier": 4 - }, - "kz_xiaobitu": { - "Tier": 4 - }, - "kz_bhop_horseshit_9": { - "Tier": 4 - }, - "kz_demonhours": { - "Tier": 4 - }, - "kz_slide_piss": { - "Tier": 4 - }, - "kz_nomibo": { - "Tier": 4 - }, - "kz_vnl_crimson": { - "Tier": 4 - }, - "kz_itz_updown": { - "Tier": 4 - }, - "kz_sxb_poi": { - "Tier": 4 - }, - "kz_bhop_exodus": { - "Tier": 4 - }, - "kz_euclide_illusionary": { - "Tier": 4 - }, - "kz_sp1_saishuu": { - "Tier": 4 - }, - "kz_vnl_crimdaddy": { - "Tier": 4 - }, - "vnl_caverun": { - "Tier": 4 - }, - "bkz_apricity_v3": { - "Tier": 5 - }, - "bkz_fear4": { - "Tier": 5 - }, - "bkz_underground_crypt_v3": { - "Tier": 5 - }, - "kzpro_gull_pidr_reborn": { - "Tier": 5 - }, - "kz_aether_fix": { - "Tier": 5 - }, - "kz_alfie": { - "Tier": 5 - }, - "kz_alpha": { - "Tier": 5 - }, - "kz_altum_od": { - "Tier": 5 - }, - "kz_antharas": { - "Tier": 5 - }, - "kz_armored_core": { - "Tier": 5 - }, - "kz_avoria": { - "Tier": 5 - }, - "kz_backwards": { - "Tier": 5 - }, - "kz_bananaysoda_v2": { - "Tier": 5 - }, - "kz_bhop_badges2": { - "Tier": 5 - }, - "kz_carpet": { - "Tier": 5 - }, - "kz_choka_fix": { - "Tier": 5 - }, - "kz_custos": { - "Tier": 5 - }, - "kz_dethroned": { - "Tier": 5 - }, - "kz_failed_fastrun_rt": { - "Tier": 5 - }, - "kz_hb_fafnir": { - "Tier": 5 - }, - "kz_high_socks": { - "Tier": 5 - }, - "kz_hitech": { - "Tier": 5 - }, - "kz_imaginary_final": { - "Tier": 5 - }, - "kz_kiwitech": { - "Tier": 5 - }, - "kz_kzro_hexonay": { - "Tier": 5 - }, - "kz_kzro_mountainroad": { - "Tier": 5 - }, - "kz_ladderdespair": { - "Tier": 5 - }, - "kz_list_gnida_v2": { - "Tier": 5 - }, - "kz_lovely": { - "Tier": 5 - }, - "kz_modernvomit": { - "Tier": 5 - }, - "kz_nix_od": { - "Tier": 5 - }, - "kz_noobfort": { - "Tier": 5 - }, - "kz_okaychamp": { - "Tier": 5 - }, - "kz_simple_sp": { - "Tier": 5 - }, - "kz_slide_isnt_kz": { - "Tier": 5 - }, - "kz_slide_purple_x": { - "Tier": 5 - }, - "kz_slide_rovod": { - "Tier": 5 - }, - "kz_sp1_icecave": { - "Tier": 5 - }, - "kz_sp1_katakana": { - "Tier": 5 - }, - "kz_strafehop_fix": { - "Tier": 5 - }, - "kz_synergy_x": { - "Tier": 5 - }, - "kz_technical_difficulties": { - "Tier": 5 - }, - "kz_techtonic_v2_ldr": { - "Tier": 5 - }, - "skz_bananaysoda_2": { - "Tier": 5 - }, - "skz_sati": { - "Tier": 5 - }, - "skz_sequence_shot": { - "Tier": 5 - }, - "kz_sp1_vines": { - "Tier": 5 - }, - "kz_bhop_mentalism": { - "Tier": 5 - }, - "kz_dishonest": { - "Tier": 5 - }, - "kz_mess": { - "Tier": 5 - }, - "kz_sc_collapse": { - "Tier": 5 - }, - "kz_sc_surf": { - "Tier": 5 - }, - "kz_unnamed": { - "Tier": 5 - }, - "vnl_simplebrickrooms": { - "Tier": 5 - }, - "kz_bhop_algetic": { - "Tier": 5 - }, - "kz_sc_ruins": { - "Tier": 5 - }, - "kz_auuughh": { - "Tier": 5 - }, - "kz_gus_sct2": { - "Tier": 5 - }, - "kz_slide_wasteland": { - "Tier": 5 - }, - "kz_kiwiqualia": { - "Tier": 5 - }, - "kz_simplyhard": { - "Tier": 5 - }, - "kz_slide_era": { - "Tier": 5 - }, - "kz_hoist_fix": { - "Tier": 5 - }, - "kz_persona_is_a_furry": { - "Tier": 5 - }, - "kz_ggsh": { - "Tier": 5 - }, - "vnl_farewell_fix": { - "Tier": 5 - }, - "kz_sxb_biewan": { - "Tier": 5 - }, - "kz_hope": { - "Tier": 5 - }, - "kz_rlk": { - "Tier": 5 - }, - "kz_sxb_despacito": { - "Tier": 5 - }, - "kz_sxb_remake": { - "Tier": 5 - }, - "kzpro_psilocybin": { - "Tier": 6 - }, - "kz_afterlife": { - "Tier": 6 - }, - "kz_alien_city": { - "Tier": 6 - }, - "kz_angina_final": { - "Tier": 6 - }, - "kz_bhop_koki_niwa": { - "Tier": 6 - }, - "kz_blackness": { - "Tier": 6 - }, - "kz_chloroplast": { - "Tier": 6 - }, - "kz_continuum": { - "Tier": 6 - }, - "kz_drunkards": { - "Tier": 6 - }, - "kz_erratum_v2": { - "Tier": 6 - }, - "kz_gemischte_gefuehlslagen": { - "Tier": 6 - }, - "kz_goquicklol_v2": { - "Tier": 6 - }, - "kz_kareful": { - "Tier": 6 - }, - "kz_kiwi_cod": { - "Tier": 6 - }, - "kz_kzro_hardvalley": { - "Tier": 6 - }, - "kz_kzro_skyrocks": { - "Tier": 6 - }, - "kz_lionheart": { - "Tier": 6 - }, - "kz_mieszaneuczucia": { - "Tier": 6 - }, - "kz_neoncity_z": { - "Tier": 6 - }, - "kz_oloramasa": { - "Tier": 6 - }, - "kz_p1": { - "Tier": 6 - }, - "kz_pendulum": { - "Tier": 6 - }, - "kz_portalclimb": { - "Tier": 6 - }, - "kz_procrastination_f": { - "Tier": 6 - }, - "kz_psychosomatic": { - "Tier": 6 - }, - "kz_purgatory": { - "Tier": 6 - }, - "kz_retribution_v2_final": { - "Tier": 6 - }, - "kz_shell": { - "Tier": 6 - }, - "kz_slidebober": { - "Tier": 6 - }, - "kz_slidemap_fix": { - "Tier": 6 - }, - "kz_slide_deee": { - "Tier": 6 - }, - "kz_slide_svn_extreme": { - "Tier": 6 - }, - "kz_slowrun_global_fix": { - "Tier": 6 - }, - "kz_sp1_bloodyljs_v2": { - "Tier": 6 - }, - "kz_spacemario_h": { - "Tier": 6 - }, - "kz_surf_larry": { - "Tier": 6 - }, - "kz_zaloopazxc": { - "Tier": 6 - }, - "skz_makalaka": { - "Tier": 6 - }, - "skz_odious_v2": { - "Tier": 6 - }, - "vnl_oy_lj": { - "Tier": 6 - }, - "kz_bhop_slide": { - "Tier": 6 - }, - "kz_func_detail_v2": { - "Tier": 6 - }, - "kz_dabitu_fix2": { - "Tier": 6 - }, - "kz_d_decompile": { - "Tier": 6 - }, - "kz_rarkovosis": { - "Tier": 6 - }, - "kz_bozo": { - "Tier": 6 - }, - "kz_cthulhu": { - "Tier": 6 - }, - "kz_kukkojapallokidutus": { - "Tier": 6 - }, - "kz_lastwork_p2": { - "Tier": 6 - }, - "kz_scicret": { - "Tier": 6 - }, - "kz_wafflehouse_easy": { - "Tier": 6 - }, - "kz_kiwimind": { - "Tier": 6 - }, - "kz_ltt": { - "Tier": 6 - }, - "kz_mazemerized": { - "Tier": 6 - }, - "kz_slide_red": { - "Tier": 6 - }, - "kz_surf_abaddon": { - "Tier": 6 - }, - "kz_sxb_makabaka": { - "Tier": 6 - }, - "kz_sxb_xbcmzl": { - "Tier": 6 - }, - "kz_climb": { - "Tier": 6 - }, - "kz_divert": { - "Tier": 6 - }, - "kz_dystopia_h": { - "Tier": 6 - }, - "kz_hemochromatosis": { - "Tier": 6 - }, - "kz_maxine": { - "Tier": 6 - }, - "kz_monstrosity": { - "Tier": 6 - }, - "kz_nbdy_maps": { - "Tier": 6 - }, - "kz_thrombosis": { - "Tier": 6 - }, - "kz_zhongbitu": { - "Tier": 6 - }, - "kz_unmake": { - "Tier": 7 - }, - "kzpro_wrath": { - "Tier": 7 - }, - "kz_kiwideath": { - "Tier": 7 - }, - "kz_spacemario_xt": { - "Tier": 7 - }, - "kz_sp1_strafechampion": { - "Tier": 7 - }, - "kz_ladderhorror": { - "Tier": 7 - }, - "kz_slowerrun": { - "Tier": 7 - }, - "kz_wafflehouse_hard": { - "Tier": 7 - }, - "kz_kiwipsychosis": { - "Tier": 7 - }, - "vnl_sewers": { - "Tier": 7 - }, - "kz_kiwislide": { - "Tier": 7 - }, - "kz_w1_holiday": { - "Tier": 7 - }, - "kz_tense": { - "Tier": 7 - }, - "kz_cf_foliage": { - "Tier": 7 - }, - "kz_kiwiexophoric": { - "Tier": 7 - }, - "kz_kiwi_hym": { - "Tier": 7 - }, - "kz_sandbox": { - "Tier": 7 - }, - "kz_wafflehouse_x": { - "Tier": 7 - } -} diff --git a/src/API/SharpTimerAPI.cs b/src/API/SharpTimerAPI.cs new file mode 100644 index 00000000..9e6d2343 --- /dev/null +++ b/src/API/SharpTimerAPI.cs @@ -0,0 +1,80 @@ +using CounterStrikeSharp.API.Core; +using SharpTimerAPI.Events; +using SharpTimerAPI; + +namespace SharpTimer; + +public class SharpTimerAPI_Manager : ISharpTimerManager +{ + public void RestartTimer(CCSPlayerController player) + { + SharpTimer.Instance.RespawnPlayer(player); + } + + public bool IsTimerOn(CCSPlayerController player) + { + return !SharpTimer.Instance.playerTimers[player.Slot].IsTimerBlocked; + } + + public void ToggleTimer(CCSPlayerController player) + { + //should probably create a method that actually forces timer toggle. + //this one wont toggle if player is in command cd or is mid replay. + SharpTimer.Instance.ForceStopTimer(player, null!); + } + + public void BlockTimerCmd(CCSPlayerController player, bool block) + { + SharpTimer.Instance.playerTimers[player.Slot].TimerCmdBlocked = block; + } + + public void BlockRespawnCmd(CCSPlayerController player, bool block) + { + SharpTimer.Instance.playerTimers[player.Slot].RespawnCmdBlocked = block; + } +} + +public class SharpTimerAPI_EventSender : ISharpTimerEventSender +{ + public void TriggerEvent(ISharpTimerPlayerEvent @event) + { + STEventSender?.Invoke(this, @event); + } + + public event EventHandler? STEventSender; +} + +public class SharpTimerAPI_Database : ISharpTimerDatabase +{ + public async Task> GetSortedRecordsFromDatabase(int limit = 0, int bonusX = 0, string mapName = "", int style = 0) + { + var sortedRecords = await SharpTimer.Instance.GetSortedRecordsFromDatabase(limit, bonusX, mapName, style); + var mappedRecords = sortedRecords.ToDictionary( + kvp => kvp.Key, + kvp => new ISharpTimerDatabase.PlayerRecord + { + RecordID = kvp.Value.RecordID, + PlayerName = kvp.Value.PlayerName, + SteamID = kvp.Value.SteamID, + MapName = kvp.Value.MapName, + TimerTicks = kvp.Value.TimerTicks, + Replay = kvp.Value.Replay + }); + return mappedRecords; + } + + public async Task> GetAllSortedRecordsFromDatabase(int limit = 0, int bonusX = 0, int style = 0) + { + var sortedRecords = await SharpTimer.Instance.GetAllSortedRecordsFromDatabase(limit, bonusX, style); + var mappedRecords = sortedRecords.Select(record => new ISharpTimerDatabase.PlayerRecord + { + RecordID = record.RecordID, + PlayerName = record.PlayerName, + SteamID = record.SteamID, + MapName = record.MapName, + TimerTicks = record.TimerTicks, + Replay = record.Replay + }).ToList(); + return mappedRecords; + } +} diff --git a/src/API/TagsApi.dll b/src/API/TagsApi.dll new file mode 100644 index 00000000..ca9eccac Binary files /dev/null and b/src/API/TagsApi.dll differ diff --git a/src/Commands/ChatCommands.cs b/src/Commands/ChatCommands.cs index 722b53d0..93ecd210 100644 --- a/src/Commands/ChatCommands.cs +++ b/src/Commands/ChatCommands.cs @@ -21,55 +21,56 @@ You should have received a copy of the GNU General Public License using CounterStrikeSharp.API.Modules.Utils; using CounterStrikeSharp.API.Modules.Memory; using CounterStrikeSharp.API.Modules.Admin; +using FixVectorLeak; using SharpTimer.Mixins; namespace SharpTimer { public partial class SharpTimer { - [ConsoleCommand("css_dp_timers", "Prints playerTimers")] [CommandHelper(whoCanExecute: CommandUsage.SERVER_ONLY)] public void DeepPrintPlayerTimers(CCSPlayerController? player, CommandInfo command) { - SharpTimerConPrint("Printing Player Timers:"); + Utils.ConPrint("Printing Player Timers:"); foreach (var kvp in playerTimers) { - SharpTimerConPrint($"PlayerSlot: {kvp.Key}"); + Utils.ConPrint($"Player Slot: {kvp.Key}"); foreach (var prop in typeof(PlayerTimerInfo).GetProperties()) { var value = prop.GetValue(kvp.Value, null); - SharpTimerConPrint($" {prop.Name}: {value}"); + Utils.ConPrint($" {prop.Name}: {value}"); if (value is Dictionary intIntDictionary) { - SharpTimerConPrint($" {prop.Name}:"); + Utils.ConPrint($" {prop.Name}:"); foreach (var entry in intIntDictionary) { - SharpTimerConPrint($" {entry.Key}: {entry.Value}"); + Utils.ConPrint($" {entry.Key}: {entry.Value}"); } } else if (value is Dictionary intStringDictionary) { - SharpTimerConPrint($" {prop.Name}:"); + Utils.ConPrint($" {prop.Name}:"); foreach (var entry in intStringDictionary) { - SharpTimerConPrint($" {entry.Key}: {entry.Value}"); + Utils.ConPrint($" {entry.Key}: {entry.Value}"); } } } - SharpTimerConPrint(" "); + Utils.ConPrint(" "); } - SharpTimerConPrint("End of Player Timers"); + Utils.ConPrint("End of Player Timers"); } [ConsoleCommand("css_replaypb", "Replay your last pb")] [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] public void ReplaySelfCommand(CCSPlayerController? player, CommandInfo command) { - if (!IsAllowedPlayer(player) || enableReplays == false) return; + if (!IsAllowedPlayer(player) || enableReplays == false) + return; - var playerSlot = player!.Slot; + var slot = player!.Slot; var steamID = player.SteamID.ToString(); var playerName = player.PlayerName; @@ -81,7 +82,7 @@ public void ReplaySelfCommand(CCSPlayerController? player, CommandInfo command) if (ReplayCheck(player)) return; - _ = Task.Run(async () => await ReplayHandler(player, playerSlot, "self", steamID, playerName, 0, playerTimers[playerSlot].currentStyle)); + _ = Task.Run(async () => await ReplayHandler(player, slot, "self", steamID, playerName, 0, playerTimers[slot].currentStyle)); } [ConsoleCommand("css_replay", "Replay server map record")] @@ -89,11 +90,12 @@ public void ReplaySelfCommand(CCSPlayerController? player, CommandInfo command) [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] public void ReplaySRCommand(CCSPlayerController? player, CommandInfo command) { - if (!IsAllowedPlayer(player) || enableReplays == false) return; + if (!IsAllowedPlayer(player) || enableReplays == false) + return; - var playerSlot = player!.Slot; + int slot = player!.Slot; - QuietStopTimer(player); + QuietStopTimer(player!); if (IsTimerBlocked(player)) return; @@ -101,18 +103,19 @@ public void ReplaySRCommand(CCSPlayerController? player, CommandInfo command) if (ReplayCheck(player)) return; - PrintToChat(player, Localizer["available_replay_cmds"]); + Utils.PrintToChat(player, Localizer["available_replay_cmds"]); - _ = Task.Run(async () => await ReplayHandler(player, playerSlot, "1", "69", "unknown", 0, playerTimers[playerSlot].currentStyle)); + _ = Task.Run(async () => await ReplayHandler(player, slot, "1", "69", "unknown", 0, playerTimers[slot].currentStyle)); } [ConsoleCommand("css_replaytop", "Replay a top 10 server map record")] [CommandHelper(minArgs: 1, usage: "[1-10]", whoCanExecute: CommandUsage.CLIENT_ONLY)] public void ReplayTop10SRCommand(CCSPlayerController? player, CommandInfo command) { - if (!IsAllowedPlayer(player) || enableReplays == false) return; + if (!IsAllowedPlayer(player) || enableReplays == false) + return; - var playerSlot = player!.Slot; + int slot = player!.Slot; QuietStopTimer(player); @@ -124,16 +127,17 @@ public void ReplayTop10SRCommand(CCSPlayerController? player, CommandInfo comman string arg = command.ArgByIndex(1); - _ = Task.Run(async () => await ReplayHandler(player, playerSlot, arg, "69", "unknown", 0, playerTimers[playerSlot].currentStyle)); + _ = Task.Run(async () => await ReplayHandler(player, slot, arg, "69", "unknown", 0, playerTimers[slot].currentStyle)); } [ConsoleCommand("css_replaywr", "Replay a top 10 world record")] [CommandHelper(minArgs: 1, usage: "[1-10]", whoCanExecute: CommandUsage.CLIENT_ONLY)] public void ReplayTop10WRCommand(CCSPlayerController? player, CommandInfo command) { - if (!IsAllowedPlayer(player) || enableReplays == false) return; + if (!IsAllowedPlayer(player) || enableReplays == false) + return; - var playerSlot = player!.Slot; + int slot = player!.Slot; QuietStopTimer(player); @@ -145,54 +149,53 @@ public void ReplayTop10WRCommand(CCSPlayerController? player, CommandInfo comman string arg = command.ArgByIndex(1); - _ = Task.Run(async () => await ReplayHandler(player, playerSlot, arg, "69", "unknown", 0, playerTimers[playerSlot].currentStyle, true)); + _ = Task.Run(async () => await ReplayHandler(player, slot, arg, "69", "unknown", 0, playerTimers[slot].currentStyle, true)); } [ConsoleCommand("css_gc", "Globalcheck")] [CommandHelper(whoCanExecute: CommandUsage.CLIENT_AND_SERVER)] public async void GlobalCheckCommand(CCSPlayerController? player, CommandInfo command) { - if (!IsAllowedPlayer(player)) return; - - var playerSlot = player!.Slot; + if (player == null || !IsAllowedPlayer(player)) + return; if (apiKey == "") { - Server.NextFrame(() => PrintToChat(player, $"[GC] {ChatColors.LightRed}Missing API Key!")); + Server.NextFrame(() => Utils.PrintToChat(player, $"[GC] {ChatColors.LightRed}Missing API Key!")); return; } var validKey = await CheckKeyAsync(); if (!validKey) - Server.NextFrame(() => PrintToChat(player, $"[GC] {ChatColors.LightRed}Invalid API Key!")); + Server.NextFrame(() => Utils.PrintToChat(player, $"[GC] {ChatColors.LightRed}Invalid API Key!")); else - Server.NextFrame(() => PrintToChat(player, $"[GC] {ChatColors.Green}Valid API Key")); + Server.NextFrame(() => Utils.PrintToChat(player, $"[GC] {ChatColors.Green}Valid API Key")); var validHash = await CheckHashAsync(); if (!validHash) - Server.NextFrame(() => PrintToChat(player, $"[GC] {ChatColors.LightRed}Invalid ST build!")); + Server.NextFrame(() => Utils.PrintToChat(player, $"[GC] {ChatColors.LightRed}Invalid ST build!")); else - Server.NextFrame(() => PrintToChat(player, $"[GC] {ChatColors.Green}Valid ST build")); + Server.NextFrame(() => Utils.PrintToChat(player, $"[GC] {ChatColors.Green}Valid ST build")); var validAddon = await CheckAddonAsync(); if (!validAddon) - Server.NextFrame(() => PrintToChat(player, $"[GC] {ChatColors.LightRed}Map is not verified!")); + Server.NextFrame(() => Utils.PrintToChat(player, $"[GC] {ChatColors.LightRed}Map is not verified!")); else - Server.NextFrame(() => PrintToChat(player, $"[GC] {ChatColors.Green}Map is verified")); + Server.NextFrame(() => Utils.PrintToChat(player, $"[GC] {ChatColors.Green}Map is verified")); Server.NextFrame(() => { var (globalCheck, maxVel, maxWish) = CheckCvarsAndMaxVelo(); if (!globalCheck) - PrintToChat(player, $"[GC] {ChatColors.LightRed}Cvar Check Failed"); + Utils.PrintToChat(player, $"[GC] {ChatColors.LightRed}Cvar Check Failed"); else - PrintToChat(player, $"[GC] {ChatColors.Green}Cvar Check Passed"); + Utils.PrintToChat(player, $"[GC] {ChatColors.Green}Cvar Check Passed"); }); if (!globalDisabled && validKey && validHash && validAddon) - Server.NextFrame(() => PrintToChat(player, $"[GC] {ChatColors.Green}All checks passed!")); + Server.NextFrame(() => Utils.PrintToChat(player, $"[GC] {ChatColors.Green}All checks passed!")); else - Server.NextFrame(() => PrintToChat(player, $"[GC] {ChatColors.LightRed}Some checks failed")); + Server.NextFrame(() => Utils.PrintToChat(player, $"[GC] {ChatColors.LightRed}Some checks failed")); } [ConsoleCommand("css_gethash", "GetHash")] @@ -200,7 +203,8 @@ public async void GlobalCheckCommand(CCSPlayerController? player, CommandInfo co [RequiresPermissions("@css/cheats")] public void GetHashCommand(CCSPlayerController? player, CommandInfo command) { - if (!IsAllowedPlayer(player)) return; + if (!IsAllowedPlayer(player)) + return; var hash = GetHash(); Server.NextFrame(() => player!.PrintToConsole($"ST HASH: {hash}")); @@ -211,9 +215,10 @@ public void GetHashCommand(CCSPlayerController? player, CommandInfo command) [CommandHelper(minArgs: 1, usage: "[1-10] [bonus stage]", whoCanExecute: CommandUsage.CLIENT_ONLY)] public void ReplayBonusCommand(CCSPlayerController? player, CommandInfo command) { - if (!IsAllowedPlayer(player) || enableReplays == false) return; + if (!IsAllowedPlayer(player) || enableReplays == false) + return; - var playerSlot = player!.Slot; + int slot = player!.Slot; QuietStopTimer(player); @@ -226,7 +231,7 @@ public void ReplayBonusCommand(CCSPlayerController? player, CommandInfo command) string arg = command.ArgByIndex(1); string arg2 = command.ArgByIndex(2); - _ = Task.Run(async () => await ReplayHandler(player, playerSlot, arg, "69", "unknown", Int16.Parse(arg2), playerTimers[playerSlot].currentStyle)); + _ = Task.Run(async () => await ReplayHandler(player, slot, arg, "69", "unknown", Int16.Parse(arg2), playerTimers[slot].currentStyle)); } [ConsoleCommand("css_replaybpb", "Replay your bonus pb")] @@ -234,9 +239,10 @@ public void ReplayBonusCommand(CCSPlayerController? player, CommandInfo command) [CommandHelper(minArgs: 1, usage: "[bonus stage]", whoCanExecute: CommandUsage.CLIENT_ONLY)] public void ReplayBonusPBCommand(CCSPlayerController? player, CommandInfo command) { - if (!IsAllowedPlayer(player) || enableReplays == false) return; + if (!IsAllowedPlayer(player) || enableReplays == false) + return; - var playerSlot = player!.Slot; + var slot = player!.Slot; var steamID = player.SteamID.ToString(); var playerName = player.PlayerName; @@ -251,10 +257,10 @@ public void ReplayBonusPBCommand(CCSPlayerController? player, CommandInfo comman string arg = command.ArgByIndex(1); int bonusX = Int16.Parse(arg); - _ = Task.Run(async () => await ReplayHandler(player, playerSlot, "self", steamID, playerName, bonusX, playerTimers[playerSlot].currentStyle)); + _ = Task.Run(async () => await ReplayHandler(player, slot, "self", steamID, playerName, bonusX, playerTimers[slot].currentStyle)); } - public async Task ReplayHandler(CCSPlayerController player, int playerSlot, string arg = "1", string pbSteamID = "69", string playerName = "unknown", int bonusX = 0, int style = 0, bool wr = false) + public async Task ReplayHandler(CCSPlayerController player, int slot, string arg = "1", string pbSteamID = "69", string playerName = "unknown", int bonusX = 0, int style = 0, bool wr = false) { bool self = false; @@ -268,8 +274,8 @@ public async Task ReplayHandler(CCSPlayerController player, int playerSlot, stri self = true; } - playerReplays.Remove(playerSlot); - playerReplays[playerSlot] = new PlayerReplays(); + playerReplays.Remove(slot); + playerReplays[slot] = new PlayerReplays(); var (srSteamID, srPlayerName, srTime) = ("null", "null", "null"); var (wrID, wrSteamID, wrPlayerName, wrTime) = (0, "null", "null", "null"); @@ -277,29 +283,25 @@ public async Task ReplayHandler(CCSPlayerController player, int playerSlot, stri if (!self) { if (enableDb) - { (srSteamID, srPlayerName, srTime) = await GetMapRecordSteamIDFromDatabase(bonusX, top10, style); - } + else - { (srSteamID, srPlayerName, srTime) = await GetMapRecordSteamID(bonusX, top10); - } + if (wr) { var sortedRecords = await GetSortedRecordsFromGlobal(10, bonusX, currentMapName!, style); wrID = sortedRecords[top10-1].RecordID; wrSteamID = sortedRecords[top10-1].SteamID; wrPlayerName = sortedRecords[top10-1].PlayerName; - wrTime = FormatTime(sortedRecords[top10-1].TimerTicks); + wrTime = Utils.FormatTime(sortedRecords[top10-1].TimerTicks); } - } - if ((srSteamID == "null" || srPlayerName == "null" || srTime == "null") && !self) { Server.NextFrame(() => { - PrintToChat(player, Localizer["no_sr_replay"]); + Utils.PrintToChat(player, Localizer["no_sr_replay"]); RespawnPlayer(player); }); return; @@ -307,44 +309,40 @@ public async Task ReplayHandler(CCSPlayerController player, int playerSlot, stri if (wr) await ReadReplayFromGlobal(player, wrID, style, bonusX); - else { - if (useBinaryReplays) - await ReadReplayFromBinary(player, !self ? srSteamID : pbSteamID, playerSlot, bonusX, style); - else - await ReadReplayFromJson(player, !self ? srSteamID : pbSteamID, playerSlot, bonusX, style); - } + else + await ReadReplayFromJson(player, !self ? srSteamID : pbSteamID, slot, bonusX, style); + + if (playerReplays[slot].replayFrames.Count == 0) return; - if (playerReplays[playerSlot].replayFrames.Count == 0) return; + if (!wr) await GetReplayVIPGif(!self ? srSteamID : pbSteamID, slot); - if (!wr) await GetReplayVIPGif(!self ? srSteamID : pbSteamID, playerSlot); + playerTimers[slot].IsReplaying = !playerTimers[slot].IsReplaying; - playerTimers[playerSlot].IsReplaying = !playerTimers[playerSlot].IsReplaying; if (wr) - playerTimers[playerSlot].ReplayHUDString = $"{wrPlayerName} | {wrTime}"; + playerTimers[slot].ReplayHUDString = $"{wrPlayerName} | {wrTime}"; else - playerTimers[playerSlot].ReplayHUDString = !self ? $"{srPlayerName} | {srTime}" : $"{playerName} | {playerTimers[playerSlot].CachedPB}"; + playerTimers[slot].ReplayHUDString = !self ? $"{srPlayerName} | {srTime}" : $"{playerName} | {playerTimers[slot].CachedPB}"; - playerTimers[playerSlot].IsTimerRunning = false; - playerTimers[playerSlot].TimerTicks = 0; - playerTimers[playerSlot].IsBonusTimerRunning = false; - playerTimers[playerSlot].BonusTimerTicks = 0; - playerReplays[playerSlot].CurrentPlaybackFrame = 0; - if (stageTriggers.Count != 0) playerTimers[playerSlot].StageTimes!.Clear(); //remove previous stage times if the map has stages - if (stageTriggers.Count != 0) playerTimers[playerSlot].StageVelos!.Clear(); //remove previous stage times if the map has stages + playerTimers[slot].IsTimerRunning = false; + playerTimers[slot].TimerTicks = 0; + playerTimers[slot].IsBonusTimerRunning = false; + playerTimers[slot].BonusTimerTicks = 0; + playerReplays[slot].CurrentPlaybackFrame = 0; + + if (stageTriggers.Count != 0) playerTimers[slot].StageTimes!.Clear(); //remove previous stage times if the map has stages + if (stageTriggers.Count != 0) playerTimers[slot].StageVelos!.Clear(); //remove previous stage times if the map has stages if (IsAllowedPlayer(player)) { if (wr) - Server.NextFrame(() => PrintToChat(player, Localizer["replaying_world_top", top10])); + Server.NextFrame(() => Utils.PrintToChat(player, Localizer["replaying_world_top", top10])); else if (!self) - Server.NextFrame(() => PrintToChat(player, Localizer["replaying_server_top", top10])); + Server.NextFrame(() => Utils.PrintToChat(player, Localizer["replaying_server_top", top10])); else - Server.NextFrame(() => PrintToChat(player, Localizer["replaying_pb"])); + Server.NextFrame(() => Utils.PrintToChat(player, Localizer["replaying_pb"])); } else - { - SharpTimerError($"Error in ReplayHandler: player not allowed or not on server anymore"); - } + Utils.LogError($"Error in ReplayHandler: player not allowed or not on server anymore"); } [ConsoleCommand("css_stop", "stops the current replay")] @@ -352,36 +350,41 @@ public async Task ReplayHandler(CCSPlayerController player, int playerSlot, stri [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] public void StopReplayCommand(CCSPlayerController? player, CommandInfo command) { - if (!IsAllowedPlayer(player) || enableReplays == false) return; + if (!IsAllowedPlayer(player) || enableReplays == false) + return; StopReplay(player); } public void StopReplay(CCSPlayerController? player) { - var playerSlot = player!.Slot; + var slot = player!.Slot; - if (!playerTimers[playerSlot].IsTimerBlocked || !playerTimers[playerSlot].IsReplaying) + if (!playerTimers[slot].IsTimerBlocked || !playerTimers[slot].IsReplaying) { - PrintToChat(player, Localizer["no_replay"]); + Utils.PrintToChat(player, Localizer["no_replay"]); return; } - if (playerTimers[playerSlot].IsReplaying) + if (playerTimers[slot].IsReplaying) { - PrintToChat(player, Localizer["ending_replay"]); - playerTimers[playerSlot].IsReplaying = false; + Utils.PrintToChat(player, Localizer["ending_replay"]); + playerTimers[slot].IsReplaying = false; + if (player.PlayerPawn.Value!.MoveType != MoveType_t.MOVETYPE_WALK || player.PlayerPawn.Value.ActualMoveType != MoveType_t.MOVETYPE_WALK) SetMoveType(player, MoveType_t.MOVETYPE_WALK); - playerReplays.Remove(playerSlot); - playerReplays[playerSlot] = new PlayerReplays(); - playerTimers[playerSlot].IsTimerBlocked = false; - playerTimers[playerSlot].IsTimerRunning = false; - playerTimers[playerSlot].TimerTicks = 0; - playerTimers[playerSlot].IsBonusTimerRunning = false; - playerTimers[playerSlot].BonusTimerTicks = 0; - playerReplays[playerSlot].CurrentPlaybackFrame = 0; - if (stageTriggers.Count != 0) playerTimers[playerSlot].StageTimes!.Clear(); //remove previous stage times if the map has stages - if (stageTriggers.Count != 0) playerTimers[playerSlot].StageVelos!.Clear(); //remove previous stage times if the map has stages + playerReplays.Remove(slot); + + playerReplays[slot] = new PlayerReplays(); + playerTimers[slot].IsTimerBlocked = false; + playerTimers[slot].IsTimerRunning = false; + playerTimers[slot].TimerTicks = 0; + playerTimers[slot].IsBonusTimerRunning = false; + playerTimers[slot].BonusTimerTicks = 0; + playerReplays[slot].CurrentPlaybackFrame = 0; + + if (stageTriggers.Count != 0) playerTimers[slot].StageTimes!.Clear(); //remove previous stage times if the map has stages + if (stageTriggers.Count != 0) playerTimers[slot].StageVelos!.Clear(); //remove previous stage times if the map has stages + RespawnPlayer(player); } } @@ -391,7 +394,7 @@ public void StopReplay(CCSPlayerController? player) [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] public void HelpCommand(CCSPlayerController? player, CommandInfo command) { - if (!IsAllowedClient(player) || !helpEnabled) + if (!IsPlayerOrSpectator(player) || !helpEnabled) return; PrintAllEnabledCommands(player!); @@ -402,10 +405,10 @@ public void HelpCommand(CCSPlayerController? player, CommandInfo command) [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] public void SpecCommand(CCSPlayerController? player, CommandInfo command) { - if (player == null || !player.IsValid || player.Pawn == null || !player.PlayerPawn.IsValid) + if (!IsAllowedPlayer(player)) return; - if (player.Team == CsTeam.Spectator) + if (player!.Team == CsTeam.Spectator) { player.ChangeTeam(CsTeam.CounterTerrorist); player.Respawn(); @@ -415,7 +418,7 @@ public void SpecCommand(CCSPlayerController? player, CommandInfo command) else if (player.Team != CsTeam.Spectator) { player.ChangeTeam(CsTeam.Spectator); - player.PrintToChat($"{Localizer["prefix"]} You have been moved to Spectator."); + Utils.PrintToChat(player, $"You have been moved to Spectator."); } } @@ -423,146 +426,87 @@ public void SpecCommand(CCSPlayerController? player, CommandInfo command) [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] public void HUDSwitchCommand(CCSPlayerController? player, CommandInfo command) { - if (!IsAllowedPlayer(player)) - { - if (!IsAllowedSpectator(player)) - return; - } + if (!IsPlayerOrSpectator(player)) + return; - var playerName = player!.PlayerName; - var playerSlot = player.Slot; + var slot = player!.Slot; + var playerName = player.PlayerName; var steamID = player.SteamID.ToString(); - SharpTimerDebug($"{playerName} calling css_hud..."); + Utils.LogDebug($"{playerName} calling css_hud..."); if (CommandCooldown(player)) return; - playerTimers[playerSlot].TicksSinceLastCmd = 0; - - playerTimers[playerSlot].HideTimerHud = !playerTimers[playerSlot].HideTimerHud; + playerTimers[slot].HideTimerHud = !playerTimers[slot].HideTimerHud; - if (playerTimers[playerSlot].HideTimerHud) - PrintToChat(player, Localizer["hud_hidden"]); + if (playerTimers[slot].HideTimerHud) + Utils.PrintToChat(player, Localizer["hud_hidden"]); else - PrintToChat(player, Localizer["hud_shown"]); + Utils.PrintToChat(player, Localizer["hud_shown"]); - SharpTimerDebug($"Hide Timer HUD set to: {playerTimers[playerSlot].HideTimerHud} for {playerName}"); + Utils.LogDebug($"Hide Timer HUD set to: {playerTimers[slot].HideTimerHud} for {playerName}"); if (enableDb) - { - _ = Task.Run(async () => await SetPlayerStats(player, steamID, playerName, playerSlot)); - } + _ = Task.Run(async () => await SetPlayerStats(player, steamID, playerName, slot)); } [ConsoleCommand("css_keys", "Draws/Hides HUD Keys")] [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] public void KeysSwitchCommand(CCSPlayerController? player, CommandInfo command) { - if (!IsAllowedPlayer(player)) - { - if (!IsAllowedSpectator(player)) - return; - } + if (!IsPlayerOrSpectator(player)) + return; - var playerName = player!.PlayerName; - var playerSlot = player.Slot; + var slot = player!.Slot; + var playerName = player.PlayerName; var steamID = player.SteamID.ToString(); - SharpTimerDebug($"{playerName} calling css_keys..."); + Utils.LogDebug($"{playerName} calling css_keys..."); if (CommandCooldown(player)) return; - - playerTimers[playerSlot].TicksSinceLastCmd = 0; - playerTimers[playerSlot].HideKeys = playerTimers[playerSlot].HideKeys ? false : true; + playerTimers[slot].HideKeys = playerTimers[slot].HideKeys ? false : true; - if (playerTimers[playerSlot].HideKeys) - PrintToChat(player, Localizer["keys_hidden"]); + if (playerTimers[slot].HideKeys) + Utils.PrintToChat(player, Localizer["keys_hidden"]); else - PrintToChat(player, Localizer["keys_shown"]); + Utils.PrintToChat(player, Localizer["keys_shown"]); - SharpTimerDebug($"Hide Timer HUD set to: {playerTimers[playerSlot].HideKeys} for {playerName}"); + Utils.LogDebug($"Hide Timer HUD set to: {playerTimers[slot].HideKeys} for {playerName}"); if (enableDb) - { - _ = Task.Run(async () => await SetPlayerStats(player, steamID, playerName, playerSlot)); - } - + _ = Task.Run(async () => await SetPlayerStats(player, steamID, playerName, slot)); } [ConsoleCommand("css_sounds", "Toggles Sounds")] [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] public void SoundsSwitchCommand(CCSPlayerController? player, CommandInfo command) { - if (!IsAllowedPlayer(player)) - { - if (!IsAllowedSpectator(player)) - return; - } - - var playerName = player!.PlayerName; - var playerSlot = player.Slot; - var steamID = player.SteamID.ToString(); - - SharpTimerDebug($"{playerName} calling css_sounds..."); - - if (CommandCooldown(player)) + if (!IsPlayerOrSpectator(player)) return; - playerTimers[playerSlot].TicksSinceLastCmd = 0; - - playerTimers[playerSlot].SoundsEnabled = playerTimers[playerSlot].SoundsEnabled ? false : true; - - if (playerTimers[playerSlot].SoundsEnabled) - PrintToChat(player, Localizer["sounds_on"]); - else - PrintToChat(player, Localizer["sounds_off"]); - - SharpTimerDebug($"Timer Sounds set to: {playerTimers[playerSlot].SoundsEnabled} for {playerName}"); - - if (enableDb) - { - _ = Task.Run(async () => await SetPlayerStats(player, steamID, playerName, playerSlot)); - } - } - - [ConsoleCommand("css_jumpstats", "Toggles JumpStats")] - [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] - public void JSSwitchCommand(CCSPlayerController? player, CommandInfo command) - { - if (!IsAllowedPlayer(player) || jumpStatsEnabled == false) - { - if (!IsAllowedSpectator(player)) - return; - } - - var playerName = player!.PlayerName; - var playerSlot = player.Slot; + var slot = player!.Slot; + var playerName = player.PlayerName; var steamID = player.SteamID.ToString(); - SharpTimerDebug($"{playerName} calling css_jumpstats..."); + Utils.LogDebug($"{playerName} calling css_sounds..."); if (CommandCooldown(player)) return; - playerTimers[playerSlot].TicksSinceLastCmd = 0; - - playerTimers[playerSlot].HideJumpStats = playerTimers[playerSlot].HideJumpStats ? false : true; + playerTimers[slot].SoundsEnabled = playerTimers[slot].SoundsEnabled ? false : true; - if (playerTimers[playerSlot].HideJumpStats) - PrintToChat(player, Localizer["jumpstats_hidden"]); + if (playerTimers[slot].SoundsEnabled) + Utils.PrintToChat(player, Localizer["sounds_on"]); else - PrintToChat(player, Localizer["jumpstats_shown"]); + Utils.PrintToChat(player, Localizer["sounds_off"]); - SharpTimerDebug($"Hide Jump Stats set to: {playerTimers[playerSlot].HideJumpStats} for {playerName}"); + Utils.LogDebug($"Timer Sounds set to: {playerTimers[slot].SoundsEnabled} for {playerName}"); if (enableDb) - { - _ = Task.Run(async () => await SetPlayerStats(player, steamID, playerName, playerSlot)); - } - + _ = Task.Run(async () => await SetPlayerStats(player, steamID, playerName, slot)); } [ConsoleCommand("css_hideweapon", "Toggles the player's weapon visibility")] @@ -570,22 +514,23 @@ public void JSSwitchCommand(CCSPlayerController? player, CommandInfo command) [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] public void ToggleWeaponCommand(CCSPlayerController? player, CommandInfo command) { - if (player == null || !IsAllowedPlayer(player) || player.Team == CsTeam.Spectator) + if (!IsPlayerOrSpectator(player)) return; - - var playerName = player!.PlayerName; - var playerSlot = player.Slot; + + var slot = player!.Slot; + var playerName = player.PlayerName; var steamID = player.SteamID.ToString(); - playerTimers[player.Slot].HideWeapon = !playerTimers[player.Slot].HideWeapon; - _ = Task.Run(async () => await SetPlayerStats(player, steamID, playerName, playerSlot)); + playerTimers[slot].HideWeapon = !playerTimers[slot].HideWeapon; + _ = Task.Run(async () => await SetPlayerStats(player, steamID, playerName, slot)); } [ConsoleCommand("css_fov", "Sets the player's FOV")] [CommandHelper(minArgs: 1, usage: "[fov]")] public void FovCommand(CCSPlayerController? player, CommandInfo command) { - if (!IsAllowedPlayer(player) || fovChangerEnabled == false) return; + if (!IsAllowedPlayer(player) || fovChangerEnabled == false) + return; if (!Int32.TryParse(command.GetArg(1), out var desiredFov)) return; @@ -598,14 +543,12 @@ public void SetFov(CCSPlayerController? player, int desiredFov, bool noMySql = f Utilities.SetStateChanged(player, "CBasePlayerController", "m_iDesiredFOV"); var playerName = player.PlayerName; - var playerSlot = player.Slot; + var slot = player.Slot; var steamID = player.SteamID.ToString(); - if (noMySql == false) playerTimers[player.Slot].PlayerFov = desiredFov; + if (noMySql == false) playerTimers[slot].PlayerFov = desiredFov; if (enableDb) - { - _ = Task.Run(async () => await SetPlayerStats(player, steamID, playerName, playerSlot)); - } + _ = Task.Run(async () => await SetPlayerStats(player, steamID, playerName, slot)); } [ConsoleCommand("css_top", "Prints top players of this map")] @@ -614,21 +557,20 @@ public void SetFov(CCSPlayerController? player, int desiredFov, bool noMySql = f [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] public void PrintTopRecords(CCSPlayerController? player, CommandInfo command) { - if (!IsAllowedClient(player) || topEnabled == false) + if (!IsPlayerOrSpectator(player) || topEnabled == false) return; - var playerName = player!.PlayerName; - - SharpTimerDebug($"{playerName} calling css_top..."); + Utils.LogDebug($"{player!.PlayerName} calling css_top..."); if (CommandCooldown(player)) return; - playerTimers[player.Slot].TicksSinceLastCmd = 0; - var mapName = command.ArgByIndex(1); - _ = Task.Run(async () => await PrintTopRecordsHandler(player, playerName, 0, string.IsNullOrEmpty(mapName) ? "" : mapName, playerTimers[player.Slot].currentStyle)); + Server.NextFrame(async () => + { + await PrintTopRecordsHandler(player, player.PlayerName, 0, string.IsNullOrEmpty(mapName) ? "" : mapName, playerTimers[player.Slot].currentStyle); + }); } [ConsoleCommand("css_points", "Prints top points")] @@ -636,111 +578,91 @@ public void PrintTopRecords(CCSPlayerController? player, CommandInfo command) [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] public void PrintTopPoints(CCSPlayerController? player, CommandInfo command) { - if (!IsAllowedClient(player) || globalRanksEnabled == false) + if (!IsPlayerOrSpectator(player) || globalRanksEnabled == false) return; - var playerName = player!.PlayerName; - - SharpTimerDebug($"{playerName} calling css_points..."); + Utils.LogDebug($"{player!.PlayerName} calling css_points..."); if (CommandCooldown(player)) return; - playerTimers[player.Slot].TicksSinceLastCmd = 0; - _ = Task.Run(async () => await PrintTop10PlayerPoints(player)); } - [ConsoleCommand("css_wr", "Prints world record for current map")] [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] public void PrintWR(CCSPlayerController? player, CommandInfo command) { - if (!IsAllowedClient(player)) + if (!IsPlayerOrSpectator(player)) return; - var playerName = player!.PlayerName; - - SharpTimerDebug($"{playerName} calling css_wr..."); + Utils.LogDebug($"{player!.PlayerName} calling css_wr..."); if (CommandCooldown(player)) return; - playerTimers[player.Slot].TicksSinceLastCmd = 0; - PrintWorldRecord(player); - } + [ConsoleCommand("css_gpoints", "Prints top global points")] [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] public void PrintTopGlobalPoints(CCSPlayerController? player, CommandInfo command) { - if (!IsAllowedClient(player)) + if (!IsPlayerOrSpectator(player)) return; - var playerName = player!.PlayerName; - - SharpTimerDebug($"{playerName} calling css_gpoints..."); + Utils.LogDebug($"{player!.PlayerName} calling css_gpoints..."); if (CommandCooldown(player)) return; - playerTimers[player.Slot].TicksSinceLastCmd = 0; - PrintGlobalPoints(player); - } + [ConsoleCommand("css_grank", "Prints personal global rank")] [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] public void PrintPlayerGlobalPoints(CCSPlayerController? player, CommandInfo command) { - if (!IsAllowedClient(player)) + if (!IsPlayerOrSpectator(player)) return; - var playerName = player!.PlayerName; - - SharpTimerDebug($"{playerName} calling css_grank..."); - - if (CommandCooldown(player)) - return; + Utils.LogDebug($"{player!.PlayerName} calling css_grank..."); - playerTimers[player.Slot].TicksSinceLastCmd = 0; + if (CommandCooldown(player)) return; _ = Task.Run(async () => await PrintGlobalRankAsync(player)); - } + [ConsoleCommand("css_topbonus", "Prints top players of this map bonus")] [ConsoleCommand("css_btop", "alias for !topbonus")] [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] public void PrintTopBonusRecords(CCSPlayerController? player, CommandInfo command) { - if (!IsAllowedClient(player) || topEnabled == false) + if (!IsPlayerOrSpectator(player) || topEnabled == false) return; - var playerName = player!.PlayerName; - - SharpTimerDebug($"{playerName} calling css_topbonus..."); + Utils.LogDebug($"{player!.PlayerName} calling css_topbonus..."); if (CommandCooldown(player)) return; - playerTimers[player.Slot].TicksSinceLastCmd = 0; - if (!int.TryParse(command.ArgString, out int bonusX)) { - SharpTimerDebug("css_topbonus conversion failed. The input string is not a valid integer."); + Utils.LogDebug("css_topbonus conversion failed. The input string is not a valid integer."); - PrintToChat(player, Localizer["invalid_bonus_stage"]); + Utils.PrintToChat(player, Localizer["invalid_bonus_stage"]); return; } - _ = Task.Run(async () => await PrintTopRecordsHandler(player, playerName, bonusX)); + Server.NextFrame(async () => await PrintTopRecordsHandler(player, player.PlayerName, bonusX)); } public async Task PrintTopRecordsHandler(CCSPlayerController? player, string playerName, int bonusX = 0, string mapName = "", int style = 0) { - if (!IsAllowedClient(player) || topEnabled == false) return; - SharpTimerDebug($"Handling !top for {playerName}"); + if (!IsPlayerOrSpectator(player) || topEnabled == false) + return; + + Utils.LogDebug($"Handling !top for {playerName}"); string? currentMapNamee; if (string.IsNullOrEmpty(mapName)) @@ -750,54 +672,46 @@ public async Task PrintTopRecordsHandler(CCSPlayerController? player, string pla var sortedRecords = await GetSortedRecordsFromDatabase(10, bonusX, mapName, style); - - if (sortedRecords.Count == 0) + Server.NextFrame(() => { - Server.NextFrame(() => - { - if (IsAllowedClient(player)) - { - if (bonusX != 0) - PrintToChat(player, Localizer["no_records_available_bonus", bonusX, currentMapNamee]); - else - PrintToChat(player, Localizer["no_records_available", currentMapNamee]); - } - }); - return; - } + if (!IsPlayerOrSpectator(player)) + return; - List printStatements; + if (sortedRecords.Count == 0) + { + if (bonusX != 0) + Utils.PrintToChat(player!, Localizer["no_records_available_bonus", bonusX, currentMapNamee]); + else + Utils.PrintToChat(player!, Localizer["no_records_available", currentMapNamee]); + return; + } - if (bonusX != 0) - printStatements = [$" {Localizer["prefix"]} {Localizer["top10_records_bonus", GetNamedStyle(style), bonusX, currentMapNamee]}"]; - else - printStatements = [$" {Localizer["prefix"]} {Localizer["top10_records", GetNamedStyle(style), currentMapNamee]}"]; + List printStatements; - int rank = 1; + if (bonusX != 0) + printStatements = [$" {Localizer["top10_records_bonus", GetNamedStyle(style), bonusX, currentMapNamee]}"]; + else + printStatements = [$" {Localizer["top10_records", GetNamedStyle(style), currentMapNamee]}"]; - foreach (var kvp in sortedRecords.Take(10)) - { - string _playerName = kvp.Value.PlayerName!; - int timerTicks = kvp.Value.TimerTicks; + int rank = 1; - bool showReplays = false; - if (enableReplays == true) showReplays = await CheckSRReplay(kvp.Value.SteamID!, bonusX); + foreach (var kvp in sortedRecords.Take(10)) + { + string _playerName = kvp.Value.PlayerName!; + int timerTicks = kvp.Value.TimerTicks; - string replayIndicator = enableReplays ? (showReplays ? $"{ChatColors.Red}◉" : "") : ""; + bool showReplays = false; + if (enableReplays == true) + showReplays = Task.Run(() => CheckSRReplay(kvp.Value.SteamID!, bonusX)).Result; - printStatements.Add($" {Localizer["prefix"]} {Localizer["records_map", rank, _playerName, replayIndicator, FormatTime(timerTicks)]}"); - rank++; - } + string replayIndicator = enableReplays ? (showReplays ? $"{ChatColors.Red}◉" : "") : ""; - Server.NextFrame(() => - { - if (IsAllowedClient(player)) - { - foreach (var statement in printStatements) - { - player!.PrintToChat(statement); - } + printStatements.Add($" {Localizer["records_map", rank, _playerName, replayIndicator, Utils.FormatTime(timerTicks)]}"); + rank++; } + + foreach (var statement in printStatements) + Utils.PrintToChat(player!, statement); }); } @@ -805,44 +719,42 @@ public async Task PrintTopRecordsHandler(CCSPlayerController? player, string pla [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] public void RankCommand(CCSPlayerController? player, CommandInfo command) { - if (!IsAllowedClient(player) || rankEnabled == false) + if (!IsPlayerOrSpectator(player) || rankEnabled == false) return; - var playerName = player!.PlayerName; - var playerSlot = player.Slot; + var slot = player!.Slot; + var playerName = player.PlayerName; var steamID = player.SteamID.ToString(); - SharpTimerDebug($"{playerName} calling css_rank..."); + Utils.LogDebug($"{playerName} calling css_rank..."); if (CommandCooldown(player)) return; - _ = Task.Run(async () => await RankCommandHandler(player, steamID, playerSlot, playerName, false, playerTimers[playerSlot].currentStyle)); + _ = Task.Run(async () => await RankCommandHandler(player, steamID, slot, playerName, false, playerTimers[slot].currentStyle)); } - public async Task RankCommandHandler(CCSPlayerController? player, string steamId, int playerSlot, string playerName, bool sendRankToHUD = false, int style = 0) + public async Task RankCommandHandler(CCSPlayerController? player, string steamId, int slot, string playerName, bool sendRankToHUD = false, int style = 0) { + if (player!.IsBot || player.SteamID.ToString() == "0") + return; + try { - if (!IsAllowedClient(player)) + if (!IsPlayerOrSpectator(player)) { - SharpTimerError($"Error in RankCommandHandler: Player not allowed or not on server anymore"); + Utils.LogError($"Error in RankCommandHandler: Player not allowed or not on server anymore"); return; } - //SharpTimerDebug($"Handling !rank for {playerName}..."); + //Utils.LogDebug($"Handling !rank for {playerName}..."); string ranking, rankIcon, mapPlacement, serverPoints = "", serverPlacement = ""; bool useGlobalRanks = enableDb && globalRanksEnabled; - ranking = useGlobalRanks ? await GetPlayerServerPlacement(steamId, playerName) : await GetPlayerMapPlacementWithTotal(player, steamId, playerName, false, false, 0, style); - rankIcon = useGlobalRanks ? await GetPlayerServerPlacement(steamId, playerName, true) : await GetPlayerMapPlacementWithTotal(player, steamId, playerName, true, false, 0, style); + ranking = useGlobalRanks ? await GetPlayerServerPlacement(player, steamId, playerName) : await GetPlayerMapPlacementWithTotal(player, steamId, playerName, false, false, 0, style); + rankIcon = useGlobalRanks ? await GetPlayerServerPlacement(player, steamId, playerName, true) : await GetPlayerMapPlacementWithTotal(player, steamId, playerName, true, false, 0, style); mapPlacement = await GetPlayerMapPlacementWithTotal(player, steamId, playerName, false, true, 0, style); - var percentile = - await GetPlayerMapPercentile(steamId, playerName); - - SharpTimerDebug("Ranking: " + mapPlacement); - int.TryParse(mapPlacement[..Math.Max(mapPlacement.IndexOf('/'), 0)], out var position); foreach (var bonusRespawnPose in bonusRespawnPoses) { @@ -854,11 +766,11 @@ public async Task RankCommandHandler(CCSPlayerController? player, string steamId var bonusPlacement = await GetPlayerMapPlacementWithTotal(player, steamId, playerName, false, true, bonusNumber, style); - SharpTimerDebug($"Adding bonus info for Bonus {bonusNumber}"); - SharpTimerDebug($"PbTicks: {bonusPbTicks}"); - SharpTimerDebug($"Placement: {bonusPlacement}"); + Utils.LogDebug($"Adding bonus info for Bonus {bonusNumber}"); + Utils.LogDebug($"PbTicks: {bonusPbTicks}"); + Utils.LogDebug($"Placement: {bonusPlacement}"); - playerTimers[playerSlot].CachedBonusInfo[bonusNumber] = new PlayerBonusPlacementInfo() + playerTimers[slot].CachedBonusInfo[bonusNumber] = new PlayerBonusPlacementInfo() { PbTicks = bonusPbTicks, Placement = bonusPlacement @@ -867,61 +779,58 @@ public async Task RankCommandHandler(CCSPlayerController? player, string steamId if (useGlobalRanks) { - serverPoints = await GetPlayerServerPlacement(steamId, playerName, false, false, true); - serverPlacement = await GetPlayerServerPlacement(steamId, playerName, false, true, false); + serverPoints = await GetPlayerServerPlacement(player, steamId, playerName, false, false, true); + serverPlacement = await GetPlayerServerPlacement(player, steamId, playerName, false, true, false); } int pbTicks = enableDb ? await GetPreviousPlayerRecordFromDatabase(steamId, currentMapName!, playerName, 0, style) : await GetPreviousPlayerRecord(steamId, 0); Server.NextFrame(() => { - if (!IsAllowedClient(player)) return; - playerTimers[playerSlot].RankHUDIcon = $"{(!string.IsNullOrEmpty(rankIcon) ? $" {rankIcon}" : "")}"; - playerTimers[playerSlot].CachedPB = $"{(pbTicks != 0 ? $" {FormatTime(pbTicks)}" : "")}"; - playerTimers[playerSlot].CachedRank = ranking; - playerTimers[playerSlot].CachedMapPlacement = mapPlacement; - cachedPlacements.Remove(playerSlot); - - if (Mixin.Actain != null && player != null && player.IsValid) { - Mixin.Actain.getTagService() - .SetTag(player, ranking, false); - Mixin.Actain.getTagService() - .SetTagColor(player, GetRankColorForChat(player)[0], false); + if (!IsPlayerOrSpectator(player)) return; + playerTimers[slot].RankHUDIcon = $"{(!string.IsNullOrEmpty(rankIcon) ? $" {rankIcon}" : "")}"; + playerTimers[slot].CachedPB = $"{(pbTicks != 0 ? $" {Utils.FormatTime(pbTicks)}" : "")}"; + playerTimers[slot].CachedRank = ranking; + playerTimers[slot].CachedMapPlacement = mapPlacement; + + // Update Actain tag (if available) + if (Mixin.Actain != null && player != null && player.IsValid) + { + Mixin.Actain.getTagService().SetTag(player, ranking, false); + Mixin.Actain.getTagService().SetTagColor(player, GetRankColorForChat(player)[0], false); } - if (displayScoreboardTags) AddScoreboardTagToPlayer(player!, ranking); + if (displayScoreboardTags) AddRankTagToPlayer(player!, ranking); }); if (!sendRankToHUD) { Server.NextFrame(() => { - if (!IsAllowedClient(player)) return; + if (!IsPlayerOrSpectator(player)) + return; string rankMessage = Localizer["current_rank", GetRankColorForChat(player!), ranking]; if (useGlobalRanks) rankMessage += Localizer["current_rank_points", serverPoints, serverPlacement]; - PrintToChat(player, rankMessage); + Utils.PrintToChat(player!, rankMessage); - if (pbTicks != 0) { - PrintToChat(player, Localizer["current_pb", currentMapName!, FormatTime(pbTicks), mapPlacement, FormatGroup(position, percentile)]); - } + if (pbTicks != 0) + Utils.PrintToChat(player!, Localizer["current_pb", currentMapName!, Utils.FormatTime(pbTicks), mapPlacement]); - if (playerTimers[playerSlot].CachedBonusInfo.Any()) + if (playerTimers[slot].CachedBonusInfo.Any()) { - foreach (var bonusPb in playerTimers[playerSlot].CachedBonusInfo.OrderBy(x => x.Key)) - { - PrintToChat(player, $"{Localizer["current_bonus_pb", bonusPb.Key!, FormatTime(bonusPb.Value.PbTicks), bonusPb.Value.Placement!]}"); - } + foreach (var bonusPb in playerTimers[slot].CachedBonusInfo.OrderBy(x => x.Key)) + Utils.PrintToChat(player!, $"{Localizer["current_bonus_pb", bonusPb.Key!, Utils.FormatTime(bonusPb.Value.PbTicks), bonusPb.Value.Placement!]}"); } }); } } catch (Exception ex) { - SharpTimerError($"Error in RankCommandHandler: {ex} {ex.StackTrace}"); + Utils.LogError($"Error in RankCommandHandler: {ex}"); } } @@ -929,12 +838,12 @@ public async Task RankCommandHandler(CCSPlayerController? player, string steamId [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] public void SRCommand(CCSPlayerController? player, CommandInfo command) { - if (!IsAllowedClient(player) || rankEnabled == false) + if (!IsPlayerOrSpectator(player) || rankEnabled == false) return; var playerName = player!.PlayerName; - SharpTimerDebug($"{playerName} calling css_sr..."); + Utils.LogDebug($"{playerName} calling css_sr..."); if (CommandCooldown(player)) return; @@ -944,8 +853,10 @@ public void SRCommand(CCSPlayerController? player, CommandInfo command) public async Task SRCommandHandler(CCSPlayerController? player, string _playerName) { - if (!IsAllowedClient(player) || rankEnabled == false) return; - SharpTimerDebug($"Handling !sr for {_playerName}..."); + if (!IsPlayerOrSpectator(player) || rankEnabled == false) + return; + + Utils.LogDebug($"Handling !sr for {_playerName}..."); var sortedRecords = await GetSortedRecordsFromDatabase(); @@ -954,8 +865,7 @@ public async Task SRCommandHandler(CCSPlayerController? player, string _playerNa Server.NextFrame(() => { - if (!IsAllowedClient(player)) return; - PrintToChat(player, Localizer["current_sr", currentMapName!]); + Utils.PrintToChat(player!, Localizer["current_sr", currentMapName!]); }); foreach (var kvp in sortedRecords.Take(1)) @@ -964,8 +874,7 @@ public async Task SRCommandHandler(CCSPlayerController? player, string _playerNa int timerTicks = kvp.Value.TimerTicks; Server.NextFrame(() => { - if (!IsAllowedClient(player)) return; - PrintToChat(player, Localizer["current_sr_player", playerName!, FormatTime(timerTicks)]); + Utils.PrintToChat(player!, Localizer["current_sr_player", playerName!, Utils.FormatTime(timerTicks)]); }); } } @@ -977,8 +886,14 @@ public void RespawnBonusPlayer(CCSPlayerController? player, CommandInfo command) { try { - if (!IsAllowedPlayer(player) || respawnEnabled == false) return; - SharpTimerDebug($"{player!.PlayerName} calling css_rb..."); + if (!IsAllowedPlayer(player) || respawnEnabled == false) + return; + + var slot = player!.Slot; + var playerName = player.PlayerName; + var steamID = player.SteamID.ToString(); + + Utils.LogDebug($"{playerName} calling css_rb..."); if (CommandCooldown(player)) return; @@ -986,83 +901,74 @@ public void RespawnBonusPlayer(CCSPlayerController? player, CommandInfo command) if (ReplayCheck(player)) return; - playerTimers[player.Slot].TicksSinceLastCmd = 0; - //defaults to !b 1 without any args if (command.ArgString == null || command.ArgString == "") { if (bonusRespawnPoses[1] != null) { - if (bonusRespawnAngs.TryGetValue(1, out QAngle? bonusAng) && bonusAng != null) + if (bonusRespawnAngs.TryGetValue(1, out QAngle_t? bonusAng) && bonusAng != null) { - player.PlayerPawn.Value!.Teleport(bonusRespawnPoses[1]!, bonusRespawnAngs[1]!, new Vector(0, 0, 0)); + player.PlayerPawn.Value!.Teleport(bonusRespawnPoses[1]!, bonusRespawnAngs[1]!); } else { - player.PlayerPawn.Value!.Teleport(bonusRespawnPoses[1]!, new QAngle(player.PlayerPawn.Value.EyeAngles.X, player.PlayerPawn.Value.EyeAngles.Y, player.PlayerPawn.Value.EyeAngles.Z) ?? new QAngle(0, 0, 0), new Vector(0, 0, 0)); + player.PlayerPawn.Value!.Teleport(bonusRespawnPoses[1]!, player.PlayerPawn.Value?.EyeAngles.ToQAngle_t()); } - SharpTimerDebug($"{player.PlayerName} css_rb {1} to {bonusRespawnPoses[1]}"); + Utils.LogDebug($"{player.PlayerName} css_rb {1} to {bonusRespawnPoses[1]}"); } else { - PrintToChat(player, Localizer["no_respawnpos_bonus_index", 1]); + Utils.PrintToChat(player, Localizer["no_respawnpos_bonus_index", 1]); } Server.NextFrame(() => { - playerTimers[player.Slot].IsTimerRunning = false; - playerTimers[player.Slot].TimerTicks = 0; - playerTimers[player.Slot].IsBonusTimerRunning = false; - playerTimers[player.Slot].BonusTimerTicks = 0; + playerTimers[slot].IsTimerRunning = false; + playerTimers[slot].TimerTicks = 0; + playerTimers[slot].IsBonusTimerRunning = false; + playerTimers[slot].BonusTimerTicks = 0; }); return; } if (!int.TryParse(command.ArgString, out int bonusX)) { - SharpTimerDebug("css_rb conversion failed. The input string is not a valid integer."); - PrintToChat(player, Localizer["no_respawnpos_bonus_rb"]); + Utils.LogDebug("css_rb conversion failed. The input string is not a valid integer."); + Utils.PrintToChat(player, Localizer["no_respawnpos_bonus_rb"]); return; } // Remove checkpoints for the current player - if (!playerTimers[player.Slot].IsTimerBlocked) + if (!playerTimers[slot].IsTimerBlocked) { - playerCheckpoints.Remove(player.Slot); + playerCheckpoints.Remove(slot); } - if (jumpStatsEnabled) InvalidateJS(player.Slot); - if (bonusRespawnPoses[bonusX] != null) { - if (bonusRespawnAngs.TryGetValue(bonusX, out QAngle? bonusAng) && bonusAng != null) - { - player.PlayerPawn.Value!.Teleport(bonusRespawnPoses[bonusX]!, bonusRespawnAngs[bonusX]!, new Vector(0, 0, 0)); - } + if (bonusRespawnAngs.TryGetValue(bonusX, out QAngle_t? bonusAng) && bonusAng != null) + player.PlayerPawn.Value!.Teleport(bonusRespawnPoses[bonusX]!, bonusRespawnAngs[bonusX]!, new Vector_t(0, 0, 0)); else - { - player.PlayerPawn.Value!.Teleport(bonusRespawnPoses[bonusX]!, new QAngle(player.PlayerPawn.Value.EyeAngles.X, player.PlayerPawn.Value.EyeAngles.Y, player.PlayerPawn.Value.EyeAngles.Z) ?? new QAngle(0, 0, 0), new Vector(0, 0, 0)); - } - SharpTimerDebug($"{player.PlayerName} css_rb {bonusX} to {bonusRespawnPoses[bonusX]}"); + player.PlayerPawn.Value!.Teleport(bonusRespawnPoses[bonusX]!, player.PlayerPawn.Value?.EyeAngles.ToQAngle_t(), new Vector_t(0, 0, 0)); + + Utils.LogDebug($"{player.PlayerName} css_rb {bonusX} to {bonusRespawnPoses[bonusX]}"); } else - { - PrintToChat(player, Localizer["no_respawnpos_bonus"]); - } + Utils.PrintToChat(player, Localizer["no_respawnpos_bonus"]); Server.NextFrame(() => { - playerTimers[player.Slot].IsTimerRunning = false; - playerTimers[player.Slot].TimerTicks = 0; - playerTimers[player.Slot].IsBonusTimerRunning = false; - playerTimers[player.Slot].BonusTimerTicks = 0; - playerTimers[player.Slot].IsTimerBlocked = false; + playerTimers[slot].IsTimerRunning = false; + playerTimers[slot].TimerTicks = 0; + playerTimers[slot].IsBonusTimerRunning = false; + playerTimers[slot].BonusTimerTicks = 0; + playerTimers[slot].IsTimerBlocked = false; }); PlaySound(player, respawnSound); } catch (Exception ex) { - SharpTimerError($"Exception in RespawnBonusPlayer: {ex.Message}"); + Utils.LogError($"Exception in RespawnBonusPlayer: {ex.Message}"); } } @@ -1072,71 +978,73 @@ public void RespawnBonusPlayer(CCSPlayerController? player, CommandInfo command) [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] public void SetRespawnCommand(CCSPlayerController? player, CommandInfo command) { - if (!IsAllowedPlayer(player) || respawnEnabled == false) return; + if (!IsAllowedPlayer(player) || respawnEnabled == false) + return; - SharpTimerDebug($"{player!.PlayerName} calling css_startpos..."); + var slot = player!.Slot; + var playerName = player.PlayerName; + var steamID = player.SteamID.ToString(); - if (CommandCooldown(player)) - return; + Utils.LogDebug($"{playerName} calling css_startpos..."); if (ReplayCheck(player)) return; if (useTriggers == false) { - PrintToChat(player, Localizer["map_using_manual_zones"]); + Utils.PrintToChat(player, Localizer["map_using_manual_zones"]); return; } // Get the player's current position and rotation - Vector currentPosition = player.Pawn.Value!.CBodyComponent?.SceneNode?.AbsOrigin ?? new Vector(0, 0, 0); - QAngle currentRotation = player.PlayerPawn.Value!.EyeAngles ?? new QAngle(0, 0, 0); + Vector_t currentPosition = player.Pawn.Value!.CBodyComponent?.SceneNode?.AbsOrigin.ToVector_t() ?? new Vector_t(0, 0, 0); + QAngle_t currentRotation = player.PlayerPawn.Value!.EyeAngles.ToQAngle_t(); if (useTriggers == true) { - if (IsVectorInsideBox(currentPosition + new Vector(0, 0, 10), currentMapStartTriggerMaxs!, currentMapStartTriggerMins!)) + if (Utils.IsVectorInsideBox(currentPosition + new Vector_t(0, 0, 10), currentMapStartTriggerMaxs.GetValueOrDefault(), currentMapStartTriggerMins.GetValueOrDefault())) { // Convert position and rotation to strings string positionString = $"{currentPosition.X} {currentPosition.Y} {currentPosition.Z}"; string rotationString = $"{currentRotation.X} {currentRotation.Y} {currentRotation.Z}"; - playerTimers[player.Slot].SetRespawnPos = positionString; - playerTimers[player.Slot].SetRespawnAng = rotationString; - PrintToChat(player, Localizer["saved_custom_respawnpos"]); + playerTimers[slot].SetRespawnPos = positionString; + playerTimers[slot].SetRespawnAng = rotationString; + Utils.PrintToChat(player, Localizer["saved_custom_respawnpos"]); } else - { - PrintToChat(player, Localizer["not_inside_startzone"]); - } + Utils.PrintToChat(player, Localizer["not_inside_startzone"]); } else { - if (IsVectorInsideBox(currentPosition + new Vector(0, 0, 10), currentMapStartC1, currentMapStartC2)) + if (Utils.IsVectorInsideBox(currentPosition + new Vector_t(0, 0, 10), currentMapStartC1, currentMapStartC2)) { // Convert position and rotation to strings string positionString = $"{currentPosition.X} {currentPosition.Y} {currentPosition.Z}"; string rotationString = $"{currentRotation.X} {currentRotation.Y} {currentRotation.Z}"; - playerTimers[player.Slot].SetRespawnPos = positionString; - playerTimers[player.Slot].SetRespawnAng = rotationString; - PrintToChat(player, Localizer["saved_custom_respawnpos"]); + playerTimers[slot].SetRespawnPos = positionString; + playerTimers[slot].SetRespawnAng = rotationString; + Utils.PrintToChat(player, Localizer["saved_custom_respawnpos"]); } else - { - PrintToChat(player, Localizer["not_inside_startzone"]); - } + Utils.PrintToChat(player, Localizer["not_inside_startzone"]); } } [ConsoleCommand("css_stage", "Teleports you to a stage")] - [ConsoleCommand("css_s", "Teleports you to a stage")] [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] public void TPtoStagePlayer(CCSPlayerController? player, CommandInfo command) { try { - if (!IsAllowedPlayer(player) || respawnEnabled == false) return; - SharpTimerDebug($"{player!.PlayerName} calling css_stage..."); + if (!IsAllowedPlayer(player) || respawnEnabled == false) + return; + + var slot = player!.Slot; + var playerName = player.PlayerName; + + Utils.LogDebug($"{playerName} calling css_stage..."); if (CommandCooldown(player)) return; @@ -1144,8 +1052,6 @@ public void TPtoStagePlayer(CCSPlayerController? player, CommandInfo command) if (ReplayCheck(player)) return; - playerTimers[player.Slot].TicksSinceLastCmd = 0; - QuietStopTimer(player); if (IsTimerBlocked(player)) @@ -1153,50 +1059,48 @@ public void TPtoStagePlayer(CCSPlayerController? player, CommandInfo command) if (!int.TryParse(command.ArgString, out int stageX)) { - SharpTimerDebug("css_stage conversion failed. The input string is not a valid integer."); - PrintToChat(player, Localizer["stages_enter_valid"]); + Utils.LogDebug("css_stage conversion failed. The input string is not a valid integer."); + Utils.PrintToChat(player, Localizer["stages_enter_valid"]); return; } if (useStageTriggers == false) { - SharpTimerDebug("css_stage failed useStages is false."); - PrintToChat(player, Localizer["stages_unavalible"]); + Utils.LogDebug("css_stage failed useStages is false."); + Utils.PrintToChat(player, Localizer["stages_unavalible"]); return; } // Remove checkpoints for the current player - if (!playerTimers[player.Slot].IsTimerBlocked) + if (!playerTimers[slot].IsTimerBlocked) { - playerCheckpoints.Remove(player.Slot); + playerCheckpoints.Remove(slot); } - if (jumpStatsEnabled) InvalidateJS(player.Slot); - - if (stageTriggerPoses.TryGetValue(stageX, out Vector? stagePos) && stagePos != null) + if (stageTriggerPoses.TryGetValue(stageX, out Vector_t? stagePos) && stagePos != null) { - player.PlayerPawn.Value!.Teleport(stagePos, stageTriggerAngs[stageX] ?? player.PlayerPawn.Value.EyeAngles, new Vector(0, 0, 0)); - SharpTimerDebug($"{player.PlayerName} css_stage {stageX} to {stagePos}"); + player.PlayerPawn.Value!.Teleport(stagePos, stageTriggerAngs[stageX] ?? player.PlayerPawn.Value?.EyeAngles.ToQAngle_t(), new Vector_t(0, 0, 0)); + Utils.LogDebug($"{player.PlayerName} css_stage {stageX} to {stagePos}"); } else { - PrintToChat(player, Localizer["stages_unavalible_respawnpos", stageX]); + Utils.PrintToChat(player, Localizer["stages_unavalible_respawnpos", stageX]); } Server.NextFrame(() => { - playerTimers[player.Slot].IsTimerRunning = false; - playerTimers[player.Slot].TimerTicks = 0; - playerTimers[player.Slot].IsBonusTimerRunning = false; - playerTimers[player.Slot].BonusTimerTicks = 0; - playerTimers[player.Slot].IsTimerBlocked = false; + playerTimers[slot].IsTimerRunning = false; + playerTimers[slot].TimerTicks = 0; + playerTimers[slot].IsBonusTimerRunning = false; + playerTimers[slot].BonusTimerTicks = 0; + playerTimers[slot].IsTimerBlocked = false; }); PlaySound(player, respawnSound); } catch (Exception ex) { - SharpTimerError($"Exception in TPtoStagePlayer: {ex.Message}"); + Utils.LogError($"Exception in TPtoStagePlayer: {ex.Message}"); } } @@ -1204,55 +1108,62 @@ public void TPtoStagePlayer(CCSPlayerController? player, CommandInfo command) [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] public void RespawnPlayerCommand(CCSPlayerController? player, CommandInfo command) { - if (!IsAllowedPlayer(player) || respawnEnabled == false) return; - SharpTimerDebug($"{player!.PlayerName} calling css_r..."); + if (!IsAllowedPlayer(player) || respawnEnabled == false) + return; - if (CommandCooldown(player)) + var slot = player!.Slot; + var playerName = player.PlayerName; + + Utils.LogDebug($"{playerName} calling css_r..."); + + if (CommandCooldown(player)) return; - if (playerTimers[player.Slot].IsReplaying) + if (playerTimers[slot].IsReplaying) { - PrintToChat(player, Localizer["ending_replay"]); - playerTimers[player.Slot].IsReplaying = false; + Utils.PrintToChat(player, Localizer["ending_replay"]); + playerTimers[slot].IsReplaying = false; + if (player.PlayerPawn.Value!.MoveType != MoveType_t.MOVETYPE_WALK || player.PlayerPawn.Value.ActualMoveType == MoveType_t.MOVETYPE_WALK) SetMoveType(player, MoveType_t.MOVETYPE_WALK); - playerReplays.Remove(player.Slot); - playerReplays[player.Slot] = new PlayerReplays(); - playerTimers[player.Slot].IsTimerBlocked = false; - playerTimers[player.Slot].IsTimerRunning = false; - playerTimers[player.Slot].TimerTicks = 0; - playerTimers[player.Slot].StageTicks = 0; - playerTimers[player.Slot].IsBonusTimerRunning = false; - playerTimers[player.Slot].BonusTimerTicks = 0; - playerReplays[player.Slot].CurrentPlaybackFrame = 0; - if (stageTriggers.Count != 0) playerTimers[player.Slot].StageTimes!.Clear(); //remove previous stage times if the map has stages - if (stageTriggers.Count != 0) playerTimers[player.Slot].StageVelos!.Clear(); //remove previous stage times if the map has stages - RespawnPlayer(player); - } - else - { - playerTimers[player.Slot].TicksSinceLastCmd = 0; + playerReplays.Remove(slot); + + playerReplays[slot] = new PlayerReplays(); + playerTimers[slot].IsTimerBlocked = false; + playerTimers[slot].IsTimerRunning = false; + playerTimers[slot].TimerTicks = 0; + playerTimers[slot].StageTicks = 0; + playerTimers[slot].IsBonusTimerRunning = false; + playerTimers[slot].BonusTimerTicks = 0; + playerReplays[slot].CurrentPlaybackFrame = 0; + + if (stageTriggers.Count != 0) playerTimers[slot].StageTimes!.Clear(); //remove previous stage times if the map has stages + if (stageTriggers.Count != 0) playerTimers[slot].StageVelos!.Clear(); //remove previous stage times if the map has stages + RespawnPlayer(player); } + + else RespawnPlayer(player); } [ConsoleCommand("css_end", "Teleports you to end")] [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] public void EndPlayerCommand(CCSPlayerController? player, CommandInfo command) { - if (!IsAllowedPlayer(player) || respawnEndEnabled == false) return; - SharpTimerDebug($"{player!.PlayerName} calling css_end..."); - - if (CommandCooldown(player)) + if (!IsAllowedPlayer(player) || respawnEndEnabled == false) return; - if (ReplayCheck(player)) + var slot = player!.Slot; + var playerName = player.PlayerName; + + Utils.LogDebug($"{playerName} calling css_end..."); + + if (CommandCooldown(player)) return; - playerTimers[player.Slot].TicksSinceLastCmd = 0; - playerTimers[player.Slot].IsTimerRunning = false; - playerTimers[player.Slot].TimerTicks = 0; - playerTimers[player.Slot].IsBonusTimerRunning = false; - playerTimers[player.Slot].BonusTimerTicks = 0; + playerTimers[slot].IsTimerRunning = false; + playerTimers[slot].TimerTicks = 0; + playerTimers[slot].IsBonusTimerRunning = false; + playerTimers[slot].BonusTimerTicks = 0; Server.NextFrame(() => RespawnPlayer(player, true)); } @@ -1262,105 +1173,82 @@ public void EndPlayerCommand(CCSPlayerController? player, CommandInfo command) [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] public void NoclipCommand(CCSPlayerController? player, CommandInfo command) { - if (enableNoclip == false) return; - SharpTimerDebug($"{player!.PlayerName} calling css_noclip..."); - - if (ReplayCheck(player)) - return; - - if (IsTimerBlocked(player)) + if (player == null || !player.PawnIsAlive || (enableNoclip == false && !AdminManager.PlayerHasPermissions(player, "@css/cheats"))) return; - playerTimers[player.Slot].TicksSinceLastCmd = 0; - playerTimers[player.Slot].IsTimerRunning = false; - playerTimers[player.Slot].TimerTicks = 0; - playerTimers[player.Slot].IsBonusTimerRunning = false; - playerTimers[player.Slot].BonusTimerTicks = 0; + var slot = player!.Slot; + var playerName = player.PlayerName; + var pawn = player.Pawn.Value!; - if (player!.Pawn.Value!.MoveType == MoveType_t.MOVETYPE_NOCLIP) - { - player!.Pawn.Value!.MoveType = MoveType_t.MOVETYPE_WALK; - Schema.SetSchemaValue(player!.Pawn.Value!.Handle, "CBaseEntity", "m_nActualMoveType", 2); // walk - Utilities.SetStateChanged(player!.Pawn.Value!, "CBaseEntity", "m_MoveType"); - playerTimers[player.Slot].IsNoclip = false; - } - else - { - player!.Pawn.Value!.MoveType = MoveType_t.MOVETYPE_NOCLIP; - Schema.SetSchemaValue(player!.Pawn.Value!.Handle, "CBaseEntity", "m_nActualMoveType", 8); // noclip - Utilities.SetStateChanged(player!.Pawn.Value!, "CBaseEntity", "m_MoveType"); - playerTimers[player.Slot].IsNoclip = true; - } - } + Utils.LogDebug($"{playerName} calling css_noclip..."); - [ConsoleCommand("css_adminnoclip", "Admin Noclip")] - [ConsoleCommand("css_adminnc", "Admin Noclip")] - [RequiresPermissions("@css/cheats")] - [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] - public void AdminNoclipCommand(CCSPlayerController? player, CommandInfo command) - { - SharpTimerDebug($"{player!.PlayerName} calling css_adminnoclip..."); + if (CommandCooldown(player)) + return; - if (ReplayCheck(player)) + if (IsTimerBlocked(player)) return; - playerTimers[player.Slot].TicksSinceLastCmd = 0; - playerTimers[player.Slot].IsTimerRunning = false; - playerTimers[player.Slot].TimerTicks = 0; - playerTimers[player.Slot].IsBonusTimerRunning = false; - playerTimers[player.Slot].BonusTimerTicks = 0; - playerTimers[player.Slot].IsTimerBlocked = false; + playerTimers[slot].IsTimerRunning = false; + playerTimers[slot].TimerTicks = 0; + playerTimers[slot].IsBonusTimerRunning = false; + playerTimers[slot].BonusTimerTicks = 0; - if (player!.Pawn.Value!.MoveType == MoveType_t.MOVETYPE_NOCLIP) + if (playerTimers[slot].IsNoclip) { - player!.Pawn.Value!.MoveType = MoveType_t.MOVETYPE_WALK; - Schema.SetSchemaValue(player!.Pawn.Value!.Handle, "CBaseEntity", "m_nActualMoveType", 2); // walk - Utilities.SetStateChanged(player!.Pawn.Value!, "CBaseEntity", "m_MoveType"); + pawn.MoveType = MoveType_t.MOVETYPE_WALK; + Schema.SetSchemaValue(pawn.Handle, "CBaseEntity", "m_nActualMoveType", 2); // walk + Utilities.SetStateChanged(pawn, "CBaseEntity", "m_MoveType"); + playerTimers[slot].IsNoclip = false; } else { - QuietStopTimer(player); - player!.Pawn.Value!.MoveType = MoveType_t.MOVETYPE_NOCLIP; - Schema.SetSchemaValue(player!.Pawn.Value!.Handle, "CBaseEntity", "m_nActualMoveType", 8); // noclip - Utilities.SetStateChanged(player!.Pawn.Value!, "CBaseEntity", "m_MoveType"); + pawn.MoveType = MoveType_t.MOVETYPE_NOCLIP; + Schema.SetSchemaValue(pawn.Handle, "CBaseEntity", "m_nActualMoveType", 8); // noclip + Utilities.SetStateChanged(pawn, "CBaseEntity", "m_MoveType"); + playerTimers[slot].IsNoclip = true; } } - [ConsoleCommand("css_styles", "Styles command")] [ConsoleCommand("css_style", "Styles command")] [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] public void StyleCommand(CCSPlayerController? player, CommandInfo command) { - if (!IsAllowedPlayer(player)) return; + if (!IsAllowedPlayer(player)) + return; + + var slot = player!.Slot; + var playerName = player.PlayerName; if (ReplayCheck(player)) return; if (!isLinux && !enableDb) { - PrintToChat(player, Localizer["styles_not_supported"]); + Utils.PrintToChat(player, Localizer["styles_not_supported"]); return; } if (!enableStyles) { - PrintToChat(player, Localizer["styles_disabled"]); + Utils.PrintToChat(player, Localizer["styles_disabled"]); return; } if (!player!.PlayerPawn.Value!.AbsVelocity.IsZero()) { - PrintToChat(player, Localizer["styles_moving"]); + Utils.PrintToChat(player, Localizer["styles_moving"]); return; } - SharpTimerDebug($"{player!.PlayerName} calling css_style..."); + Utils.LogDebug($"{playerName} calling css_style..."); + + if (CommandCooldown(player)) + return; - playerTimers[player.Slot].TicksSinceLastCmd = 0; - playerTimers[player.Slot].IsTimerRunning = false; - playerTimers[player.Slot].TimerTicks = 0; - playerTimers[player.Slot].IsBonusTimerRunning = false; - playerTimers[player.Slot].BonusTimerTicks = 0; + playerTimers[slot].IsTimerRunning = false; + playerTimers[slot].TimerTicks = 0; + playerTimers[slot].IsBonusTimerRunning = false; + playerTimers[slot].BonusTimerTicks = 0; var desiredStyle = command.GetArg(1); @@ -1368,9 +1256,9 @@ public void StyleCommand(CCSPlayerController? player, CommandInfo command) { for (int i = 0; i < 13; i++) //runs 13 times for the 13 styles { - PrintToChat(player, Localizer["styles_list", i, GetNamedStyle(i)]); + Utils.PrintToChat(player, Localizer["styles_list", i, GetNamedStyle(i)]); } - PrintToChat(player, Localizer["style_example"]); + Utils.PrintToChat(player, Localizer["style_example"]); return; } @@ -1392,12 +1280,13 @@ public void StyleCommand(CCSPlayerController? player, CommandInfo command) case 11: case 12: setStyle(player, desiredStyleInt); - PrintToChat(player, Localizer["style_set", GetNamedStyle(desiredStyleInt)]); + Utils.PrintToChat(player, Localizer["style_set", GetNamedStyle(desiredStyleInt)]); break; default: - PrintToChat(player, Localizer["style_not_found", desiredStyleInt]); + Utils.PrintToChat(player, Localizer["style_not_found", desiredStyleInt]); break; } + RespawnPlayer(player); } else { @@ -1408,72 +1297,73 @@ public void StyleCommand(CCSPlayerController? player, CommandInfo command) case "normal": case "nrm": setStyle(player, 0); - PrintToChat(player, Localizer["style_set", GetNamedStyle(0)]); + Utils.PrintToChat(player, Localizer["style_set", GetNamedStyle(0)]); break; case "lowgravity": case "lowgrav": case "lg": setStyle(player, 1); - PrintToChat(player, Localizer["style_set", GetNamedStyle(1)]); + Utils.PrintToChat(player, Localizer["style_set", GetNamedStyle(1)]); break; case "sideways": case "sw": setStyle(player, 2); - PrintToChat(player, Localizer["style_set", GetNamedStyle(2)]); + Utils.PrintToChat(player, Localizer["style_set", GetNamedStyle(2)]); break; case "wonly": case "onlyw": setStyle(player, 3); - PrintToChat(player, Localizer["style_set", GetNamedStyle(3)]); + Utils.PrintToChat(player, Localizer["style_set", GetNamedStyle(3)]); break; case "400vel": setStyle(player, 4); - PrintToChat(player, Localizer["style_set", GetNamedStyle(4)]); + Utils.PrintToChat(player, Localizer["style_set", GetNamedStyle(4)]); break; case "highgravity": case "highgrav": case "hg": setStyle(player, 5); - PrintToChat(player, Localizer["style_set", GetNamedStyle(5)]); + Utils.PrintToChat(player, Localizer["style_set", GetNamedStyle(5)]); break; case "aonly": case "onlya": setStyle(player, 6); - PrintToChat(player, Localizer["style_set", GetNamedStyle(6)]); + Utils.PrintToChat(player, Localizer["style_set", GetNamedStyle(6)]); break; case "donly": case "onlyd": setStyle(player, 7); - PrintToChat(player, Localizer["style_set", GetNamedStyle(7)]); + Utils.PrintToChat(player, Localizer["style_set", GetNamedStyle(7)]); break; case "sonly": case "onlys": setStyle(player, 8); - PrintToChat(player, Localizer["style_set", GetNamedStyle(8)]); + Utils.PrintToChat(player, Localizer["style_set", GetNamedStyle(8)]); break; case "halfsideways": case "hsw": setStyle(player, 9); - PrintToChat(player, Localizer["style_set", GetNamedStyle(9)]); + Utils.PrintToChat(player, Localizer["style_set", GetNamedStyle(9)]); break; case "fastforward": case "ff": setStyle(player, 10); - PrintToChat(player, Localizer["style_set", GetNamedStyle(10)]); + Utils.PrintToChat(player, Localizer["style_set", GetNamedStyle(10)]); break; case "parachute": case "para": setStyle(player, 11); - PrintToChat(player, Localizer["style_set", GetNamedStyle(11)]); + Utils.PrintToChat(player, Localizer["style_set", GetNamedStyle(11)]); break; case "tas": setStyle(player, 12); - PrintToChat(player, Localizer["style_set", GetNamedStyle(12)]); + Utils.PrintToChat(player, Localizer["style_set", GetNamedStyle(12)]); break; default: - PrintToChat(player, Localizer["style_not_found", styleLowerCase]); + Utils.PrintToChat(player, Localizer["style_not_found", styleLowerCase]); break; } + RespawnPlayer(player); } } @@ -1481,11 +1371,15 @@ public void StyleCommand(CCSPlayerController? player, CommandInfo command) [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] public void RanksCommand(CCSPlayerController? player, CommandInfo command) { - if (!IsAllowedPlayer(player)) return; + if (!IsAllowedPlayer(player)) + return; + + if (CommandCooldown(player!)) + return; if (!rankEnabled) { - PrintToChat(player, "This server has not enabled ranks"); + Utils.PrintToChat(player!, "This server has not enabled ranks"); return; } @@ -1493,82 +1387,70 @@ public void RanksCommand(CCSPlayerController? player, CommandInfo command) rankDataList .Where(rank => rank.Title != UnrankedTitle) .OrderByDescending(rank => rank.Percent) - .Select(rank => ReplaceVars($"{rank.Color}{rank.Title.Replace("[", "").Replace("]", "")}")) + .Select(rank => Utils.ReplaceVars($"{rank.Color}{rank.Title.Replace("[", "").Replace("]", "")}")) ); - PrintToChat(player, $"{rankList}"); + Utils.PrintToChat(player!, $"{rankList}"); } - public void RespawnPlayer(CCSPlayerController? player, bool toEnd = false) + public void RespawnPlayer(CCSPlayerController player, bool toEnd = false) { try { - // Remove checkpoints for the current player - if (!playerTimers[player!.Slot].IsTimerBlocked) - { - playerCheckpoints.Remove(player.Slot); - } + var slot = player.Slot; - if (jumpStatsEnabled) InvalidateJS(player.Slot); + // Remove checkpoints for the current player + if (!playerTimers[slot].IsTimerBlocked) + playerCheckpoints.Remove(slot); if (stageTriggerCount != 0 || cpTriggerCount != 0)//remove previous stage times and checkpoints if the map has stages or checkpoints { - playerTimers[player.Slot].StageTimes!.Clear(); - playerTimers[player.Slot].CurrentMapCheckpoint = 0; + playerTimers[slot].StageTimes!.Clear(); + playerTimers[slot].CurrentMapCheckpoint = 0; } if (toEnd == false) { - if (currentRespawnPos != null && playerTimers[player.Slot].SetRespawnPos == null) + if (currentRespawnPos != null && playerTimers[slot].SetRespawnPos == null) { if (currentRespawnAng != null) - { - player.PlayerPawn.Value!.Teleport(currentRespawnPos, currentRespawnAng, new Vector(0, 0, 0)); - } + player.PlayerPawn.Value!.Teleport(currentRespawnPos, currentRespawnAng); else - { - player.PlayerPawn.Value!.Teleport(currentRespawnPos, player.PlayerPawn.Value.EyeAngles ?? new QAngle(0, 0, 0), new Vector(0, 0, 0)); - } - SharpTimerDebug($"{player.PlayerName} css_r to {currentRespawnPos}"); + player.PlayerPawn.Value!.Teleport(currentRespawnPos, player.PlayerPawn.Value?.EyeAngles.ToQAngle_t()); + + Utils.LogDebug($"{player.PlayerName} css_r to {currentRespawnPos}"); } else { - if (playerTimers[player.Slot].SetRespawnPos != null && playerTimers[player.Slot].SetRespawnAng != null) - { - player.PlayerPawn.Value!.Teleport(ParseVector(playerTimers[player.Slot].SetRespawnPos!), ParseQAngle(playerTimers[player.Slot].SetRespawnAng!), new Vector(0, 0, 0)); - } + if (playerTimers[slot].SetRespawnPos != null && playerTimers[slot].SetRespawnAng != null) + player.PlayerPawn.Value!.Teleport(Utils.ParseVector_t(playerTimers[slot].SetRespawnPos!), Utils.ParseQAngle_t(playerTimers[slot].SetRespawnAng!)); else - { - PrintToChat(player, Localizer["no_respawnpos"]); - } + Utils.PrintToChat(player, Localizer["no_respawnpos"]); } } else { if (currentEndPos != null) - { - player.PlayerPawn.Value!.Teleport(currentEndPos, player.PlayerPawn.Value.EyeAngles ?? new QAngle(0, 0, 0), new Vector(0, 0, 0)); - } + player.PlayerPawn.Value!.Teleport(currentEndPos, player.PlayerPawn.Value?.EyeAngles.ToQAngle_t(), new Vector_t(0, 0, 0)); else - { - PrintToChat(player, Localizer["no_endpos"]); - } + Utils.PrintToChat(player, Localizer["no_endpos"]); } Server.NextFrame(() => { - playerTimers[player.Slot].IsTimerRunning = false; - playerTimers[player.Slot].TimerTicks = 0; - playerTimers[player.Slot].StageTicks = 0; - playerTimers[player.Slot].IsBonusTimerRunning = false; - playerTimers[player.Slot].BonusTimerTicks = 0; - playerTimers[player.Slot].IsTimerBlocked = false; + playerTimers[slot].IsTimerRunning = false; + playerTimers[slot].TimerTicks = 0; + playerTimers[slot].StageTicks = 0; + playerTimers[slot].IsBonusTimerRunning = false; + playerTimers[slot].BonusTimerTicks = 0; + playerTimers[slot].IsTimerBlocked = false; }); + PlaySound(player, respawnSound); } catch (Exception ex) { - SharpTimerError($"Exception in RespawnPlayer: {ex.Message}"); + Utils.LogError($"Exception in RespawnPlayer: {ex.Message}"); } } @@ -1576,27 +1458,31 @@ public void RespawnPlayer(CCSPlayerController? player, bool toEnd = false) [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] public void RestartCurrentStageCmd(CCSPlayerController? player, CommandInfo command) { - if (!IsAllowedPlayer(player)) return; + if (!IsAllowedPlayer(player)) + return; + + var slot = player!.Slot; + var playerName = player.PlayerName; + + Utils.LogDebug($"{playerName} calling css_rs..."); if (CommandCooldown(player)) return; - SharpTimerDebug($"{player!.PlayerName} calling css_rs..."); - if (stageTriggerCount == 0) { if (enableRsOnLinear) { player.ExecuteClientCommandFromServer("css_r"); return; } - PrintToChat(player, Localizer["map_no_stages"]); + Utils.PrintToChat(player, Localizer["map_no_stages"]); return; } - if (!playerTimers.TryGetValue(player.Slot, out PlayerTimerInfo? playerTimer) || playerTimer.CurrentMapStage == 0) + if (!playerTimers.TryGetValue(slot, out PlayerTimerInfo? playerTimer) || playerTimer.CurrentMapStage == 0) { - PrintToChat(player, Localizer["error_occured"]); - SharpTimerDebug("Failed to get playerTimer or playerTimer.CurrentMapStage == 0."); + Utils.PrintToChat(player, Localizer["error_occured"]); + Utils.LogDebug("Failed to get playerTimer or playerTimer.CurrentMapStage == 0."); return; } @@ -1604,22 +1490,18 @@ public void RestartCurrentStageCmd(CCSPlayerController? player, CommandInfo comm try { - playerTimers[player.Slot].TicksSinceLastCmd = 0; - - if (stageTriggerPoses.TryGetValue(currStage, out Vector? stagePos) && stagePos != null) + if (stageTriggerPoses.TryGetValue(currStage, out Vector_t? stagePos) && stagePos != null) { - if (jumpStatsEnabled) InvalidateJS(player.Slot); - player.PlayerPawn.Value!.Teleport(stagePos, stageTriggerAngs[currStage] ?? player.PlayerPawn.Value.EyeAngles, new Vector(0, 0, 0)); - SharpTimerDebug($"{player.PlayerName} css_rs {player.PlayerName}"); + player.PlayerPawn.Value!.Teleport(stagePos, stageTriggerAngs[currStage] ?? player.PlayerPawn.Value?.EyeAngles.ToQAngle_t(), new Vector_t(0, 0, 0)); + + Utils.LogDebug($"{playerName} css_rs"); } else - { - PrintToChat(player, Localizer["stages_unavalible_respawnpos"]); - } + Utils.PrintToChat(player, Localizer["stages_unavalible_respawnpos"]); } catch (Exception ex) { - SharpTimerError($"Exception in RestartCurrentStage: {ex.Message}"); + Utils.LogError($"Exception in RestartCurrentStage: {ex.Message}"); } } @@ -1627,8 +1509,13 @@ public void RestartCurrentStageCmd(CCSPlayerController? player, CommandInfo comm [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] public void ForceStopTimer(CCSPlayerController? player, CommandInfo command) { - if (!IsAllowedPlayer(player)) return; - SharpTimerDebug($"{player!.PlayerName} calling css_timer..."); + if (!IsAllowedPlayer(player)) + return; + + var slot = player!.Slot; + var playerName = player.PlayerName; + + Utils.LogDebug($"{playerName} calling css_timer..."); if (CommandCooldown(player)) return; @@ -1636,47 +1523,56 @@ public void ForceStopTimer(CCSPlayerController? player, CommandInfo command) if (ReplayCheck(player)) return; - playerTimers[player.Slot].TicksSinceLastCmd = 0; - // Remove checkpoints for the current player - playerCheckpoints.Remove(player.Slot); + playerCheckpoints.Remove(slot); - playerTimers[player.Slot].IsTimerBlocked = playerTimers[player.Slot].IsTimerBlocked ? false : true; - playerTimers[player.Slot].IsRecordingReplay = false; + playerTimers[slot].IsTimerBlocked = !playerTimers[slot].IsTimerBlocked; + playerTimers[slot].IsRecordingReplay = false; - - if (playerTimers[player.Slot].IsTimerBlocked) - PrintToChat(player, Localizer["timer_disabled"]); + if (playerTimers[slot].IsTimerBlocked) + Utils.PrintToChat(player, Localizer["timer_disabled"]); else - PrintToChat(player, Localizer["timer_enabled"]); + Utils.PrintToChat(player, Localizer["timer_enabled"]); + + playerTimers[slot].IsTimerRunning = false; + playerTimers[slot].TimerTicks = 0; + playerTimers[slot].IsBonusTimerRunning = false; + playerTimers[slot].BonusTimerTicks = 0; + + if (stageTriggers.Count != 0) playerTimers[slot].StageTimes!.Clear(); //remove previous stage times if the map has stages + if (stageTriggers.Count != 0) playerTimers[slot].StageVelos!.Clear(); //remove previous stage times if the map has stages - playerTimers[player.Slot].IsTimerRunning = false; - playerTimers[player.Slot].TimerTicks = 0; - playerTimers[player.Slot].IsBonusTimerRunning = false; - playerTimers[player.Slot].BonusTimerTicks = 0; + // fix timer toggle bug + if (!playerTimers[slot].IsTimerBlocked) + { + Vector_t playerPos = player.Pawn?.Value!.CBodyComponent?.SceneNode!.AbsOrigin.ToVector_t() ?? new(); + bool isInsideStartBox = Utils.IsVectorInsideBox(playerPos, currentMapStartC1, currentMapStartC2); + playerTimers[slot].inStartzone = isInsideStartBox; // Only set to true if player is actually in the start zone + } + else playerTimers[slot].inStartzone = false; - if (stageTriggers.Count != 0) playerTimers[player.Slot].StageTimes!.Clear(); //remove previous stage times if the map has stages - if (stageTriggers.Count != 0) playerTimers[player.Slot].StageVelos!.Clear(); //remove previous stage times if the map has stages PlaySound(player, timerSound); - SharpTimerDebug($"{player.PlayerName} css_timer to {playerTimers[player.Slot].IsTimerBlocked}"); + Utils.LogDebug($"{player.PlayerName} css_timer to {playerTimers[slot].IsTimerBlocked}"); } - public void QuietStopTimer(CCSPlayerController? player) + public void QuietStopTimer(CCSPlayerController player) { - playerTimers[player!.Slot].TicksSinceLastCmd = 0; + var slot = player!.Slot; // Remove checkpoints for the current player - playerCheckpoints.Remove(player.Slot); + if (playerCheckpoints.ContainsKey(slot)) + playerCheckpoints.Remove(slot); - playerTimers[player.Slot].IsTimerBlocked = true; - playerTimers[player.Slot].IsRecordingReplay = false; - playerTimers[player.Slot].IsTimerRunning = false; - playerTimers[player.Slot].TimerTicks = 0; - playerTimers[player.Slot].IsBonusTimerRunning = false; - playerTimers[player.Slot].BonusTimerTicks = 0; + playerTimers[slot].IsTimerBlocked = true; + playerTimers[slot].IsRecordingReplay = false; + playerTimers[slot].IsTimerRunning = false; + playerTimers[slot].TimerTicks = 0; + playerTimers[slot].IsBonusTimerRunning = false; + playerTimers[slot].BonusTimerTicks = 0; + + if (stageTriggers.Count != 0) playerTimers[slot].StageTimes!.Clear(); //remove previous stage times if the map has stages + if (stageTriggers.Count != 0) playerTimers[slot].StageVelos!.Clear(); //remove previous stage times if the map has stages - if (stageTriggers.Count != 0) playerTimers[player.Slot].StageTimes!.Clear(); //remove previous stage times if the map has stages - if (stageTriggers.Count != 0) playerTimers[player.Slot].StageVelos!.Clear(); //remove previous stage times if the map has stages PlaySound(player, timerSound); } @@ -1684,22 +1580,20 @@ public void QuietStopTimer(CCSPlayerController? player) [CommandHelper(whoCanExecute: CommandUsage.CLIENT_AND_SERVER)] public void STVerCommand(CCSPlayerController? player, CommandInfo command) { - if (!IsAllowedPlayer(player)) + if (player == null || !IsPlayerOrSpectator(player)) { - SharpTimerConPrint($"This server is running SharpTimer v{ModuleVersion}"); - SharpTimerConPrint($"OS: {RuntimeInformation.OSDescription}"); - SharpTimerConPrint($"Runtime: {RuntimeInformation.RuntimeIdentifier}"); + Utils.ConPrint($"This server is running SharpTimer v{ModuleVersion}"); + Utils.ConPrint($"OS: {RuntimeInformation.OSDescription}"); + Utils.ConPrint($"Runtime: {RuntimeInformation.RuntimeIdentifier}"); return; } if (CommandCooldown(player)) return; - playerTimers[player!.Slot].TicksSinceLastCmd = 0; - - PrintToChat(player, Localizer["info_version", ModuleVersion]); - PrintToChat(player, Localizer["info_os", RuntimeInformation.OSDescription]); - PrintToChat(player, Localizer["info_runtime", RuntimeInformation.RuntimeIdentifier]); + Utils.PrintToChat(player, Localizer["info_version", ModuleVersion]); + Utils.PrintToChat(player, Localizer["info_os", RuntimeInformation.OSDescription]); + Utils.PrintToChat(player, Localizer["info_runtime", RuntimeInformation.RuntimeIdentifier]); } [ConsoleCommand("css_hide", "Hides players")] @@ -1709,22 +1603,23 @@ public void HideCommand(CCSPlayerController? player, CommandInfo command) if (!IsAllowedPlayer(player)) return; + var slot = player!.Slot; + var playerName = player.PlayerName; + var steamID = player.SteamID.ToString(); + if (CommandCooldown(player)) return; - - var playerName = player!.PlayerName; - var playerSlot = player.Slot; - var steamID = player.SteamID.ToString(); - playerTimers[player!.Slot].TicksSinceLastCmd = 0; - playerTimers[player!.Slot].HidePlayers = !playerTimers[player!.Slot].HidePlayers; + bool hidingPlayers = !playerTimers[slot].HidePlayers; + + playerTimers[slot].HidePlayers = hidingPlayers; - _ = Task.Run(async () => await SetPlayerStats(player, steamID, playerName, playerSlot)); + _ = Task.Run(async () => await SetPlayerStats(player, steamID, playerName, slot)); - if (playerTimers[player!.Slot].HidePlayers) - PrintToChat(player, $"Hide: {ChatColors.Green}Enabled"); + if (hidingPlayers) + Utils.PrintToChat(player, $"Hide: {ChatColors.Green}Enabled"); else - PrintToChat(player, $"Hide: {ChatColors.LightRed}Disabled"); + Utils.PrintToChat(player, $"Hide: {ChatColors.LightRed}Disabled"); } /* [ConsoleCommand("css_mode", "Changes mode")] @@ -1732,7 +1627,7 @@ public void HideCommand(CCSPlayerController? player, CommandInfo command) public void ModeCommand(CCSPlayerController? player, CommandInfo command) { if (!IsAllowedPlayer(player) || goToEnabled == false) return; - SharpTimerDebug($"{player!.PlayerName} calling css_mode..."); + Utils.LogDebug($"{playerName} calling css_mode..."); if (CommandCooldown(player)) return; @@ -1743,34 +1638,39 @@ public void ModeCommand(CCSPlayerController? player, CommandInfo command) if (IsTimerBlocked(player)) return; - playerTimers[player.Slot].TicksSinceLastCmd = 0; + playerTimers[slot].TicksSinceLastCmd = 0; string mode = command.GetArg(1).ToLower(); switch(mode) { case "classic": - playerTimers[player.Slot].Mode = PlayerTimerInfo.CurrentMode.Classic; + playerTimers[slot].Mode = PlayerTimerInfo.CurrentMode.Classic; SetModeClassic(player); break; case "arcade": - playerTimers[player.Slot].Mode = PlayerTimerInfo.CurrentMode.Arcade; + playerTimers[slot].Mode = PlayerTimerInfo.CurrentMode.Arcade; SetModeArcade(player); break; default: - playerTimers[player.Slot].Mode = PlayerTimerInfo.CurrentMode.Classic; + playerTimers[slot].Mode = PlayerTimerInfo.CurrentMode.Classic; SetModeClassic(player); break; } - Server.NextFrame(() => PrintToChat(player, $"Mode changed to: {playerTimers[player.Slot].Mode.ToString()}")); + Server.NextFrame(() => Utils.PrintToChat(player, $"Mode changed to: {playerTimers[slot].Mode.ToString()}")); } */ [ConsoleCommand("css_goto", "Teleports you to a player")] [CommandHelper(minArgs: 1, usage: "[name]", whoCanExecute: CommandUsage.CLIENT_ONLY)] public void GoToPlayer(CCSPlayerController? player, CommandInfo command) { - if (!IsAllowedPlayer(player) || goToEnabled == false) return; - SharpTimerDebug($"{player!.PlayerName} calling css_goto..."); + if (!IsAllowedPlayer(player) || goToEnabled == false) + return; + + var slot = player!.Slot; + var playerName = player.PlayerName; + + Utils.LogDebug($"{playerName} calling css_goto..."); if (CommandCooldown(player)) return; @@ -1781,8 +1681,6 @@ public void GoToPlayer(CCSPlayerController? player, CommandInfo command) if (IsTimerBlocked(player)) return; - playerTimers[player.Slot].TicksSinceLastCmd = 0; - var name = command.GetArg(1); bool isPlayerFound = false; CCSPlayerController foundPlayer = null!; @@ -1799,34 +1697,32 @@ public void GoToPlayer(CCSPlayerController? player, CommandInfo command) if (!isPlayerFound) { - PrintToChat(player, Localizer["goto_player_not_found"]); + Utils.PrintToChat(player, Localizer["goto_player_not_found"]); return; } - if (!playerTimers[player.Slot].IsTimerBlocked) - playerCheckpoints.Remove(player.Slot); + if (!playerTimers[slot].IsTimerBlocked) + playerCheckpoints.Remove(slot); - playerTimers[player.Slot].IsTimerRunning = false; - playerTimers[player.Slot].TimerTicks = 0; + playerTimers[slot].IsTimerRunning = false; + playerTimers[slot].TimerTicks = 0; PlaySound(player, respawnSound); - if (foundPlayer != null && playerTimers[player.Slot].IsTimerBlocked) + if (foundPlayer != null && playerTimers[slot].IsTimerBlocked) { - PrintToChat(player, Localizer["goto_player", foundPlayer.PlayerName]); + Utils.PrintToChat(player, Localizer["goto_player", foundPlayer.PlayerName]); - if (player != null && IsAllowedPlayer(foundPlayer) && playerTimers[player.Slot].IsTimerBlocked) + if (player != null && IsAllowedPlayer(foundPlayer) && playerTimers[slot].IsTimerBlocked) { - if (jumpStatsEnabled) InvalidateJS(player.Slot); - player.PlayerPawn.Value!.Teleport(foundPlayer.Pawn.Value!.CBodyComponent?.SceneNode?.AbsOrigin ?? new Vector(0, 0, 0), - foundPlayer.PlayerPawn.Value!.EyeAngles ?? new QAngle(0, 0, 0), new Vector(0, 0, 0)); - SharpTimerDebug($"{player.PlayerName} css_goto to {foundPlayer.Pawn.Value.CBodyComponent?.SceneNode?.AbsOrigin ?? new Vector(0, 0, 0)}"); + player.PlayerPawn.Value!.Teleport(foundPlayer.Pawn.Value!.CBodyComponent?.SceneNode?.AbsOrigin.ToVector_t(), + foundPlayer.PlayerPawn.Value!.EyeAngles.ToQAngle_t(), new Vector_t(0, 0, 0)); + + Utils.LogDebug($"{player.PlayerName} css_goto to {foundPlayer.Pawn.Value.CBodyComponent?.SceneNode?.AbsOrigin.ToVector_t()}"); } } else - { - PrintToChat(player, Localizer["goto_player_not_found"]); - } + Utils.PrintToChat(player, Localizer["goto_player_not_found"]); } [ConsoleCommand("css_cp", "Sets a checkpoint")] @@ -1834,49 +1730,52 @@ public void GoToPlayer(CCSPlayerController? player, CommandInfo command) [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] public void SetPlayerCPCommand(CCSPlayerController? player, CommandInfo command) { - if (!IsAllowedPlayer(player) || cpEnabled == false) return; - SharpTimerDebug($"{player!.PlayerName} calling css_cp..."); + if (!IsAllowedPlayer(player) || cpEnabled == false) + return; + + var slot = player!.Slot; + var playerName = player.PlayerName; + + Utils.LogDebug($"{playerName} calling css_cp..."); if (ReplayCheck(player)) return; - SetPlayerCP(player, command); + SetPlayerCP(player, command, slot); } - public void SetPlayerCP(CCSPlayerController? player, CommandInfo command) + public void SetPlayerCP(CCSPlayerController? player, CommandInfo command, int slot) { if (((PlayerFlags)player!.Pawn.Value!.Flags & PlayerFlags.FL_ONGROUND) != PlayerFlags.FL_ONGROUND && removeCpRestrictEnabled == false) { - PrintToChat(player, Localizer["cant_use_checkpoint_in_air", (currentMapName!.Contains("surf_") ? "loc" : "checkpoint")]); + Utils.PrintToChat(player, Localizer["cant_use_checkpoint_in_air", (currentMapName!.Contains("surf_") ? "loc" : "checkpoint")]); PlaySound(player, cpSoundError); return; } if (!CanCheckpoint(player)) return; - - playerTimers[player.Slot].TicksSinceLastCmd = 0; - if(playerTimers[player.Slot].currentStyle == 12) - playerTimers[player.Slot].PrevTimerTicks.Add(playerTimers[player.Slot].TimerTicks); + if (playerTimers[slot].currentStyle == 12) + playerTimers[slot].PrevTimerTicks.Add(playerTimers[slot].TimerTicks); // Get the player's current position and rotation - Vector currentPosition = player.Pawn.Value.CBodyComponent?.SceneNode?.AbsOrigin ?? new Vector(0, 0, 0); - Vector currentSpeed = player.PlayerPawn.Value!.AbsVelocity ?? new Vector(0, 0, 0); - QAngle currentRotation = player.PlayerPawn.Value.EyeAngles ?? new QAngle(0, 0, 0); + Vector_t? currentPosition = player.Pawn.Value.CBodyComponent?.SceneNode?.AbsOrigin.ToVector_t(); + Vector_t currentSpeed = player.PlayerPawn.Value!.AbsVelocity.ToVector_t(); + QAngle_t currentRotation = player.PlayerPawn.Value.EyeAngles.ToQAngle_t(); // Convert position and rotation to strings - string positionString = $"{currentPosition.X} {currentPosition.Y} {currentPosition.Z}"; + string positionString = $"{currentPosition.GetValueOrDefault().X} {currentPosition.GetValueOrDefault().Y} {currentPosition.GetValueOrDefault().Z}"; string rotationString = $"{currentRotation.X} {currentRotation.Y} {currentRotation.Z}"; string speedString = $"{currentSpeed.X} {currentSpeed.Y} {currentSpeed.Z}"; // Add the current position and rotation strings to the player's checkpoint list - if (!playerCheckpoints.ContainsKey(player.Slot)) + if (!playerCheckpoints.ContainsKey(slot)) { - playerCheckpoints[player.Slot] = []; + playerCheckpoints[slot] = []; } - playerCheckpoints[player.Slot].Add(new PlayerCheckpoint + playerCheckpoints[slot].Add(new PlayerCheckpoint { PositionString = positionString, RotationString = rotationString, @@ -1884,13 +1783,13 @@ public void SetPlayerCP(CCSPlayerController? player, CommandInfo command) }); // Get the count of checkpoints for this player - int checkpointCount = playerCheckpoints[player.Slot].Count; - playerTimers[player.Slot].CheckpointIndex = checkpointCount - 1; + int checkpointCount = playerCheckpoints[slot].Count; + playerTimers[slot].CheckpointIndex = checkpointCount - 1; // Print the chat message with the checkpoint count - PrintToChat(player, Localizer["checkpoint_set", (currentMapName!.Contains("surf_") ? "loc" : "checkpoint"), checkpointCount]); + Utils.PrintToChat(player, Localizer["checkpoint_set", (currentMapName!.Contains("surf_") ? "loc" : "checkpoint"), checkpointCount]); PlaySound(player, cpSound); - SharpTimerDebug($"{player.PlayerName} css_cp to {checkpointCount} {positionString} {rotationString} {speedString}"); + Utils.LogDebug($"{player.PlayerName} css_cp to {checkpointCount} {positionString} {rotationString} {speedString}"); } [ConsoleCommand("css_tp", "Tp to the most recent checkpoint")] @@ -1898,45 +1797,46 @@ public void SetPlayerCP(CCSPlayerController? player, CommandInfo command) [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] public void TpPlayerCPCommand(CCSPlayerController? player, CommandInfo command) { - if (!IsAllowedPlayer(player) || cpEnabled == false) return; - SharpTimerDebug($"{player!.PlayerName} calling css_tp..."); + if (!IsAllowedPlayer(player) || cpEnabled == false) + return; + + var slot = player!.Slot; + var playerName = player.PlayerName; + + Utils.LogDebug($"{playerName} calling css_tp..."); if (ReplayCheck(player)) return; - TpPlayerCP(player, command); + TpPlayerCP(player, command, slot); } - public void TpPlayerCP(CCSPlayerController? player, CommandInfo command) + public void TpPlayerCP(CCSPlayerController player, CommandInfo command, int slot) { if (ReplayCheck(player)) return; if (!CanCheckpoint(player)) return; - - playerTimers[player!.Slot].TicksSinceLastCmd = 0; - if(playerTimers[player.Slot].currentStyle == 12) - playerTimers[player.Slot].TimerTicks = playerTimers[player.Slot].PrevTimerTicks[playerTimers[player.Slot].CheckpointIndex]; + if(playerTimers[slot].currentStyle == 12) + playerTimers[slot].TimerTicks = playerTimers[slot].PrevTimerTicks[playerTimers[slot].CheckpointIndex]; // Check if the player has any checkpoints - if (!playerCheckpoints.ContainsKey(player.Slot) || playerCheckpoints[player.Slot].Count == 0) + if (!playerCheckpoints.ContainsKey(slot) || playerCheckpoints[slot].Count == 0) { - PrintToChat(player, Localizer["no_checkpoint_set", currentMapName!.Contains("surf_") ? "loc" : "checkpoint"]); + Utils.PrintToChat(player, Localizer["no_checkpoint_set", currentMapName!.Contains("surf_") ? "loc" : "checkpoint"]); PlaySound(player, cpSoundError); return; } - if (jumpStatsEnabled) InvalidateJS(player.Slot); - // Get the most recent checkpoint from the player's list - PlayerCheckpoint lastCheckpoint = playerCheckpoints[player.Slot][playerTimers[player.Slot].CheckpointIndex]; + PlayerCheckpoint lastCheckpoint = playerCheckpoints[slot][playerTimers[slot].CheckpointIndex]; - // Convert position and rotation strings to Vector and QAngle - Vector position = ParseVector(lastCheckpoint.PositionString ?? "0 0 0"); - QAngle rotation = ParseQAngle(lastCheckpoint.RotationString ?? "0 0 0"); - Vector speed = ParseVector(lastCheckpoint.SpeedString ?? "0 0 0"); + // Convert position and rotation strings to Vector_t and QAngle_t + Vector_t position = Utils.ParseVector_t(lastCheckpoint.PositionString ?? "0 0 0"); + QAngle_t rotation = Utils.ParseQAngle_t(lastCheckpoint.RotationString ?? "0 0 0"); + Vector_t speed = Utils.ParseVector_t(lastCheckpoint.SpeedString ?? "0 0 0"); // Teleport the player to the most recent checkpoint, including the saved rotation if (removeCpRestrictEnabled == true) @@ -1945,13 +1845,13 @@ public void TpPlayerCP(CCSPlayerController? player, CommandInfo command) } else { - player.PlayerPawn.Value!.Teleport(position, rotation, new Vector(0, 0, 0)); + player.PlayerPawn.Value!.Teleport(position, rotation, new Vector_t(0, 0, 0)); } // Play a sound or provide feedback to the player PlaySound(player, tpSound); - PrintToChat(player, Localizer["used_recent_checkpoint", (currentMapName!.Contains("surf_") ? "loc" : "checkpoint")]); - SharpTimerDebug($"{player.PlayerName} css_tp to {position} {rotation} {speed}"); + Utils.PrintToChat(player, Localizer["used_recent_checkpoint", (currentMapName!.Contains("surf_") ? "loc" : "checkpoint")]); + Utils.LogDebug($"{player.PlayerName} css_tp to {position} {rotation} {speed}"); } [ConsoleCommand("css_prevcp", "Tp to the previous checkpoint")] @@ -1959,8 +1859,13 @@ public void TpPlayerCP(CCSPlayerController? player, CommandInfo command) [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] public void TpPreviousCP(CCSPlayerController? player, CommandInfo command) { - if (!IsAllowedPlayer(player) || cpEnabled == false) return; - SharpTimerDebug($"{player!.PlayerName} calling css_prevcp..."); + if (!IsAllowedPlayer(player) || cpEnabled == false) + return; + + var slot = player!.Slot; + var playerName = player.PlayerName; + + Utils.LogDebug($"{playerName} calling css_prevcp..."); if (ReplayCheck(player)) return; @@ -1968,23 +1873,20 @@ public void TpPreviousCP(CCSPlayerController? player, CommandInfo command) if (!CanCheckpoint(player)) return; - playerTimers[player.Slot].TicksSinceLastCmd = 0; - - if (!playerCheckpoints.TryGetValue(player.Slot, out List? checkpoints) || checkpoints.Count == 0) + if (!playerCheckpoints.TryGetValue(slot, out List? checkpoints) || checkpoints.Count == 0) { - PrintToChat(player, Localizer["no_checkpoint_set", (currentMapName!.Contains("surf_") ? "loc" : "checkpoint")]); + Utils.PrintToChat(player, Localizer["no_checkpoint_set", (currentMapName!.Contains("surf_") ? "loc" : "checkpoint")]); return; } - int index = playerTimers.TryGetValue(player.Slot, out var timer) ? timer.CheckpointIndex : 0; + int index = playerTimers.TryGetValue(slot, out var timer) ? timer.CheckpointIndex : 0; if (checkpoints.Count == 1) { - TpPlayerCP(player, command); + TpPlayerCP(player, command, slot); } else { - if (jumpStatsEnabled) InvalidateJS(player.Slot); // Calculate the index of the previous checkpoint, circling back if necessary index = (index - 1 + checkpoints.Count) % checkpoints.Count; @@ -1992,22 +1894,22 @@ public void TpPreviousCP(CCSPlayerController? player, CommandInfo command) // Update the player's checkpoint index and timer ticks - playerTimers[player.Slot].CheckpointIndex = index; - if(playerTimers[player.Slot].currentStyle == 12) - playerTimers[player.Slot].TimerTicks = playerTimers[player.Slot].PrevTimerTicks[playerTimers[player.Slot].CheckpointIndex]; + playerTimers[slot].CheckpointIndex = index; + if(playerTimers[slot].currentStyle == 12) + playerTimers[slot].TimerTicks = playerTimers[slot].PrevTimerTicks[playerTimers[slot].CheckpointIndex]; - // Convert position and rotation strings to Vector and QAngle - Vector position = ParseVector(previousCheckpoint.PositionString ?? "0 0 0"); - QAngle rotation = ParseQAngle(previousCheckpoint.RotationString ?? "0 0 0"); - Vector speed = ParseVector(previousCheckpoint.SpeedString ?? "0 0 0"); + // Convert position and rotation strings to Vector_t and QAngle_t + Vector_t position = Utils.ParseVector_t(previousCheckpoint.PositionString ?? "0 0 0"); + QAngle_t rotation = Utils.ParseQAngle_t(previousCheckpoint.RotationString ?? "0 0 0"); + Vector_t speed = Utils.ParseVector_t(previousCheckpoint.SpeedString ?? "0 0 0"); // Teleport the player to the previous checkpoint, including the saved rotation player.PlayerPawn.Value!.Teleport(position, rotation, speed); // Play a sound or provide feedback to the player PlaySound(player, tpSound); - PrintToChat(player, Localizer["used_previous_checkpoint", (currentMapName!.Contains("surf_") ? "loc" : "checkpoint")]); - SharpTimerDebug($"{player.PlayerName} css_prevcp to {position} {rotation}"); + Utils.PrintToChat(player, Localizer["used_previous_checkpoint", (currentMapName!.Contains("surf_") ? "loc" : "checkpoint")]); + Utils.LogDebug($"{player.PlayerName} css_prevcp to {position} {rotation}"); } } @@ -2016,8 +1918,13 @@ public void TpPreviousCP(CCSPlayerController? player, CommandInfo command) [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] public void TpNextCP(CCSPlayerController? player, CommandInfo command) { - if (!IsAllowedPlayer(player) || cpEnabled == false) return; - SharpTimerDebug($"{player!.PlayerName} calling css_nextcp..."); + if (!IsAllowedPlayer(player) || cpEnabled == false) + return; + + var slot = player!.Slot; + var playerName = player.PlayerName; + + Utils.LogDebug($"{playerName} calling css_nextcp..."); if (ReplayCheck(player)) return; @@ -2025,46 +1932,43 @@ public void TpNextCP(CCSPlayerController? player, CommandInfo command) if (!CanCheckpoint(player)) return; - playerTimers[player.Slot].TicksSinceLastCmd = 0; - - if (!playerCheckpoints.TryGetValue(player.Slot, out List? checkpoints) || checkpoints.Count == 0) + if (!playerCheckpoints.TryGetValue(slot, out List? checkpoints) || checkpoints.Count == 0) { - PrintToChat(player, Localizer["no_checkpoint_set", currentMapName!.Contains("surf_") ? "loc" : "checkpoint"]); + Utils.PrintToChat(player, Localizer["no_checkpoint_set", currentMapName!.Contains("surf_") ? "loc" : "checkpoint"]); return; } - int index = playerTimers.TryGetValue(player.Slot, out var timer) ? timer.CheckpointIndex : 0; + int index = playerTimers.TryGetValue(slot, out var timer) ? timer.CheckpointIndex : 0; if (checkpoints.Count == 1) { - TpPlayerCP(player, command); + TpPlayerCP(player, command, slot); } else { - if (jumpStatsEnabled) InvalidateJS(player.Slot); // Calculate the index of the next checkpoint, circling back if necessary index = (index + 1) % checkpoints.Count; PlayerCheckpoint nextCheckpoint = checkpoints[index]; // Update the player's checkpoint index and timer ticks - playerTimers[player.Slot].CheckpointIndex = index; - if(playerTimers[player.Slot].currentStyle == 12) - playerTimers[player.Slot].TimerTicks = playerTimers[player.Slot].PrevTimerTicks[playerTimers[player.Slot].CheckpointIndex]; + playerTimers[slot].CheckpointIndex = index; + if(playerTimers[slot].currentStyle == 12) + playerTimers[slot].TimerTicks = playerTimers[slot].PrevTimerTicks[playerTimers[slot].CheckpointIndex]; - // Convert position and rotation strings to Vector and QAngle - Vector position = ParseVector(nextCheckpoint.PositionString ?? "0 0 0"); - QAngle rotation = ParseQAngle(nextCheckpoint.RotationString ?? "0 0 0"); - Vector speed = ParseVector(nextCheckpoint.SpeedString ?? "0 0 0"); + // Convert position and rotation strings to Vector_t and QAngle_t + Vector_t position = Utils.ParseVector_t(nextCheckpoint.PositionString ?? "0 0 0"); + QAngle_t rotation = Utils.ParseQAngle_t(nextCheckpoint.RotationString ?? "0 0 0"); + Vector_t speed = Utils.ParseVector_t(nextCheckpoint.SpeedString ?? "0 0 0"); // Teleport the player to the next checkpoint, including the saved rotation player.PlayerPawn.Value!.Teleport(position, rotation, speed); // Play a sound or provide feedback to the player PlaySound(player, tpSound); - PrintToChat(player, Localizer["used_checkpoint", currentMapName!.Contains("surf_") ? "loc" : "checkpoint"]); - SharpTimerDebug($"{player.PlayerName} css_nextcp to {position} {rotation}"); + Utils.PrintToChat(player, Localizer["used_checkpoint", currentMapName!.Contains("surf_") ? "loc" : "checkpoint"]); + Utils.LogDebug($"{playerName} css_nextcp to {position} {rotation}"); } } } -} +} \ No newline at end of file diff --git a/src/Commands/ConfigConvars.cs b/src/Commands/ConfigConvars.cs index 062c42b8..3a6c39a6 100644 --- a/src/Commands/ConfigConvars.cs +++ b/src/Commands/ConfigConvars.cs @@ -24,17 +24,6 @@ namespace SharpTimer { public partial class SharpTimer { - //Because decimals are weird - private CultureInfo culture; - - public SharpTimer() { - try { - culture = CultureInfo.CreateSpecificCulture("en-US"); - } catch (CultureNotFoundException e) { - Console.WriteLine("Culture not found, using invariant culture."); - culture = CultureInfo.InvariantCulture; - } - } [ConsoleCommand("sharptimer_hostname", "Default Server Hostname.")] [CommandHelper(whoCanExecute: CommandUsage.SERVER_ONLY)] @@ -60,7 +49,7 @@ public void SharpTimerHostnameConvar(CCSPlayerController? player, CommandInfo co autosetHostname = bool.TryParse(args, out bool autosetHostnameValue) ? autosetHostnameValue : args != "0" && autosetHostname; } - [ConsoleCommand("sharptimer_custom_map_cfgs_enabled", "Whether Custom Map .cfg files should be executed for the corresponding maps (found in cfg/SharpTimer/MapData/MapExecs/kz_example.cfg). Default value: true")] + [ConsoleCommand("sharptimer_custom_map_cfgs_enabled", "Whether Custom Map .cfg files should be executed for the corresponding maps (found in cfg/SharpTimer/MapData/MapExecs/de_example.cfg). Default value: true")] [CommandHelper(whoCanExecute: CommandUsage.SERVER_ONLY)] public void SharpTimerCustomMapExecConvar(CCSPlayerController? player, CommandInfo command) { @@ -105,11 +94,11 @@ public void SharpTimerGlobalRanksMinPointsConvar(CCSPlayerController? player, Co if (int.TryParse(args, out int minPoints) && minPoints > 0) { minGlobalPointsForRank = minPoints; - SharpTimerConPrint($"SharpTimer min points for rank set to {minPoints} points."); + Utils.LogDebug($"SharpTimer min points for rank set to {minPoints} points."); } else { - SharpTimerConPrint("Invalid min points for rank value. Please provide a positive integer."); + Utils.LogError("Invalid min points for rank value. Please provide a positive integer."); } } @@ -119,14 +108,14 @@ public void SharpTimerGlobalRanksBonusPointsConvar(CCSPlayerController? player, { string args = command.ArgString; - if (double.TryParse(args, NumberStyles.Any, culture, out double multiplier) && multiplier is >= 0 and <= 1) + if (double.TryParse(args, NumberStyles.Any, CultureInfo.InvariantCulture, out double multiplier) && multiplier is >= 0 and <= 1) { globalPointsBonusMultiplier = multiplier; - SharpTimerConPrint($"SharpTimer bonus points multiplier set to {multiplier}"); + Utils.LogDebug($"SharpTimer bonus points multiplier set to {multiplier}"); } else { - SharpTimerConPrint("Invalid bonus points multiplier. Please provide a positive integer."); + Utils.LogError("Invalid bonus points multiplier. Please provide a positive integer."); } } @@ -139,11 +128,11 @@ public void SharpTimerGlobalRanksBaselineT1Convar(CCSPlayerController? player, C if (int.TryParse(args, out int baseline) && baseline > 0) { baselineT1 = baseline; - SharpTimerConPrint($"SharpTimer baseline T1 points set to {baseline}"); + Utils.LogDebug($"SharpTimer baseline T1 points set to {baseline}"); } else { - SharpTimerConPrint("Invalid baseline T1 points. Please provide a positive integer."); + Utils.LogError("Invalid baseline T1 points. Please provide a positive integer."); } } @@ -156,11 +145,11 @@ public void SharpTimerGlobalRanksBaselineT2Convar(CCSPlayerController? player, C if (int.TryParse(args, out int baseline) && baseline > 0) { baselineT2 = baseline; - SharpTimerConPrint($"SharpTimer baseline T2 points set to {baseline}"); + Utils.LogDebug($"SharpTimer baseline T2 points set to {baseline}"); } else { - SharpTimerConPrint("Invalid baseline T2 points. Please provide a positive integer."); + Utils.LogError("Invalid baseline T2 points. Please provide a positive integer."); } } @@ -173,11 +162,11 @@ public void SharpTimerGlobalRanksBaselineT3Convar(CCSPlayerController? player, C if (int.TryParse(args, out int baseline) && baseline > 0) { baselineT3 = baseline; - SharpTimerConPrint($"SharpTimer baseline T3 points set to {baseline}"); + Utils.LogDebug($"SharpTimer baseline T3 points set to {baseline}"); } else { - SharpTimerConPrint("Invalid baseline T3 points. Please provide a positive integer."); + Utils.LogError("Invalid baseline T3 points. Please provide a positive integer."); } } @@ -190,11 +179,11 @@ public void SharpTimerGlobalRanksBaselineT4Convar(CCSPlayerController? player, C if (int.TryParse(args, out int baseline) && baseline > 0) { baselineT4 = baseline; - SharpTimerConPrint($"SharpTimer baseline T4 points set to {baseline}"); + Utils.LogDebug($"SharpTimer baseline T4 points set to {baseline}"); } else { - SharpTimerConPrint("Invalid baseline T4 points. Please provide a positive integer."); + Utils.LogError("Invalid baseline T4 points. Please provide a positive integer."); } } @@ -207,11 +196,11 @@ public void SharpTimerGlobalRanksBaselineT5Convar(CCSPlayerController? player, C if (int.TryParse(args, out int baseline) && baseline > 0) { baselineT5 = baseline; - SharpTimerConPrint($"SharpTimer baseline T5 points set to {baseline}"); + Utils.LogDebug($"SharpTimer baseline T5 points set to {baseline}"); } else { - SharpTimerConPrint("Invalid baseline T5 points. Please provide a positive integer."); + Utils.LogError("Invalid baseline T5 points. Please provide a positive integer."); } } @@ -224,11 +213,11 @@ public void SharpTimerGlobalRanksBaselineT6Convar(CCSPlayerController? player, C if (int.TryParse(args, out int baseline) && baseline > 0) { baselineT6 = baseline; - SharpTimerConPrint($"SharpTimer baseline T6 points set to {baseline}"); + Utils.LogDebug($"SharpTimer baseline T6 points set to {baseline}"); } else { - SharpTimerConPrint("Invalid baseline T6 points. Please provide a positive integer."); + Utils.LogError("Invalid baseline T6 points. Please provide a positive integer."); } } @@ -241,11 +230,11 @@ public void SharpTimerGlobalRanksBaselineT7Convar(CCSPlayerController? player, C if (int.TryParse(args, out int baseline) && baseline > 0) { baselineT7 = baseline; - SharpTimerConPrint($"SharpTimer baseline T7 points set to {baseline}"); + Utils.LogDebug($"SharpTimer baseline T7 points set to {baseline}"); } else { - SharpTimerConPrint("Invalid baseline T7 points. Please provide a positive integer."); + Utils.LogError("Invalid baseline T7 points. Please provide a positive integer."); } } @@ -258,11 +247,11 @@ public void SharpTimerGlobalRanksBaselineT8Convar(CCSPlayerController? player, C if (int.TryParse(args, out int baseline) && baseline > 0) { baselineT8 = baseline; - SharpTimerConPrint($"SharpTimer baseline T8 points set to {baseline}"); + Utils.LogDebug($"SharpTimer baseline T8 points set to {baseline}"); } else { - SharpTimerConPrint("Invalid baseline T8 points. Please provide a positive integer."); + Utils.LogError("Invalid baseline T8 points. Please provide a positive integer."); } } @@ -275,11 +264,11 @@ public void SharpTimerGlobalRanksMaxRecordPointsConvar(CCSPlayerController? play if (int.TryParse(args, out int baseline) && baseline > 0) { maxRecordPointsBase = baseline; - SharpTimerConPrint($"SharpTimer max record points set to {baseline}"); + Utils.LogDebug($"SharpTimer max record points set to {baseline}"); } else { - SharpTimerConPrint("Invalid max record points. Please provide a positive integer."); + Utils.LogError("Invalid max record points. Please provide a positive integer."); } } @@ -292,11 +281,11 @@ public void SharpTimerGlobalRanksMaxCompletionsConvar(CCSPlayerController? playe if (int.TryParse(args, out int completions) && completions >= 0) { globalPointsMaxCompletions = completions; - SharpTimerConPrint($"SharpTimer max completions set to {completions}"); + Utils.LogDebug($"SharpTimer max completions set to {completions}"); } else { - SharpTimerConPrint("Invalid max completions. Please provide a positive integer."); + Utils.LogError("Invalid max completions. Please provide a positive integer."); } } @@ -306,14 +295,14 @@ public void SharpTimerGlobalRanksTop101Convar(CCSPlayerController? player, Comma { string args = command.ArgString; - if (double.TryParse(args, NumberStyles.Any, culture, out double multiplier) && multiplier is >= 0 and <= 1) + if (double.TryParse(args, NumberStyles.Any, CultureInfo.InvariantCulture, out double multiplier) && multiplier is >= 0 and <= 1) { top10_1 = multiplier; - SharpTimerConPrint($"SharpTimer top10_1 multiplier set to {multiplier}"); + Utils.LogDebug($"SharpTimer top10_1 multiplier set to {multiplier}"); } else { - SharpTimerConPrint("Invalid top10_1 multiplier. Please provide a positive double."); + Utils.LogError("Invalid top10_1 multiplier. Please provide a positive double."); } } @@ -323,14 +312,14 @@ public void SharpTimerGlobalRanksTop102Convar(CCSPlayerController? player, Comma { string args = command.ArgString; - if (double.TryParse(args, NumberStyles.Any, culture, out double multiplier) && multiplier is >= 0 and <= 1) + if (double.TryParse(args, NumberStyles.Any, CultureInfo.InvariantCulture, out double multiplier) && multiplier is >= 0 and <= 1) { top10_2 = multiplier; - SharpTimerConPrint($"SharpTimer top10_2 multiplier set to {multiplier}"); + Utils.LogDebug($"SharpTimer top10_2 multiplier set to {multiplier}"); } else { - SharpTimerConPrint("Invalid top10_2 multiplier. Please provide a positive double."); + Utils.LogError("Invalid top10_2 multiplier. Please provide a positive double."); } } @@ -340,14 +329,14 @@ public void SharpTimerGlobalRanksTop103Convar(CCSPlayerController? player, Comma { string args = command.ArgString; - if (double.TryParse(args, NumberStyles.Any, culture, out double multiplier) && multiplier is >= 0 and <= 1) + if (double.TryParse(args, NumberStyles.Any, CultureInfo.InvariantCulture, out double multiplier) && multiplier is >= 0 and <= 1) { top10_3 = multiplier; - SharpTimerConPrint($"SharpTimer top10_3 multiplier set to {multiplier}"); + Utils.LogDebug($"SharpTimer top10_3 multiplier set to {multiplier}"); } else { - SharpTimerConPrint("Invalid top10_3 multiplier. Please provide a positive double."); + Utils.LogError("Invalid top10_3 multiplier. Please provide a positive double."); } } @@ -357,14 +346,14 @@ public void SharpTimerGlobalRanksTop104Convar(CCSPlayerController? player, Comma { string args = command.ArgString; - if (double.TryParse(args, NumberStyles.Any, culture, out double multiplier) && multiplier is >= 0 and <= 1) + if (double.TryParse(args, NumberStyles.Any, CultureInfo.InvariantCulture, out double multiplier) && multiplier is >= 0 and <= 1) { top10_4 = multiplier; - SharpTimerConPrint($"SharpTimer top10_4 multiplier set to {multiplier}"); + Utils.LogDebug($"SharpTimer top10_4 multiplier set to {multiplier}"); } else { - SharpTimerConPrint("Invalid top10_4 multiplier. Please provide a positive double."); + Utils.LogError("Invalid top10_4 multiplier. Please provide a positive double."); } } @@ -374,14 +363,14 @@ public void SharpTimerGlobalRanksTop105Convar(CCSPlayerController? player, Comma { string args = command.ArgString; - if (double.TryParse(args, NumberStyles.Any, culture, out double multiplier) && multiplier is >= 0 and <= 1) + if (double.TryParse(args, NumberStyles.Any, CultureInfo.InvariantCulture, out double multiplier) && multiplier is >= 0 and <= 1) { top10_5 = multiplier; - SharpTimerConPrint($"SharpTimer top10_5 multiplier set to {multiplier}"); + Utils.LogDebug($"SharpTimer top10_5 multiplier set to {multiplier}"); } else { - SharpTimerConPrint("Invalid top10_5 multiplier. Please provide a positive double."); + Utils.LogError("Invalid top10_5 multiplier. Please provide a positive double."); } } @@ -391,14 +380,14 @@ public void SharpTimerGlobalRanksTop106Convar(CCSPlayerController? player, Comma { string args = command.ArgString; - if (double.TryParse(args, NumberStyles.Any, culture, out double multiplier) && multiplier is >= 0 and <= 1) + if (double.TryParse(args, NumberStyles.Any, CultureInfo.InvariantCulture, out double multiplier) && multiplier is >= 0 and <= 1) { top10_6 = multiplier; - SharpTimerConPrint($"SharpTimer top10_6 multiplier set to {multiplier}"); + Utils.LogDebug($"SharpTimer top10_6 multiplier set to {multiplier}"); } else { - SharpTimerConPrint("Invalid top10_6 multiplier. Please provide a positive double."); + Utils.LogError("Invalid top10_6 multiplier. Please provide a positive double."); } } @@ -408,14 +397,14 @@ public void SharpTimerGlobalRanksTop107Convar(CCSPlayerController? player, Comma { string args = command.ArgString; - if (double.TryParse(args, NumberStyles.Any, culture, out double multiplier) && multiplier is >= 0 and <= 1) + if (double.TryParse(args, NumberStyles.Any, CultureInfo.InvariantCulture, out double multiplier) && multiplier is >= 0 and <= 1) { top10_7 = multiplier; - SharpTimerConPrint($"SharpTimer top10_7 multiplier set to {multiplier}"); + Utils.LogDebug($"SharpTimer top10_7 multiplier set to {multiplier}"); } else { - SharpTimerConPrint("Invalid top10_7 multiplier. Please provide a positive double."); + Utils.LogError("Invalid top10_7 multiplier. Please provide a positive double."); } } @@ -425,14 +414,14 @@ public void SharpTimerGlobalRanksTop108Convar(CCSPlayerController? player, Comma { string args = command.ArgString; - if (double.TryParse(args, NumberStyles.Any, culture, out double multiplier) && multiplier is >= 0 and <= 1) + if (double.TryParse(args, NumberStyles.Any, CultureInfo.InvariantCulture, out double multiplier) && multiplier is >= 0 and <= 1) { top10_8 = multiplier; - SharpTimerConPrint($"SharpTimer top10_8 multiplier set to {multiplier}"); + Utils.LogDebug($"SharpTimer top10_8 multiplier set to {multiplier}"); } else { - SharpTimerConPrint("Invalid top10_8 multiplier. Please provide a positive double."); + Utils.LogError("Invalid top10_8 multiplier. Please provide a positive double."); } } @@ -442,14 +431,14 @@ public void SharpTimerGlobalRanksTop109Convar(CCSPlayerController? player, Comma { string args = command.ArgString; - if (double.TryParse(args, NumberStyles.Any, culture, out double multiplier) && multiplier is >= 0 and <= 1) + if (double.TryParse(args, NumberStyles.Any, CultureInfo.InvariantCulture, out double multiplier) && multiplier is >= 0 and <= 1) { top10_9 = multiplier; - SharpTimerConPrint($"SharpTimer top10_9 multiplier set to {multiplier}"); + Utils.LogDebug($"SharpTimer top10_9 multiplier set to {multiplier}"); } else { - SharpTimerConPrint("Invalid top10_9 multiplier. Please provide a positive double."); + Utils.LogError("Invalid top10_9 multiplier. Please provide a positive double."); } } @@ -459,14 +448,14 @@ public void SharpTimerGlobalRanksTop1010Convar(CCSPlayerController? player, Comm { string args = command.ArgString; - if (double.TryParse(args, NumberStyles.Any, culture, out double multiplier) && multiplier is >= 0 and <= 1) + if (double.TryParse(args, NumberStyles.Any, CultureInfo.InvariantCulture, out double multiplier) && multiplier is >= 0 and <= 1) { top10_10 = multiplier; - SharpTimerConPrint($"SharpTimer top10_10 multiplier set to {multiplier}"); + Utils.LogDebug($"SharpTimer top10_10 multiplier set to {multiplier}"); } else { - SharpTimerConPrint("Invalid top10_10 multiplier. Please provide a positive double."); + Utils.LogError("Invalid top10_10 multiplier. Please provide a positive double."); } } @@ -476,14 +465,14 @@ public void SharpTimerGlobalRanksGroup1Convar(CCSPlayerController? player, Comma { string args = command.ArgString; - if (double.TryParse(args, NumberStyles.Any, culture, out double percentile) && percentile is >= 0 and <= 100) + if (double.TryParse(args, NumberStyles.Any, CultureInfo.InvariantCulture, out double percentile) && percentile is >= 0 and <= 100) { group1 = percentile; - SharpTimerConPrint($"SharpTimer group #1 percentile set to {percentile}"); + Utils.LogDebug($"SharpTimer group #1 percentile set to {percentile}"); } else { - SharpTimerConPrint("Invalid group #1 percentile. Please provide a positive double."); + Utils.LogError("Invalid group #1 percentile. Please provide a positive double."); } } @@ -493,14 +482,14 @@ public void SharpTimerGlobalRanksGroup2Convar(CCSPlayerController? player, Comma { string args = command.ArgString; - if (double.TryParse(args, NumberStyles.Any, culture, out double percentile) && percentile is >= 0 and <= 100) + if (double.TryParse(args, NumberStyles.Any, CultureInfo.InvariantCulture, out double percentile) && percentile is >= 0 and <= 100) { group2 = percentile; - SharpTimerConPrint($"SharpTimer group #2 percentile set to {percentile}"); + Utils.LogDebug($"SharpTimer group #2 percentile set to {percentile}"); } else { - SharpTimerConPrint("Invalid group #2 percentile. Please provide a positive double."); + Utils.LogError("Invalid group #2 percentile. Please provide a positive double."); } } @@ -510,14 +499,14 @@ public void SharpTimerGlobalRanksGroup3Convar(CCSPlayerController? player, Comma { string args = command.ArgString; - if (double.TryParse(args, NumberStyles.Any, culture, out double percentile) && percentile is >= 0 and <= 100) + if (double.TryParse(args, NumberStyles.Any, CultureInfo.InvariantCulture, out double percentile) && percentile is >= 0 and <= 100) { group3 = percentile; - SharpTimerConPrint($"SharpTimer group #3 percentile set to {percentile}"); + Utils.LogDebug($"SharpTimer group #3 percentile set to {percentile}"); } else { - SharpTimerConPrint("Invalid group #3 percentile. Please provide a positive double."); + Utils.LogError("Invalid group #3 percentile. Please provide a positive double."); } } @@ -527,14 +516,14 @@ public void SharpTimerGlobalRanksGroup4Convar(CCSPlayerController? player, Comma { string args = command.ArgString; - if (double.TryParse(args, NumberStyles.Any, culture, out double percentile) && percentile is >= 0 and <= 100) + if (double.TryParse(args, NumberStyles.Any, CultureInfo.InvariantCulture, out double percentile) && percentile is >= 0 and <= 100) { group4 = percentile; - SharpTimerConPrint($"SharpTimer group #4 percentile set to {percentile}"); + Utils.LogDebug($"SharpTimer group #4 percentile set to {percentile}"); } else { - SharpTimerConPrint("Invalid group #4 percentile. Please provide a positive double."); + Utils.LogError("Invalid group #4 percentile. Please provide a positive double."); } } @@ -544,14 +533,14 @@ public void SharpTimerGlobalRanksGroup5Convar(CCSPlayerController? player, Comma { string args = command.ArgString; - if (double.TryParse(args, NumberStyles.Any, culture, out double percentile) && percentile is >= 0 and <= 100) + if (double.TryParse(args, NumberStyles.Any, CultureInfo.InvariantCulture, out double percentile) && percentile is >= 0 and <= 100) { group5 = percentile; - SharpTimerConPrint($"SharpTimer group #5 percentile set to {percentile}"); + Utils.LogDebug($"SharpTimer group #5 percentile set to {percentile}"); } else { - SharpTimerConPrint("Invalid group #5 percentile. Please provide a positive double."); + Utils.LogError("Invalid group #5 percentile. Please provide a positive double."); } } @@ -582,11 +571,11 @@ public void SharpTimerReplayMaxLengthConvar(CCSPlayerController? player, Command if (int.TryParse(args, out int mxLength) && mxLength > 0) { maxReplayFrames = (int)(mxLength * 64); - SharpTimerConPrint($"SharpTimer max replay length set to {mxLength} seconds."); + Utils.LogDebug($"SharpTimer max replay length set to {mxLength} seconds."); } else { - SharpTimerConPrint("Invalid max replay length value. Please provide a positive int."); + Utils.LogError("Invalid max replay length value. Please provide a positive int."); } } @@ -629,75 +618,6 @@ public void SharpTimerVipGifHost(CCSPlayerController? player, CommandInfo comman vipGifHost = $"{args}"; }*/ - [ConsoleCommand("sharptimer_jumpstats_enabled", "Whether JumpStats are enabled or not. Default value: false")] - [CommandHelper(whoCanExecute: CommandUsage.SERVER_ONLY)] - public void SharpTimerJumpStatsConvar(CCSPlayerController? player, CommandInfo command) - { - string args = command.ArgString; - - jumpStatsEnabled = bool.TryParse(args, out bool jumpStatsEnabledValue) ? jumpStatsEnabledValue : args != "0" && jumpStatsEnabled; - } - - [ConsoleCommand("sharptimer_jumpstats_min_distance", "Defines the minimum distance for a jumpstat to be printed to chat. Default value: 175.0")] - [CommandHelper(whoCanExecute: CommandUsage.SERVER_ONLY)] - public void SharpTimerJumpStatsMinDistConvar(CCSPlayerController? player, CommandInfo command) - { - string args = command.ArgString; - - if (float.TryParse(args, NumberStyles.Any, culture, out float dist) && dist > 0) - { - jumpStatsMinDist = dist; - SharpTimerConPrint($"SharpTimer JumpStats min distance set to {dist} units."); - } - else - { - SharpTimerConPrint("Invalid JumpStats min distance value. Please provide a positive float."); - } - } - - [ConsoleCommand("sharptimer_jumpstats_max_vert", "Defines the max vertical distance for a jumpstat to not be printed to chat. Default value: 32.0")] - [CommandHelper(whoCanExecute: CommandUsage.SERVER_ONLY)] - public void SharpTimerJumpStatsMaxVertConvar(CCSPlayerController? player, CommandInfo command) - { - string args = command.ArgString; - - if (float.TryParse(args, NumberStyles.Any, culture, out float dist) && dist > 0) - { - jumpStatsMaxVert = dist; - SharpTimerConPrint($"SharpTimer JumpStats max vert distance set to {dist} units."); - } - else - { - SharpTimerConPrint("Invalid JumpStats max vert distance value. Please provide a positive float."); - } - } - - [ConsoleCommand("sharptimer_jumpstats_movement_unlocker_cap", "Intended for taming movement unlocker, caps speed on the second tick of a player being on the ground. Default value: true")] - [CommandHelper(whoCanExecute: CommandUsage.SERVER_ONLY)] - public void SharpTimerJumpStatsUnlockerCapConvar(CCSPlayerController? player, CommandInfo command) - { - string args = command.ArgString; - - movementUnlockerCapEnabled = bool.TryParse(args, out bool movementUnlockerCapEnabledValue) ? movementUnlockerCapEnabledValue : args != "0" && movementUnlockerCapEnabled; - } - - [ConsoleCommand("sharptimer_jumpstats_movement_unlocker_cap_value", "Speed cap value which will kick in on the second tick of the player being on the ground. Default value: 250.0")] - [CommandHelper(whoCanExecute: CommandUsage.SERVER_ONLY)] - public void SharpTimerJumpStatsUnlockerCapValueConvar(CCSPlayerController? player, CommandInfo command) - { - string args = command.ArgString; - - if (float.TryParse(args, NumberStyles.Any, culture, out float value) && value > 0) - { - movementUnlockerCapValue = value; - if (movementUnlockerCapEnabled) SharpTimerConPrint($"SharpTimer JumpStats Movement Unlocker cap value set to {value} units."); - } - else - { - SharpTimerConPrint("Invalid JumpStats Movement Unlocker cap value. Please provide a positive float."); - } - } - [ConsoleCommand("sharptimer_global_cache_interval", "Refresh interval of record and point caching. Default value: 120")] [CommandHelper(whoCanExecute: CommandUsage.SERVER_ONLY)] public void SharpTimerGlobalCacheConvar(CCSPlayerController? player, CommandInfo command) @@ -707,11 +627,11 @@ public void SharpTimerGlobalCacheConvar(CCSPlayerController? player, CommandInfo if (int.TryParse(args, out int value) && value > 0) { globalCacheInterval = value; - SharpTimerConPrint($"SharpTimer global cache refresh interval set to {value} seconds."); + Utils.LogDebug($"SharpTimer global cache refresh interval set to {value} seconds."); } else { - SharpTimerConPrint("Invalid global ache refresh interval value. Please provide a positive float."); + Utils.LogError("Invalid global ache refresh interval value. Please provide a positive float."); } } @@ -759,11 +679,11 @@ public void SharpTimerAFKSecondsConvar(CCSPlayerController? player, CommandInfo if (int.TryParse(args, out int secs) && secs >= 0) { afkSeconds = secs; - SharpTimerConPrint($"SharpTimer afk period: {secs}s"); + Utils.LogDebug($"SharpTimer afk period: {secs}s"); } else { - SharpTimerConPrint("Invalid afk period. Please provide a positive integer."); + Utils.LogError("Invalid afk period. Please provide a positive integer."); } } @@ -776,11 +696,11 @@ public void SharpTimerHUDUpdatesConvar(CCSPlayerController? player, CommandInfo if (int.TryParse(args, out int tickrate) && tickrate >= 0 && tickrate <= 64) { hudTickrate = tickrate; - SharpTimerConPrint($"SharpTimer hud updates per second: {tickrate}"); + Utils.LogDebug($"SharpTimer hud updates per second: {tickrate}"); } else { - SharpTimerConPrint("Invalid HUD updates per second. Please provide a positive integer below 64."); + Utils.LogError("Invalid HUD updates per second. Please provide a positive integer below 64."); } } @@ -858,7 +778,7 @@ public void SharpTimerMapNameHUDConvar(CCSPlayerController? player, CommandInfo [ConsoleCommand("sharptimer_debug_enabled", "Default value: false")] [CommandHelper(whoCanExecute: CommandUsage.SERVER_ONLY)] - public void SharpTimerConPrintConvar(CCSPlayerController? player, CommandInfo command) + public void ConPrintConvar(CCSPlayerController? player, CommandInfo command) { string args = command.ArgString; @@ -906,20 +826,14 @@ public void SharpTimerInfiniteAmmoConvar(CCSPlayerController? player, CommandInf applyInfiniteAmmo = bool.TryParse(args, out bool value) ? value : args != "0" && applyInfiniteAmmo; } - - [ConsoleCommand("sharptimer_stage_times_path", "Path to the stage times folder. Default value : csgo cfg SharpTimer PlayerStageData")] + + [ConsoleCommand("sharptimer_print_start_speed", "Whether the start speed should be printed to chat when the player leaves the start zone. Default value: true")] [CommandHelper(whoCanExecute: CommandUsage.SERVER_ONLY)] - public void SharpTimerStageTimesPathConvar(CCSPlayerController? player, CommandInfo command) + public void SharpTimerPrintStartSpeed(CCSPlayerController? player, CommandInfo command) { - string args = command.ArgString.Trim(); - - if (string.IsNullOrEmpty(args)) - { - playerStagesPath = Path.Join(gameDir, "csgo", "cfg", "SharpTimer", "PlayerStageData"); - return; - } + string args = command.ArgString; - playerStagesPath = Path.Join(gameDir, args); + printStartSpeedEnabled = bool.TryParse(args, out bool value) ? value : args != "0" && printStartSpeedEnabled; } [ConsoleCommand("sharptimer_use2Dspeed_enabled", "Default value: false")] @@ -1030,14 +944,14 @@ public void SharpTimerCmdCooldownConvar(CCSPlayerController? player, CommandInfo { string args = command.ArgString; - if (float.TryParse(args, NumberStyles.Any, culture, out float cooldown) && cooldown > 0) + if (float.TryParse(args, NumberStyles.Any, CultureInfo.InvariantCulture, out float cooldown) && cooldown > 0) { - cmdCooldown = (int)(cooldown * 64); - SharpTimerConPrint($"SharpTimer command cooldown set to {cooldown} seconds."); + cmdCooldown = cooldown; + Utils.LogDebug($"SharpTimer command cooldown set to {cooldown} seconds."); } else { - SharpTimerConPrint("Invalid command cooldown value. Please provide a positive float."); + Utils.LogError("Invalid command cooldown value. Please provide a positive float."); } } @@ -1047,14 +961,14 @@ public void SharpTimerBhopBlockConvar(CCSPlayerController? player, CommandInfo c { string args = command.ArgString; - if (float.TryParse(args, NumberStyles.Any, culture, out float time) && time > 0) + if (float.TryParse(args, NumberStyles.Any, CultureInfo.InvariantCulture, out float time) && time > 0) { bhopBlockTime = (int)(time * 64); - SharpTimerConPrint($"SharpTimer max bhop block time set to {time} seconds."); + Utils.LogDebug($"SharpTimer max bhop block time set to {time} seconds."); } else { - SharpTimerConPrint("Invalid max bhop block time value. Please provide a positive float."); + Utils.LogError("Invalid max bhop block time value. Please provide a positive float."); } } @@ -1188,11 +1102,11 @@ public void SharpTimerMaxStartSpeedConvar(CCSPlayerController? player, CommandIn { maxStartingSpeed = speed; Server.ExecuteCommand($"sv_maxspeed {maxStartingSpeed}"); - SharpTimerConPrint($"SharpTimer max trigger speed set to {speed}."); + Utils.LogDebug($"SharpTimer max trigger speed set to {speed}."); } else { - SharpTimerConPrint("Invalid max trigger speed value. Please provide a positive integer."); + Utils.LogError("Invalid max trigger speed value. Please provide a positive integer."); } } @@ -1205,11 +1119,11 @@ public void SharpTimerMaxBonusStartSpeedConvar(CCSPlayerController? player, Comm if (int.TryParse(args, out int speed) && speed > 0) { maxBonusStartingSpeed = speed; - SharpTimerConPrint($"SharpTimer max bonus trigger speed set to {speed}."); + Utils.LogDebug($"SharpTimer max bonus trigger speed set to {speed}."); } else { - SharpTimerConPrint("Invalid max bonus trigger speed value. Please provide a positive integer."); + Utils.LogError("Invalid max bonus trigger speed value. Please provide a positive integer."); } } @@ -1231,11 +1145,11 @@ public void SharpTimerForcedSpeedConvar(CCSPlayerController? player, CommandInfo if (int.TryParse(args, out int speed) && speed > 0) { forcedPlayerSpeed = speed; - SharpTimerConPrint($"SharpTimer forced player speed set to {speed}."); + Utils.LogDebug($"SharpTimer forced player speed set to {speed}."); } else { - SharpTimerConPrint("Invalid forced player speed value. Please provide a positive integer."); + Utils.LogError("Invalid forced player speed value. Please provide a positive integer."); } } @@ -1248,11 +1162,11 @@ public void SharpTimerBhopBlockTicksConvar(CCSPlayerController? player, CommandI if (int.TryParse(args, out int bhopTicks) && bhopTicks > 0) { bhopBlockTime = bhopTicks; - SharpTimerConPrint($"SharpTimer forced bhop_block ticks to {bhopTicks}."); + Utils.LogDebug($"SharpTimer forced bhop_block ticks to {bhopTicks}."); } else { - SharpTimerConPrint("Invalid bhop_block ticks value. Please provide a positive integer."); + Utils.LogError("Invalid bhop_block ticks value. Please provide a positive integer."); } } @@ -1265,6 +1179,15 @@ public void SharpTimerStageTimeConvar(CCSPlayerController? player, CommandInfo c enableStageTimes = bool.TryParse(args, out bool enableStageTimesValue) ? enableStageTimesValue : args != "0" && enableStageTimes; } + [ConsoleCommand("sharptimer_stage_sr_enabled", "Whether stage time server records are enabled by default or not. Default value: true")] + [CommandHelper(whoCanExecute: CommandUsage.SERVER_ONLY)] + public void SharpTimerStageServerRecordConvar(CCSPlayerController? player, CommandInfo command) + { + string args = command.ArgString; + + enableStageSR = bool.TryParse(args, out bool enableStageSRValue) ? enableStageSRValue : args != "0" && enableStageSRValue; + } + [ConsoleCommand("sharptimer_connect_commands_msg_enabled", "Whether commands on join messages are enabled by default or not. Default value: true")] [CommandHelper(whoCanExecute: CommandUsage.SERVER_ONLY)] public void SharpTimerConnectCmdMSGConvar(CCSPlayerController? player, CommandInfo command) @@ -1320,11 +1243,11 @@ public void SharpTimerAdServerRecordTimer(CCSPlayerController? player, CommandIn if (int.TryParse(args, out int interval) && interval > 0) { adServerRecordTimer = interval; - SharpTimerConPrint($"SharpTimer sr ad interval set to {interval} seconds."); + Utils.LogDebug($"SharpTimer sr ad interval set to {interval} seconds."); } else { - SharpTimerConPrint("Invalid sr ad interval value. Please provide a positive integer."); + Utils.LogError("Invalid sr ad interval value. Please provide a positive integer."); } } @@ -1346,11 +1269,11 @@ public void SharpTimerAdMessagesTimer(CCSPlayerController? player, CommandInfo c if (int.TryParse(args, out int interval) && interval > 0) { adMessagesTimer = interval; - SharpTimerConPrint($"SharpTimer messages ad interval set to {interval} seconds."); + Utils.LogDebug($"SharpTimer messages ad interval set to {interval} seconds."); } else { - SharpTimerConPrint("Invalid messages ad interval value. Please provide a positive integer."); + Utils.LogError("Invalid messages ad interval value. Please provide a positive integer."); } } /* ad messages */ @@ -1415,14 +1338,14 @@ public void SharpTimerFakeTriggerHeightConvar(CCSPlayerController? player, Comma { string args = command.ArgString; - if (float.TryParse(args, NumberStyles.Any, culture, out float height) && height > 0) + if (float.TryParse(args, NumberStyles.Any, CultureInfo.InvariantCulture, out float height) && height > 0) { fakeTriggerHeight = height; - SharpTimerConPrint($"SharpTimer fake trigger height set to {height} units."); + Utils.LogDebug($"SharpTimer fake trigger height set to {height} units."); } else { - SharpTimerConPrint("Invalid fake trigger height value. Please provide a positive integer."); + Utils.LogError("Invalid fake trigger height value. Please provide a positive integer."); } } @@ -1463,6 +1386,15 @@ public void SharpTimerSoundEnableByDefault(CCSPlayerController? player, CommandI soundsEnabledByDefault = bool.TryParse(args, out bool soundsEnabledByDefaultValue) ? soundsEnabledByDefaultValue : args != "0" && soundsEnabledByDefault; } + [ConsoleCommand("sharptimer_enable_soundevents", "Whether to enable soundevents. Default value: false")] + [CommandHelper(whoCanExecute: CommandUsage.SERVER_ONLY)] + public void SharpTimerSoundEventsEnable(CCSPlayerController? player, CommandInfo command) + { + string args = command.ArgString; + + soundeventsEnabled = bool.TryParse(args, out bool soundeventsEnabledValue) ? soundeventsEnabledValue : args != "0" && soundeventsEnabledValue; + } + [ConsoleCommand("sharptimer_sound_timer", "Defines Timer sound. Default value: sounds/ui/counter_beep.vsnd")] [CommandHelper(whoCanExecute: CommandUsage.SERVER_ONLY)] public void SharpTimerSoundTimer(CCSPlayerController? player, CommandInfo command) @@ -1592,14 +1524,14 @@ public void SharpTimerParachuteMultiplierConvar(CCSPlayerController? player, Com { string args = command.ArgString; - if (double.TryParse(args, NumberStyles.Any, culture, out double pointModifier) && pointModifier is >= 0 and <= 2) + if (double.TryParse(args, NumberStyles.Any, CultureInfo.InvariantCulture, out double pointModifier) && pointModifier is >= 0 and <= 2) { parachutePointModifier = pointModifier; - SharpTimerConPrint($"SharpTimer parachute point modifier set to {pointModifier}."); + Utils.LogDebug($"SharpTimer parachute point modifier set to {pointModifier}."); } else { - SharpTimerConPrint("Invalid parachute point modifier. Please provide a positive integer."); + Utils.LogError("Invalid parachute point modifier. Please provide a positive integer."); } } @@ -1609,14 +1541,14 @@ public void SharpTimerTASMultiplierConvar(CCSPlayerController? player, CommandIn { string args = command.ArgString; - if (double.TryParse(args, NumberStyles.Any, culture, out double pointModifier) && pointModifier is >= 0 and <= 2) + if (double.TryParse(args, NumberStyles.Any, CultureInfo.InvariantCulture, out double pointModifier) && pointModifier is >= 0 and <= 2) { tasPointModifier = pointModifier; - SharpTimerConPrint($"SharpTimer TAS point modifier set to {pointModifier}."); + Utils.LogDebug($"SharpTimer TAS point modifier set to {pointModifier}."); } else { - SharpTimerConPrint("Invalid TAS point modifier. Please provide a positive integer."); + Utils.LogError("Invalid TAS point modifier. Please provide a positive integer."); } } @@ -1626,14 +1558,14 @@ public void SharpTimerLowGravMultiplierConvar(CCSPlayerController? player, Comma { string args = command.ArgString; - if (double.TryParse(args, NumberStyles.Any, culture, out double pointModifier) && pointModifier is >= 0 and <= 2) + if (double.TryParse(args, NumberStyles.Any, CultureInfo.InvariantCulture, out double pointModifier) && pointModifier is >= 0 and <= 2) { lowgravPointModifier = pointModifier; - SharpTimerConPrint($"SharpTimer low grav point modifier set to {pointModifier}."); + Utils.LogDebug($"SharpTimer low grav point modifier set to {pointModifier}."); } else { - SharpTimerConPrint("Invalid low grav point modifier. Please provide a positive integer."); + Utils.LogError("Invalid low grav point modifier. Please provide a positive integer."); } } [ConsoleCommand("sharptimer_style_multiplier_sideways", "Point modifier for sidways. Default value: 1.3")] @@ -1642,14 +1574,14 @@ public void SharpTimerSidewaysMultiplierConvar(CCSPlayerController? player, Comm { string args = command.ArgString; - if (double.TryParse(args, NumberStyles.Any, culture, out double pointModifier) && pointModifier is >= 0 and <= 2) + if (double.TryParse(args, NumberStyles.Any, CultureInfo.InvariantCulture, out double pointModifier) && pointModifier is >= 0 and <= 2) { sidewaysPointModifier = pointModifier; - SharpTimerConPrint($"SharpTimer sideways point modifier set to {pointModifier}."); + Utils.LogDebug($"SharpTimer sideways point modifier set to {pointModifier}."); } else { - SharpTimerConPrint("Invalid sideways point modifier. Please provide a positive integer."); + Utils.LogError("Invalid sideways point modifier. Please provide a positive integer."); } } @@ -1659,14 +1591,14 @@ public void SharpTimerOnlyWMultiplierConvar(CCSPlayerController? player, Command { string args = command.ArgString; - if (double.TryParse(args, NumberStyles.Any, culture, out double pointModifier) && pointModifier is >= 0 and <= 2) + if (double.TryParse(args, NumberStyles.Any, CultureInfo.InvariantCulture, out double pointModifier) && pointModifier is >= 0 and <= 2) { onlywPointModifier = pointModifier; - SharpTimerConPrint($"SharpTimer onlyw point modifier set to {pointModifier}."); + Utils.LogDebug($"SharpTimer onlyw point modifier set to {pointModifier}."); } else { - SharpTimerConPrint("Invalid onlyw point modifier. Please provide a positive integer."); + Utils.LogError("Invalid onlyw point modifier. Please provide a positive integer."); } } @@ -1676,14 +1608,14 @@ public void SharpTimerOnlyAMultiplierConvar(CCSPlayerController? player, Command { string args = command.ArgString; - if (double.TryParse(args, NumberStyles.Any, culture, out double pointModifier) && pointModifier is >= 0 and <= 2) + if (double.TryParse(args, NumberStyles.Any, CultureInfo.InvariantCulture, out double pointModifier) && pointModifier is >= 0 and <= 2) { onlyaPointModifier = pointModifier; - SharpTimerConPrint($"SharpTimer onlya point modifier set to {pointModifier}."); + Utils.LogDebug($"SharpTimer onlya point modifier set to {pointModifier}."); } else { - SharpTimerConPrint("Invalid onlya point modifier. Please provide a positive integer."); + Utils.LogError("Invalid onlya point modifier. Please provide a positive integer."); } } @@ -1693,14 +1625,14 @@ public void SharpTimerOnlySMultiplierConvar(CCSPlayerController? player, Command { string args = command.ArgString; - if (double.TryParse(args, NumberStyles.Any, culture, out double pointModifier) && pointModifier is >= 0 and <= 2) + if (double.TryParse(args, NumberStyles.Any, CultureInfo.InvariantCulture, out double pointModifier) && pointModifier is >= 0 and <= 2) { onlysPointModifier = pointModifier; - SharpTimerConPrint($"SharpTimer onlys point modifier set to {pointModifier}."); + Utils.LogDebug($"SharpTimer onlys point modifier set to {pointModifier}."); } else { - SharpTimerConPrint("Invalid onlys point modifier. Please provide a positive integer."); + Utils.LogError("Invalid onlys point modifier. Please provide a positive integer."); } } @@ -1710,14 +1642,14 @@ public void SharpTimerOnlyDMultiplierConvar(CCSPlayerController? player, Command { string args = command.ArgString; - if (double.TryParse(args, NumberStyles.Any, culture, out double pointModifier) && pointModifier is >= 0 and <= 2) + if (double.TryParse(args, NumberStyles.Any, CultureInfo.InvariantCulture, out double pointModifier) && pointModifier is >= 0 and <= 2) { onlydPointModifier = pointModifier; - SharpTimerConPrint($"SharpTimer onlyd point modifier set to {pointModifier}."); + Utils.LogDebug($"SharpTimer onlyd point modifier set to {pointModifier}."); } else { - SharpTimerConPrint("Invalid onlyd point modifier. Please provide a positive integer."); + Utils.LogError("Invalid onlyd point modifier. Please provide a positive integer."); } } @@ -1727,14 +1659,14 @@ public void SharpTimer400velConvar(CCSPlayerController? player, CommandInfo comm { string args = command.ArgString; - if (double.TryParse(args, NumberStyles.Any, culture, out double pointModifier) && pointModifier is >= 0 and <= 2) + if (double.TryParse(args, NumberStyles.Any, CultureInfo.InvariantCulture, out double pointModifier) && pointModifier is >= 0 and <= 2) { velPointModifier = pointModifier; - SharpTimerConPrint($"SharpTimer 400vel point modifier set to {pointModifier}."); + Utils.LogDebug($"SharpTimer 400vel point modifier set to {pointModifier}."); } else { - SharpTimerConPrint("Invalid 400vel point modifier. Please provide a positive integer."); + Utils.LogError("Invalid 400vel point modifier. Please provide a positive integer."); } } @@ -1744,14 +1676,14 @@ public void SharpTimerHighGravConvar(CCSPlayerController? player, CommandInfo co { string args = command.ArgString; - if (double.TryParse(args, NumberStyles.Any, culture, out double pointModifier) && pointModifier is >= 0 and <= 2) + if (double.TryParse(args, NumberStyles.Any, CultureInfo.InvariantCulture, out double pointModifier) && pointModifier is >= 0 and <= 2) { highgravPointModifier = pointModifier; - SharpTimerConPrint($"SharpTimer highgrav point modifier set to {pointModifier}."); + Utils.LogDebug($"SharpTimer highgrav point modifier set to {pointModifier}."); } else { - SharpTimerConPrint("Invalid highgrav point modifier. Please provide a positive integer."); + Utils.LogError("Invalid highgrav point modifier. Please provide a positive integer."); } } @@ -1761,14 +1693,14 @@ public void SharpTimerHalfSidewaysConvar(CCSPlayerController? player, CommandInf { string args = command.ArgString; - if (double.TryParse(args, NumberStyles.Any, culture, out double pointModifier) && pointModifier is >= 0 and <= 2) + if (double.TryParse(args, NumberStyles.Any, CultureInfo.InvariantCulture, out double pointModifier) && pointModifier is >= 0 and <= 2) { halfSidewaysPointModifier = pointModifier; - SharpTimerConPrint($"SharpTimer halfsideways point modifier set to {pointModifier}."); + Utils.LogDebug($"SharpTimer halfsideways point modifier set to {pointModifier}."); } else { - SharpTimerConPrint("Invalid halfsideways point modifier. Please provide a positive integer."); + Utils.LogError("Invalid halfsideways point modifier. Please provide a positive integer."); } } @@ -1778,14 +1710,14 @@ public void SharpTimerFastForwardConvar(CCSPlayerController? player, CommandInfo { string args = command.ArgString; - if (double.TryParse(args, NumberStyles.Any, culture, out double pointModifier) && pointModifier is >= 0 and <= 2) + if (double.TryParse(args, NumberStyles.Any, CultureInfo.InvariantCulture, out double pointModifier) && pointModifier is >= 0 and <= 2) { fastForwardPointModifier = pointModifier; - SharpTimerConPrint($"SharpTimer fastforward point modifier set to {pointModifier}."); + Utils.LogDebug($"SharpTimer fastforward point modifier set to {pointModifier}."); } else { - SharpTimerConPrint("Invalid fastforward point modifier. Please provide a positive integer."); + Utils.LogError("Invalid fastforward point modifier. Please provide a positive integer."); } } @@ -1805,22 +1737,6 @@ public void SharpTimerRemoteDataOverrideBhop(CCSPlayerController? player, Comman remoteBhopDataSource = $"{args}"; } - [ConsoleCommand("sharptimer_remote_data_kz", "Override for kz remote_data")] - [CommandHelper(whoCanExecute: CommandUsage.SERVER_ONLY)] - public void SharpTimerRemoteDataOverrideKZ(CCSPlayerController? player, CommandInfo command) - { - - string args = command.ArgString.Trim(); - - if (string.IsNullOrEmpty(args)) - { - remoteKZDataSource = $"https://raw.githubusercontent.com/Letaryat/poor-SharpTimer/main/remote_data/kz_.json"; - return; - } - - remoteKZDataSource = $"{args}"; - } - [ConsoleCommand("sharptimer_remote_data_surf", "Override for surf remote_data")] [CommandHelper(whoCanExecute: CommandUsage.SERVER_ONLY)] public void SharpTimerRemoteDataOverrideSurf(CCSPlayerController? player, CommandInfo command) @@ -1836,29 +1752,5 @@ public void SharpTimerRemoteDataOverrideSurf(CCSPlayerController? player, Comman remoteSurfDataSource = $"{args}"; } - - [ConsoleCommand("sharptimer_replay_data_directory", "Directory for replay data. Prepended with game dir. Default value: csgo/cfg/SharpTimer/PlayerReplayData")] - [CommandHelper(whoCanExecute: CommandUsage.SERVER_ONLY)] - public void SharpTimerReplayDataDirectory(CCSPlayerController? player, CommandInfo command) - { - string args = command.ArgString.Trim(); - - if (string.IsNullOrEmpty(args)) - { - playerReplaysPath = Path.Join(gameDir, "csgo", "cfg", "SharpTimer", "PlayerReplayData"); - return; - } - - playerReplaysPath = Path.Join([gameDir, ..args.Split('/')]); - } - - [ConsoleCommand("sharptimer_replays_use_binary", "Save replays as binary files instead of json. Default value: false")] - [CommandHelper(whoCanExecute: CommandUsage.SERVER_ONLY)] - public void SharpTimerReplaysUseBinary(CCSPlayerController? player, CommandInfo command) - { - string args = command.ArgString; - - useBinaryReplays = bool.TryParse(args, out bool useBinaryReplaysValue) ? useBinaryReplaysValue : args != "0" && useBinaryReplays; - } } } \ No newline at end of file diff --git a/src/DB/DatabaseUtils.cs b/src/DB/DatabaseUtils.cs index 3746a749..0993b67d 100644 --- a/src/DB/DatabaseUtils.cs +++ b/src/DB/DatabaseUtils.cs @@ -98,7 +98,7 @@ private string GetConnectionStringOnMainThread() } else { - using (JsonDocument? jsonConfig = LoadJsonOnMainThread(dbPath)!) + using (JsonDocument? jsonConfig = Utils.LoadJsonOnMainThread(dbPath)!) { if (jsonConfig != null) { @@ -128,19 +128,19 @@ private string GetConnectionStringOnMainThread() } else { - SharpTimerError($"Database type not supported"); + Utils.LogError($"Database type not supported"); } } else { - SharpTimerError($"Database json was null"); + Utils.LogError($"Database json was null"); } } } } catch (Exception ex) { - SharpTimerError($"Error in GetConnectionString: {ex.Message}"); + Utils.LogError($"Error in GetConnectionString: {ex.Message}"); } return "Server=localhost;Database=database;User ID=root;Password=root;Port=3306;"; } @@ -154,7 +154,7 @@ private async Task GetConnectionStringFromConfigFile() } else { - using (JsonDocument? jsonConfig = await LoadJson(dbPath)!) + using (JsonDocument? jsonConfig = await Utils.LoadJson(dbPath)!) { if (jsonConfig != null) { @@ -185,19 +185,19 @@ private async Task GetConnectionStringFromConfigFile() } else { - SharpTimerError($"Database type not supported"); + Utils.LogError($"Database type not supported"); } } else { - SharpTimerError($"Database json was null"); + Utils.LogError($"Database json was null"); } } } } catch (Exception ex) { - SharpTimerError($"Error in GetConnectionString: {ex.Message}"); + Utils.LogError($"Error in GetConnectionString: {ex.Message}"); } return "Server=localhost;Database=database;User ID=root;Password=root;Port=3306;"; } @@ -224,11 +224,8 @@ public async Task CheckTablesAsync() "TimesConnected INT DEFAULT 0", "LastConnected INT DEFAULT 0", "GlobalPoints INT DEFAULT 0", - "HideWeapon BOOL DEFAULT false", - "HidePlayers BOOL DEFAULT false", "HideTimerHud BOOL DEFAULT false", "HideKeys BOOL DEFAULT false", - "HideJS BOOL DEFAULT false", "SoundsEnabled BOOL DEFAULT false", "PlayerFov INT DEFAULT 0", "IsVip BOOL DEFAULT false", @@ -251,10 +248,8 @@ public async Task CheckTablesAsync() @"""TimesConnected"" INT DEFAULT 0", @"""LastConnected"" INT DEFAULT 0", @"""GlobalPoints"" INT DEFAULT 0", - @"""HideWeapon"" BOOL DEFAULT false", @"""HideTimerHud"" BOOL DEFAULT false", @"""HideKeys"" BOOL DEFAULT false", - @"""HideJS"" BOOL DEFAULT false", @"""SoundsEnabled"" BOOL DEFAULT false", @"""PlayerFov"" INT DEFAULT 0", @"""IsVip"" BOOL DEFAULT false", @@ -277,11 +272,8 @@ public async Task CheckTablesAsync() "TimesConnected INTEGER DEFAULT 0", "LastConnected INTEGER DEFAULT 0", "GlobalPoints INTEGER DEFAULT 0", - "HideWeapon INTEGER DEFAULT 0", - "HidePlayers INTEGER DEFAULT 0", "HideTimerHud INTEGER DEFAULT 0", "HideKeys INTEGER DEFAULT 0", - "HideJS INTEGER DEFAULT 0", "SoundsEnabled INTEGER DEFAULT 1", "PlayerFov INTEGER DEFAULT 0", "IsVip INTEGER DEFAULT 0", @@ -291,7 +283,7 @@ public async Task CheckTablesAsync() default: playerRecords = null; playerStats = null; - SharpTimerError($"Database type not supported"); + Utils.LogError($"Database type not supported"); break; } using (var connection = await OpenConnectionAsync()) @@ -299,18 +291,18 @@ public async Task CheckTablesAsync() try { // Check PlayerRecords - SharpTimerDebug($"Checking PlayerRecords Table..."); + Utils.LogDebug($"Checking PlayerRecords Table..."); await CreatePlayerRecordsTableAsync(connection); await UpdateTableColumnsAsync(connection, "PlayerRecords", playerRecords!); // Check PlayerStats - SharpTimerDebug($"Checking PlayerStats Table..."); + Utils.LogDebug($"Checking PlayerStats Table..."); await CreatePlayerStatsTableAsync(connection); await UpdateTableColumnsAsync(connection, $"{PlayerStatsTable}", playerStats!); } catch (Exception ex) { - SharpTimerError($"Error in CheckTablesAsync: {ex}"); + Utils.LogError($"Error in CheckTablesAsync: {ex}"); } } } @@ -377,7 +369,7 @@ PRIMARY KEY (MapName, SteamID, Style) } catch (Exception ex) { - SharpTimerError($"Error in CreatePlayerRecordsTableAsync: {ex.Message}"); + Utils.LogError($"Error in CreatePlayerRecordsTableAsync: {ex.Message}"); } } } @@ -390,7 +382,7 @@ private async Task UpdateTableColumnsAsync(IDbConnection connection, string tabl string columnName = columnDefinition.Split(' ')[0]; if (!await ColumnExistsAsync(connection, tableName, columnName)) { - SharpTimerDebug($"Adding column {columnName} to {tableName}..."); + Utils.LogDebug($"Adding column {columnName} to {tableName}..."); await AddColumnToTableAsync(connection, tableName, columnDefinition); } } @@ -427,7 +419,7 @@ private async Task TableExistsAsync(IDbConnection connection, string table } catch (Exception ex) { - SharpTimerError($"Error in TableExistsAsync: {ex.Message}"); + Utils.LogError($"Error in TableExistsAsync: {ex.Message}"); return false; } } @@ -471,7 +463,7 @@ private async Task ColumnExistsAsync(IDbConnection connection, string tabl } catch (Exception ex) { - SharpTimerError($"Error in ColumnExistsAsync: {ex.Message}"); + Utils.LogError($"Error in ColumnExistsAsync: {ex.Message}"); return false; } } @@ -484,7 +476,7 @@ private async Task ColumnExistsAsync(IDbConnection connection, string tabl } catch (Exception ex) { - SharpTimerError($"Error in ColumnExistsAsync: {ex.Message}"); + Utils.LogError($"Error in ColumnExistsAsync: {ex.Message}"); return false; } } @@ -521,7 +513,7 @@ private async Task AddColumnToTableAsync(IDbConnection connection, string tableN } catch (Exception ex) { - SharpTimerError($"Error in AddColumnToTableAsync: {ex.Message}"); + Utils.LogError($"Error in AddColumnToTableAsync: {ex.Message}"); } } } @@ -538,11 +530,8 @@ PlayerName VARCHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, TimesConnected INT, LastConnected INT, GlobalPoints INT, - HideWeapon BOOL, - HidePlayers BOOL, HideTimerHud BOOL, HideKeys BOOL, - HideJS BOOL, SoundsEnabled BOOL, PlayerFov INT, IsVip BOOL, @@ -558,11 +547,8 @@ PRIMARY KEY (SteamID) ""TimesConnected"" INT, ""LastConnected"" INT, ""GlobalPoints"" INT, - ""HideWeapon"" BOOL, - ""HidePlayers"" BOOL, ""HideTimerHud"" BOOL, ""HideKeys"" BOOL, - ""HideJS"" BOOL, ""SoundsEnabled"" BOOL, ""PlayerFov"" INT, ""IsVip"" BOOL, @@ -578,11 +564,8 @@ PRIMARY KEY (""SteamID"") TimesConnected INTEGER, LastConnected INTEGER, GlobalPoints INTEGER, - HideWeapon INTEGER, - HidePlayers INTEGER, HideTimerHud INTEGER, HideKeys INTEGER, - HideJS INTEGER, SoundsEnabled INTEGER, PlayerFov INTEGER, IsVip INTEGER, @@ -601,17 +584,17 @@ PRIMARY KEY (""SteamID"") } catch (Exception ex) { - SharpTimerError($"Error in CreatePlayerStatsTableAsync: {ex.Message}"); + Utils.LogError($"Error in CreatePlayerStatsTableAsync: {ex.Message}"); } } } - public async Task SavePlayerTimeToDatabase(CCSPlayerController? player, int timerTicks, string steamId, string playerName, int playerSlot, int bonusX = 0, int style = 0) + public async Task SavePlayerTimeToDatabase(CCSPlayerController? player, int timerTicks, string steamId, string playerName, int slot, int bonusX = 0, int style = 0) { - SharpTimerDebug($"Trying to save player {(bonusX != 0 ? $"bonus {bonusX} time" : "time")} to database for {playerName} {timerTicks}"); + Utils.LogDebug($"Trying to save player {(bonusX != 0 ? $"bonus {bonusX} time" : "time")} to database for {playerName} {timerTicks}"); try { if (!IsAllowedPlayer(player)) return; - //if ((bonusX == 0 && !playerTimers[playerSlot].IsTimerRunning) || (bonusX != 0 && !playerTimers[playerSlot].IsBonusTimerRunning)) return; + //if ((bonusX == 0 && !playerTimers[slot].IsTimerRunning) || (bonusX != 0 && !playerTimers[slot].IsBonusTimerRunning)) return; string currentMapNamee = bonusX == 0 ? currentMapName! : $"{currentMapName}_bonus{bonusX}"; int timeNowUnix = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds(); @@ -631,7 +614,7 @@ public async Task SavePlayerTimeToDatabase(CCSPlayerController? player, int time { await CreatePlayerRecordsTableAsync(connection); - string formattedTime = FormatTime(timerTicks); + string formattedTime = Utils.FormatTime(timerTicks); string? selectQuery; DbCommand? selectCommand; switch (dbType) @@ -679,12 +662,7 @@ public async Task SavePlayerTimeToDatabase(CCSPlayerController? player, int time dBFormattedTime = formattedTime; playerPoints = timerTicks; beatPB = true; - if (enableReplays && !onlySRReplay) { - if(useBinaryReplays) - _ = Task.Run(async () => await DumpReplayToBinary(player!, steamId, playerSlot, bonusX, playerTimers[playerSlot].currentStyle)); - else - _ = Task.Run(async () => await DumpReplayToJson(player!, steamId, playerSlot, bonusX, playerTimers[playerSlot].currentStyle)); - } + if (enableReplays && !onlySRReplay) _ = Task.Run(async () => await DumpReplayToJson(player!, steamId, slot, bonusX, playerTimers[slot].currentStyle)); } else { @@ -770,25 +748,19 @@ DO UPDATE SET upsertCommand!.AddParameterWithValue("@UnixStamp", dBunixStamp); upsertCommand!.AddParameterWithValue("@SteamID", steamId); upsertCommand!.AddParameterWithValue("@Style", style); - if (style == 0 && (stageTriggerCount != 0 || cpTriggerCount != 0) && bonusX == 0 && enableDb && timerTicks < dBtimerTicks) Server.NextFrame(() => _ = Task.Run(async () => await DumpPlayerStageTimesToJson(player, steamId, playerSlot))); + if (style == 0 && (stageTriggerCount != 0 || cpTriggerCount != 0) && bonusX == 0 && enableDb && timerTicks < dBtimerTicks && !ignoreJSON) Server.NextFrame(() => _ = Task.Run(async () => await DumpPlayerStageTimesToJson(player, steamId, slot))); var prevSRID = await GetMapRecordSteamIDFromDatabase(bonusX, 0, style); var prevSR = await GetPreviousPlayerRecordFromDatabase(prevSRID.Item1, currentMapNamee, prevSRID.Item2, bonusX, style); await upsertCommand!.ExecuteNonQueryAsync(); - Server.NextFrame(() => SharpTimerDebug($"Saved player {(bonusX != 0 ? $"bonus {bonusX} time" : "time")} to database for {playerName} {timerTicks} {DateTimeOffset.UtcNow.ToUnixTimeSeconds()}")); - if (enableDb && IsAllowedPlayer(player)) await RankCommandHandler(player, steamId, playerSlot, playerName, true, style); - if (globalRanksEnabled == true) await SavePlayerPoints(steamId, playerName, playerSlot, timerTicks, dBtimerTicks, beatPB, bonusX, style, dBtimesFinished); + Server.NextFrame(() => Utils.LogDebug($"Saved player {(bonusX != 0 ? $"bonus {bonusX} time" : "time")} to database for {playerName} {timerTicks} {DateTimeOffset.UtcNow.ToUnixTimeSeconds()}")); + if (enableDb && IsAllowedPlayer(player)) await RankCommandHandler(player, steamId, slot, playerName, true, style); + if (globalRanksEnabled == true) await SavePlayerPoints(steamId, playerName, slot, timerTicks, dBtimerTicks, beatPB, bonusX, style, dBtimesFinished); if (IsAllowedPlayer(player)) Server.NextFrame(() => _ = Task.Run(async () => await PrintMapTimeToChat(player!, steamId, playerName, dBtimerTicks, timerTicks, bonusX, dBtimesFinished, style, prevSR))); - if (enableReplays && onlySRReplay - && prevSR > timerTicks) { - if(useBinaryReplays) - _ = Task.Run(async () => await DumpReplayToBinary(player!, steamId, playerSlot, bonusX, playerTimers[playerSlot].currentStyle)); - else - _ = Task.Run(async () => await DumpReplayToJson(player!, steamId, playerSlot, bonusX, playerTimers[playerSlot].currentStyle)); - } + if (enableReplays && onlySRReplay && (prevSR == 0 || prevSR > timerTicks)) _ = Task.Run(async () => await DumpReplayToJson(player!, steamId, slot, bonusX, playerTimers[slot].currentStyle)); Server.NextFrame(async () => { - var (hostname, ip) = GetHostnameAndIp(); + var (hostname, ip) = Utils.GetHostnameAndIp(); var (globalCheck, maxVel, maxWish) = CheckCvarsAndMaxVelo(); if (!globalCheck) return; @@ -810,7 +782,7 @@ DO UPDATE SET timer_ticks = timerTicks, steamid = steamId, player_name = playerName, - formatted_time = FormatTime(timerTicks), + formatted_time = Utils.FormatTime(timerTicks), unix_stamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds(), times_finished = dBtimesFinished, style = style, @@ -837,7 +809,7 @@ DO UPDATE SET map_name = currentMapNamee, style = style, hash = GetHash(), - replay_data = await GetReplayJson(player!, player!.Slot) + replay_data = GetReplayJson(player!, player!.Slot) }; await SubmitReplayAsync(replay_payload); @@ -849,13 +821,8 @@ DO UPDATE SET } else { - Server.NextFrame(() => SharpTimerDebug($"No player record yet")); - if (enableReplays && !onlySRReplay) { - if (useBinaryReplays) - _ = Task.Run(async () => await DumpReplayToBinary(player!, steamId, playerSlot, bonusX, playerTimers[playerSlot].currentStyle)); - else - _ = Task.Run(async () => await DumpReplayToJson(player!, steamId, playerSlot, bonusX, playerTimers[playerSlot].currentStyle)); - } + Server.NextFrame(() => Utils.LogDebug($"No player record yet")); + if (enableReplays && !onlySRReplay) _ = Task.Run(async () => await DumpReplayToJson(player!, steamId, slot, bonusX, playerTimers[slot].currentStyle)); await row.CloseAsync(); string? upsertQuery; @@ -894,22 +861,18 @@ DO UPDATE SET var prevSRID = await GetMapRecordSteamIDFromDatabase(bonusX, 0, style); var prevSR = await GetPreviousPlayerRecordFromDatabase(prevSRID.Item1, currentMapNamee, prevSRID.Item2, bonusX, style); await upsertCommand!.ExecuteNonQueryAsync(); - if (globalRanksEnabled == true) await SavePlayerPoints(steamId, playerName, playerSlot, timerTicks, dBtimerTicks, beatPB, bonusX, style, dBtimesFinished); - if (style == 0 && (stageTriggerCount != 0 || cpTriggerCount != 0) && bonusX == 0) Server.NextFrame(() => _ = Task.Run(async () => await DumpPlayerStageTimesToJson(player, steamId, playerSlot))); - Server.NextFrame(() => SharpTimerDebug($"Saved player {(bonusX != 0 ? $"bonus {bonusX} time" : "time")} to database for {playerName} {timerTicks} {DateTimeOffset.UtcNow.ToUnixTimeSeconds()}")); - if (IsAllowedPlayer(player)) await RankCommandHandler(player, steamId, playerSlot, playerName, true, style); + if (globalRanksEnabled == true) await SavePlayerPoints(steamId, playerName, slot, timerTicks, dBtimerTicks, beatPB, bonusX, style, dBtimesFinished); + + if (style == 0 && (stageTriggerCount != 0 || cpTriggerCount != 0) && bonusX == 0 && !ignoreJSON) Server.NextFrame(() => _ = Task.Run(async () => await DumpPlayerStageTimesToJson(player, steamId, slot))); + Server.NextFrame(() => Utils.LogDebug($"Saved player {(bonusX != 0 ? $"bonus {bonusX} time" : "time")} to database for {playerName} {timerTicks} {DateTimeOffset.UtcNow.ToUnixTimeSeconds()}")); + + if (IsAllowedPlayer(player)) await RankCommandHandler(player, steamId, slot, playerName, true, style); if (IsAllowedPlayer(player)) Server.NextFrame(() => _ = Task.Run(async () => await PrintMapTimeToChat(player!, steamId, playerName, dBtimerTicks, timerTicks, bonusX, 1, style, prevSR))); - if (enableReplays && onlySRReplay - && prevSR > timerTicks) { - if (useBinaryReplays) - _ = Task.Run(async () => await DumpReplayToBinary(player!, steamId, playerSlot, bonusX, playerTimers[playerSlot].currentStyle)); - else - _ = Task.Run(async () => await DumpReplayToJson(player!, steamId, playerSlot, bonusX, playerTimers[playerSlot].currentStyle)); - } + if (enableReplays && onlySRReplay && (prevSR == 0 || prevSR > timerTicks)) _ = Task.Run(async () => await DumpReplayToJson(player!, steamId, slot, bonusX, playerTimers[slot].currentStyle)); Server.NextFrame(async () => { - var (hostname, ip) = GetHostnameAndIp(); + var (hostname, ip) = Utils.GetHostnameAndIp(); var (globalCheck, maxVel, maxWish) = CheckCvarsAndMaxVelo(); if (!globalCheck) return; @@ -928,7 +891,7 @@ DO UPDATE SET timer_ticks = timerTicks, steamid = steamId, player_name = playerName, - formatted_time = FormatTime(timerTicks), + formatted_time = Utils.FormatTime(timerTicks), unix_stamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds(), times_finished = dBtimesFinished, style = style, @@ -954,7 +917,7 @@ DO UPDATE SET map_name = currentMapNamee, style = style, hash = GetHash(), - replay_data = await GetReplayJson(player!, player!.Slot) + replay_data = GetReplayJson(player!, player!.Slot) }; await SubmitReplayAsync(replay_payload); @@ -968,17 +931,17 @@ DO UPDATE SET } catch (Exception ex) { - Server.NextFrame(() => SharpTimerError($"Error saving player {(bonusX != 0 ? $"bonus {bonusX} time" : "time")} to database: {ex.Message}")); + Server.NextFrame(() => Utils.LogError($"Error saving player {(bonusX != 0 ? $"bonus {bonusX} time" : "time")} to database: {ex.Message}")); } } - public async Task GetPlayerStats(CCSPlayerController? player, string steamId, string playerName, int playerSlot, bool fromConnect) + public async Task GetPlayerStats(CCSPlayerController? player, string steamId, string playerName, int slot, bool fromConnect) { - SharpTimerDebug($"Trying to get player stats from database for {playerName}"); + Utils.LogDebug($"Trying to get player stats from database for {playerName}"); try { if (player == null || !player.IsValid || player.IsBot) return; - if (!(connectedPlayers.ContainsKey(playerSlot) && playerTimers.ContainsKey(playerSlot))) return; + if (!(connectedPlayers.ContainsKey(slot) && playerTimers.ContainsKey(slot))) return; int timeNowUnix = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds(); // get player columns @@ -986,7 +949,6 @@ public async Task GetPlayerStats(CCSPlayerController? player, string steamId, st int lastConnected = 0; bool hideTimerHud = false; bool hideKeys = false; - bool hideJS = false; bool soundsEnabled = true; int playerFov = 0; bool isVip = false; @@ -1004,15 +966,15 @@ public async Task GetPlayerStats(CCSPlayerController? player, string steamId, st switch (dbType) { case DatabaseType.MySQL: - selectQuery = $@"SELECT PlayerName, TimesConnected, LastConnected, HideTimerHud, HideKeys, HideJS, SoundsEnabled, PlayerFov, IsVip, BigGifID, GlobalPoints, HideWeapon, HidePlayers FROM {PlayerStatsTable} WHERE SteamID = @SteamID"; + selectQuery = $@"SELECT PlayerName, TimesConnected, LastConnected, HideTimerHud, HideKeys, SoundsEnabled, PlayerFov, IsVip, BigGifID, GlobalPoints, HideWeapon, HidePlayers FROM {PlayerStatsTable} WHERE SteamID = @SteamID"; selectCommand = new MySqlCommand(selectQuery, (MySqlConnection)connection); break; case DatabaseType.PostgreSQL: - selectQuery = $@"SELECT ""PlayerName"", ""TimesConnected"", ""LastConnected"", ""HideTimerHud"", ""HideKeys"", ""HideJS"", ""SoundsEnabled"", ""PlayerFov"", ""IsVip"", ""BigGifID"", ""GlobalPoints"", ""HideWeapon"", ""HidePlayers"" FROM ""{PlayerStatsTable}"" WHERE ""SteamID"" = @SteamID"; + selectQuery = $@"SELECT ""PlayerName"", ""TimesConnected"", ""LastConnected"", ""HideTimerHud"", ""HideKeys"", ""SoundsEnabled"", ""PlayerFov"", ""IsVip"", ""BigGifID"", ""GlobalPoints"", ""HideWeapon"", ""HidePlayers"" FROM ""{PlayerStatsTable}"" WHERE ""SteamID"" = @SteamID"; selectCommand = new NpgsqlCommand(selectQuery, (NpgsqlConnection)connection); break; case DatabaseType.SQLite: - selectQuery = $@"SELECT PlayerName, TimesConnected, LastConnected, HideTimerHud, HideKeys, HideJS, SoundsEnabled, PlayerFov, IsVip, BigGifID, GlobalPoints, HideWeapon, HidePlayers FROM {PlayerStatsTable} WHERE SteamID = @SteamID"; + selectQuery = $@"SELECT PlayerName, TimesConnected, LastConnected, HideTimerHud, HideKeys, SoundsEnabled, PlayerFov, IsVip, BigGifID, GlobalPoints, HideWeapon, HidePlayers FROM {PlayerStatsTable} WHERE SteamID = @SteamID"; selectCommand = new SQLiteCommand(selectQuery, (SQLiteConnection)connection); break; default: @@ -1037,7 +999,6 @@ public async Task GetPlayerStats(CCSPlayerController? player, string steamId, st timesConnected = row.GetInt32("TimesConnected"); hideTimerHud = row.GetBoolean("HideTimerHud"); hideKeys = row.GetBoolean("HideKeys"); - hideJS = row.GetBoolean("HideJS"); hideWeapon = row.GetBoolean("HideWeapon"); hidePlayers = row.GetBoolean("HidePlayers"); soundsEnabled = row.GetBoolean("SoundsEnabled"); @@ -1050,7 +1011,6 @@ public async Task GetPlayerStats(CCSPlayerController? player, string steamId, st timesConnected = row.GetInt32("TimesConnected"); hideTimerHud = row.GetSQLiteBool("HideTimerHud"); hideKeys = row.GetSQLiteBool("HideKeys"); - hideJS = row.GetSQLiteBool("HideJS"); hideWeapon = row.GetSQLiteBool("HideWeapon"); hidePlayers = row.GetSQLiteBool("HidePlayers"); soundsEnabled = row.GetSQLiteBool("SoundsEnabled"); @@ -1066,11 +1026,10 @@ public async Task GetPlayerStats(CCSPlayerController? player, string steamId, st lastConnected = timeNowUnix; Server.NextFrame(() => { - if (playerTimers.TryGetValue(playerSlot, out PlayerTimerInfo? value)) + if (playerTimers.TryGetValue(slot, out PlayerTimerInfo? value)) { value.HideTimerHud = hideTimerHud; value.HideKeys = hideKeys; - value.HideJumpStats = hideJS; value.HideWeapon = hideWeapon; value.HidePlayers = hidePlayers; value.SoundsEnabled = soundsEnabled; @@ -1081,7 +1040,7 @@ public async Task GetPlayerStats(CCSPlayerController? player, string steamId, st } else { - SharpTimerError($"Error getting player stats from database for {playerName}: player was not on the server anymore"); + Utils.LogError($"Error getting player stats from database for {playerName}: player was not on the server anymore"); return; } }); @@ -1094,16 +1053,16 @@ public async Task GetPlayerStats(CCSPlayerController? player, string steamId, st switch (dbType) { case DatabaseType.MySQL: - upsertQuery = $@"REPLACE INTO {PlayerStatsTable} (PlayerName, SteamID, TimesConnected, LastConnected, HideTimerHud, HideKeys, HideJS, SoundsEnabled, PlayerFov, IsVip, BigGifID, GlobalPoints, HideWeapon, HidePlayers) - VALUES (@PlayerName, @SteamID, @TimesConnected, @LastConnected, @HideTimerHud, @HideKeys, @HideJS, @SoundsEnabled, @PlayerFov, @IsVip, @BigGifID, @GlobalPoints, @HideWeapon, @HidePlayers)"; + upsertQuery = $@"REPLACE INTO {PlayerStatsTable} (PlayerName, SteamID, TimesConnected, LastConnected, HideTimerHud, HideKeys, SoundsEnabled, PlayerFov, IsVip, BigGifID, GlobalPoints, HideWeapon, HidePlayers) + VALUES (@PlayerName, @SteamID, @TimesConnected, @LastConnected, @HideTimerHud, @HideKeys, @SoundsEnabled, @PlayerFov, @IsVip, @BigGifID, @GlobalPoints, @HideWeapon, @HidePlayers)"; upsertCommand = new MySqlCommand(upsertQuery, (MySqlConnection)connection); break; case DatabaseType.PostgreSQL: upsertQuery = $@" INSERT INTO ""{PlayerStatsTable}"" - (""PlayerName"", ""SteamID"", ""TimesConnected"", ""LastConnected"", ""HideTimerHud"", ""HideKeys"", ""HideJS"", ""SoundsEnabled"", ""PlayerFov"", ""IsVip"", ""BigGifID"", ""GlobalPoints"", ""HideWeapon"", ""HidePlayers"") + (""PlayerName"", ""SteamID"", ""TimesConnected"", ""LastConnected"", ""HideTimerHud"", ""HideKeys"", ""SoundsEnabled"", ""PlayerFov"", ""IsVip"", ""BigGifID"", ""GlobalPoints"", ""HideWeapon"", ""HidePlayers"") VALUES - (@PlayerName, @SteamID, @TimesConnected, @LastConnected, @HideTimerHud, @HideKeys, @HideJS, @SoundsEnabled, @PlayerFov, @IsVip, @BigGifID, @GlobalPoints, @HideWeapon, @HidePlayers) + (@PlayerName, @SteamID, @TimesConnected, @LastConnected, @HideTimerHud, @HideKeys, @SoundsEnabled, @PlayerFov, @IsVip, @BigGifID, @GlobalPoints, @HideWeapon, @HidePlayers) ON CONFLICT (""SteamID"") DO UPDATE SET ""PlayerName"" = EXCLUDED.""PlayerName"", @@ -1111,7 +1070,6 @@ DO UPDATE SET ""LastConnected"" = EXCLUDED.""LastConnected"", ""HideTimerHud"" = EXCLUDED.""HideTimerHud"", ""HideKeys"" = EXCLUDED.""HideKeys"", - ""HideJS"" = EXCLUDED.""HideJS"", ""SoundsEnabled"" = EXCLUDED.""SoundsEnabled"", ""PlayerFov"" = EXCLUDED.""PlayerFov"", ""IsVip"" = EXCLUDED.""IsVip"", @@ -1123,8 +1081,8 @@ DO UPDATE SET upsertCommand = new NpgsqlCommand(upsertQuery, (NpgsqlConnection)connection); break; case DatabaseType.SQLite: - upsertQuery = $@"REPLACE INTO {PlayerStatsTable} (PlayerName, SteamID, TimesConnected, LastConnected, HideTimerHud, HideKeys, HideJS, SoundsEnabled, PlayerFov, IsVip, BigGifID, GlobalPoints, HideWeapon, HidePlayers) - VALUES (@PlayerName, @SteamID, @TimesConnected, @LastConnected, @HideTimerHud, @HideKeys, @HideJS, @SoundsEnabled, @PlayerFov, @IsVip, @BigGifID, @GlobalPoints, @HideWeapon, @HidePlayers)"; + upsertQuery = $@"REPLACE INTO {PlayerStatsTable} (PlayerName, SteamID, TimesConnected, LastConnected, HideTimerHud, HideKeys, SoundsEnabled, PlayerFov, IsVip, BigGifID, GlobalPoints, HideWeapon, HidePlayers) + VALUES (@PlayerName, @SteamID, @TimesConnected, @LastConnected, @HideTimerHud, @HideKeys, @SoundsEnabled, @PlayerFov, @IsVip, @BigGifID, @GlobalPoints, @HideWeapon, @HidePlayers)"; upsertCommand = new SQLiteCommand(upsertQuery, (SQLiteConnection)connection); break; default: @@ -1141,7 +1099,6 @@ DO UPDATE SET upsertCommand!.AddParameterWithValue("@LastConnected", lastConnected); upsertCommand!.AddParameterWithValue("@HideTimerHud", hideTimerHud); upsertCommand!.AddParameterWithValue("@HideKeys", hideKeys); - upsertCommand!.AddParameterWithValue("@HideJS", hideJS); upsertCommand!.AddParameterWithValue("@SoundsEnabled", soundsEnabled); upsertCommand!.AddParameterWithValue("@PlayerFov", playerFov); upsertCommand!.AddParameterWithValue("@IsVip", isVip); @@ -1151,14 +1108,14 @@ DO UPDATE SET upsertCommand!.AddParameterWithValue("@HidePlayers", hidePlayers); await upsertCommand!.ExecuteNonQueryAsync(); - Server.NextFrame(() => SharpTimerDebug($"Got player stats from database for {playerName}")); - if (connectMsgEnabled) Server.NextFrame(() => Server.PrintToChatAll($"{Localizer["prefix"]} {Localizer["connected_message", playerName, FormatOrdinal(timesConnected)]}")); + Server.NextFrame(() => Utils.LogDebug($"Got player stats from database for {playerName}")); + if (connectMsgEnabled) Server.NextFrame(() => Utils.PrintToChatAll($"{Localizer["connected_message", playerName, Utils.FormatOrdinal(timesConnected)]}")); } } else { - Server.NextFrame(() => SharpTimerDebug($"No player stats yet")); + Server.NextFrame(() => Utils.LogDebug($"No player stats yet")); await row.CloseAsync(); string? upsertQuery; @@ -1166,15 +1123,15 @@ DO UPDATE SET switch (dbType) { case DatabaseType.MySQL: - upsertQuery = $@"REPLACE INTO {PlayerStatsTable} (PlayerName, SteamID, TimesConnected, LastConnected, HideTimerHud, HideKeys, HideJS, SoundsEnabled, PlayerFov, IsVip, BigGifID, GlobalPoints, HideWeapon, HidePlayers) VALUES (@PlayerName, @SteamID, @TimesConnected, @LastConnected, @HideTimerHud, @HideKeys, @HideJS, @SoundsEnabled, @PlayerFov, @IsVip, @BigGifID, @GlobalPoints, @HideWeapon, @HidePlayers)"; + upsertQuery = $@"REPLACE INTO {PlayerStatsTable} (PlayerName, SteamID, TimesConnected, LastConnected, HideTimerHud, HideKeys, SoundsEnabled, PlayerFov, IsVip, BigGifID, GlobalPoints, HideWeapon, HidePlayers) VALUES (@PlayerName, @SteamID, @TimesConnected, @LastConnected, @HideTimerHud, @HideKeys, @SoundsEnabled, @PlayerFov, @IsVip, @BigGifID, @GlobalPoints, @HideWeapon, @HidePlayers)"; upsertCommand = new MySqlCommand(upsertQuery, (MySqlConnection)connection); break; case DatabaseType.PostgreSQL: - upsertQuery = $@"INSERT INTO ""{PlayerStatsTable}"" (""PlayerName"", ""SteamID"", ""TimesConnected"", ""LastConnected"", ""HideTimerHud"", ""HideKeys"", ""HideJS"", ""SoundsEnabled"", ""PlayerFov"", ""IsVip"", ""BigGifID"", ""GlobalPoints"", ""HideWeapon"", ""HidePlayers"") VALUES (@PlayerName, @SteamID, @TimesConnected, @LastConnected, @HideTimerHud, @HideKeys, @HideJS, @SoundsEnabled, @PlayerFov, @IsVip, @BigGifID, @GlobalPoints, @HideWeapon, @HidePlayers)"; + upsertQuery = $@"INSERT INTO ""{PlayerStatsTable}"" (""PlayerName"", ""SteamID"", ""TimesConnected"", ""LastConnected"", ""HideTimerHud"", ""HideKeys"", ""SoundsEnabled"", ""PlayerFov"", ""IsVip"", ""BigGifID"", ""GlobalPoints"", ""HideWeapon"", ""HidePlayers"") VALUES (@PlayerName, @SteamID, @TimesConnected, @LastConnected, @HideTimerHud, @HideKeys, @SoundsEnabled, @PlayerFov, @IsVip, @BigGifID, @GlobalPoints, @HideWeapon, @HidePlayers)"; upsertCommand = new NpgsqlCommand(upsertQuery, (NpgsqlConnection)connection); break; case DatabaseType.SQLite: - upsertQuery = $@"REPLACE INTO {PlayerStatsTable} (PlayerName, SteamID, TimesConnected, LastConnected, HideTimerHud, HideKeys, HideJS, SoundsEnabled, PlayerFov, IsVip, BigGifID, GlobalPoints, HideWeapon, HidePlayers) VALUES (@PlayerName, @SteamID, @TimesConnected, @LastConnected, @HideTimerHud, @HideKeys, @HideJS, @SoundsEnabled, @PlayerFov, @IsVip, @BigGifID, @GlobalPoints, @HideWeapon, @HidePlayers)"; + upsertQuery = $@"REPLACE INTO {PlayerStatsTable} (PlayerName, SteamID, TimesConnected, LastConnected, HideTimerHud, HideKeys, SoundsEnabled, PlayerFov, IsVip, BigGifID, GlobalPoints, HideWeapon, HidePlayers) VALUES (@PlayerName, @SteamID, @TimesConnected, @LastConnected, @HideTimerHud, @HideKeys, @SoundsEnabled, @PlayerFov, @IsVip, @BigGifID, @GlobalPoints, @HideWeapon, @HidePlayers)"; upsertCommand = new SQLiteCommand(upsertQuery, (SQLiteConnection)connection); break; default: @@ -1191,7 +1148,6 @@ DO UPDATE SET upsertCommand!.AddParameterWithValue("@LastConnected", timeNowUnix); upsertCommand!.AddParameterWithValue("@HideTimerHud", false); upsertCommand!.AddParameterWithValue("@HideKeys", false); - upsertCommand!.AddParameterWithValue("@HideJS", false); upsertCommand!.AddParameterWithValue("@SoundsEnabled", soundsEnabledByDefault); upsertCommand!.AddParameterWithValue("@PlayerFov", 0); upsertCommand!.AddParameterWithValue("@IsVip", false); @@ -1201,8 +1157,8 @@ DO UPDATE SET upsertCommand!.AddParameterWithValue("@HidePlayers", false); await upsertCommand!.ExecuteNonQueryAsync(); - Server.NextFrame(() => SharpTimerDebug($"Got player stats from database for {playerName}")); - if (connectMsgEnabled) Server.NextFrame(() => Server.PrintToChatAll($"{Localizer["prefix"]} {Localizer["connected_message_first", playerName]}")); + Server.NextFrame(() => Utils.LogDebug($"Got player stats from database for {playerName}")); + if (connectMsgEnabled) Server.NextFrame(() => Utils.PrintToChatAll($"{Localizer["connected_message_first", playerName]}")); } } } @@ -1210,16 +1166,19 @@ DO UPDATE SET } catch (Exception ex) { - Server.NextFrame(() => SharpTimerError($"Error getting player stats from database for {playerName}: {ex}")); + Server.NextFrame(() => Utils.LogError($"Error getting player stats from database for {playerName}: {ex}")); } } - public async Task SavePlayerStageTimeToDatabase(CCSPlayerController? player, int timerTicks, int stage, string velocity, string steamId, string playerName, int playerSlot, int bonusX = 0, int style = 0) + + public async Task SavePlayerStageTimeToDatabase(CCSPlayerController? player, int timerTicks, int stage, string velocity, string steamId, string playerName, int slot, int bonusX = 0, int style = 0) { - SharpTimerDebug($"Trying to save player {(bonusX != 0 ? $"bonus {bonusX} stage {stage} time" : $"stage {stage} time")} to database for {playerName} {timerTicks}"); + Utils.LogDebug($"Trying to save player {(bonusX != 0 ? $"bonus {bonusX} stage {stage} time" : $"stage {stage} time")} to database for {playerName} {timerTicks}"); try { - if (!IsAllowedPlayer(player)) return; - //if ((bonusX == 0 && !playerTimers[playerSlot].IsTimerRunning) || (bonusX != 0 && !playerTimers[playerSlot].IsBonusTimerRunning)) return; + if (player == null || !IsAllowedPlayer(player)) + return; + + //if ((bonusX == 0 && !playerTimers[slot].IsTimerRunning) || (bonusX != 0 && !playerTimers[slot].IsBonusTimerRunning)) return; string currentMapNamee = bonusX == 0 ? currentMapName! : $"{currentMapName}_bonus{bonusX}"; int timeNowUnix = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds(); @@ -1233,7 +1192,7 @@ public async Task SavePlayerStageTimeToDatabase(CCSPlayerController? player, int using (var connection = await OpenConnectionAsync()) { - string formattedTime = FormatTime(timerTicks); + string formattedTime = Utils.FormatTime(timerTicks); string? selectQuery; DbCommand? selectCommand; switch (dbType) @@ -1279,7 +1238,7 @@ public async Task SavePlayerStageTimeToDatabase(CCSPlayerController? player, int playerPoints = 320000; } //not saving replays for stage times - //if (enableReplays == true && enableDb) _ = Task.Run(async () => await DumpReplayToJson(player!, steamId, playerSlot, bonusX, playerTimers[playerSlot].currentStyle)); + //if (enableReplays == true && enableDb) _ = Task.Run(async () => await DumpReplayToJson(player!, steamId, slot, bonusX, playerTimers[slot].currentStyle)); } else { @@ -1358,21 +1317,21 @@ DO UPDATE SET upsertCommand!.AddParameterWithValue("@Stage", stage); upsertCommand!.AddParameterWithValue("@Velocity", velocity); //no points for stage times until points overhaul - //if (enableDb && globalRanksEnabled == true && ((dBtimesFinished <= maxGlobalFreePoints && globalRanksFreePointsEnabled == true) || beatPB)) await SavePlayerPoints(steamId, playerName, playerSlot, playerPoints, dBtimerTicks, beatPB, bonusX, style); + //if (enableDb && globalRanksEnabled == true && ((dBtimesFinished <= maxGlobalFreePoints && globalRanksFreePointsEnabled == true) || beatPB)) await SavePlayerPoints(steamId, playerName, slot, playerPoints, dBtimerTicks, beatPB, bonusX, style); //dont save stagetimes unless they complete map - //if ((stageTriggerCount != 0 || cpTriggerCount != 0) && bonusX == 0 && enableDb && timerTicks < dBtimerTicks) Server.NextFrame(() => _ = Task.Run(async () => await DumpPlayerStageTimesToJson(player, steamId, playerSlot))); + //if ((stageTriggerCount != 0 || cpTriggerCount != 0) && bonusX == 0 && enableDb && timerTicks < dBtimerTicks) Server.NextFrame(() => _ = Task.Run(async () => await DumpPlayerStageTimesToJson(player, steamId, slot))); var prevSRID = await GetStageRecordSteamIDFromDatabase(bonusX, 0, style); var prevSR = await GetPreviousPlayerStageRecordFromDatabase(player, prevSRID.Item1, currentMapNamee, stage, prevSRID.Item2, bonusX); await upsertCommand!.ExecuteNonQueryAsync(); - Server.NextFrame(() => SharpTimerDebug($"Saved player {(bonusX != 0 ? $"bonus {bonusX} stage {stage} time" : $"{stage} time")} to database for {playerName} {timerTicks} {DateTimeOffset.UtcNow.ToUnixTimeSeconds()}")); - if (IsAllowedPlayer(player)) Server.NextFrame(() => _ = Task.Run(async () => await PrintStageTimeToChat(player!, steamId, playerName, dBtimerTicks, timerTicks, stage, bonusX, prevSR))); + Server.NextFrame(() => Utils.LogDebug($"Saved player {(bonusX != 0 ? $"bonus {bonusX} stage {stage} time" : $"{stage} time")} to database for {playerName} {timerTicks} {DateTimeOffset.UtcNow.ToUnixTimeSeconds()}")); + if (IsAllowedPlayer(player) && enableStageTimes && enableStageSR) Server.NextFrame(() => _ = Task.Run(async () => await PrintStageTimeToChat(player!, steamId, playerName, dBtimerTicks, timerTicks, stage, bonusX, prevSR))); } } else { - Server.NextFrame(() => SharpTimerDebug($"No player record yet")); + Server.NextFrame(() => Utils.LogDebug($"No player record yet")); //dont save stagetimes unless they complete map - //if (enableReplays == true && usePostgres == true) _ = Task.Run(async () => await DumpReplayToJson(player!, steamId, playerSlot, bonusX, playerTimers[playerSlot].currentStyle)); + //if (enableReplays == true && usePostgres == true) _ = Task.Run(async () => await DumpReplayToJson(player!, steamId, slot, bonusX, playerTimers[slot].currentStyle)); await row.CloseAsync(); string? upsertQuery; @@ -1410,11 +1369,11 @@ DO UPDATE SET var prevSR = await GetPreviousPlayerStageRecordFromDatabase(player, prevSRID.Item1, currentMapNamee, stage, prevSRID.Item2, bonusX); await upsertCommand!.ExecuteNonQueryAsync(); //no points until points overhaul - //if (globalRanksEnabled == true) await SavePlayerPoints(steamId, playerName, playerSlot, timerTicks, dBtimerTicks, beatPB, bonusX, style); + //if (globalRanksEnabled == true) await SavePlayerPoints(steamId, playerName, slot, timerTicks, dBtimerTicks, beatPB, bonusX, style); //dont save stagetimes unless they complete map - //if ((stageTriggerCount != 0 || cpTriggerCount != 0) && bonusX == 0) Server.NextFrame(() => _ = Task.Run(async () => await DumpPlayerStageTimesToJson(player, steamId, playerSlot))); - Server.NextFrame(() => SharpTimerDebug($"Saved player {(bonusX != 0 ? $"bonus {bonusX} stage {stage} time" : $"stage {stage} time")} to database for {playerName} {timerTicks} {DateTimeOffset.UtcNow.ToUnixTimeSeconds()}")); - if (IsAllowedPlayer(player) && enableStageTimes) Server.NextFrame(() => _ = Task.Run(async () => await PrintStageTimeToChat(player!, steamId, playerName, dBtimerTicks, timerTicks, stage, bonusX, prevSR))); + //if ((stageTriggerCount != 0 || cpTriggerCount != 0) && bonusX == 0) Server.NextFrame(() => _ = Task.Run(async () => await DumpPlayerStageTimesToJson(player, steamId, slot))); + Server.NextFrame(() => Utils.LogDebug($"Saved player {(bonusX != 0 ? $"bonus {bonusX} stage {stage} time" : $"stage {stage} time")} to database for {playerName} {timerTicks} {DateTimeOffset.UtcNow.ToUnixTimeSeconds()}")); + if (IsAllowedPlayer(player) && enableStageTimes && enableStageSR) Server.NextFrame(() => _ = Task.Run(async () => await PrintStageTimeToChat(player!, steamId, playerName, dBtimerTicks, timerTicks, stage, bonusX, prevSR))); } } @@ -1422,13 +1381,13 @@ DO UPDATE SET } catch (Exception ex) { - Server.NextFrame(() => SharpTimerError($"Error saving player {(bonusX != 0 ? $"bonus {bonusX} time" : "time")} to database: {ex.Message}")); + Server.NextFrame(() => Utils.LogError($"Error saving player {(bonusX != 0 ? $"bonus {bonusX} time" : "time")} to database: {ex.Message}")); } } - public async Task SetPlayerStats(CCSPlayerController? player, string steamId, string playerName, int playerSlot) + public async Task SetPlayerStats(CCSPlayerController? player, string steamId, string playerName, int slot) { - SharpTimerDebug($"Trying to set player stats in database for {playerName}"); + Utils.LogDebug($"Trying to set player stats in database for {playerName}"); try { if (!IsAllowedPlayer(player)) return; @@ -1436,13 +1395,12 @@ public async Task SetPlayerStats(CCSPlayerController? player, string steamId, st // get player columns int timesConnected = 0; int lastConnected = 0; - bool hideTimerHud = false; + /*bool hideTimerHud = false; bool hideKeys = false; - bool hideJS = false; bool hideWeapon = false; bool hidePlayers = false; bool soundsEnabled = true; - int playerFov = 0; + int playerFov = 0;*/ bool isVip = false; string bigGif = "x"; int playerPoints = 0; @@ -1506,15 +1464,15 @@ public async Task SetPlayerStats(CCSPlayerController? player, string steamId, st switch (dbType) { case DatabaseType.MySQL: - upsertQuery = $"REPLACE INTO {PlayerStatsTable} (PlayerName, SteamID, TimesConnected, LastConnected, HideTimerHud, HideKeys, HideJS, SoundsEnabled, PlayerFov, IsVip, BigGifID, GlobalPoints, HideWeapon, HidePlayers) VALUES (@PlayerName, @SteamID, @TimesConnected, @LastConnected, @HideTimerHud, @HideKeys, @HideJS, @SoundsEnabled, @PlayerFov, @IsVip, @BigGifID, @GlobalPoints, @HideWeapon, @HidePlayers)"; + upsertQuery = $"REPLACE INTO {PlayerStatsTable} (PlayerName, SteamID, TimesConnected, LastConnected, HideTimerHud, HideKeys, SoundsEnabled, PlayerFov, IsVip, BigGifID, GlobalPoints, HideWeapon, HidePlayers) VALUES (@PlayerName, @SteamID, @TimesConnected, @LastConnected, @HideTimerHud, @HideKeys, @SoundsEnabled, @PlayerFov, @IsVip, @BigGifID, @GlobalPoints, @HideWeapon, @HidePlayers)"; upsertCommand = new MySqlCommand(upsertQuery, (MySqlConnection)connection); break; case DatabaseType.PostgreSQL: upsertQuery = $@" INSERT INTO ""{PlayerStatsTable}"" - (""PlayerName"", ""SteamID"", ""TimesConnected"", ""LastConnected"", ""HideTimerHud"", ""HideKeys"", ""HideJS"", ""SoundsEnabled"", ""PlayerFov"", ""IsVip"", ""BigGifID"", ""GlobalPoints"", ""HideWeapon"", ""HidePlayers"") + (""PlayerName"", ""SteamID"", ""TimesConnected"", ""LastConnected"", ""HideTimerHud"", ""HideKeys"", ""SoundsEnabled"", ""PlayerFov"", ""IsVip"", ""BigGifID"", ""GlobalPoints"", ""HideWeapon"", ""HidePlayers"") VALUES - (@PlayerName, @SteamID, @TimesConnected, @LastConnected, @HideTimerHud, @HideKeys, @HideJS, @SoundsEnabled, @PlayerFov, @IsVip, @BigGifID, @GlobalPoints, @HideWeapon, @HidePlayers) + (@PlayerName, @SteamID, @TimesConnected, @LastConnected, @HideTimerHud, @HideKeys, @SoundsEnabled, @PlayerFov, @IsVip, @BigGifID, @GlobalPoints, @HideWeapon, @HidePlayers) ON CONFLICT (""SteamID"") DO UPDATE SET ""PlayerName"" = EXCLUDED.""PlayerName"", @@ -1522,7 +1480,6 @@ DO UPDATE SET ""LastConnected"" = EXCLUDED.""LastConnected"", ""HideTimerHud"" = EXCLUDED.""HideTimerHud"", ""HideKeys"" = EXCLUDED.""HideKeys"", - ""HideJS"" = EXCLUDED.""HideJS"", ""SoundsEnabled"" = EXCLUDED.""SoundsEnabled"", ""PlayerFov"" = EXCLUDED.""PlayerFov"", ""IsVip"" = EXCLUDED.""IsVip"", @@ -1534,7 +1491,7 @@ DO UPDATE SET upsertCommand = new NpgsqlCommand(upsertQuery, (NpgsqlConnection)connection); break; case DatabaseType.SQLite: - upsertQuery = $"REPLACE INTO {PlayerStatsTable} (PlayerName, SteamID, TimesConnected, LastConnected, HideTimerHud, HideKeys, HideJS, SoundsEnabled, PlayerFov, IsVip, BigGifID, GlobalPoints, HideWeapon, HidePlayers) VALUES (@PlayerName, @SteamID, @TimesConnected, @LastConnected, @HideTimerHud, @HideKeys, @HideJS, @SoundsEnabled, @PlayerFov, @IsVip, @BigGifID, @GlobalPoints, @HideWeapon, @HidePlayers)"; + upsertQuery = $"REPLACE INTO {PlayerStatsTable} (PlayerName, SteamID, TimesConnected, LastConnected, HideTimerHud, HideKeys, SoundsEnabled, PlayerFov, IsVip, BigGifID, GlobalPoints, HideWeapon, HidePlayers) VALUES (@PlayerName, @SteamID, @TimesConnected, @LastConnected, @HideTimerHud, @HideKeys, @SoundsEnabled, @PlayerFov, @IsVip, @BigGifID, @GlobalPoints, @HideWeapon, @HidePlayers)"; upsertCommand = new SQLiteCommand(upsertQuery, (SQLiteConnection)connection); break; default: @@ -1545,7 +1502,7 @@ DO UPDATE SET using (upsertCommand) { - if (playerTimers.TryGetValue(playerSlot, out PlayerTimerInfo? value)) + if (playerTimers.TryGetValue(slot, out PlayerTimerInfo? value)) { upsertCommand!.AddParameterWithValue("@PlayerName", playerName); upsertCommand!.AddParameterWithValue("@SteamID", steamId); @@ -1555,7 +1512,6 @@ DO UPDATE SET upsertCommand!.AddParameterWithValue("@HideKeys", value.HideKeys); upsertCommand!.AddParameterWithValue("@HideWeapon", value.HideWeapon); upsertCommand!.AddParameterWithValue("@HidePlayers", value.HidePlayers); - upsertCommand!.AddParameterWithValue("@HideJS", value.HideJumpStats); upsertCommand!.AddParameterWithValue("@SoundsEnabled", value.SoundsEnabled); upsertCommand!.AddParameterWithValue("@PlayerFov", value.PlayerFov); upsertCommand!.AddParameterWithValue("@IsVip", isVip); @@ -1563,11 +1519,11 @@ DO UPDATE SET upsertCommand!.AddParameterWithValue("@GlobalPoints", playerPoints); await upsertCommand!.ExecuteNonQueryAsync(); - Server.NextFrame(() => SharpTimerDebug($"Set player stats in database for {playerName}")); + Server.NextFrame(() => Utils.LogDebug($"Set player stats in database for {playerName}")); } else { - SharpTimerError($"Error setting player stats in database for {playerName}: player was not on the server anymore"); + Utils.LogError($"Error setting player stats in database for {playerName}: player was not on the server anymore"); return; } @@ -1576,7 +1532,7 @@ DO UPDATE SET } else { - Server.NextFrame(() => SharpTimerDebug($"No player stats yet")); + Server.NextFrame(() => Utils.LogDebug($"No player stats yet")); await row.CloseAsync(); string? upsertQuery; @@ -1584,15 +1540,15 @@ DO UPDATE SET switch (dbType) { case DatabaseType.MySQL: - upsertQuery = $"REPLACE INTO {PlayerStatsTable} (PlayerName, SteamID, TimesConnected, LastConnected, HideTimerHud, HideKeys, HideJS, SoundsEnabled, PlayerFov, IsVip, BigGifID, GlobalPoints, HideWeapon, HidePlayers) VALUES (@PlayerName, @SteamID, @TimesConnected, @LastConnected, @HideTimerHud, @HideKeys, @HideJS, @SoundsEnabled, @PlayerFov, @IsVip, @BigGifID, @GlobalPoints, @HideWeapon, @HidePlayers)"; + upsertQuery = $"REPLACE INTO {PlayerStatsTable} (PlayerName, SteamID, TimesConnected, LastConnected, HideTimerHud, HideKeys, SoundsEnabled, PlayerFov, IsVip, BigGifID, GlobalPoints, HideWeapon, HidePlayers) VALUES (@PlayerName, @SteamID, @TimesConnected, @LastConnected, @HideTimerHud, @HideKeys, @SoundsEnabled, @PlayerFov, @IsVip, @BigGifID, @GlobalPoints, @HideWeapon, @HidePlayers)"; upsertCommand = new MySqlCommand(upsertQuery, (MySqlConnection)connection); break; case DatabaseType.PostgreSQL: - upsertQuery = $@"INSERT INTO ""{PlayerStatsTable}"" (""PlayerName"", ""SteamID"", ""TimesConnected"", ""LastConnected"", ""HideTimerHud"", ""HideKeys"", ""HideJS"", ""SoundsEnabled"", ""PlayerFov"", ""IsVip"", ""BigGifID"", ""GlobalPoints"", ""HideWeapon"", ""HidePlayers"") VALUES (@PlayerName, @SteamID, @TimesConnected, @LastConnected, @HideTimerHud, @HideKeys, @HideJS, @SoundsEnabled, @PlayerFov, @IsVip, @BigGifID, @GlobalPoints, @HideWeapon, @HidePlayers)"; + upsertQuery = $@"INSERT INTO ""{PlayerStatsTable}"" (""PlayerName"", ""SteamID"", ""TimesConnected"", ""LastConnected"", ""HideTimerHud"", ""HideKeys"", ""SoundsEnabled"", ""PlayerFov"", ""IsVip"", ""BigGifID"", ""GlobalPoints"", ""HideWeapon"", ""HidePlayers"") VALUES (@PlayerName, @SteamID, @TimesConnected, @LastConnected, @HideTimerHud, @HideKeys, @SoundsEnabled, @PlayerFov, @IsVip, @BigGifID, @GlobalPoints, @HideWeapon, @HidePlayers)"; upsertCommand = new NpgsqlCommand(upsertQuery, (NpgsqlConnection)connection); break; case DatabaseType.SQLite: - upsertQuery = $"REPLACE INTO {PlayerStatsTable} (PlayerName, SteamID, TimesConnected, LastConnected, HideTimerHud, HideKeys, HideJS, SoundsEnabled, PlayerFov, IsVip, BigGifID, GlobalPoints, HideWeapon, HidePlayers) VALUES (@PlayerName, @SteamID, @TimesConnected, @LastConnected, @HideTimerHud, @HideKeys, @HideJS, @SoundsEnabled, @PlayerFov, @IsVip, @BigGifID, @GlobalPoints, @HideWeapon, @HidePlayers)"; + upsertQuery = $"REPLACE INTO {PlayerStatsTable} (PlayerName, SteamID, TimesConnected, LastConnected, HideTimerHud, HideKeys, SoundsEnabled, PlayerFov, IsVip, BigGifID, GlobalPoints, HideWeapon, HidePlayers) VALUES (@PlayerName, @SteamID, @TimesConnected, @LastConnected, @HideTimerHud, @HideKeys, @SoundsEnabled, @PlayerFov, @IsVip, @BigGifID, @GlobalPoints, @HideWeapon, @HidePlayers)"; upsertCommand = new SQLiteCommand(upsertQuery, (SQLiteConnection)connection); break; default: @@ -1603,29 +1559,28 @@ DO UPDATE SET using (upsertCommand) { - if (playerTimers.TryGetValue(playerSlot, out PlayerTimerInfo? value)) + if (playerTimers.TryGetValue(slot, out PlayerTimerInfo? value)) { upsertCommand!.AddParameterWithValue("@PlayerName", playerName); upsertCommand!.AddParameterWithValue("@SteamID", steamId); upsertCommand!.AddParameterWithValue("@TimesConnected", 1); upsertCommand!.AddParameterWithValue("@LastConnected", timeNowUnix); - upsertCommand!.AddParameterWithValue("@HideTimerHud", playerTimers[playerSlot].HideTimerHud); - upsertCommand!.AddParameterWithValue("@HideKeys", playerTimers[playerSlot].HideKeys); - upsertCommand!.AddParameterWithValue("@HideWeapon", playerTimers[playerSlot].HideWeapon); - upsertCommand!.AddParameterWithValue("@HidePlayers", playerTimers[playerSlot].HidePlayers); - upsertCommand!.AddParameterWithValue("@HideJS", playerTimers[playerSlot].HideJumpStats); - upsertCommand!.AddParameterWithValue("@SoundsEnabled", playerTimers[playerSlot].SoundsEnabled); - upsertCommand!.AddParameterWithValue("@PlayerFov", playerTimers[playerSlot].PlayerFov); + upsertCommand!.AddParameterWithValue("@HideTimerHud", playerTimers[slot].HideTimerHud); + upsertCommand!.AddParameterWithValue("@HideKeys", playerTimers[slot].HideKeys); + upsertCommand!.AddParameterWithValue("@HideWeapon", playerTimers[slot].HideWeapon); + upsertCommand!.AddParameterWithValue("@HidePlayers", playerTimers[slot].HidePlayers); + upsertCommand!.AddParameterWithValue("@SoundsEnabled", playerTimers[slot].SoundsEnabled); + upsertCommand!.AddParameterWithValue("@PlayerFov", playerTimers[slot].PlayerFov); upsertCommand!.AddParameterWithValue("@IsVip", false); upsertCommand!.AddParameterWithValue("@BigGifID", "x"); upsertCommand!.AddParameterWithValue("@GlobalPoints", 0); await upsertCommand!.ExecuteNonQueryAsync(); - Server.NextFrame(() => SharpTimerDebug($"Set player stats in database for {playerName}")); + Server.NextFrame(() => Utils.LogDebug($"Set player stats in database for {playerName}")); } else { - SharpTimerError($"Error setting player stats in database for {playerName}: player was not on the server anymore"); + Utils.LogError($"Error setting player stats in database for {playerName}: player was not on the server anymore"); return; } @@ -1637,13 +1592,13 @@ DO UPDATE SET } catch (Exception ex) { - Server.NextFrame(() => SharpTimerError($"Error setting player stats in database for {playerName}: {ex}")); + Server.NextFrame(() => Utils.LogError($"Error setting player stats in database for {playerName}: {ex}")); } } public void GainPointsMessage(string playerName, double newPoints, double playerPoints) { - // PrintToChatAll(Localizer["gained_points", playerName, Convert.ToInt32(newPoints - playerPoints), newPoints]); + Utils.PrintToChatAll(Localizer["gained_points", playerName, Convert.ToInt32(newPoints - playerPoints), newPoints]); } public (string, int) FixMapAndBonus(string mapName) @@ -1663,9 +1618,9 @@ public void GainPointsMessage(string playerName, double newPoints, double player return (mapName, 0); } - public async Task SavePlayerPoints(string steamId, string playerName, int playerSlot, int timerTicks, int oldTicks, bool beatPB = false, int bonusX = 0, int style = 0, int completions = 0, string mapname = "", bool import = false) + public async Task SavePlayerPoints(string steamId, string playerName, int slot, int timerTicks, int oldTicks, bool beatPB = false, int bonusX = 0, int style = 0, int completions = 0, string mapname = "", bool import = false) { - SharpTimerDebug($"Trying to set player points in database for {playerName}"); + Utils.LogDebug($"Trying to set player points in database for {playerName}"); try { if (mapname == "") mapname = currentMapName!; @@ -1678,11 +1633,10 @@ public async Task SavePlayerPoints(string steamId, string playerName, int player // get player columns int timesConnected = 0; int lastConnected = 0; - bool hideTimerHud = false; + /*bool hideTimerHud = false; bool hideKeys = false; - bool hideJS = false; bool soundsEnabled = true; - int playerFov = 0; + int playerFov = 0;*/ bool isVip = false; string bigGif = "x"; int playerPoints = 0; @@ -1752,15 +1706,15 @@ public async Task SavePlayerPoints(string steamId, string playerName, int player switch (dbType) { case DatabaseType.MySQL: - upsertQuery = $@"REPLACE INTO {PlayerStatsTable} (PlayerName, SteamID, TimesConnected, LastConnected, HideTimerHud, HideKeys, HideJS, SoundsEnabled, PlayerFov, IsVip, BigGifID, GlobalPoints, HideWeapon, HidePlayers) VALUES (@PlayerName, @SteamID, @TimesConnected, @LastConnected, @HideTimerHud, @HideKeys, @HideJS, @SoundsEnabled, @PlayerFov, @IsVip, @BigGifID, @GlobalPoints, @HideWeapon, @HidePlayers)"; + upsertQuery = $@"REPLACE INTO {PlayerStatsTable} (PlayerName, SteamID, TimesConnected, LastConnected, HideTimerHud, HideKeys, SoundsEnabled, PlayerFov, IsVip, BigGifID, GlobalPoints, HideWeapon, HidePlayers) VALUES (@PlayerName, @SteamID, @TimesConnected, @LastConnected, @HideTimerHud, @HideKeys, @SoundsEnabled, @PlayerFov, @IsVip, @BigGifID, @GlobalPoints, @HideWeapon, @HidePlayers)"; upsertCommand = new MySqlCommand(upsertQuery, (MySqlConnection)connection); break; case DatabaseType.PostgreSQL: upsertQuery = $@" INSERT INTO ""{PlayerStatsTable}"" - (""PlayerName"", ""SteamID"", ""TimesConnected"", ""LastConnected"", ""HideTimerHud"", ""HideKeys"", ""HideJS"", ""SoundsEnabled"", ""PlayerFov"", ""IsVip"", ""BigGifID"", ""GlobalPoints"", ""HideWeapon"", ""HidePlayers"") + (""PlayerName"", ""SteamID"", ""TimesConnected"", ""LastConnected"", ""HideTimerHud"", ""HideKeys"", ""SoundsEnabled"", ""PlayerFov"", ""IsVip"", ""BigGifID"", ""GlobalPoints"", ""HideWeapon"", ""HidePlayers"") VALUES - (@PlayerName, @SteamID, @TimesConnected, @LastConnected, @HideTimerHud, @HideKeys, @HideJS, @SoundsEnabled, @PlayerFov, @IsVip, @BigGifID, @GlobalPoints, @HideWeapon, @HidePlayers) + (@PlayerName, @SteamID, @TimesConnected, @LastConnected, @HideTimerHud, @HideKeys, @SoundsEnabled, @PlayerFov, @IsVip, @BigGifID, @GlobalPoints, @HideWeapon, @HidePlayers) ON CONFLICT (""SteamID"") DO UPDATE SET ""PlayerName"" = EXCLUDED.""PlayerName"", @@ -1768,7 +1722,6 @@ DO UPDATE SET ""LastConnected"" = EXCLUDED.""LastConnected"", ""HideTimerHud"" = EXCLUDED.""HideTimerHud"", ""HideKeys"" = EXCLUDED.""HideKeys"", - ""HideJS"" = EXCLUDED.""HideJS"", ""SoundsEnabled"" = EXCLUDED.""SoundsEnabled"", ""PlayerFov"" = EXCLUDED.""PlayerFov"", ""IsVip"" = EXCLUDED.""IsVip"", @@ -1780,7 +1733,7 @@ DO UPDATE SET upsertCommand = new NpgsqlCommand(upsertQuery, (NpgsqlConnection)connection); break; case DatabaseType.SQLite: - upsertQuery = $@"REPLACE INTO {PlayerStatsTable} (PlayerName, SteamID, TimesConnected, LastConnected, HideTimerHud, HideKeys, HideJS, SoundsEnabled, PlayerFov, IsVip, BigGifID, GlobalPoints, HideWeapon, HidePlayers) VALUES (@PlayerName, @SteamID, @TimesConnected, @LastConnected, @HideTimerHud, @HideKeys, @HideJS, @SoundsEnabled, @PlayerFov, @IsVip, @BigGifID, @GlobalPoints, @HideWeapon, @HidePlayers)"; + upsertQuery = $@"REPLACE INTO {PlayerStatsTable} (PlayerName, SteamID, TimesConnected, LastConnected, HideTimerHud, HideKeys, SoundsEnabled, PlayerFov, IsVip, BigGifID, GlobalPoints, HideWeapon, HidePlayers) VALUES (@PlayerName, @SteamID, @TimesConnected, @LastConnected, @HideTimerHud, @HideKeys, @SoundsEnabled, @PlayerFov, @IsVip, @BigGifID, @GlobalPoints, @HideWeapon, @HidePlayers)"; upsertCommand = new SQLiteCommand(upsertQuery, (SQLiteConnection)connection); break; default: @@ -1791,19 +1744,18 @@ DO UPDATE SET using (upsertCommand) { - if (playerTimers.TryGetValue(playerSlot, out PlayerTimerInfo? value) || playerSlot == -1) + if (playerTimers.TryGetValue(slot, out PlayerTimerInfo? value) || slot == -1) { upsertCommand!.AddParameterWithValue("@PlayerName", playerName); upsertCommand!.AddParameterWithValue("@SteamID", steamId); upsertCommand!.AddParameterWithValue("@TimesConnected", timesConnected); upsertCommand!.AddParameterWithValue("@LastConnected", lastConnected); - upsertCommand!.AddParameterWithValue("@HideTimerHud", playerSlot != -1 && value!.HideTimerHud); - upsertCommand!.AddParameterWithValue("@HideKeys", playerSlot != -1 && value!.HideKeys); - upsertCommand!.AddParameterWithValue("@HideWeapon", playerSlot != -1 && value!.HideWeapon); - upsertCommand!.AddParameterWithValue("@HidePlayers", playerSlot != -1 && value!.HidePlayers); - upsertCommand!.AddParameterWithValue("@HideJS", playerSlot != -1 && value!.HideJumpStats); - upsertCommand!.AddParameterWithValue("@SoundsEnabled", playerSlot != -1 && value!.SoundsEnabled); - upsertCommand!.AddParameterWithValue("@PlayerFov", playerSlot == -1 ? 0 : value!.PlayerFov); + upsertCommand!.AddParameterWithValue("@HideTimerHud", slot != -1 && value!.HideTimerHud); + upsertCommand!.AddParameterWithValue("@HideKeys", slot != -1 && value!.HideKeys); + upsertCommand!.AddParameterWithValue("@HideWeapon", slot != -1 && value!.HideWeapon); + upsertCommand!.AddParameterWithValue("@HidePlayers", slot != -1 && value!.HidePlayers); + upsertCommand!.AddParameterWithValue("@SoundsEnabled", slot != -1 && value!.SoundsEnabled); + upsertCommand!.AddParameterWithValue("@PlayerFov", slot == -1 ? 0 : value!.PlayerFov); upsertCommand!.AddParameterWithValue("@IsVip", isVip); upsertCommand!.AddParameterWithValue("@BigGifID", bigGif); upsertCommand!.AddParameterWithValue("@GlobalPoints", newPoints); @@ -1811,18 +1763,18 @@ DO UPDATE SET await upsertCommand!.ExecuteNonQueryAsync(); if (!import) Server.NextFrame(() => GainPointsMessage(playerName, newPoints, playerPoints)); - Server.NextFrame(() => SharpTimerDebug($"Set points in database for {playerName} from {playerPoints} to {newPoints}")); + Server.NextFrame(() => Utils.LogDebug($"Set points in database for {playerName} from {playerPoints} to {newPoints}")); } else { - SharpTimerError($"Error setting player points to database for {playerName}: player was not on the server anymore"); + Utils.LogError($"Error setting player points to database for {playerName}: player was not on the server anymore"); } } } else { - Server.NextFrame(() => SharpTimerDebug($"No player stats yet")); + Server.NextFrame(() => Utils.LogDebug($"No player stats yet")); int newPoints = await CalculatePlayerPoints(steamId, playerName, timerTicks, oldTicks, beatPB, bonusX, style, completions, mapname, false) + playerPoints; @@ -1833,15 +1785,15 @@ DO UPDATE SET switch (dbType) { case DatabaseType.MySQL: - upsertQuery = $@"REPLACE INTO {PlayerStatsTable} (PlayerName, SteamID, TimesConnected, LastConnected, HideTimerHud, HideKeys, HideJS, SoundsEnabled, PlayerFov, IsVip, BigGifID, GlobalPoints, HideWeapon, HidePlayers) VALUES (@PlayerName, @SteamID, @TimesConnected, @LastConnected, @HideTimerHud, @HideKeys, @HideJS, @SoundsEnabled, @PlayerFov, @IsVip, @BigGifID, @GlobalPoints, @HideWeapon, @HidePlayers)"; + upsertQuery = $@"REPLACE INTO {PlayerStatsTable} (PlayerName, SteamID, TimesConnected, LastConnected, HideTimerHud, HideKeys, SoundsEnabled, PlayerFov, IsVip, BigGifID, GlobalPoints, HideWeapon, HidePlayers) VALUES (@PlayerName, @SteamID, @TimesConnected, @LastConnected, @HideTimerHud, @HideKeys, @SoundsEnabled, @PlayerFov, @IsVip, @BigGifID, @GlobalPoints, @HideWeapon, @HidePlayers)"; upsertCommand = new MySqlCommand(upsertQuery, (MySqlConnection)connection); break; case DatabaseType.PostgreSQL: - upsertQuery = $@"INSERT INTO ""{PlayerStatsTable}"" (""PlayerName"", ""SteamID"", ""TimesConnected"", ""LastConnected"", ""HideTimerHud"", ""HideKeys"", ""HideJS"", ""SoundsEnabled"", ""PlayerFov"", ""IsVip"", ""BigGifID"", ""GlobalPoints"", ""HideWeapon"", ""HidePlayers"") VALUES (@PlayerName, @SteamID, @TimesConnected, @LastConnected, @HideTimerHud, @HideKeys, @HideJS, @SoundsEnabled, @PlayerFov, @IsVip, @BigGifID, @GlobalPoints, @HideWeapon, @HidePlayers)"; + upsertQuery = $@"INSERT INTO ""{PlayerStatsTable}"" (""PlayerName"", ""SteamID"", ""TimesConnected"", ""LastConnected"", ""HideTimerHud"", ""HideKeys"", ""SoundsEnabled"", ""PlayerFov"", ""IsVip"", ""BigGifID"", ""GlobalPoints"", ""HideWeapon"", ""HidePlayers"") VALUES (@PlayerName, @SteamID, @TimesConnected, @LastConnected, @HideTimerHud, @HideKeys, @SoundsEnabled, @PlayerFov, @IsVip, @BigGifID, @GlobalPoints, @HideWeapon, @HidePlayers)"; upsertCommand = new NpgsqlCommand(upsertQuery, (NpgsqlConnection)connection); break; case DatabaseType.SQLite: - upsertQuery = $@"REPLACE INTO {PlayerStatsTable} (PlayerName, SteamID, TimesConnected, LastConnected, HideTimerHud, HideKeys, HideJS, SoundsEnabled, PlayerFov, IsVip, BigGifID, GlobalPoints, HideWeapon, HidePlayers) VALUES (@PlayerName, @SteamID, @TimesConnected, @LastConnected, @HideTimerHud, @HideKeys, @HideJS, @SoundsEnabled, @PlayerFov, @IsVip, @BigGifID, @GlobalPoints, @HideWeapon, @HidePlayers)"; + upsertQuery = $@"REPLACE INTO {PlayerStatsTable} (PlayerName, SteamID, TimesConnected, LastConnected, HideTimerHud, HideKeys, SoundsEnabled, PlayerFov, IsVip, BigGifID, GlobalPoints, HideWeapon, HidePlayers) VALUES (@PlayerName, @SteamID, @TimesConnected, @LastConnected, @HideTimerHud, @HideKeys, @SoundsEnabled, @PlayerFov, @IsVip, @BigGifID, @GlobalPoints, @HideWeapon, @HidePlayers)"; upsertCommand = new SQLiteCommand(upsertQuery, (SQLiteConnection)connection); break; default: @@ -1852,19 +1804,18 @@ DO UPDATE SET using (upsertCommand) { - if (playerTimers.TryGetValue(playerSlot, out PlayerTimerInfo? value) || playerSlot == -1) + if (playerTimers.TryGetValue(slot, out PlayerTimerInfo? value) || slot == -1) { upsertCommand!.AddParameterWithValue("@PlayerName", playerName); upsertCommand!.AddParameterWithValue("@SteamID", steamId); upsertCommand!.AddParameterWithValue("@TimesConnected", 1); upsertCommand!.AddParameterWithValue("@LastConnected", timeNowUnix); - upsertCommand!.AddParameterWithValue("@HideTimerHud", playerSlot != -1 && value!.HideTimerHud); - upsertCommand!.AddParameterWithValue("@HideKeys", playerSlot != -1 && value!.HideKeys); - upsertCommand!.AddParameterWithValue("@HideWeapon", playerSlot != -1 && value!.HideWeapon); - upsertCommand!.AddParameterWithValue("@HidePlayers", playerSlot != -1 && value!.HidePlayers); - upsertCommand!.AddParameterWithValue("@HideJS", playerSlot != -1 && value!.HideJumpStats); - upsertCommand!.AddParameterWithValue("@SoundsEnabled", playerSlot != -1 && value!.SoundsEnabled); - upsertCommand!.AddParameterWithValue("@PlayerFov", playerSlot == -1 ? 0 : value!.PlayerFov); + upsertCommand!.AddParameterWithValue("@HideTimerHud", slot != -1 && value!.HideTimerHud); + upsertCommand!.AddParameterWithValue("@HideKeys", slot != -1 && value!.HideKeys); + upsertCommand!.AddParameterWithValue("@HideWeapon", slot != -1 && value!.HideWeapon); + upsertCommand!.AddParameterWithValue("@HidePlayers", slot != -1 && value!.HidePlayers); + upsertCommand!.AddParameterWithValue("@SoundsEnabled", slot != -1 && value!.SoundsEnabled); + upsertCommand!.AddParameterWithValue("@PlayerFov", slot == -1 ? 0 : value!.PlayerFov); upsertCommand!.AddParameterWithValue("@IsVip", false); upsertCommand!.AddParameterWithValue("@BigGifID", "x"); upsertCommand!.AddParameterWithValue("@GlobalPoints", newPoints); @@ -1872,11 +1823,11 @@ DO UPDATE SET await upsertCommand!.ExecuteNonQueryAsync(); if (!import) Server.NextFrame(() => GainPointsMessage(playerName, newPoints, playerPoints)); - Server.NextFrame(() => SharpTimerDebug($"Set points in database for {playerName} from {playerPoints} to {newPoints}")); + Server.NextFrame(() => Utils.LogDebug($"Set points in database for {playerName} from {playerPoints} to {newPoints}")); } else { - SharpTimerError($"Error setting player points to database for {playerName}: player was not on the server anymore"); + Utils.LogError($"Error setting player points to database for {playerName}: player was not on the server anymore"); } } } @@ -1885,13 +1836,13 @@ DO UPDATE SET } catch (Exception ex) { - Server.NextFrame(() => SharpTimerError($"Error getting player stats from database for {playerName}: {ex}")); + Server.NextFrame(() => Utils.LogError($"Error getting player stats from database for {playerName}: {ex}")); } } public async Task CalculatePlayerPoints(string steamId, string playerName, int timerTicks, int oldTicks, bool beatPB = false, int bonusX = 0, int style = 0, int completions = 0, string mapname = "", bool forGlobal = false) { - SharpTimerDebug($"Trying to calculate player points for {playerName}"); + Utils.LogDebug($"Trying to calculate player points for {playerName}"); try { if (mapname == "") mapname = currentMapName!; @@ -1916,7 +1867,7 @@ public async Task CalculatePlayerPoints(string steamId, string playerName, if (sortedRecords.Count == 0) { newPoints += CalculateTop10(maxPoints, rank, forGlobal); - SharpTimerDebug($"First map entry, player {playerName} is rank #1"); + Utils.LogDebug($"First map entry, player {playerName} is rank #1"); isTop10 = true; } else @@ -1927,7 +1878,7 @@ public async Task CalculatePlayerPoints(string steamId, string playerName, { newPoints += CalculateTop10(maxPoints, rank); isTop10 = true; - SharpTimerDebug($"Player {playerName} is rank #{rank}"); + Utils.LogDebug($"Player {playerName} is rank #{rank}"); break; } rank++; @@ -1978,7 +1929,7 @@ public async Task CalculatePlayerPoints(string steamId, string playerName, } catch (Exception ex) { - Server.NextFrame(() => SharpTimerError($"Error calculating player points for {playerName}: {ex}")); + Server.NextFrame(() => Utils.LogError($"Error calculating player points for {playerName}: {ex}")); } return 0; } @@ -1987,7 +1938,7 @@ public async Task PlayerCompletions(string steamId, int bonusX = 0, int sty { try { - //if ((bonusX == 0 && !playerTimers[playerSlot].IsTimerRunning) || (bonusX != 0 && !playerTimers[playerSlot].IsBonusTimerRunning)) return; + //if ((bonusX == 0 && !playerTimers[slot].IsTimerRunning) || (bonusX != 0 && !playerTimers[slot].IsBonusTimerRunning)) return; string currentMapNamee = bonusX == 0 ? currentMapName! : $"{currentMapName}_bonus{bonusX}"; using (var connection = await OpenConnectionAsync()) @@ -2030,7 +1981,7 @@ public async Task PlayerCompletions(string steamId, int bonusX = 0, int sty } catch (Exception ex) { - Server.NextFrame(() => SharpTimerError($"Error getting player completions from database for id:{steamId}: {ex}")); + Server.NextFrame(() => Utils.LogError($"Error getting player completions from database for id:{steamId}: {ex}")); } return 0; } @@ -2048,8 +1999,7 @@ public async Task PrintTop10PlayerPoints(CCSPlayerController player) switch (dbType) { case DatabaseType.MySQL: - // query = $@"SELECT PlayerName, GlobalPoints FROM {PlayerStatsTable} ORDER BY GlobalPoints DESC LIMIT 10"; - query = $@"SELECT PlayerName, GlobalPoints FROM PlayerLeaderboard ORDER BY GlobalPoints DESC LIMIT 10"; + query = $@"SELECT PlayerName, GlobalPoints FROM {PlayerStatsTable} ORDER BY GlobalPoints DESC LIMIT 10"; command = new MySqlCommand(query, (MySqlConnection)connection); break; case DatabaseType.PostgreSQL: @@ -2072,7 +2022,7 @@ public async Task PrintTop10PlayerPoints(CCSPlayerController player) { Server.NextFrame(() => { - if (IsAllowedClient(player)) PrintToChat(player, Localizer["top_10_points"]); + if (IsPlayerOrSpectator(player)) Utils.PrintToChat(player, Localizer["top_10_points"]); }); int rank = 0; @@ -2087,7 +2037,7 @@ public async Task PrintTop10PlayerPoints(CCSPlayerController player) int currentRank = ++rank; Server.NextFrame(() => { - if (IsAllowedClient(player)) PrintToChat(player, Localizer["top_10_points_list", currentRank, playerName, points]); + if (IsPlayerOrSpectator(player)) Utils.PrintToChat(player, Localizer["top_10_points_list", currentRank, playerName, points]); }); } } @@ -2096,24 +2046,24 @@ public async Task PrintTop10PlayerPoints(CCSPlayerController player) } catch (Exception ex) { - Server.NextFrame(() => SharpTimerError($"An error occurred in PrintTop10PlayerPoints inside using con: {ex}")); + Server.NextFrame(() => Utils.LogError($"An error occurred in PrintTop10PlayerPoints inside using con: {ex}")); } } } catch (Exception ex) { - Server.NextFrame(() => SharpTimerError($"An error occurred in PrintTop10PlayerPoints: {ex}")); + Server.NextFrame(() => Utils.LogError($"An error occurred in PrintTop10PlayerPoints: {ex}")); } } - public async Task GetReplayVIPGif(string steamId, int playerSlot) + public async Task GetReplayVIPGif(string steamId, int slot) { - Server.NextFrame(() => SharpTimerDebug($"Trying to get replay VIP Gif from database")); + Server.NextFrame(() => Utils.LogDebug($"Trying to get replay VIP Gif from database")); try { if (await IsSteamIDaTester(steamId)) { - playerTimers[playerSlot].VipReplayGif = await GetTesterBigGif(steamId); + playerTimers[slot].VipReplayGif = await GetTesterBigGif(steamId); return; } @@ -2148,7 +2098,7 @@ public async Task GetReplayVIPGif(string steamId, int playerSlot) var row = await selectCommand!.ExecuteReaderAsync(); - if (row.Read() && playerTimers.TryGetValue(playerSlot, out PlayerTimerInfo? value)) + if (row.Read() && playerTimers.TryGetValue(slot, out PlayerTimerInfo? value)) { // get player columns bool isVip = false; @@ -2164,12 +2114,12 @@ public async Task GetReplayVIPGif(string steamId, int playerSlot) } if (isVip) { - Server.NextFrame(() => SharpTimerDebug($"Replay is VIP setting gif...")); + Server.NextFrame(() => Utils.LogDebug($"Replay is VIP setting gif...")); value.VipReplayGif = $"

"; } else { - Server.NextFrame(() => SharpTimerDebug($"Replay is not VIP...")); + Server.NextFrame(() => Utils.LogDebug($"Replay is not VIP...")); value.VipReplayGif = "x"; } @@ -2178,7 +2128,7 @@ public async Task GetReplayVIPGif(string steamId, int playerSlot) else { await row.CloseAsync(); - Server.NextFrame(() => SharpTimerDebug($"Replay is not VIP... goofy")); + Server.NextFrame(() => Utils.LogDebug($"Replay is not VIP... goofy")); } } @@ -2186,13 +2136,13 @@ public async Task GetReplayVIPGif(string steamId, int playerSlot) } catch (Exception ex) { - Server.NextFrame(() => SharpTimerError($"Error getting ReplayVIPGif from database: {ex}")); + Server.NextFrame(() => Utils.LogError($"Error getting ReplayVIPGif from database: {ex}")); } } public async Task<(string, string, string)> GetMapRecordSteamIDFromDatabase(int bonusX = 0, int top10 = 0, int style = 0) { - SharpTimerDebug($"Trying to get {(bonusX != 0 ? $"bonus {bonusX}" : "map")} record steamid from database"); + Utils.LogDebug($"Trying to get {(bonusX != 0 ? $"bonus {bonusX}" : "map")} record steamid from database"); try { using (IDbConnection connection = await OpenConnectionAsync()) @@ -2275,7 +2225,7 @@ public async Task GetReplayVIPGif(string steamId, int playerSlot) { string steamId64 = row.GetString("SteamID"); string playerName = row.GetString("PlayerName"); - string timerTicks = FormatTime(row.GetInt32("TimerTicks")); + string timerTicks = Utils.FormatTime(row.GetInt32("TimerTicks")); await row.CloseAsync(); @@ -2293,13 +2243,13 @@ public async Task GetReplayVIPGif(string steamId, int playerSlot) } catch (Exception ex) { - Server.NextFrame(() => SharpTimerError($"Error getting GetMapRecordSteamIDFromDatabase from database: {ex}")); + Server.NextFrame(() => Utils.LogError($"Error getting GetMapRecordSteamIDFromDatabase from database: {ex}")); return ("null", "null", "null"); } } public async Task<(string, string, string)> GetStageRecordSteamIDFromDatabase(int stage, int bonusX = 0, int top10 = 0) { - SharpTimerDebug($"Trying to get {(bonusX != 0 ? $"bonus {bonusX} stage {stage}" : $"stage {stage}")} record steamid from database"); + Utils.LogDebug($"Trying to get {(bonusX != 0 ? $"bonus {bonusX} stage {stage}" : $"stage {stage}")} record steamid from database"); try { using (IDbConnection connection = await OpenConnectionAsync()) @@ -2381,8 +2331,7 @@ public async Task GetReplayVIPGif(string steamId, int playerSlot) { string steamId64 = row.GetString("SteamID"); string playerName = row.GetString("PlayerName"); - string timerTicks = FormatTime(row.GetInt32("TimerTicks")); - + string timerTicks = Utils.FormatTime(row.GetInt32("TimerTicks")); await row.CloseAsync(); @@ -2399,14 +2348,14 @@ public async Task GetReplayVIPGif(string steamId, int playerSlot) } catch (Exception ex) { - Server.NextFrame(() => SharpTimerError($"Error getting GetStageRecordSteamIDFromDatabase from database: {ex}")); + Server.NextFrame(() => Utils.LogError($"Error getting GetStageRecordSteamIDFromDatabase from database: {ex}")); return ("null", "null", "null"); } } public async Task<(int, string)> GetStageRecordFromDatabase(int stage, string steamId, int bonusX = 0) { - SharpTimerDebug($"Trying to get {(bonusX != 0 ? $"bonus {bonusX} stage {stage}" : $"stage {stage}")} record steamid from database"); + Utils.LogDebug($"Trying to get {(bonusX != 0 ? $"bonus {bonusX} stage {stage}" : $"stage {stage}")} record steamid from database"); try { using (IDbConnection connection = await OpenConnectionAsync()) @@ -2483,14 +2432,14 @@ public async Task GetReplayVIPGif(string steamId, int playerSlot) } catch (Exception ex) { - Server.NextFrame(() => SharpTimerError($"Error getting GetStageRecord from database: {ex}")); + Server.NextFrame(() => Utils.LogError($"Error getting GetStageRecord from database: {ex}")); return (0, "null"); } } public async Task GetPreviousPlayerRecordFromDatabase(string steamId, string currentMapName, string playerName, int bonusX = 0, int style = 0) { - SharpTimerDebug($"Trying to get Previous {(bonusX != 0 ? $"bonus {bonusX} time" : "time")} from database for {playerName}"); + Utils.LogDebug($"Trying to get Previous {(bonusX != 0 ? $"bonus {bonusX} time" : "time")} from database for {playerName}"); try { string currentMapNamee = bonusX == 0 ? currentMapName : $"{currentMapName}_bonus{bonusX}"; @@ -2533,7 +2482,7 @@ public async Task GetPreviousPlayerRecordFromDatabase(string steamId, strin // Check for DBNull if (result != null && result != DBNull.Value) { - SharpTimerDebug($"Got Previous Time from database for {playerName}"); + Utils.LogDebug($"Got Previous Time from database for {playerName}"); return Convert.ToInt32(result); } } @@ -2542,17 +2491,17 @@ public async Task GetPreviousPlayerRecordFromDatabase(string steamId, strin } catch (Exception ex) { - SharpTimerError($"Error getting previous player {(bonusX != 0 ? $"bonus {bonusX} time" : "time")} from database: {ex.Message}"); + Utils.LogError($"Error getting previous player {(bonusX != 0 ? $"bonus {bonusX} time" : "time")} from database: {ex.Message}"); } return 0; } public async Task GetPreviousPlayerStageRecordFromDatabase(CCSPlayerController? player, string steamId, string currentMapName, int stage, string playerName, int bonusX = 0) { - SharpTimerDebug($"Trying to get Previous {(bonusX != 0 ? $"bonus {bonusX} stage {stage} time" : $"stage {stage} time")} from database for {playerName}"); + Utils.LogDebug($"Trying to get Previous {(bonusX != 0 ? $"bonus {bonusX} stage {stage} time" : $"stage {stage} time")} from database for {playerName}"); try { - if (!IsAllowedClient(player)) + if (!IsPlayerOrSpectator(player)) { return 0; } @@ -2596,7 +2545,7 @@ public async Task GetPreviousPlayerStageRecordFromDatabase(CCSPlayerControl // Check for DBNull if (result != null && result != DBNull.Value) { - SharpTimerDebug($"Got Previous stage {stage} Time from database for {playerName}"); + Utils.LogDebug($"Got Previous stage {stage} Time from database for {playerName}"); return Convert.ToInt32(result); } } @@ -2605,19 +2554,24 @@ public async Task GetPreviousPlayerStageRecordFromDatabase(CCSPlayerControl } catch (Exception ex) { - SharpTimerError($"Error getting previous player {(bonusX != 0 ? $"bonus {bonusX} stage {stage} time" : $"stage {stage} time")} from database: {ex.Message}"); + Utils.LogError($"Error getting previous player {(bonusX != 0 ? $"bonus {bonusX} stage {stage} time" : $"stage {stage} time")} from database: {ex.Message}"); } return 0; } - public async Task GetPlayerPointsFromDatabase(string steamId, string? playerName = null) + public async Task GetPlayerPointsFromDatabase(CCSPlayerController? player, string steamId, string playerName) { - SharpTimerDebug("Trying GetPlayerPointsFromDatabase"); + Utils.LogDebug("Trying GetPlayerPointsFromDatabase"); int playerPoints = 0; try { + if (!IsPlayerOrSpectator(player)) + { + return playerPoints; + } + using (var connection = await OpenConnectionAsync()) { await CreatePlayerStatsTableAsync(connection); @@ -2626,7 +2580,7 @@ public async Task GetPlayerPointsFromDatabase(string steamId, string? playe switch (dbType) { case DatabaseType.MySQL: - selectQuery = $"SELECT GlobalPoints FROM PlayerLeaderboard WHERE SteamID = @SteamID"; + selectQuery = $"SELECT GlobalPoints FROM {PlayerStatsTable} WHERE SteamID = @SteamID"; selectCommand = new MySqlCommand(selectQuery, (MySqlConnection)connection); break; case DatabaseType.PostgreSQL: @@ -2653,7 +2607,7 @@ public async Task GetPlayerPointsFromDatabase(string steamId, string? playe if (result != null && result != DBNull.Value) { playerPoints = Convert.ToInt32(result); - SharpTimerDebug($"Got Player Points from database for {playerName} p: {playerPoints}"); + Utils.LogDebug($"Got Player Points from database for {playerName} p: {playerPoints}"); return playerPoints; } } @@ -2662,14 +2616,14 @@ public async Task GetPlayerPointsFromDatabase(string steamId, string? playe } catch (Exception ex) { - SharpTimerError($"Error getting player points from database: {ex.Message}"); + Utils.LogError($"Error getting player points from database: {ex.Message}"); } return playerPoints; } public async Task> GetSortedRecordsFromDatabase(int limit = 0, int bonusX = 0, string mapName = "", int style = 0) { - SharpTimerDebug($"Trying GetSortedRecords {(bonusX != 0 ? $"bonus {bonusX}" : "")} from database"); + Utils.LogDebug($"Trying GetSortedRecords {(bonusX != 0 ? $"bonus {bonusX}" : "")} from database"); using (var connection = await OpenConnectionAsync()) { try @@ -2755,7 +2709,7 @@ public async Task> GetSortedRecordsFromDatabase(in sortedRecords = sortedRecords.OrderBy(record => record.Value.TimerTicks) .ToDictionary(record => record.Key, record => record.Value); - SharpTimerDebug($"Got GetSortedRecords {(bonusX != 0 ? $"bonus {bonusX}" : "")} from database"); + Utils.LogDebug($"Got GetSortedRecords {(bonusX != 0 ? $"bonus {bonusX}" : "")} from database"); return sortedRecords; } @@ -2763,14 +2717,14 @@ public async Task> GetSortedRecordsFromDatabase(in } catch (Exception ex) { - SharpTimerError($"Error getting sorted records from database: {ex.Message}"); + Utils.LogError($"Error getting sorted records from database: {ex.Message}"); } } return []; } public async Task> GetAllSortedRecordsFromDatabase(int limit = 0, int bonusX = 0, int style = 0) { - SharpTimerDebug($"Trying GetSortedRecords {(bonusX != 0 ? $"bonus {bonusX}" : "")} from database"); + Utils.LogDebug($"Trying GetSortedRecords {(bonusX != 0 ? $"bonus {bonusX}" : "")} from database"); using (var connection = await OpenConnectionAsync()) { try @@ -2855,7 +2809,7 @@ public async Task> GetAllSortedRecordsFromDatabase(int limit .OrderBy(record => record.TimerTicks) .ToList(); - SharpTimerDebug($"Got GetSortedRecords {(bonusX != 0 ? $"bonus {bonusX}" : "")} from database"); + Utils.LogDebug($"Got GetSortedRecords {(bonusX != 0 ? $"bonus {bonusX}" : "")} from database"); return sortedList; } @@ -2863,14 +2817,14 @@ public async Task> GetAllSortedRecordsFromDatabase(int limit } catch (Exception ex) { - SharpTimerError($"Error getting all sorted records from database: {ex.Message}"); + Utils.LogError($"Error getting all sorted records from database: {ex.Message}"); } } return []; } public async Task> GetSortedStageRecordsFromDatabase(int stage, int limit = 0, int bonusX = 0, string mapName = "") { - SharpTimerDebug($"Trying GetSortedStageRecords {(bonusX != 0 ? $"bonus {bonusX}" : "")} from database"); + Utils.LogDebug($"Trying GetSortedStageRecords {(bonusX != 0 ? $"bonus {bonusX}" : "")} from database"); using (var connection = await OpenConnectionAsync()) { try @@ -2953,7 +2907,7 @@ public async Task> GetSortedStageRecordsFromDat sortedRecords = sortedRecords.OrderBy(record => record.Value.TimerTicks) .ToDictionary(record => record.Key, record => record.Value); - SharpTimerDebug($"Got GetSortedStageRecords {(bonusX != 0 ? $"bonus {bonusX}" : "")} from database"); + Utils.LogDebug($"Got GetSortedStageRecords {(bonusX != 0 ? $"bonus {bonusX}" : "")} from database"); return sortedRecords; } @@ -2961,7 +2915,7 @@ public async Task> GetSortedStageRecordsFromDat } catch (Exception ex) { - SharpTimerError($"Error getting sorted stage records from database: {ex.Message}"); + Utils.LogError($"Error getting sorted stage records from database: {ex.Message}"); } } return []; @@ -2969,7 +2923,7 @@ public async Task> GetSortedStageRecordsFromDat public async Task> GetSortedPointsFromDatabase() { - SharpTimerDebug("Trying GetSortedPoints from database"); + Utils.LogDebug("Trying GetSortedPoints from database"); using (var connection = await OpenConnectionAsync()) { try @@ -2980,7 +2934,7 @@ public async Task> GetSortedPointsFromDatabase( switch (dbType) { case DatabaseType.MySQL: - selectQuery = $@"SELECT SteamID, PlayerName, GlobalPoints FROM PlayerLeaderboard ORDER BY GlobalPoints DESC"; + selectQuery = $@"SELECT SteamID, PlayerName, GlobalPoints FROM {PlayerStatsTable}"; selectCommand = new MySqlCommand(selectQuery, (MySqlConnection)connection); break; case DatabaseType.PostgreSQL: @@ -3006,7 +2960,7 @@ public async Task> GetSortedPointsFromDatabase( { string steamId = reader.GetString(0); string playerName = reader.IsDBNull(1) ? "Unknown" : reader.GetString(1); - int globalPoints = Convert.ToInt32(reader["GlobalPoints"]); + int globalPoints = reader.GetInt32(2); if (globalPoints >= minGlobalPointsForRank) // Only add if GlobalPoints is above or equal to minGlobalPointsForRank { @@ -3018,15 +2972,18 @@ public async Task> GetSortedPointsFromDatabase( } } - // sortedPoints = sortedPoints.OrderByDescending(record => record.Value.GlobalPoints) - // .ToDictionary(record => record.Key, record => record.Value); + sortedPoints = sortedPoints.OrderByDescending(record => record.Value.GlobalPoints) + .ToDictionary(record => record.Key, record => record.Value); + + + return sortedPoints; } } } catch (Exception ex) { - SharpTimerError($"Error getting GetSortedPoints from database: {ex.Message}"); + Utils.LogError($"Error getting GetSortedPoints from database: {ex.Message}"); } } return []; @@ -3044,7 +3001,7 @@ public async Task ImportPlayerPoints() { try { - Server.NextFrame(() => PrintToChatAll("Points import initialized")); + Server.NextFrame(() => Utils.PrintToChatAll("Points import initialized")); var sortedRecords = await GetAllSortedRecordsFromDatabase(); int batchSize = 10; @@ -3055,11 +3012,11 @@ public async Task ImportPlayerPoints() await Task.WhenAll(tasks); } - Server.NextFrame(() => PrintToChatAll("Points import completed")); + Server.NextFrame(() => Utils.PrintToChatAll("Points import completed")); } catch (Exception ex) { - SharpTimerError($"Error ImportPlayerPoints to the database: {ex.Message}"); + Utils.LogError($"Error ImportPlayerPoints to the database: {ex.Message}"); } } @@ -3106,7 +3063,7 @@ public async Task ResetPlayerPoints() } catch (Exception ex) { - SharpTimerError($"Error in ResetPlayerPoints: {ex.Message}"); + Utils.LogError($"Error in ResetPlayerPoints: {ex.Message}"); } } } @@ -3128,7 +3085,7 @@ public async Task AddJsonTimesToDatabaseAsync() if (!Directory.Exists(playerRecordsPathh)) { - SharpTimerDebug($"Error: Directory not found at {playerRecordsPathh}"); + Utils.LogDebug($"Error: Directory not found at {playerRecordsPathh}"); return; } @@ -3146,7 +3103,7 @@ public async Task AddJsonTimesToDatabaseAsync() connection = new SQLiteConnection(connectionString); break; default: - SharpTimerError($"Error: Invalid database type."); + Utils.LogError($"Error: Invalid database type."); return; } using (connection) @@ -3219,7 +3176,7 @@ PRIMARY KEY (MapName, SteamID, Style) if (records == null) { - SharpTimerDebug($"Error: Failed to deserialize JSON data from {filePath}"); + Utils.LogDebug($"Error: Failed to deserialize JSON data from {filePath}"); continue; } @@ -3270,7 +3227,7 @@ ON CONFLICT (MapName, SteamID, Style) DO UPDATE insertOrUpdateCommand!.AddParameterWithValue("@SteamID", steamId); insertOrUpdateCommand!.AddParameterWithValue("@PlayerName", playerRecord.PlayerName!); insertOrUpdateCommand!.AddParameterWithValue("@TimerTicks", playerRecord.TimerTicks); - insertOrUpdateCommand!.AddParameterWithValue("@FormattedTime", FormatTime(playerRecord.TimerTicks)); + insertOrUpdateCommand!.AddParameterWithValue("@FormattedTime", Utils.FormatTime(playerRecord.TimerTicks)); insertOrUpdateCommand!.AddParameterWithValue("@MapName", mapName); insertOrUpdateCommand!.AddParameterWithValue("@UnixStamp", 0); insertOrUpdateCommand!.AddParameterWithValue("@TimesFinished", 0); @@ -3281,13 +3238,13 @@ ON CONFLICT (MapName, SteamID, Style) DO UPDATE } } - SharpTimerDebug($"JSON times from {Path.GetFileName(filePath)} successfully added to the database."); + Utils.LogDebug($"JSON times from {Path.GetFileName(filePath)} successfully added to the database."); } } } catch (Exception ex) { - SharpTimerError($"Error adding JSON times to the database: {ex.Message}"); + Utils.LogError($"Error adding JSON times to the database: {ex.Message}"); } } } diff --git a/src/DB/Migration.cs b/src/DB/Migration.cs index 33c1741e..e1c04ce0 100644 --- a/src/DB/Migration.cs +++ b/src/DB/Migration.cs @@ -95,7 +95,7 @@ version VARCHAR(255) NOT NULL // Update the last applied migration version UpdateLastAppliedVersion(connection, version); - SharpTimerDebug($"Migration \"{version}\" successfully applied."); + Utils.LogDebug($"Migration \"{version}\" successfully applied."); } } } diff --git a/src/Extensions/CUserCmd.cs b/src/Extensions/CUserCmd.cs index 543719a7..1aec4bd1 100644 --- a/src/Extensions/CUserCmd.cs +++ b/src/Extensions/CUserCmd.cs @@ -1,5 +1,6 @@ using System.Runtime.CompilerServices; using CounterStrikeSharp.API.Modules.Utils; +using FixVectorLeak; public class CUserCmd { @@ -88,7 +89,7 @@ public unsafe void DisableInput(IntPtr userCmd, nint value) { Unsafe.Write((void*)(userCmd + 0x50), Unsafe.Read((void*)(userCmd + 0x50)) & ~(value)); } - public unsafe QAngle? GetViewAngles() + public unsafe QAngle_t? GetViewAngles() { if (Handle == IntPtr.Zero) return null; @@ -97,12 +98,12 @@ public unsafe void DisableInput(IntPtr userCmd, nint value) if (baseCmd == IntPtr.Zero) return null; - var msgQAngle = Unsafe.Read((void*)(baseCmd + 0x40)); - if (msgQAngle == IntPtr.Zero) + var msgQAngle_t = Unsafe.Read((void*)(baseCmd + 0x40)); + if (msgQAngle_t == IntPtr.Zero) return null; - var viewAngles = new QAngle(msgQAngle + 0x18); + var viewAngles = new QAngle_t(msgQAngle_t + 0x18); - return viewAngles.Handle == IntPtr.Zero ? null : viewAngles; + return viewAngles; } } \ No newline at end of file diff --git a/src/Extensions/FixVectorLeaks.cs b/src/Extensions/FixVectorLeaks.cs new file mode 100644 index 00000000..3559d798 --- /dev/null +++ b/src/Extensions/FixVectorLeaks.cs @@ -0,0 +1,280 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Memory; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Numerics; +using CounterStrikeSharp.API.Modules.Utils; + +namespace FixVectorLeak; + +public struct Vector_t : IAdditionOperators, + ISubtractionOperators, + IMultiplyOperators, + IDivisionOperators +{ + public float X, Y, Z; + + public const int SIZE = 3; + + public unsafe float this[int i] + { + readonly get + { + if (i < 0 || i > SIZE) + { + throw new IndexOutOfRangeException(); + } + + fixed (void* ptr = &this) + { + return Unsafe.Read(Unsafe.Add(ptr, i)); + } + } + set + { + if (i < 0 || i > SIZE) + { + throw new IndexOutOfRangeException(); + } + + fixed (void* ptr = &this) + { + Unsafe.Write(Unsafe.Add(ptr, i), value); + } + } + } + + public Vector_t() + { + } + + public unsafe Vector_t(nint ptr) : this(MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef((void*)ptr), SIZE)) + { + } + + public Vector_t(float x, float y, float z) + { + X = x; + Y = y; + Z = z; + } + + public Vector_t(ReadOnlySpan values) + { + if (values.Length < SIZE) + { + throw new ArgumentOutOfRangeException(nameof(values)); + } + + this = Unsafe.ReadUnaligned(ref Unsafe.As(ref MemoryMarshal.GetReference(values))); + } + + public readonly float Length() + { + return (float)Math.Sqrt(X * X + Y * Y + Z * Z); + } + + public readonly float Length2D() + { + return (float)Math.Sqrt(X * X + Y * Y); + } + + public readonly bool IsZero(float tolerance = 0.0001f) + { + return Math.Abs(X) <= tolerance && Math.Abs(Y) <= tolerance && Math.Abs(Z) <= tolerance; + } + + public void Scale(float scale) + { + X *= scale; + Y *= scale; + Z *= scale; + } + + public readonly override string ToString() + { + return $"{X:n2} {Y:n2} {Z:n2}"; + } + + public static Vector_t operator +(Vector_t a, Vector_t b) + { + return new Vector_t(a.X + b.X, a.Y + b.Y, a.Z + b.Z); + } + + public static Vector_t operator -(Vector_t a, Vector_t b) + { + return new Vector_t(a.X - b.X, a.Y - b.Y, a.Z - b.Z); + } + + public static Vector_t operator -(Vector_t a) + { + return new Vector_t(-a.X, -a.Y, -a.Z); + } + + public static Vector_t operator *(Vector_t a, float b) + { + return new Vector_t(a.X * b, a.Y * b, a.Z * b); + } + + public static Vector_t operator /(Vector_t a, float b) + { + return new Vector_t(a.X / b, a.Y / b, a.Z / b); + } +} + +public struct QAngle_t : IAdditionOperators, + ISubtractionOperators, + IMultiplyOperators, + IDivisionOperators +{ + public float X, Y, Z; + + public const int SIZE = 3; + + public unsafe float this[int i] + { + readonly get + { + if (i < 0 || i > SIZE) + { + throw new IndexOutOfRangeException(); + } + + fixed (void* ptr = &this) + { + return Unsafe.Read(Unsafe.Add(ptr, i)); + } + } + set + { + if (i < 0 || i > SIZE) + { + throw new IndexOutOfRangeException(); + } + + fixed (void* ptr = &this) + { + Unsafe.Write(Unsafe.Add(ptr, i), value); + } + } + } + + public QAngle_t() + { + } + + public unsafe QAngle_t(nint ptr) : this(MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef((void*)ptr), SIZE)) + { + } + + public QAngle_t(float x, float y, float z) + { + X = x; + Y = y; + Z = z; + } + + public QAngle_t(ReadOnlySpan values) + { + if (values.Length < SIZE) + { + throw new ArgumentOutOfRangeException(nameof(values)); + } + + this = Unsafe.ReadUnaligned(ref Unsafe.As(ref MemoryMarshal.GetReference(values))); + } + + public unsafe (Vector_t fwd, Vector_t right, Vector_t up) AngleVectors() + { + Vector_t fwd = default, right = default, up = default; + + nint pFwd = (nint)Unsafe.AsPointer(ref fwd); + nint pRight = (nint)Unsafe.AsPointer(ref right); + nint pUp = (nint)Unsafe.AsPointer(ref up); + + fixed (void* ptr = &this) + { + NativeAPI.AngleVectors((nint)ptr, pFwd, pRight, pUp); + } + + return (fwd, right, up); + } + + public unsafe void AngleVectors(out Vector_t fwd, out Vector_t right, out Vector_t up) + { + fixed (void* ptr = &this, pFwd = &fwd, pRight = &right, pUp = &up) + { + NativeAPI.AngleVectors((nint)ptr, (nint)pFwd, (nint)pRight, (nint)pUp); + } + } + + public readonly override string ToString() + { + return $"{X:n2} {Y:n2} {Z:n2}"; + } + + public static QAngle_t operator +(QAngle_t a, QAngle_t b) + { + return new QAngle_t(a.X + b.X, a.Y + b.Y, a.Z + b.Z); + } + + public static QAngle_t operator -(QAngle_t a, QAngle_t b) + { + return new QAngle_t(a.X - b.X, a.Y - b.Y, a.Z - b.Z); + } + + public static QAngle_t operator -(QAngle_t a) + { + return new QAngle_t(-a.X, -a.Y, -a.Z); + } + + public static QAngle_t operator *(QAngle_t a, float b) + { + return new QAngle_t(a.X * b, a.Y * b, a.Z * b); + } + + public static QAngle_t operator /(QAngle_t a, float b) + { + return new QAngle_t(a.X / b, a.Y / b, a.Z / b); + } +} + +unsafe static class Extensions +{ + public static void Teleport(this CBaseEntity entity, Vector_t? position = null, QAngle_t? angles = null, Vector_t? velocity = null) + { + Guard.IsValidEntity(entity); + + void* pPos = null, pAng = null, pVel = null; + + // Structs are stored on the stack, GC should not break pointers. + + if (position.HasValue) + { + var pos = position.Value; // Remove nullable wrapper + pPos = &pos; + } + + if (angles.HasValue) + { + var ang = angles.Value; + pAng = ∠ + } + + if (velocity.HasValue) + { + var vel = velocity.Value; + pVel = &vel; + } + + VirtualFunction.CreateVoid(entity.Handle, GameData.GetOffset("CBaseEntity_Teleport"))(entity.Handle, (nint)pPos, + (nint)pAng, (nint)pVel); + } + + public static (Vector_t fwd, Vector_t right, Vector_t up) AngleVectors(this QAngle vec) => vec.ToQAngle_t().AngleVectors(); + public static void AngleVectors(this QAngle vec, out Vector_t fwd, out Vector_t right, out Vector_t up) => vec.ToQAngle_t().AngleVectors(out fwd, out right, out up); + + public static Vector_t ToVector_t(this CounterStrikeSharp.API.Modules.Utils.Vector vec) => new(vec.Handle); + public static QAngle_t ToQAngle_t(this QAngle vec) => new(vec.Handle); +} \ No newline at end of file diff --git a/src/Extensions/ForceFullUpdate.cs b/src/Extensions/ForceFullUpdate.cs index db5fcadc..47042d52 100644 --- a/src/Extensions/ForceFullUpdate.cs +++ b/src/Extensions/ForceFullUpdate.cs @@ -13,7 +13,7 @@ struct CUtlMemory } [StructLayout(LayoutKind.Sequential)] -struct CUtlVector +struct CUtlVector_t { public unsafe nint this[int index] { @@ -46,17 +46,17 @@ public class INetworkGameServer : NativeObject { private static int SlotsOffset = GameData.GetOffset("INetworkGameServer_Slots"); - private CUtlVector Slots; + private CUtlVector_t Slots; public INetworkGameServer(nint ptr) : base(ptr) { - this.Slots = Marshal.PtrToStructure(base.Handle + SlotsOffset); + this.Slots = Marshal.PtrToStructure(base.Handle + SlotsOffset); } - public CServerSideClient? GetClientBySlot(int playerSlot) + public CServerSideClient? GetClientBySlot(int slot) { - if (playerSlot >= 0 && playerSlot < this.Slots.m_iSize) - return this.Slots[playerSlot] == IntPtr.Zero ? null : new CServerSideClient(this.Slots[playerSlot]); + if (slot >= 0 && slot < this.Slots.m_iSize) + return this.Slots[slot] == IntPtr.Zero ? null : new CServerSideClient(this.Slots[slot]); return null; } diff --git a/src/Features/Anticheat.cs b/src/Features/Anticheat.cs index 85bd26c4..ab0e3b6d 100644 --- a/src/Features/Anticheat.cs +++ b/src/Features/Anticheat.cs @@ -4,7 +4,7 @@ using CounterStrikeSharp.API.Core.Attributes.Registration; using CounterStrikeSharp.API.Modules.Admin; using CounterStrikeSharp.API.Modules.Commands; -using CounterStrikeSharp.API.Modules.Utils; +using FixVectorLeak; using static SharpTimer.PlayerTimerInfo; namespace SharpTimer @@ -16,7 +16,7 @@ public partial class SharpTimer // Strafe optimization detection // Store the last 200 viewangles of the player; viewangles are gathered (at fastest) each tick. 200ticks is around 4 strafes - public void ParseStrafes(CCSPlayerController? player, QAngle viewangles) + public void ParseStrafes(CCSPlayerController? player, QAngle_t viewangles) { var playerTimer = playerTimers[player!.Slot]; @@ -80,12 +80,12 @@ public void ParseStrafes(CCSPlayerController? player, QAngle viewangles) playerTimer.YawSpikeFlagged = true; StartStopRecord(player, "Unusually frequent m_yaw accel spikes (Strafe optimizer)"); Server.NextFrame(async () => await DiscordACMessage(player, "Unusually frequent m_yaw accel spikes (Strafe optimizer)")); - SharpTimerConPrint($"::::BEGIN:::: Yaw Accel Spike % of Total"); + Utils.ConPrint($"::::BEGIN:::: Yaw Accel Spike % of Total"); foreach (var percent in playerTimer.YawAccelPercents) { - SharpTimerConPrint($"Spike %: {percent}"); + Utils.ConPrint($"Spike %: {percent}"); } - SharpTimerConPrint($"::::END:::: Yaw Accel Spike % of Total"); + Utils.ConPrint($"::::END:::: Yaw Accel Spike % of Total"); } } @@ -175,8 +175,8 @@ private void StartStopRecord(CCSPlayerController player, string reason) var name = player.PlayerName.Replace(" ", "-").Replace("\\", "-").Replace("/", "-"); var file = $"{currentMapName}_{name}_{DateTimeOffset.UtcNow.ToUnixTimeSeconds()}"; - SharpTimerConPrint($"[AC] Unusal input detected, demo will be available at demos/{file} in 60 seconds"); - SharpTimerConPrint($"[AC] Reason: {reason}"); + Utils.ConPrint($"[AC] Unusal input detected, demo will be available at demos/{file} in 60 seconds"); + Utils.ConPrint($"[AC] Reason: {reason}"); Server.ExecuteCommand($"tv_record demos/{file}"); AddTimer(60.0f, () => Server.ExecuteCommand("tv_stoprecord")); }); @@ -198,8 +198,9 @@ public void GetFlaggedCommand(CCSPlayerController? player, CommandInfo command) } Server.NextFrame(() => { - SharpTimerConPrint($"Flagged players: {flaggedPlayers}"); - if (player is not null) player!.PrintToChat($"Flagged players: {flaggedPlayers}"); + Utils.ConPrint($"Flagged players: {flaggedPlayers}"); + if (player is not null) + Utils.PrintToChat(player, $"Flagged players: {flaggedPlayers}"); }); } } diff --git a/src/Features/DiscordWebhook.cs b/src/Features/DiscordWebhook.cs index b788cfb1..c54b155f 100644 --- a/src/Features/DiscordWebhook.cs +++ b/src/Features/DiscordWebhook.cs @@ -27,7 +27,7 @@ private async Task GetDiscordWebhookURLFromConfigFile(string discordURLpath) { try { - using JsonDocument? jsonConfig = await LoadJson(discordURLpath)!; + using JsonDocument? jsonConfig = await Utils.LoadJson(discordURLpath)!; if (jsonConfig != null) { JsonElement root = jsonConfig.RootElement; @@ -37,7 +37,7 @@ T GetPropertyValue(string propertyName, T defaultValue, Func try { return getValue(property); } catch (Exception ex) { - SharpTimerError($"Error parsing {propertyName}: {ex.Message}"); + Utils.LogError($"Error parsing {propertyName}: {ex.Message}"); return defaultValue; } } @@ -82,12 +82,12 @@ T GetPropertyValue(string propertyName, T defaultValue, Func } else { - SharpTimerError($"DiscordWebhookUrl json was null"); + Utils.LogError($"DiscordWebhookUrl json was null"); } } catch (Exception ex) { - SharpTimerError($"Error in GetDiscordWebhookURLFromConfigFile: {ex.Message}"); + Utils.LogError($"Error in GetDiscordWebhookURLFromConfigFile: {ex.Message}"); } } @@ -107,7 +107,7 @@ public async Task DiscordRecordMessage(CCSPlayerController? player, string playe if (string.IsNullOrEmpty(webhookURL) || webhookURL == "your_discord_webhook_url") { - SharpTimerError($"DiscordWebhookUrl was invalid"); + Utils.LogError($"DiscordWebhookUrl was invalid"); return; } @@ -257,12 +257,12 @@ public async Task DiscordRecordMessage(CCSPlayerController? player, string playe if (!response.IsSuccessStatusCode) { - SharpTimerError($"Failed to send message. Status code: {response.StatusCode}"); + Utils.LogError($"Failed to send message. Status code: {response.StatusCode}"); } } catch (Exception ex) { - SharpTimerError($"An error occurred while sending Discord PB message: {ex.Message}"); + Utils.LogError($"An error occurred while sending Discord PB message: {ex.Message}"); } } @@ -274,7 +274,7 @@ public async Task DiscordACMessage(CCSPlayerController? player, string reason) if (string.IsNullOrEmpty(webhookURL)) { - SharpTimerError($"DiscordACWebhookUrl was invalid"); + Utils.LogError($"DiscordACWebhookUrl was invalid"); return; } using var client = new HttpClient(); @@ -351,12 +351,12 @@ public async Task DiscordACMessage(CCSPlayerController? player, string reason) if (!response.IsSuccessStatusCode) { - SharpTimerError($"Failed to send message. Status code: {response.StatusCode}"); + Utils.LogError($"Failed to send message. Status code: {response.StatusCode}"); } } catch (Exception ex) { - SharpTimerError($"An error occurred while sending Discord AC message: {ex.Message}"); + Utils.LogError($"An error occurred while sending Discord AC message: {ex.Message}"); } } @@ -371,7 +371,7 @@ public async Task GetMapImage(int bonusX = 0) } string imageRepo = $"{discordWebhookImageRepoURL}{(bonusX == 0 ? currentMapName : $"{currentMapName}_b{bonusX}")}.jpg"; - string error = $"{discordWebhookImageRepoURL}{(currentMapName!.Contains("surf_") ? "surf404" : $"{(currentMapName!.Contains("kz_") ? "kz404" : $"{(currentMapName!.Contains("bhop_") ? "bhop404" : "404")}")}")}.jpg"; + string error = $"{discordWebhookImageRepoURL}{(currentMapName!.Contains("surf_") ? "surf404" : $"{(currentMapName!.Contains("bhop_") ? "bhop404" : "404")}")}.jpg"; try { using var client = new HttpClient(); @@ -386,7 +386,7 @@ public async Task GetMapImage(int bonusX = 0) } catch (Exception ex) { - SharpTimerError($"Failed to get DiscordWebhook img. {ex.Message}"); + Utils.LogError($"Failed to get DiscordWebhook img. {ex.Message}"); return error; } } @@ -425,7 +425,7 @@ public async Task GetAvatarLink(string xmlUrl) } catch (Exception ex) { - SharpTimerError("GetAvatarLink Error occurred: " + ex.Message); + Utils.LogError("GetAvatarLink Error occurred: " + ex.Message); return "https://cdn.discordapp.com/icons/1196646791450472488/634963a8207fdb1b30bf909d31f05e57.webp"; } } diff --git a/src/Features/FakeZoneTool.cs b/src/Features/FakeZoneTool.cs index fd9db2e2..a4629745 100644 --- a/src/Features/FakeZoneTool.cs +++ b/src/Features/FakeZoneTool.cs @@ -22,6 +22,7 @@ You should have received a copy of the GNU General Public License using CounterStrikeSharp.API.Modules.Commands; using CounterStrikeSharp.API.Modules.Menu; using CounterStrikeSharp.API.Modules.Utils; +using FixVectorLeak; namespace SharpTimer { @@ -63,7 +64,7 @@ public void AddStartZoneCommand(CCSPlayerController? player) playerTimers[player.Slot].IsAddingStartZone = false; playerTimers[player.Slot].IsAddingEndZone = false; playerTimers[player.Slot].StartZoneC2 = $"{player.Pawn.Value!.CBodyComponent?.SceneNode?.AbsOrigin.X} {player.Pawn.Value.CBodyComponent?.SceneNode?.AbsOrigin.Y} {player.Pawn.Value.CBodyComponent?.SceneNode?.AbsOrigin.Z}"; - player.PrintToChat($" {ChatColors.LightPurple}[ZONE TOOL] {ChatColors.Grey}Startzone set..."); + Utils.PrintToChat(player, $" {ChatColors.LightPurple}[ZONE TOOL] {ChatColors.Grey}Startzone set..."); } else { @@ -71,8 +72,8 @@ public void AddStartZoneCommand(CCSPlayerController? player) playerTimers[player.Slot].StartZoneC2 = ""; playerTimers[player.Slot].IsAddingStartZone = true; playerTimers[player.Slot].IsAddingEndZone = false; - player.PrintToChat($" {ChatColors.LightPurple}[ZONE TOOL] {ChatColors.Default}Please go to the opposite zone corner now"); - player.PrintToChat($" {ChatColors.LightPurple}[ZONE TOOL] {ChatColors.Default}and type {primaryChatColor}!1 {ChatColors.Default}again"); + Utils.PrintToChat(player, $" {ChatColors.LightPurple}[ZONE TOOL] {ChatColors.Default}Please go to the opposite zone corner now"); + Utils.PrintToChat(player, $" {ChatColors.LightPurple}[ZONE TOOL] {ChatColors.Default}and type {primaryChatColor}!1 {ChatColors.Default}again"); } } @@ -85,7 +86,7 @@ public void AddEndZoneCommand(CCSPlayerController? player) playerTimers[player.Slot].IsAddingStartZone = false; playerTimers[player.Slot].IsAddingEndZone = false; playerTimers[player.Slot].EndZoneC2 = $"{player.Pawn.Value!.CBodyComponent?.SceneNode?.AbsOrigin.X} {player.Pawn.Value.CBodyComponent?.SceneNode?.AbsOrigin.Y} {player.Pawn.Value.CBodyComponent?.SceneNode?.AbsOrigin.Z}"; - player.PrintToChat($" {ChatColors.LightPurple}[ZONE TOOL] {ChatColors.Grey}Endzone set..."); + Utils.PrintToChat(player, $" {ChatColors.LightPurple}[ZONE TOOL] {ChatColors.Grey}Endzone set..."); } else { @@ -93,8 +94,8 @@ public void AddEndZoneCommand(CCSPlayerController? player) playerTimers[player.Slot].EndZoneC2 = ""; playerTimers[player.Slot].IsAddingStartZone = false; playerTimers[player.Slot].IsAddingEndZone = true; - player.PrintToChat($" {ChatColors.LightPurple}[ZONE TOOL] {ChatColors.Default}Please go to the opposite zone corner now"); - player.PrintToChat($" {ChatColors.LightPurple}[ZONE TOOL] {ChatColors.Default}and type {primaryChatColor}!2 {ChatColors.Default}again"); + Utils.PrintToChat(player, $" {ChatColors.LightPurple}[ZONE TOOL] {ChatColors.Default}Please go to the opposite zone corner now"); + Utils.PrintToChat(player, $" {ChatColors.LightPurple}[ZONE TOOL] {ChatColors.Default}and type {primaryChatColor}!2 {ChatColors.Default}again"); } } @@ -103,12 +104,12 @@ public void AddRespawnPosCommand(CCSPlayerController? player) if (!IsAllowedPlayer(player)) return; // Get the player's current position - Vector currentPosition = player!.Pawn.Value!.CBodyComponent?.SceneNode?.AbsOrigin ?? new Vector(0, 0, 0); + Vector_t currentPosition = player!.Pawn.Value!.CBodyComponent?.SceneNode?.AbsOrigin.ToVector_t() ?? new Vector_t(0, 0, 0); // Convert position string positionString = $"{currentPosition.X} {currentPosition.Y} {currentPosition.Z}"; playerTimers[player.Slot].RespawnPos = positionString; - player.PrintToChat($" {ChatColors.LightPurple}[ZONE TOOL] {ChatColors.Default}RespawnPos added!"); + Utils.PrintToChat(player, $" {ChatColors.LightPurple}[ZONE TOOL] {ChatColors.Default}RespawnPos added!"); } public void SaveZonesCommand(CCSPlayerController? player) @@ -117,7 +118,7 @@ public void SaveZonesCommand(CCSPlayerController? player) if (playerTimers[player!.Slot].EndZoneC1 == null || playerTimers[player.Slot].EndZoneC2 == null || playerTimers[player.Slot].StartZoneC1 == null || playerTimers[player.Slot].StartZoneC2 == null || playerTimers[player.Slot].RespawnPos == null) { - player.PrintToChat($" {ChatColors.LightPurple}[ZONE TOOL] {ChatColors.Red}Please make sure you have done all 3 zoning steps (startzone, endzone, respawnpos)"); + Utils.PrintToChat(player, $" {ChatColors.LightPurple}[ZONE TOOL] {ChatColors.Red}Please make sure you have done all 3 zoning steps (startzone, endzone, respawnpos)"); return; } @@ -136,7 +137,7 @@ public void SaveZonesCommand(CCSPlayerController? player) string updatedJson = JsonSerializer.Serialize(newMapInfo, jsonSerializerOptions); File.WriteAllText(mapdataPath, updatedJson); - player.PrintToChat($" {ChatColors.LightPurple}[ZONE TOOL] {ChatColors.Default}Zones saved successfully! {ChatColors.Grey}Reloading data..."); + Utils.PrintToChat(player, $" {ChatColors.LightPurple}[ZONE TOOL] {ChatColors.Default}Zones saved successfully! {ChatColors.Grey}Reloading data..."); Server.ExecuteCommand("mp_restartgame 1"); } @@ -152,7 +153,7 @@ public void AddBonusStartZoneCommand(CCSPlayerController? player, CommandInfo co playerTimers[player.Slot].IsAddingBonusStartZone = false; playerTimers[player.Slot].IsAddingBonusEndZone = false; playerTimers[player.Slot].BonusStartZoneC2 = $"{player.Pawn.Value!.CBodyComponent?.SceneNode?.AbsOrigin.X} {player.Pawn.Value.CBodyComponent?.SceneNode?.AbsOrigin.Y} {player.Pawn.Value.CBodyComponent?.SceneNode?.AbsOrigin.Z}"; - player.PrintToChat($" {ChatColors.LightPurple}[ZONE TOOL] {ChatColors.Grey}Bonus Startzone set..."); + Utils.PrintToChat(player, $" {ChatColors.LightPurple}[ZONE TOOL] {ChatColors.Grey}Bonus Startzone set..."); } else { @@ -160,8 +161,8 @@ public void AddBonusStartZoneCommand(CCSPlayerController? player, CommandInfo co playerTimers[player.Slot].BonusStartZoneC2 = ""; playerTimers[player.Slot].IsAddingBonusStartZone = true; playerTimers[player.Slot].IsAddingBonusEndZone = false; - player.PrintToChat($" {ChatColors.LightPurple}[ZONE TOOL] {ChatColors.Default}Please go to the opposite zone corner now"); - player.PrintToChat($" {ChatColors.LightPurple}[ZONE TOOL] {ChatColors.Default}and type {primaryChatColor}!addbonusstartzone {ChatColors.Default}again"); + Utils.PrintToChat(player, $" {ChatColors.LightPurple}[ZONE TOOL] {ChatColors.Default}Please go to the opposite zone corner now"); + Utils.PrintToChat(player, $" {ChatColors.LightPurple}[ZONE TOOL] {ChatColors.Default}and type {primaryChatColor}!addbonusstartzone {ChatColors.Default}again"); } } @@ -177,7 +178,7 @@ public void AddBonusEndZoneCommand(CCSPlayerController? player, CommandInfo comm playerTimers[player.Slot].IsAddingBonusStartZone = false; playerTimers[player.Slot].IsAddingBonusEndZone = false; playerTimers[player.Slot].BonusEndZoneC2 = $"{player.Pawn.Value!.CBodyComponent?.SceneNode?.AbsOrigin.X} {player.Pawn.Value.CBodyComponent?.SceneNode?.AbsOrigin.Y} {player.Pawn.Value.CBodyComponent?.SceneNode?.AbsOrigin.Z}"; - player.PrintToChat($" {ChatColors.LightPurple}[ZONE TOOL] {ChatColors.Grey}Bonus Endzone set..."); + Utils.PrintToChat(player, $" {ChatColors.LightPurple}[ZONE TOOL] {ChatColors.Grey}Bonus Endzone set..."); } else { @@ -185,8 +186,8 @@ public void AddBonusEndZoneCommand(CCSPlayerController? player, CommandInfo comm playerTimers[player.Slot].BonusEndZoneC2 = ""; playerTimers[player.Slot].IsAddingBonusStartZone = false; playerTimers[player.Slot].IsAddingBonusEndZone = true; - player.PrintToChat($" {ChatColors.LightPurple}[ZONE TOOL] {ChatColors.Default}Please go to the opposite zone corner now"); - player.PrintToChat($" {ChatColors.LightPurple}[ZONE TOOL] {ChatColors.Default}and type {primaryChatColor}!addbonusendzone {ChatColors.Default}again"); + Utils.PrintToChat(player, $" {ChatColors.LightPurple}[ZONE TOOL] {ChatColors.Default}Please go to the opposite zone corner now"); + Utils.PrintToChat(player, $" {ChatColors.LightPurple}[ZONE TOOL] {ChatColors.Default}and type {primaryChatColor}!addbonusendzone {ChatColors.Default}again"); } } @@ -198,12 +199,12 @@ public void AddBonusRespawnPosCommand(CCSPlayerController? player, CommandInfo c if (!IsAllowedPlayer(player)) return; // Get the player's current position - Vector currentPosition = player!.Pawn.Value!.CBodyComponent?.SceneNode?.AbsOrigin ?? new Vector(0, 0, 0); + Vector_t? currentPosition = player!.Pawn.Value!.CBodyComponent?.SceneNode?.AbsOrigin.ToVector_t(); // Convert position - string positionString = $"{currentPosition.X} {currentPosition.Y} {currentPosition.Z}"; + string positionString = $"{currentPosition.GetValueOrDefault().X} {currentPosition.GetValueOrDefault().Y} {currentPosition.GetValueOrDefault().Z}"; playerTimers[player.Slot].BonusRespawnPos = positionString; - player.PrintToChat($" {ChatColors.LightPurple}[ZONE TOOL] {ChatColors.Default}Bonus RespawnPos added!"); + Utils.PrintToChat(player, $" {ChatColors.LightPurple}[ZONE TOOL] {ChatColors.Default}Bonus RespawnPos added!"); } [ConsoleCommand("css_savebonuszones", "Saves defined zones")] @@ -215,14 +216,14 @@ public void SaveBonusZonesCommand(CCSPlayerController? player, CommandInfo comma if (playerTimers[player!.Slot].BonusEndZoneC1 == null || playerTimers[player.Slot].BonusEndZoneC2 == null || playerTimers[player.Slot].BonusStartZoneC1 == null || playerTimers[player.Slot].BonusStartZoneC2 == null || playerTimers[player.Slot].BonusRespawnPos == null) { - player.PrintToChat($" {ChatColors.LightPurple}[ZONE TOOL] {ChatColors.Red}Please make sure you have done all 3 zoning steps (!addbonusstartzone, !addbonusendzone, !addbonusrespawnpos)"); + Utils.PrintToChat(player, $" {ChatColors.LightPurple}[ZONE TOOL] {ChatColors.Red}Please make sure you have done all 3 zoning steps (!addbonusstartzone, !addbonusendzone, !addbonusrespawnpos)"); return; } if (!int.TryParse(command.ArgString, out int bonusX)) { - SharpTimerDebug("SaveBonusZones failed, not vaild integer."); - player.PrintToChat($" {Localizer["prefix"]} Please enter a valid Bonus stage i.e: {primaryChatColor}!savebonuszones "); + Utils.LogDebug("SaveBonusZones failed, not vaild integer."); + Utils.PrintToChat(player, $"Please enter a valid Bonus stage i.e: {primaryChatColor}!savebonuszones "); return; } @@ -241,7 +242,7 @@ public void SaveBonusZonesCommand(CCSPlayerController? player, CommandInfo comma string updatedJson = JsonSerializer.Serialize(newMapInfo, jsonSerializerOptions); File.WriteAllText(mapdataPath, updatedJson); - player.PrintToChat($" {ChatColors.LightPurple}[ZONE TOOL] {ChatColors.Default}Bonus {bonusX} Zones saved successfully! {ChatColors.Grey}Reloading data..."); + Utils.PrintToChat(player, $" {ChatColors.LightPurple}[ZONE TOOL] {ChatColors.Default}Bonus {bonusX} Zones saved successfully! {ChatColors.Grey}Reloading data..."); Server.ExecuteCommand("mp_restartgame 1"); } @@ -266,120 +267,120 @@ public void OnTickZoneTool(CCSPlayerController? player) { if (playerTimer.IsAddingStartZone) { - Vector pawnPosition = player.Pawn?.Value!.CBodyComponent?.SceneNode?.AbsOrigin ?? new Vector(0, 0, 0); - DrawZoneToolWireframe(ParseVector(playerTimer.StartZoneC1!), pawnPosition, player.Slot); + Vector_t pawnPosition = player.Pawn?.Value!.CBodyComponent?.SceneNode?.AbsOrigin.ToVector_t() ?? new Vector_t(0, 0, 0); + DrawZoneToolWireframe(Utils.ParseVector_t(playerTimer.StartZoneC1!), pawnPosition, player.Slot); } else if (playerTimer.IsAddingEndZone) { - Vector pawnPosition = player.Pawn?.Value!.CBodyComponent?.SceneNode?.AbsOrigin ?? new Vector(0, 0, 0); - DrawZoneToolWireframe(ParseVector(playerTimer.EndZoneC1!), pawnPosition, player.Slot); + Vector_t pawnPosition = player.Pawn?.Value!.CBodyComponent?.SceneNode?.AbsOrigin.ToVector_t() ?? new Vector_t(0, 0, 0); + DrawZoneToolWireframe(Utils.ParseVector_t(playerTimer.EndZoneC1!), pawnPosition, player.Slot); } else if (playerTimer.IsAddingBonusStartZone) { - Vector pawnPosition = player.Pawn?.Value!.CBodyComponent?.SceneNode?.AbsOrigin ?? new Vector(0, 0, 0); - DrawZoneToolWireframe(ParseVector(playerTimer.BonusStartZoneC1!), pawnPosition, player.Slot); + Vector_t pawnPosition = player.Pawn?.Value!.CBodyComponent?.SceneNode?.AbsOrigin.ToVector_t() ?? new Vector_t(0, 0, 0); + DrawZoneToolWireframe(Utils.ParseVector_t(playerTimer.BonusStartZoneC1!), pawnPosition, player.Slot); } else if (playerTimer.IsAddingBonusEndZone) { - Vector pawnPosition = player.Pawn?.Value!.CBodyComponent?.SceneNode?.AbsOrigin ?? new Vector(0, 0, 0); - DrawZoneToolWireframe(ParseVector(playerTimer.BonusEndZoneC1!), pawnPosition, player.Slot); + Vector_t pawnPosition = player.Pawn?.Value!.CBodyComponent?.SceneNode?.AbsOrigin.ToVector_t() ?? new Vector_t(0, 0, 0); + DrawZoneToolWireframe(Utils.ParseVector_t(playerTimer.BonusEndZoneC1!), pawnPosition, player.Slot); } } } catch (Exception ex) { if (ex.Message != "Invalid game event") - SharpTimerError($"Error in OnTickZoneTool: {ex.Message}"); + Utils.LogError($"Error in OnTickZoneTool: {ex.Message}"); } } - public void DrawZoneToolWireframe(Vector corner1, Vector corner8, int playerSlot) + public void DrawZoneToolWireframe(Vector_t? corner1, Vector_t? corner8, int slot) { try { - Vector corner2 = new(corner1.X, corner8.Y, corner1.Z); - Vector corner3 = new(corner8.X, corner8.Y, corner1.Z); - Vector corner4 = new(corner8.X, corner1.Y, corner1.Z); + Vector_t? corner2 = new(corner1!.Value.X, corner8!.Value.Y, corner1.Value.Z); + Vector_t? corner3 = new(corner8.Value.X, corner8.Value.Y, corner1.Value.Z); + Vector_t? corner4 = new(corner8.Value.X, corner1.Value.Y, corner1.Value.Z); - Vector corner5 = new(corner8.X, corner1.Y, corner8.Z); - Vector corner6 = new(corner1.X, corner1.Y, corner8.Z); - Vector corner7 = new(corner1.X, corner8.Y, corner8.Z); + Vector_t? corner5 = new(corner8.Value.X, corner1.Value.Y, corner8.Value.Z); + Vector_t? corner6 = new(corner1.Value.X, corner1.Value.Y, corner8.Value.Z); + Vector_t? corner7 = new(corner1.Value.X, corner8.Value.Y, corner8.Value.Z); if (corner1 != null && corner2 != null && corner3 != null && corner4 != null && corner5 != null && corner6 != null && corner7 != null && corner8 != null) { // top square - DrawZoneToolWire(corner1, corner2, playerSlot, 1); - DrawZoneToolWire(corner2, corner3, playerSlot, 2); - DrawZoneToolWire(corner3, corner4, playerSlot, 3); - DrawZoneToolWire(corner4, corner1, playerSlot, 4); + DrawZoneToolWire(corner1, corner2, slot, 1); + DrawZoneToolWire(corner2, corner3, slot, 2); + DrawZoneToolWire(corner3, corner4, slot, 3); + DrawZoneToolWire(corner4, corner1, slot, 4); // bottom square - DrawZoneToolWire(corner5, corner6, playerSlot, 5); - DrawZoneToolWire(corner6, corner7, playerSlot, 6); - DrawZoneToolWire(corner7, corner8, playerSlot, 7); - DrawZoneToolWire(corner8, corner5, playerSlot, 8); + DrawZoneToolWire(corner5, corner6, slot, 5); + DrawZoneToolWire(corner6, corner7, slot, 6); + DrawZoneToolWire(corner7, corner8, slot, 7); + DrawZoneToolWire(corner8, corner5, slot, 8); // connect them both to build a cube, - DrawZoneToolWire(corner1, corner6, playerSlot, 9); - DrawZoneToolWire(corner2, corner7, playerSlot, 10); - DrawZoneToolWire(corner3, corner8, playerSlot, 11); - DrawZoneToolWire(corner4, corner5, playerSlot, 12); + DrawZoneToolWire(corner1, corner6, slot, 9); + DrawZoneToolWire(corner2, corner7, slot, 10); + DrawZoneToolWire(corner3, corner8, slot, 11); + DrawZoneToolWire(corner4, corner5, slot, 12); } else { - SharpTimerDebug("One of the vectors is null in DrawZoneToolWireframe"); + Utils.LogDebug("One of the Vector_ts is null in DrawZoneToolWireframe"); } } catch (Exception ex) { - SharpTimerError($"Error in DrawZoneToolWireframe: {ex.Message}"); + Utils.LogError($"Error in DrawZoneToolWireframe: {ex.Message}"); } } - public void DrawZoneToolWire(Vector startPos, Vector endPos, int playerSlot, int wireIndex) + public void DrawZoneToolWire(Vector_t? startPos, Vector_t? endPos, int slot, int wireIndex) { try { - if (playerTimers.ContainsKey(playerSlot) && playerTimers[playerSlot] != null) + if (playerTimers.ContainsKey(slot) && playerTimers[slot] != null) { - if (!playerTimers[playerSlot].ZoneToolWire!.ContainsKey(wireIndex)) + if (!playerTimers[slot].ZoneToolWire!.ContainsKey(wireIndex)) { - playerTimers[playerSlot].ZoneToolWire![wireIndex] = Utilities.CreateEntityByName("beam")!; + playerTimers[slot].ZoneToolWire![wireIndex] = Utilities.CreateEntityByName("beam")!; } else { - playerTimers[playerSlot].ZoneToolWire![wireIndex].Remove(); - playerTimers[playerSlot].ZoneToolWire![wireIndex] = Utilities.CreateEntityByName("beam")!; + playerTimers[slot].ZoneToolWire![wireIndex].Remove(); + playerTimers[slot].ZoneToolWire![wireIndex] = Utilities.CreateEntityByName("beam")!; } - CBeam wire = playerTimers[playerSlot].ZoneToolWire![wireIndex]; + CBeam wire = playerTimers[slot].ZoneToolWire![wireIndex]; if (wire != null) { wire.Render = Color.Green; wire.Width = 1.5f; - wire.Teleport(startPos, new QAngle(0, 0, 0), new Vector(0, 0, 0)); - wire.EndPos.X = endPos.X; - wire.EndPos.Z = endPos.Z; - wire.EndPos.Y = endPos.Y; + wire.Teleport(startPos, new QAngle_t(0, 0, 0), new Vector_t(0, 0, 0)); + wire.EndPos.X = endPos!.Value.X; + wire.EndPos.Z = endPos.Value.Z; + wire.EndPos.Y = endPos.Value.Y; wire.FadeMinDist = 9999; wire.DispatchSpawn(); } else { - SharpTimerDebug($"Failed to create ZoneTool beam for wireIndex {wireIndex}..."); + Utils.LogDebug($"Failed to create ZoneTool beam for wireIndex {wireIndex}..."); } } else { - SharpTimerDebug($"Player slot {playerSlot} not found in the dictionary."); + Utils.LogDebug($"Player slot {slot} not found in the dictionary."); } } catch (Exception ex) { - SharpTimerError($"Error in DrawZoneToolWire: {ex.Message}"); + Utils.LogError($"Error in DrawZoneToolWire: {ex.Message}"); } } } diff --git a/src/Features/GlobalAPI.cs b/src/Features/GlobalAPI.cs index 0608d7ac..19abf424 100644 --- a/src/Features/GlobalAPI.cs +++ b/src/Features/GlobalAPI.cs @@ -39,16 +39,16 @@ public async Task SubmitRecordAsync(object payload) if (response.IsSuccessStatusCode) { - SharpTimerConPrint("Record submitted successfully."); + Utils.ConPrint("Record submitted successfully."); } else { - SharpTimerError($"Failed to submit record. Status code: {response.StatusCode}"); + Utils.LogError($"Failed to submit record. Status code: {response.StatusCode}"); } } catch (Exception ex) { - SharpTimerError($"Error in SubmitRecordAsync: {ex.Message}"); + Utils.LogError($"Error in SubmitRecordAsync: {ex.Message}"); } } @@ -76,7 +76,7 @@ public async Task CheckAddonAsync() workshop_id = currentAddonID }; string jsonPayload = JsonSerializer.Serialize(payload); - SharpTimerDebug($"CheckAddon payload: {jsonPayload}"); + Utils.LogDebug($"CheckAddon payload: {jsonPayload}"); var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json"); client.DefaultRequestHeaders.Clear(); @@ -92,7 +92,7 @@ public async Task CheckAddonAsync() } catch (Exception ex) { - SharpTimerError($"Error in CheckAddonAsync: {ex.Message}"); + Utils.LogError($"Error in CheckAddonAsync: {ex.Message}"); return false; } } @@ -122,7 +122,7 @@ public async Task CacheGlobalPoints() public async Task> GetTopPointsAsync(int limit = 10) { if (apiKey == "") - return null; + return null!; try { @@ -161,19 +161,19 @@ public async Task> GetTopPointsAsync(int limit = 10) } return player_points; } - return null; + return null!; } } else { - SharpTimerError($"Failed to get top points. Status code: {response.StatusCode}; Message: {response.Content}"); - return null; + Utils.LogError($"Failed to get top points. Status code: {response.StatusCode}; Message: {response.Content}"); + return null!; } } catch (Exception ex) { - SharpTimerError($"Error in GetRecordIDAsync: {ex.Message}"); - return null; + Utils.LogError($"Error in GetRecordIDAsync: {ex.Message}"); + return null!; } } @@ -204,25 +204,25 @@ public async Task GetRecordIDAsync(object payload) } else { - SharpTimerError($"No record ID found"); + Utils.LogError($"No record ID found"); return 0; } } } else { - SharpTimerError($"Failed to retrieve record_id. Status code: {response.StatusCode}; Message: {response.Content}"); + Utils.LogError($"Failed to retrieve record_id. Status code: {response.StatusCode}; Message: {response.Content}"); return 0; } } catch (Exception ex) { - SharpTimerError($"Error in GetRecordIDAsync: {ex.Message}"); + Utils.LogError($"Error in GetRecordIDAsync: {ex.Message}"); return 0; } } - public async Task<(int, int, int)> GetGlobalRank(CCSPlayerController? player) + public async Task<(int, int, int)> GetGlobalRank(CCSPlayerController player) { if (apiKey == "") return (0, 0, 0); @@ -268,19 +268,19 @@ public async Task GetRecordIDAsync(object payload) } else { - SharpTimerError($"Failed to retrieve player rank. Status code: {response.StatusCode}; Message: {response.Content}"); + Utils.LogError($"Failed to retrieve player rank. Status code: {response.StatusCode}; Message: {response.Content}"); return (0, 0, 0); } } catch (Exception ex) { - SharpTimerError($"Error in GetGlobalRankAsync: {ex.Message}"); + Utils.LogError($"Error in GetGlobalRankAsync: {ex.Message}"); return (0, 0, 0); } return (0, 0, 0); } - public async Task PrintGlobalRankAsync(CCSPlayerController? player) + public async Task PrintGlobalRankAsync(CCSPlayerController player) { if (apiKey == "") return; @@ -288,8 +288,8 @@ public async Task PrintGlobalRankAsync(CCSPlayerController? player) var (points, rank, totalPlayers) = await GetGlobalRank(player); Server.NextFrame(() => { - PrintToChat(player, $"{Localizer["total_gpoints"]}: {points}"); - PrintToChat(player, $"{Localizer["grank"]}: {rank}/{totalPlayers}"); + Utils.PrintToChat(player, $"{Localizer["total_gpoints"]}: {points}"); + Utils.PrintToChat(player, $"{Localizer["grank"]}: {rank}/{totalPlayers}"); }); } @@ -313,16 +313,16 @@ public async Task SubmitReplayAsync(object payload) if (response.IsSuccessStatusCode) { - SharpTimerConPrint("Replay uploaded successfully."); + Utils.ConPrint("Replay uploaded successfully."); } else { - SharpTimerError($"Failed to upload replay. Status code: {response.StatusCode}; Message: {response.Content}"); + Utils.LogError($"Failed to upload replay. Status code: {response.StatusCode}; Message: {response.Content}"); } } catch (Exception ex) { - SharpTimerError($"Error in SubmitReplayAsync: {ex.Message}"); + Utils.LogError($"Error in SubmitReplayAsync: {ex.Message}"); } } @@ -335,19 +335,23 @@ public void PrintWorldRecord(CCSPlayerController player) Server.NextFrame(() => { - PrintToChat(player, Localizer["current_wr", currentMapName!]); + Utils.PrintToChat(player, Localizer["current_wr", currentMapName!]); + + if (cache.CachedWorldRecords == null || cache.CachedWorldRecords.Count <= 0) + return; + int position = 1; - foreach (var record in cache.CachedWorldRecords!) + foreach (var record in cache.CachedWorldRecords) { string replayIndicator = record.Value.Replay ? $"{ChatColors.Red}◉" : ""; - PrintToChat(player, $"{Localizer["records_map", position, record.Value.PlayerName!, replayIndicator, FormatTime(record.Value.TimerTicks)]}"); + Utils.PrintToChat(player, $"{Localizer["records_map", position, record.Value.PlayerName!, replayIndicator, Utils.FormatTime(record.Value.TimerTicks)]}"); position++; } }); } catch (Exception ex) { - SharpTimerError($"Error in PrintWorldRecord: {ex.Message}"); + Utils.LogError($"Error in PrintWorldRecord: {ex.Message}"); } } @@ -360,30 +364,34 @@ public void PrintGlobalPoints(CCSPlayerController player) Server.NextFrame(() => { - PrintToChat(player, Localizer["top_10_points"]); + Utils.PrintToChat(player, Localizer["top_10_points"]); + + if (cache.CachedGlobalPoints == null || cache.CachedGlobalPoints.Count <= 0) + return; + int position = 1; - foreach (var p in cache.CachedGlobalPoints!) + foreach (var p in cache.CachedGlobalPoints) { - PrintToChat(player, $"{Localizer["top_10_points_list", position, p.PlayerName!, p.GlobalPoints]}"); + Utils.PrintToChat(player, $"{Localizer["top_10_points_list", position, p.PlayerName!, p.GlobalPoints]}"); position++; } }); } catch (Exception ex) { - SharpTimerError($"Error in PrintGlobalPoints: {ex.Message}"); + Utils.LogError($"Error in PrintGlobalPoints: {ex.Message}"); } } public async Task> GetSortedRecordsFromGlobal(int limit = 0, int bonusX = 0, string mapName = "", int style = 0) { if (apiKey == "") - return null; + return null!; if (globalDisabled) - return null; + return null!; - SharpTimerDebug($"Trying GetSortedRecordsFromGlobal {(bonusX != 0 ? $"bonus {bonusX}" : "")}"); + Utils.LogDebug($"Trying GetSortedRecordsFromGlobal {(bonusX != 0 ? $"bonus {bonusX}" : "")}"); using (var connection = await OpenConnectionAsync()) { string? currentMapNamee; @@ -442,24 +450,24 @@ public async Task> GetSortedRecordsFromGlobal(int sortedRecords = sortedRecords.OrderBy(record => record.Value.TimerTicks) .ToDictionary(record => record.Key, record => record.Value); - SharpTimerDebug("Got sorted records from global"); + Utils.LogDebug("Got sorted records from global"); return sortedRecords; } else { - SharpTimerDebug("No data returned"); + Utils.LogDebug("No data returned"); return sortedRecords; } } } else { - SharpTimerError($"Failed to GetSortedRecordsFromGlobal. Status code: {response.StatusCode}"); + Utils.LogError($"Failed to GetSortedRecordsFromGlobal. Status code: {response.StatusCode}"); } } catch (Exception ex) { - SharpTimerError($"Error in GetSortedRecordsFromGlobal: {ex.Message}"); + Utils.LogError($"Error in GetSortedRecordsFromGlobal: {ex.Message}"); } } return []; @@ -489,12 +497,12 @@ public async Task GetReplayFromGlobal(object payload) } else { - SharpTimerError($"Failed to get global replay. Status code: {response.StatusCode}"); + Utils.LogError($"Failed to get global replay. Status code: {response.StatusCode}"); } } catch (Exception ex) { - SharpTimerError($"Error in GetReplayFromGlobal: {ex.Message}"); + Utils.LogError($"Error in GetReplayFromGlobal: {ex.Message}"); } return ""; } @@ -507,7 +515,7 @@ public async Task GetPreviousPlayerRecordFromGlobal(string steamId, string if (globalDisabled) return 0; - SharpTimerDebug($"Trying to get Previous {(bonusX != 0 ? $"bonus {bonusX} time" : "time")} from global for {playerName}"); + Utils.LogDebug($"Trying to get Previous {(bonusX != 0 ? $"bonus {bonusX} time" : "time")} from global for {playerName}"); try { string currentMapNamee = bonusX == 0 ? currentMapName : $"{currentMapName}_bonus{bonusX}"; @@ -548,13 +556,13 @@ public async Task GetPreviousPlayerRecordFromGlobal(string steamId, string } else { - SharpTimerConPrint($"No previous record found for steamid: {steamId}"); + Utils.ConPrint($"No previous record found for steamid: {steamId}"); return 0; } } catch (Exception ex) { - SharpTimerError($"Error getting previous player {(bonusX != 0 ? $"bonus {bonusX} time" : "time")} from global: {ex.Message}"); + Utils.LogError($"Error getting previous player {(bonusX != 0 ? $"bonus {bonusX} time" : "time")} from global: {ex.Message}"); } return 0; } @@ -587,6 +595,7 @@ public async Task CheckKeyAsync() } catch (Exception ex) { + Utils.LogError(ex.Message); return false; } } @@ -623,6 +632,7 @@ public async Task CheckHashAsync() } catch (Exception ex) { + Utils.LogError(ex.Message); return false; } } @@ -631,45 +641,53 @@ public async Task CheckHashAsync() { if (!globalDisabled) { - if (IsApproximatelyEqual(ConVar.Find("sv_accelerate")!.GetPrimitiveValue(), 10) - && ((IsApproximatelyEqual(ConVar.Find("sv_airaccelerate")!.GetPrimitiveValue(), 150) && currentMapName!.Contains("surf_")) - || (IsApproximatelyEqual(ConVar.Find("sv_airaccelerate")!.GetPrimitiveValue(), 1000) && currentMapName!.Contains("bhop_"))) - && IsApproximatelyEqual(ConVar.Find("sv_friction")!.GetPrimitiveValue(), (float)5.2) - && IsApproximatelyEqual(ConVar.Find("sv_gravity")!.GetPrimitiveValue(), 800) - && IsApproximatelyEqual(ConVar.Find("sv_ladder_scale_speed")!.GetPrimitiveValue(), 1) - && IsApproximatelyEqual(ConVar.Find("sv_staminajumpcost")!.GetPrimitiveValue(), 0) - && IsApproximatelyEqual(ConVar.Find("sv_staminalandcost")!.GetPrimitiveValue(), 0) - && IsApproximatelyEqual(ConVar.Find("sv_staminamax")!.GetPrimitiveValue(), 0) - && IsApproximatelyEqual(ConVar.Find("sv_staminarecoveryrate")!.GetPrimitiveValue(), 0) - && IsApproximatelyEqual(ConVar.Find("sv_wateraccelerate")!.GetPrimitiveValue(), 10) + var equal = Utils.IsApproximatelyEqual; + + if (equal(ConVar.Find("sv_accelerate")!.GetPrimitiveValue(), 10) + + && ((equal(ConVar.Find("sv_airaccelerate")!.GetPrimitiveValue(), 150) && currentMapName!.Contains("surf_")) || + (equal(ConVar.Find("sv_airaccelerate")!.GetPrimitiveValue(), 1000) && currentMapName!.Contains("bhop_"))) + + && equal(ConVar.Find("sv_friction")!.GetPrimitiveValue(), (float)5.2) + && equal(ConVar.Find("sv_gravity")!.GetPrimitiveValue(), 800) + && equal(ConVar.Find("sv_ladder_scale_speed")!.GetPrimitiveValue(), 1) + && equal(ConVar.Find("sv_staminajumpcost")!.GetPrimitiveValue(), 0) + && equal(ConVar.Find("sv_staminalandcost")!.GetPrimitiveValue(), 0) + && equal(ConVar.Find("sv_staminamax")!.GetPrimitiveValue(), 0) + && equal(ConVar.Find("sv_staminarecoveryrate")!.GetPrimitiveValue(), 0) + && equal(ConVar.Find("sv_wateraccelerate")!.GetPrimitiveValue(), 10) && ConVar.Find("sv_cheats")!.GetPrimitiveValue() == false - && (IsApproximatelyEqual(ConVar.Find("sv_air_max_wishspeed")!.GetPrimitiveValue(), 30) || IsApproximatelyEqual(ConVar.Find("sv_air_max_wishspeed")!.GetPrimitiveValue(), (float)37.41)) - && IsApproximatelyEqual(ConVar.Find("sv_maxspeed")!.GetPrimitiveValue(), 420) + + && (equal(ConVar.Find("sv_air_max_wishspeed")!.GetPrimitiveValue(), 30) || + equal(ConVar.Find("sv_air_max_wishspeed")!.GetPrimitiveValue(), (float)37.41)) + + && equal(ConVar.Find("sv_maxspeed")!.GetPrimitiveValue(), 420) && useCheckpointVerification) { // THICK globalChecksPassed = true; return (true, ConVar.Find("sv_maxvelocity")!.GetPrimitiveValue(), ConVar.Find("sv_air_max_wishspeed")!.GetPrimitiveValue()); } + //Checks failed, disable global api - SharpTimerConPrint($"GLOBAL CHECK FAILED -- Current Values:"); - SharpTimerConPrint($"sv_accelerate: {ConVar.Find("sv_accelerate")!.GetPrimitiveValue()} [should be 10]"); - SharpTimerConPrint($"sv_airaccelerate: {ConVar.Find("sv_airaccelerate")!.GetPrimitiveValue()} [should be 150 for surf_ or 1000 for bhop_]"); - SharpTimerConPrint($"sv_friction: {ConVar.Find("sv_friction")!.GetPrimitiveValue()} [should be 5.2]"); - SharpTimerConPrint($"sv_gravity: {ConVar.Find("sv_gravity")!.GetPrimitiveValue()} [should be 800]"); - SharpTimerConPrint($"sv_ladder_scale_speed: {ConVar.Find("sv_ladder_scale_speed")!.GetPrimitiveValue()} [should be 1]"); - SharpTimerConPrint($"sv_staminajumpcost: {ConVar.Find("sv_staminajumpcost")!.GetPrimitiveValue()} [should be 0]"); - SharpTimerConPrint($"sv_staminalandcost: {ConVar.Find("sv_staminalandcost")!.GetPrimitiveValue()} [should be 0]"); - SharpTimerConPrint($"sv_staminamax: {ConVar.Find("sv_staminamax")!.GetPrimitiveValue()} [should be 0]"); - SharpTimerConPrint($"sv_staminarecoveryrate: {ConVar.Find("sv_staminarecoveryrate")!.GetPrimitiveValue()} [should be 0]"); - SharpTimerConPrint($"sv_wateraccelerate: {ConVar.Find("sv_wateraccelerate")!.GetPrimitiveValue()} [should be 10]"); - SharpTimerConPrint($"sv_maxspeed: {ConVar.Find("sv_maxspeed")!.GetPrimitiveValue()} [should be 420]"); - SharpTimerConPrint($"sharptimer_max_start_speed: {ConVar.Find("sv_maxspeed")!.GetPrimitiveValue()} [should be 420]"); - SharpTimerConPrint($"sv_air_max_wishspeed: {ConVar.Find("sv_air_max_wishspeed")!.GetPrimitiveValue()} [should be 30 or 37.41]"); - SharpTimerConPrint($"sv_cheats: {ConVar.Find("sv_cheats")!.GetPrimitiveValue()} [should be false]"); - SharpTimerConPrint($"Map is properly zoned?: {useTriggers} [should be true]"); - SharpTimerConPrint($"Use checkpoint verification?: {useCheckpointVerification} [should be true]"); - SharpTimerConPrint($"Using StripperCS2 on current map?: {Directory.Exists($"{gameDir}/addons/StripperCS2/maps/{Server.MapName}")} [should be false]"); + Utils.ConPrint($"GLOBAL CHECK FAILED -- Current Values:"); + Utils.ConPrint($"sv_accelerate: {ConVar.Find("sv_accelerate")!.GetPrimitiveValue()} [should be 10]"); + Utils.ConPrint($"sv_airaccelerate: {ConVar.Find("sv_airaccelerate")!.GetPrimitiveValue()} [should be 150 for surf_ or 1000 for bhop_]"); + Utils.ConPrint($"sv_friction: {ConVar.Find("sv_friction")!.GetPrimitiveValue()} [should be 5.2]"); + Utils.ConPrint($"sv_gravity: {ConVar.Find("sv_gravity")!.GetPrimitiveValue()} [should be 800]"); + Utils.ConPrint($"sv_ladder_scale_speed: {ConVar.Find("sv_ladder_scale_speed")!.GetPrimitiveValue()} [should be 1]"); + Utils.ConPrint($"sv_staminajumpcost: {ConVar.Find("sv_staminajumpcost")!.GetPrimitiveValue()} [should be 0]"); + Utils.ConPrint($"sv_staminalandcost: {ConVar.Find("sv_staminalandcost")!.GetPrimitiveValue()} [should be 0]"); + Utils.ConPrint($"sv_staminamax: {ConVar.Find("sv_staminamax")!.GetPrimitiveValue()} [should be 0]"); + Utils.ConPrint($"sv_staminarecoveryrate: {ConVar.Find("sv_staminarecoveryrate")!.GetPrimitiveValue()} [should be 0]"); + Utils.ConPrint($"sv_wateraccelerate: {ConVar.Find("sv_wateraccelerate")!.GetPrimitiveValue()} [should be 10]"); + Utils.ConPrint($"sv_maxspeed: {ConVar.Find("sv_maxspeed")!.GetPrimitiveValue()} [should be 420]"); + Utils.ConPrint($"sharptimer_max_start_speed: {ConVar.Find("sv_maxspeed")!.GetPrimitiveValue()} [should be 420]"); + Utils.ConPrint($"sv_air_max_wishspeed: {ConVar.Find("sv_air_max_wishspeed")!.GetPrimitiveValue()} [should be 30 or 37.41]"); + Utils.ConPrint($"sv_cheats: {ConVar.Find("sv_cheats")!.GetPrimitiveValue()} [should be false]"); + Utils.ConPrint($"Map is properly zoned?: {useTriggers} [should be true]"); + Utils.ConPrint($"Use checkpoint verification?: {useCheckpointVerification} [should be true]"); + Utils.ConPrint($"Using StripperCS2 on current map?: {Directory.Exists($"{gameDir}/addons/StripperCS2/maps/{Server.MapName}")} [should be false]"); globalDisabled = true; globalChecksPassed = false; diff --git a/src/Features/JumpStats.cs b/src/Features/JumpStats.cs deleted file mode 100644 index 8af15d28..00000000 --- a/src/Features/JumpStats.cs +++ /dev/null @@ -1,505 +0,0 @@ -/* -Copyright (C) 2024 Dea Brcka - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -using CounterStrikeSharp.API; -using CounterStrikeSharp.API.Core; -using CounterStrikeSharp.API.Modules.Utils; -using Vector = CounterStrikeSharp.API.Modules.Utils.Vector; - -namespace SharpTimer -{ - public partial class SharpTimer - { - //based on https://github.com/deafps/cs2-kz-lua/blob/main/kz.lua - public void OnJumpStatJumped(CCSPlayerController player) - { - if (IsAllowedPlayer(player)) - { - int playerSlot = player.Slot; - playerJumpStats[playerSlot].Jumped = true; - playerJumpStats[playerSlot].OldJumpPos = string.IsNullOrEmpty(playerJumpStats[playerSlot].JumpPos) - ? $"{player.Pawn.Value!.AbsOrigin!.X} {player.Pawn.Value!.AbsOrigin.Y!} {player.Pawn.Value!.AbsOrigin.Z}" - : playerJumpStats[playerSlot].JumpPos; - playerJumpStats[playerSlot].JumpPos = $"{player.Pawn.Value!.AbsOrigin!.X} {player.Pawn.Value!.AbsOrigin.Y!} {player.Pawn.Value!.AbsOrigin.Z!}"; - } - } - - public void OnJumpStatSound(CCSPlayerController player) - { - if (IsAllowedPlayer(player)) - { - int playerSlot = player.Slot; - if (playerJumpStats[playerSlot].Jumped == true && playerJumpStats[playerSlot].FramesOnGround == 0) - { - playerJumpStats[playerSlot].LandedFromSound = true; - Server.NextFrame(() => - { - if (IsAllowedPlayer(player)) playerJumpStats[playerSlot].LandedFromSound = false; - }); - } - } - } - - public void OnJumpStatTick(CCSPlayerController player, Vector velocity, Vector playerpos, QAngle eyeangle, PlayerButtons? buttons) - { - try - { - if (playerJumpStats.TryGetValue(player.Slot, out PlayerJumpStats? playerJumpStat)) - { - playerJumpStat.OnGround = ((PlayerFlags)player.Pawn.Value!.Flags & PlayerFlags.FL_ONGROUND) == PlayerFlags.FL_ONGROUND; //need hull trace for this to detect surf and edgebug etc - - if (playerJumpStat.OnGround) - { - playerJumpStat.FramesOnGround++; - } - else - { - playerJumpStat.FramesOnGround = 0; - OnJumpStatTickInAir(player, playerJumpStat, buttons, playerpos, velocity, eyeangle); - } - - if (playerJumpStat.FramesOnGround == 2) - { - if (movementUnlockerCapEnabled && velocity.Length2D() > movementUnlockerCapValue) - { - float mult = movementUnlockerCapValue / velocity.Length2D(); - velocity.X *= mult; - velocity.Y *= mult; - player.PlayerPawn.Value!.AbsVelocity.X = velocity.X; - player.PlayerPawn.Value!.AbsVelocity.Y = velocity.Y; - } - } - else if (playerJumpStat.FramesOnGround == 1) - { - if (playerJumpStat.Jumped) - { - double distance = Calculate2DDistanceWithVerticalMargins(ParseVector(playerJumpStat.JumpPos!), playerpos); - if (distance != 0 && playerJumpStat.LastFramesOnGround > 2) - { - playerJumpStat.LastJumpType = "LJ"; - PrintJS(player, playerJumpStat, distance, playerpos); - } - else if (distance != 0 && playerJumpStat.LastFramesOnGround <= 2 && (playerJumpStat.LastJumpType == "LJ" || playerJumpStat.LastJumpType == "JB")) - { - playerJumpStat.LastJumpType = "BH"; - PrintJS(player, playerJumpStat, distance, playerpos); - } - else if (distance != 0 && playerJumpStat.LastFramesOnGround <= 2 && (playerJumpStat.LastJumpType == "BH" || playerJumpStat.LastJumpType == "MBH" || playerJumpStat.LastJumpType == "JB")) - { - playerJumpStat.LastJumpType = "MBH"; - PrintJS(player, playerJumpStat, distance, playerpos); - } - } - - playerJumpStat.Jumped = false; - - playerJumpStat.jumpFrames.Clear(); - playerJumpStat.jumpInterp.Clear(); - playerJumpStat.WTicks = 0; - } - else if (playerJumpStat.LandedFromSound == true) //workaround for PlayerFlags.FL_ONGROUND being 1 frame late - { - if (playerJumpStat.Jumped) - { - double distance = Calculate2DDistanceWithVerticalMargins(ParseVector(playerJumpStat.OldJumpPos!), playerpos, true); - if (distance != 0 && !playerJumpStat.LastOnGround && playerJumpStat.LastDucked && ((PlayerFlags)player.Pawn.Value.Flags & PlayerFlags.FL_DUCKING) != PlayerFlags.FL_DUCKING) - { - playerJumpStat.LastJumpType = "JB"; - PrintJS(player, playerJumpStat, distance, playerpos); - playerJumpStat.LastFramesOnGround = playerJumpStat.FramesOnGround; - playerJumpStat.Jumped = true; // assume player jumped again if JB is successful - if (playerTimers[player.Slot].SoundsEnabled == true) player.ExecuteClientCommand($"play player/death_fem_0{new Random().Next(1, 9)}"); - } - } - else - { - playerJumpStat.Jumped = false; - } - playerJumpStat.jumpFrames.Clear(); - playerJumpStat.jumpInterp.Clear(); - playerJumpStat.WTicks = 0; - - playerJumpStat.FramesOnGround++; - } - - playerJumpStat.LastLandedFromSound = playerJumpStat.LandedFromSound; - - playerJumpStat.LastOnGround = playerJumpStat.OnGround; - playerJumpStat.LastDucked = ((PlayerFlags)player.Pawn.Value.Flags & PlayerFlags.FL_DUCKING) == PlayerFlags.FL_DUCKING; - if (playerJumpStat.OnGround) - { - playerJumpStat.LastSpeed = $"{velocity.X} {velocity.Y} {velocity.Z}"; - playerJumpStat.LastFramesOnGround = playerJumpStat.FramesOnGround; - playerJumpStat.LastPosOnGround = $"{playerpos.X} {playerpos.Y} {playerpos.Z}"; - } - } - } - catch (Exception ex) - { - SharpTimerDebug($"Exception in OnJumpStatTick: {ex}"); - } - } - - public void OnJumpStatTickInAir(CCSPlayerController player, PlayerJumpStats playerJumpStat, PlayerButtons? buttons, Vector playerpos, Vector velocity, QAngle eyeangle) - { - try - { - var LastJumpFrame = playerJumpStat.jumpFrames.Count != 0 ? playerJumpStat.jumpFrames.Last() : new PlayerJumpStats.IFrame - { - PositionString = $" ", - SpeedString = $" ", - LastLeft = false, - LastRight = false, - LastLeftRight = false, - MaxHeight = 0, - MaxSpeed = 0 - }; - - bool left = false; - bool right = false; - bool leftRight = false; - if ((buttons & PlayerButtons.Moveleft) != 0 && (buttons & PlayerButtons.Moveright) != 0) - leftRight = true; - else if ((buttons & PlayerButtons.Moveleft) != 0) - left = true; - else if ((buttons & PlayerButtons.Moveright) != 0) - right = true; - - if ((buttons & PlayerButtons.Forward) != 0) - playerJumpStat.WTicks++; - - double maxHeight; - if (IsVectorHigherThan(playerpos, ParseVector(LastJumpFrame.PositionString!))) - maxHeight = playerpos.Z - ParseVector(playerJumpStat.LastPosOnGround ?? "0 0 0").Z; - else - maxHeight = LastJumpFrame?.MaxHeight ?? 0; - - double maxSpeed; - if (velocity.Length2D() > LastJumpFrame!.MaxSpeed) - maxSpeed = velocity.Length2D(); - else - maxSpeed = LastJumpFrame?.MaxSpeed ?? 0; - - var JumpFrame = new PlayerJumpStats.IFrame - { - PositionString = $"{playerpos.X} {playerpos.Y} {playerpos.Z}", - SpeedString = $"{velocity.X} {velocity.Y} {velocity.Z}", - RotationString = $"{eyeangle.X} {eyeangle.Y} {eyeangle.Z}", - LastLeft = left, - LastRight = right, - LastLeftRight = leftRight, - MaxHeight = maxHeight, - MaxSpeed = maxSpeed - }; - - playerJumpStat.jumpFrames.Add(JumpFrame); - } - catch (Exception ex) - { - SharpTimerDebug($"Exception in OnJumpStatTickInAir: {ex}"); - } - } - - public void OnSyncTick(CCSPlayerController player, PlayerButtons? buttons, QAngle eyeangle) - { - try - { - var playerTimer = playerTimers[player.Slot]; - bool strafingLeft = false; - bool strafingRight = false; - // Start with 100% sync initially - if (playerTimers[player.Slot].inStartzone) playerTimer.Sync = 100.00f; - - if ((buttons & PlayerButtons.Moveleft) != 0 && (buttons & PlayerButtons.Moveright) != 0) - { - return; // Ignore if both left and right are pressed - } - else if ((buttons & PlayerButtons.Moveleft) != 0) - { - strafingLeft = true; - } - else if ((buttons & PlayerButtons.Moveright) != 0) - { - strafingRight = true; - } - else - { - return; // Ignore if neither left nor right is pressed - } - - // Add the current eye angle to the rotation history - QAngle newEyeAngle = new QAngle(eyeangle.X, eyeangle.Y, eyeangle.Z); - playerTimer.Rotation.Add(newEyeAngle); - - // Cap rotation history at 1000 entries - if (playerTimer.Rotation.Count > 1000) - { - playerTimer.Rotation.RemoveAt(0); // Remove the oldest entry - } - - // Only proceed if we have enough data points in Rotation - if (playerTimer.Rotation.Count > 1) - { - float previousEyeAngleY = playerTimer.Rotation[playerTimer.Rotation.Count - 2].Y; // Use Rotation.Count - 2 - float currentEyeAngleY = eyeangle.Y; - - // Normalize angle difference to handle wrapping from -180 to 180 - float deltaY = currentEyeAngleY - previousEyeAngleY; - if (deltaY > 180) - { - deltaY -= 360; - } - else if (deltaY < -180) - { - deltaY += 360; - } - - if (Math.Abs(deltaY) < 0.01f) return; - - bool onGround = ((PlayerFlags)player.Pawn.Value!.Flags & PlayerFlags.FL_ONGROUND) == PlayerFlags.FL_ONGROUND; - if (onGround || (!onGround && (buttons & (PlayerButtons.Moveleft | PlayerButtons.Moveright)) == 0)) - { - return; // Ignore calculation if the player is on the ground or airborne without pressing movement buttons - } - else - { - // Increment frames in the air - playerTimer.TotalSync++; - } - - // Determine rotation direction - bool rotatingLeft = deltaY > 0; - bool rotatingRight = deltaY < 0; - - // Add sync frame if strafing and rotating match and the player is airborne - if (!onGround && ((strafingLeft && rotatingLeft) || (strafingRight && rotatingRight))) - { - playerTimer.GoodSync++; // Increment sync frames - } - } - - // Calculate sync percentage - if (playerTimer.TotalSync >= 2) // Adjust threshold as needed - { - playerTimer.Sync = (playerTimer.TotalSync > 0) - ? (playerTimer.GoodSync / (float)playerTimer.TotalSync) * 100 - : 0; - } - } - catch (Exception ex) - { - SharpTimerDebug($"Exception in OnSyncTick: {ex}"); - } - } - - public static char GetJSColor(double distance) - { - if (distance < 230) - { - return ChatColors.Grey; - } - else if (distance < 235) - { - return ChatColors.Blue; - } - else if (distance < 240) - { - return ChatColors.Green; - } - else if (distance < 244) - { - return ChatColors.DarkRed; - } - else if (distance < 246) - { - return ChatColors.Gold; - } - else - { - return ChatColors.Purple; - } - } - - double Calculate2DDistanceWithVerticalMargins(Vector vector1, Vector vector2, bool noVertCheck = false) - { - if (vector1 == null || vector2 == null) - { - return 0; - } - - float verticalDistance = Math.Abs(vector1.Z - vector2.Z); - - if (verticalDistance >= 32 && noVertCheck == false) - { - return 0; - } - - double distance2D = Distance(vector1, vector2); - - if (distance2D > jumpStatsMinDist || noVertCheck == true) - { - double result = distance2D + 16.0f; - return result; - } - else - { - return 0; - } - } - - public static (int lastLeftGroups, int leftSync, int leftFrames) CountLeftGroupsAndSync(PlayerJumpStats playerJumpStat, bool timersync) - { - int lastLeftGroups = 0; - int leftSync = 0; - int leftFrames = 0; - bool inGroup = false; - QAngle previousRotation = null!; - - var frames = timersync ? playerJumpStat.timerSyncFrames : playerJumpStat.jumpFrames; - foreach (var frame in frames) - { - if (frame.LastLeftRight || frame.LastRight) - { - if (inGroup) - lastLeftGroups++; - inGroup = false; - } - else if (frame.LastLeft) - { - inGroup = true; - leftFrames++; - if (previousRotation != null && ParseQAngle(frame.RotationString!).Y > previousRotation.Y) - leftSync++; - } - previousRotation = ParseQAngle(frame.RotationString!); - } - - if (inGroup) - lastLeftGroups++; - - return (lastLeftGroups, leftSync, leftFrames); - } - - public static (int lastRightGroups, int rightSync, int rightFrames) CountRightGroupsAndSync(PlayerJumpStats playerJumpStat, bool timersync) - { - int lastRightGroups = 0; - int rightSync = 0; - int rightFrames = 0; - bool inGroup = false; - QAngle previousRotation = null!; - - var frames = timersync ? playerJumpStat.timerSyncFrames : playerJumpStat.jumpFrames; - foreach (var frame in frames) - { - if (frame.LastLeftRight || frame.LastLeft) - { - if (inGroup) - lastRightGroups++; - inGroup = false; - - } - else if (frame.LastRight) - { - inGroup = true; - rightFrames++; - if (previousRotation != null && ParseQAngle(frame.RotationString!).Y < previousRotation.Y) - rightSync++; - } - previousRotation = ParseQAngle(frame.RotationString!); - } - - if (inGroup) - lastRightGroups++; - - return (lastRightGroups, rightSync, rightFrames); - } - - public static float GetMaxWidth(Vector playerpos, PlayerJumpStats playerJumpStat) - { - InterpolateVectors(ParseVector(playerJumpStat.JumpPos!), playerpos, playerJumpStat); - - float distance = 0; - for (int jumpFrameIndex = 0; jumpFrameIndex < Math.Min(playerJumpStat.jumpFrames.Count, playerJumpStat.jumpInterp.Count); jumpFrameIndex++) - { - var frame = playerJumpStat.jumpFrames[jumpFrameIndex]; - float width = (float)Distance2D(ParseVector(frame.PositionString!), ParseVector(playerJumpStat.jumpInterp[jumpFrameIndex].InterpString!)); - if (width > distance) distance = width; - } - - return (float)Math.Round(distance, 2); - } - - public static void InterpolateVectors(Vector vector1, Vector vector2, PlayerJumpStats playerJumpStat) - { - int numInterpolations = playerJumpStat.jumpFrames.Count; - float stepX = (vector2.X - vector1.X) / (numInterpolations + 1); - float stepY = (vector2.Y - vector1.Y) / (numInterpolations + 1); - float stepZ = (vector2.Z - vector1.Z) / (numInterpolations + 1); - - for (int i = 0; i < numInterpolations; i++) - { - float interpolatedX = vector1.X + stepX * (i + 1); - float interpolatedY = vector1.Y + stepY * (i + 1); - float interpolatedZ = vector1.Z + stepZ * (i + 1); - - var interpFrame = new PlayerJumpStats.JumpInterp - { - InterpString = $"{interpolatedX} {interpolatedY} {interpolatedZ}" - }; - - playerJumpStat.jumpInterp.Add(interpFrame); - } - } - - public void InvalidateJS(int playerSlot) - { - try - { - if (playerJumpStats.TryGetValue(playerSlot, out PlayerJumpStats? value)) - { - value.LastFramesOnGround = 0; - value.Jumped = false; - } - } - catch(Exception ex) - { - // Suppress trigger_teleport null reference exceptions (the player has likely disconnected) - } - } - - public void PrintJS(CCSPlayerController player, PlayerJumpStats playerJumpStat, double distance, Vector playerpos) - { - if (playerTimers[player.Slot].HideJumpStats == true) return; - - char color = GetJSColor(distance); - - var (lStrafes, lSync, lFrames) = CountLeftGroupsAndSync(playerJumpStat, false); - var (rStrafes, rSync, rFrames) = CountRightGroupsAndSync(playerJumpStat, false); - - int strafes = rStrafes + lStrafes; - int strafeFrames = rFrames + lFrames; - int syncedFrames = rSync + lSync; - - double sync = (strafeFrames != 0) ? Math.Round(syncedFrames * 100f / strafeFrames, 2) : 0; - - PrintToChat(player, Localizer["js_msg1", playerJumpStat.LastJumpType!, color, Math.Round(distance, 2), Math.Round(ParseVector(playerJumpStat.LastSpeed!).Length2D(), 2), Math.Round(playerJumpStat.jumpFrames.Last().MaxSpeed, 2), strafes]); - PrintToChat(player, Localizer["js_msg2", Math.Round(playerJumpStat.jumpFrames.Last().MaxHeight, 2), GetMaxWidth(playerpos, playerJumpStat), playerJumpStat.WTicks, sync]); - - player.PrintToConsole($"-----------------------------------------------------------------------------------------------------------------------"); - player.PrintToConsole($" {Localizer["js_msg1", playerJumpStat.LastJumpType!, color, Math.Round(distance, 2), Math.Round(ParseVector(playerJumpStat.LastSpeed!).Length2D(), 2), Math.Round(playerJumpStat.jumpFrames.Last().MaxSpeed, 2), strafes]}"); - player.PrintToConsole($" {Localizer["js_msg2", Math.Round(playerJumpStat.jumpFrames.Last().MaxHeight, 2), GetMaxWidth(playerpos, playerJumpStat), playerJumpStat.WTicks, sync]}"); - } - } -} diff --git a/src/Features/Points.cs b/src/Features/Points.cs index 14105b3f..7727461e 100644 --- a/src/Features/Points.cs +++ b/src/Features/Points.cs @@ -36,10 +36,10 @@ public async Task CalculateTier(int completions, string mapname) string? _; if(disableRemoteData) - (tier, _) = await FindMapInfoFromLocal(GetMapInfoSource(), mapname); + (tier, _) = await Utils.FindMapInfoFromLocal(Utils.GetMapInfoSource(), mapname); else - (tier, _) = await FindMapInfoFromHTTP(GetMapInfoSource(), mapname); + (tier, _) = await Utils.FindMapInfoFromHTTP(Utils.GetMapInfoSource(), mapname); if (tier != null) { @@ -126,62 +126,5 @@ public double CalculateGroups(double points, double percentile, bool forGlobal = _ => 0, }; } - - public string FormatGroup(int placement, double percentile) { - percentile *= 100; - if (placement <= 10) - return placement switch { - 1 => "First", - 2 => "Second", - 3 => "Third", - > 0 => placement + "th", - _ => "N/A" - }; - - if (percentile > 0.5) return "N/A"; - - return percentile switch { - double p when p <= 3.125 => "Group 1", - double p when p <= 6.25 => "Group 2", - double p when p <= 12.5 => "Group 3", - double p when p <= 25 => "Group 4", - double p when p <= 50 => "Group 5", - _ => "N/A" - }; - } - - public int GetGroupIndex(double percentile, bool forGlobal = false) - { - // double baseMultiplier = points * 0.25; - double divisor = 1.5; - - double threshold1, threshold2, threshold3, threshold4, threshold5; - if (forGlobal) - { - threshold1 = 3.125; - threshold2 = 6.25; - threshold3 = 12.5; - threshold4 = 25; - threshold5 = 50; - } - else - { - threshold1 = group1; - threshold2 = group2; - threshold3 = group3; - threshold4 = group4; - threshold5 = group5; - } - - return percentile switch - { - double p when p <= threshold1 => 1, - double p when p <= threshold2 => 2, - double p when p <= threshold3 => 3, - double p when p <= threshold4 => 4, - double p when p <= threshold5 => 5, - _ => 0, - }; - } } } diff --git a/src/Hooks/Damage.cs b/src/Features/RemoveDamage.cs similarity index 58% rename from src/Hooks/Damage.cs rename to src/Features/RemoveDamage.cs index 7b8ff257..dd0abfa6 100644 --- a/src/Hooks/Damage.cs +++ b/src/Features/RemoveDamage.cs @@ -22,56 +22,73 @@ You should have received a copy of the GNU General Public License namespace SharpTimer { - public partial class SharpTimer + public class RemoveDamage { - public void DamageHook() + private readonly SharpTimer Plugin; + private readonly Utils Utils; + + public RemoveDamage(SharpTimer plugin) + { + Plugin = plugin ?? throw new ArgumentNullException(nameof(plugin)); + Utils = plugin.Utils ?? throw new ArgumentNullException(nameof(plugin.Utils)); + } + + public void Hook() { + Utils.LogDebug("Hook RemoveDamage"); + try { - SharpTimerDebug("Init Damage hook..."); - if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + if (Plugin.isLinux) { - SharpTimerDebug("Trying to register Linux Damage hook..."); - VirtualFunctions.CBaseEntity_TakeDamageOldFunc.Hook(this.OnTakeDamage, HookMode.Pre); + Utils.LogDebug("Trying to register Linux Damage hook..."); + VirtualFunctions.CBaseEntity_TakeDamageOldFunc.Hook(OnTakeDamage, HookMode.Pre); } else { - SharpTimerDebug("Trying to register Windows Damage hook..."); - RegisterEventHandler(OnPlayerHurt, HookMode.Pre); + Utils.LogDebug("Trying to register Windows Damage hook..."); + Plugin.RegisterEventHandler(OnPlayerHurt, HookMode.Pre); } } catch (Exception ex) { if (ex.Message == "Invalid function pointer") - SharpTimerError($"Error in DamageHook: Conflict between cs2fixes and SharpTimer"); + Utils.LogError($"Error in DamageHook: Conflict between cs2fixes and SharpTimer"); else - SharpTimerError($"Error in DamageHook: {ex.Message}"); + Utils.LogError($"Error in DamageHook: {ex.Message}"); } } - public void DamageUnHook() + public void Unhook() { + Utils.LogDebug("Unhook RemoveDamage"); + try { if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { VirtualFunctions.CBaseEntity_TakeDamageOldFunc.Unhook(OnTakeDamage, HookMode.Pre); } + else + { + Plugin.DeregisterEventHandler(OnPlayerHurt, HookMode.Pre); + } } catch (Exception ex) { if (ex.Message == "Invalid function pointer") - SharpTimerError($"Error in DamageUnHook: Conflict between cs2fixes and SharpTimer"); + Utils.LogError($"Error in DamageUnHook: Conflict between cs2fixes and SharpTimer"); else - SharpTimerError($"Error in DamageUnHook: {ex.Message}"); + Utils.LogError($"Error in DamageUnHook: {ex.Message}"); } } - HookResult OnTakeDamage(DynamicHook h) + private HookResult OnTakeDamage(DynamicHook hook) { - var ent = h.GetParam(0); - var info = h.GetParam(1); - if(disableDamage) h.GetParam(1).Damage = 0; + var ent = hook.GetParam(0); + var info = hook.GetParam(1); + + if (Plugin.disableDamage) hook.GetParam(1).Damage = 0; if (!ent.IsValid || !info.Attacker.IsValid) return HookResult.Continue; @@ -82,16 +99,16 @@ HookResult OnTakeDamage(DynamicHook h) return HookResult.Continue; } - HookResult OnPlayerHurt(EventPlayerHurt @event, GameEventInfo info) + private HookResult OnPlayerHurt(EventPlayerHurt @event, GameEventInfo info) { - if (disableDamage == true) + if (Plugin.disableDamage == true) { var player = @event.Userid; if (!player!.IsValid) return HookResult.Continue; - Vector playerSpeed = player!.PlayerPawn.Value!.AbsVelocity ?? new Vector(0, 0, 0); + Vector playerSpeed = player!.PlayerPawn.Value!.AbsVelocity; player.PlayerPawn.Value.Health = int.MaxValue; player.PlayerPawn.Value.ArmorValue = int.MaxValue; @@ -101,7 +118,7 @@ HookResult OnPlayerHurt(EventPlayerHurt @event, GameEventInfo info) Server.NextFrame(() => { - if (IsAllowedPlayer(player)) AdjustPlayerVelocity(player, playerSpeed.Length(), true); + if (Plugin.IsAllowedPlayer(player)) Plugin.AdjustPlayerVelocity(player, playerSpeed.Length(), true); }); } diff --git a/src/Features/ReplayUtils.cs b/src/Features/ReplayUtils.cs index aede7b86..e85565c8 100644 --- a/src/Features/ReplayUtils.cs +++ b/src/Features/ReplayUtils.cs @@ -13,13 +13,13 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -using System.Runtime.Serialization.Formatters.Binary; using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Utils; using CounterStrikeSharp.API.Modules.Entities.Constants; using System.Text.Json; -using Vector = CounterStrikeSharp.API.Modules.Utils.Vector; +using FixVectorLeak; +using CounterStrikeSharp.API.Modules.Timers; namespace SharpTimer { @@ -32,9 +32,9 @@ private void ReplayUpdate(CCSPlayerController player, int timerTicks) if (!IsAllowedPlayer(player)) return; // Get the player's current position and rotation - ReplayVector currentPosition = ReplayVector.GetVectorish(player.Pawn.Value!.CBodyComponent?.SceneNode?.AbsOrigin ?? new Vector(0, 0, 0)); - ReplayVector currentSpeed = ReplayVector.GetVectorish(player.PlayerPawn.Value!.AbsVelocity ?? new Vector(0, 0, 0)); - ReplayQAngle currentRotation = ReplayQAngle.GetQAngleish(player.PlayerPawn.Value.EyeAngles ?? new QAngle(0, 0, 0)); + ReplayVector currentPosition = ReplayVector.GetVectorish(player.Pawn.Value!.CBodyComponent?.SceneNode?.AbsOrigin ?? new(0, 0, 0)); + ReplayVector currentSpeed = ReplayVector.GetVectorish(player.PlayerPawn.Value!.AbsVelocity); + ReplayQAngle currentRotation = ReplayQAngle.GetQAngleish(player.PlayerPawn.Value.EyeAngles); var buttons = player.Buttons; var flags = player.Pawn.Value.Flags; @@ -54,7 +54,7 @@ private void ReplayUpdate(CCSPlayerController player, int timerTicks) } catch (Exception ex) { - SharpTimerError($"Error in ReplayUpdate: {ex.Message}"); + Utils.LogError($"Error in ReplayUpdate: {ex.Message}"); } } @@ -106,7 +106,7 @@ private void ReplayPlayback(CCSPlayerController player, int plackbackTick) } catch (Exception ex) { - SharpTimerError($"Error in ReplayPlayback: {ex.Message}"); + Utils.LogError($"Error in ReplayPlayback: {ex.Message}"); } } @@ -128,14 +128,13 @@ private void ReplayPlay(CCSPlayerController player) adjustVelocity(player, 0, false); } - if (jumpStatsEnabled) InvalidateJS(player.Slot); ReplayPlayback(player, playerReplays[player.Slot].CurrentPlaybackFrame); playerReplays[player.Slot].CurrentPlaybackFrame++; } catch (Exception ex) { - SharpTimerError($"Error in ReplayPlay: {ex.Message}"); + Utils.LogError($"Error in ReplayPlay: {ex.Message}"); } } @@ -153,7 +152,7 @@ private void OnRecordingStart(CCSPlayerController player, int bonusX = 0, int st } catch (Exception ex) { - SharpTimerError($"Error in OnRecordingStart: {ex.Message}"); + Utils.LogError($"Error in OnRecordingStart: {ex.Message}"); } } @@ -166,25 +165,25 @@ private void OnRecordingStop(CCSPlayerController player) } catch (Exception ex) { - SharpTimerError($"Error in OnRecordingStop: {ex.Message}"); + Utils.LogError($"Error in OnRecordingStop: {ex.Message}"); } } - public async Task DumpReplayToJson(CCSPlayerController player, string steamID, int playerSlot, int bonusX = 0, int style = 0) + public async Task DumpReplayToJson(CCSPlayerController player, string steamID, int slot, int bonusX = 0, int style = 0) { await Task.Run(() => { if (!IsAllowedPlayer(player)) { - SharpTimerError($"Error in DumpReplayToJson: Player not allowed or not on server anymore"); + Utils.LogError($"Error in DumpReplayToJson: Player not allowed or not on server anymore"); return; } string fileName = $"{steamID}_replay.json"; string playerReplaysDirectory; - if(style != 0) playerReplaysDirectory = Path.Join(this.playerReplaysPath, bonusX == 0 ? $"{currentMapName}" : $"{currentMapName}_bonus{bonusX}", GetNamedStyle(style)); - else playerReplaysDirectory = Path.Join(this.playerReplaysPath, bonusX == 0 ? $"{currentMapName}" : $"{currentMapName}_bonus{bonusX}"); - string replayFilePath = Path.Join(playerReplaysDirectory, fileName); + if (style != 0) playerReplaysDirectory = Path.Join(gameDir, "csgo", "cfg", "SharpTimer", "PlayerReplayData", bonusX == 0 ? $"{currentMapName}" : $"{currentMapName}_bonus{bonusX}", GetNamedStyle(style)); + else playerReplaysDirectory = Path.Join(gameDir, "csgo", "cfg", "SharpTimer", "PlayerReplayData", bonusX == 0 ? $"{currentMapName}" : $"{currentMapName}_bonus{bonusX}"); + string playerReplaysPath = Path.Join(playerReplaysDirectory, fileName); try { @@ -193,94 +192,37 @@ await Task.Run(() => Directory.CreateDirectory(playerReplaysDirectory); } - if (playerReplays[playerSlot].replayFrames.Count >= maxReplayFrames) return; + if (playerReplays[slot].replayFrames.Count >= maxReplayFrames) return; - var indexedReplayFrames = playerReplays[playerSlot].replayFrames + var indexedReplayFrames = playerReplays[slot].replayFrames .Select((frame, index) => new IndexedReplayFrames { Index = index, Frame = frame }) .ToList(); - using (Stream stream = new FileStream(replayFilePath, FileMode.Create)) + using (Stream stream = new FileStream(playerReplaysPath, FileMode.Create)) { JsonSerializer.Serialize(stream, indexedReplayFrames); } } catch (Exception ex) { - SharpTimerError($"Error during serialization: {ex.Message}"); + Utils.LogError($"Error during serialization: {ex.Message}"); } }); } - public async Task DumpReplayToBinary(CCSPlayerController player, string steamID, int playerSlot, int bonusX = 0, int style = 0) - { - await Task.Run(() => - { - if (!IsAllowedPlayer(player)) - { - SharpTimerError($"Error in DumpReplayToJson: Player not allowed or not on server anymore"); - return; - } - - string fileName = $"{steamID}_replay.dat"; - string playerReplaysDirectory; - if(style != 0) playerReplaysDirectory = Path.Join(this.playerReplaysPath, bonusX == 0 ? $"{currentMapName}" : $"{currentMapName}_bonus{bonusX}", GetNamedStyle(style)); - else playerReplaysDirectory = Path.Join(this.playerReplaysPath, bonusX == 0 ? $"{currentMapName}" : $"{currentMapName}_bonus{bonusX}"); - string replayFilePath = Path.Join(playerReplaysDirectory, fileName); - - try - { - if (!Directory.Exists(playerReplaysDirectory)) - { - Directory.CreateDirectory(playerReplaysDirectory); - } - - if (playerReplays[playerSlot].replayFrames.Count >= maxReplayFrames) return; - - var indexedReplayFrames = playerReplays[playerSlot].replayFrames - .Select((frame, index) => new IndexedReplayFrames { Index = index, Frame = frame }) - .ToList(); - - using Stream stream = new FileStream(replayFilePath, FileMode.Create); - BinaryWriter writer = new BinaryWriter(stream); - - writer.Write(REPLAY_VERSION); - - foreach (var frame in indexedReplayFrames) - { - writer.Write(frame.Frame.Position!.X); - writer.Write(frame.Frame.Position!.Y); - writer.Write(frame.Frame.Position!.Z); - writer.Write(frame.Frame.Rotation!.Pitch); - writer.Write(frame.Frame.Rotation!.Yaw); - writer.Write(frame.Frame.Rotation!.Roll); - writer.Write(frame.Frame.Speed!.X); - writer.Write(frame.Frame.Speed!.Y); - writer.Write(frame.Frame.Speed!.Z); - writer.Write((int)frame.Frame.Buttons); - writer.Write((int)frame.Frame.Flags); - writer.Write((int)frame.Frame.MoveType); - } - } - catch (Exception ex) - { - SharpTimerError($"Error during serialization: {ex.Message}"); - } - }); - } - - public async Task GetReplayJson(CCSPlayerController player, int playerSlot) + public string GetReplayJson(CCSPlayerController player, int slot) { if (!IsAllowedPlayer(player)) { - SharpTimerError($"Error in GetReplayJson: Player not allowed or not on server anymore"); + Utils.LogError($"Error in GetReplayJson: Player not allowed or not on server anymore"); return ""; } try { - if (playerReplays[playerSlot].replayFrames.Count >= maxReplayFrames) return ""; + if (playerReplays[slot].replayFrames.Count >= maxReplayFrames) return ""; - var indexedReplayFrames = playerReplays[playerSlot].replayFrames + var indexedReplayFrames = playerReplays[slot].replayFrames .Select((frame, index) => new IndexedReplayFrames { Index = index, Frame = frame }) .ToList(); @@ -288,24 +230,22 @@ public async Task GetReplayJson(CCSPlayerController player, int playerSl } catch (Exception ex) { - SharpTimerError($"Error during serialization: {ex.Message}"); + Utils.LogError($"Error during serialization: {ex.Message}"); return ""; } } - private async Task ReadReplayFromJson(CCSPlayerController player, string steamId, int playerSlot, int bonusX = 0, int style = 0) + private async Task ReadReplayFromJson(CCSPlayerController player, string steamId, int slot, int bonusX = 0, int style = 0) { - SharpTimerDebug($"Reading replay from JSON"); string fileName = $"{steamId}_replay.json"; string playerReplaysPath; - if(style != 0) playerReplaysPath = Path.Join(this.playerReplaysPath, bonusX == 0 ? currentMapName : $"{currentMapName}_bonus{bonusX}", GetNamedStyle(style), fileName); - else playerReplaysPath = Path.Join(this.playerReplaysPath, bonusX == 0 ? currentMapName : $"{currentMapName}_bonus{bonusX}", fileName); + if (style != 0) playerReplaysPath = Path.Join(gameDir, "csgo", "cfg", "SharpTimer", "PlayerReplayData", bonusX == 0 ? currentMapName : $"{currentMapName}_bonus{bonusX}", GetNamedStyle(style), fileName); + else playerReplaysPath = Path.Join(gameDir, "csgo", "cfg", "SharpTimer", "PlayerReplayData", bonusX == 0 ? currentMapName : $"{currentMapName}_bonus{bonusX}", fileName); try { if (File.Exists(playerReplaysPath)) { - SharpTimerDebug($"Path: {playerReplaysPath}, creating stream"); var jsonString = await File.ReadAllTextAsync(playerReplaysPath); if (!jsonString.Contains("PositionString")) { @@ -318,10 +258,10 @@ private async Task ReadReplayFromJson(CCSPlayerController player, string steamId .Select(frame => frame.Frame) .ToList(); - if (!playerReplays.TryGetValue(playerSlot, out PlayerReplays? value)) + if (!playerReplays.TryGetValue(slot, out PlayerReplays? value)) { value = new PlayerReplays(); - playerReplays[playerSlot] = value; + playerReplays[slot] = value; } value.replayFrames = replayFrames!; @@ -329,88 +269,18 @@ private async Task ReadReplayFromJson(CCSPlayerController player, string steamId } else { - Server.NextFrame(() => { PrintToChat(player, $"Unsupported replay format"); }); + Server.NextFrame(() => { Utils.PrintToChat(player, $"Unsupported replay format"); }); } } else { - SharpTimerError($"File does not exist: {playerReplaysPath}"); - Server.NextFrame(() => PrintToChat(player, Localizer["replay_dont_exist"])); - } - } - catch (Exception ex) - { - SharpTimerError($"Error during deserialization: {ex.Message}"); - SharpTimerError($"Error during deserialization: {ex.StackTrace}"); - } - } - - private async Task ReadReplayFromBinary(CCSPlayerController player, string steamId, int playerSlot, int bonusX = 0, int style = 0) - { - SharpTimerDebug($"Reading replay from Binary"); - string fileName = $"{steamId}_replay.dat"; - string playerReplaysPath; - if(style != 0) playerReplaysPath = Path.Join(this.playerReplaysPath, bonusX == 0 ? currentMapName : $"{currentMapName}_bonus{bonusX}", GetNamedStyle(style), fileName); - else playerReplaysPath = Path.Join(this.playerReplaysPath, bonusX == 0 ? currentMapName : $"{currentMapName}_bonus{bonusX}", fileName); - - try - { - if (!File.Exists(playerReplaysPath)) - { - SharpTimerError($"File does not exist: {playerReplaysPath}"); - Server.NextFrame(() => PrintToChat(player, Localizer["replay_dont_exist"])); - return; - } - - SharpTimerDebug($"Path: {playerReplaysPath}, creating stream"); - - using Stream stream = new FileStream(playerReplaysPath, FileMode.Open); - BinaryReader reader = new BinaryReader(stream); - - var version = reader.ReadInt32(); - if (version != REPLAY_VERSION) - { - SharpTimerError($"Unsupported replay version: {version}"); - Server.NextFrame(() => PrintToChat(player, $"Unsupported replay version: {version}")); - return; + Utils.LogError($"File does not exist: {playerReplaysPath}"); + Server.NextFrame(() => Utils.PrintToChat(player, Localizer["replay_dont_exist"])); } - - var replayFrames = new List(); - - await Server.NextFrameAsync(() => { - while (reader.BaseStream.Position != reader.BaseStream.Length) - { - var position = new Vector(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); - var rotation = new QAngle(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); - var speed = new Vector(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); - var buttons = (PlayerButtons)reader.ReadInt32(); - var flags = (uint)reader.ReadInt32(); - var moveType = (MoveType_t)reader.ReadInt32(); - - replayFrames.Add(new PlayerReplays.ReplayFrames - { - Position = ReplayVector.GetVectorish(position), - Rotation = ReplayQAngle.GetQAngleish(rotation), - Speed = ReplayVector.GetVectorish(speed), - Buttons = buttons, - Flags = flags, - MoveType = moveType - }); - } - }); - - if (!playerReplays.TryGetValue(playerSlot, out PlayerReplays? value)) - { - value = new PlayerReplays(); - playerReplays[playerSlot] = value; - } - - value.replayFrames = replayFrames; } catch (Exception ex) { - SharpTimerError($"Error during deserialization: {ex.Message}"); - SharpTimerError($"Error during deserialization: {ex.StackTrace}"); + Utils.LogError($"Error during deserialization: {ex.Message}"); } } @@ -448,104 +318,88 @@ private async Task ReadReplayFromGlobal(CCSPlayerController player, int recordId } catch (Exception ex) { - SharpTimerError($"Error during deserialization: {ex.Message}"); + Utils.LogError($"Error during deserialization: {ex.Message}"); } } private async Task SpawnReplayBot() { - try + if (!await CheckSRReplay()) { - if (await CheckSRReplay() != true) return; + Utils.LogError("Replay check failed, not spawning bot."); + return; + } - Server.NextFrame(() => + Server.NextFrame(() => + { + AddTimer(3.0f, () => { - startKickingAllFuckingBotsExceptReplayOneIFuckingHateValveDogshitFuckingCompanySmile = false; - foreach (CCSPlayerController bot in connectedReplayBots.Values.ToList()) - { - if (bot != null) - { - OnPlayerDisconnect(bot, true); - if (connectedReplayBots.TryGetValue(bot.Slot, out var someValue)) connectedReplayBots.Remove(bot.Slot); - } - } - Server.ExecuteCommand("sv_cheats 1"); - Server.ExecuteCommand("bot_add_ct"); - Server.ExecuteCommand("bot_quota 1"); - Server.ExecuteCommand("bot_quota_mode 0"); - Server.ExecuteCommand("bot_stop 1"); - Server.ExecuteCommand("bot_freeze 1"); - Server.ExecuteCommand("bot_zombie 1"); + Server.ExecuteCommand("bot_quota_mode normal"); + Server.ExecuteCommand("bot_quota 0"); Server.ExecuteCommand("bot_chatter off"); - Server.ExecuteCommand("sv_cheats 0"); + Server.ExecuteCommand("bot_controllable 0"); + Server.ExecuteCommand("bot_kick"); + replayBotController = null; AddTimer(3.0f, () => { - foundReplayBot = false; - SharpTimerDebug($"Trying to find replay bot!"); - var playerEntities = Utilities.FindAllEntitiesByDesignerName("cs_player_controller"); - foreach (var tempPlayer in playerEntities) + // wtf is this game even + Server.ExecuteCommand("bot_quota 1"); + Server.ExecuteCommand("bot_add_ct"); + Server.ExecuteCommand("bot_quota 1"); + + Utils.LogDebug("Searching for replay bot..."); + + AddTimer(0.0f, () => { - if (tempPlayer == null || !tempPlayer.IsValid || !tempPlayer.IsBot || tempPlayer.IsHLTV) - continue; - if (tempPlayer.UserId.HasValue) + // find and setup bot + var bot = Utilities.GetPlayers().Where(b => b.IsBot && !b.IsHLTV).FirstOrDefault(); + if (bot != null) { - if (foundReplayBot == true) - { - OnPlayerDisconnect(tempPlayer, true); - Server.ExecuteCommand($"kickid {tempPlayer.Slot}"); - SharpTimerDebug($"Kicking unused replay bot!"); - } - else - { - SharpTimerDebug($"Found replay bot!"); - OnReplayBotConnect(tempPlayer); - tempPlayer.PlayerPawn.Value!.Bot!.IsSleeping = true; - tempPlayer.PlayerPawn.Value!.Bot!.AllowActive = true; - tempPlayer.RemoveWeapons(); - tempPlayer!.Pawn.Value!.Collision.CollisionAttribute.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_DISSOLVING; - tempPlayer!.Pawn.Value!.Collision.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_DISSOLVING; - Utilities.SetStateChanged(tempPlayer, "CCollisionProperty", "m_CollisionGroup"); - Utilities.SetStateChanged(tempPlayer, "CCollisionProperty", "m_collisionAttribute"); - SharpTimerDebug($"Removed Collison for replay bot!"); - foundReplayBot = true; - startKickingAllFuckingBotsExceptReplayOneIFuckingHateValveDogshitFuckingCompanySmile = true; - } + replayBotController = bot; + Utils.LogDebug($"Found replay bot: {bot.PlayerName}"); + + var botPawn = bot.PlayerPawn.Value; + if (botPawn == null) return; + + // bot settings + bot.RemoveWeapons(); + botPawn.Bot!.IsStopping = true; + botPawn.Bot.IsSleeping = true; + botPawn.Bot.AllowActive = true; + botPawn.Collision.CollisionAttribute.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_DISSOLVING; + botPawn.Collision.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_DISSOLVING; + Utilities.SetStateChanged(bot, "CCollisionProperty", "m_CollisionGroup"); + Utilities.SetStateChanged(bot, "CCollisionProperty", "m_collisionAttribute"); + Utils.LogDebug($"Configured replay bot collision and weapons for {bot.PlayerName}"); + + // start bot replay + OnPlayerConnect(bot, true); + ChangePlayerName(bot, replayBotName); + playerTimers[bot.Slot].IsTimerBlocked = true; + _ = Task.Run(async () => await ReplayHandler(bot, bot.Slot)); + Utils.LogDebug($"Starting replay for {bot.PlayerName}"); + } + else + { + Utils.LogError($"Failed to spawn replay bot"); + return; } - } - }); - }); - } - catch (Exception ex) - { - SharpTimerError($"Error in SpawnReplayBot: {ex.Message}"); - } - } - - private void OnReplayBotConnect(CCSPlayerController bot) - { - try - { - var botSlot = bot.Slot; - var botName = bot.PlayerName; - - if(bot.IsHLTV) - return; - AddTimer(3.0f, () => - { - OnPlayerConnect(bot, true); - connectedReplayBots[botSlot] = new CCSPlayerController(bot.Handle); - ChangePlayerName(bot, replayBotName); - playerTimers[botSlot].IsTimerBlocked = true; - _ = Task.Run(async () => await ReplayHandler(bot, botSlot)); - SharpTimerDebug($"Starting replay for {botName}"); - }); - } - catch (Exception ex) - { - SharpTimerError($"Error in OnReplayBotConnect: {ex.Message}"); - } + // kick unused bots if there are any + var bots = Utilities.GetPlayers().Where(b => b.IsBot && !b.IsHLTV && b != replayBotController); + foreach (var kicked in bots) + { + OnPlayerDisconnect(kicked, true); + Server.ExecuteCommand("bot_quota 1"); + Server.ExecuteCommand($"kickid {kicked.UserId}"); + Server.ExecuteCommand("bot_quota 1"); + Utils.LogDebug($"Kicking unused bot on spawn... {kicked.PlayerName}"); + } + }); + }, TimerFlags.STOP_ON_MAPCHANGE); + }, TimerFlags.STOP_ON_MAPCHANGE); + }); } public async Task CheckSRReplay(string topSteamID = "x", int bonusX = 0, int style = 0) @@ -563,21 +417,15 @@ public async Task CheckSRReplay(string topSteamID = "x", int bonusX = 0, i if ((srSteamID == "null" || srPlayerName == "null" || srTime == "null") && topSteamID != "x") return false; - string ext = useBinaryReplays ? "dat" : "json"; - string fileName = $"{(topSteamID == "x" ? $"{srSteamID}" : $"{topSteamID}")}_replay.{ext}"; + string fileName = $"{(topSteamID == "x" ? $"{srSteamID}" : $"{topSteamID}")}_replay.json"; string playerReplaysPath; - if(style != 0) playerReplaysPath = Path.Join(this.playerReplaysPath, (bonusX == 0 ? currentMapName : $"{currentMapName}_bonus{bonusX}"), GetNamedStyle(style), fileName); - else playerReplaysPath = Path.Join(this.playerReplaysPath, (bonusX == 0 ? currentMapName : $"{currentMapName}_bonus{bonusX}"), fileName); + if (style != 0) playerReplaysPath = Path.Join(gameDir, "csgo", "cfg", "SharpTimer", "PlayerReplayData", (bonusX == 0 ? currentMapName : $"{currentMapName}_bonus{bonusX}"), GetNamedStyle(style), fileName); + else playerReplaysPath = Path.Join(gameDir, "csgo", "cfg", "SharpTimer", "PlayerReplayData", (bonusX == 0 ? currentMapName : $"{currentMapName}_bonus{bonusX}"), fileName); try { - if (File.Exists(playerReplaysPath)) { - if (useBinaryReplays) { - var reader = new BinaryReader(File.Open(playerReplaysPath, FileMode.Open)); - var version = reader.ReadInt32(); - - return version == REPLAY_VERSION; - } + if (File.Exists(playerReplaysPath)) + { var jsonString = await File.ReadAllTextAsync(playerReplaysPath); if (!jsonString.Contains("PositionString")) { diff --git a/src/Features/Styles.cs b/src/Features/Styles.cs index 9f93a421..5dd872c6 100644 --- a/src/Features/Styles.cs +++ b/src/Features/Styles.cs @@ -1,5 +1,5 @@ using CounterStrikeSharp.API.Core; -using Vector = CounterStrikeSharp.API.Modules.Utils.Vector; +using FixVectorLeak; namespace SharpTimer { @@ -138,7 +138,7 @@ public void SetTAS(CCSPlayerController player) playerTimers[player.Slot].changedStyle = true; } - public void SetVelocity(CCSPlayerController player, Vector currentVel, int desiredVel) + public void SetVelocity(CCSPlayerController player, Vector_t currentVel, int desiredVel) { if(currentVel.X > desiredVel) player!.PlayerPawn.Value!.AbsVelocity.X = desiredVel; if(currentVel.X < -desiredVel) player!.PlayerPawn.Value!.AbsVelocity.X = -desiredVel; diff --git a/src/Player/PlayerChecks.cs b/src/Player/PlayerChecks.cs index dc116b0f..da9ccf17 100644 --- a/src/Player/PlayerChecks.cs +++ b/src/Player/PlayerChecks.cs @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License using System.Text.Json; using CounterStrikeSharp.API.Core; -using CounterStrikeSharp.API.Modules.Utils; +using FixVectorLeak; namespace SharpTimer { @@ -23,50 +23,44 @@ public partial class SharpTimer { public bool IsAllowedPlayer(CCSPlayerController? player) { - if (player == null || !player.IsValid || player.Pawn == null || !player.PlayerPawn.IsValid || !player.PawnIsAlive || playerTimers[player.Slot].IsNoclip) - { + if (player == null) return false; - } - int playerSlot = player.Slot; + if (playerTimers.TryGetValue(player.Slot, out var playTimer)) + { + if (playTimer.IsNoclip) + return false; + } - CsTeam teamNum = (CsTeam)player.TeamNum; + bool isConnected = connectedPlayers.ContainsKey(player.Slot) && playerTimers.ContainsKey(player.Slot); bool isAlive = player.PawnIsAlive; - bool isTeamValid = teamNum == CsTeam.CounterTerrorist || teamNum == CsTeam.Terrorist; + bool isTeamValid = player.TeamCT() || player.TeamT(); - bool isTeamSpectatorOrNone = teamNum != CsTeam.Spectator && teamNum != CsTeam.None; - bool isConnected = connectedPlayers.ContainsKey(playerSlot) && playerTimers.ContainsKey(playerSlot); - bool isConnectedJS = !jumpStatsEnabled || playerJumpStats.ContainsKey(playerSlot); - - return isTeamValid && isTeamSpectatorOrNone && isConnected && isConnectedJS && isAlive; + return isConnected && isAlive && isTeamValid; } private bool IsAllowedSpectator(CCSPlayerController? player) { - if (player == null || !player.IsValid || player.IsBot) - { + if (player == null) return false; - } - CsTeam teamNum = (CsTeam)player.TeamNum; - bool isTeamValid = teamNum == CsTeam.Spectator; bool isConnected = connectedPlayers.ContainsKey(player.Slot) && playerTimers.ContainsKey(player.Slot); bool isObservingValid = player.Pawn?.Value!.ObserverServices?.ObserverTarget != null && - specTargets.ContainsKey(player.Pawn.Value.ObserverServices.ObserverTarget.Index); + specTargets.ContainsKey(player.Pawn.Value.ObserverServices.ObserverTarget.Index); - return isTeamValid && isConnected && isObservingValid; + return isConnected && isObservingValid; } - public bool IsAllowedClient(CCSPlayerController? player) + public bool IsPlayerOrSpectator(CCSPlayerController? player) { - if (player == null || !player.IsValid || player.Pawn == null || !player.PlayerPawn.IsValid) + if (player == null) return false; - return true; + return IsAllowedPlayer(player) || IsAllowedSpectator(player); } - async Task IsPlayerATester(string steamId64, int playerSlot) + async Task IsPlayerATester(string steamId64, int slot) { try { @@ -74,7 +68,7 @@ async Task IsPlayerATester(string steamId64, int playerSlot) using (JsonDocument jsonDocument = JsonDocument.Parse(response)) { - if (playerTimers.TryGetValue(playerSlot, out PlayerTimerInfo? playerTimer)) + if (playerTimers.TryGetValue(slot, out PlayerTimerInfo? playerTimer)) { playerTimer.IsTester = jsonDocument.RootElement.TryGetProperty(steamId64, out JsonElement steamData); @@ -93,13 +87,13 @@ async Task IsPlayerATester(string steamId64, int playerSlot) } else { - SharpTimerError($"Error in IsPlayerATester: player not on server anymore"); + Utils.LogError($"Error in IsPlayerATester: player not on server anymore"); } } } catch (Exception ex) { - SharpTimerError($"Error in IsPlayerATester: {ex.Message}"); + Utils.LogError($"Error in IsPlayerATester: {ex.Message}"); } } @@ -121,7 +115,7 @@ async Task GetTesterBigGif(string steamId64) } catch (Exception ex) { - SharpTimerError($"Error in GetTesterBigGif: {ex.Message}"); + Utils.LogError($"Error in GetTesterBigGif: {ex.Message}"); return ""; } } @@ -144,7 +138,7 @@ async Task GetTesterSmolGif(string steamId64) } catch (Exception ex) { - SharpTimerError($"Error in GetTesterSmolGif: {ex.Message}"); + Utils.LogError($"Error in GetTesterSmolGif: {ex.Message}"); return ""; } } @@ -165,12 +159,13 @@ async Task IsSteamIDaTester(string steamId64) } catch (Exception ex) { - SharpTimerError($"Error in IsSteamIDaTester: {ex.Message}"); + Utils.LogError($"Error in IsSteamIDaTester: {ex.Message}"); return false; } } - private void CheckPlayerCoords(CCSPlayerController? player, Vector playerSpeed) + + private void CheckPlayerCoords(CCSPlayerController? player, Vector_t playerSpeed) { try { @@ -179,20 +174,20 @@ private void CheckPlayerCoords(CCSPlayerController? player, Vector playerSpeed) return; } - Vector incorrectVector = new(0, 0, 0); - Vector? playerPos = player.Pawn?.Value!.CBodyComponent?.SceneNode!.AbsOrigin; + Vector_t incorrectVector = new(0, 0, 0); + Vector_t playerPos = player.Pawn?.Value!.CBodyComponent?.SceneNode!.AbsOrigin.ToVector_t() ?? new(); bool isInsideStartBox = false; bool isInsideEndBox = false; - if (playerPos == null || currentMapStartC1 == incorrectVector || currentMapStartC2 == incorrectVector || - currentMapEndC1 == incorrectVector || currentMapEndC2 == incorrectVector) + if (playerPos.Equals(incorrectVector) || currentMapStartC1.Equals(incorrectVector) || currentMapStartC2.Equals(incorrectVector) || + currentMapEndC1.Equals(incorrectVector) || currentMapEndC2.Equals(incorrectVector)) { return; } if (!useTriggersAndFakeZones) { - isInsideStartBox = IsVectorInsideBox(playerPos, currentMapStartC1, currentMapStartC2); - isInsideEndBox = IsVectorInsideBox(playerPos, currentMapEndC1, currentMapEndC2); + isInsideStartBox = Utils.IsVectorInsideBox(playerPos, currentMapStartC1, currentMapStartC2); + isInsideEndBox = Utils.IsVectorInsideBox(playerPos, currentMapEndC1, currentMapEndC2); } bool[] isInsideBonusStartBox = new bool[11]; bool[] isInsideBonusEndBox = new bool[11]; @@ -209,13 +204,13 @@ private void CheckPlayerCoords(CCSPlayerController? player, Vector playerSpeed) currentBonusEndC1 == null || currentBonusEndC1.Length <= bonus || currentBonusEndC2 == null || currentBonusEndC2.Length <= bonus) { - SharpTimerError($"Invalid bonus coordinates for bonus {bonus}"); + Utils.LogError($"Invalid bonus coordinates for bonus {bonus}"); } else { - isInsideBonusStartBox[bonus] = IsVectorInsideBox(playerPos, currentBonusStartC1[bonus], currentBonusStartC2[bonus]); - isInsideBonusEndBox[bonus] = IsVectorInsideBox(playerPos, currentBonusEndC1[bonus], currentBonusEndC2[bonus]); + isInsideBonusStartBox[bonus] = Utils.IsVectorInsideBox(playerPos, currentBonusStartC1[bonus], currentBonusStartC2[bonus]); + isInsideBonusEndBox[bonus] = Utils.IsVectorInsideBox(playerPos, currentBonusEndC1[bonus], currentBonusEndC2[bonus]); } } } @@ -229,7 +224,7 @@ private void CheckPlayerCoords(CCSPlayerController? player, Vector playerSpeed) } else if (isInsideStartBox) { - if(playerTimers.TryGetValue(player.Slot, out PlayerTimerInfo? playerTimer)) + if (playerTimers.TryGetValue(player.Slot, out PlayerTimerInfo? playerTimer)) { playerTimer.inStartzone = true; InvalidateTimer(player); @@ -265,7 +260,7 @@ private void CheckPlayerCoords(CCSPlayerController? player, Vector playerSpeed) currentBonusEndC1 == null || currentBonusEndC1.Length <= bonus || currentBonusEndC2 == null || currentBonusEndC2.Length <= bonus) { - SharpTimerError($"Invalid bonus coordinates for bonus {bonus}"); + Utils.LogError($"Invalid bonus coordinates for bonus {bonus}"); } else @@ -277,7 +272,7 @@ private void CheckPlayerCoords(CCSPlayerController? player, Vector playerSpeed) } else if (isInsideBonusStartBox[bonus]) { - if(playerTimers.TryGetValue(player.Slot, out PlayerTimerInfo? playerTimer)) + if (playerTimers.TryGetValue(player.Slot, out PlayerTimerInfo? playerTimer)) { playerTimer.inStartzone = true; } @@ -294,11 +289,11 @@ private void CheckPlayerCoords(CCSPlayerController? player, Vector playerSpeed) } else if (!isInsideBonusStartBox[bonus]) { - if(playerTimers.TryGetValue(player.Slot, out PlayerTimerInfo? playerTimer)) + if (playerTimers.TryGetValue(player.Slot, out PlayerTimerInfo? playerTimer)) { playerTimer.inStartzone = false; } - + } } } @@ -307,16 +302,25 @@ private void CheckPlayerCoords(CCSPlayerController? player, Vector playerSpeed) } catch (Exception ex) { - SharpTimerError($"Error in CheckPlayerCoords: {ex.Message}"); + Utils.LogError($"Error in CheckPlayerCoords: {ex.Message}"); } } - public bool CommandCooldown(CCSPlayerController? player) + public bool CommandCooldown(CCSPlayerController player) { - if (playerTimers[player!.Slot].TicksSinceLastCmd < cmdCooldown) + if (playerTimers.TryGetValue(player.Slot, out var playerTimer)) { - PrintToChat(player, Localizer["command_cooldown"]); - return true; + double secondsRemaining = (playerTimer.CmdCooldown - DateTime.Now).TotalSeconds; + if (secondsRemaining > 0) + { + Utils.PrintToChat(player, Localizer["command_cooldown", secondsRemaining]); + return true; + } + else + { + playerTimer.CmdCooldown = DateTime.Now.AddSeconds(cmdCooldown); + return false; + } } return false; } @@ -325,7 +329,7 @@ public bool IsTimerBlocked(CCSPlayerController? player) { if (!playerTimers[player!.Slot].IsTimerBlocked) { - PrintToChat(player, Localizer["stop_using_timer"]); + Utils.PrintToChat(player, Localizer["stop_using_timer"]); return true; } return false; @@ -335,7 +339,7 @@ public bool ReplayCheck(CCSPlayerController? player) { if (playerTimers[player!.Slot].IsReplaying) { - PrintToChat(player, Localizer["end_your_replay"]); + Utils.PrintToChat(player, Localizer["end_your_replay"]); return true; } return false; @@ -347,7 +351,7 @@ public bool CanCheckpoint(CCSPlayerController? player) { if (playerTimers[player.Slot].currentStyle == 12) return true; - PrintToChat(player, Localizer["cant_use_checkpoint", (currentMapName!.Contains("surf_") ? "loc" : "checkpoint")]); + Utils.PrintToChat(player, Localizer["cant_use_checkpoint", (currentMapName!.Contains("surf_") ? "loc" : "checkpoint")]); PlaySound(player, cpSoundError); return false; } diff --git a/src/Player/PlayerEvents.cs b/src/Player/PlayerEvents.cs index ca8a68f9..92727984 100644 --- a/src/Player/PlayerEvents.cs +++ b/src/Player/PlayerEvents.cs @@ -13,13 +13,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -using System.Drawing; using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Admin; -using CounterStrikeSharp.API.Modules.Commands; -using CounterStrikeSharp.API.Modules.Utils; -using CounterStrikeSharp.API.Modules.Cvars; namespace SharpTimer { @@ -31,121 +27,98 @@ private void OnPlayerConnect(CCSPlayerController? player, bool isForBot = false) { if (player == null) { - SharpTimerError("Player object is null."); + Utils.LogError("Player object is null."); return; } if (player.PlayerPawn == null) { - SharpTimerError("PlayerPawn is null."); + Utils.LogError("PlayerPawn is null."); return; } if (player.PlayerPawn.Value!.MovementServices == null) { - SharpTimerError("MovementServices is null."); + Utils.LogError("MovementServices is null."); return; } - int playerSlot = player.Slot; - string steamID = player.SteamID.ToString(); + int slot = player.Slot; string playerName = player.PlayerName; try { - connectedPlayers[playerSlot] = new CCSPlayerController(player.Handle); - playerTimers[playerSlot] = new PlayerTimerInfo(); - playerJumpStats[playerSlot] = new PlayerJumpStats(); - if (enableReplays) playerReplays[playerSlot] = new PlayerReplays(); - playerTimers[playerSlot].MovementService = new CCSPlayer_MovementServices(player.PlayerPawn.Value.MovementServices!.Handle); - playerTimers[playerSlot].StageTimes = new Dictionary(); - playerTimers[playerSlot].StageVelos = new Dictionary(); - if (AdminManager.PlayerHasPermissions(player, "@css/root")) playerTimers[playerSlot].ZoneToolWire = new Dictionary(); - playerTimers[playerSlot].CurrentMapStage = 0; - playerTimers[playerSlot].CurrentMapCheckpoint = 0; - SetNormalStyle(player); - playerTimers[playerSlot].IsRecordingReplay = false; - playerTimers[playerSlot].SetRespawnPos = null; - playerTimers[playerSlot].SetRespawnAng = null; - playerTimers[playerSlot].SoundsEnabled = soundsEnabledByDefault; - - if (isForBot == false) _ = Task.Run(async () => await IsPlayerATester(steamID, playerSlot)); - - //PlayerSettings - if (enableDb) _ = Task.Run(async () => await GetPlayerStats(player, steamID, playerName, playerSlot, true)); - - if (connectMsgEnabled == true && !enableDb) PrintToChatAll(Localizer["connect_message", player.PlayerName]); - if (cmdJoinMsgEnabled == true && isForBot == false) PrintAllEnabledCommands(player); - - SharpTimerDebug($"Added player {player.PlayerName} with UserID {player.UserId} to connectedPlayers"); - SharpTimerDebug($"Total players connected: {connectedPlayers.Count}"); - SharpTimerDebug($"Total playerTimers: {playerTimers.Count}"); - SharpTimerDebug($"Total playerReplays: {playerReplays.Count}"); - - if (removeLegsEnabled == true) + connectedPlayers[slot] = new CCSPlayerController(player.Handle); + playerTimers[slot] = new PlayerTimerInfo(); + + if (playerTimers.TryGetValue(slot, out var playerTime)) { - player.PlayerPawn.Value.Render = Color.FromArgb(254, 254, 254, 254); - Utilities.SetStateChanged(player.PlayerPawn.Value, "CBaseModelEntity", "m_clrRender"); + if (enableReplays) + playerReplays[slot] = new PlayerReplays(); + + if (AdminManager.PlayerHasPermissions(player, "@css/root")) + playerTime.ZoneToolWire = new Dictionary(); + + playerTime.MovementService = new CCSPlayer_MovementServices(player.PlayerPawn.Value.MovementServices!.Handle); + playerTime.StageTimes = new Dictionary(); + playerTime.StageVelos = new Dictionary(); + playerTime.CurrentMapStage = 0; + playerTime.CurrentMapCheckpoint = 0; + playerTime.IsRecordingReplay = false; + playerTime.SetRespawnPos = null; + playerTime.SetRespawnAng = null; + playerTime.SoundsEnabled = soundsEnabledByDefault; + + SetNormalStyle(player); + } + + if (isForBot == false) + { + string steamID = player.SteamID.ToString(); + + _ = Task.Run(async () => await IsPlayerATester(steamID, slot)); + + if (enableDb) + _ = Task.Run(async () => await GetPlayerStats(player, steamID, playerName, slot, true)); + + if (cmdJoinMsgEnabled == true) + PrintAllEnabledCommands(player); + + if (connectMsgEnabled == true && !enableDb) + Utils.PrintToChatAll(Localizer["connect_message", player.PlayerName]); } + + Utils.LogDebug($"Added player {player.PlayerName} with UserID {player.UserId} to connectedPlayers"); + Utils.LogDebug($"Total players connected: {connectedPlayers.Count}"); + Utils.LogDebug($"Total playerTimers: {playerTimers.Count}"); + Utils.LogDebug($"Total playerReplays: {playerReplays.Count}"); } finally { - if (connectedPlayers[playerSlot] == null) - { - connectedPlayers.Remove(playerSlot); - } + if (connectedPlayers[slot] == null) + connectedPlayers.Remove(slot); - if (playerTimers[playerSlot] == null) + if (playerTimers[slot] == null) { - playerTimers.Remove(playerSlot); + playerTimers.Remove(slot); } } } catch (Exception ex) { - SharpTimerError($"Error in OnPlayerConnect: {ex.Message}"); + Utils.LogError($"Error in OnPlayerConnect: {ex.Message}"); } } - private void OnPlayerSpawn(CCSPlayerController? player) - { - //just.. dont ask. - AddTimer(0f, () => - { - if (spawnOnRespawnPos == true && currentRespawnPos != null) - player!.PlayerPawn.Value!.Teleport(currentRespawnPos!, null, null); - }); - - if (enableReplays && enableSRreplayBot && connectedReplayBots.Count == 0) - { - AddTimer(5.0f, () => - { - if (ConVar.Find("mp_force_pick_time")!.GetPrimitiveValue() == 1.0 && ConVar.Find("mp_humanteam")!.StringValue == "ct") - _ = Task.Run(async () => await SpawnReplayBot()); - else - { - SharpTimerError("Couldnt Spawn Replay bot! Please make sure you have the following in your custom_exec.cfg\n" - + "mp_force_pick_time 1\n" - + "mp_humanteam ct\n"); - } - }); - } - } - private void OnPlayerDisconnect(CCSPlayerController? player, bool isForBot = false) { if (player == null) return; try { - if (isForBot == true && connectedReplayBots.TryGetValue(player.Slot, out var connectedReplayBot)) - { - connectedReplayBots.Remove(player.Slot); - SharpTimerDebug($"Removed bot {connectedReplayBot.PlayerName} with UserID {connectedReplayBot.UserId} from connectedReplayBots."); - } if (connectedPlayers.TryGetValue(player.Slot, out var connectedPlayer)) { - + connectedPlayers.Remove(player.Slot); //schizo removing data from memory @@ -156,13 +129,6 @@ private void OnPlayerDisconnect(CCSPlayerController? player, bool isForBot = fal playerCheckpoints[player.Slot] = new List(); playerCheckpoints.Remove(player.Slot); - //schizo removing replay bots after last dc - AddTimer(5.0f, () => - { - if(Utilities.GetPlayers().Count == 0) - connectedReplayBots = []; - }); - specTargets.Remove(player.Pawn.Value!.EntityHandle.Index); if (enableReplays) @@ -172,61 +138,22 @@ private void OnPlayerDisconnect(CCSPlayerController? player, bool isForBot = fal playerReplays.Remove(player.Slot); } - SharpTimerDebug($"Removed player {connectedPlayer.PlayerName} with UserID {connectedPlayer.UserId} from connectedPlayers."); - SharpTimerDebug($"Removed specTarget index {player.Pawn.Value.EntityHandle.Index} from specTargets."); - SharpTimerDebug($"Total players connected: {connectedPlayers.Count}"); - SharpTimerDebug($"Total playerTimers: {playerTimers.Count}"); - SharpTimerDebug($"Total specTargets: {specTargets.Count}"); + Utils.LogDebug($"Removed player {connectedPlayer.PlayerName} with UserID {connectedPlayer.UserId} from connectedPlayers."); + Utils.LogDebug($"Removed specTarget index {player.Pawn.Value.EntityHandle.Index} from specTargets."); + Utils.LogDebug($"Total players connected: {connectedPlayers.Count}"); + Utils.LogDebug($"Total playerTimers: {playerTimers.Count}"); + Utils.LogDebug($"Total specTargets: {specTargets.Count}"); if (connectMsgEnabled == true && isForBot == false) { - PrintToChatAll(Localizer["disconnect_message", connectedPlayer.PlayerName]); + Utils.PrintToChatAll(Localizer["disconnect_message", connectedPlayer.PlayerName]); } } } catch (Exception ex) { - SharpTimerError($"Error in OnPlayerDisconnect (probably replay bot related lolxd): {ex.Message}"); - } - } - - private HookResult OnPlayerChat(CCSPlayerController? player, CommandInfo message) - { - if (displayChatTags == false) - return HookResult.Continue; - - string msg; - - if (player == null || !player.IsValid || player.IsBot || string.IsNullOrEmpty(message.GetArg(1))) - return HookResult.Handled; - else - msg = message.GetArg(1); - - playerTimers[player.Slot].AFKTicks = 0; - - if (msg.Length > 0 && (msg[0] == '!' || msg[0] == '/' || msg[0] == '.')) - return HookResult.Continue; - else - { - string rankColor = GetRankColorForChat(player); - - if (playerTimers.TryGetValue(player.Slot, out PlayerTimerInfo? value)) - { - string deadText = player.PawnIsAlive ? "" : $"{ChatColors.Grey}*DEAD* "; - string vipText = (value.IsVip ? $"{ChatColors.Magenta}{customVIPTag} " : ""); - if (player.Team == CsTeam.Terrorist) - Server.PrintToChatAll($" {deadText}{vipText}{rankColor}{value.CachedRank} {ChatColors.ForTeam(CsTeam.Terrorist)}{player.PlayerName} {ChatColors.Default}: {msg}"); - if (player.Team == CsTeam.CounterTerrorist) - Server.PrintToChatAll($" {deadText}{vipText}{rankColor}{value.CachedRank} {ChatColors.ForTeam(CsTeam.CounterTerrorist)}{player.PlayerName} {ChatColors.Default}: {msg}"); - if (player.Team == CsTeam.Spectator) - Server.PrintToChatAll($" {ChatColors.Grey}*SPEC* {ChatColors.ForTeam(CsTeam.Spectator)}{player.PlayerName} {ChatColors.Default}: {msg}"); - if (player.Team == CsTeam.None) - Server.PrintToChatAll($" {ChatColors.ForTeam(CsTeam.None)}{player.PlayerName} {ChatColors.Default}: {msg}"); - } - - return HookResult.Handled; + Utils.LogError($"Error in OnPlayerDisconnect (probably replay bot related lolxd): {ex.Message}"); } - } } } \ No newline at end of file diff --git a/src/Player/PlayerOnTick.cs b/src/Player/PlayerOnTick.cs index 3dd7bf3c..3c9ea48f 100644 --- a/src/Player/PlayerOnTick.cs +++ b/src/Player/PlayerOnTick.cs @@ -17,6 +17,7 @@ You should have received a copy of the GNU General Public License using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Entities.Constants; using CounterStrikeSharp.API.Modules.Utils; +using FixVectorLeak; namespace SharpTimer { @@ -25,90 +26,100 @@ public partial class SharpTimer public void PlayerOnTick() { try - { - int currentTick = Server.TickCount; + { + int currentTick = Server.TickCount; + foreach (CCSPlayerController player in connectedPlayers.Values) { if (player == null || !player.IsValid) continue; - var playerSlot = player.Slot; + int slot = player.Slot; + string playerName = player.PlayerName; + string steamID = player.SteamID.ToString(); - if ((CsTeam)player.TeamNum == CsTeam.Spectator) + if ((CsTeam)player.TeamNum == CsTeam.Spectator || !player.PawnIsAlive) { + if (currentTick % (64 / hudTickrate) != 0) + continue; + SpectatorOnTick(player); continue; } - if (playerTimers[playerSlot].IsAddingStartZone || playerTimers[playerSlot].IsAddingEndZone || playerTimers[playerSlot].IsAddingBonusStartZone || playerTimers[playerSlot].IsAddingBonusEndZone) + if (playerTimers.TryGetValue(slot, out PlayerTimerInfo? playerTimer)) { - OnTickZoneTool(player); - continue; - } + if (playerTimer.IsAddingStartZone || playerTimer.IsAddingEndZone || playerTimer.IsAddingBonusStartZone || playerTimer.IsAddingBonusEndZone) + { + OnTickZoneTool(player); + continue; + } - if (playerTimers.TryGetValue(playerSlot, out PlayerTimerInfo? playerTimer) && IsAllowedPlayer(player)) - { if (!IsAllowedPlayer(player)) { InvalidateTimer(player); - playerTimer.TicksSinceLastCmd++; continue; } - bool isOnBhopBlock = playerTimer.IsOnBhopBlock; - bool isTimerRunning = playerTimer.IsTimerRunning; - bool isBonusTimerRunning = playerTimer.IsBonusTimerRunning; - bool isTimerBlocked = playerTimer.IsTimerBlocked; - int timerTicks = playerTimer.TimerTicks; + var playerPawn = player.PlayerPawn?.Value; + if (playerPawn == null) continue; + PlayerButtons? playerButtons = player.Buttons; - Vector playerSpeed = player.PlayerPawn!.Value!.AbsVelocity; - var hasWeapons = player.PlayerPawn?.Value?.WeaponServices?.MyWeapons?.Count > 0; - - if(connectedAFKPlayers.ContainsKey(player.Slot)) + Vector_t playerSpeed = playerPawn.AbsVelocity.ToVector_t(); + bool isTimerBlocked = playerTimer.IsTimerBlocked; + + /* afk */ + if (connectedAFKPlayers.ContainsKey(player.Slot)) { - if(!playerSpeed.IsZero()) + if (!playerSpeed.IsZero()) { connectedAFKPlayers.Remove(player.Slot); playerTimer.AFKWarned = false; playerTimer.AFKTicks = 0; } - else - { - continue; - } + else continue; } - if(playerTimer.AFKTicks >= afkSeconds*48 && !playerTimer.AFKWarned && afkWarning) + if (playerTimer.AFKTicks >= afkSeconds*48 && !playerTimer.AFKWarned && afkWarning) { - player.PrintToChat($"{Localizer["prefix"]} {Localizer["afk_message"]}"); + Utils.PrintToChat(player, $"{Localizer["afk_message"]}"); playerTimer.AFKWarned = true; } - if(playerTimer.AFKTicks >= afkSeconds*64) + if (playerTimer.AFKTicks >= afkSeconds*64) connectedAFKPlayers[player.Slot] = connectedPlayers[player.Slot]; - if(playerSpeed.IsZero()) + if (playerSpeed.IsZero()) playerTimer.AFKTicks++; else playerTimer.AFKTicks = 0; + /* afk */ - if (!startzoneJumping && playerTimers[player.Slot].inStartzone) - { - if((playerButtons & PlayerButtons.Jump) != 0 || playerTimer.MovementService!.OldJumpPressed) - { - player!.Pawn.Value!.AbsVelocity.Z = 0f; - } - } + /* timer counting */ + bool isTimerRunning = playerTimer.IsTimerRunning; + bool isBonusTimerRunning = playerTimer.IsBonusTimerRunning; if (isTimerRunning) { playerTimer.TimerTicks++; - if (useStageTriggers) playerTimer.StageTicks++; + + if (useStageTriggers) + playerTimer.StageTicks++; } else if (isBonusTimerRunning) { playerTimer.BonusTimerTicks++; } + /* timer counting */ + // remove jumping in startzone + if (!startzoneJumping && playerTimers[player.Slot].inStartzone) + { + if((playerButtons & PlayerButtons.Jump) != 0 || playerTimer.MovementService!.OldJumpPressed) + playerPawn.AbsVelocity.Z = 0f; + } + + /* hide weapons */ + bool hasWeapons = playerPawn.WeaponServices?.MyWeapons?.Count > 0; if (playerTimer.HideWeapon) { if (hasWeapons) @@ -121,13 +132,15 @@ public void PlayerOnTick() { if (!hasWeapons && !playerTimer.GivenWeapon) { - if (player.Team == CsTeam.Terrorist) + if (player.TeamT()) { + player.RemoveWeapons(); player.GiveNamedItem("weapon_knife_t"); player.GiveNamedItem("weapon_glock"); } - else if (player.Team == CsTeam.CounterTerrorist) + else if (player.TeamCT()) { + player.RemoveWeapons(); player.GiveNamedItem("weapon_knife"); player.GiveNamedItem("weapon_usp_silencer"); } @@ -135,241 +148,256 @@ public void PlayerOnTick() playerTimer.GivenWeapon = true; } } - - if(playerTimer.currentStyle.Equals(4)) //check if 400vel - { - SetVelocity(player, player!.Pawn.Value!.AbsVelocity, 400); - } + /* hide weapons */ + + /* styles */ + if (playerTimer.currentStyle.Equals(4)) //check if 400vel + SetVelocity(player, playerPawn.AbsVelocity.ToVector_t(), 400); + + if (playerTimer.currentStyle.Equals(10) && !playerPawn.GroundEntity.IsValid && currentTick % 2 != 0) //check if ff + IncreaseVelocity(player); - if(playerTimer.currentStyle.Equals(10) && !player.PlayerPawn.Value.GroundEntity.IsValid) //check if ff + if (playerTimer.changedStyle) { - if (currentTick % 2 != 0) IncreaseVelocity(player); + _ = Task.Run(async () => await RankCommandHandler(player, steamID, slot, playerName, true, playerTimer.currentStyle)); + playerTimer.changedStyle = false; } + /* styles */ + // respawn player if on bhop block too long + bool isOnBhopBlock = playerTimer.IsOnBhopBlock; if (isOnBhopBlock) { playerTimer.TicksOnBhopBlock++; + if (playerTimer.TicksOnBhopBlock > bhopBlockTime) - { RespawnPlayer(player); - } } + /* checking if player in zones */ if (useTriggers == false && isTimerBlocked == false) - { CheckPlayerCoords(player, playerSpeed); - } - if (useTriggers == true && isTimerBlocked == false && useTriggersAndFakeZones == true) - { + + // idk why there is another one but replay breaks with them merged into one :D + if (useTriggers == true && isTimerBlocked == false && useTriggersAndFakeZones) CheckPlayerCoords(player, playerSpeed); - } + /* checking if player in zones */ + + /* hud strafe sync % */ + if (StrafeHudEnabled) + OnSyncTick(player, playerButtons, playerPawn.EyeAngles!); - if (jumpStatsEnabled == true) OnJumpStatTick(player, playerSpeed, player.Pawn?.Value!.CBodyComponent?.SceneNode!.AbsOrigin!, player.PlayerPawn?.Value.EyeAngles!, playerButtons); - if (StrafeHudEnabled == true) OnSyncTick(player, playerButtons, player.PlayerPawn?.Value.EyeAngles!); - if(StrafeHudEnabled == true && playerTimers[player.Slot].inStartzone && playerTimer.Rotation.Count > 0) + // reset in startzone + if (StrafeHudEnabled && playerTimer.inStartzone && playerTimer.Rotation.Count > 0) { playerTimer.Sync = 100.00f; playerTimer.Rotation.Clear(); - }//reset sync in startzone - + } + /* hud strafe sync % */ - if (forcePlayerSpeedEnabled == true) + if (forcePlayerSpeedEnabled) { - string designerName = player.Pawn!.Value!.WeaponServices!.ActiveWeapon?.Value?.DesignerName ?? "no_knife"; + string designerName = playerPawn.WeaponServices!.ActiveWeapon?.Value?.DesignerName ?? "no_knife"; ForcePlayerSpeed(player, designerName); } + /* ranks */ if (playerTimer.IsRankPbCached == false) { - var playerName = player.PlayerName; - var steamID = player.SteamID.ToString(); - SharpTimerDebug($"{playerName} has rank and pb null... calling handler"); - _ = Task.Run(async () => await RankCommandHandler(player, steamID, playerSlot, playerName, true, playerTimer.currentStyle)); + Utils.LogDebug($"{playerName} has rank and pb null... calling handler"); + _ = Task.Run(async () => await RankCommandHandler(player, steamID, slot, playerName, true, playerTimer.currentStyle)); playerTimer.IsRankPbCached = true; } - //attempted bugfix on rank not appearing + // attempted bugfix on rank not appearing if (playerTimer.CachedMapPlacement == null && !playerTimer.IsRankPbReallyCached) { - var playerName = player.PlayerName; - var steamID = player.SteamID.ToString(); - SharpTimerDebug($"{playerName} CachedMapPlacement is still null, calling rank handler once more"); - AddTimer(3.0f, () => { _ = Task.Run(async () => await RankCommandHandler(player, steamID, playerSlot, playerName, true, playerTimer.currentStyle)); }); + Utils.LogDebug($"{playerName} CachedMapPlacement is still null, calling rank handler once more"); playerTimer.IsRankPbReallyCached = true; + AddTimer(3.0f, () => { _ = Task.Run(async () => await RankCommandHandler(player, steamID, slot, playerName, true, playerTimer.currentStyle)); }); } + /* ranks */ - if (playerTimer.changedStyle) - { - var playerName = player.PlayerName; - var steamID = player.SteamID.ToString(); - _ = Task.Run(async () => await RankCommandHandler(player, steamID, playerSlot, playerName, true, playerTimer.currentStyle)); - playerTimer.changedStyle = false; - } - - if (displayScoreboardTags == true) - { - if (playerTimer.TicksSinceLastRankUpdate > 511 && playerTimer.CachedRank != null && (player.Clan != null || !player.Clan!.Contains($"[{playerTimer.CachedRank}]"))) - { - AddScoreboardTagToPlayer(player, playerTimer.CachedRank); - playerTimer.TicksSinceLastRankUpdate = 0; - SharpTimerDebug($"Setting Scoreboard Tag for {player.PlayerName} from TimerOnTick"); - } - } - - if (playerTimer.IsSpecTargetCached == false || specTargets.ContainsKey(player.Pawn!.Value!.EntityHandle.Index) == false) + if (playerTimer.IsSpecTargetCached == false || specTargets.ContainsKey(playerPawn.EntityHandle.Index) == false) { - specTargets[player.Pawn!.Value!.EntityHandle.Index] = new CCSPlayerController(player.Handle); + specTargets[playerPawn.EntityHandle.Index] = new CCSPlayerController(player.Handle); playerTimer.IsSpecTargetCached = true; - SharpTimerDebug($"{player.PlayerName} was not in specTargets, adding..."); + Utils.LogDebug($"{playerName} was not in specTargets, adding..."); } - if (removeCollisionEnabled == true) + if (removeCollisionEnabled) { - if (player.PlayerPawn!.Value.Collision.CollisionGroup != (byte)CollisionGroup.COLLISION_GROUP_DISSOLVING || player.PlayerPawn.Value.Collision.CollisionAttribute.CollisionGroup != (byte)CollisionGroup.COLLISION_GROUP_DISSOLVING) + if (playerPawn.Collision.CollisionGroup != (byte)CollisionGroup.COLLISION_GROUP_DISSOLVING || + playerPawn.Collision.CollisionAttribute.CollisionGroup != (byte)CollisionGroup.COLLISION_GROUP_DISSOLVING + ) { - SharpTimerDebug($"{player.PlayerName} has wrong collision group... RemovePlayerCollision"); + Utils.LogDebug($"{playerName} has wrong collision group... RemovePlayerCollision"); RemovePlayerCollision(player); } } - if (removeCrouchFatigueEnabled == true) + if (removeCrouchFatigueEnabled) { if (playerTimer.MovementService != null && playerTimer.MovementService.DuckSpeed != 7.0f) - { playerTimer.MovementService.DuckSpeed = 7.0f; - } } - if (((PlayerFlags)player.Pawn.Value.Flags & PlayerFlags.FL_ONGROUND) != PlayerFlags.FL_ONGROUND) + // update pre speed for hud + if (((PlayerFlags)playerPawn.Flags & PlayerFlags.FL_ONGROUND) != PlayerFlags.FL_ONGROUND) { playerTimer.TicksInAir++; + if (playerTimer.TicksInAir == 1) - { playerTimer.PreSpeed = $"{playerSpeed.X} {playerSpeed.Y} {playerSpeed.Z}"; - } - } - else - { - playerTimer.TicksInAir = 0; } + else playerTimer.TicksInAir = 0; + // replays if (enableReplays) { + int timerTicks = playerTimer.TimerTicks; if (!playerTimer.IsReplaying && (timerTicks > 0 || playerTimer.BonusTimerTicks > 0) && playerTimer.IsRecordingReplay && !isTimerBlocked) - { ReplayUpdate(player, timerTicks); - } if (playerTimer.IsReplaying && !playerTimer.IsRecordingReplay && isTimerBlocked) - { ReplayPlay(player); - } - else - { - if (!isTimerBlocked && (player.PlayerPawn!.Value.MoveType.HasFlag(MoveType_t.MOVETYPE_OBSERVER) || player.PlayerPawn.Value.ActualMoveType.HasFlag(MoveType_t.MOVETYPE_OBSERVER))) SetMoveType(player, MoveType_t.MOVETYPE_WALK); - } - } - - if (playerTimer.TicksSinceLastCmd < cmdCooldown) playerTimer.TicksSinceLastCmd++; - if (playerTimer.TicksSinceLastRankUpdate < 511) playerTimer.TicksSinceLastRankUpdate++; - - if (currentTick % (64 / hudTickrate) != 0) continue; - - bool keyEnabled = !playerTimer.HideKeys && keysOverlayEnabled; - bool hudEnabled = !playerTimer.HideTimerHud && hudOverlayEnabled; - string formattedPlayerVel = Math.Round(use2DSpeed ? playerSpeed.Length2D() - : playerSpeed.Length()) - .ToString("0000"); - int playerVel = int.Parse(formattedPlayerVel); - - string secondaryHUDcolorDynamic = "LimeGreen"; - int[] velocityThresholds = { 349, 699, 1049, 1399, 1749, 2099, 2449, 2799, 3149, 3499 }; - string[] hudColors = { "LimeGreen", "Lime", "GreenYellow", "Yellow", "Gold", "Orange", "DarkOrange", "Tomato", "OrangeRed", "Red", "Crimson" }; - - for (int i = 0; i < velocityThresholds.Length; i++) - { - if (playerVel < velocityThresholds[i]) + else if ( + !isTimerBlocked && + (playerPawn.MoveType.HasFlag(MoveType_t.MOVETYPE_OBSERVER) || playerPawn.ActualMoveType.HasFlag(MoveType_t.MOVETYPE_OBSERVER)) && + !playerPawn.MoveType.HasFlag(MoveType_t.MOVETYPE_LADDER)) { - secondaryHUDcolorDynamic = hudColors[i]; - break; + SetMoveType(player, MoveType_t.MOVETYPE_WALK); } } - string playerVelColor = useDynamicColor ? secondaryHUDcolorDynamic : secondaryHUDcolor; - string formattedPlayerPre = Math.Round(ParseVector(playerTimer.PreSpeed ?? "0 0 0").Length2D()).ToString("000"); - string playerTime = FormatTime(timerTicks); - string playerBonusTime = FormatTime(playerTimer.BonusTimerTicks); - string timerLine = isBonusTimerRunning - ? $" Time: {playerBonusTime}
" - : isTimerRunning - ? $" Time: {playerTime} ({GetPlayerPlacement(player)}){((playerTimer.CurrentMapStage != 0 && useStageTriggers == true) ? $" {playerTimer.CurrentMapStage}/{stageTriggerCount}" : "")}
" - : playerTimer.IsReplaying - ? $" ◉ REPLAY {FormatTime(playerReplays[playerSlot].CurrentPlaybackFrame)}
" - : ""; - - string veloLine = $" {(playerTimer.IsTester ? playerTimer.TesterSmolGif : "")}Speed: {(playerTimer.IsReplaying ? "{formattedPlayerVel} ({formattedPlayerPre}){(playerTimer.IsTester ? playerTimer.TesterSmolGif : "")} "; - - string syncLine = $"Sync: {playerTimer.Sync:F2}%
";//2f - - string infoLine = ""; - if (playerTimer.CurrentZoneInfo.InBonusStartZone) - { - infoLine = GetBonusInfoLine(playerTimer); - } - else - { - infoLine = GetMainMapInfoLine(playerTimer); - } - - string keysLineNoHtml = $"{(hudEnabled ? "
" : "")}{((playerButtons & PlayerButtons.Moveleft) != 0 ? "A" : "_")} " + - $"{((playerButtons & PlayerButtons.Forward) != 0 ? "W" : "_")} " + - $"{((playerButtons & PlayerButtons.Moveright) != 0 ? "D" : "_")} " + - $"{((playerButtons & PlayerButtons.Back) != 0 ? "S" : "_")} " + - $"{((playerButtons & PlayerButtons.Jump) != 0 || playerTimer.MovementService!.OldJumpPressed ? "J" : "_")} " + - $"{((playerButtons & PlayerButtons.Duck) != 0 ? "C" : "_")}"; - + // timer hud content + if (currentTick % (64 / hudTickrate) != 0) + continue; - string hudContent = (hudEnabled ? timerLine + - (VelocityHudEnabled ? veloLine : "") + - (StrafeHudEnabled && !playerTimer.IsReplaying ? syncLine : "") + - infoLine : "") + - (keyEnabled && !playerTimer.IsReplaying ? keysLineNoHtml : "") + - ((playerTimer.IsTester && !playerTimer.IsReplaying) ? $"{(!keyEnabled ? "
" : "")}" + playerTimer.TesterBigGif : "") + - ((playerTimer.IsVip && !playerTimer.IsTester && !playerTimer.IsReplaying) ? $"{(!keyEnabled ? "

" : "")}" + $"

" : "") + - ((playerTimer.IsReplaying && playerTimer.VipReplayGif != "x") ? playerTimer.VipReplayGif : ""); + string hudContent = GetHudContent(playerTimer, player); - if (hudEnabled || keyEnabled) - { + if (!string.IsNullOrEmpty(hudContent)) player.PrintToCenterHtml(hudContent); - } + // idk what this is for playerTimer.MovementService!.OldJumpPressed = false; } } } catch (Exception ex) { - if (ex.Message != "Invalid game event") SharpTimerError($"Error in TimerOnTick: {ex.StackTrace}"); + if (ex.Message != "Invalid game event") Utils.LogError($"Error in TimerOnTick: {ex.StackTrace}"); + } + } + + private string GetHudContent(PlayerTimerInfo playerTimer, CCSPlayerController player) + { + bool isTimerRunning = playerTimer.IsTimerRunning; + bool isBonusTimerRunning = playerTimer.IsBonusTimerRunning; + int timerTicks = playerTimer.TimerTicks; + PlayerButtons? playerButtons = player.Buttons; + Vector_t playerSpeed = player.PlayerPawn!.Value!.AbsVelocity.ToVector_t(); + bool keyEnabled = !playerTimer.HideKeys && !playerTimer.IsReplaying && keysOverlayEnabled; + bool hudEnabled = !playerTimer.HideTimerHud && hudOverlayEnabled; + + string formattedPlayerVel = Math.Round(use2DSpeed + ? playerSpeed.Length2D() + : playerSpeed.Length()) + .ToString("0000"); + + int playerVel = int.Parse(formattedPlayerVel); + + string secondaryHUDcolorDynamic = "LimeGreen"; + int[] velocityThresholds = { 349, 699, 1049, 1399, 1749, 2099, 2449, 2799, 3149, 3499 }; + string[] hudColors = { "LimeGreen", "Lime", "GreenYellow", "Yellow", "Gold", "Orange", "DarkOrange", "Tomato", "OrangeRed", "Red", "Crimson" }; + + for (int i = 0; i < velocityThresholds.Length; i++) + { + if (playerVel < velocityThresholds[i]) + { + secondaryHUDcolorDynamic = hudColors[i]; + break; + } } + + string playerVelColor = useDynamicColor ? secondaryHUDcolorDynamic : secondaryHUDcolor; + string formattedPlayerPre = Math.Round(Utils.ParseVector_t(playerTimer.PreSpeed ?? "0 0 0").Length2D()).ToString("000"); + string playerTime = Utils.FormatTime(timerTicks); + string playerBonusTime = Utils.FormatTime(playerTimer.BonusTimerTicks); + + string timerLine = + isBonusTimerRunning + ? $" Bonus #{playerTimer.BonusStage} Timer: " + + $"{playerBonusTime} " + + $"
" + : isTimerRunning + ? $" Timer: " + + $"{playerTime} " + + $"({GetPlayerPlacement(player)})" + + $"{((playerTimer.CurrentMapStage != 0 && useStageTriggers == true) ? $" " + + $" {playerTimer.CurrentMapStage}/{stageTriggerCount}" : "")} " + + $"
" + : playerTimer.IsReplaying + ? $" ◉ REPLAY {Utils.FormatTime(playerReplays[player.Slot].CurrentPlaybackFrame)} " + + $"
" + : ""; + + string veloLine = + $" {(playerTimer.IsTester ? playerTimer.TesterSmolGif : "")}" + + $"Speed: " + + $"{(playerTimer.IsReplaying ? "{formattedPlayerVel} " + + $"({formattedPlayerPre}){(playerTimer.IsTester ? playerTimer.TesterSmolGif : "")} " + + $"
"; + + string syncLine = + $"Sync: " + + $"{playerTimer.Sync:F2}% " + + $"
"; + + string infoLine = ""; + + if (playerTimer.CurrentZoneInfo.InBonusStartZone) + infoLine = GetBonusInfoLine(playerTimer); + + else infoLine = GetMainMapInfoLine(playerTimer); + + string keysLineNoHtml = $"{(hudEnabled ? "
" : "")}{((playerButtons & PlayerButtons.Moveleft) != 0 ? "A" : "_")} " + + $"{((playerButtons & PlayerButtons.Forward) != 0 ? "W" : "_")} " + + $"{((playerButtons & PlayerButtons.Moveright) != 0 ? "D" : "_")} " + + $"{((playerButtons & PlayerButtons.Back) != 0 ? "S" : "_")} " + + $"{((playerButtons & PlayerButtons.Jump) != 0 || playerTimer.MovementService!.OldJumpPressed ? "J" : "_")} " + + $"{((playerButtons & PlayerButtons.Duck) != 0 ? "C" : "_")}"; + + + string hudContent = (hudEnabled ? timerLine + + (VelocityHudEnabled ? veloLine : "") + + (StrafeHudEnabled && !playerTimer.IsReplaying ? syncLine : "") + + infoLine : "") + + (keyEnabled && !playerTimer.IsReplaying ? keysLineNoHtml : "") + + ((playerTimer.IsTester && !playerTimer.IsReplaying) ? $"{(!keyEnabled ? "
" : "")}" + playerTimer.TesterBigGif : "") + + ((playerTimer.IsVip && !playerTimer.IsTester && !playerTimer.IsReplaying) ? $"{(!keyEnabled ? "

" : "")}" + $"

" : "") + + ((playerTimer.IsReplaying && playerTimer.VipReplayGif != "x") ? playerTimer.VipReplayGif : ""); + + return hudContent; } private string GetMainMapInfoLine(PlayerTimerInfo playerTimer) { - return !playerTimer.IsReplaying - ? $"" + - - $"{playerTimer.CachedPB} " + - $"({playerTimer.CachedMapPlacement})" + - $"{(RankIconsEnabled ? $" | " : "")}" + - $"{(enableStyles ? $" | {GetNamedStyle(playerTimer.currentStyle)}" : "")}" + - $"{((MapTierHudEnabled && currentMapTier != null) ? $" | Tier {currentMapTier}" : "")}" + - $"{((MapTypeHudEnabled && currentMapType != null) ? $" | {currentMapType}" : "")}" + - $"{((MapNameHudEnabled && currentMapType == null && currentMapTier == null) ? $" | {currentMapName}" : "")}" + - $"" - - : $" {playerTimer.ReplayHUDString}"; + return !playerTimer.IsReplaying + ? $"" + + + $"{playerTimer.CachedPB} " + + $"({playerTimer.CachedMapPlacement})" + + $"{(RankIconsEnabled ? $" | " : "")}" + + $"{(enableStyles ? $" | {GetNamedStyle(playerTimer.currentStyle)}" : "")}" + + $"{((MapTierHudEnabled && currentMapTier != null) ? $" | Tier: {currentMapTier}" : "")}" + + $"{((MapTypeHudEnabled && currentMapType != null) ? $" | {currentMapType}" : "")}" + + $"{((MapNameHudEnabled && currentMapType == null && currentMapTier == null) ? $" | {currentMapName}" : "")}" + + $"" + + : $" {playerTimer.ReplayHUDString}"; } private string GetBonusInfoLine(PlayerTimerInfo playerTimer) @@ -381,13 +409,13 @@ private string GetBonusInfoLine(PlayerTimerInfo playerTimer) var cachedBonusInfo = playerTimer.CachedBonusInfo.FirstOrDefault(x => x.Key == currentBonusNumber); return !playerTimer.IsReplaying - ? $"" + - $"{(cachedBonusInfo.Value != null ? $"{FormatTime(cachedBonusInfo.Value.PbTicks)}" : "Unranked")}" + - $"{(cachedBonusInfo.Value != null ? $" ({cachedBonusInfo.Value.Placement})" : "")}" + - $"" + - $"{(enableStyles ? $" | {GetNamedStyle(playerTimer.currentStyle)}" : "")}" + - $" | Bonus #{currentBonusNumber} " - : $" {playerTimer.ReplayHUDString}"; + ? $"" + + $"{(cachedBonusInfo.Value != null ? $"{Utils.FormatTime(cachedBonusInfo.Value.PbTicks)}" : "Unranked")}" + + $"{(cachedBonusInfo.Value != null ? $" ({cachedBonusInfo.Value.Placement})" : "")}" + + $"" + + $"{(enableStyles ? $" | {GetNamedStyle(playerTimer.currentStyle)}" : "")}" + + $" | Bonus #{currentBonusNumber} " + : $" {playerTimer.ReplayHUDString}"; } else { @@ -397,75 +425,23 @@ private string GetBonusInfoLine(PlayerTimerInfo playerTimer) public void SpectatorOnTick(CCSPlayerController player) { - if (!IsAllowedSpectator(player)) return; + if (!IsAllowedSpectator(player)) + return; + try { var target = specTargets[player.Pawn.Value!.ObserverServices!.ObserverTarget.Index]; if (playerTimers.TryGetValue(target.Slot, out PlayerTimerInfo? playerTimer) && IsAllowedPlayer(target)) { - bool isTimerRunning = playerTimer.IsTimerRunning; - bool isBonusTimerRunning = playerTimer.IsBonusTimerRunning; - int timerTicks = playerTimer.TimerTicks; - PlayerButtons? playerButtons = target.Buttons; - Vector playerSpeed = target.PlayerPawn!.Value!.AbsVelocity; - bool keyEnabled = !playerTimer.HideKeys && !playerTimer.IsReplaying && keysOverlayEnabled; - bool hudEnabled = !playerTimer.HideTimerHud && hudOverlayEnabled; - - string formattedPlayerVel = Math.Round(use2DSpeed ? playerSpeed.Length2D() - : playerSpeed.Length()) - .ToString("0000"); - string formattedPlayerPre = Math.Round(ParseVector(playerTimer.PreSpeed ?? "0 0 0").Length2D()).ToString("000"); - string playerTime = FormatTime(timerTicks); - string playerBonusTime = FormatTime(playerTimer.BonusTimerTicks); - string timerLine = isBonusTimerRunning - ? $" Time: {playerBonusTime}
" - : isTimerRunning - ? $" Time: {playerTime} ({GetPlayerPlacement(target)}){((playerTimer.CurrentMapStage != 0 && useStageTriggers == true) ? $" {playerTimer.CurrentMapStage}/{stageTriggerCount}" : "")}
" - : playerTimer.IsReplaying - ? $" ◉ REPLAY {FormatTime(playerReplays[target.Slot].CurrentPlaybackFrame)}
" - : ""; - - string veloLine = $" {(playerTimer.IsTester ? playerTimer.TesterSmolGif : "")}Speed: {(playerTimer.IsReplaying ? "{formattedPlayerVel} u/s ({formattedPlayerPre} u/s){(playerTimer.IsTester ? playerTimer.TesterSmolGif : "")} "; - - string syncLine = $"Sync: {playerTimer.Sync:F2}%
";//2f - - string infoLine = ""; - if (playerTimer.CurrentZoneInfo.InBonusStartZone) - { - infoLine = GetBonusInfoLine(playerTimer); - } - else - { - infoLine = GetMainMapInfoLine(playerTimer); - } + string hudContent = GetHudContent(playerTimer, target); - string keysLineNoHtml = $"{(hudEnabled ? "
" : "")}{((playerButtons & PlayerButtons.Moveleft) != 0 ? "A" : "_")} " + - $"{((playerButtons & PlayerButtons.Forward) != 0 ? "W" : "_")} " + - $"{((playerButtons & PlayerButtons.Moveright) != 0 ? "D" : "_")} " + - $"{((playerButtons & PlayerButtons.Back) != 0 ? "S" : "_")} " + - $"{((playerButtons & PlayerButtons.Jump) != 0 || playerTimer.MovementService!.OldJumpPressed ? "J" : "_")} " + - $"{((playerButtons & PlayerButtons.Duck) != 0 ? "C" : "_")}"; - - if (playerTimer.MovementService!.OldJumpPressed == true) playerTimer.MovementService.OldJumpPressed = false; - - string hudContent = (hudEnabled ? timerLine + - (VelocityHudEnabled ? veloLine : "") + - (StrafeHudEnabled && !playerTimer.IsReplaying ? syncLine : "") + - infoLine : "") + - (keyEnabled && !playerTimer.IsReplaying ? keysLineNoHtml : "") + - ((playerTimer.IsTester && !playerTimer.IsReplaying) ? playerTimer.TesterBigGif : "") + - ((playerTimer.IsVip && !playerTimer.IsTester && !playerTimer.IsReplaying) ? $"

" : "") + - ((playerTimer.IsReplaying && playerTimer.VipReplayGif != "x") ? playerTimer.VipReplayGif : ""); - - if (hudEnabled || keyEnabled) - { + if (!string.IsNullOrEmpty(hudContent)) player.PrintToCenterHtml(hudContent); - } } } catch (Exception ex) { - if (ex.Message != "Invalid game event") SharpTimerError($"Error in SpectatorOnTick: {ex.Message}"); + if (ex.Message != "Invalid game event") Utils.LogError($"Error in SpectatorOnTick: {ex.Message}"); } } } diff --git a/src/Player/PlayerScoreboard.cs b/src/Player/PlayerScoreboard.cs deleted file mode 100644 index 10aa4fa8..00000000 --- a/src/Player/PlayerScoreboard.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System.Net; -using CounterStrikeSharp.API; -using CounterStrikeSharp.API.Core; -using CounterStrikeSharp.API.Modules.Utils; - -namespace SharpTimer; - -public partial class SharpTimer { - private Dictionary cachedPlacements = new(); - - public void AssignPlayerScoreboards() { - foreach (var player in connectedPlayers.Values.Where(player - => player.IsValid)) - assignScoreboard(player); - } - - private void assignScoreboard(CCSPlayerController player) { - if (player.Team <= CsTeam.Spectator || player.IsBot) return; - var matchStats = player.ActionTrackingServices?.MatchStats; - if (matchStats == null) return; - - var slot = player.Slot; - - if (!playerTimers.TryGetValue(slot, out var timer)) return; - - if (timer.IsAddingStartZone || timer.IsAddingEndZone - || timer.IsAddingBonusStartZone || timer.IsAddingBonusEndZone) - return; - - var ticks = timer.TimerTicks; - var span = TimeSpan.FromSeconds(ticks / 64.0); - - var seconds = span.Seconds; - var minutes = span.Minutes; - - matchStats.Assists = seconds; - matchStats.Deaths = minutes; - - if (!cachedPlacements.TryGetValue(slot, out var placement)) - fetchPlayerPlacement(slot, player.SteamID.ToString()); - else - player.Score = -(placement == 0 ? 99999 : placement); - - if (stageTriggerCount <= 1) { // Linear map, show checkpoints - matchStats.Kills = timer.CurrentMapCheckpoint; - } else { - matchStats.Kills = timer.IsBonusTimerRunning ? - -timer.BonusStage : - timer.CurrentMapStage; - } - - Utilities.SetStateChanged(player, "CCSPlayerController", - "m_pActionTrackingServices"); - } - - private void fetchPlayerPlacement(int slot, string steamId) { - Task.Run(async () => { - var rank = (await GetPlayerServerRank(steamId)).Item1; - cachedPlacements[slot] = rank; - }); - } -} \ No newline at end of file diff --git a/src/Player/PlayerTimers.cs b/src/Player/PlayerTimers.cs index 8cf6ca25..e3fd1399 100644 --- a/src/Player/PlayerTimers.cs +++ b/src/Player/PlayerTimers.cs @@ -17,6 +17,7 @@ You should have received a copy of the GNU General Public License using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Utils; +using SharpTimerAPI.Events; namespace SharpTimer { @@ -25,21 +26,29 @@ public partial class SharpTimer public void OnTimerStart(CCSPlayerController? player, int bonusX = 0) { if (!IsAllowedPlayer(player)) return; + + try + { + StEventSenderCapability.Get()?.TriggerEvent(new StartTimerEvent(player)); + } + catch (Exception e) + { + Utils.LogError($"Couldn't trigger timer start event {e.Message}"); + } if (bonusX != 0) { - if (useTriggers || useTriggersAndFakeZones) SharpTimerDebug($"Starting Bonus Timer for {player!.PlayerName}"); + if (useTriggers || useTriggersAndFakeZones) Utils.LogDebug($"Starting Bonus Timer for {player!.PlayerName}"); playerTimers[player!.Slot].IsTimerRunning = false; playerTimers[player!.Slot].IsBonusTimerRunning = true; } else { - if (useTriggers || useTriggersAndFakeZones) SharpTimerDebug($"Starting Timer for {player!.PlayerName}"); + if (useTriggers || useTriggersAndFakeZones) Utils.LogDebug($"Starting Timer for {player!.PlayerName}"); playerTimers[player!.Slot].IsTimerRunning = true; playerTimers[player!.Slot].IsBonusTimerRunning = false; } - playerCheckpoints.Remove(player!.Slot); playerTimers[player!.Slot].TimerTicks = 0; playerTimers[player!.Slot].StageTicks = 0; playerTimers[player.Slot].StageTimes!.Clear(); @@ -51,22 +60,24 @@ public void OnTimerStart(CCSPlayerController? player, int bonusX = 0) playerTimers[player.Slot].Sync = 0; playerTimers[player!.Slot].IsRecordingReplay = true; + + if (printStartSpeedEnabled) PrintStartSpeed(player); } public void OnTimerStop(CCSPlayerController? player) { var playerName = player!.PlayerName; - var playerSlot = player.Slot; + var slot = player.Slot; var steamID = player.SteamID.ToString(); - var playerTimer = playerTimers[playerSlot]; + var playerTimer = playerTimers[slot]; var currentTicks = playerTimer.TimerTicks; if (!IsAllowedPlayer(player) || playerTimer.IsTimerRunning == false) return; if(currentTicks == 0) { - PrintToChat(player, $"{ChatColors.LightRed}{Localizer["error_savingtime"]}"); + Utils.PrintToChat(player, $"{ChatColors.LightRed}{Localizer["error_savingtime"]}"); playerTimer.IsTimerRunning = false; playerTimer.IsRecordingReplay = false; return; @@ -76,8 +87,8 @@ public void OnTimerStop(CCSPlayerController? player) { if (playerTimer.CurrentMapStage != stageTriggerCount && currentMapOverrideStageRequirement == true) { - PrintToChat(player, $"{ChatColors.LightRed}{Localizer["error_stagenotmatchfinalone"]}({stageTriggerCount})"); - SharpTimerDebug($"Player current stage: {playerTimers[playerSlot].CurrentMapStage}; Final checkpoint: {stageTriggerCount}"); + Utils.PrintToChat(player, $"{ChatColors.LightRed}{Localizer["error_stagenotmatchfinalone"]}({stageTriggerCount})"); + Utils.LogDebug($"Player current stage: {playerTimers[slot].CurrentMapStage}; Final checkpoint: {stageTriggerCount}"); playerTimer.IsTimerRunning = false; playerTimer.IsRecordingReplay = false; return; @@ -85,8 +96,8 @@ public void OnTimerStop(CCSPlayerController? player) if (playerTimer.CurrentMapCheckpoint != cpTriggerCount && useCheckpointVerification) { - PrintToChat(player, $"{ChatColors.LightRed}{Localizer["error_checkpointnotmatchfinalone"]}({cpTriggerCount})"); - SharpTimerDebug($"Player current checkpoint: {playerTimers[playerSlot].CurrentMapCheckpoint}; Final checkpoint: {cpTriggerCount}"); + Utils.PrintToChat(player, $"{ChatColors.LightRed}{Localizer["error_checkpointnotmatchfinalone"]}({cpTriggerCount})"); + Utils.LogDebug($"Player current checkpoint: {playerTimers[slot].CurrentMapCheckpoint}; Final checkpoint: {cpTriggerCount}"); playerTimer.IsTimerRunning = false; playerTimer.IsRecordingReplay = false; return; @@ -95,10 +106,10 @@ public void OnTimerStop(CCSPlayerController? player) if (useStageTriggers == true && useCheckpointTriggers == false) { - if (playerTimer.CurrentMapStage != stageTriggerCount && currentMapOverrideStageRequirement == true) + if (playerTimer.CurrentMapStage != stageTriggerCount && currentMapOverrideStageRequirement == false) { - PrintToChat(player, $"{ChatColors.LightRed}{Localizer["error_stagenotmatchfinalone"]}({stageTriggerCount})"); - SharpTimerDebug($"Player current stage: {playerTimers[playerSlot].CurrentMapStage}; Final checkpoint: {stageTriggerCount}"); + Utils.PrintToChat(player, $"{ChatColors.LightRed}{Localizer["error_stagenotmatchfinalone"]} ({playerTimer.CurrentMapStage}/{stageTriggerCount})"); + Utils.LogDebug($"Player {player.PlayerName} ({player.SteamID}) tried to finish a map with a current stage of {playerTimer.CurrentMapStage}, but this map has {stageTriggerCount} stages. It is recommended that you review {Server.MapName} for exploits."); playerTimer.IsTimerRunning = false; playerTimer.IsRecordingReplay = false; return; @@ -109,50 +120,51 @@ public void OnTimerStop(CCSPlayerController? player) { if (playerTimer.CurrentMapCheckpoint != cpTriggerCount && useCheckpointVerification) { - PrintToChat(player, $"{ChatColors.LightRed}{Localizer["error_checkpointnotmatchfinalone"]}({cpTriggerCount})"); - SharpTimerDebug($"Player current checkpoint: {playerTimers[playerSlot].CurrentMapCheckpoint}; Final checkpoint: {cpTriggerCount}"); + Utils.PrintToChat(player, $"{ChatColors.LightRed}{Localizer["error_checkpointnotmatchfinalone"]}({cpTriggerCount})"); + Utils.LogDebug($"Player current checkpoint: {playerTimers[slot].CurrentMapCheckpoint}; Final checkpoint: {cpTriggerCount}"); playerTimer.IsTimerRunning = false; playerTimer.IsRecordingReplay = false; return; } } - if (useTriggers || useTriggersAndFakeZones) SharpTimerDebug($"Stopping Timer for {playerName}"); + if (useTriggers || useTriggersAndFakeZones) Utils.LogDebug($"Stopping Timer for {playerName}"); if (!ignoreJSON) SavePlayerTime(player, currentTicks); - if (enableDb) _ = Task.Run(async () => await SavePlayerTimeToDatabase(player, currentTicks, steamID, playerName, playerSlot, 0, playerTimer.currentStyle)); + if (enableDb) _ = Task.Run(async () => await SavePlayerTimeToDatabase(player, currentTicks, steamID, playerName, slot, 0, playerTimer.currentStyle)); - //if (enableReplays == true) _ = Task.Run(async () => await DumpReplayToJson(player!, steamID, playerSlot)); + //if (enableReplays == true) _ = Task.Run(async () => await DumpReplayToJson(player!, steamID, slot)); playerTimer.IsTimerRunning = false; playerTimer.IsRecordingReplay = false; - if (!enableDb) _ = Task.Run(async () => await RankCommandHandler(player, steamID, playerSlot, playerName, true)); + if (!enableDb) _ = Task.Run(async () => await RankCommandHandler(player, steamID, slot, playerName, true)); } public void OnBonusTimerStop(CCSPlayerController? player, int bonusX) { - if (!IsAllowedPlayer(player) || playerTimers[player!.Slot].IsBonusTimerRunning == false) return; + if (!IsAllowedPlayer(player) || playerTimers[player!.Slot].IsBonusTimerRunning == false) + return; var playerName = player.PlayerName; - var playerSlot = player.Slot; - var playerTimer = playerTimers[playerSlot]; + var slot = player.Slot; + var playerTimer = playerTimers[slot]; var steamID = player.SteamID.ToString(); - if (useTriggers || useTriggersAndFakeZones) SharpTimerDebug($"Stopping Bonus Timer for {playerName}"); + if (useTriggers || useTriggersAndFakeZones) Utils.LogDebug($"Stopping Bonus Timer for {playerName}"); int currentTicks = playerTimers[player.Slot].BonusTimerTicks; if(currentTicks == 0) { - PrintToChat(player, $"{ChatColors.LightRed}Error Saving Time: Player time is 0 ticks"); + Utils.PrintToChat(player, $"{ChatColors.LightRed}Error Saving Time: Player time is 0 ticks"); playerTimer.IsTimerRunning = false; playerTimer.IsRecordingReplay = false; return; } if (!ignoreJSON) SavePlayerTime(player, currentTicks, bonusX); - if (enableDb) _ = Task.Run(async () => await SavePlayerTimeToDatabase(player, currentTicks, steamID, playerName, playerSlot, bonusX, playerTimers[player.Slot].currentStyle)); - //if (enableReplays == true) _ = Task.Run(async () => await DumpReplayToJson(player!, steamID, playerSlot, bonusX)); + if (enableDb) _ = Task.Run(async () => await SavePlayerTimeToDatabase(player, currentTicks, steamID, playerName, slot, bonusX, playerTimers[player.Slot].currentStyle)); + //if (enableReplays == true) _ = Task.Run(async () => await DumpReplayToJson(player!, steamID, slot, bonusX)); playerTimers[player.Slot].IsBonusTimerRunning = false; playerTimers[player.Slot].IsRecordingReplay = false; } @@ -161,18 +173,18 @@ public void SavePlayerTime(CCSPlayerController? player, int timerTicks, int bonu { if (!IsAllowedPlayer(player)) return; var playerName = player!.PlayerName; - var playerSlot = player!.Slot; + var slot = player!.Slot; var steamId = player.SteamID.ToString(); - if ((bonusX == 0 && playerTimers[playerSlot].IsTimerRunning == false) || (bonusX != 0 && playerTimers[playerSlot].IsBonusTimerRunning == false)) return; + if ((bonusX == 0 && playerTimers[slot].IsTimerRunning == false) || (bonusX != 0 && playerTimers[slot].IsBonusTimerRunning == false)) return; - SharpTimerDebug($"Saving player {(bonusX != 0 ? $"bonus {bonusX} time" : "time")} of {timerTicks} ticks for {playerName} to json"); + Utils.LogDebug($"Saving player {(bonusX != 0 ? $"bonus {bonusX} time" : "time")} of {timerTicks} ticks for {playerName} to json"); string mapRecordsPath = Path.Combine(playerRecordsPath!, bonusX == 0 ? $"{currentMapName}.json" : $"{currentMapName}_bonus{bonusX}.json"); Task.Run(async () => { try { - using (JsonDocument? jsonDocument = await LoadJson(mapRecordsPath)!) + using (JsonDocument? jsonDocument = await Utils.LoadJson(mapRecordsPath)!) { Dictionary records; @@ -199,12 +211,13 @@ public void SavePlayerTime(CCSPlayerController? player, int timerTicks, int bonu string updatedJson = JsonSerializer.Serialize(records, jsonSerializerOptions); File.WriteAllText(mapRecordsPath, updatedJson); - if ((stageTriggerCount != 0 || cpTriggerCount != 0) && bonusX == 0 && (!enableDb) && playerTimers[player.Slot].currentStyle == 0) _ = Task.Run(async () => await DumpPlayerStageTimesToJson(player, steamId, playerSlot)); - if (enableReplays == true && !enableDb) { - if (useBinaryReplays) - _ = Task.Run(async () => await DumpReplayToBinary(player!, steamId, playerSlot, bonusX, playerTimers[player.Slot].currentStyle)); - else - _ = Task.Run(async () => await DumpReplayToJson(player!, steamId, playerSlot, bonusX, playerTimers[player.Slot].currentStyle)); + if ((stageTriggerCount != 0 || cpTriggerCount != 0) && bonusX == 0 && (!enableDb) && playerTimers[player.Slot].currentStyle == 0 && !ignoreJSON) + { + _ = Task.Run(async () => await DumpPlayerStageTimesToJson(player, steamId, slot)); + } + if (enableReplays == true && !enableDb) + { + _ = Task.Run(async () => await DumpReplayToJson(player!, steamId, slot, bonusX, playerTimers[player.Slot].currentStyle)); } } else @@ -216,36 +229,31 @@ public void SavePlayerTime(CCSPlayerController? player, int timerTicks, int bonu } catch (Exception ex) { - SharpTimerError($"Error in SavePlayerTime: {ex.Message}"); + Utils.LogError($"Error in SavePlayerTime: {ex.Message}"); } }); } - private async Task HandlePlayerStageTimes(CCSPlayerController player, nint triggerHandle, int playerSlot, string playerSteamID, string playerName) + private async Task HandlePlayerStageTimes(CCSPlayerController player, nint triggerHandle, int slot, string playerSteamID, string playerName) { try { if (!IsAllowedPlayer(player)) - { return; - } - SharpTimerDebug($"Player {playerName} has a stage trigger with handle {triggerHandle}"); + Utils.LogDebug($"Player {playerName} has a stage trigger with handle {triggerHandle}"); if (stageTriggers.TryGetValue(triggerHandle, out int stageTrigger)) { - //var playerTimerTicks = playerTimers[playerSlot].TimerTicks; // store so its in sync with player - var playerStageTicks = playerTimers[playerSlot].StageTicks; - var formattedStageTicks = FormatTime(playerStageTicks); + //var playerTimerTicks = playerTimers[slot].TimerTicks; // store so its in sync with player + var playerStageTicks = playerTimers[slot].StageTicks; + var formattedStageTicks = Utils.FormatTime(playerStageTicks); var prevStage = stageTrigger - 1; - string currentSpeed = Math.Round(use2DSpeed ? Math.Sqrt(player.PlayerPawn.Value!.AbsVelocity.X * player.PlayerPawn.Value.AbsVelocity.X + player.PlayerPawn.Value.AbsVelocity.Y * player.PlayerPawn.Value.AbsVelocity.Y) - : Math.Sqrt(player.PlayerPawn.Value!.AbsVelocity.X * player.PlayerPawn.Value.AbsVelocity.X + player.PlayerPawn.Value.AbsVelocity.Y * player.PlayerPawn.Value.AbsVelocity.Y + player.PlayerPawn.Value.AbsVelocity.Z * player.PlayerPawn.Value.AbsVelocity.Z)) - .ToString("0000"); - + string currentSpeed = GetCurrentPlayerSpeed(player); var (srSteamID, srPlayerName, srTime) = ("null", "null", "null"); - if (playerTimers[playerSlot].CurrentMapStage == stageTrigger || playerTimers[playerSlot] == null) return; + if (playerTimers[slot].CurrentMapStage == stageTrigger || playerTimers[slot] == null) return; (srSteamID, srPlayerName, srTime) = await GetStageRecordSteamIDFromDatabase(prevStage); @@ -255,22 +263,23 @@ private async Task HandlePlayerStageTimes(CCSPlayerController player, nint trigg Server.NextFrame(() => { if (!IsAllowedPlayer(player)) return; - if (playerTimers.TryGetValue(playerSlot, out PlayerTimerInfo? playerTimer)) + if (playerTimers.TryGetValue(slot, out PlayerTimerInfo? playerTimer)) { if (playerTimer.CurrentMapStage == stageTrigger || playerTimer == null) return; + //TO-DO: Add player setting to enabled/disable printing time comparisons to chat if (previousStageTime != 0) { - PrintToChat(player, Localizer["stages_entrance_message", stageTrigger]); - PrintToChat(player, $"Time: {ChatColors.White}[{primaryChatColor}{formattedStageTicks}{ChatColors.White}] " + - $" [{FormatTimeDifference(playerStageTicks, previousStageTime)}{ChatColors.White}]" + - $" {(previousStageTime != srStageTime ? $"[SR {FormatTimeDifference(playerStageTicks, srStageTime)}{ChatColors.White}]" : "")}"); + Utils.PrintToChat(player, $"Entering Stage: {stageTrigger}"); + Utils.PrintToChat(player, $"Time: {ChatColors.White}[{primaryChatColor}{formattedStageTicks}{ChatColors.White}] " + + $" [{Utils.FormatTimeDifference(playerStageTicks, previousStageTime)}{ChatColors.White}]" + + $" {(previousStageTime != srStageTime && enableStageSR ? $"[SR {Utils.FormatTimeDifference(playerStageTicks, srStageTime)}{ChatColors.White}]" : "")}"); if (float.TryParse(currentSpeed, out float speed) && speed >= 100) //workaround for staged maps with not telehops - PrintToChat(player, $"Speed: {ChatColors.White}[{primaryChatColor}{currentSpeed}u/s{ChatColors.White}]" + - $" [{FormatSpeedDifferenceFromString(currentSpeed, previousStageSpeed)}u/s{ChatColors.White}]" + - $" {(previousStageSpeed != srStageSpeed ? $"[SR {FormatSpeedDifferenceFromString(currentSpeed, srStageSpeed)}u/s{ChatColors.White}]" : "")}"); + Utils.PrintToChat(player, $"Speed: {ChatColors.White}[{primaryChatColor}{currentSpeed}u/s{ChatColors.White}]" + + $" [{Utils.FormatSpeedDifferenceFromString(currentSpeed, previousStageSpeed)}u/s{ChatColors.White}]" + + $" {(previousStageSpeed != srStageSpeed && enableStageSR ? $"[SR {Utils.FormatSpeedDifferenceFromString(currentSpeed, srStageSpeed)}u/s{ChatColors.White}]" : "")}"); } if (playerTimer.StageVelos != null && playerTimer.StageTimes != null && playerTimer.IsTimerRunning == true && IsAllowedPlayer(player)) @@ -279,12 +288,12 @@ private async Task HandlePlayerStageTimes(CCSPlayerController player, nint trigg { playerTimer.StageTimes[stageTrigger] = playerStageTicks; playerTimer.StageVelos[stageTrigger] = $"{currentSpeed}"; - SharpTimerDebug($"Player {playerName} Entering stage {stageTrigger} Time {playerTimer.StageTimes[stageTrigger]}"); + Utils.LogDebug($"Player {playerName} Entering stage {stageTrigger} Time {playerTimer.StageTimes[stageTrigger]}"); } catch (Exception ex) { - SharpTimerError($"Error updating StageTimes dictionary: {ex.Message}"); - SharpTimerDebug($"Player {playerName} dictionary keys: {string.Join(", ", playerTimer.StageTimes.Keys)}"); + Utils.LogError($"Error updating StageTimes dictionary: {ex.Message}"); + Utils.LogDebug($"Player {playerName} dictionary keys: {string.Join(", ", playerTimer.StageTimes.Keys)}"); } } @@ -293,84 +302,81 @@ private async Task HandlePlayerStageTimes(CCSPlayerController player, nint trigg } }); - if (playerTimers[player.Slot].currentStyle == 0) await SavePlayerStageTimeToDatabase(player, playerStageTicks, prevStage, currentSpeed, playerSteamID, playerName, playerSlot); + if (playerTimers[player.Slot].currentStyle == 0) + { + await SavePlayerStageTimeToDatabase(player, playerStageTicks, prevStage, currentSpeed, playerSteamID, playerName, slot); + } } } catch (Exception ex) { - SharpTimerError($"Error in HandlePlayerStageTimes: {ex.Message}"); + Utils.LogError($"Error in HandlePlayerStageTimes: {ex.Message}"); } } - private async Task HandlePlayerCheckpointTimes(CCSPlayerController player, nint triggerHandle, int playerSlot, string playerSteamID, string playerName) + private async Task HandlePlayerCheckpointTimes(CCSPlayerController player, nint triggerHandle, int slot, string playerSteamID, string playerName) { try { if (!IsAllowedPlayer(player)) - { return; - } if (cpTriggers.TryGetValue(triggerHandle, out int cpTrigger)) { if (useStageTriggers == true) //use stagetime instead { - playerTimers[playerSlot].CurrentMapCheckpoint++; + playerTimers[slot].CurrentMapCheckpoint++; return; } - SharpTimerDebug($"Player {playerName} has a checkpoint trigger with handle {triggerHandle}"); + Utils.LogDebug($"Player {playerName} has a checkpoint trigger with handle {triggerHandle}"); - playerTimers[playerSlot].CurrentMapCheckpoint++; + playerTimers[slot].CurrentMapCheckpoint++; - var playerTimerTicks = playerTimers[playerSlot].TimerTicks; // store so its in sync with player + var playerTimerTicks = playerTimers[slot].TimerTicks; // store so its in sync with player var (srSteamID, srPlayerName, srTime) = ("null", "null", "null"); - if (playerTimers[playerSlot] == null) return; + if (playerTimers[slot] == null) return; if (enableDb) - { (srSteamID, srPlayerName, srTime) = await GetMapRecordSteamIDFromDatabase(); - } else - { (srSteamID, srPlayerName, srTime) = await GetMapRecordSteamID(); - } - var (previousStageTime, previousStageSpeed) = await GetStageTime(playerSteamID, cpTrigger); - var (srStageTime, srStageSpeed) = await GetStageTime(srSteamID, cpTrigger); + (srSteamID, srPlayerName, srTime) = await GetStageRecordSteamIDFromDatabase(cpTrigger); + var (previousStageTime, previousStageSpeed) = await GetStageRecordFromDatabase(cpTrigger, playerSteamID); + var (srStageTime, srStageSpeed) = await GetStageRecordFromDatabase(cpTrigger, srSteamID); + + string currentStageSpeed = GetCurrentPlayerSpeed(player); Server.NextFrame(() => { if (!IsAllowedPlayer(player)) return; - if (playerTimers.TryGetValue(playerSlot, out PlayerTimerInfo? playerTimer)) + if (playerTimers.TryGetValue(slot, out PlayerTimerInfo? playerTimer)) { - if (playerTimer == null) return; - string currentStageSpeed = Math.Round(use2DSpeed ? Math.Sqrt(player.PlayerPawn.Value!.AbsVelocity.X * player.PlayerPawn.Value.AbsVelocity.X + player.PlayerPawn.Value.AbsVelocity.Y * player.PlayerPawn.Value.AbsVelocity.Y) - : Math.Sqrt(player.PlayerPawn.Value!.AbsVelocity.X * player.PlayerPawn.Value.AbsVelocity.X + player.PlayerPawn.Value.AbsVelocity.Y * player.PlayerPawn.Value.AbsVelocity.Y + player.PlayerPawn.Value.AbsVelocity.Z * player.PlayerPawn.Value.AbsVelocity.Z)) - .ToString("0000"); - + //TO-DO: Add player setting to enabled/disable printing time comparisons to chat if (previousStageTime != 0) { - player.PrintToChat($" {Localizer["prefix"]} Checkpoint: {playerTimer.CurrentMapCheckpoint}"); - player.PrintToChat($" {Localizer["prefix"]} Time: {ChatColors.White}[{primaryChatColor}{FormatTime(playerTimerTicks)}{ChatColors.White}] " + - $" [{FormatTimeDifference(playerTimerTicks, previousStageTime)}{ChatColors.White}]" + - $" {(previousStageTime != srStageTime ? $"[SR {FormatTimeDifference(playerTimerTicks, srStageTime)}{ChatColors.White}]" : "")}"); + Utils.PrintToChat(player, $"Checkpoint: {playerTimer.CurrentMapCheckpoint}"); + Utils.PrintToChat(player, $"Time: {ChatColors.White}[{primaryChatColor}{Utils.FormatTime(playerTimerTicks)}{ChatColors.White}] " + + $" [{Utils.FormatTimeDifference(playerTimerTicks, previousStageTime)}{ChatColors.White}]" + + $" {(previousStageTime != srStageTime ? $"[SR {Utils.FormatTimeDifference(playerTimerTicks, srStageTime)}{ChatColors.White}]" : "")}"); if (float.TryParse(currentStageSpeed, out float speed) && speed >= 100) //workaround for staged maps with not telehops - player.PrintToChat($" {Localizer["prefix"]} Speed: {ChatColors.White}[{primaryChatColor}{currentStageSpeed}u/s{ChatColors.White}]" + - $" [{FormatSpeedDifferenceFromString(currentStageSpeed, previousStageSpeed)}u/s{ChatColors.White}]" + - $" {(previousStageSpeed != srStageSpeed ? $"[SR {FormatSpeedDifferenceFromString(currentStageSpeed, srStageSpeed)}u/s{ChatColors.White}]" : "")}"); + Utils.PrintToChat(player, $"Speed: {ChatColors.White}[{primaryChatColor}{currentStageSpeed}u/s{ChatColors.White}]" + + $" [{Utils.FormatSpeedDifferenceFromString(currentStageSpeed, previousStageSpeed)}u/s{ChatColors.White}]" + + $" {(previousStageSpeed != srStageSpeed ? $"[SR {Utils.FormatSpeedDifferenceFromString(currentStageSpeed, srStageSpeed)}u/s{ChatColors.White}]" : "")}"); } - if (playerTimer.StageVelos != null && playerTimer.StageTimes != null && playerTimer.IsTimerRunning == true && IsAllowedPlayer(player) && playerTimer.currentStyle == 0) + if (playerTimer.StageVelos != null && playerTimer.StageTimes != null && + playerTimer.IsTimerRunning == true && IsAllowedPlayer(player) && playerTimer.currentStyle == 0) { if (!playerTimer.StageTimes.ContainsKey(cpTrigger)) { - SharpTimerDebug($"Player {playerName} cleared StageTimes before (cpTrigger)"); + Utils.LogDebug($"Player {playerName} cleared StageTimes before (cpTrigger)"); playerTimer.StageTimes.Add(cpTrigger, playerTimerTicks); - playerTimer.StageVelos.Add(cpTrigger, $"{currentStageSpeed}"); + playerTimer.StageVelos.Add(cpTrigger, currentStageSpeed); } else { @@ -378,92 +384,95 @@ private async Task HandlePlayerCheckpointTimes(CCSPlayerController player, nint { playerTimer.StageTimes[cpTrigger] = playerTimerTicks; playerTimer.StageVelos[cpTrigger] = $"{currentStageSpeed}"; - SharpTimerDebug($"Player {playerName} Entering checkpoint {cpTrigger} Time {playerTimer.StageTimes[cpTrigger]}"); + Utils.LogDebug($"Player {playerName} Entering checkpoint {cpTrigger} Time {playerTimer.StageTimes[cpTrigger]}"); } catch (Exception ex) { - SharpTimerError($"Error updating StageTimes dictionary: {ex.Message}"); - SharpTimerDebug($"Player {playerName} dictionary keys: {string.Join(", ", playerTimer.StageTimes.Keys)}"); + Utils.LogError($"Error updating StageTimes dictionary: {ex.Message}"); + Utils.LogDebug($"Player {playerName} dictionary keys: {string.Join(", ", playerTimer.StageTimes.Keys)}"); } } } } }); + + if (playerTimers[slot].currentStyle == 0) + { + await SavePlayerStageTimeToDatabase(player, playerTimerTicks, cpTrigger, currentStageSpeed, playerSteamID, playerName, slot); + } } } catch (Exception ex) { - SharpTimerError($"Error in HandlePlayerCheckpointTimes: {ex.Message}"); + Utils.LogError($"Error in HandlePlayerCheckpointTimes: {ex.Message}"); } } - private async Task HandlePlayerBonusCheckpointTimes(CCSPlayerController player, nint triggerHandle, int playerSlot, string playerSteamID, string playerName) + private async Task HandlePlayerBonusCheckpointTimes(CCSPlayerController player, nint triggerHandle, int slot, string playerSteamID, string playerName) { try { if (!IsAllowedPlayer(player)) - { return; - } if (bonusCheckpointTriggers.TryGetValue(triggerHandle, out int bonusCheckpointTrigger)) { if (useStageTriggers == true) //use stagetime instead { - playerTimers[playerSlot].CurrentMapCheckpoint++; + playerTimers[slot].CurrentMapCheckpoint++; return; } - SharpTimerDebug($"Player {playerName} has a checkpoint trigger with handle {triggerHandle}"); + Utils.LogDebug($"Player {playerName} has a checkpoint trigger with handle {triggerHandle}"); - var playerTimerTicks = playerTimers[playerSlot].TimerTicks; // store so its in sync with player + var playerTimerTicks = playerTimers[slot].TimerTicks; // store so its in sync with player var (srSteamID, srPlayerName, srTime) = ("null", "null", "null"); - if (playerTimers[playerSlot].CurrentMapCheckpoint == bonusCheckpointTrigger || playerTimers[playerSlot] == null) return; + if (playerTimers[slot].CurrentMapCheckpoint == bonusCheckpointTrigger || playerTimers[slot] == null) + return; if (enableDb) - { (srSteamID, srPlayerName, srTime) = await GetMapRecordSteamIDFromDatabase(); - } else - { (srSteamID, srPlayerName, srTime) = await GetMapRecordSteamID(); - } - var (previousStageTime, previousStageSpeed) = await GetStageTime(playerSteamID, bonusCheckpointTrigger); - var (srStageTime, srStageSpeed) = await GetStageTime(srSteamID, bonusCheckpointTrigger); + (srSteamID, srPlayerName, srTime) = await GetStageRecordSteamIDFromDatabase(bonusCheckpointTrigger); + var (previousStageTime, previousStageSpeed) = await GetStageRecordFromDatabase(bonusCheckpointTrigger, playerSteamID); + var (srStageTime, srStageSpeed) = await GetStageRecordFromDatabase(bonusCheckpointTrigger, srSteamID); + + string currentStageSpeed = GetCurrentPlayerSpeed(player); Server.NextFrame(() => { - if (!IsAllowedPlayer(player)) return; - if (playerTimers.TryGetValue(playerSlot, out PlayerTimerInfo? playerTimer)) + if (!IsAllowedPlayer(player)) + return; + + if (playerTimers.TryGetValue(slot, out PlayerTimerInfo? playerTimer)) { + if (playerTimer == null) + return; - if (playerTimer.CurrentMapCheckpoint == bonusCheckpointTrigger || playerTimer == null) return; - - string currentStageSpeed = Math.Round(use2DSpeed ? Math.Sqrt(player.PlayerPawn.Value!.AbsVelocity.X * player.PlayerPawn.Value.AbsVelocity.X + player.PlayerPawn.Value.AbsVelocity.Y * player.PlayerPawn.Value.AbsVelocity.Y) - : Math.Sqrt(player.PlayerPawn.Value!.AbsVelocity.X * player.PlayerPawn.Value.AbsVelocity.X + player.PlayerPawn.Value.AbsVelocity.Y * player.PlayerPawn.Value.AbsVelocity.Y + player.PlayerPawn.Value.AbsVelocity.Z * player.PlayerPawn.Value.AbsVelocity.Z)) - .ToString("0000"); - + //TO-DO: Add player setting to enabled/disable printing time comparisons to chat if (previousStageTime != 0) { - player.PrintToChat($" {Localizer["prefix"]} Bonus Checkpoint: {bonusCheckpointTrigger}"); - player.PrintToChat($" {Localizer["prefix"]} Time: {ChatColors.White}[{primaryChatColor}{FormatTime(playerTimerTicks)}{ChatColors.White}] " + - $" [{FormatTimeDifference(playerTimerTicks, previousStageTime)}{ChatColors.White}]" + - $" {(previousStageTime != srStageTime ? $"[SR {FormatTimeDifference(playerTimerTicks, srStageTime)}{ChatColors.White}]" : "")}"); + Utils.PrintToChat(player, $"Bonus Checkpoint: {bonusCheckpointTrigger}"); + Utils.PrintToChat(player, $"Time: {ChatColors.White}[{primaryChatColor}{Utils.FormatTime(playerTimerTicks)}{ChatColors.White}] " + + $" [{Utils.FormatTimeDifference(playerTimerTicks, previousStageTime)}{ChatColors.White}]" + + $" {(previousStageTime != srStageTime ? $"[SR {Utils.FormatTimeDifference(playerTimerTicks, srStageTime)}{ChatColors.White}]" : "")}"); if (float.TryParse(currentStageSpeed, out float speed) && speed >= 100) //workaround for staged maps with not telehops - player.PrintToChat($" {Localizer["prefix"]} Speed: {ChatColors.White}[{primaryChatColor}{currentStageSpeed}u/s{ChatColors.White}]" + - $" [{FormatSpeedDifferenceFromString(currentStageSpeed, previousStageSpeed)}u/s{ChatColors.White}]" + - $" {(previousStageSpeed != srStageSpeed ? $"[SR {FormatSpeedDifferenceFromString(currentStageSpeed, srStageSpeed)}u/s{ChatColors.White}]" : "")}"); + Utils.PrintToChat(player, $"Speed: {ChatColors.White}[{primaryChatColor}{currentStageSpeed}u/s{ChatColors.White}]" + + $" [{Utils.FormatSpeedDifferenceFromString(currentStageSpeed, previousStageSpeed)}u/s{ChatColors.White}]" + + $" {(previousStageSpeed != srStageSpeed ? $"[SR {Utils.FormatSpeedDifferenceFromString(currentStageSpeed, srStageSpeed)}u/s{ChatColors.White}]" : "")}"); } - if (playerTimer.StageVelos != null && playerTimer.StageTimes != null && playerTimer.IsTimerRunning == true && IsAllowedPlayer(player)) + if (playerTimer.StageVelos != null && playerTimer.StageTimes != null && + playerTimer.IsTimerRunning == true && IsAllowedPlayer(player) && playerTimer.currentStyle == 0) { if (!playerTimer.StageTimes.ContainsKey(bonusCheckpointTrigger)) { - SharpTimerDebug($"Player {playerName} cleared StageTimes before (cpTrigger)"); + Utils.LogDebug($"Player {playerName} cleared StageTimes before (cpTrigger)"); playerTimer.StageTimes.Add(bonusCheckpointTrigger, playerTimerTicks); - playerTimer.StageVelos.Add(bonusCheckpointTrigger, $"{currentStageSpeed}"); + playerTimer.StageVelos.Add(bonusCheckpointTrigger, currentStageSpeed); } else { @@ -471,36 +480,42 @@ private async Task HandlePlayerBonusCheckpointTimes(CCSPlayerController player, { playerTimer.StageTimes[bonusCheckpointTrigger] = playerTimerTicks; playerTimer.StageVelos[bonusCheckpointTrigger] = $"{currentStageSpeed}"; - SharpTimerDebug($"Player {playerName} Entering checkpoint {bonusCheckpointTrigger} Time {playerTimer.StageTimes[bonusCheckpointTrigger]}"); + Utils.LogDebug($"Player {playerName} Entering checkpoint {bonusCheckpointTrigger} Time {playerTimer.StageTimes[bonusCheckpointTrigger]}"); } catch (Exception ex) { - SharpTimerError($"Error updating StageTimes dictionary: {ex.Message}"); - SharpTimerDebug($"Player {playerName} dictionary keys: {string.Join(", ", playerTimer.StageTimes.Keys)}"); + Utils.LogError($"Error updating StageTimes dictionary: {ex.Message}"); + Utils.LogDebug($"Player {playerName} dictionary keys: {string.Join(", ", playerTimer.StageTimes.Keys)}"); } } } playerTimer.CurrentMapCheckpoint++; } }); + + if (playerTimers[slot].currentStyle == 0) + { + await SavePlayerStageTimeToDatabase(player, playerTimerTicks, bonusCheckpointTrigger, currentStageSpeed, playerSteamID, playerName, slot); + } } } catch (Exception ex) { - SharpTimerError($"Error in HandlePlayerBonusCheckpointTimes: {ex.Message}"); + Utils.LogError($"Error in HandlePlayerBonusCheckpointTimes: {ex.Message}"); } } - public async Task DumpPlayerStageTimesToJson(CCSPlayerController? player, string playerId, int playerSlot) + public async Task DumpPlayerStageTimesToJson(CCSPlayerController? player, string playerId, int slot) { - if (!IsAllowedPlayer(player)) return; + if (!IsAllowedPlayer(player)) + return; string fileName = $"{currentMapName!.ToLower()}_stage_times.json"; - string playerStageRecordsPath = Path.Join(playerStagesPath, fileName); + string playerStageRecordsPath = Path.Join(gameDir, "csgo", "cfg", "SharpTimer", "PlayerStageData", fileName); try { - using (JsonDocument? jsonDocument = await LoadJson(playerStageRecordsPath)!) + using (JsonDocument? jsonDocument = await Utils.LoadJson(playerStageRecordsPath)!) { if (jsonDocument != null) { @@ -521,14 +536,14 @@ public async Task DumpPlayerStageTimesToJson(CCSPlayerController? player, string playerData[playerId] = new PlayerStageData(); } - if (playerTimers.TryGetValue(playerSlot, out PlayerTimerInfo? playerTimer)) + if (playerTimers.TryGetValue(slot, out PlayerTimerInfo? playerTimer)) { playerData[playerId].StageTimes = playerTimer.StageTimes; playerData[playerId].StageVelos = playerTimer.StageVelos; } else { - SharpTimerError($"Error in DumpPlayerStageTimesToJson: playerTimers does not have the requested playerSlot"); + Utils.LogError($"Error in DumpPlayerStageTimesToJson: playerTimers does not have the requested slot"); } string updatedJson = JsonSerializer.Serialize(playerData, jsonSerializerOptions); @@ -538,17 +553,17 @@ public async Task DumpPlayerStageTimesToJson(CCSPlayerController? player, string { Dictionary playerData = []; - if (playerTimers.TryGetValue(playerSlot, out PlayerTimerInfo? playerTimer)) + if (playerTimers.TryGetValue(slot, out PlayerTimerInfo? playerTimer)) { playerData[playerId] = new PlayerStageData { - StageTimes = playerTimers[playerSlot].StageTimes, - StageVelos = playerTimers[playerSlot].StageVelos + StageTimes = playerTimers[slot].StageTimes, + StageVelos = playerTimers[slot].StageVelos }; } else { - SharpTimerError($"Error in DumpPlayerStageTimesToJson: playerTimers does not have the requested playerSlot"); + Utils.LogError($"Error in DumpPlayerStageTimesToJson: playerTimers does not have the requested slot"); } string updatedJson = JsonSerializer.Serialize(playerData, jsonSerializerOptions); @@ -558,8 +573,8 @@ public async Task DumpPlayerStageTimesToJson(CCSPlayerController? player, string } catch (Exception ex) { - SharpTimerError($"Error in DumpPlayerStageTimesToJson: {ex.Message}"); + Utils.LogError($"Error in DumpPlayerStageTimesToJson: {ex.Message}"); } } } -} +} \ No newline at end of file diff --git a/src/Player/PlayerUtils.cs b/src/Player/PlayerUtils.cs index 11ff5b72..c40be7c6 100644 --- a/src/Player/PlayerUtils.cs +++ b/src/Player/PlayerUtils.cs @@ -15,9 +15,14 @@ You should have received a copy of the GNU General Public License using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Admin; using CounterStrikeSharp.API.Modules.Entities.Constants; using CounterStrikeSharp.API.Modules.Utils; +using FixVectorLeak; +using System.Diagnostics.CodeAnalysis; using System.Text.Json; +using SharpTimerAPI.Events; +using TagsApi; namespace SharpTimer { @@ -25,8 +30,8 @@ public partial class SharpTimer { public void PrintAllEnabledCommands(CCSPlayerController player) { - SharpTimerDebug($"Printing Commands for {player.PlayerName}"); - player.PrintToChat($"{Localizer["prefix"]} {Localizer["Check_console"]}"); + Utils.LogDebug($"Printing Commands for {player.PlayerName}"); + Utils.PrintToChat(player, $"{Localizer["Check_console"]}"); if (respawnEnabled) player.PrintToConsole($"{Localizer["console_r"]}"); if (respawnEnabled && bonusRespawnPoses.Count != 0) player.PrintToConsole($"{Localizer["console_rb"]}"); @@ -70,9 +75,9 @@ public void PrintAllEnabledCommands(CCSPlayerController player) player.PrintToConsole($"{Localizer["console_replaybonuspb"]}"); } - if (jumpStatsEnabled) player.PrintToConsole($"{Localizer["console_jumpstats"]}"); player.PrintToConsole($"{Localizer["console_hideweapon"]}"); player.PrintToConsole($"{Localizer["console_spec"]}"); + if (enableStyles) player.PrintToConsole($"{Localizer["console_styles"]}"); } @@ -91,11 +96,11 @@ public void ForcePlayerSpeed(CCSPlayerController player, string activeWeapon) } catch (Exception ex) { - SharpTimerError($"Error in ForcePlayerSpeed: {ex.Message}"); + Utils.LogError($"Error in ForcePlayerSpeed: {ex.Message}"); } } - private void AdjustPlayerVelocity(CCSPlayerController? player, float velocity, bool forceNoDebug = false) + public void AdjustPlayerVelocity(CCSPlayerController? player, float velocity, bool forceNoDebug = false) { if (!IsAllowedPlayer(player)) return; @@ -124,16 +129,16 @@ private void AdjustPlayerVelocity(CCSPlayerController? player, float velocity, b player!.PlayerPawn.Value!.AbsVelocity.Y = (float)adjustedY; player!.PlayerPawn.Value!.AbsVelocity.Z = (float)adjustedZ; - if (!forceNoDebug) SharpTimerDebug($"Adjusted Velo for {player.PlayerName} to {player.PlayerPawn.Value.AbsVelocity}"); + if (!forceNoDebug) Utils.LogDebug($"Adjusted Velo for {player.PlayerName} to {player.PlayerPawn.Value.AbsVelocity}"); } else { - if (!forceNoDebug) SharpTimerDebug($"Cannot adjust velocity for {player.PlayerName} because current speed is zero."); + if (!forceNoDebug) Utils.LogDebug($"Cannot adjust velocity for {player.PlayerName} because current speed is zero."); } } catch (Exception ex) { - SharpTimerError($"Error in AdjustPlayerVelocity: {ex.Message}"); + Utils.LogError($"Error in AdjustPlayerVelocity: {ex.Message}"); } } @@ -162,19 +167,38 @@ private void AdjustPlayerVelocity2D(CCSPlayerController? player, float velocity, player.PlayerPawn.Value.AbsVelocity.X = (float)adjustedX; player.PlayerPawn.Value.AbsVelocity.Y = (float)adjustedY; - if (!forceNoDebug) SharpTimerDebug($"Adjusted Velo for {player.PlayerName} to {player.PlayerPawn.Value.AbsVelocity}"); + if (!forceNoDebug) Utils.LogDebug($"Adjusted Velo for {player.PlayerName} to {player.PlayerPawn.Value.AbsVelocity}"); } else { - if (!forceNoDebug) SharpTimerDebug($"Cannot adjust velocity for {player.PlayerName} because current speed is zero."); + if (!forceNoDebug) Utils.LogDebug($"Cannot adjust velocity for {player.PlayerName} because current speed is zero."); } } catch (Exception ex) { - SharpTimerError($"Error in AdjustPlayerVelocity2D: {ex.Message}"); + Utils.LogError($"Error in AdjustPlayerVelocity2D: {ex.Message}"); } } + private string GetCurrentPlayerSpeed(CCSPlayerController player) + { + return Math.Round( + use2DSpeed ? + Math.Sqrt(player.PlayerPawn.Value!.AbsVelocity.X * player.PlayerPawn.Value!.AbsVelocity.X + + player.PlayerPawn.Value!.AbsVelocity.Y * player.PlayerPawn.Value!.AbsVelocity.Y) + : Math.Sqrt(player.PlayerPawn.Value!.AbsVelocity.X * player.PlayerPawn.Value!.AbsVelocity.X + + player.PlayerPawn.Value!.AbsVelocity.Y * player.PlayerPawn.Value!.AbsVelocity.Y + + player.PlayerPawn.Value!.AbsVelocity.Z * player.PlayerPawn.Value!.AbsVelocity.Z) + ).ToString("0000"); + } + + public void PrintStartSpeed(CCSPlayerController player) + { + int startSpeed = int.Parse(GetCurrentPlayerSpeed(player)); + int printSpeed = (maxStartingSpeedEnabled && startSpeed > maxStartingSpeed) ? maxStartingSpeed : startSpeed; + player.PrintToChat($"{Localizer["prefix"]} {Localizer["start_speed"]} {ChatColors.Olive}{printSpeed}"); + } + private void RemovePlayerCollision(CCSPlayerController? player) { try @@ -189,23 +213,23 @@ private void RemovePlayerCollision(CCSPlayerController? player) Utilities.SetStateChanged(player, "CCollisionProperty", "m_CollisionGroup"); Utilities.SetStateChanged(player, "CCollisionProperty", "m_collisionAttribute"); - SharpTimerDebug($"Removed Collison for {player.PlayerName}"); + Utils.LogDebug($"Removed Collison for {player.PlayerName}"); }); } catch (Exception ex) { - SharpTimerError($"Error in RemovePlayerCollision: {ex.Message}"); + Utils.LogError($"Error in RemovePlayerCollision: {ex.Message}"); } } public async Task<(int, string)> GetStageTime(string steamId, int stageIndex) { string fileName = $"{currentMapName!.ToLower()}_stage_times.json"; - string playerStageRecordsPath = Path.Join(playerStagesPath, fileName); + string playerStageRecordsPath = Path.Join(gameDir, "csgo", "cfg", "SharpTimer", "PlayerStageData", fileName); try { - using (JsonDocument? jsonDocument = await LoadJson(playerStageRecordsPath)!) + using (JsonDocument? jsonDocument = await Utils.LoadJson(playerStageRecordsPath)!) { if (jsonDocument != null) { @@ -228,13 +252,13 @@ private void RemovePlayerCollision(CCSPlayerController? player) } else { - SharpTimerDebug($"Error in GetStageTime jsonDoc was null"); + Utils.LogDebug($"Error in GetStageTime jsonDoc was null"); } } } catch (Exception ex) { - SharpTimerError($"Error in GetStageTime: {ex.Message}"); + Utils.LogError($"Error in GetStageTime: {ex.Message}"); } return (0, string.Empty); @@ -248,7 +272,7 @@ public async Task GetPreviousPlayerRecord(string steamId, int bonusX = 0) try { - JsonDocument? jsonDoc = await LoadJson(mapRecordsPath); + JsonDocument? jsonDoc = await Utils.LoadJson(mapRecordsPath); if (jsonDoc != null) { var root = jsonDoc.RootElement; @@ -259,12 +283,12 @@ public async Task GetPreviousPlayerRecord(string steamId, int bonusX = 0) } else { - SharpTimerDebug($"Map records file does not exist: {mapRecordsPath}"); + Utils.LogDebug($"Map records file does not exist: {mapRecordsPath}"); } } catch (Exception ex) { - SharpTimerError($"Error in GetPreviousPlayerRecord: {ex.Message}"); + Utils.LogError($"Error in GetPreviousPlayerRecord: {ex.Message}"); } return 0; @@ -272,8 +296,8 @@ public async Task GetPreviousPlayerRecord(string steamId, int bonusX = 0) public string GetPlayerPlacement(CCSPlayerController? player) { - if (!IsAllowedPlayer(player) || !playerTimers[player!.Slot].IsTimerRunning) return ""; - + if (!IsAllowedPlayer(player) || !playerTimers[player!.Slot].IsTimerRunning) + return ""; int currentPlayerTime = playerTimers[player.Slot].TimerTicks; @@ -306,7 +330,7 @@ public async Task GetPlayerMapPlacementWithTotal(CCSPlayerController? pl { try { - if (!IsAllowedClient(player)) + if (!IsPlayerOrSpectator(player)) return ""; string currentMapNamee = bonusX == 0 ? currentMapName! : $"{currentMapName}_bonus{bonusX}"; @@ -326,7 +350,7 @@ public async Task GetPlayerMapPlacementWithTotal(CCSPlayerController? pl } catch (Exception ex) { - SharpTimerError($"Error in GetPlayerMapPlacementWithTotal: {ex}"); + Utils.LogError($"Error in GetPlayerMapPlacementWithTotal: {ex}"); return UnrankedTitle; } } @@ -372,13 +396,13 @@ public async Task GetPlayerMapPercentile(string steamId, string playerNa double percentage = totalPlayers == 0 ? 100 : (double)placement / totalPlayers * 100; - SharpTimerDebug($"Player: {playerName}, Placement: {placement}, Total Players: {totalPlayers}, Percentage: {percentage}th"); + Utils.LogDebug($"Player: {playerName}, Placement: {placement}, Total Players: {totalPlayers}, Percentage: {percentage}th"); return percentage; } catch (Exception ex) { - SharpTimerError($"Error in GetPlayerMapPercentile: {ex}"); + Utils.LogError($"Error in GetPlayerMapPercentile: {ex}"); return 0; } } @@ -386,7 +410,7 @@ public async Task GetPlayerStagePlacementWithTotal(CCSPlayerController? { try { - if (!IsAllowedClient(player)) + if (!IsPlayerOrSpectator(player)) return ""; string currentMapNamee = bonusX == 0 ? currentMapName! : $"{currentMapName}_bonus{bonusX}"; @@ -406,16 +430,19 @@ public async Task GetPlayerStagePlacementWithTotal(CCSPlayerController? } catch (Exception ex) { - SharpTimerError($"Error in GetPlayerStagePlacementWithTotal: {ex}"); + Utils.LogError($"Error in GetPlayerStagePlacementWithTotal: {ex}"); return UnrankedTitle; } } - public async Task GetPlayerServerPlacement(string steamId, string playerName, bool getRankImg = false, bool getPlacementOnly = false, bool getPointsOnly = false) + public async Task GetPlayerServerPlacement(CCSPlayerController? player, string steamId, string playerName, bool getRankImg = false, bool getPlacementOnly = false, bool getPointsOnly = false) { try { - int savedPlayerPoints = enableDb ? await GetPlayerPointsFromDatabase(steamId, playerName) : 0; + if (!IsPlayerOrSpectator(player)) + return ""; + + int savedPlayerPoints = enableDb ? await GetPlayerPointsFromDatabase(player, steamId, playerName) : 0; if (getPointsOnly) return savedPlayerPoints.ToString(); @@ -433,33 +460,10 @@ public async Task GetPlayerServerPlacement(string steamId, string player } catch (Exception ex) { - SharpTimerError($"Error in GetPlayerServerPlacement: {ex}"); + Utils.LogError($"Error in GetPlayerServerPlacement: {ex}"); return UnrankedTitle; } } - - public async Task<(int, int)> GetPlayerServerRank(string steamId, string? playerName = null) - { - try - { - int savedPlayerPoints = enableDb ? await GetPlayerPointsFromDatabase(steamId, playerName) : 0; - - if (savedPlayerPoints == 0 || savedPlayerPoints <= minGlobalPointsForRank) - return (0, 0); - - Dictionary sortedPoints = enableDb ? await GetSortedPointsFromDatabase() : []; - - int placement = sortedPoints.Count(kv => kv.Value.GlobalPoints > savedPlayerPoints) + 1; - int totalPlayers = sortedPoints.Count; - - return (placement, totalPlayers); - } - catch (Exception ex) - { - SharpTimerError($"Error in GetPlayerServerRank: {ex}"); - return (0, 0); - } - } public string CalculateRankStuff(int totalPlayers, int placement, double percentage, bool getRankImg = false, bool getPlacementOnly = false) { @@ -477,7 +481,7 @@ public string CalculateRankStuff(int totalPlayers, int placement, double percent } catch (Exception ex) { - SharpTimerError($"Error in CalculateRankStuff: {ex}"); + Utils.LogError($"Error in CalculateRankStuff: {ex}"); return UnrankedTitle; } } @@ -486,21 +490,19 @@ public void InvalidateTimer(CCSPlayerController player, nint callerHandle = 0) { if (player.IsValid && playerTimers!.TryGetValue(player.Slot, out var playerTimer)) { - if (!playerTimers[player.Slot].IsTimerBlocked) - { - playerCheckpoints.Remove(player.Slot); - } playerTimers[player.Slot].TimerTicks = 0; playerTimers[player.Slot].StageTicks = 0; playerTimers[player.Slot].BonusTimerTicks = 0; playerTimers[player.Slot].IsTimerRunning = false; playerTimers[player.Slot].IsBonusTimerRunning = false; + if (stageTriggerCount != 0 && useStageTriggers == true) { playerTimers[player.Slot].StageTimes!.Clear(); playerTimers[player.Slot].StageVelos!.Clear(); playerTimers[player.Slot].CurrentMapStage = stageTriggers.GetValueOrDefault(callerHandle, 0); } + if (cpTriggerCount != 0) { playerTimers[player.Slot].StageTimes!.Clear(); @@ -510,35 +512,117 @@ public void InvalidateTimer(CCSPlayerController player, nint callerHandle = 0) } } - private HookResult OnCommandJoinTeam(CCSPlayerController? player, CounterStrikeSharp.API.Modules.Commands.CommandInfo commandInfo) + public void OnSyncTick(CCSPlayerController player, PlayerButtons? buttons, QAngle eyeangle) { - if (player == null || !player.IsValid) return HookResult.Handled; - InvalidateTimer(player); - return HookResult.Continue; + try + { + var playerTimer = playerTimers[player.Slot]; + bool strafingLeft = false; + bool strafingRight = false; + // Start with 100% sync initially + if (playerTimers[player.Slot].inStartzone) playerTimer.Sync = 100.00f; + + if ((buttons & PlayerButtons.Moveleft) != 0 && (buttons & PlayerButtons.Moveright) != 0) + { + return; // Ignore if both left and right are pressed + } + else if ((buttons & PlayerButtons.Moveleft) != 0) + { + strafingLeft = true; + } + else if ((buttons & PlayerButtons.Moveright) != 0) + { + strafingRight = true; + } + else + { + return; // Ignore if neither left nor right is pressed + } + + // Add the current eye angle to the rotation history + QAngle_t newEyeAngle = new QAngle_t(eyeangle.X, eyeangle.Y, eyeangle.Z); + playerTimer.Rotation.Add(newEyeAngle); + + // Cap rotation history at 1000 entries + if (playerTimer.Rotation.Count > 1000) + { + playerTimer.Rotation.RemoveAt(0); // Remove the oldest entry + } + + // Only proceed if we have enough data points in Rotation + if (playerTimer.Rotation.Count > 1) + { + float previousEyeAngleY = playerTimer.Rotation[playerTimer.Rotation.Count - 2].Y; // Use Rotation.Count - 2 + float currentEyeAngleY = eyeangle.Y; + + // Normalize angle difference to handle wrapping from -180 to 180 + float deltaY = currentEyeAngleY - previousEyeAngleY; + if (deltaY > 180) + { + deltaY -= 360; + } + else if (deltaY < -180) + { + deltaY += 360; + } + + if (Math.Abs(deltaY) < 0.01f) return; + + bool onGround = ((PlayerFlags)player.Pawn.Value!.Flags & PlayerFlags.FL_ONGROUND) == PlayerFlags.FL_ONGROUND; + if (onGround || (!onGround && (buttons & (PlayerButtons.Moveleft | PlayerButtons.Moveright)) == 0)) + { + return; // Ignore calculation if the player is on the ground or airborne without pressing movement buttons + } + else + { + // Increment frames in the air + playerTimer.TotalSync++; + } + + // Determine rotation direction + bool rotatingLeft = deltaY > 0; + bool rotatingRight = deltaY < 0; + + // Add sync frame if strafing and rotating match and the player is airborne + if (!onGround && ((strafingLeft && rotatingLeft) || (strafingRight && rotatingRight))) + { + playerTimer.GoodSync++; // Increment sync frames + } + } + + // Calculate sync percentage + if (playerTimer.TotalSync >= 2) // Adjust threshold as needed + { + playerTimer.Sync = (playerTimer.TotalSync > 0) + ? (playerTimer.GoodSync / (float)playerTimer.TotalSync) * 100 + : 0; + } + } + catch (Exception ex) + { + Utils.LogDebug($"Exception in OnSyncTick: {ex}"); + } } public async Task PrintMapTimeToChat(CCSPlayerController player, string steamID, string playerName, int oldticks, int newticks, int bonusX = 0, int timesFinished = 0, int style = 0, int prevSR = 0) { if (!IsAllowedPlayer(player)) { - SharpTimerError($"Error in PrintMapTimeToChat: Player {playerName} not allowed or not on server anymore"); + Utils.LogError($"Error in PrintMapTimeToChat: Player {playerName} not allowed or not on server anymore"); return; } string ranking = await GetPlayerMapPlacementWithTotal(player, steamID, playerName, false, true, bonusX, style); - SharpTimerDebug($"Player {playerName} finished map with time {newticks} ticks, placing {ranking}"); - var percentile = await GetPlayerMapPercentile(steamID, playerName, currentMapName!, bonusX, style, false, newticks); - int.TryParse(ranking[..ranking.IndexOf('/')], out int position); - bool newSR = GetNumberBeforeSlash(ranking) == 1 && (oldticks > newticks || oldticks == 0); + bool newSR = Utils.GetNumberBeforeSlash(ranking) == 1 && (oldticks > newticks || oldticks == 0); bool beatPB = oldticks > newticks; - string newTime = FormatTime(newticks); + string newTime = Utils.FormatTime(newticks); string timeDifferenceNoCol = ""; string timeDifference = ""; if (oldticks != 0) { - if (discordWebhookEnabled) timeDifferenceNoCol = FormatTimeDifference(newticks, oldticks, true); - timeDifference = $"[{FormatTimeDifference(newticks, oldticks)}{ChatColors.White}] "; + if (discordWebhookEnabled) timeDifferenceNoCol = Utils.FormatTimeDifference(newticks, oldticks, true); + timeDifference = $"[{Utils.FormatTimeDifference(newticks, oldticks)}{ChatColors.White}] "; } Server.NextFrame(() => @@ -547,41 +631,47 @@ public async Task PrintMapTimeToChat(CCSPlayerController player, string steamID, { if (prevSR != 0) { - timeDifference = $"[{FormatTimeDifference(newticks, prevSR)}{ChatColors.White}] "; + timeDifference = $"[{Utils.FormatTimeDifference(newticks, prevSR)}{ChatColors.White}] "; } - if (bonusX != 0) PrintToChatAll(Localizer[enableStyles && style != 0 ? "new_server_record_bonus_style" : "new_server_record_bonus", playerName, bonusX, GetNamedStyle(style)]); + if (bonusX != 0) Utils.PrintToChatAll(Localizer["new_server_record_bonus", playerName, bonusX]); else { - PrintToChatAll(Localizer[ enableStyles && style != 0 ? "new_server_record_style" : "new_server_record", playerName, GetNamedStyle(style)]); - if (srSoundAll) SendCommandToEveryone($"play {srSound}"); - else PlaySound(player, srSound); + Utils.PrintToChatAll(Localizer["new_server_record", playerName]); + PlaySound(player, srSound, srSoundAll ? true : false); } if (discordWebhookPrintSR && discordWebhookEnabled && enableDb) _ = Task.Run(async () => await DiscordRecordMessage(player, playerName, newTime, steamID, ranking, timesFinished, true, timeDifferenceNoCol, bonusX)); } else if (beatPB) { - if (bonusX != 0) PrintToChatAll(Localizer["new_pb_record_bonus", playerName, bonusX]); - else PrintToChatAll(Localizer["new_pb_record", playerName]); + if (bonusX != 0) Utils.PrintToChatAll(Localizer["new_pb_record_bonus", playerName, bonusX]); + else Utils.PrintToChatAll(Localizer["new_pb_record", playerName]); if (discordWebhookPrintPB && discordWebhookEnabled && enableDb) _ = Task.Run(async () => await DiscordRecordMessage(player, playerName, newTime, steamID, ranking, timesFinished, false, timeDifferenceNoCol, bonusX)); PlaySound(player, pbSound); } else { - if (bonusX != 0) PrintToChatAll(Localizer["map_finish_bonus", playerName, bonusX]); - else PrintToChatAll(Localizer["map_finish", playerName]); + if (bonusX != 0) Utils.PrintToChatAll(Localizer["map_finish_bonus", playerName, bonusX]); + else Utils.PrintToChatAll(Localizer["map_finish", playerName]); if (discordWebhookPrintPB && discordWebhookEnabled && timesFinished == 1 && enableDb) _ = Task.Run(async () => await DiscordRecordMessage(player, playerName, newTime, steamID, ranking, timesFinished, false, timeDifferenceNoCol, bonusX)); PlaySound(player, timerSound); } - if (enableDb || bonusX != 0) { - PrintToChatAll(Localizer["map_finish_rank", ranking, timesFinished]); - PrintToChatAll(Localizer["map_finish_group", FormatGroup(position, percentile)]); - } + if (enableDb || bonusX != 0) + Utils.PrintToChatAll(Localizer["map_finish_rank", ranking, timesFinished]); - PrintToChatAll(Localizer["timer_time", newTime, timeDifference]); + Utils.PrintToChatAll(Localizer["timer_time", newTime, timeDifference]); + if (enableStyles) Utils.PrintToChatAll(Localizer["timer_style", GetNamedStyle(style)]); if (enableReplays == true && enableSRreplayBot == true && newSR && (oldticks > newticks || oldticks == 0)) - { _ = Task.Run(async () => await SpawnReplayBot()); + + try + { + StEventSenderCapability.Get() + ?.TriggerEvent(new FinishMapEvent(player, newSR, beatPB, currentMapTier ?? 1)); + } + catch (Exception e) + { + Utils.LogError($"Couldn't trigger timer stop event {e.Message}"); } }); } @@ -589,21 +679,21 @@ public async Task PrintStageTimeToChat(CCSPlayerController player, string steamI { if (!IsAllowedPlayer(player)) { - SharpTimerError($"Error in PrintStageTimeToChat: Player {playerName} not allowed or not on server anymore"); + Utils.LogError($"Error in PrintStageTimeToChat: Player {playerName} not allowed or not on server anymore"); return; } string ranking = await GetPlayerStagePlacementWithTotal(player, steamID, playerName, stage, false, true, bonusX); - bool newSR = GetNumberBeforeSlash(ranking) == 1 && (oldticks > newticks || oldticks == 0); + bool newSR = Utils.GetNumberBeforeSlash(ranking) == 1 && (oldticks > newticks || oldticks == 0); bool beatPB = oldticks > newticks; - string newTime = FormatTime(newticks); + string newTime = Utils.FormatTime(newticks); string timeDifferenceNoCol = ""; string timeDifference = ""; if (oldticks != 0) { - if (discordWebhookEnabled) timeDifferenceNoCol = FormatTimeDifference(newticks, oldticks, true); - timeDifference = $"[{FormatTimeDifference(newticks, oldticks)}{ChatColors.White}] "; + if (discordWebhookEnabled) timeDifferenceNoCol = Utils.FormatTimeDifference(newticks, oldticks, true); + timeDifference = $"[{Utils.FormatTimeDifference(newticks, oldticks)}{ChatColors.White}] "; } Server.NextFrame(() => @@ -612,60 +702,65 @@ public async Task PrintStageTimeToChat(CCSPlayerController player, string steamI { if (prevSR != 0) { - timeDifference = $"[{FormatTimeDifference(newticks, prevSR)}{ChatColors.White}] "; + timeDifference = $"[{Utils.FormatTimeDifference(newticks, prevSR)}{ChatColors.White}] "; } - PrintToChatAll(Localizer["new_stage_server_record", playerName, stage]); - if (stageSoundAll) SendCommandToEveryone($"play {srSound}"); - else PlaySound(player, srSound); - PrintToChatAll(Localizer["timer_time", newTime, timeDifference]); + Utils.PrintToChatAll(Localizer["new_stage_server_record", playerName]); + PlaySound(player, srSound, stageSoundAll ? true : false); + Utils.PrintToChatAll(Localizer["timer_time", newTime, timeDifference]); //TODO: Discord webhook stage sr //if (discordWebhookPrintSR && discordWebhookEnabled && enableDb) _ = Task.Run(async () => await DiscordRecordMessage(player, playerName, newTime, steamID, ranking, timesFinished, true, timeDifferenceNoCol, bonusX)); } }); } - public void AddScoreboardTagToPlayer(CCSPlayerController player, string tag) + public void AddRankTagToPlayer(CCSPlayerController player, string rank) { try { - if (string.IsNullOrEmpty(tag)) + if (string.IsNullOrEmpty(rank)) return; - if (player == null || !player.IsValid) - return; + if (TagApi == null) + TagApi = ITagApi.Capability.Get(); - string originalPlayerName = player.PlayerName; + if (TagApi == null) + { + Utils.LogError("(SetClanTagAPI) Failed load TagApi"); + return; + } - string stripedClanTag = RemovePlayerTags(player.Clan ?? ""); - - player.Clan = $" {stripedClanTag}{(playerTimers[player.Slot].IsVip ? $"{customVIPTag}" : "")}{tag}"; + string clanTag = $"{rank} {(playerTimers[player.Slot].IsVip ? $"{customVIPTag}" : "")}"; - player.PlayerName = originalPlayerName + " "; + string rankColor = GetRankColorForChat(player); + string chatTag = $"{rankColor}{rank} "; - AddTimer(0.1f, () => + if (displayChatTags) { - if (player.IsValid) + TagApi.ResetAttribute(player, Tags.TagType.ChatTag); + + Server.NextFrame(() => { - Utilities.SetStateChanged(player, "CCSPlayerController", "m_szClan"); - Utilities.SetStateChanged(player, "CBasePlayerController", "m_iszPlayerName"); - } - }); + string oldChatTag = TagApi.GetAttribute(player, Tags.TagType.ChatTag) ?? ""; + TagApi.SetAttribute(player, Tags.TagType.ChatTag, oldChatTag + chatTag); + }); + } - AddTimer(0.2f, () => + if (displayScoreboardTags) { - if (player.IsValid) player.PlayerName = originalPlayerName; - }); + TagApi.ResetAttribute(player, Tags.TagType.ScoreTag); - AddTimer(0.3f, () => - { - if (player.IsValid) Utilities.SetStateChanged(player, "CBasePlayerController", "m_iszPlayerName"); - }); + Server.NextFrame(() => + { + string oldClanTag = TagApi.GetAttribute(player, Tags.TagType.ScoreTag) ?? ""; + TagApi.SetAttribute(player, Tags.TagType.ScoreTag, oldClanTag + clanTag); + }); + } - SharpTimerDebug($"Set Scoreboard Tag for {player.Clan} {player.PlayerName}"); + Utils.LogDebug($"Set Scoreboard Tag for {player.Clan} {player.PlayerName}"); } catch (Exception ex) { - SharpTimerError($"Error in AddScoreboardTagToPlayer: {ex.Message}"); + Utils.LogError($"Error in AddScoreboardTagToPlayer: {ex.Message}"); } } @@ -680,7 +775,10 @@ public void ChangePlayerName(CCSPlayerController player, string name) player.PlayerName = name; Utilities.SetStateChanged(player, "CBasePlayerController", "m_iszPlayerName"); - SharpTimerDebug($"Changed PlayerName to {player.PlayerName}"); + var fakeEvent = new EventNextlevelChanged(false); + fakeEvent.FireEvent(false); + + Utils.LogDebug($"Changed PlayerName to {player.PlayerName}"); } static void SetMoveType(CCSPlayerController player, MoveType_t nMoveType) @@ -704,7 +802,7 @@ public string GetRankColorForChat(CCSPlayerController player) string color = $"{ChatColors.Default}"; if (playerTimer.CachedRank.Contains(UnrankedTitle)) - color = ReplaceVars(UnrankedColor); + color = Utils.ReplaceVars(UnrankedColor); else { @@ -712,7 +810,7 @@ public string GetRankColorForChat(CCSPlayerController player) { if (playerTimer.CachedRank.Contains(rank.Title!)) { - color = ReplaceVars(rank.Color!); + color = Utils.ReplaceVars(rank.Color!); break; } } @@ -727,22 +825,11 @@ public string GetRankColorForChat(CCSPlayerController player) } catch (Exception ex) { - SharpTimerError($"Error in GetRankColorForChat: {ex.Message}"); + Utils.LogError($"Error in GetRankColorForChat: {ex.Message}"); return $"{ChatColors.Default}"; } } - public void SendCommandToEveryone(string command) - { - Utilities.GetPlayers().ForEach(player => - { - if (player is { IsValid: true, IsBot: false } && playerTimers[player.Slot].SoundsEnabled) - { - player.ExecuteClientCommand(command); - } - }); - } - public static (int, int) GetPlayerTeamCount() { int ct_count = 0; @@ -762,20 +849,94 @@ public static (int, int) GetPlayerTeamCount() return (ct_count, t_count); } - public void PlaySound(CCSPlayerController? player, string Sound) + public void PlaySound(CCSPlayerController player, string sound, bool allPlayers = false) + { + if (string.IsNullOrEmpty(sound)) + { + Utils.LogError("PlaySound: Sound string is null or empty"); + return; + } + + var targets = allPlayers + ? Utilities.GetPlayers().Where(p => !p.IsBot && playerTimers.TryGetValue(p.Slot, out var t) && t.SoundsEnabled) + : (!player.IsBot && playerTimers.TryGetValue(player.Slot, out var t) && t.SoundsEnabled) ? new[] { player } : null; + + if (targets == null || targets.Count() <= 0) + return; + + foreach (var target in targets) + { + Server.NextFrame(() => + { + try + { + if (soundeventsEnabled) + target.EmitSound(sound, new(target)); + else + target.ExecuteClientCommand($"play {sound}"); + } + catch (Exception ex) + { + Utils.LogError($"PlaySound: Error playing sound for {target.PlayerName}: {ex.Message}"); + } + }); + } + } + } + + public static class EntityExtends + { + public static bool Valid(this CCSPlayerController? player) { - if (playerTimers[player!.Slot].SoundsEnabled != false && IsAllowedPlayer(player)) - player.ExecuteClientCommand($"play {Sound}"); + if (player == null) return false; + + return player.IsValid && !player.IsBot && !player.IsHLTV; } - public void PrintToChat(CCSPlayerController? player, string message) + public static CCSPlayerPawn? PlayerPawn([NotNullWhen(true)] this CCSPlayerController player) { - player?.PrintToChat($" {Localizer["prefix"]} {message}"); + CCSPlayerPawn? playerPawn = player.PlayerPawn.Value; + + return playerPawn; } - public void PrintToChatAll(string message) + public static CBasePlayerPawn? Pawn([NotNullWhen(true)] this CCSPlayerController player) { - Server.PrintToChatAll($" {Localizer["prefix"]} {message}"); + CBasePlayerPawn? pawn = player.Pawn.Value; + + return pawn; + } + + public static bool TeamT([NotNullWhen(true)] this CCSPlayerController player) + { + return player.Team == CsTeam.Terrorist; + } + public static bool TeamCT([NotNullWhen(true)] this CCSPlayerController player) + { + return player.Team == CsTeam.CounterTerrorist; + } + public static bool TeamSpec([NotNullWhen(true)] this CCSPlayerController player) + { + return player.Team == CsTeam.Spectator; + } + public static bool TeamNone([NotNullWhen(true)] this CCSPlayerController player) + { + return player.Team == CsTeam.None; + } + + public static bool isAdmin([NotNullWhen(true)] this CCSPlayerController player) + { + if (AdminManager.PlayerHasPermissions(player, "@css/ban")) + return true; + + return false; + } + public static bool isVIP([NotNullWhen(true)] this CCSPlayerController player) + { + if (AdminManager.PlayerHasPermissions(player, "@css/reservation")) + return true; + + return false; } } } diff --git a/src/Plugin/Classes.cs b/src/Plugin/Classes.cs index 86746d41..4fb5c4a8 100644 --- a/src/Plugin/Classes.cs +++ b/src/Plugin/Classes.cs @@ -16,7 +16,11 @@ You should have received a copy of the GNU General Public License using System.Text.Json.Serialization; using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Commands; using CounterStrikeSharp.API.Modules.Utils; +using SharpTimerAPI; +using SharpTimerAPI.Events; +using FixVectorLeak; namespace SharpTimer { @@ -25,14 +29,11 @@ public class EntityCache { public List Triggers { get; private set; } public List InfoTeleportDestinations { get; private set; } - public List InfoTargetEntities { get; private set; } public EntityCache() { - Triggers = []; - InfoTeleportDestinations = []; - InfoTargetEntities = []; - UpdateCache(); + Triggers = new(); + InfoTeleportDestinations = new(); } public void UpdateCache() @@ -161,7 +162,7 @@ public enum CurrentMode public double Sync { get; set; } public int GoodSync { get; set; } public int TotalSync { get; set; } - public List Rotation { get; set; } = new List(); + public List Rotation { get; set; } = new List(); //player settings/stats public bool Azerty { get; set; } @@ -172,11 +173,9 @@ public enum CurrentMode public bool GivenWeapon { get; set; } public bool SoundsEnabled { get; set; } public bool BindsDisabled { get; set; } - public bool HideJumpStats { get; set; } public int PlayerFov { get; set; } public int TimesConnected { get; set; } - public int TicksSinceLastCmd { get; set; } - public int TicksSinceLastRankUpdate { get; set; } + public DateTime CmdCooldown { get; set; } //super special stuff for testers public bool IsTester { get; set; } @@ -208,6 +207,9 @@ public enum CurrentMode //set respawn public string? SetRespawnPos { get; set; } public string? SetRespawnAng { get; set; } + //api stuff + public bool RespawnCmdBlocked { get; set; } + public bool TimerCmdBlocked { get; set; } public class ViewAngle { @@ -215,7 +217,7 @@ public class ViewAngle public float Y { get; set; } public float Z { get; set; } - public ViewAngle (QAngle angles) + public ViewAngle (QAngle_t angles) { X = angles.X; Y = angles.Y; @@ -247,45 +249,6 @@ public class CurrentZoneInfo public int CurrentBonusNumber { get; set; } } - public class PlayerJumpStats - { - public int FramesOnGround { get; set; } - public int LastFramesOnGround { get; set; } - public bool OnGround { get; set; } - public bool LastOnGround { get; set; } - public string? LastPosOnGround { get; set; } - public string? LastSpeed { get; set; } - public string? JumpPos { get; set; } - public string? OldJumpPos { get; set; } - public string? JumpSpeed { get; set; } - public bool Jumped { get; set; } - public string? LastJumpType { get; set; } - public bool LastDucked { get; set; } - public bool LandedFromSound { get; set; } - public bool LastLandedFromSound { get; set; } - public int WTicks { get; set; } - - public List