mirror of
				https://github.com/QRouland/SGTool.git
				synced 2025-11-04 01:16:31 +00:00 
			
		
		
		
	Initial parser for stormfate replay
This commit is contained in:
		
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -14,3 +14,6 @@ Cargo.lock
 | 
				
			|||||||
# MSVC Windows builds of rustc generate these, which store debugging information
 | 
					# MSVC Windows builds of rustc generate these, which store debugging information
 | 
				
			||||||
*.pdb
 | 
					*.pdb
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Project specific
 | 
				
			||||||
 | 
					replays
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										13
									
								
								Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								Cargo.toml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					[package]
 | 
				
			||||||
 | 
					name = "sgtool"
 | 
				
			||||||
 | 
					version = "0.0.1-dev"
 | 
				
			||||||
 | 
					edition = "2021"
 | 
				
			||||||
 | 
					authors = [ "Quentin Rouland <quentin@qrouland.com>" ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[dependencies]
 | 
				
			||||||
 | 
					clap = { version = "4.5", features = ["derive"] }
 | 
				
			||||||
 | 
					byteorder = "1.5"
 | 
				
			||||||
 | 
					flate2 = "1.0"
 | 
				
			||||||
 | 
					quick-protobuf = { version = "0.8", features = ["std"] }
 | 
				
			||||||
 | 
					log = "0.4.21"
 | 
				
			||||||
 | 
					pretty_env_logger = "0.5.0"
 | 
				
			||||||
							
								
								
									
										14
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								README.md
									
									
									
									
									
								
							@@ -1,2 +1,14 @@
 | 
				
			|||||||
# SGTools
 | 
					[](https://www.gnu.org/licenses/agpl-3.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# SGTool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SGTool is a library and tool for analyze of the replay of the Stormgate game. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Acknowledgement
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[shroudstone](https://github.com/acarapetis/shroudstone) : A project with similar goal wrote in python. We thank them for part of the reverse engineering notabally the protobuf schema also used this project.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Disclamer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SGTool is community build which is not affiliate in any way to the official Stormgate Game in anyway. 
 | 
				
			||||||
							
								
								
									
										10
									
								
								gen_proto.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										10
									
								
								gen_proto.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					#!/bin/sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if ! command -v pb-rs &> /dev/null
 | 
				
			||||||
 | 
					then
 | 
				
			||||||
 | 
					    echo "Failed to find pb-rs command"
 | 
				
			||||||
 | 
					    echo "To install it run : cargo install pb-rs"
 | 
				
			||||||
 | 
					    exit 1
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pb-rs src/protos/stormgate.proto
 | 
				
			||||||
							
								
								
									
										4
									
								
								src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								src/lib.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					#[macro_use] extern crate log;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub mod parser;
 | 
				
			||||||
 | 
					mod protos;
 | 
				
			||||||
							
								
								
									
										27
									
								
								src/main.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/main.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					extern crate pretty_env_logger;
 | 
				
			||||||
 | 
					#[macro_use] extern crate log;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use std::path::PathBuf;
 | 
				
			||||||
 | 
					use clap::Parser;
 | 
				
			||||||
 | 
					use crate::parser::Replay;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mod protos;
 | 
				
			||||||
 | 
					mod parser;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Simple replay Stormgate replay parser
 | 
				
			||||||
 | 
					#[derive(Parser, Debug)]
 | 
				
			||||||
 | 
					#[command(version, about, long_about = None)]
 | 
				
			||||||
 | 
					struct Args {
 | 
				
			||||||
 | 
					    /// Path of replay to parse
 | 
				
			||||||
 | 
					    #[arg(short, long)]
 | 
				
			||||||
 | 
					    input: PathBuf,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn main() {
 | 
				
			||||||
 | 
					    pretty_env_logger::init();
 | 
				
			||||||
 | 
					    let args = Args::parse();
 | 
				
			||||||
 | 
					    info!("Input : {}", args.input.to_string_lossy());
 | 
				
			||||||
 | 
					    let mut bytes = Vec::new();
 | 
				
			||||||
 | 
					    debug!("{:#?}", Replay::load_file(&args.input, &mut bytes).unwrap());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										101
									
								
								src/parser.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								src/parser.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,101 @@
 | 
				
			|||||||
 | 
					use std::{fs::OpenOptions, io::{BufRead, BufReader, Read}, path::Path};
 | 
				
			||||||
 | 
					use byteorder::{ByteOrder, LittleEndian};
 | 
				
			||||||
 | 
					use flate2::bufread::GzDecoder;
 | 
				
			||||||
 | 
					use quick_protobuf::BytesReader;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::protos::stormgate::ReplayChunk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Stormgate Replay Header.
 | 
				
			||||||
 | 
					/// It consists of 16 bytes at the top of the replay
 | 
				
			||||||
 | 
					#[derive(Debug, Clone)]
 | 
				
			||||||
 | 
					pub struct Header {
 | 
				
			||||||
 | 
					    h1: u32, // 12 first bytes repsentation are unknown at the moment
 | 
				
			||||||
 | 
					    build_number: u32, // 4 next is he build number
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Stormgate Replay Payload.
 | 
				
			||||||
 | 
					/// After the the 16 bytes header, the actual payload of the replay of Protobuf messages that are gzipped
 | 
				
			||||||
 | 
					/// Each Protobuf messages represents events that appended in the game from the differetns clients
 | 
				
			||||||
 | 
					#[derive(Debug, Clone)]
 | 
				
			||||||
 | 
					pub struct Payload<'a> {
 | 
				
			||||||
 | 
					    chunks: Vec<ReplayChunk<'a>>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Stormgate replay
 | 
				
			||||||
 | 
					#[derive(Debug, Clone)]
 | 
				
			||||||
 | 
					pub struct Replay<'a> {
 | 
				
			||||||
 | 
					    header: Header, // header of the replay
 | 
				
			||||||
 | 
					    payload: Payload<'a>, // the content of a replay is set of messages
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn load_part<'a, R: Read>(reader: &'a mut R) -> impl FnMut(usize) -> Result<Vec<u8>, std::io::Error> + 'a {
 | 
				
			||||||
 | 
					    move |size| {
 | 
				
			||||||
 | 
					        let mut buf = vec![0u8; size];
 | 
				
			||||||
 | 
					        reader.read_exact(&mut buf)?;
 | 
				
			||||||
 | 
					        Ok(buf)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Header {
 | 
				
			||||||
 | 
					    /// 
 | 
				
			||||||
 | 
					    fn load<T: BufRead>(reader: &mut T) -> Result<Header, std::io::Error> {
 | 
				
			||||||
 | 
					        let mut load = load_part(reader);
 | 
				
			||||||
 | 
					        let h1 = LittleEndian::read_u32(&load(12)?);
 | 
				
			||||||
 | 
					        let build_number = LittleEndian::read_u32(&load(4)?);
 | 
				
			||||||
 | 
					        Ok(Header { h1, build_number })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> Payload<'a> {
 | 
				
			||||||
 | 
					    fn load<T: BufRead>(buf_reader: &mut T, buf: &'a mut Vec<u8>) -> Result<Payload<'a>, Box<dyn std::error::Error>> {
 | 
				
			||||||
 | 
					        let mut d = GzDecoder::new(buf_reader);
 | 
				
			||||||
 | 
					        d.read_to_end(buf)?;
 | 
				
			||||||
 | 
					        let mut reader = BytesReader::from_bytes(&buf);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        let mut data = Vec::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        while !reader.is_eof() {
 | 
				
			||||||
 | 
					            let read_message = reader.read_message::<ReplayChunk>(buf)?;
 | 
				
			||||||
 | 
					            data.push(read_message);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ok(Payload { chunks: data })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> Replay<'a> {
 | 
				
			||||||
 | 
					    fn load<T: BufRead>(buf_reader: &mut T, buf: &'a mut Vec<u8>) -> Result<Replay<'a>, Box<dyn std::error::Error>> {
 | 
				
			||||||
 | 
					        // Get Header
 | 
				
			||||||
 | 
					        let header = Header::load(buf_reader)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Get Payload
 | 
				
			||||||
 | 
					        let data = Payload::load(buf_reader, buf)?;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        Ok(Replay { header, payload: data })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn load_file(path: &Path, buf: &'a mut Vec<u8>) -> Result<Replay<'a>, Box<dyn std::error::Error>> {
 | 
				
			||||||
 | 
					        let file = OpenOptions::new().read(true).open(path).unwrap();
 | 
				
			||||||
 | 
					        let mut buf_reader = BufReader::new(file);
 | 
				
			||||||
 | 
					        Replay::load(&mut buf_reader, buf)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[cfg(test)]
 | 
				
			||||||
 | 
					mod tests {
 | 
				
			||||||
 | 
					    use super::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn load_file() {
 | 
				
			||||||
 | 
					        // Replay used is form Alpha phase of stormgate, threfore is not provided in the repo to avoid any problem with NDA at this time 
 | 
				
			||||||
 | 
					        // TODO : when the game officially can out fix provide sample replay for testing directly in the repo
 | 
				
			||||||
 | 
					        let replay_path = Path::new("replays/CL55366-2024.05.12-01.53.SGReplay"); 
 | 
				
			||||||
 | 
					        let mut buffer : Vec<u8> = vec![];
 | 
				
			||||||
 | 
					        let r = Replay::load_file(replay_path, &mut buffer).unwrap();
 | 
				
			||||||
 | 
					        assert_eq!(r.header.build_number, 55366);
 | 
				
			||||||
 | 
					        assert_eq!(r.payload.chunks.len(), 1373);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										1
									
								
								src/protos/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/protos/mod.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					pub mod stormgate;
 | 
				
			||||||
							
								
								
									
										104
									
								
								src/protos/stormgate.proto
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								src/protos/stormgate.proto
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,104 @@
 | 
				
			|||||||
 | 
					syntax = "proto3";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package stormgate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// protobuf schema for parsing lobby info from Stormgate replays
 | 
				
			||||||
 | 
					// Thanks to CascadeFury for most of this.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Each chunk seems to be of the form 3: {1: {actual content}}
 | 
				
			||||||
 | 
					// Since I don't know the meaning of those outer structs yet, I'm just putting them as inline messages:
 | 
				
			||||||
 | 
					message ReplayChunk {
 | 
				
			||||||
 | 
					    int32 timestamp = 1; // Time since game start in units of 1/1024 seconds
 | 
				
			||||||
 | 
					    int32 client_id = 2;
 | 
				
			||||||
 | 
					    message Wrapper {
 | 
				
			||||||
 | 
					        message ReplayContent {
 | 
				
			||||||
 | 
					            oneof content_type {
 | 
				
			||||||
 | 
					                Map map = 3;
 | 
				
			||||||
 | 
					                Player player = 12;
 | 
				
			||||||
 | 
					                LobbyChangeSlot change_slot = 13;
 | 
				
			||||||
 | 
					                LobbySetVariable set_variable = 15;
 | 
				
			||||||
 | 
					                StartGame start_game = 18;
 | 
				
			||||||
 | 
					                PlayerLeftGame player_left_game = 25;
 | 
				
			||||||
 | 
					                AssignPlayerSlot assign_player_slot = 37;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        ReplayContent content = 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    Wrapper inner = 3;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 3 - Map
 | 
				
			||||||
 | 
					message Map {
 | 
				
			||||||
 | 
					    string folder = 1;
 | 
				
			||||||
 | 
					    string name = 2;
 | 
				
			||||||
 | 
					    int32 seed = 3;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					message Player {
 | 
				
			||||||
 | 
					    UUID uuid = 2;
 | 
				
			||||||
 | 
					    message PlayerName {
 | 
				
			||||||
 | 
					        string nickname = 1;
 | 
				
			||||||
 | 
					        string discriminator = 2;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    PlayerName name = 3;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 13 - Sent when player changes slot (leave/enter), note that SlotChoice
 | 
				
			||||||
 | 
					// contains either a request for a specific slot, or what I assume is a "next
 | 
				
			||||||
 | 
					// slot available", slot 255 is observer
 | 
				
			||||||
 | 
					message LobbyChangeSlot {
 | 
				
			||||||
 | 
					    message SlotChoice {
 | 
				
			||||||
 | 
					        message SpecificSlot {
 | 
				
			||||||
 | 
					            int32 slot = 1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        oneof choice_type {
 | 
				
			||||||
 | 
					            SpecificSlot specific_slot = 2;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    SlotChoice choice = 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 15 - Sent when a player slot has a variable changed
 | 
				
			||||||
 | 
					// Var 374945738: Type, 0 = Closed, 1 = Human, 2 = AI
 | 
				
			||||||
 | 
					// Var 2952722564: Faction, 0 = Vanguard, 1 = Infernals
 | 
				
			||||||
 | 
					// Var 655515685: AIType, 0 = Peaceful, 1 = Junior, 2 = Senior
 | 
				
			||||||
 | 
					message LobbySetVariable {
 | 
				
			||||||
 | 
					    int32 slot = 3;
 | 
				
			||||||
 | 
					    uint32 variable_id = 4;
 | 
				
			||||||
 | 
					    uint32 value = 5;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 18 - "Start Game" Sent by players after second ReadyUp, that probably indicates player finished loading into the map
 | 
				
			||||||
 | 
					message StartGame {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum LeaveReason {
 | 
				
			||||||
 | 
					   Unknown = 0;
 | 
				
			||||||
 | 
					   Surrender = 1;  // Player surrenders
 | 
				
			||||||
 | 
					   Leave = 2;      // Player leaves game normally (game ended earlier, if this is the first PlayerLeftGame message, the outcome should be considered unknown)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 25 - When a player exits the game/disconnects
 | 
				
			||||||
 | 
					message PlayerLeftGame {
 | 
				
			||||||
 | 
					    UUID player_uuid = 1;
 | 
				
			||||||
 | 
					    LeaveReason reason = 2;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 37 - AssignPlayer (done by server as pl=64)
 | 
				
			||||||
 | 
					// Appears only in ladder games?
 | 
				
			||||||
 | 
					message AssignPlayerSlot {
 | 
				
			||||||
 | 
					    UUID uuid = 1;
 | 
				
			||||||
 | 
					    int64 slot = 2;
 | 
				
			||||||
 | 
					    string nickname = 3;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// UUIDs are encoded as 2 varints.
 | 
				
			||||||
 | 
					// To recover the original UUID, encode these as signed 64-bit big-endian
 | 
				
			||||||
 | 
					// integers and concatenate the resulting bitstrings; or in python:
 | 
				
			||||||
 | 
					// uuid.UUID(bytes=struct.pack(">qq", part1, part2))
 | 
				
			||||||
 | 
					message UUID {
 | 
				
			||||||
 | 
					    int64 part1 = 1;
 | 
				
			||||||
 | 
					    int64 part2 = 2;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										619
									
								
								src/protos/stormgate.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										619
									
								
								src/protos/stormgate.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,619 @@
 | 
				
			|||||||
 | 
					// Automatically generated rust module for 'stormgate.proto' file
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#![allow(non_snake_case)]
 | 
				
			||||||
 | 
					#![allow(non_upper_case_globals)]
 | 
				
			||||||
 | 
					#![allow(non_camel_case_types)]
 | 
				
			||||||
 | 
					#![allow(unused_imports)]
 | 
				
			||||||
 | 
					#![allow(unknown_lints)]
 | 
				
			||||||
 | 
					#![allow(clippy::all)]
 | 
				
			||||||
 | 
					#![cfg_attr(rustfmt, rustfmt_skip)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use std::borrow::Cow;
 | 
				
			||||||
 | 
					use quick_protobuf::{MessageInfo, MessageRead, MessageWrite, BytesReader, Writer, WriterBackend, Result};
 | 
				
			||||||
 | 
					use quick_protobuf::sizeofs::*;
 | 
				
			||||||
 | 
					use super::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, PartialEq, Eq, Clone, Copy)]
 | 
				
			||||||
 | 
					pub enum LeaveReason {
 | 
				
			||||||
 | 
					    Unknown = 0,
 | 
				
			||||||
 | 
					    Surrender = 1,
 | 
				
			||||||
 | 
					    Leave = 2,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Default for LeaveReason {
 | 
				
			||||||
 | 
					    fn default() -> Self {
 | 
				
			||||||
 | 
					        LeaveReason::Unknown
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl From<i32> for LeaveReason {
 | 
				
			||||||
 | 
					    fn from(i: i32) -> Self {
 | 
				
			||||||
 | 
					        match i {
 | 
				
			||||||
 | 
					            0 => LeaveReason::Unknown,
 | 
				
			||||||
 | 
					            1 => LeaveReason::Surrender,
 | 
				
			||||||
 | 
					            2 => LeaveReason::Leave,
 | 
				
			||||||
 | 
					            _ => Self::default(),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> From<&'a str> for LeaveReason {
 | 
				
			||||||
 | 
					    fn from(s: &'a str) -> Self {
 | 
				
			||||||
 | 
					        match s {
 | 
				
			||||||
 | 
					            "Unknown" => LeaveReason::Unknown,
 | 
				
			||||||
 | 
					            "Surrender" => LeaveReason::Surrender,
 | 
				
			||||||
 | 
					            "Leave" => LeaveReason::Leave,
 | 
				
			||||||
 | 
					            _ => Self::default(),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[allow(clippy::derive_partial_eq_without_eq)]
 | 
				
			||||||
 | 
					#[derive(Debug, Default, PartialEq, Clone)]
 | 
				
			||||||
 | 
					pub struct ReplayChunk<'a> {
 | 
				
			||||||
 | 
					    pub timestamp: i32,
 | 
				
			||||||
 | 
					    pub client_id: i32,
 | 
				
			||||||
 | 
					    pub inner: Option<stormgate::mod_ReplayChunk::Wrapper<'a>>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> MessageRead<'a> for ReplayChunk<'a> {
 | 
				
			||||||
 | 
					    fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
 | 
				
			||||||
 | 
					        let mut msg = Self::default();
 | 
				
			||||||
 | 
					        while !r.is_eof() {
 | 
				
			||||||
 | 
					            match r.next_tag(bytes) {
 | 
				
			||||||
 | 
					                Ok(8) => msg.timestamp = r.read_int32(bytes)?,
 | 
				
			||||||
 | 
					                Ok(16) => msg.client_id = r.read_int32(bytes)?,
 | 
				
			||||||
 | 
					                Ok(26) => msg.inner = Some(r.read_message::<stormgate::mod_ReplayChunk::Wrapper>(bytes)?),
 | 
				
			||||||
 | 
					                Ok(t) => { r.read_unknown(bytes, t)?; }
 | 
				
			||||||
 | 
					                Err(e) => return Err(e),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Ok(msg)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> MessageWrite for ReplayChunk<'a> {
 | 
				
			||||||
 | 
					    fn get_size(&self) -> usize {
 | 
				
			||||||
 | 
					        0
 | 
				
			||||||
 | 
					        + if self.timestamp == 0i32 { 0 } else { 1 + sizeof_varint(*(&self.timestamp) as u64) }
 | 
				
			||||||
 | 
					        + if self.client_id == 0i32 { 0 } else { 1 + sizeof_varint(*(&self.client_id) as u64) }
 | 
				
			||||||
 | 
					        + self.inner.as_ref().map_or(0, |m| 1 + sizeof_len((m).get_size()))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
 | 
				
			||||||
 | 
					        if self.timestamp != 0i32 { w.write_with_tag(8, |w| w.write_int32(*&self.timestamp))?; }
 | 
				
			||||||
 | 
					        if self.client_id != 0i32 { w.write_with_tag(16, |w| w.write_int32(*&self.client_id))?; }
 | 
				
			||||||
 | 
					        if let Some(ref s) = self.inner { w.write_with_tag(26, |w| w.write_message(s))?; }
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub mod mod_ReplayChunk {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use super::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[allow(clippy::derive_partial_eq_without_eq)]
 | 
				
			||||||
 | 
					#[derive(Debug, Default, PartialEq, Clone)]
 | 
				
			||||||
 | 
					pub struct Wrapper<'a> {
 | 
				
			||||||
 | 
					    pub content: Option<stormgate::mod_ReplayChunk::mod_Wrapper::ReplayContent<'a>>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> MessageRead<'a> for Wrapper<'a> {
 | 
				
			||||||
 | 
					    fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
 | 
				
			||||||
 | 
					        let mut msg = Self::default();
 | 
				
			||||||
 | 
					        while !r.is_eof() {
 | 
				
			||||||
 | 
					            match r.next_tag(bytes) {
 | 
				
			||||||
 | 
					                Ok(10) => msg.content = Some(r.read_message::<stormgate::mod_ReplayChunk::mod_Wrapper::ReplayContent>(bytes)?),
 | 
				
			||||||
 | 
					                Ok(t) => { r.read_unknown(bytes, t)?; }
 | 
				
			||||||
 | 
					                Err(e) => return Err(e),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Ok(msg)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> MessageWrite for Wrapper<'a> {
 | 
				
			||||||
 | 
					    fn get_size(&self) -> usize {
 | 
				
			||||||
 | 
					        0
 | 
				
			||||||
 | 
					        + self.content.as_ref().map_or(0, |m| 1 + sizeof_len((m).get_size()))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
 | 
				
			||||||
 | 
					        if let Some(ref s) = self.content { w.write_with_tag(10, |w| w.write_message(s))?; }
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub mod mod_Wrapper {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use super::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[allow(clippy::derive_partial_eq_without_eq)]
 | 
				
			||||||
 | 
					#[derive(Debug, Default, PartialEq, Clone)]
 | 
				
			||||||
 | 
					pub struct ReplayContent<'a> {
 | 
				
			||||||
 | 
					    pub content_type: stormgate::mod_ReplayChunk::mod_Wrapper::mod_ReplayContent::OneOfcontent_type<'a>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> MessageRead<'a> for ReplayContent<'a> {
 | 
				
			||||||
 | 
					    fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
 | 
				
			||||||
 | 
					        let mut msg = Self::default();
 | 
				
			||||||
 | 
					        while !r.is_eof() {
 | 
				
			||||||
 | 
					            match r.next_tag(bytes) {
 | 
				
			||||||
 | 
					                Ok(26) => msg.content_type = stormgate::mod_ReplayChunk::mod_Wrapper::mod_ReplayContent::OneOfcontent_type::map(r.read_message::<stormgate::Map>(bytes)?),
 | 
				
			||||||
 | 
					                Ok(98) => msg.content_type = stormgate::mod_ReplayChunk::mod_Wrapper::mod_ReplayContent::OneOfcontent_type::player(r.read_message::<stormgate::Player>(bytes)?),
 | 
				
			||||||
 | 
					                Ok(106) => msg.content_type = stormgate::mod_ReplayChunk::mod_Wrapper::mod_ReplayContent::OneOfcontent_type::change_slot(r.read_message::<stormgate::LobbyChangeSlot>(bytes)?),
 | 
				
			||||||
 | 
					                Ok(122) => msg.content_type = stormgate::mod_ReplayChunk::mod_Wrapper::mod_ReplayContent::OneOfcontent_type::set_variable(r.read_message::<stormgate::LobbySetVariable>(bytes)?),
 | 
				
			||||||
 | 
					                Ok(146) => msg.content_type = stormgate::mod_ReplayChunk::mod_Wrapper::mod_ReplayContent::OneOfcontent_type::start_game(r.read_message::<stormgate::StartGame>(bytes)?),
 | 
				
			||||||
 | 
					                Ok(202) => msg.content_type = stormgate::mod_ReplayChunk::mod_Wrapper::mod_ReplayContent::OneOfcontent_type::player_left_game(r.read_message::<stormgate::PlayerLeftGame>(bytes)?),
 | 
				
			||||||
 | 
					                Ok(298) => msg.content_type = stormgate::mod_ReplayChunk::mod_Wrapper::mod_ReplayContent::OneOfcontent_type::assign_player_slot(r.read_message::<stormgate::AssignPlayerSlot>(bytes)?),
 | 
				
			||||||
 | 
					                Ok(t) => { r.read_unknown(bytes, t)?; }
 | 
				
			||||||
 | 
					                Err(e) => return Err(e),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Ok(msg)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> MessageWrite for ReplayContent<'a> {
 | 
				
			||||||
 | 
					    fn get_size(&self) -> usize {
 | 
				
			||||||
 | 
					        0
 | 
				
			||||||
 | 
					        + match self.content_type {
 | 
				
			||||||
 | 
					            stormgate::mod_ReplayChunk::mod_Wrapper::mod_ReplayContent::OneOfcontent_type::map(ref m) => 1 + sizeof_len((m).get_size()),
 | 
				
			||||||
 | 
					            stormgate::mod_ReplayChunk::mod_Wrapper::mod_ReplayContent::OneOfcontent_type::player(ref m) => 1 + sizeof_len((m).get_size()),
 | 
				
			||||||
 | 
					            stormgate::mod_ReplayChunk::mod_Wrapper::mod_ReplayContent::OneOfcontent_type::change_slot(ref m) => 1 + sizeof_len((m).get_size()),
 | 
				
			||||||
 | 
					            stormgate::mod_ReplayChunk::mod_Wrapper::mod_ReplayContent::OneOfcontent_type::set_variable(ref m) => 1 + sizeof_len((m).get_size()),
 | 
				
			||||||
 | 
					            stormgate::mod_ReplayChunk::mod_Wrapper::mod_ReplayContent::OneOfcontent_type::start_game(ref m) => 2 + sizeof_len((m).get_size()),
 | 
				
			||||||
 | 
					            stormgate::mod_ReplayChunk::mod_Wrapper::mod_ReplayContent::OneOfcontent_type::player_left_game(ref m) => 2 + sizeof_len((m).get_size()),
 | 
				
			||||||
 | 
					            stormgate::mod_ReplayChunk::mod_Wrapper::mod_ReplayContent::OneOfcontent_type::assign_player_slot(ref m) => 2 + sizeof_len((m).get_size()),
 | 
				
			||||||
 | 
					            stormgate::mod_ReplayChunk::mod_Wrapper::mod_ReplayContent::OneOfcontent_type::None => 0,
 | 
				
			||||||
 | 
					    }    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
 | 
				
			||||||
 | 
					        match self.content_type {            stormgate::mod_ReplayChunk::mod_Wrapper::mod_ReplayContent::OneOfcontent_type::map(ref m) => { w.write_with_tag(26, |w| w.write_message(m))? },
 | 
				
			||||||
 | 
					            stormgate::mod_ReplayChunk::mod_Wrapper::mod_ReplayContent::OneOfcontent_type::player(ref m) => { w.write_with_tag(98, |w| w.write_message(m))? },
 | 
				
			||||||
 | 
					            stormgate::mod_ReplayChunk::mod_Wrapper::mod_ReplayContent::OneOfcontent_type::change_slot(ref m) => { w.write_with_tag(106, |w| w.write_message(m))? },
 | 
				
			||||||
 | 
					            stormgate::mod_ReplayChunk::mod_Wrapper::mod_ReplayContent::OneOfcontent_type::set_variable(ref m) => { w.write_with_tag(122, |w| w.write_message(m))? },
 | 
				
			||||||
 | 
					            stormgate::mod_ReplayChunk::mod_Wrapper::mod_ReplayContent::OneOfcontent_type::start_game(ref m) => { w.write_with_tag(146, |w| w.write_message(m))? },
 | 
				
			||||||
 | 
					            stormgate::mod_ReplayChunk::mod_Wrapper::mod_ReplayContent::OneOfcontent_type::player_left_game(ref m) => { w.write_with_tag(202, |w| w.write_message(m))? },
 | 
				
			||||||
 | 
					            stormgate::mod_ReplayChunk::mod_Wrapper::mod_ReplayContent::OneOfcontent_type::assign_player_slot(ref m) => { w.write_with_tag(298, |w| w.write_message(m))? },
 | 
				
			||||||
 | 
					            stormgate::mod_ReplayChunk::mod_Wrapper::mod_ReplayContent::OneOfcontent_type::None => {},
 | 
				
			||||||
 | 
					    }        Ok(())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub mod mod_ReplayContent {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use super::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, PartialEq, Clone)]
 | 
				
			||||||
 | 
					pub enum OneOfcontent_type<'a> {
 | 
				
			||||||
 | 
					    map(stormgate::Map<'a>),
 | 
				
			||||||
 | 
					    player(stormgate::Player<'a>),
 | 
				
			||||||
 | 
					    change_slot(stormgate::LobbyChangeSlot),
 | 
				
			||||||
 | 
					    set_variable(stormgate::LobbySetVariable),
 | 
				
			||||||
 | 
					    start_game(stormgate::StartGame),
 | 
				
			||||||
 | 
					    player_left_game(stormgate::PlayerLeftGame),
 | 
				
			||||||
 | 
					    assign_player_slot(stormgate::AssignPlayerSlot<'a>),
 | 
				
			||||||
 | 
					    None,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> Default for OneOfcontent_type<'a> {
 | 
				
			||||||
 | 
					    fn default() -> Self {
 | 
				
			||||||
 | 
					        OneOfcontent_type::None
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[allow(clippy::derive_partial_eq_without_eq)]
 | 
				
			||||||
 | 
					#[derive(Debug, Default, PartialEq, Clone)]
 | 
				
			||||||
 | 
					pub struct Map<'a> {
 | 
				
			||||||
 | 
					    pub folder: Cow<'a, str>,
 | 
				
			||||||
 | 
					    pub name: Cow<'a, str>,
 | 
				
			||||||
 | 
					    pub seed: i32,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> MessageRead<'a> for Map<'a> {
 | 
				
			||||||
 | 
					    fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
 | 
				
			||||||
 | 
					        let mut msg = Self::default();
 | 
				
			||||||
 | 
					        while !r.is_eof() {
 | 
				
			||||||
 | 
					            match r.next_tag(bytes) {
 | 
				
			||||||
 | 
					                Ok(10) => msg.folder = r.read_string(bytes).map(Cow::Borrowed)?,
 | 
				
			||||||
 | 
					                Ok(18) => msg.name = r.read_string(bytes).map(Cow::Borrowed)?,
 | 
				
			||||||
 | 
					                Ok(24) => msg.seed = r.read_int32(bytes)?,
 | 
				
			||||||
 | 
					                Ok(t) => { r.read_unknown(bytes, t)?; }
 | 
				
			||||||
 | 
					                Err(e) => return Err(e),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Ok(msg)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> MessageWrite for Map<'a> {
 | 
				
			||||||
 | 
					    fn get_size(&self) -> usize {
 | 
				
			||||||
 | 
					        0
 | 
				
			||||||
 | 
					        + if self.folder == "" { 0 } else { 1 + sizeof_len((&self.folder).len()) }
 | 
				
			||||||
 | 
					        + if self.name == "" { 0 } else { 1 + sizeof_len((&self.name).len()) }
 | 
				
			||||||
 | 
					        + if self.seed == 0i32 { 0 } else { 1 + sizeof_varint(*(&self.seed) as u64) }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
 | 
				
			||||||
 | 
					        if self.folder != "" { w.write_with_tag(10, |w| w.write_string(&**&self.folder))?; }
 | 
				
			||||||
 | 
					        if self.name != "" { w.write_with_tag(18, |w| w.write_string(&**&self.name))?; }
 | 
				
			||||||
 | 
					        if self.seed != 0i32 { w.write_with_tag(24, |w| w.write_int32(*&self.seed))?; }
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[allow(clippy::derive_partial_eq_without_eq)]
 | 
				
			||||||
 | 
					#[derive(Debug, Default, PartialEq, Clone)]
 | 
				
			||||||
 | 
					pub struct Player<'a> {
 | 
				
			||||||
 | 
					    pub uuid: Option<stormgate::UUID>,
 | 
				
			||||||
 | 
					    pub name: Option<stormgate::mod_Player::PlayerName<'a>>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> MessageRead<'a> for Player<'a> {
 | 
				
			||||||
 | 
					    fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
 | 
				
			||||||
 | 
					        let mut msg = Self::default();
 | 
				
			||||||
 | 
					        while !r.is_eof() {
 | 
				
			||||||
 | 
					            match r.next_tag(bytes) {
 | 
				
			||||||
 | 
					                Ok(18) => msg.uuid = Some(r.read_message::<stormgate::UUID>(bytes)?),
 | 
				
			||||||
 | 
					                Ok(26) => msg.name = Some(r.read_message::<stormgate::mod_Player::PlayerName>(bytes)?),
 | 
				
			||||||
 | 
					                Ok(t) => { r.read_unknown(bytes, t)?; }
 | 
				
			||||||
 | 
					                Err(e) => return Err(e),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Ok(msg)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> MessageWrite for Player<'a> {
 | 
				
			||||||
 | 
					    fn get_size(&self) -> usize {
 | 
				
			||||||
 | 
					        0
 | 
				
			||||||
 | 
					        + self.uuid.as_ref().map_or(0, |m| 1 + sizeof_len((m).get_size()))
 | 
				
			||||||
 | 
					        + self.name.as_ref().map_or(0, |m| 1 + sizeof_len((m).get_size()))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
 | 
				
			||||||
 | 
					        if let Some(ref s) = self.uuid { w.write_with_tag(18, |w| w.write_message(s))?; }
 | 
				
			||||||
 | 
					        if let Some(ref s) = self.name { w.write_with_tag(26, |w| w.write_message(s))?; }
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub mod mod_Player {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use std::borrow::Cow;
 | 
				
			||||||
 | 
					use super::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[allow(clippy::derive_partial_eq_without_eq)]
 | 
				
			||||||
 | 
					#[derive(Debug, Default, PartialEq, Clone)]
 | 
				
			||||||
 | 
					pub struct PlayerName<'a> {
 | 
				
			||||||
 | 
					    pub nickname: Cow<'a, str>,
 | 
				
			||||||
 | 
					    pub discriminator: Cow<'a, str>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> MessageRead<'a> for PlayerName<'a> {
 | 
				
			||||||
 | 
					    fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
 | 
				
			||||||
 | 
					        let mut msg = Self::default();
 | 
				
			||||||
 | 
					        while !r.is_eof() {
 | 
				
			||||||
 | 
					            match r.next_tag(bytes) {
 | 
				
			||||||
 | 
					                Ok(10) => msg.nickname = r.read_string(bytes).map(Cow::Borrowed)?,
 | 
				
			||||||
 | 
					                Ok(18) => msg.discriminator = r.read_string(bytes).map(Cow::Borrowed)?,
 | 
				
			||||||
 | 
					                Ok(t) => { r.read_unknown(bytes, t)?; }
 | 
				
			||||||
 | 
					                Err(e) => return Err(e),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Ok(msg)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> MessageWrite for PlayerName<'a> {
 | 
				
			||||||
 | 
					    fn get_size(&self) -> usize {
 | 
				
			||||||
 | 
					        0
 | 
				
			||||||
 | 
					        + if self.nickname == "" { 0 } else { 1 + sizeof_len((&self.nickname).len()) }
 | 
				
			||||||
 | 
					        + if self.discriminator == "" { 0 } else { 1 + sizeof_len((&self.discriminator).len()) }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
 | 
				
			||||||
 | 
					        if self.nickname != "" { w.write_with_tag(10, |w| w.write_string(&**&self.nickname))?; }
 | 
				
			||||||
 | 
					        if self.discriminator != "" { w.write_with_tag(18, |w| w.write_string(&**&self.discriminator))?; }
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[allow(clippy::derive_partial_eq_without_eq)]
 | 
				
			||||||
 | 
					#[derive(Debug, Default, PartialEq, Clone)]
 | 
				
			||||||
 | 
					pub struct LobbyChangeSlot {
 | 
				
			||||||
 | 
					    pub choice: Option<stormgate::mod_LobbyChangeSlot::SlotChoice>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> MessageRead<'a> for LobbyChangeSlot {
 | 
				
			||||||
 | 
					    fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
 | 
				
			||||||
 | 
					        let mut msg = Self::default();
 | 
				
			||||||
 | 
					        while !r.is_eof() {
 | 
				
			||||||
 | 
					            match r.next_tag(bytes) {
 | 
				
			||||||
 | 
					                Ok(10) => msg.choice = Some(r.read_message::<stormgate::mod_LobbyChangeSlot::SlotChoice>(bytes)?),
 | 
				
			||||||
 | 
					                Ok(t) => { r.read_unknown(bytes, t)?; }
 | 
				
			||||||
 | 
					                Err(e) => return Err(e),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Ok(msg)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl MessageWrite for LobbyChangeSlot {
 | 
				
			||||||
 | 
					    fn get_size(&self) -> usize {
 | 
				
			||||||
 | 
					        0
 | 
				
			||||||
 | 
					        + self.choice.as_ref().map_or(0, |m| 1 + sizeof_len((m).get_size()))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
 | 
				
			||||||
 | 
					        if let Some(ref s) = self.choice { w.write_with_tag(10, |w| w.write_message(s))?; }
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub mod mod_LobbyChangeSlot {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use super::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[allow(clippy::derive_partial_eq_without_eq)]
 | 
				
			||||||
 | 
					#[derive(Debug, Default, PartialEq, Clone)]
 | 
				
			||||||
 | 
					pub struct SlotChoice {
 | 
				
			||||||
 | 
					    pub choice_type: stormgate::mod_LobbyChangeSlot::mod_SlotChoice::OneOfchoice_type,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> MessageRead<'a> for SlotChoice {
 | 
				
			||||||
 | 
					    fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
 | 
				
			||||||
 | 
					        let mut msg = Self::default();
 | 
				
			||||||
 | 
					        while !r.is_eof() {
 | 
				
			||||||
 | 
					            match r.next_tag(bytes) {
 | 
				
			||||||
 | 
					                Ok(18) => msg.choice_type = stormgate::mod_LobbyChangeSlot::mod_SlotChoice::OneOfchoice_type::specific_slot(r.read_message::<stormgate::mod_LobbyChangeSlot::mod_SlotChoice::SpecificSlot>(bytes)?),
 | 
				
			||||||
 | 
					                Ok(t) => { r.read_unknown(bytes, t)?; }
 | 
				
			||||||
 | 
					                Err(e) => return Err(e),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Ok(msg)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl MessageWrite for SlotChoice {
 | 
				
			||||||
 | 
					    fn get_size(&self) -> usize {
 | 
				
			||||||
 | 
					        0
 | 
				
			||||||
 | 
					        + match self.choice_type {
 | 
				
			||||||
 | 
					            stormgate::mod_LobbyChangeSlot::mod_SlotChoice::OneOfchoice_type::specific_slot(ref m) => 1 + sizeof_len((m).get_size()),
 | 
				
			||||||
 | 
					            stormgate::mod_LobbyChangeSlot::mod_SlotChoice::OneOfchoice_type::None => 0,
 | 
				
			||||||
 | 
					    }    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
 | 
				
			||||||
 | 
					        match self.choice_type {            stormgate::mod_LobbyChangeSlot::mod_SlotChoice::OneOfchoice_type::specific_slot(ref m) => { w.write_with_tag(18, |w| w.write_message(m))? },
 | 
				
			||||||
 | 
					            stormgate::mod_LobbyChangeSlot::mod_SlotChoice::OneOfchoice_type::None => {},
 | 
				
			||||||
 | 
					    }        Ok(())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub mod mod_SlotChoice {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use super::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[allow(clippy::derive_partial_eq_without_eq)]
 | 
				
			||||||
 | 
					#[derive(Debug, Default, PartialEq, Clone)]
 | 
				
			||||||
 | 
					pub struct SpecificSlot {
 | 
				
			||||||
 | 
					    pub slot: i32,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> MessageRead<'a> for SpecificSlot {
 | 
				
			||||||
 | 
					    fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
 | 
				
			||||||
 | 
					        let mut msg = Self::default();
 | 
				
			||||||
 | 
					        while !r.is_eof() {
 | 
				
			||||||
 | 
					            match r.next_tag(bytes) {
 | 
				
			||||||
 | 
					                Ok(8) => msg.slot = r.read_int32(bytes)?,
 | 
				
			||||||
 | 
					                Ok(t) => { r.read_unknown(bytes, t)?; }
 | 
				
			||||||
 | 
					                Err(e) => return Err(e),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Ok(msg)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl MessageWrite for SpecificSlot {
 | 
				
			||||||
 | 
					    fn get_size(&self) -> usize {
 | 
				
			||||||
 | 
					        0
 | 
				
			||||||
 | 
					        + if self.slot == 0i32 { 0 } else { 1 + sizeof_varint(*(&self.slot) as u64) }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
 | 
				
			||||||
 | 
					        if self.slot != 0i32 { w.write_with_tag(8, |w| w.write_int32(*&self.slot))?; }
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, PartialEq, Clone)]
 | 
				
			||||||
 | 
					pub enum OneOfchoice_type {
 | 
				
			||||||
 | 
					    specific_slot(stormgate::mod_LobbyChangeSlot::mod_SlotChoice::SpecificSlot),
 | 
				
			||||||
 | 
					    None,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Default for OneOfchoice_type {
 | 
				
			||||||
 | 
					    fn default() -> Self {
 | 
				
			||||||
 | 
					        OneOfchoice_type::None
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[allow(clippy::derive_partial_eq_without_eq)]
 | 
				
			||||||
 | 
					#[derive(Debug, Default, PartialEq, Clone)]
 | 
				
			||||||
 | 
					pub struct LobbySetVariable {
 | 
				
			||||||
 | 
					    pub slot: i32,
 | 
				
			||||||
 | 
					    pub variable_id: u32,
 | 
				
			||||||
 | 
					    pub value: u32,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> MessageRead<'a> for LobbySetVariable {
 | 
				
			||||||
 | 
					    fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
 | 
				
			||||||
 | 
					        let mut msg = Self::default();
 | 
				
			||||||
 | 
					        while !r.is_eof() {
 | 
				
			||||||
 | 
					            match r.next_tag(bytes) {
 | 
				
			||||||
 | 
					                Ok(24) => msg.slot = r.read_int32(bytes)?,
 | 
				
			||||||
 | 
					                Ok(32) => msg.variable_id = r.read_uint32(bytes)?,
 | 
				
			||||||
 | 
					                Ok(40) => msg.value = r.read_uint32(bytes)?,
 | 
				
			||||||
 | 
					                Ok(t) => { r.read_unknown(bytes, t)?; }
 | 
				
			||||||
 | 
					                Err(e) => return Err(e),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Ok(msg)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl MessageWrite for LobbySetVariable {
 | 
				
			||||||
 | 
					    fn get_size(&self) -> usize {
 | 
				
			||||||
 | 
					        0
 | 
				
			||||||
 | 
					        + if self.slot == 0i32 { 0 } else { 1 + sizeof_varint(*(&self.slot) as u64) }
 | 
				
			||||||
 | 
					        + if self.variable_id == 0u32 { 0 } else { 1 + sizeof_varint(*(&self.variable_id) as u64) }
 | 
				
			||||||
 | 
					        + if self.value == 0u32 { 0 } else { 1 + sizeof_varint(*(&self.value) as u64) }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
 | 
				
			||||||
 | 
					        if self.slot != 0i32 { w.write_with_tag(24, |w| w.write_int32(*&self.slot))?; }
 | 
				
			||||||
 | 
					        if self.variable_id != 0u32 { w.write_with_tag(32, |w| w.write_uint32(*&self.variable_id))?; }
 | 
				
			||||||
 | 
					        if self.value != 0u32 { w.write_with_tag(40, |w| w.write_uint32(*&self.value))?; }
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[allow(clippy::derive_partial_eq_without_eq)]
 | 
				
			||||||
 | 
					#[derive(Debug, Default, PartialEq, Clone)]
 | 
				
			||||||
 | 
					pub struct StartGame { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> MessageRead<'a> for StartGame {
 | 
				
			||||||
 | 
					    fn from_reader(r: &mut BytesReader, _: &[u8]) -> Result<Self> {
 | 
				
			||||||
 | 
					        r.read_to_end();
 | 
				
			||||||
 | 
					        Ok(Self::default())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl MessageWrite for StartGame { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[allow(clippy::derive_partial_eq_without_eq)]
 | 
				
			||||||
 | 
					#[derive(Debug, Default, PartialEq, Clone)]
 | 
				
			||||||
 | 
					pub struct PlayerLeftGame {
 | 
				
			||||||
 | 
					    pub player_uuid: Option<stormgate::UUID>,
 | 
				
			||||||
 | 
					    pub reason: stormgate::LeaveReason,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> MessageRead<'a> for PlayerLeftGame {
 | 
				
			||||||
 | 
					    fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
 | 
				
			||||||
 | 
					        let mut msg = Self::default();
 | 
				
			||||||
 | 
					        while !r.is_eof() {
 | 
				
			||||||
 | 
					            match r.next_tag(bytes) {
 | 
				
			||||||
 | 
					                Ok(10) => msg.player_uuid = Some(r.read_message::<stormgate::UUID>(bytes)?),
 | 
				
			||||||
 | 
					                Ok(16) => msg.reason = r.read_enum(bytes)?,
 | 
				
			||||||
 | 
					                Ok(t) => { r.read_unknown(bytes, t)?; }
 | 
				
			||||||
 | 
					                Err(e) => return Err(e),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Ok(msg)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl MessageWrite for PlayerLeftGame {
 | 
				
			||||||
 | 
					    fn get_size(&self) -> usize {
 | 
				
			||||||
 | 
					        0
 | 
				
			||||||
 | 
					        + self.player_uuid.as_ref().map_or(0, |m| 1 + sizeof_len((m).get_size()))
 | 
				
			||||||
 | 
					        + if self.reason == stormgate::LeaveReason::Unknown { 0 } else { 1 + sizeof_varint(*(&self.reason) as u64) }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
 | 
				
			||||||
 | 
					        if let Some(ref s) = self.player_uuid { w.write_with_tag(10, |w| w.write_message(s))?; }
 | 
				
			||||||
 | 
					        if self.reason != stormgate::LeaveReason::Unknown { w.write_with_tag(16, |w| w.write_enum(*&self.reason as i32))?; }
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[allow(clippy::derive_partial_eq_without_eq)]
 | 
				
			||||||
 | 
					#[derive(Debug, Default, PartialEq, Clone)]
 | 
				
			||||||
 | 
					pub struct AssignPlayerSlot<'a> {
 | 
				
			||||||
 | 
					    pub uuid: Option<stormgate::UUID>,
 | 
				
			||||||
 | 
					    pub slot: i64,
 | 
				
			||||||
 | 
					    pub nickname: Cow<'a, str>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> MessageRead<'a> for AssignPlayerSlot<'a> {
 | 
				
			||||||
 | 
					    fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
 | 
				
			||||||
 | 
					        let mut msg = Self::default();
 | 
				
			||||||
 | 
					        while !r.is_eof() {
 | 
				
			||||||
 | 
					            match r.next_tag(bytes) {
 | 
				
			||||||
 | 
					                Ok(10) => msg.uuid = Some(r.read_message::<stormgate::UUID>(bytes)?),
 | 
				
			||||||
 | 
					                Ok(16) => msg.slot = r.read_int64(bytes)?,
 | 
				
			||||||
 | 
					                Ok(26) => msg.nickname = r.read_string(bytes).map(Cow::Borrowed)?,
 | 
				
			||||||
 | 
					                Ok(t) => { r.read_unknown(bytes, t)?; }
 | 
				
			||||||
 | 
					                Err(e) => return Err(e),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Ok(msg)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> MessageWrite for AssignPlayerSlot<'a> {
 | 
				
			||||||
 | 
					    fn get_size(&self) -> usize {
 | 
				
			||||||
 | 
					        0
 | 
				
			||||||
 | 
					        + self.uuid.as_ref().map_or(0, |m| 1 + sizeof_len((m).get_size()))
 | 
				
			||||||
 | 
					        + if self.slot == 0i64 { 0 } else { 1 + sizeof_varint(*(&self.slot) as u64) }
 | 
				
			||||||
 | 
					        + if self.nickname == "" { 0 } else { 1 + sizeof_len((&self.nickname).len()) }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
 | 
				
			||||||
 | 
					        if let Some(ref s) = self.uuid { w.write_with_tag(10, |w| w.write_message(s))?; }
 | 
				
			||||||
 | 
					        if self.slot != 0i64 { w.write_with_tag(16, |w| w.write_int64(*&self.slot))?; }
 | 
				
			||||||
 | 
					        if self.nickname != "" { w.write_with_tag(26, |w| w.write_string(&**&self.nickname))?; }
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[allow(clippy::derive_partial_eq_without_eq)]
 | 
				
			||||||
 | 
					#[derive(Debug, Default, PartialEq, Clone)]
 | 
				
			||||||
 | 
					pub struct UUID {
 | 
				
			||||||
 | 
					    pub part1: i64,
 | 
				
			||||||
 | 
					    pub part2: i64,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'a> MessageRead<'a> for UUID {
 | 
				
			||||||
 | 
					    fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self> {
 | 
				
			||||||
 | 
					        let mut msg = Self::default();
 | 
				
			||||||
 | 
					        while !r.is_eof() {
 | 
				
			||||||
 | 
					            match r.next_tag(bytes) {
 | 
				
			||||||
 | 
					                Ok(8) => msg.part1 = r.read_int64(bytes)?,
 | 
				
			||||||
 | 
					                Ok(16) => msg.part2 = r.read_int64(bytes)?,
 | 
				
			||||||
 | 
					                Ok(t) => { r.read_unknown(bytes, t)?; }
 | 
				
			||||||
 | 
					                Err(e) => return Err(e),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Ok(msg)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl MessageWrite for UUID {
 | 
				
			||||||
 | 
					    fn get_size(&self) -> usize {
 | 
				
			||||||
 | 
					        0
 | 
				
			||||||
 | 
					        + if self.part1 == 0i64 { 0 } else { 1 + sizeof_varint(*(&self.part1) as u64) }
 | 
				
			||||||
 | 
					        + if self.part2 == 0i64 { 0 } else { 1 + sizeof_varint(*(&self.part2) as u64) }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn write_message<W: WriterBackend>(&self, w: &mut Writer<W>) -> Result<()> {
 | 
				
			||||||
 | 
					        if self.part1 != 0i64 { w.write_with_tag(8, |w| w.write_int64(*&self.part1))?; }
 | 
				
			||||||
 | 
					        if self.part2 != 0i64 { w.write_with_tag(16, |w| w.write_int64(*&self.part2))?; }
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Reference in New Issue
	
	Block a user