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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 7.0.x
dotnet-version: 8.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
Expand Down
198 changes: 177 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,175 @@
# PLEASE DO NOT USE THIS, IT IS NOT COMPLETE AND IS AN ACTIVE WORK-IN-PROGRESS. ISSUES HAVE BEEN DISABLED FOR THIS REASON.
# EVERYONE IS WELCOME TO BUILD UP ON THIS PROJECT AND CONTRIBUTE. ISSUES ARE DISABLED FOR THE TIME BEING
## Please join the Discord: https://discord.cs.surf

# Timer
Core plugin for CS2 Surf Servers. This project is aimed to be fully open-source with the goal of uniting all of CS2 surf towards building the game mode.
<br>
<details>
<summary>Center HUD Speedometer</summary>
<p>Different time formatting is available in the code base but not implemented for players to change it themselves. Refer to <strong>PlayerTimer.TimeFormatStyle</strong> in codebase</p>
<ul>
<li><strong>Map</strong>
<p><em>Shown while player starts their Map Run from the map start zone (!r)</em></p>
<details>
<summary>Zone name + Start speed</summary>
<p>Map Run mode:</p>
<img src="https://i.imgur.com/IqUL067.png" alt="Map Start Zone">
<img src="https://i.imgur.com/ITooApq.png" alt="Map Start Zone exit">
</details>
</li>
<li><strong>Checkpoints</strong>
<p><em>Only shown during Map Run after exiting a Checkpoint/Stage zone</em></p>
<details>
<summary>Zone name + Start speed</summary>
<p>Checkpoint comparison:</p>
<img src="https://i.imgur.com/recf26f.png" alt="Checkpoint Start Zone exit">
</details>
</li>
<li><strong>Stages</strong>
<p><em>Only shown while in Stage Mode, accessed through !s X or !stage X commands</em></p>
<details>
<summary>Zone name + Start speed</summary>
<p>Stage Run mode:</p>
<img src="https://i.imgur.com/Zi3HN2b.png" alt="Stages Start Zone">
<img src="https://i.imgur.com/uYyumVJ.png" alt="Stages Start Zone exit">
</details>
</li>
<li><strong>Bonuses</strong>
<p><em>Only shown while in Bonus Mode, accessed through !b X or !bonus X commands</em></p>
<details>
<summary>Zone name + Start speed</summary>
<p>Bonus Run mode:</p>
<img src="https://i.imgur.com/Tlmdq9r.png" alt="Bonuses Start Zone">
<img src="https://i.imgur.com/Rfm9qG4.png" alt="Bonuses Start Zone exit">
</details>
</li>
</ul>
</details>

# Goals
<details>
<summary>Replays</summary>
<p>Currently only accessible through the <strong>!spec</strong> command and cycling the players. Different time formatting is available in the code base but not implemented for players to change it themselves. Refer to <strong>PlayerTimer.TimeFormatStyle</strong> in codebase</p>
<p>Replays are saved for all types of runs Map/Stage/Bonus (and future Styles) regardless if they are a World Record or just a Personal Best. No functionality is implemented for replaying PB replays yet, feel free to add and Pull Request it</p>
<ul>
<li><strong>Map</strong>
<details>
<summary>Spectating Map Replay</summary>
<p>Map Run:</p>
<img src="https://i.imgur.com/gZutBkS.png" alt="Map Run Replay">
</details>
</li>
<li><strong>Stages</strong>
<details>
<summary>Spectating Stage Replay</summary>
<p>Stage Run:</p>
<img src="https://i.imgur.com/tL7kM1l.png" alt="Stages Run Replay">
</details>
</li>
<li><strong>Bonuses</strong>
<p>Bonus Replays are also available but no screenshots at the time of writing.</p>
</li>
<li><strong>Scoreboard</strong>
<details>
<summary>Currently available replays for the map</summary>
<p>Scoreboard:</p>
<img src="https://i.imgur.com/RNTTFgi.png" alt="Scoreboard showing all available Replays">
</details>
</li>
</ul>
</details>


<details>
<summary>Chat Messages</summary>
<ul>
<li><strong>Map Run</strong>
<details>
<summary>Improving a Record</summary>
<p>Timer sends a chat message to all players upon a player beating the Map Record. Missing it sends a message only to the player:</p>
<img src="https://i.imgur.com/ggCNjZ8.png" alt="Beating a Map record">
</details>
<details>
<summary>Checkpoint Comparison</summary>
<p>Timer sends a chat message the player comparing their PB checkpoint times with the current run (value in brackets after the time indicate the Speed):</p>
<img src="https://i.imgur.com/ts4FfhY.png" alt="Checkpoints Comparison">
</details>
</li>
<li><strong>Stage Records</strong>
<details>
<summary>New Stage record and improving Stage record</summary>
<p>Timer sends a chat message to all players upon a player beating a Stage/Bonus/Map record. Different scenarios for missed/comparing times are also available and shown in chat but only to the player who is doing the run:</p>
<img src="https://i.imgur.com/MNehNmv.png" alt="Stage Records and comparisons">
</details>
</li>
<li><strong>QOL</strong>
<details>
<summary>Player Connected + Map Info (!mi / !tier)</summary>
<p>LL is used for Local development and testing:</p>
<img src="https://i.imgur.com/JtHwYnx.png" alt="Player Connected + Map Info">
</details>
<details>
<summary>Player Rank</summary>
<p>Displays the rank of the player on the current map:</p>
<img src="https://i.imgur.com/4BXJjMv.png" alt="Player Rank">
</details>
</li>
</ul>
</details>

<details>
<summary>Player Commands</summary>
<p>We recommend making binds using the <strong>Console</strong> commands, chat commands may flood the server and not always work.</p>
<ul>
<li><strong>Saveloc (Practice Mode)</strong>
<details>
<summary>Save the current location</summary>
<p>Chat: !saveloc</p>
<p>Console: css_saveloc</p>
</details>
<details>
<summary>Teleport to the last saved location</summary>
<p>Chat: !tele</p>
<p>Console: css_tele</p>
</details>
<details>
<summary>Teleport to the previous saved location</summary>
<p>Chat: !teleprev</p>
<p>Console: css_teleprev</p>
</details>
<details>
<summary>Teleport to the next saved location</summary>
<p>Chat: !telenext</p>
<p>Console: css_telenext</p>
</details>
</li>
</ul>
<ul>
<li><strong>Spectate</strong>
<details>
<summary>Enter Spectator Mode</summary>
<p>Chat: !spec</p>
<p>Console: css_spec</p>
</details>
<details>
<summary>Exiting Spectator Mode</summary>
<p>No command currently available to go back to Play Mode (time may NOT be reset and you will loose your progress post entering Spectator Mode)</p>
<p>Open team choosing menu <strong>M</strong> and select CT</p>
</details>
</li>
</ul>
</details>
</br>

# Main list with tasks (more details can be found [here](https://github.com/CS2Surf/Timer/blob/dev/TODO)):
*Note: This is not definitive/complete and simply serves as a reference for what we should try to achieve. Subject to change.*
Bold & Italics = being worked on.

- [ ] Database
- [ ] MySQL database schema ([W.I.P Design Diagram](https://dbdiagram.io/d/CS2Surf-Timer-DB-Schema-6560b76b3be1495787ace4d2))
- [X] MySQL database schema ([Design Diagram](https://dbdiagram.io/d/CS2Surf-Timer-DB-Schema-6560b76b3be1495787ace4d2))
- [ ] Plugin auto-create tables for easier setup?
- [X] Base database class implementation
- [ ] Maps
- [X] Maps
- [X] Implement map info object (DB)
- [ ] Zoning
- [X] Zoning
- [X] Hook zones from map triggers
- [X] Map start/end zones
- [X] Stage zones
Expand All @@ -23,45 +178,46 @@ Bold & Italics = being worked on.
- [X] Support for stages/checkpoints
- [X] Hook to their start/end zones
- [X] Save/Compare checkpoint times
- [ ] Save Stage times
- [X] Save Stage times
- [X] Support for bonuses
- [X] Hook to their start/end zones
- [ ] Save Bonus times
- [X] Save Bonus times
- [X] Start/End trigger touch hooks
- [X] Load zone information automatically from standardised triggers: https://github.com/CS2Surf/Timer/wiki/CS2-Surf-Mapping
- [X] _**Support for stages (`/rs`, teleporting with `/s`)**_
- [ ] _**Support for bonuses (`/rs`, teleporting with `/b #`)**_
- [ ] _**Start/End touch hooks implemented for all zones**_
- [X] Support for stages (`/rs`, teleporting with `/s`)
- [X] Support for bonuses (`/rs`, teleporting with `/b #`)
- [X] Start/End touch hooks implemented for all zones
- [ ] Surf configs
- [X] Server settings configuration
- [ ] Plugin configuration
- [X] Database configuration
- [ ] Timing
- [X] Timing
- [X] Base timer class implementation
- [X] Base timer HUD implementation
- [X] Prespeed measurement and display
- [ ] Save/load times
- [X] Save/load times
- [x] Map times
- [x] Checkpoint times
- [ ] Stage times
- [ ] Bonus times
- [X] Stage times
- [X] Bonus times
- [X] Practice Mode implementation
- [ ] Announce records to Discord
- [ ] Stretch goal: sub-tick timing
- [ ] Player Data
- [X] Base player class
- [ ] **_Player stat classes_**
- [ ] Player stat classes
- [ ] Profile implementation (DB)
- [ ] Points/Skill Groups (DB)
- [ ] Player settings (DB)
- [x] Replays - Not tracking Stage/Bonus times but Replay functionality for them is there
- [x] Replays
- [x] Personal Best
- [x] Map Record
- [ ] Stage Record
- [ ] Bonus Record
- [X] Stage Record
- [X] Bonus Record
- [x] World Record
- [X] Map Record
- [ ] Stage Record
- [ ] Bonus Record
- [X] Stage Record
- [X] Bonus Record
- [ ] Style implementation (SW, HSW, BW)
- [ ] Paint (?)
- [ ] API Integration (Repo can be found [here](https://github.com/CS2Surf/CS2-Surf-API))
65 changes: 65 additions & 0 deletions TODO
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
- Re-add the MySQL queries in code and make it switch between API and DB functions
- Map Time is NOT being saved with API
- Make configs generate themselves inside the `./configs/plugins/...` folder
- Fix loading MapTimes for each type (stage, bonus, maps)
- API
- DB
- Change `DB_QUERY_MAP_GET_RUNS` query with `DB_QUERY_MAP_GET_RECORD_RUNS_AND_COUNT` in API and edit code in plugin
- Change `DB_QUERY_PB_GET_RUNTIME` query in API

- Double check the Start/End velocities for End Zone,Checkpoints, Stages, Bonuses
+ Maps
+ Checkpoints
- Stages
- Try and get the Start/End velocity values from the Checkpoint object in Map Run
+ Bonuses

- Using `!spec` from any start zone and going back to CT starts your timer

- Try and determine Left/Right side for Bonuses (surf_ace)
- Try and determine Left/Right side for Maps
- Try and determine Left/Right side for Stages
# Done
+ Hibernation fucks up the creation of `CurrentMap`, if nobody has joined the first map it was on and you change to another map, server segfaults. I guess a query is being held?? :think:
+ Solution is to use `Server.NextWorldUpdate` as hibernation stops all `Timer`s :peepoHappy:
+ Introduce `async` for queries and some methods
+ Make Database spawn a new connection for each query to avoid `Connection in use` error
+ Add notes to apply `using` blocks for certain methods for proper operation
+ Move **PlayerProfile** queries to the respective class
+ Move **Map** queries to the respective class
+ Total Completions for a map are wrong in HUD
+ Add `Situation` to each `ReplayFrame` and load it properly
+ Fix `STAGE_EXIT_ZONE` situations - not triggered (logic in `TriggerEndTouch` is most likely bad)
+ Fix Map Replays
+ Reload after setting a new WR
+ Load if no replay existed before a new run
+ Use the `ReplayFrameSituation` for determining where to cut replays
+ Do not cut replay as soon as we enter end zone (determined by the AddTimer amount for `SaveMapTime`)
+ Double check the Checkpoints comparison messages
+ 1st run: [CS2 Surf] CP [1]: 02.468 (1083) [PB: N/A (N/A) | WR: N/A (N/A)]
+ 2nd run: [CS2 Surf] CP [1]: 02.421 (1128) [PB: +02.390 (+46) | WR: +02.390 (+46)]
+ Fix Stage replays
+ Track the times even during Map Run on staged maps
+ Include the pre-strafe
+ Load all of them instead of overwriting and cycle (maybe make StageWR a Dictionary)
+ Reload them after setting a new Stage WR
+ Load if no replay existed before
+ Use the `ReplayFrameSituation` for determining where to cut replays
+ Save stage replays when `IsStageMode` is enabled
+ Use seperate method
+ Save the correct amount of `Ticks` for stage runs during map run
+ Use seperate method
+ Save the last stage time - triggered in `END_ZONE_ENTER`
+ `IsStageMode`
+ Use seperate method
+ Map run
+ Use seperate method
+ When loading new stage replays the cycling of them does not work
+ First ever map run does not save Checkpoints, check if we wait to retrieve the MapTime_ID before trying to insert Checkpoints
+ Trim different type of replays based on situations
+ Map Replays
+ Stage Replays during Map runs
+ Stage Replays in `IsStageMode`
+ Bonus Replays
+ Replay bots are not being spawned on `Linear` maps
+ Needs the CS2Fixes NAV mesh patch to work with our implementation
41 changes: 41 additions & 0 deletions src/ST-API/Api.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System.Net.Http.Json;

namespace SurfTimer;

internal class ApiCall
{
public static async Task Api_Save_Stage_MapTime(Player player)
{
// This is a trick to record the time before the player exits the start zone
int last_exit_tick = player.ReplayRecorder.LastExitTick();
int last_enter_tick = player.ReplayRecorder.LastEnterTick();

// player.Controller.PrintToChat($"CS2 Surf DEBUG >> OnTriggerStartTouch -> Last Exit Tick: {last_exit_tick} | Current Frame: {player.ReplayRecorder.Frames.Count}");

int stage_run_time = player.ReplayRecorder.Frames.Count - 1 - last_exit_tick; // Would like some check on this
int time_since_last_enter = player.ReplayRecorder.Frames.Count - 1 - last_enter_tick;

int tt = -1;
if (last_exit_tick - last_enter_tick > 2 * 64)
tt = last_exit_tick - 2 * 64;
else
tt = last_enter_tick;

API_CurrentRun stage_time = new()
{
player_id = player.Profile.ID,
map_id = player.CurrMap.ID,
style = player.Timer.Style,
type = 2,
stage = player.Timer.Stage - 1,
run_time = stage_run_time,
run_date = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
replay_frames = player.ReplayRecorder.SerializeReplayPortion(tt, time_since_last_enter)

};

await ApiMethod.POST(Config.API.Endpoints.ENDPOINT_CR_SAVE_STAGE_TIME, stage_time);
// player.Stats.LoadStageTime(player);
// await CurrentMap.ApiGetMapRecordAndTotals(); // Reload the Map record and totals for the HUD
}
}
Loading
Loading