summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1
-rw-r--r--Cargo.toml4
-rw-r--r--rustfmt.toml6
-rw-r--r--src/main.rs260
4 files changed, 231 insertions, 40 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 1481974..901bd67 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -209,7 +209,6 @@ dependencies = [
[[package]]
name = "mcproto-rs"
version = "0.2.0"
-source = "git+https://github.com/Web-44/mcproto-rs.git#2572b329cc18a0413dea19297bab805be2b9f2ab"
dependencies = [
"base64",
"rand",
diff --git a/Cargo.toml b/Cargo.toml
index 138f7fe..7b38169 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -20,9 +20,11 @@ version = "*"
[dependencies.mcproto-rs]
version = "*"
+features = ["default", "v1_19_3"]
[patch.crates-io.mcproto-rs]
-git = "https://github.com/Web-44/mcproto-rs.git"
+# git = "https://github.com/Web-44/mcproto-rs.git"
+path = "../mcproto-rs"
[patch.crates-io.craftio-rs]
git = "https://github.com/romangraef/craftio-rs.git"
diff --git a/rustfmt.toml b/rustfmt.toml
new file mode 100644
index 0000000..2fd9f19
--- /dev/null
+++ b/rustfmt.toml
@@ -0,0 +1,6 @@
+format_macro_matchers = true
+reorder_imports = true
+format_macro_bodies = true
+skip_macro_invocations = []
+imports_indent = "Visual"
+indent_style = "Visual" \ No newline at end of file
diff --git a/src/main.rs b/src/main.rs
index 8f925e3..b7f1203 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -2,12 +2,14 @@ use std::net::{IpAddr, Ipv4Addr, SocketAddr, TcpListener, TcpStream};
use anyhow::Result;
use craftio_rs::{CraftIo, CraftSyncReader, CraftSyncWriter, CraftTcpConnection};
-use mcproto_rs::protocol::State;
-use mcproto_rs::status::{StatusFaviconSpec, StatusPlayersSpec, StatusSpec, StatusVersionSpec};
-use mcproto_rs::types::{Chat, TextComponent};
-use mcproto_rs::types::Chat::Text;
-use mcproto_rs::v1_19::{HandshakeNextState, Packet759, RawPacket759, StatusPingSpec, StatusPongSpec, StatusResponseSpec};
-use mcproto_rs::v1_19::Packet759Kind::{Handshake, PlayServerPlayerAbilities};
+use mcproto_rs::nbt::{NamedTag, Tag};
+use mcproto_rs::protocol::{HasPacketKind, State};
+use mcproto_rs::status::{StatusPlayersSpec, StatusSpec, StatusVersionSpec};
+use mcproto_rs::types::{Chat, NamedNbtTag};
+use mcproto_rs::uuid::UUID4;
+use mcproto_rs::v1_19_3::{GameMode, HandshakeNextState, LoginPlaySpec, LoginSuccessSpec,
+ Packet761, Packet761Kind, PingRequestSpec, PingResponseSpec,
+ PreviousGameMode, RawPacket761, StatusResponseSpec};
use tokio;
pub struct MinecraftClient {
@@ -19,29 +21,128 @@ impl MinecraftClient {
Self { connection }
}
- pub fn from_stream(stream: TcpStream) -> anyhow::Result<Self> {
+ pub fn from_stream(stream: TcpStream) -> Result<Self> {
Ok(Self {
- connection: CraftTcpConnection::from_std(stream, mcproto_rs::protocol::PacketDirection::ServerBound)?,
+ connection: CraftTcpConnection::from_std(
+ stream,
+ mcproto_rs::protocol::PacketDirection::ServerBound,
+ )?,
})
}
- pub async fn read_next_packet(&mut self) -> Result<Option<Packet759>> {
- if let Some(raw) = self.connection.read_packet::<RawPacket759>()? {
+ pub async fn read_next_packet(&mut self) -> Result<Option<Packet761>> {
+ if let Some(raw) = self.connection.read_packet::<RawPacket761>()? {
println!("Client -> Server: {:?}", raw);
Ok(Some(raw))
} else {
Ok(None)
}
}
- pub async fn send_packet(&mut self, packet: Packet759) -> Result<()> {
+ pub async fn send_packet(&mut self, packet: Packet761) -> Result<()> {
+ println!("Server -> Client: {:?}", packet);
self.connection.write_packet(packet)?;
Ok(())
}
+ pub async fn wait_for_packet(&mut self, packet_kind: Packet761Kind) -> Result<Packet761> {
+ loop {
+ if let Some(packet) = self.read_next_packet().await? {
+ if packet.kind() == packet_kind {
+ return Ok(packet);
+ }
+ println!("Skipping packet {:?}", packet);
+ }
+ }
+ }
+}
+
+macro_rules! await_packet {
+ ($packet_type:ident, $conn:expr) => {
+ assert_packet!($packet_type,
+ $conn.wait_for_packet(Packet761Kind::$packet_type).await?)
+ };
}
macro_rules! assert_packet {
- ($packet_type:ident, $obj:expr) => {if let Packet759::$packet_type(packet_data) = $obj { packet_data } else {panic!("Expected packet of type {}", stringify!($packet_type))}};
+ ($packet_type:ident, $obj:expr) => {
+ if let Packet761::$packet_type(packet_data) = $obj {
+ packet_data
+ } else {
+ panic!("Expected packet of type {}", stringify!($packet_type))
+ }
+ };
+ ($packet_type:ident, $conn:expr, $errmgs:literal) => {
+ assert_packet!($packet_type,
+ $conn.read_next_packet()
+ .await?
+ .ok_or(anyhow::anyhow!("Missing packet"))?)
+ };
+}
+
+trait ShittyToNbt {
+ fn to_nbt(self) -> Tag;
+}
+
+impl ShittyToNbt for String {
+ fn to_nbt(self) -> Tag {
+ Tag::String(self)
+ }
+}
+
+impl ShittyToNbt for &str {
+ fn to_nbt(self) -> Tag {
+ Tag::String(self.into())
+ }
+}
+
+impl ShittyToNbt for i32 {
+ fn to_nbt(self) -> Tag {
+ Tag::Int(self)
+ }
+}
+
+impl ShittyToNbt for i64 {
+ fn to_nbt(self) -> Tag {
+ Tag::Long(self)
+ }
+}
+
+impl ShittyToNbt for bool {
+ fn to_nbt(self) -> Tag {
+ Tag::Byte(if self { 1 } else { 0 })
+ }
}
+impl ShittyToNbt for Tag {
+ fn to_nbt(self) -> Tag {
+ self
+ }
+}
+
+macro_rules! nbt {
+ { {$($name:literal :: $value:tt),* $(,)? } } => {
+ Tag::Compound(vec![
+ $(
+ nbt!($value).with_name($name)
+ ),*
+ ])
+ };
+ { $($name:literal :: $value:tt),* $(,)? } => {
+ Tag::Compound(vec![
+ $(
+ nbt!($value).with_name($name)
+ ),*
+ ])
+ };
+ ([ $($value:tt),* $(,)? ]) => {
+ Tag::List(vec![
+ $(
+ nbt!($value)
+ ),*
+ ])
+ };
+ (($e:expr)) => {
+ ShittyToNbt::to_nbt($e)
+ };
+}
#[tokio::main]
async fn main() -> Result<()> {
println!("Starting server");
@@ -49,30 +150,116 @@ async fn main() -> Result<()> {
loop {
if let Ok((socket, address)) = bind.accept() {
println!("Connection accepted from {}", address);
- let mut client = MinecraftClient::from_stream(socket)?;
- if let Err(x) = handle_conn(client).await {
- println!("Error: {:?}", x);
- }
+ let client = MinecraftClient::from_stream(socket)?;
+ tokio::spawn(async {
+ if let Err(x) = handle_conn(client).await {
+ println!("Error: {:?}", x);
+ }
+ });
}
}
}
async fn handle_conn(mut client: MinecraftClient) -> Result<()> {
- let hs = assert_packet!(Handshake, client.read_next_packet().await?.ok_or(anyhow::anyhow!("Missing packet"))?);
- println!("Hs: {:?}", hs);
+ let hs = assert_packet!(Handshake, client, "Missing packet");
if hs.next_state == HandshakeNextState::Login {
client.connection.set_state(State::Login);
- let loginstart = assert_packet!(LoginStart, client.read_next_packet().await?.ok_or(anyhow::anyhow!("Missing packet"))?);
- println!("Login: {:?}", loginstart)
+ let loginstart = assert_packet!(LoginStart,
+ client.read_next_packet()
+ .await?
+ .ok_or(anyhow::anyhow!("Missing packet"))?);
+ println!("Login: {:?}", loginstart);
+ let uuid = UUID4::random();
+ client.send_packet(Packet761::LoginSuccess(LoginSuccessSpec { uuid,
+ username:
+ loginstart.name,
+ properties:
+ vec![].into() }))
+ .await?;
+ let registry_doex = nbt! {
+ "minecraft:dimension_type" :: {
+ "type" :: ("minecraft:dimension_type"),
+ "value" :: [{
+ "id" :: (0),
+ "name" :: ("minecraft:overworld"),
+ "element" :: {
+ "ambient_light" :: (false),
+ "bed_works" :: (true),
+ "coordinate_scale" :: (1),
+ "effects" :: ("minecraft:overworld"),
+ "has_ceiling" :: (false),
+ "has_skylight" :: (true),
+ "has_raids" :: (false),
+ "height" :: (384),
+ "infiniburn" :: ("#minecraft:infiniburn_overworld"),
+ "logical_height" :: (384),
+ "min_y" :: (-64),
+ "monster_spawn_block_light_limit" :: (0),
+ "monster_spawn_light_level" :: {
+ "type" :: ("minecraft:uniform"),
+ "value" :: {
+ "max_inclusive" :: (7),
+ "min_inclusive" :: (0),
+ },
+ },
+ "natural" :: (true),
+ "piglin_safe" :: (false),
+ "respawn_anchor_works" :: (false),
+ "ultrawarm" :: (false),
+
+ },
+ }]
+ },
+ };
+ client.connection.set_state(State::Play);
+ client
+ .send_packet(Packet761::LoginPlay(LoginPlaySpec {
+ entity_id: 0,
+ is_hardcore: false,
+ gamemode: GameMode::Survival,
+ previous_gamemode: PreviousGameMode::NoPrevious,
+ dimension_names: vec!["world".into()].into(),
+ registry_codex: NamedNbtTag {
+ root: registry_doex.with_name("root"),
+ },
+ dimension_type: "minecraft:overworld".into(),
+ dimension_name: "world".into(),
+ hashed_seed: 0,
+ max_players: 10.into(),
+ view_distance: 10.into(),
+ simulation_distance: 10.into(),
+ reduced_debug_info: false,
+ enable_respawn_screen: false,
+ is_debug: false,
+ is_flat: false,
+ death_location: None,
+ }))
+ .await?;
+ let client_information = await_packet!(ClientInformation, client);
+ println!("Client Information: {:?}", client_information);
+ anyhow::bail!("TODO");
+ } else if hs.next_state == HandshakeNextState::Status {
+ return handle_status(client).await;
} else {
- client.connection.set_state(State::Status);
- loop {
- println!("Polling status packet");
- match client.read_next_packet().await?.ok_or(anyhow::anyhow!("Missing packet"))? {
- Packet759::StatusRequest(_) => {
- client.send_packet(Packet759::StatusResponse(StatusResponseSpec {
+ anyhow::bail!("Unknown next status")
+ }
+}
+
+async fn handle_status(mut client: MinecraftClient) -> Result<()> {
+ client.connection.set_state(State::Status);
+ loop {
+ match client.read_next_packet()
+ .await?
+ .ok_or(anyhow::anyhow!("Missing packet"))?
+ {
+ Packet761::StatusRequest(_) => {
+ client
+ .send_packet(Packet761::StatusRespone(StatusResponseSpec {
response: StatusSpec {
- version: Some(StatusVersionSpec { name: "1.19 mgasi".to_string(), protocol: 759 }),
+ version: Some(StatusVersionSpec {
+ name: "1.19.3 mgasi".to_string(),
+ protocol: 761,
+ }),
players: StatusPlayersSpec {
max: 100,
online: 0,
@@ -81,18 +268,15 @@ async fn handle_conn(mut client: MinecraftClient) -> Result<()> {
description: Chat::from_text("hehehe"),
favicon: None,
},
- })).await?;
- }
- Packet759::StatusPing(StatusPingSpec { payload }) => {
- client.send_packet(Packet759::StatusPong(StatusPongSpec {
- payload,
- })).await?;
- return Ok(())
- }
- _ => anyhow::bail!("")
+ }))
+ .await?;
}
+ Packet761::PingRequest(PingRequestSpec { payload }) => {
+ client.send_packet(Packet761::PingResponse(PingResponseSpec { payload }))
+ .await?;
+ return Ok(());
+ }
+ _ => anyhow::bail!("Unexpected packet during status communication"),
}
}
- Ok(())
}
-