Compare commits
No commits in common. "be729aa533bb0e702e3cc5eab7e9287307de927b" and "af1e423b56af4d24d517025e20e1f4b2dd58062b" have entirely different histories.
be729aa533
...
af1e423b56
10 changed files with 24 additions and 275 deletions
35
Cargo.lock
generated
35
Cargo.lock
generated
|
@ -2,12 +2,6 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.0.4"
|
||||
|
@ -181,15 +175,6 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
|
@ -352,16 +337,6 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
|
@ -440,7 +415,6 @@ dependencies = [
|
|||
"base64",
|
||||
"diesel",
|
||||
"dotenvy",
|
||||
"flate2",
|
||||
"maplit",
|
||||
"password-auth",
|
||||
"regex",
|
||||
|
@ -716,15 +690,6 @@ version = "0.3.17"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
|
||||
dependencies = [
|
||||
"adler",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.8.6"
|
||||
|
|
|
@ -5,9 +5,8 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
base64 = "0.21.3"
|
||||
diesel = { version = "=2.1.0", features = ["postgres", "64-column-tables"] }
|
||||
diesel = { version = "=2.1.0", features = ["postgres"] }
|
||||
dotenvy = "0.15.7"
|
||||
flate2 = "1.0.27"
|
||||
maplit = "1.0.2"
|
||||
password-auth = "0.3.0"
|
||||
regex = "1.9.4"
|
||||
|
|
|
@ -20,8 +20,4 @@ allow_registration = true
|
|||
|
||||
[db]
|
||||
# path for your data to be stored
|
||||
data_folder = "data"
|
||||
|
||||
[levels]
|
||||
# object ids to block
|
||||
blocklist = [ 31 ] # start position
|
||||
data_folder = "data"
|
|
@ -24,12 +24,11 @@ CREATE TABLE levels (
|
|||
|
||||
song_id INTEGER NOT NULL,
|
||||
|
||||
length INTEGER NOT NULL,
|
||||
length_real DOUBLE PRECISION NOT NULL,
|
||||
objects INTEGER NOT NULL,
|
||||
coins INTEGER NOT NULL DEFAULT 0,
|
||||
has_ldm INTEGER NOT NULL DEFAULT 0,
|
||||
two_player INTEGER NOT NULL DEFAULT 0,
|
||||
length INTEGER NOT NULL,
|
||||
objects INTEGER NOT NULL,
|
||||
coins INTEGER NOT NULL DEFAULT 0,
|
||||
has_ldm INTEGER NOT NULL DEFAULT 0,
|
||||
two_player INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
downloads INTEGER NOT NULL DEFAULT 0,
|
||||
likes INTEGER NOT NULL DEFAULT 0,
|
||||
|
|
|
@ -34,8 +34,8 @@ _these features are implemented_
|
|||
|
||||
## todo
|
||||
|
||||
- swap to chrono instead of `(TO_CHAR(CURRENT_TIMESTAMP, 'YYYY-MM-DD HH24:MI:SS.MS'))` (thats REALLY ugly!!)
|
||||
- patch `upload_level` to use 2.2 unlisted (friends only stuff)
|
||||
- in our level parsing, check for dual portals rather than just starting dual
|
||||
- <small>green name users...</small>
|
||||
- maybe tone down the clone usage (this is for sure causing memory problems 😉)
|
||||
- patch uploadlevel to use 2.2 unlisted(honsetly idk what this is)
|
||||
- clean up uploadlevel
|
||||
- add level parsing
|
||||
- maybe swap to chrono instead of `(TO_CHAR(CURRENT_TIMESTAMP, 'YYYY-MM-DD HH24:MI:SS.MS'))` (thats REALLY ugly!!)
|
|
@ -6,8 +6,7 @@ use std::sync::LazyLock;
|
|||
pub struct Config {
|
||||
pub general: ConfigGeneral,
|
||||
pub accounts: ConfigAccounts,
|
||||
pub db: ConfigDB,
|
||||
pub levels: ConfigLevels
|
||||
pub db: ConfigDB
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
|
@ -26,11 +25,6 @@ pub struct ConfigDB {
|
|||
pub data_folder: String
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct ConfigLevels {
|
||||
pub blocklist: Vec<i32>
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn load_from_file(file_path: &str) -> Self {
|
||||
let toml_str = fs::read_to_string(file_path).expect("Error finding toml config:");
|
||||
|
|
|
@ -108,7 +108,6 @@ pub struct Level {
|
|||
pub editor_time_copies: i32,
|
||||
pub song_id: i32,
|
||||
pub length: i32,
|
||||
pub length_real: f64,
|
||||
pub objects: i32,
|
||||
pub coins: i32,
|
||||
pub has_ldm: i32,
|
||||
|
@ -143,7 +142,6 @@ pub struct NewLevel {
|
|||
pub editor_time_copies: i32,
|
||||
pub song_id: i32,
|
||||
pub length: i32,
|
||||
pub length_real: f64,
|
||||
pub objects: i32,
|
||||
pub coins: i32,
|
||||
pub has_ldm: i32,
|
||||
|
|
|
@ -46,7 +46,6 @@ diesel::table! {
|
|||
editor_time_copies -> Int4,
|
||||
song_id -> Int4,
|
||||
length -> Int4,
|
||||
length_real -> Float8,
|
||||
objects -> Int4,
|
||||
coins -> Int4,
|
||||
has_ldm -> Int4,
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use password_auth::verify_password;
|
||||
use rocket::form::Form;
|
||||
use rocket::http::Status;
|
||||
use rocket::response::status;
|
||||
|
@ -73,35 +74,7 @@ pub fn upload_level(input: Form<FormUploadLevel>) -> status::Custom<&'static str
|
|||
None => { extra_string = helpers::levels::DEFAULT_EXTRA_STRING.to_owned() }
|
||||
}
|
||||
|
||||
// level parsing
|
||||
let level_raw_objects = helpers::levels::decode(input.levelString.clone());
|
||||
let level_objects = helpers::levels::to_objectdata(level_raw_objects.clone());
|
||||
let inner_level_string = level_raw_objects
|
||||
.iter()
|
||||
.find(|obj| !obj.contains_key("1") && obj.get("kA9") == Some(&"0".to_string()))
|
||||
.expect("couldnt decode inner level string");
|
||||
|
||||
let level_length_secs = helpers::levels::measure_length(
|
||||
level_objects.clone(),
|
||||
inner_level_string.get("kA4").unwrap_or(&String::from("0")).parse::<i32>().expect("kA4 not int")
|
||||
);
|
||||
|
||||
let coins_val = level_objects.iter().filter(|obj| obj.id() == 1329).count(); // 1329 is coin id
|
||||
let objects_val = level_objects.len();
|
||||
let two_player_val = if inner_level_string.get("kA10").unwrap_or(&String::from("0")).parse::<i32>().expect("kA10 not int") == 1 { 1 } else { 0 };
|
||||
let level_length_val = helpers::levels::secs_to_time(level_length_secs);
|
||||
|
||||
// blocking coins
|
||||
if coins_val > 3 {
|
||||
return status::Custom(Status::Ok, "-1")
|
||||
}
|
||||
|
||||
// forbidden object checking
|
||||
if let Some(_forbidden_object) = level_objects.iter().find(|obj| crate::CONFIG.levels.blocklist.contains(&obj.id())) {
|
||||
return status::Custom(Status::Ok, "-1")
|
||||
}
|
||||
|
||||
// data base 🤣😁
|
||||
// db shit
|
||||
use crate::models::{Level, NewLevel};
|
||||
|
||||
{
|
||||
|
@ -138,11 +111,11 @@ pub fn upload_level(input: Form<FormUploadLevel>) -> status::Custom<&'static str
|
|||
editor_time.eq(input.wt.unwrap_or(0)),
|
||||
editor_time_copies.eq(input.wt2.unwrap_or(0)),
|
||||
song_id.eq(song_id_val),
|
||||
length.eq(level_length_val),
|
||||
objects.eq(objects_val as i32),
|
||||
coins.eq(coins_val as i32),
|
||||
length.eq(0), // unimplemeneted
|
||||
objects.eq(0), // unimplemented
|
||||
coins.eq(0), // unimplemented
|
||||
has_ldm.eq(input.ldm.unwrap_or(0)),
|
||||
two_player.eq(two_player_val)
|
||||
two_player.eq(0) // unimplemented
|
||||
))
|
||||
.get_result::<Level, >(connection)
|
||||
.expect("failed to update level");
|
||||
|
@ -171,12 +144,11 @@ pub fn upload_level(input: Form<FormUploadLevel>) -> status::Custom<&'static str
|
|||
editor_time: input.wt.unwrap_or(0),
|
||||
editor_time_copies: input.wt2.unwrap_or(0),
|
||||
song_id: song_id_val,
|
||||
length: level_length_val,
|
||||
length_real: level_length_secs,
|
||||
objects: objects_val as i32,
|
||||
coins: coins_val as i32,
|
||||
length: 0, // not implemeneted
|
||||
objects: 0, // not implemeneted
|
||||
coins: 0, // not implemeneted
|
||||
has_ldm: input.ldm.unwrap_or(0),
|
||||
two_player: two_player_val
|
||||
two_player: 0 // not implemented
|
||||
};
|
||||
|
||||
let inserted_level = diesel::insert_into(levels)
|
||||
|
|
|
@ -1,180 +1,7 @@
|
|||
use std::sync::LazyLock;
|
||||
use std::io::prelude::*;
|
||||
|
||||
use base64::{Engine as _, engine::general_purpose};
|
||||
|
||||
use flate2::read::GzDecoder;
|
||||
|
||||
pub static DEFAULT_EXTRA_STRING: LazyLock<String> = LazyLock::new(|| {
|
||||
let string = String::from("29_29_29_40_29_29_29_29_29_29_29_29_29_29_29_29");
|
||||
|
||||
|
||||
return string;
|
||||
});
|
||||
|
||||
macro_rules! object_prop_bool {
|
||||
($key:expr, $name:ident) => {
|
||||
pub fn $name(&self) -> bool {
|
||||
self.raw.get($key).map_or(false, |value| value == "1")
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ObjectData {
|
||||
raw: HashMap<String, String>
|
||||
}
|
||||
|
||||
impl ObjectData {
|
||||
pub fn new(raw: HashMap<String, String>) -> Self {
|
||||
ObjectData { raw }
|
||||
}
|
||||
|
||||
pub fn id(&self) -> i32 {
|
||||
self.raw.get("1").unwrap_or(&String::new()).parse().unwrap_or(0)
|
||||
}
|
||||
|
||||
pub fn x(&self) -> f64 {
|
||||
self.raw.get("2").unwrap_or(&String::new()).parse().unwrap_or(0.0)
|
||||
}
|
||||
|
||||
pub fn y(&self) -> f64 {
|
||||
self.raw.get("3").unwrap_or(&String::new()).parse().unwrap_or(0.0)
|
||||
}
|
||||
|
||||
object_prop_bool!("13", checked);
|
||||
}
|
||||
|
||||
pub mod portal_speed {
|
||||
pub enum PortalSpeed {
|
||||
Slow,
|
||||
Normal,
|
||||
Medium,
|
||||
Fast,
|
||||
VeryFast
|
||||
}
|
||||
|
||||
impl PortalSpeed {
|
||||
pub fn portal_speed(&self) -> f64 {
|
||||
match self {
|
||||
PortalSpeed::Slow => 251.16,
|
||||
PortalSpeed::Normal => 311.58,
|
||||
PortalSpeed::Medium => 387.42,
|
||||
PortalSpeed::Fast => 478.0,
|
||||
PortalSpeed::VeryFast => 576.0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn id_to_portal_speed(id: i32) -> Option<portal_speed::PortalSpeed> {
|
||||
match id {
|
||||
200 => Some(portal_speed::PortalSpeed::Slow),
|
||||
201 => Some(portal_speed::PortalSpeed::Normal),
|
||||
202 => Some(portal_speed::PortalSpeed::Medium),
|
||||
203 => Some(portal_speed::PortalSpeed::Fast),
|
||||
1334 => Some(portal_speed::PortalSpeed::VeryFast),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_seconds_from_xpos(pos: f64, start_speed: portal_speed::PortalSpeed, portals: Vec<ObjectData>) -> f64 {
|
||||
let mut speed;
|
||||
let mut last_obj_pos = 0.0;
|
||||
let mut last_segment = 0.0;
|
||||
let mut segments = 0.0;
|
||||
|
||||
speed = start_speed.portal_speed();
|
||||
|
||||
if portals.is_empty() {
|
||||
return pos / speed
|
||||
}
|
||||
|
||||
for portal in portals {
|
||||
let mut s = portal.x() - last_obj_pos;
|
||||
|
||||
if pos < s {
|
||||
s = s / speed;
|
||||
last_segment = s;
|
||||
segments += s;
|
||||
|
||||
speed = id_to_portal_speed(portal.id()).expect("not a portal").portal_speed();
|
||||
|
||||
last_obj_pos = portal.x()
|
||||
}
|
||||
}
|
||||
|
||||
return ((pos - last_segment) / speed) + segments;
|
||||
}
|
||||
|
||||
pub fn measure_length(objects: Vec<ObjectData>, ka4: i32) -> f64 {
|
||||
let start_speed = match ka4 {
|
||||
0 => portal_speed::PortalSpeed::Normal,
|
||||
1 => portal_speed::PortalSpeed::Slow,
|
||||
2 => portal_speed::PortalSpeed::Medium,
|
||||
3 => portal_speed::PortalSpeed::Fast,
|
||||
4 => portal_speed::PortalSpeed::VeryFast,
|
||||
_ => portal_speed::PortalSpeed::Normal
|
||||
};
|
||||
|
||||
let max_x_pos = objects
|
||||
.iter()
|
||||
.fold(0.0, |max_x, obj| f64::max(max_x, obj.x()));
|
||||
|
||||
let mut portals: Vec<ObjectData> = objects
|
||||
.into_iter()
|
||||
.filter(|obj| id_to_portal_speed(obj.id()).is_some() && obj.checked())
|
||||
.collect();
|
||||
|
||||
portals.sort_by(|a, b| a.x().partial_cmp(&b.x()).unwrap());
|
||||
|
||||
return get_seconds_from_xpos(max_x_pos, start_speed, portals)
|
||||
}
|
||||
|
||||
pub fn secs_to_time(time: f64) -> i32 {
|
||||
match time {
|
||||
time if time < 10.0 => return 0,
|
||||
time if time < 30.0 => return 1,
|
||||
time if time < 60.0 => return 2,
|
||||
time if time < 120.0 => return 3,
|
||||
time if time >= 120.0 => return 4,
|
||||
_ => 0
|
||||
}
|
||||
}
|
||||
|
||||
pub fn array_to_hash(arr: Vec<String>) -> HashMap<String, String> {
|
||||
return arr.chunks(2)
|
||||
.map(|chunk| (chunk[0].clone(), chunk[1].clone()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn parse(raw_level_data: &str) -> Vec<HashMap<String, String>> {
|
||||
raw_level_data
|
||||
.trim_end_matches(';')
|
||||
.split(';')
|
||||
.map(|v| {
|
||||
let values: Vec<String> = v.split(',').map(|s| s.to_string()).collect();
|
||||
array_to_hash(values)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn decode(level_data: String) -> Vec<HashMap<String, String>> {
|
||||
let decoded_bytes = general_purpose::URL_SAFE.decode(level_data).expect("couldnt decode b64");
|
||||
|
||||
let mut decoder = GzDecoder::new(&decoded_bytes[..]);
|
||||
|
||||
let mut uncompressed_data = String::new();
|
||||
decoder.read_to_string(&mut uncompressed_data).expect("err unzipping level");
|
||||
|
||||
return parse(uncompressed_data.as_str())
|
||||
}
|
||||
|
||||
pub fn to_objectdata(objects: Vec<HashMap<String, String>>) -> Vec<ObjectData> {
|
||||
return objects
|
||||
.into_iter()
|
||||
.filter(|v| v.contains_key("1"))
|
||||
.map(|v| ObjectData::new(v))
|
||||
.collect()
|
||||
}
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue