From da11614c38e83d6172941f44ffaf2873f7a18142 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Mon, 30 Dec 2024 04:36:10 -0800 Subject: [PATCH 01/31] Initial commit --- .gitignore | 1 + Cargo.lock | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 7 ++++ src/lib.rs | 1 + src/v1.rs | 1 + 5 files changed, 103 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/lib.rs create mode 100644 src/v1.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..4e57f40 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,93 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "array-init" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc" + +[[package]] +name = "binrw" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d4bca59c20d6f40c2cc0802afbe1e788b89096f61bdf7aeea6bf00f10c2909b" +dependencies = [ + "array-init", + "binrw_derive", + "bytemuck", +] + +[[package]] +name = "binrw_derive" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8ba42866ce5bced2645bfa15e97eef2c62d2bdb530510538de8dd3d04efff3c" +dependencies = [ + "either", + "owo-colors", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "bytemuck" +version = "1.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "owo-colors" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" + +[[package]] +name = "proc-macro2" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "strafesnet_roblox_bot_file" +version = "0.1.0" +dependencies = [ + "binrw", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..4f209b1 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "strafesnet_roblox_bot_file" +version = "0.1.0" +edition = "2021" + +[dependencies] +binrw = "0.14.1" diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..a3a6d96 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1 @@ +pub mod v1; diff --git a/src/v1.rs b/src/v1.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/v1.rs @@ -0,0 +1 @@ + From b0a1e4b1267ec5b14191988f2b0a70d577c19b77 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Mon, 30 Dec 2024 04:37:57 -0800 Subject: [PATCH 02/31] open source --- LICENSE-APACHE | 176 +++++++++++++++++++++++++++++++++++++++++++++++++ LICENSE-MIT | 23 +++++++ 2 files changed, 199 insertions(+) create mode 100644 LICENSE-APACHE create mode 100644 LICENSE-MIT diff --git a/LICENSE-APACHE b/LICENSE-APACHE new file mode 100644 index 0000000..a7e77cb --- /dev/null +++ b/LICENSE-APACHE @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 0000000..468cd79 --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. \ No newline at end of file From 39196119ff2d3b02f421ec425726b057e6293a7a Mon Sep 17 00:00:00 2001 From: Quaternions Date: Mon, 30 Dec 2024 04:36:15 -0800 Subject: [PATCH 03/31] lib --- src/v1.rs | 332 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 332 insertions(+) diff --git a/src/v1.rs b/src/v1.rs index 8b13789..14c75cf 100644 --- a/src/v1.rs +++ b/src/v1.rs @@ -1 +1,333 @@ +use binrw::{binrw,BinReaderExt,io::TakeSeekExt}; +#[binrw] +#[brw(little)] +pub enum Bool{ + #[brw(magic=0u32)] + False, + #[brw(magic=1u32)] + True, +} +#[binrw] +#[brw(little)] +pub struct Vector2{ + pub x:f32, + pub y:f32, +} +#[binrw] +#[brw(little)] +pub struct Vector3{ + pub x:f32, + pub y:f32, + pub z:f32, +} + +// input +#[binrw] +#[brw(little)] +pub struct InputEvent{ + pub game_controls:u32, + pub mouse_pos:Vector2, +} +#[binrw] +#[brw(little)] +pub struct TimedInputEvent{ + pub time:f64, + pub event:InputEvent, +} + +// output +#[binrw] +#[brw(little)] +pub struct OutputEvent{ + pub tick_info:u32, + pub angles:Vector3, + pub position:Vector3, + pub velocity:Vector3, + pub acceleration:Vector3, +} +#[binrw] +#[brw(little)] +pub struct TimedOutputEvent{ + pub time:f64, + pub event:OutputEvent, +} + +// sound +#[binrw] +#[brw(little)] +pub struct SoundEvent{ + pub sound_type:u32, + pub material:u32, +} +#[binrw] +#[brw(little)] +pub struct TimedSoundEvent{ + pub time:f64, + pub event:SoundEvent, +} + +// world +#[binrw] +#[brw(little)] +pub struct WorldEventReset{ + pub position:Vector3, +} +#[binrw] +#[brw(little)] +pub struct WorldEventButton{ + pub button_id:u32, + #[brw(magic=b"quatdata")] + __:(), +} +#[binrw] +#[brw(little)] +pub struct WorldEventSetTime{ + pub time:f64, + #[brw(magic=b"data")] + __:(), +} +#[binrw] +#[brw(little)] +pub struct WorldEventSetPaused{ + pub paused:Bool, + #[brw(magic=b"quatdata")] + __:(), +} +#[binrw] +#[brw(little)] +pub enum WorldEvent{ + #[brw(magic=0u32)] + Reset(WorldEventReset), + #[brw(magic=1u32)] + Button(WorldEventButton), + #[brw(magic=2u32)] + SetTime(WorldEventSetTime), + #[brw(magic=3u32)] + SetPaused(WorldEventSetPaused), +} +#[binrw] +#[brw(little)] +pub struct TimedWorldEvent{ + pub time:f64, + pub event:WorldEvent, +} + +// gravity +#[binrw] +#[brw(little)] +pub struct GravityEvent{ + pub gravity:Vector3, +} +#[binrw] +#[brw(little)] +pub struct TimedGravityEvent{ + pub time:f64, + pub event:GravityEvent, +} + +// run +#[binrw] +#[brw(little)] +pub enum RunEventType{ + #[brw(magic=0u32)] + Prepare, + #[brw(magic=1u32)] + Start, + #[brw(magic=2u32)] + Finish, + #[brw(magic=3u32)] + Clear, + #[brw(magic=4u32)] + Flag, + #[brw(magic=5u32)] + LoadState, + #[brw(magic=6u32)] + SaveState, +} +#[binrw] +#[brw(little)] +pub struct RunEvent{ + run_event_type:RunEventType, + mode_id:i32, + flag_reason_id:u32, +} +#[binrw] +#[brw(little)] +pub struct TimedRunEvent{ + pub time:f64, + pub event:RunEvent, +} + +// camera +#[binrw] +#[brw(little)] +pub struct CameraEvent{ + pub camera_event_id:u32, + pub value:Vector3, +} +#[binrw] +#[brw(little)] +pub struct TimedCameraEvent{ + pub time:f64, + pub event:CameraEvent, +} + +// setting +#[binrw] +#[brw(little)] +pub struct SettingEvent{ + pub setting_id:u32, + pub value:f64, +} +#[binrw] +#[brw(little)] +pub struct TimedSettingEvent{ + pub time:f64, + pub event:SettingEvent, +} + +#[derive(Default)] +pub struct Block{ + pub input_events:Vec, + pub output_events:Vec, + pub sound_events:Vec, + pub world_events:Vec, + pub gravity_events:Vec, + pub run_events:Vec, + pub camera_events:Vec, + pub setting_events:Vec, +} + +#[binrw] +#[brw(little)] +enum EventType{ + #[brw(magic=1u32)] + Input, + #[brw(magic=2u32)] + Output, + #[brw(magic=3u32)] + Sound, + #[brw(magic=4u32)] + World, + #[brw(magic=5u32)] + Gravity, + #[brw(magic=6u32)] + Run, + #[brw(magic=7u32)] + Camera, + #[brw(magic=8u32)] + Setting, +} +#[binrw] +#[brw(little)] +struct EventChunkHeader{ + event_type:EventType, + num_events:u32, +} + +// first time I've managed to write BinRead generics without this stupid T::Args<'a>:Required thing blocking me +fn read_data_into_events<'a,R:BinReaderExt,T>(data:&mut R,events:&mut Vec,num_events:usize)->binrw::BinResult<()> +where + T:binrw::BinRead, + T::Args<'a>:binrw::__private::Required, +{ + // there is only supposed to be at most one of each type of event chunk per block, so no need to amortize. + events.reserve_exact(num_events); + for _ in 0..num_events{ + events.push(data.read_le()?); + } + Ok(()) +} + +impl Block{ + fn read(mut data:R)->binrw::BinResult{ + let mut block=Block::default(); + // well... this looks error prone + while let Ok(event_chunk_header)=data.read_le::(){ + match event_chunk_header.event_type{ + EventType::Input=>read_data_into_events(&mut data,&mut block.input_events,event_chunk_header.num_events as usize)?, + EventType::Output=>read_data_into_events(&mut data,&mut block.output_events,event_chunk_header.num_events as usize)?, + EventType::Sound=>read_data_into_events(&mut data,&mut block.sound_events,event_chunk_header.num_events as usize)?, + EventType::World=>read_data_into_events(&mut data,&mut block.world_events,event_chunk_header.num_events as usize)?, + EventType::Gravity=>read_data_into_events(&mut data,&mut block.gravity_events,event_chunk_header.num_events as usize)?, + EventType::Run=>read_data_into_events(&mut data,&mut block.run_events,event_chunk_header.num_events as usize)?, + EventType::Camera=>read_data_into_events(&mut data,&mut block.camera_events,event_chunk_header.num_events as usize)?, + EventType::Setting=>read_data_into_events(&mut data,&mut block.setting_events,event_chunk_header.num_events as usize)?, + } + } + Ok(block) + } +} + +#[derive(Debug)] +pub enum Error{ + InvalidBlockId(BlockId), + Seek(std::io::Error), + InvalidData(binrw::Error), +} +impl std::fmt::Display for Error{ + fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{ + write!(f,"{self:?}") + } +} +impl std::error::Error for Error{} + +#[binrw] +#[brw(little)] +#[derive(Debug)] +pub struct BlockId(u32); + +#[binrw] +#[brw(little)] +pub struct TimedBlockId{ + pub time:f64, + pub block_id:BlockId, +} + +#[binrw] +#[brw(little)] +pub struct FileHeader{ + #[brw(magic=b"qbot")] + pub file_version:u32, + pub num_offline_events:u32, + pub num_realtime_events:u32, + #[br(count=num_offline_events+num_realtime_events+1)] + pub block_positions:Vec, + #[br(count=num_offline_events)] + pub offline_blocks_timeline:Vec, + #[br(count=num_realtime_events)] + pub realtime_blocks_timeline:Vec, +} + +pub struct File{ + header:FileHeader, + //reference to the data + data:R, +} + +impl File{ + pub fn new(mut input:R)->Result,binrw::Error>{ + Ok(File{ + header:input.read_le()?, + data:input, + }) + } + fn data_mut(&mut self)->&mut R{ + &mut self.data + } + fn block_reader(&mut self,block_id:BlockId)->Result,Error>{ + if self.header.block_positions.len() as u32<=block_id.0{ + return Err(Error::InvalidBlockId(block_id)) + } + let block_start=self.header.block_positions[block_id.0 as usize] as u64; + let block_end=self.header.block_positions[block_id.0 as usize+1] as u64; + self.data.seek(std::io::SeekFrom::Start(block_start)).map_err(Error::Seek)?; + Ok(self.data_mut().take_seek(block_end-block_start)) + } + pub fn read_block(&mut self,block_id:BlockId)->Result{ + let data=self.block_reader(block_id)?; + let block=Block::read(data).map_err(Error::InvalidData)?; + Ok(block) + } +} From 1f78c98c6fdb2bbb021d1f84a8ba4a94cad9286f Mon Sep 17 00:00:00 2001 From: Quaternions Date: Mon, 30 Dec 2024 04:46:59 -0800 Subject: [PATCH 04/31] readme --- README.md | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..cf08a3d --- /dev/null +++ b/README.md @@ -0,0 +1,38 @@ +Roblox Bhop/Surf Bot File Format +================================ + +## Example + +```rust +use strafesnet_roblox_bot_file::File; + +let file=std::fs::File::open("bot_file")?; +let input=std::io::BufReader::new(file); +let bot_file=File::new(input)?; + +for &(time,block_id) in &bot_file.header.offline_blocks_timeline{ + let block=bot_file.read_block(block_id)?; + // offline blocks include the following event types: + // World, Gravity, Run, Camera, Setting +} +for &(time,block_id) in &bot_file.header.realtime_blocks_timeline{ + let block=bot_file.read_block(block_id)?; + // realtime blocks include the following event types: + // Input, Output, Sound +} +``` + +#### License + + +Licensed under either of Apache License, Version +2.0 or MIT license at your option. + + +
+ + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + From 22543defa89982cf727f30dff99ff12b73e2527a Mon Sep 17 00:00:00 2001 From: Quaternions Date: Mon, 30 Dec 2024 04:51:20 -0800 Subject: [PATCH 05/31] convenient impl --- src/v1.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/v1.rs b/src/v1.rs index 14c75cf..e78ac66 100644 --- a/src/v1.rs +++ b/src/v1.rs @@ -2,12 +2,21 @@ use binrw::{binrw,BinReaderExt,io::TakeSeekExt}; #[binrw] #[brw(little)] +#[derive(Clone,Copy,Debug)] pub enum Bool{ #[brw(magic=0u32)] False, #[brw(magic=1u32)] True, } +impl Into for Bool{ + fn into(self)->bool{ + match self{ + Bool::False=>false, + Bool::True=>true, + } + } +} #[binrw] #[brw(little)] pub struct Vector2{ From 0c251f90fd32e5d7d7bc5e5127970d47f650f525 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Mon, 30 Dec 2024 21:08:58 -0800 Subject: [PATCH 06/31] fixups for test --- src/v1.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/v1.rs b/src/v1.rs index e78ac66..3386644 100644 --- a/src/v1.rs +++ b/src/v1.rs @@ -284,11 +284,12 @@ impl std::error::Error for Error{} #[binrw] #[brw(little)] -#[derive(Debug)] +#[derive(Debug,Clone,Copy)] pub struct BlockId(u32); #[binrw] #[brw(little)] +#[derive(Debug,Clone,Copy)] pub struct TimedBlockId{ pub time:f64, pub block_id:BlockId, @@ -296,6 +297,7 @@ pub struct TimedBlockId{ #[binrw] #[brw(little)] +#[derive(Debug)] pub struct FileHeader{ #[brw(magic=b"qbot")] pub file_version:u32, @@ -310,7 +312,7 @@ pub struct FileHeader{ } pub struct File{ - header:FileHeader, + pub header:FileHeader, //reference to the data data:R, } From 083a735d8570ce64b072eef04f0d486d0285ec04 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Mon, 30 Dec 2024 21:09:05 -0800 Subject: [PATCH 07/31] test --- src/lib.rs | 3 +++ src/tests.rs | 23 +++++++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 src/tests.rs diff --git a/src/lib.rs b/src/lib.rs index a3a6d96..d80700a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1 +1,4 @@ pub mod v1; + +#[cfg(test)] +mod tests; diff --git a/src/tests.rs b/src/tests.rs new file mode 100644 index 0000000..bcaa243 --- /dev/null +++ b/src/tests.rs @@ -0,0 +1,23 @@ +use crate::v1::TimedBlockId; + +#[test] +fn _1()->Result<(),crate::v1::Error>{ + let file=std::fs::File::open("files/bhop_marble_7cf33a64-7120-4514-b9fa-4fe29d9523d").unwrap(); + let input=std::io::BufReader::new(file); + let mut bot_file=crate::v1::File::new(input).unwrap(); + println!("header={:?}",bot_file.header); + for TimedBlockId{time,block_id} in bot_file.header.offline_blocks_timeline.clone(){ + println!("offline time={} block_id={:?}",time,block_id); + let block=bot_file.read_block(block_id)?; + // offline blocks include the following event types: + // World, Gravity, Run, Camera, Setting + } + for TimedBlockId{time,block_id} in bot_file.header.realtime_blocks_timeline.clone(){ + println!("realtime time={} block_id={:?}",time,block_id); + let block=bot_file.read_block(block_id)?; + // realtime blocks include the following event types: + // Input, Output, Sound + } + + Ok(()) +} From 43ee18a2caa7b4f1643ccb3c1c17247c474ee8cc Mon Sep 17 00:00:00 2001 From: Quaternions Date: Mon, 30 Dec 2024 23:12:05 -0800 Subject: [PATCH 08/31] fix 1-indexed block id --- src/v1.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/v1.rs b/src/v1.rs index 3386644..72b4257 100644 --- a/src/v1.rs +++ b/src/v1.rs @@ -285,7 +285,7 @@ impl std::error::Error for Error{} #[binrw] #[brw(little)] #[derive(Debug,Clone,Copy)] -pub struct BlockId(u32); +pub struct BlockId(#[br(map=|i:u32|i-1)]u32); #[binrw] #[brw(little)] From 9003f88a9d9773e6636e3321c7ffd9cdcf86d40b Mon Sep 17 00:00:00 2001 From: Quaternions Date: Tue, 31 Dec 2024 01:44:28 -0800 Subject: [PATCH 09/31] trey floating point format is not standard --- src/v1.rs | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/src/v1.rs b/src/v1.rs index 72b4257..2aea4f6 100644 --- a/src/v1.rs +++ b/src/v1.rs @@ -1,5 +1,55 @@ use binrw::{binrw,BinReaderExt,io::TakeSeekExt}; +// whatever this is +fn trey_float(f:f32)->f32{ + let bits=f.to_bits(); + let s=bits&1!=0; + let e=((bits>>1)&((1<<8)-1)) as i32; + let m=(bits>>(1+8))&((1<<23)-1); + if e==255{ + if m==0{ + if s{ + f32::NEG_INFINITY + }else{ + f32::INFINITY + } + }else if m==1{ + f32::NAN + }else{ + // this is supposed to be QNAN but idk how to say it in rust + f32::NAN + } + }else if e==0{ + if s{-(m as f32)*2.0f32.powi(-149)}else{(m as f32)*2.0f32.powi(-149)} + }else{ + if s{-(m as f32/2.0f32.powi(23)+1.0)*2.0f32.powi(e-127)}else{(m as f32/2.0f32.powi(23)+1.0)*2.0f32.powi(e-127)} + } +} +fn trey_double(f:f64)->f64{ + let bits=f.to_bits(); + let s=bits&1!=0; + let e=((bits>>1)&((1<<11)-1)) as i32; + let m=(bits>>(1+11))&((1<<52)-1); + if e==2047{ + if m==0{ + if s{ + f64::NEG_INFINITY + }else{ + f64::INFINITY + } + }else if m==1{ + f64::NAN + }else{ + // this is supposed to be QNAN but idk how to say it in rust + f64::NAN + } + }else if e==0{ + if s{-(m as f64)*2.0f64.powi(-1074)}else{(m as f64)*2.0f64.powi(-1074)} + }else{ + if s{-(m as f64/2.0f64.powi(52)+1.0)*2.0f64.powi(e-1023)}else{(m as f64/2.0f64.powi(52)+1.0)*2.0f64.powi(e-1023)} + } +} + #[binrw] #[brw(little)] #[derive(Clone,Copy,Debug)] @@ -20,14 +70,19 @@ impl Into for Bool{ #[binrw] #[brw(little)] pub struct Vector2{ + #[br(map=trey_float)] pub x:f32, + #[br(map=trey_float)] pub y:f32, } #[binrw] #[brw(little)] pub struct Vector3{ + #[br(map=trey_float)] pub x:f32, + #[br(map=trey_float)] pub y:f32, + #[br(map=trey_float)] pub z:f32, } @@ -41,6 +96,7 @@ pub struct InputEvent{ #[binrw] #[brw(little)] pub struct TimedInputEvent{ + #[br(map=trey_double)] pub time:f64, pub event:InputEvent, } @@ -58,6 +114,7 @@ pub struct OutputEvent{ #[binrw] #[brw(little)] pub struct TimedOutputEvent{ + #[br(map=trey_double)] pub time:f64, pub event:OutputEvent, } @@ -72,6 +129,7 @@ pub struct SoundEvent{ #[binrw] #[brw(little)] pub struct TimedSoundEvent{ + #[br(map=trey_double)] pub time:f64, pub event:SoundEvent, } @@ -92,6 +150,7 @@ pub struct WorldEventButton{ #[binrw] #[brw(little)] pub struct WorldEventSetTime{ + #[br(map=trey_double)] pub time:f64, #[brw(magic=b"data")] __:(), @@ -118,6 +177,7 @@ pub enum WorldEvent{ #[binrw] #[brw(little)] pub struct TimedWorldEvent{ + #[br(map=trey_double)] pub time:f64, pub event:WorldEvent, } @@ -131,6 +191,7 @@ pub struct GravityEvent{ #[binrw] #[brw(little)] pub struct TimedGravityEvent{ + #[br(map=trey_double)] pub time:f64, pub event:GravityEvent, } @@ -164,6 +225,7 @@ pub struct RunEvent{ #[binrw] #[brw(little)] pub struct TimedRunEvent{ + #[br(map=trey_double)] pub time:f64, pub event:RunEvent, } @@ -178,6 +240,7 @@ pub struct CameraEvent{ #[binrw] #[brw(little)] pub struct TimedCameraEvent{ + #[br(map=trey_double)] pub time:f64, pub event:CameraEvent, } @@ -187,11 +250,13 @@ pub struct TimedCameraEvent{ #[brw(little)] pub struct SettingEvent{ pub setting_id:u32, + #[br(map=trey_double)] pub value:f64, } #[binrw] #[brw(little)] pub struct TimedSettingEvent{ + #[br(map=trey_double)] pub time:f64, pub event:SettingEvent, } @@ -291,6 +356,7 @@ pub struct BlockId(#[br(map=|i:u32|i-1)]u32); #[brw(little)] #[derive(Debug,Clone,Copy)] pub struct TimedBlockId{ + #[br(map=trey_double)] pub time:f64, pub block_id:BlockId, } From 716354df2b320da5b12185b31044bf6bae82224d Mon Sep 17 00:00:00 2001 From: Quaternions Date: Tue, 31 Dec 2024 01:57:22 -0800 Subject: [PATCH 10/31] trey decoder 2.0 --- src/v1.rs | 48 +++++++----------------------------------------- 1 file changed, 7 insertions(+), 41 deletions(-) diff --git a/src/v1.rs b/src/v1.rs index 2aea4f6..a15d53c 100644 --- a/src/v1.rs +++ b/src/v1.rs @@ -1,53 +1,19 @@ use binrw::{binrw,BinReaderExt,io::TakeSeekExt}; -// whatever this is +// the bit chunks are deposited in reverse fn trey_float(f:f32)->f32{ let bits=f.to_bits(); - let s=bits&1!=0; - let e=((bits>>1)&((1<<8)-1)) as i32; + let s=bits&1; + let e=(bits>>1)&((1<<8)-1); let m=(bits>>(1+8))&((1<<23)-1); - if e==255{ - if m==0{ - if s{ - f32::NEG_INFINITY - }else{ - f32::INFINITY - } - }else if m==1{ - f32::NAN - }else{ - // this is supposed to be QNAN but idk how to say it in rust - f32::NAN - } - }else if e==0{ - if s{-(m as f32)*2.0f32.powi(-149)}else{(m as f32)*2.0f32.powi(-149)} - }else{ - if s{-(m as f32/2.0f32.powi(23)+1.0)*2.0f32.powi(e-127)}else{(m as f32/2.0f32.powi(23)+1.0)*2.0f32.powi(e-127)} - } + f32::from_bits(m|(e<<23)|(s<<31)) } fn trey_double(f:f64)->f64{ let bits=f.to_bits(); - let s=bits&1!=0; - let e=((bits>>1)&((1<<11)-1)) as i32; + let s=bits&1; + let e=(bits>>1)&((1<<11)-1); let m=(bits>>(1+11))&((1<<52)-1); - if e==2047{ - if m==0{ - if s{ - f64::NEG_INFINITY - }else{ - f64::INFINITY - } - }else if m==1{ - f64::NAN - }else{ - // this is supposed to be QNAN but idk how to say it in rust - f64::NAN - } - }else if e==0{ - if s{-(m as f64)*2.0f64.powi(-1074)}else{(m as f64)*2.0f64.powi(-1074)} - }else{ - if s{-(m as f64/2.0f64.powi(52)+1.0)*2.0f64.powi(e-1023)}else{(m as f64/2.0f64.powi(52)+1.0)*2.0f64.powi(e-1023)} - } + f64::from_bits(m|(e<<52)|(s<<63)) } #[binrw] From 3ddd31a489757cb019e8b580ac6fd0e449a8c74f Mon Sep 17 00:00:00 2001 From: Quaternions Date: Tue, 31 Dec 2024 03:36:33 -0800 Subject: [PATCH 11/31] split borrow to prevent clone --- src/tests.rs | 8 ++++---- src/v1.rs | 28 ++++++++++++++++------------ 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/tests.rs b/src/tests.rs index bcaa243..1e44e2a 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -6,15 +6,15 @@ fn _1()->Result<(),crate::v1::Error>{ let input=std::io::BufReader::new(file); let mut bot_file=crate::v1::File::new(input).unwrap(); println!("header={:?}",bot_file.header); - for TimedBlockId{time,block_id} in bot_file.header.offline_blocks_timeline.clone(){ + for &TimedBlockId{time,block_id} in &bot_file.header.offline_blocks_timeline{ println!("offline time={} block_id={:?}",time,block_id); - let block=bot_file.read_block(block_id)?; + let block=bot_file.data.read_block(&bot_file.header,block_id)?; // offline blocks include the following event types: // World, Gravity, Run, Camera, Setting } - for TimedBlockId{time,block_id} in bot_file.header.realtime_blocks_timeline.clone(){ + for &TimedBlockId{time,block_id} in &bot_file.header.realtime_blocks_timeline{ println!("realtime time={} block_id={:?}",time,block_id); - let block=bot_file.read_block(block_id)?; + let block=bot_file.data.read_block(&bot_file.header,block_id)?; // realtime blocks include the following event types: // Input, Output, Sound } diff --git a/src/v1.rs b/src/v1.rs index a15d53c..6762578 100644 --- a/src/v1.rs +++ b/src/v1.rs @@ -345,31 +345,35 @@ pub struct FileHeader{ pub struct File{ pub header:FileHeader, - //reference to the data - data:R, + pub data:FileData, } - impl File{ - pub fn new(mut input:R)->Result,binrw::Error>{ + pub fn new(mut data:R)->Result,binrw::Error>{ Ok(File{ - header:input.read_le()?, - data:input, + header:data.read_le()?, + data:FileData{data}, }) } +} + +pub struct FileData{ + data:R, +} +impl FileData{ fn data_mut(&mut self)->&mut R{ &mut self.data } - fn block_reader(&mut self,block_id:BlockId)->Result,Error>{ - if self.header.block_positions.len() as u32<=block_id.0{ + fn block_reader(&mut self,header:&FileHeader,block_id:BlockId)->Result,Error>{ + if header.block_positions.len() as u32<=block_id.0{ return Err(Error::InvalidBlockId(block_id)) } - let block_start=self.header.block_positions[block_id.0 as usize] as u64; - let block_end=self.header.block_positions[block_id.0 as usize+1] as u64; + let block_start=header.block_positions[block_id.0 as usize] as u64; + let block_end=header.block_positions[block_id.0 as usize+1] as u64; self.data.seek(std::io::SeekFrom::Start(block_start)).map_err(Error::Seek)?; Ok(self.data_mut().take_seek(block_end-block_start)) } - pub fn read_block(&mut self,block_id:BlockId)->Result{ - let data=self.block_reader(block_id)?; + pub fn read_block(&mut self,header:&FileHeader,block_id:BlockId)->Result{ + let data=self.block_reader(header,block_id)?; let block=Block::read(data).map_err(Error::InvalidData)?; Ok(block) } From 8b976c8e7d3be86878fd12cf3c195cb816faac98 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Tue, 31 Dec 2024 03:46:11 -0800 Subject: [PATCH 12/31] slightly different api --- src/tests.rs | 6 ++++-- src/v1.rs | 29 +++++++++++++++++++---------- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/tests.rs b/src/tests.rs index 1e44e2a..d9c1da7 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -8,13 +8,15 @@ fn _1()->Result<(),crate::v1::Error>{ println!("header={:?}",bot_file.header); for &TimedBlockId{time,block_id} in &bot_file.header.offline_blocks_timeline{ println!("offline time={} block_id={:?}",time,block_id); - let block=bot_file.data.read_block(&bot_file.header,block_id)?; + let block_info=bot_file.header.block_info(block_id)?; + let block=bot_file.data.read_block_info(block_info)?; // offline blocks include the following event types: // World, Gravity, Run, Camera, Setting } for &TimedBlockId{time,block_id} in &bot_file.header.realtime_blocks_timeline{ println!("realtime time={} block_id={:?}",time,block_id); - let block=bot_file.data.read_block(&bot_file.header,block_id)?; + let block_info=bot_file.header.block_info(block_id)?; + let block=bot_file.data.read_block_info(block_info)?; // realtime blocks include the following event types: // Input, Output, Sound } diff --git a/src/v1.rs b/src/v1.rs index 6762578..7e8415b 100644 --- a/src/v1.rs +++ b/src/v1.rs @@ -342,6 +342,20 @@ pub struct FileHeader{ #[br(count=num_realtime_events)] pub realtime_blocks_timeline:Vec, } +pub struct BlockInfo{ + start:u32, + length:u32, +} +impl FileHeader{ + pub fn block_info(&self,block_id:BlockId)->Result{ + if self.block_positions.len() as u32<=block_id.0{ + return Err(Error::InvalidBlockId(block_id)); + } + let start=self.block_positions[block_id.0 as usize]; + let end=self.block_positions[block_id.0 as usize+1]; + Ok(BlockInfo{start,length:end-start}) + } +} pub struct File{ pub header:FileHeader, @@ -363,17 +377,12 @@ impl FileData{ fn data_mut(&mut self)->&mut R{ &mut self.data } - fn block_reader(&mut self,header:&FileHeader,block_id:BlockId)->Result,Error>{ - if header.block_positions.len() as u32<=block_id.0{ - return Err(Error::InvalidBlockId(block_id)) - } - let block_start=header.block_positions[block_id.0 as usize] as u64; - let block_end=header.block_positions[block_id.0 as usize+1] as u64; - self.data.seek(std::io::SeekFrom::Start(block_start)).map_err(Error::Seek)?; - Ok(self.data_mut().take_seek(block_end-block_start)) + fn block_reader(&mut self,block_info:BlockInfo)->Result,Error>{ + self.data.seek(std::io::SeekFrom::Start(block_info.start as u64)).map_err(Error::Seek)?; + Ok(self.data_mut().take_seek(block_info.length as u64)) } - pub fn read_block(&mut self,header:&FileHeader,block_id:BlockId)->Result{ - let data=self.block_reader(header,block_id)?; + pub fn read_block_info(&mut self,block_info:BlockInfo)->Result{ + let data=self.block_reader(block_info)?; let block=Block::read(data).map_err(Error::InvalidData)?; Ok(block) } From 40a4920b120cff0fd6db7a1b61c4dab74a33053d Mon Sep 17 00:00:00 2001 From: Quaternions Date: Tue, 31 Dec 2024 03:59:54 -0800 Subject: [PATCH 13/31] fix example --- README.md | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index cf08a3d..918eba2 100644 --- a/README.md +++ b/README.md @@ -4,19 +4,22 @@ Roblox Bhop/Surf Bot File Format ## Example ```rust -use strafesnet_roblox_bot_file::File; +use strafesnet_roblox_bot_file::{File,TimedBlockId}; let file=std::fs::File::open("bot_file")?; let input=std::io::BufReader::new(file); -let bot_file=File::new(input)?; - -for &(time,block_id) in &bot_file.header.offline_blocks_timeline{ - let block=bot_file.read_block(block_id)?; +let mut bot_file=File::new(input)?; +for &TimedBlockId{time,block_id} in &bot_file.header.offline_blocks_timeline{ + // header is immutably borrowed + // while data is mutably borrowed + let block_info=bot_file.header.block_info(block_id)?; + let block=bot_file.data.read_block_info(block_info)?; // offline blocks include the following event types: // World, Gravity, Run, Camera, Setting } -for &(time,block_id) in &bot_file.header.realtime_blocks_timeline{ - let block=bot_file.read_block(block_id)?; +for &TimedBlockId{time,block_id} in &bot_file.header.realtime_blocks_timeline{ + let block_info=bot_file.header.block_info(block_id)?; + let block=bot_file.data.read_block_info(block_info)?; // realtime blocks include the following event types: // Input, Output, Sound } From c3e5696a83fd3d2c78be267b55c433ebb45a6fb2 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Tue, 31 Dec 2024 04:20:10 -0800 Subject: [PATCH 14/31] no stupid Bool thing --- src/v1.rs | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/src/v1.rs b/src/v1.rs index 7e8415b..621ba29 100644 --- a/src/v1.rs +++ b/src/v1.rs @@ -16,23 +16,6 @@ fn trey_double(f:f64)->f64{ f64::from_bits(m|(e<<52)|(s<<63)) } -#[binrw] -#[brw(little)] -#[derive(Clone,Copy,Debug)] -pub enum Bool{ - #[brw(magic=0u32)] - False, - #[brw(magic=1u32)] - True, -} -impl Into for Bool{ - fn into(self)->bool{ - match self{ - Bool::False=>false, - Bool::True=>true, - } - } -} #[binrw] #[brw(little)] pub struct Vector2{ @@ -124,7 +107,9 @@ pub struct WorldEventSetTime{ #[binrw] #[brw(little)] pub struct WorldEventSetPaused{ - pub paused:Bool, + #[br(map=|paused:u32|paused!=0)] + #[bw(map=|paused:&bool|*paused as u32)] + pub paused:bool, #[brw(magic=b"quatdata")] __:(), } From 65cc20bdf99f07b3c6e0d82ff0c3f8c3cb904581 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Tue, 31 Dec 2024 16:56:48 -0800 Subject: [PATCH 15/31] one less step --- src/v1.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/v1.rs b/src/v1.rs index 621ba29..b341c0d 100644 --- a/src/v1.rs +++ b/src/v1.rs @@ -1,15 +1,13 @@ use binrw::{binrw,BinReaderExt,io::TakeSeekExt}; // the bit chunks are deposited in reverse -fn trey_float(f:f32)->f32{ - let bits=f.to_bits(); +fn trey_float(bits:u32)->f32{ let s=bits&1; let e=(bits>>1)&((1<<8)-1); let m=(bits>>(1+8))&((1<<23)-1); f32::from_bits(m|(e<<23)|(s<<31)) } -fn trey_double(f:f64)->f64{ - let bits=f.to_bits(); +fn trey_double(bits:u64)->f64{ let s=bits&1; let e=(bits>>1)&((1<<11)-1); let m=(bits>>(1+11))&((1<<52)-1); From dd8cf2544d67eeeb76e92f6182eee82994fd5df1 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Tue, 31 Dec 2024 16:56:55 -0800 Subject: [PATCH 16/31] rename functions --- src/v1.rs | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/v1.rs b/src/v1.rs index b341c0d..887caa3 100644 --- a/src/v1.rs +++ b/src/v1.rs @@ -1,13 +1,13 @@ use binrw::{binrw,BinReaderExt,io::TakeSeekExt}; // the bit chunks are deposited in reverse -fn trey_float(bits:u32)->f32{ +fn read_trey_float(bits:u32)->f32{ let s=bits&1; let e=(bits>>1)&((1<<8)-1); let m=(bits>>(1+8))&((1<<23)-1); f32::from_bits(m|(e<<23)|(s<<31)) } -fn trey_double(bits:u64)->f64{ +fn read_trey_double(bits:u64)->f64{ let s=bits&1; let e=(bits>>1)&((1<<11)-1); let m=(bits>>(1+11))&((1<<52)-1); @@ -17,19 +17,19 @@ fn trey_double(bits:u64)->f64{ #[binrw] #[brw(little)] pub struct Vector2{ - #[br(map=trey_float)] + #[br(map=read_trey_float)] pub x:f32, - #[br(map=trey_float)] + #[br(map=read_trey_float)] pub y:f32, } #[binrw] #[brw(little)] pub struct Vector3{ - #[br(map=trey_float)] + #[br(map=read_trey_float)] pub x:f32, - #[br(map=trey_float)] + #[br(map=read_trey_float)] pub y:f32, - #[br(map=trey_float)] + #[br(map=read_trey_float)] pub z:f32, } @@ -43,7 +43,7 @@ pub struct InputEvent{ #[binrw] #[brw(little)] pub struct TimedInputEvent{ - #[br(map=trey_double)] + #[br(map=read_trey_double)] pub time:f64, pub event:InputEvent, } @@ -61,7 +61,7 @@ pub struct OutputEvent{ #[binrw] #[brw(little)] pub struct TimedOutputEvent{ - #[br(map=trey_double)] + #[br(map=read_trey_double)] pub time:f64, pub event:OutputEvent, } @@ -76,7 +76,7 @@ pub struct SoundEvent{ #[binrw] #[brw(little)] pub struct TimedSoundEvent{ - #[br(map=trey_double)] + #[br(map=read_trey_double)] pub time:f64, pub event:SoundEvent, } @@ -97,7 +97,7 @@ pub struct WorldEventButton{ #[binrw] #[brw(little)] pub struct WorldEventSetTime{ - #[br(map=trey_double)] + #[br(map=read_trey_double)] pub time:f64, #[brw(magic=b"data")] __:(), @@ -126,7 +126,7 @@ pub enum WorldEvent{ #[binrw] #[brw(little)] pub struct TimedWorldEvent{ - #[br(map=trey_double)] + #[br(map=read_trey_double)] pub time:f64, pub event:WorldEvent, } @@ -140,7 +140,7 @@ pub struct GravityEvent{ #[binrw] #[brw(little)] pub struct TimedGravityEvent{ - #[br(map=trey_double)] + #[br(map=read_trey_double)] pub time:f64, pub event:GravityEvent, } @@ -174,7 +174,7 @@ pub struct RunEvent{ #[binrw] #[brw(little)] pub struct TimedRunEvent{ - #[br(map=trey_double)] + #[br(map=read_trey_double)] pub time:f64, pub event:RunEvent, } @@ -189,7 +189,7 @@ pub struct CameraEvent{ #[binrw] #[brw(little)] pub struct TimedCameraEvent{ - #[br(map=trey_double)] + #[br(map=read_trey_double)] pub time:f64, pub event:CameraEvent, } @@ -199,13 +199,13 @@ pub struct TimedCameraEvent{ #[brw(little)] pub struct SettingEvent{ pub setting_id:u32, - #[br(map=trey_double)] + #[br(map=read_trey_double)] pub value:f64, } #[binrw] #[brw(little)] pub struct TimedSettingEvent{ - #[br(map=trey_double)] + #[br(map=read_trey_double)] pub time:f64, pub event:SettingEvent, } @@ -305,7 +305,7 @@ pub struct BlockId(#[br(map=|i:u32|i-1)]u32); #[brw(little)] #[derive(Debug,Clone,Copy)] pub struct TimedBlockId{ - #[br(map=trey_double)] + #[br(map=read_trey_double)] pub time:f64, pub block_id:BlockId, } From 4a1e26e5be5212ebfc9992eb249138decbe2086d Mon Sep 17 00:00:00 2001 From: Quaternions Date: Tue, 31 Dec 2024 16:59:50 -0800 Subject: [PATCH 17/31] use padding instead of magic --- src/v1.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/v1.rs b/src/v1.rs index 887caa3..07bc82d 100644 --- a/src/v1.rs +++ b/src/v1.rs @@ -90,26 +90,23 @@ pub struct WorldEventReset{ #[binrw] #[brw(little)] pub struct WorldEventButton{ + #[br(pad_after=8)] pub button_id:u32, - #[brw(magic=b"quatdata")] - __:(), } #[binrw] #[brw(little)] pub struct WorldEventSetTime{ #[br(map=read_trey_double)] + #[br(pad_after=4)] pub time:f64, - #[brw(magic=b"data")] - __:(), } #[binrw] #[brw(little)] pub struct WorldEventSetPaused{ #[br(map=|paused:u32|paused!=0)] #[bw(map=|paused:&bool|*paused as u32)] + #[br(pad_after=8)] pub paused:bool, - #[brw(magic=b"quatdata")] - __:(), } #[binrw] #[brw(little)] From 38d106d008c789c07304ecb71abd6a7d1e411b34 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Tue, 31 Dec 2024 18:37:36 -0800 Subject: [PATCH 18/31] read_all --- src/v1.rs | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 98 insertions(+), 4 deletions(-) diff --git a/src/v1.rs b/src/v1.rs index 07bc82d..42a0567 100644 --- a/src/v1.rs +++ b/src/v1.rs @@ -249,8 +249,8 @@ struct EventChunkHeader{ // first time I've managed to write BinRead generics without this stupid T::Args<'a>:Required thing blocking me fn read_data_into_events<'a,R:BinReaderExt,T>(data:&mut R,events:&mut Vec,num_events:usize)->binrw::BinResult<()> where - T:binrw::BinRead, - T::Args<'a>:binrw::__private::Required, + T:binrw::BinRead, + T::Args<'a>:binrw::__private::Required, { // there is only supposed to be at most one of each type of event chunk per block, so no need to amortize. events.reserve_exact(num_events); @@ -259,10 +259,26 @@ where } Ok(()) } +fn read_data_into_events_amortized<'a,R:BinReaderExt,T>(data:&mut R,events:&mut Vec,num_events:usize)->binrw::BinResult<()> +where + T:binrw::BinRead, + T::Args<'a>:binrw::__private::Required, +{ + // this is used when reading multiple blocks into a single object, so amortize the allocation cost. + events.reserve(num_events); + for _ in 0..num_events{ + events.push(data.read_le()?); + } + Ok(()) +} impl Block{ - fn read(mut data:R)->binrw::BinResult{ + fn read(data:R)->binrw::BinResult{ let mut block=Block::default(); + Block::read_into(data,&mut block)?; + Ok(block) + } + fn read_into(mut data:R,block:&mut Block)->binrw::BinResult<()>{ // well... this looks error prone while let Ok(event_chunk_header)=data.read_le::(){ match event_chunk_header.event_type{ @@ -276,7 +292,23 @@ impl Block{ EventType::Setting=>read_data_into_events(&mut data,&mut block.setting_events,event_chunk_header.num_events as usize)?, } } - Ok(block) + Ok(()) + } + fn read_into_amortized(mut data:R,block:&mut Block)->binrw::BinResult<()>{ + // sad code duplication + while let Ok(event_chunk_header)=data.read_le::(){ + match event_chunk_header.event_type{ + EventType::Input=>read_data_into_events_amortized(&mut data,&mut block.input_events,event_chunk_header.num_events as usize)?, + EventType::Output=>read_data_into_events_amortized(&mut data,&mut block.output_events,event_chunk_header.num_events as usize)?, + EventType::Sound=>read_data_into_events_amortized(&mut data,&mut block.sound_events,event_chunk_header.num_events as usize)?, + EventType::World=>read_data_into_events_amortized(&mut data,&mut block.world_events,event_chunk_header.num_events as usize)?, + EventType::Gravity=>read_data_into_events_amortized(&mut data,&mut block.gravity_events,event_chunk_header.num_events as usize)?, + EventType::Run=>read_data_into_events_amortized(&mut data,&mut block.run_events,event_chunk_header.num_events as usize)?, + EventType::Camera=>read_data_into_events_amortized(&mut data,&mut block.camera_events,event_chunk_header.num_events as usize)?, + EventType::Setting=>read_data_into_events_amortized(&mut data,&mut block.setting_events,event_chunk_header.num_events as usize)?, + } + } + Ok(()) } } @@ -306,6 +338,16 @@ pub struct TimedBlockId{ pub time:f64, pub block_id:BlockId, } +impl PartialEq for TimedBlockId{ + fn eq(&self,other:&Self)->bool{ + self.time.eq(&other.time) + } +} +impl PartialOrd for TimedBlockId{ + fn partial_cmp(&self,other:&Self)->Option{ + self.time.partial_cmp(&other.time) + } +} #[binrw] #[brw(little)] @@ -337,6 +379,41 @@ impl FileHeader{ } } +struct MergeIter,It1:Iterator>{ + it0:It0, + it1:It1, + item0:Option, + item1:Option, +} +impl,It1:Iterator> MergeIter{ + fn new(mut it0:It0,mut it1:It1)->Self{ + Self{ + item0:it0.next(), + item1:it1.next(), + it0, + it1, + } + } +} +impl,It1:Iterator> Iterator for MergeIter{ + type Item=T; + fn next(&mut self)->Option{ + match (&self.item0,&self.item1){ + (None,None)=>None, + (Some(_),None)=>core::mem::replace(&mut self.item0,self.it0.next()), + (None,Some(_))=>core::mem::replace(&mut self.item1,self.it1.next()), + (Some(item0),Some(item1))=>match item0.partial_cmp(item1){ + Some(core::cmp::Ordering::Less) + |Some(core::cmp::Ordering::Equal) + |None + =>core::mem::replace(&mut self.item0,self.it0.next()), + Some(core::cmp::Ordering::Greater) + =>core::mem::replace(&mut self.item1,self.it1.next()), + }, + } + } +} + pub struct File{ pub header:FileHeader, pub data:FileData, @@ -348,6 +425,18 @@ impl File{ data:FileData{data}, }) } + pub fn read_all(&mut self)->Result{ + let block_iter=MergeIter::new( + self.header.offline_blocks_timeline.iter(), + self.header.realtime_blocks_timeline.iter(), + ); + let mut big_block=Block::default(); + for &TimedBlockId{time:_,block_id} in block_iter{ + let block_info=self.header.block_info(block_id)?; + self.data.read_block_info_into(block_info,&mut big_block)?; + } + Ok(big_block) + } } pub struct FileData{ @@ -366,4 +455,9 @@ impl FileData{ let block=Block::read(data).map_err(Error::InvalidData)?; Ok(block) } + pub fn read_block_info_into(&mut self,block_info:BlockInfo,block:&mut Block)->Result<(),Error>{ + let data=self.block_reader(block_info)?; + Block::read_into_amortized(data,block).map_err(Error::InvalidData)?; + Ok(()) + } } From 5177061ae5afe9eafb45a52996dbfc2629aa849a Mon Sep 17 00:00:00 2001 From: Quaternions Date: Tue, 31 Dec 2024 18:40:27 -0800 Subject: [PATCH 19/31] test read_all --- src/tests.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/tests.rs b/src/tests.rs index d9c1da7..fedd861 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -23,3 +23,14 @@ fn _1()->Result<(),crate::v1::Error>{ Ok(()) } + +#[test] +fn _2()->Result<(),crate::v1::Error>{ + let file=std::fs::File::open("files/bhop_marble_7cf33a64-7120-4514-b9fa-4fe29d9523d").unwrap(); + let input=std::io::BufReader::new(file); + let mut bot_file=crate::v1::File::new(input).unwrap(); + + let block=bot_file.read_all()?; + + Ok(()) +} From 942e5ee1d8ed7db08c3a7d63ca05d447355a50f9 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Tue, 31 Dec 2024 18:42:02 -0800 Subject: [PATCH 20/31] update example --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 918eba2..ebdf7a7 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,11 @@ use strafesnet_roblox_bot_file::{File,TimedBlockId}; let file=std::fs::File::open("bot_file")?; let input=std::io::BufReader::new(file); let mut bot_file=File::new(input)?; + +// read the whole file +let block=bot_file.read_all()?; + +// or do data streaming block by block for &TimedBlockId{time,block_id} in &bot_file.header.offline_blocks_timeline{ // header is immutably borrowed // while data is mutably borrowed From 5b58efe05261d9c11c72894816feb3d55b4ccacc Mon Sep 17 00:00:00 2001 From: Quaternions Date: Tue, 31 Dec 2024 19:07:00 -0800 Subject: [PATCH 21/31] fix 1-indexed block positions --- src/v1.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/v1.rs b/src/v1.rs index 42a0567..60b71fe 100644 --- a/src/v1.rs +++ b/src/v1.rs @@ -329,6 +329,10 @@ impl std::error::Error for Error{} #[brw(little)] #[derive(Debug,Clone,Copy)] pub struct BlockId(#[br(map=|i:u32|i-1)]u32); +#[binrw] +#[brw(little)] +#[derive(Debug,Clone,Copy)] +pub struct BlockPosition(#[br(map=|i:u32|i-1)]u32); #[binrw] #[brw(little)] @@ -358,7 +362,7 @@ pub struct FileHeader{ pub num_offline_events:u32, pub num_realtime_events:u32, #[br(count=num_offline_events+num_realtime_events+1)] - pub block_positions:Vec, + pub block_positions:Vec, #[br(count=num_offline_events)] pub offline_blocks_timeline:Vec, #[br(count=num_realtime_events)] @@ -373,8 +377,8 @@ impl FileHeader{ if self.block_positions.len() as u32<=block_id.0{ return Err(Error::InvalidBlockId(block_id)); } - let start=self.block_positions[block_id.0 as usize]; - let end=self.block_positions[block_id.0 as usize+1]; + let start=self.block_positions[block_id.0 as usize].0; + let end=self.block_positions[block_id.0 as usize+1].0; Ok(BlockInfo{start,length:end-start}) } } From 301b4681804673e094d2edd955d57c3c373aa655 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Tue, 31 Dec 2024 21:18:29 -0800 Subject: [PATCH 22/31] ignore test files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index ea8c4bf..51124b9 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +/files From 53bde2bc3f1af11e68e0566c389f4c8cefde43b8 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Tue, 31 Dec 2024 21:33:48 -0800 Subject: [PATCH 23/31] test time --- src/tests.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/tests.rs b/src/tests.rs index fedd861..b030ef4 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -28,9 +28,14 @@ fn _1()->Result<(),crate::v1::Error>{ fn _2()->Result<(),crate::v1::Error>{ let file=std::fs::File::open("files/bhop_marble_7cf33a64-7120-4514-b9fa-4fe29d9523d").unwrap(); let input=std::io::BufReader::new(file); + + let t0=std::time::Instant::now(); + let mut bot_file=crate::v1::File::new(input).unwrap(); let block=bot_file.read_all()?; + println!("{:?}",t0.elapsed()); + Ok(()) } From a78be6b79ab792c3e2471967809c2e8b2d2e784f Mon Sep 17 00:00:00 2001 From: Quaternions Date: Tue, 31 Dec 2024 21:50:20 -0800 Subject: [PATCH 24/31] rename symbol --- src/v1.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/v1.rs b/src/v1.rs index 60b71fe..8600e76 100644 --- a/src/v1.rs +++ b/src/v1.rs @@ -437,7 +437,7 @@ impl File{ let mut big_block=Block::default(); for &TimedBlockId{time:_,block_id} in block_iter{ let block_info=self.header.block_info(block_id)?; - self.data.read_block_info_into(block_info,&mut big_block)?; + self.data.read_block_info_into_block(block_info,&mut big_block)?; } Ok(big_block) } @@ -459,7 +459,7 @@ impl FileData{ let block=Block::read(data).map_err(Error::InvalidData)?; Ok(block) } - pub fn read_block_info_into(&mut self,block_info:BlockInfo,block:&mut Block)->Result<(),Error>{ + pub fn read_block_info_into_block(&mut self,block_info:BlockInfo,block:&mut Block)->Result<(),Error>{ let data=self.block_reader(block_info)?; Block::read_into_amortized(data,block).map_err(Error::InvalidData)?; Ok(()) From 9f0505cdc9edefb71aadeca8e41b65c8a0e2d6e9 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Tue, 31 Dec 2024 22:17:09 -0800 Subject: [PATCH 25/31] expand on id types with enums --- src/v1.rs | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 89 insertions(+), 5 deletions(-) diff --git a/src/v1.rs b/src/v1.rs index 8600e76..762c0af 100644 --- a/src/v1.rs +++ b/src/v1.rs @@ -69,8 +69,29 @@ pub struct TimedOutputEvent{ // sound #[binrw] #[brw(little)] +pub enum SoundType{ + #[brw(magic=101u32)] + TrackGround, + #[brw(magic=102u32)] + TrackLadder, + #[brw(magic=103u32)] + TrackWater, + #[brw(magic=104u32)] + TrackAir, + #[brw(magic=201u32)] + JumpGround, + #[brw(magic=202u32)] + JumpLadder, + #[brw(magic=301u32)] + SmashGround, + #[brw(magic=302u32)] + SmashWall, +} +#[binrw] +#[brw(little)] pub struct SoundEvent{ - pub sound_type:u32, + pub sound_type:SoundType, + /// Roblox enum pub material:u32, } #[binrw] @@ -163,10 +184,51 @@ pub enum RunEventType{ } #[binrw] #[brw(little)] +pub enum Mode{ + #[brw(magic=0i32)] + Main, + #[brw(magic=1i32)] + Bonus, + #[brw(magic=-1i32)] + All, + #[brw(magic=-2i32)] + Invalid, + #[brw(magic=-3i32)] + InProgress, +} +#[binrw] +#[brw(little)] +pub enum FlagReason{ + #[brw(magic=0u32)] + Anticheat, + #[brw(magic=1u32)] + StyleChange, + #[brw(magic=2u32)] + Clock, + #[brw(magic=3u32)] + Pause, + #[brw(magic=4u32)] + Flying, + #[brw(magic=5u32)] + Gravity, + #[brw(magic=6u32)] + Timescale, + #[brw(magic=7u32)] + Timetravel, + #[brw(magic=8u32)] + Teleport, + #[brw(magic=9u32)] + Practice, + // b"data" + #[brw(magic=1635017060u32)] + None, +} +#[binrw] +#[brw(little)] pub struct RunEvent{ run_event_type:RunEventType, - mode_id:i32, - flag_reason_id:u32, + mode:Mode, + flag_reason:FlagReason, } #[binrw] #[brw(little)] @@ -179,8 +241,16 @@ pub struct TimedRunEvent{ // camera #[binrw] #[brw(little)] +pub enum CameraEventType{ + #[brw(magic=0u32)] + CameraPunch, + #[brw(magic=1u32)] + Transform, +} +#[binrw] +#[brw(little)] pub struct CameraEvent{ - pub camera_event_id:u32, + pub camera_event_type:CameraEventType, pub value:Vector3, } #[binrw] @@ -194,8 +264,22 @@ pub struct TimedCameraEvent{ // setting #[binrw] #[brw(little)] +pub enum SettingType{ + #[brw(magic=0u32)] + FieldOfView, + #[brw(magic=1u32)] + Sensitivity, + #[brw(magic=2u32)] + VerticalSensitivityMultiplier, + #[brw(magic=3u32)] + AbsoluteSensitivity, + #[brw(magic=4u32)] + TurnSpeed, +} +#[binrw] +#[brw(little)] pub struct SettingEvent{ - pub setting_id:u32, + pub setting_type:SettingType, #[br(map=read_trey_double)] pub value:f64, } From f7f937aa67a318d4db1baa8c505587e0251eaa92 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Tue, 31 Dec 2024 22:32:21 -0800 Subject: [PATCH 26/31] bitflags dep --- Cargo.lock | 7 +++++++ Cargo.toml | 1 + 2 files changed, 8 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 4e57f40..2408728 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,6 +32,12 @@ dependencies = [ "syn", ] +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + [[package]] name = "bytemuck" version = "1.21.0" @@ -73,6 +79,7 @@ name = "strafesnet_roblox_bot_file" version = "0.1.0" dependencies = [ "binrw", + "bitflags", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 4f209b1..afd8180 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,3 +5,4 @@ edition = "2021" [dependencies] binrw = "0.14.1" +bitflags = "2.6.0" From 728d13080f50f5c740c15f4ad4d0b7ed173f5450 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Tue, 31 Dec 2024 22:33:14 -0800 Subject: [PATCH 27/31] bitflags --- src/v1.rs | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/src/v1.rs b/src/v1.rs index 762c0af..d839554 100644 --- a/src/v1.rs +++ b/src/v1.rs @@ -33,11 +33,48 @@ pub struct Vector3{ pub z:f32, } +bitflags::bitflags!{ + pub struct GameControls:u32{ + const MoveForward=1<<0; + const MoveLeft=1<<1; + const MoveBack=1<<2; + const MoveRight=1<<3; + const MoveUp=1<<4; + const MoveDown=1<<5; + const LookUp=1<<6; + const LookLeft=1<<7; + const LookDown=1<<8; + const LookRight=1<<9; + const Jump=1<<10; + const Crouch=1<<11; + const Sprint=1<<12; + const Zoom=1<<13; + const Use=1<<14; + const Action1=1<<15; + const Action2=1<<16; + } +} +#[derive(Debug)] +pub struct GameControlsError; +impl std::fmt::Display for GameControlsError{ + fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{ + write!(f,"{self:?}") + } +} +impl std::error::Error for GameControlsError{} +impl GameControls{ + fn try_from_bits(bits:u32)->Result{ + Self::from_bits(bits).ok_or(GameControlsError) + } +} + // input #[binrw] #[brw(little)] pub struct InputEvent{ - pub game_controls:u32, + #[br(try_map=GameControls::try_from_bits)] + #[bw(map=GameControls::bits)] + pub game_controls:GameControls, pub mouse_pos:Vector2, } #[binrw] @@ -49,10 +86,33 @@ pub struct TimedInputEvent{ } // output +bitflags::bitflags!{ + pub struct TickInfo:u32{ + const TickEnd=1<<0; + const Jump=1<<1; + const Strafe=1<<2; + const Touching=1<<3; + } +} +#[derive(Debug)] +pub struct TickInfoError; +impl std::fmt::Display for TickInfoError{ + fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{ + write!(f,"{self:?}") + } +} +impl std::error::Error for TickInfoError{} +impl TickInfo{ + fn try_from_bits(bits:u32)->Result{ + Self::from_bits(bits).ok_or(TickInfoError) + } +} #[binrw] #[brw(little)] pub struct OutputEvent{ - pub tick_info:u32, + #[br(try_map=TickInfo::try_from_bits)] + #[bw(map=TickInfo::bits)] + pub tick_info:TickInfo, pub angles:Vector3, pub position:Vector3, pub velocity:Vector3, From 79c12b1af12bb9cb340bb8b152d2ebba78513bd1 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Tue, 31 Dec 2024 22:48:40 -0800 Subject: [PATCH 28/31] pub typo --- src/v1.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/v1.rs b/src/v1.rs index d839554..f448d70 100644 --- a/src/v1.rs +++ b/src/v1.rs @@ -286,9 +286,9 @@ pub enum FlagReason{ #[binrw] #[brw(little)] pub struct RunEvent{ - run_event_type:RunEventType, - mode:Mode, - flag_reason:FlagReason, + pub run_event_type:RunEventType, + pub mode:Mode, + pub flag_reason:FlagReason, } #[binrw] #[brw(little)] From 08269a2d3f6ecd381710a5b6f29c75926a082506 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Tue, 31 Dec 2024 22:50:14 -0800 Subject: [PATCH 29/31] version typo --- src/lib.rs | 2 +- src/tests.rs | 10 +++++----- src/{v1.rs => v0.rs} | 0 3 files changed, 6 insertions(+), 6 deletions(-) rename src/{v1.rs => v0.rs} (100%) diff --git a/src/lib.rs b/src/lib.rs index d80700a..cc08a0d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -pub mod v1; +pub mod v0; #[cfg(test)] mod tests; diff --git a/src/tests.rs b/src/tests.rs index b030ef4..d1d3f84 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,10 +1,10 @@ -use crate::v1::TimedBlockId; +use crate::v0::TimedBlockId; #[test] -fn _1()->Result<(),crate::v1::Error>{ +fn _1()->Result<(),crate::v0::Error>{ let file=std::fs::File::open("files/bhop_marble_7cf33a64-7120-4514-b9fa-4fe29d9523d").unwrap(); let input=std::io::BufReader::new(file); - let mut bot_file=crate::v1::File::new(input).unwrap(); + let mut bot_file=crate::v0::File::new(input).unwrap(); println!("header={:?}",bot_file.header); for &TimedBlockId{time,block_id} in &bot_file.header.offline_blocks_timeline{ println!("offline time={} block_id={:?}",time,block_id); @@ -25,13 +25,13 @@ fn _1()->Result<(),crate::v1::Error>{ } #[test] -fn _2()->Result<(),crate::v1::Error>{ +fn _2()->Result<(),crate::v0::Error>{ let file=std::fs::File::open("files/bhop_marble_7cf33a64-7120-4514-b9fa-4fe29d9523d").unwrap(); let input=std::io::BufReader::new(file); let t0=std::time::Instant::now(); - let mut bot_file=crate::v1::File::new(input).unwrap(); + let mut bot_file=crate::v0::File::new(input).unwrap(); let block=bot_file.read_all()?; diff --git a/src/v1.rs b/src/v0.rs similarity index 100% rename from src/v1.rs rename to src/v0.rs From 0f448fd707b2d98c4611b8fb348a0f330dd0b04c Mon Sep 17 00:00:00 2001 From: Quaternions Date: Tue, 31 Dec 2024 22:50:24 -0800 Subject: [PATCH 30/31] v0.2.0 fixes --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2408728..42ad11c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -76,7 +76,7 @@ dependencies = [ [[package]] name = "strafesnet_roblox_bot_file" -version = "0.1.0" +version = "0.2.0" dependencies = [ "binrw", "bitflags", diff --git a/Cargo.toml b/Cargo.toml index afd8180..90803cf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "strafesnet_roblox_bot_file" -version = "0.1.0" +version = "0.2.0" edition = "2021" [dependencies] From ea98660f01b972acc1e63978174cbe0808c953ab Mon Sep 17 00:00:00 2001 From: Quaternions Date: Thu, 2 Jan 2025 19:56:29 -0800 Subject: [PATCH 31/31] roblox_bot_file: move into folder --- .gitignore => lib/roblox_bot_file/.gitignore | 0 Cargo.lock => lib/roblox_bot_file/Cargo.lock | 0 Cargo.toml => lib/roblox_bot_file/Cargo.toml | 0 LICENSE-APACHE => lib/roblox_bot_file/LICENSE-APACHE | 0 LICENSE-MIT => lib/roblox_bot_file/LICENSE-MIT | 0 README.md => lib/roblox_bot_file/README.md | 0 {src => lib/roblox_bot_file/src}/lib.rs | 0 {src => lib/roblox_bot_file/src}/tests.rs | 0 {src => lib/roblox_bot_file/src}/v0.rs | 0 9 files changed, 0 insertions(+), 0 deletions(-) rename .gitignore => lib/roblox_bot_file/.gitignore (100%) rename Cargo.lock => lib/roblox_bot_file/Cargo.lock (100%) rename Cargo.toml => lib/roblox_bot_file/Cargo.toml (100%) rename LICENSE-APACHE => lib/roblox_bot_file/LICENSE-APACHE (100%) rename LICENSE-MIT => lib/roblox_bot_file/LICENSE-MIT (100%) rename README.md => lib/roblox_bot_file/README.md (100%) rename {src => lib/roblox_bot_file/src}/lib.rs (100%) rename {src => lib/roblox_bot_file/src}/tests.rs (100%) rename {src => lib/roblox_bot_file/src}/v0.rs (100%) diff --git a/.gitignore b/lib/roblox_bot_file/.gitignore similarity index 100% rename from .gitignore rename to lib/roblox_bot_file/.gitignore diff --git a/Cargo.lock b/lib/roblox_bot_file/Cargo.lock similarity index 100% rename from Cargo.lock rename to lib/roblox_bot_file/Cargo.lock diff --git a/Cargo.toml b/lib/roblox_bot_file/Cargo.toml similarity index 100% rename from Cargo.toml rename to lib/roblox_bot_file/Cargo.toml diff --git a/LICENSE-APACHE b/lib/roblox_bot_file/LICENSE-APACHE similarity index 100% rename from LICENSE-APACHE rename to lib/roblox_bot_file/LICENSE-APACHE diff --git a/LICENSE-MIT b/lib/roblox_bot_file/LICENSE-MIT similarity index 100% rename from LICENSE-MIT rename to lib/roblox_bot_file/LICENSE-MIT diff --git a/README.md b/lib/roblox_bot_file/README.md similarity index 100% rename from README.md rename to lib/roblox_bot_file/README.md diff --git a/src/lib.rs b/lib/roblox_bot_file/src/lib.rs similarity index 100% rename from src/lib.rs rename to lib/roblox_bot_file/src/lib.rs diff --git a/src/tests.rs b/lib/roblox_bot_file/src/tests.rs similarity index 100% rename from src/tests.rs rename to lib/roblox_bot_file/src/tests.rs diff --git a/src/v0.rs b/lib/roblox_bot_file/src/v0.rs similarity index 100% rename from src/v0.rs rename to lib/roblox_bot_file/src/v0.rs