-
Notifications
You must be signed in to change notification settings - Fork 22
Expand file tree
/
Copy pathRaceTracker.hpp
More file actions
252 lines (218 loc) · 8.07 KB
/
Copy pathRaceTracker.hpp
File metadata and controls
252 lines (218 loc) · 8.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
/**
* Alicia Server - dedicated server software
* Copyright (C) 2024 Story Of Alicia
*
* 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 2 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
**/
#ifndef RACETRACKER_HPP
#define RACETRACKER_HPP
#include "server/tracker/Tracker.hpp"
#include <libserver/data/DataDefinitions.hpp>
#include <libserver/network/command/proto/CommonStructureDefinitions.hpp>
#include <array>
#include <chrono>
#include <map>
#include <unordered_map>
#include <unordered_set>
namespace server::tracker
{
//! Invalid course time represents a did not finish state in the client scoreboard.
constexpr uint32_t InvalidCourseTime = std::numeric_limits<uint32_t>::max();
constexpr std::chrono::milliseconds EventThrottleDuration{250};
//! A race tracker.
class RaceTracker
{
public:
//! A per-racer event item (e.g. egg) visible only to one racer.
struct EventItem
{
Oid oid{};
uint32_t itemType{};
protocol::Vector3 position{};
};
//! A racer.
struct Racer
{
enum class State
{
Disconnected,
Loading,
Racing,
Finishing,
};
using Team = protocol::TeamColor;
struct ItemInstance
{
std::chrono::steady_clock::time_point expiryTimePoint;
};
Oid oid{InvalidEntityOid};
State state{State::Disconnected};
Team team{Team::Solo};
//! The racer's position in the world, as a vector.
protocol::Vector3 worldPosition{};
uint32_t starPointValue{};
uint32_t jumpComboValue{};
uint32_t courseTime{InvalidCourseTime};
std::optional<uint32_t> magicItem{};
//! The racer's progress on the race track.
//! Normalised by the client to: 0.0f <= x <= 1.0f
float raceProgress{};
//! A set of tracked items in racer's proximity.
std::unordered_set<Oid> trackedDecks;
//! A deck cooldown time point tracker.
std::unordered_map<Oid, std::chrono::steady_clock::time_point> deckCooldown;
//! Per-racer event items (e.g. eggs) visible only to this racer.
std::vector<EventItem> eventItems;
//! Active skill effects indexed by skillEffectId (0-23).
static constexpr size_t EffectCount = 24;
std::array<bool, EffectCount> effects{};
//! Per-effect generation counter, incremented on each apply, used to invalidate stale removal timers.
std::array<uint32_t, EffectCount> effectGenerations{};
//! Rank of the currently active removeMagic attack (0 = none active).
uint32_t attackRank{};
std::chrono::steady_clock::time_point dragonReceivedAt{};
//! Anchor for time-based magic gauge regen. Default-constructed = uninitialized,
//! lazily set to raceStartTimePoint on the first regen tick.
std::chrono::steady_clock::time_point lastGaugeUpdateTimePoint{
std::chrono::steady_clock::time_point::max()};
//! Snapshot of the racer's mount stats taken at race start, used by per-tick
//! magic-mode calculations to avoid a DataDirector lookup on every pos-update.
struct MountStatsSnapshot
{
uint32_t agility{};
uint32_t ambition{};
uint32_t rush{};
uint32_t endurance{};
uint32_t courage{};
};
MountStatsSnapshot mountStats{};
struct MagicTargetInfo
{
uint16_t casterOid;
uint16_t effectInstanceId;
};
std::optional<MagicTargetInfo> pendingMagicTarget{};
};
//! An item deck.
struct ItemDeck
{
//! An object identifier.
Oid oid{};
//! A list of items spawnable in this item deck.
std::vector<uint32_t> items{};
//!
uint32_t currentItem{};
//! A respawn time for the items in the deck.
std::chrono::milliseconds respawnTime{};
//! A time point of the next respawn.
std::chrono::steady_clock::time_point respawnTimePoint{
std::chrono::steady_clock::time_point::min()};
protocol::Vector3 position{};
};
//! An event
struct Event
{
uint32_t id{};
std::chrono::steady_clock::time_point throttledUntil{};
};
struct TeamInfo
{
uint32_t points{0};
uint32_t boostCount{0};
bool gaugeLocked{false};
};
TeamInfo blueTeam{};
TeamInfo redTeam{};
//! A flag to indicate whether all items should be spawned.
bool firstPassItemSpawn{true};
//! An object map.
using RacerObjectMap = std::map<data::Uid, Racer>;
//! A deck item object map.
using ItemDeckMap = std::map<Oid, ItemDeck>;
//! An event map.
using EventMap = std::unordered_map<uint32_t, Event>;
//! Adds a racer for tracking.
//! @param characterUid Character UID.
//! @returns A reference to the racer record.
Racer& AddRacer(data::Uid characterUid);
//! Removes a racer from tracking.
//! @param characterUid Character UID.
void RemoveRacer(data::Uid characterUid);
//! Returns whether the character is a racer.
//! @param characterUid Character UID.
//! @return `true` if the character is a racer,
//! otherwise returns `false`;
bool IsRacer(data::Uid characterUid) const;
//! Returns reference to the racer record.
//! @returns Racer record.
[[nodiscard]] Racer& GetRacer(data::Uid characterUid);
//! Returns a reference to all racer records.
//! @return Reference to racer records.
[[nodiscard]] RacerObjectMap& GetRacers();
//! Adds an item for tracking.
//! @returns A reference to the new item record.
ItemDeck& AddItemDeck();
//! Removes an item from tracking.
//! @param itemId Item OID.
void RemoveItemDeck(Oid itemId);
//! Returns reference to the item record.
//! @param itemId Item OID.
//! @returns Item record.
[[nodiscard]] ItemDeck& GetItemDeck(Oid itemId);
//! Returns a reference to all item records.
//! @return Reference to item records.
[[nodiscard]] ItemDeckMap& GetItemDecks();
//! Returns a reference to all of the event records.
//! @return Reference to event records.
[[nodiscard]] EventMap& GetEvents();
//! Checks and throttles an event.
//! @param eventId Event ID.
//! @returns True if event exists and is throttled, else event is tracked.
bool IsEventThrottled(uint32_t eventId);
//! Adds a per-racer event item for the given character.
//! @returns Reference to the new event item record.
EventItem& AddEventItem(data::Uid characterUid);
//! Finds a per-racer event item by OID.
//! @returns The OID if found, otherwise InvalidEntityOid.
Oid FindEventItem(data::Uid characterUid, Oid oid);
//! Returns reference to a per-racer event item by OID.
//! @throws std::runtime_error if not found.
[[nodiscard]] EventItem& GetEventItem(data::Uid characterUid, Oid oid);
//! Removes a per-racer event item by OID.
void RemoveEventItem(data::Uid characterUid, Oid oid);
//! Returns the next object instance ID and increments the internal counter.
//! @param increment The value to increment the internal counter by.
//! @returns The next object instance ID before incrementing.
uint16_t GetNextEffectInstanceIdAndIncrementBy(uint16_t increment);
void Clear();
private:
//! Mapping between character UIDs and their assigned OIDs.
//! It's important these persist across races in a room as the client does not clear assignments internally.
std::unordered_map<data::Uid, Oid> _characterOids;
//! Next OID for new character entities (100+).
Oid _nextCharacterOid = 100;
//! Next OID for item entities (1–99, reset each race).
Oid _nextItemDeckOid = 1;
//! Racer entities.
RacerObjectMap _racers;
//! Item deck entities.
ItemDeckMap _itemDecks;
//! Tracked race map events.
EventMap _events;
//! Next effect instance ID.
uint16_t _nextEffectInstanceId = 0;
};
} // namespace server::tracker
#endif // RACETRACKER_HPP