/** Check if all GRFs in the GRF config from a savegame can be loaded. * @param grfconfig GrfConfig to check * @return will return any of the following 3 values:<br> * <ul> * <li> GLC_ALL_GOOD: No problems occured, all GRF files were found and loaded * <li> GLC_COMPATIBLE: For one or more GRF's no exact match was found, but a * compatible GRF with the same grfid was found and used instead * <li> GLC_NOT_FOUND: For one or more GRF's no match was found at all * </ul> */ GRFListCompatibility IsGoodGRFConfigList(GRFConfig *grfconfig) { GRFListCompatibility res = GLC_ALL_GOOD; for (GRFConfig *c = grfconfig; c != NULL; c = c->next) { const GRFConfig *f = FindGRFConfig(c->ident.grfid, c->ident.md5sum); if (f == NULL) { char buf[256]; /* If we have not found the exactly matching GRF try to find one with the * same grfid, as it most likely is compatible */ f = FindGRFConfig(c->ident.grfid); if (f != NULL) { md5sumToString(buf, lastof(buf), c->ident.md5sum); DEBUG(grf, 1, "NewGRF %08X (%s) not found; checksum %s. Compatibility mode on", BSWAP32(c->ident.grfid), c->filename, buf); if (!HasBit(c->flags, GCF_COMPATIBLE)) { /* Preserve original_md5sum after it has been assigned */ SetBit(c->flags, GCF_COMPATIBLE); memcpy(c->original_md5sum, c->ident.md5sum, sizeof(c->original_md5sum)); } /* Non-found has precedence over compatibility load */ if (res != GLC_NOT_FOUND) res = GLC_COMPATIBLE; goto compatible_grf; } /* No compatible grf was found, mark it as disabled */ md5sumToString(buf, lastof(buf), c->ident.md5sum); DEBUG(grf, 0, "NewGRF %08X (%s) not found; checksum %s", BSWAP32(c->ident.grfid), c->filename, buf); c->status = GCS_NOT_FOUND; res = GLC_NOT_FOUND; } else { compatible_grf: DEBUG(grf, 1, "Loading GRF %08X from %s", BSWAP32(f->ident.grfid), f->filename); /* The filename could be the filename as in the savegame. As we need * to load the GRF here, we need the correct filename, so overwrite that * in any case and set the name and info when it is not set already. * When the GCF_COPY flag is set, it is certain that the filename is * already a local one, so there is no need to replace it. */ if (!HasBit(c->flags, GCF_COPY)) { free(c->filename); c->filename = strdup(f->filename); memcpy(c->ident.md5sum, f->ident.md5sum, sizeof(c->ident.md5sum)); if (c->name == NULL && f->name != NULL) c->name = strdup(f->name); if (c->info == NULL && f->info != NULL) c->info = strdup(f->info); c->error = NULL; } } } return res; }
DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_CHECK_NEWGRFS) { if (this->status != STATUS_JOIN) return NETWORK_RECV_STATUS_MALFORMED_PACKET; uint grf_count = p->Recv_uint8(); NetworkRecvStatus ret = NETWORK_RECV_STATUS_OKAY; /* Check all GRFs */ for (; grf_count > 0; grf_count--) { GRFIdentifier c; this->ReceiveGRFIdentifier(p, &c); /* Check whether we know this GRF */ const GRFConfig *f = FindGRFConfig(c.grfid, FGCM_EXACT, c.md5sum); if (f == NULL) { /* We do not know this GRF, bail out of initialization */ char buf[sizeof(c.md5sum) * 2 + 1]; md5sumToString(buf, lastof(buf), c.md5sum); DEBUG(grf, 0, "NewGRF %08X not found; checksum %s", BSWAP32(c.grfid), buf); ret = NETWORK_RECV_STATUS_NEWGRF_MISMATCH; } } if (ret == NETWORK_RECV_STATUS_OKAY) { /* Start receiving the map */ return SendNewGRFsOk(); } /* NewGRF mismatch, bail out */ _switch_mode_errorstr = STR_NETWORK_ERROR_NEWGRF_MISMATCH; return ret; }
static void WriteSavegameInfo(const char *name) { extern uint16 _sl_version; uint32 last_ottd_rev = 0; byte ever_modified = 0; bool removed_newgrfs = false; GamelogInfo(_load_check_data.gamelog_action, _load_check_data.gamelog_actions, &last_ottd_rev, &ever_modified, &removed_newgrfs); char buf[8192]; char *p = buf; p += seprintf(p, lastof(buf), "Name: %s\n", name); p += seprintf(p, lastof(buf), "Savegame ver: %d\n", _sl_version); p += seprintf(p, lastof(buf), "NewGRF ver: 0x%08X\n", last_ottd_rev); p += seprintf(p, lastof(buf), "Modified: %d\n", ever_modified); if (removed_newgrfs) { p += seprintf(p, lastof(buf), "NewGRFs have been removed\n"); } p = strecpy(p, "NewGRFs:\n", lastof(buf)); if (_load_check_data.HasNewGrfs()) { for (GRFConfig *c = _load_check_data.grfconfig; c != NULL; c = c->next) { char md5sum[33]; md5sumToString(md5sum, lastof(md5sum), HasBit(c->flags, GCF_COMPATIBLE) ? c->original_md5sum : c->ident.md5sum); p += seprintf(p, lastof(buf), "%08X %s %s\n", c->ident.grfid, md5sum, c->filename); } } /* ShowInfo put output to stderr, but version information should go * to stdout; this is the only exception */ #if !defined(WIN32) && !defined(WIN64) printf("%s\n", buf); #else ShowInfo(buf); #endif }
/** * Check if all GRFs in the GRF config from a savegame can be loaded. * @param grfconfig GrfConfig to check * @return will return any of the following 3 values:<br> * <ul> * <li> GLC_ALL_GOOD: No problems occurred, all GRF files were found and loaded * <li> GLC_COMPATIBLE: For one or more GRF's no exact match was found, but a * compatible GRF with the same grfid was found and used instead * <li> GLC_NOT_FOUND: For one or more GRF's no match was found at all * </ul> */ GRFListCompatibility IsGoodGRFConfigList(GRFConfig *grfconfig) { GRFListCompatibility res = GLC_ALL_GOOD; for (GRFConfig *c = grfconfig; c != NULL; c = c->next) { const GRFConfig *f = FindGRFConfig(c->ident.grfid, FGCM_EXACT, c->ident.md5sum); if (f == NULL || HasBit(f->flags, GCF_INVALID)) { char buf[256]; /* If we have not found the exactly matching GRF try to find one with the * same grfid, as it most likely is compatible */ f = FindGRFConfig(c->ident.grfid, FGCM_COMPATIBLE, NULL, c->version); if (f != NULL) { md5sumToString(buf, lastof(buf), c->ident.md5sum); DEBUG(grf, 1, "NewGRF %08X (%s) not found; checksum %s. Compatibility mode on", BSWAP32(c->ident.grfid), c->filename, buf); if (!HasBit(c->flags, GCF_COMPATIBLE)) { /* Preserve original_md5sum after it has been assigned */ SetBit(c->flags, GCF_COMPATIBLE); memcpy(c->original_md5sum, c->ident.md5sum, sizeof(c->original_md5sum)); } /* Non-found has precedence over compatibility load */ if (res != GLC_NOT_FOUND) res = GLC_COMPATIBLE; goto compatible_grf; } /* No compatible grf was found, mark it as disabled */ md5sumToString(buf, lastof(buf), c->ident.md5sum); DEBUG(grf, 0, "NewGRF %08X (%s) not found; checksum %s", BSWAP32(c->ident.grfid), c->filename, buf); c->status = GCS_NOT_FOUND; res = GLC_NOT_FOUND; } else { compatible_grf: DEBUG(grf, 1, "Loading GRF %08X from %s", BSWAP32(f->ident.grfid), f->filename); /* The filename could be the filename as in the savegame. As we need * to load the GRF here, we need the correct filename, so overwrite that * in any case and set the name and info when it is not set already. * When the GCF_COPY flag is set, it is certain that the filename is * already a local one, so there is no need to replace it. */ if (!HasBit(c->flags, GCF_COPY)) { free(c->filename); c->filename = stredup(f->filename); memcpy(c->ident.md5sum, f->ident.md5sum, sizeof(c->ident.md5sum)); c->name->Release(); c->name = f->name; c->name->AddRef(); c->info->Release(); c->info = f->name; c->info->AddRef(); c->error = NULL; c->version = f->version; c->min_loadable_version = f->min_loadable_version; c->num_valid_params = f->num_valid_params; c->has_param_defaults = f->has_param_defaults; for (uint i = 0; i < f->param_info.Length(); i++) { if (f->param_info[i] == NULL) { *c->param_info.Append() = NULL; } else { *c->param_info.Append() = new GRFParameterInfo(*f->param_info[i]); } } } } } return res; }
static void ShowNewGRFInfo(const GRFConfig *c, uint x, uint y, uint right, uint bottom, bool show_params) { char buff[256]; if (c->error != NULL) { char message[512]; SetDParamStr(0, c->error->custom_message); // is skipped by built-in messages SetDParam (1, STR_JUST_RAW_STRING); SetDParamStr(2, c->filename); SetDParam (3, STR_JUST_RAW_STRING); SetDParamStr(4, c->error->data); for (uint i = 0; i < c->error->num_params; i++) { SetDParam(5 + i, c->error->param_value[i]); } GetString(message, c->error->custom_message == NULL ? c->error->message : STR_JUST_RAW_STRING, lastof(message)); SetDParamStr(0, message); y = DrawStringMultiLine(x, right, y, bottom, c->error->severity); } /* Draw filename or not if it is not known (GRF sent over internet) */ if (c->filename != NULL) { SetDParamStr(0, c->filename); y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_FILENAME); } /* Prepare and draw GRF ID */ snprintf(buff, lengthof(buff), "%08X", BSWAP32(c->grfid)); SetDParamStr(0, buff); y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_GRF_ID); /* Prepare and draw MD5 sum */ md5sumToString(buff, lastof(buff), c->md5sum); SetDParamStr(0, buff); y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_MD5SUM); /* Show GRF parameter list */ if (show_params) { if (c->num_params > 0) { GRFBuildParamList(buff, c, lastof(buff)); SetDParam(0, STR_JUST_RAW_STRING); SetDParamStr(1, buff); } else { SetDParam(0, STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE); } y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_PARAMETER); /* Draw the palette of the NewGRF */ SetDParamStr(0, c->windows_paletted ? "Windows" : "DOS"); y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_PALETTE); } /* Show flags */ if (c->status == GCS_NOT_FOUND) y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_NOT_FOUND); if (c->status == GCS_DISABLED) y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_DISABLED); if (HasBit(c->flags, GCF_COMPATIBLE)) y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_COMPATIBLE_LOADED); /* Draw GRF info if it exists */ if (!StrEmpty(c->info)) { SetDParam(0, STR_JUST_RAW_STRING); SetDParamStr(1, c->info); y = DrawStringMultiLine(x, right, y, bottom, STR_BLACK_STRING); } else { y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_NO_INFO); } }
/** * Generic .PNG file image writer. * @param name Filename, including extension. * @param callb Callback function for generating lines of pixels. * @param userdata User data, passed on to \a callb. * @param w Width of the image in pixels. * @param h Height of the image in pixels. * @param pixelformat Bits per pixel (bpp), either 8 or 32. * @param palette %Colour palette (for 8bpp images). * @return File was written successfully. * @see ScreenshotHandlerProc */ static bool MakePNGImage(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette) { png_color rq[256]; FILE *f; uint i, y, n; uint maxlines; uint bpp = pixelformat / 8; png_structp png_ptr; png_infop info_ptr; /* only implemented for 8bit and 32bit images so far. */ if (pixelformat != 8 && pixelformat != 32) return false; f = fopen(name, "wb"); if (f == NULL) return false; png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, const_cast<char *>(name), png_my_error, png_my_warning); if (png_ptr == NULL) { fclose(f); return false; } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_write_struct(&png_ptr, (png_infopp)NULL); fclose(f); return false; } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); fclose(f); return false; } png_init_io(png_ptr, f); png_set_filter(png_ptr, 0, PNG_FILTER_NONE); png_set_IHDR(png_ptr, info_ptr, w, h, 8, pixelformat == 8 ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); #ifdef PNG_TEXT_SUPPORTED /* Try to add some game metadata to the PNG screenshot so * it's more useful for debugging and archival purposes. */ png_text_struct text[2]; memset(text, 0, sizeof(text)); text[0].key = const_cast<char *>("Software"); text[0].text = const_cast<char *>(_openttd_revision); text[0].text_length = strlen(_openttd_revision); text[0].compression = PNG_TEXT_COMPRESSION_NONE; char buf[8192]; char *p = buf; p += seprintf(p, lastof(buf), "Graphics set: %s (%u)\n", BaseGraphics::GetUsedSet()->name, BaseGraphics::GetUsedSet()->version); p = strecpy(p, "NewGRFs:\n", lastof(buf)); for (const GRFConfig *c = _game_mode == GM_MENU ? NULL : _grfconfig; c != NULL; c = c->next) { p += seprintf(p, lastof(buf), "%08X ", BSWAP32(c->ident.grfid)); p = md5sumToString(p, lastof(buf), c->ident.md5sum); p += seprintf(p, lastof(buf), " %s\n", c->filename); } p = strecpy(p, "\nCompanies:\n", lastof(buf)); const Company *c; FOR_ALL_COMPANIES(c) { if (c->ai_info == NULL) { p += seprintf(p, lastof(buf), "%2i: Human\n", (int)c->index); } else { p += seprintf(p, lastof(buf), "%2i: %s (v%d)\n", (int)c->index, c->ai_info->GetName(), c->ai_info->GetVersion()); } } text[1].key = const_cast<char *>("Description"); text[1].text = buf; text[1].text_length = p - buf; text[1].compression = PNG_TEXT_COMPRESSION_zTXt; png_set_text(png_ptr, info_ptr, text, 2); #endif /* PNG_TEXT_SUPPORTED */ if (pixelformat == 8) { /* convert the palette to the .PNG format. */ for (i = 0; i != 256; i++) { rq[i].red = palette[i].r; rq[i].green = palette[i].g; rq[i].blue = palette[i].b; } png_set_PLTE(png_ptr, info_ptr, rq, 256); } png_write_info(png_ptr, info_ptr); png_set_flush(png_ptr, 512); if (pixelformat == 32) { png_color_8 sig_bit; /* Save exact colour/alpha resolution */ sig_bit.alpha = 0; sig_bit.blue = 8; sig_bit.green = 8; sig_bit.red = 8; sig_bit.gray = 8; png_set_sBIT(png_ptr, info_ptr, &sig_bit); #if TTD_ENDIAN == TTD_LITTLE_ENDIAN png_set_bgr(png_ptr); png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); #else png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); #endif /* TTD_ENDIAN == TTD_LITTLE_ENDIAN */ } /* use by default 64k temp memory */ maxlines = Clamp(65536 / w, 16, 128); /* now generate the bitmap bits */ void *buff = CallocT<uint8>(w * maxlines * bpp); // by default generate 128 lines at a time. y = 0; do { /* determine # lines to write */ n = min(h - y, maxlines); /* render the pixels into the buffer */ callb(userdata, buff, y, w, n); y += n; /* write them to png */ for (i = 0; i != n; i++) { png_write_row(png_ptr, (png_bytep)buff + i * w * bpp); } } while (y != h); png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); free(buff); fclose(f); return true; }