29#include "table/strings.h"
40# include <emscripten.h>
83 default:
return nullptr;
89 auto ci = std::make_unique<ContentInfo>();
103 ci->dependencies.reserve(dependency_count);
104 for (uint i = 0; i < dependency_count; i++) {
106 ci->dependencies.push_back(dependency_cid);
111 ci->tags.reserve(tag_count);
114 if (!ci->IsValid()) {
120 if (proc !=
nullptr) {
121 if (proc(*ci,
true)) {
125 if (proc(*ci,
false)) ci->upgrade =
true;
135 for (
const auto &ici : this->
infos) {
136 if (ici->type == ci->type && ici->unique_id == ci->unique_id && ci->md5sum == ici->md5sum) {
138 if (ci->name.empty()) ci->name = ici->name;
139 if (ici->IsSelected()) ci->state = ici->state;
154 if (ci->filesize == 0) {
158 ContentInfo *info = this->infos.emplace_back(std::move(ci)).get();
196 p->Send_uint32(0xffffffff);
198 p->Send_string(
"vanilla");
199 p->Send_string(_openttd_content_version);
224 static constexpr size_t MAX_CONTENT_IDS_PER_PACKET = (
TCP_MTU -
sizeof(
PacketSize) -
sizeof(uint8_t) -
sizeof(uint16_t)) /
sizeof(uint32_t);
226 if (content_ids.empty())
return;
230 for (
auto it = std::begin(content_ids); it != std::end(content_ids); ) {
231 auto last = std::ranges::next(it, MAX_CONTENT_IDS_PER_PACKET, std::end(content_ids));
234 p->Send_uint16(std::distance(it, last));
236 for (; it != last; ++it) {
251 if (cv ==
nullptr)
return;
255 assert(cv->size() < 255);
256 assert(cv->size() < (
TCP_MTU -
sizeof(
PacketSize) -
sizeof(uint8_t) -
sizeof(uint8_t)) /
257 (
sizeof(uint8_t) +
sizeof(uint32_t) + (send_md5sum ? MD5_HASH_BYTES : 0)));
260 p->Send_uint8((uint8_t)cv->size());
262 for (
const auto &ci : *cv) {
263 p->Send_uint8((uint8_t)ci->type);
264 p->Send_uint32(ci->unique_id);
265 if (!send_md5sum)
continue;
266 p->Send_bytes(ci->md5sum);
271 for (
auto &ci : *cv) {
273 for (
const auto &ci2 : this->
infos) {
274 if (ci->type == ci2->type && ci->unique_id == ci2->unique_id &&
275 (!send_md5sum || ci->md5sum == ci2->md5sum)) {
281 this->infos.push_back(std::move(ci));
297 for (
const auto &ci : this->
infos) {
300 content.push_back(ci->id);
301 bytes += ci->filesize;
304 files = (uint)content.size();
307 if (files == 0)
return;
324 std::string content_request;
326 format_append(content_request,
"{}\n",
id);
340 uint count = (uint)content.size();
341 const ContentID *content_ids = content.data();
349 uint p_count = std::min<uint>(count, (
TCP_MTU -
sizeof(
PacketSize) -
sizeof(uint8_t) -
sizeof(uint16_t)) /
sizeof(uint32_t));
352 p->Send_uint16(p_count);
354 for (uint i = 0; i < p_count; i++) {
355 p->Send_uint32(content_ids[i]);
360 content_ids += p_count;
378 buf += compressed ?
".tar.gz" :
".tar";
390#if defined(WITH_ZLIB)
395 if (!ftmp.has_value())
return false;
397 int fdup = dup(fileno(*ftmp));
398 gzFile fin = gzdopen(fdup,
"rb");
403 if (fin ==
nullptr || !fout.has_value()) {
408 int read = gzread(fin, buff,
sizeof(buff));
423 gzerror(fin, &errnum);
424 if (errnum != 0 && errnum != Z_STREAM_END) ret =
false;
427 if (read < 0 ||
static_cast<size_t>(read) != fwrite(buff, 1, read, *fout)) {
437 if (fin !=
nullptr) {
439 }
else if (fdup != -1) {
454 this->
cur_info = std::make_unique<ContentInfo>();
467 auto write_to_disk = [
this](std::span<const uint8_t> buffer) {
468 return fwrite(buffer.data(), 1, buffer.size(), *this->cur_file);
470 if (to_read != 0 && p.
TransferOut(write_to_disk) != to_read) {
501 if (this->
cur_info->filesize != 0) {
504 if (filename.empty() || !(this->cur_file =
FileHandle::Open(filename,
"wb")).has_value()) {
544 EM_ASM(
if (window[
"openttd_syncfs"]) openttd_syncfs());
581 assert(data.get() ==
nullptr || length != 0);
589 if (data !=
nullptr) {
602 if (data !=
nullptr) {
604 if (fwrite(data.get(), 1, length, *this->cur_file) != length) {
630 this->
cur_info = std::make_unique<ContentInfo>();
636 auto len = buffer.find(
'\n');
637 if (len == std::string_view::npos)
throw std::exception{};
645 if (!consumer.
ReadIf(
","))
throw std::exception{};
649 if (!consumer.
ReadIf(
","))
throw std::exception{};
653 if (!consumer.
ReadIf(
","))
throw std::exception{};
659 if (consumer.
ReadIf(
"ottd")) {
666 std::string_view filename;
669 if (!consumer.
ReadIf(
"/"))
throw std::exception{};
674 for (uint i = 0; i < 2; i++) {
675 auto pos = filename.find_last_of(
'.');
676 if (pos == std::string::npos)
throw std::exception{};
677 filename = filename.substr(0, pos);
681 this->
cur_info->filename = filename;
689 }
catch (
const std::exception&) {
797 this->
queued.push_back(cid);
806 if (this->
queued.empty())
return;
819 queue.erase(std::remove_if(std::begin(queue), std::end(queue), [
this](
ContentID content_id) {
821 }), std::end(queue));
833 for (
const auto &ci : this->
infos) {
834 if (ci->id == cid)
return ci.get();
860 if (ci ==
nullptr || !ci->
IsSelected())
return;
869 for (
const auto &ci : this->
infos) {
880 for (
const auto &ci : this->
infos) {
891 for (
const auto &ci : this->
infos) {
926 for (
auto iter = range.first; iter != range.second; ++iter) {
938 tree.push_back(child);
944 for (
size_t i = 0; i < tree.size(); i++) {
985 if (!c->IsSelected())
continue;
1004 bool force_selection =
false;
1006 if (parent_ci->IsSelected()) sel_count++;
1009 if (sel_count == 0) {
1015 if (force_selection)
continue;
1025 force_selection =
true;
1030 if (force_selection)
continue;
1048 this->
infos.clear();
1058 for (
size_t i = 0; i < this->
callbacks.size(); ) {
1062 if (i != this->
callbacks.size() && this->callbacks[i] == cb) i++;
1068 for (
size_t i = 0; i < this->
callbacks.size(); ) {
1071 if (i != this->
callbacks.size() && this->callbacks[i] == cb) i++;
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++;
1097 if (ci !=
nullptr) {
1101 for (
size_t i = 0; i < this->
callbacks.size(); ) {
1105 if (i != this->
callbacks.size() && this->callbacks[i] == cb) i++;
Base functions for all AIs.
static bool HasAILibrary(const ContentInfo &ci, bool md5sum)
Check whether we have an AI library with the exact characteristics as ci.
static bool HasAI(const 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.
void DownloadSelectedContent(uint &files, uint &bytes, bool fallback=false)
Actually begin downloading the content we selected.
void ToggleSelectedState(const ContentInfo &ci)
Toggle the state of a content info and check its dependencies.
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.
void OnReceiveContentInfo(const ContentInfo &ci) override
We received a content info.
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.
bool is_connecting
Whether we're connecting.
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.
ContentIDList queued
ContentID queue to be requested.
void OnDownloadProgress(const ContentInfo &ci, int bytes) override
We have progress in the download of a file.
void DownloadContentInfo(ContentID cid)
Download information of a given Content ID if not already tried.
bool ReceiveServerInfo(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.
std::vector< ContentID > ContentIDList
List of content IDs to (possibly) select.
ContentInfo * GetContent(ContentID cid) const
Get the content info based on a ContentID.
void Connect()
Connect with the content server.
std::unordered_multimap< ContentID, ContentID > reverse_dependency_map
Content reverse dependency map.
bool ReceiveServerContent(Packet &p) override
Server sending list of content info: uint32_t unique id uint32_t file size (0 == does not exist) stri...
bool BeforeDownload()
Handle the opening of the file before downloading.
void CheckDependencyState(const ContentInfo &ci)
Check the dependencies (recursively) of this content info.
void Clear()
Clear all downloaded content information.
void RequestQueuedContentInfo()
Send a content request for queued content info download.
std::optional< FileHandle > cur_file
Currently downloaded file.
std::chrono::steady_clock::time_point last_activity
The last time there was network activity.
void AfterDownload()
Handle the closing and extracting of a file after downloading it has been done.
void ReverseLookupDependency(ConstContentVector &parents, const ContentInfo &child) const
Reverse lookup the dependencies of (direct) parents over a given child.
bool IsCancelled() const override
Check if there is a request to cancel the transfer.
std::vector< ContentCallback * > callbacks
Callbacks to notify "the world".
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.
std::unique_ptr< ContentInfo > cur_info
Information about the currently downloaded file.
bool is_cancelled
Whether the download has been cancelled.
void SelectAll()
Select everything we can select.
static std::optional< FileHandle > Open(const std::string &filename, std::string_view mode)
Open an RAII file handle if possible.
static bool HasGameLibrary(const ContentInfo &ci, bool md5sum)
Check whether we have an Game library with the exact characteristics as ci.
static bool HasGame(const ContentInfo &ci, bool md5sum)
Wrapper function for GameScanner::HasGame.
void OnFailure() override
Callback for when the connection attempt failed.
void OnConnect(SOCKET s) override
Callback when the connection succeeded.
NetworkContentConnecter(std::string_view connection_string)
Initiate the connecting.
bool ReceivePackets()
Receive a packet at TCP level.
static void Connect(std::string_view uri, HTTPCallback *callback, std::string &&data="")
Connect to the given URI.
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.
Parse data from a string / buffer.
std::string_view ReadUntilChar(char c, SeparatorUsage sep)
Read data until the first occurrence of 8-bit char 'c', and advance reader.
void SkipUntilChar(char c, SeparatorUsage sep)
Skip data until the first occurrence of 8-bit char 'c'.
@ KEEP_SEPARATOR
Keep the separator in the data as next value to be read.
bool AnyBytesLeft() const noexcept
Check whether any bytes left to read.
bool ReadIf(std::string_view str)
Check whether the next data matches 'str', and skip it.
T ReadIntegerBase(int base, T def=0, bool clamp=false)
Read and parse an integer in number 'base', and advance the reader.
std::string_view GetLeftData() const noexcept
Get data left to read.
std::string connection_string
Current address we are connecting to (before resolving).
static std::shared_ptr< TCPConnecter > Create(Args &&... args)
Create the connecter, and initiate connecting by putting it in the collection of TCP connections to m...
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.
A timeout timer will fire once after the interval.
std::string_view NetworkContentMirrorUriString()
Get the URI string for the content mirror from the environment variable OTTD_CONTENT_MIRROR_URI,...
std::string_view 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.
@ Okay
Everything is okay.
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23).
Functions related to errors.
@ Error
Errors (eg. saving/loading failed).
void ShowErrorMessage(EncodedString &&summary_msg, int x, int y, 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.
Functions for standard in/out file operations.
@ AutodownloadDir
Search within the autodownload directory.
Subdirectory
The different kinds of subdirectories OpenTTD uses.
@ None
A path without any base directory.
@ Baseset
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.
Base functions for all Games.
bool(const ContentInfo &ci, bool md5sum) HasContentProc
Check whether a function piece of content is locally known.
static bool HasGRFConfig(const ContentInfo &ci, bool md5sum)
Check whether NewGRF content exists.
ClientNetworkContentSocketHandler _network_content_client
The client we use to connect to the server.
static HasContentProc * GetHasContentProcforContentType(ContentType type)
Get the has-content check function for the given content type.
bool HasScenario(const ContentInfo &ci, bool md5sum)
Check whether we've got a given scenario based on its unique ID.
static bool GunzipFile(const ContentInfo &ci)
Gunzip a given file and remove the .gz if successful.
static TimeoutTimer< TimerWindow > _request_queue_timeout
Timer delay requesting content, so it can be batched more efficiently in asynchronous contexts.
static constexpr auto CONTENT_QUEUE_TIMEOUT
Timeout after queueing content for it to try to be requested.
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< std::unique_ptr< ContentInfo > > ContentVector
Vector with content info.
std::vector< const ContentInfo * > ConstContentVector
Vector with constant content info.
Base for the NewGRF implementation.
constexpr T UnflattenNewGRFLabel(uint32_t value)
Unflatten a NewGRF related label from a 32 bits integer.
const GRFConfig * FindGRFConfig(GrfID grfid, FindGRFConfigMode mode, const MD5Hash *md5sum, uint32_t desired_version)
Find a NewGRF in the scanned list.
@ Exact
Only find Grfs matching md5sum.
uint16_t PacketSize
Size of the whole packet.
Declaration of OTTD revision dependent variables.
A number of safeguards to prevent using unsafe methods.
Types related to global configuration settings.
Definition of base types and functions in a cross-platform compatible way.
@ ReplaceWithQuestionMark
Replace the unknown/bad bits with question marks.
@ AllowNewline
Allow newlines; replaces '\r ' with ' ' during processing.
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
Functions related to OTTD's strings.
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 OnReceiveContentInfo(const ContentInfo &ci)
We received a content info.
virtual void OnDownloadComplete(ContentID cid)
We have finished downloading a file.
virtual void OnConnect(bool success)
Callback for when the connection has finished.
Container for all important information about a piece of content.
uint32_t unique_id
Unique ID; either GRF ID or shortname.
MD5Hash md5sum
The MD5 checksum.
State state
Whether the content info is selected (for download).
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).
@ Unselected
The content has not been selected.
@ AlreadyHere
The content is already at the client side.
@ Selected
The content has been manually selected.
@ Autoselected
The content has been selected as dependency.
@ DoesNotExist
The content does not exist in the content system.
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.
std::string Recv_string(size_t length, StringValidationSettings settings=StringValidationSetting::ReplaceWithQuestionMark)
Reads characters (bytes) from the packet until it finds a '\0', or reaches a maximum of length charac...
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)
Transfer data from the packet to the given function.
Subdirectory GetContentInfoSubDir(ContentType type)
Helper to get the subdirectory a ContentInfo is located in.
@ ClientContent
Request a content file given an internal ID.
@ ClientInfoExternalID
Queries the content server for information about a list of external IDs.
@ ClientInfoID
Queries the content server for information about a list of internal IDs.
@ ClientInfoExternalIDMD5
Queries the content server for information about a list of external IDs and MD5.
@ ClientInfoList
Queries the content server for a list of info of a given content type.
uint32_t ContentID
Unique identifier for the content.
ContentType
The values in the enum are important; they are received over the network from the content servers.
@ BaseSounds
The content consists of base sounds.
@ GsLibrary
The content consists of a GS library.
@ Scenario
The content consists of a scenario.
@ Heightmap
The content consists of a heightmap.
@ BaseGraphics
The content consists of base graphics.
@ Ai
The content consists of an AI.
@ End
Helper to mark the end of the types.
@ BaseMusic
The content consists of base music.
@ Gs
The content consists of a game script.
@ NewGRF
The content consists of a NewGRF.
@ AiLibrary
The content consists of an AI library.
Definition of Interval and OneShot timers.
Definition of the Window system.
void CloseWindowById(WindowClass cls, WindowNumber number, bool force, int data)
Close a window by its class and window number (if it is open).
Window functions not directly related to making/drawing windows.
@ ContentDownload
Network content download status.