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.
*/