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"
19#include "../strings_func.h"
22#include "table/strings.h"
33# include <emscripten.h>
36#include "../safeguards.h"
75 for (uint i = 0; i < dependency_count; i++) {
82 ci->
tags.reserve(tag_count);
115 proc = AI::HasAILibrary;
break;
123 proc = Game::HasGameLibrary;
break;
135 if (proc !=
nullptr) {
136 if (proc(ci,
true)) {
140 if (proc(ci,
false)) ci->
upgrade =
true;
151 if (ici->type == ci->
type && ici->unique_id == ci->
unique_id && ci->
md5sum == ici->md5sum) {
153 if (ci->
name.empty()) ci->
name = ici->name;
154 if (ici->IsSelected()) ci->
state = ici->state;
175 this->
infos.push_back(ci);
212 p->Send_uint8 ((uint8_t)type);
213 p->Send_uint32(0xffffffff);
215 p->Send_string(
"vanilla");
216 p->Send_string(_openttd_content_version);
245 uint p_count = std::min<uint>(count, (
TCP_MTU -
sizeof(
PacketSize) -
sizeof(uint8_t) -
sizeof(uint16_t)) /
sizeof(uint32_t));
248 p->Send_uint16(p_count);
250 for (uint i = 0; i < p_count; i++) {
251 p->Send_uint32(content_ids[i]);
256 content_ids += p_count;
267 if (cv ==
nullptr)
return;
271 assert(cv->size() < 255);
272 assert(cv->size() < (
TCP_MTU -
sizeof(
PacketSize) -
sizeof(uint8_t) -
sizeof(uint8_t)) /
273 (
sizeof(uint8_t) +
sizeof(uint32_t) + (send_md5sum ? MD5_HASH_BYTES : 0)));
276 p->Send_uint8((uint8_t)cv->size());
279 p->Send_uint8((uint8_t)ci->type);
280 p->Send_uint32(ci->unique_id);
281 if (!send_md5sum)
continue;
282 p->Send_bytes(ci->md5sum);
290 if (ci->type == ci2->type && ci->unique_id == ci2->unique_id &&
291 (!send_md5sum || ci->md5sum == ci2->md5sum)) {
297 this->
infos.push_back(ci);
318 content.push_back(ci->id);
319 bytes += ci->filesize;
322 files = (uint)content.size();
325 if (files == 0)
return;
342 std::string content_request;
344 content_request += std::to_string(
id) +
"\n";
358 uint count = (uint)content.size();
359 const ContentID *content_ids = content.data();
367 uint p_count = std::min<uint>(count, (
TCP_MTU -
sizeof(
PacketSize) -
sizeof(uint8_t) -
sizeof(uint16_t)) /
sizeof(uint32_t));
370 p->Send_uint16(p_count);
372 for (uint i = 0; i < p_count; i++) {
373 p->Send_uint32(content_ids[i]);
378 content_ids += p_count;
396 buf += compressed ?
".tar.gz" :
".tar";
408#if defined(WITH_ZLIB)
413 if (!ftmp.has_value())
return false;
415 int fdup = dup(fileno(*ftmp));
416 gzFile fin = gzdopen(fdup,
"rb");
421 if (fin ==
nullptr || !fout.has_value()) {
426 int read = gzread(fin, buff,
sizeof(buff));
441 gzerror(fin, &errnum);
442 if (errnum != 0 && errnum != Z_STREAM_END) ret =
false;
445 if (read < 0 ||
static_cast<size_t>(read) != fwrite(buff, 1, read, *fout)) {
455 if (fin !=
nullptr) {
457 }
else if (fdup != -1) {
475static inline ssize_t
TransferOutFWrite(std::optional<FileHandle> &file,
const char *buffer,
size_t amount)
477 return fwrite(buffer, 1, amount, *file);
482 if (!this->
curFile.has_value()) {
533 if (filename.empty() || !(this->curFile =
FileHandle::Open(filename,
"wb")).has_value()) {
573 EM_ASM(
if (window[
"openttd_syncfs"]) openttd_syncfs());
594 if (this->
curFile.has_value()) {
610 assert(data.get() ==
nullptr || length != 0);
618 if (data !=
nullptr) {
631 if (data !=
nullptr) {
633 if (fwrite(data.get(), 1, length, *this->curFile) != length) {
645 if (this->
curFile.has_value()) {
663#define check_not_null(p) { if ((p) == nullptr) { this->OnFailure(); return; } }
665#define check_and_terminate(p) { check_not_null(p); *(p) = '\0'; }
669 char *p = strchr(str,
'\n');
670 check_and_terminate(p);
676 p = strchr(str,
',');
677 check_and_terminate(p);
682 p = strchr(str,
',');
683 check_and_terminate(p);
688 p = strchr(str,
',');
689 check_and_terminate(p);
695 if (strncmp(str,
"ottd", 4) == 0) {
704 p = strrchr(str,
'/');
708 std::string filename = p;
710 for (uint i = 0; i < 2; i++) {
711 auto pos = filename.find_last_of(
'.');
712 if (pos == std::string::npos) {
733#undef check_and_terminate
741 http_response_index(-2),
742 curFile(std::nullopt),
866 if (ci->id == cid)
return ci;
892 if (ci ==
nullptr || !ci->
IsSelected())
return;
955 for (
auto iter = range.first; iter != range.second; ++iter) {
967 tree.push_back(child);
973 for (uint i = 0; i < tree.size(); i++) {
1014 if (!c->IsSelected())
continue;
1033 bool force_selection =
false;
1035 if (parent_ci->IsSelected()) sel_count++;
1038 if (sel_count == 0) {
1044 if (force_selection)
continue;
1054 force_selection =
true;
1059 if (force_selection)
continue;
1079 this->
infos.clear();
1088 for (
size_t i = 0; i < this->
callbacks.size(); ) {
1092 if (i != this->
callbacks.size() && this->callbacks[i] == cb) i++;
1098 for (
size_t i = 0; i < this->
callbacks.size(); ) {
1101 if (i != this->
callbacks.size() && this->callbacks[i] == cb) i++;
1107 for (
size_t i = 0; i < this->
callbacks.size(); ) {
1111 if (i != this->
callbacks.size() && this->callbacks[i] == cb) i++;
1117 for (
size_t i = 0; i < this->
callbacks.size(); ) {
1120 if (i != this->
callbacks.size() && this->callbacks[i] == cb) i++;
1127 if (ci !=
nullptr) {
1131 for (
size_t i = 0; i < this->
callbacks.size(); ) {
1135 if (i != this->
callbacks.size() && this->callbacks[i] == cb) i++;
static bool HasAI(const struct ContentInfo *ci, bool md5sum)
Wrapper function for AIScanner::HasAI.
Socket handler for the content server connection.
void SelectUpgrade()
Select everything that's an update for something we've got.
void OnConnect(bool success) override
Callback for when the connection has finished.
void DownloadSelectedContentHTTP(const ContentIDList &content)
Initiate downloading the content over HTTP.
std::chrono::steady_clock::time_point lastActivity
The last time there was network activity.
void DownloadSelectedContent(uint &files, uint &bytes, bool fallback=false)
Actually begin downloading the content we selected.
bool isCancelled
Whether the download has been cancelled.
void ToggleSelectedState(const ContentInfo *ci)
Toggle the state of a content info and check its dependencies.
ClientNetworkContentSocketHandler()
Create a socket handler to handle the connection.
bool isConnecting
Whether we're connecting.
void OnDownloadProgress(const ContentInfo *ci, int bytes) override
We have progress in the download of a file.
void CheckDependencyState(const ContentInfo *ci)
Check the dependencies (recursively) of this content info.
static constexpr std::chrono::seconds IDLE_TIMEOUT
The idle timeout; when to close the connection because it's idle.
void OnReceiveData(std::unique_ptr< char[]> data, size_t length) override
We're receiving data.
void Select(ContentID cid)
Select a specific content id.
int http_response_index
Where we are, in the response, with handling it.
NetworkRecvStatus CloseConnection(bool error=true) override
Disconnect from the content server.
ContentIDList requested
ContentIDs we already requested (so we don't do it again)
void UnselectAll()
Unselect everything that we've not downloaded so far.
void RequestContentList(ContentType type)
Request the content list for the given type.
std::vector< char > http_response
The HTTP response to the requests we've been doing.
void ReverseLookupTreeDependency(ConstContentVector &tree, const ContentInfo *child) const
Reverse lookup the dependencies of all parents over a given child.
void DownloadContentInfo(ContentID cid)
Download information of a given Content ID if not already tried.
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...
void SendReceive()
Check whether we received/can send some data from/to the content server and when that's the case hand...
void OnDownloadComplete(ContentID cid) override
We have finished downloading a file.
ContentVector infos
All content info we received.
void OnFailure() override
An error has occurred and the connection has been closed.
ContentInfo * GetContent(ContentID cid) const
Get the content info based on a ContentID.
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...
void Connect()
Connect with the content server.
std::unordered_multimap< ContentID, ContentID > reverse_dependency_map
Content reverse dependency map.
bool BeforeDownload()
Handle the opening of the file before downloading.
void Clear()
Clear all downloaded content information.
ContentInfo * curInfo
Information about the currently downloaded file.
std::optional< FileHandle > curFile
Currently downloaded file.
std::vector< ContentID > ContentIDList
List of content IDs to (possibly) select.
void AfterDownload()
Handle the closing and extracting of a file after downloading it has been done.
bool IsCancelled() const override
Check if there is a request to cancel the transfer.
std::vector< ContentCallback * > callbacks
Callbacks to notify "the world".
~ClientNetworkContentSocketHandler()
Clear up the mess ;)
void DownloadSelectedContentFallback(const ContentIDList &content)
Initiate downloading the content over the fallback protocol.
void Unselect(ContentID cid)
Unselect a specific content id.
void Cancel()
Cancel the current download.
void OnDisconnect() override
Callback for when the connection got disconnected.
void ReverseLookupDependency(ConstContentVector &parents, const ContentInfo *child) const
Reverse lookup the dependencies of (direct) parents over a given child.
void SelectAll()
Select everything we can select.
void OnReceiveContentInfo(const ContentInfo *ci) override
We received a content info.
static std::optional< FileHandle > Open(const std::string &filename, const std::string &mode)
Open an RAII file handle if possible.
static bool HasGame(const struct ContentInfo *ci, bool md5sum)
Wrapper function for GameScanner::HasGame.
Connect to the content server.
void OnFailure() override
Callback for when the connection attempt failed.
void OnConnect(SOCKET s) override
Callback when the connection succeeded.
NetworkContentConnecter(const std::string &connection_string)
Initiate the connecting.
Base socket handler for all Content TCP sockets.
bool ReceivePackets()
Receive a packet at TCP level.
static void Connect(const std::string &uri, HTTPCallback *callback, const std::string data="")
Connect to the given URI.
void Reopen()
Reopen the socket so we can send/receive stuff again.
virtual NetworkRecvStatus CloseConnection(bool error=true)
This will put this socket handler in a close state.
SOCKET sock
The socket currently connected to.
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.
SendPacketsState SendPackets(bool closing_down=false)
Sends all the buffered packets out for this client.
void CloseSocket()
Close the actual socket of the connection.
bool CanSendReceive()
Check whether this socket can send or receive something.
"Helper" class for creating TCP connections in a non-blocking manner
std::string connection_string
Current address we are connecting to (before resolving).
Helper for scanning for files with tar as extension.
bool AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename={}) override
Add a file with the given filename.
const char * NetworkContentMirrorUriString()
Get the URI string for the content mirror from the environment variable OTTD_CONTENT_MIRROR_URI,...
const char * NetworkContentServerConnectionString()
Get the connection string for the content server from the environment variable OTTD_CONTENT_SERVER_CS...
static const uint16_t NETWORK_CONTENT_SERVER_PORT
The default port of the content server (TCP)
static const uint NETWORK_CONTENT_URL_LENGTH
The maximum length of a content's url, in bytes including '\0'.
static const uint NETWORK_CONTENT_VERSION_LENGTH
The maximum length of a content's version, in bytes including '\0'.
static const size_t TCP_MTU
Number of bytes we can pack in a single TCP packet.
static const uint NETWORK_CONTENT_FILENAME_LENGTH
The maximum length of a content's filename, in bytes including '\0'.
static const uint NETWORK_CONTENT_DESC_LENGTH
The maximum length of a content's description, in bytes including '\0'.
static const uint NETWORK_CONTENT_TAG_LENGTH
The maximum length of a content's tag, in bytes including '\0'.
static const uint NETWORK_CONTENT_NAME_LENGTH
The maximum length of a content's name, in bytes including '\0'.
bool include(Container &container, typename Container::const_reference &item)
Helper function to append an item to a container if it is not already contained.
NetworkRecvStatus
Status of a network client; reasons why a client has quit.
@ NETWORK_RECV_STATUS_OKAY
Everything is okay.
@ WL_ERROR
Errors (eg. saving/loading failed)
void ShowErrorMessage(EncodedString &&summary_msg, int x, int y, const CommandCost &cc)
Display an error message in a window.
bool ExtractTar(const std::string &tar_filename, Subdirectory subdir)
Extract the tar with the given filename in the directory where the tar resides.
bool FioRemove(const std::string &filename)
Remove a file.
@ SP_AUTODOWNLOAD_DIR
Search within the autodownload directory.
Subdirectory
The different kinds of subdirectories OpenTTD uses.
@ NO_DIRECTORY
A path without any base directory.
@ BASESET_DIR
Subdirectory for all base data (base sets, intro game)
bool HasScenario(const ContentInfo *ci, bool md5sum)
Check whether we've got a given scenario based on its unique ID.
bool HasScenario(const ContentInfo *ci, bool md5sum)
Check whether we've got a given scenario based on its unique ID.
static bool HasGRFConfig(const ContentInfo *ci, bool md5sum)
Wrapper function for the HasProc.
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.
ClientNetworkContentSocketHandler _network_content_client
The client we use to connect to the server.
static bool GunzipFile(const ContentInfo *ci)
Gunzip a given file and remove the .gz if successful.
bool(* HasProc)(const ContentInfo *ci, bool md5sum)
Check whether a function piece of content is locally known.
static std::string GetFullFilename(const ContentInfo *ci, bool compressed)
Determine the full filename of a piece of content information.
Part of the network protocol handling content distribution.
std::vector< const ContentInfo * > ConstContentVector
Vector with constant content info.
std::vector< ContentInfo * > ContentVector
Vector with content info.
const GRFConfig * FindGRFConfig(uint32_t grfid, FindGRFConfigMode mode, const MD5Hash *md5sum, uint32_t desired_version)
Find a NewGRF in the scanned list.
@ FGCM_ANY
Use first found.
@ FGCM_EXACT
Only find Grfs matching md5sum.
uint16_t PacketSize
Size of the whole packet.
@ SVS_ALLOW_NEWLINE
Allow newlines; replaces '\r ' with ' ' during processing.
@ SVS_REPLACE_WITH_QUESTION_MARK
Replace the unknown/bad bits with question marks.
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
Callbacks for notifying others about incoming data.
virtual void OnDownloadProgress(const ContentInfo *ci, int bytes)
We have progress in the download of a file.
virtual void OnDisconnect()
Callback for when the connection got disconnected.
virtual void OnDownloadComplete(ContentID cid)
We have finished downloading a file.
virtual void OnConnect(bool success)
Callback for when the connection has finished.
virtual void OnReceiveContentInfo(const ContentInfo *ci)
We received a content info.
Container for all important information about a piece of content.
uint32_t unique_id
Unique ID; either GRF ID or shortname.
bool IsValid() const
Is the information from this content info valid?
uint32_t filesize
Size of the file.
MD5Hash md5sum
The MD5 checksum.
std::string url
URL related to the content.
State state
Whether the content info is selected (for download)
std::string name
Name of the content.
std::string description
Description of the content.
std::string version
Version of the content.
ContentID id
Unique (server side) ID for the content.
std::string filename
Filename (for the .tar.gz; only valid on download)
bool IsSelected() const
Is the state either selected or autoselected?
ContentType type
Type of content.
std::vector< ContentID > dependencies
The dependencies (unique server side ids)
@ DOES_NOT_EXIST
The content does not exist in the content system.
@ ALREADY_HERE
The content is already at the client side.
@ AUTOSELECTED
The content has been selected as dependency.
@ UNSELECTED
The content has not been selected.
@ SELECTED
The content has been manually selected.
StringList tags
Tags associated with the content.
bool upgrade
This item is an upgrade.
Internal entity of a packet.
size_t Recv_bytes(std::span< uint8_t > span)
Extract at most the length of the span bytes from the packet into the span.
uint32_t Recv_uint32()
Read a 32 bits integer from the packet.
uint8_t Recv_uint8()
Read a 8 bits integer from the packet.
size_t RemainingBytesToTransfer() const
Get the amount of bytes that are still available for the Transfer functions.
ssize_t TransferOut(F transfer_function, D destination, Args &&... args)
Transfer data from the packet to the given function.
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...
Subdirectory GetContentInfoSubDir(ContentType type)
Helper to get the subdirectory a ContentInfo is located in.
uint32_t ContentID
Unique identifier for the content.
ContentType
The values in the enum are important; they are used as database 'keys'.
@ CONTENT_TYPE_AI_LIBRARY
The content consists of an AI library.
@ CONTENT_TYPE_BASE_SOUNDS
The content consists of base sounds.
@ CONTENT_TYPE_GAME_LIBRARY
The content consists of a GS library.
@ CONTENT_TYPE_BASE_GRAPHICS
The content consists of base graphics.
@ CONTENT_TYPE_AI
The content consists of an AI.
@ CONTENT_TYPE_SCENARIO
The content consists of a scenario.
@ CONTENT_TYPE_NEWGRF
The content consists of a NewGRF.
@ CONTENT_TYPE_BASE_MUSIC
The content consists of base music.
@ CONTENT_TYPE_GAME
The content consists of a game script.
@ CONTENT_TYPE_END
Helper to mark the end of the types.
@ CONTENT_TYPE_HEIGHTMAP
The content consists of a heightmap.
@ PACKET_CONTENT_CLIENT_CONTENT
Request a content file given an internal ID.
@ PACKET_CONTENT_CLIENT_INFO_LIST
Queries the content server for a list of info of a given content type.
@ PACKET_CONTENT_CLIENT_INFO_EXTID_MD5
Queries the content server for information about a list of external IDs and MD5.
@ PACKET_CONTENT_CLIENT_INFO_ID
Queries the content server for information about a list of internal IDs.
@ PACKET_CONTENT_CLIENT_INFO_EXTID
Queries the content server for information about a list of external IDs.
void CloseWindowById(WindowClass cls, WindowNumber number, bool force, int data)
Close a window by its class and window number (if it is open).
@ WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD
Network content download status.
@ WC_NETWORK_STATUS_WINDOW
Network status window; Window numbers: