JaneDoe-ZS/nap_gameserver/src/handlers/client_systems.rs
YYHEggEgg 28864ff1e4 Teleport Map & Switching Dynamic Wallpaper Support, Gacha optimization ()
## Abstract

This PR implements

- Showing Teleports on map
- Quick Menu usage
- Dynamic Wallpaper switching
- Settings UP for Bangboo pool (via CLI)

## Support list

- The support of Teleport with map.
- Unlocking the 3 buttons (Interknow, DMs, Map) as a prerequisite of the previous feature. By pressing 'F' you can also modify the buttons in Quick Menu.
- Changing Dynamic Wallpaper to a specific one instead of being randomly chosen. **Notice that you can't use one's Dynamic Wallpaper if you don't own this agent.**
- Fixed some Gacha bugs, including:
  - Obtained items won't be sent to your bag unless you're pulling the standard banner;
  - Obtained items won't show in bag until relogin;
- Alternative command `gacha up` to choose the UP Bangboo. Start with `gacha up [player_uid]` and follow the guide to fill params.

## Principle

- Player's `UnlockModelBin` stores Quick Menu data, with the player's chosen buttons and their positions.
- Separate Gacha's DTO & Saving model to make it more standardized, and ensure ID validation is always performed.
- Player's bag information is now sync to client appropriately after finishing any gacha operations.
- `gacha up` search for pools with a `chooseable` Category Guarantee Policy, then list included items if user has provided the target pool's `gacha_schedule_id`.

## Known issues

- **Specifically for 1.1 Beta**, teleport may meet these issues leading to a 'black screen', forcing you to restart the client (or use `player kick` command as an alternative).
  - Don't try to teleport to `治安局光映分署`, it won't succeed. This is the 32nd teleport out of the 31 ones defined visible in assets.
  - Don't close the page after opening map. Teleport to somewhere.
- `gacha up` command is an alternative to in-game operation. You still can not see any bangboos in the collection when choosing Bangboo.

Co-authored-by: YYHEggEgg <53960525+YYHEggEgg@users.noreply.github.com>
Reviewed-on: 
Co-authored-by: YYHEggEgg <yyheggegg@xeondev.com>
Co-committed-by: YYHEggEgg <yyheggegg@xeondev.com>
2024-08-06 17:15:04 +00:00

263 lines
7.6 KiB
Rust

use crate::logic::{EOperator, ESystem};
use super::*;
use data::tables::{self, QuickFuncID};
pub async fn on_get_tips_info(
_session: &NetSession,
_player: &mut Player,
req: GetTipsInfoCsReq,
) -> NetResult<GetTipsInfoScRsp> {
Ok(GetTipsInfoScRsp {
retcode: Retcode::RetSucc.into(),
tips_info: Some(TipsInfo::default()),
r#type: req.r#type, // tips group type
})
}
pub async fn on_get_client_systems_info(
_session: &NetSession,
player: &mut Player,
_req: GetClientSystemsInfoCsReq,
) -> NetResult<GetClientSystemsInfoScRsp> {
let mut post_girl_data = PostGirlData {
post_girl_list: tables::post_girl_config_template_tb::iter()
.map(|template| PostGirlItem {
template_id: template.id.value(),
unlock_time: 1720052644,
})
.collect(),
..Default::default()
};
if let Some(post_girl_id) = player.basic_data_model.selected_post_girl_id {
post_girl_data
.selected_post_girl_id_list
.push(post_girl_id.value());
}
Ok(GetClientSystemsInfoScRsp {
retcode: Retcode::RetSucc.into(),
info: Some(ClientSystemsInfo {
post_girl_data: Some(post_girl_data),
unlock_data: Some(player.lock_model.to_client()),
calling_card_data: Some(CallingCardData::default()),
teleport_data: Some(TeleportData {
unlock_id_list: tables::teleport_config_template_tb::iter()
.filter(|template| template.client_visible > 0)
.map(|template| template.teleport_id.value())
.collect(),
..Default::default()
}),
..Default::default()
}),
})
}
pub async fn on_get_news_stand_data(
_session: &NetSession,
_player: &mut Player,
_req: GetNewsStandDataCsReq,
) -> NetResult<GetNewsStandDataScRsp> {
Ok(GetNewsStandDataScRsp {
retcode: Retcode::RetSucc.into(),
news_stand_data: Some(NewsStandData::default()),
})
}
pub async fn on_news_stand_seen(
_session: &NetSession,
_player: &mut Player,
_req: NewsStandSeenCsReq,
) -> NetResult<NewsStandSeenScRsp> {
Ok(NewsStandSeenScRsp {
retcode: Retcode::RetSucc.into(),
})
}
pub async fn on_get_trashbin_hermit_data(
_session: &NetSession,
_player: &mut Player,
_req: GetTrashbinHermitDataCsReq,
) -> NetResult<GetTrashbinHermitDataScRsp> {
Ok(GetTrashbinHermitDataScRsp {
retcode: Retcode::RetSucc.into(),
trashbin_hermit_data: Some(TrashbinHermitData::default()),
})
}
pub async fn on_get_exploration_data(
_session: &NetSession,
_player: &mut Player,
_req: GetExplorationDataCsReq,
) -> NetResult<GetExplorationDataScRsp> {
Ok(GetExplorationDataScRsp {
retcode: Retcode::RetSucc.into(),
..Default::default()
})
}
pub async fn on_report_ui_layout_platform(
_session: &NetSession,
_player: &mut Player,
_req: ReportUiLayoutPlatformCsReq,
) -> NetResult<ReportUiLayoutPlatformScRsp> {
Ok(ReportUiLayoutPlatformScRsp {
retcode: Retcode::RetSucc.into(),
})
}
pub async fn on_unlock_newbie_group(
_session: &NetSession,
_player: &mut Player,
req: UnlockNewbieGroupCsReq,
) -> NetResult<UnlockNewbieGroupScRsp> {
Ok(UnlockNewbieGroupScRsp {
retcode: Retcode::RetSucc.into(),
group_id: req.group_id,
})
}
pub async fn on_battle_report(
_session: &NetSession,
_player: &mut Player,
_req: BattleReportCsReq,
) -> NetResult<BattleReportScRsp> {
Ok(BattleReportScRsp {
retcode: Retcode::RetSucc.into(),
})
}
pub async fn on_player_operation(
_session: &NetSession,
_player: &mut Player,
req: PlayerOperationCsReq,
) -> NetResult<PlayerOperationScRsp> {
tracing::info!(
"PlayerOperation(system={:?}, operator={:?}, param={})",
ESystem::from(req.system),
EOperator::from(req.operator),
req.param
);
Ok(PlayerOperationScRsp {
retcode: Retcode::RetSucc.into(),
})
}
pub async fn on_player_system_parameter_change(
_session: &NetSession,
_player: &mut Player,
req: PlayerSystemParameterChangeCsReq,
) -> NetResult<PlayerSystemParameterChangeScRsp> {
tracing::info!(
"PlayerSystemParameterChange(type={}, param={})",
req.r#type,
req.params,
);
Ok(PlayerSystemParameterChangeScRsp {
retcode: Retcode::RetSucc.into(),
})
}
pub async fn on_pop_up_window_seen(
_session: &NetSession,
_player: &mut Player,
req: PopUpWindowSeenCsReq,
) -> NetResult<PopUpWindowSeenScRsp> {
Ok(PopUpWindowSeenScRsp {
retcode: Retcode::RetSucc.into(),
popup_group_id_list: req.popup_group_id_list,
})
}
pub async fn on_report_system_settings_change(
_session: &NetSession,
_player: &mut Player,
req: ReportSystemSettingsChangeCsReq,
) -> NetResult<ReportSystemSettingsChangeScRsp> {
tracing::info!("system settings change {req:?}");
Ok(ReportSystemSettingsChangeScRsp {
retcode: Retcode::RetSucc.into(),
})
}
pub async fn on_interact_with_scene_object(
_session: &NetSession,
_player: &mut Player,
_req: InteractWithSceneObjectCsReq,
) -> NetResult<InteractWithSceneObjectScRsp> {
// this request is used for interaction with STATIC scene objects (not controlled by server, e.g. door in workshop)
Ok(InteractWithSceneObjectScRsp {
retcode: Retcode::RetSucc.into(),
})
}
pub async fn on_mod_quick_menu(
_session: &NetSession,
_player: &mut Player,
_req: ModQuickMenuCsReq,
) -> NetResult<ModQuickMenuScRsp> {
let mut quick_access_data_list: Vec<QuickAccessData> = vec![];
for data in _req.quick_access_data_list.iter() {
quick_access_data_list.push(
_player
.lock_model
.mod_quick_access(data.quick_access_index, QuickFuncID::new(data.btn_id)),
);
}
_session
.notify(PlayerSyncScNotify {
client_systems_sync: Some(ClientSystemsSync {
quick_access_data_list: _player.lock_model.quick_access_to_client(),
..Default::default()
}),
..Default::default()
})
.await?;
Ok(ModQuickMenuScRsp {
retcode: Retcode::RetSucc.into(),
..Default::default()
})
}
pub async fn on_change_post_girl(
_session: &NetSession,
_player: &mut Player,
_req: ChangePostGirlCsReq,
) -> NetResult<ChangePostGirlScRsp> {
if _req.new_selected_post_girl_id_list.len() != 1 {
return Ok(ChangePostGirlScRsp {
retcode: Retcode::RetFail.into(),
..Default::default()
});
};
match tables::PostGirlConfigID::new(*_req.new_selected_post_girl_id_list.get(0).unwrap()) {
Some(post_girl_id) => {
_player.basic_data_model.selected_post_girl_id = Some(post_girl_id);
_session
.notify(PlayerSyncScNotify {
client_systems_sync: Some(ClientSystemsSync {
post_girl_data: Some(PostGirlSync {
selected_post_girl_id_list: vec![post_girl_id.value()],
..Default::default()
}),
..Default::default()
}),
..Default::default()
})
.await?;
Ok(ChangePostGirlScRsp {
retcode: Retcode::RetSucc.into(),
..Default::default()
})
}
None => Ok(ChangePostGirlScRsp {
retcode: Retcode::RetFail.into(),
..Default::default()
}),
}
}