OpenTTD Source
20240917-master-g9ab0a47812
|
Go to the documentation of this file.
10 #include "../stdafx.h"
12 #include "../ai/ai.hpp"
13 #include "../game/game.hpp"
14 #include "../window_func.h"
16 #include "../fileio_func.h"
17 #include "../base_media_base.h"
18 #include "../settings_type.h"
21 #include "table/strings.h"
23 #if defined(WITH_ZLIB)
28 # include <emscripten.h>
31 #include "../safeguards.h"
70 for (uint i = 0; i < dependency_count; i++) {
77 ci->
tags.reserve(tag_count);
110 proc = AI::HasAILibrary;
break;
118 proc = Game::HasGameLibrary;
break;
130 if (proc !=
nullptr) {
131 if (proc(ci,
true)) {
135 if (proc(ci,
false)) ci->
upgrade =
true;
146 if (ici->type == ci->
type && ici->unique_id == ci->
unique_id && ci->
md5sum == ici->md5sum) {
148 if (ci->
name.empty()) ci->
name = ici->name;
149 if (ici->IsSelected()) ci->
state = ici->state;
159 this->OnReceiveContentInfo(ici);
170 this->infos.push_back(ci);
179 this->OnReceiveContentInfo(ci);
207 p->Send_uint8 ((uint8_t)type);
208 p->Send_uint32(0xffffffff);
210 p->Send_string(
"vanilla");
211 p->Send_string(_openttd_content_version);
240 uint p_count = std::min<uint>(count, (
TCP_MTU -
sizeof(
PacketSize) -
sizeof(uint8_t) -
sizeof(uint16_t)) /
sizeof(uint32_t));
243 p->Send_uint16(p_count);
245 for (uint i = 0; i < p_count; i++) {
246 p->Send_uint32(content_ids[i]);
251 content_ids += p_count;
262 if (cv ==
nullptr)
return;
266 assert(cv->size() < 255);
267 assert(cv->size() < (
TCP_MTU -
sizeof(
PacketSize) -
sizeof(uint8_t) -
sizeof(uint8_t)) /
268 (
sizeof(uint8_t) +
sizeof(uint32_t) + (send_md5sum ? MD5_HASH_BYTES : 0)));
271 p->Send_uint8((uint8_t)cv->size());
274 p->Send_uint8((uint8_t)ci->type);
275 p->Send_uint32(ci->unique_id);
276 if (!send_md5sum)
continue;
277 p->Send_bytes(ci->md5sum);
285 if (ci->type == ci2->type && ci->unique_id == ci2->unique_id &&
286 (!send_md5sum || ci->md5sum == ci2->md5sum)) {
292 this->infos.push_back(ci);
313 content.push_back(ci->id);
314 bytes += ci->filesize;
317 files = (uint)content.size();
320 if (files == 0)
return;
337 std::string content_request;
339 content_request += std::to_string(
id) +
"\n";
353 uint count = (uint)content.size();
354 const ContentID *content_ids = content.data();
362 uint p_count = std::min<uint>(count, (
TCP_MTU -
sizeof(
PacketSize) -
sizeof(uint8_t) -
sizeof(uint16_t)) /
sizeof(uint32_t));
365 p->Send_uint16(p_count);
367 for (uint i = 0; i < p_count; i++) {
368 p->Send_uint32(content_ids[i]);
373 content_ids += p_count;
391 buf += compressed ?
".tar.gz" :
".tar";
403 #if defined(WITH_ZLIB)
408 if (!ftmp.has_value())
return false;
410 int fdup = dup(fileno(*ftmp));
411 gzFile fin = gzdopen(fdup,
"rb");
416 if (fin ==
nullptr || !fout.has_value()) {
421 int read = gzread(fin, buff,
sizeof(buff));
436 gzerror(fin, &errnum);
437 if (errnum != 0 && errnum != Z_STREAM_END) ret =
false;
440 if (read < 0 ||
static_cast<size_t>(read) != fwrite(buff, 1, read, *fout)) {
450 if (fin !=
nullptr) {
452 }
else if (fdup != -1) {
470 static inline ssize_t
TransferOutFWrite(std::optional<FileHandle> &file,
const char *buffer,
size_t amount)
472 return fwrite(buffer, 1, amount, *file);
477 if (!this->
curFile.has_value()) {
495 ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD, STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE,
WL_ERROR);
502 this->OnDownloadProgress(this->
curInfo, (
int)toRead);
525 if (filename.empty() || !(this->curFile =
FileHandle::Open(filename,
"wb")).has_value()) {
528 ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD, STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE,
WL_ERROR);
561 #ifdef __EMSCRIPTEN__
562 EM_ASM(
if (window[
"openttd_syncfs"]) openttd_syncfs());
565 this->OnDownloadComplete(this->
curInfo->
id);
583 if (this->
curFile.has_value()) {
584 this->OnDownloadProgress(this->
curInfo, -1);
599 assert(data.get() ==
nullptr || length != 0);
607 if (data !=
nullptr) {
620 if (data !=
nullptr) {
622 if (fwrite(data.get(), 1, length, *this->curFile) != length) {
627 this->OnDownloadProgress(this->
curInfo, (
int)length);
634 if (this->
curFile.has_value()) {
652 #define check_not_null(p) { if ((p) == nullptr) { this->OnFailure(); return; } }
654 #define check_and_terminate(p) { check_not_null(p); *(p) = '\0'; }
658 char *p = strchr(str,
'\n');
659 check_and_terminate(p);
665 p = strchr(str,
',');
666 check_and_terminate(p);
671 p = strchr(str,
',');
672 check_and_terminate(p);
677 p = strchr(str,
',');
678 check_and_terminate(p);
684 if (strncmp(str,
"ottd", 4) == 0) {
693 p = strrchr(str,
'/');
697 std::string filename = p;
699 for (uint i = 0; i < 2; i++) {
700 auto pos = filename.find_last_of(
'.');
701 if (pos == std::string::npos) {
722 #undef check_and_terminate
730 http_response_index(-2),
731 curFile(std::nullopt),
762 void OnConnect(SOCKET s)
override
841 if (std::find(this->
requested.begin(), this->requested.end(), cid) != this->requested.end())
return;
855 if (ci->id == cid)
return ci;
881 if (ci ==
nullptr || !ci->
IsSelected())
return;
944 for (
auto iter = range.first; iter != range.second; ++iter) {
956 tree.push_back(child);
962 for (uint i = 0; i < tree.size(); i++) {
1003 if (!c->IsSelected())
continue;
1022 bool force_selection =
false;
1024 if (parent_ci->IsSelected()) sel_count++;
1027 if (sel_count == 0) {
1033 if (force_selection)
continue;
1043 force_selection =
true;
1048 if (force_selection)
continue;
1068 this->infos.clear();
1075 void ClientNetworkContentSocketHandler::OnConnect(
bool success)
1077 for (
size_t i = 0; i < this->
callbacks.size(); ) {
1081 if (i != this->
callbacks.size() && this->callbacks[i] == cb) i++;
1087 for (
size_t i = 0; i < this->
callbacks.size(); ) {
1090 if (i != this->
callbacks.size() && this->callbacks[i] == cb) i++;
1094 void ClientNetworkContentSocketHandler::OnReceiveContentInfo(
const ContentInfo *ci)
1096 for (
size_t i = 0; i < this->
callbacks.size(); ) {
1100 if (i != this->
callbacks.size() && this->callbacks[i] == cb) i++;
1104 void ClientNetworkContentSocketHandler::OnDownloadProgress(
const ContentInfo *ci,
int bytes)
1106 for (
size_t i = 0; i < this->
callbacks.size(); ) {
1109 if (i != this->
callbacks.size() && this->callbacks[i] == cb) i++;
1113 void ClientNetworkContentSocketHandler::OnDownloadComplete(
ContentID cid)
1116 if (ci !=
nullptr) {
1120 for (
size_t i = 0; i < this->
callbacks.size(); ) {
1124 if (i != this->
callbacks.size() && this->callbacks[i] == cb) i++;
bool IsSelected() const
Is the state either selected or autoselected?
virtual void OnDownloadProgress([[maybe_unused]] const ContentInfo *ci, [[maybe_unused]] int bytes)
We have progress in the download of a file.
NetworkContentConnecter(const std::string &connection_string)
Initiate the connecting.
@ SP_AUTODOWNLOAD_DIR
Search within the autodownload directory.
Callbacks for notifying others about incoming data.
virtual void OnReceiveContentInfo([[maybe_unused]] const ContentInfo *ci)
We received a content info.
std::string name
Name of the content.
virtual void OnConnect([[maybe_unused]] bool success)
Callback for when the connection has finished.
bool ExtractTar(const std::string &tar_filename, Subdirectory subdir)
Extract the tar with the given filename in the directory where the tar resides.
ContentType type
Type of content.
Base socket handler for all Content TCP sockets.
void ReverseLookupDependency(ConstContentVector &parents, const ContentInfo *child) const
Reverse lookup the dependencies of (direct) parents over a given child.
@ SVS_ALLOW_NEWLINE
Allow newlines; replaces '\r ' with ' ' during processing.
std::string connection_string
Current address we are connecting to (before resolving).
void SendReceive()
Check whether we received/can send some data from/to the content server and when that's the case hand...
virtual void SendPacket(std::unique_ptr< Packet > &&packet)
This function puts the packet in the send-queue and it is send as soon as possible.
void ShowErrorMessage(StringID summary_msg, int x, int y, CommandCost cc)
Display an error message in a window.
@ PACKET_CONTENT_CLIENT_INFO_EXTID
Queries the content server for information about a list of external IDs.
@ CONTENT_TYPE_GAME_LIBRARY
The content consists of a GS library.
void OnReceiveData(std::unique_ptr< char[]> data, size_t length) override
We're receiving data.
bool upgrade
This item is an upgrade.
@ DOES_NOT_EXIST
The content does not exist in the content system.
"Helper" class for creating TCP connections in a non-blocking manner
uint32_t filesize
Size of the file.
static ssize_t TransferOutFWrite(std::optional< FileHandle > &file, const char *buffer, size_t amount)
Simple wrapper around fwrite to be able to pass it to Packet's TransferOut.
bool HasScenario(const ContentInfo *ci, bool md5sum)
Check whether we've got a given scenario based on its unique ID.
@ BASESET_DIR
Subdirectory for all base data (base sets, intro game)
void CloseWindowById(WindowClass cls, WindowNumber number, bool force, int data)
Close a window by its class and window number (if it is open).
std::optional< FileHandle > curFile
Currently downloaded file.
std::chrono::steady_clock::time_point lastActivity
The last time there was network activity.
int http_response_index
Where we are, in the response, with handling it.
bool Receive_SERVER_CONTENT(Packet &p) override
Server sending list of content info: uint32_t unique id uint32_t file size (0 == does not exist) stri...
@ CONTENT_TYPE_NEWGRF
The content consists of a NewGRF.
std::vector< ContentInfo * > ContentVector
Vector with content info.
static void Connect(const std::string &uri, HTTPCallback *callback, const std::string data="")
Connect to the given URI.
SOCKET sock
The socket currently connected to.
bool ReceivePackets()
Receive a packet at TCP level.
std::string url
URL related to the content.
void CheckDependencyState(ContentInfo *ci)
Check the dependencies (recursively) of this content info.
static const uint NETWORK_CONTENT_VERSION_LENGTH
The maximum length of a content's version, in bytes including '\0'.
Socket handler for the content server connection.
std::unordered_multimap< ContentID, ContentID > reverse_dependency_map
Content reverse dependency map.
ssize_t TransferOut(F transfer_function, D destination, Args &&... args)
Transfer data from the packet to the given function.
bool FioRemove(const std::string &filename)
Remove a file.
static std::optional< FileHandle > Open(const std::string &filename, const std::string &mode)
Open an RAII file handle if possible.
@ CONTENT_TYPE_END
Helper to mark the end of the types.
std::string version
Version of the content.
void Clear()
Clear all downloaded content information.
bool isConnecting
Whether we're connecting.
MD5Hash md5sum
The MD5 checksum.
static bool HasGRFConfig(const ContentInfo *ci, bool md5sum)
Wrapper function for the HasProc.
bool IsValid() const
Is the information from this content info valid?
ContentType
The values in the enum are important; they are used as database 'keys'.
ContentInfo * curInfo
Information about the currently downloaded file.
size_t Recv_bytes(std::span< uint8_t > span)
Extract at most the length of the span bytes from the packet into the span.
void DownloadSelectedContentHTTP(const ContentIDList &content)
Initiate downloading the content over HTTP.
Subdirectory GetContentInfoSubDir(ContentType type)
Helper to get the subdirectory a ContentInfo is located in.
std::string Recv_string(size_t length, StringValidationSettings settings=SVS_REPLACE_WITH_QUESTION_MARK)
Reads characters (bytes) from the packet until it finds a '\0', or reaches a maximum of length charac...
void RequestContentList(ContentType type)
Request the content list for the given type.
@ FGCM_ANY
Use first found.
bool include(Container &container, typename Container::const_reference &item)
Helper function to append an item to a container if it is not already contained.
static std::string GetFullFilename(const ContentInfo *ci, bool compressed)
Determine the full filename of a piece of content information.
@ CONTENT_TYPE_GAME
The content consists of a game script.
void OnDisconnect() override
Callback for when the connection got disconnected.
@ UNSELECTED
The content has not been selected.
static uint32_t BSWAP32(uint32_t x)
Perform a 32 bits endianness bitswap on x.
void OnFailure() override
Callback for when the connection attempt failed.
void Reopen()
Reopen the socket so we can send/receive stuff again.
static const uint NETWORK_CONTENT_DESC_LENGTH
The maximum length of a content's description, in bytes including '\0'.
ContentVector infos
All content info we received.
void DownloadContentInfo(ContentID cid)
Download information of a given Content ID if not already tried.
uint32_t Recv_uint32()
Read a 32 bits integer from the packet.
~ClientNetworkContentSocketHandler()
Clear up the mess ;)
void UnselectAll()
Unselect everything that we've not downloaded so far.
Container for all important information about a piece of content.
void Unselect(ContentID cid)
Unselect a specific content id.
bool isCancelled
Whether the download has been cancelled.
virtual void OnDownloadComplete([[maybe_unused]] ContentID cid)
We have finished downloading a file.
static bool HasAI(const struct ContentInfo *ci, bool md5sum)
Wrapper function for AIScanner::HasAI.
void OnFailure() override
An error has occurred and the connection has been closed.
const char * NetworkContentServerConnectionString()
Get the connection string for the content server from the environment variable OTTD_CONTENT_SERVER_CS...
virtual NetworkRecvStatus CloseConnection(bool error=true)
This will put this socket handler in a close state.
@ SELECTED
The content has been manually selected.
static constexpr std::chrono::seconds IDLE_TIMEOUT
The idle timeout; when to close the connection because it's idle.
ContentInfo * GetContent(ContentID cid) const
Get the content info based on a ContentID.
static const size_t TCP_MTU
Number of bytes we can pack in a single TCP packet.
bool(* HasProc)(const ContentInfo *ci, bool md5sum)
Check whether a function piece of content is locally known.
StringList tags
Tags associated with the content.
Internal entity of a packet.
void DownloadSelectedContent(uint &files, uint &bytes, bool fallback=false)
Actually begin downloading the content we selected.
@ PACKET_CONTENT_CLIENT_CONTENT
Request a content file given an internal ID.
uint16_t PacketSize
Size of the whole packet.
std::vector< char > http_response
The HTTP response to the requests we've been doing.
bool Receive_SERVER_INFO(Packet &p) override
Server sending list of content info: uint8_t type (invalid ID == does not exist) uint32_t id uint32_t...
const char * NetworkContentMirrorUriString()
Get the URI string for the content mirror from the environment variable OTTD_CONTENT_MIRROR_URI,...
std::vector< ContentID > dependencies
The dependencies (unique server side ids)
bool AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename={}) override
Add a file with the given filename.
@ PACKET_CONTENT_CLIENT_INFO_LIST
Queries the content server for a list of info of a given content type.
static const uint NETWORK_CONTENT_FILENAME_LENGTH
The maximum length of a content's filename, in bytes including '\0'.
@ CONTENT_TYPE_AI
The content consists of an AI.
@ PACKET_CONTENT_CLIENT_INFO_ID
Queries the content server for information about a list of internal IDs.
bool IsCancelled() const override
Check if there is a request to cancel the transfer.
ClientNetworkContentSocketHandler _network_content_client
The client we use to connect to the server.
std::vector< ContentID > ContentIDList
List of content IDs to (possibly) select.
@ CONTENT_TYPE_BASE_GRAPHICS
The content consists of base graphics.
SendPacketsState SendPackets(bool closing_down=false)
Sends all the buffered packets out for this client.
bool CanSendReceive()
Check whether this socket can send or receive something.
@ ALREADY_HERE
The content is already at the client side.
static const uint16_t NETWORK_CONTENT_SERVER_PORT
The default port of the content server (TCP)
void ReverseLookupTreeDependency(ConstContentVector &tree, const ContentInfo *child) const
Reverse lookup the dependencies of all parents over a given child.
void Connect()
Connect with the content server.
@ AUTOSELECTED
The content has been selected as dependency.
@ CONTENT_TYPE_AI_LIBRARY
The content consists of an AI library.
@ NO_DIRECTORY
A path without any base directory.
void ToggleSelectedState(const ContentInfo *ci)
Toggle the state of a content info and check its dependencies.
NetworkRecvStatus
Status of a network client; reasons why a client has quit.
@ WC_NETWORK_STATUS_WINDOW
Network status window; Window numbers:
ContentID
Unique identifier for the content.
std::string filename
Filename (for the .tar.gz; only valid on download)
std::vector< ContentCallback * > callbacks
Callbacks to notify "the world".
static bool HasGame(const struct ContentInfo *ci, bool md5sum)
Wrapper function for GameScanner::HasGame.
void Select(ContentID cid)
Select a specific content id.
static bool GunzipFile(const ContentInfo *ci)
Gunzip a given file and remove the .gz if successful.
Subdirectory
The different kinds of subdirectories OpenTTD uses.
ContentIDList requested
ContentIDs we already requested (so we don't do it again)
Connect to the content server.
void DownloadSelectedContentFallback(const ContentIDList &content)
Initiate downloading the content over the fallback protocol.
@ WL_ERROR
Errors (eg. saving/loading failed)
State state
Whether the content info is selected (for download)
@ CONTENT_TYPE_BASE_SOUNDS
The content consists of base sounds.
Helper for scanning for files with tar as extension.
void SelectAll()
Select everything we can select.
@ PACKET_CONTENT_CLIENT_INFO_EXTID_MD5
Queries the content server for information about a list of external IDs and MD5.
void Cancel()
Cancel the current download.
static const uint NETWORK_CONTENT_NAME_LENGTH
The maximum length of a content's name, in bytes including '\0'.
@ NETWORK_RECV_STATUS_OKAY
Everything is okay.
@ CONTENT_TYPE_SCENARIO
The content consists of a scenario.
bool BeforeDownload()
Handle the opening of the file before downloading.
@ FGCM_EXACT
Only find Grfs matching md5sum.
static const uint NETWORK_CONTENT_TAG_LENGTH
The maximum length of a content's tag, in bytes including '\0'.
NetworkRecvStatus CloseConnection(bool error=true) override
Disconnect from the content server.
static const uint NETWORK_CONTENT_URL_LENGTH
The maximum length of a content's url, in bytes including '\0'.
void SelectUpgrade()
Select everything that's an update for something we've got.
ContentID id
Unique (server side) ID for the content.
size_t RemainingBytesToTransfer() const
Get the amount of bytes that are still available for the Transfer functions.
void AfterDownload()
Handle the closing and extracting of a file after downloading it has been done.
std::string description
Description of the content.
const GRFConfig * FindGRFConfig(uint32_t grfid, FindGRFConfigMode mode, const MD5Hash *md5sum, uint32_t desired_version)
Find a NewGRF in the scanned list.
@ CONTENT_TYPE_HEIGHTMAP
The content consists of a heightmap.
ClientNetworkContentSocketHandler()
Create a socket handler to handle the connection.
virtual void OnDisconnect()
Callback for when the connection got disconnected.
@ SVS_REPLACE_WITH_QUESTION_MARK
Replace the unknown/bad bits with question marks.
std::vector< const ContentInfo * > ConstContentVector
Vector with constant content info.
@ WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD
Network content download status.
void CloseSocket()
Close the actual socket of the connection.
uint32_t unique_id
Unique ID; either GRF ID or shortname.
uint8_t Recv_uint8()
Read a 8 bits integer from the packet.
static const StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames)
@ CONTENT_TYPE_BASE_MUSIC
The content consists of base music.