Files
@ r28486:aff297ed5a05
Branch filter:
Location: cpp/openttd-patchpack/source/src/base_media_base.h
r28486:aff297ed5a05
12.5 KiB
text/x-c
Codechange: Allow constexpr NWidgetPart construction.
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 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 | /*
* This file is part of OpenTTD.
* OpenTTD 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, version 2.
* OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file base_media_base.h Generic functions for replacing base data (graphics, sounds). */
#ifndef BASE_MEDIA_BASE_H
#define BASE_MEDIA_BASE_H
#include "fileio_func.h"
#include "gfx_type.h"
#include "textfile_type.h"
#include "textfile_gui.h"
#include "3rdparty/md5/md5.h"
#include <unordered_map>
/* Forward declare these; can't do 'struct X' in functions as older GCCs barf on that */
struct IniFile;
struct ContentInfo;
/** Structure holding filename and MD5 information about a single file */
struct MD5File {
/** The result of a checksum check */
enum ChecksumResult {
CR_UNKNOWN, ///< The file has not been checked yet
CR_MATCH, ///< The file did exist and the md5 checksum did match
CR_MISMATCH, ///< The file did exist, just the md5 checksum did not match
CR_NO_FILE, ///< The file did not exist
};
std::string filename; ///< filename
MD5Hash hash; ///< md5 sum of the file
std::string missing_warning; ///< warning when this file is missing
ChecksumResult check_result; ///< cached result of md5 check
ChecksumResult CheckMD5(Subdirectory subdir, size_t max_size) const;
};
/**
* Information about a single base set.
* @tparam T the real class we're going to be
* @tparam Tnum_files the number of files in the set
* @tparam Tsearch_in_tars whether to search in the tars or not
*/
template <class T, size_t Tnum_files, bool Tsearch_in_tars>
struct BaseSet {
typedef std::unordered_map<std::string, std::string> TranslatedStrings;
/** Number of files in this set */
static const size_t NUM_FILES = Tnum_files;
/** Whether to search in the tars or not. */
static const bool SEARCH_IN_TARS = Tsearch_in_tars;
/** Internal names of the files in this set. */
static const char * const *file_names;
std::string name; ///< The name of the base set
std::string url; ///< URL for information about the base set
TranslatedStrings description; ///< Description of the base set
uint32_t shortname; ///< Four letter short variant of the name
uint32_t version; ///< The version of this base set
bool fallback; ///< This set is a fallback set, i.e. it should be used only as last resort
MD5File files[NUM_FILES]; ///< All files part of this set
uint found_files; ///< Number of the files that could be found
uint valid_files; ///< Number of the files that could be found and are valid
T *next; ///< The next base set in this list
/** Free everything we allocated */
~BaseSet()
{
delete this->next;
}
/**
* Get the number of missing files.
* @return the number
*/
int GetNumMissing() const
{
return Tnum_files - this->found_files;
}
/**
* Get the number of invalid files.
* @note a missing file is invalid too!
* @return the number
*/
int GetNumInvalid() const
{
return Tnum_files - this->valid_files;
}
bool FillSetDetails(const IniFile &ini, const std::string &path, const std::string &full_filename, bool allow_empty_filename = true);
void CopyCompatibleConfig([[maybe_unused]] const T &src) {}
/**
* Get the description for the given ISO code.
* It falls back to the first two characters of the ISO code in case
* no match could be made with the full ISO code. If even then the
* matching fails the default is returned.
* @param isocode the isocode to search for
* @return the description
*/
const std::string &GetDescription(const std::string &isocode) const
{
if (!isocode.empty()) {
/* First the full ISO code */
auto desc = this->description.find(isocode);
if (desc != this->description.end()) return desc->second;
/* Then the first two characters */
desc = this->description.find(isocode.substr(0, 2));
if (desc != this->description.end()) return desc->second;
}
/* Then fall back */
return this->description.at(std::string{});
}
/**
* Get string to use when listing this set in the settings window.
* If there are no invalid files, then this is just the set name,
* otherwise a string is formatted including the number of invalid files.
* @return the string to display.
*/
std::string GetListLabel() const
{
if (this->GetNumInvalid() == 0) return this->name;
SetDParamStr(0, this->name);
SetDParam(1, this->GetNumInvalid());
return GetString(STR_BASESET_STATUS);
}
/**
* Calculate and check the MD5 hash of the supplied file.
* @param file The file get the hash of.
* @param subdir The sub directory to get the files from.
* @return
* - #CR_MATCH if the MD5 hash matches
* - #CR_MISMATCH if the MD5 does not match
* - #CR_NO_FILE if the file misses
*/
static MD5File::ChecksumResult CheckMD5(const MD5File *file, Subdirectory subdir)
{
return file->CheckMD5(subdir, SIZE_MAX);
}
/**
* Search a textfile file next to this base media.
* @param type The type of the textfile to search for.
* @return The filename for the textfile.
*/
std::optional<std::string> GetTextfile(TextfileType type) const
{
for (uint i = 0; i < NUM_FILES; i++) {
auto textfile = ::GetTextfile(type, BASESET_DIR, this->files[i].filename);
if (textfile.has_value()) {
return textfile;
}
}
return std::nullopt;
}
};
/**
* Base for all base media (graphics, sounds)
* @tparam Tbase_set the real set we're going to be
*/
template <class Tbase_set>
class BaseMedia : FileScanner {
protected:
static Tbase_set *available_sets; ///< All available sets
static Tbase_set *duplicate_sets; ///< All sets that aren't available, but needed for not downloading base sets when a newer version than the one on BaNaNaS is loaded.
static const Tbase_set *used_set; ///< The currently used set
bool AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename) override;
/**
* Get the extension that is used to identify this set.
* @return the extension
*/
static const char *GetExtension();
public:
/**
* Determine the graphics pack that has to be used.
* The one with the most correct files wins.
* @return true if a best set has been found.
*/
static bool DetermineBestSet();
/** Do the scan for files. */
static uint FindSets()
{
BaseMedia<Tbase_set> fs;
/* Searching in tars is only done in the old "data" directories basesets. */
uint num = fs.Scan(GetExtension(), Tbase_set::SEARCH_IN_TARS ? OLD_DATA_DIR : OLD_GM_DIR, Tbase_set::SEARCH_IN_TARS);
return num + fs.Scan(GetExtension(), BASESET_DIR, Tbase_set::SEARCH_IN_TARS);
}
static Tbase_set *GetAvailableSets();
static bool SetSet(const Tbase_set *set);
static bool SetSetByName(const std::string &name);
static bool SetSetByShortname(uint32_t shortname);
static void GetSetsList(std::back_insert_iterator<std::string> &output_iterator);
static int GetNumSets();
static int GetIndexOfUsedSet();
static const Tbase_set *GetSet(int index);
static const Tbase_set *GetUsedSet();
/**
* Check whether we have an set with the exact characteristics as ci.
* @param ci the characteristics to search on (shortname and md5sum)
* @param md5sum whether to check the MD5 checksum
* @return true iff we have an set matching.
*/
static bool HasSet(const ContentInfo *ci, bool md5sum);
};
template <class Tbase_set> /* static */ const Tbase_set *BaseMedia<Tbase_set>::used_set;
template <class Tbase_set> /* static */ Tbase_set *BaseMedia<Tbase_set>::available_sets;
template <class Tbase_set> /* static */ Tbase_set *BaseMedia<Tbase_set>::duplicate_sets;
/**
* Check whether there's a base set matching some information.
* @param ci The content info to compare it to.
* @param md5sum Should the MD5 checksum be tested as well?
* @param s The list with sets.
* @return The filename of the first file of the base set, or \c nullptr if there is no match.
*/
template <class Tbase_set>
const char *TryGetBaseSetFile(const ContentInfo *ci, bool md5sum, const Tbase_set *s);
/** Types of graphics in the base graphics set */
enum GraphicsFileType {
GFT_BASE, ///< Base sprites for all climates
GFT_LOGOS, ///< Logos, landscape icons and original terrain generator sprites
GFT_ARCTIC, ///< Landscape replacement sprites for arctic
GFT_TROPICAL, ///< Landscape replacement sprites for tropical
GFT_TOYLAND, ///< Landscape replacement sprites for toyland
GFT_EXTRA, ///< Extra sprites that were not part of the original sprites
MAX_GFT, ///< We are looking for this amount of GRFs
};
/** Blitter type for base graphics sets. */
enum BlitterType {
BLT_8BPP, ///< Base set has 8 bpp sprites only.
BLT_32BPP, ///< Base set has both 8 bpp and 32 bpp sprites.
};
struct GRFConfig;
/** All data of a graphics set. */
struct GraphicsSet : BaseSet<GraphicsSet, MAX_GFT, true> {
private:
mutable std::unique_ptr<GRFConfig> extra_cfg; ///< Parameters for extra GRF
public:
PaletteType palette; ///< Palette of this graphics set
BlitterType blitter; ///< Blitter of this graphics set
GraphicsSet();
~GraphicsSet();
bool FillSetDetails(const IniFile &ini, const std::string &path, const std::string &full_filename);
GRFConfig *GetExtraConfig() const { return this->extra_cfg.get(); }
GRFConfig &GetOrCreateExtraConfig() const;
bool IsConfigurable() const;
void CopyCompatibleConfig(const GraphicsSet &src);
static MD5File::ChecksumResult CheckMD5(const MD5File *file, Subdirectory subdir);
};
/** All data/functions related with replacing the base graphics. */
class BaseGraphics : public BaseMedia<GraphicsSet> {
public:
/** Values loaded from config file. */
struct Ini {
std::string name;
uint32_t shortname; ///< unique key for base set
uint32_t extra_version; ///< version of the extra GRF
std::vector<uint32_t> extra_params; ///< parameters for the extra GRF
};
static inline Ini ini_data;
};
/** All data of a sounds set. */
struct SoundsSet : BaseSet<SoundsSet, 1, true> {
};
/** All data/functions related with replacing the base sounds */
class BaseSounds : public BaseMedia<SoundsSet> {
public:
/** The set as saved in the config file. */
static inline std::string ini_set;
};
/** Maximum number of songs in the 'class' playlists. */
static const uint NUM_SONGS_CLASS = 10;
/** Number of classes for songs */
static const uint NUM_SONG_CLASSES = 3;
/** Maximum number of songs in the full playlist; theme song + the classes */
static const uint NUM_SONGS_AVAILABLE = 1 + NUM_SONG_CLASSES * NUM_SONGS_CLASS;
/** Maximum number of songs in the (custom) playlist */
static const uint NUM_SONGS_PLAYLIST = 32;
/* Functions to read DOS music CAT files, similar to but not quite the same as sound effect CAT files */
char *GetMusicCatEntryName(const std::string &filename, size_t entrynum);
byte *GetMusicCatEntryData(const std::string &filename, size_t entrynum, size_t &entrylen);
enum MusicTrackType {
MTT_STANDARDMIDI, ///< Standard MIDI file
MTT_MPSMIDI, ///< MPS GM driver MIDI format (contained in a CAT file)
};
/** Metadata about a music track. */
struct MusicSongInfo {
std::string songname; ///< name of song displayed in UI
byte tracknr; ///< track number of song displayed in UI
std::string filename; ///< file on disk containing song (when used in MusicSet class)
MusicTrackType filetype; ///< decoder required for song file
int cat_index; ///< entry index in CAT file, for filetype==MTT_MPSMIDI
bool loop; ///< song should play in a tight loop if possible, never ending
int override_start; ///< MIDI ticks to skip over in beginning
int override_end; ///< MIDI tick to end the song at (0 if no override)
};
/** All data of a music set. */
struct MusicSet : BaseSet<MusicSet, NUM_SONGS_AVAILABLE, false> {
/** Data about individual songs in set. */
MusicSongInfo songinfo[NUM_SONGS_AVAILABLE];
/** Number of valid songs in set. */
byte num_available;
bool FillSetDetails(const IniFile &ini, const std::string &path, const std::string &full_filename);
};
/** All data/functions related with replacing the base music */
class BaseMusic : public BaseMedia<MusicSet> {
public:
/** The set as saved in the config file. */
static inline std::string ini_set;
};
#endif /* BASE_MEDIA_BASE_H */
|