From 10e35ca8e4249a7f443b5c89dd9a59df83052d0d Mon Sep 17 00:00:00 2001 From: Rubidium Date: Wed, 14 Apr 2021 17:41:45 +0200 Subject: Codechange: let NewGRF make use of SpriteFile instead of most of the FIO slot functions --- src/gfxinit.cpp | 20 +++--- src/newgrf.cpp | 175 ++++++++++++++++++++++++++++---------------------- src/newgrf.h | 4 +- src/newgrf_config.cpp | 4 +- 4 files changed, 110 insertions(+), 93 deletions(-) diff --git a/src/gfxinit.cpp b/src/gfxinit.cpp index 3bacc5af6..063d777ed 100644 --- a/src/gfxinit.cpp +++ b/src/gfxinit.cpp @@ -39,16 +39,15 @@ static const SpriteID * const _landscape_spriteindexes[] = { * Load an old fashioned GRF file. * @param filename The name of the file to open. * @param load_index The offset of the first sprite. - * @param file_index The Fio offset to load the file in. * @param needs_palette_remap Whether the colours in the GRF file need a palette remap. * @return The number of loaded sprites. */ -static uint LoadGrfFile(const char *filename, uint load_index, int file_index, bool needs_palette_remap) +static uint LoadGrfFile(const char *filename, uint load_index, bool needs_palette_remap) { uint load_index_org = load_index; uint sprite_id = 0; - SpriteFile &file = FioOpenFile(file_index, filename, BASESET_DIR, needs_palette_remap); + SpriteFile &file = OpenCachedSpriteFile(filename, BASESET_DIR, needs_palette_remap); DEBUG(sprite, 2, "Reading grf-file '%s'", filename); @@ -77,16 +76,15 @@ static uint LoadGrfFile(const char *filename, uint load_index, int file_index, b * Load an old fashioned GRF file to replace already loaded sprites. * @param filename The name of the file to open. * @param index_tbl The offsets of each of the sprites. - * @param file_index The Fio offset to load the file in. * @param needs_palette_remap Whether the colours in the GRF file need a palette remap. * @return The number of loaded sprites. */ -static void LoadGrfFileIndexed(const char *filename, const SpriteID *index_tbl, int file_index, bool needs_palette_remap) +static void LoadGrfFileIndexed(const char *filename, const SpriteID *index_tbl, bool needs_palette_remap) { uint start; uint sprite_id = 0; - SpriteFile &file = FioOpenFile(file_index, filename, BASESET_DIR, needs_palette_remap); + SpriteFile &file = OpenCachedSpriteFile(filename, BASESET_DIR, needs_palette_remap); DEBUG(sprite, 2, "Reading indexed grf-file '%s'", filename); @@ -161,10 +159,9 @@ void CheckExternalFiles() /** Actually load the sprite tables. */ static void LoadSpriteTables() { - uint i = FIRST_GRF_SLOT; const GraphicsSet *used_set = BaseGraphics::GetUsedSet(); - LoadGrfFile(used_set->files[GFT_BASE].filename, 0, i++, (PAL_DOS != used_set->palette)); + LoadGrfFile(used_set->files[GFT_BASE].filename, 0, PAL_DOS != used_set->palette); /* * The second basic file always starts at the given location and does @@ -172,7 +169,7 @@ static void LoadSpriteTables() * has a few sprites less. However, we do not care about those missing * sprites as they are not shown anyway (logos in intro game). */ - LoadGrfFile(used_set->files[GFT_LOGOS].filename, 4793, i++, (PAL_DOS != used_set->palette)); + LoadGrfFile(used_set->files[GFT_LOGOS].filename, 4793, PAL_DOS != used_set->palette); /* * Load additional sprites for climates other than temperate. @@ -183,8 +180,7 @@ static void LoadSpriteTables() LoadGrfFileIndexed( used_set->files[GFT_ARCTIC + _settings_game.game_creation.landscape - 1].filename, _landscape_spriteindexes[_settings_game.game_creation.landscape - 1], - i++, - (PAL_DOS != used_set->palette) + PAL_DOS != used_set->palette ); } @@ -223,7 +219,7 @@ static void LoadSpriteTables() master->next = extra; _grfconfig = master; - LoadNewGRF(SPR_NEWGRFS_BASE, i, 2); + LoadNewGRF(SPR_NEWGRFS_BASE, 2); uint total_extra_graphics = SPR_NEWGRFS_BASE - SPR_OPENTTD_BASE; _missing_extra_graphics = GetSpriteCountForFile(used_set->files[GFT_EXTRA].filename, SPR_OPENTTD_BASE, SPR_NEWGRFS_BASE); diff --git a/src/newgrf.cpp b/src/newgrf.cpp index aadd1a3a9..7b8ab9de1 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -80,6 +80,7 @@ static uint32 _ttdpatch_flags[8]; GRFLoadedFeatures _loaded_newgrf_features; static const uint MAX_SPRITEGROUP = UINT8_MAX; ///< Maximum GRF-local ID for a spritegroup. +static const uint MAX_GRF_COUNT = 128; ///< Maximum number of NewGRF files that could be loaded. /** Temporary data during loading of GRFs */ struct GrfProcessingState { @@ -6395,19 +6396,20 @@ static void CfgApply(ByteReader *buf) * to place where parameter is to be stored. */ /* Preload the next sprite */ - size_t pos = FioGetPos(); - uint32 num = _cur.file->GetContainerVersion() >= 2 ? FioReadDword() : FioReadWord(); - uint8 type = FioReadByte(); + SpriteFile &file = *_cur.file; + size_t pos = file.GetPos(); + uint32 num = file.GetContainerVersion() >= 2 ? file.ReadDword() : file.ReadWord(); + uint8 type = file.ReadByte(); byte *preload_sprite = nullptr; /* Check if the sprite is a pseudo sprite. We can't operate on real sprites. */ if (type == 0xFF) { preload_sprite = MallocT(num); - FioReadBlock(preload_sprite, num); + file.ReadBlock(preload_sprite, num); } /* Reset the file position to the start of the next sprite */ - FioSeekTo(pos, SEEK_SET); + file.SeekTo(pos, SEEK_SET); if (type != 0xFF) { grfmsg(2, "CfgApply: Ignoring (next sprite is real, unsupported)"); @@ -6653,7 +6655,7 @@ static void SkipIf(ByteReader *buf) if (choice != nullptr) { grfmsg(2, "SkipIf: Jumping to label 0x%0X at line %d, test was true", choice->label, choice->nfo_line); - FioSeekTo(choice->pos, SEEK_SET); + _cur.file->SeekTo(choice->pos, SEEK_SET); _cur.nfo_line = choice->nfo_line; return; } @@ -7493,7 +7495,7 @@ static void DefineGotoLabel(ByteReader *buf) GRFLabel *label = MallocT(1); label->label = nfo_label; label->nfo_line = _cur.nfo_line; - label->pos = FioGetPos(); + label->pos = _cur.file->GetPos(); label->next = nullptr; /* Set up a linked list of goto targets which we will search in an Action 0x7/0x9 */ @@ -7516,8 +7518,8 @@ static void DefineGotoLabel(ByteReader *buf) static void ImportGRFSound(SoundEntry *sound) { const GRFFile *file; - uint32 grfid = FioReadDword(); - SoundID sound_id = FioReadWord(); + uint32 grfid = _cur.file->ReadDword(); + SoundID sound_id = _cur.file->ReadWord(); file = GetFileByGRFID(grfid); if (file == nullptr || file->sound_offset == 0) { @@ -7577,6 +7579,8 @@ static void GRFSound(ByteReader *buf) sound = GetSound(_cur.grffile->sound_offset); } + SpriteFile &file = *_cur.file; + byte grf_container_version = file.GetContainerVersion(); for (int i = 0; i < num; i++) { _cur.nfo_line++; @@ -7584,22 +7588,21 @@ static void GRFSound(ByteReader *buf) * While this is invalid, we do not check for this. But we should prevent it from causing bigger trouble */ bool invalid = i >= _cur.grffile->num_sounds; - size_t offs = FioGetPos(); + size_t offs = file.GetPos(); - byte grf_container_version = _cur.file->GetContainerVersion(); - uint32 len = grf_container_version >= 2 ? FioReadDword() : FioReadWord(); - byte type = FioReadByte(); + uint32 len = grf_container_version >= 2 ? file.ReadDword() : file.ReadWord(); + byte type = file.ReadByte(); if (grf_container_version >= 2 && type == 0xFD) { /* Reference to sprite section. */ if (invalid) { grfmsg(1, "GRFSound: Sound index out of range (multiple Action 11?)"); - FioSkipBytes(len); + file.SkipBytes(len); } else if (len != 4) { grfmsg(1, "GRFSound: Invalid sprite section import"); - FioSkipBytes(len); + file.SkipBytes(len); } else { - uint32 id = FioReadDword(); + uint32 id = file.ReadDword(); if (_cur.stage == GLS_INIT) LoadGRFSound(GetGRFSpriteOffset(id), sound + i); } continue; @@ -7607,17 +7610,17 @@ static void GRFSound(ByteReader *buf) if (type != 0xFF) { grfmsg(1, "GRFSound: Unexpected RealSprite found, skipping"); - FioSkipBytes(7); + file.SkipBytes(7); SkipSpriteData(*_cur.file, type, len - 8); continue; } if (invalid) { grfmsg(1, "GRFSound: Sound index out of range (multiple Action 11?)"); - FioSkipBytes(len); + file.SkipBytes(len); } - byte action = FioReadByte(); + byte action = file.ReadByte(); switch (action) { case 0xFF: /* Allocate sound only in init stage. */ @@ -7628,23 +7631,23 @@ static void GRFSound(ByteReader *buf) LoadGRFSound(offs, sound + i); } } - FioSkipBytes(len - 1); // already read + file.SkipBytes(len - 1); // already read break; case 0xFE: if (_cur.stage == GLS_ACTIVATION) { /* XXX 'Action 0xFE' isn't really specified. It is only mentioned for * importing sounds, so this is probably all wrong... */ - if (FioReadByte() != 0) grfmsg(1, "GRFSound: Import type mismatch"); + if (file.ReadByte() != 0) grfmsg(1, "GRFSound: Import type mismatch"); ImportGRFSound(sound + i); } else { - FioSkipBytes(len - 1); // already read + file.SkipBytes(len - 1); // already read } break; default: grfmsg(1, "GRFSound: Unexpected Action %x found, skipping", action); - FioSkipBytes(len - 1); // already read + file.SkipBytes(len - 1); // already read break; } } @@ -9234,14 +9237,14 @@ static void DecodeSpecialSprite(byte *buf, uint num, GrfLoadingStage stage) if (it == _grf_line_to_action6_sprite_override.end()) { /* No preloaded sprite to work with; read the * pseudo sprite content. */ - FioReadBlock(buf, num); + _cur.file->ReadBlock(buf, num); } else { /* Use the preloaded sprite data. */ buf = _grf_line_to_action6_sprite_override[location]; grfmsg(7, "DecodeSpecialSprite: Using preloaded pseudo sprite data"); /* Skip the real (original) content of this action. */ - FioSeekTo(num, SEEK_CUR); + _cur.file->SeekTo(num, SEEK_CUR); } ByteReader br(buf, buf + num); @@ -9268,47 +9271,20 @@ static void DecodeSpecialSprite(byte *buf, uint num, GrfLoadingStage stage) } } - /** - * Load a particular NewGRF. - * @param config The configuration of the to be loaded NewGRF. - * @param file_index The Fio index of the first NewGRF to load. - * @param stage The loading stage of the NewGRF. - * @param subdir The sub directory to find the NewGRF in. + * Load a particular NewGRF from a SpriteFile. + * @param config The configuration of the to be loaded NewGRF. + * @param stage The loading stage of the NewGRF. + * @param file The file to load the GRF data from. */ -void LoadNewGRFFile(GRFConfig *config, uint file_index, GrfLoadingStage stage, Subdirectory subdir) +static void LoadNewGRFFileFromFile(GRFConfig *config, GrfLoadingStage stage, SpriteFile &file) { - const char *filename = config->filename; - - /* A .grf file is activated only if it was active when the game was - * started. If a game is loaded, only its active .grfs will be - * reactivated, unless "loadallgraphics on" is used. A .grf file is - * considered active if its action 8 has been processed, i.e. its - * action 8 hasn't been skipped using an action 7. - * - * During activation, only actions 0, 1, 2, 3, 4, 5, 7, 8, 9, 0A and 0B are - * carried out. All others are ignored, because they only need to be - * processed once at initialization. */ - if (stage != GLS_FILESCAN && stage != GLS_SAFETYSCAN && stage != GLS_LABELSCAN) { - _cur.grffile = GetFileByFilename(filename); - if (_cur.grffile == nullptr) usererror("File '%s' lost in cache.\n", filename); - if (stage == GLS_RESERVE && config->status != GCS_INITIALISED) return; - if (stage == GLS_ACTIVATION && !HasBit(config->flags, GCF_RESERVED)) return; - } - - if (file_index >= MAX_FILE_SLOTS) { - DEBUG(grf, 0, "'%s' is not loaded as the maximum number of file slots has been reached", filename); - config->status = GCS_DISABLED; - config->error = new GRFError(STR_NEWGRF_ERROR_MSG_FATAL, STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED); - return; - } - - _cur.file = &FioOpenFile(file_index, filename, subdir, config->palette & GRFP_USE_MASK); + _cur.file = &file; _cur.grfconfig = config; - DEBUG(grf, 2, "LoadNewGRFFile: Reading NewGRF-file '%s'", filename); + DEBUG(grf, 2, "LoadNewGRFFile: Reading NewGRF-file '%s'", config->filename); - byte grf_container_version = _cur.file->GetContainerVersion(); + byte grf_container_version = file.GetContainerVersion(); if (grf_container_version == 0) { DEBUG(grf, 7, "LoadNewGRFFile: Custom .grf has invalid format"); return; @@ -9317,15 +9293,15 @@ void LoadNewGRFFile(GRFConfig *config, uint file_index, GrfLoadingStage stage, S if (stage == GLS_INIT || stage == GLS_ACTIVATION) { /* We need the sprite offsets in the init stage for NewGRF sounds * and in the activation stage for real sprites. */ - ReadGRFSpriteOffsets(*_cur.file); + ReadGRFSpriteOffsets(file); } else { /* Skip sprite section offset if present. */ - if (grf_container_version >= 2) FioReadDword(); + if (grf_container_version >= 2) file.ReadDword(); } if (grf_container_version >= 2) { /* Read compression value. */ - byte compression = FioReadByte(); + byte compression = file.ReadByte(); if (compression != 0) { DEBUG(grf, 7, "LoadNewGRFFile: Unsupported compression format"); return; @@ -9335,9 +9311,9 @@ void LoadNewGRFFile(GRFConfig *config, uint file_index, GrfLoadingStage stage, S /* Skip the first sprite; we don't care about how many sprites this * does contain; newest TTDPatches and George's longvehicles don't * neither, apparently. */ - uint32 num = grf_container_version >= 2 ? FioReadDword() : FioReadWord(); - if (num == 4 && FioReadByte() == 0xFF) { - FioReadDword(); + uint32 num = grf_container_version >= 2 ? file.ReadDword() : file.ReadWord(); + if (num == 4 && file.ReadByte() == 0xFF) { + file.ReadDword(); } else { DEBUG(grf, 7, "LoadNewGRFFile: Custom .grf has invalid format"); return; @@ -9347,8 +9323,8 @@ void LoadNewGRFFile(GRFConfig *config, uint file_index, GrfLoadingStage stage, S ReusableBuffer buf; - while ((num = (grf_container_version >= 2 ? FioReadDword() : FioReadWord())) != 0) { - byte type = FioReadByte(); + while ((num = (grf_container_version >= 2 ? file.ReadDword() : file.ReadWord())) != 0) { + byte type = file.ReadByte(); _cur.nfo_line++; if (type == 0xFF) { @@ -9360,7 +9336,7 @@ void LoadNewGRFFile(GRFConfig *config, uint file_index, GrfLoadingStage stage, S continue; } else { - FioSkipBytes(num); + file.SkipBytes(num); } } else { if (_cur.skip_sprites == 0) { @@ -9371,10 +9347,10 @@ void LoadNewGRFFile(GRFConfig *config, uint file_index, GrfLoadingStage stage, S if (grf_container_version >= 2 && type == 0xFD) { /* Reference to data section. Container version >= 2 only. */ - FioSkipBytes(num); + file.SkipBytes(num); } else { - FioSkipBytes(7); - SkipSpriteData(*_cur.file, type, num - 8); + file.SkipBytes(7); + SkipSpriteData(file, type, num - 8); } } @@ -9382,6 +9358,43 @@ void LoadNewGRFFile(GRFConfig *config, uint file_index, GrfLoadingStage stage, S } } +/** + * Load a particular NewGRF. + * @param config The configuration of the to be loaded NewGRF. + * @param stage The loading stage of the NewGRF. + * @param subdir The sub directory to find the NewGRF in. + * @param temporary The NewGRF/sprite file is to be loaded temporarily and should be closed immediately, + * contrary to loading the SpriteFile and having it cached by the SpriteCache. + */ +void LoadNewGRFFile(GRFConfig *config, GrfLoadingStage stage, Subdirectory subdir, bool temporary) +{ + const char *filename = config->filename; + + /* A .grf file is activated only if it was active when the game was + * started. If a game is loaded, only its active .grfs will be + * reactivated, unless "loadallgraphics on" is used. A .grf file is + * considered active if its action 8 has been processed, i.e. its + * action 8 hasn't been skipped using an action 7. + * + * During activation, only actions 0, 1, 2, 3, 4, 5, 7, 8, 9, 0A and 0B are + * carried out. All others are ignored, because they only need to be + * processed once at initialization. */ + if (stage != GLS_FILESCAN && stage != GLS_SAFETYSCAN && stage != GLS_LABELSCAN) { + _cur.grffile = GetFileByFilename(filename); + if (_cur.grffile == nullptr) usererror("File '%s' lost in cache.\n", filename); + if (stage == GLS_RESERVE && config->status != GCS_INITIALISED) return; + if (stage == GLS_ACTIVATION && !HasBit(config->flags, GCF_RESERVED)) return; + } + + bool needs_palette_remap = config->palette & GRFP_USE_MASK; + if (temporary) { + SpriteFile temporarySpriteFile(filename, subdir, needs_palette_remap); + LoadNewGRFFileFromFile(config, stage, temporarySpriteFile); + } else { + LoadNewGRFFileFromFile(config, stage, OpenCachedSpriteFile(filename, subdir, needs_palette_remap)); + } +} + /** * Relocates the old shore sprites at new positions. * @@ -9677,10 +9690,9 @@ static void AfterLoadGRFs() /** * Load all the NewGRFs. * @param load_index The offset for the first sprite to add. - * @param file_index The Fio index of the first NewGRF to load. * @param num_baseset Number of NewGRFs at the front of the list to look up in the baseset dir instead of the newgrf dir. */ -void LoadNewGRF(uint load_index, uint file_index, uint num_baseset) +void LoadNewGRF(uint load_index, uint num_baseset) { /* In case of networking we need to "sync" the start values * so all NewGRFs are loaded equally. For this we use the @@ -9738,7 +9750,7 @@ void LoadNewGRF(uint load_index, uint file_index, uint num_baseset) } } - uint slot = file_index; + uint num_grfs = 0; uint num_non_static = 0; _cur.stage = stage; @@ -9746,7 +9758,7 @@ void LoadNewGRF(uint load_index, uint file_index, uint num_baseset) if (c->status == GCS_DISABLED || c->status == GCS_NOT_FOUND) continue; if (stage > GLS_INIT && HasBit(c->flags, GCF_INIT_ONLY)) continue; - Subdirectory subdir = slot < file_index + num_baseset ? BASESET_DIR : NEWGRF_DIR; + Subdirectory subdir = num_grfs < num_baseset ? BASESET_DIR : NEWGRF_DIR; if (!FioCheckFileExists(c->filename, subdir)) { DEBUG(grf, 0, "NewGRF file is missing '%s'; disabling", c->filename); c->status = GCS_NOT_FOUND; @@ -9764,7 +9776,16 @@ void LoadNewGRF(uint load_index, uint file_index, uint num_baseset) } num_non_static++; } - LoadNewGRFFile(c, slot++, stage, subdir); + + if (num_grfs >= MAX_GRF_COUNT) { + DEBUG(grf, 0, "'%s' is not loaded as the maximum number of file slots has been reached", c->filename); + c->status = GCS_DISABLED; + c->error = new GRFError(STR_NEWGRF_ERROR_MSG_FATAL, STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED); + continue; + } + num_grfs++; + + LoadNewGRFFile(c, stage, subdir, false); if (stage == GLS_RESERVE) { SetBit(c->flags, GCF_RESERVED); } else if (stage == GLS_ACTIVATION) { diff --git a/src/newgrf.h b/src/newgrf.h index 477bfa892..eb6c22d47 100644 --- a/src/newgrf.h +++ b/src/newgrf.h @@ -192,8 +192,8 @@ static inline bool HasGrfMiscBit(GrfMiscBit bit) /* Indicates which are the newgrf features currently loaded ingame */ extern GRFLoadedFeatures _loaded_newgrf_features; -void LoadNewGRFFile(struct GRFConfig *config, uint file_index, GrfLoadingStage stage, Subdirectory subdir); -void LoadNewGRF(uint load_index, uint file_index, uint num_baseset); +void LoadNewGRFFile(struct GRFConfig *config, GrfLoadingStage stage, Subdirectory subdir, bool temporary); +void LoadNewGRF(uint load_index, uint num_baseset); void ReloadNewGRFData(); // in saveload/afterload.cpp void ResetNewGRFData(); void ResetPersistentNewGRFData(); diff --git a/src/newgrf_config.cpp b/src/newgrf_config.cpp index a4ec52f0f..b92b297da 100644 --- a/src/newgrf_config.cpp +++ b/src/newgrf_config.cpp @@ -375,7 +375,7 @@ bool FillGRFDetails(GRFConfig *config, bool is_static, Subdirectory subdir) } /* Find and load the Action 8 information */ - LoadNewGRFFile(config, CONFIG_SLOT, GLS_FILESCAN, subdir); + LoadNewGRFFile(config, GLS_FILESCAN, subdir, true); config->SetSuitablePalette(); config->FinalizeParameterInfo(); @@ -384,7 +384,7 @@ bool FillGRFDetails(GRFConfig *config, bool is_static, Subdirectory subdir) if (is_static) { /* Perform a 'safety scan' for static GRFs */ - LoadNewGRFFile(config, CONFIG_SLOT, GLS_SAFETYSCAN, subdir); + LoadNewGRFFile(config, GLS_SAFETYSCAN, subdir, true); /* GCF_UNSAFE is set if GLS_SAFETYSCAN finds unsafe actions */ if (HasBit(config->flags, GCF_UNSAFE)) return false; -- cgit v1.2.3-70-g09d2