Skip to content

Commit

Permalink
Board open and Board take
Browse files Browse the repository at this point in the history
  • Loading branch information
sorokya committed Oct 13, 2023
1 parent 5c3c5ec commit a4fe475
Show file tree
Hide file tree
Showing 19 changed files with 384 additions and 12 deletions.
31 changes: 31 additions & 0 deletions Config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -144,4 +144,35 @@ max_bank_gold = 2000000000
# Maximum amount of an item a player can have in their inventory
max_item = 2000000000

[board]

# Maximum number of posts a board will hold before deleting old posts
max_posts = 20

# Maximum number of posts a user can have on a board at any one time
# Any less than 2 will not be enforced by the official client
max_user_posts = 6

# Maximum number of "recent" posts a user can have on a board
# Any less than 2 will not be enforced by the official client
max_recent_posts = 2

# Age of a post to be considered "recent" in minutes
recent_post_time = 30

# Maximum length of board post subjects
# Shouldn't be changed unless using a custom client which supports it
max_subject_length = 32

# Maximum length of board posts
max_post_length = 2048

# Adds "(x minutes ago)" text to every post on a board
date_posts = true

# Board number that reports/requests are logged (1 to 8)
# This board can't be accessed by players if placed in-game
admin_board = 8

# Maximum number of posts that the AdminBoard can hold
admin_max_posts = 100
36 changes: 28 additions & 8 deletions db-init/init.sql
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,27 @@ CREATE TABLE `Bank` (
`item_id` int NOT NULL,
`quantity` int NOT NULL,
PRIMARY KEY (`character_id`,`item_id`),
CONSTRAINT `bank_character_id` FOREIGN KEY (`character_id`) REFERENCES `Character` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
CONSTRAINT `bank_character_id` FOREIGN KEY (`character_id`) REFERENCES `Character` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Table structure for table `BoardPost`
--

DROP TABLE IF EXISTS `BoardPost`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `BoardPost` (
`id` int NOT NULL AUTO_INCREMENT,
`board_id` tinyint NOT NULL,
`character_id` int NOT NULL,
`subject` varchar(32) NOT NULL,
`body` varchar(2048) NOT NULL,
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `board_id_idx` (`board_id`),
CONSTRAINT `board_post_character_id` FOREIGN KEY (`character_id`) REFERENCES `Character` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

Expand Down Expand Up @@ -89,7 +109,7 @@ CREATE TABLE `Character` (
PRIMARY KEY (`id`),
UNIQUE KEY `name_UNIQUE` (`name`),
KEY `account_id_idx` (`account_id`),
CONSTRAINT `character_account_id` FOREIGN KEY (`account_id`) REFERENCES `Account` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
CONSTRAINT `character_account_id` FOREIGN KEY (`account_id`) REFERENCES `Account` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

Expand Down Expand Up @@ -124,7 +144,7 @@ CREATE TABLE `GuildRank` (
`rank` varchar(64) NOT NULL,
PRIMARY KEY (`id`),
KEY `guild_rank_guild_id` (`guild_id`),
CONSTRAINT `guild_rank_guild_id` FOREIGN KEY (`guild_id`) REFERENCES `Guild` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
CONSTRAINT `guild_rank_guild_id` FOREIGN KEY (`guild_id`) REFERENCES `Guild` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

Expand All @@ -140,7 +160,7 @@ CREATE TABLE `Inventory` (
`item_id` int NOT NULL,
`quantity` int NOT NULL,
PRIMARY KEY (`character_id`,`item_id`),
CONSTRAINT `inventory_character_id` FOREIGN KEY (`character_id`) REFERENCES `Character` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
CONSTRAINT `inventory_character_id` FOREIGN KEY (`character_id`) REFERENCES `Character` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

Expand Down Expand Up @@ -169,7 +189,7 @@ CREATE TABLE `Paperdoll` (
`bracer` int NOT NULL DEFAULT '0',
`bracer2` int NOT NULL DEFAULT '0',
PRIMARY KEY (`character_id`),
CONSTRAINT `paperdoll_character_id` FOREIGN KEY (`character_id`) REFERENCES `Character` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
CONSTRAINT `paperdoll_character_id` FOREIGN KEY (`character_id`) REFERENCES `Character` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

Expand All @@ -189,7 +209,7 @@ CREATE TABLE `Position` (
`sitting` int NOT NULL DEFAULT '0',
`hidden` int NOT NULL DEFAULT '0',
PRIMARY KEY (`character_id`),
CONSTRAINT `position_character_id` FOREIGN KEY (`character_id`) REFERENCES `Character` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
CONSTRAINT `position_character_id` FOREIGN KEY (`character_id`) REFERENCES `Character` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

Expand All @@ -205,7 +225,7 @@ CREATE TABLE `Spell` (
`spell_id` int NOT NULL,
`level` int NOT NULL DEFAULT '0',
PRIMARY KEY (`character_id`,`spell_id`),
CONSTRAINT `spell_character_id` FOREIGN KEY (`character_id`) REFERENCES `Character` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
CONSTRAINT `spell_character_id` FOREIGN KEY (`character_id`) REFERENCES `Character` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

Expand Down Expand Up @@ -233,7 +253,7 @@ CREATE TABLE `Stats` (
`karma` int NOT NULL DEFAULT '1000',
`usage` int NOT NULL DEFAULT '0',
PRIMARY KEY (`character_id`),
CONSTRAINT `stats_character_id` FOREIGN KEY (`character_id`) REFERENCES `Character` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
CONSTRAINT `stats_character_id` FOREIGN KEY (`character_id`) REFERENCES `Character` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
Expand Down
41 changes: 41 additions & 0 deletions src/handlers/board.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use eo::{
data::{EOShort, StreamReader},
protocol::PacketAction,
};

use crate::{map::MapHandle, player::PlayerHandle};

fn open(reader: StreamReader, player_id: EOShort, map: MapHandle) {
let board_id = reader.get_short();
map.open_board(player_id, board_id);
}

fn take(reader: StreamReader, player_id: EOShort, map: MapHandle) {
let _board_id = reader.get_short();
let post_id = reader.get_short();
map.view_board_post(player_id, post_id);
}

pub async fn board(action: PacketAction, reader: StreamReader, player: PlayerHandle) {
let player_id = match player.get_player_id().await {
Ok(player_id) => player_id,
Err(e) => {
error!("Failed to get player id: {}", e);
return;
}
};

let map = match player.get_map().await {
Ok(map) => map,
Err(e) => {
error!("Failed to get map: {}", e);
return;
}
};

match action {
PacketAction::Open => open(reader, player_id, map),
PacketAction::Take => take(reader, player_id, map),
_ => error!("Unhandled packet Board_{:?}", action),
}
}
3 changes: 3 additions & 0 deletions src/handlers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ pub use attack::attack;
mod bank;
pub use bank::bank;

mod board;
pub use board::board;

mod chair;
pub use chair::chair;

Expand Down
8 changes: 8 additions & 0 deletions src/map/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ pub enum Command {
player_id: EOShort,
npc_index: EOChar,
},
OpenBoard {
player_id: EOShort,
board_id: EOShort,
},
OpenChest {
player_id: EOShort,
coords: Coords,
Expand Down Expand Up @@ -198,6 +202,10 @@ pub enum Command {
player_id: EOShort,
item_id: EOShort,
},
ViewBoardPost {
player_id: EOShort,
post_id: EOShort,
},
Walk {
target_player_id: EOShort,
direction: Direction,
Expand Down
12 changes: 12 additions & 0 deletions src/map/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,14 @@ mod learn_skill;
mod leave;
mod level_stat;
mod open_bank;
mod open_board;
mod open_chest;
mod open_door;
mod open_locker;
mod open_shop;
mod open_skill_master;
mod play_effect;
mod player_in_range_of_tile;
mod recover_npcs;
mod recover_players;
mod request_paperdoll;
Expand All @@ -83,6 +85,7 @@ mod take_locker_item;
mod unequip;
mod upgrade_locker;
mod use_item;
mod view_board_post;
mod walk;
mod withdraw_gold;

Expand Down Expand Up @@ -232,6 +235,11 @@ impl Map {
npc_index,
} => self.open_bank(player_id, npc_index).await,

Command::OpenBoard {
player_id,
board_id,
} => self.open_board(player_id, board_id),

Command::OpenChest { player_id, coords } => self.open_chest(player_id, coords),

Command::OpenDoor {
Expand Down Expand Up @@ -322,6 +330,10 @@ impl Map {

Command::UseItem { player_id, item_id } => self.use_item(player_id, item_id),

Command::ViewBoardPost { player_id, post_id } => {
self.view_board_post(player_id, post_id).await
}

Command::Walk {
target_player_id,
direction,
Expand Down
80 changes: 80 additions & 0 deletions src/map/map/open_board.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
use eo::{
data::{EOChar, EOShort, StreamBuilder, EO_BREAK_CHAR},
protocol::{PacketAction, PacketFamily},
};
use mysql_async::{params, prelude::Queryable, Row};

use crate::{utils::get_board_tile_spec, SETTINGS};

use super::Map;

struct BoardPost {
id: EOShort,
author: String,
subject: String,
}

impl Map {
pub fn open_board(&mut self, player_id: EOShort, board_id: EOShort) {
let character = match self.characters.get(&player_id) {
Some(character) => character,
None => return,
};

let board_tile_spec = match get_board_tile_spec(board_id) {
Some(spec) => spec,
None => return,
};

if !self.player_in_range_of_tile(player_id, board_tile_spec) {
return;
}

let player = match &character.player {
Some(player) => player.clone(),
None => return,
};

player.set_board_id(board_id);

let pool = self.pool.clone();
tokio::spawn(async move {
let mut builder = StreamBuilder::new();

let mut conn = pool.get_conn().await.unwrap();
let limit = if board_id == SETTINGS.board.admin_board as EOShort {
SETTINGS.board.admin_max_posts
} else {
SETTINGS.board.max_posts
};

let posts = conn
.exec_map(
include_str!("../../sql/get_board_posts.sql"),
params! {
"board_id" => board_id,
"limit" => limit,
},
|mut row: Row| BoardPost {
id: row.take("id").unwrap(),
author: row.take("author").unwrap(),
subject: row.take("subject").unwrap(),
},
)
.await
.unwrap();

builder.add_char(board_id as EOChar);
builder.add_char(posts.len() as EOChar);

for post in posts {
builder.add_short(post.id);
builder.add_byte(EO_BREAK_CHAR);
builder.add_break_string(&post.author);
builder.add_break_string(&post.subject);
}

player.send(PacketAction::Open, PacketFamily::Board, builder.get());
});
}
}
30 changes: 30 additions & 0 deletions src/map/map/player_in_range_of_tile.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use eo::{data::EOShort, protocol::Coords, pubs::EmfTileSpec};

use crate::utils::in_client_range;

use super::Map;

impl Map {
pub fn player_in_range_of_tile(&self, player_id: EOShort, spec_id: EmfTileSpec) -> bool {
let character = match self.characters.get(&player_id) {
Some(character) => character,
None => return false,
};

for row in &self.file.spec_rows {
for tile in row.tiles.iter().filter(|tile| tile.spec == spec_id) {
if in_client_range(
&character.coords,
&Coords {
x: tile.x,
y: row.y,
},
) {
return true;
}
}
}

false
}
}
Loading

0 comments on commit a4fe475

Please sign in to comment.