Compare commits

..

No commits in common. "2402853863597d8899d87eb19c216fdfb6604b10" and "ac358082cb9b12d175e0f9890f7eef4418499c25" have entirely different histories.

2 changed files with 50 additions and 71 deletions

View File

@ -8,7 +8,6 @@ use std::{
}; };
use hashbrown::HashMap; use hashbrown::HashMap;
use log::{debug, info};
use tokio::runtime::Runtime; use tokio::runtime::Runtime;
use vek::{Quaternion, Vec3}; use vek::{Quaternion, Vec3};
use veloren_client::{addr::ConnectionArgs, Client, Event as VelorenEvent, SiteInfoRich, WorldExt}; use veloren_client::{addr::ConnectionArgs, Client, Event as VelorenEvent, SiteInfoRich, WorldExt};
@ -84,7 +83,7 @@ impl Bot {
orientation: Option<f32>, orientation: Option<f32>,
announcement: Option<String>, announcement: Option<String>,
) -> Result<Self, String> { ) -> Result<Self, String> {
info!("Connecting to veloren"); log::info!("Connecting to veloren");
let mut client = connect_to_veloren(game_server, auth_server, &username, password)?; let mut client = connect_to_veloren(game_server, auth_server, &username, password)?;
let mut clock = Clock::new(CLIENT_TPS); let mut clock = Clock::new(CLIENT_TPS);
@ -108,7 +107,7 @@ impl Bot {
.id .id
.ok_or("Failed to get character ID")?; .ok_or("Failed to get character ID")?;
info!("Selecting a character"); log::info!("Selecting a character");
// This loop waits and retries requesting the character in the case that the character has // This loop waits and retries requesting the character in the case that the character has
// logged out too recently. // logged out too recently.
@ -163,8 +162,7 @@ impl Bot {
}) })
} }
/// Run the bot for a single tick. This should be called in a loop. Returns `true` if the loop /// Run the bot for a single tick. This should be called in a loop.
/// should continue running.
/// ///
/// There are three timers in this function: /// There are three timers in this function:
/// - The [Clock] runs the Veloren client. At **30 ticks per second** this timer is faster than /// - The [Clock] runs the Veloren client. At **30 ticks per second** this timer is faster than
@ -176,18 +174,14 @@ impl Bot {
/// This function should be modified with care. In addition to being the bot's main loop, it /// This function should be modified with care. In addition to being the bot's main loop, it
/// also accepts incoming trade invites, which has a potential for error if the bot accepts an /// also accepts incoming trade invites, which has a potential for error if the bot accepts an
/// invite while in the wrong trade mode. /// invite while in the wrong trade mode.
pub fn tick(&mut self) -> Result<bool, String> { pub fn tick(&mut self) -> Result<(), String> {
let veloren_events = self let veloren_events = self
.client .client
.tick(ControllerInputs::default(), self.clock.dt()) .tick(ControllerInputs::default(), self.clock.dt())
.map_err(|error| format!("{error:?}"))?; .map_err(|error| format!("{error:?}"))?;
for event in veloren_events { for event in veloren_events {
let should_continue = self.handle_veloren_event(event)?; self.handle_veloren_event(event)?;
if !should_continue {
return Ok(false);
}
} }
if self.last_trade_action.elapsed() > TRADE_ACTION_DELAY { if self.last_trade_action.elapsed() > TRADE_ACTION_DELAY {
@ -224,9 +218,9 @@ impl Bot {
self.sort_count -= 1; self.sort_count -= 1;
if self.sort_count == 0 { if self.sort_count == 0 {
debug!("Sorted inventory, finished") log::info!("Sorted inventory, finished")
} else { } else {
debug!("Sorted inventory, {} more times to go", self.sort_count); log::info!("Sorted inventory, {} more times to go", self.sort_count);
} }
} }
@ -241,18 +235,17 @@ impl Bot {
self.clock.tick(); self.clock.tick();
Ok(true) Ok(())
} }
/// Consume and manage a client-side Veloren event. Returns a boolean indicating whether the /// Consume and manage a client-side Veloren event.
/// bot should continue processing events. fn handle_veloren_event(&mut self, event: VelorenEvent) -> Result<(), String> {
fn handle_veloren_event(&mut self, event: VelorenEvent) -> Result<bool, String> {
match event { match event {
VelorenEvent::Chat(message) => { VelorenEvent::Chat(message) => {
let sender = if let ChatType::Tell(uid, _) = message.chat_type { let sender = if let ChatType::Tell(uid, _) = message.chat_type {
uid uid
} else { } else {
return Ok(true); return Ok(());
}; };
let content = message.content().as_plain().unwrap_or_default(); let content = message.content().as_plain().unwrap_or_default();
let mut split_content = content.split(' '); let mut split_content = content.split(' ');
@ -261,7 +254,7 @@ impl Bot {
let correction_message = match command { let correction_message = match command {
"admin_access" => { "admin_access" => {
if self.is_user_admin(&sender)? && !self.client.is_trading() { if self.is_user_admin(&sender)? && !self.client.is_trading() {
info!("Providing admin access"); log::info!("Providing admin access");
self.previous_trade = None; self.previous_trade = None;
self.trade_mode = TradeMode::AdminAccess; self.trade_mode = TradeMode::AdminAccess;
@ -337,13 +330,13 @@ impl Bot {
.parse::<u8>() .parse::<u8>()
.map_err(|error| error.to_string())?; .map_err(|error| error.to_string())?;
debug!("Sorting inventory {sort_count} times"); log::info!("Sorting inventory {sort_count} times");
self.sort_count = sort_count; self.sort_count = sort_count;
} else { } else {
self.client.sort_inventory(); self.client.sort_inventory();
debug!("Sorting inventory once"); log::info!("Sorting inventory once");
} }
None None
@ -381,7 +374,7 @@ impl Bot {
} }
VelorenEvent::Outcome(Outcome::HealthChange { info, .. }) => { VelorenEvent::Outcome(Outcome::HealthChange { info, .. }) => {
if let Some(DamageSource::Buff(_)) = info.cause { if let Some(DamageSource::Buff(_)) = info.cause {
return Ok(true); return Ok(());
} }
if let Some(uid) = self.client.uid() { if let Some(uid) = self.client.uid() {
@ -410,7 +403,7 @@ impl Bot {
match result { match result {
TradeResult::Completed => { TradeResult::Completed => {
if let Some(reciept) = &self.previous_trade_receipt { if let Some(reciept) = &self.previous_trade_receipt {
info!("Trade with {their_name}: {:?}", reciept); log::info!("Trade with {their_name}: {:?}", reciept);
} }
self.client.send_command( self.client.send_command(
@ -418,25 +411,22 @@ impl Bot {
vec!["Thank you for trading with me!".to_string()], vec!["Thank you for trading with me!".to_string()],
); );
} }
TradeResult::Declined => info!("Trade with {their_name} declined"), TradeResult::Declined => log::info!("Trade with {their_name} declined"),
TradeResult::NotEnoughSpace => { TradeResult::NotEnoughSpace => {
info!("Trade with {their_name} failed: not enough space") log::info!("Trade with {their_name} failed: not enough space")
} }
} }
if let TradeMode::AdminAccess = self.trade_mode { if let TradeMode::AdminAccess = self.trade_mode {
info!("End of admin access for {their_name}"); log::info!("End of admin access for {their_name}");
self.trade_mode = TradeMode::Trade; self.trade_mode = TradeMode::Trade;
} }
} }
VelorenEvent::Disconnect => {
return Ok(false);
}
_ => (), _ => (),
} }
Ok(true) Ok(())
} }
/// Make the bot's trading and help accouncements /// Make the bot's trading and help accouncements
@ -445,7 +435,7 @@ impl Bot {
/// is always made. If an announcement was provided when the bot was created, it will make it /// is always made. If an announcement was provided when the bot was created, it will make it
/// in /world. /// in /world.
fn handle_announcement(&mut self) -> Result<(), String> { fn handle_announcement(&mut self) -> Result<(), String> {
debug!("Making an announcement"); log::info!("Making an announcement");
self.client.send_command( self.client.send_command(
"region".to_string(), "region".to_string(),
@ -517,10 +507,10 @@ impl Bot {
/// 4. If the trade is balanced, accept it. /// 4. If the trade is balanced, accept it.
/// 5. If the total value of their offer is greater than the total value of my offer: /// 5. If the total value of their offer is greater than the total value of my offer:
/// 1. If they are offering coins, remove them to balance. /// 1. If they are offering coins, remove them to balance.
/// 2. If they are not offering coins, add mine to balance if I have enough. /// 2. If they are not offering coins, add mine to balance.
/// 6. If the total value of my offer is greater than the total value of their offer: /// 6. If the total value of my offer is greater than the total value of their offer:
/// 1. If I am offering coins, remove them to balance. /// 1. If I am offering coins, remove them to balance.
/// 2. If I am not offering coins, add theirs to balance if they have enough. /// 2. If I am not offering coins, add theirs to balance.
/// 7. If the trade is still unbalanced, tell them the value of the greater offer and the /// 7. If the trade is still unbalanced, tell them the value of the greater offer and the
/// other party's total coin amount. /// other party's total coin amount.
/// ///
@ -690,7 +680,7 @@ impl Bot {
// offer now. The trade action is infallible from here. // offer now. The trade action is infallible from here.
self.previous_trade = Some(trade); self.previous_trade = Some(trade);
debug!("Performing trade action with {their_name}"); log::info!("Performing trade action with {their_name}");
// Before running any actual trade logic, remove items that are not for sale or not being // 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. // purchased. End this trade action if an item was removed.
@ -719,8 +709,7 @@ impl Bot {
// The if/else statements below implement the bot's main feature: buying, selling and // The if/else statements below implement the bot's main feature: buying, selling and
// trading items according to the values set in the configuration file. Coins are used to // trading items according to the values set in the configuration file. Coins are used to
// balance the value of the trade. If there are not enough or no coins to balance the // balance the value of the trade.
// trade, a message is sent to the user.
// If the trade is balanced // If the trade is balanced
if difference == 0 { if difference == 0 {
@ -737,18 +726,19 @@ impl Bot {
// If they are offering coins // If they are offering coins
if their_offered_coin_amount > 0 { if their_offered_coin_amount > 0 {
if let Some(their_coins) = get_their_coins { if let Some(their_coins) = get_their_coins {
// Remove their coins to balance if their_coin_amount >= difference as u32 {
self.client.perform_trade_action(TradeAction::RemoveItem { // Remove their coins to balance
item: their_coins, self.client.perform_trade_action(TradeAction::RemoveItem {
quantity: difference as u32, item: their_coins,
ours: false, quantity: difference as u32,
}); ours: false,
});
return Ok(()); return Ok(());
}
} }
// If they are not offering coins // If they are not offering coins
} else if let Some(my_coins) = get_my_coins { } else if let Some(my_coins) = get_my_coins {
// If I have enough coins
if my_coin_amount >= difference as u32 { if my_coin_amount >= difference as u32 {
// Add my coins to balanace // Add my coins to balanace
self.client.perform_trade_action(TradeAction::AddItem { self.client.perform_trade_action(TradeAction::AddItem {
@ -770,8 +760,6 @@ impl Bot {
), ),
], ],
); );
return Ok(());
} }
// If I am offering more // If I am offering more
@ -779,18 +767,19 @@ impl Bot {
// If I am offering coins // If I am offering coins
if my_offered_coin_amount > 0 { if my_offered_coin_amount > 0 {
if let Some(my_coins) = get_my_coins { if let Some(my_coins) = get_my_coins {
// Remove my coins to balance if my_coin_amount >= difference.unsigned_abs() {
self.client.perform_trade_action(TradeAction::RemoveItem { // Remove my coins to balance
item: my_coins, self.client.perform_trade_action(TradeAction::RemoveItem {
quantity: difference.unsigned_abs(), item: my_coins,
ours: true, quantity: difference.unsigned_abs(),
}); ours: true,
});
return Ok(()); return Ok(());
}
} }
// If I am not offering coins // If I am not offering coins
} else if let Some(their_coins) = get_their_coins { } else if let Some(their_coins) = get_their_coins {
// If they have enough coins
if their_coin_amount >= difference.unsigned_abs() { if their_coin_amount >= difference.unsigned_abs() {
// Add their coins to balance // Add their coins to balance
self.client.perform_trade_action(TradeAction::AddItem { self.client.perform_trade_action(TradeAction::AddItem {
@ -803,6 +792,8 @@ impl Bot {
} }
} }
let their_name = self.find_player_alias(&their_uid).unwrap().clone();
self.client.send_command( self.client.send_command(
"tell".to_string(), "tell".to_string(),
vec![ vec![
@ -867,7 +858,7 @@ impl Bot {
let total_found = buying.len() + selling.len(); let total_found = buying.len() + selling.len();
if total_found == 0 { if total_found == 0 {
debug!("Found no price for \"{original_search_term}\" for {player_name}"); log::info!("Found no price for \"{original_search_term}\" for {player_name}");
self.client.send_command( self.client.send_command(
"tell".to_string(), "tell".to_string(),
@ -881,7 +872,7 @@ impl Bot {
} }
if total_found > 10 { if total_found > 10 {
debug!( log::info!(
"Found {total_found} prices for \"{original_search_term}\" for {player_name}, not sending." "Found {total_found} prices for \"{original_search_term}\" for {player_name}, not sending."
); );
@ -898,7 +889,7 @@ impl Bot {
return Ok(()); return Ok(());
} }
debug!("Found {total_found} prices for \"{original_search_term}\" for {player_name}, sending prices."); log::info!("Found {total_found} prices for \"{original_search_term}\" for {player_name}, sending prices.");
for (item_name, price) in buying { for (item_name, price) in buying {
self.client.send_command( self.client.send_command(
@ -943,8 +934,6 @@ impl Bot {
fn handle_position_and_orientation(&mut self) -> Result<(), String> { fn handle_position_and_orientation(&mut self) -> Result<(), String> {
if let Some(current_position) = self.client.current::<Pos>() { if let Some(current_position) = self.client.current::<Pos>() {
if current_position != self.position { if current_position != self.position {
debug!("Updating position to {}", self.position.0);
let entity = self.client.entity(); let entity = self.client.entity();
let ecs = self.client.state_mut().ecs(); let ecs = self.client.state_mut().ecs();
let mut position_state = ecs.write_storage::<Pos>(); let mut position_state = ecs.write_storage::<Pos>();
@ -957,8 +946,6 @@ impl Bot {
if let Some(current_orientation) = self.client.current::<Ori>() { if let Some(current_orientation) = self.client.current::<Ori>() {
if current_orientation != self.orientation { if current_orientation != self.orientation {
debug!("Updating orientation to {:?}", self.orientation);
let entity = self.client.entity(); let entity = self.client.entity();
let ecs = self.client.state_mut().ecs(); let ecs = self.client.state_mut().ecs();
let mut orientation_state = ecs.write_storage::<Ori>(); let mut orientation_state = ecs.write_storage::<Ori>();

View File

@ -7,11 +7,9 @@ use std::{env::var, fs::read_to_string};
use bot::Bot; use bot::Bot;
use config::{Config, Secrets}; use config::{Config, Secrets};
use env_logger::Env;
use log::error;
fn main() { fn main() {
env_logger::Builder::from_env(Env::default().default_filter_or("debug")).init(); env_logger::init();
let secrets = { let secrets = {
let secrets_path = let secrets_path =
@ -49,12 +47,6 @@ fn main() {
.expect("Failed to create bot"); .expect("Failed to create bot");
loop { loop {
match bot.tick() { let _ = bot.tick().inspect_err(|error| log::error!("{error}"));
Ok(true) => return,
Ok(false) => {}
Err(error) => {
error!("{error}");
}
}
} }
} }