R-Type
Distributed multiplayer game engine in C++
Loading...
Searching...
No Matches
PlayerInput.hpp
Go to the documentation of this file.
1/*
2** EPITECH PROJECT, 2025
3** Created on 09/12/2025.
4** File description:
5** PlayerInput.hpp
6*/
7
8#pragma once
9
10#include <capnp/message.h>
11#include <capnp/serialize.h>
12#include <cstdint>
13#include <stdexcept>
14#include <vector>
15#include "../Shared/SharedTypes.hpp"
16#include "schemas/c2s_messages.capnp.h"
17
18namespace RType::Messages::C2S {
19
27 public:
29 uint32_t sequenceId;
30 std::vector<Shared::Action> actions;
31 };
32
33 std::vector<InputSnapshot> inputs;
34
35 PlayerInput() = default;
36
37 // Constructor for a single input (legacy support, wraps in list)
38 PlayerInput(uint32_t seqId, const std::vector<Shared::Action> &acts) {
39 inputs.push_back({seqId, acts});
40 }
41
42 // Constructor for full history
43 explicit PlayerInput(const std::vector<InputSnapshot> &history) : inputs(history) {}
44
48 [[nodiscard]] std::vector<uint8_t> serialize() const {
49 capnp::MallocMessageBuilder message;
50 auto builder = message.initRoot<::PlayerInput>();
51
52 auto inputsBuilder = builder.initInputs(static_cast<unsigned int>(inputs.size()));
53
54 for (size_t i = 0; i < inputs.size(); ++i) {
55 auto snapshotBuilder = inputsBuilder[i];
56 snapshotBuilder.setSequenceId(inputs[i].sequenceId);
57
58 auto actionsBuilder =
59 snapshotBuilder.initActions(static_cast<unsigned int>(inputs[i].actions.size()));
60 for (size_t j = 0; j < inputs[i].actions.size(); ++j) {
61 actionsBuilder.set(static_cast<unsigned int>(j),
62 Shared::toCapnpAction(inputs[i].actions[j]));
63 }
64 }
65
66 auto bytes = capnp::messageToFlatArray(message);
67 auto byteArray = bytes.asBytes();
68 return std::vector<uint8_t>(byteArray.begin(), byteArray.end());
69 }
70
74 static PlayerInput deserialize(const std::vector<uint8_t> &data) {
75 KJ_REQUIRE(data.size() % sizeof(capnp::word) == 0,
76 "Serialized data size must be a multiple of capnp::word");
77 auto aligned = kj::heapArray<uint8_t>(data.size());
78 memcpy(aligned.begin(), data.data(), data.size());
79 kj::ArrayPtr<const capnp::word> words(reinterpret_cast<const capnp::word *>(aligned.begin()),
80 data.size() / sizeof(capnp::word));
81
82 capnp::FlatArrayMessageReader message(words);
83 auto reader = message.getRoot<::PlayerInput>();
84
85 PlayerInput result;
86 auto inputsReader = reader.getInputs();
87
88 static constexpr size_t MAX_INPUTS_PER_PACKET = 64; // Safety limit
89 if (inputsReader.size() > MAX_INPUTS_PER_PACKET) {
90 throw std::runtime_error("Too many inputs in PlayerInput message");
91 }
92
93 result.inputs.reserve(inputsReader.size());
94
95 for (auto snapshotReader : inputsReader) {
96 InputSnapshot snapshot;
97 snapshot.sequenceId = snapshotReader.getSequenceId();
98
99 auto actionsReader = snapshotReader.getActions();
100 snapshot.actions.reserve(actionsReader.size());
101
102 for (auto action : actionsReader) {
103 snapshot.actions.push_back(Shared::fromCapnpAction(action));
104 }
105 result.inputs.push_back(snapshot);
106 }
107
108 return result;
109 }
110 };
111
112} // namespace RType::Messages::C2S
Player input message sent from client to server (with redundancy)
PlayerInput(const std::vector< InputSnapshot > &history)
std::vector< InputSnapshot > inputs
std::vector< uint8_t > serialize() const
Serialize to byte vector.
PlayerInput(uint32_t seqId, const std::vector< Shared::Action > &acts)
static PlayerInput deserialize(const std::vector< uint8_t > &data)
Deserialize from byte vector.
Client-to-Server messages.
Action fromCapnpAction(::Action action)
inline ::Action toCapnpAction(Action action)