Initial Commit (working!)

This commit is contained in:
Anthony Cicchetti 2022-03-07 22:16:07 -05:00
commit d56b9d4952
10 changed files with 733082 additions and 0 deletions

1
.env Normal file
View file

@ -0,0 +1 @@
DATABASE_URL="sqlite:monsters.db"

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/target

1265
Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

18
Cargo.toml Normal file
View file

@ -0,0 +1,18 @@
[package]
name = "osrsbox-sqlite"
version = "0.1.0"
edition = "2021"
license = "BlueOak-1.0.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
tokio = { version = "1", features = [ "full" ] }
sqlx = { version = "0.5", features = [ "runtime-tokio-rustls", "sqlite", "macros"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
clap = "3.1"
eyre = "0.6"
[profile.dev.package.sqlx-macros]
opt-level = 3

55
LICENSE Normal file
View file

@ -0,0 +1,55 @@
# Blue Oak Model License
Version 1.0.0
## Purpose
This license gives everyone as much permission to work with
this software as possible, while protecting contributors
from liability.
## Acceptance
In order to receive this license, you must agree to its
rules. The rules of this license are both obligations
under that agreement and conditions to your license.
You must not do anything with this software that triggers
a rule that you cannot or will not follow.
## Copyright
Each contributor licenses you to do everything with this
software that would otherwise infringe that contributor's
copyright in it.
## Notices
You must ensure that everyone who gets a copy of
any part of this software from you, with or without
changes, also gets the text of this license or a link to
<https://blueoakcouncil.org/license/1.0.0>.
## Excuse
If anyone notifies you in writing that you have not
complied with [Notices](#notices), you can keep your
license by taking all practical steps to comply within 30
days after the notice. If you do not do so, your license
ends immediately.
## Patent
Each contributor licenses you to do everything with this
software that would otherwise infringe any patent claims
they can license or become able to license.
## Reliability
No contributor can revoke this license.
## No Liability
***As far as the law allows, this software comes as is,
without any warranty or condition, and no contributor
will be liable to anyone for any damages related to this
software or this license, under any kind of legal claim.***

13
justfile Normal file
View file

@ -0,0 +1,13 @@
set dotenv-load
@default:
echo "Don't forget to set DATABASE_URL"
run_migrations: create_db
sqlx migrate run
create_db: install-cli
sqlx db create
install-cli:
cargo install sqlx-cli --no-default-features --features rustls --features sqlite

View file

@ -0,0 +1,19 @@
create table if not exists monsters
(
id integer
constraint monsters_pk
primary key,
name text not null,
health integer not null,
attributes text,
attack_level integer not null,
strength_level integer not null,
defence_level integer not null,
ranged_level integer not null,
magic_level integer not null,
defence_stab integer not null,
defence_slash integer not null,
defence_crush integer not null,
defence_magic integer not null,
defence_ranged integer not null
);

730677
monsters-complete.json Normal file

File diff suppressed because it is too large Load diff

870
monsters-vorkath.json Normal file
View file

@ -0,0 +1,870 @@
{
"1": {
"id": 1,
"name": "Molanisk",
"last_updated": "2022-03-03",
"incomplete": true,
"members": true,
"release_date": "2007-03-20",
"combat_level": 51,
"size": 1,
"hitpoints": 52,
"max_hit": 5,
"attack_type": [
"melee"
],
"attack_speed": 4,
"aggressive": true,
"poisonous": false,
"venomous": false,
"immune_poison": false,
"immune_venom": false,
"attributes": [],
"category": [
"molanisks"
],
"slayer_monster": true,
"slayer_level": 39,
"slayer_xp": 52,
"slayer_masters": [
"vannaka",
"chaeldar"
],
"duplicate": false,
"examine": "A strange mole-like being.",
"wiki_name": "Molanisk",
"wiki_url": "https://oldschool.runescape.wiki/w/Molanisk",
"attack_level": 40,
"strength_level": 40,
"defence_level": 50,
"magic_level": 0,
"ranged_level": 1,
"attack_bonus": 0,
"strength_bonus": 0,
"attack_magic": 0,
"magic_bonus": 0,
"attack_ranged": 0,
"ranged_bonus": 0,
"defence_stab": 45,
"defence_slash": 45,
"defence_crush": 35,
"defence_magic": 30,
"defence_ranged": 55,
"drops": [
{
"id": 526,
"name": "Bones",
"members": false,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 205,
"name": "Grimy harralander",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 207,
"name": "Grimy ranarr weed",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 209,
"name": "Grimy irit leaf",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 211,
"name": "Grimy avantoe",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 213,
"name": "Grimy kwuarm",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 215,
"name": "Grimy cadantine",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 2485,
"name": "Grimy lantadyme",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 217,
"name": "Grimy dwarf weed",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 10978,
"name": "Swamp weed",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 10978,
"name": "Swamp weed",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 555,
"name": "Water rune",
"members": false,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 995,
"name": "Coins",
"members": false,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 7416,
"name": "Mole claw",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 557,
"name": "Earth rune",
"members": false,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 2677,
"name": "Clue scroll (easy)",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 561,
"name": "Nature rune",
"members": false,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 564,
"name": "Cosmic rune",
"members": false,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 4698,
"name": "Mud rune",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 199,
"name": "Grimy guam leaf",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 201,
"name": "Grimy marrentill",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 203,
"name": "Grimy tarromin",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
}
]
},
"8061": {
"id": 8061,
"name": "Vorkath",
"last_updated": "2022-03-03",
"incomplete": true,
"members": true,
"release_date": "2018-01-04",
"combat_level": 732,
"size": 7,
"hitpoints": 750,
"max_hit": 30,
"attack_type": [
"slash",
"ranged",
"magic",
"dragonfire"
],
"attack_speed": 5,
"aggressive": false,
"poisonous": true,
"venomous": true,
"immune_poison": true,
"immune_venom": true,
"attributes": [
"dragon",
"fiery",
"undead"
],
"category": [
"blue dragons",
"zombies",
"bosses"
],
"slayer_monster": true,
"slayer_level": 1,
"slayer_xp": 750,
"slayer_masters": [
"turael",
"spria",
"mazchna",
"konar",
"nieve",
"duradel"
],
"duplicate": false,
"examine": "Let sleeping dragons lie.",
"wiki_name": "Vorkath (Post-quest)",
"wiki_url": "https://oldschool.runescape.wiki/w/Vorkath#Post-quest",
"attack_level": 560,
"strength_level": 308,
"defence_level": 214,
"magic_level": 150,
"ranged_level": 308,
"attack_bonus": 16,
"strength_bonus": 0,
"attack_magic": 150,
"magic_bonus": 56,
"attack_ranged": 78,
"ranged_bonus": 0,
"defence_stab": 26,
"defence_slash": 108,
"defence_crush": 108,
"defence_magic": 240,
"defence_ranged": 26,
"drops": [
{
"id": 22124,
"name": "Superior dragon bones",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 562,
"name": "Chaos rune",
"members": false,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 560,
"name": "Death rune",
"members": false,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 21880,
"name": "Wrath rune",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 1751,
"name": "Blue dragonhide",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 1753,
"name": "Green dragonhide",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 1749,
"name": "Red dragonhide",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 1747,
"name": "Black dragonhide",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 21930,
"name": "Dragon bolts (unf)",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 9189,
"name": "Sapphire bolt tips",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 9190,
"name": "Emerald bolt tips",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 1751,
"name": "Blue dragonhide",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 9191,
"name": "Ruby bolt tips",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 9192,
"name": "Diamond bolt tips",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 9193,
"name": "Dragonstone bolt tips",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 9193,
"name": "Dragonstone bolt tips",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 9194,
"name": "Onyx bolt tips",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 9194,
"name": "Onyx bolt tips",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 824,
"name": "Rune dart tip",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 11232,
"name": "Dragon dart tip",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 11237,
"name": "Dragon arrowtips",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 5295,
"name": "Ranarr seed",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 1303,
"name": "Rune longsword",
"members": false,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 5300,
"name": "Snapdragon seed",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 5304,
"name": "Torstol seed",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 5321,
"name": "Watermelon seed",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 5313,
"name": "Willow seed",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 21488,
"name": "Mahogany seed",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 5314,
"name": "Maple seed",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 21486,
"name": "Teak seed",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 5315,
"name": "Yew seed",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 5288,
"name": "Papaya tree seed",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 5316,
"name": "Magic seed",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 1201,
"name": "Rune kiteshield",
"members": false,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 5289,
"name": "Palm tree seed",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 5317,
"name": "Spirit seed",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 22877,
"name": "Dragonfruit tree seed",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 22869,
"name": "Celastrus seed",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 22871,
"name": "Redwood tree seed",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 449,
"name": "Adamantite ore",
"members": false,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 995,
"name": "Coins",
"members": false,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 1987,
"name": "Grapes",
"members": false,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 1513,
"name": "Magic logs",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 391,
"name": "Manta ray",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 1391,
"name": "Battlestaff",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 536,
"name": "Dragon bones",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 1601,
"name": "Diamond",
"members": false,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 1615,
"name": "Dragonstone",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 22118,
"name": "Wrath talisman",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 1377,
"name": "Dragon battleaxe",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 1305,
"name": "Dragon longsword",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 4087,
"name": "Dragon platelegs",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 21907,
"name": "Vorkath's head",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 23083,
"name": "Brimstone key",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 12073,
"name": "Clue scroll (elite)",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 22111,
"name": "Dragonbone necklace",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 22106,
"name": "Jar of decay",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 21992,
"name": "Vorki",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 11286,
"name": "Draconic visage",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 22006,
"name": "Skeletal visage",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
},
{
"id": 4585,
"name": "Dragon plateskirt",
"members": true,
"quantity": null,
"noted": false,
"rarity": 0.001953125,
"rolls": 1
}
]
}
}

163
src/main.rs Normal file
View file

@ -0,0 +1,163 @@
use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use sqlx::SqlitePool;
use eyre::{eyre};
#[derive(Deserialize, Debug, Serialize, Copy, Clone)]
#[serde(rename_all = "lowercase")]
enum MonsterProperties {
Fiery,
Dragon,
Undead,
Spectral,
Demon,
Leafy,
Kalphite,
Vampyre,
Shade,
Golem,
Penance,
Xerician,
}
#[derive(Debug, Clone)]
struct ValidMonster {
id: i32,
name: String,
health: i32,
attributes: Vec<MonsterProperties>,
attack_level: i32,
strength_level: i32,
defence_level: i32,
ranged_level: i32,
magic_level: i32,
defence_stab: i32,
defence_slash: i32,
defence_crush: i32,
defence_magic: i32,
defence_ranged: i32,
}
impl TryFrom<Monster> for ValidMonster {
type Error = eyre::Error;
fn try_from(value: Monster) -> Result<Self, Self::Error> {
Ok(ValidMonster {
id: value.id,
name: value.name.clone(),
health: value.health.ok_or(eyre!("Couldn't unwrap health for {}", value.name))?,
attributes: value.attributes,
attack_level: value.attack_level,
strength_level: value.strength_level,
defence_level: value.defence_level,
ranged_level: value.ranged_level,
magic_level: value.magic_level,
defence_stab: value.defence_stab,
defence_slash: value.defence_slash,
defence_crush: value.defence_crush,
defence_magic: value.defence_magic,
defence_ranged: value.defence_ranged,
})
}
}
#[derive(Deserialize, Debug)]
struct Monster {
id: i32,
name: String,
#[serde(rename = "hitpoints")]
health: Option<i32>,
attributes: Vec<MonsterProperties>,
attack_level: i32,
strength_level: i32,
defence_level: i32,
ranged_level: i32,
magic_level: i32,
defence_stab: i32,
defence_slash: i32,
defence_crush: i32,
defence_magic: i32,
defence_ranged: i32,
}
use tokio::fs;
use tokio::sync::mpsc;
#[tokio::main]
async fn main() -> eyre::Result<()> {
let pool = SqlitePool::connect("sqlite:monsters.db").await?;
let f = fs::read_to_string("monsters-complete.json").await?;
let a= serde_json::from_str::<HashMap<usize, Monster>>(&f)?;
let validmonsters: Vec<ValidMonster> = a.into_iter()
.filter_map(|(_, monster)| {monster.try_into().ok()})
.collect();
println!("Found {} valid monsters", validmonsters.len());
let (tx, mut rx) = mpsc::unbounded_channel();
validmonsters.into_iter().for_each(|monster| {
let sender = tx.clone();
match sender.send(monster.clone()) {
Ok(_) => {println!("Sent {} successfully", &monster.name)}
Err(_) => {eprintln!("{}", eyre::eyre!("Couldn't send {} successfully", &monster.name))}
};
});
drop(tx);
while let Some(monster) = rx.recv().await {
println!("Writing {}", &monster.name);
add_monster(&pool, &monster).await?;
};
Ok(())
}
async fn add_monster(pool: &SqlitePool, monster: &ValidMonster) -> eyre::Result<()> {
let mut conn = pool.acquire().await?;
// Insert the task, then obtain the ID of this row
let attributes = serde_json::to_string(&monster.attributes).unwrap();
sqlx::query!(
r#"
INSERT INTO monsters ( id, name, health, attributes, attack_level, strength_level, defence_level, ranged_level, magic_level, defence_stab, defence_slash, defence_crush, defence_magic, defence_ranged )
VALUES ( ?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12 , ?13, ?14 )
ON CONFLICT(id)
DO UPDATE SET
name=excluded.name,
health=excluded.health,
attributes=excluded.attributes,
attack_level=excluded.attack_level,
strength_level=excluded.strength_level,
defence_level=excluded.defence_level,
ranged_level=excluded.ranged_level,
magic_level=excluded.magic_level,
defence_stab=excluded.defence_stab,
defence_slash=excluded.defence_slash,
defence_crush=excluded.defence_crush,
defence_magic=excluded.defence_magic,
defence_ranged=excluded.defence_ranged
"#,
monster.id,
monster.name,
monster.health,
attributes,
monster.attack_level,
monster.strength_level,
monster.defence_level,
monster.ranged_level,
monster.magic_level,
monster.defence_stab,
monster.defence_slash,
monster.defence_crush,
monster.defence_magic,
monster.defence_ranged
)
.execute(&mut conn)
.await?;
Ok(())
}