first commit
This commit is contained in:
commit
0cb536b42b
38 changed files with 9044 additions and 0 deletions
218
src/main.rs
Normal file
218
src/main.rs
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
use crate::client::Client;
|
||||
use crate::client::ClientEvent;
|
||||
use crate::commands::Arguments;
|
||||
use crate::commands::CommandRegistry;
|
||||
use cap::Cap;
|
||||
use serde::Deserialize;
|
||||
use sqlx::postgres::PgPoolOptions;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
pub mod client;
|
||||
pub mod commands;
|
||||
pub mod log;
|
||||
pub mod midi_helper;
|
||||
|
||||
use crate::commands::*;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
#[global_allocator]
|
||||
static ALLOCATOR: Cap<std::alloc::System> = Cap::new(std::alloc::System, usize::MAX);
|
||||
|
||||
#[derive(sqlx::FromRow)]
|
||||
struct User {
|
||||
_id: String,
|
||||
balance: i32,
|
||||
items: sqlx::types::Json<Vec<String>>,
|
||||
}
|
||||
|
||||
macro_rules! register_all {
|
||||
($registry:expr, $client:expr, [ $($cmd:expr),+ $(,)? ]) => {
|
||||
$(
|
||||
$registry.register($cmd, $client.clone()).await;
|
||||
)+
|
||||
};
|
||||
}
|
||||
#[derive(Deserialize)]
|
||||
struct Configuration {
|
||||
database: DatabaseConfig,
|
||||
commands: CommandsConfig,
|
||||
client: ClientConfig,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct DatabaseConfig {
|
||||
url: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct CommandsConfig {
|
||||
prefix: String,
|
||||
name: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct ClientConfig {
|
||||
token: String,
|
||||
ws: String,
|
||||
room: String,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
rustls::crypto::CryptoProvider::install_default(rustls_rustcrypto::provider())
|
||||
.expect("install rustcrypto provider");
|
||||
|
||||
let s = tokio::fs::read_to_string("config.hocon").await?;
|
||||
let conf: Configuration = hocon::de::from_str(&s)?;
|
||||
|
||||
let (mut client, event_rx) = Client::new();
|
||||
let pool = PgPoolOptions::new()
|
||||
.max_connections(5)
|
||||
.connect(conf.database.url.as_str())
|
||||
.await?;
|
||||
let arc_pool = Arc::new(pool);
|
||||
|
||||
let midi_state = Arc::new(Mutex::new(MidiState::new()));
|
||||
|
||||
let mut registry = CommandRegistry::new();
|
||||
|
||||
register_all!(
|
||||
registry,
|
||||
client,
|
||||
[
|
||||
PlayCommand::new(midi_state.clone()),
|
||||
StopCommand::new(midi_state.clone()),
|
||||
PlaylistCommand::new(midi_state.clone()),
|
||||
QueueCommand::new(midi_state.clone()),
|
||||
SkipCommand::new(midi_state),
|
||||
LaunchCommand,
|
||||
FollowCommand::new(),
|
||||
TestCommand::new(),
|
||||
BalanceCommand::new(arc_pool.clone()),
|
||||
InventoryCommand::new(arc_pool.clone()),
|
||||
FishCommand::new(arc_pool.clone()),
|
||||
FarmCommand::new(arc_pool.clone()),
|
||||
ShopCommand::new(arc_pool.clone()),
|
||||
CoinflipCommand::new(arc_pool.clone()),
|
||||
TranslateCommand,
|
||||
AboutCommand,
|
||||
HelpCommand::new(registry.clone()),
|
||||
]
|
||||
);
|
||||
|
||||
let client_events = client.clone();
|
||||
let events_pool = arc_pool.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
while let Ok(event) = event_rx.recv_async().await {
|
||||
match event {
|
||||
ClientEvent::Connected => {
|
||||
log!(CONNECTED);
|
||||
}
|
||||
ClientEvent::Sync { e } => {
|
||||
let t = e - chrono::Utc::now().timestamp_millis();
|
||||
|
||||
let username = {
|
||||
let ram = ALLOCATOR.allocated() / 1_000_000;
|
||||
if ram != 0 {
|
||||
format!("{} 📶{} ms 🐏{} mb ", conf.commands.name, t, ram)
|
||||
} else {
|
||||
format!("{} 📶{} ms", conf.commands.name, -t)
|
||||
}
|
||||
};
|
||||
|
||||
let _ = client_events
|
||||
.userset(username.as_str().into(), "#B7410E".into())
|
||||
.await;
|
||||
}
|
||||
ClientEvent::Message { player, message } => {
|
||||
if let Some(no_prefix) = message.strip_prefix(conf.commands.prefix.as_str()) {
|
||||
let mut parts = no_prefix.split_whitespace();
|
||||
if let Some(cmd_name) = parts.next() {
|
||||
let args = Arguments::new(parts.map(|s| s.to_string()).collect());
|
||||
|
||||
let mut cmd_opt: Option<CommandArc> = None;
|
||||
for cmd in registry.values() {
|
||||
let cmd_lock = cmd.lock().await;
|
||||
if cmd_lock.name() == cmd_name
|
||||
|| cmd_lock.aliases().contains(&cmd_name)
|
||||
{
|
||||
cmd_opt = Some(cmd.clone());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(cmd) = cmd_opt {
|
||||
let mut cmd_lock = cmd.lock().await;
|
||||
let specs = cmd_lock.argument_spec();
|
||||
match crate::commands::argument::parse_arguments(specs, &args.args)
|
||||
{
|
||||
Ok(parsed_args_struct) => {
|
||||
cmd_lock
|
||||
.execute(
|
||||
client_events.clone(),
|
||||
player.clone(),
|
||||
parsed_args_struct,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
Err(e) => {
|
||||
client_events
|
||||
.message(format!("Argument error: {}", e))
|
||||
.await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if message == "!ping" {
|
||||
client_events.message("pong").await;
|
||||
}
|
||||
log!(MSG, player.name, message);
|
||||
}
|
||||
ClientEvent::PlayerJoined(player) => {
|
||||
log!(PLAYER_JOINED, player.name);
|
||||
|
||||
let user = sqlx::query_as::<_, User>("SELECT * FROM users WHERE _id = $1")
|
||||
.bind(&player._id)
|
||||
.fetch_optional(events_pool.as_ref())
|
||||
.await;
|
||||
|
||||
let user_exists = user.unwrap().is_some();
|
||||
|
||||
if !user_exists {
|
||||
let _ = sqlx::query!(
|
||||
"INSERT INTO users (_id, balance, items) VALUES ($1, $2, $3)",
|
||||
player.id,
|
||||
0,
|
||||
serde_json::json!([])
|
||||
)
|
||||
.execute(events_pool.as_ref())
|
||||
.await;
|
||||
}
|
||||
}
|
||||
ClientEvent::PlayerLeft(id) => {
|
||||
log!(PLAYER_LEFT, id);
|
||||
}
|
||||
ClientEvent::Mouse { x, y, id } => {
|
||||
let cmd_lock = registry.get("follow").unwrap();
|
||||
let mut cmd = cmd_lock.lock().await;
|
||||
cmd.event(client_events.clone(), ClientEvent::Mouse { x, y, id })
|
||||
.await;
|
||||
}
|
||||
ClientEvent::NameChanged { now: _, before: _ } => {}
|
||||
ClientEvent::ChannelInfo(channel) => {
|
||||
log!(CHANNEL_INFO, channel.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
client
|
||||
.connect(conf.client.ws, conf.client.token, conf.client.room)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue