116 lines
3.3 KiB
C++
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
|