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
|
/*
Cached info about the map's available replay bots stored in an ArrayList.
*/
// =====[ PUBLIC ]=====
// Adds a replay to the cache
void AddToReplayInfoCache(int course, int mode, int style, int timeType)
{
int index = g_ReplayInfoCache.Length;
g_ReplayInfoCache.Resize(index + 1);
g_ReplayInfoCache.Set(index, course, 0);
g_ReplayInfoCache.Set(index, mode, 1);
g_ReplayInfoCache.Set(index, style, 2);
g_ReplayInfoCache.Set(index, timeType, 3);
}
// Use this to sort the cache after finished adding to it
void SortReplayInfoCache()
{
g_ReplayInfoCache.SortCustom(SortFunc_ReplayInfoCache);
}
public int SortFunc_ReplayInfoCache(int index1, int index2, Handle array, Handle hndl)
{
// Do not expect any indexes to be 'equal'
int replayInfo1[RP_CACHE_BLOCKSIZE], replayInfo2[RP_CACHE_BLOCKSIZE];
g_ReplayInfoCache.GetArray(index1, replayInfo1);
g_ReplayInfoCache.GetArray(index2, replayInfo2);
// Compare courses - lower course number goes first
if (replayInfo1[0] < replayInfo2[0])
{
return -1;
}
else if (replayInfo1[0] > replayInfo2[0])
{
return 1;
}
// Same course, so compare mode
else if (replayInfo1[1] < replayInfo2[1])
{
return -1;
}
else if (replayInfo1[1] > replayInfo2[1])
{
return 1;
}
// Same course and mode, so compare style
else if (replayInfo1[2] < replayInfo2[2])
{
return -1;
}
else if (replayInfo1[2] > replayInfo2[2])
{
return 1;
}
// Same course, mode and style so compare time type, assuming can't be identical
else if (replayInfo1[3] == TimeType_Pro)
{
return 1;
}
return -1;
}
// =====[ EVENTS ]=====
void OnMapStart_ReplayCache()
{
if (g_ReplayInfoCache == null)
{
g_ReplayInfoCache = new ArrayList(RP_CACHE_BLOCKSIZE, 0);
}
else
{
g_ReplayInfoCache.Clear();
}
char path[PLATFORM_MAX_PATH];
BuildPath(Path_SM, path, sizeof(path), "%s/%s", RP_DIRECTORY_RUNS, gC_CurrentMap);
DirectoryListing dir = OpenDirectory(path);
// We want to find files that look like "0_KZT_NRM_PRO.rec"
char file[PLATFORM_MAX_PATH], pieces[4][16];
int length, dotpos, course, mode, style, timeType;
while (dir.GetNext(file, sizeof(file)))
{
// Some credit to Influx Timer - https://github.com/TotallyMehis/Influx-Timer
// Check file extension
length = strlen(file);
dotpos = 0;
for (int i = 0; i < length; i++)
{
if (file[i] == '.')
{
dotpos = i;
}
}
if (!StrEqual(file[dotpos + 1], RP_FILE_EXTENSION, false))
{
continue;
}
// Remove file extension
Format(file, dotpos + 1, file);
// Break down file name into pieces
if (ExplodeString(file, "_", pieces, sizeof(pieces), sizeof(pieces[])) != sizeof(pieces))
{
continue;
}
// Extract info from the pieces
course = StringToInt(pieces[0]);
mode = GetModeIDFromString(pieces[1]);
style = GetStyleIDFromString(pieces[2]);
timeType = GetTimeTypeIDFromString(pieces[3]);
if (!GOKZ_IsValidCourse(course) || mode == -1 || style == -1 || timeType == -1)
{
continue;
}
// Add it to the cache
AddToReplayInfoCache(course, mode, style, timeType);
}
SortReplayInfoCache();
delete dir;
}
// =====[ PRIVATE ]=====
static int GetModeIDFromString(const char[] mode)
{
for (int modeID = 0; modeID < MODE_COUNT; modeID++)
{
if (StrEqual(mode, gC_ModeNamesShort[modeID], false))
{
return modeID;
}
}
return -1;
}
static int GetStyleIDFromString(const char[] style)
{
for (int styleID = 0; styleID < STYLE_COUNT; styleID++)
{
if (StrEqual(style, gC_StyleNamesShort[styleID], false))
{
return styleID;
}
}
return -1;
}
static int GetTimeTypeIDFromString(const char[] timeType)
{
for (int timeTypeID = 0; timeTypeID < TIMETYPE_COUNT; timeTypeID++)
{
if (StrEqual(timeType, gC_TimeTypeNames[timeTypeID], false))
{
return timeTypeID;
}
}
return -1;
}
|