smol bot
-rw-r--r--src/bot/logic.rs2
-rw-r--r--src/bot/map.rs30
-rw-r--r--src/bot/mod.rs234
-rw-r--r--src/bot/repos.rs123
-rw-r--r--src/bot/schematic.rs20
-rw-r--r--src/expose.rs4
6 files changed, 255 insertions, 158 deletions
diff --git a/src/bot/logic.rs b/src/bot/logic.rs
index ad8880a..f0257c2 100644
--- a/src/bot/logic.rs
+++ b/src/bot/logic.rs
@@ -1,6 +1,6 @@
use super::{Context, Result};
use lemu::Executor;
-use poise::{serenity_prelude::*, CodeBlock, KeyValueArgs};
+use poise::{CodeBlock, KeyValueArgs, serenity_prelude::*};
#[poise::command(slash_command, rename = "eval_file", install_context = "Guild|User")]
/// Execute MLOG from a file.
diff --git a/src/bot/map.rs b/src/bot/map.rs
index f798627..99e6906 100644
--- a/src/bot/map.rs
+++ b/src/bot/map.rs
@@ -15,15 +15,13 @@ fn string((x, f): (ReadError, &str)) -> String {
format!("not a map.")
}
ReadError::NoBlockFound(b) => {
- format!("couldnt find block `{b}`. mods are not supported")
+ format!("couldnt find block `{b}`. mods are not supported")
}
ReadError::NoSuchBlock(b) => {
format!("couldnt find block at index `{b}`. mods are not supported")
}
ReadError::Version(v) => {
- format!(
- "unsupported version: `{v}`. supported versions: `7, 8`.",
- )
+ format!("unsupported version: `{v}`. supported versions: `7, 8`.",)
}
ReadError::Read(r) => {
format!("failed to read map. error: `{r}`. originates from `{f}`")
@@ -71,11 +69,13 @@ pub async fn reply(
let (a, e) = match embed(m, deser_took).await {
Ok(x) => x,
Err(e) => {
- BENDN.send_files(
- &c,
- [CreateAttachment::bytes(b, "map.msav")],
- CreateMessage::new().content(format!("<@696196765564534825> failure: {e}")),
- );
+ BENDN
+ .send_files(
+ &c,
+ [CreateAttachment::bytes(b, "map.msav")],
+ CreateMessage::new().content(format!("<@696196765564534825> failure: {e}")),
+ )
+ .await?;
return Ok(ControlFlow::Break(CreateReply::default().content(
"there was a problem. i have notified bendn about this issue.",
)));
@@ -213,11 +213,13 @@ pub async fn render_message(c: super::Context<'_>, m: Message) -> Result<()> {
let (png, embed) = match embed(m, deser_took).await {
Ok(x) => x,
Err(e) => {
- BENDN.send_files(
- &c,
- [CreateAttachment::bytes(b, "map.msav")],
- CreateMessage::new().content(format!("<@696196765564534825> failure: {e}")),
- );
+ BENDN
+ .send_files(
+ &c,
+ [CreateAttachment::bytes(b, "map.msav")],
+ CreateMessage::new().content(format!("<@696196765564534825> failure: {e}")),
+ )
+ .await?;
c.say("there was a problem. i have notified bendn about this issue.")
.await?;
return Ok(());
diff --git a/src/bot/mod.rs b/src/bot/mod.rs
index 24f0cc0..548b674 100644
--- a/src/bot/mod.rs
+++ b/src/bot/mod.rs
@@ -1,3 +1,5 @@
+mod data;
+mod db;
mod logic;
mod map;
pub mod ownership;
@@ -5,19 +7,16 @@ pub mod repos;
mod schematic;
pub mod search;
mod sorter;
-mod db;
-mod data;
use charts_rs::{Series, THEME_GRAFANA};
pub use data::log;
-
use crate::emoji;
use anyhow::Result;
use dashmap::DashMap;
-use mindus::data::DataWrite;
use mindus::Serializable;
-use poise::{serenity_prelude::*, CreateReply};
-use repos::{Repo, FORUMS, SPECIAL, THREADED};
+use mindus::data::DataWrite;
+use poise::{CreateReply, serenity_prelude::*};
+use repos::{FORUMS, Repo, SPECIAL, THREADED};
use serenity::futures::StreamExt;
use std::collections::{HashMap, HashSet};
use std::fmt::Write;
@@ -134,12 +133,20 @@ pub async fn scour(
match ty {
Type::Basic(tg) => {
let mut msgs = ch.messages_iter(c).boxed();
- let tags = tags(tg);
while let Some(msg) = msgs.next().await {
let Ok(msg) = msg else {
continue;
};
if let Ok(Some(mut x)) = schematic::from((&msg.content, &msg.attachments)).await {
+ use emoji::to_mindustry::named::*;
+ let tags = if tg == &["find unit factory"] {
+ tags(&[x.block_iter().find_map(|x| match x.1.block.name() {
+ "air-factory" => Some(AIR_FACTORY),
+ "ground-factory" => Some(GROUND_FACTORY),
+ "naval-factory" => Some(NAVAL_FACTORY),
+ _ => None,
+ }).unwrap_or(AIR_FACTORY)])
+ } else { tags(tg) };
x.schem.tags.insert("labels".into(), tags.clone());
let who = msg.author_nick(c).await.unwrap_or(msg.author.name.clone());
ownership::get(repo)
@@ -167,21 +174,35 @@ pub async fn scour(
Ok(())
}
-async fn del(c: &serenity::prelude::Context,& Ch{ d:dir, repo: git, ..}: &Ch, deleted_message_id: u64) {
+async fn del(
+ c: &serenity::prelude::Context,
+ &Ch {
+ d: dir, repo: git, ..
+ }: &Ch,
+ deleted_message_id: u64,
+) {
use crate::emoji::named::*;
- if let Ok(s) = git.schem(dir, deleted_message_id.into()){
+ if let Ok(s) = git.schem(dir, deleted_message_id.into()) {
let own = git.own().await.erase(deleted_message_id).unwrap();
git.remove(dir, deleted_message_id.into());
git.commit("plent", &format!("remove {deleted_message_id:x}"));
git.push();
if git == &repos::DESIGN_IT && !cfg!(debug_assertions) {
- send(c,|x| x
- .username("plent")
- .embed(CreateEmbed::new().color(RM)
- .description(format!("{CANCEL} remove {} (added by {own}) (`{:x}.msch`)", emoji::mindustry::to_discord(&strip_colors(s.tags.get("name").unwrap())), deleted_message_id))
- .footer(CreateEmbedFooter::new("message was deleted.")
- ))
- ).await;
+ send(c, |x| {
+ x.username("plent").embed(
+ CreateEmbed::new()
+ .color(RM)
+ .description(format!(
+ "{CANCEL} remove {} (added by {own}) (`{:x}.msch`)",
+ emoji::mindustry::to_discord(&strip_colors(
+ s.tags.get("name").unwrap()
+ )),
+ deleted_message_id
+ ))
+ .footer(CreateEmbedFooter::new("message was deleted.")),
+ )
+ })
+ .await;
};
}
}
@@ -189,9 +210,10 @@ async fn del(c: &serenity::prelude::Context,& Ch{ d:dir, repo: git, ..}: &Ch, de
static HOOK: OnceLock<Webhook> = OnceLock::new();
pub async fn hookup(c: &impl AsRef<Http>) {
- let v = Webhook::from_url(c,
+ let v = Webhook::from_url(
+ c,
&std::env::var("WEBHOOK")
- .unwrap_or_else(|_| read_to_string("webhook").expect("wher webhook"))
+ .unwrap_or_else(|_| read_to_string("webhook").expect("wher webhook")),
)
.await
.unwrap();
@@ -230,9 +252,13 @@ async fn handle_message(
let (dir, l, repo) = sep(SPECIAL.get(&new_message.channel_id.get()).or(post.as_ref()));
let m = Msg {
author: who.clone(),
- locale: new_message.author.locale.clone().unwrap_or("unknown locale".to_string()),
+ locale: new_message
+ .author
+ .locale
+ .clone()
+ .unwrap_or("unknown locale".to_string()),
author_id: new_message.author.id.get(),
- guild: new_message.guild_id.map_or(0,Into::into),
+ guild: new_message.guild_id.map_or(0, Into::into),
avatar: new_message.author.face(),
attachments: new_message.attachments.clone(),
content: new_message.content.clone(),
@@ -510,6 +536,7 @@ impl Bot {
925674713429184564.into(),
)
.await?;
+ poise::builtins::register_in_guild(ctx, &[scour()], 1388427745066750045.into()).await?;
println!("registered");
let tracker = Arc::new(DashMap::new());
let tc = Arc::clone(&tracker);
@@ -869,10 +896,10 @@ pub fn png(p: fimg::Image<Vec<u8>, 3>) -> Vec<u8> {
)]
/// Pong!
pub async fn ping(c: Context<'_>) -> Result<()> {
- // let p = Timestamp::now()
- // .signed_duration_since(*c.created_at())
- // .to_std()?
- // .as_millis() as _;
+ // let p = Timestamp::now()
+ // .signed_duration_since(*c.created_at())
+ // .to_std()?
+ // .as_millis() as _;
log(&c);
use emoji::named::*;
let m = memory_stats::memory_stats().unwrap().physical_mem as f32 / (1 << 20) as f32;
@@ -906,19 +933,13 @@ pub async fn ping(c: Context<'_>) -> Result<()> {
/// Renders base64 schematic.
pub async fn render(c: Context<'_>, #[description = "schematic, base64"] s: String) -> Result<()> {
log(&c);
- poise::send_reply(c,
- match schematic::from_b64(&s) {
- Ok(s) =>
- schematic::reply(
- s,
- &c.author().name,
- &c.author().face(),
- )
- .await?,
- Err(e) =>
- CreateReply::default()
- .content(format!("schem broken / not schem: {e}")),
- })
+ poise::send_reply(
+ c,
+ match schematic::from_b64(&s) {
+ Ok(s) => schematic::reply(s, &c.author().name, &c.author().face()).await?,
+ Err(e) => CreateReply::default().content(format!("schem broken / not schem: {e}")),
+ },
+ )
.await?;
Ok(())
}
@@ -940,7 +961,7 @@ pub async fn render_file(
match map::reply(c, &s).await? {
ControlFlow::Break(x) => return Ok(drop(poise::send_reply(c, x).await?)),
ControlFlow::Continue(e) if e != "not a map." => {
- return Ok(drop(poise::say_reply(c, e).await?))
+ return Ok(drop(poise::say_reply(c, e).await?));
}
ControlFlow::Continue(_) => (),
};
@@ -955,12 +976,7 @@ pub async fn render_file(
};
poise::send_reply(
c,
- schematic::reply(
- s,
- &c.author().name,
- &c.author().face(),
- )
- .await?,
+ schematic::reply(s, &c.author().name, &c.author().face()).await?,
)
.await?;
Ok(())
@@ -968,40 +984,52 @@ pub async fn render_file(
#[poise::command(slash_command)]
/// Rename a schematic.
-async fn rename_file(c: Context<'_>, #[description = "schematic, msch"] s: Attachment, #[description = "new name"] name:String) -> Result<()> {
+async fn rename_file(
+ c: Context<'_>,
+ #[description = "schematic, msch"] s: Attachment,
+ #[description = "new name"] name: String,
+) -> Result<()> {
log(&c);
- let Some(schematic::Schem{schem: mut s}) = schematic::from_attachments(std::slice::from_ref(&s)).await? else {
+ let Some(schematic::Schem { schem: mut s }) =
+ schematic::from_attachments(std::slice::from_ref(&s)).await?
+ else {
c.reply("no schem!").await?;
return Ok(());
};
s.tags.insert("name".to_string(), name);
- let mut o= DataWrite::default();
+ let mut o = DataWrite::default();
s.serialize(&mut o)?;
- poise::send_reply(c, CreateReply::default().attachment(
- CreateAttachment::bytes(o.consume(),"out.msch")
- )).await?;
+ poise::send_reply(
+ c,
+ CreateReply::default().attachment(CreateAttachment::bytes(o.consume(), "out.msch")),
+ )
+ .await?;
Ok(())
}
-
#[poise::command(slash_command)]
/// Rename a schematic.
-async fn rename(c: Context<'_>, #[description = "schematic, base64"] s: String, #[description = "new name"] name:String) -> Result<()> {
- log(&c);let Ok(schematic::Schem{schem: mut s}) = schematic::from_b64(&*s) else {
+async fn rename(
+ c: Context<'_>,
+ #[description = "schematic, base64"] s: String,
+ #[description = "new name"] name: String,
+) -> Result<()> {
+ log(&c);
+ let Ok(schematic::Schem { schem: mut s }) = schematic::from_b64(&*s) else {
c.reply("no schem!").await?;
return Ok(());
};
s.tags.insert("name".to_string(), name);
- let mut o= DataWrite::default();
+ let mut o = DataWrite::default();
s.serialize(&mut o)?;
- poise::send_reply(c, CreateReply::default().attachment(
- CreateAttachment::bytes(o.consume(),"out.msch")
- )).await?;
+ poise::send_reply(
+ c,
+ CreateReply::default().attachment(CreateAttachment::bytes(o.consume(), "out.msch")),
+ )
+ .await?;
Ok(())
}
-
-
#[poise::command(
context_menu_command = "Render schematic",
install_context = "User",
@@ -1009,25 +1037,25 @@ async fn rename(c: Context<'_>, #[description = "schematic, base64"] s: String,
)]
/// Renders schematic inside a message.
pub async fn render_message(c: Context<'_>, m: Message) -> Result<()> {
- log(&c);poise::send_reply(
- c, match schematic::from((&m.content, &m.attachments)).await {
- Ok(Some(s)) =>
- schematic::reply(
- s,
- &m.author_nick(c)
- .await
- .unwrap_or_else(|| m.author.name.clone()),
- &m.author.face(),
- )
- .await?,
- Err(e) =>
- CreateReply::default()
- .content(format!("schematic error {e}")),
- Ok(None) =>
- CreateReply::default()
+ log(&c);
+ poise::send_reply(
+ c,
+ match schematic::from((&m.content, &m.attachments)).await {
+ Ok(Some(s)) => {
+ schematic::reply(
+ s,
+ &m.author_nick(c)
+ .await
+ .unwrap_or_else(|| m.author.name.clone()),
+ &m.author.face(),
+ )
+ .await?
+ }
+ Err(e) => CreateReply::default().content(format!("schematic error {e}")),
+ Ok(None) => CreateReply::default()
.content("no schem found")
- .ephemeral(true)
- }
+ .ephemeral(true),
+ },
)
.await?;
Ok(())
@@ -1035,12 +1063,13 @@ pub async fn render_message(c: Context<'_>, m: Message) -> Result<()> {
#[poise::command(
slash_command,
- install_context = "Guild",
+ install_context = "Guild|User",
interaction_context = "Guild|PrivateChannel"
)]
/// Instructions on adding a schematic repository to YOUR server!
pub async fn schembrowser_instructions(c: Context<'_>) -> Result<()> {
- log(&c);poise::send_reply(
+ log(&c);
+ poise::send_reply(
c,
poise::CreateReply::default()
.content(include_str!("repo.md"))
@@ -1050,12 +1079,7 @@ pub async fn schembrowser_instructions(c: Context<'_>) -> Result<()> {
Ok(())
}
-
-#[poise::command(
- slash_command,
- install_context = "Guild",
- interaction_context = "Guild|PrivateChannel"
-)]
+#[poise::command(slash_command)]
/// Statistics
#[implicit_fn::implicit_fn]
pub async fn stats(c: Context<'_>) -> Result<()> {
@@ -1063,25 +1087,41 @@ pub async fn stats(c: Context<'_>) -> Result<()> {
let mut schem_calls = 0;
let mut map_calls = 0;
let mut eval_calls = 0;
- for x in std::fs::read_to_string("data").unwrap().lines().map(serde_json::from_str::<serde_json::Value>).filter_map(Result::ok) {
- *guilds.entry(x.get("guild").unwrap().as_u64().unwrap()).or_default() += 1;
+ for x in std::fs::read_to_string("data")
+ .unwrap()
+ .lines()
+ .map(serde_json::from_str::<serde_json::Value>)
+ .filter_map(Result::ok)
+ {
+ *guilds
+ .entry(x.get("guild").unwrap().as_u64().unwrap())
+ .or_default() += 1;
let x = x.get("cname").unwrap().as_str().unwrap();
- if x.contains("schematic"){
- schem_calls+=1;
+ if x.contains("schematic") {
+ schem_calls += 1;
}
if x.contains("map") {
- map_calls +=1;
+ map_calls += 1;
}
- if x.contains("eval") {
- eval_calls+=1;
+ if x.contains("eval") {
+ eval_calls += 1;
}
}
use futures::stream;
let mut x = stream::iter(guilds.into_iter().filter(_.0 != 0).filter(_.1 > 25))
- .map(async |(k,v)| {GuildId::new(k).to_partial_guild(c.http()).await.map(|x| (x.name, v)).unwrap_or(("DM".to_string(), v))})
- .buffer_unordered(16).collect::<Vec<_>>().await.into_iter()
- .map(|(a,b)| Series::new(a, vec![b as f32]))
+ .map(async |(k, v)| {
+ GuildId::new(k)
+ .to_partial_guild(c.http())
+ .await
+ .map(|x| (x.name, v))
+ .unwrap_or(("DM".to_string(), v))
+ })
+ .buffer_unordered(16)
+ .collect::<Vec<_>>()
+ .await
+ .into_iter()
+ .map(|(a, b)| Series::new(a, vec![b as f32]))
.collect::<Vec<_>>();
x.sort_by_key(|x| x.data[0] as u64);
@@ -1095,6 +1135,6 @@ pub async fn stats(c: Context<'_>) -> Result<()> {
use emoji::named::*;
let x = charts_rs::svg_to_webp(&ch.svg().unwrap()).unwrap();
- poise::send_reply(c, poise::CreateReply::default().attachment(CreateAttachment::bytes(x, "chart.webp")).content(format!("{EDIT} total schematics rendered: {schem_calls}\n{MAP} total maps rendered: {map_calls}\n{WORLD_PROCESSOR} eval calls: {eval_calls}"))).await?;
+ poise::send_reply(c, poise::CreateReply::default().attachment(CreateAttachment::bytes(x, "chart.webp")).content(format!("{EDIT} total schematics rendered: {schem_calls}\n{MAP} total maps rendered: {map_calls}\n{WORLD_PROCESSOR} eval calls: {eval_calls}"))).await?;
Ok(())
-} \ No newline at end of file
+}
diff --git a/src/bot/repos.rs b/src/bot/repos.rs
index 4e27c24..cb4d595 100644
--- a/src/bot/repos.rs
+++ b/src/bot/repos.rs
@@ -67,48 +67,56 @@ impl Repo {
}
pub fn remove(&self, dir: &str, x: MessageId) {
- assert!(std::process::Command::new("git")
- .current_dir(self.repopath())
- .arg("rm")
- .arg("-q")
- .arg("-f")
- .arg(self.gpath(dir, x))
- .status()
- .unwrap()
- .success());
+ assert!(
+ std::process::Command::new("git")
+ .current_dir(self.repopath())
+ .arg("rm")
+ .arg("-q")
+ .arg("-f")
+ .arg(self.gpath(dir, x))
+ .status()
+ .unwrap()
+ .success()
+ );
}
pub fn pull(&self) {
- assert!(std::process::Command::new("git")
- .current_dir(self.repopath())
- .arg("pull")
- .arg("-q")
- .status()
- .unwrap()
- .success());
+ assert!(
+ std::process::Command::new("git")
+ .current_dir(self.repopath())
+ .arg("pull")
+ .arg("-q")
+ .status()
+ .unwrap()
+ .success()
+ );
}
pub fn commit(&self, by: &str, msg: &str) {
- assert!(std::process::Command::new("git")
- .current_dir(self.repopath())
- .args(["commit", "--no-gpg-sign", "-q", "--author"])
- .arg(format!("{by} <@designit>"))
- .arg("-m")
- .arg(msg)
- .status()
- .unwrap()
- .success());
+ assert!(
+ std::process::Command::new("git")
+ .current_dir(self.repopath())
+ .args(["commit", "--no-gpg-sign", "-q", "--author"])
+ .arg(format!("{by} <@designit>"))
+ .arg("-m")
+ .arg(msg)
+ .status()
+ .unwrap()
+ .success()
+ );
}
pub fn push(&self) {
#[cfg(not(debug_assertions))]
- assert!(std::process::Command::new("git")
- .current_dir(self.repopath())
- .arg("push")
- .arg("-q")
- .status()
- .unwrap()
- .success())
+ assert!(
+ std::process::Command::new("git")
+ .current_dir(self.repopath())
+ .arg("push")
+ .arg("-q")
+ .status()
+ .unwrap()
+ .success()
+ )
}
pub fn write(&self, dir: &str, x: MessageId, s: Schem) {
@@ -120,13 +128,15 @@ impl Repo {
}
pub fn add(&self) {
- assert!(std::process::Command::new("git")
- .current_dir(self.repopath())
- .arg("add")
- .arg(".")
- .status()
- .unwrap()
- .success());
+ assert!(
+ std::process::Command::new("git")
+ .current_dir(self.repopath())
+ .arg("add")
+ .arg(".")
+ .status()
+ .unwrap()
+ .success()
+ );
}
}
@@ -197,6 +207,11 @@ repos! {
chief: 705503407179431937,
deny_emoji: 1192388789952319499u64,
},
+ EVICT => {
+ admins: &[person!(&1394078459940175963), person!(&1389145164299243520)],
+ chief: 954347786193747968,
+ deny_emoji: 1395478597451518085u64,
+ }
}
decl! {
@@ -271,6 +286,34 @@ forum 1297463616035098654u64 => "e-units"
ACP => [
1276759410722738186u64 => "schems": ["plague"]
];
+EVICT => [
+1394340637758722048u64 => "t1" : ["find unit factory"],
+1394340696227319808u64 => "t2" : [ADDITIVE_RECONSTRUCTOR],
+1394340759297065252u64 => "t3" : [MULTIPLICATIVE_RECONSTRUCTOR],
+1394340939685953656u64 => "t4" : [EXPONENTIAL_RECONSTRUCTOR],
+1394340961550729237u64 => "t5" : [TETRATIVE_RECONSTRUCTOR],
+1394418354634362910u64 => "combustion-gen" : [COMBUSTION_GENERATOR],
+1394418605461999769u64 => "differential-gen" : [DIFFERENTIAL_GENERATOR],
+1394418707257626795u64 => "impact-reactor" : [IMPACT_REACTOR],
+1394418470430707712u64 => "steam-gen" : [STEAM_GENERATOR],
+1394418672755282040u64 => "thorium-reactor" : [THORIUM_REACTOR],
+1394412929587347556u64 => "coal" : [COAL],
+1394081205024063529u64 => "graphite" : [GRAPHITE],
+1394081280978583624u64 => "meta" : [METAGLASS],
+1394081566950424577u64 => "phase" : [PHASEFABRIC],
+1394081445781176493u64 => "plast" : [PLASTANIUM],
+1394341640105103400u64 => "resource-mix" : [ROUTER],
+1394081152611913918u64 => "silicon" : [SILICON],
+1394081607991820368u64 => "surge" : [SURGEALLOY],
+1394342304021741672u64 => "miners" : [BLAST_DRILL],
+1394342482027745351u64 => "scrap-schematics" : [SCRAP],
+1394335945074933901u64 => "cyclone" : [CYCLONE],
+1394083007245320244u64 => "fuse" : [FUSE],
+1394083227001557034u64 => "hail-scorch" : [HAIL, SCORCH],
+1394082982733680722u64 => "scatter": [SCATTER],
+1394335981691211806u64 => "swarmer": [SWARMER],
+1394414493957881906u64 => "miscellaneous" : [NEOPLASM]
+ ];
}
macro_rules! chief {
@@ -279,7 +322,7 @@ macro_rules! chief {
.get(&$c.channel_id().get())
.ok_or(anyhow::anyhow!("not repo"))?
.repo;
- if repo.chief != $c.author().id.get() {
+ if repo.chief != $c.author().id.get() && $c.author().id.get() != OWNER {
poise::send_reply(
$c,
poise::CreateReply::default()
diff --git a/src/bot/schematic.rs b/src/bot/schematic.rs
index 9964943..736af7e 100644
--- a/src/bot/schematic.rs
+++ b/src/bot/schematic.rs
@@ -2,16 +2,16 @@ use crate::emoji;
use anyhow::Result;
use base64::Engine;
use logos::Logos;
-use mindus::data::schematic::R64Error;
use mindus::data::DataRead;
+use mindus::data::schematic::R64Error;
use mindus::*;
-use poise::{serenity_prelude::*, CreateReply};
+use poise::{CreateReply, serenity_prelude::*};
use regex::Regex;
use std::ops::ControlFlow;
use std::sync::LazyLock;
use std::{fmt::Write, ops::Deref};
-use super::{strip_colors, Msg, SUCCESS};
+use super::{Msg, SUCCESS, strip_colors};
static RE: LazyLock<Regex> = LazyLock::new(|| {
Regex::new(r"(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?").unwrap()
@@ -153,7 +153,19 @@ pub async fn with(
"guild": m.guild,
"channel": m.channel.get(),
}});
- if let Some(x) = labels {
+ if let Some(mut x) = labels {
+ if x.contains("find unit factory") {
+ use emoji::to_mindustry::named::*;
+ x = super::tags(&[v
+ .block_iter()
+ .find_map(|x| match x.1.block.name() {
+ "air-factory" => Some(AIR_FACTORY),
+ "ground-factory" => Some(GROUND_FACTORY),
+ "naval-factory" => Some(NAVAL_FACTORY),
+ _ => None,
+ })
+ .unwrap_or(AIR_FACTORY)]);
+ }
v.schem.tags.insert("labels".into(), x);
};
return Ok(ControlFlow::Break(send(m, c, v).await?));
diff --git a/src/expose.rs b/src/expose.rs
index 812629b..677cdba 100644
--- a/src/expose.rs
+++ b/src/expose.rs
@@ -1,9 +1,9 @@
use axum::{
+ Router, Server as AxumServer,
extract::Path,
- http::{header::*, StatusCode},
+ http::{StatusCode, header::*},
response::{AppendHeaders, Html},
routing::get,
- Router, Server as AxumServer,
};
use std::{net::SocketAddr, sync::LazyLock, time::SystemTime};