use yog_registry::ItemDef;
#[derive(Debug, Clone)]
pub struct BookMacro(pub String, pub String);
#[derive(Debug, Clone)]
pub enum BookPage {
Text {
text: String,
},
Spotlight {
item: ItemDef,
title: Option<String>,
text: Option<String>,
},
Crafting {
recipe_id: String,
text: Option<String>,
},
Smelting {
recipe_id: String,
text: Option<String>,
},
Image {
texture: String,
title: Option<String>,
text: Option<String>,
border: bool,
},
Entity {
entity_type: String,
name: Option<String>,
text: Option<String>,
},
Relations {
entries: Vec<String>,
text: Option<String>,
},
Empty,
Pattern {
op_id: String,
anchor: String,
input: String,
output: String,
text: String,
},
}
#[derive(Debug, Clone)]
pub struct BookCategory {
pub id: String,
pub name: String,
pub description: Option<String>,
pub icon: Option<String>,
pub sortnum: i32,
}
#[derive(Debug, Clone, Default)]
pub struct BookEntry {
pub id: String,
pub name: String,
pub category: String,
pub pages: Vec<BookPage>,
pub icon: Option<String>,
pub secret: bool,
pub priority: i32,
pub read_by_default: bool,
pub advancement: Option<String>,
}
#[derive(Debug, Clone)]
pub struct Book {
pub id: String,
pub name: String,
pub nameplate_color: String,
pub landing_text: String,
pub author: Option<String>,
pub book_texture: String,
pub filler_texture: String,
pub model: String,
pub categories: Vec<BookCategory>,
pub entries: Vec<BookEntry>,
pub macros: Vec<BookMacro>,
pub use_resource_pack: bool,
pub show_progress: bool,
pub i18n: bool,
pub creative_tab: Option<String>,
}
impl Book {
pub fn new(id: impl Into<String>, name: impl Into<String>) -> Self {
Self {
id: id.into(),
name: name.into(),
nameplate_color: "000000".into(),
landing_text: String::new(),
author: None,
book_texture: "yog:textures/gui/book.png".into(),
filler_texture: "yog:textures/gui/book_filler.png".into(),
model: "minecraft:book".into(),
categories: Vec::new(),
entries: Vec::new(),
macros: Vec::new(),
use_resource_pack: false,
show_progress: true,
i18n: false,
creative_tab: None,
}
}
pub fn author(mut self, author: impl Into<String>) -> Self {
self.author = Some(author.into());
self
}
pub fn book_texture(mut self, tex: impl Into<String>) -> Self {
self.book_texture = tex.into();
self
}
pub fn filler_texture(mut self, tex: impl Into<String>) -> Self {
self.filler_texture = tex.into();
self
}
pub fn nameplate(mut self, color: impl Into<String>) -> Self {
self.nameplate_color = color.into();
self
}
pub fn landing_text(mut self, text: impl Into<String>) -> Self {
self.landing_text = text.into();
self
}
pub fn model(mut self, model: impl Into<String>) -> Self {
self.model = model.into();
self
}
pub fn creative_tab(mut self, tab: impl Into<String>) -> Self {
self.creative_tab = Some(tab.into());
self
}
pub fn show_progress(mut self, show: bool) -> Self {
self.show_progress = show;
self
}
pub fn i18n(mut self, val: bool) -> Self {
self.i18n = val;
self
}
pub fn use_resource_pack(mut self, val: bool) -> Self {
self.use_resource_pack = val;
self
}
pub fn add_macro(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
self.macros.push(BookMacro(key.into(), value.into()));
self
}
pub fn add_category(mut self, category: BookCategory) -> Self {
self.categories.push(category);
self
}
pub fn add_entry(mut self, entry: BookEntry) -> Self {
self.entries.push(entry);
self
}
}
impl Default for Book {
fn default() -> Self {
Self::new("yog:default", "Unknown Book")
}
}
#[derive(Debug, Default)]
pub struct BookRegistry {
books: std::collections::HashMap<String, Book>,
}
impl BookRegistry {
pub fn register(&mut self, book: Book) {
self.books.insert(book.id.clone(), book);
}
pub fn get(&self, id: &str) -> Option<&Book> {
self.books.get(id)
}
pub fn all(&self) -> impl Iterator<Item = &Book> {
self.books.values()
}
}
pub fn text_page(text: impl Into<String>) -> BookPage {
BookPage::Text { text: text.into() }
}
pub fn spotlight_page(item: ItemDef) -> BookPage {
BookPage::Spotlight { item, title: None, text: None }
}
pub fn crafting_page(recipe_id: impl Into<String>) -> BookPage {
BookPage::Crafting { recipe_id: recipe_id.into(), text: None }
}
pub fn crafting_page_with_text(recipe_id: impl Into<String>, text: impl Into<String>) -> BookPage {
BookPage::Crafting { recipe_id: recipe_id.into(), text: Some(text.into()) }
}
pub fn smelting_page(recipe_id: impl Into<String>) -> BookPage {
BookPage::Smelting { recipe_id: recipe_id.into(), text: None }
}
pub fn image_page(texture: impl Into<String>) -> BookPage {
BookPage::Image { texture: texture.into(), title: None, text: None, border: true }
}
pub fn entity_page(entity_type: impl Into<String>) -> BookPage {
BookPage::Entity { entity_type: entity_type.into(), name: None, text: None }
}
pub fn relations_page(entries: Vec<String>) -> BookPage {
BookPage::Relations { entries, text: None }
}
pub fn pattern_page(op_id: impl Into<String>, anchor: impl Into<String>, input: impl Into<String>, output: impl Into<String>, text: impl Into<String>) -> BookPage {
BookPage::Pattern {
op_id: op_id.into(),
anchor: anchor.into(),
input: input.into(),
output: output.into(),
text: text.into(),
}
}
fn esc(s: &str) -> String {
s.replace('\\', "\\\\").replace('"', "\\\"")
}
impl BookPage {
pub fn to_json(&self) -> String {
match self {
Self::Text { text } =>
format!(r#"{{"type":"text","text":"{}"}}"#, esc(text)),
Self::Spotlight { item, title, text } => {
let t = title.as_deref().map(|s| format!(r#","title":"{}""#, esc(s))).unwrap_or_default();
let tx = text.as_deref().map(|s| format!(r#","text":"{}""#, esc(s))).unwrap_or_default();
format!(r#"{{"type":"spotlight","item":"{id}"{t}{tx}}}"#, id = esc(&item.id))
}
Self::Crafting { recipe_id, text } => {
let tx = text.as_deref().map(|s| format!(r#","text":"{}""#, esc(s))).unwrap_or_default();
format!(r#"{{"type":"crafting","recipe":"{}"{}}}"#, esc(recipe_id), tx)
}
Self::Smelting { recipe_id, text } => {
let tx = text.as_deref().map(|s| format!(r#","text":"{}""#, esc(s))).unwrap_or_default();
format!(r#"{{"type":"smelting","recipe":"{}"{}}}"#, esc(recipe_id), tx)
}
Self::Image { texture, title, text, border } => {
let t = title.as_deref().map(|s| format!(r#","title":"{}""#, esc(s))).unwrap_or_default();
let tx = text.as_deref().map(|s| format!(r#","text":"{}""#, esc(s))).unwrap_or_default();
format!(r#"{{"type":"image","texture":"{}","border":{}{}{}}}"#,
esc(texture), border, t, tx)
}
Self::Entity { entity_type, name, text } => {
let n = name.as_deref().map(|s| format!(r#","name":"{}""#, esc(s))).unwrap_or_default();
let tx = text.as_deref().map(|s| format!(r#","text":"{}""#, esc(s))).unwrap_or_default();
format!(r#"{{"type":"entity","entity":"{}"{}{}}}"#, esc(entity_type), n, tx)
}
Self::Relations { entries, text } => {
let e: String = entries.iter().map(|s| format!(r#""{}""#, esc(s))).collect::<Vec<_>>().join(",");
let tx = text.as_deref().map(|s| format!(r#","text":"{}""#, esc(s))).unwrap_or_default();
format!(r#"{{"type":"relations","entries":[{}]{}}}"#, e, tx)
}
Self::Empty => r#"{"type":"empty"}"#.to_string(),
Self::Pattern { op_id, anchor, input, output, text } =>
format!(r#"{{"type":"pattern","op_id":"{}","anchor":"{}","input":"{}","output":"{}","text":"{}"}}"#,
esc(op_id), esc(anchor), esc(input), esc(output), esc(text)),
}
}
}
impl BookEntry {
pub fn to_json(&self) -> String {
let pages: String = self.pages.iter().map(|p| p.to_json()).collect::<Vec<_>>().join(",");
let icon = self.icon.as_deref().map(|s| format!(r#","icon":"{}""#, esc(s))).unwrap_or_default();
let adv = self.advancement.as_deref().map(|s| format!(r#","advancement":"{}""#, esc(s))).unwrap_or_default();
format!(
r#"{{"id":"{}","name":"{}","category":"{}","pages":[{}],"secret":{},"priority":{},"read_by_default":{}{}{}}}"#,
esc(&self.id), esc(&self.name), esc(&self.category), pages,
self.secret, self.priority, self.read_by_default, icon, adv
)
}
}
impl BookCategory {
pub fn to_json(&self) -> String {
let desc = self.description.as_deref().map(|s| format!(r#","description":"{}""#, esc(s))).unwrap_or_default();
let icon = self.icon.as_deref().map(|s| format!(r#","icon":"{}""#, esc(s))).unwrap_or_default();
format!(
r#"{{"id":"{}","name":"{}","sortnum":{}{}{}}}"#,
esc(&self.id), esc(&self.name), self.sortnum, desc, icon
)
}
}
impl Book {
pub fn to_json(&self) -> String {
let cats: String = self.categories.iter().map(|c| c.to_json()).collect::<Vec<_>>().join(",");
let entries: String = self.entries.iter().map(|e| e.to_json()).collect::<Vec<_>>().join(",");
let author = self.author.as_deref().map(|s| format!(r#","author":"{}""#, esc(s))).unwrap_or_default();
let tab = self.creative_tab.as_deref().map(|s| format!(r#","creative_tab":"{}""#, esc(s))).unwrap_or_default();
format!(
r#"{{"id":"{}","name":"{}","nameplate_color":"{}","landing_text":"{}","book_texture":"{}","filler_texture":"{}","model":"{}","show_progress":{},"i18n":{},"use_resource_pack":{},"categories":[{}],"entries":[{}]{}{}}}"#,
esc(&self.id), esc(&self.name), esc(&self.nameplate_color), esc(&self.landing_text),
esc(&self.book_texture), esc(&self.filler_texture), esc(&self.model),
self.show_progress, self.i18n, self.use_resource_pack,
cats, entries, author, tab
)
}
}