Skip to content
This repository has been archived by the owner on Jul 1, 2024. It is now read-only.

Commit

Permalink
Merge pull request #5 from Mubelotix/minecraft-1.20.2
Browse files Browse the repository at this point in the history
Minecraft 1.20.2
  • Loading branch information
Mubelotix authored Oct 31, 2023
2 parents 07725e9 + ac5a734 commit 466a78b
Show file tree
Hide file tree
Showing 95 changed files with 2,747 additions and 663 deletions.
31 changes: 31 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Rust

on:
push:
branches: [ main ]
pull_request:
branches: [ '**' ]

env:
CARGO_TERM_COLOR: always

jobs:
Tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/cache@v3
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/rust.yml') }}
- name: Download library minecraft-protocol-derive
run: git clone https://github.com/Mubelotix/minecraft-protocol-derive ../minecraft-packet-derive || (cd ../minecraft-packet-derive ; git pull)
- name: Build
run: cargo build
- name: Run tests
run: cargo test
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/target
Cargo.lock
logs
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,7 @@ minecraft-packet-derive = {path="../minecraft-packet-derive"}
minreq = {version="2.3", features=["https"]}
serde_json = "1.0"
serde = {version="1.0", features=["derive"]}
convert_case = "0.4"
convert_case = "0.6"

[features]
all-packets = []
5 changes: 4 additions & 1 deletion build/blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ impl BlockState {
format!(
r#"#[derive(Debug, Clone, Copy)]
#[repr(u8)]
#[cfg_attr(test, derive(PartialEq))]
pub enum {} {{{}
}}"#,
self.ty(block_name, competing_definitions),
Expand All @@ -101,6 +102,7 @@ pub enum {} {{{}
}

#[derive(Debug, Serialize, Deserialize)]
#[cfg_attr(test, derive(PartialEq))]
#[serde(rename_all = "camelCase")]
struct Block {
id: u32,
Expand Down Expand Up @@ -747,6 +749,7 @@ use crate::*;
{enum_definitions}
/// Can be converted for free to [super::blocks::Block] which implements [useful methods](super::blocks::Block#implementations).
#[cfg_attr(test, derive(PartialEq))]
#[derive(Debug, Clone)]
#[repr(u32)]
pub enum BlockWithState {{
Expand Down Expand Up @@ -788,7 +791,7 @@ impl From<super::blocks::Block> for BlockWithState {{
impl<'a> MinecraftPacketPart<'a> for BlockWithState {{
#[inline]
fn serialize_minecraft_packet_part(self, _output: &mut Vec<u8>) -> Result<(), &'static str> {{
unimplemented!("Cannot serialize BlockWithState yet");
VarInt::from(self.block_state_id().unwrap_or(0)).serialize_minecraft_packet_part(_output)
}}
#[inline]
Expand Down
14 changes: 5 additions & 9 deletions build/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
use std::io::{ErrorKind, Read, Write};
use std::{collections::HashMap, fs::File};

const VERSION: &str = "1.17.1";
const VERSION: &str = "1.20.1";

fn get_data(url: &str, cache: &str) -> serde_json::Value {
match File::open(cache) {
Expand All @@ -24,12 +24,10 @@ fn get_data(url: &str, cache: &str) -> serde_json::Value {
Err(e) => panic!("The minecraft-format library uses a build script to generate data structures from extracted data. The extracted data is downloaded and cached to `{}`. Unfortunately, this file appears to contain invalid text data. Error: {}\nNote: Deleting the file will allow the library to download it again.", cache, e),
};

let json = match serde_json::from_str(&json_text) {
match serde_json::from_str(&json_text) {
Ok(json) => json,
Err(e) => panic!("The minecraft-format library uses a build script to generate data structures from extracted data. The extracted data is downloaded and cached to `{}`. Unfortunately, this file appears to contain invalid json data. Error: {}\nNote: Deleting the file will allow the library to download it again.", cache, e),
};

json
}
}
// The cache file needs to be downloaded
Err(e) if e.kind() == ErrorKind::NotFound => {
Expand All @@ -52,12 +50,10 @@ fn get_data(url: &str, cache: &str) -> serde_json::Value {
panic!("The minecraft-format library uses a build script to generate data structures from extracted data. The extracted data is downloaded and cached to `{}`. Unfortunately, we can't write to this path. Error: {}", cache, e)
};

let json = match serde_json::from_str(json_text) {
match serde_json::from_str(json_text) {
Ok(json) => json,
Err(e) => panic!("The minecraft-format library uses a build script to generate data structures from extracted data. The extracted data is downloaded and cached to `{}`. Unfortunately, this file appears to contain invalid json data. Error: {}\nNote: Deleting the file will allow the library to download it again.", cache, e),
};

json
}
}

// The cache file cannot be accessed
Expand Down
2 changes: 1 addition & 1 deletion build/items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ impl Item {{
impl<'a> MinecraftPacketPart<'a> for Item {{
#[inline]
fn serialize_minecraft_packet_part(self, output: &mut Vec<u8>) -> Result<(), &'static str> {{
VarInt((self as u32) as i32).serialize_minecraft_packet_part(output)
VarInt(self as i32).serialize_minecraft_packet_part(output)
}}
#[inline]
Expand Down
14 changes: 7 additions & 7 deletions build/recipes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,18 +274,18 @@ fn item_id_to_item(id: u32, items: &[super::items::Item]) -> String {
}

pub fn generate_recipes(data: serde_json::Value, items: Vec<super::items::Item>) {
let item_recipes: HashMap<u32, Vec<Recipe>> =
let mut item_recipes: HashMap<u32, Vec<Recipe>> =
serde_json::from_value(data).expect("Invalid recipes");

// Count recipes
let mut recipes_count = 0;
for recipes in item_recipes.values() {
recipes_count += recipes.len();
for recipe in recipes {
if matches!(recipe, Recipe::DoubleShaped{..}) {
panic!("Contains a double shaped recipe, which support has been removed as an optimization. It needs to be enabled again if required by future minecraft updates.")
}
for recipes in item_recipes.values_mut() {
let recipes_len = recipes.len();
recipes.retain(|recipe| !matches!(recipe, Recipe::DoubleShaped{..}));
if recipes.len() != recipes_len {
println!("Contains a double shaped recipe, which support has been removed as an optimization. It needs to be enabled again if required by future minecraft updates.");
}
recipes_count += recipes.len();
}

// Generate recipes
Expand Down
247 changes: 247 additions & 0 deletions examples/proxy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
use minecraft_protocol::{
network::{read_packet, send_packet, NetworkError},
packets::play_serverbound::ServerboundPacket as PlayServerbound,
packets::play_clientbound::ClientboundPacket as PlayClientbound,
packets::handshake::ServerboundPacket as HandshakeServerbound,
packets::login::ServerboundPacket as LoginServerbound,
packets::{login::ClientboundPacket as LoginClientbound, VarInt},
packets::config::ClientboundPacket as ConfigClientbound,
packets::config::ServerboundPacket as ConfigServerbound,
packets::status::ServerboundPacket as StatusServerbound,
packets::status::ClientboundPacket as StatusClientbound,
*, components::chunk::Chunk,
};
use std::{net::{TcpListener, TcpStream}, collections::HashSet};

const TEST_PATTERN: &str = r#"
//! This test was automatically generated. Please run the proxy example to regenerate it.
//!
//! ```
//! cargo run --example proxy
//! ```
use minecraft_protocol::{MinecraftPacketPart, packets::play_[DEST_LOWER]::[DEST]Packet};
#[test]
fn auto_play_[DEST_LOWER]_[ID]() {
let input = &[DATA];
let packet_deserialized = [DEST]Packet::deserialize_uncompressed_minecraft_packet(input).unwrap();
match packet_deserialized.serialize_minecraft_packet() {
Ok(packet) => {
//reserialize let _reserialized = [DEST]Packet::deserialize_uncompressed_minecraft_packet(&packet).unwrap();
//reserialize assert!(matches!([DEST]Packet::deserialize_uncompressed_minecraft_packet(input).unwrap(), _reserialized));
}
Err(e) => panic!("Failed to serialize packet: {:?}", e),
};
}
"#;

fn proxy_serverbound(client_stream: TcpStream, server_stream: TcpStream) -> Result<(), NetworkError> {
let mut play = false;
let mut saved_packets = HashSet::new();

loop {
let packet = read_packet(&client_stream, None, None)?;

if let Ok(packet) = PlayServerbound::deserialize_uncompressed_minecraft_packet(&packet) {
play = true;
#[cfg(feature = "all-packets")]
{
let mut fpacket = format!("{:?}", packet);
if fpacket.len() > 400 {
fpacket.truncate(400);
fpacket.push_str("...");
}
println!("\u{001b}[35mclient\u{001b}[0m: {fpacket}");
}
} else if let Ok(packet) = LoginServerbound::deserialize_uncompressed_minecraft_packet(&packet) {
#[cfg(feature = "all-packets")]
{
let mut fpacket = format!("{:?}", packet);
if fpacket.len() > 400 {
fpacket.truncate(400);
fpacket.push_str("...");
}
println!("\u{001b}[35mclient\u{001b}[0m: {fpacket}");
}
} else if let Ok(packet) = HandshakeServerbound::deserialize_uncompressed_minecraft_packet(&packet) {
#[cfg(feature = "all-packets")]
{
let mut fpacket = format!("{:?}", packet);
if fpacket.len() > 400 {
fpacket.truncate(400);
fpacket.push_str("...");
}
println!("\u{001b}[35mclient\u{001b}[0m: {fpacket}");
}
} else if let Ok(packet) = ConfigServerbound::deserialize_uncompressed_minecraft_packet(&packet) {
#[cfg(feature = "all-packets")]
{
let mut fpacket = format!("{:?}", packet);
if fpacket.len() > 400 {
fpacket.truncate(400);
fpacket.push_str("...");
}
println!("\u{001b}[35mclient\u{001b}[0m: {fpacket}");
}
} else if let Ok(packet) = StatusServerbound::deserialize_uncompressed_minecraft_packet(&packet) {
#[cfg(feature = "all-packets")]
{
let mut fpacket = format!("{:?}", packet);
if fpacket.len() > 400 {
fpacket.truncate(400);
fpacket.push_str("...");
}
println!("\u{001b}[35mclient\u{001b}[0m: {fpacket}");
}
} else {
let fpacket = if packet.len() > 200 {
format!("{:?}...", &packet[..200])
} else {
format!("{:?}", packet)
};
let err = PlayServerbound::deserialize_uncompressed_minecraft_packet(&packet).unwrap_err();
println!("\u{001b}[35mclient\u{001b}[0m: \u{001b}[31m{fpacket:?}\nwith {err}\u{001b}[0m");
}

if play {
let packet_id = VarInt::deserialize_minecraft_packet_part(&packet)?.0.0;
if saved_packets.insert(packet_id) {
let mut test = TEST_PATTERN
.replace("[ID]", &format!("{:x}", packet_id))
.replace("[DEST]", "Serverbound")
.replace("[DEST_LOWER]", "serverbound")
.replace("[DATA]", &format!("{:?}", packet));
if !packet.starts_with(&[37]) {
test = test.replace("//reserialize ", "");
}
let _ = std::fs::write(format!("tests/auto_play_serverbound_{packet_id:03X}.rs"), test);
}
}

send_packet(&server_stream, packet, None, None)?;
}
}

fn proxy_clientbound(client_stream: TcpStream, server_stream: TcpStream) -> Result<(), NetworkError> {
let mut play = false;
let mut saved_packets = HashSet::new();

loop {
let packet = read_packet(&server_stream, None, None)?;

if let Ok(packet) = PlayClientbound::deserialize_uncompressed_minecraft_packet(&packet) {
play = true;
#[cfg(feature = "all-packets")]
{
let mut fpacket = format!("{:?}", packet);
if fpacket.len() > 400 {
fpacket.truncate(400);
fpacket.push_str("...");
}
println!("\u{001b}[33mserver\u{001b}[0m: {fpacket}");
}
if let PlayClientbound::ChunkData { mut value } = packet {
let chunks = match Chunk::from_data(&value.data.items) {
Ok(chunks) => chunks,
Err(e) => {
println!("Failed to deserialize chunks: {:?}", e);
continue;
}
};
let reserialized = match Chunk::into_data(chunks) {
Ok(reserialized) => reserialized,
Err(e) => {
println!("Failed to reserialize chunks: {:?}", e);
continue;
}
};
value.data.items = reserialized;
let packet = match (PlayClientbound::ChunkData{value}.serialize_minecraft_packet()) {
Ok(packet) => packet,
Err(e) => {
println!("Failed to reserialize chunk packet: {:?}", e);
continue;
}
};
send_packet(&client_stream, packet, None, None)?;
continue;
}
} else if let Ok(packet) = LoginClientbound::deserialize_uncompressed_minecraft_packet(&packet) {
#[cfg(feature = "all-packets")]
{
let mut fpacket = format!("{:?}", packet);
if fpacket.len() > 400 {
fpacket.truncate(400);
fpacket.push_str("...");
}
println!("\u{001b}[33mserver\u{001b}[0m: {fpacket}");
}
} else if let Ok(packet) = ConfigClientbound::deserialize_uncompressed_minecraft_packet(&packet) {
#[cfg(feature = "all-packets")]
{
let mut fpacket = format!("{:?}", packet);
if fpacket.len() > 400 {
fpacket.truncate(400);
fpacket.push_str("...");
}
println!("\u{001b}[33mserver\u{001b}[0m: {fpacket}");
}
} else if let Ok(packet) = StatusClientbound::deserialize_uncompressed_minecraft_packet(&packet) {
#[cfg(feature = "all-packets")]
{
let mut fpacket = format!("{:?}", packet);
if fpacket.len() > 400 {
fpacket.truncate(400);
fpacket.push_str("...");
}
println!("\u{001b}[33mserver\u{001b}[0m: {fpacket}");
}
} else {
let fpacket = if packet.len() > 200 {
format!("{:?}...", &packet[..200])
} else {
format!("{:?}", packet)
};
let err = PlayClientbound::deserialize_uncompressed_minecraft_packet(&packet).unwrap_err();
println!("\u{001b}[33mserver\u{001b}[0m: \u{001b}[31m{fpacket:?}\nwith {err}\u{001b}[0m");
}

if play {
let packet_id = VarInt::deserialize_minecraft_packet_part(&packet)?.0.0;
if saved_packets.insert(packet_id) {
let test = TEST_PATTERN
.replace("[ID]", &format!("{:x}", packet_id))
.replace("[DEST]", "Clientbound")
.replace("[DEST_LOWER]", "clientbound")
.replace("[DATA]", &format!("{:?}", packet));
let _ = std::fs::write(format!("tests/auto_play_clientbound_{packet_id:03X}.rs"), test);
}
}

send_packet(&client_stream, packet, None, None)?;
}
}

fn main() {
let listener = TcpListener::bind("127.0.0.1:25566").unwrap();

loop {
match listener.accept() {
Ok((client_stream, addr)) => {
println!("new client: {addr:?}");
let server_stream = TcpStream::connect("127.0.0.1:25565").unwrap();

let client_stream2 = client_stream.try_clone().unwrap();
let server_stream2 = server_stream.try_clone().unwrap();
let handle1 = std::thread::spawn(move || proxy_serverbound(client_stream, server_stream));
let handle2 = std::thread::spawn(move || proxy_clientbound(client_stream2, server_stream2));
let _ = handle1.join().unwrap();
let _ = handle2.join().unwrap();
println!("client disconnected: {addr:?}")
}
Err(e) => println!("couldn't get client: {e:?}"),
}
}
}
Loading

0 comments on commit 466a78b

Please sign in to comment.