1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
//! Utilities for [RuneScape] cache interaction. //! //! # Features //! //! The following features are currently provided: //! - Reading from the cache. //! - Huffman buffer access. //! - Checksum with simple-to-use validation. //! - Compression and decompression: //! - [Gzip] //! - [Bzip2] //! //! # Quick Start //! //! A possible use case of this utility is to read data from the RuneScape cache and send them to the //! client during the update protocol. //! The example listed below quickly shows how you can pass the `index_id` and the `archive_id` to the cache //! and get the correct data to send to the client. //! //! ``` //! # use std::net::TcpStream; //! # use std::io::Write; //! use rscache::{ Cache, CacheError, LinkedListExt }; //! # struct UpdatePacket { //! # pub index_id: u8, //! # pub archive_id: u16 //! # } //! //! fn process_update(packet: UpdatePacket, stream: &mut TcpStream) -> Result<(), CacheError> { //! # let cache = Cache::new("path/to/cache")?; //! // read the specified archive from the given index to an owned vector. //! let buffer = cache.read(packet.index_id, packet.archive_id)?.to_vec(); //! //! // ... format buffer. //! # let formatted_buffer = buffer; //! //! // send formatted_buffer to client. //! stream.write_all(&formatted_buffer)?; //! //! Ok(()) //! } //! ``` //! //! In the above example the data that was read from the cache is transformed into a vector of bytes. //! You can also use the `LinkedList<&[u8]>` to `iter()` over the `data_block`s instead of making the bytes owned. //! //! ``` //! # use std::net::TcpStream; //! # use std::io::Write; //! # use rscache::{ Cache, CacheError, LinkedListExt }; //! # struct UpdatePacket { //! # pub index_id: u8, //! # pub archive_id: u16 //! # } //! # fn process_update(packet: UpdatePacket, stream: &mut TcpStream) -> Result<(), CacheError> { //! # let cache = Cache::new("path/to/cache")?; //! # // read the specified archive from the given index to an owned vector. //! let buffer = cache.read(packet.index_id, packet.archive_id)?; //! //! for data_block in buffer.iter() { //! // data_block contains 512 byte slices that directly link into the MainData buffer. //! // this can be useful when creating a new formatted buffer. //! } //! # Ok(()) //! # } //! ``` //! //! # Definitions //! //! Currently only item definitions are supported. //! These definitions are fields that can be looked up for a certain item id. //! i.e. you need to know if a certain item is stackable or members only the [ItemDefinition](struct.ItemDefinition.html) struct //! contains that information. //! //! See the [ItemDefinition](struct.ItemDefinition.html) struct to view the available fields each item might have. //! //! ### Example //! //! ``` //! # use rscache::{ Cache, CacheError }; //! use rscache::ItemLoader; //! //! # fn main() -> Result<(), CacheError> { //! # let path = "./data/cache"; //! # let cache = Cache::new(path)?; //! let item_loader = ItemLoader::new(&cache)?; //! //! // magic logs id = 1513 //! let magic_logs = item_loader.load(1513); //! //! match magic_logs { //! Some(item_def) => { //! assert_eq!("Magic logs", item_def.name); //! assert_eq!(false, item_def.stackable); //! assert_eq!(true, item_def.members_only); //! }, //! None => (), //! } //! # Ok(()) //! # } //! ``` //! //! [RuneScape]: https://oldschool.runescape.com/ //! [Gzip]: https://crates.io/crates/libflate //! [Bzip2]: https://crates.io/crates/bzip2 #![warn(clippy::all, clippy::nursery, clippy::clone_on_ref_ptr, clippy::redundant_clone, clippy::default_trait_access, clippy::expl_impl_clone_on_copy, clippy::explicit_into_iter_loop, clippy::explicit_iter_loop, clippy::filter_map, clippy::filter_map_next, clippy::find_map, clippy::get_unwrap, clippy::items_after_statements, clippy::large_digit_groups, clippy::map_flatten, clippy::match_same_arms, clippy::maybe_infinite_iter, clippy::mem_forget, clippy::missing_inline_in_public_items, clippy::multiple_inherent_impl, clippy::mut_mut, clippy::needless_continue, clippy::needless_pass_by_value, clippy::option_map_unwrap_or, clippy::option_map_unwrap_or_else, clippy::pub_enum_variant_names, clippy::unused_self, clippy::result_map_unwrap_or_else, clippy::similar_names, clippy::single_match_else, clippy::too_many_lines, clippy::type_repetition_in_bounds, clippy::unseparated_literal_suffix, clippy::used_underscore_binding)] #![allow(clippy::suspicious_else_formatting)] mod cache; mod checksum; mod errors; mod traits; mod definitions; pub mod codec; pub use cache::Cache; pub use checksum::Checksum; pub use errors::*; pub use traits::*; pub use definitions::*; mod djd2 { #[inline] pub fn hash(string: &str) -> i32 { let mut hash = 0; for index in 0..string.len() { hash = string.chars().nth(index).unwrap() as i32 + ((hash << 5) - hash); } hash } }