Skip to content

Commit

Permalink
Char restoration works now
Browse files Browse the repository at this point in the history
  • Loading branch information
artemijan committed Jan 28, 2025
1 parent 8e4cf88 commit f795396
Show file tree
Hide file tree
Showing 11 changed files with 117 additions and 3 deletions.
8 changes: 8 additions & 0 deletions entities/src/dao/character.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ impl character::Model {
active_model.delete_at = ActiveValue::Set(Some((Utc::now() + Duration::days(7)).into()));
active_model.update(db_pool).await
}
pub async fn restore_char(
db_pool: &DBPool,
c: character::Model,
) -> Result<character::Model, DbErr> {
let mut active_model: character::ActiveModel = c.into();
active_model.delete_at = ActiveValue::Set(None);
active_model.update(db_pool).await
}
pub async fn find_by_username(
db_pool: &DBPool,
username: &str,
Expand Down
14 changes: 14 additions & 0 deletions game/src/client_thread/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,20 @@ impl ClientHandler {
}
Ok(())
}
#[allow(clippy::cast_sign_loss)]
pub async fn restore_char_by_slot_id(&mut self, slot_id: i32) -> anyhow::Result<()> {
if let Some(chars) = self.account_chars.as_mut() {
if slot_id >= i32::try_from(chars.len())? || slot_id < 0 {
bail!("Missing character at slot: {slot_id}")
}
let mut char_info: CharacterInfo = chars.remove(slot_id as usize);
let model = char_info.char_model.clone();
let updated_char = character::Model::restore_char(&self.db_pool, model).await?;
char_info.char_model = updated_char;
chars.insert(slot_id as usize, char_info);
}
Ok(())
}

pub fn set_encryption(&mut self, bf_key: Option<Encryption>) {
self.blowfish = bf_key;
Expand Down
2 changes: 2 additions & 0 deletions game/src/cp_factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use crate::packets::HandleablePacket;
use anyhow::bail;
use l2_core::shared_packets::common::ReadablePacket;
use tracing::error;
use crate::packets::from_client::char_restore::RestoreChar;
use crate::packets::from_client::delete_char::DeleteChar;
use crate::packets::from_client::logout::Logout;

Expand All @@ -28,6 +29,7 @@ pub fn build_client_packet(
CreateCharRequest::PACKET_ID => Ok(Box::new(CreateCharRequest::read(packet_body)?)),
Logout::PACKET_ID => Ok(Box::new(Logout::read(packet_body)?)),
DeleteChar::PACKET_ID => Ok(Box::new(DeleteChar::read(packet_body)?)),
RestoreChar::PACKET_ID => Ok(Box::new(RestoreChar::read(packet_body)?)),
0xD0 => build_ex_client_packet(packet_body),
_ => {
error!("Unknown GS packet ID:0x{:02X}", data[0]);
Expand Down
51 changes: 51 additions & 0 deletions game/src/packets/from_client/char_restore.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use crate::client_thread::ClientHandler;
use crate::packets::to_client::CharSelectionInfo;
use crate::packets::HandleablePacket;
use async_trait::async_trait;
use tracing::info;
use l2_core::shared_packets::common::ReadablePacket;
use l2_core::shared_packets::read::ReadablePacketBuffer;
use l2_core::traits::handlers::{PacketHandler, PacketSender};

#[derive(Debug, Clone)]
pub struct RestoreChar {
char_slot: i32,
}

impl ReadablePacket for RestoreChar {
const PACKET_ID: u8 = 0x7B;
const EX_PACKET_ID: Option<u16> = None;
fn read(data: &[u8]) -> anyhow::Result<Self> {
let mut buffer = ReadablePacketBuffer::new(data.to_vec());
Ok(Self {
char_slot: buffer.read_i32(),
})
}
}

#[async_trait]
impl HandleablePacket for RestoreChar {
type HandlerType = ClientHandler;
async fn handle(&self, handler: &mut Self::HandlerType) -> anyhow::Result<()> {
//todo flood protection
info!("Restore slot: {}", self.char_slot);
handler.restore_char_by_slot_id(self.char_slot).await?;
let sk = handler.get_session_key().ok_or(anyhow::anyhow!(
"Error after char restoration, Session is missing"
))?;
let chars = handler.get_account_chars().ok_or(anyhow::anyhow!(
"Programming error, seems like all chars dropped from the list during restoration"
))?;
let controller = handler.get_controller();
let user_name = &handler
.user
.as_ref()
.ok_or(anyhow::anyhow!(
"Programming error, or possible cheating: missing user in handler for char restoration"
))?
.username;
let p = CharSelectionInfo::new(user_name, sk.get_play_session_id(), controller, chars)?;
handler.send_packet(Box::new(p)).await?;
Ok(())
}
}
2 changes: 1 addition & 1 deletion game/src/packets/from_client/delete_char.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use crate::client_thread::ClientHandler;
use crate::packets::to_client::CharSelectionInfo;
use crate::packets::HandleablePacket;
use async_trait::async_trait;
use tracing::info;
use l2_core::shared_packets::common::ReadablePacket;
use l2_core::shared_packets::read::ReadablePacketBuffer;
use l2_core::traits::handlers::{PacketHandler, PacketSender};
Expand All @@ -27,6 +26,7 @@ impl ReadablePacket for DeleteChar {
impl HandleablePacket for DeleteChar {
type HandlerType = ClientHandler;
async fn handle(&self, handler: &mut Self::HandlerType) -> anyhow::Result<()> {
//todo handle proper deletion checks, e.g. check in clan, war, and so on
handler.delete_char_by_slot_id(self.char_slot).await?;
let sk = handler.get_session_key().ok_or(anyhow::anyhow!(
"Error after char deletion, Session is missing"
Expand Down
3 changes: 2 additions & 1 deletion game/src/packets/from_client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ pub mod new_char_request;
pub mod extended;
pub mod char_create;
pub mod logout;
pub mod delete_char;
pub mod delete_char;
pub mod char_restore;
24 changes: 24 additions & 0 deletions game/src/packets/to_client/char_delete_fail.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use l2_core::enums::CharDeletionFailReasons;
use l2_core::shared_packets::write::SendablePacketBuffer;
use macro_common::SendablePacketImpl;

#[allow(unused)]
#[derive(Debug, Clone, SendablePacketImpl)]
pub struct CharDeleteFail {
buffer: SendablePacketBuffer,
}

#[allow(unused)]
impl CharDeleteFail {
const PACKET_ID: u8 = 0x1E;
const EX_PACKET_ID: Option<u16> = None;

pub fn new(reason: CharDeletionFailReasons) -> anyhow::Result<Self> {
let mut inst = Self {
buffer: SendablePacketBuffer::new(),
};
inst.buffer.write(Self::PACKET_ID)?;
inst.buffer.write_i32(reason as i32)?;
Ok(inst)
}
}
1 change: 0 additions & 1 deletion game/src/packets/to_client/char_selection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ impl CharSelectionInfo {
buffer.write_i32(0)?; // clan id
buffer.write_i32(0)?; // Builder level
buffer.write_i32(i32::from(char.sex))?;
info!("Race id: {}", char.race_id);
buffer.write_i32(i32::from(char.race_id))?;
buffer.write_i32(i32::from(char.base_class_id))?;
buffer.write_i32(1)?; // GameServerName
Expand Down
1 change: 1 addition & 0 deletions game/src/packets/to_client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod new_char_response;
pub mod extended;
mod char_create_fail;
mod char_create_ok;
mod char_delete_fail;

pub use protocol_response::*;
pub use login_response::*;
Expand Down
13 changes: 13 additions & 0 deletions l2-core/src/enums.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#[repr(i32)]
#[derive(Clone, Debug)]
pub enum CharDeletionFailReasons {
None,
Unknown,
PledgeMember,
PledgeMaster,
ProhibitCharDeletion,
Commission,
Mentor,
Mentee,
Mail,
}
1 change: 1 addition & 0 deletions l2-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub mod shared_packets;
pub mod str;
pub mod tests;
pub mod traits;
pub mod enums;

#[allow(clippy::missing_errors_doc, clippy::missing_panics_doc)]
pub async fn hash_password(password: &str) -> anyhow::Result<String> {
Expand Down

0 comments on commit f795396

Please sign in to comment.