Fix bug that prevented trades

This commit is contained in:
Jeff 2024-07-17 19:28:45 -04:00
parent 2a2a295cc2
commit 546346f707
2 changed files with 36 additions and 57 deletions

View File

@ -57,7 +57,7 @@ pub struct Bot {
sell_prices: PriceList,
trade_mode: TradeMode,
previous_offer: Option<(HashMap<InvSlotId, u32>, HashMap<InvSlotId, u32>)>,
previous_trade: Option<PendingTrade>,
last_trade_action: Instant,
last_announcement: Instant,
last_ouch: Instant,
@ -153,7 +153,7 @@ impl Bot {
buy_prices,
sell_prices,
trade_mode: TradeMode::Trade,
previous_offer: None,
previous_trade: None,
last_trade_action: now,
last_announcement: now,
last_ouch: now,
@ -256,7 +256,7 @@ impl Bot {
if self.is_user_admin(&sender)? && !self.client.is_trading() {
log::info!("Providing admin access");
self.previous_offer = None;
self.previous_trade = None;
self.trade_mode = TradeMode::AdminAccess;
self.client.send_invite(sender, InviteKind::Trade);
@ -402,8 +402,8 @@ impl Bot {
match result {
TradeResult::Completed => {
if let Some(offer) = &self.previous_offer {
log::info!("Trade with {their_name}: {offer:?}",);
if let Some(trade) = &self.previous_trade {
log::info!("Trade with {their_name}: {:?}", trade.offers);
}
self.client.send_command(
@ -531,8 +531,8 @@ impl Bot {
};
// If the trade hasn't changed, do nothing to avoid spamming the server.
if let Some(previous) = &self.previous_offer {
if (&previous.0, &previous.1) == (my_offer, their_offer) {
if let Some(previous) = &self.previous_trade {
if previous == &trade {
return Ok(());
}
}
@ -627,7 +627,7 @@ impl Bot {
}
if !self.sell_prices.0.contains_key(&item_id) {
my_item_to_remove = Some((slot_id, amount));
my_item_to_remove = Some((*slot_id, *amount));
}
}
@ -642,23 +642,25 @@ impl Bot {
}
if !self.buy_prices.0.contains_key(&item_id) {
their_item_to_remove = Some((slot_id, amount));
their_item_to_remove = Some((*slot_id, *amount));
}
}
drop(inventories);
let phase = trade.phase;
// Up until now there may have been an error, so we only update the previous offer now.
// The trade action is infallible from here.
self.previous_offer = Some((my_offer.clone(), their_offer.clone()));
self.previous_trade = Some(trade);
// Before running any actual trade logic, remove items that are not for sale or not being
// purchased. End this trade action if an item was removed.
if let Some((slot_id, quantity)) = my_item_to_remove {
self.client.perform_trade_action(TradeAction::RemoveItem {
item: *slot_id,
quantity: *quantity,
item: slot_id,
quantity,
ours: true,
});
@ -667,8 +669,8 @@ impl Bot {
if let Some((slot_id, quantity)) = their_item_to_remove {
self.client.perform_trade_action(TradeAction::RemoveItem {
item: *slot_id,
quantity: *quantity,
item: slot_id,
quantity,
ours: false,
});
@ -685,8 +687,7 @@ impl Bot {
// If the trade is balanced
if difference == 0 {
// Accept
self.client
.perform_trade_action(TradeAction::Accept(trade.phase));
self.client.perform_trade_action(TradeAction::Accept(phase));
// If they are offering more
} else if difference > 0 {
// If they are offering coins
@ -748,7 +749,7 @@ impl Bot {
.to_string();
let mut found = false;
for (item_id, price) in &self.buy_prices {
for (item_id, price) in &self.buy_prices.0 {
let item_name = self.get_item_name(item_id.as_ref());
if item_name.to_lowercase().contains(&search_term) {
@ -784,7 +785,7 @@ impl Bot {
}
}
for (item_id, price) in &self.sell_prices {
for (item_id, price) in &self.sell_prices.0 {
let item_name = self.get_item_name(item_id.as_ref());
if item_name.to_lowercase().contains(&search_term) {

View File

@ -1,16 +1,14 @@
/**
Configuration used to initiate the bot.
The Config struct is used to store configuration values that are not sensitive. This includes the
price data for items, the game server to connect to, and the position and orientation of the bot.
The price lists have manual implementations for deserialization to allow turning shortened item
IDs into the full IDs used by the Veloren client.
The Secrets struct is used to store sensitive information that should not be shared. This should
be read from a separate file that is not checked into version control. In production, use a secure
means of storing this information, such as the secret manager for Podman.
*/
use hashbrown::{hash_map, HashMap};
/// Configuration used to initiate the bot.
///
/// The Config struct is used to store configuration values that are not sensitive. This includes
/// the price data for items, the game server to connect to, and the position and orientation of
/// the bot. The price lists have manual implementations for deserialization to allow turning
/// shortened item IDs into the full IDs used by the Veloren client.
///
/// The Secrets struct is used to store sensitive information that should not be shared. This
/// should be read from a separate file that is not checked into version control. In production,
/// use a secure means of storing this information, such as the secret manager for Podman.
use hashbrown::HashMap;
use serde::{
de::{self, Visitor},
Deserialize,
@ -54,31 +52,13 @@ impl<'de> Deserialize<'de> for PriceList {
}
}
impl IntoIterator for PriceList {
type Item = (ItemDefinitionIdOwned, u32);
type IntoIter = hash_map::IntoIter<ItemDefinitionIdOwned, u32>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<'a> IntoIterator for &'a PriceList {
type Item = (&'a ItemDefinitionIdOwned, &'a u32);
type IntoIter = hash_map::Iter<'a, ItemDefinitionIdOwned, u32>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
pub struct PriceListVisitor;
impl<'de> Visitor<'de> for PriceListVisitor {
type Value = PriceList;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a map with simple and/or modular keys: Material|primary|secondary")
formatter.write_str("a map with simple and/or modular keys: material|primary|secondary")
}
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
@ -95,7 +75,7 @@ impl<'de> Visitor<'de> for PriceListVisitor {
let mut secondary = secondary.to_string();
primary.insert_str(0, "common.items.modular.weapon.primary.");
secondary.insert_str(0, "common.items.modular.weapon.secondar.");
secondary.insert_str(0, "common.items.modular.weapon.secondary.");
let material = ItemDefinitionIdOwned::Simple(
material
@ -108,15 +88,13 @@ impl<'de> Visitor<'de> for PriceListVisitor {
})?
.to_string(),
);
let secondary = ItemDefinitionIdOwned::Compound {
// This unwrap is safe because the ItemDefinitionId is always Simple.
simple_base: primary,
components: vec![material],
};
ItemDefinitionIdOwned::Modular {
pseudo_base: "veloren.core.pseudo_items.modular.tool".to_string(),
components: vec![secondary],
components: vec![ItemDefinitionIdOwned::Compound {
simple_base: primary,
components: vec![ItemDefinitionIdOwned::Simple(secondary), material],
}],
}
}
[simple] => {