diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ef8cbac5e0..5e0ba41b83 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -84,6 +84,7 @@ add_files( clear_map.h cmd_helper.h command.cpp + command_aux.h command_func.h command_type.h company_base.h diff --git a/src/command_aux.h b/src/command_aux.h new file mode 100644 index 0000000000..e9a3749a4d --- /dev/null +++ b/src/command_aux.h @@ -0,0 +1,119 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file command_aux.h Command auxiliary data. */ + +#ifndef COMMAND_AUX_H +#define COMMAND_AUX_H + +#include "command_type.h" +#include "command_func.h" +#include "string_type.h" +#include "core/serialisation.hpp" +#include "3rdparty/optional/ottd_optional.h" + +struct CommandDeserialisationBuffer : public BufferDeserialisationHelper { + const uint8 *buffer; + size_t size; + size_t pos = 0; + bool error = false; + + CommandDeserialisationBuffer(const uint8 *buffer, size_t size) : buffer(buffer), size(size) {} + + const byte *GetDeserialisationBuffer() const { return this->buffer; } + size_t GetDeserialisationBufferSize() const { return this->size; } + size_t &GetDeserialisationPosition() { return this->pos; } + + bool CanDeserialiseBytes(size_t bytes_to_read, bool raise_error) + { + if (this->error) return false; + + /* Check if variable is within packet-size */ + if (this->pos + bytes_to_read > this->size) { + if (raise_error) this->error = true; + return false; + } + + return true; + } +}; + +struct CommandSerialisationBuffer : public BufferSerialisationHelper { + std::vector &buffer; + size_t limit; + + CommandSerialisationBuffer(std::vector &buffer, size_t limit) : buffer(buffer), limit(limit) {} + + std::vector &GetSerialisationBuffer() { return this->buffer; } + size_t GetSerialisationLimit() const { return this->limit; } +}; + +struct CommandAuxiliarySerialised : public CommandAuxiliaryBase { + std::vector serialised_data; + + CommandAuxiliaryBase *Clone() const + { + return new CommandAuxiliarySerialised(*this); + } + + virtual const std::vector *GetDeserialisationSrc() const override { return &(this->serialised_data); } + + virtual void Serialise(CommandSerialisationBuffer &buffer) const override { buffer.Send_binary((const char *)this->serialised_data.data(), this->serialised_data.size()); } +}; + +template +struct CommandAuxiliarySerialisable : public CommandAuxiliaryBase { + virtual const std::vector *GetDeserialisationSrc() const override { return nullptr; } + + CommandAuxiliaryBase *Clone() const + { + return new T(*static_cast(this)); + } +}; + +template +struct CommandAuxData { + private: + opt::optional store; + const T *data = nullptr; + + public: + inline CommandCost Load(const CommandAuxiliaryBase *base) + { + if (base == nullptr) return CMD_ERROR; + const std::vector *deserialise_from = base->GetDeserialisationSrc(); + if (deserialise_from != nullptr) { + this->store = T(); + CommandDeserialisationBuffer buffer(deserialise_from->data(), deserialise_from->size()); + CommandCost res = this->store->Deserialise(buffer); + if (res.Failed()) return res; + if (buffer.error || buffer.pos != buffer.size) { + /* Other deserialisation error or wrong number of bytes read */ + return CMD_ERROR; + } + this->data = &(*(this->store)); + return res; + } else { + this->data = dynamic_cast(base); + if (this->data == nullptr) return CMD_ERROR; + return CommandCost(); + } + } + + inline const T *operator->() const + { + return this->data; + } + + inline const T &operator*() const + { + return *(this->data); + } +}; + +#endif /* COMMAND_AUX_H */ + diff --git a/src/command_type.h b/src/command_type.h index e5619348ed..0247b23b33 100644 --- a/src/command_type.h +++ b/src/command_type.h @@ -689,6 +689,40 @@ typedef void CommandCallback(const CommandCost &result, TileIndex tile, uint32 p #define MAX_CMD_TEXT_LENGTH 32000 +struct CommandSerialisationBuffer; + +struct CommandAuxiliaryBase { + virtual ~CommandAuxiliaryBase() {} + + virtual CommandAuxiliaryBase *Clone() const = 0; + + virtual const std::vector *GetDeserialisationSrc() const = 0; + + virtual void Serialise(CommandSerialisationBuffer &buffer) const = 0; +}; + +struct CommandAuxiliaryPtr : public std::unique_ptr +{ + using std::unique_ptr::unique_ptr; + + CommandAuxiliaryPtr() {}; + + CommandAuxiliaryPtr(const CommandAuxiliaryPtr &other) : + std::unique_ptr(CommandAuxiliaryPtr::Clone(other)) {} + + CommandAuxiliaryPtr& operator=(const CommandAuxiliaryPtr &other) + { + this->reset(CommandAuxiliaryPtr::Clone(other)); + return *this; + } + +private: + static CommandAuxiliaryBase *Clone(const CommandAuxiliaryPtr &other) + { + return other != nullptr ? other->Clone() : nullptr; + } +}; + /** * Structure for buffering the build command when selecting a station to join. */