Compare commits
No commits in common. "master" and "ddab0ab6a3769f3601b95b45645d809258e785b0" have entirely different histories.
master
...
ddab0ab6a3
.drone.ymlCargo.lockCargo.toml
src
bin
client
common
drops
entity
Cargo.tomlaccount.rscharacter.rs
gateway
item
mod.rssrc
items
lib.rslocation
login
login_server
maps
networking
patch
patch_server
pktbuilder
quests
room
ship
16
.drone.yml
16
.drone.yml
@ -1,24 +1,12 @@
|
|||||||
---
|
---
|
||||||
kind: pipeline
|
kind: pipeline
|
||||||
type: docker
|
type: docker
|
||||||
name: test elseware
|
name: test elseware
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
limit: 1
|
limit: 1
|
||||||
|
|
||||||
environment:
|
|
||||||
CARGO_INCREMENTAL: false
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: clean cache
|
|
||||||
image: rustlang/rust:nightly
|
|
||||||
volumes:
|
|
||||||
- name: cache
|
|
||||||
path: /usr/local/cargo
|
|
||||||
- name: target-cache
|
|
||||||
path: /drone/src/target
|
|
||||||
commands:
|
|
||||||
- cargo prune
|
|
||||||
- name: build
|
- name: build
|
||||||
image: rustlang/rust:nightly
|
image: rustlang/rust:nightly
|
||||||
volumes:
|
volumes:
|
||||||
@ -45,7 +33,7 @@ steps:
|
|||||||
- name: target-cache
|
- name: target-cache
|
||||||
path: /drone/src/target
|
path: /drone/src/target
|
||||||
commands:
|
commands:
|
||||||
- cargo test --jobs 1
|
- cargo test
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
- name: cache
|
- name: cache
|
||||||
|
2390
Cargo.lock
generated
Normal file
2390
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
70
Cargo.toml
70
Cargo.toml
@ -4,46 +4,8 @@ version = "0.1.0"
|
|||||||
authors = ["Jake Probst <jake.probst@gmail.com>"]
|
authors = ["Jake Probst <jake.probst@gmail.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[workspace]
|
[dependencies]
|
||||||
members = [
|
libpso = { git = "http://git.sharnoth.com/jake/libpso" }
|
||||||
"src/client",
|
|
||||||
"src/drops",
|
|
||||||
"src/entity",
|
|
||||||
"src/items",
|
|
||||||
"src/location",
|
|
||||||
"src/maps",
|
|
||||||
"src/networking",
|
|
||||||
"src/pktbuilder",
|
|
||||||
"src/quests",
|
|
||||||
"src/room",
|
|
||||||
"src/shops",
|
|
||||||
"src/stats",
|
|
||||||
"src/trade",
|
|
||||||
"src/patch_server",
|
|
||||||
"src/login_server",
|
|
||||||
"src/ship_server",
|
|
||||||
]
|
|
||||||
|
|
||||||
[workspace.dependencies]
|
|
||||||
entity = { path = "./src/entity" }
|
|
||||||
maps = { path = "./src/maps" }
|
|
||||||
networking = { path = "./src/networking" }
|
|
||||||
shops = { path = "./src/shops" }
|
|
||||||
stats = { path = "./src/stats" }
|
|
||||||
items = { path = "./src/items" }
|
|
||||||
pktbuilder = { path = "./src/pktbuilder" }
|
|
||||||
quests = { path = "./src/quests" }
|
|
||||||
location = { path = "./src/location" }
|
|
||||||
client = { path = "./src/client" }
|
|
||||||
drops = { path = "./src/drops" }
|
|
||||||
trade = { path = "./src/trade" }
|
|
||||||
room = { path = "./src/room" }
|
|
||||||
patch_server = { path = "./src/patch_server" }
|
|
||||||
login_server = { path = "./src/login_server" }
|
|
||||||
ship_server = { path = "./src/ship_server" }
|
|
||||||
|
|
||||||
libpso = { git = "http://git.sharnoth.com/jake/libpso", rev="90246b6" }
|
|
||||||
|
|
||||||
async-std = { version = "1.9.0", features = ["unstable", "attributes"] }
|
async-std = { version = "1.9.0", features = ["unstable", "attributes"] }
|
||||||
futures = "0.3.5"
|
futures = "0.3.5"
|
||||||
rand = "0.7.3"
|
rand = "0.7.3"
|
||||||
@ -65,33 +27,9 @@ ages-prs = "0.1"
|
|||||||
async-trait = "0.1.51"
|
async-trait = "0.1.51"
|
||||||
async-recursion= "1.0.0"
|
async-recursion= "1.0.0"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
|
barrel = { version = "0.6.5", features = ["pg"] }
|
||||||
refinery = { version = "0.5.0", features = ["postgres"] }
|
refinery = { version = "0.5.0", features = ["postgres"] }
|
||||||
sqlx = { version = "0.6.2", features = ["runtime-async-std-native-tls", "postgres", "json", "chrono"] }
|
sqlx = { version = "0.5.10", features = ["runtime-async-std-native-tls", "postgres", "json", "chrono"] }
|
||||||
strum = "0.19.5"
|
strum = "0.19.5"
|
||||||
strum_macros = "0.19"
|
strum_macros = "0.19"
|
||||||
anyhow = { version = "1.0.68", features = ["backtrace"] }
|
anyhow = { version = "1.0.68", features = ["backtrace"] }
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
entity = { workspace = true }
|
|
||||||
maps = { workspace = true }
|
|
||||||
networking = { workspace = true }
|
|
||||||
patch_server = { workspace = true }
|
|
||||||
login_server = { workspace = true }
|
|
||||||
ship_server = { workspace = true }
|
|
||||||
|
|
||||||
libpso = { workspace = true }
|
|
||||||
|
|
||||||
async-std = { workspace = true }
|
|
||||||
bcrypt = { workspace = true }
|
|
||||||
chrono = { workspace = true }
|
|
||||||
fern = { workspace = true }
|
|
||||||
futures = { workspace = true }
|
|
||||||
log = { workspace = true }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
drops = { workspace = true }
|
|
||||||
shops = { workspace = true }
|
|
||||||
items = { workspace = true }
|
|
||||||
quests = { workspace = true }
|
|
||||||
stats = { workspace = true }
|
|
||||||
async-trait = { workspace = true }
|
|
@ -1,8 +1,8 @@
|
|||||||
use log::{info};
|
use log::{info};
|
||||||
use entity::gateway::postgres::PostgresGateway;
|
use elseware::entity::gateway::postgres::PostgresGateway;
|
||||||
use login_server::login::LoginServerState;
|
use elseware::login::login::LoginServerState;
|
||||||
use login_server::character::CharacterServerState;
|
use elseware::login::character::CharacterServerState;
|
||||||
use networking::interserver::AuthToken;
|
use elseware::common::interserver::AuthToken;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let colors = fern::colors::ColoredLevelConfig::new()
|
let colors = fern::colors::ColoredLevelConfig::new()
|
||||||
@ -38,17 +38,17 @@ fn main() {
|
|||||||
|
|
||||||
let login_state = LoginServerState::new(entity_gateway.clone(), charserv_ip);
|
let login_state = LoginServerState::new(entity_gateway.clone(), charserv_ip);
|
||||||
let login_loop = async_std::task::spawn(async move {
|
let login_loop = async_std::task::spawn(async move {
|
||||||
networking::mainloop::run_server(login_state, login_server::login::LOGIN_PORT).await;
|
elseware::common::mainloop::run_server(login_state, elseware::login::login::LOGIN_PORT).await;
|
||||||
});
|
});
|
||||||
|
|
||||||
let char_state = CharacterServerState::new(entity_gateway, AuthToken(shipgate_token));
|
let char_state = CharacterServerState::new(entity_gateway, AuthToken(shipgate_token));
|
||||||
let sub_char_state = char_state.clone();
|
let sub_char_state = char_state.clone();
|
||||||
let character_loop = async_std::task::spawn(async move {
|
let character_loop = async_std::task::spawn(async move {
|
||||||
networking::mainloop::run_server(sub_char_state, login_server::character::CHARACTER_PORT).await;
|
elseware::common::mainloop::run_server(sub_char_state, elseware::login::character::CHARACTER_PORT).await;
|
||||||
});
|
});
|
||||||
|
|
||||||
let inter_character_loop = async_std::task::spawn(async move {
|
let inter_character_loop = async_std::task::spawn(async move {
|
||||||
networking::mainloop::run_interserver_listen(char_state, login_server::login::COMMUNICATION_PORT).await;
|
elseware::common::mainloop::run_interserver_listen(char_state, elseware::login::login::COMMUNICATION_PORT).await;
|
||||||
});
|
});
|
||||||
|
|
||||||
info!("[auth/character] starting server");
|
info!("[auth/character] starting server");
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
use log::{info};
|
use log::{info};
|
||||||
|
|
||||||
use networking::interserver::AuthToken;
|
use elseware::common::interserver::AuthToken;
|
||||||
use login_server::login::LoginServerState;
|
use elseware::login::login::LoginServerState;
|
||||||
use login_server::character::CharacterServerState;
|
use elseware::login::character::CharacterServerState;
|
||||||
use patch_server::{PatchServerState, generate_patch_tree, load_config, load_motd};
|
use elseware::patch::patch::{PatchServerState, generate_patch_tree, load_config, load_motd};
|
||||||
use ship_server::ShipServerStateBuilder;
|
use elseware::ship::ship::{ShipServerStateBuilder, ShipEvent};
|
||||||
|
|
||||||
use maps::Holiday;
|
#[allow(unused_imports)]
|
||||||
use entity::gateway::{EntityGateway, InMemoryGateway};
|
use elseware::entity::gateway::{EntityGateway, InMemoryGateway, PostgresGateway};
|
||||||
use entity::account::{NewUserAccountEntity, NewUserSettingsEntity};
|
use elseware::entity::account::{NewUserAccountEntity, NewUserSettingsEntity};
|
||||||
use entity::character::NewCharacterEntity;
|
use elseware::entity::character::NewCharacterEntity;
|
||||||
use entity::item::{NewItemEntity, ItemDetail, InventoryItemEntity};
|
use elseware::entity::item::{NewItemEntity, ItemDetail, InventoryItemEntity};
|
||||||
use entity::item;
|
use elseware::entity::item;
|
||||||
|
|
||||||
fn setup_logger() {
|
fn setup_logger() {
|
||||||
let colors = fern::colors::ColoredLevelConfig::new()
|
let colors = fern::colors::ColoredLevelConfig::new()
|
||||||
@ -68,14 +68,14 @@ fn main() {
|
|||||||
character.name = format!("Test Char {}", i*2);
|
character.name = format!("Test Char {}", i*2);
|
||||||
let character = entity_gateway.create_character(character).await.unwrap();
|
let character = entity_gateway.create_character(character).await.unwrap();
|
||||||
entity_gateway.set_character_meseta(&character.id, item::Meseta(999999)).await.unwrap();
|
entity_gateway.set_character_meseta(&character.id, item::Meseta(999999)).await.unwrap();
|
||||||
entity_gateway.set_bank_meseta(&character.id, &item::BankIdentifier::Character, item::Meseta(999999)).await.unwrap();
|
entity_gateway.set_bank_meseta(&character.id, &item::BankName("".into()), item::Meseta(999999)).await.unwrap();
|
||||||
let mut character = NewCharacterEntity::new(fake_user.id);
|
let mut character = NewCharacterEntity::new(fake_user.id);
|
||||||
character.slot = 2;
|
character.slot = 2;
|
||||||
character.name = "ItemRefactor".into();
|
character.name = "ItemRefactor".into();
|
||||||
character.exp = 80000000;
|
character.exp = 80000000;
|
||||||
let character = entity_gateway.create_character(character).await.unwrap();
|
let character = entity_gateway.create_character(character).await.unwrap();
|
||||||
entity_gateway.set_character_meseta(&character.id, item::Meseta(999999)).await.unwrap();
|
entity_gateway.set_character_meseta(&character.id, item::Meseta(999999)).await.unwrap();
|
||||||
entity_gateway.set_bank_meseta(&character.id, &item::BankIdentifier::Character, item::Meseta(999999)).await.unwrap();
|
entity_gateway.set_bank_meseta(&character.id, &item::BankName("".into()), item::Meseta(999999)).await.unwrap();
|
||||||
|
|
||||||
for _ in 0..3 {
|
for _ in 0..3 {
|
||||||
entity_gateway.create_item(
|
entity_gateway.create_item(
|
||||||
@ -329,7 +329,7 @@ fn main() {
|
|||||||
item8_s.into(), item9_u0.into(), item10_u1.into(), item11_u2.into(), item12_u3.into(),
|
item8_s.into(), item9_u0.into(), item10_u1.into(), item11_u2.into(), item12_u3.into(),
|
||||||
item13.into(), item14.into(), monomates.into()]);
|
item13.into(), item14.into(), monomates.into()]);
|
||||||
entity_gateway.set_character_inventory(&character.id, &inventory).await.unwrap();
|
entity_gateway.set_character_inventory(&character.id, &inventory).await.unwrap();
|
||||||
entity_gateway.set_character_bank(&character.id, &item::BankEntity::default(), &item::BankIdentifier::Character).await.unwrap();
|
entity_gateway.set_character_bank(&character.id, &item::BankEntity::default(), &item::BankName("".into())).await.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("[patch] starting server");
|
info!("[patch] starting server");
|
||||||
@ -338,73 +338,73 @@ fn main() {
|
|||||||
let (patch_file_tree, patch_file_lookup) = generate_patch_tree(patch_config.path.as_str());
|
let (patch_file_tree, patch_file_lookup) = generate_patch_tree(patch_config.path.as_str());
|
||||||
let patch_state = PatchServerState::new(patch_file_tree, patch_file_lookup, patch_motd);
|
let patch_state = PatchServerState::new(patch_file_tree, patch_file_lookup, patch_motd);
|
||||||
let patch_loop = async_std::task::spawn(async move {
|
let patch_loop = async_std::task::spawn(async move {
|
||||||
networking::mainloop::run_server(patch_state, patch_config.port).await;
|
elseware::common::mainloop::run_server(patch_state, patch_config.port).await;
|
||||||
});
|
});
|
||||||
|
|
||||||
info!("[auth] starting server");
|
info!("[auth] starting server");
|
||||||
let login_state = LoginServerState::new(entity_gateway.clone(), "127.0.0.1".parse().unwrap());
|
let login_state = LoginServerState::new(entity_gateway.clone(), "127.0.0.1".parse().unwrap());
|
||||||
let login_loop = async_std::task::spawn(async move {
|
let login_loop = async_std::task::spawn(async move {
|
||||||
networking::mainloop::run_server(login_state, login_server::login::LOGIN_PORT).await;
|
elseware::common::mainloop::run_server(login_state, elseware::login::login::LOGIN_PORT).await;
|
||||||
});
|
});
|
||||||
|
|
||||||
info!("[character] starting server");
|
info!("[character] starting server");
|
||||||
let char_state = CharacterServerState::new(entity_gateway.clone(), AuthToken("".into()));
|
let char_state = CharacterServerState::new(entity_gateway.clone(), AuthToken("".into()));
|
||||||
let sub_char_state = char_state.clone();
|
let sub_char_state = char_state.clone();
|
||||||
let character_loop = async_std::task::spawn(async move {
|
let character_loop = async_std::task::spawn(async move {
|
||||||
networking::mainloop::run_server(sub_char_state, login_server::character::CHARACTER_PORT).await;
|
elseware::common::mainloop::run_server(sub_char_state, elseware::login::character::CHARACTER_PORT).await;
|
||||||
});
|
});
|
||||||
|
|
||||||
let sub_char_state = char_state.clone();
|
let sub_char_state = char_state.clone();
|
||||||
let inter_character_loop = async_std::task::spawn(async move {
|
let inter_character_loop = async_std::task::spawn(async move {
|
||||||
networking::mainloop::run_interserver_listen(sub_char_state, login_server::login::COMMUNICATION_PORT).await;
|
elseware::common::mainloop::run_interserver_listen(sub_char_state, elseware::login::login::COMMUNICATION_PORT).await;
|
||||||
});
|
});
|
||||||
|
|
||||||
info!("[ship] starting servers");
|
info!("[ship] starting servers");
|
||||||
let ship_state = ShipServerStateBuilder::default()
|
let ship_state = ShipServerStateBuilder::default()
|
||||||
.name("US/Sona-Nyl".into())
|
.name("US/Sona-Nyl".into())
|
||||||
.ip(Ipv4Addr::new(127,0,0,1))
|
.ip(Ipv4Addr::new(127,0,0,1))
|
||||||
.port(ship_server::SHIP_PORT)
|
.port(elseware::ship::ship::SHIP_PORT)
|
||||||
.event(Holiday::Halloween)
|
.event(ShipEvent::Halloween)
|
||||||
.gateway(entity_gateway.clone())
|
.gateway(entity_gateway.clone())
|
||||||
.build();
|
.build();
|
||||||
let sub_ship_state = ship_state.clone();
|
let sub_ship_state = ship_state.clone();
|
||||||
let ship_loop1 = async_std::task::spawn(async move {
|
let ship_loop1 = async_std::task::spawn(async move {
|
||||||
networking::mainloop::run_server(sub_ship_state, ship_server::SHIP_PORT).await;
|
elseware::common::mainloop::run_server(sub_ship_state, elseware::ship::ship::SHIP_PORT).await;
|
||||||
});
|
});
|
||||||
let sub_ship_state = ship_state.clone();
|
let sub_ship_state = ship_state.clone();
|
||||||
let inter_ship_loop1 = async_std::task::spawn(async move {
|
let inter_ship_loop1 = async_std::task::spawn(async move {
|
||||||
networking::mainloop::run_interserver_connect(sub_ship_state, std::net::Ipv4Addr::new(127, 0, 0, 1), login_server::login::COMMUNICATION_PORT).await;
|
elseware::common::mainloop::run_interserver_connect(sub_ship_state, std::net::Ipv4Addr::new(127, 0, 0, 1), elseware::login::login::COMMUNICATION_PORT).await;
|
||||||
});
|
});
|
||||||
|
|
||||||
let ship_state = ShipServerStateBuilder::default()
|
let ship_state = ShipServerStateBuilder::default()
|
||||||
.name("EU/Dylath-Leen".into())
|
.name("EU/Dylath-Leen".into())
|
||||||
.ip(Ipv4Addr::new(127,0,0,1))
|
.ip(Ipv4Addr::new(127,0,0,1))
|
||||||
.port(ship_server::SHIP_PORT+2000)
|
.port(elseware::ship::ship::SHIP_PORT+2000)
|
||||||
.event(Holiday::Christmas)
|
.event(ShipEvent::Christmas)
|
||||||
.gateway(entity_gateway.clone())
|
.gateway(entity_gateway.clone())
|
||||||
.build();
|
.build();
|
||||||
let sub_ship_state = ship_state.clone();
|
let sub_ship_state = ship_state.clone();
|
||||||
let ship_loop2 = async_std::task::spawn(async move {
|
let ship_loop2 = async_std::task::spawn(async move {
|
||||||
networking::mainloop::run_server(sub_ship_state, ship_server::SHIP_PORT+2000).await;
|
elseware::common::mainloop::run_server(sub_ship_state, elseware::ship::ship::SHIP_PORT+2000).await;
|
||||||
});
|
});
|
||||||
let sub_ship_state = ship_state.clone();
|
let sub_ship_state = ship_state.clone();
|
||||||
let inter_ship_loop2 = async_std::task::spawn(async move {
|
let inter_ship_loop2 = async_std::task::spawn(async move {
|
||||||
networking::mainloop::run_interserver_connect(sub_ship_state, std::net::Ipv4Addr::new(127, 0, 0, 1), login_server::login::COMMUNICATION_PORT).await;
|
elseware::common::mainloop::run_interserver_connect(sub_ship_state, std::net::Ipv4Addr::new(127, 0, 0, 1), elseware::login::login::COMMUNICATION_PORT).await;
|
||||||
});
|
});
|
||||||
|
|
||||||
let ship_state = ShipServerStateBuilder::default()
|
let ship_state = ShipServerStateBuilder::default()
|
||||||
.name("JP/Thalarion".into())
|
.name("JP/Thalarion".into())
|
||||||
.ip(Ipv4Addr::new(127,0,0,1))
|
.ip(Ipv4Addr::new(127,0,0,1))
|
||||||
.port(ship_server::SHIP_PORT+3000)
|
.port(elseware::ship::ship::SHIP_PORT+3000)
|
||||||
.gateway(entity_gateway.clone())
|
.gateway(entity_gateway.clone())
|
||||||
.build();
|
.build();
|
||||||
let sub_ship_state = ship_state.clone();
|
let sub_ship_state = ship_state.clone();
|
||||||
let ship_loop3 = async_std::task::spawn(async move {
|
let ship_loop3 = async_std::task::spawn(async move {
|
||||||
networking::mainloop::run_server(sub_ship_state, ship_server::SHIP_PORT+3000).await;
|
elseware::common::mainloop::run_server(sub_ship_state, elseware::ship::ship::SHIP_PORT+3000).await;
|
||||||
});
|
});
|
||||||
let sub_ship_state = ship_state.clone();
|
let sub_ship_state = ship_state.clone();
|
||||||
let inter_ship_loop3 = async_std::task::spawn(async move {
|
let inter_ship_loop3 = async_std::task::spawn(async move {
|
||||||
networking::mainloop::run_interserver_connect(sub_ship_state, std::net::Ipv4Addr::new(127, 0, 0, 1), login_server::login::COMMUNICATION_PORT).await;
|
elseware::common::mainloop::run_interserver_connect(sub_ship_state, std::net::Ipv4Addr::new(127, 0, 0, 1), elseware::login::login::COMMUNICATION_PORT).await;
|
||||||
});
|
});
|
||||||
|
|
||||||
futures::future::join_all(vec![patch_loop, login_loop, character_loop, inter_character_loop,
|
futures::future::join_all(vec![patch_loop, login_loop, character_loop, inter_character_loop,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use patch_server::{PatchServerState, generate_patch_tree, load_config_env, load_motd};
|
use elseware::patch::patch::{PatchServerState, generate_patch_tree, load_config_env, load_motd};
|
||||||
use log::info;
|
use log::{info};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
info!("[patch] starting server");
|
info!("[patch] starting server");
|
||||||
@ -9,8 +9,10 @@ fn main() {
|
|||||||
let patch_state = PatchServerState::new(patch_file_tree, patch_file_lookup, patch_motd);
|
let patch_state = PatchServerState::new(patch_file_tree, patch_file_lookup, patch_motd);
|
||||||
|
|
||||||
let patch_loop = async_std::task::spawn(async move {
|
let patch_loop = async_std::task::spawn(async move {
|
||||||
networking::mainloop::run_server(patch_state, patch_config.port).await;
|
elseware::common::mainloop::run_server(patch_state, patch_config.port).await;
|
||||||
});
|
});
|
||||||
|
|
||||||
async_std::task::block_on(patch_loop);
|
async_std::task::block_on(async move {
|
||||||
|
patch_loop.await
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use log::info;
|
use log::{info};
|
||||||
use entity::gateway::postgres::PostgresGateway;
|
use elseware::entity::gateway::postgres::PostgresGateway;
|
||||||
use ship_server::ShipServerStateBuilder;
|
use elseware::ship::ship::ShipServerStateBuilder;
|
||||||
use networking::interserver::AuthToken;
|
use elseware::common::interserver::AuthToken;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let colors = fern::colors::ColoredLevelConfig::new()
|
let colors = fern::colors::ColoredLevelConfig::new()
|
||||||
@ -40,7 +40,7 @@ fn main() {
|
|||||||
let ship_state = ShipServerStateBuilder::default()
|
let ship_state = ShipServerStateBuilder::default()
|
||||||
.name(ship_name)
|
.name(ship_name)
|
||||||
.ip(ip)
|
.ip(ip)
|
||||||
.port(ship_server::SHIP_PORT)
|
.port(elseware::ship::ship::SHIP_PORT)
|
||||||
.gateway(entity_gateway)
|
.gateway(entity_gateway)
|
||||||
.auth_token(AuthToken(shipgate_token))
|
.auth_token(AuthToken(shipgate_token))
|
||||||
.build();
|
.build();
|
||||||
@ -49,10 +49,10 @@ fn main() {
|
|||||||
|
|
||||||
let sub_ship_state = ship_state.clone();
|
let sub_ship_state = ship_state.clone();
|
||||||
let ship_loop = async_std::task::spawn(async move {
|
let ship_loop = async_std::task::spawn(async move {
|
||||||
networking::mainloop::run_server(sub_ship_state, ship_server::SHIP_PORT).await;
|
elseware::common::mainloop::run_server(sub_ship_state, elseware::ship::ship::SHIP_PORT).await;
|
||||||
});
|
});
|
||||||
let inter_ship_loop = async_std::task::spawn(async move {
|
let inter_ship_loop = async_std::task::spawn(async move {
|
||||||
networking::mainloop::run_interserver_connect(ship_state, shipgate_ip, login_server::login::COMMUNICATION_PORT).await;
|
elseware::common::mainloop::run_interserver_connect(ship_state, shipgate_ip, elseware::login::login::COMMUNICATION_PORT).await;
|
||||||
});
|
});
|
||||||
|
|
||||||
info!("[auth/character] starting server");
|
info!("[auth/character] starting server");
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "client"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
entity = { workspace = true }
|
|
||||||
maps = { workspace = true }
|
|
||||||
networking = { workspace = true }
|
|
||||||
shops = { workspace = true }
|
|
||||||
items = { workspace = true }
|
|
||||||
|
|
||||||
libpso = { workspace = true }
|
|
||||||
|
|
||||||
async-std = { workspace = true }
|
|
||||||
futures = { workspace = true }
|
|
||||||
anyhow = { workspace = true }
|
|
||||||
thiserror = { workspace = true }
|
|
||||||
chrono = { workspace = true }
|
|
@ -2,8 +2,8 @@ use std::net::Ipv4Addr;
|
|||||||
use async_std::channel;
|
use async_std::channel;
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use entity::account::UserAccountId;
|
use crate::entity::account::UserAccountId;
|
||||||
use entity::character::CharacterEntityId;
|
use crate::entity::character::CharacterEntityId;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Serialize, Deserialize, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Copy, Clone, Serialize, Deserialize, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct ServerId(pub usize);
|
pub struct ServerId(pub usize);
|
@ -1,6 +1,6 @@
|
|||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use entity::character::CharacterClass;
|
use crate::entity::character::CharacterClass;
|
||||||
use std::sync::LazyLock;
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
pub static LEVEL_TABLE: LazyLock<CharacterLevelTable> = LazyLock::new(CharacterLevelTable::default);
|
pub static LEVEL_TABLE: LazyLock<CharacterLevelTable> = LazyLock::new(CharacterLevelTable::default);
|
@ -9,8 +9,8 @@ use log::{trace, info, warn, error};
|
|||||||
|
|
||||||
use libpso::crypto::{PSOCipher, NullCipher, CipherError};
|
use libpso::crypto::{PSOCipher, NullCipher, CipherError};
|
||||||
use libpso::PacketParseError;
|
use libpso::PacketParseError;
|
||||||
use crate::serverstate::ClientId;
|
use crate::common::serverstate::ClientId;
|
||||||
use crate::serverstate::{RecvServerPacket, SendServerPacket, ServerState, OnConnect};
|
use crate::common::serverstate::{RecvServerPacket, SendServerPacket, ServerState, OnConnect};
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -72,7 +72,7 @@ impl<C: PSOCipher> PacketReceiver<C> {
|
|||||||
let mut dec_buf = {
|
let mut dec_buf = {
|
||||||
//let mut cipher = self.cipher.lock().await;
|
//let mut cipher = self.cipher.lock().await;
|
||||||
let block_chunk_len = self.recv_buffer.len() / self.cipher.block_size() * self.cipher.block_size();
|
let block_chunk_len = self.recv_buffer.len() / self.cipher.block_size() * self.cipher.block_size();
|
||||||
let buf = self.recv_buffer.drain(..block_chunk_len).collect::<Vec<_>>();
|
let buf = self.recv_buffer.drain(..block_chunk_len).collect();
|
||||||
self.cipher.decrypt(&buf)?
|
self.cipher.decrypt(&buf)?
|
||||||
};
|
};
|
||||||
self.incoming_data.append(&mut dec_buf);
|
self.incoming_data.append(&mut dec_buf);
|
||||||
@ -255,7 +255,7 @@ where
|
|||||||
let (mut socket, addr) = listener.accept().await.unwrap();
|
let (mut socket, addr) = listener.accept().await.unwrap();
|
||||||
id += 1;
|
id += 1;
|
||||||
|
|
||||||
let client_id = crate::serverstate::ClientId(id);
|
let client_id = crate::common::serverstate::ClientId(id);
|
||||||
info!("new client {:?} {:?} {:?}", client_id, socket, addr);
|
info!("new client {:?} {:?} {:?}", client_id, socket, addr);
|
||||||
|
|
||||||
let (client_tx, client_rx) = async_std::channel::unbounded();
|
let (client_tx, client_rx) = async_std::channel::unbounded();
|
@ -8,11 +8,13 @@ use std::collections::HashMap;
|
|||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
|
|
||||||
use crate::interserver::{ServerId, InterserverActor};
|
use crate::common::interserver::{ServerId, InterserverActor};
|
||||||
|
|
||||||
use libpso::crypto::{PSOCipher, NullCipher, CipherError};
|
use libpso::crypto::{PSOCipher, NullCipher, CipherError};
|
||||||
use crate::serverstate::{ServerState, SendServerPacket, RecvServerPacket};
|
use crate::common::serverstate::{ServerState, SendServerPacket, RecvServerPacket};
|
||||||
use entity::gateway::entitygateway::EntityGateway;
|
use crate::login::character::CharacterServerState;
|
||||||
|
//use crate::ship::ship::ShipServerState;
|
||||||
|
use crate::entity::gateway::entitygateway::EntityGateway;
|
||||||
|
|
||||||
use async_std::channel;
|
use async_std::channel;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
@ -147,7 +149,7 @@ where
|
|||||||
info!("[interserver listen] new server: {:?} {:?}", socket, addr);
|
info!("[interserver listen] new server: {:?} {:?}", socket, addr);
|
||||||
|
|
||||||
id += 1;
|
id += 1;
|
||||||
let server_id = crate::interserver::ServerId(id);
|
let server_id = crate::common::interserver::ServerId(id);
|
||||||
let (client_tx, client_rx) = async_std::channel::unbounded();
|
let (client_tx, client_rx) = async_std::channel::unbounded();
|
||||||
state.set_sender(server_id, client_tx.clone()).await;
|
state.set_sender(server_id, client_tx.clone()).await;
|
||||||
|
|
||||||
@ -194,7 +196,7 @@ where
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
id += 1;
|
id += 1;
|
||||||
let server_id = crate::interserver::ServerId(id);
|
let server_id = crate::common::interserver::ServerId(id);
|
||||||
info!("[interserver connect] found loginserv: {:?} {:?}", server_id, socket);
|
info!("[interserver connect] found loginserv: {:?} {:?}", server_id, socket);
|
||||||
|
|
||||||
let (client_tx, client_rx) = async_std::channel::unbounded();
|
let (client_tx, client_rx) = async_std::channel::unbounded();
|
||||||
@ -218,8 +220,12 @@ where
|
|||||||
let mut buf = [0u8; 1];
|
let mut buf = [0u8; 1];
|
||||||
loop {
|
loop {
|
||||||
let peek = socket.peek(&mut buf).await;
|
let peek = socket.peek(&mut buf).await;
|
||||||
if let Ok(0) = peek {
|
match peek {
|
||||||
break
|
Ok(len) if len == 0 => {
|
||||||
|
break
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
19
src/common/mod.rs
Normal file
19
src/common/mod.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
pub mod cipherkeys;
|
||||||
|
pub mod serverstate;
|
||||||
|
pub mod mainloop;
|
||||||
|
pub mod leveltable;
|
||||||
|
pub mod interserver;
|
||||||
|
|
||||||
|
// https://www.reddit.com/r/rust/comments/33xhhu/how_to_create_an_array_of_structs_that_havent/
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! init_array(
|
||||||
|
($ty:ty, $len:expr, $val:expr) => (
|
||||||
|
{
|
||||||
|
let mut array: [$ty; $len] = unsafe { std::mem::uninitialized() };
|
||||||
|
for i in array.iter_mut() {
|
||||||
|
unsafe { ::std::ptr::write(i, $val); }
|
||||||
|
}
|
||||||
|
array
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
@ -1,17 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "drops"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
entity = { workspace = true }
|
|
||||||
maps = { workspace = true }
|
|
||||||
stats = { workspace = true }
|
|
||||||
|
|
||||||
rand = { workspace = true }
|
|
||||||
rand_chacha = { workspace = true }
|
|
||||||
serde = { workspace = true }
|
|
||||||
enum-utils = { workspace = true }
|
|
||||||
toml = { workspace = true }
|
|
||||||
chrono = { workspace = true }
|
|
@ -1,23 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "entity"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
libpso = { workspace = true }
|
|
||||||
maps = { workspace = true }
|
|
||||||
chrono = { workspace = true }
|
|
||||||
anyhow = { workspace = true }
|
|
||||||
async-std = { workspace = true }
|
|
||||||
sqlx = { workspace = true }
|
|
||||||
thiserror = { workspace = true }
|
|
||||||
serde = { workspace = true }
|
|
||||||
async-trait = { workspace = true }
|
|
||||||
enum-utils = { workspace = true }
|
|
||||||
derive_more = { workspace = true }
|
|
||||||
refinery = { workspace = true }
|
|
||||||
lazy_static = { workspace = true }
|
|
||||||
futures = { workspace = true }
|
|
||||||
strum = { workspace = true }
|
|
||||||
strum_macros = { workspace = true }
|
|
||||||
toml = { workspace = true }
|
|
@ -4,8 +4,8 @@ use serde::{Serialize, Deserialize};
|
|||||||
|
|
||||||
use libpso::packet::ship::{UpdateConfig, WriteInfoboard};
|
use libpso::packet::ship::{UpdateConfig, WriteInfoboard};
|
||||||
use libpso::character::settings::{DEFAULT_PALETTE_CONFIG, DEFAULT_TECH_MENU};
|
use libpso::character::settings::{DEFAULT_PALETTE_CONFIG, DEFAULT_TECH_MENU};
|
||||||
use crate::item::tech::Technique;
|
use crate::entity::item::tech::Technique;
|
||||||
use crate::account::UserAccountId;
|
use crate::entity::account::UserAccountId;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, enum_utils::FromStr, derive_more::Display, Serialize, Deserialize, Default)]
|
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, enum_utils::FromStr, derive_more::Display, Serialize, Deserialize, Default)]
|
||||||
pub enum CharacterClass {
|
pub enum CharacterClass {
|
||||||
@ -223,7 +223,7 @@ impl CharacterInfoboard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_infoboard(&mut self, new_board: &WriteInfoboard) {
|
pub fn update_infoboard(&mut self, new_board: &WriteInfoboard) {
|
||||||
self.board = libpso::util::utf8_to_utf16_array(&new_board.message);
|
self.board = libpso::utf8_to_utf16_array!(new_board.message, 172);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,13 +1,13 @@
|
|||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use futures::future::{Future, BoxFuture};
|
use futures::Future;
|
||||||
|
|
||||||
use crate::account::*;
|
use crate::entity::account::*;
|
||||||
use crate::character::*;
|
use crate::entity::character::*;
|
||||||
use crate::item::*;
|
use crate::entity::item::*;
|
||||||
use crate::room::*;
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: better granularity?
|
// TODO: better granularity?
|
||||||
|
//#[derive(Error, Debug)]
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum GatewayError {
|
pub enum GatewayError {
|
||||||
#[error("unknown error")]
|
#[error("unknown error")]
|
||||||
@ -19,12 +19,12 @@ pub enum GatewayError {
|
|||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
pub trait EntityGateway: Send + Sync {
|
pub trait EntityGateway: Send + Sync {
|
||||||
type Transaction<'t>: EntityGatewayTransaction + Clone where Self: 't;
|
type Transaction: EntityGatewayTransaction + Clone;
|
||||||
|
|
||||||
fn with_transaction<'a, F, Fut, R>(&'a mut self, _func: F) -> BoxFuture<'a, Result<R, anyhow::Error>>
|
async fn with_transaction<'a, F, Fut, R>(&'a mut self, _func: F) -> Result<R, anyhow::Error>
|
||||||
where
|
where
|
||||||
Fut: Future<Output = Result<(Self::Transaction<'a>, R), anyhow::Error>> + Send + 'a,
|
Fut: Future<Output = Result<(Self::Transaction, R), anyhow::Error>> + Send + 'a,
|
||||||
F: FnOnce(Self::Transaction<'a>) -> Fut + Send + 'a,
|
F: FnOnce(Self::Transaction) -> Fut + Send,
|
||||||
R: Send,
|
R: Send,
|
||||||
Self: Sized
|
Self: Sized
|
||||||
{
|
{
|
||||||
@ -104,7 +104,7 @@ pub trait EntityGateway: Send + Sync {
|
|||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_character_bank(&mut self, _char_id: &CharacterEntityId, _bank_identifier: &BankIdentifier) -> Result<BankEntity, GatewayError> {
|
async fn get_character_bank(&mut self, _char_id: &CharacterEntityId, _bank_name: &BankName) -> Result<BankEntity, GatewayError> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,7 +112,7 @@ pub trait EntityGateway: Send + Sync {
|
|||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_character_bank(&mut self, _char_id: &CharacterEntityId, _bank: &BankEntity, _bank_identifier: &BankIdentifier) -> Result<(), GatewayError> {
|
async fn set_character_bank(&mut self, _char_id: &CharacterEntityId, _inventory: &BankEntity, _bank_name: &BankName) -> Result<(), GatewayError> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,11 +132,11 @@ pub trait EntityGateway: Send + Sync {
|
|||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_bank_meseta(&mut self, _char_id: &CharacterEntityId, _bank_identifier: &BankIdentifier) -> Result<Meseta, GatewayError> {
|
async fn get_bank_meseta(&mut self, _char_id: &CharacterEntityId, _bank: &BankName) -> Result<Meseta, GatewayError> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_bank_meseta(&mut self, _char_id: &CharacterEntityId, _bank_identifier: &BankIdentifier, _amount: Meseta) -> Result<(), GatewayError> {
|
async fn set_bank_meseta(&mut self, _char_id: &CharacterEntityId, _bank: &BankName, _amount: Meseta) -> Result<(), GatewayError> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,14 +147,6 @@ pub trait EntityGateway: Send + Sync {
|
|||||||
async fn set_character_playtime(&mut self, _char_id: &CharacterEntityId, _playtime: u32) -> Result<(), GatewayError> {
|
async fn set_character_playtime(&mut self, _char_id: &CharacterEntityId, _playtime: u32) -> Result<(), GatewayError> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn create_room(&mut self, _room: NewRoomEntity) -> Result<RoomEntity, GatewayError> {
|
|
||||||
unimplemented!();
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn add_room_note(&mut self, _room_id: RoomEntityId, _note: RoomNote) -> Result<(), GatewayError> {
|
|
||||||
unimplemented!();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,12 +1,11 @@
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use futures::future::{Future, BoxFuture};
|
use futures::Future;
|
||||||
|
|
||||||
use crate::account::*;
|
use crate::entity::account::*;
|
||||||
use crate::character::*;
|
use crate::entity::character::*;
|
||||||
use crate::gateway::{EntityGateway, EntityGatewayTransaction, GatewayError};
|
use crate::entity::gateway::{EntityGateway, EntityGatewayTransaction, GatewayError};
|
||||||
use crate::item::*;
|
use crate::entity::item::*;
|
||||||
use crate::room::*;
|
|
||||||
|
|
||||||
use async_std::sync::{Arc, Mutex};
|
use async_std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
@ -32,7 +31,7 @@ where
|
|||||||
// functions here have been skipped as they are not used in transactions, add as needed
|
// functions here have been skipped as they are not used in transactions, add as needed
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl EntityGateway for InMemoryGatewayTransaction {
|
impl EntityGateway for InMemoryGatewayTransaction {
|
||||||
type Transaction<'t> = InMemoryGatewayTransaction where Self: 't;
|
type Transaction = InMemoryGatewayTransaction;
|
||||||
|
|
||||||
async fn create_user(&mut self, user: NewUserAccountEntity) -> Result<UserAccountEntity, GatewayError> {
|
async fn create_user(&mut self, user: NewUserAccountEntity) -> Result<UserAccountEntity, GatewayError> {
|
||||||
self.working_gateway.create_user(user).await
|
self.working_gateway.create_user(user).await
|
||||||
@ -118,11 +117,11 @@ impl EntityGateway for InMemoryGatewayTransaction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_character_bank(&mut self, char_id: &CharacterEntityId, bank_identifier: &BankIdentifier) -> Result<BankEntity, GatewayError> {
|
async fn get_character_bank(&mut self, char_id: &CharacterEntityId, bank_name: &BankName) -> Result<BankEntity, GatewayError> {
|
||||||
match self.working_gateway.get_character_bank(char_id, bank_identifier).await {
|
match self.working_gateway.get_character_bank(char_id, bank_name).await {
|
||||||
Ok(bank) => Ok(bank),
|
Ok(bank) => Ok(bank),
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
self.original_gateway.get_character_bank(char_id, bank_identifier).await
|
self.original_gateway.get_character_bank(char_id, bank_name).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -131,10 +130,11 @@ impl EntityGateway for InMemoryGatewayTransaction {
|
|||||||
self.working_gateway.set_character_inventory(char_id, inventory).await
|
self.working_gateway.set_character_inventory(char_id, inventory).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_character_bank(&mut self, char_id: &CharacterEntityId, bank: &BankEntity, bank_identifier: &BankIdentifier) -> Result<(), GatewayError> {
|
async fn set_character_bank(&mut self, char_id: &CharacterEntityId, bank: &BankEntity, bank_name: &BankName) -> Result<(), GatewayError> {
|
||||||
self.working_gateway.set_character_bank(char_id, bank, bank_identifier).await
|
self.working_gateway.set_character_bank(char_id, bank, bank_name).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async fn get_character_equips(&mut self, char_id: &CharacterEntityId) -> Result<EquippedEntity, GatewayError> {
|
async fn get_character_equips(&mut self, char_id: &CharacterEntityId) -> Result<EquippedEntity, GatewayError> {
|
||||||
match self.working_gateway.get_character_equips(char_id).await {
|
match self.working_gateway.get_character_equips(char_id).await {
|
||||||
Ok(equips) => Ok(equips),
|
Ok(equips) => Ok(equips),
|
||||||
@ -161,15 +161,15 @@ impl EntityGateway for InMemoryGatewayTransaction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_bank_meseta(&mut self, char_id: &CharacterEntityId, bank_identifier: &BankIdentifier, meseta: Meseta) -> Result<(), GatewayError> {
|
async fn set_bank_meseta(&mut self, char_id: &CharacterEntityId, bank: &BankName, meseta: Meseta) -> Result<(), GatewayError> {
|
||||||
self.working_gateway.set_bank_meseta(char_id, bank_identifier, meseta).await
|
self.working_gateway.set_bank_meseta(char_id, bank, meseta).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_bank_meseta(&mut self, char_id: &CharacterEntityId, bank_identifier: &BankIdentifier) -> Result<Meseta, GatewayError> {
|
async fn get_bank_meseta(&mut self, char_id: &CharacterEntityId, bank: &BankName) -> Result<Meseta, GatewayError> {
|
||||||
match self.working_gateway.get_bank_meseta(char_id, bank_identifier).await {
|
match self.working_gateway.get_bank_meseta(char_id, bank).await {
|
||||||
Ok(meseta) => Ok(meseta),
|
Ok(meseta) => Ok(meseta),
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
self.original_gateway.get_bank_meseta(char_id, bank_identifier).await
|
self.original_gateway.get_bank_meseta(char_id, bank).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -201,11 +201,9 @@ impl EntityGatewayTransaction for InMemoryGatewayTransaction {
|
|||||||
self.original_gateway.characters.lock().await.extend(self.working_gateway.characters.lock().await.clone());
|
self.original_gateway.characters.lock().await.extend(self.working_gateway.characters.lock().await.clone());
|
||||||
self.original_gateway.character_meseta.lock().await.extend(self.working_gateway.character_meseta.lock().await.clone());
|
self.original_gateway.character_meseta.lock().await.extend(self.working_gateway.character_meseta.lock().await.clone());
|
||||||
self.original_gateway.bank_meseta.lock().await.extend(self.working_gateway.bank_meseta.lock().await.clone());
|
self.original_gateway.bank_meseta.lock().await.extend(self.working_gateway.bank_meseta.lock().await.clone());
|
||||||
self.original_gateway.shared_bank_meseta.lock().await.extend(self.working_gateway.shared_bank_meseta.lock().await.clone());
|
|
||||||
self.original_gateway.items.lock().await.extend(self.working_gateway.items.lock().await.clone());
|
self.original_gateway.items.lock().await.extend(self.working_gateway.items.lock().await.clone());
|
||||||
self.original_gateway.inventories.lock().await.extend(self.working_gateway.inventories.lock().await.clone());
|
self.original_gateway.inventories.lock().await.extend(self.working_gateway.inventories.lock().await.clone());
|
||||||
self.original_gateway.character_banks.lock().await.extend(self.working_gateway.character_banks.lock().await.clone());
|
self.original_gateway.banks.lock().await.extend(self.working_gateway.banks.lock().await.clone());
|
||||||
self.original_gateway.shared_banks.lock().await.extend(self.working_gateway.shared_banks.lock().await.clone());
|
|
||||||
self.original_gateway.equips.lock().await.extend(self.working_gateway.equips.lock().await.clone());
|
self.original_gateway.equips.lock().await.extend(self.working_gateway.equips.lock().await.clone());
|
||||||
self.original_gateway.mag_modifiers.lock().await.extend(self.working_gateway.mag_modifiers.lock().await.clone());
|
self.original_gateway.mag_modifiers.lock().await.extend(self.working_gateway.mag_modifiers.lock().await.clone());
|
||||||
self.original_gateway.weapon_modifiers.lock().await.extend(self.working_gateway.weapon_modifiers.lock().await.clone());
|
self.original_gateway.weapon_modifiers.lock().await.extend(self.working_gateway.weapon_modifiers.lock().await.clone());
|
||||||
@ -227,12 +225,10 @@ pub struct InMemoryGateway {
|
|||||||
user_settings: Arc<Mutex<BTreeMap<UserSettingsId, UserSettingsEntity>>>,
|
user_settings: Arc<Mutex<BTreeMap<UserSettingsId, UserSettingsEntity>>>,
|
||||||
characters: Arc<Mutex<BTreeMap<CharacterEntityId, CharacterEntity>>>,
|
characters: Arc<Mutex<BTreeMap<CharacterEntityId, CharacterEntity>>>,
|
||||||
character_meseta: Arc<Mutex<BTreeMap<CharacterEntityId, Meseta>>>,
|
character_meseta: Arc<Mutex<BTreeMap<CharacterEntityId, Meseta>>>,
|
||||||
bank_meseta: Arc<Mutex<BTreeMap<CharacterEntityId, Meseta>>>,
|
bank_meseta: Arc<Mutex<BTreeMap<(CharacterEntityId, BankName), Meseta>>>,
|
||||||
shared_bank_meseta: Arc<Mutex<BTreeMap<(UserAccountId, BankName), Meseta>>>,
|
|
||||||
items: Arc<Mutex<BTreeMap<ItemEntityId, ItemEntity>>>,
|
items: Arc<Mutex<BTreeMap<ItemEntityId, ItemEntity>>>,
|
||||||
inventories: Arc<Mutex<BTreeMap<CharacterEntityId, Vec<InventoryItemElement>>>>,
|
inventories: Arc<Mutex<BTreeMap<CharacterEntityId, Vec<InventoryItemElement>>>>,
|
||||||
character_banks: Arc<Mutex<BTreeMap<CharacterEntityId, BankEntity>>>,
|
banks: Arc<Mutex<BTreeMap<CharacterEntityId, BankEntity>>>,
|
||||||
shared_banks: Arc<Mutex<BTreeMap<(UserAccountId, BankName), BankEntity>>>,
|
|
||||||
equips: Arc<Mutex<BTreeMap<CharacterEntityId, EquippedEntity>>>,
|
equips: Arc<Mutex<BTreeMap<CharacterEntityId, EquippedEntity>>>,
|
||||||
mag_modifiers: Arc<Mutex<BTreeMap<ItemEntityId, Vec<mag::MagModifier>>>>,
|
mag_modifiers: Arc<Mutex<BTreeMap<ItemEntityId, Vec<mag::MagModifier>>>>,
|
||||||
weapon_modifiers: Arc<Mutex<BTreeMap<ItemEntityId, Vec<weapon::WeaponModifier>>>>,
|
weapon_modifiers: Arc<Mutex<BTreeMap<ItemEntityId, Vec<weapon::WeaponModifier>>>>,
|
||||||
@ -247,11 +243,9 @@ impl Default for InMemoryGateway {
|
|||||||
characters: Arc::new(Mutex::new(BTreeMap::new())),
|
characters: Arc::new(Mutex::new(BTreeMap::new())),
|
||||||
character_meseta: Arc::new(Mutex::new(BTreeMap::new())),
|
character_meseta: Arc::new(Mutex::new(BTreeMap::new())),
|
||||||
bank_meseta: Arc::new(Mutex::new(BTreeMap::new())),
|
bank_meseta: Arc::new(Mutex::new(BTreeMap::new())),
|
||||||
shared_bank_meseta: Arc::new(Mutex::new(BTreeMap::new())),
|
|
||||||
items: Arc::new(Mutex::new(BTreeMap::new())),
|
items: Arc::new(Mutex::new(BTreeMap::new())),
|
||||||
inventories: Arc::new(Mutex::new(BTreeMap::new())),
|
inventories: Arc::new(Mutex::new(BTreeMap::new())),
|
||||||
character_banks: Arc::new(Mutex::new(BTreeMap::new())),
|
banks: Arc::new(Mutex::new(BTreeMap::new())),
|
||||||
shared_banks: Arc::new(Mutex::new(BTreeMap::new())),
|
|
||||||
equips: Arc::new(Mutex::new(BTreeMap::new())),
|
equips: Arc::new(Mutex::new(BTreeMap::new())),
|
||||||
mag_modifiers: Arc::new(Mutex::new(BTreeMap::new())),
|
mag_modifiers: Arc::new(Mutex::new(BTreeMap::new())),
|
||||||
weapon_modifiers: Arc::new(Mutex::new(BTreeMap::new())),
|
weapon_modifiers: Arc::new(Mutex::new(BTreeMap::new())),
|
||||||
@ -318,57 +312,51 @@ fn apply_modifiers(items: &BTreeMap<ItemEntityId, ItemEntity>,
|
|||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl EntityGateway for InMemoryGateway {
|
impl EntityGateway for InMemoryGateway {
|
||||||
type Transaction<'t> = InMemoryGatewayTransaction where Self: 't;
|
type Transaction = InMemoryGatewayTransaction;
|
||||||
|
|
||||||
fn with_transaction<'a, F, Fut, R>(&'a mut self, func: F) -> BoxFuture<'a, Result<R, anyhow::Error>>
|
async fn with_transaction<'a, F, Fut, R>(&'a mut self, func: F) -> Result<R, anyhow::Error>
|
||||||
where
|
where
|
||||||
Fut: Future<Output = Result<(Self::Transaction<'a>, R), anyhow::Error>> + Send + 'a,
|
Fut: Future<Output = Result<(Self::Transaction, R), anyhow::Error>> + Send + 'a,
|
||||||
F: FnOnce(Self::Transaction<'a>) -> Fut + Send + 'a,
|
F: FnOnce(Self::Transaction) -> Fut + Send,
|
||||||
R: Send,
|
R: Send,
|
||||||
{
|
{
|
||||||
Box::pin(async move {
|
let users = self.users.lock().await.clone();
|
||||||
let users = self.users.lock().await.clone();
|
let user_settings = self.user_settings.lock().await.clone();
|
||||||
let user_settings = self.user_settings.lock().await.clone();
|
let characters = self.characters.lock().await.clone();
|
||||||
let characters = self.characters.lock().await.clone();
|
let character_meseta = self.character_meseta.lock().await.clone();
|
||||||
let character_meseta = self.character_meseta.lock().await.clone();
|
let bank_meseta = self.bank_meseta.lock().await.clone();
|
||||||
let bank_meseta = self.bank_meseta.lock().await.clone();
|
let items = self.items.lock().await.clone();
|
||||||
let shared_bank_meseta = self.shared_bank_meseta.lock().await.clone();
|
let inventories = self.inventories.lock().await.clone();
|
||||||
let items = self.items.lock().await.clone();
|
let banks = self.banks.lock().await.clone();
|
||||||
let inventories = self.inventories.lock().await.clone();
|
let equips = self.equips.lock().await.clone();
|
||||||
let character_banks = self.character_banks.lock().await.clone();
|
let mag_modifiers = self.mag_modifiers.lock().await.clone();
|
||||||
let shared_banks = self.shared_banks.lock().await.clone();
|
let weapon_modifiers = self.weapon_modifiers.lock().await.clone();
|
||||||
let equips = self.equips.lock().await.clone();
|
let trades = self.trades.lock().await.clone();
|
||||||
let mag_modifiers = self.mag_modifiers.lock().await.clone();
|
|
||||||
let weapon_modifiers = self.weapon_modifiers.lock().await.clone();
|
|
||||||
let trades = self.trades.lock().await.clone();
|
|
||||||
|
|
||||||
let working_gateway = InMemoryGateway {
|
let working_gateway = InMemoryGateway {
|
||||||
users: Arc::new(Mutex::new(users)),
|
users: Arc::new(Mutex::new(users)),
|
||||||
user_settings: Arc::new(Mutex::new(user_settings)),
|
user_settings: Arc::new(Mutex::new(user_settings)),
|
||||||
characters: Arc::new(Mutex::new(characters)),
|
characters: Arc::new(Mutex::new(characters)),
|
||||||
character_meseta: Arc::new(Mutex::new(character_meseta)),
|
character_meseta: Arc::new(Mutex::new(character_meseta)),
|
||||||
bank_meseta: Arc::new(Mutex::new(bank_meseta)),
|
bank_meseta: Arc::new(Mutex::new(bank_meseta)),
|
||||||
shared_bank_meseta: Arc::new(Mutex::new(shared_bank_meseta)),
|
items: Arc::new(Mutex::new(items)),
|
||||||
items: Arc::new(Mutex::new(items)),
|
inventories: Arc::new(Mutex::new(inventories)),
|
||||||
inventories: Arc::new(Mutex::new(inventories)),
|
banks: Arc::new(Mutex::new(banks)),
|
||||||
character_banks: Arc::new(Mutex::new(character_banks)),
|
equips: Arc::new(Mutex::new(equips)),
|
||||||
shared_banks: Arc::new(Mutex::new(shared_banks)),
|
mag_modifiers: Arc::new(Mutex::new(mag_modifiers)),
|
||||||
equips: Arc::new(Mutex::new(equips)),
|
weapon_modifiers: Arc::new(Mutex::new(weapon_modifiers)),
|
||||||
mag_modifiers: Arc::new(Mutex::new(mag_modifiers)),
|
trades: Arc::new(Mutex::new(trades)),
|
||||||
weapon_modifiers: Arc::new(Mutex::new(weapon_modifiers)),
|
};
|
||||||
trades: Arc::new(Mutex::new(trades)),
|
|
||||||
};
|
|
||||||
|
|
||||||
let transaction = InMemoryGatewayTransaction {
|
let transaction = InMemoryGatewayTransaction {
|
||||||
working_gateway,
|
working_gateway,
|
||||||
original_gateway: self.clone(),
|
original_gateway: self.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let (transaction, result) = func(transaction).await?;
|
let (transaction, result) = func(transaction).await?;
|
||||||
|
|
||||||
transaction.commit().await?;
|
transaction.commit().await?;
|
||||||
Ok(result)
|
Ok(result)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn create_user(&mut self, user: NewUserAccountEntity) -> Result<UserAccountEntity, GatewayError> {
|
async fn create_user(&mut self, user: NewUserAccountEntity) -> Result<UserAccountEntity, GatewayError> {
|
||||||
@ -583,33 +571,13 @@ impl EntityGateway for InMemoryGateway {
|
|||||||
.unwrap_or_default())
|
.unwrap_or_default())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_character_bank(&mut self, char_id: &CharacterEntityId, bank_identifier: &BankIdentifier) -> Result<BankEntity, GatewayError> {
|
async fn get_character_bank(&mut self, char_id: &CharacterEntityId, _bank_name: &BankName) -> Result<BankEntity, GatewayError> {
|
||||||
match bank_identifier {
|
let banks = self.banks.lock().await;
|
||||||
BankIdentifier::Character => {
|
Ok(banks
|
||||||
let character_banks = self.character_banks.lock().await;
|
.iter()
|
||||||
Ok(character_banks
|
.find(|(id, _)| **id == *char_id)
|
||||||
.iter()
|
.map(|(_, b)| b.clone())
|
||||||
.find(|(id, _)| **id == *char_id)
|
.unwrap_or_default())
|
||||||
.map(|(_, b)| b.clone())
|
|
||||||
.unwrap_or_default())
|
|
||||||
},
|
|
||||||
BankIdentifier::Shared(bank_name) => {
|
|
||||||
let user_id = self.characters
|
|
||||||
.lock()
|
|
||||||
.await
|
|
||||||
.iter()
|
|
||||||
.find(|(id, _)| **id == *char_id)
|
|
||||||
.unwrap()
|
|
||||||
.1
|
|
||||||
.user_id;
|
|
||||||
let shared_banks = self.shared_banks.lock().await;
|
|
||||||
Ok(shared_banks
|
|
||||||
.iter()
|
|
||||||
.find(|((id, name), _)| *id == user_id && *name == *bank_name)
|
|
||||||
.map(|(_, b)| b.clone())
|
|
||||||
.unwrap_or_default())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_character_inventory(&mut self, char_id: &CharacterEntityId, inventory: &InventoryEntity) -> Result<(), GatewayError> {
|
async fn set_character_inventory(&mut self, char_id: &CharacterEntityId, inventory: &InventoryEntity) -> Result<(), GatewayError> {
|
||||||
@ -636,26 +604,10 @@ impl EntityGateway for InMemoryGateway {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_character_bank(&mut self, char_id: &CharacterEntityId, bank: &BankEntity, bank_identifier: &BankIdentifier) -> Result<(), GatewayError> {
|
// TOOD: impl bank name
|
||||||
match bank_identifier {
|
async fn set_character_bank(&mut self, char_id: &CharacterEntityId, bank: &BankEntity, _bank_name: &BankName) -> Result<(), GatewayError> {
|
||||||
BankIdentifier::Character => {
|
let mut banks = self.banks.lock().await;
|
||||||
let mut character_banks = self.character_banks.lock().await;
|
banks.insert(*char_id, bank.clone());
|
||||||
character_banks.insert(*char_id, bank.clone());
|
|
||||||
},
|
|
||||||
BankIdentifier::Shared(bank_name) => {
|
|
||||||
let user_id = self.characters
|
|
||||||
.lock()
|
|
||||||
.await
|
|
||||||
.iter()
|
|
||||||
.find(|(id, _)| **id == *char_id)
|
|
||||||
.unwrap()
|
|
||||||
.1
|
|
||||||
.user_id;
|
|
||||||
let mut shared_banks = self.shared_banks.lock().await;
|
|
||||||
shared_banks.insert((user_id, bank_name.clone()), bank.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -690,58 +642,19 @@ impl EntityGateway for InMemoryGateway {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_bank_meseta(&mut self, char_id: &CharacterEntityId, bank_identifier: &BankIdentifier, meseta: Meseta) -> Result<(), GatewayError> {
|
async fn set_bank_meseta(&mut self, char_id: &CharacterEntityId, bank: &BankName, meseta: Meseta) -> Result<(), GatewayError> {
|
||||||
match bank_identifier {
|
let mut bank_meseta = self.bank_meseta.lock().await;
|
||||||
BankIdentifier::Character => {
|
bank_meseta.insert((*char_id, bank.clone()), meseta);
|
||||||
let mut bank_meseta = self.bank_meseta.lock().await;
|
|
||||||
bank_meseta.insert(*char_id, meseta);
|
|
||||||
}
|
|
||||||
BankIdentifier::Shared(bank_name) => {
|
|
||||||
let user_id = self.characters
|
|
||||||
.lock()
|
|
||||||
.await
|
|
||||||
.iter()
|
|
||||||
.find(|(id, _)| **id == *char_id)
|
|
||||||
.unwrap()
|
|
||||||
.1
|
|
||||||
.user_id;
|
|
||||||
self.shared_bank_meseta
|
|
||||||
.lock()
|
|
||||||
.await
|
|
||||||
.insert((user_id, bank_name.clone()), meseta);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_bank_meseta(&mut self, char_id: &CharacterEntityId, bank_identifier: &BankIdentifier) -> Result<Meseta, GatewayError> {
|
async fn get_bank_meseta(&mut self, char_id: &CharacterEntityId, bank: &BankName) -> Result<Meseta, GatewayError> {
|
||||||
match bank_identifier {
|
let mut bank_meseta = self.bank_meseta.lock().await;
|
||||||
BankIdentifier::Character => {
|
if let Some(meseta) = bank_meseta.get_mut(&(*char_id, bank.clone())) {
|
||||||
let mut bank_meseta = self.bank_meseta.lock().await;
|
Ok(*meseta)
|
||||||
if let Some(meseta) = bank_meseta.get_mut(char_id) {
|
}
|
||||||
Ok(*meseta)
|
else {
|
||||||
}
|
Err(GatewayError::Error)
|
||||||
else {
|
|
||||||
Err(GatewayError::Error)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
BankIdentifier::Shared(bank_name) => {
|
|
||||||
let mut shared_bank_meseta = self.shared_bank_meseta.lock().await;
|
|
||||||
let user_id = self.characters
|
|
||||||
.lock()
|
|
||||||
.await
|
|
||||||
.iter()
|
|
||||||
.find(|(id, _)| **id == *char_id)
|
|
||||||
.unwrap()
|
|
||||||
.1
|
|
||||||
.user_id;
|
|
||||||
if let Some(meseta) = shared_bank_meseta.get_mut(&(user_id, bank_name.clone())) {
|
|
||||||
Ok(*meseta)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Ok(Meseta(0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -767,21 +680,4 @@ impl EntityGateway for InMemoryGateway {
|
|||||||
Err(GatewayError::Error)
|
Err(GatewayError::Error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// I do not care to replicate this in testing
|
|
||||||
async fn create_room(&mut self, room: NewRoomEntity) -> Result<RoomEntity, GatewayError> {
|
|
||||||
Ok(RoomEntity {
|
|
||||||
id: RoomEntityId(0),
|
|
||||||
name: room.name,
|
|
||||||
section_id: room.section_id,
|
|
||||||
episode: room.episode,
|
|
||||||
difficulty: room.difficulty,
|
|
||||||
mode: room.mode,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// I do not care to replicate this in testing
|
|
||||||
async fn add_room_note(&mut self, _room_id: RoomEntityId, _note: RoomNote) -> Result<(), GatewayError> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
3
src/entity/gateway/postgres/migrations/mod.rs
Normal file
3
src/entity/gateway/postgres/migrations/mod.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
use refinery::include_migration_mods;
|
||||||
|
|
||||||
|
include_migration_mods!("src/entity/gateway/postgres/migrations");
|
@ -4,13 +4,10 @@ use std::convert::Into;
|
|||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use libpso::character::settings;
|
use libpso::character::settings;
|
||||||
use libpso::util::vec_to_array;
|
use libpso::util::vec_to_array;
|
||||||
use crate::account::*;
|
use crate::entity::account::*;
|
||||||
use crate::character::*;
|
use crate::entity::character::*;
|
||||||
use crate::item::*;
|
use crate::entity::item::*;
|
||||||
use crate::room::*;
|
use crate::ship::map::MapArea;
|
||||||
use maps::area::MapArea;
|
|
||||||
use maps::room::{Episode, Difficulty};
|
|
||||||
use maps::monster::MonsterType;
|
|
||||||
|
|
||||||
#[derive(Debug, sqlx::FromRow)]
|
#[derive(Debug, sqlx::FromRow)]
|
||||||
pub struct PgUserAccount {
|
pub struct PgUserAccount {
|
||||||
@ -253,7 +250,7 @@ impl From<PgCharacter> for CharacterEntity {
|
|||||||
raw_data: vec_to_array(other.config)
|
raw_data: vec_to_array(other.config)
|
||||||
},
|
},
|
||||||
info_board: CharacterInfoboard {
|
info_board: CharacterInfoboard {
|
||||||
board: libpso::util::utf8_to_utf16_array(other.infoboard),
|
board: libpso::utf8_to_utf16_array!(other.infoboard, 172),
|
||||||
},
|
},
|
||||||
guildcard: CharacterGuildCard {
|
guildcard: CharacterGuildCard {
|
||||||
description: other.guildcard,
|
description: other.guildcard,
|
||||||
@ -580,16 +577,6 @@ pub enum PgItemNoteDetail {
|
|||||||
},
|
},
|
||||||
EnemyDrop {
|
EnemyDrop {
|
||||||
character_id: u32,
|
character_id: u32,
|
||||||
room_id: u32,
|
|
||||||
monster_type: MonsterType,
|
|
||||||
map_area: MapArea,
|
|
||||||
x: f32,
|
|
||||||
y: f32,
|
|
||||||
z: f32,
|
|
||||||
},
|
|
||||||
BoxDrop {
|
|
||||||
character_id: u32,
|
|
||||||
room_id: u32,
|
|
||||||
map_area: MapArea,
|
map_area: MapArea,
|
||||||
x: f32,
|
x: f32,
|
||||||
y: f32,
|
y: f32,
|
||||||
@ -605,19 +592,14 @@ pub enum PgItemNoteDetail {
|
|||||||
y: f32,
|
y: f32,
|
||||||
z: f32,
|
z: f32,
|
||||||
},
|
},
|
||||||
Consumed {
|
Consumed,
|
||||||
character_id: u32,
|
|
||||||
},
|
|
||||||
FedToMag {
|
FedToMag {
|
||||||
character_id: u32,
|
|
||||||
mag: u32,
|
mag: u32,
|
||||||
},
|
},
|
||||||
BoughtAtShop {
|
BoughtAtShop {
|
||||||
character_id: u32,
|
character_id: u32,
|
||||||
},
|
},
|
||||||
SoldToShop {
|
SoldToShop,
|
||||||
character_id: u32,
|
|
||||||
},
|
|
||||||
Trade {
|
Trade {
|
||||||
trade_id: u32,
|
trade_id: u32,
|
||||||
character_to: u32,
|
character_to: u32,
|
||||||
@ -625,14 +607,11 @@ pub enum PgItemNoteDetail {
|
|||||||
},
|
},
|
||||||
Withdraw {
|
Withdraw {
|
||||||
character_id: u32,
|
character_id: u32,
|
||||||
bank: BankIdentifier,
|
bank: String,
|
||||||
},
|
},
|
||||||
Deposit {
|
Deposit {
|
||||||
character_id: u32,
|
character_id: u32,
|
||||||
bank: BankIdentifier,
|
bank: String,
|
||||||
},
|
|
||||||
FloorLimitReached {
|
|
||||||
map_area: MapArea,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -642,16 +621,8 @@ impl From<ItemNote> for PgItemNoteDetail {
|
|||||||
ItemNote::CharacterCreation{character_id} => PgItemNoteDetail::CharacterCreation {
|
ItemNote::CharacterCreation{character_id} => PgItemNoteDetail::CharacterCreation {
|
||||||
character_id: character_id.0,
|
character_id: character_id.0,
|
||||||
},
|
},
|
||||||
ItemNote::EnemyDrop{character_id, room_id, monster_type, map_area, x, y, z} => PgItemNoteDetail::EnemyDrop {
|
ItemNote::EnemyDrop{character_id, map_area, x, y, z} => PgItemNoteDetail::EnemyDrop {
|
||||||
character_id: character_id.0,
|
character_id: character_id.0,
|
||||||
room_id: room_id.0,
|
|
||||||
monster_type,
|
|
||||||
map_area,
|
|
||||||
x,y,z,
|
|
||||||
},
|
|
||||||
ItemNote::BoxDrop{character_id, room_id, map_area, x, y, z} => PgItemNoteDetail::BoxDrop {
|
|
||||||
character_id: character_id.0,
|
|
||||||
room_id: room_id.0,
|
|
||||||
map_area,
|
map_area,
|
||||||
x,y,z,
|
x,y,z,
|
||||||
},
|
},
|
||||||
@ -663,19 +634,14 @@ impl From<ItemNote> for PgItemNoteDetail {
|
|||||||
map_area,
|
map_area,
|
||||||
x,y,z,
|
x,y,z,
|
||||||
},
|
},
|
||||||
ItemNote::Consumed{character_id} => PgItemNoteDetail::Consumed {
|
ItemNote::Consumed => PgItemNoteDetail::Consumed,
|
||||||
character_id: character_id.0,
|
ItemNote::FedToMag{mag} => PgItemNoteDetail::FedToMag{
|
||||||
},
|
|
||||||
ItemNote::FedToMag{character_id, mag} => PgItemNoteDetail::FedToMag{
|
|
||||||
character_id: character_id.0,
|
|
||||||
mag: mag.0
|
mag: mag.0
|
||||||
},
|
},
|
||||||
ItemNote::BoughtAtShop{character_id} => PgItemNoteDetail::BoughtAtShop {
|
ItemNote::BoughtAtShop{character_id} => PgItemNoteDetail::BoughtAtShop {
|
||||||
character_id: character_id.0,
|
character_id: character_id.0,
|
||||||
},
|
},
|
||||||
ItemNote::SoldToShop{character_id} => PgItemNoteDetail::SoldToShop {
|
ItemNote::SoldToShop => PgItemNoteDetail::SoldToShop,
|
||||||
character_id: character_id.0,
|
|
||||||
},
|
|
||||||
ItemNote::Trade{trade_id, character_to, character_from} => PgItemNoteDetail::Trade {
|
ItemNote::Trade{trade_id, character_to, character_from} => PgItemNoteDetail::Trade {
|
||||||
trade_id: trade_id.0,
|
trade_id: trade_id.0,
|
||||||
character_to: character_to.0,
|
character_to: character_to.0,
|
||||||
@ -684,20 +650,15 @@ impl From<ItemNote> for PgItemNoteDetail {
|
|||||||
ItemNote::Withdraw{character_id, bank} => {
|
ItemNote::Withdraw{character_id, bank} => {
|
||||||
PgItemNoteDetail::Withdraw {
|
PgItemNoteDetail::Withdraw {
|
||||||
character_id: character_id.0,
|
character_id: character_id.0,
|
||||||
bank,
|
bank: bank.0,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ItemNote::Deposit{character_id, bank} => {
|
ItemNote::Deposit{character_id, bank} => {
|
||||||
PgItemNoteDetail::Deposit {
|
PgItemNoteDetail::Deposit {
|
||||||
character_id: character_id.0,
|
character_id: character_id.0,
|
||||||
bank,
|
bank: bank.0,
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
ItemNote::FloorLimitReached { map_area } => {
|
|
||||||
PgItemNoteDetail::FloorLimitReached {
|
|
||||||
map_area,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -708,16 +669,8 @@ impl From<PgItemNoteDetail> for ItemNote {
|
|||||||
PgItemNoteDetail::CharacterCreation{character_id} => ItemNote::CharacterCreation {
|
PgItemNoteDetail::CharacterCreation{character_id} => ItemNote::CharacterCreation {
|
||||||
character_id: CharacterEntityId(character_id),
|
character_id: CharacterEntityId(character_id),
|
||||||
},
|
},
|
||||||
PgItemNoteDetail::EnemyDrop{character_id, room_id, monster_type, map_area, x, y, z} => ItemNote::EnemyDrop {
|
PgItemNoteDetail::EnemyDrop{character_id, map_area, x, y, z} => ItemNote::EnemyDrop {
|
||||||
character_id: CharacterEntityId(character_id),
|
character_id: CharacterEntityId(character_id),
|
||||||
room_id: RoomEntityId(room_id),
|
|
||||||
monster_type,
|
|
||||||
map_area,
|
|
||||||
x,y,z,
|
|
||||||
},
|
|
||||||
PgItemNoteDetail::BoxDrop{character_id, room_id, map_area, x, y, z} => ItemNote::BoxDrop {
|
|
||||||
character_id: CharacterEntityId(character_id),
|
|
||||||
room_id: RoomEntityId(room_id),
|
|
||||||
map_area,
|
map_area,
|
||||||
x,y,z,
|
x,y,z,
|
||||||
},
|
},
|
||||||
@ -729,19 +682,14 @@ impl From<PgItemNoteDetail> for ItemNote {
|
|||||||
map_area,
|
map_area,
|
||||||
x,y,z,
|
x,y,z,
|
||||||
},
|
},
|
||||||
PgItemNoteDetail::Consumed{character_id} => ItemNote::Consumed {
|
PgItemNoteDetail::Consumed => ItemNote::Consumed,
|
||||||
character_id: CharacterEntityId(character_id),
|
PgItemNoteDetail::FedToMag{mag} => ItemNote::FedToMag{
|
||||||
},
|
|
||||||
PgItemNoteDetail::FedToMag{character_id, mag} => ItemNote::FedToMag{
|
|
||||||
character_id: CharacterEntityId(character_id),
|
|
||||||
mag: ItemEntityId(mag)
|
mag: ItemEntityId(mag)
|
||||||
},
|
},
|
||||||
PgItemNoteDetail::BoughtAtShop{character_id} => ItemNote::BoughtAtShop {
|
PgItemNoteDetail::BoughtAtShop{character_id} => ItemNote::BoughtAtShop {
|
||||||
character_id: CharacterEntityId(character_id),
|
character_id: CharacterEntityId(character_id),
|
||||||
},
|
},
|
||||||
PgItemNoteDetail::SoldToShop{character_id} => ItemNote::SoldToShop {
|
PgItemNoteDetail::SoldToShop => ItemNote::SoldToShop,
|
||||||
character_id: CharacterEntityId(character_id),
|
|
||||||
},
|
|
||||||
PgItemNoteDetail::Trade {trade_id, character_to, character_from} => ItemNote::Trade {
|
PgItemNoteDetail::Trade {trade_id, character_to, character_from} => ItemNote::Trade {
|
||||||
trade_id: TradeId(trade_id),
|
trade_id: TradeId(trade_id),
|
||||||
character_to: CharacterEntityId(character_to),
|
character_to: CharacterEntityId(character_to),
|
||||||
@ -749,14 +697,11 @@ impl From<PgItemNoteDetail> for ItemNote {
|
|||||||
},
|
},
|
||||||
PgItemNoteDetail::Withdraw{character_id, bank} => ItemNote::Withdraw {
|
PgItemNoteDetail::Withdraw{character_id, bank} => ItemNote::Withdraw {
|
||||||
character_id: CharacterEntityId(character_id),
|
character_id: CharacterEntityId(character_id),
|
||||||
bank,
|
bank: BankName(bank),
|
||||||
},
|
},
|
||||||
PgItemNoteDetail::Deposit{character_id, bank} => ItemNote::Deposit {
|
PgItemNoteDetail::Deposit{character_id, bank} => ItemNote::Deposit {
|
||||||
character_id: CharacterEntityId(character_id),
|
character_id: CharacterEntityId(character_id),
|
||||||
bank,
|
bank: BankName(bank),
|
||||||
},
|
|
||||||
PgItemNoteDetail::FloorLimitReached { map_area } => ItemNote::FloorLimitReached {
|
|
||||||
map_area,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -924,27 +869,3 @@ impl From<PgTradeEntity> for TradeEntity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, sqlx::FromRow, Serialize)]
|
|
||||||
pub struct PgRoomEntity {
|
|
||||||
id: i32,
|
|
||||||
name: String,
|
|
||||||
section_id: i8,
|
|
||||||
mode: i8,
|
|
||||||
episode: i8,
|
|
||||||
difficulty: i8,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<PgRoomEntity> for RoomEntity {
|
|
||||||
fn from(other: PgRoomEntity) -> RoomEntity {
|
|
||||||
RoomEntity {
|
|
||||||
id: RoomEntityId(other.id as u32),
|
|
||||||
name: other.name,
|
|
||||||
section_id: SectionID::from(other.section_id as u8),
|
|
||||||
mode: RoomEntityMode::from(other.mode as u8),
|
|
||||||
episode: Episode::try_from(other.episode as u8).unwrap(),
|
|
||||||
difficulty: Difficulty::try_from(other.difficulty as u8).unwrap(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,16 +1,15 @@
|
|||||||
// this lint is currently bugged and suggests incorrect code https://github.com/rust-lang/rust-clippy/issues/9123
|
// this lint is currently bugged and suggests incorrect code https://github.com/rust-lang/rust-clippy/issues/9123
|
||||||
#![allow(clippy::explicit_auto_deref)]
|
#![allow(clippy::explicit_auto_deref)]
|
||||||
|
|
||||||
use std::convert::{From, Into};
|
use std::convert::{From, TryFrom, Into};
|
||||||
use futures::future::{Future, BoxFuture};
|
use futures::Future;
|
||||||
use futures::stream::{StreamExt, FuturesOrdered};
|
use async_std::stream::StreamExt;
|
||||||
use async_std::sync::{Arc, Mutex};
|
use async_std::sync::{Arc, Mutex};
|
||||||
use libpso::character::guildcard;
|
use libpso::character::guildcard;
|
||||||
use crate::account::*;
|
use crate::entity::account::*;
|
||||||
use crate::character::*;
|
use crate::entity::character::*;
|
||||||
use crate::gateway::{EntityGateway, EntityGatewayTransaction, GatewayError};
|
use crate::entity::gateway::{EntityGateway, EntityGatewayTransaction, GatewayError};
|
||||||
use crate::item::*;
|
use crate::entity::item::*;
|
||||||
use crate::room::*;
|
|
||||||
use super::models::*;
|
use super::models::*;
|
||||||
|
|
||||||
use sqlx::postgres::PgPoolOptions;
|
use sqlx::postgres::PgPoolOptions;
|
||||||
@ -19,7 +18,7 @@ use sqlx::Connection;
|
|||||||
|
|
||||||
mod embedded {
|
mod embedded {
|
||||||
use refinery::embed_migrations;
|
use refinery::embed_migrations;
|
||||||
embed_migrations!("src/gateway/postgres/migrations");
|
embed_migrations!("src/entity/gateway/postgres/migrations");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -37,7 +36,9 @@ impl<'t> EntityGatewayTransaction for PostgresTransaction<'t> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//async fn commit(self: Box<Self>) -> Result<(), GatewayError> {
|
||||||
async fn commit(self) -> Result<(), GatewayError> {
|
async fn commit(self) -> Result<(), GatewayError> {
|
||||||
|
//self.pgtransaction.lock().await.commit().await?;
|
||||||
Arc::try_unwrap(self.pgtransaction)
|
Arc::try_unwrap(self.pgtransaction)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.into_inner()
|
.into_inner()
|
||||||
@ -49,12 +50,13 @@ impl<'t> EntityGatewayTransaction for PostgresTransaction<'t> {
|
|||||||
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct PostgresGateway {
|
pub struct PostgresGateway<'t> {
|
||||||
pool: sqlx::Pool<sqlx::Postgres>,
|
pool: sqlx::Pool<sqlx::Postgres>,
|
||||||
|
_t: std::marker::PhantomData<&'t ()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PostgresGateway {
|
impl<'t> PostgresGateway<'t> {
|
||||||
pub fn new(host: &str, dbname: &str, username: &str, password: &str) -> PostgresGateway {
|
pub fn new(host: &str, dbname: &str, username: &str, password: &str) -> PostgresGateway<'t> {
|
||||||
let mut conn = refinery::config::Config::new(refinery::config::ConfigDbType::Postgres)
|
let mut conn = refinery::config::Config::new(refinery::config::ConfigDbType::Postgres)
|
||||||
.set_db_host(host)
|
.set_db_host(host)
|
||||||
.set_db_user(username)
|
.set_db_user(username)
|
||||||
@ -70,6 +72,7 @@ impl PostgresGateway {
|
|||||||
|
|
||||||
PostgresGateway {
|
PostgresGateway {
|
||||||
pool,
|
pool,
|
||||||
|
_t: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -90,7 +93,7 @@ async fn apply_item_modifications(conn: &mut sqlx::PgConnection, item: ItemEntit
|
|||||||
.bind(id.0 as i32)
|
.bind(id.0 as i32)
|
||||||
.fetch(conn);
|
.fetch(conn);
|
||||||
|
|
||||||
weapon_modifiers.for_each(|modifier| async move {
|
weapon_modifiers.for_each(|modifier| {
|
||||||
if let Ok(modifier) = modifier {
|
if let Ok(modifier) = modifier {
|
||||||
weapon.apply_modifier(&modifier.modifier);
|
weapon.apply_modifier(&modifier.modifier);
|
||||||
}
|
}
|
||||||
@ -98,7 +101,7 @@ async fn apply_item_modifications(conn: &mut sqlx::PgConnection, item: ItemEntit
|
|||||||
|
|
||||||
ItemDetail::Weapon(weapon)
|
ItemDetail::Weapon(weapon)
|
||||||
},
|
},
|
||||||
ItemDetail::Mag(mag) => {
|
ItemDetail::Mag(mut mag) => {
|
||||||
let q = r#"select mag, modifier, item.item -> 'Tool' as feed, item2.item -> 'Tool' as cell
|
let q = r#"select mag, modifier, item.item -> 'Tool' as feed, item2.item -> 'Tool' as cell
|
||||||
from mag_modifier
|
from mag_modifier
|
||||||
left join item on item.id = cast (modifier ->> 'FeedMag' as integer)
|
left join item on item.id = cast (modifier ->> 'FeedMag' as integer)
|
||||||
@ -108,7 +111,7 @@ async fn apply_item_modifications(conn: &mut sqlx::PgConnection, item: ItemEntit
|
|||||||
.bind(id.0 as i32)
|
.bind(id.0 as i32)
|
||||||
.fetch(conn);
|
.fetch(conn);
|
||||||
|
|
||||||
let mag = mag_modifiers.fold(mag, |mut mag, modifier| async {
|
mag_modifiers.for_each(|modifier| {
|
||||||
let PgMagModifierWithParameters {modifier, feed, cell, ..} = modifier.unwrap();
|
let PgMagModifierWithParameters {modifier, feed, cell, ..} = modifier.unwrap();
|
||||||
let modifier: mag::MagModifier = modifier.0.into();
|
let modifier: mag::MagModifier = modifier.0.into();
|
||||||
match modifier {
|
match modifier {
|
||||||
@ -125,8 +128,6 @@ async fn apply_item_modifications(conn: &mut sqlx::PgConnection, item: ItemEntit
|
|||||||
mag.change_owner(class, section_id)
|
mag.change_owner(class, section_id)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
mag
|
|
||||||
}).await;
|
}).await;
|
||||||
|
|
||||||
ItemDetail::Mag(mag)
|
ItemDetail::Mag(mag)
|
||||||
@ -140,31 +141,6 @@ async fn apply_item_modifications(conn: &mut sqlx::PgConnection, item: ItemEntit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn fetch_item<T>(conn: &mut sqlx::PgConnection, item: PgInventoryItemEntity, individual: fn(ItemEntity) -> T, stacked: fn(Vec<ItemEntity>) -> T) -> Result<T, GatewayError>
|
|
||||||
{
|
|
||||||
match item {
|
|
||||||
PgInventoryItemEntity::Individual(item) => {
|
|
||||||
let entity = sqlx::query_as::<_, PgItemEntity>("select item.id, item.item from item where id = $1")
|
|
||||||
.bind(item)
|
|
||||||
.fetch_one(&mut *conn).await
|
|
||||||
.map(|item| item.into())
|
|
||||||
.map(|item| apply_item_modifications(&mut *conn, item))?
|
|
||||||
.await;
|
|
||||||
Ok(individual(entity))
|
|
||||||
},
|
|
||||||
PgInventoryItemEntity::Stacked(items) => {
|
|
||||||
let mut stacked_item = Vec::new();
|
|
||||||
for s_item in items {
|
|
||||||
stacked_item.push(sqlx::query_as::<_, PgItemEntity>("select item.id, item.item from item where id = $1")
|
|
||||||
.bind(s_item)
|
|
||||||
.fetch_one(&mut *conn).await
|
|
||||||
.map(|item| item.into())?)
|
|
||||||
}
|
|
||||||
Ok(stacked(stacked_item))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn create_user(conn: &mut sqlx::PgConnection, user: NewUserAccountEntity) -> Result<UserAccountEntity, GatewayError>
|
async fn create_user(conn: &mut sqlx::PgConnection, user: NewUserAccountEntity) -> Result<UserAccountEntity, GatewayError>
|
||||||
{
|
{
|
||||||
let new_user = sqlx::query_as::<_, PgUserAccount>("insert into user_accounts (email, username, password, activated) values ($1, $2, $3, $4) returning *;")
|
let new_user = sqlx::query_as::<_, PgUserAccount>("insert into user_accounts (email, username, password, activated) values ($1, $2, $3, $4) returning *;")
|
||||||
@ -179,7 +155,7 @@ async fn create_user(conn: &mut sqlx::PgConnection, user: NewUserAccountEntity)
|
|||||||
async fn get_user_by_id(conn: &mut sqlx::PgConnection, id: UserAccountId) -> Result<UserAccountEntity, GatewayError>
|
async fn get_user_by_id(conn: &mut sqlx::PgConnection, id: UserAccountId) -> Result<UserAccountEntity, GatewayError>
|
||||||
{
|
{
|
||||||
let user = sqlx::query_as::<_, PgUserAccount>("select * from user_accounts where id = $1")
|
let user = sqlx::query_as::<_, PgUserAccount>("select * from user_accounts where id = $1")
|
||||||
.bind(id.0 as i32)
|
.bind(id.0)
|
||||||
.fetch_one(conn).await?;
|
.fetch_one(conn).await?;
|
||||||
Ok(user.into())
|
Ok(user.into())
|
||||||
}
|
}
|
||||||
@ -200,8 +176,8 @@ async fn save_user(conn: &mut sqlx::PgConnection, user: &UserAccountEntity) -> R
|
|||||||
.bind(&user.password)
|
.bind(&user.password)
|
||||||
.bind(user.banned_until)
|
.bind(user.banned_until)
|
||||||
.bind(user.muted_until)
|
.bind(user.muted_until)
|
||||||
.bind(user.flags as i32)
|
.bind(user.flags)
|
||||||
.bind(user.id.0 as i32)
|
.bind(user.id.0)
|
||||||
.execute(conn).await?;
|
.execute(conn).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -210,7 +186,7 @@ async fn create_user_settings(conn: &mut sqlx::PgConnection, settings: NewUserSe
|
|||||||
{
|
{
|
||||||
let new_settings = sqlx::query_as::<_, PgUserSettings>("insert into user_settings (user_account, blocked_users, key_config, joystick_config, option_flags, shortcuts, symbol_chats, team_name)
|
let new_settings = sqlx::query_as::<_, PgUserSettings>("insert into user_settings (user_account, blocked_users, key_config, joystick_config, option_flags, shortcuts, symbol_chats, team_name)
|
||||||
values ($1, $2, $3, $4, $5, $6, $7, $8) returning *;")
|
values ($1, $2, $3, $4, $5, $6, $7, $8) returning *;")
|
||||||
.bind(settings.user_id.0 as i32)
|
.bind(settings.user_id.0)
|
||||||
.bind(settings.settings.blocked_users.iter().copied().flat_map(|i| i.to_le_bytes().to_vec()).collect::<Vec<u8>>())
|
.bind(settings.settings.blocked_users.iter().copied().flat_map(|i| i.to_le_bytes().to_vec()).collect::<Vec<u8>>())
|
||||||
.bind(settings.settings.keyboard_config.to_vec())
|
.bind(settings.settings.keyboard_config.to_vec())
|
||||||
.bind(settings.settings.gamepad_config.to_vec())
|
.bind(settings.settings.gamepad_config.to_vec())
|
||||||
@ -225,7 +201,7 @@ async fn create_user_settings(conn: &mut sqlx::PgConnection, settings: NewUserSe
|
|||||||
async fn get_user_settings_by_user(conn: &mut sqlx::PgConnection, user: &UserAccountEntity) -> Result<UserSettingsEntity, GatewayError>
|
async fn get_user_settings_by_user(conn: &mut sqlx::PgConnection, user: &UserAccountEntity) -> Result<UserSettingsEntity, GatewayError>
|
||||||
{
|
{
|
||||||
let settings = sqlx::query_as::<_, PgUserSettings>("select * from user_settings where user_account = $1")
|
let settings = sqlx::query_as::<_, PgUserSettings>("select * from user_settings where user_account = $1")
|
||||||
.bind(user.id.0 as i32)
|
.bind(user.id.0)
|
||||||
.fetch_one(conn).await?;
|
.fetch_one(conn).await?;
|
||||||
Ok(settings.into())
|
Ok(settings.into())
|
||||||
}
|
}
|
||||||
@ -236,11 +212,11 @@ async fn save_user_settings(conn: &mut sqlx::PgConnection, settings: &UserSettin
|
|||||||
.bind(settings.settings.blocked_users.iter().copied().flat_map(|i| i.to_le_bytes().to_vec()).collect::<Vec<u8>>())
|
.bind(settings.settings.blocked_users.iter().copied().flat_map(|i| i.to_le_bytes().to_vec()).collect::<Vec<u8>>())
|
||||||
.bind(&settings.settings.keyboard_config.to_vec())
|
.bind(&settings.settings.keyboard_config.to_vec())
|
||||||
.bind(&settings.settings.gamepad_config.to_vec())
|
.bind(&settings.settings.gamepad_config.to_vec())
|
||||||
.bind(settings.settings.option_flags as i32)
|
.bind(settings.settings.option_flags)
|
||||||
.bind(&settings.settings.shortcuts.to_vec())
|
.bind(&settings.settings.shortcuts.to_vec())
|
||||||
.bind(&settings.settings.symbol_chats.to_vec())
|
.bind(&settings.settings.symbol_chats.to_vec())
|
||||||
.bind(settings.settings.team_name.iter().copied().flat_map(|i| i.to_le_bytes().to_vec()).collect::<Vec<u8>>())
|
.bind(settings.settings.team_name.iter().copied().flat_map(|i| i.to_le_bytes().to_vec()).collect::<Vec<u8>>())
|
||||||
.bind(settings.id.0 as i32)
|
.bind(settings.id.0)
|
||||||
.execute(conn).await?;
|
.execute(conn).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -252,10 +228,10 @@ async fn create_character(conn: &mut sqlx::PgConnection, char: NewCharacterEntit
|
|||||||
section_id, costume, skin, face, head,
|
section_id, costume, skin, face, head,
|
||||||
hair, hair_r, hair_g, hair_b, prop_x,
|
hair, hair_r, hair_g, hair_b, prop_x,
|
||||||
prop_y, techs, config, infoboard, guildcard,
|
prop_y, techs, config, infoboard, guildcard,
|
||||||
power, mind, def, evade, luck,
|
power, mind, def, evade, luck,
|
||||||
hp, tp, tech_menu, option_flags, playtime)
|
hp, tp, tech_menu, option_flags, playtime)
|
||||||
values
|
values
|
||||||
($1, $2, $3, $4, $5,
|
($1, $2, $3, $4, $5,
|
||||||
$6, $7, $8, $9, $10,
|
$6, $7, $8, $9, $10,
|
||||||
$11, $12, $13, $14, $15,
|
$11, $12, $13, $14, $15,
|
||||||
$16, $17, $18, $19, $20,
|
$16, $17, $18, $19, $20,
|
||||||
@ -263,7 +239,7 @@ async fn create_character(conn: &mut sqlx::PgConnection, char: NewCharacterEntit
|
|||||||
$26, $27, $28, $29, $30)
|
$26, $27, $28, $29, $30)
|
||||||
returning *;"#;
|
returning *;"#;
|
||||||
let character = sqlx::query_as::<_, PgCharacter>(q)
|
let character = sqlx::query_as::<_, PgCharacter>(q)
|
||||||
.bind(char.user_id.0 as i32)
|
.bind(char.user_id.0)
|
||||||
.bind(char.slot as i16)
|
.bind(char.slot as i16)
|
||||||
.bind(char.name)
|
.bind(char.name)
|
||||||
.bind(char.exp as i32)
|
.bind(char.exp as i32)
|
||||||
@ -301,10 +277,10 @@ async fn create_character(conn: &mut sqlx::PgConnection, char: NewCharacterEntit
|
|||||||
async fn get_characters_by_user(conn: &mut sqlx::PgConnection, user: &UserAccountEntity) -> Result<[Option<CharacterEntity>; 4], GatewayError>
|
async fn get_characters_by_user(conn: &mut sqlx::PgConnection, user: &UserAccountEntity) -> Result<[Option<CharacterEntity>; 4], GatewayError>
|
||||||
{
|
{
|
||||||
let stream = sqlx::query_as::<_, PgCharacter>("select * from player_character where user_account = $1 and slot < 4 order by created_at;")
|
let stream = sqlx::query_as::<_, PgCharacter>("select * from player_character where user_account = $1 and slot < 4 order by created_at;")
|
||||||
.bind(user.id.0 as i32)
|
.bind(user.id.0)
|
||||||
.fetch(conn);
|
.fetch(conn);
|
||||||
|
|
||||||
Ok(stream.fold(core::array::from_fn(|_| None), |mut acc, char| async move {
|
Ok(stream.fold(core::array::from_fn(|_| None), |mut acc, char| {
|
||||||
if let Ok(char) = char {
|
if let Ok(char) = char {
|
||||||
let slot = char.slot as usize;
|
let slot = char.slot as usize;
|
||||||
acc[slot] = Some(char.into())
|
acc[slot] = Some(char.into())
|
||||||
@ -321,7 +297,7 @@ async fn save_character(conn: &mut sqlx::PgConnection, char: &CharacterEntity) -
|
|||||||
evade=$24, luck=$25, hp=$26, tp=$27, tech_menu=$28, option_flags=$29, playtime=$30
|
evade=$24, luck=$25, hp=$26, tp=$27, tech_menu=$28, option_flags=$29, playtime=$30
|
||||||
where id=$31;"#;
|
where id=$31;"#;
|
||||||
sqlx::query(q)
|
sqlx::query(q)
|
||||||
.bind(char.user_id.0 as i32) // $1
|
.bind(char.user_id.0) // $1
|
||||||
.bind(char.slot as i16) // $2
|
.bind(char.slot as i16) // $2
|
||||||
.bind(&char.name) // $3
|
.bind(&char.name) // $3
|
||||||
.bind(char.exp as i32) // $4
|
.bind(char.exp as i32) // $4
|
||||||
@ -371,7 +347,7 @@ async fn create_item(conn: &mut sqlx::PgConnection, item: NewItemEntity) -> Resu
|
|||||||
async fn add_item_note(conn: &mut sqlx::PgConnection, item_id: &ItemEntityId, item_note: ItemNote) -> Result<(), GatewayError>
|
async fn add_item_note(conn: &mut sqlx::PgConnection, item_id: &ItemEntityId, item_note: ItemNote) -> Result<(), GatewayError>
|
||||||
{
|
{
|
||||||
sqlx::query("insert into item_note(item, note) values ($1, $2)")
|
sqlx::query("insert into item_note(item, note) values ($1, $2)")
|
||||||
.bind(item_id.0 as i32)
|
.bind(item_id.0)
|
||||||
.bind(sqlx::types::Json(PgItemNoteDetail::from(item_note)))
|
.bind(sqlx::types::Json(PgItemNoteDetail::from(item_note)))
|
||||||
.execute(conn).await?;
|
.execute(conn).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -380,7 +356,7 @@ async fn add_item_note(conn: &mut sqlx::PgConnection, item_id: &ItemEntityId, it
|
|||||||
async fn feed_mag(conn: &mut sqlx::PgConnection, mag_item_id: &ItemEntityId, tool_item_id: &ItemEntityId) -> Result<(), GatewayError>
|
async fn feed_mag(conn: &mut sqlx::PgConnection, mag_item_id: &ItemEntityId, tool_item_id: &ItemEntityId) -> Result<(), GatewayError>
|
||||||
{
|
{
|
||||||
sqlx::query("insert into mag_modifier (mag, modifier) values ($1, $2);")
|
sqlx::query("insert into mag_modifier (mag, modifier) values ($1, $2);")
|
||||||
.bind(mag_item_id.0 as i32)
|
.bind(mag_item_id.0)
|
||||||
.bind(sqlx::types::Json(PgMagModifierDetail::from(mag::MagModifier::FeedMag{food: *tool_item_id})))
|
.bind(sqlx::types::Json(PgMagModifierDetail::from(mag::MagModifier::FeedMag{food: *tool_item_id})))
|
||||||
.execute(conn).await?;
|
.execute(conn).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -389,7 +365,7 @@ async fn feed_mag(conn: &mut sqlx::PgConnection, mag_item_id: &ItemEntityId, too
|
|||||||
async fn change_mag_owner(conn: &mut sqlx::PgConnection, mag_item_id: &ItemEntityId, character: &CharacterEntity) -> Result<(), GatewayError>
|
async fn change_mag_owner(conn: &mut sqlx::PgConnection, mag_item_id: &ItemEntityId, character: &CharacterEntity) -> Result<(), GatewayError>
|
||||||
{
|
{
|
||||||
sqlx::query("insert into mag_modifier (mag, modifier) values ($1, $2);")
|
sqlx::query("insert into mag_modifier (mag, modifier) values ($1, $2);")
|
||||||
.bind(mag_item_id.0 as i32)
|
.bind(mag_item_id.0)
|
||||||
.bind(sqlx::types::Json(PgMagModifierDetail::from(mag::MagModifier::OwnerChange(character.char_class, character.section_id))))
|
.bind(sqlx::types::Json(PgMagModifierDetail::from(mag::MagModifier::OwnerChange(character.char_class, character.section_id))))
|
||||||
.execute(conn).await?;
|
.execute(conn).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -398,7 +374,7 @@ async fn change_mag_owner(conn: &mut sqlx::PgConnection, mag_item_id: &ItemEntit
|
|||||||
async fn use_mag_cell(conn: &mut sqlx::PgConnection, mag_item_id: &ItemEntityId, mag_cell_id: &ItemEntityId) -> Result<(), GatewayError>
|
async fn use_mag_cell(conn: &mut sqlx::PgConnection, mag_item_id: &ItemEntityId, mag_cell_id: &ItemEntityId) -> Result<(), GatewayError>
|
||||||
{
|
{
|
||||||
sqlx::query("insert into mag_modifier (mag, modifier) values ($1, $2);")
|
sqlx::query("insert into mag_modifier (mag, modifier) values ($1, $2);")
|
||||||
.bind(mag_item_id.0 as i32)
|
.bind(mag_item_id.0)
|
||||||
.bind(sqlx::types::Json(PgMagModifierDetail::from(mag::MagModifier::MagCell(*mag_cell_id))))
|
.bind(sqlx::types::Json(PgMagModifierDetail::from(mag::MagModifier::MagCell(*mag_cell_id))))
|
||||||
.execute(conn).await?;
|
.execute(conn).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -407,7 +383,7 @@ async fn use_mag_cell(conn: &mut sqlx::PgConnection, mag_item_id: &ItemEntityId,
|
|||||||
async fn add_weapon_modifier(conn: &mut sqlx::PgConnection, item_id: &ItemEntityId, modifier: &weapon::WeaponModifier) -> Result<(), GatewayError>
|
async fn add_weapon_modifier(conn: &mut sqlx::PgConnection, item_id: &ItemEntityId, modifier: &weapon::WeaponModifier) -> Result<(), GatewayError>
|
||||||
{
|
{
|
||||||
sqlx::query("insert into weapon_modifier (weapon, modifier) values ($1, $2);")
|
sqlx::query("insert into weapon_modifier (weapon, modifier) values ($1, $2);")
|
||||||
.bind(item_id.0 as i32)
|
.bind(item_id.0)
|
||||||
.bind(sqlx::types::Json(modifier))
|
.bind(sqlx::types::Json(modifier))
|
||||||
.execute(conn).await?;
|
.execute(conn).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -415,65 +391,76 @@ async fn add_weapon_modifier(conn: &mut sqlx::PgConnection, item_id: &ItemEntity
|
|||||||
|
|
||||||
async fn get_character_inventory(conn: &mut sqlx::PgConnection, char_id: &CharacterEntityId) -> Result<InventoryEntity, GatewayError>
|
async fn get_character_inventory(conn: &mut sqlx::PgConnection, char_id: &CharacterEntityId) -> Result<InventoryEntity, GatewayError>
|
||||||
{
|
{
|
||||||
let conn = Arc::new(Mutex::new(conn.begin().await?)); // this is some degen shit
|
let mut t = conn.begin().await?;
|
||||||
let inventory = sqlx::query_as::<_, PgInventoryEntity>("select * from inventory where pchar = $1")
|
let inventory = sqlx::query_as::<_, PgInventoryEntity>("select * from inventory where pchar = $1")
|
||||||
.bind(char_id.0 as i32)
|
.bind(char_id.0)
|
||||||
.fetch_one(&mut **conn.lock().await).await?;
|
.fetch_one(&mut t).await?;
|
||||||
|
|
||||||
Ok(InventoryEntity::new(
|
// TODO: inefficient
|
||||||
inventory.items.0
|
let mut real_inventory = Vec::new();
|
||||||
.into_iter()
|
for inv_item in inventory.items.0.into_iter() {
|
||||||
.map(move |item| {
|
match inv_item {
|
||||||
let conn = conn.clone();
|
PgInventoryItemEntity::Individual(item) => {
|
||||||
async move {
|
let entity = sqlx::query_as::<_, PgItemEntity>("select item.id, item.item from item where id = $1")
|
||||||
fetch_item(&mut **conn.lock().await, item, InventoryItemEntity::Individual, InventoryItemEntity::Stacked).await
|
.bind(item)
|
||||||
|
.fetch_one(&mut t).await
|
||||||
|
.map(|item| item.into())
|
||||||
|
.map(|item| apply_item_modifications(&mut t, item))?
|
||||||
|
.await;
|
||||||
|
real_inventory.push(InventoryItemEntity::Individual(entity));
|
||||||
|
},
|
||||||
|
PgInventoryItemEntity::Stacked(items) => {
|
||||||
|
let mut stacked_item = Vec::new();
|
||||||
|
for s_item in items {
|
||||||
|
stacked_item.push(sqlx::query_as::<_, PgItemEntity>("select item.id, item.item from item where id = $1")
|
||||||
|
.bind(s_item)
|
||||||
|
.fetch_one(&mut t).await
|
||||||
|
.map(|item| item.into())?)
|
||||||
}
|
}
|
||||||
})
|
real_inventory.push(InventoryItemEntity::Stacked(stacked_item));
|
||||||
.collect::<FuturesOrdered<_>>()
|
}
|
||||||
.collect::<Vec<_>>()
|
}
|
||||||
.await
|
}
|
||||||
.into_iter()
|
|
||||||
.collect::<Result<Vec<_>, _>>()?))
|
Ok(InventoryEntity::new(real_inventory))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_character_bank(conn: &mut sqlx::PgConnection, char_id: &CharacterEntityId, bank_identifier: &BankIdentifier) -> Result<BankEntity, GatewayError>
|
async fn get_character_bank(conn: &mut sqlx::PgConnection, char_id: &CharacterEntityId, bank_name: &BankName) -> Result<BankEntity, GatewayError>
|
||||||
{
|
{
|
||||||
let conn = Arc::new(Mutex::new(conn.begin().await?)); // this is some degen shit
|
let mut t = conn.begin().await?;
|
||||||
let bank = match bank_identifier {
|
let bank = sqlx::query_as::<_, PgInventoryEntity>("select * from bank where pchar = $1 and name = $2")
|
||||||
BankIdentifier::Character => {
|
.bind(char_id.0)
|
||||||
sqlx::query_as::<_, PgInventoryEntity>("select * from bank where pchar = $1")
|
.bind(bank_name.0.clone())
|
||||||
.bind(char_id.0 as i32)
|
.fetch_one(&mut t).await?;
|
||||||
.fetch_one(&mut **conn.lock().await).await?
|
// TODO: inefficient
|
||||||
},
|
let mut real_bank = Vec::new();
|
||||||
BankIdentifier::Shared(bank_name) => {
|
for bank_item in bank.items.0.into_iter() {
|
||||||
sqlx::query_as::<_, PgInventoryEntity>("select player_character.id as pchar, shared_bank.items as items from shared_bank
|
match bank_item {
|
||||||
join player_character on shared_bank.user_account = player_character.user_account
|
PgInventoryItemEntity::Individual(item) => {
|
||||||
where player_character.id = $1 and shared_bank.name = $2")
|
let entity = sqlx::query_as::<_, PgItemEntity>("select item.id, item.item from item where id = $1")
|
||||||
.bind(char_id.0 as i32)
|
.bind(item)
|
||||||
.bind(&bank_name.0)
|
.fetch_one(&mut t).await
|
||||||
.fetch_optional(&mut **conn.lock().await)
|
.map(|item| item.into())
|
||||||
.await?
|
.map(|item| apply_item_modifications(&mut t, item))?
|
||||||
.unwrap_or_else(|| PgInventoryEntity {
|
.await;
|
||||||
pchar: char_id.0 as i32,
|
real_bank.push(BankItemEntity::Individual(entity));
|
||||||
items: sqlx::types::Json::default(),
|
},
|
||||||
})
|
PgInventoryItemEntity::Stacked(items) => {
|
||||||
}
|
let mut stacked_item = Vec::new();
|
||||||
};
|
for s_item in items {
|
||||||
|
stacked_item.push(sqlx::query_as::<_, PgItemEntity>("select item.id, item.item from item where id = $1")
|
||||||
Ok(BankEntity::new(
|
.bind(s_item)
|
||||||
bank.items.0
|
.fetch_one(&mut t).await
|
||||||
.into_iter()
|
.map(|item| item.into())
|
||||||
.map(move |item| {
|
.map(|item| apply_item_modifications(&mut t, item))?
|
||||||
let conn = conn.clone();
|
.await)
|
||||||
async move {
|
|
||||||
fetch_item(&mut **conn.lock().await, item, BankItemEntity::Individual, BankItemEntity::Stacked).await
|
|
||||||
}
|
}
|
||||||
})
|
real_bank.push(BankItemEntity::Stacked(stacked_item));
|
||||||
.collect::<FuturesOrdered<_>>()
|
}
|
||||||
.collect::<Vec<_>>()
|
}
|
||||||
.await
|
}
|
||||||
.into_iter()
|
|
||||||
.collect::<Result<Vec<_>, _>>()?))
|
Ok(BankEntity::new(real_bank))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_character_inventory(conn: &mut sqlx::PgConnection, char_id: &CharacterEntityId, inventory: &InventoryEntity) -> Result<(), GatewayError>
|
async fn set_character_inventory(conn: &mut sqlx::PgConnection, char_id: &CharacterEntityId, inventory: &InventoryEntity) -> Result<(), GatewayError>
|
||||||
@ -492,15 +479,15 @@ async fn set_character_inventory(conn: &mut sqlx::PgConnection, char_id: &Charac
|
|||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
sqlx::query("insert into inventory (pchar, items) values ($1, $2) on conflict (pchar) do update set items = $2")
|
sqlx::query("insert into inventory (pchar, items) values ($1, $2) on conflict (pchar) do update set items = $2")
|
||||||
.bind(char_id.0 as i32)
|
.bind(char_id.0)
|
||||||
.bind(sqlx::types::Json(inventory))
|
.bind(sqlx::types::Json(inventory))
|
||||||
.execute(conn)
|
.execute(conn)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn set_character_bank(conn: &mut sqlx::PgConnection, char_id: &CharacterEntityId, bank: &BankEntity, bank_name: &BankName) -> Result<(), GatewayError>
|
||||||
async fn set_character_bank(conn: &mut sqlx::PgConnection, char_id: &CharacterEntityId, bank: &BankEntity, bank_identifier: &BankIdentifier) -> Result<(), GatewayError> {
|
{
|
||||||
let bank = bank.items.iter()
|
let bank = bank.items.iter()
|
||||||
.map(|item| {
|
.map(|item| {
|
||||||
match item {
|
match item {
|
||||||
@ -514,33 +501,19 @@ async fn set_character_bank(conn: &mut sqlx::PgConnection, char_id: &CharacterEn
|
|||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
match bank_identifier {
|
sqlx::query("insert into bank (pchar, items, name) values ($1, $2, $3) on conflict (pchar, name) do update set items = $2")
|
||||||
BankIdentifier::Character => {
|
.bind(char_id.0)
|
||||||
sqlx::query("insert into bank (pchar, items, name) values ($1, $2, '') on conflict (pchar, name) do update set items = $2")
|
.bind(sqlx::types::Json(bank))
|
||||||
.bind(char_id.0 as i32)
|
.bind(bank_name.0.clone())
|
||||||
.bind(sqlx::types::Json(bank))
|
.execute(conn)
|
||||||
.execute(conn)
|
.await?;
|
||||||
.await?;
|
|
||||||
},
|
|
||||||
BankIdentifier::Shared(bank_name) => {
|
|
||||||
sqlx::query("insert into shared_bank (user_account, items, name)
|
|
||||||
select player_character.user_account, $2, $3 from player_character
|
|
||||||
where player_character.id = $1
|
|
||||||
on conflict (user_account, name) do update set items = $2;")
|
|
||||||
.bind(char_id.0 as i32)
|
|
||||||
.bind(sqlx::types::Json(bank))
|
|
||||||
.bind(&bank_name.0)
|
|
||||||
.execute(conn)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_character_equips(conn: &mut sqlx::PgConnection, char_id: &CharacterEntityId) -> Result<EquippedEntity, GatewayError>
|
async fn get_character_equips(conn: &mut sqlx::PgConnection, char_id: &CharacterEntityId) -> Result<EquippedEntity, GatewayError>
|
||||||
{
|
{
|
||||||
let equips = sqlx::query_as::<_, PgEquipped>("select * from equipped where pchar = $1")
|
let equips = sqlx::query_as::<_, PgEquipped>("select * from equipped where pchar = $1")
|
||||||
.bind(char_id.0 as i32)
|
.bind(char_id.0)
|
||||||
.fetch_one(conn)
|
.fetch_one(conn)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@ -551,7 +524,7 @@ async fn set_character_equips(conn: &mut sqlx::PgConnection, char_id: &Character
|
|||||||
{
|
{
|
||||||
sqlx::query(r#"insert into equipped (pchar, weapon, armor, shield, unit0, unit1, unit2, unit3, mag) values ($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
sqlx::query(r#"insert into equipped (pchar, weapon, armor, shield, unit0, unit1, unit2, unit3, mag) values ($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
||||||
on conflict (pchar) do update set weapon=$2, armor=$3, shield=$4, unit0=$5, unit1=$6, unit2=$7, unit3=$8, mag=$9"#)
|
on conflict (pchar) do update set weapon=$2, armor=$3, shield=$4, unit0=$5, unit1=$6, unit2=$7, unit3=$8, mag=$9"#)
|
||||||
.bind(char_id.0 as i32)
|
.bind(char_id.0)
|
||||||
.bind(equips.weapon.map(|i| i.0 as i32))
|
.bind(equips.weapon.map(|i| i.0 as i32))
|
||||||
.bind(equips.armor.map(|i| i.0 as i32))
|
.bind(equips.armor.map(|i| i.0 as i32))
|
||||||
.bind(equips.shield.map(|i| i.0 as i32))
|
.bind(equips.shield.map(|i| i.0 as i32))
|
||||||
@ -565,11 +538,10 @@ async fn set_character_equips(conn: &mut sqlx::PgConnection, char_id: &Character
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async fn set_character_meseta(conn: &mut sqlx::PgConnection, char_id: &CharacterEntityId, meseta: Meseta) -> Result<(), GatewayError>
|
async fn set_character_meseta(conn: &mut sqlx::PgConnection, char_id: &CharacterEntityId, meseta: Meseta) -> Result<(), GatewayError>
|
||||||
{
|
{
|
||||||
sqlx::query("insert into character_meseta values ($1, $2) on conflict (pchar) do update set meseta = $2")
|
sqlx::query("insert into character_meseta values ($1, $2) on conflict (pchar) do update set meseta = $2")
|
||||||
.bind(char_id.0 as i32)
|
.bind(char_id.0)
|
||||||
.bind(meseta.0 as i32)
|
.bind(meseta.0 as i32)
|
||||||
.execute(conn)
|
.execute(conn)
|
||||||
.await?;
|
.await?;
|
||||||
@ -581,69 +553,40 @@ async fn get_character_meseta(conn: &mut sqlx::PgConnection, char_id: &Character
|
|||||||
#[derive(sqlx::FromRow)]
|
#[derive(sqlx::FromRow)]
|
||||||
struct PgMeseta(i32);
|
struct PgMeseta(i32);
|
||||||
let meseta = sqlx::query_as::<_, PgMeseta>(r#"select meseta from character_meseta where pchar = $1"#)
|
let meseta = sqlx::query_as::<_, PgMeseta>(r#"select meseta from character_meseta where pchar = $1"#)
|
||||||
.bind(char_id.0 as i32)
|
.bind(char_id.0)
|
||||||
.fetch_one(conn)
|
.fetch_one(conn)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(Meseta(meseta.0 as u32))
|
Ok(Meseta(meseta.0 as u32))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_bank_meseta(conn: &mut sqlx::PgConnection, char_id: &CharacterEntityId, bank_identifier: &BankIdentifier, meseta: Meseta) -> Result<(), GatewayError>
|
async fn set_bank_meseta(conn: &mut sqlx::PgConnection, char_id: &CharacterEntityId, bank: &BankName, meseta: Meseta) -> Result<(), GatewayError>
|
||||||
{
|
{
|
||||||
match bank_identifier {
|
sqlx::query("insert into bank_meseta values ($1, $2, $3) on conflict (pchar, bank) do update set meseta = $3")
|
||||||
BankIdentifier::Character => {
|
.bind(char_id.0)
|
||||||
sqlx::query("insert into bank_meseta values ($1, '', $2) on conflict (pchar, bank) do update set meseta = $2")
|
.bind(bank.0.clone())
|
||||||
.bind(char_id.0 as i32)
|
.bind(meseta.0 as i32)
|
||||||
.bind(meseta.0 as i32)
|
.execute(conn)
|
||||||
.execute(conn)
|
.await?;
|
||||||
.await?;
|
|
||||||
},
|
|
||||||
BankIdentifier::Shared(bank_name) => {
|
|
||||||
sqlx::query("insert into shared_bank_meseta (user_account, name, meseta)
|
|
||||||
select player_character.user_account, $2, $3 from player_character
|
|
||||||
where player_character.id = $1
|
|
||||||
on conflict (user_account, name) do update set meseta = $3")
|
|
||||||
.bind(char_id.0 as i32)
|
|
||||||
.bind(&bank_name.0)
|
|
||||||
.bind(meseta.0 as i32)
|
|
||||||
.execute(conn)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_bank_meseta(conn: &mut sqlx::PgConnection, char_id: &CharacterEntityId, bank_identifier: &BankIdentifier) -> Result<Meseta, GatewayError>
|
async fn get_bank_meseta(conn: &mut sqlx::PgConnection, char_id: &CharacterEntityId, bank: &BankName) -> Result<Meseta, GatewayError>
|
||||||
{
|
{
|
||||||
#[derive(sqlx::FromRow)]
|
#[derive(sqlx::FromRow)]
|
||||||
struct PgMeseta(i32);
|
struct PgMeseta(i32);
|
||||||
|
let meseta = sqlx::query_as::<_, PgMeseta>(r#"select meseta from bank_meseta where pchar = $1 and bank = $2"#)
|
||||||
let meseta = match bank_identifier {
|
.bind(char_id.0)
|
||||||
BankIdentifier::Character => {
|
.bind(bank.0.clone())
|
||||||
sqlx::query_as::<_, PgMeseta>(r#"select meseta from bank_meseta where pchar = $1"#)
|
.fetch_one(conn)
|
||||||
.bind(char_id.0 as i32)
|
.await?;
|
||||||
.fetch_one(conn)
|
|
||||||
.await?
|
|
||||||
},
|
|
||||||
BankIdentifier::Shared(bank_name) => {
|
|
||||||
sqlx::query_as::<_, PgMeseta>(r#"select shared_bank_meseta.meseta from shared_bank_meseta
|
|
||||||
join player_character on shared_bank_meseta.user_account = player_character.user_account
|
|
||||||
where player_character.id = $1 and shared_bank_meseta.name = $2"#)
|
|
||||||
.bind(char_id.0 as i32)
|
|
||||||
.bind(&bank_name.0)
|
|
||||||
.fetch_optional(conn)
|
|
||||||
.await?
|
|
||||||
.unwrap_or(PgMeseta(0))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok(Meseta(meseta.0 as u32))
|
Ok(Meseta(meseta.0 as u32))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn create_trade(conn: &mut sqlx::PgConnection, char_id1: &CharacterEntityId, char_id2: &CharacterEntityId) -> Result<TradeEntity, GatewayError>
|
async fn create_trade(conn: &mut sqlx::PgConnection, char_id1: &CharacterEntityId, char_id2: &CharacterEntityId) -> Result<TradeEntity, GatewayError>
|
||||||
{
|
{
|
||||||
let trade = sqlx::query_as::<_, PgTradeEntity>(r#"insert into trades (character1, character2) values ($1, $2) returning *;"#)
|
let trade = sqlx::query_as::<_, PgTradeEntity>(r#"insert into trades (character1, character2) values ($1, $2) returning *;"#)
|
||||||
.bind(char_id1.0 as i32)
|
.bind(char_id1.0)
|
||||||
.bind(char_id2.0 as i32)
|
.bind(char_id2.0)
|
||||||
.fetch_one(conn)
|
.fetch_one(conn)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(trade.into())
|
Ok(trade.into())
|
||||||
@ -652,53 +595,29 @@ async fn create_trade(conn: &mut sqlx::PgConnection, char_id1: &CharacterEntityI
|
|||||||
async fn set_character_playtime(conn: &mut sqlx::PgConnection, char_id: &CharacterEntityId, playtime: u32) -> Result<(), GatewayError>
|
async fn set_character_playtime(conn: &mut sqlx::PgConnection, char_id: &CharacterEntityId, playtime: u32) -> Result<(), GatewayError>
|
||||||
{
|
{
|
||||||
sqlx::query(r#"update player_character set playtime=$2 where id=$1;"#)
|
sqlx::query(r#"update player_character set playtime=$2 where id=$1;"#)
|
||||||
.bind(char_id.0 as i32)
|
.bind(char_id.0)
|
||||||
.bind(playtime as i32)
|
.bind(playtime)
|
||||||
.execute(conn)
|
|
||||||
.await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn create_room(conn: &mut sqlx::PgConnection, room: NewRoomEntity) -> Result<RoomEntity, GatewayError> {
|
|
||||||
sqlx::query_as::<_, PgRoomEntity>("insert into room (name, section_id, mode, episode, difficulty) values ($1, $2, $3, $4, $5) returning *")
|
|
||||||
.bind(room.name)
|
|
||||||
.bind(u8::from(room.section_id) as i8)
|
|
||||||
.bind(u8::from(room.mode) as i8)
|
|
||||||
.bind(u8::from(room.episode) as i8)
|
|
||||||
.bind(u8::from(room.difficulty) as i8)
|
|
||||||
.fetch_one(conn)
|
|
||||||
.await
|
|
||||||
.map(|room| room.into())
|
|
||||||
.map_err(|err| err.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn add_room_note(conn: &mut sqlx::PgConnection, room_id: RoomEntityId, note: RoomNote) -> Result<(), GatewayError> {
|
|
||||||
sqlx::query("insert into room_note (room, note) values ($1, $2)")
|
|
||||||
.bind(room_id.0 as i32)
|
|
||||||
.bind(sqlx::types::Json(note))
|
|
||||||
.execute(conn)
|
.execute(conn)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl EntityGateway for PostgresGateway {
|
impl<'t> EntityGateway for PostgresGateway<'t> {
|
||||||
type Transaction<'t> = PostgresTransaction<'t> where Self: 't;
|
type Transaction = PostgresTransaction<'t>;
|
||||||
|
|
||||||
fn with_transaction<'a, F, Fut, R>(&'a mut self, func: F) -> BoxFuture<'a, Result<R, anyhow::Error>>
|
async fn with_transaction<'a, F, Fut, R>(&'a mut self, func: F) -> Result<R, anyhow::Error>
|
||||||
where
|
where
|
||||||
Fut: Future<Output = Result<(Self::Transaction<'a>, R), anyhow::Error>> + Send + 'a,
|
Fut: Future<Output = Result<(Self::Transaction, R), anyhow::Error>> + Send + 'a,
|
||||||
F: FnOnce(Self::Transaction<'a>) -> Fut + Send + 'a,
|
F: FnOnce(Self::Transaction) -> Fut + Send,
|
||||||
R: Send,
|
R: Send,
|
||||||
{
|
{
|
||||||
Box::pin(async move {
|
let transaction = PostgresTransaction {
|
||||||
let transaction = PostgresTransaction {
|
pgtransaction: Arc::new(Mutex::new(self.pool.begin().await?))
|
||||||
pgtransaction: Arc::new(Mutex::new(self.pool.begin().await?))
|
};
|
||||||
};
|
let (transaction, result) = func(transaction).await?;
|
||||||
let (transaction, result) = func(transaction).await?;
|
transaction.commit().await?;
|
||||||
transaction.commit().await?;
|
Ok(result)
|
||||||
Ok(result)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn create_user(&mut self, user: NewUserAccountEntity) -> Result<UserAccountEntity, GatewayError> {
|
async fn create_user(&mut self, user: NewUserAccountEntity) -> Result<UserAccountEntity, GatewayError> {
|
||||||
@ -777,16 +696,16 @@ impl EntityGateway for PostgresGateway {
|
|||||||
get_character_inventory(&mut *self.pool.acquire().await?, char_id).await
|
get_character_inventory(&mut *self.pool.acquire().await?, char_id).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_character_bank(&mut self, char_id: &CharacterEntityId, bank_identifier: &BankIdentifier) -> Result<BankEntity, GatewayError> {
|
async fn get_character_bank(&mut self, char_id: &CharacterEntityId, bank_name: &BankName) -> Result<BankEntity, GatewayError> {
|
||||||
get_character_bank(&mut *self.pool.acquire().await?, char_id, bank_identifier).await
|
get_character_bank(&mut *self.pool.acquire().await?, char_id, bank_name).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_character_inventory(&mut self, char_id: &CharacterEntityId, inventory: &InventoryEntity) -> Result<(), GatewayError> {
|
async fn set_character_inventory(&mut self, char_id: &CharacterEntityId, inventory: &InventoryEntity) -> Result<(), GatewayError> {
|
||||||
set_character_inventory(&mut *self.pool.acquire().await?, char_id, inventory).await
|
set_character_inventory(&mut *self.pool.acquire().await?, char_id, inventory).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_character_bank(&mut self, char_id: &CharacterEntityId, bank: &BankEntity, bank_identifier: &BankIdentifier) -> Result<(), GatewayError> {
|
async fn set_character_bank(&mut self, char_id: &CharacterEntityId, bank: &BankEntity, bank_name: &BankName) -> Result<(), GatewayError> {
|
||||||
set_character_bank(&mut *self.pool.acquire().await?, char_id, bank, bank_identifier).await
|
set_character_bank(&mut *self.pool.acquire().await?, char_id, bank, bank_name).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_character_equips(&mut self, char_id: &CharacterEntityId) -> Result<EquippedEntity, GatewayError> {
|
async fn get_character_equips(&mut self, char_id: &CharacterEntityId) -> Result<EquippedEntity, GatewayError> {
|
||||||
@ -805,12 +724,12 @@ impl EntityGateway for PostgresGateway {
|
|||||||
get_character_meseta(&mut *self.pool.acquire().await?, char_id).await
|
get_character_meseta(&mut *self.pool.acquire().await?, char_id).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_bank_meseta(&mut self, char_id: &CharacterEntityId, bank_identifier: &BankIdentifier, meseta: Meseta) -> Result<(), GatewayError> {
|
async fn set_bank_meseta(&mut self, char_id: &CharacterEntityId, bank: &BankName, meseta: Meseta) -> Result<(), GatewayError> {
|
||||||
set_bank_meseta(&mut *self.pool.acquire().await?, char_id, bank_identifier, meseta).await
|
set_bank_meseta(&mut *self.pool.acquire().await?, char_id, bank, meseta).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_bank_meseta(&mut self, char_id: &CharacterEntityId, bank_identifier: &BankIdentifier) -> Result<Meseta, GatewayError> {
|
async fn get_bank_meseta(&mut self, char_id: &CharacterEntityId, bank: &BankName) -> Result<Meseta, GatewayError> {
|
||||||
get_bank_meseta(&mut *self.pool.acquire().await?, char_id, bank_identifier).await
|
get_bank_meseta(&mut *self.pool.acquire().await?, char_id, bank).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn create_trade(&mut self, char_id1: &CharacterEntityId, char_id2: &CharacterEntityId) -> Result<TradeEntity, GatewayError> {
|
async fn create_trade(&mut self, char_id1: &CharacterEntityId, char_id2: &CharacterEntityId) -> Result<TradeEntity, GatewayError> {
|
||||||
@ -820,20 +739,12 @@ impl EntityGateway for PostgresGateway {
|
|||||||
async fn set_character_playtime(&mut self, char_id: &CharacterEntityId, playtime: u32) -> Result<(), GatewayError> {
|
async fn set_character_playtime(&mut self, char_id: &CharacterEntityId, playtime: u32) -> Result<(), GatewayError> {
|
||||||
set_character_playtime(&mut *self.pool.acquire().await?, char_id, playtime).await
|
set_character_playtime(&mut *self.pool.acquire().await?, char_id, playtime).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn create_room(&mut self, room: NewRoomEntity) -> Result<RoomEntity, GatewayError> {
|
|
||||||
create_room(&mut *self.pool.acquire().await?, room).await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn add_room_note(&mut self, room_id: RoomEntityId, note: RoomNote) -> Result<(), GatewayError> {
|
|
||||||
add_room_note(&mut *self.pool.acquire().await?, room_id, note).await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl<'c> EntityGateway for PostgresTransaction<'c> {
|
impl<'c> EntityGateway for PostgresTransaction<'c> {
|
||||||
type Transaction<'t> = PostgresTransaction<'c> where Self: 't;
|
type Transaction = PostgresTransaction<'c>;
|
||||||
|
|
||||||
async fn create_user(&mut self, user: NewUserAccountEntity) -> Result<UserAccountEntity, GatewayError> {
|
async fn create_user(&mut self, user: NewUserAccountEntity) -> Result<UserAccountEntity, GatewayError> {
|
||||||
create_user(&mut *self.pgtransaction.lock().await, user).await
|
create_user(&mut *self.pgtransaction.lock().await, user).await
|
||||||
@ -911,16 +822,16 @@ impl<'c> EntityGateway for PostgresTransaction<'c> {
|
|||||||
get_character_inventory(&mut *self.pgtransaction.lock().await, char_id).await
|
get_character_inventory(&mut *self.pgtransaction.lock().await, char_id).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_character_bank(&mut self, char_id: &CharacterEntityId, bank_identifier: &BankIdentifier) -> Result<BankEntity, GatewayError> {
|
async fn get_character_bank(&mut self, char_id: &CharacterEntityId, bank_name: &BankName) -> Result<BankEntity, GatewayError> {
|
||||||
get_character_bank(&mut *self.pgtransaction.lock().await, char_id, bank_identifier).await
|
get_character_bank(&mut *self.pgtransaction.lock().await, char_id, bank_name).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_character_inventory(&mut self, char_id: &CharacterEntityId, inventory: &InventoryEntity) -> Result<(), GatewayError> {
|
async fn set_character_inventory(&mut self, char_id: &CharacterEntityId, inventory: &InventoryEntity) -> Result<(), GatewayError> {
|
||||||
set_character_inventory(&mut *self.pgtransaction.lock().await, char_id, inventory).await
|
set_character_inventory(&mut *self.pgtransaction.lock().await, char_id, inventory).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_character_bank(&mut self, char_id: &CharacterEntityId, bank: &BankEntity, bank_identifier: &BankIdentifier) -> Result<(), GatewayError> {
|
async fn set_character_bank(&mut self, char_id: &CharacterEntityId, bank: &BankEntity, bank_name: &BankName) -> Result<(), GatewayError> {
|
||||||
set_character_bank(&mut *self.pgtransaction.lock().await, char_id, bank, bank_identifier).await
|
set_character_bank(&mut *self.pgtransaction.lock().await, char_id, bank, bank_name).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_character_equips(&mut self, char_id: &CharacterEntityId) -> Result<EquippedEntity, GatewayError> {
|
async fn get_character_equips(&mut self, char_id: &CharacterEntityId) -> Result<EquippedEntity, GatewayError> {
|
||||||
@ -939,12 +850,12 @@ impl<'c> EntityGateway for PostgresTransaction<'c> {
|
|||||||
get_character_meseta(&mut *self.pgtransaction.lock().await, char_id).await
|
get_character_meseta(&mut *self.pgtransaction.lock().await, char_id).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_bank_meseta(&mut self, char_id: &CharacterEntityId, bank_identifier: &BankIdentifier, meseta: Meseta) -> Result<(), GatewayError> {
|
async fn set_bank_meseta(&mut self, char_id: &CharacterEntityId, bank: &BankName, meseta: Meseta) -> Result<(), GatewayError> {
|
||||||
set_bank_meseta(&mut *self.pgtransaction.lock().await, char_id, bank_identifier, meseta).await
|
set_bank_meseta(&mut *self.pgtransaction.lock().await, char_id, bank, meseta).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_bank_meseta(&mut self, char_id: &CharacterEntityId, bank_identifier: &BankIdentifier) -> Result<Meseta, GatewayError> {
|
async fn get_bank_meseta(&mut self, char_id: &CharacterEntityId, bank: &BankName) -> Result<Meseta, GatewayError> {
|
||||||
get_bank_meseta(&mut *self.pgtransaction.lock().await, char_id, bank_identifier).await
|
get_bank_meseta(&mut *self.pgtransaction.lock().await, char_id, bank).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn create_trade(&mut self, char_id1: &CharacterEntityId, char_id2: &CharacterEntityId) -> Result<TradeEntity, GatewayError> {
|
async fn create_trade(&mut self, char_id1: &CharacterEntityId, char_id2: &CharacterEntityId) -> Result<TradeEntity, GatewayError> {
|
||||||
@ -954,13 +865,5 @@ impl<'c> EntityGateway for PostgresTransaction<'c> {
|
|||||||
async fn set_character_playtime(&mut self, char_id: &CharacterEntityId, playtime: u32) -> Result<(), GatewayError> {
|
async fn set_character_playtime(&mut self, char_id: &CharacterEntityId, playtime: u32) -> Result<(), GatewayError> {
|
||||||
set_character_playtime(&mut *self.pgtransaction.lock().await, char_id, playtime).await
|
set_character_playtime(&mut *self.pgtransaction.lock().await, char_id, playtime).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn create_room(&mut self, room: NewRoomEntity) -> Result<RoomEntity, GatewayError> {
|
|
||||||
create_room(&mut *self.pgtransaction.lock().await, room).await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn add_room_note(&mut self, room_id: RoomEntityId, note: RoomNote) -> Result<(), GatewayError> {
|
|
||||||
add_room_note(&mut *self.pgtransaction.lock().await, room_id, note).await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
|||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use crate::item::ItemEntityId;
|
use crate::entity::item::ItemEntityId;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub enum ItemParseError {
|
pub enum ItemParseError {
|
@ -1,9 +1,9 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
use std::collections::HashMap;
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use crate::item::tool::ToolType;
|
use crate::entity::item::tool::ToolType;
|
||||||
use crate::character::{CharacterClass, SectionID};
|
use crate::entity::character::{CharacterClass, SectionID};
|
||||||
use crate::item::ItemEntityId;
|
use crate::entity::item::ItemEntityId;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
|
||||||
use std::cmp::Ordering::{Less, Greater, Equal};
|
use std::cmp::Ordering::{Less, Greater, Equal};
|
@ -9,11 +9,9 @@ pub mod mag;
|
|||||||
pub mod esweapon;
|
pub mod esweapon;
|
||||||
|
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use crate::character::CharacterEntityId;
|
use crate::entity::character::CharacterEntityId;
|
||||||
use crate::room::RoomEntityId;
|
use crate::ship::map::MapArea;
|
||||||
use maps::area::MapArea;
|
use crate::ship::drops::ItemDropType;
|
||||||
use maps::monster::MonsterType;
|
|
||||||
//use crate::ship::drops::ItemDropType;
|
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct ItemEntityId(pub u32);
|
pub struct ItemEntityId(pub u32);
|
||||||
@ -24,12 +22,6 @@ pub struct BankName(pub String);
|
|||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct TradeId(pub u32);
|
pub struct TradeId(pub u32);
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize, derive_more::Display)]
|
|
||||||
pub enum BankIdentifier {
|
|
||||||
Character,
|
|
||||||
Shared(BankName),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum ItemNote {
|
pub enum ItemNote {
|
||||||
CharacterCreation {
|
CharacterCreation {
|
||||||
@ -37,16 +29,8 @@ pub enum ItemNote {
|
|||||||
},
|
},
|
||||||
EnemyDrop {
|
EnemyDrop {
|
||||||
character_id: CharacterEntityId,
|
character_id: CharacterEntityId,
|
||||||
room_id: RoomEntityId,
|
//monster_type: MonsterType,
|
||||||
monster_type: MonsterType,
|
//droprate: f32,
|
||||||
map_area: MapArea,
|
|
||||||
x: f32,
|
|
||||||
y: f32,
|
|
||||||
z: f32,
|
|
||||||
},
|
|
||||||
BoxDrop {
|
|
||||||
character_id: CharacterEntityId,
|
|
||||||
room_id: RoomEntityId,
|
|
||||||
map_area: MapArea,
|
map_area: MapArea,
|
||||||
x: f32,
|
x: f32,
|
||||||
y: f32,
|
y: f32,
|
||||||
@ -62,19 +46,15 @@ pub enum ItemNote {
|
|||||||
y: f32,
|
y: f32,
|
||||||
z: f32,
|
z: f32,
|
||||||
},
|
},
|
||||||
Consumed {
|
Consumed, // TODO: character_id
|
||||||
character_id: CharacterEntityId,
|
|
||||||
},
|
|
||||||
FedToMag {
|
FedToMag {
|
||||||
character_id: CharacterEntityId,
|
//character_id: CharacterEntityId,
|
||||||
mag: ItemEntityId,
|
mag: ItemEntityId,
|
||||||
},
|
},
|
||||||
BoughtAtShop {
|
BoughtAtShop {
|
||||||
character_id: CharacterEntityId,
|
character_id: CharacterEntityId,
|
||||||
},
|
},
|
||||||
SoldToShop {
|
SoldToShop,
|
||||||
character_id: CharacterEntityId,
|
|
||||||
},
|
|
||||||
Trade {
|
Trade {
|
||||||
trade_id: TradeId,
|
trade_id: TradeId,
|
||||||
character_to: CharacterEntityId,
|
character_to: CharacterEntityId,
|
||||||
@ -82,14 +62,11 @@ pub enum ItemNote {
|
|||||||
},
|
},
|
||||||
Withdraw {
|
Withdraw {
|
||||||
character_id: CharacterEntityId,
|
character_id: CharacterEntityId,
|
||||||
bank: BankIdentifier,
|
bank: BankName,
|
||||||
},
|
},
|
||||||
Deposit {
|
Deposit {
|
||||||
character_id: CharacterEntityId,
|
character_id: CharacterEntityId,
|
||||||
bank: BankIdentifier,
|
bank: BankName,
|
||||||
},
|
|
||||||
FloorLimitReached {
|
|
||||||
map_area: MapArea,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,6 +133,26 @@ impl ItemDetail {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parse_item_from_bytes(data: [u8; 16]) -> Option<ItemDropType> {
|
||||||
|
let item_type = weapon::WeaponType::parse_type([data[0],data[1],data[2]]).map(ItemType::Weapon)
|
||||||
|
.or_else(|_| armor::ArmorType::parse_type([data[0],data[1],data[2]]).map(ItemType::Armor))
|
||||||
|
.or_else(|_| shield::ShieldType::parse_type([data[0],data[1],data[2]]).map(ItemType::Shield))
|
||||||
|
.or_else(|_| unit::UnitType::parse_type([data[0],data[1],data[2]]).map(ItemType::Unit))
|
||||||
|
.or_else(|_| mag::MagType::parse_type([data[0],data[1],data[2]]).map(ItemType::Mag))
|
||||||
|
.or_else(|_| tool::ToolType::parse_type([data[0],data[1],data[2]]).map(ItemType::Tool))
|
||||||
|
.or_else(|_| esweapon::ESWeaponType::parse_type([data[0],data[1],data[2]]).map(ItemType::ESWeapon)).ok()?;
|
||||||
|
|
||||||
|
match item_type {
|
||||||
|
ItemType::Weapon(_w) => Some(ItemDropType::Weapon(weapon::Weapon::from_bytes(data).ok()?)),
|
||||||
|
ItemType::Armor(_a) => Some(ItemDropType::Armor(armor::Armor::from_bytes(data).ok()?)),
|
||||||
|
ItemType::Shield(_s) => Some(ItemDropType::Shield(shield::Shield::from_bytes(data).ok()?)),
|
||||||
|
ItemType::Unit(_u) => Some(ItemDropType::Unit(unit::Unit::from_bytes(data).ok()?)),
|
||||||
|
ItemType::Mag(_m) => Some(ItemDropType::Mag(mag::Mag::from_bytes(data).ok()?)),
|
||||||
|
ItemType::Tool(_t) => Some(ItemDropType::Tool(tool::Tool::from_bytes(data).ok()?)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn as_client_bytes(&self) -> [u8; 16] {
|
pub fn as_client_bytes(&self) -> [u8; 16] {
|
||||||
match self {
|
match self {
|
||||||
ItemDetail::Weapon(w) => w.as_bytes(),
|
ItemDetail::Weapon(w) => w.as_bytes(),
|
@ -1,4 +1,4 @@
|
|||||||
use crate::item::ItemEntityId;
|
use crate::entity::item::ItemEntityId;
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
@ -2,4 +2,3 @@ pub mod gateway;
|
|||||||
pub mod account;
|
pub mod account;
|
||||||
pub mod character;
|
pub mod character;
|
||||||
pub mod item;
|
pub mod item;
|
||||||
pub mod room;
|
|
@ -1,16 +0,0 @@
|
|||||||
|
|
||||||
create table shared_bank (
|
|
||||||
user_account integer references user_accounts (id) not null,
|
|
||||||
items jsonb not null,
|
|
||||||
name varchar(128) not null,
|
|
||||||
unique (user_account, name)
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
create table shared_bank_meseta (
|
|
||||||
user_account integer references user_accounts (id) not null,
|
|
||||||
name varchar(128) not null,
|
|
||||||
meseta integer not null,
|
|
||||||
unique (user_account, name)
|
|
||||||
);
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
|||||||
create table room (
|
|
||||||
id serial primary key not null,
|
|
||||||
name varchar(32) not null,
|
|
||||||
section_id char not null,
|
|
||||||
mode char not null,
|
|
||||||
episode char not null,
|
|
||||||
difficulty char not null
|
|
||||||
);
|
|
||||||
|
|
||||||
create table room_note (
|
|
||||||
room integer references room (id) not null,
|
|
||||||
note jsonb not null,
|
|
||||||
created_at timestamptz default current_timestamp not null
|
|
||||||
);
|
|
@ -1,17 +0,0 @@
|
|||||||
drop table room_note;
|
|
||||||
drop table room;
|
|
||||||
|
|
||||||
create table room (
|
|
||||||
id serial primary key not null,
|
|
||||||
name varchar(32) not null,
|
|
||||||
section_id "char" not null,
|
|
||||||
mode "char" not null,
|
|
||||||
episode "char" not null,
|
|
||||||
difficulty "char" not null
|
|
||||||
);
|
|
||||||
|
|
||||||
create table room_note (
|
|
||||||
room integer references room (id) not null,
|
|
||||||
note jsonb not null,
|
|
||||||
created_at timestamptz default current_timestamp not null
|
|
||||||
);
|
|
@ -1,3 +0,0 @@
|
|||||||
use refinery::include_migration_mods;
|
|
||||||
|
|
||||||
include_migration_mods!("src/gateway/postgres/migrations");
|
|
@ -1,83 +0,0 @@
|
|||||||
use serde::{Serialize, Deserialize};
|
|
||||||
|
|
||||||
|
|
||||||
use crate::character::{CharacterEntityId, SectionID};
|
|
||||||
use maps::room::{Episode, Difficulty};
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash, PartialOrd, Ord, Serialize, Deserialize)]
|
|
||||||
pub struct RoomEntityId(pub u32);
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
|
||||||
pub enum RoomEntityMode {
|
|
||||||
Multi,
|
|
||||||
Single,
|
|
||||||
Challenge,
|
|
||||||
Battle,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<u8> for RoomEntityMode {
|
|
||||||
fn from(other: u8) -> RoomEntityMode {
|
|
||||||
match other {
|
|
||||||
0 => RoomEntityMode::Multi,
|
|
||||||
1 => RoomEntityMode::Single,
|
|
||||||
2 => RoomEntityMode::Challenge,
|
|
||||||
3 => RoomEntityMode::Battle,
|
|
||||||
_ => unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<RoomEntityMode> for u8 {
|
|
||||||
fn from(other: RoomEntityMode) -> u8 {
|
|
||||||
match other {
|
|
||||||
RoomEntityMode::Multi => 0,
|
|
||||||
RoomEntityMode::Single => 1,
|
|
||||||
RoomEntityMode::Challenge => 2,
|
|
||||||
RoomEntityMode::Battle => 3,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct RoomEntity {
|
|
||||||
pub id: RoomEntityId,
|
|
||||||
pub name: String,
|
|
||||||
pub section_id: SectionID,
|
|
||||||
pub mode: RoomEntityMode,
|
|
||||||
pub episode: Episode,
|
|
||||||
pub difficulty: Difficulty,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct NewRoomEntity {
|
|
||||||
pub name: String,
|
|
||||||
pub section_id: SectionID,
|
|
||||||
pub mode: RoomEntityMode,
|
|
||||||
pub episode: Episode,
|
|
||||||
pub difficulty: Difficulty,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Serialize)]
|
|
||||||
pub enum RoomNote {
|
|
||||||
Create {
|
|
||||||
character_id: CharacterEntityId,
|
|
||||||
},
|
|
||||||
PlayerJoin {
|
|
||||||
character_id: CharacterEntityId,
|
|
||||||
},
|
|
||||||
PlayerLeave {
|
|
||||||
character_id: CharacterEntityId,
|
|
||||||
},
|
|
||||||
QuestStart {
|
|
||||||
// quest id
|
|
||||||
},
|
|
||||||
QuestComplete {
|
|
||||||
// quest id
|
|
||||||
},
|
|
||||||
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
use serde::{Serialize, Deserialize};
|
|
||||||
|
|
||||||
use super::account::UserAccountId;
|
|
||||||
|
|
||||||
// [2022-10-23 00:11:18][elseware::common::mainloop::client][WARN] error RecvServerPacket::from_bytes: WrongPacketForServerType(490, [40, 0, 234, 1, 0, 0, 0, 0, 9, 0, 74, 0, 97, 0, 115, 0, 100, 0, 102, 0, 0, 0, 0, 0, 192, 52, 67, 3, 60, 159, 129, 0, 32, 64, 233, 10, 196, 156, 152, 0])
|
|
||||||
// [2022-10-23 00:20:14][elseware::common::mainloop::client][WARN] error RecvServerPacket::from_bytes: WrongPacketForServerType(490, [40, 0, 234, 1, 0, 0, 0, 0, 9, 0, 74, 0, 97, 0, 97, 0, 97, 0, 97, 0, 97, 0, 97, 0, 97, 0, 97, 0, 97, 0, 97, 0, 97, 0, 97, 0, 0, 0, 152, 0])
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash, PartialOrd, Ord, Serialize, Deserialize)]
|
|
||||||
pub struct TeamEntityId(pub u32);
|
|
||||||
|
|
||||||
pub struct NewTeamEntity {
|
|
||||||
pub created_by: UserAccountId,
|
|
||||||
pub name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct TeamEntity {
|
|
||||||
pub id: TeamEntityId,
|
|
||||||
pub owner: UserAccountId,
|
|
||||||
pub name: String,
|
|
||||||
|
|
||||||
pub team_flag: [u8; 2048],
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "items"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
entity = { workspace = true }
|
|
||||||
maps = { workspace = true }
|
|
||||||
shops = { workspace = true }
|
|
||||||
location = { workspace = true }
|
|
||||||
drops = { workspace = true }
|
|
||||||
|
|
||||||
libpso = { workspace = true }
|
|
||||||
|
|
||||||
enum-utils = { workspace = true }
|
|
||||||
derive_more = { workspace = true }
|
|
||||||
serde = { workspace = true }
|
|
||||||
rand = { workspace = true }
|
|
||||||
rand_chacha = { workspace = true }
|
|
||||||
async-recursion = { workspace = true }
|
|
||||||
async-std = { workspace = true }
|
|
||||||
async-trait = { workspace = true }
|
|
||||||
futures = { workspace = true }
|
|
||||||
anyhow = { workspace = true }
|
|
||||||
thiserror = { workspace = true }
|
|
@ -1,38 +0,0 @@
|
|||||||
use crate::ClientItemId;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum TradeItem {
|
|
||||||
Individual(ClientItemId),
|
|
||||||
Stacked(ClientItemId, usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TradeItem {
|
|
||||||
pub fn stacked(&self) -> Option<(ClientItemId, usize)> {
|
|
||||||
match self {
|
|
||||||
TradeItem::Stacked(item_id, amount) => Some((*item_id, *amount)),
|
|
||||||
_ => None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn stacked_mut(&mut self) -> Option<(ClientItemId, &mut usize)> {
|
|
||||||
match self {
|
|
||||||
TradeItem::Stacked(item_id, ref mut amount) => Some((*item_id, amount)),
|
|
||||||
_ => None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn item_id(&self) -> ClientItemId {
|
|
||||||
match self {
|
|
||||||
TradeItem::Individual(item_id) => *item_id,
|
|
||||||
TradeItem::Stacked(item_id, _) => *item_id,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn amount(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
TradeItem::Individual(_) => 1,
|
|
||||||
TradeItem::Stacked(_, amount) => *amount,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
17
src/lib.rs
Normal file
17
src/lib.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#![allow(clippy::type_complexity)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
#![feature(inline_const)]
|
||||||
|
#![feature(drain_filter)]
|
||||||
|
#![feature(try_blocks)]
|
||||||
|
#![feature(once_cell)]
|
||||||
|
#![feature(test)]
|
||||||
|
#![feature(error_generic_member_access)]
|
||||||
|
#![feature(provide_any)]
|
||||||
|
|
||||||
|
extern crate test;
|
||||||
|
|
||||||
|
pub mod common;
|
||||||
|
pub mod entity;
|
||||||
|
pub mod patch;
|
||||||
|
pub mod login;
|
||||||
|
pub mod ship;
|
@ -1,12 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "location"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
networking = { workspace = true }
|
|
||||||
|
|
||||||
async-std = { workspace = true }
|
|
||||||
derive_more = { workspace = true }
|
|
||||||
futures= { workspace = true }
|
|
||||||
thiserror = { workspace = true }
|
|
@ -12,31 +12,30 @@ use libpso::packet::login::*;
|
|||||||
use libpso::packet::ship::{MenuDetail, SmallLeftDialog};
|
use libpso::packet::ship::{MenuDetail, SmallLeftDialog};
|
||||||
use libpso::{PacketParseError, PSOPacket};
|
use libpso::{PacketParseError, PSOPacket};
|
||||||
use libpso::crypto::bb::PSOBBCipher;
|
use libpso::crypto::bb::PSOBBCipher;
|
||||||
|
use crate::entity::item;
|
||||||
use libpso::character::character;
|
use libpso::character::character;
|
||||||
use entity::item;
|
|
||||||
|
|
||||||
use networking::cipherkeys::{ELSEWHERE_PRIVATE_KEY, ELSEWHERE_PARRAY};
|
use crate::common::cipherkeys::{ELSEWHERE_PRIVATE_KEY, ELSEWHERE_PARRAY};
|
||||||
use networking::serverstate::{SendServerPacket, RecvServerPacket, ServerState, OnConnect, ClientId};
|
use crate::common::serverstate::{SendServerPacket, RecvServerPacket, ServerState, OnConnect, ClientId};
|
||||||
use networking::interserver::{ServerId, InterserverActor, LoginMessage, ShipMessage, Ship};
|
use crate::common::interserver::{ServerId, InterserverActor, LoginMessage, ShipMessage, Ship};
|
||||||
use stats::leveltable::LEVEL_TABLE;
|
use crate::common::leveltable::LEVEL_TABLE;
|
||||||
use libpso::util::{utf8_to_array, utf8_to_utf16_array};
|
use libpso::{utf8_to_array, utf8_to_utf16_array};
|
||||||
|
|
||||||
use entity::gateway::{EntityGateway, GatewayError};
|
use crate::entity::gateway::{EntityGateway, GatewayError};
|
||||||
use entity::account::{UserAccountId, UserAccountEntity, NewUserSettingsEntity, USERFLAG_NEWCHAR, USERFLAG_DRESSINGROOM};
|
use crate::entity::account::{UserAccountId, UserAccountEntity, NewUserSettingsEntity, USERFLAG_NEWCHAR, USERFLAG_DRESSINGROOM};
|
||||||
use entity::item::{NewItemEntity, ItemDetail, ItemNote, InventoryItemEntity, InventoryEntity, BankEntity, BankIdentifier, EquippedEntity, Meseta};
|
use crate::entity::item::{NewItemEntity, ItemDetail, ItemNote, InventoryItemEntity, InventoryEntity, BankEntity, BankName, EquippedEntity, Meseta};
|
||||||
use entity::item::weapon::Weapon;
|
use crate::entity::item::weapon::Weapon;
|
||||||
use entity::item::armor::Armor;
|
use crate::entity::item::armor::Armor;
|
||||||
use entity::item::tech::Technique;
|
use crate::entity::item::tech::Technique;
|
||||||
use entity::item::tool::Tool;
|
use crate::entity::item::tool::Tool;
|
||||||
use entity::item::mag::Mag;
|
use crate::entity::item::mag::Mag;
|
||||||
use entity::character::{CharacterEntity, NewCharacterEntity, CharacterClass, TechLevel};
|
use crate::entity::character::{CharacterEntity, NewCharacterEntity, CharacterClass, TechLevel};
|
||||||
|
|
||||||
use crate::login::get_login_status;
|
use crate::login::login::{get_login_status};
|
||||||
use networking::interserver::AuthToken;
|
use crate::common::interserver::AuthToken;
|
||||||
|
|
||||||
use pktbuilder::ship::SHIP_MENU_ID;
|
|
||||||
|
|
||||||
pub const CHARACTER_PORT: u16 = 12001;
|
pub const CHARACTER_PORT: u16 = 12001;
|
||||||
|
pub const SHIP_MENU_ID: u32 = 1;
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
pub enum CharacterError {
|
pub enum CharacterError {
|
||||||
@ -150,7 +149,7 @@ fn generate_param_data(path: &str) -> (ParamDataHeader, Vec<u8>) {
|
|||||||
size: len as u32,
|
size: len as u32,
|
||||||
checksum: crc.sum32(),
|
checksum: crc.sum32(),
|
||||||
offset: buffer.len() as u32,
|
offset: buffer.len() as u32,
|
||||||
filename: utf8_to_array(param.file_name().unwrap().to_str().unwrap()),
|
filename: utf8_to_array!(param.file_name().unwrap().to_str().unwrap(), 0x40),
|
||||||
});
|
});
|
||||||
|
|
||||||
buffer.append(&mut filebuf);
|
buffer.append(&mut filebuf);
|
||||||
@ -177,7 +176,7 @@ impl ClientState {
|
|||||||
user: None,
|
user: None,
|
||||||
characters: None,
|
characters: None,
|
||||||
guildcard_data_buffer: None,
|
guildcard_data_buffer: None,
|
||||||
session: Session::default(),
|
session: Session::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -212,7 +211,7 @@ async fn new_character<EG: EntityGateway + Clone>(entity_gateway: &mut EG, user:
|
|||||||
|
|
||||||
let character = entity_gateway.create_character(character).await?;
|
let character = entity_gateway.create_character(character).await?;
|
||||||
entity_gateway.set_character_meseta(&character.id, Meseta(300)).await?;
|
entity_gateway.set_character_meseta(&character.id, Meseta(300)).await?;
|
||||||
entity_gateway.set_bank_meseta(&character.id, &BankIdentifier::Character, Meseta(0)).await?;
|
entity_gateway.set_bank_meseta(&character.id, &BankName("".into()), Meseta(0)).await?;
|
||||||
|
|
||||||
let new_weapon = match character.char_class {
|
let new_weapon = match character.char_class {
|
||||||
CharacterClass::HUmar | CharacterClass::HUnewearl | CharacterClass::HUcast | CharacterClass::HUcaseal => item::weapon::WeaponType::Saber,
|
CharacterClass::HUmar | CharacterClass::HUnewearl | CharacterClass::HUcast | CharacterClass::HUcaseal => item::weapon::WeaponType::Saber,
|
||||||
@ -306,7 +305,7 @@ async fn new_character<EG: EntityGateway + Clone>(entity_gateway: &mut EG, user:
|
|||||||
InventoryItemEntity::Stacked(monomates), InventoryItemEntity::Stacked(monofluids)],
|
InventoryItemEntity::Stacked(monomates), InventoryItemEntity::Stacked(monofluids)],
|
||||||
};
|
};
|
||||||
entity_gateway.set_character_inventory(&character.id, &inventory).await?;
|
entity_gateway.set_character_inventory(&character.id, &inventory).await?;
|
||||||
entity_gateway.set_character_bank(&character.id, &BankEntity::default(), &BankIdentifier::Character).await?;
|
entity_gateway.set_character_bank(&character.id, &BankEntity::default(), &BankName("".into())).await?;
|
||||||
let equipped = EquippedEntity {
|
let equipped = EquippedEntity {
|
||||||
weapon: Some(weapon.id),
|
weapon: Some(weapon.id),
|
||||||
armor: Some(armor.id),
|
armor: Some(armor.id),
|
||||||
@ -342,15 +341,15 @@ impl<EG: EntityGateway + Clone> CharacterServerState<EG> {
|
|||||||
if let Some(connected_client) = self.connected_clients.read().await.get(&user.id) {
|
if let Some(connected_client) = self.connected_clients.read().await.get(&user.id) {
|
||||||
if let Some(expires) = connected_client.expires {
|
if let Some(expires) = connected_client.expires {
|
||||||
if expires > chrono::Utc::now() {
|
if expires > chrono::Utc::now() {
|
||||||
return Ok(vec![SendCharacterPacket::LoginResponse(LoginResponse::by_status(AccountStatus::AlreadyOnline, Session::default()))]);
|
return Ok(vec![SendCharacterPacket::LoginResponse(LoginResponse::by_status(AccountStatus::AlreadyOnline, Session::new()))]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return Ok(vec![SendCharacterPacket::LoginResponse(LoginResponse::by_status(AccountStatus::AlreadyOnline, Session::default()))]);
|
return Ok(vec![SendCharacterPacket::LoginResponse(LoginResponse::by_status(AccountStatus::AlreadyOnline, Session::new()))]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut response = LoginResponse::by_status(AccountStatus::Ok, Session::default());
|
let mut response = LoginResponse::by_status(AccountStatus::Ok, Session::new());
|
||||||
response.guildcard = user.guildcard;
|
response.guildcard = user.guildcard;
|
||||||
response.team_id = user.team_id.map_or(0, |ti| ti);
|
response.team_id = user.team_id.map_or(0, |ti| ti);
|
||||||
|
|
||||||
@ -367,7 +366,7 @@ impl<EG: EntityGateway + Clone> CharacterServerState<EG> {
|
|||||||
Ok(vec![SendCharacterPacket::LoginResponse(response)])
|
Ok(vec![SendCharacterPacket::LoginResponse(response)])
|
||||||
},
|
},
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
Ok(vec![SendCharacterPacket::LoginResponse(LoginResponse::by_status(err, Session::default()))])
|
Ok(vec![SendCharacterPacket::LoginResponse(LoginResponse::by_status(err, Session::new()))])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -379,7 +378,7 @@ impl<EG: EntityGateway + Clone> CharacterServerState<EG> {
|
|||||||
menu: SHIP_MENU_ID,
|
menu: SHIP_MENU_ID,
|
||||||
item: i.0 as u32,
|
item: i.0 as u32,
|
||||||
flags: 0,
|
flags: 0,
|
||||||
name: utf8_to_utf16_array(&s.name)
|
name: utf8_to_utf16_array!(s.name, 0x11)
|
||||||
}
|
}
|
||||||
}).collect()))
|
}).collect()))
|
||||||
])
|
])
|
||||||
@ -485,7 +484,7 @@ impl<EG: EntityGateway + Clone> CharacterServerState<EG> {
|
|||||||
async fn set_flag(&mut self, id: ClientId, setflag: &SetFlag) -> Result<std::option::IntoIter<SendCharacterPacket>, anyhow::Error> {
|
async fn set_flag(&mut self, id: ClientId, setflag: &SetFlag) -> Result<std::option::IntoIter<SendCharacterPacket>, anyhow::Error> {
|
||||||
let mut client = self.clients.write().await;
|
let mut client = self.clients.write().await;
|
||||||
let client = client.get_mut(&id).ok_or_else(|| CharacterError::ClientNotFound(id))?;
|
let client = client.get_mut(&id).ok_or_else(|| CharacterError::ClientNotFound(id))?;
|
||||||
let user = client.user.as_mut().unwrap();
|
let mut user = client.user.as_mut().unwrap();
|
||||||
user.flags = setflag.flags;
|
user.flags = setflag.flags;
|
||||||
self.entity_gateway.save_user(user).await.unwrap();
|
self.entity_gateway.save_user(user).await.unwrap();
|
||||||
Ok(None.into_iter())
|
Ok(None.into_iter())
|
||||||
@ -516,7 +515,7 @@ impl<EG: EntityGateway + Clone> CharacterServerState<EG> {
|
|||||||
async fn character_preview(&mut self, id: ClientId, preview: &CharacterPreview) -> Result<Vec<SendCharacterPacket>, anyhow::Error> {
|
async fn character_preview(&mut self, id: ClientId, preview: &CharacterPreview) -> Result<Vec<SendCharacterPacket>, anyhow::Error> {
|
||||||
let mut client = self.clients.write().await;
|
let mut client = self.clients.write().await;
|
||||||
let client = client.get_mut(&id).ok_or_else(|| CharacterError::ClientNotFound(id))?;
|
let client = client.get_mut(&id).ok_or_else(|| CharacterError::ClientNotFound(id))?;
|
||||||
let user = client.user.as_mut().unwrap();
|
let mut user = client.user.as_mut().unwrap();
|
||||||
if user.flags == USERFLAG_NEWCHAR {
|
if user.flags == USERFLAG_NEWCHAR {
|
||||||
new_character(&mut self.entity_gateway, user, preview).await?
|
new_character(&mut self.entity_gateway, user, preview).await?
|
||||||
}
|
}
|
||||||
@ -824,7 +823,7 @@ impl<'a> SelectScreenCharacterBuilder<'a> {
|
|||||||
hair_b: character.appearance.hair_b,
|
hair_b: character.appearance.hair_b,
|
||||||
prop_x: character.appearance.prop_x,
|
prop_x: character.appearance.prop_x,
|
||||||
prop_y: character.appearance.prop_y,
|
prop_y: character.appearance.prop_y,
|
||||||
name: utf8_to_utf16_array(&character.name),
|
name: utf8_to_utf16_array!(character.name, 16),
|
||||||
play_time: character.playtime,
|
play_time: character.playtime,
|
||||||
..character::SelectScreenCharacter::default()
|
..character::SelectScreenCharacter::default()
|
||||||
}
|
}
|
||||||
@ -835,21 +834,9 @@ impl<'a> SelectScreenCharacterBuilder<'a> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use entity::account::*;
|
use crate::entity::account::*;
|
||||||
use libpso::character::{settings, character};
|
use libpso::character::{settings, character};
|
||||||
use entity::gateway::{InMemoryGateway, EntityGatewayTransaction, GatewayError};
|
use crate::entity::gateway::{InMemoryGateway, GatewayError};
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
struct CharTestDb;
|
|
||||||
|
|
||||||
impl EntityGateway for CharTestDb {
|
|
||||||
type Transaction<'t> = CharTestDb where Self: 't;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EntityGatewayTransaction for CharTestDb {
|
|
||||||
type ParentGateway = CharTestDb;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[async_std::test]
|
#[async_std::test]
|
||||||
async fn test_option_send() {
|
async fn test_option_send() {
|
||||||
@ -859,7 +846,7 @@ mod test {
|
|||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl EntityGateway for TestData {
|
impl EntityGateway for TestData {
|
||||||
type Transaction<'a> = CharTestDb where Self: 'a;
|
type Transaction = ();
|
||||||
async fn get_user_settings_by_user(&mut self, user: &UserAccountEntity) -> Result<UserSettingsEntity, GatewayError> {
|
async fn get_user_settings_by_user(&mut self, user: &UserAccountEntity) -> Result<UserSettingsEntity, GatewayError> {
|
||||||
Ok(UserSettingsEntity {
|
Ok(UserSettingsEntity {
|
||||||
id: UserSettingsId(0),
|
id: UserSettingsId(0),
|
||||||
@ -902,7 +889,7 @@ mod test {
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct TestData;
|
struct TestData;
|
||||||
impl EntityGateway for TestData {
|
impl EntityGateway for TestData {
|
||||||
type Transaction<'a> = CharTestDb where Self: 'a;
|
type Transaction = ();
|
||||||
}
|
}
|
||||||
let mut server = CharacterServerState::new(TestData {}, AuthToken("".into()));
|
let mut server = CharacterServerState::new(TestData {}, AuthToken("".into()));
|
||||||
let send = server.handle(ClientId(1), RecvCharacterPacket::Checksum(Checksum {checksum: 1234,
|
let send = server.handle(ClientId(1), RecvCharacterPacket::Checksum(Checksum {checksum: 1234,
|
@ -11,11 +11,11 @@ use libpso::{PacketParseError, PSOPacket};
|
|||||||
use libpso::crypto::bb::PSOBBCipher;
|
use libpso::crypto::bb::PSOBBCipher;
|
||||||
use libpso::util::array_to_utf8;
|
use libpso::util::array_to_utf8;
|
||||||
|
|
||||||
use networking::cipherkeys::{ELSEWHERE_PRIVATE_KEY, ELSEWHERE_PARRAY};
|
use crate::common::cipherkeys::{ELSEWHERE_PRIVATE_KEY, ELSEWHERE_PARRAY};
|
||||||
use networking::serverstate::{SendServerPacket, RecvServerPacket, ServerState, OnConnect, ClientId};
|
use crate::common::serverstate::{SendServerPacket, RecvServerPacket, ServerState, OnConnect, ClientId};
|
||||||
|
|
||||||
use entity::gateway::EntityGateway;
|
use crate::entity::gateway::EntityGateway;
|
||||||
use entity::account::{UserAccountEntity};
|
use crate::entity::account::{UserAccountEntity};
|
||||||
|
|
||||||
pub const LOGIN_PORT: u16 = 12000;
|
pub const LOGIN_PORT: u16 = 12000;
|
||||||
pub const COMMUNICATION_PORT: u16 = 12123;
|
pub const COMMUNICATION_PORT: u16 = 12123;
|
||||||
@ -83,13 +83,21 @@ pub async fn get_login_status(entity_gateway: &mut impl EntityGateway, pkt: &Log
|
|||||||
|
|
||||||
pub fn check_if_already_online(user: UserAccountEntity) -> Result<UserAccountEntity, AccountStatus> {
|
pub fn check_if_already_online(user: UserAccountEntity) -> Result<UserAccountEntity, AccountStatus> {
|
||||||
Ok(user)
|
Ok(user)
|
||||||
|
/*
|
||||||
|
if user.is_currently_online() {
|
||||||
|
Err(AccountStatus::PayUp)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Ok(user)
|
||||||
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct LoginServerState<EG: EntityGateway + Clone> {
|
pub struct LoginServerState<EG: EntityGateway + Clone> {
|
||||||
character_server_ip: net::Ipv4Addr,
|
character_server_ip: net::Ipv4Addr,
|
||||||
entity_gateway: EG,
|
entity_gateway: EG,
|
||||||
clients: HashMap<ClientId, String>, // TODO: this should be arc/mutex'd?
|
clients: HashMap<ClientId, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<EG: EntityGateway + Clone> LoginServerState<EG> {
|
impl<EG: EntityGateway + Clone> LoginServerState<EG> {
|
||||||
@ -111,7 +119,7 @@ impl<EG: EntityGateway + Clone> LoginServerState<EG> {
|
|||||||
let response = SendLoginPacket::LoginResponse(LoginResponse::by_status(AccountStatus::Ok, pkt.session));
|
let response = SendLoginPacket::LoginResponse(LoginResponse::by_status(AccountStatus::Ok, pkt.session));
|
||||||
let ip = u32::from_ne_bytes(self.character_server_ip.octets());
|
let ip = u32::from_ne_bytes(self.character_server_ip.octets());
|
||||||
Ok(vec![response,
|
Ok(vec![response,
|
||||||
SendLoginPacket::RedirectClient(RedirectClient::new(ip, crate::character::CHARACTER_PORT))])
|
SendLoginPacket::RedirectClient(RedirectClient::new(ip, crate::login::character::CHARACTER_PORT))])
|
||||||
},
|
},
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
Ok(vec![SendLoginPacket::LoginResponse(LoginResponse::by_status(err, pkt.session))])
|
Ok(vec![SendLoginPacket::LoginResponse(LoginResponse::by_status(err, pkt.session))])
|
||||||
@ -170,8 +178,8 @@ impl<EG: EntityGateway + Clone> ServerState for LoginServerState<EG> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use entity::account::{UserAccountId};
|
use crate::entity::account::{UserAccountId};
|
||||||
use entity::gateway::{EntityGatewayTransaction, GatewayError};
|
use crate::entity::gateway::{EntityGatewayTransaction, GatewayError};
|
||||||
|
|
||||||
const LOGIN_PACKET: RecvLoginPacket = RecvLoginPacket::Login(Login {
|
const LOGIN_PACKET: RecvLoginPacket = RecvLoginPacket::Login(Login {
|
||||||
tag: 65536,
|
tag: 65536,
|
||||||
@ -196,16 +204,13 @@ mod test {
|
|||||||
character_slot: 0,
|
character_slot: 0,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
#[derive(Clone)]
|
impl EntityGateway for () {
|
||||||
struct LoginTestDb;
|
type Transaction = ();
|
||||||
|
|
||||||
impl EntityGateway for LoginTestDb {
|
|
||||||
type Transaction<'t> = LoginTestDb where Self: 't;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EntityGatewayTransaction for LoginTestDb {
|
impl EntityGatewayTransaction for () {
|
||||||
type ParentGateway = LoginTestDb;
|
type ParentGateway = ();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_std::test]
|
#[async_std::test]
|
||||||
@ -216,7 +221,7 @@ mod test {
|
|||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl EntityGateway for TestData {
|
impl EntityGateway for TestData {
|
||||||
type Transaction<'t> = LoginTestDb where Self: 't;
|
type Transaction = ();
|
||||||
async fn get_user_by_name(&mut self, name: String) -> Result<UserAccountEntity, GatewayError> {
|
async fn get_user_by_name(&mut self, name: String) -> Result<UserAccountEntity, GatewayError> {
|
||||||
assert!(name == "testuser");
|
assert!(name == "testuser");
|
||||||
Ok(UserAccountEntity {
|
Ok(UserAccountEntity {
|
||||||
@ -275,7 +280,7 @@ mod test {
|
|||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl EntityGateway for TestData {
|
impl EntityGateway for TestData {
|
||||||
type Transaction<'t> = LoginTestDb where Self: 't;
|
type Transaction = ();
|
||||||
async fn get_user_by_name(&mut self, _name: String) -> Result<UserAccountEntity, GatewayError> {
|
async fn get_user_by_name(&mut self, _name: String) -> Result<UserAccountEntity, GatewayError> {
|
||||||
Err(GatewayError::Error)
|
Err(GatewayError::Error)
|
||||||
}
|
}
|
||||||
@ -310,7 +315,7 @@ mod test {
|
|||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl EntityGateway for TestData {
|
impl EntityGateway for TestData {
|
||||||
type Transaction<'t> = LoginTestDb where Self: 't;
|
type Transaction = ();
|
||||||
async fn get_user_by_name(&mut self, name: String) -> Result<UserAccountEntity, GatewayError> {
|
async fn get_user_by_name(&mut self, name: String) -> Result<UserAccountEntity, GatewayError> {
|
||||||
assert!(name == "testuser");
|
assert!(name == "testuser");
|
||||||
Ok(UserAccountEntity {
|
Ok(UserAccountEntity {
|
||||||
@ -360,7 +365,7 @@ mod test {
|
|||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl EntityGateway for TestData {
|
impl EntityGateway for TestData {
|
||||||
type Transaction<'t> = LoginTestDb where Self: 't;
|
type Transaction = ();
|
||||||
async fn get_user_by_name(&mut self, name: String) -> Result<UserAccountEntity, GatewayError> {
|
async fn get_user_by_name(&mut self, name: String) -> Result<UserAccountEntity, GatewayError> {
|
||||||
assert!(name == "testuser");
|
assert!(name == "testuser");
|
||||||
Ok(UserAccountEntity {
|
Ok(UserAccountEntity {
|
3
src/login/mod.rs
Normal file
3
src/login/mod.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#[allow(clippy::module_inception)]
|
||||||
|
pub mod login;
|
||||||
|
pub mod character;
|
92
src/login/models.rs
Normal file
92
src/login/models.rs
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
use std::time::SystemTime;
|
||||||
|
use std::io::Write;
|
||||||
|
//use diesel::sql_types::Timestamp;
|
||||||
|
use diesel::{Insertable, Queryable, Identifiable, Associations, AsExpression, FromSqlRow};
|
||||||
|
//use bcrypt::{DEFAULT_COST, hash};
|
||||||
|
use diesel::pg::Pg;
|
||||||
|
use diesel::sql_types;
|
||||||
|
use diesel::deserialize::{self, FromSql};
|
||||||
|
use diesel::serialize::{self, ToSql, Output, IsNull};
|
||||||
|
use diesel::backend::Backend;
|
||||||
|
|
||||||
|
use libpso::character::settings;
|
||||||
|
|
||||||
|
use elseware::schema::*;
|
||||||
|
|
||||||
|
//const ELSEWHERE_COST: u32 = bcrypt::DEFAULT_COST;
|
||||||
|
const ELSEWHERE_COST: u32 = 5;
|
||||||
|
|
||||||
|
#[derive(Debug, AsExpression, FromSqlRow)]
|
||||||
|
#[sql_type="sql_types::Binary"]
|
||||||
|
pub struct EUserSettings(pub settings::UserSettings);
|
||||||
|
|
||||||
|
impl std::ops::Deref for EUserSettings {
|
||||||
|
type Target = settings::UserSettings;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Queryable, Identifiable, Debug)]
|
||||||
|
pub struct UserAccount {
|
||||||
|
pub id: i32,
|
||||||
|
pub username: String,
|
||||||
|
pub password: String,
|
||||||
|
pub guildcard: Option<i32>,
|
||||||
|
pub team_id: Option<i32>,
|
||||||
|
pub banned: bool,
|
||||||
|
pub muted_until: SystemTime,
|
||||||
|
pub created_at: SystemTime,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Insertable)]
|
||||||
|
#[table_name="user_accounts"]
|
||||||
|
pub struct NewUser {
|
||||||
|
username: String,
|
||||||
|
password: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NewUser {
|
||||||
|
pub fn new(username: String, password: String) -> NewUser {
|
||||||
|
let crypt_password = bcrypt::hash(password, ELSEWHERE_COST).expect("could not hash password?");
|
||||||
|
NewUser {
|
||||||
|
username: username,
|
||||||
|
password: crypt_password,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Queryable, Identifiable, Associations)]
|
||||||
|
#[belongs_to(UserAccount, foreign_key="user_id")]
|
||||||
|
#[table_name="user_settings"]
|
||||||
|
pub struct UserSettings {
|
||||||
|
pub id: i32,
|
||||||
|
pub user_id: i32,
|
||||||
|
//settings: Vec<u8>,
|
||||||
|
pub settings: EUserSettings,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Insertable, Debug)]
|
||||||
|
#[table_name="user_settings"]
|
||||||
|
pub struct NewUserSettings {
|
||||||
|
pub user_id: i32,
|
||||||
|
pub settings: EUserSettings,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToSql<sql_types::Binary, Pg> for EUserSettings {
|
||||||
|
fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
|
||||||
|
out.write_all(&self.0.as_bytes()[..])
|
||||||
|
.map(|_| IsNull::No)
|
||||||
|
.map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromSql<sql_types::Binary, Pg> for EUserSettings {
|
||||||
|
fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {
|
||||||
|
let bytes_vec: Vec<u8> = <Vec<u8> as FromSql<sql_types::Binary, Pg>>::from_sql(bytes)?;
|
||||||
|
let mut static_bytes = [0u8; 0x1160];
|
||||||
|
static_bytes[..0x1160].clone_from_slice(&bytes_vec);
|
||||||
|
Ok(EUserSettings(settings::UserSettings::from_bytes(static_bytes)))
|
||||||
|
}
|
||||||
|
}
|
@ -1,21 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "login_server"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
entity = { workspace = true }
|
|
||||||
networking = { workspace = true }
|
|
||||||
pktbuilder = { workspace = true }
|
|
||||||
stats = { workspace = true }
|
|
||||||
|
|
||||||
libpso = { workspace = true }
|
|
||||||
|
|
||||||
async-std = { workspace = true }
|
|
||||||
async-trait = { workspace = true }
|
|
||||||
anyhow = { workspace = true }
|
|
||||||
bcrypt = { workspace = true }
|
|
||||||
crc = { workspace = true }
|
|
||||||
thiserror = { workspace = true }
|
|
||||||
chrono = { workspace = true }
|
|
||||||
rand= { workspace = true }
|
|
@ -1,2 +0,0 @@
|
|||||||
pub mod login;
|
|
||||||
pub mod character;
|
|
@ -1,14 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "maps"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
byteorder = { workspace = true }
|
|
||||||
serde = { workspace = true }
|
|
||||||
thiserror = { workspace = true }
|
|
||||||
rand = { workspace = true }
|
|
||||||
rand_chacha = { workspace = true }
|
|
||||||
toml = { workspace = true }
|
|
||||||
enum-utils = { workspace = true }
|
|
||||||
derive_more = { workspace = true }
|
|
@ -1,59 +0,0 @@
|
|||||||
pub mod area;
|
|
||||||
pub mod enemy;
|
|
||||||
pub mod object;
|
|
||||||
pub mod variant;
|
|
||||||
pub mod maps;
|
|
||||||
pub mod monster;
|
|
||||||
pub mod room;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum Holiday {
|
|
||||||
None,
|
|
||||||
Christmas,
|
|
||||||
Valentines,
|
|
||||||
Easter,
|
|
||||||
Halloween,
|
|
||||||
Sonic,
|
|
||||||
NewYear,
|
|
||||||
Summer,
|
|
||||||
White,
|
|
||||||
Wedding,
|
|
||||||
Fall,
|
|
||||||
Spring,
|
|
||||||
Summer2,
|
|
||||||
Spring2,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl From<Holiday> for u32 {
|
|
||||||
fn from(other: Holiday) -> u32 {
|
|
||||||
u16::from(other) as u32
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Holiday> for u16 {
|
|
||||||
fn from(other: Holiday) -> u16 {
|
|
||||||
u8::from(other) as u16
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Holiday> for u8 {
|
|
||||||
fn from(other: Holiday) -> u8 {
|
|
||||||
match other {
|
|
||||||
Holiday::None => 0,
|
|
||||||
Holiday::Christmas => 1,
|
|
||||||
Holiday::Valentines => 3,
|
|
||||||
Holiday::Easter => 4,
|
|
||||||
Holiday::Halloween => 5,
|
|
||||||
Holiday::Sonic => 6,
|
|
||||||
Holiday::NewYear => 7,
|
|
||||||
Holiday::Summer => 8,
|
|
||||||
Holiday::White => 9,
|
|
||||||
Holiday::Wedding => 10,
|
|
||||||
Holiday::Fall => 11,
|
|
||||||
Holiday::Spring => 12,
|
|
||||||
Holiday::Summer2 => 13,
|
|
||||||
Holiday::Spring2 => 14,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,150 +0,0 @@
|
|||||||
#[derive(Debug, Copy, Clone, derive_more::Display)]
|
|
||||||
pub enum Episode {
|
|
||||||
#[display(fmt="ep1")]
|
|
||||||
One,
|
|
||||||
#[display(fmt="ep2")]
|
|
||||||
Two,
|
|
||||||
#[display(fmt="ep4")]
|
|
||||||
Four,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<u8> for Episode {
|
|
||||||
type Error = ();
|
|
||||||
|
|
||||||
fn try_from(value: u8) -> Result<Episode, ()> {
|
|
||||||
match value {
|
|
||||||
1 => Ok(Episode::One),
|
|
||||||
2 => Ok(Episode::Two),
|
|
||||||
3 => Ok(Episode::Four),
|
|
||||||
_ => Err(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Episode> for u8 {
|
|
||||||
fn from(other: Episode) -> u8 {
|
|
||||||
match other {
|
|
||||||
Episode::One => 1,
|
|
||||||
Episode::Two => 2,
|
|
||||||
Episode::Four => 3,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Episode {
|
|
||||||
pub fn from_quest(value: u8) -> Option<Episode> {
|
|
||||||
match value {
|
|
||||||
0 => Some(Episode::One),
|
|
||||||
1 => Some(Episode::Two),
|
|
||||||
2 => Some(Episode::Four),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, derive_more::Display)]
|
|
||||||
pub enum Difficulty {
|
|
||||||
Normal,
|
|
||||||
Hard,
|
|
||||||
VeryHard,
|
|
||||||
Ultimate,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<u8> for Difficulty {
|
|
||||||
type Error = ();
|
|
||||||
|
|
||||||
fn try_from(value: u8) -> Result<Difficulty, ()> {
|
|
||||||
match value {
|
|
||||||
0 => Ok(Difficulty::Normal),
|
|
||||||
1 => Ok(Difficulty::Hard),
|
|
||||||
2 => Ok(Difficulty::VeryHard),
|
|
||||||
3 => Ok(Difficulty::Ultimate),
|
|
||||||
_ => Err(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Difficulty> for u8 {
|
|
||||||
fn from(other: Difficulty) -> u8 {
|
|
||||||
match other {
|
|
||||||
Difficulty::Normal => 0,
|
|
||||||
Difficulty::Hard => 1,
|
|
||||||
Difficulty::VeryHard => 2,
|
|
||||||
Difficulty::Ultimate => 3,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
|
||||||
pub enum PlayerMode {
|
|
||||||
Single,
|
|
||||||
Multi,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PlayerMode {
|
|
||||||
pub fn value(&self) -> u8 {
|
|
||||||
match self {
|
|
||||||
PlayerMode::Single => 1,
|
|
||||||
PlayerMode::Multi => 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, derive_more::Display)]
|
|
||||||
pub enum RoomMode {
|
|
||||||
#[display(fmt="single")]
|
|
||||||
Single {
|
|
||||||
episode: Episode,
|
|
||||||
difficulty: Difficulty,
|
|
||||||
},
|
|
||||||
#[display(fmt="multi")]
|
|
||||||
Multi {
|
|
||||||
episode: Episode,
|
|
||||||
difficulty: Difficulty,
|
|
||||||
},
|
|
||||||
#[display(fmt="challenge")]
|
|
||||||
Challenge {
|
|
||||||
episode: Episode,
|
|
||||||
},
|
|
||||||
#[display(fmt="battle")]
|
|
||||||
Battle {
|
|
||||||
episode: Episode,
|
|
||||||
difficulty: Difficulty,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl RoomMode {
|
|
||||||
pub fn difficulty(&self) -> Difficulty {
|
|
||||||
match self {
|
|
||||||
RoomMode::Single {difficulty, ..} => *difficulty,
|
|
||||||
RoomMode::Multi {difficulty, ..} => *difficulty,
|
|
||||||
RoomMode::Battle {difficulty, ..} => *difficulty,
|
|
||||||
RoomMode::Challenge {..} => Difficulty::Normal,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn episode(&self) -> Episode {
|
|
||||||
match self {
|
|
||||||
RoomMode::Single {episode, ..} => *episode,
|
|
||||||
RoomMode::Multi {episode, ..} => *episode,
|
|
||||||
RoomMode::Battle {episode, ..} => *episode,
|
|
||||||
RoomMode::Challenge {episode, ..} => *episode,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn battle(&self) -> bool {
|
|
||||||
matches!(self, RoomMode::Battle {..})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn challenge(&self) -> bool {
|
|
||||||
matches!(self, RoomMode::Challenge {..})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn player_mode(&self) -> PlayerMode {
|
|
||||||
match self {
|
|
||||||
RoomMode::Single {..} => PlayerMode::Single,
|
|
||||||
_ => PlayerMode::Multi,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "networking"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
entity = { workspace = true }
|
|
||||||
|
|
||||||
libpso = { workspace = true }
|
|
||||||
|
|
||||||
async-std = { workspace = true }
|
|
||||||
async-trait = { workspace = true }
|
|
||||||
futures = { workspace = true }
|
|
||||||
log = { workspace = true }
|
|
||||||
serde = { workspace = true }
|
|
||||||
serde_json = { workspace = true }
|
|
||||||
derive_more = { workspace = true }
|
|
@ -1,4 +0,0 @@
|
|||||||
pub mod cipherkeys;
|
|
||||||
pub mod serverstate;
|
|
||||||
pub mod mainloop;
|
|
||||||
pub mod interserver;
|
|
2
src/patch/mod.rs
Normal file
2
src/patch/mod.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#[allow(clippy::module_inception)]
|
||||||
|
pub mod patch;
|
@ -11,8 +11,8 @@ use libpso::crypto::pc::PSOPCCipher;
|
|||||||
use ron::de::from_str;
|
use ron::de::from_str;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use networking::mainloop::{NetworkError};
|
use crate::common::mainloop::{NetworkError};
|
||||||
use networking::serverstate::{RecvServerPacket, SendServerPacket, ServerState, OnConnect, ClientId};
|
use crate::common::serverstate::{RecvServerPacket, SendServerPacket, ServerState, OnConnect, ClientId};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum PatchError {
|
pub enum PatchError {
|
||||||
@ -341,7 +341,7 @@ impl Iterator for SendFileIterator {
|
|||||||
if len == 0 {
|
if len == 0 {
|
||||||
self.current_file = None;
|
self.current_file = None;
|
||||||
self.chunk_num = 0;
|
self.chunk_num = 0;
|
||||||
Some(SendPatchPacket::EndFileSend(EndFileSend::default()))
|
Some(SendPatchPacket::EndFileSend(EndFileSend::new()))
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
let mut crc = crc32::Digest::new(crc32::IEEE);
|
let mut crc = crc32::Digest::new(crc32::IEEE);
|
@ -1,15 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "patch_server"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
networking = { workspace = true }
|
|
||||||
|
|
||||||
libpso = { workspace = true }
|
|
||||||
|
|
||||||
async-trait = { workspace = true }
|
|
||||||
rand = { workspace = true }
|
|
||||||
crc = { workspace = true }
|
|
||||||
ron = { workspace = true }
|
|
||||||
serde = { workspace = true }
|
|
@ -1,22 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "pktbuilder"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
quests = { workspace = true }
|
|
||||||
stats = { workspace = true }
|
|
||||||
location = { workspace = true }
|
|
||||||
client = { workspace = true }
|
|
||||||
items = { workspace = true }
|
|
||||||
networking = { workspace = true }
|
|
||||||
maps = { workspace = true }
|
|
||||||
room = { workspace = true }
|
|
||||||
shops = { workspace = true }
|
|
||||||
entity = { workspace = true }
|
|
||||||
|
|
||||||
libpso = { workspace = true }
|
|
||||||
|
|
||||||
anyhow = { workspace = true }
|
|
||||||
futures = { workspace = true }
|
|
||||||
thiserror = { workspace = true }
|
|
@ -1,107 +0,0 @@
|
|||||||
use futures::stream::{FuturesOrdered, StreamExt};
|
|
||||||
use libpso::packet::ship::*;
|
|
||||||
use crate::common::serverstate::ClientId;
|
|
||||||
use crate::entity::gateway::EntityGateway;
|
|
||||||
use crate::ship::client::{Clients, ClientState};
|
|
||||||
use crate::ship::teams::Teams;
|
|
||||||
use crate::ship::location::ClientLocation;
|
|
||||||
use crate::ship::ship::ShipError;
|
|
||||||
use crate::entity::team::TeamEntity;
|
|
||||||
|
|
||||||
|
|
||||||
pub fn client_team_state_changed(client_id: ClientId, client: &ClientState, team: &TeamEntity) -> ClientTeamStateChanged {
|
|
||||||
ClientTeamStateChanged {
|
|
||||||
unknown: 0,
|
|
||||||
guildcard: client.user.guildcard(),
|
|
||||||
team_id: team.id.0,
|
|
||||||
unknown2: [0;2],
|
|
||||||
privilege: 0x40, // TODO: improve
|
|
||||||
team_name: libpso::utf8_to_utf16_array!(team.name, 14),
|
|
||||||
unknown3: 0x00986C84, // TODO: what if we omit this?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn player_team_info(client_id: ClientId, client: &ClientState, team: &TeamEntity) -> PlayerTeamInfo {
|
|
||||||
PlayerTeamInfo {
|
|
||||||
guildcard: client.user.guildcard(),
|
|
||||||
team_id: team.id.0,
|
|
||||||
info: 0,
|
|
||||||
info2: 0,
|
|
||||||
privilege: 0x40, // TODO: improve
|
|
||||||
team_name: libpso::utf8_to_utf16_array!(team.name, 14),
|
|
||||||
unknown: 0x00986C84, // TODO: what if we omit this?
|
|
||||||
guildcard_again: client.user.guildcard(),
|
|
||||||
client_id: client_id.0 as u32,
|
|
||||||
character_name: libpso::utf8_to_utf16_array!(client.character.name, 12),
|
|
||||||
unknown2: 0,
|
|
||||||
unknown3: 0,
|
|
||||||
team_flag: team.team_flag,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn team_info_individual(client_id: ClientId, client: &ClientState, team: &TeamEntity) -> TeamInfo {
|
|
||||||
TeamInfo {
|
|
||||||
clients: vec![player_team_info(client_id, client, team)]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub async fn player_team_info_list<EG>(id: ClientId,
|
|
||||||
client_location: &ClientLocation,
|
|
||||||
clients: &Clients,
|
|
||||||
teams: &Teams<EG>,
|
|
||||||
) -> Result<Vec<PlayerTeamInfo>, ShipError>
|
|
||||||
where
|
|
||||||
EG: EntityGateway + Clone + 'static,
|
|
||||||
{
|
|
||||||
Ok(futures::stream::iter(client_location.get_all_clients_by_client(id).await?.into_iter())
|
|
||||||
.filter_map(|area_client| {
|
|
||||||
let clients = clients.clone();
|
|
||||||
async move {
|
|
||||||
clients.with(area_client.client, |client| {
|
|
||||||
let mut teams = teams.clone();
|
|
||||||
Box::pin(async move {
|
|
||||||
let team = teams.get_team(area_client.client).await.ok()??;
|
|
||||||
Some(player_team_info(area_client.client, client, &team))
|
|
||||||
})}).await.ok()?
|
|
||||||
}})
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.await)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn team_info<EG>(id: ClientId,
|
|
||||||
client_location: &ClientLocation,
|
|
||||||
clients: &Clients,
|
|
||||||
teams: &Teams<EG>,
|
|
||||||
) -> Result<TeamInfo, ShipError>
|
|
||||||
where
|
|
||||||
EG: EntityGateway + Clone + 'static,
|
|
||||||
{
|
|
||||||
Ok(TeamInfo {
|
|
||||||
clients: player_team_info_list(id, client_location, clients, teams).await?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn lobby_team_list<EG>(id: ClientId,
|
|
||||||
client_location: &ClientLocation,
|
|
||||||
clients: &Clients,
|
|
||||||
teams: &Teams<EG>,
|
|
||||||
) -> Result<TeamLobbyList, ShipError>
|
|
||||||
where
|
|
||||||
EG: EntityGateway + Clone + 'static,
|
|
||||||
{
|
|
||||||
Ok(TeamLobbyList {
|
|
||||||
clients: player_team_info_list(id, client_location, clients, teams).await?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn team_invitation_info(client_id: ClientId, client: &ClientState, team: &TeamEntity) -> TeamInvitationInfo {
|
|
||||||
TeamInvitationInfo {
|
|
||||||
guildcard: client.user.guildcard(),
|
|
||||||
team_id: team.id.0,
|
|
||||||
unknown: [0; 2],
|
|
||||||
team_name: libpso::utf8_to_utf16_array!(team.name, 14),
|
|
||||||
unknown2: 0x00986C84, // TODO: what if we omit this?
|
|
||||||
team_flag: team.team_flag,
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "quests"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
maps = { workspace = true }
|
|
||||||
|
|
||||||
libpso = { workspace = true }
|
|
||||||
|
|
||||||
async-std = { workspace = true }
|
|
||||||
ages-prs = { workspace = true }
|
|
||||||
log = { workspace = true }
|
|
||||||
byteorder = { workspace = true }
|
|
||||||
thiserror = { workspace = true }
|
|
||||||
anyhow = { workspace = true }
|
|
||||||
toml = { workspace = true }
|
|
||||||
serde = { workspace = true }
|
|
@ -1,17 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "room"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
maps = { workspace = true }
|
|
||||||
entity = { workspace = true }
|
|
||||||
quests = { workspace = true }
|
|
||||||
location = { workspace = true }
|
|
||||||
drops = { workspace = true }
|
|
||||||
|
|
||||||
rand = { workspace = true }
|
|
||||||
async-std = { workspace = true }
|
|
||||||
futures = { workspace = true }
|
|
||||||
anyhow = { workspace = true }
|
|
||||||
thiserror = { workspace = true }
|
|
@ -1,274 +0,0 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
use std::convert::{From, Into};
|
|
||||||
use async_std::sync::{Arc, RwLock, RwLockReadGuard};
|
|
||||||
use futures::future::BoxFuture;
|
|
||||||
use futures::stream::{FuturesOrdered, Stream};
|
|
||||||
|
|
||||||
use thiserror::Error;
|
|
||||||
use rand::Rng;
|
|
||||||
|
|
||||||
use quests::{QuestList, QuestLoadError};
|
|
||||||
use maps::maps::Maps;
|
|
||||||
use drops::DropTable;
|
|
||||||
use entity::character::SectionID;
|
|
||||||
use entity::room::{RoomEntityId, RoomEntityMode};
|
|
||||||
use maps::monster::{load_monster_stats_table, MonsterType, MonsterStats};
|
|
||||||
use maps::area::MapAreaLookup;
|
|
||||||
use maps::Holiday;
|
|
||||||
use location::{MAX_ROOMS, RoomId};
|
|
||||||
|
|
||||||
use maps::room::{Episode, Difficulty, RoomMode};
|
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
|
||||||
pub enum RoomError {
|
|
||||||
#[error("invalid room id {0}")]
|
|
||||||
Invalid(u32),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Rooms([Arc<RwLock<Option<RoomState>>>; MAX_ROOMS]);
|
|
||||||
|
|
||||||
|
|
||||||
impl Default for Rooms {
|
|
||||||
fn default() -> Rooms {
|
|
||||||
Rooms(core::array::from_fn(|_| Arc::new(RwLock::new(None))))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Rooms {
|
|
||||||
pub async fn add(&self, room_id: RoomId, room: RoomState) -> Result<(), anyhow::Error> {
|
|
||||||
*self.0
|
|
||||||
.get(room_id.0)
|
|
||||||
.ok_or(RoomError::Invalid(room_id.0 as u32))?
|
|
||||||
.write()
|
|
||||||
.await = Some(room);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn remove(&self, room_id: RoomId) {
|
|
||||||
if let Some(room) = self.0.get(room_id.0) {
|
|
||||||
*room
|
|
||||||
.write()
|
|
||||||
.await = None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn exists(&self, room_id: RoomId) -> bool {
|
|
||||||
match self.0.get(room_id.0) {
|
|
||||||
Some(room) => {
|
|
||||||
room
|
|
||||||
.read()
|
|
||||||
.await
|
|
||||||
.is_some()
|
|
||||||
},
|
|
||||||
None => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn with<'a, T, F>(&'a self, room_id: RoomId, func: F) -> Result<T, anyhow::Error>
|
|
||||||
where
|
|
||||||
T: Send,
|
|
||||||
F: for<'b> FnOnce(&'b RoomState) -> BoxFuture<'b, T> + Send + 'a
|
|
||||||
{
|
|
||||||
let room = self.0
|
|
||||||
.get(room_id.0)
|
|
||||||
.ok_or(RoomError::Invalid(room_id.0 as u32))?
|
|
||||||
.read()
|
|
||||||
.await;
|
|
||||||
if let Some(room) = room.as_ref() {
|
|
||||||
Ok(func(room).await)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Err(RoomError::Invalid(room_id.0 as u32).into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn with_mut<'a, T, F>(&'a self, room_id: RoomId, func: F) -> Result<T, anyhow::Error>
|
|
||||||
where
|
|
||||||
T: Send,
|
|
||||||
F: for<'b> FnOnce(&'b mut RoomState) -> BoxFuture<'b, T> + Send + 'a
|
|
||||||
{
|
|
||||||
let mut room = self.0
|
|
||||||
.get(room_id.0)
|
|
||||||
.ok_or(RoomError::Invalid(room_id.0 as u32))?
|
|
||||||
.write()
|
|
||||||
.await;
|
|
||||||
|
|
||||||
if let Some(room) = room.as_mut() {
|
|
||||||
Ok(func(room).await)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Err(RoomError::Invalid(room_id.0 as u32).into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn get(&self, room_id: RoomId) -> RwLockReadGuard<Option<RoomState>> {
|
|
||||||
self.0
|
|
||||||
.get(room_id.0)
|
|
||||||
.unwrap()
|
|
||||||
.read()
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn stream(&self) -> impl Stream<Item = RwLockReadGuard<Option<RoomState>>> {
|
|
||||||
self.0
|
|
||||||
.iter()
|
|
||||||
.map(|room| async move {
|
|
||||||
room
|
|
||||||
.read()
|
|
||||||
.await
|
|
||||||
})
|
|
||||||
.collect::<FuturesOrdered<_>>()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
|
||||||
#[error("")]
|
|
||||||
pub enum RoomCreationError {
|
|
||||||
InvalidMode,
|
|
||||||
InvalidEpisode(u8),
|
|
||||||
InvalidDifficulty(u8),
|
|
||||||
CouldNotLoadMonsterStats(RoomMode),
|
|
||||||
CouldNotLoadQuests,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub enum QuestCategoryType {
|
|
||||||
Standard,
|
|
||||||
Government,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<usize> for QuestCategoryType {
|
|
||||||
fn from(f: usize) -> QuestCategoryType {
|
|
||||||
match f {
|
|
||||||
0 => QuestCategoryType::Standard,
|
|
||||||
_ => QuestCategoryType::Government,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<u32> for QuestCategoryType {
|
|
||||||
fn from(f: u32) -> QuestCategoryType {
|
|
||||||
match f {
|
|
||||||
0 => QuestCategoryType::Standard,
|
|
||||||
_ => QuestCategoryType::Government,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl QuestCategoryType {
|
|
||||||
pub fn value(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
QuestCategoryType::Standard => 0,
|
|
||||||
QuestCategoryType::Government => 1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct RoomState {
|
|
||||||
pub room_id: RoomEntityId,
|
|
||||||
pub mode: RoomMode,
|
|
||||||
pub name: String,
|
|
||||||
pub password: [u16; 16],
|
|
||||||
pub maps: Maps,
|
|
||||||
pub drop_table: Box<dyn DropTable + Send + Sync>,
|
|
||||||
pub section_id: SectionID,
|
|
||||||
pub random_seed: u32,
|
|
||||||
pub bursting: bool,
|
|
||||||
pub monster_stats: Box<HashMap<MonsterType, MonsterStats>>,
|
|
||||||
pub map_areas: MapAreaLookup,
|
|
||||||
pub quest_group: QuestCategoryType,
|
|
||||||
pub standard_quests: QuestList,
|
|
||||||
pub government_quests: QuestList,
|
|
||||||
// enemy info
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RoomState {
|
|
||||||
pub fn get_flags_for_room_list(&self) -> u8 {
|
|
||||||
let mut flags = 0u8;
|
|
||||||
|
|
||||||
match self.mode {
|
|
||||||
RoomMode::Single {..} => {flags += 0x04}
|
|
||||||
RoomMode::Battle {..} => {flags += 0x10},
|
|
||||||
RoomMode::Challenge {..} => {flags += 0x20},
|
|
||||||
_ => {flags += 0x40},
|
|
||||||
};
|
|
||||||
|
|
||||||
if self.password[0] > 0 {
|
|
||||||
flags += 0x02;
|
|
||||||
}
|
|
||||||
flags
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_episode_for_room_list(&self) -> u8 {
|
|
||||||
let episode: u8 = self.mode.episode().into();
|
|
||||||
|
|
||||||
match self.mode {
|
|
||||||
RoomMode::Single {..} => episode + 0x10,
|
|
||||||
_ => episode + 0x40,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_difficulty_for_room_list(&self) -> u8 {
|
|
||||||
let difficulty: u8 = self.mode.difficulty().into();
|
|
||||||
difficulty + 0x22
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn quests(&self) -> &QuestList {
|
|
||||||
match self.quest_group {
|
|
||||||
QuestCategoryType::Standard => &self.standard_quests,
|
|
||||||
QuestCategoryType::Government => &self.government_quests,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments, clippy::type_complexity)]
|
|
||||||
pub fn new (room_id: RoomEntityId,
|
|
||||||
mode: RoomEntityMode,
|
|
||||||
episode: Episode,
|
|
||||||
difficulty: Difficulty,
|
|
||||||
section_id: SectionID,
|
|
||||||
name: String,
|
|
||||||
password: [u16; 16],
|
|
||||||
event: Holiday,
|
|
||||||
map_builder: Arc<Box<dyn Fn(RoomMode, Holiday) -> Maps + Send + Sync>>,
|
|
||||||
drop_table_builder: Arc<Box<dyn Fn(Episode, Difficulty, SectionID) -> Box<dyn DropTable + Send + Sync> + Send + Sync>>,
|
|
||||||
standard_quest_builder: Arc<Box<dyn Fn(RoomMode) -> Result<QuestList, QuestLoadError> + Send + Sync>>,
|
|
||||||
government_quest_builder: Arc<Box<dyn Fn(RoomMode) -> Result<QuestList, QuestLoadError> + Send + Sync>>,
|
|
||||||
) -> Result<RoomState, anyhow::Error> {
|
|
||||||
let mode = match mode {
|
|
||||||
RoomEntityMode::Single => RoomMode::Single {
|
|
||||||
episode,
|
|
||||||
difficulty,
|
|
||||||
},
|
|
||||||
RoomEntityMode::Multi => RoomMode::Multi {
|
|
||||||
episode,
|
|
||||||
difficulty,
|
|
||||||
},
|
|
||||||
RoomEntityMode::Challenge => RoomMode::Challenge {
|
|
||||||
episode,
|
|
||||||
},
|
|
||||||
RoomEntityMode::Battle => RoomMode::Battle {
|
|
||||||
episode,
|
|
||||||
difficulty,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(RoomState {
|
|
||||||
room_id,
|
|
||||||
monster_stats: Box::new(load_monster_stats_table(&mode).map_err(|_| RoomCreationError::CouldNotLoadMonsterStats(mode))?),
|
|
||||||
mode,
|
|
||||||
random_seed: rand::thread_rng().gen(),
|
|
||||||
name,
|
|
||||||
password,
|
|
||||||
maps: map_builder(mode, event),
|
|
||||||
section_id,
|
|
||||||
drop_table: drop_table_builder(episode, difficulty, section_id),
|
|
||||||
bursting: false,
|
|
||||||
map_areas: MapAreaLookup::new(&episode),
|
|
||||||
quest_group: QuestCategoryType::Standard,
|
|
||||||
standard_quests: standard_quest_builder(mode)?,
|
|
||||||
government_quests: government_quest_builder(mode)?,
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +1,10 @@
|
|||||||
use libpso::character::character;
|
use libpso::character::character;
|
||||||
use stats::leveltable::CharacterStats;
|
use crate::common::leveltable::CharacterStats;
|
||||||
use entity::character::CharacterEntity;
|
use crate::entity::character::CharacterEntity;
|
||||||
use items::bank::BankState;
|
//use crate::ship::items::{CharacterInventory, CharacterBank};
|
||||||
use items::inventory::InventoryState;
|
use crate::ship::items::bank::BankState;
|
||||||
use entity::item::Meseta;
|
use crate::ship::items::inventory::InventoryState;
|
||||||
|
use crate::entity::item::Meseta;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
@ -53,7 +54,7 @@ impl<'a> CharacterBytesBuilder<'a> {
|
|||||||
let level = self.level.unwrap();
|
let level = self.level.unwrap();
|
||||||
let meseta = self.meseta.unwrap();
|
let meseta = self.meseta.unwrap();
|
||||||
character::Character {
|
character::Character {
|
||||||
name: libpso::util::utf8_to_utf16_array(&character.name),
|
name: libpso::utf8_to_utf16_array!(character.name, 16),
|
||||||
hp: stats.hp,
|
hp: stats.hp,
|
||||||
atp: stats.atp + character.materials.power as u16 * 2,
|
atp: stats.atp + character.materials.power as u16 * 2,
|
||||||
mst: stats.mst + character.materials.mind as u16 * 2,
|
mst: stats.mst + character.materials.mind as u16 * 2,
|
19
src/ship/chatcommand.rs
Normal file
19
src/ship/chatcommand.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
|
||||||
|
use libpso::packet::ship::PlayerChat;
|
||||||
|
use crate::entity::gateway::EntityGateway;
|
||||||
|
|
||||||
|
use crate::common::serverstate::ClientId;
|
||||||
|
use crate::ship::ship::{ShipServerState, SendShipPacket};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pub async fn handle_chat_command<EG>(id: ClientId,
|
||||||
|
message: PlayerChat,
|
||||||
|
state: &mut ShipServerState<EG>)
|
||||||
|
-> Option<Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error>>
|
||||||
|
where
|
||||||
|
EG: EntityGateway + Clone + 'static,
|
||||||
|
{
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
@ -6,20 +6,15 @@ use futures::future::BoxFuture;
|
|||||||
use libpso::packet::ship::*;
|
use libpso::packet::ship::*;
|
||||||
use libpso::packet::login::Session;
|
use libpso::packet::login::Session;
|
||||||
|
|
||||||
use networking::serverstate::ClientId;
|
use crate::common::serverstate::ClientId;
|
||||||
use entity::account::{UserAccountEntity, UserSettingsEntity};
|
use crate::entity::account::{UserAccountEntity, UserSettingsEntity};
|
||||||
use entity::character::CharacterEntity;
|
use crate::entity::character::CharacterEntity;
|
||||||
use entity::item;
|
use crate::entity::item;
|
||||||
|
|
||||||
use maps::area::MapArea;
|
use crate::ship::ship::ShipError;
|
||||||
use shops::{WeaponShopItem, ToolShopItem, ArmorShopItem};
|
use crate::ship::items;
|
||||||
|
use crate::ship::map::MapArea;
|
||||||
|
use crate::ship::shops::{WeaponShopItem, ToolShopItem, ArmorShopItem};
|
||||||
#[derive(thiserror::Error, Debug)]
|
|
||||||
pub enum ClientError {
|
|
||||||
#[error("not found {0}")]
|
|
||||||
NotFound(ClientId),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
@ -51,7 +46,7 @@ impl Clients {
|
|||||||
.await;
|
.await;
|
||||||
let client = clients
|
let client = clients
|
||||||
.get(&client_id)
|
.get(&client_id)
|
||||||
.ok_or(ClientError::NotFound(client_id))?
|
.ok_or_else(|| ShipError::ClientNotFound(client_id))?
|
||||||
.read()
|
.read()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
@ -74,14 +69,17 @@ impl Clients {
|
|||||||
for (cindex, client_id) in client_ids.iter().enumerate() {
|
for (cindex, client_id) in client_ids.iter().enumerate() {
|
||||||
let c = clients
|
let c = clients
|
||||||
.get(client_id)
|
.get(client_id)
|
||||||
.ok_or(ClientError::NotFound(*client_id))?
|
.ok_or_else(|| ShipError::ClientNotFound(*client_id))?
|
||||||
.read()
|
.read()
|
||||||
.await;
|
.await;
|
||||||
client_states[cindex].write(c);
|
client_states[cindex].write(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
let client_states = unsafe {
|
let client_states = unsafe {
|
||||||
std::mem::transmute_copy(&client_states)
|
// TODO: this should just be a normal transmute but due to compiler limitations it
|
||||||
|
// does not yet work with const generics
|
||||||
|
// https://github.com/rust-lang/rust/issues/61956
|
||||||
|
std::mem::transmute_copy::<_, [RwLockReadGuard<ClientState>; N]>(&client_states)
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(func(client_states).await)
|
Ok(func(client_states).await)
|
||||||
@ -97,7 +95,7 @@ impl Clients {
|
|||||||
.await;
|
.await;
|
||||||
let mut client = clients
|
let mut client = clients
|
||||||
.get(&client_id)
|
.get(&client_id)
|
||||||
.ok_or(ClientError::NotFound(client_id))?
|
.ok_or_else(|| ShipError::ClientNotFound(client_id))?
|
||||||
.write()
|
.write()
|
||||||
.await;
|
.await;
|
||||||
|
|
@ -2,17 +2,18 @@
|
|||||||
use rand::{Rng};
|
use rand::{Rng};
|
||||||
use rand::distributions::{WeightedIndex, Distribution};
|
use rand::distributions::{WeightedIndex, Distribution};
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use entity::character::SectionID;
|
use crate::entity::character::SectionID;
|
||||||
use maps::room::{Difficulty, Episode};
|
use crate::ship::room::{Difficulty, Episode};
|
||||||
use maps::area::MapArea;
|
use crate::ship::map::MapArea;
|
||||||
use crate::{ItemDropType, load_data_file};
|
use crate::ship::drops::{ItemDropType, load_data_file};
|
||||||
use maps::object::{MapObject, MapObjectType, FixedBoxDropType};
|
use crate::ship::map::{MapObject, MapObjectType, FixedBoxDropType};
|
||||||
use crate::rare_drop_table::{RareDropTable, RareDropItem};
|
use crate::ship::drops::rare_drop_table::{RareDropTable, RareDropItem};
|
||||||
use crate::generic_weapon::GenericWeaponTable;
|
use crate::ship::drops::generic_weapon::GenericWeaponTable;
|
||||||
use crate::generic_armor::GenericArmorTable;
|
use crate::ship::drops::generic_armor::GenericArmorTable;
|
||||||
use crate::generic_shield::GenericShieldTable;
|
use crate::ship::drops::generic_shield::GenericShieldTable;
|
||||||
use crate::generic_unit::GenericUnitTable;
|
use crate::ship::drops::generic_unit::GenericUnitTable;
|
||||||
use crate::tool_table::ToolTable;
|
use crate::ship::drops::tool_table::ToolTable;
|
||||||
|
use crate::entity::item::ItemDetail;
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
struct BoxDropRate {
|
struct BoxDropRate {
|
||||||
@ -175,8 +176,8 @@ impl BoxDropTable {
|
|||||||
fn random_box_drop<R: Rng>(&self, map_area: &MapArea, rng: &mut R) -> Option<ItemDropType> {
|
fn random_box_drop<R: Rng>(&self, map_area: &MapArea, rng: &mut R) -> Option<ItemDropType> {
|
||||||
self.rare_drop(map_area, rng).or_else(|| {
|
self.rare_drop(map_area, rng).or_else(|| {
|
||||||
let rate = self.box_rates.rates_by_area(map_area);
|
let rate = self.box_rates.rates_by_area(map_area);
|
||||||
let type_weights = WeightedIndex::new([rate.weapon_rate, rate.armor_rate, rate.shield_rate, rate.unit_rate,
|
let type_weights = WeightedIndex::new(&[rate.weapon_rate, rate.armor_rate, rate.shield_rate, rate.unit_rate,
|
||||||
rate.tool_rate, rate.meseta_rate, rate.nothing_rate]).unwrap();
|
rate.tool_rate, rate.meseta_rate, rate.nothing_rate]).unwrap();
|
||||||
let btype = type_weights.sample(rng);
|
let btype = type_weights.sample(rng);
|
||||||
match btype {
|
match btype {
|
||||||
0 => self.weapon_table.get_drop(map_area, rng),
|
0 => self.weapon_table.get_drop(map_area, rng),
|
||||||
@ -203,7 +204,7 @@ impl BoxDropTable {
|
|||||||
FixedBoxDropType::Specific(value) => {
|
FixedBoxDropType::Specific(value) => {
|
||||||
let mut buf: [u8; 16] = [0; 16];
|
let mut buf: [u8; 16] = [0; 16];
|
||||||
buf[0..4].copy_from_slice(&u32::to_be_bytes(value));
|
buf[0..4].copy_from_slice(&u32::to_be_bytes(value));
|
||||||
ItemDropType::parse_item_from_bytes(buf)
|
ItemDetail::parse_item_from_bytes(buf)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,14 +1,14 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use rand::Rng;
|
use rand::{Rng};
|
||||||
use rand::distributions::{WeightedIndex, Distribution};
|
use rand::distributions::{WeightedIndex, Distribution};
|
||||||
|
|
||||||
use entity::character::SectionID;
|
use crate::entity::item::armor::{ArmorType, Armor};
|
||||||
use entity::item::armor::{ArmorType, Armor};
|
use crate::ship::room::{Difficulty, Episode};
|
||||||
use maps::room::{Difficulty, Episode};
|
use crate::ship::map::MapArea;
|
||||||
use maps::area::MapArea;
|
use crate::entity::character::SectionID;
|
||||||
use crate::{ItemDropType, load_data_file};
|
use crate::ship::drops::{ItemDropType, load_data_file};
|
||||||
use stats::items::{armor_stats, ArmorStats};
|
use crate::ship::item_stats::{armor_stats, ArmorStats};
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
@ -46,8 +46,8 @@ impl GenericArmorTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn armor_type<R: Rng>(&self, area_map: &MapArea, rng: &mut R) -> ArmorType {
|
fn armor_type<R: Rng>(&self, area_map: &MapArea, rng: &mut R) -> ArmorType {
|
||||||
let rank_weights = WeightedIndex::new([self.rank_rates.rank0, self.rank_rates.rank1, self.rank_rates.rank2,
|
let rank_weights = WeightedIndex::new(&[self.rank_rates.rank0, self.rank_rates.rank1, self.rank_rates.rank2,
|
||||||
self.rank_rates.rank3, self.rank_rates.rank4]).unwrap();
|
self.rank_rates.rank3, self.rank_rates.rank4]).unwrap();
|
||||||
let rank = rank_weights.sample(rng) as i32;
|
let rank = rank_weights.sample(rng) as i32;
|
||||||
let armor_level = std::cmp::max(0i32, self.armor_set as i32 - 3i32 + rank + area_map.drop_area_value().unwrap_or(0) as i32);
|
let armor_level = std::cmp::max(0i32, self.armor_set as i32 - 3i32 + rank + area_map.drop_area_value().unwrap_or(0) as i32);
|
||||||
match armor_level {
|
match armor_level {
|
||||||
@ -80,8 +80,8 @@ impl GenericArmorTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn slots<R: Rng>(&self, _area_map: &MapArea, rng: &mut R) -> usize {
|
pub fn slots<R: Rng>(&self, _area_map: &MapArea, rng: &mut R) -> usize {
|
||||||
let slot_weights = WeightedIndex::new([self.slot_rates.slot0, self.slot_rates.slot1, self.slot_rates.slot2,
|
let slot_weights = WeightedIndex::new(&[self.slot_rates.slot0, self.slot_rates.slot1, self.slot_rates.slot2,
|
||||||
self.slot_rates.slot3, self.slot_rates.slot4]).unwrap();
|
self.slot_rates.slot3, self.slot_rates.slot4]).unwrap();
|
||||||
slot_weights.sample(rng)
|
slot_weights.sample(rng)
|
||||||
}
|
}
|
||||||
|
|
@ -1,14 +1,14 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use rand::Rng;
|
use rand::{Rng};
|
||||||
use rand::distributions::{WeightedIndex, Distribution};
|
use rand::distributions::{WeightedIndex, Distribution};
|
||||||
|
|
||||||
use entity::item::shield::{ShieldType, Shield};
|
use crate::entity::item::shield::{ShieldType, Shield};
|
||||||
use entity::character::SectionID;
|
use crate::ship::room::{Difficulty, Episode};
|
||||||
use maps::room::{Difficulty, Episode};
|
use crate::ship::map::MapArea;
|
||||||
use maps::area::MapArea;
|
use crate::entity::character::SectionID;
|
||||||
use crate::{ItemDropType, load_data_file};
|
use crate::ship::drops::{ItemDropType, load_data_file};
|
||||||
use stats::items::{shield_stats, ShieldStats};
|
use crate::ship::item_stats::{shield_stats, ShieldStats};
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
@ -36,8 +36,8 @@ impl GenericShieldTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn shield_type<R: Rng>(&self, area_map: &MapArea, rng: &mut R) -> ShieldType {
|
fn shield_type<R: Rng>(&self, area_map: &MapArea, rng: &mut R) -> ShieldType {
|
||||||
let rank_weights = WeightedIndex::new([self.rank_rates.rank0, self.rank_rates.rank1, self.rank_rates.rank2,
|
let rank_weights = WeightedIndex::new(&[self.rank_rates.rank0, self.rank_rates.rank1, self.rank_rates.rank2,
|
||||||
self.rank_rates.rank3, self.rank_rates.rank4]).unwrap();
|
self.rank_rates.rank3, self.rank_rates.rank4]).unwrap();
|
||||||
let rank = rank_weights.sample(rng) as i32;
|
let rank = rank_weights.sample(rng) as i32;
|
||||||
let shield_level = std::cmp::max(0i32, self.shield_set as i32 - 3i32 + rank + area_map.drop_area_value().unwrap_or(0) as i32);
|
let shield_level = std::cmp::max(0i32, self.shield_set as i32 - 3i32 + rank + area_map.drop_area_value().unwrap_or(0) as i32);
|
||||||
match shield_level {
|
match shield_level {
|
@ -1,14 +1,14 @@
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use rand::Rng;
|
use rand::{Rng};
|
||||||
use rand::seq::IteratorRandom;
|
use rand::seq::IteratorRandom;
|
||||||
|
|
||||||
use entity::character::SectionID;
|
use crate::entity::item::unit::{UnitType, Unit, UnitModifier};
|
||||||
use entity::item::unit::{UnitType, Unit, UnitModifier};
|
use crate::ship::room::{Difficulty, Episode};
|
||||||
use maps::room::{Difficulty, Episode};
|
use crate::ship::map::MapArea;
|
||||||
use maps::area::MapArea;
|
use crate::entity::character::SectionID;
|
||||||
use crate::{ItemDropType, load_data_file};
|
use crate::ship::drops::{ItemDropType, load_data_file};
|
||||||
use stats::items::{unit_stats, UnitStats};
|
use crate::ship::item_stats::{unit_stats, UnitStats};
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
|||||||
use std::collections::{HashMap, BTreeMap};
|
use std::collections::{HashMap, BTreeMap};
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use rand::Rng;
|
use rand::{Rng};
|
||||||
use rand::distributions::{WeightedIndex, Distribution};
|
use rand::distributions::{WeightedIndex, Distribution};
|
||||||
use rand::seq::SliceRandom;
|
use rand::seq::SliceRandom;
|
||||||
|
|
||||||
use entity::character::SectionID;
|
use crate::entity::item::weapon::{Weapon, WeaponType, Attribute, WeaponAttribute, WeaponSpecial};
|
||||||
use entity::item::weapon::{Weapon, WeaponType, Attribute, WeaponAttribute, WeaponSpecial};
|
use crate::ship::room::{Difficulty, Episode};
|
||||||
use maps::room::{Difficulty, Episode};
|
use crate::ship::map::MapArea;
|
||||||
use maps::area::MapArea;
|
use crate::entity::character::SectionID;
|
||||||
use crate::{ItemDropType, load_data_file};
|
use crate::ship::drops::{ItemDropType, load_data_file};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -240,7 +240,7 @@ impl AttributeTable {
|
|||||||
|
|
||||||
|
|
||||||
fn generate_attribute<R: Rng>(&self, pattern: &PercentPatternType, rates: &AttributeRate, rng: &mut R) -> Option<WeaponAttribute> {
|
fn generate_attribute<R: Rng>(&self, pattern: &PercentPatternType, rates: &AttributeRate, rng: &mut R) -> Option<WeaponAttribute> {
|
||||||
let attribute_weights = WeightedIndex::new([rates.none, rates.native, rates.abeast, rates.machine, rates.dark, rates.hit]).unwrap();
|
let attribute_weights = WeightedIndex::new(&[rates.none, rates.native, rates.abeast, rates.machine, rates.dark, rates.hit]).unwrap();
|
||||||
let attr = match attribute_weights.sample(rng) {
|
let attr = match attribute_weights.sample(rng) {
|
||||||
0 => return None,
|
0 => return None,
|
||||||
1 => Attribute::Native,
|
1 => Attribute::Native,
|
||||||
@ -253,7 +253,7 @@ impl AttributeTable {
|
|||||||
|
|
||||||
let percents = self.percent_rates.get_by_pattern(pattern);
|
let percents = self.percent_rates.get_by_pattern(pattern);
|
||||||
|
|
||||||
let value_weights = WeightedIndex::new(percents.as_array()).unwrap();
|
let value_weights = WeightedIndex::new(&percents.as_array()).unwrap();
|
||||||
let value = value_weights.sample(rng);
|
let value = value_weights.sample(rng);
|
||||||
let percent = ((value + 1) * 5) as i8;
|
let percent = ((value + 1) * 5) as i8;
|
||||||
|
|
||||||
@ -477,7 +477,7 @@ impl GenericWeaponTable {
|
|||||||
let pattern = std::cmp::min(area % ratio.inc, 3);
|
let pattern = std::cmp::min(area % ratio.inc, 3);
|
||||||
|
|
||||||
let weights = self.grind_rates.grind_rate[pattern as usize];
|
let weights = self.grind_rates.grind_rate[pattern as usize];
|
||||||
let grind_choice = WeightedIndex::new(weights).unwrap();
|
let grind_choice = WeightedIndex::new(&weights).unwrap();
|
||||||
grind_choice.sample(rng)
|
grind_choice.sample(rng)
|
||||||
}
|
}
|
||||||
|
|
@ -5,6 +5,7 @@
|
|||||||
// to their drops
|
// to their drops
|
||||||
|
|
||||||
|
|
||||||
|
mod drop_table;
|
||||||
pub mod rare_drop_table;
|
pub mod rare_drop_table;
|
||||||
mod generic_weapon;
|
mod generic_weapon;
|
||||||
mod generic_armor;
|
mod generic_armor;
|
||||||
@ -21,19 +22,19 @@ use std::io::Read;
|
|||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use rand::{Rng, SeedableRng};
|
use rand::{Rng, SeedableRng};
|
||||||
|
|
||||||
use maps::monster::MonsterType;
|
use crate::ship::monster::MonsterType;
|
||||||
use maps::room::{Difficulty, Episode};
|
use crate::ship::room::{Difficulty, Episode};
|
||||||
use maps::area::MapArea;
|
use crate::ship::map::MapArea;
|
||||||
use entity::character::SectionID;
|
use crate::entity::character::SectionID;
|
||||||
use crate::generic_weapon::GenericWeaponTable;
|
use crate::ship::drops::generic_weapon::GenericWeaponTable;
|
||||||
use crate::generic_armor::GenericArmorTable;
|
use crate::ship::drops::generic_armor::GenericArmorTable;
|
||||||
use crate::generic_shield::GenericShieldTable;
|
use crate::ship::drops::generic_shield::GenericShieldTable;
|
||||||
use crate::generic_unit::GenericUnitTable;
|
use crate::ship::drops::generic_unit::GenericUnitTable;
|
||||||
use crate::tool_table::ToolTable;
|
use crate::ship::drops::tool_table::ToolTable;
|
||||||
use crate::rare_drop_table::RareDropTable;
|
use crate::ship::drops::rare_drop_table::RareDropTable;
|
||||||
use crate::box_drop_table::BoxDropTable;
|
use crate::ship::drops::box_drop_table::BoxDropTable;
|
||||||
use maps::object::MapObject;
|
use crate::ship::map::MapObject;
|
||||||
use entity::item::{ItemType, weapon, armor, shield, unit, mag, tool, tech, esweapon};
|
use crate::entity::item::{weapon, armor, shield, unit, mag, tool, tech};
|
||||||
|
|
||||||
|
|
||||||
fn data_file_path(episode: Episode, difficulty: Difficulty, section_id: SectionID, filename: &str) -> PathBuf {
|
fn data_file_path(episode: Episode, difficulty: Difficulty, section_id: SectionID, filename: &str) -> PathBuf {
|
||||||
@ -54,6 +55,18 @@ pub fn load_data_file<T: serde::de::DeserializeOwned>(episode: Episode, difficul
|
|||||||
toml::from_str::<T>(s.as_str()).unwrap()
|
toml::from_str::<T>(s.as_str()).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this is just copypaste
|
||||||
|
pub fn load_rare_monster_file<T: serde::de::DeserializeOwned>(episode: Episode) -> T {
|
||||||
|
// TODO: where does the rare monster toml file actually live
|
||||||
|
let mut path = PathBuf::from("data/battle_param/");
|
||||||
|
path.push(episode.to_string().to_lowercase() + "_rare_monster.toml");
|
||||||
|
|
||||||
|
let mut f = File::open(path).unwrap();
|
||||||
|
let mut s = String::new();
|
||||||
|
f.read_to_string(&mut s);
|
||||||
|
toml::from_str::<T>(s.as_str()).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Copy, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Copy, Clone)]
|
||||||
pub enum MonsterDropType {
|
pub enum MonsterDropType {
|
||||||
#[serde(rename = "weapon")]
|
#[serde(rename = "weapon")]
|
||||||
@ -89,28 +102,6 @@ pub enum ItemDropType {
|
|||||||
Meseta(u32),
|
Meseta(u32),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ItemDropType {
|
|
||||||
pub fn parse_item_from_bytes(data: [u8; 16]) -> Option<ItemDropType> {
|
|
||||||
let item_type = weapon::WeaponType::parse_type([data[0],data[1],data[2]]).map(ItemType::Weapon)
|
|
||||||
.or_else(|_| armor::ArmorType::parse_type([data[0],data[1],data[2]]).map(ItemType::Armor))
|
|
||||||
.or_else(|_| shield::ShieldType::parse_type([data[0],data[1],data[2]]).map(ItemType::Shield))
|
|
||||||
.or_else(|_| unit::UnitType::parse_type([data[0],data[1],data[2]]).map(ItemType::Unit))
|
|
||||||
.or_else(|_| mag::MagType::parse_type([data[0],data[1],data[2]]).map(ItemType::Mag))
|
|
||||||
.or_else(|_| tool::ToolType::parse_type([data[0],data[1],data[2]]).map(ItemType::Tool))
|
|
||||||
.or_else(|_| esweapon::ESWeaponType::parse_type([data[0],data[1],data[2]]).map(ItemType::ESWeapon)).ok()?;
|
|
||||||
|
|
||||||
match item_type {
|
|
||||||
ItemType::Weapon(_w) => Some(ItemDropType::Weapon(weapon::Weapon::from_bytes(data).ok()?)),
|
|
||||||
ItemType::Armor(_a) => Some(ItemDropType::Armor(armor::Armor::from_bytes(data).ok()?)),
|
|
||||||
ItemType::Shield(_s) => Some(ItemDropType::Shield(shield::Shield::from_bytes(data).ok()?)),
|
|
||||||
ItemType::Unit(_u) => Some(ItemDropType::Unit(unit::Unit::from_bytes(data).ok()?)),
|
|
||||||
ItemType::Mag(_m) => Some(ItemDropType::Mag(mag::Mag::from_bytes(data).ok()?)),
|
|
||||||
ItemType::Tool(_t) => Some(ItemDropType::Tool(tool::Tool::from_bytes(data).ok()?)),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ItemDrop {
|
pub struct ItemDrop {
|
||||||
pub map_area: MapArea,
|
pub map_area: MapArea,
|
||||||
@ -121,12 +112,7 @@ pub struct ItemDrop {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub trait DropTable {
|
pub struct DropTable {
|
||||||
fn get_drop(&mut self, map_area: &MapArea, monster: &MonsterType) -> Option<ItemDropType>;
|
|
||||||
fn get_box_drop(&mut self, map_area: &MapArea, object: &MapObject) -> Option<ItemDropType>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct StandardDropTable {
|
|
||||||
monster_stats: HashMap<MonsterType, MonsterDropStats>,
|
monster_stats: HashMap<MonsterType, MonsterDropStats>,
|
||||||
rare_table: RareDropTable,
|
rare_table: RareDropTable,
|
||||||
weapon_table: GenericWeaponTable,
|
weapon_table: GenericWeaponTable,
|
||||||
@ -138,12 +124,11 @@ pub struct StandardDropTable {
|
|||||||
rng: rand_chacha::ChaCha20Rng,
|
rng: rand_chacha::ChaCha20Rng,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StandardDropTable {
|
impl DropTable {
|
||||||
#[allow(clippy::new_ret_no_self)]
|
pub fn new(episode: Episode, difficulty: Difficulty, section_id: SectionID) -> DropTable {
|
||||||
pub fn new(episode: Episode, difficulty: Difficulty, section_id: SectionID) -> Box<dyn DropTable + Send + Sync> {
|
|
||||||
let monster_stats: HashMap<String, MonsterDropStats> = load_data_file(episode, difficulty, section_id, "monster_dar.toml");
|
let monster_stats: HashMap<String, MonsterDropStats> = load_data_file(episode, difficulty, section_id, "monster_dar.toml");
|
||||||
|
|
||||||
Box::new(StandardDropTable {
|
DropTable {
|
||||||
monster_stats: monster_stats.into_iter().map(|(m, s)| (m.parse().unwrap(), s)).collect(),
|
monster_stats: monster_stats.into_iter().map(|(m, s)| (m.parse().unwrap(), s)).collect(),
|
||||||
rare_table: RareDropTable::new(episode, difficulty, section_id),
|
rare_table: RareDropTable::new(episode, difficulty, section_id),
|
||||||
weapon_table: GenericWeaponTable::new(episode, difficulty, section_id),
|
weapon_table: GenericWeaponTable::new(episode, difficulty, section_id),
|
||||||
@ -153,7 +138,7 @@ impl StandardDropTable {
|
|||||||
tool_table: ToolTable::new(episode, difficulty, section_id),
|
tool_table: ToolTable::new(episode, difficulty, section_id),
|
||||||
box_table: BoxDropTable::new(episode, difficulty, section_id),
|
box_table: BoxDropTable::new(episode, difficulty, section_id),
|
||||||
rng: rand_chacha::ChaCha20Rng::from_entropy(),
|
rng: rand_chacha::ChaCha20Rng::from_entropy(),
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn builder() -> DropTableBuilder {
|
pub fn builder() -> DropTableBuilder {
|
||||||
@ -183,10 +168,8 @@ impl StandardDropTable {
|
|||||||
MonsterDropType::None => None,
|
MonsterDropType::None => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl DropTable for StandardDropTable {
|
pub fn get_drop(&mut self, map_area: &MapArea, monster: &MonsterType) -> Option<ItemDropType> {
|
||||||
fn get_drop(&mut self, map_area: &MapArea, monster: &MonsterType) -> Option<ItemDropType> {
|
|
||||||
let monster_stat = *self.monster_stats.get(monster)?;
|
let monster_stat = *self.monster_stats.get(monster)?;
|
||||||
|
|
||||||
let drop_anything = self.rng.gen_range(0, 100);
|
let drop_anything = self.rng.gen_range(0, 100);
|
||||||
@ -199,7 +182,7 @@ impl DropTable for StandardDropTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let drop_type = self.rng.gen_range(0, 3);
|
let drop_type = self.rng.gen_range(0, 3);
|
||||||
|
|
||||||
match drop_type {
|
match drop_type {
|
||||||
0 => {
|
0 => {
|
||||||
self.generate_meseta(&monster_stat)
|
self.generate_meseta(&monster_stat)
|
||||||
@ -214,7 +197,7 @@ impl DropTable for StandardDropTable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_box_drop(&mut self, map_area: &MapArea, object: &MapObject) -> Option<ItemDropType> {
|
pub fn get_box_drop(&mut self, map_area: &MapArea, object: &MapObject) -> Option<ItemDropType> {
|
||||||
self.box_table.get_drop(map_area, object, &mut self.rng)
|
self.box_table.get_drop(map_area, object, &mut self.rng)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -261,8 +244,8 @@ impl DropTableBuilder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(self, episode: Episode, difficulty: Difficulty, section_id: SectionID) -> Box<dyn DropTable + Send + Sync> {
|
pub fn build(self, episode: Episode, difficulty: Difficulty, section_id: SectionID) -> DropTable {
|
||||||
Box::new(StandardDropTable {
|
DropTable {
|
||||||
monster_stats: self.monster_stats.unwrap_or_else(|| {
|
monster_stats: self.monster_stats.unwrap_or_else(|| {
|
||||||
let monster_stats: HashMap<String, MonsterDropStats> = load_data_file(episode, difficulty, section_id, "monster_dar.toml");
|
let monster_stats: HashMap<String, MonsterDropStats> = load_data_file(episode, difficulty, section_id, "monster_dar.toml");
|
||||||
monster_stats.into_iter().map(|(m, s)| (m.parse().unwrap(), s)).collect()
|
monster_stats.into_iter().map(|(m, s)| (m.parse().unwrap(), s)).collect()
|
||||||
@ -275,10 +258,11 @@ impl DropTableBuilder {
|
|||||||
tool_table: self.tool_table.unwrap_or_else(|| ToolTable::new(episode, difficulty, section_id)),
|
tool_table: self.tool_table.unwrap_or_else(|| ToolTable::new(episode, difficulty, section_id)),
|
||||||
box_table: self.box_table.unwrap_or_else(|| BoxDropTable::new(episode, difficulty, section_id)),
|
box_table: self.box_table.unwrap_or_else(|| BoxDropTable::new(episode, difficulty, section_id)),
|
||||||
rng: self.rng.unwrap_or_else(rand_chacha::ChaCha20Rng::from_entropy),
|
rng: self.rng.unwrap_or_else(rand_chacha::ChaCha20Rng::from_entropy),
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
@ -1,20 +1,20 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use entity::item::weapon::{Weapon, WeaponType};
|
use crate::entity::item::weapon::{Weapon, WeaponType};
|
||||||
use entity::item::armor::{Armor, ArmorType};
|
use crate::entity::item::armor::{Armor, ArmorType};
|
||||||
use entity::item::shield::{Shield, ShieldType};
|
use crate::entity::item::shield::{Shield, ShieldType};
|
||||||
use entity::item::unit::{Unit, UnitType};
|
use crate::entity::item::unit::{Unit, UnitType};
|
||||||
use entity::item::tool::{Tool, ToolType};
|
use crate::entity::item::tool::{Tool, ToolType};
|
||||||
use entity::item::mag::{Mag, MagType};
|
use crate::entity::item::mag::{Mag, MagType};
|
||||||
use entity::character::SectionID;
|
use crate::entity::character::SectionID;
|
||||||
use maps::monster::MonsterType;
|
use crate::ship::monster::MonsterType;
|
||||||
use maps::room::{Difficulty, Episode};
|
use crate::ship::room::{Difficulty, Episode};
|
||||||
use maps::area::MapArea;
|
use crate::ship::map::MapArea;
|
||||||
use crate::{ItemDropType, load_data_file};
|
use crate::ship::drops::{ItemDropType, load_data_file};
|
||||||
use crate::generic_weapon::AttributeTable;
|
use crate::ship::drops::generic_weapon::AttributeTable;
|
||||||
use crate::generic_armor::GenericArmorTable;
|
use crate::ship::drops::generic_armor::GenericArmorTable;
|
||||||
use crate::generic_shield::GenericShieldTable;
|
use crate::ship::drops::generic_shield::GenericShieldTable;
|
||||||
|
|
||||||
type ItemParseFn = Box<dyn Fn(&String) -> Option<RareDropItem>>;
|
type ItemParseFn = Box<dyn Fn(&String) -> Option<RareDropItem>>;
|
||||||
|
|
@ -3,11 +3,11 @@ use serde::{Serialize, Deserialize};
|
|||||||
use rand::{Rng};
|
use rand::{Rng};
|
||||||
use rand::distributions::{WeightedIndex, Distribution};
|
use rand::distributions::{WeightedIndex, Distribution};
|
||||||
|
|
||||||
use entity::item::tech::{Technique, TechniqueDisk};
|
use crate::entity::item::tech::{Technique, TechniqueDisk};
|
||||||
use maps::room::{Difficulty, Episode};
|
use crate::ship::room::{Difficulty, Episode};
|
||||||
use maps::area::MapArea;
|
use crate::ship::map::MapArea;
|
||||||
use entity::character::SectionID;
|
use crate::entity::character::SectionID;
|
||||||
use crate::{ItemDropType, load_data_file};
|
use crate::ship::drops::{ItemDropType, load_data_file};
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::{BTreeMap};
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use rand::Rng;
|
use rand::{Rng};
|
||||||
use rand::distributions::{WeightedIndex, Distribution};
|
use rand::distributions::{WeightedIndex, Distribution};
|
||||||
|
|
||||||
use entity::item::tool::{Tool, ToolType};
|
use crate::entity::item::tool::{Tool, ToolType};
|
||||||
use maps::room::{Difficulty, Episode};
|
use crate::ship::room::{Difficulty, Episode};
|
||||||
use maps::area::MapArea;
|
use crate::ship::map::MapArea;
|
||||||
use entity::character::SectionID;
|
use crate::entity::character::SectionID;
|
||||||
use crate::{ItemDropType, load_data_file};
|
use crate::ship::drops::{ItemDropType, load_data_file};
|
||||||
use crate::tech_table::TechniqueTable;
|
use crate::ship::drops::tech_table::TechniqueTable;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, enum_utils::FromStr)]
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, enum_utils::FromStr)]
|
@ -4,13 +4,13 @@ use serde::{Serialize, Deserialize};
|
|||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
|
||||||
use entity::item::weapon::WeaponType;
|
use crate::entity::item::weapon::WeaponType;
|
||||||
use entity::item::armor::ArmorType;
|
use crate::entity::item::armor::ArmorType;
|
||||||
use entity::item::shield::ShieldType;
|
use crate::entity::item::shield::ShieldType;
|
||||||
use entity::item::unit::UnitType;
|
use crate::entity::item::unit::UnitType;
|
||||||
use entity::item::mag::MagType;
|
use crate::entity::item::mag::MagType;
|
||||||
use entity::item::tool::ToolType;
|
use crate::entity::item::tool::ToolType;
|
||||||
use entity::item::tech::Technique;
|
use crate::entity::item::tech::Technique;
|
||||||
|
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
@ -1,48 +1,45 @@
|
|||||||
// TODO: replace various u32s and usizes denoting item amounts for ItemAmount(u32) for consistency
|
// TODO: replace various u32s and usizes denoting item amounts for ItemAmount(u32) for consistency
|
||||||
use crate::ClientItemId;
|
use crate::ship::items::ClientItemId;
|
||||||
use entity::item::{Meseta, ItemNote};
|
use crate::entity::item::{Meseta, ItemNote};
|
||||||
use async_std::sync::Arc;
|
use async_std::sync::Arc;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use futures::future::BoxFuture;
|
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::iter::IntoIterator;
|
use std::iter::IntoIterator;
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
|
|
||||||
use entity::character::{CharacterEntity, CharacterEntityId};
|
use libpso::packet::{ship::Message, messages::GameMessage};
|
||||||
use entity::gateway::{EntityGateway, EntityGatewayTransaction};
|
use crate::ship::map::MapArea;
|
||||||
use entity::item::{ItemDetail, NewItemEntity, TradeId, ItemModifier};
|
use crate::ship::ship::SendShipPacket;
|
||||||
use entity::item::tool::Tool;
|
use crate::entity::character::{CharacterEntity, CharacterEntityId};
|
||||||
use entity::room::RoomEntityId;
|
use crate::entity::gateway::{EntityGateway, EntityGatewayTransaction};
|
||||||
use maps::area::MapArea;
|
use crate::ship::items::state::{ItemStateProxy, ItemStateError, AddItemResult, StackedItemDetail, IndividualItemDetail};
|
||||||
use crate::state::{ItemStateProxy, ItemStateError, AddItemResult, StackedItemDetail, IndividualItemDetail};
|
use crate::ship::items::bank::{BankItem, BankItemDetail};
|
||||||
use crate::bank::{BankItem, BankItemDetail};
|
use crate::ship::items::inventory::{InventoryItem, InventoryItemDetail};
|
||||||
use crate::inventory::{InventoryItem, InventoryItemDetail};
|
use crate::ship::items::floor::{FloorItem, FloorItemDetail};
|
||||||
use crate::floor::{FloorItem, FloorItemDetail};
|
use crate::ship::items::apply_item::{apply_item, ApplyItemAction};
|
||||||
use crate::apply_item::{apply_item, ApplyItemAction};
|
use crate::entity::item::{ItemDetail, NewItemEntity, TradeId};
|
||||||
use shops::ShopItem;
|
use crate::entity::item::tool::Tool;
|
||||||
use drops::{ItemDrop, ItemDropType};
|
use crate::entity::item::ItemModifier;
|
||||||
use location::AreaClient;
|
use crate::ship::shops::ShopItem;
|
||||||
use maps::monster::MonsterType;
|
use crate::ship::drops::{ItemDrop, ItemDropType};
|
||||||
|
use crate::ship::packet::builder;
|
||||||
|
use crate::ship::location::AreaClient;
|
||||||
|
|
||||||
|
type BoxFuture<T> = Pin<Box<dyn Future<Output=T> + Send>>;
|
||||||
|
|
||||||
pub enum TriggerCreateItem {
|
pub enum TriggerCreateItem {
|
||||||
Yes,
|
Yes,
|
||||||
No
|
No
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
pub(super) fn take_item_from_floor<EG, TR>(
|
||||||
pub enum CreateItem {
|
|
||||||
Individual(AreaClient, ClientItemId, IndividualItemDetail),
|
|
||||||
Stacked(AreaClient, ClientItemId, Tool, usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn take_item_from_floor<'a, EG, TR>(
|
|
||||||
character_id: CharacterEntityId,
|
character_id: CharacterEntityId,
|
||||||
item_id: ClientItemId
|
item_id: ClientItemId
|
||||||
) -> impl Fn((ItemStateProxy, TR), ())
|
) -> impl Fn((ItemStateProxy, TR), ())
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), FloorItem), anyhow::Error>> + 'a
|
-> BoxFuture<Result<((ItemStateProxy, TR), FloorItem), anyhow::Error>>
|
||||||
where
|
where
|
||||||
EG: EntityGateway + Send,
|
EG: EntityGateway + Send,
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'a,
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
{
|
{
|
||||||
move |(mut item_state, transaction): (ItemStateProxy, TR) , _| {
|
move |(mut item_state, transaction): (ItemStateProxy, TR) , _| {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
@ -55,13 +52,13 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn add_floor_item_to_inventory<'a, EG, TR>(
|
pub(super) fn add_floor_item_to_inventory<EG, TR>(
|
||||||
character: &CharacterEntity
|
character: &CharacterEntity
|
||||||
) -> impl Fn((ItemStateProxy, TR), FloorItem)
|
) -> impl Fn((ItemStateProxy, TR), FloorItem)
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), TriggerCreateItem), anyhow::Error>>
|
-> BoxFuture<Result<((ItemStateProxy, TR), TriggerCreateItem), anyhow::Error>>
|
||||||
where
|
where
|
||||||
EG: EntityGateway,
|
EG: EntityGateway,
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + Clone + 'a,
|
TR: EntityGatewayTransaction<ParentGateway = EG> + Clone + 'static,
|
||||||
{
|
{
|
||||||
let character = character.clone();
|
let character = character.clone();
|
||||||
move |(mut item_state, transaction), floor_item| {
|
move |(mut item_state, transaction), floor_item| {
|
||||||
@ -101,15 +98,15 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub(super) fn remove_item_from_inventory<'a, EG, TR>(
|
pub(super) fn remove_item_from_inventory<EG, TR>(
|
||||||
character_id: CharacterEntityId,
|
character_id: CharacterEntityId,
|
||||||
item_id: ClientItemId,
|
item_id: ClientItemId,
|
||||||
amount: u32,
|
amount: u32,
|
||||||
) -> impl Fn((ItemStateProxy, TR), ())
|
) -> impl Fn((ItemStateProxy, TR), ())
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), InventoryItemDetail), anyhow::Error>>
|
-> BoxFuture<Result<((ItemStateProxy, TR), InventoryItemDetail), anyhow::Error>>
|
||||||
where
|
where
|
||||||
EG: EntityGateway,
|
EG: EntityGateway,
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'a,
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
{
|
{
|
||||||
move |(mut item_state, mut transaction), _| {
|
move |(mut item_state, mut transaction), _| {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
@ -127,23 +124,22 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn take_item_from_inventory<'a, EG, TR>(
|
pub(super) fn take_item_from_inventory<EG, TR>(
|
||||||
character_id: CharacterEntityId,
|
character_id: CharacterEntityId,
|
||||||
item_id: ClientItemId,
|
item_id: ClientItemId,
|
||||||
amount: u32,
|
amount: u32,
|
||||||
) -> impl Fn((ItemStateProxy, TR), ())
|
) -> impl Fn((ItemStateProxy, TR), ())
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), InventoryItem), anyhow::Error>>
|
-> BoxFuture<Result<((ItemStateProxy, TR), InventoryItem), anyhow::Error>>
|
||||||
where
|
where
|
||||||
EG: EntityGateway + 'a,
|
EG: EntityGateway,
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'a,
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
{
|
{
|
||||||
move |(mut item_state, mut transaction), _| {
|
move |(mut item_state, mut transaction), _| {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let mut inventory = item_state.inventory(&character_id).await?;
|
let mut inventory = item_state.inventory(&character_id).await?;
|
||||||
let item = inventory.take_item(&item_id, amount)
|
let item = inventory.take_item(&item_id, amount)
|
||||||
.await
|
.await
|
||||||
.ok_or_else(|| ItemStateError::NoInventoryItem(item_id))
|
.ok_or_else(|| ItemStateError::NoInventoryItem(item_id))?;
|
||||||
.with_context(|| format!("{inventory:#?}"))?;
|
|
||||||
|
|
||||||
transaction.gateway().set_character_inventory(&character_id, &inventory.as_inventory_entity(&character_id)).await?;
|
transaction.gateway().set_character_inventory(&character_id, &inventory.as_inventory_entity(&character_id)).await?;
|
||||||
item_state.set_inventory(inventory).await;
|
item_state.set_inventory(inventory).await;
|
||||||
@ -154,15 +150,15 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub(super) fn add_inventory_item_to_shared_floor<'a, EG, TR>(
|
pub(super) fn add_inventory_item_to_shared_floor<EG, TR>(
|
||||||
character_id: CharacterEntityId,
|
character_id: CharacterEntityId,
|
||||||
map_area: MapArea,
|
map_area: MapArea,
|
||||||
drop_position: (f32, f32, f32),
|
drop_position: (f32, f32, f32),
|
||||||
) -> impl Fn((ItemStateProxy, TR), InventoryItem)
|
) -> impl Fn((ItemStateProxy, TR), InventoryItem)
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), FloorItem), anyhow::Error>>
|
-> BoxFuture<Result<((ItemStateProxy, TR), FloorItem), anyhow::Error>>
|
||||||
where
|
where
|
||||||
EG: EntityGateway,
|
EG: EntityGateway,
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'a,
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
{
|
{
|
||||||
move |(mut item_state, transaction), inventory_item| {
|
move |(mut item_state, transaction), inventory_item| {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
@ -188,14 +184,14 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub(super) fn take_meseta_from_inventory<'a, EG, TR>(
|
pub(super) fn take_meseta_from_inventory<EG, TR>(
|
||||||
character_id: CharacterEntityId,
|
character_id: CharacterEntityId,
|
||||||
amount: u32,
|
amount: u32,
|
||||||
) -> impl Fn((ItemStateProxy, TR), ())
|
) -> impl Fn((ItemStateProxy, TR), ())
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), ()), anyhow::Error>>
|
-> BoxFuture<Result<((ItemStateProxy, TR), ()), anyhow::Error>>
|
||||||
where
|
where
|
||||||
EG: EntityGateway,
|
EG: EntityGateway,
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'a,
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
{
|
{
|
||||||
move |(mut item_state, mut transaction), _| {
|
move |(mut item_state, mut transaction), _| {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
@ -209,14 +205,14 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn add_meseta_to_inventory<'a, EG, TR>(
|
pub(super) fn add_meseta_to_inventory<EG, TR>(
|
||||||
character_id: CharacterEntityId,
|
character_id: CharacterEntityId,
|
||||||
amount: u32
|
amount: u32
|
||||||
) -> impl Fn((ItemStateProxy, TR), ())
|
) -> impl Fn((ItemStateProxy, TR), ())
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), ()), anyhow::Error>>
|
-> BoxFuture<Result<((ItemStateProxy, TR), ()), anyhow::Error>>
|
||||||
where
|
where
|
||||||
EG: EntityGateway,
|
EG: EntityGateway,
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'a,
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
{
|
{
|
||||||
move |(mut item_state, mut transaction), _| {
|
move |(mut item_state, mut transaction), _| {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
@ -230,16 +226,16 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn add_meseta_to_shared_floor<'a, EG, TR>(
|
pub(super) fn add_meseta_to_shared_floor<EG, TR>(
|
||||||
character_id: CharacterEntityId,
|
character_id: CharacterEntityId,
|
||||||
amount: u32,
|
amount: u32,
|
||||||
map_area: MapArea,
|
map_area: MapArea,
|
||||||
drop_position: (f32, f32)
|
drop_position: (f32, f32)
|
||||||
) -> impl Fn((ItemStateProxy, TR), ())
|
) -> impl Fn((ItemStateProxy, TR), ())
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), FloorItem), anyhow::Error>>
|
-> BoxFuture<Result<((ItemStateProxy, TR), FloorItem), anyhow::Error>>
|
||||||
where
|
where
|
||||||
EG: EntityGateway,
|
EG: EntityGateway,
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'a,
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
{
|
{
|
||||||
move |(mut item_state, transaction), _| {
|
move |(mut item_state, transaction), _| {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
@ -261,20 +257,20 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn take_meseta_from_bank<'a, EG, TR>(
|
pub(super) fn take_meseta_from_bank<EG, TR>(
|
||||||
character_id: CharacterEntityId,
|
character_id: CharacterEntityId,
|
||||||
amount: u32,
|
amount: u32,
|
||||||
) -> impl Fn((ItemStateProxy, TR), ())
|
) -> impl Fn((ItemStateProxy, TR), ())
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), ()), anyhow::Error>>
|
-> BoxFuture<Result<((ItemStateProxy, TR), ()), anyhow::Error>>
|
||||||
where
|
where
|
||||||
EG: EntityGateway,
|
EG: EntityGateway,
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'a,
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
{
|
{
|
||||||
move |(mut item_state, mut transaction), _| {
|
move |(mut item_state, mut transaction), _| {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let mut bank = item_state.bank(&character_id).await?;
|
let mut bank = item_state.bank(&character_id).await?;
|
||||||
bank.remove_meseta(amount)?;
|
bank.remove_meseta(amount)?;
|
||||||
transaction.gateway().set_bank_meseta(&character_id, &bank.identifier, bank.meseta).await?;
|
transaction.gateway().set_bank_meseta(&character_id, &bank.name, bank.meseta).await?;
|
||||||
item_state.set_bank(bank).await;
|
item_state.set_bank(bank).await;
|
||||||
|
|
||||||
Ok(((item_state, transaction), ()))
|
Ok(((item_state, transaction), ()))
|
||||||
@ -282,14 +278,14 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn add_meseta_from_bank_to_inventory<'a, EG, TR>(
|
pub(super) fn add_meseta_from_bank_to_inventory<EG, TR>(
|
||||||
character_id: CharacterEntityId,
|
character_id: CharacterEntityId,
|
||||||
amount: u32,
|
amount: u32,
|
||||||
) -> impl Fn((ItemStateProxy, TR), ())
|
) -> impl Fn((ItemStateProxy, TR), ())
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), ()), anyhow::Error>>
|
-> BoxFuture<Result<((ItemStateProxy, TR), ()), anyhow::Error>>
|
||||||
where
|
where
|
||||||
EG: EntityGateway,
|
EG: EntityGateway,
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'a,
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
{
|
{
|
||||||
move |(mut item_state, mut transaction), _| {
|
move |(mut item_state, mut transaction), _| {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
@ -304,20 +300,20 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub(super) fn add_meseta_to_bank<'a, EG, TR>(
|
pub(super) fn add_meseta_to_bank<EG, TR>(
|
||||||
character_id: CharacterEntityId,
|
character_id: CharacterEntityId,
|
||||||
amount: u32,
|
amount: u32,
|
||||||
) -> impl Fn((ItemStateProxy, TR), ())
|
) -> impl Fn((ItemStateProxy, TR), ())
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), ()), anyhow::Error>>
|
-> BoxFuture<Result<((ItemStateProxy, TR), ()), anyhow::Error>>
|
||||||
where
|
where
|
||||||
EG: EntityGateway,
|
EG: EntityGateway,
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'a,
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
{
|
{
|
||||||
move |(mut item_state, mut transaction), _| {
|
move |(mut item_state, mut transaction), _| {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let mut bank = item_state.bank(&character_id).await?;
|
let mut bank = item_state.bank(&character_id).await?;
|
||||||
bank.add_meseta(amount)?;
|
bank.add_meseta(amount)?;
|
||||||
transaction.gateway().set_bank_meseta(&character_id, &bank.identifier, bank.meseta).await?;
|
transaction.gateway().set_bank_meseta(&character_id, &bank.name, bank.meseta).await?;
|
||||||
item_state.set_bank(bank).await;
|
item_state.set_bank(bank).await;
|
||||||
|
|
||||||
Ok(((item_state, transaction), ()))
|
Ok(((item_state, transaction), ()))
|
||||||
@ -326,15 +322,15 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub(super) fn take_item_from_bank<'a, EG, TR>(
|
pub(super) fn take_item_from_bank<EG, TR>(
|
||||||
character_id: CharacterEntityId,
|
character_id: CharacterEntityId,
|
||||||
item_id: ClientItemId,
|
item_id: ClientItemId,
|
||||||
amount: u32,
|
amount: u32,
|
||||||
) -> impl Fn((ItemStateProxy, TR), ())
|
) -> impl Fn((ItemStateProxy, TR), ())
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), BankItem), anyhow::Error>>
|
-> BoxFuture<Result<((ItemStateProxy, TR), BankItem), anyhow::Error>>
|
||||||
where
|
where
|
||||||
EG: EntityGateway,
|
EG: EntityGateway,
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'a,
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
{
|
{
|
||||||
move |(mut item_state, mut transaction), _| {
|
move |(mut item_state, mut transaction), _| {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
@ -342,7 +338,7 @@ where
|
|||||||
let item = bank.take_item(&item_id, amount)
|
let item = bank.take_item(&item_id, amount)
|
||||||
.await
|
.await
|
||||||
.ok_or_else(|| ItemStateError::NoBankItem(item_id))?;
|
.ok_or_else(|| ItemStateError::NoBankItem(item_id))?;
|
||||||
transaction.gateway().set_character_bank(&character_id, &bank.as_bank_entity(), &bank.identifier).await?;
|
transaction.gateway().set_character_bank(&character_id, &bank.as_bank_entity(), &bank.name).await?;
|
||||||
item_state.set_bank(bank).await;
|
item_state.set_bank(bank).await;
|
||||||
|
|
||||||
Ok(((item_state, transaction), item))
|
Ok(((item_state, transaction), item))
|
||||||
@ -350,28 +346,28 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn add_bank_item_to_inventory<'a, EG, TR>(
|
pub(super) fn add_bank_item_to_inventory<EG, TR>(
|
||||||
character: &CharacterEntity,
|
character: &CharacterEntity,
|
||||||
) -> impl Fn((ItemStateProxy, TR), BankItem)
|
) -> impl Fn((ItemStateProxy, TR), BankItem)
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), InventoryItem), anyhow::Error>>
|
-> BoxFuture<Result<((ItemStateProxy, TR), InventoryItem), anyhow::Error>>
|
||||||
where
|
where
|
||||||
EG: EntityGateway,
|
EG: EntityGateway,
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'a,
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
{
|
{
|
||||||
let character = character.clone();
|
let character = character.clone();
|
||||||
move |(mut item_state, transaction), bank_item| {
|
move |(mut item_state, transaction), bank_item| {
|
||||||
let character = character.clone();
|
let character = character.clone();
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let bank_identifier = item_state.bank(&character.id).await?.identifier;
|
let bank_name = item_state.bank(&character.id).await?.name;
|
||||||
let mut inventory = item_state.inventory(&character.id).await?;
|
let mut inventory = item_state.inventory(&character.id).await?;
|
||||||
|
|
||||||
let character_id = character.id;
|
let character_id = character.id;
|
||||||
let transaction = bank_item.with_entity_id(transaction, |mut transaction, entity_id| {
|
let transaction = bank_item.with_entity_id(transaction, |mut transaction, entity_id| {
|
||||||
let bank_identifier = bank_identifier.clone();
|
let bank_name = bank_name.clone();
|
||||||
async move {
|
async move {
|
||||||
transaction.gateway().add_item_note(&entity_id, ItemNote::Withdraw {
|
transaction.gateway().add_item_note(&entity_id, ItemNote::Withdraw {
|
||||||
character_id,
|
character_id,
|
||||||
bank: bank_identifier,
|
bank: bank_name,
|
||||||
}).await?;
|
}).await?;
|
||||||
Ok(transaction)
|
Ok(transaction)
|
||||||
}}).await?;
|
}}).await?;
|
||||||
@ -401,48 +397,49 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub(super) fn add_inventory_item_to_bank<'a, EG, TR>(
|
pub(super) fn add_inventory_item_to_bank<EG, TR>(
|
||||||
character_id: CharacterEntityId,
|
character_id: CharacterEntityId,
|
||||||
) -> impl Fn((ItemStateProxy, TR), InventoryItem)
|
) -> impl Fn((ItemStateProxy, TR), InventoryItem)
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), ()), anyhow::Error>>
|
-> BoxFuture<Result<((ItemStateProxy, TR), ()), anyhow::Error>>
|
||||||
where
|
where
|
||||||
EG: EntityGateway,
|
EG: EntityGateway,
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'a,
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
{
|
{
|
||||||
move |(mut item_state, transaction), inventory_item| {
|
move |(mut item_state, transaction), inventory_item| {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let mut bank = item_state.bank(&character_id).await?;
|
let mut bank = item_state.bank(&character_id).await?;
|
||||||
let bank_identifier = bank.identifier.clone();
|
let bank_name = bank.name.clone();
|
||||||
let mut transaction = inventory_item.with_entity_id(transaction, move |mut transaction, entity_id| {
|
let mut transaction = inventory_item.with_entity_id(transaction, move |mut transaction, entity_id| {
|
||||||
let bank_identifier = bank_identifier.clone();
|
let bank_name = bank_name.clone();
|
||||||
async move {
|
async move {
|
||||||
transaction.gateway().add_item_note(&entity_id, ItemNote::Deposit {
|
transaction.gateway().add_item_note(&entity_id, ItemNote::Deposit {
|
||||||
character_id,
|
character_id,
|
||||||
bank: bank_identifier,
|
bank: bank_name,
|
||||||
}).await?;
|
}).await?;
|
||||||
Ok(transaction)
|
Ok(transaction)
|
||||||
}}).await?;
|
}}).await?;
|
||||||
|
|
||||||
bank.add_inventory_item(inventory_item)?;
|
bank.add_inventory_item(inventory_item)?;
|
||||||
|
|
||||||
transaction.gateway().set_character_bank(&character_id, &bank.as_bank_entity(), &bank.identifier).await?;
|
transaction.gateway().set_character_bank(&character_id, &bank.as_bank_entity(), &bank.name).await?;
|
||||||
item_state.set_bank(bank).await;
|
item_state.set_bank(bank).await;
|
||||||
|
|
||||||
|
|
||||||
Ok(((item_state, transaction), ()))
|
Ok(((item_state, transaction), ()))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub(super) fn equip_inventory_item<'a, EG, TR>(
|
pub(super) fn equip_inventory_item<EG, TR>(
|
||||||
character_id: CharacterEntityId,
|
character_id: CharacterEntityId,
|
||||||
item_id: ClientItemId,
|
item_id: ClientItemId,
|
||||||
equip_slot: u8,
|
equip_slot: u8,
|
||||||
) -> impl Fn((ItemStateProxy, TR), ())
|
) -> impl Fn((ItemStateProxy, TR), ())
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), ()), anyhow::Error>>
|
-> BoxFuture<Result<((ItemStateProxy, TR), ()), anyhow::Error>>
|
||||||
where
|
where
|
||||||
EG: EntityGateway,
|
EG: EntityGateway,
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'a,
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
{
|
{
|
||||||
move |(mut item_state, mut transaction), _| {
|
move |(mut item_state, mut transaction), _| {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
@ -457,14 +454,14 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub(super) fn unequip_inventory_item<'a, EG, TR>(
|
pub(super) fn unequip_inventory_item<EG, TR>(
|
||||||
character_id: CharacterEntityId,
|
character_id: CharacterEntityId,
|
||||||
item_id: ClientItemId,
|
item_id: ClientItemId,
|
||||||
) -> impl Fn((ItemStateProxy, TR), ())
|
) -> impl Fn((ItemStateProxy, TR), ())
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), ()), anyhow::Error>>
|
-> BoxFuture<Result<((ItemStateProxy, TR), ()), anyhow::Error>>
|
||||||
where
|
where
|
||||||
EG: EntityGateway,
|
EG: EntityGateway,
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'a,
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
{
|
{
|
||||||
move |(mut item_state, mut transaction), _| {
|
move |(mut item_state, mut transaction), _| {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
@ -480,14 +477,14 @@ where
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
pub(super) fn sort_inventory_items<'a, EG, TR>(
|
pub(super) fn sort_inventory_items<EG, TR>(
|
||||||
character_id: CharacterEntityId,
|
character_id: CharacterEntityId,
|
||||||
item_ids: Vec<ClientItemId>,
|
item_ids: Vec<ClientItemId>,
|
||||||
) -> impl Fn((ItemStateProxy, TR), ())
|
) -> impl Fn((ItemStateProxy, TR), ())
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), ()), anyhow::Error>>
|
-> BoxFuture<Result<((ItemStateProxy, TR), ()), anyhow::Error>>
|
||||||
where
|
where
|
||||||
EG: EntityGateway,
|
EG: EntityGateway,
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'a,
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
{
|
{
|
||||||
move |(mut item_state, mut transaction), _| {
|
move |(mut item_state, mut transaction), _| {
|
||||||
let item_ids = item_ids.clone();
|
let item_ids = item_ids.clone();
|
||||||
@ -503,13 +500,13 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub(super) fn use_consumed_item<'a, EG, TR>(
|
pub(super) fn use_consumed_item<EG, TR>(
|
||||||
character: &CharacterEntity,
|
character: &CharacterEntity,
|
||||||
) -> impl Fn((ItemStateProxy, TR), InventoryItemDetail)
|
) -> impl Fn((ItemStateProxy, TR), InventoryItemDetail)
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), Vec<ApplyItemAction>), anyhow::Error>>
|
-> BoxFuture<Result<((ItemStateProxy, TR), Vec<ApplyItemAction>), anyhow::Error>>
|
||||||
where
|
where
|
||||||
EG: EntityGateway + Clone + 'a,
|
EG: EntityGateway + Clone + 'static,
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'a,
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
{
|
{
|
||||||
let character = character.clone();
|
let character = character.clone();
|
||||||
move |(mut item_state, transaction), inventory_item| {
|
move |(mut item_state, transaction), inventory_item| {
|
||||||
@ -517,9 +514,7 @@ where
|
|||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let mut transaction = inventory_item.with_entity_id(transaction, |mut transaction, entity_id| {
|
let mut transaction = inventory_item.with_entity_id(transaction, |mut transaction, entity_id| {
|
||||||
async move {
|
async move {
|
||||||
transaction.gateway().add_item_note(&entity_id, ItemNote::Consumed {
|
transaction.gateway().add_item_note(&entity_id, ItemNote::Consumed).await?;
|
||||||
character_id: character.id,
|
|
||||||
}).await?;
|
|
||||||
Ok(transaction)
|
Ok(transaction)
|
||||||
}}).await?;
|
}}).await?;
|
||||||
|
|
||||||
@ -531,14 +526,14 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub(super) fn feed_mag_item<'a, EG, TR>(
|
pub(super) fn feed_mag_item<EG, TR>(
|
||||||
character: CharacterEntity,
|
character: CharacterEntity,
|
||||||
mag_item_id: ClientItemId,
|
mag_item_id: ClientItemId,
|
||||||
) -> impl Fn((ItemStateProxy, TR), InventoryItem)
|
) -> impl Fn((ItemStateProxy, TR), InventoryItem)
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), CharacterEntity), anyhow::Error>>
|
-> BoxFuture<Result<((ItemStateProxy, TR), CharacterEntity), anyhow::Error>>
|
||||||
where
|
where
|
||||||
EG: EntityGateway,
|
EG: EntityGateway,
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'a,
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
{
|
{
|
||||||
move |(mut item_state, transaction), tool| {
|
move |(mut item_state, transaction), tool| {
|
||||||
let character = character.clone();
|
let character = character.clone();
|
||||||
@ -554,7 +549,7 @@ where
|
|||||||
let mut transaction = tool.with_entity_id(transaction, |mut transaction, entity_id| {
|
let mut transaction = tool.with_entity_id(transaction, |mut transaction, entity_id| {
|
||||||
async move {
|
async move {
|
||||||
transaction.gateway().add_item_note(&entity_id, ItemNote::FedToMag {
|
transaction.gateway().add_item_note(&entity_id, ItemNote::FedToMag {
|
||||||
character_id: character.id,
|
//character_id: character.id,
|
||||||
mag: mag_entity_id,
|
mag: mag_entity_id,
|
||||||
}).await?;
|
}).await?;
|
||||||
transaction.gateway().feed_mag(&mag_entity_id, &entity_id).await?;
|
transaction.gateway().feed_mag(&mag_entity_id, &entity_id).await?;
|
||||||
@ -592,7 +587,7 @@ pub(super) fn add_bought_item_to_inventory<'a, EG, TR>(
|
|||||||
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy, TR), InventoryItem), anyhow::Error>> + Send + 'a>>
|
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy, TR), InventoryItem), anyhow::Error>> + Send + 'a>>
|
||||||
where
|
where
|
||||||
EG: EntityGateway,
|
EG: EntityGateway,
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'a,
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
{
|
{
|
||||||
move |(mut item_state, mut transaction), _| {
|
move |(mut item_state, mut transaction), _| {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
@ -619,8 +614,7 @@ where
|
|||||||
tool,
|
tool,
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
inventory.add_item(inventory_item.clone())
|
inventory.add_item(inventory_item)?.1
|
||||||
.with_context(|| format!("inventory {inventory:?}\nitem {inventory_item:?}"))?.1
|
|
||||||
},
|
},
|
||||||
item_detail => {
|
item_detail => {
|
||||||
let item_entity = transaction.gateway().create_item(NewItemEntity {
|
let item_entity = transaction.gateway().create_item(NewItemEntity {
|
||||||
@ -637,8 +631,7 @@ where
|
|||||||
item: item_detail,
|
item: item_detail,
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
inventory.add_item(inventory_item.clone())
|
inventory.add_item(inventory_item)?.1
|
||||||
.with_context(|| format!("inventory {inventory:?}\nitem {inventory_item:?}"))?.1
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -650,13 +643,13 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub(super) fn sell_inventory_item<'a, EG, TR>(
|
pub(super) fn sell_inventory_item<EG, TR>(
|
||||||
character_id: CharacterEntityId,
|
character_id: CharacterEntityId,
|
||||||
) -> impl Fn((ItemStateProxy, TR), InventoryItem)
|
) -> impl Fn((ItemStateProxy, TR), InventoryItem)
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), InventoryItem), anyhow::Error>>
|
-> BoxFuture<Result<((ItemStateProxy, TR), InventoryItem), anyhow::Error>>
|
||||||
where
|
where
|
||||||
EG: EntityGateway,
|
EG: EntityGateway,
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'a,
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
{
|
{
|
||||||
move |(mut item_state, transaction), inventory_item| {
|
move |(mut item_state, transaction), inventory_item| {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
@ -666,9 +659,7 @@ where
|
|||||||
|
|
||||||
let mut transaction = inventory_item.with_entity_id(transaction, |mut transaction, entity_id| {
|
let mut transaction = inventory_item.with_entity_id(transaction, |mut transaction, entity_id| {
|
||||||
async move {
|
async move {
|
||||||
transaction.gateway().add_item_note(&entity_id, ItemNote::SoldToShop {
|
transaction.gateway().add_item_note(&entity_id, ItemNote::SoldToShop).await?;
|
||||||
character_id,
|
|
||||||
}).await?;
|
|
||||||
Ok(transaction)
|
Ok(transaction)
|
||||||
}}).await?;
|
}}).await?;
|
||||||
transaction.gateway().set_character_meseta(&character_id, inventory.meseta).await?;
|
transaction.gateway().set_character_meseta(&character_id, inventory.meseta).await?;
|
||||||
@ -693,9 +684,9 @@ where
|
|||||||
I: Send,
|
I: Send,
|
||||||
O: Send,
|
O: Send,
|
||||||
T: Clone + Send + Sync,
|
T: Clone + Send + Sync,
|
||||||
F: Fn(I) -> FR + Send + Sync + Clone + 'a,
|
F: Fn(I) -> FR + Send + Sync + Clone + 'static,
|
||||||
FR: Fn((ItemStateProxy, TR), T)
|
FR: Fn((ItemStateProxy, TR), T)
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), O), anyhow::Error>> + Send + Sync,
|
-> BoxFuture<Result<((ItemStateProxy, TR), O), anyhow::Error>> + Send + Sync,
|
||||||
{
|
{
|
||||||
let item = match input.pop() {
|
let item = match input.pop() {
|
||||||
Some(item) => item,
|
Some(item) => item,
|
||||||
@ -711,20 +702,20 @@ where
|
|||||||
Ok((state, output))
|
Ok((state, output))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn iterate<'a, EG, TR, I, O, T, F, FR>(
|
pub(super) fn iterate<EG, TR, I, O, T, F, FR>(
|
||||||
input: Vec<I>,
|
input: Vec<I>,
|
||||||
func: F,
|
func: F,
|
||||||
) -> impl Fn((ItemStateProxy, TR), T)
|
) -> impl Fn((ItemStateProxy, TR), T)
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), Vec<O>), anyhow::Error>>
|
-> BoxFuture<Result<((ItemStateProxy, TR), Vec<O>), anyhow::Error>>
|
||||||
where
|
where
|
||||||
EG: EntityGateway,
|
EG: EntityGateway,
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'a,
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
O: Send,
|
O: Send,
|
||||||
I: Send + Clone + 'static + std::fmt::Debug,
|
I: Send + Clone + 'static + std::fmt::Debug,
|
||||||
T: Send + Clone + 'static + std::fmt::Debug,
|
T: Send + Clone + 'static + std::fmt::Debug,
|
||||||
F: Fn(I) -> FR + Send + Sync + Clone + 'a,
|
F: Fn(I) -> FR + Send + Sync + Clone + 'static,
|
||||||
FR: Fn((ItemStateProxy, TR), T)
|
FR: Fn((ItemStateProxy, TR), T)
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), O), anyhow::Error>> + Send + Sync,
|
-> BoxFuture<Result<((ItemStateProxy, TR), O), anyhow::Error>> + Send + Sync,
|
||||||
T: Clone + Send + Sync,
|
T: Clone + Send + Sync,
|
||||||
{
|
{
|
||||||
move |(item_state, transaction), arg| {
|
move |(item_state, transaction), arg| {
|
||||||
@ -747,12 +738,12 @@ async fn foreach_inner<'a, EG, TR, O, T, F, I>(
|
|||||||
where
|
where
|
||||||
'a: 'async_recursion,
|
'a: 'async_recursion,
|
||||||
EG: EntityGateway,
|
EG: EntityGateway,
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'a,
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
O: Send,
|
O: Send,
|
||||||
T: Send,
|
T: Send,
|
||||||
F: Fn((ItemStateProxy, TR), T)
|
F: Fn((ItemStateProxy, TR), T)
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), O), anyhow::Error>> + Send + Sync,
|
-> BoxFuture<Result<((ItemStateProxy, TR), O), anyhow::Error>> + Send + Sync,
|
||||||
I: Iterator<Item = T> + Send + Sync + 'a,
|
I: Iterator<Item = T> + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
let item = match input.next() {
|
let item = match input.next() {
|
||||||
Some(item) => item,
|
Some(item) => item,
|
||||||
@ -767,19 +758,19 @@ where
|
|||||||
Ok((state, output))
|
Ok((state, output))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn foreach<'a, EG, TR, O, T, F, I>(
|
pub(super) fn foreach<EG, TR, O, T, F, I>(
|
||||||
func: F
|
func: F
|
||||||
) -> impl Fn((ItemStateProxy, TR), I)
|
) -> impl Fn((ItemStateProxy, TR), I)
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), Vec<O>), anyhow::Error>>
|
-> BoxFuture<Result<((ItemStateProxy, TR), Vec<O>), anyhow::Error>>
|
||||||
where
|
where
|
||||||
EG: EntityGateway,
|
EG: EntityGateway,
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'a,
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
O: Send,
|
O: Send,
|
||||||
T: Send + Clone + 'static + std::fmt::Debug,
|
T: Send + Clone + 'static + std::fmt::Debug,
|
||||||
F: Fn((ItemStateProxy, TR), T)
|
F: Fn((ItemStateProxy, TR), T)
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), O), anyhow::Error>> + Send + Sync + 'a,
|
-> BoxFuture<Result<((ItemStateProxy, TR), O), anyhow::Error>> + Send + Sync + 'static,
|
||||||
T: Send + Sync,
|
T: Send + Sync,
|
||||||
I: IntoIterator<Item = T> + Send + Sync + 'a,
|
I: IntoIterator<Item = T> + Send + Sync + 'static,
|
||||||
I::IntoIter: Send + Sync,
|
I::IntoIter: Send + Sync,
|
||||||
{
|
{
|
||||||
let func = Arc::new(func);
|
let func = Arc::new(func);
|
||||||
@ -799,7 +790,7 @@ pub(super) fn insert<'a, EG, TR, T>(
|
|||||||
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy, TR), T), anyhow::Error>> + Send + 'a>>
|
-> Pin<Box<dyn Future<Output=Result<((ItemStateProxy, TR), T), anyhow::Error>> + Send + 'a>>
|
||||||
where
|
where
|
||||||
EG: EntityGateway,
|
EG: EntityGateway,
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'a,
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
T: Send + Clone + 'a,
|
T: Send + Clone + 'a,
|
||||||
{
|
{
|
||||||
move |state, _| {
|
move |state, _| {
|
||||||
@ -810,17 +801,17 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn fork<'a, EG, TR, F1, F2, T, O1, O2>(
|
pub(super) fn fork<EG, TR, F1, F2, T, O1, O2>(
|
||||||
func1: F1,
|
func1: F1,
|
||||||
func2: F2,
|
func2: F2,
|
||||||
) -> impl Fn((ItemStateProxy, TR), T)
|
) -> impl Fn((ItemStateProxy, TR), T)
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), (O1, O2)), anyhow::Error>>
|
-> BoxFuture<Result<((ItemStateProxy, TR), (O1, O2)), anyhow::Error>>
|
||||||
where
|
where
|
||||||
EG: EntityGateway,
|
EG: EntityGateway,
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'a,
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
F1: Fn((ItemStateProxy, TR), T) -> BoxFuture<'a, Result<((ItemStateProxy, TR), O1), anyhow::Error>> + Send + Sync + 'a,
|
F1: Fn((ItemStateProxy, TR), T) -> BoxFuture<Result<((ItemStateProxy, TR), O1), anyhow::Error>> + Send + Sync + 'static,
|
||||||
F2: Fn((ItemStateProxy, TR), T) -> BoxFuture<'a, Result<((ItemStateProxy, TR), O2), anyhow::Error>> + Send + Sync + 'a,
|
F2: Fn((ItemStateProxy, TR), T) -> BoxFuture<Result<((ItemStateProxy, TR), O2), anyhow::Error>> + Send + Sync + 'static,
|
||||||
T: Send + Sync + Clone + 'a,
|
T: Send + Sync + Clone + 'static,
|
||||||
O1: Send,
|
O1: Send,
|
||||||
O2: Send,
|
O2: Send,
|
||||||
{
|
{
|
||||||
@ -838,13 +829,13 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn add_item_to_inventory<'a, EG, TR>(
|
pub(super) fn add_item_to_inventory<EG, TR>(
|
||||||
character: CharacterEntity,
|
character: CharacterEntity,
|
||||||
) -> impl Fn((ItemStateProxy, TR), InventoryItem)
|
) -> impl Fn((ItemStateProxy, TR), InventoryItem)
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), InventoryItem), anyhow::Error>> + Clone
|
-> BoxFuture<Result<((ItemStateProxy, TR), InventoryItem), anyhow::Error>> + Clone
|
||||||
where
|
where
|
||||||
EG: EntityGateway,
|
EG: EntityGateway,
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'a,
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
{
|
{
|
||||||
move |(mut item_state, transaction), inventory_item| {
|
move |(mut item_state, transaction), inventory_item| {
|
||||||
let character = character.clone();
|
let character = character.clone();
|
||||||
@ -866,15 +857,15 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn record_trade<'a, EG, TR>(
|
pub(super) fn record_trade<EG, TR>(
|
||||||
trade_id: TradeId,
|
trade_id: TradeId,
|
||||||
character_to: CharacterEntityId,
|
character_to: CharacterEntityId,
|
||||||
character_from: CharacterEntityId,
|
character_from: CharacterEntityId,
|
||||||
) -> impl Fn((ItemStateProxy, TR), Vec<InventoryItem>)
|
) -> impl Fn((ItemStateProxy, TR), Vec<InventoryItem>)
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), Vec<InventoryItem>), anyhow::Error>> + Clone
|
-> BoxFuture<Result<((ItemStateProxy, TR), Vec<InventoryItem>), anyhow::Error>> + Clone
|
||||||
where
|
where
|
||||||
EG: EntityGateway,
|
EG: EntityGateway,
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'a,
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
{
|
{
|
||||||
move |(item_state, mut transaction), traded_items| {
|
move |(item_state, mut transaction), traded_items| {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
@ -895,12 +886,12 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub(super) fn assign_new_item_id<'a, EG, TR>(
|
pub(super) fn assign_new_item_id<EG, TR>(
|
||||||
) -> impl Fn((ItemStateProxy, TR), InventoryItem)
|
) -> impl Fn((ItemStateProxy, TR), InventoryItem)
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), InventoryItem), anyhow::Error>> + Clone
|
-> BoxFuture<Result<((ItemStateProxy, TR), InventoryItem), anyhow::Error>> + Clone
|
||||||
where
|
where
|
||||||
EG: EntityGateway,
|
EG: EntityGateway,
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'a,
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
{
|
{
|
||||||
move |(mut item_state, transaction), mut inventory_item| {
|
move |(mut item_state, transaction), mut inventory_item| {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
@ -911,13 +902,14 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub(super) fn convert_item_drop_to_floor_item<'a, EG, TR>(
|
pub(super) fn convert_item_drop_to_floor_item<EG, TR>(
|
||||||
|
character_id: CharacterEntityId,
|
||||||
item_drop: ItemDrop,
|
item_drop: ItemDrop,
|
||||||
) -> impl Fn((ItemStateProxy, TR), ())
|
) -> impl Fn((ItemStateProxy, TR), ())
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), FloorItem), anyhow::Error>> + Clone
|
-> BoxFuture<Result<((ItemStateProxy, TR), FloorItem), anyhow::Error>> + Clone
|
||||||
where
|
where
|
||||||
EG: EntityGateway,
|
EG: EntityGateway,
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'a,
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
{
|
{
|
||||||
move |(mut item_state, mut transaction), _| {
|
move |(mut item_state, mut transaction), _| {
|
||||||
let item_drop = item_drop.clone();
|
let item_drop = item_drop.clone();
|
||||||
@ -953,6 +945,13 @@ where
|
|||||||
let entity = transaction.gateway().create_item(NewItemEntity {
|
let entity = transaction.gateway().create_item(NewItemEntity {
|
||||||
item: item_detail.clone(),
|
item: item_detail.clone(),
|
||||||
}).await?;
|
}).await?;
|
||||||
|
transaction.gateway().add_item_note(&entity.id, ItemNote::EnemyDrop {
|
||||||
|
character_id,
|
||||||
|
map_area: item_drop.map_area,
|
||||||
|
x: item_drop.x,
|
||||||
|
y: item_drop.y,
|
||||||
|
z: item_drop.z,
|
||||||
|
}).await?;
|
||||||
FloorItem {
|
FloorItem {
|
||||||
item_id,
|
item_id,
|
||||||
item: FloorItemDetail::Individual(IndividualItemDetail {
|
item: FloorItemDetail::Individual(IndividualItemDetail {
|
||||||
@ -969,6 +968,13 @@ where
|
|||||||
let entity = transaction.gateway().create_item(NewItemEntity {
|
let entity = transaction.gateway().create_item(NewItemEntity {
|
||||||
item: ItemDetail::Tool(tool),
|
item: ItemDetail::Tool(tool),
|
||||||
}).await?;
|
}).await?;
|
||||||
|
transaction.gateway().add_item_note(&entity.id, ItemNote::EnemyDrop {
|
||||||
|
character_id,
|
||||||
|
map_area: item_drop.map_area,
|
||||||
|
x: item_drop.x,
|
||||||
|
y: item_drop.y,
|
||||||
|
z: item_drop.z,
|
||||||
|
}).await?;
|
||||||
FloorItem {
|
FloorItem {
|
||||||
item_id,
|
item_id,
|
||||||
item: FloorItemDetail::Stacked(StackedItemDetail{
|
item: FloorItemDetail::Stacked(StackedItemDetail{
|
||||||
@ -998,95 +1004,13 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn add_item_to_local_floor<EG, TR>(
|
||||||
pub(super) fn item_note_enemy_drop<'a, EG, TR>(
|
|
||||||
character_id: CharacterEntityId,
|
|
||||||
room_id: RoomEntityId,
|
|
||||||
monster_type: MonsterType,
|
|
||||||
) -> impl Fn((ItemStateProxy, TR), FloorItem)
|
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), FloorItem), anyhow::Error>> + Clone
|
|
||||||
where
|
|
||||||
EG: EntityGateway,
|
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'a,
|
|
||||||
{
|
|
||||||
move |(item_state, mut transaction), floor_item| {
|
|
||||||
Box::pin(async move {
|
|
||||||
match &floor_item.item {
|
|
||||||
FloorItemDetail::Individual(individual) => {
|
|
||||||
transaction.gateway().add_item_note(&individual.entity_id, ItemNote::EnemyDrop {
|
|
||||||
character_id,
|
|
||||||
room_id,
|
|
||||||
monster_type,
|
|
||||||
map_area: floor_item.map_area,
|
|
||||||
x: floor_item.x,
|
|
||||||
y: floor_item.y,
|
|
||||||
z: floor_item.z,
|
|
||||||
}).await?;
|
|
||||||
},
|
|
||||||
FloorItemDetail::Stacked(stacked) => {
|
|
||||||
transaction.gateway().add_item_note(&stacked.entity_ids[0], ItemNote::EnemyDrop {
|
|
||||||
character_id,
|
|
||||||
room_id,
|
|
||||||
monster_type,
|
|
||||||
map_area: floor_item.map_area,
|
|
||||||
x: floor_item.x,
|
|
||||||
y: floor_item.y,
|
|
||||||
z: floor_item.z,
|
|
||||||
}).await?;
|
|
||||||
},
|
|
||||||
_ => {},
|
|
||||||
}
|
|
||||||
Ok(((item_state, transaction), floor_item))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn item_note_box_drop<'a, EG, TR>(
|
|
||||||
character_id: CharacterEntityId,
|
|
||||||
room_id: RoomEntityId,
|
|
||||||
) -> impl Fn((ItemStateProxy, TR), FloorItem)
|
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), FloorItem), anyhow::Error>> + Clone
|
|
||||||
where
|
|
||||||
EG: EntityGateway,
|
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'a,
|
|
||||||
{
|
|
||||||
move |(item_state, mut transaction), floor_item| {
|
|
||||||
Box::pin(async move {
|
|
||||||
match &floor_item.item {
|
|
||||||
FloorItemDetail::Individual(individual) => {
|
|
||||||
transaction.gateway().add_item_note(&individual.entity_id, ItemNote::BoxDrop {
|
|
||||||
character_id,
|
|
||||||
room_id,
|
|
||||||
map_area: floor_item.map_area,
|
|
||||||
x: floor_item.x,
|
|
||||||
y: floor_item.y,
|
|
||||||
z: floor_item.z,
|
|
||||||
}).await?;
|
|
||||||
},
|
|
||||||
FloorItemDetail::Stacked(stacked) => {
|
|
||||||
transaction.gateway().add_item_note(&stacked.entity_ids[0], ItemNote::BoxDrop {
|
|
||||||
character_id,
|
|
||||||
room_id,
|
|
||||||
map_area: floor_item.map_area,
|
|
||||||
x: floor_item.x,
|
|
||||||
y: floor_item.y,
|
|
||||||
z: floor_item.z,
|
|
||||||
}).await?;
|
|
||||||
},
|
|
||||||
_ => {},
|
|
||||||
}
|
|
||||||
Ok(((item_state, transaction), floor_item))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn add_item_to_local_floor<'a, EG, TR>(
|
|
||||||
character_id: CharacterEntityId,
|
character_id: CharacterEntityId,
|
||||||
) -> impl Fn((ItemStateProxy, TR), FloorItem)
|
) -> impl Fn((ItemStateProxy, TR), FloorItem)
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), FloorItem), anyhow::Error>>
|
-> BoxFuture<Result<((ItemStateProxy, TR), FloorItem), anyhow::Error>>
|
||||||
where
|
where
|
||||||
EG: EntityGateway,
|
EG: EntityGateway,
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'a,
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
{
|
{
|
||||||
move |(mut item_state, transaction) , floor_item| {
|
move |(mut item_state, transaction) , floor_item| {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
@ -1099,13 +1023,13 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn apply_modifier_to_inventory_item<'a, EG, TR>(
|
pub(super) fn apply_modifier_to_inventory_item<EG, TR>(
|
||||||
modifier: ItemModifier,
|
modifier: ItemModifier,
|
||||||
) -> impl Fn((ItemStateProxy, TR), InventoryItem)
|
) -> impl Fn((ItemStateProxy, TR), InventoryItem)
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), InventoryItem), anyhow::Error>>
|
-> BoxFuture<Result<((ItemStateProxy, TR), InventoryItem), anyhow::Error>>
|
||||||
where
|
where
|
||||||
EG: EntityGateway,
|
EG: EntityGateway,
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'a,
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
{
|
{
|
||||||
move |(item_state, mut transaction), mut inventory_item| {
|
move |(item_state, mut transaction), mut inventory_item| {
|
||||||
let modifier = modifier.clone();
|
let modifier = modifier.clone();
|
||||||
@ -1123,12 +1047,12 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn as_individual_item<'a, EG, TR>(
|
pub(super) fn as_individual_item<EG, TR>(
|
||||||
) -> impl Fn((ItemStateProxy, TR), InventoryItem)
|
) -> impl Fn((ItemStateProxy, TR), InventoryItem)
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), IndividualItemDetail), anyhow::Error>>
|
-> BoxFuture<Result<((ItemStateProxy, TR), IndividualItemDetail), anyhow::Error>>
|
||||||
where
|
where
|
||||||
EG: EntityGateway,
|
EG: EntityGateway,
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'a,
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
{
|
{
|
||||||
move |(item_state, transaction), inventory_item| {
|
move |(item_state, transaction), inventory_item| {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
@ -1143,14 +1067,14 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub(super) fn apply_item_action_packets<'a, EG, TR>(
|
pub(super) fn apply_item_action_packets<EG, TR>(
|
||||||
character_id: CharacterEntityId,
|
character_id: CharacterEntityId,
|
||||||
area_client: AreaClient,
|
area_client: AreaClient,
|
||||||
) -> impl Fn((ItemStateProxy, TR), ApplyItemAction)
|
) -> impl Fn((ItemStateProxy, TR), ApplyItemAction)
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), Vec<CreateItem>), anyhow::Error>>
|
-> BoxFuture<Result<((ItemStateProxy, TR), Vec<SendShipPacket>), anyhow::Error>>
|
||||||
where
|
where
|
||||||
EG: EntityGateway,
|
EG: EntityGateway,
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'a,
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
{
|
{
|
||||||
move |(mut item_state, mut transaction), apply_item_action| {
|
move |(mut item_state, mut transaction), apply_item_action| {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
@ -1164,7 +1088,7 @@ where
|
|||||||
let (inventory_item_detail, create_item) = if item_detail.is_stackable() {
|
let (inventory_item_detail, create_item) = if item_detail.is_stackable() {
|
||||||
let tool = item_detail.as_tool().ok_or_else(|| ItemStateError::NotATool(ClientItemId(0xFFFFFFFF)))?;
|
let tool = item_detail.as_tool().ok_or_else(|| ItemStateError::NotATool(ClientItemId(0xFFFFFFFF)))?;
|
||||||
|
|
||||||
let create_item = CreateItem::Stacked(area_client, item_id, tool, 1);
|
let create_item = builder::message::create_stacked_item(area_client, item_id, &tool, 1).map_err(|_err| ItemStateError::Dummy)?;
|
||||||
let item_detail = StackedItemDetail {
|
let item_detail = StackedItemDetail {
|
||||||
entity_ids: vec![new_item.id],
|
entity_ids: vec![new_item.id],
|
||||||
tool
|
tool
|
||||||
@ -1176,7 +1100,7 @@ where
|
|||||||
entity_id: new_item.id,
|
entity_id: new_item.id,
|
||||||
item: item_detail,
|
item: item_detail,
|
||||||
};
|
};
|
||||||
let create_item = CreateItem::Individual(area_client, item_id, item_detail.clone());
|
let create_item = builder::message::create_individual_item(area_client, item_id, &item_detail).map_err(|_err| ItemStateError::Dummy)?;
|
||||||
(InventoryItemDetail::Individual(item_detail), create_item)
|
(InventoryItemDetail::Individual(item_detail), create_item)
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1190,8 +1114,7 @@ where
|
|||||||
transaction.gateway().set_character_inventory(&character_id, &inventory.as_inventory_entity(&character_id)).await?;
|
transaction.gateway().set_character_inventory(&character_id, &inventory.as_inventory_entity(&character_id)).await?;
|
||||||
item_state.set_inventory(inventory).await;
|
item_state.set_inventory(inventory).await;
|
||||||
|
|
||||||
//vec![SendShipPacket::Message(Message::new(GameMessage::CreateItem(create_item)))]
|
vec![SendShipPacket::Message(Message::new(GameMessage::CreateItem(create_item)))]
|
||||||
vec![create_item]
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
@ -1202,13 +1125,13 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn apply_item_action_character<'a, EG, TR>(
|
pub(super) fn apply_item_action_character<EG, TR>(
|
||||||
character: &CharacterEntity
|
character: &CharacterEntity
|
||||||
) -> impl Fn((ItemStateProxy, TR), Vec<ApplyItemAction>)
|
) -> impl Fn((ItemStateProxy, TR), Vec<ApplyItemAction>)
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), CharacterEntity), anyhow::Error>>
|
-> BoxFuture<Result<((ItemStateProxy, TR), CharacterEntity), anyhow::Error>>
|
||||||
where
|
where
|
||||||
EG: EntityGateway,
|
EG: EntityGateway,
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + 'a,
|
TR: EntityGatewayTransaction<ParentGateway = EG> + 'static,
|
||||||
{
|
{
|
||||||
let character = character.clone();
|
let character = character.clone();
|
||||||
move |(item_state, transaction), apply_item_actions| {
|
move |(item_state, transaction), apply_item_actions| {
|
||||||
@ -1224,25 +1147,3 @@ where
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn delete_item_from_floor<'a, EG, TR>(
|
|
||||||
map_area: MapArea
|
|
||||||
) -> impl Fn((ItemStateProxy, TR), FloorItem)
|
|
||||||
-> BoxFuture<'a, Result<((ItemStateProxy, TR), ()), anyhow::Error>>
|
|
||||||
where
|
|
||||||
EG: EntityGateway,
|
|
||||||
TR: EntityGatewayTransaction<ParentGateway = EG> + Clone + 'a,
|
|
||||||
{
|
|
||||||
move |(item_state, transaction), floor_item| {
|
|
||||||
Box::pin(async move {
|
|
||||||
let transaction = floor_item.with_entity_id(transaction, |mut transaction, entity_id| {
|
|
||||||
async move {
|
|
||||||
transaction.gateway().add_item_note(&entity_id, ItemNote::FloorLimitReached {
|
|
||||||
map_area
|
|
||||||
}).await?;
|
|
||||||
Ok(transaction)
|
|
||||||
}}).await?;
|
|
||||||
Ok(((item_state, transaction), ()))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,15 +4,15 @@ use thiserror::Error;
|
|||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use rand::SeedableRng;
|
use rand::SeedableRng;
|
||||||
use rand::distributions::{WeightedIndex, Distribution};
|
use rand::distributions::{WeightedIndex, Distribution};
|
||||||
use entity::gateway::{EntityGateway, GatewayError};
|
use crate::entity::gateway::{EntityGateway, GatewayError};
|
||||||
use entity::character::{CharacterEntity, TechLevel};
|
use crate::entity::character::{CharacterEntity, TechLevel};
|
||||||
use entity::item::mag::{MagCell, MagCellError};
|
use crate::entity::item::mag::{MagCell, MagCellError};
|
||||||
use entity::item::tool::{Tool, ToolType};
|
use crate::entity::item::tool::{Tool, ToolType};
|
||||||
use entity::item::tech::TechniqueDisk;
|
use crate::entity::item::tech::TechniqueDisk;
|
||||||
use entity::item::{ItemDetail, ItemEntityId};
|
use crate::entity::item::{ItemDetail, ItemEntityId};
|
||||||
use entity::item::weapon::WeaponModifier;
|
use crate::entity::item::weapon::WeaponModifier;
|
||||||
use crate::state::ItemStateProxy;
|
use crate::ship::items::state::ItemStateProxy;
|
||||||
use crate::inventory::InventoryItemDetail;
|
use crate::ship::items::inventory::InventoryItemDetail;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
@ -226,7 +226,7 @@ pub async fn liberta_kit<EG: EntityGateway>(entity_gateway: &mut EG, used_cell:
|
|||||||
|
|
||||||
fn jack_o_lantern() -> Result<Vec<ApplyItemAction>, anyhow::Error>
|
fn jack_o_lantern() -> Result<Vec<ApplyItemAction>, anyhow::Error>
|
||||||
{
|
{
|
||||||
let mag_rate = WeightedIndex::new([13, 13, 13, 13, 12, 12, 12, 12]).unwrap();
|
let mag_rate = WeightedIndex::new(&[13, 13, 13, 13, 12, 12, 12, 12]).unwrap();
|
||||||
let mag_type = match mag_rate.sample(&mut rand_chacha::ChaChaRng::from_entropy()) {
|
let mag_type = match mag_rate.sample(&mut rand_chacha::ChaChaRng::from_entropy()) {
|
||||||
0 => ToolType::CellOfMag502,
|
0 => ToolType::CellOfMag502,
|
||||||
1 => ToolType::CellOfMag213,
|
1 => ToolType::CellOfMag213,
|
||||||
@ -354,13 +354,13 @@ where
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn apply_item<'a, EG>(item_state: &'a mut ItemStateProxy,
|
pub async fn apply_item<'a, EG>(item_state: &mut ItemStateProxy,
|
||||||
entity_gateway: &'a mut EG,
|
entity_gateway: &mut EG,
|
||||||
character: &'a mut CharacterEntity,
|
character: &mut CharacterEntity,
|
||||||
item: InventoryItemDetail
|
item: InventoryItemDetail
|
||||||
) -> Result<Vec<ApplyItemAction>, anyhow::Error>
|
) -> Result<Vec<ApplyItemAction>, anyhow::Error>
|
||||||
where
|
where
|
||||||
EG: EntityGateway + ?Sized + Clone + 'a
|
EG: EntityGateway + ?Sized + Clone + 'static
|
||||||
{
|
{
|
||||||
match item {
|
match item {
|
||||||
InventoryItemDetail::Individual(individual_item) => {
|
InventoryItemDetail::Individual(individual_item) => {
|
@ -1,15 +1,14 @@
|
|||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use libpso::character::character;
|
use libpso::character::character;
|
||||||
use crate::ClientItemId;
|
use crate::ship::items::ClientItemId;
|
||||||
use entity::item::{Meseta, ItemEntityId, ItemDetail, ItemEntity, BankEntity, BankItemEntity};
|
use crate::entity::item::{Meseta, ItemEntityId, ItemDetail, ItemEntity, BankEntity, BankItemEntity, BankName};
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use async_std::sync::{Arc, Mutex};
|
use async_std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use entity::character::CharacterEntityId;
|
use crate::entity::character::CharacterEntityId;
|
||||||
use entity::item::BankIdentifier;
|
use crate::ship::items::state::ItemStateError;
|
||||||
use crate::state::ItemStateError;
|
use crate::ship::items::state::{IndividualItemDetail, StackedItemDetail, AddItemResult};
|
||||||
use crate::state::{IndividualItemDetail, StackedItemDetail, AddItemResult};
|
use crate::ship::items::inventory::{InventoryItem, InventoryItemDetail};
|
||||||
use crate::inventory::{InventoryItem, InventoryItemDetail};
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
@ -23,7 +22,6 @@ pub enum BankError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum BankItemDetail {
|
pub enum BankItemDetail {
|
||||||
Individual(IndividualItemDetail),
|
Individual(IndividualItemDetail),
|
||||||
@ -100,7 +98,7 @@ impl Bank {
|
|||||||
pub struct BankState {
|
pub struct BankState {
|
||||||
pub character_id: CharacterEntityId,
|
pub character_id: CharacterEntityId,
|
||||||
pub item_id_counter: Arc<Mutex<u32>>,
|
pub item_id_counter: Arc<Mutex<u32>>,
|
||||||
pub identifier: BankIdentifier,
|
pub name: BankName,
|
||||||
pub bank: Bank,
|
pub bank: Bank,
|
||||||
pub meseta: Meseta,
|
pub meseta: Meseta,
|
||||||
}
|
}
|
||||||
@ -114,12 +112,12 @@ async fn new_item_id(item_id_counter: &Arc<Mutex<u32>>) -> ClientItemId {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl BankState {
|
impl BankState {
|
||||||
pub fn new(character_id: CharacterEntityId, identifier: BankIdentifier, mut bank: Bank, meseta: Meseta) -> BankState {
|
pub fn new(character_id: CharacterEntityId, name: BankName, mut bank: Bank, meseta: Meseta) -> BankState {
|
||||||
bank.0.sort();
|
bank.0.sort();
|
||||||
BankState {
|
BankState {
|
||||||
character_id,
|
character_id,
|
||||||
item_id_counter: Arc::new(Mutex::new(0)),
|
item_id_counter: Arc::new(Mutex::new(0)),
|
||||||
identifier,
|
name,
|
||||||
bank,
|
bank,
|
||||||
meseta,
|
meseta,
|
||||||
}
|
}
|
||||||
@ -305,14 +303,12 @@ impl BankState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::cmp::PartialEq for BankItem {
|
||||||
|
fn eq(&self, other: &BankItem) -> bool {
|
||||||
impl std::cmp::PartialEq for BankItemDetail {
|
|
||||||
fn eq(&self, other: &BankItemDetail) -> bool {
|
|
||||||
let mut self_bytes = [0u8; 4];
|
let mut self_bytes = [0u8; 4];
|
||||||
let mut other_bytes = [0u8; 4];
|
let mut other_bytes = [0u8; 4];
|
||||||
self_bytes.copy_from_slice(&self.as_client_bytes()[0..4]);
|
self_bytes.copy_from_slice(&self.item.as_client_bytes()[0..4]);
|
||||||
other_bytes.copy_from_slice(&other.as_client_bytes()[0..4]);
|
other_bytes.copy_from_slice(&other.item.as_client_bytes()[0..4]);
|
||||||
|
|
||||||
let self_value = u32::from_be_bytes(self_bytes);
|
let self_value = u32::from_be_bytes(self_bytes);
|
||||||
let other_value = u32::from_be_bytes(other_bytes);
|
let other_value = u32::from_be_bytes(other_bytes);
|
||||||
@ -321,46 +317,35 @@ impl std::cmp::PartialEq for BankItemDetail {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::cmp::Eq for BankItemDetail {}
|
|
||||||
|
|
||||||
impl std::cmp::PartialOrd for BankItemDetail {
|
|
||||||
fn partial_cmp(&self, other: &BankItemDetail) -> Option<std::cmp::Ordering> {
|
|
||||||
Some(self.cmp(other))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::cmp::Ord for BankItemDetail {
|
|
||||||
fn cmp(&self, other: &BankItemDetail) -> std::cmp::Ordering {
|
|
||||||
let mut self_bytes = [0u8; 4];
|
|
||||||
let mut other_bytes = [0u8; 4];
|
|
||||||
self_bytes.copy_from_slice(&self.as_client_bytes()[0..4]);
|
|
||||||
other_bytes.copy_from_slice(&other.as_client_bytes()[0..4]);
|
|
||||||
|
|
||||||
let self_value = u32::from_be_bytes(self_bytes);
|
|
||||||
let other_value = u32::from_be_bytes(other_bytes);
|
|
||||||
|
|
||||||
self_value.cmp(&other_value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl std::cmp::PartialEq for BankItem {
|
|
||||||
fn eq(&self, other: &BankItem) -> bool {
|
|
||||||
self.item.eq(&other.item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::cmp::Eq for BankItem {}
|
impl std::cmp::Eq for BankItem {}
|
||||||
|
|
||||||
impl std::cmp::PartialOrd for BankItem {
|
impl std::cmp::PartialOrd for BankItem {
|
||||||
fn partial_cmp(&self, other: &BankItem) -> Option<std::cmp::Ordering> {
|
fn partial_cmp(&self, other: &BankItem) -> Option<std::cmp::Ordering> {
|
||||||
Some(self.cmp(other))
|
let mut self_bytes = [0u8; 4];
|
||||||
|
let mut other_bytes = [0u8; 4];
|
||||||
|
self_bytes.copy_from_slice(&self.item.as_client_bytes()[0..4]);
|
||||||
|
other_bytes.copy_from_slice(&other.item.as_client_bytes()[0..4]);
|
||||||
|
|
||||||
|
|
||||||
|
let self_value = u32::from_be_bytes(self_bytes);
|
||||||
|
let other_value = u32::from_be_bytes(other_bytes);
|
||||||
|
|
||||||
|
self_value.partial_cmp(&other_value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::cmp::Ord for BankItem {
|
impl std::cmp::Ord for BankItem {
|
||||||
fn cmp(&self, other: &BankItem) -> std::cmp::Ordering {
|
fn cmp(&self, other: &BankItem) -> std::cmp::Ordering {
|
||||||
self.item.cmp(&other.item)
|
let mut self_bytes = [0u8; 4];
|
||||||
|
let mut other_bytes = [0u8; 4];
|
||||||
|
self_bytes.copy_from_slice(&self.item.as_client_bytes()[0..4]);
|
||||||
|
other_bytes.copy_from_slice(&other.item.as_client_bytes()[0..4]);
|
||||||
|
|
||||||
|
|
||||||
|
let self_value = u32::from_le_bytes(self_bytes);
|
||||||
|
let other_value = u32::from_le_bytes(other_bytes);
|
||||||
|
|
||||||
|
self_value.cmp(&other_value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,14 +1,14 @@
|
|||||||
use crate::ClientItemId;
|
use crate::ship::items::ClientItemId;
|
||||||
use entity::item::{Meseta, ItemEntityId, ItemDetail};
|
use crate::entity::item::{Meseta, ItemEntityId, ItemDetail};
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
|
||||||
use maps::area::MapArea;
|
use crate::ship::map::MapArea;
|
||||||
use entity::character::CharacterEntityId;
|
use crate::entity::character::CharacterEntityId;
|
||||||
use entity::item::mag::Mag;
|
use crate::entity::item::mag::Mag;
|
||||||
|
|
||||||
use crate::state::ItemStateError;
|
use crate::ship::items::state::ItemStateError;
|
||||||
use crate::state::{IndividualItemDetail, StackedItemDetail};
|
use crate::ship::items::state::{IndividualItemDetail, StackedItemDetail};
|
||||||
use crate::inventory::{InventoryItem, InventoryItemDetail};
|
use crate::ship::items::inventory::{InventoryItem, InventoryItemDetail};
|
||||||
|
|
||||||
pub enum FloorType {
|
pub enum FloorType {
|
||||||
Local,
|
Local,
|
||||||
@ -96,13 +96,13 @@ pub struct FloorState {
|
|||||||
impl FloorState {
|
impl FloorState {
|
||||||
pub fn take_item(&mut self, item_id: &ClientItemId) -> Option<FloorItem> {
|
pub fn take_item(&mut self, item_id: &ClientItemId) -> Option<FloorItem> {
|
||||||
let item = self.local.0
|
let item = self.local.0
|
||||||
.extract_if(|item| {
|
.drain_filter(|item| {
|
||||||
item.item_id == *item_id
|
item.item_id == *item_id
|
||||||
})
|
})
|
||||||
.next();
|
.next();
|
||||||
item.or_else(|| {
|
item.or_else(|| {
|
||||||
self.shared.0
|
self.shared.0
|
||||||
.extract_if(|item| {
|
.drain_filter(|item| {
|
||||||
item.item_id == *item_id
|
item.item_id == *item_id
|
||||||
})
|
})
|
||||||
.next()
|
.next()
|
@ -1,18 +1,18 @@
|
|||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use libpso::character::character;
|
use libpso::character::character;
|
||||||
use crate::ClientItemId;
|
use crate::ship::items::ClientItemId;
|
||||||
use entity::item::{Meseta, ItemEntityId, ItemDetail, ItemEntity, InventoryEntity, InventoryItemEntity, EquippedEntity};
|
use crate::entity::item::{Meseta, ItemEntityId, ItemDetail, ItemEntity, InventoryEntity, InventoryItemEntity, EquippedEntity};
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use async_std::sync::{Arc, Mutex};
|
use async_std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use entity::character::CharacterEntityId;
|
use crate::entity::character::CharacterEntityId;
|
||||||
use entity::item::tool::ToolType;
|
use crate::entity::item::tool::ToolType;
|
||||||
use entity::item::mag::Mag;
|
use crate::entity::item::mag::Mag;
|
||||||
use entity::item::weapon::Weapon;
|
use crate::entity::item::weapon::Weapon;
|
||||||
use shops::{ShopItem, ArmorShopItem, ToolShopItem, WeaponShopItem};
|
use crate::ship::shops::{ShopItem, ArmorShopItem, ToolShopItem, WeaponShopItem};
|
||||||
use crate::state::ItemStateError;
|
use crate::ship::items::state::ItemStateError;
|
||||||
use crate::state::{IndividualItemDetail, StackedItemDetail, AddItemResult};
|
use crate::ship::items::state::{IndividualItemDetail, StackedItemDetail, AddItemResult};
|
||||||
use crate::floor::{FloorItem, FloorItemDetail};
|
use crate::ship::items::floor::{FloorItem, FloorItemDetail};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum InventoryItemDetail {
|
pub enum InventoryItemDetail {
|
@ -34,40 +34,38 @@ where
|
|||||||
S: Send + Sync,
|
S: Send + Sync,
|
||||||
E: Send + Sync,
|
E: Send + Sync,
|
||||||
{
|
{
|
||||||
pub fn act<'a, O, F, Fut>(self, f: F) -> ItemActionStage<'a, O, ItemStateAction<T, S, E>, F, Fut, S, E>
|
pub fn act<O, F, Fut>(self, f: F) -> ItemActionStage<O, ItemStateAction<T, S, E>, F, Fut, S, E>
|
||||||
where
|
where
|
||||||
F: Fn(S, ()) -> Fut + Send + Sync + 'a,
|
F: Fn(S, ()) -> Fut + Send + Sync,
|
||||||
Fut: Future<Output=Result<(S, O), E>> + Send + 'a
|
Fut: Future<Output=Result<(S, O), E>> + Send
|
||||||
{
|
{
|
||||||
ItemActionStage {
|
ItemActionStage {
|
||||||
_s: Default::default(),
|
_s: Default::default(),
|
||||||
_e: std::marker::PhantomData,
|
_e: std::marker::PhantomData,
|
||||||
_a: Default::default(),
|
|
||||||
prev: self,
|
prev: self,
|
||||||
actionf: f,
|
actionf: f,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ItemActionStage<'a, O, P, F, Fut, S, E>
|
pub struct ItemActionStage<O, P, F, Fut, S, E>
|
||||||
where
|
where
|
||||||
P: ItemAction,
|
P: ItemAction,
|
||||||
F: Fn(S, P::Output) -> Fut + Send + Sync + 'a,
|
F: Fn(S, P::Output) -> Fut + Send + Sync,
|
||||||
Fut: Future<Output=Result<(S, O) , E>> + Send + 'a,
|
Fut: Future<Output=Result<(S, O) , E>> + Send,
|
||||||
{
|
{
|
||||||
_s: std::marker::PhantomData<S>,
|
_s: std::marker::PhantomData<S>,
|
||||||
_e: std::marker::PhantomData<E>,
|
_e: std::marker::PhantomData<E>,
|
||||||
_a: std::marker::PhantomData<&'a ()>,
|
|
||||||
prev: P,
|
prev: P,
|
||||||
actionf: F,
|
actionf: F,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl<'a, O, P: ItemAction, F, Fut, S, E> ItemAction for ItemActionStage<'a, O, P, F, Fut, S, E>
|
impl<O, P: ItemAction, F, Fut, S, E> ItemAction for ItemActionStage<O, P, F, Fut, S, E>
|
||||||
where
|
where
|
||||||
P: ItemAction + ItemAction<Start = S, Error = E> + Send + Sync,
|
P: ItemAction + ItemAction<Start = S, Error = E> + Send + Sync,
|
||||||
F: Fn(S, P::Output) -> Fut + Send + Sync + 'a,
|
F: Fn(S, P::Output) -> Fut + Send + Sync,
|
||||||
Fut: Future<Output=Result<(S, O), E>> + Send + 'a,
|
Fut: Future<Output=Result<(S, O), E>> + Send,
|
||||||
S: Send + Sync,
|
S: Send + Sync,
|
||||||
P::Output: Send + Sync,
|
P::Output: Send + Sync,
|
||||||
E: Send + Sync,
|
E: Send + Sync,
|
||||||
@ -89,11 +87,11 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, O, P: ItemAction, F, Fut, S, E> ItemActionStage<'a, O, P, F, Fut, S, E>
|
impl<O, P: ItemAction, F, Fut, S, E> ItemActionStage<O, P, F, Fut, S, E>
|
||||||
where
|
where
|
||||||
P: ItemAction<Start = S, Error = E> + Send + Sync,
|
P: ItemAction<Start = S, Error = E> + Send + Sync,
|
||||||
F: Fn(S, P::Output) -> Fut + Send + Sync + 'a,
|
F: Fn(S, P::Output) -> Fut + Send + Sync,
|
||||||
Fut: Future<Output=Result<(S, O), E>> + Send + 'a,
|
Fut: Future<Output=Result<(S, O), E>> + Send,
|
||||||
S: Send + Sync,
|
S: Send + Sync,
|
||||||
P::Output: Send + Sync,
|
P::Output: Send + Sync,
|
||||||
E: Send + Sync,
|
E: Send + Sync,
|
||||||
@ -101,17 +99,16 @@ where
|
|||||||
P::Error: Send + Sync,
|
P::Error: Send + Sync,
|
||||||
{
|
{
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
pub fn act<'b, O2, G, GFut>(self, g: G) -> ItemActionStage<'b, O2, ItemActionStage<'a, O, P, F, Fut, S, E>, G, GFut, S, E>
|
pub fn act<O2, G, GFut>(self, g: G) -> ItemActionStage<O2, ItemActionStage<O, P, F, Fut, S, E>, G, GFut, S, E>
|
||||||
where
|
where
|
||||||
S: Send + Sync,
|
S: Send + Sync,
|
||||||
G: Fn(S, <ItemActionStage<'a, O, P, F, Fut, S, E> as ItemAction>::Output) -> GFut + Send + Sync + 'b,
|
G: Fn(S, <ItemActionStage<O, P, F, Fut, S, E> as ItemAction>::Output) -> GFut + Send + Sync,
|
||||||
GFut: Future<Output=Result<(S, O2), E>> + Send + 'b,
|
GFut: Future<Output=Result<(S, O2), E>> + Send,
|
||||||
O2: Send + Sync,
|
O2: Send + Sync,
|
||||||
{
|
{
|
||||||
ItemActionStage {
|
ItemActionStage {
|
||||||
_s: Default::default(),
|
_s: Default::default(),
|
||||||
_e: Default::default(),
|
_e: Default::default(),
|
||||||
_a: Default::default(),
|
|
||||||
prev: self,
|
prev: self,
|
||||||
actionf: g,
|
actionf: g,
|
||||||
}
|
}
|
1380
src/ship/items/manager.rs
Normal file
1380
src/ship/items/manager.rs
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,3 @@
|
|||||||
#![feature(extract_if)]
|
|
||||||
|
|
||||||
pub mod state;
|
pub mod state;
|
||||||
pub mod actions;
|
pub mod actions;
|
||||||
pub mod apply_item;
|
pub mod apply_item;
|
||||||
@ -8,7 +6,6 @@ pub mod inventory;
|
|||||||
pub mod floor;
|
pub mod floor;
|
||||||
pub mod bank;
|
pub mod bank;
|
||||||
pub mod tasks;
|
pub mod tasks;
|
||||||
pub mod trade;
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, serde::Serialize, serde::Deserialize, derive_more::Display)]
|
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, serde::Serialize, serde::Deserialize, derive_more::Display)]
|
||||||
pub struct ClientItemId(pub u32);
|
pub struct ClientItemId(pub u32);
|
@ -1,21 +1,20 @@
|
|||||||
use std::collections::{HashMap, BinaryHeap};
|
use std::collections::HashMap;
|
||||||
use std::cmp::Reverse;
|
|
||||||
use async_std::sync::{Arc, RwLock, Mutex};
|
use async_std::sync::{Arc, RwLock, Mutex};
|
||||||
use futures::stream::{FuturesOrdered, StreamExt};
|
use futures::future::join_all;
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
|
|
||||||
use entity::gateway::{EntityGateway, GatewayError};
|
use crate::entity::gateway::{EntityGateway, GatewayError};
|
||||||
use entity::character::{CharacterEntity, CharacterEntityId};
|
use crate::entity::character::{CharacterEntity, CharacterEntityId};
|
||||||
use entity::item::{ItemEntityId, ItemDetail, ItemEntity, InventoryItemEntity, BankItemEntity, BankIdentifier};
|
use crate::entity::item::{ItemEntityId, ItemDetail, ItemEntity, InventoryItemEntity, BankItemEntity, BankName};
|
||||||
use entity::item::tool::Tool;
|
use crate::entity::item::tool::Tool;
|
||||||
use entity::item::weapon::Weapon;
|
use crate::entity::item::weapon::Weapon;
|
||||||
use entity::item::mag::Mag;
|
use crate::entity::item::mag::Mag;
|
||||||
use drops::ItemDrop;
|
use crate::ship::drops::ItemDrop;
|
||||||
use crate::ClientItemId;
|
use crate::ship::items::ClientItemId;
|
||||||
use crate::inventory::{Inventory, InventoryItem, InventoryItemDetail, InventoryError, InventoryState};
|
use crate::ship::items::inventory::{Inventory, InventoryItem, InventoryItemDetail, InventoryError, InventoryState};
|
||||||
use crate::floor::{FloorState, FloorItem, LocalFloor, SharedFloor, FloorType};
|
use crate::ship::items::floor::{FloorState, FloorItem, LocalFloor, SharedFloor, FloorType};
|
||||||
use crate::bank::{Bank, BankState, BankItem, BankItemDetail, BankError};
|
use crate::ship::items::bank::{Bank, BankState, BankItem, BankItemDetail, BankError};
|
||||||
use location::{AreaClient, RoomId};
|
use crate::ship::location::{AreaClient, RoomId};
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
pub enum ItemStateError {
|
pub enum ItemStateError {
|
||||||
@ -50,7 +49,7 @@ pub enum ItemStateError {
|
|||||||
#[error("stacked item")]
|
#[error("stacked item")]
|
||||||
StackedItemError(Vec<ItemEntity>),
|
StackedItemError(Vec<ItemEntity>),
|
||||||
#[error("apply item {0}")]
|
#[error("apply item {0}")]
|
||||||
ApplyItemError(#[from] crate::apply_item::ApplyItemError),
|
ApplyItemError(#[from] crate::ship::items::apply_item::ApplyItemError),
|
||||||
#[error("item is not a mag {0}")]
|
#[error("item is not a mag {0}")]
|
||||||
NotAMag(ClientItemId),
|
NotAMag(ClientItemId),
|
||||||
#[error("item is not mag food {0}")]
|
#[error("item is not mag food {0}")]
|
||||||
@ -219,8 +218,9 @@ impl ItemState {
|
|||||||
Ok(ClientItemId(*self.room_item_id_counter.read().await))
|
Ok(ClientItemId(*self.room_item_id_counter.read().await))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn load_character_inventory<EG: EntityGateway>(&mut self, entity_gateway: &mut EG, character: &CharacterEntity) -> Result<(), anyhow::Error> {
|
pub async fn load_character<EG: EntityGateway>(&mut self, entity_gateway: &mut EG, character: &CharacterEntity) -> Result<(), anyhow::Error> {
|
||||||
let inventory = entity_gateway.get_character_inventory(&character.id).await?;
|
let inventory = entity_gateway.get_character_inventory(&character.id).await?;
|
||||||
|
let bank = entity_gateway.get_character_bank(&character.id, &BankName("".into())).await?;
|
||||||
let equipped = entity_gateway.get_character_equips(&character.id).await?;
|
let equipped = entity_gateway.get_character_equips(&character.id).await?;
|
||||||
|
|
||||||
let inventory_items = inventory.items.into_iter()
|
let inventory_items = inventory.items.into_iter()
|
||||||
@ -262,58 +262,49 @@ impl ItemState {
|
|||||||
meseta: character_meseta,
|
meseta: character_meseta,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let bank_items = join_all(
|
||||||
|
bank.items.into_iter()
|
||||||
|
.map(|item| {
|
||||||
|
let mut citem_state = self.clone();
|
||||||
|
async move {
|
||||||
|
Ok(match item {
|
||||||
|
BankItemEntity::Individual(item) => {
|
||||||
|
BankItem {
|
||||||
|
item_id: citem_state.new_item_id().await?,
|
||||||
|
item: BankItemDetail::Individual(IndividualItemDetail {
|
||||||
|
entity_id: item.id,
|
||||||
|
item: item.item,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
BankItemEntity::Stacked(items) => {
|
||||||
|
BankItem {
|
||||||
|
item_id: citem_state.new_item_id().await?,
|
||||||
|
item: BankItemDetail::Stacked(StackedItemDetail {
|
||||||
|
entity_ids: items.iter().map(|i| i.id).collect(),
|
||||||
|
tool: items.get(0)
|
||||||
|
.ok_or_else(|| ItemStateError::StackedItemError(items.clone()))?
|
||||||
|
.item
|
||||||
|
.clone()
|
||||||
|
.as_tool()
|
||||||
|
.ok_or_else(|| ItemStateError::StackedItemError(items.clone()))?
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}})
|
||||||
|
.collect::<Vec<_>>())
|
||||||
|
.await
|
||||||
|
.into_iter()
|
||||||
|
.collect::<Result<Vec<_>, anyhow::Error>>()?;
|
||||||
|
|
||||||
|
let bank_meseta = entity_gateway.get_bank_meseta(&character.id, &BankName("".into())).await?;
|
||||||
|
let bank_state = BankState::new(character.id, BankName("".into()), Bank::new(bank_items), bank_meseta);
|
||||||
|
|
||||||
self.character_inventory
|
self.character_inventory
|
||||||
.write()
|
.write()
|
||||||
.await
|
.await
|
||||||
.insert(character.id, RwLock::new(inventory_state));
|
.insert(character.id, RwLock::new(inventory_state));
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn load_character_bank<EG: EntityGateway>(&mut self, entity_gateway: &mut EG, character: &CharacterEntity, bank_identifier: BankIdentifier) -> Result<(), anyhow::Error> {
|
|
||||||
let bank = entity_gateway.get_character_bank(&character.id, &bank_identifier).await?;
|
|
||||||
let bank_items = bank.items
|
|
||||||
.into_iter()
|
|
||||||
.map(|item| {
|
|
||||||
Ok(Reverse(match item {
|
|
||||||
BankItemEntity::Individual(item) => {
|
|
||||||
BankItemDetail::Individual(IndividualItemDetail {
|
|
||||||
entity_id: item.id,
|
|
||||||
item: item.item,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
BankItemEntity::Stacked(items) => {
|
|
||||||
BankItemDetail::Stacked(StackedItemDetail {
|
|
||||||
entity_ids: items.iter().map(|i| i.id).collect(),
|
|
||||||
tool: items.get(0)
|
|
||||||
.ok_or_else(|| ItemStateError::StackedItemError(items.clone()))?
|
|
||||||
.item
|
|
||||||
.clone()
|
|
||||||
.as_tool()
|
|
||||||
.ok_or_else(|| ItemStateError::StackedItemError(items.clone()))?
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
.collect::<Result<BinaryHeap<_>, anyhow::Error>>()?
|
|
||||||
.into_iter()
|
|
||||||
.map(|item| {
|
|
||||||
let mut citem_state = self.clone();
|
|
||||||
async move {
|
|
||||||
Ok(BankItem {
|
|
||||||
item_id: citem_state.new_item_id().await?,
|
|
||||||
item: item.0,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<FuturesOrdered<_>>()
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.await
|
|
||||||
.into_iter()
|
|
||||||
.collect::<Result<Vec<_>, anyhow::Error>>()?;
|
|
||||||
|
|
||||||
let bank_meseta = entity_gateway.get_bank_meseta(&character.id, &bank_identifier).await?;
|
|
||||||
let bank_state = BankState::new(character.id, bank_identifier, Bank::new(bank_items), bank_meseta);
|
|
||||||
|
|
||||||
self.character_bank
|
self.character_bank
|
||||||
.write()
|
.write()
|
||||||
.await
|
.await
|
||||||
@ -321,13 +312,6 @@ impl ItemState {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn load_character<EG: EntityGateway>(&mut self, entity_gateway: &mut EG, character: &CharacterEntity) -> Result<(), anyhow::Error> {
|
|
||||||
self.load_character_inventory(entity_gateway, character).await?;
|
|
||||||
self.load_character_bank(entity_gateway, character, BankIdentifier::Character).await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn add_character_to_room(&mut self, room_id: RoomId, character: &CharacterEntity, area_client: AreaClient) {
|
pub async fn add_character_to_room(&mut self, room_id: RoomId, character: &CharacterEntity, area_client: AreaClient) {
|
||||||
let mut base_item_ids = self.room_gem_item_ids
|
let mut base_item_ids = self.room_gem_item_ids
|
||||||
.write()
|
.write()
|
||||||
@ -382,7 +366,7 @@ impl ItemState {
|
|||||||
let removed = {
|
let removed = {
|
||||||
self.character_room.write().await.remove(&character.id)
|
self.character_room.write().await.remove(&character.id)
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(room) = removed.as_ref() {
|
if let Some(room) = removed.as_ref() {
|
||||||
// TODO: this looks wrong, .all(r != room) maybe?
|
// TODO: this looks wrong, .all(r != room) maybe?
|
||||||
if self.character_room.read().await.iter().any(|(_, r)| r == room) {
|
if self.character_room.read().await.iter().any(|(_, r)| r == room) {
|
@ -1,35 +1,33 @@
|
|||||||
use futures::future::BoxFuture;
|
use crate::ship::items::ClientItemId;
|
||||||
use crate::ClientItemId;
|
use crate::entity::item::Meseta;
|
||||||
use entity::item::Meseta;
|
|
||||||
|
|
||||||
use maps::area::MapArea;
|
use crate::ship::ship::SendShipPacket;
|
||||||
use entity::character::{CharacterEntity, CharacterEntityId};
|
use crate::ship::map::MapArea;
|
||||||
use entity::gateway::{EntityGateway, EntityGatewayTransaction};
|
use crate::entity::character::{CharacterEntity, CharacterEntityId};
|
||||||
use entity::item::ItemModifier;
|
use crate::entity::gateway::{EntityGateway, EntityGatewayTransaction};
|
||||||
use entity::room::RoomEntityId;
|
use crate::ship::items::state::{ItemState, ItemStateProxy, IndividualItemDetail};
|
||||||
use crate::state::{ItemState, ItemStateProxy, IndividualItemDetail};
|
use crate::ship::items::itemstateaction::{ItemStateAction, ItemAction};
|
||||||
use crate::itemstateaction::{ItemStateAction, ItemAction};
|
use crate::ship::items::inventory::InventoryItem;
|
||||||
use crate::inventory::InventoryItem;
|
use crate::ship::items::floor::FloorItem;
|
||||||
use crate::floor::FloorItem;
|
use crate::entity::item::ItemModifier;
|
||||||
use shops::ShopItem;
|
use crate::ship::shops::ShopItem;
|
||||||
use crate::trade::TradeItem;
|
use crate::ship::trade::TradeItem;
|
||||||
use location::AreaClient;
|
use crate::ship::location::AreaClient;
|
||||||
use drops::ItemDrop;
|
use crate::ship::drops::ItemDrop;
|
||||||
use maps::monster::MonsterType;
|
|
||||||
|
|
||||||
use crate::actions;
|
use crate::ship::items::actions;
|
||||||
|
|
||||||
pub fn pick_up_item<'a, EG>(
|
pub async fn pick_up_item<EG>(
|
||||||
item_state: &'a mut ItemState,
|
item_state: &mut ItemState,
|
||||||
entity_gateway: &'a mut EG,
|
entity_gateway: &mut EG,
|
||||||
character: &'a CharacterEntity,
|
character: &CharacterEntity,
|
||||||
item_id: &'a ClientItemId,
|
item_id: &ClientItemId)
|
||||||
) -> BoxFuture<'a, Result<actions::TriggerCreateItem, anyhow::Error>>
|
-> Result<actions::TriggerCreateItem, anyhow::Error>
|
||||||
where
|
where
|
||||||
EG: EntityGateway + 'static,
|
EG: EntityGateway + 'static,
|
||||||
EG::Transaction<'a>: Clone,
|
EG::Transaction: Clone,
|
||||||
{
|
{
|
||||||
entity_gateway.with_transaction(move |transaction| async move {
|
entity_gateway.with_transaction(|transaction| async move {
|
||||||
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
||||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||||
.act(actions::take_item_from_floor(character.id, *item_id))
|
.act(actions::take_item_from_floor(character.id, *item_id))
|
||||||
@ -38,22 +36,21 @@ where
|
|||||||
.await?;
|
.await?;
|
||||||
item_state_proxy.commit().await;
|
item_state_proxy.commit().await;
|
||||||
Ok((transaction, result))
|
Ok((transaction, result))
|
||||||
})
|
}).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn drop_item<'a, EG>(
|
pub async fn drop_item<EG>(
|
||||||
item_state: &'a mut ItemState,
|
item_state: &mut ItemState,
|
||||||
entity_gateway: &'a mut EG,
|
entity_gateway: &mut EG,
|
||||||
character: &'a CharacterEntity,
|
character: &CharacterEntity,
|
||||||
item_id: &'a ClientItemId,
|
item_id: &ClientItemId,
|
||||||
map_area: MapArea,
|
map_area: MapArea,
|
||||||
drop_position: (f32, f32, f32),
|
drop_position: (f32, f32, f32))
|
||||||
)-> BoxFuture<'a, Result<FloorItem, anyhow::Error>>
|
-> Result<FloorItem, anyhow::Error>
|
||||||
where
|
where
|
||||||
EG: EntityGateway + 'static,
|
EG: EntityGateway + 'static,
|
||||||
EG::Transaction<'a>: Clone,
|
|
||||||
{
|
{
|
||||||
entity_gateway.with_transaction(move |transaction| async move {
|
entity_gateway.with_transaction(|transaction| async move {
|
||||||
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
||||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||||
.act(actions::take_item_from_inventory(character.id, *item_id, 0))
|
.act(actions::take_item_from_inventory(character.id, *item_id, 0))
|
||||||
@ -62,22 +59,22 @@ where
|
|||||||
.await?;
|
.await?;
|
||||||
item_state_proxy.commit().await;
|
item_state_proxy.commit().await;
|
||||||
Ok((transaction, result))
|
Ok((transaction, result))
|
||||||
})
|
}).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn drop_partial_item<'a, EG>(
|
pub async fn drop_partial_item<'a, EG>(
|
||||||
item_state: &'a mut ItemState,
|
item_state: &'a mut ItemState,
|
||||||
entity_gateway: &'a mut EG,
|
entity_gateway: &mut EG,
|
||||||
character: &'a CharacterEntity,
|
character: &CharacterEntity,
|
||||||
item_id: &'a ClientItemId,
|
item_id: &ClientItemId,
|
||||||
map_area: MapArea,
|
map_area: MapArea,
|
||||||
drop_position: (f32, f32),
|
drop_position: (f32, f32),
|
||||||
amount: u32
|
amount: u32)
|
||||||
) -> BoxFuture<'a, Result<FloorItem, anyhow::Error>>
|
-> Result<FloorItem, anyhow::Error>
|
||||||
where
|
where
|
||||||
EG: EntityGateway + 'static,
|
EG: EntityGateway + 'static,
|
||||||
{
|
{
|
||||||
entity_gateway.with_transaction(move |transaction| async move {
|
entity_gateway.with_transaction(|transaction| async move {
|
||||||
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
||||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||||
.act(actions::take_item_from_inventory(character.id, *item_id, amount))
|
.act(actions::take_item_from_inventory(character.id, *item_id, amount))
|
||||||
@ -86,23 +83,23 @@ where
|
|||||||
.await?;
|
.await?;
|
||||||
item_state_proxy.commit().await;
|
item_state_proxy.commit().await;
|
||||||
Ok((transaction, result))
|
Ok((transaction, result))
|
||||||
})
|
}).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pub fn drop_meseta<'a, EG>(
|
pub async fn drop_meseta<'a, EG>(
|
||||||
item_state: &'a mut ItemState,
|
item_state: &'a mut ItemState,
|
||||||
entity_gateway: &'a mut EG,
|
entity_gateway: &mut EG,
|
||||||
character: &'a CharacterEntity,
|
character: &CharacterEntity,
|
||||||
map_area: MapArea,
|
map_area: MapArea,
|
||||||
drop_position: (f32, f32),
|
drop_position: (f32, f32),
|
||||||
amount: u32,
|
amount: u32)
|
||||||
) -> BoxFuture<'a, Result<FloorItem, anyhow::Error>>
|
-> Result<FloorItem, anyhow::Error>
|
||||||
where
|
where
|
||||||
EG: EntityGateway + 'static,
|
EG: EntityGateway + 'static,
|
||||||
{
|
{
|
||||||
entity_gateway.with_transaction(move |transaction| async move {
|
entity_gateway.with_transaction(|transaction| async move {
|
||||||
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
||||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||||
.act(actions::take_meseta_from_inventory(character.id, amount))
|
.act(actions::take_meseta_from_inventory(character.id, amount))
|
||||||
@ -111,20 +108,20 @@ where
|
|||||||
.await?;
|
.await?;
|
||||||
item_state_proxy.commit().await;
|
item_state_proxy.commit().await;
|
||||||
Ok((transaction, result))
|
Ok((transaction, result))
|
||||||
})
|
}).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn withdraw_meseta<'a, EG>(
|
pub async fn withdraw_meseta<'a, EG>(
|
||||||
item_state: &'a mut ItemState,
|
item_state: &'a mut ItemState,
|
||||||
entity_gateway: &'a mut EG,
|
entity_gateway: &mut EG,
|
||||||
character: &'a CharacterEntity,
|
character: &CharacterEntity,
|
||||||
amount: u32,
|
amount: u32)
|
||||||
) -> BoxFuture<'a, Result<(), anyhow::Error>>
|
-> Result<(), anyhow::Error>
|
||||||
where
|
where
|
||||||
EG: EntityGateway + 'static,
|
EG: EntityGateway + 'static,
|
||||||
{
|
{
|
||||||
entity_gateway.with_transaction(move |transaction| async move {
|
entity_gateway.with_transaction(|transaction| async move {
|
||||||
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
||||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||||
.act(actions::take_meseta_from_bank(character.id, amount))
|
.act(actions::take_meseta_from_bank(character.id, amount))
|
||||||
@ -133,20 +130,20 @@ where
|
|||||||
.await?;
|
.await?;
|
||||||
item_state_proxy.commit().await;
|
item_state_proxy.commit().await;
|
||||||
Ok((transaction, result))
|
Ok((transaction, result))
|
||||||
})
|
}).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn deposit_meseta<'a, EG>(
|
pub async fn deposit_meseta<'a, EG>(
|
||||||
item_state: &'a mut ItemState,
|
item_state: &'a mut ItemState,
|
||||||
entity_gateway: &'a mut EG,
|
entity_gateway: &mut EG,
|
||||||
character: &'a CharacterEntity,
|
character: &CharacterEntity,
|
||||||
amount: u32,
|
amount: u32)
|
||||||
) -> BoxFuture<'a, Result<(), anyhow::Error>>
|
-> Result<(), anyhow::Error>
|
||||||
where
|
where
|
||||||
EG: EntityGateway + 'static,
|
EG: EntityGateway + 'static,
|
||||||
{
|
{
|
||||||
entity_gateway.with_transaction(move |transaction| async move {
|
entity_gateway.with_transaction(|transaction| async move {
|
||||||
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
||||||
let ((item_state_proxy, transaction), _) = ItemStateAction::default()
|
let ((item_state_proxy, transaction), _) = ItemStateAction::default()
|
||||||
.act(actions::take_meseta_from_inventory(character.id, amount))
|
.act(actions::take_meseta_from_inventory(character.id, amount))
|
||||||
@ -155,21 +152,21 @@ where
|
|||||||
.await?;
|
.await?;
|
||||||
item_state_proxy.commit().await;
|
item_state_proxy.commit().await;
|
||||||
Ok((transaction, ()))
|
Ok((transaction, ()))
|
||||||
})
|
}).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn withdraw_item<'a, EG>(
|
pub async fn withdraw_item<'a, EG>(
|
||||||
item_state: &'a mut ItemState,
|
item_state: &'a mut ItemState,
|
||||||
entity_gateway: &'a mut EG,
|
entity_gateway: &mut EG,
|
||||||
character: &'a CharacterEntity,
|
character: &CharacterEntity,
|
||||||
item_id: &'a ClientItemId,
|
item_id: &ClientItemId,
|
||||||
amount: u32,
|
amount: u32)
|
||||||
) -> BoxFuture<'a, Result<InventoryItem, anyhow::Error>>
|
-> Result<InventoryItem, anyhow::Error>
|
||||||
where
|
where
|
||||||
EG: EntityGateway + 'static,
|
EG: EntityGateway + 'static,
|
||||||
{
|
{
|
||||||
entity_gateway.with_transaction(move |transaction| async move {
|
entity_gateway.with_transaction(|transaction| async move {
|
||||||
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
||||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||||
.act(actions::take_item_from_bank(character.id, *item_id, amount))
|
.act(actions::take_item_from_bank(character.id, *item_id, amount))
|
||||||
@ -180,21 +177,21 @@ where
|
|||||||
.await?;
|
.await?;
|
||||||
item_state_proxy.commit().await;
|
item_state_proxy.commit().await;
|
||||||
Ok((transaction, result))
|
Ok((transaction, result))
|
||||||
})
|
}).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn deposit_item<'a, EG> (
|
pub async fn deposit_item<'a, EG> (
|
||||||
item_state: &'a mut ItemState,
|
item_state: &'a mut ItemState,
|
||||||
entity_gateway: &'a mut EG,
|
entity_gateway: &mut EG,
|
||||||
character: &'a CharacterEntity,
|
character: &CharacterEntity,
|
||||||
item_id: &'a ClientItemId,
|
item_id: &ClientItemId,
|
||||||
amount: u32,
|
amount: u32)
|
||||||
) -> BoxFuture<'a, Result<(), anyhow::Error>>
|
-> Result<(), anyhow::Error>
|
||||||
where
|
where
|
||||||
EG: EntityGateway + 'static,
|
EG: EntityGateway + 'static,
|
||||||
{
|
{
|
||||||
entity_gateway.with_transaction(move |transaction| async move {
|
entity_gateway.with_transaction(|transaction| async move {
|
||||||
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
||||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||||
.act(actions::take_item_from_inventory(character.id, *item_id, amount))
|
.act(actions::take_item_from_inventory(character.id, *item_id, amount))
|
||||||
@ -203,20 +200,20 @@ where
|
|||||||
.await?;
|
.await?;
|
||||||
item_state_proxy.commit().await;
|
item_state_proxy.commit().await;
|
||||||
Ok((transaction, result))
|
Ok((transaction, result))
|
||||||
})
|
}).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn equip_item<'a, EG> (
|
pub async fn equip_item<'a, EG> (
|
||||||
item_state: &'a mut ItemState,
|
item_state: &'a mut ItemState,
|
||||||
entity_gateway: &'a mut EG,
|
entity_gateway: &mut EG,
|
||||||
character: &'a CharacterEntity,
|
character: &CharacterEntity,
|
||||||
item_id: &'a ClientItemId,
|
item_id: &ClientItemId,
|
||||||
equip_slot: u8,
|
equip_slot: u8,
|
||||||
) -> BoxFuture<'a, Result<(), anyhow::Error>>
|
) -> Result<(), anyhow::Error>
|
||||||
where
|
where
|
||||||
EG: EntityGateway + 'static,
|
EG: EntityGateway + 'static,
|
||||||
{
|
{
|
||||||
entity_gateway.with_transaction(move |transaction| async move {
|
entity_gateway.with_transaction(|transaction| async move {
|
||||||
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
||||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||||
.act(actions::equip_inventory_item(character.id, *item_id, equip_slot))
|
.act(actions::equip_inventory_item(character.id, *item_id, equip_slot))
|
||||||
@ -224,20 +221,20 @@ where
|
|||||||
.await?;
|
.await?;
|
||||||
item_state_proxy.commit().await;
|
item_state_proxy.commit().await;
|
||||||
Ok((transaction, result))
|
Ok((transaction, result))
|
||||||
})
|
}).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn unequip_item<'a, EG> (
|
pub async fn unequip_item<'a, EG> (
|
||||||
item_state: &'a mut ItemState,
|
item_state: &'a mut ItemState,
|
||||||
entity_gateway: &'a mut EG,
|
entity_gateway: &mut EG,
|
||||||
character: &'a CharacterEntity,
|
character: &CharacterEntity,
|
||||||
item_id: &'a ClientItemId,
|
item_id: &ClientItemId,
|
||||||
) -> BoxFuture<'a, Result<(), anyhow::Error>>
|
) -> Result<(), anyhow::Error>
|
||||||
where
|
where
|
||||||
EG: EntityGateway + 'static,
|
EG: EntityGateway + 'static,
|
||||||
{
|
{
|
||||||
entity_gateway.with_transaction(move |transaction| async move {
|
entity_gateway.with_transaction(|transaction| async move {
|
||||||
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
||||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||||
.act(actions::unequip_inventory_item(character.id, *item_id))
|
.act(actions::unequip_inventory_item(character.id, *item_id))
|
||||||
@ -245,20 +242,20 @@ where
|
|||||||
.await?;
|
.await?;
|
||||||
item_state_proxy.commit().await;
|
item_state_proxy.commit().await;
|
||||||
Ok((transaction, result))
|
Ok((transaction, result))
|
||||||
})
|
}).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn sort_inventory<'a, EG> (
|
pub async fn sort_inventory<'a, EG> (
|
||||||
item_state: &'a mut ItemState,
|
item_state: &'a mut ItemState,
|
||||||
entity_gateway: &'a mut EG,
|
entity_gateway: &mut EG,
|
||||||
character: &'a CharacterEntity,
|
character: &CharacterEntity,
|
||||||
item_ids: Vec<ClientItemId>,
|
item_ids: Vec<ClientItemId>,
|
||||||
) -> BoxFuture<'a, Result<(), anyhow::Error>>
|
) -> Result<(), anyhow::Error>
|
||||||
where
|
where
|
||||||
EG: EntityGateway + 'static,
|
EG: EntityGateway + 'static,
|
||||||
{
|
{
|
||||||
entity_gateway.with_transaction(move |transaction| async move {
|
entity_gateway.with_transaction(|transaction| async move {
|
||||||
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
||||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||||
.act(actions::sort_inventory_items(character.id, item_ids))
|
.act(actions::sort_inventory_items(character.id, item_ids))
|
||||||
@ -266,22 +263,22 @@ where
|
|||||||
.await?;
|
.await?;
|
||||||
item_state_proxy.commit().await;
|
item_state_proxy.commit().await;
|
||||||
Ok((transaction, result))
|
Ok((transaction, result))
|
||||||
})
|
}).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn use_item<'a, EG> (
|
pub async fn use_item<'a, EG> (
|
||||||
item_state: &'a mut ItemState,
|
item_state: &'a mut ItemState,
|
||||||
entity_gateway: &'a mut EG,
|
entity_gateway: &mut EG,
|
||||||
character: &'a mut CharacterEntity,
|
character: &mut CharacterEntity,
|
||||||
area_client: AreaClient,
|
area_client: AreaClient,
|
||||||
item_id: &'a ClientItemId,
|
item_id: &ClientItemId,
|
||||||
amount: u32,
|
amount: u32,
|
||||||
) -> BoxFuture<'a, Result<Vec<actions::CreateItem>, anyhow::Error>>
|
) -> Result<Vec<SendShipPacket>, anyhow::Error>
|
||||||
where
|
where
|
||||||
EG: EntityGateway + 'static,
|
EG: EntityGateway + 'static,
|
||||||
{
|
{
|
||||||
entity_gateway.with_transaction(move |transaction| async move {
|
entity_gateway.with_transaction(|transaction| async move {
|
||||||
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
||||||
let ((item_state_proxy, transaction), (pkts, new_character)) = ItemStateAction::default()
|
let ((item_state_proxy, transaction), (pkts, new_character)) = ItemStateAction::default()
|
||||||
.act(actions::remove_item_from_inventory(character.id, *item_id, amount))
|
.act(actions::remove_item_from_inventory(character.id, *item_id, amount))
|
||||||
@ -296,21 +293,21 @@ where
|
|||||||
|
|
||||||
*character = new_character;
|
*character = new_character;
|
||||||
Ok((transaction, pkts.into_iter().flatten().collect()))
|
Ok((transaction, pkts.into_iter().flatten().collect()))
|
||||||
})
|
}).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn feed_mag<'a, EG> (
|
pub async fn feed_mag<'a, EG> (
|
||||||
item_state: &'a mut ItemState,
|
item_state: &'a mut ItemState,
|
||||||
entity_gateway: &'a mut EG,
|
entity_gateway: &mut EG,
|
||||||
character: &'a CharacterEntity,
|
character: &CharacterEntity,
|
||||||
mag_item_id: &'a ClientItemId,
|
mag_item_id: &ClientItemId,
|
||||||
tool_item_id: &'a ClientItemId,
|
tool_item_id: &ClientItemId,
|
||||||
) -> BoxFuture<'a, Result<(), anyhow::Error>>
|
) -> Result<(), anyhow::Error>
|
||||||
where
|
where
|
||||||
EG: EntityGateway + 'static,
|
EG: EntityGateway + 'static,
|
||||||
{
|
{
|
||||||
entity_gateway.with_transaction(move |transaction| async move {
|
entity_gateway.with_transaction(|transaction| async move {
|
||||||
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
||||||
let ((item_state_proxy, transaction), _) = ItemStateAction::default()
|
let ((item_state_proxy, transaction), _) = ItemStateAction::default()
|
||||||
.act(actions::take_item_from_inventory(character.id, *tool_item_id, 1))
|
.act(actions::take_item_from_inventory(character.id, *tool_item_id, 1))
|
||||||
@ -319,23 +316,23 @@ where
|
|||||||
.await?;
|
.await?;
|
||||||
item_state_proxy.commit().await;
|
item_state_proxy.commit().await;
|
||||||
Ok((transaction, ()))
|
Ok((transaction, ()))
|
||||||
})
|
}).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn buy_shop_item<'a, EG> (
|
pub async fn buy_shop_item<'a, EG> (
|
||||||
item_state: &'a mut ItemState,
|
item_state: &'a mut ItemState,
|
||||||
entity_gateway: &'a mut EG,
|
entity_gateway: &mut EG,
|
||||||
character: &'a CharacterEntity,
|
character: &CharacterEntity,
|
||||||
shop_item: &'a (dyn ShopItem + Send + Sync),
|
shop_item: &'a (dyn ShopItem + Send + Sync),
|
||||||
item_id: ClientItemId,
|
item_id: ClientItemId,
|
||||||
amount: u32,
|
amount: u32,
|
||||||
) -> BoxFuture<'a, Result<InventoryItem, anyhow::Error>>
|
) -> Result<InventoryItem, anyhow::Error>
|
||||||
where
|
where
|
||||||
EG: EntityGateway + 'static,
|
EG: EntityGateway + 'static,
|
||||||
{
|
{
|
||||||
let item_price = shop_item.price() as u32 * amount;
|
let item_price = shop_item.price() as u32 * amount;
|
||||||
entity_gateway.with_transaction(move |transaction| async move {
|
entity_gateway.with_transaction(|transaction| async move {
|
||||||
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
||||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||||
.act(actions::take_meseta_from_inventory(character.id, item_price))
|
.act(actions::take_meseta_from_inventory(character.id, item_price))
|
||||||
@ -346,21 +343,21 @@ where
|
|||||||
.await?;
|
.await?;
|
||||||
item_state_proxy.commit().await;
|
item_state_proxy.commit().await;
|
||||||
Ok((transaction, result))
|
Ok((transaction, result))
|
||||||
})
|
}).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn sell_item<'a, EG> (
|
pub async fn sell_item<'a, EG> (
|
||||||
item_state: &'a mut ItemState,
|
item_state: &'a mut ItemState,
|
||||||
entity_gateway: &'a mut EG,
|
entity_gateway: &mut EG,
|
||||||
character: &'a CharacterEntity,
|
character: &CharacterEntity,
|
||||||
item_id: ClientItemId,
|
item_id: ClientItemId,
|
||||||
amount: u32,
|
amount: u32,
|
||||||
) -> BoxFuture<'a, Result<InventoryItem, anyhow::Error>>
|
) -> Result<InventoryItem, anyhow::Error>
|
||||||
where
|
where
|
||||||
EG: EntityGateway + 'static,
|
EG: EntityGateway + 'static,
|
||||||
{
|
{
|
||||||
entity_gateway.with_transaction(move |transaction| async move {
|
entity_gateway.with_transaction(|transaction| async move {
|
||||||
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
||||||
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
let ((item_state_proxy, transaction), result) = ItemStateAction::default()
|
||||||
.act(actions::take_item_from_inventory(character.id, item_id, amount))
|
.act(actions::take_item_from_inventory(character.id, item_id, amount))
|
||||||
@ -369,16 +366,14 @@ where
|
|||||||
.await?;
|
.await?;
|
||||||
item_state_proxy.commit().await;
|
item_state_proxy.commit().await;
|
||||||
Ok((transaction, result))
|
Ok((transaction, result))
|
||||||
})
|
}).await
|
||||||
}
|
}
|
||||||
|
pub async fn trade_items<'a, EG> (
|
||||||
#[allow(clippy::type_complexity)]
|
|
||||||
pub fn trade_items<'a, EG> (
|
|
||||||
item_state: &'a mut ItemState,
|
item_state: &'a mut ItemState,
|
||||||
entity_gateway: &'a mut EG,
|
entity_gateway: &mut EG,
|
||||||
p1: (&'a AreaClient, &'a CharacterEntity, &'a Vec<TradeItem>, Meseta),
|
p1: (&AreaClient, &CharacterEntity, &Vec<TradeItem>, Meseta),
|
||||||
p2: (&'a AreaClient, &'a CharacterEntity, &'a Vec<TradeItem>, Meseta))
|
p2: (&AreaClient, &CharacterEntity, &Vec<TradeItem>, Meseta))
|
||||||
-> BoxFuture<'a, Result<(Vec<InventoryItem>, Vec<InventoryItem>), anyhow::Error>>
|
-> Result<(Vec<InventoryItem>, Vec<InventoryItem>), anyhow::Error>
|
||||||
where
|
where
|
||||||
EG: EntityGateway + 'static,
|
EG: EntityGateway + 'static,
|
||||||
{
|
{
|
||||||
@ -400,7 +395,7 @@ where
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
entity_gateway.with_transaction(move |mut transaction| async move {
|
entity_gateway.with_transaction(|mut transaction| async move {
|
||||||
let p1_id = p1.1.id;
|
let p1_id = p1.1.id;
|
||||||
let p2_id = p2.1.id;
|
let p2_id = p2.1.id;
|
||||||
let trade = transaction.gateway().create_trade(&p1_id, &p2_id).await?;
|
let trade = transaction.gateway().create_trade(&p1_id, &p2_id).await?;
|
||||||
@ -439,20 +434,20 @@ where
|
|||||||
|
|
||||||
item_state_proxy.commit().await;
|
item_state_proxy.commit().await;
|
||||||
Ok((transaction, (p1_new_items, p2_new_items)))
|
Ok((transaction, (p1_new_items, p2_new_items)))
|
||||||
})
|
}).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn take_meseta<'a, EG> (
|
pub async fn take_meseta<'a, EG> (
|
||||||
item_state: &'a mut ItemState,
|
item_state: &'a mut ItemState,
|
||||||
entity_gateway: &'a mut EG,
|
entity_gateway: &mut EG,
|
||||||
character_id: &'a CharacterEntityId,
|
character_id: &CharacterEntityId,
|
||||||
meseta: Meseta)
|
meseta: Meseta)
|
||||||
-> BoxFuture<'a, Result<(), anyhow::Error>>
|
-> Result<(), anyhow::Error>
|
||||||
where
|
where
|
||||||
EG: EntityGateway + 'static,
|
EG: EntityGateway + 'static,
|
||||||
{
|
{
|
||||||
entity_gateway.with_transaction(move |transaction| async move {
|
entity_gateway.with_transaction(|transaction| async move {
|
||||||
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
||||||
let ((item_state_proxy, transaction), _) = ItemStateAction::default()
|
let ((item_state_proxy, transaction), _) = ItemStateAction::default()
|
||||||
.act(actions::take_meseta_from_inventory(*character_id, meseta.0))
|
.act(actions::take_meseta_from_inventory(*character_id, meseta.0))
|
||||||
@ -461,70 +456,43 @@ where
|
|||||||
|
|
||||||
item_state_proxy.commit().await;
|
item_state_proxy.commit().await;
|
||||||
Ok((transaction, ()))
|
Ok((transaction, ()))
|
||||||
})
|
}).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enemy_drops_item<'a, EG> (
|
pub async fn enemy_drops_item<'a, EG> (
|
||||||
item_state: &'a mut ItemState,
|
item_state: &'a mut ItemState,
|
||||||
entity_gateway: &'a mut EG,
|
entity_gateway: &mut EG,
|
||||||
character_id: CharacterEntityId,
|
character_id: CharacterEntityId,
|
||||||
room_id: RoomEntityId,
|
|
||||||
monster_type: MonsterType,
|
|
||||||
item_drop: ItemDrop)
|
item_drop: ItemDrop)
|
||||||
-> BoxFuture<'a, Result<FloorItem, anyhow::Error>>
|
-> Result<FloorItem, anyhow::Error>
|
||||||
where
|
where
|
||||||
EG: EntityGateway + 'static,
|
EG: EntityGateway + 'static,
|
||||||
{
|
{
|
||||||
entity_gateway.with_transaction(move |transaction| async move {
|
entity_gateway.with_transaction(|transaction| async move {
|
||||||
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
||||||
let ((item_state_proxy, transaction), floor_item) = ItemStateAction::default()
|
let ((item_state_proxy, transaction), floor_item) = ItemStateAction::default()
|
||||||
.act(actions::convert_item_drop_to_floor_item(item_drop))
|
.act(actions::convert_item_drop_to_floor_item(character_id, item_drop))
|
||||||
.act(actions::item_note_enemy_drop(character_id, room_id, monster_type))
|
|
||||||
.act(actions::add_item_to_local_floor(character_id))
|
.act(actions::add_item_to_local_floor(character_id))
|
||||||
.commit((item_state_proxy, transaction))
|
.commit((item_state_proxy, transaction))
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
item_state_proxy.commit().await;
|
item_state_proxy.commit().await;
|
||||||
Ok((transaction, floor_item))
|
Ok((transaction, floor_item))
|
||||||
})
|
}).await
|
||||||
}
|
|
||||||
|
|
||||||
pub fn box_drops_item<'a, EG> (
|
|
||||||
item_state: &'a mut ItemState,
|
|
||||||
entity_gateway: &'a mut EG,
|
|
||||||
character_id: CharacterEntityId,
|
|
||||||
room_id: RoomEntityId,
|
|
||||||
item_drop: ItemDrop)
|
|
||||||
-> BoxFuture<'a, Result<FloorItem, anyhow::Error>>
|
|
||||||
where
|
|
||||||
EG: EntityGateway + 'static,
|
|
||||||
{
|
|
||||||
entity_gateway.with_transaction(move |transaction| async move {
|
|
||||||
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
|
||||||
let ((item_state_proxy, transaction), floor_item) = ItemStateAction::default()
|
|
||||||
.act(actions::convert_item_drop_to_floor_item(item_drop))
|
|
||||||
.act(actions::item_note_box_drop(character_id, room_id))
|
|
||||||
.act(actions::add_item_to_local_floor(character_id))
|
|
||||||
.commit((item_state_proxy, transaction))
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
item_state_proxy.commit().await;
|
|
||||||
Ok((transaction, floor_item))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn apply_modifier<'a, EG> (
|
pub async fn apply_modifier<'a, EG> (
|
||||||
item_state: &'a mut ItemState,
|
item_state: &'a mut ItemState,
|
||||||
entity_gateway: &'a mut EG,
|
entity_gateway: &mut EG,
|
||||||
character: &'a CharacterEntity,
|
character: &CharacterEntity,
|
||||||
item_id: ClientItemId,
|
item_id: ClientItemId,
|
||||||
modifier: ItemModifier)
|
modifier: ItemModifier)
|
||||||
-> BoxFuture<'a, Result<IndividualItemDetail, anyhow::Error>>
|
-> Result<IndividualItemDetail, anyhow::Error>
|
||||||
where
|
where
|
||||||
EG: EntityGateway + 'static,
|
EG: EntityGateway + 'static,
|
||||||
{
|
{
|
||||||
entity_gateway.with_transaction(move |transaction| async move {
|
entity_gateway.with_transaction(|transaction| async move {
|
||||||
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
||||||
let ((item_state_proxy, transaction), item) = ItemStateAction::default()
|
let ((item_state_proxy, transaction), item) = ItemStateAction::default()
|
||||||
.act(actions::take_item_from_inventory(character.id, item_id, 1))
|
.act(actions::take_item_from_inventory(character.id, item_id, 1))
|
||||||
@ -536,29 +504,5 @@ where
|
|||||||
|
|
||||||
item_state_proxy.commit().await;
|
item_state_proxy.commit().await;
|
||||||
Ok((transaction, item))
|
Ok((transaction, item))
|
||||||
})
|
}).await
|
||||||
}
|
|
||||||
|
|
||||||
pub fn floor_item_limit_reached<'a, EG> (
|
|
||||||
item_state: &'a ItemState,
|
|
||||||
entity_gateway: &'a mut EG,
|
|
||||||
character: &'a CharacterEntity,
|
|
||||||
item_id: &'a ClientItemId,
|
|
||||||
map_area: MapArea
|
|
||||||
) -> BoxFuture<'a, Result<(), anyhow::Error>>
|
|
||||||
where
|
|
||||||
EG: EntityGateway + 'static,
|
|
||||||
EG::Transaction<'a>: Clone,
|
|
||||||
{
|
|
||||||
entity_gateway.with_transaction(move |transaction| async move {
|
|
||||||
let item_state_proxy = ItemStateProxy::new(item_state.clone());
|
|
||||||
let((item_state_proxy, transaction), result) = ItemStateAction::default()
|
|
||||||
.act(actions::take_item_from_floor(character.id, *item_id))
|
|
||||||
.act(actions::delete_item_from_floor(map_area))
|
|
||||||
.commit((item_state_proxy, transaction))
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
item_state_proxy.commit().await;
|
|
||||||
Ok((transaction, result))
|
|
||||||
})
|
|
||||||
}
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user