| 1 | /* |
| 2 | * LegacyClonk |
| 3 | * |
| 4 | * Copyright (c) RedWolf Design |
| 5 | * Copyright (c) 2017-2021, The LegacyClonk Team and contributors |
| 6 | * |
| 7 | * Distributed under the terms of the ISC license; see accompanying file |
| 8 | * "COPYING" for details. |
| 9 | * |
| 10 | * "Clonk" is a registered trademark of Matthes Bender, used with permission. |
| 11 | * See accompanying file "TRADEMARK" for details. |
| 12 | * |
| 13 | * To redistribute this file separately, substitute the full license texts |
| 14 | * for the above references. |
| 15 | */ |
| 16 | |
| 17 | // statistics |
| 18 | // by peter |
| 19 | |
| 20 | #include <C4Include.h> |
| 21 | #include <C4Stat.h> |
| 22 | |
| 23 | #include <C4Game.h> |
| 24 | |
| 25 | // ** implemetation of C4MainStat |
| 26 | |
| 27 | C4MainStat::C4MainStat() |
| 28 | : bStatFileOpen(false), pFirst(nullptr) {} |
| 29 | |
| 30 | C4MainStat::~C4MainStat() |
| 31 | { |
| 32 | CloseStatFile(); |
| 33 | } |
| 34 | |
| 35 | void C4MainStat::RegisterStat(C4Stat *pStat) |
| 36 | { |
| 37 | // add to list |
| 38 | if (!pFirst) |
| 39 | { |
| 40 | pFirst = pStat; |
| 41 | pStat->pNext = nullptr; |
| 42 | pStat->pPrev = nullptr; |
| 43 | } |
| 44 | else |
| 45 | { |
| 46 | pStat->pNext = pFirst; |
| 47 | pFirst->pPrev = pStat; |
| 48 | pStat->pPrev = nullptr; |
| 49 | pFirst = pStat; |
| 50 | } |
| 51 | } |
| 52 | |
| 53 | void C4MainStat::UnRegStat(C4Stat *pStat) |
| 54 | { |
| 55 | // first item? |
| 56 | if (!pStat->pPrev) |
| 57 | { |
| 58 | pFirst = pStat->pNext; |
| 59 | pStat->pNext = nullptr; |
| 60 | } |
| 61 | // last item? |
| 62 | else if (!pStat->pNext) |
| 63 | { |
| 64 | pStat->pPrev->pNext = nullptr; |
| 65 | pStat->pPrev = nullptr; |
| 66 | } |
| 67 | else |
| 68 | { |
| 69 | pStat->pNext->pPrev = pStat->pPrev; |
| 70 | pStat->pPrev->pNext = pStat->pNext; |
| 71 | pStat->pNext = nullptr; |
| 72 | pStat->pPrev = nullptr; |
| 73 | } |
| 74 | } |
| 75 | |
| 76 | void C4MainStat::Reset() |
| 77 | { |
| 78 | CloseStatFile(); |
| 79 | for (C4Stat *pAkt = pFirst; pAkt; pAkt = pAkt->pNext) |
| 80 | pAkt->Reset(); |
| 81 | } |
| 82 | |
| 83 | void C4MainStat::ResetPart() |
| 84 | { |
| 85 | for (C4Stat *pAkt = pFirst; pAkt; pAkt = pAkt->pNext) |
| 86 | pAkt->ResetPart(); |
| 87 | } |
| 88 | |
| 89 | void C4MainStat::Show() |
| 90 | { |
| 91 | // output the whole statistic (to stat.txt) |
| 92 | |
| 93 | // open file |
| 94 | if (!bStatFileOpen) |
| 95 | OpenStatFile(); |
| 96 | |
| 97 | // count stats |
| 98 | unsigned int iCnt = 0; |
| 99 | C4Stat *pAkt; |
| 100 | for (pAkt = pFirst; pAkt; pAkt = pAkt->pNext) |
| 101 | iCnt++; |
| 102 | |
| 103 | // create array |
| 104 | C4Stat **StatArray = new C4Stat *[iCnt]; |
| 105 | bool *bHS = new bool[iCnt]; |
| 106 | |
| 107 | // sort it |
| 108 | unsigned int i, ii; |
| 109 | for (ii = 0; ii < iCnt; ii++) bHS[ii] = false; |
| 110 | for (i = 0; i < iCnt; i++) |
| 111 | { |
| 112 | C4Stat *pBestStat; |
| 113 | unsigned int iBestNr = ~0u; |
| 114 | |
| 115 | for (ii = 0, pAkt = pFirst; ii < iCnt; ii++, pAkt = pAkt->pNext) |
| 116 | if (!bHS[ii]) |
| 117 | if (iBestNr == ~0u) |
| 118 | { |
| 119 | iBestNr = ii; |
| 120 | pBestStat = pAkt; |
| 121 | } |
| 122 | else if (stricmp(s1: pBestStat->strName, s2: pAkt->strName) > 0) |
| 123 | { |
| 124 | iBestNr = ii; |
| 125 | pBestStat = pAkt; |
| 126 | } |
| 127 | |
| 128 | if (iBestNr == ~0u) |
| 129 | break; |
| 130 | bHS[iBestNr] = true; |
| 131 | |
| 132 | StatArray[i] = pBestStat; |
| 133 | } |
| 134 | |
| 135 | delete[] bHS; |
| 136 | |
| 137 | fprintf(stream: StatFile, format: "** Stat\n" ); |
| 138 | |
| 139 | // output in order |
| 140 | for (i = 0; i < iCnt; i++) |
| 141 | { |
| 142 | pAkt = StatArray[i]; |
| 143 | |
| 144 | // output it! |
| 145 | if (pAkt->iCount) |
| 146 | fprintf(stream: StatFile, format: "%s: n = %d, t = %d, td = %.2f\n" , |
| 147 | pAkt->strName, pAkt->iCount, pAkt->iTimeSum, |
| 148 | double(pAkt->iTimeSum) / std::max<int>(a: 1, b: pAkt->iCount - 100) * 1000); |
| 149 | } |
| 150 | |
| 151 | // delete... |
| 152 | delete[] StatArray; |
| 153 | |
| 154 | // ok. job done |
| 155 | fputs(s: "** Stat end\n" , stream: StatFile); |
| 156 | fflush(stream: StatFile); |
| 157 | } |
| 158 | |
| 159 | void C4MainStat::ShowPart() |
| 160 | { |
| 161 | C4Stat *pAkt; |
| 162 | |
| 163 | // open file |
| 164 | if (!bStatFileOpen) |
| 165 | OpenStatFile(); |
| 166 | |
| 167 | // insert tick nr |
| 168 | fprintf(stream: StatFile, format: "** PartStat begin %d\n" , Game.FrameCounter); |
| 169 | |
| 170 | // insert all stats |
| 171 | for (pAkt = pFirst; pAkt; pAkt = pAkt->pNext) |
| 172 | fprintf(stream: StatFile, format: "%s: n=%d, t=%d\n" , pAkt->strName, pAkt->iCountPart, pAkt->iTimeSumPart); |
| 173 | |
| 174 | // insert part stat end idtf |
| 175 | fprintf(stream: StatFile, format: "** PartStat end\n" ); |
| 176 | fflush(stream: StatFile); |
| 177 | } |
| 178 | |
| 179 | // stat file handling |
| 180 | void C4MainStat::OpenStatFile() |
| 181 | { |
| 182 | if (bStatFileOpen) return; |
| 183 | |
| 184 | // open & reset file |
| 185 | StatFile = fopen(filename: "stat.txt" , modes: "w" ); |
| 186 | |
| 187 | // success? |
| 188 | if (!StatFile) |
| 189 | return; |
| 190 | |
| 191 | bStatFileOpen = true; |
| 192 | } |
| 193 | |
| 194 | void C4MainStat::CloseStatFile() |
| 195 | { |
| 196 | if (!bStatFileOpen) return; |
| 197 | |
| 198 | // open & reset file |
| 199 | fclose(stream: StatFile); |
| 200 | |
| 201 | bStatFileOpen = false; |
| 202 | } |
| 203 | |
| 204 | // ** implemetation of C4Stat |
| 205 | |
| 206 | C4Stat::C4Stat(const char *strnName) |
| 207 | : strName(strnName) |
| 208 | { |
| 209 | Reset(); |
| 210 | getMainStat()->RegisterStat(pStat: this); |
| 211 | } |
| 212 | |
| 213 | C4Stat::~C4Stat() |
| 214 | { |
| 215 | getMainStat()->UnRegStat(pStat: this); |
| 216 | } |
| 217 | |
| 218 | void C4Stat::Reset() |
| 219 | { |
| 220 | iStartCalled = 0; |
| 221 | |
| 222 | iTimeSum = 0; |
| 223 | iCount = 0; |
| 224 | |
| 225 | ResetPart(); |
| 226 | } |
| 227 | |
| 228 | void C4Stat::ResetPart() |
| 229 | { |
| 230 | iTimeSumPart = 0; |
| 231 | iCountPart = 0; |
| 232 | } |
| 233 | |
| 234 | C4MainStat *C4Stat::getMainStat() |
| 235 | { |
| 236 | static C4MainStat *pMainStat = new C4MainStat(); |
| 237 | return pMainStat; |
| 238 | } |
| 239 | |