azalea_protocol/packets/game/
c_merchant_offers.rs1use std::{
2 any::Any,
3 fmt::{self, Debug},
4 io::{self, Cursor, Write},
5 mem::ManuallyDrop,
6};
7
8use azalea_buf::{AzBuf, BufReadError};
9use azalea_inventory::{
10 DataComponentPatch, ItemStack, ItemStackData,
11 components::{self, DataComponentUnion},
12};
13use azalea_protocol_macros::ClientboundGamePacket;
14use azalea_registry::builtin::{DataComponentKind, ItemKind};
15
16#[derive(AzBuf, ClientboundGamePacket, Clone, Debug, PartialEq)]
17pub struct ClientboundMerchantOffers {
18 #[var]
19 pub container_id: i32,
20 pub offers: Vec<MerchantOffer>,
21 #[var]
22 pub villager_level: u32,
23 #[var]
24 pub villager_xp: u32,
25 pub show_progress: bool,
26 pub can_restock: bool,
27}
28
29#[derive(AzBuf, Clone, Debug, PartialEq)]
30pub struct MerchantOffer {
31 pub base_cost_a: ItemCost,
32 pub result: ItemStack,
33 pub cost_b: Option<ItemCost>,
34 pub out_of_stock: bool,
35 pub uses: i32,
36 pub max_uses: i32,
37 pub xp: i32,
38 pub special_price_diff: i32,
39 pub price_multiplier: f32,
40 pub demand: i32,
41}
42
43#[derive(AzBuf, Clone, Debug, PartialEq)]
48pub struct ItemCost {
49 pub item: ItemKind,
50 #[var]
51 pub count: i32,
52 pub components: DataComponentExactPredicate,
53}
54impl ItemCost {
55 pub fn into_item_stack(self) -> ItemStackData {
56 let mut component_patch = DataComponentPatch::default();
57 for component in self.components.expected {
58 let component = ManuallyDrop::new(component);
59 let value = unsafe { std::ptr::read(&component.value) };
63 unsafe {
64 component_patch.unchecked_insert_component(component.kind, Some(value));
65 }
66 }
67 ItemStackData {
71 kind: self.item,
72 count: self.count,
73 component_patch,
74 }
75 }
76}
77
78#[derive(AzBuf, Clone, Debug, PartialEq)]
84pub struct DataComponentExactPredicate {
85 pub expected: Vec<TypedDataComponent>,
86}
87
88pub struct TypedDataComponent {
89 kind: DataComponentKind,
90 value: DataComponentUnion,
91}
92impl TypedDataComponent {
93 pub fn kind(&self) -> &DataComponentKind {
94 &self.kind
95 }
96 pub fn value(&self) -> &DataComponentUnion {
97 &self.value
98 }
99 pub fn as_dyn(&self) -> &dyn components::EncodableDataComponent {
100 unsafe { self.value.as_kind(self.kind) }
103 }
104 pub fn get<T: components::DataComponentTrait>(&self) -> Option<&T> {
105 let component = self.as_dyn();
106 let component_any = component as &dyn Any;
107 component_any.downcast_ref::<T>()
108 }
109}
110impl AzBuf for TypedDataComponent {
111 fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
112 let kind = DataComponentKind::azalea_read(buf)?;
113 let value = DataComponentUnion::azalea_read_as(kind, buf)?;
114 Ok(Self { kind, value })
115 }
116 fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> {
117 self.kind.azalea_write(buf)?;
118 unsafe { self.value.azalea_write_as(self.kind, buf) }
119 }
120}
121impl Debug for TypedDataComponent {
122 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123 f.debug_struct("TypedDataComponent")
124 .field("kind", &self.kind)
125 .finish()
126 }
127}
128impl Clone for TypedDataComponent {
129 fn clone(&self) -> Self {
130 Self {
131 kind: self.kind,
132 value: unsafe { self.value.clone_as(self.kind) },
133 }
134 }
135}
136impl Drop for TypedDataComponent {
137 fn drop(&mut self) {
138 unsafe { self.value.drop_as(self.kind) };
139 }
140}
141impl PartialEq for TypedDataComponent {
142 fn eq(&self, other: &Self) -> bool {
143 if self.kind != other.kind {
144 return false;
145 }
146 self.as_dyn().eq(other.as_dyn())
147 }
148}