Support for Nested combat messages and JSPatch Notify from files (#2)

Reviewed-on: Shorekeeper/Shorekeeper#2
Co-authored-by: xavo95 <xavo95@xeondev.com>
Co-committed-by: xavo95 <xavo95@xeondev.com>
This commit is contained in:
xavo95 2024-09-14 09:05:17 +00:00 committed by xeon
parent e5892ed9e5
commit 96d1994fe2
31 changed files with 159 additions and 60 deletions

View file

@ -1,4 +1,4 @@
FROM alpine:3.20 as release FROM alpine:3.20
ARG MICROSERVICE ARG MICROSERVICE
WORKDIR /app WORKDIR /app

View file

@ -4,7 +4,7 @@ pub trait TomlConfig: DeserializeOwned {
const DEFAULT_TOML: &str; const DEFAULT_TOML: &str;
} }
pub fn load_or_create<'a, C>(path: &str) -> C pub fn load_or_create<C>(path: &str) -> C
where where
C: DeserializeOwned + TomlConfig, C: DeserializeOwned + TomlConfig,
{ {

View file

@ -4,7 +4,7 @@ pub fn unix_timestamp() -> u64 {
SystemTime::now() SystemTime::now()
.duration_since(UNIX_EPOCH) .duration_since(UNIX_EPOCH)
.unwrap() .unwrap()
.as_secs() as u64 .as_secs()
} }
pub fn unix_timestamp_ms() -> u64 { pub fn unix_timestamp_ms() -> u64 {

View file

@ -26,10 +26,7 @@ macro_rules! impl_from_data {
impl Component for Attribute { impl Component for Attribute {
fn set_pb_data(&self, pb: &mut shorekeeper_protocol::EntityPb) { fn set_pb_data(&self, pb: &mut shorekeeper_protocol::EntityPb) {
pb.living_status = self pb.living_status = (if self.is_alive() { LivingStatus::Alive } else { LivingStatus::Dead })
.is_alive()
.then_some(LivingStatus::Alive)
.unwrap_or(LivingStatus::Dead)
.into(); .into();
pb.component_pbs.push(EntityComponentPb { pb.component_pbs.push(EntityComponentPb {

View file

@ -5,6 +5,7 @@ mod owner_player;
mod player_entity_marker; mod player_entity_marker;
mod position; mod position;
mod visibility; mod visibility;
mod weapon;
pub use attribute::Attribute; pub use attribute::Attribute;
pub use entity_config::EntityConfig; pub use entity_config::EntityConfig;
@ -13,3 +14,4 @@ pub use owner_player::OwnerPlayer;
pub use player_entity_marker::PlayerEntityMarker; pub use player_entity_marker::PlayerEntityMarker;
pub use position::Position; pub use position::Position;
pub use visibility::Visibility; pub use visibility::Visibility;
pub use weapon::Weapon;

View file

@ -0,0 +1,19 @@
use shorekeeper_protocol::{EntityComponentPb, EquipComponentPb};
use shorekeeper_protocol::entity_component_pb::ComponentPb;
use crate::logic::ecs::component::Component;
pub struct Weapon {
pub weapon_id: i32,
pub weapon_breach_level: i32,
}
impl Component for Weapon {
fn set_pb_data(&self, pb: &mut shorekeeper_protocol::EntityPb) {
pb.component_pbs.push(EntityComponentPb {
component_pb: Some(ComponentPb::EquipComponent(EquipComponentPb {
weapon_id: self.weapon_id,
weapon_breach_level: self.weapon_breach_level,
}))
})
}
}

View file

@ -30,6 +30,7 @@ impl_component_container! {
Attribute; Attribute;
PlayerEntityMarker; PlayerEntityMarker;
Movement; Movement;
Weapon;
} }
pub trait Component { pub trait Component {

View file

@ -59,6 +59,6 @@ macro_rules! query_components {
}), }),
)*) )*)
}) })
.unwrap_or_else(|| ($( crate::ident_as_none!($comp), )*)) .unwrap_or_else(|| ($( $crate::ident_as_none!($comp), )*))
}; };
} }

View file

@ -24,7 +24,7 @@ impl World {
pub fn create_entity(&mut self) -> EntityBuilder { pub fn create_entity(&mut self) -> EntityBuilder {
let entity = self.entity_manager.create(); let entity = self.entity_manager.create();
EntityBuilder::builder(entity, self.components.entry(entity).or_insert(Vec::new())) EntityBuilder::builder(entity, self.components.entry(entity).or_default())
} }
pub fn is_in_world(&self, entity_id: i64) -> bool { pub fn is_in_world(&self, entity_id: i64) -> bool {

View file

@ -4,23 +4,23 @@ pub use scene::*;
use shorekeeper_protocol::message::Message; use shorekeeper_protocol::message::Message;
macro_rules! handle_request { macro_rules! handle_request {
($($name:ident;)*) => { ($($name:ident $(, $inner_package:ident)?;)*) => {
fn handle_request(player: &mut super::player::Player, mut msg: Message) { fn handle_request(player: &mut super::player::Player, mut msg: Message) {
use ::shorekeeper_protocol::{MessageID, Protobuf}; use ::shorekeeper_protocol::{MessageID, Protobuf};
::paste::paste! { ::paste::paste! {
match msg.get_message_id() { match msg.get_message_id() {
$( $(
::shorekeeper_protocol::[<$name Request>]::MESSAGE_ID => { ::shorekeeper_protocol::$($inner_package::)?[<$name Request>]::MESSAGE_ID => {
let Ok(request) = ::shorekeeper_protocol::[<$name Request>]::decode(&*msg.remove_payload()) else { let Ok(request) = ::shorekeeper_protocol::$($inner_package::)?[<$name Request>]::decode(&*msg.remove_payload()) else {
tracing::debug!("failed to decode {}, player_id: {}", stringify!([<$name Request>]), player.basic_info.id); tracing::debug!("failed to decode {}, player_id: {}", stringify!($($inner_package::)?[<$name Request>]), player.basic_info.id);
return; return;
}; };
tracing::debug!("logic: processing request {}", stringify!([<$name Request>])); tracing::debug!("logic: processing request {}", stringify!($($inner_package::)?[<$name Request>]));
let mut response = ::shorekeeper_protocol::[<$name Response>]::default(); let mut response = ::shorekeeper_protocol::$($inner_package::)?[<$name Response>]::default();
[<on_ $name:snake _request>](player, request, &mut response); [<on_ $($inner_package:snake _)? $name:snake _request>](player, request, &mut response);
player.respond(response, msg.get_rpc_id()); player.respond(response, msg.get_rpc_id());
}, },
@ -33,20 +33,22 @@ macro_rules! handle_request {
} }
macro_rules! handle_push { macro_rules! handle_push {
($($name:ident;)*) => { ($($name:ident $(, $inner_package:ident)?;)*) => {
fn handle_push(player: &mut super::player::Player, mut msg: Message) { fn handle_push(player: &mut super::player::Player, mut msg: Message) {
use ::shorekeeper_protocol::{MessageID, Protobuf}; use ::shorekeeper_protocol::{MessageID, Protobuf};
::paste::paste! { ::paste::paste! {
match msg.get_message_id() { match msg.get_message_id() {
$( $(
::shorekeeper_protocol::[<$name Push>]::MESSAGE_ID => { ::shorekeeper_protocol::$($inner_package::)?[<$name Push>]::MESSAGE_ID => {
let Ok(push) = ::shorekeeper_protocol::[<$name Push>]::decode(&*msg.remove_payload()) else { let Ok(push) = ::shorekeeper_protocol::$($inner_package::)?[<$name Push>]::decode(&*msg.remove_payload()) else {
tracing::debug!("failed to decode {}, player_id: {}", stringify!([<$name Push>]), player.basic_info.id); tracing::debug!("failed to decode {}, player_id: {}", stringify!($($inner_package::)?[<$name Push>]), player.basic_info.id);
return; return;
}; };
[<on_ $name:snake _push>](player, push); tracing::debug!("logic: processing push {}", stringify!($($inner_package::)?[<$name Push>]));
[<on_ $($inner_package:snake _)? $name:snake _push>](player, push);
}, },
)* )*
unhandled => ::tracing::warn!("can't find handler for push with message_id={unhandled}") unhandled => ::tracing::warn!("can't find handler for push with message_id={unhandled}")
@ -60,6 +62,7 @@ handle_request! {
UpdateSceneDate; UpdateSceneDate;
EntityActive; EntityActive;
EntityOnLanded; EntityOnLanded;
CombatSendPack, combat_message;
} }
handle_push! { handle_push! {

View file

@ -2,6 +2,7 @@ use shorekeeper_protocol::{
EntityActiveRequest, EntityActiveResponse, EntityOnLandedRequest, EntityOnLandedResponse, EntityActiveRequest, EntityActiveResponse, EntityOnLandedRequest, EntityOnLandedResponse,
ErrorCode, MovePackagePush, UpdateSceneDateRequest, UpdateSceneDateResponse, ErrorCode, MovePackagePush, UpdateSceneDateRequest, UpdateSceneDateResponse,
}; };
use shorekeeper_protocol::combat_message::{CombatSendPackRequest, CombatSendPackResponse};
use crate::{logic::ecs::component::ComponentContainer, logic::player::Player, query_components}; use crate::{logic::ecs::component::ComponentContainer, logic::player::Player, query_components};
@ -13,6 +14,14 @@ pub fn on_update_scene_date_request(
response.error_code = ErrorCode::Success.into(); response.error_code = ErrorCode::Success.into();
} }
pub fn on_combat_message_combat_send_pack_request(
_player: &Player,
_request: CombatSendPackRequest,
response: &mut CombatSendPackResponse,
) {
response.error_code = ErrorCode::Success.into();
}
pub fn on_entity_active_request( pub fn on_entity_active_request(
player: &Player, player: &Player,
request: EntityActiveRequest, request: EntityActiveRequest,

View file

@ -43,7 +43,7 @@ impl Player {
// we need shorekeeper // we need shorekeeper
// TODO: remove this part after implementing team switch // TODO: remove this part after implementing team switch
if !self.role_list.iter().any(|r| r.role_id == 1505) { if !self.role_list.iter().any(|r| r.role_id == 1505) {
self.role_list.push(Role::new(1505)); self.role_list.push(Role::new(1505, Some(21050036)));
} }
self.formation_list.clear(); self.formation_list.clear();
@ -126,8 +126,7 @@ impl Player {
.unwrap() .unwrap()
.role_id_set .role_id_set
.iter() .iter()
.map(|id| self.role_list.iter().find(|r| r.role_id == *id)) .flat_map(|id| self.role_list.iter().find(|r| r.role_id == *id))
.flatten()
.collect() .collect()
} }
@ -217,8 +216,8 @@ impl Player {
fn create_main_character_role(name: String, sex: i32) -> Role { fn create_main_character_role(name: String, sex: i32) -> Role {
let mut role = match sex { let mut role = match sex {
0 => Role::new(Role::MAIN_CHARACTER_FEMALE_ID), 0 => Role::new(Role::MAIN_CHARACTER_FEMALE_ID, None),
1 => Role::new(Role::MAIN_CHARACTER_MALE_ID), 1 => Role::new(Role::MAIN_CHARACTER_MALE_ID, None),
_ => unreachable!(), _ => unreachable!(),
}; };

View file

@ -1,12 +1,11 @@
use std::collections::HashMap; use std::collections::HashMap;
use common::time_util; use common::time_util;
pub use formation::RoleFormation;
use shorekeeper_data::role_info_data; use shorekeeper_data::role_info_data;
use shorekeeper_protocol::{ArrayIntInt, RoleData, RoleInfo}; use shorekeeper_protocol::{ArrayIntInt, RoleData, RoleInfo};
mod formation; mod formation;
pub use formation::RoleFormation;
pub struct Role { pub struct Role {
pub role_id: i32, pub role_id: i32,
pub name: String, pub name: String,
@ -17,14 +16,19 @@ pub struct Role {
pub star: i32, pub star: i32,
pub favor: i32, pub favor: i32,
pub create_time: u32, pub create_time: u32,
pub equip_weapon: i32,
} }
impl Role { impl Role {
pub const MAIN_CHARACTER_MALE_ID: i32 = 1501; pub const MAIN_CHARACTER_MALE_ID: i32 = 1501;
pub const MAIN_CHARACTER_FEMALE_ID: i32 = 1502; pub const MAIN_CHARACTER_FEMALE_ID: i32 = 1502;
pub fn new(role_id: i32) -> Self { pub fn new(role_id: i32, weapon_id: Option<i32>) -> Self {
let data = role_info_data::iter().find(|d| d.id == role_id).unwrap(); let data = role_info_data::iter().find(|d| d.id == role_id).unwrap();
let equip_weapon = match weapon_id {
None => data.init_weapon_item_id,
Some(x) => x,
};
Self { Self {
role_id, role_id,
@ -36,6 +40,7 @@ impl Role {
star: 0, star: 0,
favor: 0, favor: 0,
create_time: time_util::unix_timestamp() as u32, create_time: time_util::unix_timestamp() as u32,
equip_weapon,
} }
} }
@ -69,6 +74,7 @@ impl Role {
star: data.star, star: data.star,
favor: data.favor, favor: data.favor,
create_time: data.create_time, create_time: data.create_time,
equip_weapon: data.equip_weapon,
} }
} }
@ -83,6 +89,7 @@ impl Role {
star: self.star, star: self.star,
favor: self.favor, favor: self.favor,
create_time: self.create_time, create_time: self.create_time,
equip_weapon: self.equip_weapon,
..Default::default() ..Default::default()
} }
} }

View file

@ -11,8 +11,9 @@ use std::{
}; };
use common::time_util; use common::time_util;
use shorekeeper_protocol::{message::Message, JoinSceneNotify, TransitionOptionPb}; use shorekeeper_protocol::{message::Message, JoinSceneNotify, TransitionOptionPb,
use shorekeeper_protocol::{AfterJoinSceneNotify, EnterGameResponse, PlayerSaveData}; AfterJoinSceneNotify, EnterGameResponse, JsPatchNotify};
use shorekeeper_protocol::{PlayerSaveData};
use crate::{ use crate::{
player_save_task::{self, PlayerSaveReason}, player_save_task::{self, PlayerSaveReason},
@ -21,6 +22,9 @@ use crate::{
use super::{ecs::world::World, player::Player, utils::world_util}; use super::{ecs::world::World, player::Player, utils::world_util};
const WATER_MASK: &str = include_str!("../../watermask.js");
const UID_FIX: &str = include_str!("../../uidfix.js");
pub enum LogicInput { pub enum LogicInput {
AddPlayer { AddPlayer {
player_id: i32, player_id: i32,
@ -105,8 +109,7 @@ fn logic_thread_func(receiver: mpsc::Receiver<LogicInput>, load: Arc<AtomicUsize
let mut world = world.borrow_mut(); let mut world = world.borrow_mut();
let mut players = world let mut players = world
.player_ids() .player_ids()
.map(|id| state.players.get(id).map(|pl| pl.borrow_mut())) .flat_map(|id| state.players.get(id).map(|pl| pl.borrow_mut()))
.flatten()
.collect::<Box<_>>(); .collect::<Box<_>>();
super::systems::tick_systems(&mut world, &mut players); super::systems::tick_systems(&mut world, &mut players);
@ -164,6 +167,14 @@ fn handle_logic_input(state: &mut LogicState, input: LogicInput) {
scene_info: Some(scene_info), scene_info: Some(scene_info),
transition_option: Some(TransitionOptionPb::default()), transition_option: Some(TransitionOptionPb::default()),
}); });
player.notify(JsPatchNotify {
content: WATER_MASK.to_string(),
});
player.notify(JsPatchNotify {
content: UID_FIX
.replace("{PLAYER_USERNAME}", &player.basic_info.name)
.replace("{SELECTED_COLOR}", "50FC71"),
});
player.respond(EnterGameResponse::default(), enter_rpc_id); player.respond(EnterGameResponse::default(), enter_rpc_id);
player.notify(AfterJoinSceneNotify::default()); player.notify(AfterJoinSceneNotify::default());

View file

@ -11,8 +11,7 @@ pub fn build_scene_add_on_init_data(world: &World) -> PlayerSceneAoiData {
let mut aoi_data = PlayerSceneAoiData::default(); let mut aoi_data = PlayerSceneAoiData::default();
for entity in entities { for entity in entities {
let mut pb = EntityPb::default(); let mut pb = EntityPb { id: entity.into(), ..Default::default() };
pb.id = entity.into();
world world
.get_entity_components(entity) .get_entity_components(entity)

View file

@ -8,14 +8,13 @@ use crate::{
logic::{ logic::{
components::{ components::{
Attribute, EntityConfig, Movement, OwnerPlayer, PlayerEntityMarker, Position, Attribute, EntityConfig, Movement, OwnerPlayer, PlayerEntityMarker, Position,
Visibility, Visibility, Weapon
}, },
ecs::{component::ComponentContainer, world::World}, ecs::{component::ComponentContainer, world::World},
player::Player, player::Player,
}, },
query_with, query_with,
}; };
use super::entity_serializer; use super::entity_serializer;
pub fn add_player_entities(world: &mut World, player: &Player) { pub fn add_player_entities(world: &mut World, player: &Player) {
@ -44,6 +43,10 @@ pub fn add_player_entities(world: &mut World, player: &Player) {
.unwrap(), .unwrap(),
))) )))
.with(ComponentContainer::Movement(Movement::default())) .with(ComponentContainer::Movement(Movement::default()))
.with(ComponentContainer::Weapon(Weapon {
weapon_id: role.equip_weapon,
weapon_breach_level: 0, // TODO: store this too
}))
.build(); .build();
tracing::debug!( tracing::debug!(

9
game-server/uidfix.js Normal file
View file

@ -0,0 +1,9 @@
setTimeout(() => {
const UiManager_1 = require("../Ui/UiManager");
const UE = require("ue");
const ControllerManagerBase_1 = require("../../Core/Framework/ControllerManagerBase");
const UiText = UiManager_1.UiManager.GetViewByName("UidView").GetText(0);
UiText.SetText("{PLAYER_USERNAME} - Reversed Rooms");
UiText.SetColor(UE. Color.FromHex("{SELECTED_COLOR}"));
}, 10000);

38
game-server/watermask.js Normal file
View file

@ -0,0 +1,38 @@
const UE = require("ue"),
Info_1 = require("../../../Core/Common/Info"),
MathUtils_1 = require("../../../Core/Utils/MathUtils"),
EventDefine_1 = require("../../Common/Event/EventDefine"),
EventSystem_1 = require("../../Common/Event/EventSystem"),
UiControllerBase_1 = require("../../Ui/Base/UiControllerBase"),
UiLayerType_1 = require("../../Ui/Define/UiLayerType"),
UiLayer_1 = require("../../Ui/UiLayer");
var _a = require('../Module/WaterMask/WaterMaskController').WaterMaskView;
_a.vOo = function () {
void 0 !== _a.SOo && _a.EOo();
var e = UiLayer_1.UiLayer.GetLayerRootUiItem(UiLayerType_1.ELayerType.WaterMask),
t = (_a.SOo = UE.KuroActorManager.SpawnActor(Info_1.Info.World, UE.UIContainerActor.StaticClass(),
MathUtils_1.MathUtils.DefaultTransform, void 0), _a.SOo.RootComponent),
e = (t.SetDisplayName("WaterMaskContainer"), UE.KuroStaticLibrary.SetActorPermanent(_a.SOo, !0, !0), _a.SOo
.K2_AttachRootComponentTo(e), t.GetRootCanvas().GetOwner().RootComponent),
i = e.widget.width % _a.yOo / 2,
r = e.widget.height % _a.IOo / 2,
n = e.widget.width / 2,
_ = e.widget.height / 2,
s = Math.ceil(e.widget.width / _a.yOo),
o = Math.ceil(e.widget.height / _a.IOo),
v = "discord.gg/reversedrooms";
for (let a = 0; a < s; a++)
for (let e = 0; e < o; e++) {
var E = UE.KuroActorManager.SpawnActor(Info_1.Info.World, UE.UITextActor.StaticClass(), MathUtils_1
.MathUtils.DefaultTransform, void 0),
U = E.RootComponent,
U = (E.K2_AttachRootComponentTo(t), U.SetDisplayName("WaterMaskText"), E.GetComponentByClass(UE
.UIText.StaticClass()));
U.SetFontSize(_a.vFt), U.SetOverflowType(0), U.SetAlpha(_a.LOo), U.SetFont(UE.LGUIFontData
.GetDefaultFont()), U.SetText(v), U.SetUIRelativeLocation(new UE.Vector(a * _a.yOo - n + i, e *
_a.IOo - _ + r, 0)), U.SetUIRelativeRotation(new UE.Rotator(0, _a.TOo, 0)), UE.KuroStaticLibrary
.SetActorPermanent(E, !0, !0)
}
};
_a.vOo();

View file

@ -867,7 +867,7 @@ impl<Output> Kcp<Output> {
} }
let mut ts_flush = self.ts_flush; let mut ts_flush = self.ts_flush;
let mut tm_packet = u32::max_value(); let mut tm_packet = u32::MAX;
if timediff(current, ts_flush) >= 10000 || timediff(current, ts_flush) < -10000 { if timediff(current, ts_flush) >= 10000 || timediff(current, ts_flush) < -10000 {
ts_flush = current; ts_flush = current;
@ -1142,7 +1142,7 @@ impl<Output: Write> Kcp<Output> {
let resent = if self.fastresend > 0 { let resent = if self.fastresend > 0 {
self.fastresend self.fastresend
} else { } else {
u32::max_value() u32::MAX
}; };
let rtomin = if !self.nodelay { self.rx_rto >> 3 } else { 0 }; let rtomin = if !self.nodelay { self.rx_rto >> 3 } else { 0 };
@ -1381,7 +1381,7 @@ impl<Output: AsyncWrite + Unpin + Send> Kcp<Output> {
let resent = if self.fastresend > 0 { let resent = if self.fastresend > 0 {
self.fastresend self.fastresend
} else { } else {
u32::max_value() u32::MAX
}; };
let rtomin = if !self.nodelay { self.rx_rto >> 3 } else { 0 }; let rtomin = if !self.nodelay { self.rx_rto >> 3 } else { 0 };

View file

@ -140,7 +140,7 @@ async fn on_login_request(
session.player_id = Some(player_id); session.player_id = Some(player_id);
response.code = ErrorCode::Success.into(); response.code = ErrorCode::Success.into();
response.timestamp = time_util::unix_timestamp() as i64; response.timestamp = time_util::unix_timestamp_ms() as i64;
tracing::info!( tracing::info!(
"login success, user_id: {}, player_id: {}", "login success, user_id: {}, player_id: {}",

View file

@ -155,11 +155,11 @@ impl Session {
fn next_message(&mut self) -> Option<Message> { fn next_message(&mut self) -> Option<Message> {
self.decoder.pop_with(|buf| { self.decoder.pop_with(|buf| {
Message::decode(&buf) Message::decode(buf)
.inspect_err(|err| { .inspect_err(|err| {
tracing::error!( tracing::error!(
"failed to decode a message, err: {err}, buf: {}", "failed to decode a message, err: {err}, buf: {}",
hex::encode(&buf) hex::encode(buf)
) )
}) })
.ok() .ok()

View file

@ -15,8 +15,7 @@ impl LengthFieldBasedDecoder {
pub fn input(&mut self, data: &[u8]) { pub fn input(&mut self, data: &[u8]) {
self.ensure_capacity(data.len()); self.ensure_capacity(data.len());
self.buffer[self.cur_index..self.cur_index + data.len()].copy_from_slice(data);
(&mut self.buffer[self.cur_index..self.cur_index + data.len()]).copy_from_slice(data);
self.cur_index += data.len(); self.cur_index += data.len();
} }

View file

@ -64,7 +64,7 @@ impl UdpServer {
conv_id, conv_id,
addr, addr,
self.socket.clone(), self.socket.clone(),
&self.protokey_helper, self.protokey_helper,
self.db.clone(), self.db.clone(),
); );
self.session_mgr.add(conv_id, session); self.session_mgr.add(conv_id, session);

View file

@ -11,13 +11,10 @@ pub async fn handle_login_api_call(
tracing::debug!("login requested"); tracing::debug!("login requested");
let user_data = parameters.user_data; let user_data = parameters.user_data;
let result = match login(&state, parameters).await { let result = login(&state, parameters).await.unwrap_or_else(|err| {
Ok(result) => result,
Err(err) => {
tracing::warn!("login: internal error occurred {err:?}"); tracing::warn!("login: internal error occurred {err:?}");
schema::LoginResult::error(-1, String::from("Internal server error")) schema::LoginResult::error(-1, String::from("Internal server error"))
} });
};
Json(result.with_user_data(user_data)) Json(result.with_user_data(user_data))
} }
@ -32,7 +29,7 @@ async fn login(state: &ServiceState, params: schema::LoginParameters) -> Result<
Some(account) => { Some(account) => {
if let Some(ban_time_stamp) = account.ban_time_stamp { if let Some(ban_time_stamp) = account.ban_time_stamp {
if time_util::unix_timestamp() < ban_time_stamp as u64 { if time_util::unix_timestamp() < ban_time_stamp as u64 {
return Ok(schema::LoginResult::banned(String::from("You're banned MF"), ban_time_stamp as i64)); return Ok(schema::LoginResult::banned(String::from("You're banned MF"), ban_time_stamp));
} }
} }

View file

@ -24,6 +24,12 @@ pub struct Application<S> {
impl Application<()> { impl Application<()> {
pub fn new() -> Self { pub fn new() -> Self {
Default::default()
}
}
impl Default for Application<()> {
fn default() -> Self {
Self { Self {
router: Router::new(), router: Router::new(),
state: (), state: (),

View file

@ -15,7 +15,7 @@ impl ServiceMessage {
w.write_u16::<LE>(self.rpc_id)?; w.write_u16::<LE>(self.rpc_id)?;
w.write_u16::<LE>(self.message_id)?; w.write_u16::<LE>(self.message_id)?;
w.write_u32::<LE>(self.data.len() as u32)?; w.write_u32::<LE>(self.data.len() as u32)?;
w.write(&self.data)?; w.write_all(&self.data)?;
Ok(()) Ok(())
} }

View file

@ -28,8 +28,7 @@ impl ServiceListener {
for message in data for message in data
.into_vec() .into_vec()
.into_iter() .into_iter()
.map(|b| ServiceMessage::decode(b.as_ref())) .flat_map(|b| ServiceMessage::decode(b.as_ref()))
.flatten()
{ {
let _ = sender.send(message).await; let _ = sender.send(message).await;
} }

View file

@ -15,7 +15,7 @@ pub fn main() {
let config_path = Path::new("proto/config.csv"); let config_path = Path::new("proto/config.csv");
if config_path.exists() { if config_path.exists() {
println!("cargo:rerun-if-changed={config_file}"); println!("cargo:rerun-if-changed={config_file}");
impl_proto_config(config_path, &Path::new("generated/proto_config.rs")).unwrap(); impl_proto_config(config_path, Path::new("generated/proto_config.rs")).unwrap();
} }
let proto_file = "proto/shorekeeper.proto"; let proto_file = "proto/shorekeeper.proto";

View file

@ -43,6 +43,7 @@ message RoleData {
repeated int32 models = 12; repeated int32 models = 12;
repeated RoleSkillNodeData skill_node_state = 13; repeated RoleSkillNodeData skill_node_state = 13;
int32 resonant_chain_group_index = 14; int32 resonant_chain_group_index = 14;
int32 equip_weapon = 15;
} }
message RoleFormationData { message RoleFormationData {

View file

@ -92,7 +92,7 @@ impl Message {
let recv_crc = r.read_u32::<LE>()?; let recv_crc = r.read_u32::<LE>()?;
let mut payload = vec![0u8; src.len() - r.position() as usize].into_boxed_slice(); let mut payload = vec![0u8; src.len() - r.position() as usize].into_boxed_slice();
r.read(&mut payload)?; let _ = r.read(&mut payload)?;
let calc_crc = crc32fast::hash(&payload); let calc_crc = crc32fast::hash(&payload);

View file

@ -187,6 +187,6 @@ fn encrypt_aes256_ecb_pkcs7(
) -> Result<Box<[u8]>, InvalidLength> { ) -> Result<Box<[u8]>, InvalidLength> {
let cipher = Aes256::new_from_slice(session_key)?; let cipher = Aes256::new_from_slice(session_key)?;
Ok(cipher Ok(cipher
.encrypt_padded_vec::<Pkcs7>(&data[..]) .encrypt_padded_vec::<Pkcs7>(data)
.into_boxed_slice()) .into_boxed_slice())
} }