M1c: Gleichschritt im Netz #9
@@ -19,16 +19,20 @@ use crate::world::TICKS_PER_SECOND;
|
||||
/// Version of the messages. Raise it whenever a message changes.
|
||||
pub const PROTOCOL_VERSION: u32 = 1;
|
||||
/// 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;
|
||||
/// Ticks between two state checksums in the stream of ticks: one second.
|
||||
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_ACT: u8 = 2;
|
||||
const TO_HOST_DIVERGED: u8 = 3;
|
||||
|
||||
const TO_GUEST_WORLD: u8 = 1;
|
||||
// Never changes, see the module documentation.
|
||||
const TO_GUEST_REFUSED: u8 = 2;
|
||||
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)]
|
||||
pub enum Refusal {
|
||||
/// The guest's game speaks another version of these messages.
|
||||
|
||||
+41
-2
@@ -12,7 +12,7 @@ use grovewright_core::command::Command;
|
||||
use grovewright_core::hash::fnv1a64;
|
||||
use grovewright_core::map::{Map, Pos, Terrain, Tile};
|
||||
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::rules::{
|
||||
end_hash, frozen_offline_script, frozen_script, rules_id, RULES_SEED,
|
||||
@@ -162,6 +162,45 @@ fn the_protocol_format_is_unchanged() {
|
||||
fnv1a64(&bytes),
|
||||
0xc263_69c0_f892_247b,
|
||||
"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"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user