1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
|
use std::{
any::Any,
fmt::{self, Debug},
io::{self, Cursor, Write},
mem::ManuallyDrop,
};
use azalea_buf::{AzBuf, BufReadError};
use azalea_inventory::{
DataComponentPatch, ItemStack, ItemStackData,
components::{self, DataComponentUnion},
};
use azalea_protocol_macros::ClientboundGamePacket;
use azalea_registry::builtin::{DataComponentKind, ItemKind};
#[derive(AzBuf, ClientboundGamePacket, Clone, Debug, PartialEq)]
pub struct ClientboundMerchantOffers {
#[var]
pub container_id: i32,
pub offers: Vec<MerchantOffer>,
#[var]
pub villager_level: u32,
#[var]
pub villager_xp: u32,
pub show_progress: bool,
pub can_restock: bool,
}
#[derive(AzBuf, Clone, Debug, PartialEq)]
pub struct MerchantOffer {
pub base_cost_a: ItemCost,
pub result: ItemStack,
pub cost_b: Option<ItemCost>,
pub out_of_stock: bool,
pub uses: i32,
pub max_uses: i32,
pub xp: i32,
pub special_price_diff: i32,
pub price_multiplier: f32,
pub demand: i32,
}
/// An item that a merchant can buy.
///
/// This can be converted into an [`ItemStackData`] with
/// [`Self::into_item_stack`].
#[derive(AzBuf, Clone, Debug, PartialEq)]
pub struct ItemCost {
pub item: ItemKind,
#[var]
pub count: i32,
pub components: DataComponentExactPredicate,
}
impl ItemCost {
pub fn into_item_stack(self) -> ItemStackData {
let mut component_patch = DataComponentPatch::default();
for component in self.components.expected {
let component = ManuallyDrop::new(component);
// SAFETY: DataComponentUnion does not run any destructors unless it's dropped
// through drop_as, so since TypedDataComponent is now ManuallyDrop, the value
// will stay in memory.
let value = unsafe { std::ptr::read(&component.value) };
unsafe {
component_patch.unchecked_insert_component(component.kind, Some(value));
}
}
// TODO: add a fast way to iterate over default components, and insert the ones
// that aren't present as None
ItemStackData {
kind: self.item,
count: self.count,
component_patch,
}
}
}
/// Similar to [`DataComponentPatch`], but it's only additive, meaning that
/// there are no `None` values.
///
/// If you got this from [`ItemCost`], consider using
/// [`ItemCost::into_item_stack`] for a better API instead.
#[derive(AzBuf, Clone, Debug, PartialEq)]
pub struct DataComponentExactPredicate {
pub expected: Vec<TypedDataComponent>,
}
pub struct TypedDataComponent {
kind: DataComponentKind,
value: DataComponentUnion,
}
impl TypedDataComponent {
pub fn kind(&self) -> &DataComponentKind {
&self.kind
}
pub fn value(&self) -> &DataComponentUnion {
&self.value
}
pub fn as_dyn(&self) -> &dyn components::EncodableDataComponent {
// SAFETY: the kind is correct because we got it from azalea_read_as, and the
// kind isn't mutable
unsafe { self.value.as_kind(self.kind) }
}
pub fn get<T: components::DataComponentTrait>(&self) -> Option<&T> {
let component = self.as_dyn();
let component_any = component as &dyn Any;
component_any.downcast_ref::<T>()
}
}
impl AzBuf for TypedDataComponent {
fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
let kind = DataComponentKind::azalea_read(buf)?;
let value = DataComponentUnion::azalea_read_as(kind, buf)?;
Ok(Self { kind, value })
}
fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> {
self.kind.azalea_write(buf)?;
unsafe { self.value.azalea_write_as(self.kind, buf) }
}
}
impl Debug for TypedDataComponent {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("TypedDataComponent")
.field("kind", &self.kind)
.finish()
}
}
impl Clone for TypedDataComponent {
fn clone(&self) -> Self {
Self {
kind: self.kind,
value: unsafe { self.value.clone_as(self.kind) },
}
}
}
impl Drop for TypedDataComponent {
fn drop(&mut self) {
unsafe { self.value.drop_as(self.kind) };
}
}
impl PartialEq for TypedDataComponent {
fn eq(&self, other: &Self) -> bool {
if self.kind != other.kind {
return false;
}
self.as_dyn().eq(other.as_dyn())
}
}
|