M1c: Gleichschritt im Netz #9

Merged
steven merged 20 commits from m1c-gleichschritt-im-netz into main 2026-10-02 06:41:02 +00:00
2 changed files with 48 additions and 4 deletions
Showing only changes of commit b7d5383650 - Show all commits
+7 -2
View File
@@ -19,16 +19,20 @@ use crate::world::TICKS_PER_SECOND;
/// Version of the messages. Raise it whenever a message changes. /// Version of the messages. Raise it whenever a message changes.
pub const PROTOCOL_VERSION: u32 = 1; pub const PROTOCOL_VERSION: u32 = 1;
/// Longest message a guest may send, in bytes. The longest one is a greeting /// Longest message a guest may send, in bytes. The longest one is a greeting
/// with a name of full length, which needs 65 bytes. /// with a name of full length, which needs 65 bytes. Greetings of every
/// future version must fit as well: a longer one is rejected unread instead
/// of being recognised as another version.
pub const MAX_GUEST_MESSAGE_BYTES: usize = 128; pub const MAX_GUEST_MESSAGE_BYTES: usize = 128;
/// Ticks between two state checksums in the stream of ticks: one second. /// Ticks between two state checksums in the stream of ticks: one second.
pub const CHECK_INTERVAL_TICKS: u64 = TICKS_PER_SECOND as u64; pub const CHECK_INTERVAL_TICKS: u64 = TICKS_PER_SECOND as u64;
// Never changes, see the module documentation.
const TO_HOST_HELLO: u8 = 1; const TO_HOST_HELLO: u8 = 1;
const TO_HOST_ACT: u8 = 2; const TO_HOST_ACT: u8 = 2;
const TO_HOST_DIVERGED: u8 = 3; const TO_HOST_DIVERGED: u8 = 3;
const TO_GUEST_WORLD: u8 = 1; const TO_GUEST_WORLD: u8 = 1;
// Never changes, see the module documentation.
const TO_GUEST_REFUSED: u8 = 2; const TO_GUEST_REFUSED: u8 = 2;
const TO_GUEST_TICK: u8 = 3; const TO_GUEST_TICK: u8 = 3;
@@ -75,7 +79,8 @@ impl Action {
} }
} }
/// Why a host turned a guest away. /// Why a host turned a guest away. The codes never change, because games of
/// other versions read them.
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Refusal { pub enum Refusal {
/// The guest's game speaks another version of these messages. /// The guest's game speaks another version of these messages.
+41 -2
View File
@@ -12,7 +12,7 @@ use grovewright_core::command::Command;
use grovewright_core::hash::fnv1a64; use grovewright_core::hash::fnv1a64;
use grovewright_core::map::{Map, Pos, Terrain, Tile}; use grovewright_core::map::{Map, Pos, Terrain, Tile};
use grovewright_core::player::PlayerId; use grovewright_core::player::PlayerId;
use grovewright_core::protocol::{Action, Refusal, ToGuest, ToHost}; use grovewright_core::protocol::{Action, Refusal, ToGuest, ToHost, PROTOCOL_VERSION};
use grovewright_core::replay::Recording; use grovewright_core::replay::Recording;
use grovewright_core::rules::{ use grovewright_core::rules::{
end_hash, frozen_offline_script, frozen_script, rules_id, RULES_SEED, end_hash, frozen_offline_script, frozen_script, rules_id, RULES_SEED,
@@ -162,6 +162,45 @@ fn the_protocol_format_is_unchanged() {
fnv1a64(&bytes), fnv1a64(&bytes),
0xc263_69c0_f892_247b, 0xc263_69c0_f892_247b,
"the messages between host and guests changed; raise \ "the messages between host and guests changed; raise \
PROTOCOL_VERSION in core/src/protocol.rs; then update this value" PROTOCOL_VERSION in core/src/protocol.rs; then update this value. \
The start of a greeting and the refusal must never change, see \
the_greeting_start_and_the_refusal_never_change"
); );
} }
/// Covers the promise that games of every version can still tell each other
/// that they do not fit: a greeting starts with its tag and the version, and
/// a refusal is its tag and the code of its reason. Unlike every other part
/// of the messages, these stay the same when PROTOCOL_VERSION is raised.
#[test]
fn the_greeting_start_and_the_refusal_never_change() {
let hello = ToHost::Hello {
rules: 1,
key: [3; 16],
name: "Ada".to_owned(),
}
.encode();
let mut start = vec![1];
start.extend(PROTOCOL_VERSION.to_le_bytes());
assert_eq!(
hello[..start.len()],
start[..],
"a greeting starts with the tag 1 and the version; this never \
changes, not even with a new PROTOCOL_VERSION"
);
let refusals = [
(Refusal::OtherProtocol, 1),
(Refusal::OtherRules, 2),
(Refusal::WorldFull, 3),
(Refusal::TooManyPlayers, 4),
(Refusal::AlreadyPlaying, 5),
];
for (refusal, code) in refusals {
assert_eq!(
ToGuest::Refused(refusal).encode(),
vec![2, code],
"a refusal is the tag 2 and the code of its reason; this never \
changes, not even with a new PROTOCOL_VERSION"
);
}
}