Compare commits
No commits in common. "2402853863597d8899d87eb19c216fdfb6604b10" and "ac358082cb9b12d175e0f9890f7eef4418499c25" have entirely different histories.
2402853863
...
ac358082cb
81
src/bot.rs
81
src/bot.rs
@ -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,6 +726,7 @@ 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 {
|
||||||
|
if their_coin_amount >= difference as u32 {
|
||||||
// Remove their coins to balance
|
// Remove their coins to balance
|
||||||
self.client.perform_trade_action(TradeAction::RemoveItem {
|
self.client.perform_trade_action(TradeAction::RemoveItem {
|
||||||
item: their_coins,
|
item: their_coins,
|
||||||
@ -746,9 +736,9 @@ impl Bot {
|
|||||||
|
|
||||||
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,6 +767,7 @@ 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 {
|
||||||
|
if my_coin_amount >= difference.unsigned_abs() {
|
||||||
// Remove my coins to balance
|
// Remove my coins to balance
|
||||||
self.client.perform_trade_action(TradeAction::RemoveItem {
|
self.client.perform_trade_action(TradeAction::RemoveItem {
|
||||||
item: my_coins,
|
item: my_coins,
|
||||||
@ -788,9 +777,9 @@ impl Bot {
|
|||||||
|
|
||||||
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>();
|
||||||
|
12
src/main.rs
12
src/main.rs
@ -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}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user