Files
shadow-over-bishkek001/src/game_server/NetworkProtocol.h
T

116 lines
3.3 KiB
C++

#pragma once
#include "../external/nlohmann/json.hpp"
#include <Eigen/Dense>
#include <cstdint>
#include <map>
#include <string>
#include <variant>
#include <vector>
#include "../navigation/PathFinder.h"
namespace FRG {
inline constexpr int kGameProtocolVersion = 2;
inline constexpr std::int64_t kSimulationTickMs = 100;
inline constexpr std::uint32_t kDefaultInputDelayTicks = 2;
struct InitialStateMessage {
nlohmann::json state;
std::string assignedPlayerId;
std::uint64_t snapshotTick = 0;
std::int64_t tickMs = kSimulationTickMs;
std::uint32_t inputDelayTicks = kDefaultInputDelayTicks;
std::string compatibilityFingerprint;
};
struct DestinationInputMessage {
std::uint64_t clientSequence = 0;
Vec3fp target;
};
struct CharacterActionInputMessage {
std::uint64_t clientSequence = 0;
std::string action;
std::string targetId;
};
struct ScheduledDestinationCommand {
std::uint64_t commandSequence = 0;
std::string playerId;
Vec3fp target;
};
struct ScheduledCharacterEnabledCommand {
std::uint64_t commandSequence = 0;
std::string locationId;
std::string characterId;
bool enabled = false;
};
struct ScheduledCharacterActionCommand {
std::uint64_t commandSequence = 0;
std::string playerId;
std::string action;
std::string targetId;
};
using ScheduledCommand = std::variant<
ScheduledDestinationCommand,
ScheduledCharacterEnabledCommand,
ScheduledCharacterActionCommand>;
struct TickMessage {
std::uint64_t tickId = 0;
std::vector<ScheduledCommand> commands;
std::string stateHash;
};
class LockstepTimeline {
public:
explicit LockstepTimeline(
std::uint32_t inputDelayTicks = kDefaultInputDelayTicks)
: inputDelayTicks_(inputDelayTicks) {}
std::uint64_t currentTick() const { return currentTick_; }
std::uint64_t schedule(
const std::string& playerId, const Vec3fp& target);
std::uint64_t scheduleCharacterEnabled(
const std::string& locationId, const std::string& characterId,
bool enabled);
std::uint64_t scheduleCharacterAction(
const std::string& playerId, std::string action,
std::string targetId = {});
TickMessage advance();
private:
std::uint32_t inputDelayTicks_;
std::uint64_t currentTick_ = 0;
std::uint64_t nextCommandSequence_ = 1;
std::map<std::uint64_t, std::vector<ScheduledCommand>> pending_;
};
std::string makeInitialStateMessage(const InitialStateMessage& message);
bool parseInitialStateMessage(
const std::string& text, InitialStateMessage& message, std::string& error);
std::string makeDestinationInputMessage(const DestinationInputMessage& message);
bool parseDestinationInputMessage(
const std::string& text, DestinationInputMessage& message, std::string& error);
std::string makeCharacterActionInputMessage(
const CharacterActionInputMessage& message);
bool parseCharacterActionInputMessage(
const std::string& text, CharacterActionInputMessage& message,
std::string& error);
std::string makeTickMessage(const TickMessage& message);
bool parseTickMessage(
const std::string& text, TickMessage& message, std::string& error);
std::string makeErrorMessage(const std::string& code, const std::string& detail);
bool parseErrorMessage(
const std::string& text, std::string& code, std::string& detail);
// Stable for the same executable/content build. Persistence-only wall-clock
// fields are removed before hashing.
std::string canonicalStateHash(nlohmann::json state);
} // namespace FRG