Compare commits

..

No commits in common. "caec5fa7f896b362b56108c7401c5694679baaba" and "884081d414094ab1c8fee6d0d1c803d786937391" have entirely different histories.

7 changed files with 9 additions and 433 deletions

218
Cargo.lock generated
View File

@ -143,15 +143,6 @@ version = "1.0.96"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b964d184e89d9b6b67dd2715bc8e74cf3107fb2b529990c90cf517326150bf4" checksum = "6b964d184e89d9b6b67dd2715bc8e74cf3107fb2b529990c90cf517326150bf4"
[[package]]
name = "arbitrary"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223"
dependencies = [
"derive_arbitrary",
]
[[package]] [[package]]
name = "arrayvec" name = "arrayvec"
version = "0.7.6" version = "0.7.6"
@ -961,25 +952,6 @@ version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9" checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9"
[[package]]
name = "bzip2"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49ecfb22d906f800d4fe833b6282cf4dc1c298f5057ca0b5445e5c209735ca47"
dependencies = [
"bzip2-sys",
]
[[package]]
name = "bzip2-sys"
version = "0.1.13+1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14"
dependencies = [
"cc",
"pkg-config",
]
[[package]] [[package]]
name = "castaway" name = "castaway"
version = "0.2.3" version = "0.2.3"
@ -1206,12 +1178,6 @@ dependencies = [
"tiny-keccak", "tiny-keccak",
] ]
[[package]]
name = "constant_time_eq"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6"
[[package]] [[package]]
name = "cpufeatures" name = "cpufeatures"
version = "0.2.17" version = "0.2.17"
@ -1221,21 +1187,6 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "crc"
version = "3.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636"
dependencies = [
"crc-catalog",
]
[[package]]
name = "crc-catalog"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
[[package]] [[package]]
name = "crc32fast" name = "crc32fast"
version = "1.4.2" version = "1.4.2"
@ -1302,12 +1253,6 @@ version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "575f75dfd25738df5b91b8e43e14d44bda14637a58fae779fd2b064f8bf3e010" checksum = "575f75dfd25738df5b91b8e43e14d44bda14637a58fae779fd2b064f8bf3e010"
[[package]]
name = "deflate64"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b"
[[package]] [[package]]
name = "der" name = "der"
version = "0.7.9" version = "0.7.9"
@ -1319,26 +1264,6 @@ dependencies = [
"zeroize", "zeroize",
] ]
[[package]]
name = "deranged"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
dependencies = [
"powerfmt",
]
[[package]]
name = "derive_arbitrary"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "derive_more" name = "derive_more"
version = "1.0.0" version = "1.0.0"
@ -1456,7 +1381,6 @@ dependencies = [
"anyhow", "anyhow",
"azalea", "azalea",
"bevy_app", "bevy_app",
"bevy_ecs",
"bevy_log", "bevy_log",
"built", "built",
"clap", "clap",
@ -1469,10 +1393,7 @@ dependencies = [
"log", "log",
"mlua", "mlua",
"ncr", "ncr",
"parking_lot",
"serde_json",
"tokio", "tokio",
"zip",
] ]
[[package]] [[package]]
@ -2238,12 +2159,6 @@ dependencies = [
"scopeguard", "scopeguard",
] ]
[[package]]
name = "lockfree-object-pool"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e"
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.26" version = "0.4.26"
@ -2259,16 +2174,6 @@ dependencies = [
"linked-hash-map", "linked-hash-map",
] ]
[[package]]
name = "lzma-rs"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "297e814c836ae64db86b36cf2a557ba54368d03f6afcd7d947c266692f71115e"
dependencies = [
"byteorder",
"crc",
]
[[package]] [[package]]
name = "matchers" name = "matchers"
version = "0.1.0" version = "0.1.0"
@ -2476,12 +2381,6 @@ dependencies = [
"num-traits", "num-traits",
] ]
[[package]]
name = "num-conv"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
[[package]] [[package]]
name = "num-format" name = "num-format"
version = "0.4.4" version = "0.4.4"
@ -2596,7 +2495,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2"
dependencies = [ dependencies = [
"digest", "digest",
"hmac",
] ]
[[package]] [[package]]
@ -2713,12 +2611,6 @@ dependencies = [
"universal-hash", "universal-hash",
] ]
[[package]]
name = "powerfmt"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]] [[package]]
name = "ppv-lite86" name = "ppv-lite86"
version = "0.2.20" version = "0.2.20"
@ -3208,12 +3100,6 @@ dependencies = [
"rand_core", "rand_core",
] ]
[[package]]
name = "simd-adler32"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
[[package]] [[package]]
name = "simd_cesu8" name = "simd_cesu8"
version = "1.0.1" version = "1.0.1"
@ -3442,25 +3328,6 @@ dependencies = [
"once_cell", "once_cell",
] ]
[[package]]
name = "time"
version = "0.3.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dad298b01a40a23aac4580b67e3dbedb7cc8402f3592d7f49469de2ea4aecdd8"
dependencies = [
"deranged",
"num-conv",
"powerfmt",
"serde",
"time-core",
]
[[package]]
name = "time-core"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "765c97a5b985b7c11d7bc27fa927dc4fe6af3a6dfb021d28deb60d3bf51e76ef"
[[package]] [[package]]
name = "tiny-keccak" name = "tiny-keccak"
version = "2.0.2" version = "2.0.2"
@ -4183,20 +4050,6 @@ name = "zeroize"
version = "1.8.1" version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
dependencies = [
"zeroize_derive",
]
[[package]]
name = "zeroize_derive"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "zerovec" name = "zerovec"
@ -4219,74 +4072,3 @@ dependencies = [
"quote", "quote",
"syn", "syn",
] ]
[[package]]
name = "zip"
version = "2.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b280484c454e74e5fff658bbf7df8fdbe7a07c6b2de4a53def232c15ef138f3a"
dependencies = [
"aes",
"arbitrary",
"bzip2",
"constant_time_eq",
"crc32fast",
"crossbeam-utils",
"deflate64",
"displaydoc",
"flate2",
"hmac",
"indexmap 2.7.1",
"lzma-rs",
"memchr",
"pbkdf2",
"rand",
"sha1",
"thiserror 2.0.11",
"time",
"zeroize",
"zopfli",
"zstd",
]
[[package]]
name = "zopfli"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946"
dependencies = [
"bumpalo",
"crc32fast",
"lockfree-object-pool",
"log",
"once_cell",
"simd-adler32",
]
[[package]]
name = "zstd"
version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a"
dependencies = [
"zstd-safe",
]
[[package]]
name = "zstd-safe"
version = "7.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3051792fbdc2e1e143244dc28c60f73d8470e93f3f9cbd0ead44da5ed802722"
dependencies = [
"zstd-sys",
]
[[package]]
name = "zstd-sys"
version = "2.0.14+zstd.1.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fb060d4926e4ac3a3ad15d864e99ceb5f343c6b34f5bd6d81ae6ed417311be5"
dependencies = [
"cc",
"pkg-config",
]

View File

@ -22,7 +22,6 @@ built = { version = "0", features = ["git2"] }
anyhow = "1" anyhow = "1"
azalea = { git = "https://github.com/azalea-rs/azalea.git" } azalea = { git = "https://github.com/azalea-rs/azalea.git" }
bevy_app = "0" bevy_app = "0"
bevy_ecs = "0"
bevy_log = "0" bevy_log = "0"
clap = { version = "4", features = ["derive", "string"] } clap = { version = "4", features = ["derive", "string"] }
console-subscriber = { version = "0", optional = true } console-subscriber = { version = "0", optional = true }
@ -34,10 +33,7 @@ hyper-util = "0"
log = { version = "0" } log = { version = "0" }
mlua = { version = "0", features = ["async", "luajit", "send"] } mlua = { version = "0", features = ["async", "luajit", "send"] }
ncr = { version = "0", features = ["cfb8", "ecb", "gcm"] } ncr = { version = "0", features = ["cfb8", "ecb", "gcm"] }
parking_lot = "0"
serde_json = "1"
tokio = { version = "1", features = ["macros"] } tokio = { version = "1", features = ["macros"] }
zip = "2"
[features] [features]
console-subscriber = ["dep:console-subscriber"] console-subscriber = ["dep:console-subscriber"]

View File

@ -12,7 +12,6 @@ A Minecraft bot with Lua scripting support, written in Rust with [azalea](https:
- Pathfinding (from azalea) - Pathfinding (from azalea)
- Entity and chest interaction - Entity and chest interaction
- NoChatReports encryption - NoChatReports encryption
- Saving ReplayMod recordings
## Usage ## Usage

View File

@ -2,11 +2,9 @@ use crate::{
State, State,
commands::CommandSource, commands::CommandSource,
http::serve, http::serve,
lua::{client, direction::Direction, player::Player, vec3::Vec3}, lua::{self, direction::Direction, player::Player, vec3::Vec3},
particle, particle,
replay::Recorder,
}; };
use anyhow::Context;
use azalea::{ use azalea::{
brigadier::exceptions::BuiltInExceptions::DispatcherUnknownCommand, prelude::*, brigadier::exceptions::BuiltInExceptions::DispatcherUnknownCommand, prelude::*,
protocol::packets::game::ClientboundGamePacket, protocol::packets::game::ClientboundGamePacket,
@ -14,7 +12,7 @@ use azalea::{
use hyper::{server::conn::http1, service::service_fn}; use hyper::{server::conn::http1, service::service_fn};
use hyper_util::rt::TokioIo; use hyper_util::rt::TokioIo;
use log::{debug, error, info, trace}; use log::{debug, error, info, trace};
use mlua::{Error, Function, IntoLuaMulti, Table}; use mlua::{Function, IntoLuaMulti, Table};
use ncr::utils::trim_header; use ncr::utils::trim_header;
use tokio::net::TcpListener; use tokio::net::TcpListener;
@ -35,8 +33,8 @@ pub async fn handle_event(client: Client, event: Event, state: State) -> anyhow:
let mut is_encrypted = false; let mut is_encrypted = false;
if let Some(ref sender) = sender { if let Some(ref sender) = sender {
let mut ncr_options = None; let ncr_options = globals.get::<Table>("NcrOptions").ok();
if let Ok(options) = globals.get::<Table>("NcrOptions") if let Some(ref options) = ncr_options
&& let Ok(decrypt) = globals.get::<Function>("ncr_decrypt") && let Ok(decrypt) = globals.get::<Function>("ncr_decrypt")
&& let Some(plaintext) = decrypt && let Some(plaintext) = decrypt
.call::<String>((options.clone(), content.clone())) .call::<String>((options.clone(), content.clone()))
@ -45,7 +43,6 @@ pub async fn handle_event(client: Client, event: Event, state: State) -> anyhow:
.and_then(|s| trim_header(s).ok()) .and_then(|s| trim_header(s).ok())
{ {
is_encrypted = true; is_encrypted = true;
ncr_options = Some(options);
plaintext.clone_into(&mut content); plaintext.clone_into(&mut content);
info!("decrypted message from {sender}: {content}"); info!("decrypted message from {sender}: {content}");
} }
@ -169,23 +166,9 @@ pub async fn handle_event(client: Client, event: Event, state: State) -> anyhow:
Event::Init => { Event::Init => {
debug!("received initialize event"); debug!("received initialize event");
let globals = state.lua.globals(); state.lua.globals().set(
let lua_ecs = client.ecs.clone();
globals.set(
"finish_replay_recording",
state.lua.create_function_mut(move |_, (): ()| {
lua_ecs
.lock()
.remove_resource::<Recorder>()
.context("recording not active")
.map_err(Error::external)?
.finish()
.map_err(Error::external)
})?,
)?;
globals.set(
"client", "client",
client::Client { lua::client::Client {
inner: Some(client), inner: Some(client),
}, },
)?; )?;

View File

@ -7,7 +7,6 @@ mod events;
mod http; mod http;
mod lua; mod lua;
mod particle; mod particle;
mod replay;
use arguments::Arguments; use arguments::Arguments;
use azalea::{ use azalea::{
@ -22,8 +21,7 @@ use clap::Parser;
use commands::{CommandSource, register}; use commands::{CommandSource, register};
use futures::lock::Mutex; use futures::lock::Mutex;
use futures_locks::RwLock; use futures_locks::RwLock;
use mlua::{Function, Lua, Table}; use mlua::{Function, Lua};
use replay::{Recorder, plugin::RecordPlugin};
use std::{ use std::{
collections::HashMap, collections::HashMap,
env, env,
@ -39,10 +37,10 @@ type ListenerMap = Arc<RwLock<HashMap<String, Vec<(String, Function)>>>>;
#[derive(Default, Clone, Component)] #[derive(Default, Clone, Component)]
pub struct State { pub struct State {
http_address: Option<SocketAddr>,
lua: Arc<Lua>, lua: Arc<Lua>,
event_listeners: ListenerMap, event_listeners: ListenerMap,
commands: Arc<CommandDispatcher<Mutex<CommandSource>>>, commands: Arc<CommandDispatcher<Mutex<CommandSource>>>,
http_address: Option<SocketAddr>,
} }
#[tokio::main] #[tokio::main]
@ -93,33 +91,15 @@ async fn main() -> anyhow::Result<()> {
..Default::default() ..Default::default()
}) })
}; };
let record_plugin = RecordPlugin {
recorder: Arc::new(parking_lot::Mutex::new(
if let Ok(options) = globals.get::<Table>("ReplayRecordingOptions")
&& let Ok(path) = options.get::<String>("path")
{
Some(Recorder::new(
path,
server.clone(),
options
.get::<bool>("ignore_compression")
.unwrap_or_default(),
)?)
} else {
None
},
)),
};
let Err(error) = ClientBuilder::new_without_plugins() let Err(error) = ClientBuilder::new_without_plugins()
.add_plugins(default_plugins) .add_plugins(default_plugins)
.add_plugins(record_plugin)
.add_plugins(DefaultBotPlugins) .add_plugins(DefaultBotPlugins)
.set_handler(events::handle_event) .set_handler(events::handle_event)
.set_state(State { .set_state(State {
http_address: args.http_address,
lua: Arc::new(lua), lua: Arc::new(lua),
event_listeners, event_listeners,
commands: Arc::new(commands), commands: Arc::new(commands),
http_address: args.http_address,
}) })
.start( .start(
if username.contains('@') { if username.contains('@') {

View File

@ -1,88 +0,0 @@
pub mod plugin;
use crate::build_info;
use anyhow::Result;
use azalea::{
buf::AzaleaWriteVar,
prelude::Resource,
protocol::packets::{PROTOCOL_VERSION, ProtocolPacket, VERSION_NAME},
};
use serde_json::json;
use std::{
fs::File,
io::Write,
time::{SystemTime, UNIX_EPOCH},
};
use zip::{ZipWriter, write::SimpleFileOptions};
#[derive(Resource)]
pub struct Recorder {
zip_writer: ZipWriter<File>,
start_time: u128,
server: String,
ignore_compression: bool,
}
impl Recorder {
pub fn new(path: String, server: String, ignore_compression: bool) -> Result<Self> {
let mut zip_writer = ZipWriter::new(
File::options()
.write(true)
.create(true)
.truncate(true)
.open(path)?,
);
zip_writer.start_file("recording.tmcpr", SimpleFileOptions::default())?;
Ok(Self {
zip_writer,
start_time: SystemTime::now().duration_since(UNIX_EPOCH)?.as_millis(),
server,
ignore_compression,
})
}
pub fn finish(mut self) -> Result<()> {
self.zip_writer
.start_file("metaData.json", SimpleFileOptions::default())?;
self.zip_writer.write_all(
json!({
"singleplayer": false,
"serverName": self.server,
"duration": SystemTime::now().duration_since(UNIX_EPOCH)?.as_millis() - self.start_time,
"date": self.start_time,
"mcversion": VERSION_NAME,
"fileFormat": "MCPR",
"fileFormatVersion": 14,
"protocol": PROTOCOL_VERSION,
"generator": build_info::version_formatted(),
})
.to_string()
.as_bytes(),
)?;
self.zip_writer.finish()?;
Ok(())
}
fn get_timestamp(&self) -> Result<[u8; 4]> {
Ok(TryInto::<u32>::try_into(
SystemTime::now().duration_since(UNIX_EPOCH)?.as_millis() - self.start_time,
)?
.to_be_bytes())
}
fn save_raw_packet(&mut self, raw_packet: &[u8]) -> Result<()> {
let mut data = Vec::from(self.get_timestamp()?);
data.extend(TryInto::<u32>::try_into(raw_packet.len())?.to_be_bytes());
data.extend(raw_packet);
self.zip_writer.write_all(&data)?;
Ok(())
}
fn save_packet<T: ProtocolPacket>(&mut self, packet: &T) -> Result<()> {
let mut raw_packet = Vec::new();
packet.id().azalea_write_var(&mut raw_packet)?;
packet.write(&mut raw_packet)?;
self.save_raw_packet(&raw_packet)
}
}

View File

@ -1,76 +0,0 @@
use super::Recorder;
use azalea::{
ecs::{event::EventReader, system::Query},
packet_handling::{
configuration::ConfigurationEvent,
game::send_packet_events,
login::{LoginPacketEvent, process_packet_events},
},
protocol::packets::login::ClientboundLoginPacket,
raw_connection::RawConnection,
};
use bevy_app::{First, Plugin};
use bevy_ecs::{schedule::IntoSystemConfigs, system::ResMut};
use log::error;
use parking_lot::Mutex;
use std::sync::Arc;
pub struct RecordPlugin {
pub recorder: Arc<Mutex<Option<Recorder>>>,
}
impl Plugin for RecordPlugin {
fn build(&self, app: &mut bevy_app::App) {
if let Some(recorder) = self.recorder.lock().take() {
app.insert_resource(recorder);
}
app.add_systems(First, record_login_packets.before(process_packet_events))
.add_systems(First, record_configuration_packets)
.add_systems(First, record_game_packets.before(send_packet_events));
}
}
fn record_login_packets(
recorder: Option<ResMut<Recorder>>,
mut events: EventReader<LoginPacketEvent>,
) {
if let Some(mut recorder) = recorder {
for event in events.read() {
if recorder.ignore_compression
&& let ClientboundLoginPacket::LoginCompression(_) = *event.packet
{
continue;
}
if let Err(error) = recorder.save_packet(event.packet.as_ref()) {
error!("failed to record login packet: {error:?}");
}
}
}
}
fn record_configuration_packets(
recorder: Option<ResMut<Recorder>>,
mut events: EventReader<ConfigurationEvent>,
) {
if let Some(mut recorder) = recorder {
for event in events.read() {
if let Err(error) = recorder.save_packet(&event.packet) {
error!("failed to record configuration packet: {error:?}");
}
}
}
}
fn record_game_packets(recorder: Option<ResMut<Recorder>>, query: Query<&RawConnection>) {
if let Some(mut recorder) = recorder
&& let Ok(raw_conn) = query.get_single()
{
let queue = raw_conn.incoming_packet_queue();
for raw_packet in queue.lock().iter() {
if let Err(error) = recorder.save_raw_packet(raw_packet) {
error!("failed to record game packet: {error:?}");
}
}
}
}