1
2
Fork 0
mirror of https://github.com/mat-1/azalea.git synced 2025-08-02 14:26:04 +00:00
azalea/azalea-protocol/src/packets/game/clientbound_update_recipes_packet.rs
mat 5a9fca0ca9
Better errors (#14)
* make reading use thiserror

* finish implementing all the error things

* clippy warnings related to ok_or

* fix some errors in other places

* thiserror in more places

* don't use closures in a couple places

* errors in writing packet

* rip backtraces

* change some BufReadError::Custom to UnexpectedEnumVariant

* Errors say what packet is bad

* error on leftover data and fix

it wasn't reading the properties for gameprofile
2022-08-06 02:22:19 -05:00

219 lines
7.6 KiB
Rust

use std::io::{Read, Write};
use azalea_buf::{BufReadError, McBuf};
use azalea_core::{ResourceLocation, Slot};
use packet_macros::ClientboundGamePacket;
use azalea_buf::{McBufReadable, McBufWritable, Readable, Writable};
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
pub struct ClientboundUpdateRecipesPacket {
pub recipes: Vec<Recipe>,
}
#[derive(Clone, Debug)]
pub struct Recipe {
pub identifier: ResourceLocation,
pub data: RecipeData,
}
#[derive(Clone, Debug, McBuf)]
pub struct ShapelessRecipe {
/// Used to group similar recipes together in the recipe book.
/// Tag is present in recipe JSON
group: String,
ingredients: Vec<Ingredient>,
result: Slot,
}
#[derive(Clone, Debug)]
pub struct ShapedRecipe {
// TODO: make own McBufReadable and McBufWritable for this
width: usize,
height: usize,
group: String,
ingredients: Vec<Ingredient>,
result: Slot,
}
impl McBufWritable for ShapedRecipe {
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
buf.write_varint(self.width.try_into().unwrap())?;
buf.write_varint(self.height.try_into().unwrap())?;
buf.write_utf(&self.group)?;
for ingredient in &self.ingredients {
ingredient.write_into(buf)?;
}
self.result.write_into(buf)?;
Ok(())
}
}
impl McBufReadable for ShapedRecipe {
fn read_from(buf: &mut impl Read) -> Result<Self, BufReadError> {
let width = buf.read_varint()?.try_into().unwrap();
let height = buf.read_varint()?.try_into().unwrap();
let group = buf.read_utf()?;
let mut ingredients = Vec::with_capacity(width * height);
for _ in 0..width * height {
ingredients.push(Ingredient::read_from(buf)?);
}
let result = Slot::read_from(buf)?;
Ok(ShapedRecipe {
width,
height,
group,
ingredients,
result,
})
}
}
#[derive(Clone, Debug, McBuf)]
pub struct CookingRecipe {
group: String,
ingredient: Ingredient,
result: Slot,
experience: f32,
#[var]
cooking_time: u32,
}
#[derive(Clone, Debug, McBuf)]
pub struct StoneCuttingRecipe {
group: String,
ingredient: Ingredient,
result: Slot,
}
#[derive(Clone, Debug, McBuf)]
pub struct SmithingRecipe {
base: Ingredient,
addition: Ingredient,
result: Slot,
}
#[derive(Clone, Debug)]
pub enum RecipeData {
CraftingShapeless(ShapelessRecipe),
CraftingShaped(ShapedRecipe),
CraftingSpecialArmorDye,
CraftingSpecialBookCloning,
CraftingSpecialMapCloning,
CraftingSpecialMapExtending,
CraftingSpecialFireworkRocket,
CraftingSpecialFireworkStar,
CraftingSpecialFireworkStarFade,
CraftingSpecialRepairItem,
CraftingSpecialTippedArrow,
CraftingSpecialBannerDuplicate,
CraftingSpecialBannerAddPattern,
CraftingSpecialShieldDecoration,
CraftingSpecialShulkerBoxColoring,
CraftingSpecialSuspiciousStew,
Smelting(CookingRecipe),
Blasting(CookingRecipe),
Smoking(CookingRecipe),
CampfireCooking(CookingRecipe),
Stonecutting(StoneCuttingRecipe),
Smithing(SmithingRecipe),
}
#[derive(Clone, Debug, McBuf)]
pub struct Ingredient {
pub allowed: Vec<Slot>,
}
impl McBufWritable for Recipe {
fn write_into(&self, _buf: &mut impl Write) -> Result<(), std::io::Error> {
todo!()
}
}
impl McBufReadable for Recipe {
fn read_from(buf: &mut impl Read) -> Result<Self, BufReadError> {
let recipe_type = ResourceLocation::read_from(buf)?;
let identifier = ResourceLocation::read_from(buf)?;
// rust doesn't let us match ResourceLocation so we have to do a big
// if-else chain :(
let data = if recipe_type == ResourceLocation::new("minecraft:crafting_shapeless").unwrap()
{
RecipeData::CraftingShapeless(ShapelessRecipe::read_from(buf)?)
} else if recipe_type == ResourceLocation::new("minecraft:crafting_shaped").unwrap() {
RecipeData::CraftingShaped(ShapedRecipe::read_from(buf)?)
} else if recipe_type
== ResourceLocation::new("minecraft:crafting_special_armordye").unwrap()
{
RecipeData::CraftingSpecialArmorDye
} else if recipe_type
== ResourceLocation::new("minecraft:crafting_special_bookcloning").unwrap()
{
RecipeData::CraftingSpecialBookCloning
} else if recipe_type
== ResourceLocation::new("minecraft:crafting_special_mapcloning").unwrap()
{
RecipeData::CraftingSpecialMapCloning
} else if recipe_type
== ResourceLocation::new("minecraft:crafting_special_mapextending").unwrap()
{
RecipeData::CraftingSpecialMapExtending
} else if recipe_type
== ResourceLocation::new("minecraft:crafting_special_firework_rocket").unwrap()
{
RecipeData::CraftingSpecialFireworkRocket
} else if recipe_type
== ResourceLocation::new("minecraft:crafting_special_firework_star").unwrap()
{
RecipeData::CraftingSpecialFireworkStar
} else if recipe_type
== ResourceLocation::new("minecraft:crafting_special_firework_star_fade").unwrap()
{
RecipeData::CraftingSpecialFireworkStarFade
} else if recipe_type
== ResourceLocation::new("minecraft:crafting_special_repairitem").unwrap()
{
RecipeData::CraftingSpecialRepairItem
} else if recipe_type
== ResourceLocation::new("minecraft:crafting_special_tippedarrow").unwrap()
{
RecipeData::CraftingSpecialTippedArrow
} else if recipe_type
== ResourceLocation::new("minecraft:crafting_special_bannerduplicate").unwrap()
{
RecipeData::CraftingSpecialBannerDuplicate
} else if recipe_type
== ResourceLocation::new("minecraft:crafting_special_banneraddpattern").unwrap()
{
RecipeData::CraftingSpecialBannerAddPattern
} else if recipe_type
== ResourceLocation::new("minecraft:crafting_special_shielddecoration").unwrap()
{
RecipeData::CraftingSpecialShieldDecoration
} else if recipe_type
== ResourceLocation::new("minecraft:crafting_special_shulkerboxcoloring").unwrap()
{
RecipeData::CraftingSpecialShulkerBoxColoring
} else if recipe_type
== ResourceLocation::new("minecraft:crafting_special_suspiciousstew").unwrap()
{
RecipeData::CraftingSpecialSuspiciousStew
} else if recipe_type == ResourceLocation::new("minecraft:smelting").unwrap() {
RecipeData::Smelting(CookingRecipe::read_from(buf)?)
} else if recipe_type == ResourceLocation::new("minecraft:blasting").unwrap() {
RecipeData::Blasting(CookingRecipe::read_from(buf)?)
} else if recipe_type == ResourceLocation::new("minecraft:smoking").unwrap() {
RecipeData::Smoking(CookingRecipe::read_from(buf)?)
} else if recipe_type == ResourceLocation::new("minecraft:campfire_cooking").unwrap() {
RecipeData::CampfireCooking(CookingRecipe::read_from(buf)?)
} else if recipe_type == ResourceLocation::new("minecraft:stonecutting").unwrap() {
RecipeData::Stonecutting(StoneCuttingRecipe::read_from(buf)?)
} else if recipe_type == ResourceLocation::new("minecraft:smithing").unwrap() {
RecipeData::Smithing(SmithingRecipe::read_from(buf)?)
} else {
panic!("Unknown recipe type sent by server: {}", recipe_type);
};
let recipe = Recipe { identifier, data };
Ok(recipe)
}
}