Compare commits

..

No commits in common. "5e68a19066e8ed13e29d1122f0b16e24886309b8" and "4d9035b66342d7dcffb54cc6b9d7e0d525fc998c" have entirely different histories.

50 changed files with 2612 additions and 1800 deletions

View file

@ -1,30 +0,0 @@
// Folder-specific settings
//
// For a full list of overridable settings, and general information on folder-specific settings,
// see the documentation: https://zed.dev/docs/configuring-zed#settings-files
{
"lsp": {
"rust-analyzer": {
"initialization_options": {
// get more cargo-less diagnostics from rust-analyzer,
// which might include false-positives (those can be turned off by their names)
"diagnostics": {
"experimental": {
"enable": true
}
},
// To disable the checking entirely
// (ignores all cargo and check settings below)
"checkOnSave": false,
// To check the `lib` target only.
"cargo": {
"allTargets": false
},
// Use `-p` instead of `--workspace` for cargo check
"check": {
"workspace": false
}
}
}
}
}

461
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
[workspace]
members = ["wicked-waifus-asset-updater", "wicked-waifus-commons", "wicked-waifus-config-server", "wicked-waifus-hotpatch-server", "wicked-waifus-login-server", "wicked-waifus-gateway-server", "wicked-waifus-database", "wicked-waifus-http", "wicked-waifus-protokey", "wicked-waifus-protocol-internal", "wicked-waifus-game-server", "wicked-waifus-network", "wicked-waifus-data"]
members = ["wicked-waifus-asset-updater", "wicked-waifus-commons", "wicked-waifus-config-server", "wicked-waifus-hotpatch-server", "wicked-waifus-login-server", "wicked-waifus-gateway-server", "wicked-waifus-gateway-server/kcp", "wicked-waifus-database", "wicked-waifus-http", "wicked-waifus-protokey", "wicked-waifus-protocol-internal", "wicked-waifus-game-server", "wicked-waifus-network", "wicked-waifus-data"]
resolver = "2"
[workspace.package]
@ -46,6 +46,7 @@ tracing = "0.1.40"
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
# Internal
kcp = { path = "wicked-waifus-gateway-server/kcp" }
wicked-waifus-asset-updater = { path = "wicked-waifus-asset-updater" }
wicked-waifus-commons = { path = "wicked-waifus-commons" }
wicked-waifus-http = { path = "wicked-waifus-http" }

View file

@ -11,5 +11,5 @@ serve_dir_path = "data/assets/config-server"
[asset_config]
repository_url = "https://git.xeondev.com/wickedwaifus/wicked-waifus-config-server-files.git"
reference = "f088e91db3"
reference = "8f109f2724"
discard_local_changes = true

View file

@ -47,6 +47,21 @@ pub struct BasePropertyData {
pub damage_reduce_element4: i32,
pub damage_reduce_element5: i32,
pub damage_reduce_element6: i32,
pub reaction_change1: i32,
pub reaction_change2: i32,
pub reaction_change3: i32,
pub reaction_change4: i32,
pub reaction_change5: i32,
pub reaction_change6: i32,
pub reaction_change7: i32,
pub reaction_change8: i32,
pub reaction_change9: i32,
pub reaction_change10: i32,
pub reaction_change11: i32,
pub reaction_change12: i32,
pub reaction_change13: i32,
pub reaction_change14: i32,
pub reaction_change15: i32,
pub energy_max: i32,
pub energy: i32,
pub special_energy_1_max: i32,

View file

@ -138,7 +138,6 @@ json_data! {
LevelPlayNodeData;
LivenessTask;
LordGym;
ModelConfigPreload;
MonsterDetection;
MonsterPropertyGrowth;
Motion;
@ -150,7 +149,6 @@ json_data! {
RoleInfo;
RoleLevelConsume;
RolePropertyGrowth;
RoleSkin;
SilentAreaDetection;
SynthesisFormula;
Teleporter;

View file

@ -68,8 +68,6 @@ pub enum GachaViewTypeInfoId {
StandardResonatorConvene = 4,
StandardWeaponConvene = 5,
BeginnersChoiceConvene = 6,
MultipleChoiceResonatorConvene = 7,
MultipleChoiceWeaponConvene = 8,
}
#[derive(Debug, Deserialize, Clone)]
@ -122,7 +120,6 @@ pub enum EntityType {
ControlConnector,
ConveyorBelt,
CookTool,
CurveControlDestructible,
CustomAoiEditor,
Destructible,
DestructibleControl,
@ -135,7 +132,6 @@ pub enum EntityType {
DynamicPortalCreater,
EffectArea,
EnrichmentArea,
EntityBatchRefresh,
EntityBundle,
EntityList,
EntityPackage,
@ -167,7 +163,6 @@ pub enum EntityType {
LevelPlay,
LevelPlayReward,
LevelQteTrigger,
LevelSeqTrigger,
LevitateMagnet,
LifePointCenter,
Lift,
@ -207,19 +202,16 @@ pub enum EntityType {
SimpleInteract,
SimpleNPc,
SkyboxTrigger,
SlideRail,
SoundBox,
SpawnMonster,
SpawnPasserbyNpc,
Spline,
SplineRange,
SummonGongduolaPoint,
StateSceneItem,
StateTrigger,
StatueFoundation,
SuiGuangHook,
TargetGear,
TargetGear2,
TargetGearGroup,
TargetGearGroup2,
TargetGearPro,
@ -228,7 +220,6 @@ pub enum EntityType {
TeleControl3,
TeleControlGroup,
Teleporter,
TemplateEntitySpawner,
TemporaryTeleporter,
TimedStrikeDevice,
TimelineTrackController,

View file

@ -1,26 +0,0 @@
use serde::Deserialize;
#[derive(Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct ModelConfigPreloadData {
pub id: i32,
pub actor_class_path: String,
#[cfg(feature = "strict_json_fields")]
pub actor_class: Vec<String>,
#[cfg(feature = "strict_json_fields")]
pub animations: Vec<String>,
#[cfg(feature = "strict_json_fields")]
pub effects: Vec<String>,
#[cfg(feature = "strict_json_fields")]
pub audios: Vec<String>,
#[cfg(feature = "strict_json_fields")]
pub meshes: Vec<String>,
#[cfg(feature = "strict_json_fields")]
pub materials: Vec<String>,
#[cfg(feature = "strict_json_fields")]
pub animation_blueprints: Vec<String>,
#[cfg(feature = "strict_json_fields")]
pub others: Vec<String>,
}

View file

@ -217,15 +217,6 @@ pub struct NodeDataDetailAction {
pub actions: Vec<Action>,
}
#[derive(Debug, Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct NodeDataDetailActionWithResult {
#[serde(flatten)]
pub common: NodeDataDetailCommon,
pub action: Action,
}
#[derive(Debug, Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
@ -267,7 +258,6 @@ pub enum NodeDataDetail {
Repeater(NodeDataDetailRepeater),
Condition(NodeDataDetailCondition),
Action(NodeDataDetailAction),
ActionWithResult(NodeDataDetailActionWithResult),
QuestSucceed(NodeDataDetailQuestSucceed),
QuestFailed(NodeDataDetailQuestFailed),
AlwaysFalse(NodeDataDetailAlways),

View file

@ -196,8 +196,7 @@ pub enum LeisureInteractOption {
FailurePose,
GameplayPose1,
GameplayPose2,
GameplayPose3,
FaithJump
GameplayPose3
}
#[derive(Deserialize, Debug, Clone)]
@ -509,11 +508,6 @@ pub struct CameraLookAt {
pub camera_pos: Option<Point>,
}
#[derive(Deserialize, Debug, Clone)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct StopCameraLookAt {}
#[derive(Deserialize, Debug, Clone)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
@ -2263,94 +2257,6 @@ pub struct ActiveAntiGravitySafePoint {
pub config: serde_json::Value,
}
#[derive(Deserialize, Debug, Clone)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct BvbPlayDialog {
#[cfg(feature = "strict_json_fields")]
pub config: serde_json::Value,
}
#[derive(Deserialize, Debug, Clone)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct BvbSendSystemEvent {
#[cfg(feature = "strict_json_fields")]
pub config: serde_json::Value,
}
#[derive(Deserialize, Debug, Clone)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct BvbSendAiEvent {
#[cfg(feature = "strict_json_fields")]
pub config: serde_json::Value,
}
#[derive(Deserialize, Debug, Clone)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct BvbPlayerOperationConstraint {
#[cfg(feature = "strict_json_fields")]
pub config: serde_json::Value,
}
#[derive(Deserialize, Debug, Clone)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct ExecClientBattleAction {
#[cfg(feature = "strict_json_fields")]
pub config: serde_json::Value,
}
#[derive(Deserialize, Debug, Clone)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct TriggerSpecificScanEffect {
#[cfg(feature = "strict_json_fields")]
pub config: serde_json::Value,
}
#[derive(Deserialize, Debug, Clone)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct SetActorVar {
#[cfg(feature = "strict_json_fields")]
pub config: serde_json::Value,
}
#[derive(Deserialize, Debug, Clone)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct RunActorCustomEvent {
#[cfg(feature = "strict_json_fields")]
pub config: serde_json::Value,
}
#[derive(Deserialize, Debug, Clone)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct StopUiScreenEffect {
#[cfg(feature = "strict_json_fields")]
pub config: serde_json::Value,
}
#[derive(Deserialize, Debug, Clone)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct StopNewMoveWithSpline {
#[cfg(feature = "strict_json_fields")]
pub config: serde_json::Value,
}
#[derive(Deserialize, Debug, Clone)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct RequestSystemFunction {
#[cfg(feature = "strict_json_fields")]
pub config: serde_json::Value,
}
#[derive(Deserialize, Debug, Clone)]
#[serde(tag = "Name")]
pub enum Action {
@ -2373,7 +2279,6 @@ pub enum Action {
TeleportDungeon(ActionFields<TeleportDungeon>),
DestroySelf(ActionFields<DestroySelf>),
CameraLookAt(ActionFields<CameraLookAt>),
StopCameraLookAt(ActionFields<StopCameraLookAt>),
EnterOrbitalCamera(ActionFields<EnterOrbitalCamera>),
ExitOrbitalCamera(ActionFields<ExitOrbitalCamera>),
SendAiEvent(ActionFields<SendAiEvent>),
@ -2527,17 +2432,6 @@ pub enum Action {
GetRewardByInteract(ActionFields<GetRewardByInteract>),
OpenQte(ActionFields<OpenQte>),
ActiveAntiGravitySafePoint(ActionFields<ActiveAntiGravitySafePoint>),
BvbPlayDialog(ActionFields<BvbPlayDialog>),
BvbSendSystemEvent(ActionFields<BvbSendSystemEvent>),
BvbSendAiEvent(ActionFields<BvbSendAiEvent>),
BvbPlayerOperationConstraint(ActionFields<BvbPlayerOperationConstraint>),
ExecClientBattleAction(ActionFields<ExecClientBattleAction>),
TriggerSpecificScanEffect(ActionFields<TriggerSpecificScanEffect>),
SetActorVar(ActionFields<SetActorVar>),
RunActorCustomEvent(ActionFields<RunActorCustomEvent>),
StopUiScreenEffect(ActionFields<StopUiScreenEffect>),
StopNewMoveWithSpline(ActionFields<StopNewMoveWithSpline>),
RequestSystemFunction(ActionFields<RequestSystemFunction>),
}
#[derive(Deserialize, Debug, Clone)]

View file

@ -335,7 +335,6 @@ pub struct UsingVehicle {
pub enum VehicleType {
FishingBoat,
Gongduola,
SceneItemAutoMoveVehicle,
}
#[derive(Deserialize, Debug, Clone)]
@ -758,13 +757,6 @@ pub struct AddFlowInteractOption {
pub config: serde_json::Value,
}
#[derive(Deserialize, Debug, Clone)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct MonsterMergedHpBarSettings {
pub display_buff_ids: Vec<i64>,
}
#[derive(Deserialize, Debug, Clone)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase", deny_unknown_fields)]
@ -773,7 +765,6 @@ pub struct MonsterCreator {
pub prefab_var: Option<Var>,
pub show_monster_merged_hp_bar: Option<bool>,
pub tid_monster_group_name: Option<String>,
pub monster_merged_hp_bar_settings: Option<MonsterMergedHpBarSettings>,
}
#[derive(Deserialize, Debug, Clone)]
@ -1144,60 +1135,6 @@ pub struct CheckEntityReward {
pub UiType: serde_json::Value,
}
#[derive(Deserialize, Debug, Clone)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct CheckIsGramophonePlayingMusic {
// TODO:
#[cfg(feature = "strict_json_fields")]
pub UiType: serde_json::Value,
}
#[derive(Deserialize, Debug, Clone)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct CheckBVBEvent {
// TODO:
#[cfg(feature = "strict_json_fields")]
pub UiType: serde_json::Value,
}
#[derive(Deserialize, Debug, Clone)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct FinishBvbChallenge {
// TODO:
#[cfg(feature = "strict_json_fields")]
pub UiType: serde_json::Value,
}
#[derive(Deserialize, Debug, Clone)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct CompareActorVarElement {
// TODO: ActorRef > PathName(String)
// pub var1: Var,
// pub compare: CompareType,
// pub var2: Var,
}
#[derive(Deserialize, Debug, Clone)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct CompareActorVar {
pub conditions: Vec<CompareActorVarElement>,
pub count: i32,
}
#[derive(Deserialize, Debug, Clone)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct CheckDangoCultivationProgress {
// TODO:
#[cfg(feature = "strict_json_fields")]
pub UiType: serde_json::Value,
}
#[derive(Deserialize, Debug, Clone)]
#[serde(tag = "Type")]
pub enum Condition {
@ -1300,11 +1237,6 @@ pub enum Condition {
CheckEntityGravityDirection(CheckEntityGravityDirection),
CheckTeleControlState(CheckTeleControlState),
CheckEntityReward(CheckEntityReward),
CheckIsGramophonePlayingMusic(CheckIsGramophonePlayingMusic),
CheckBVBEvent(CheckBVBEvent),
FinishBvbChallenge(FinishBvbChallenge),
CompareActorVar(CompareActorVar),
CheckDangoCultivationProgress(CheckDangoCultivationProgress),
}
#[derive(Deserialize, Debug, Clone)]

View file

@ -4,8 +4,8 @@ use serde::Deserialize;
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct ModelType {
pub r#type: Option<String>,
pub model_id: Option<i32>
r#type: Option<String>,
model_id: Option<i32>
}
#[derive(Deserialize, Debug, Clone)]

View file

@ -91,13 +91,6 @@ pub struct SelfVar {
pub name: String,
}
#[derive(Deserialize, Debug, Clone)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct System {
pub r#type: VarType,
// TODO: Add Var substruct
}
#[derive(Deserialize, Debug, Clone)]
#[serde(tag = "Source")]
@ -107,5 +100,4 @@ pub enum Var {
Global(Global),
#[serde(rename = "Self")]
SelfVar(SelfVar),
System(System),
}

View file

@ -100,6 +100,7 @@ pub struct RoleInfoData {
pub role_guide: i32,
#[cfg(feature = "strict_json_fields")]
pub red_dot_disable_rule: i32,
#[cfg(feature = "strict_json_fields")]
pub skin_damage: Vec<String>,
#[cfg(feature = "strict_json_fields")]
pub hide_hu_lu: bool,

View file

@ -1,101 +0,0 @@
use serde::Deserialize;
#[derive(Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct RoleSkinData {
pub id: i32,
pub role_id: i32,
pub suit_weapon_skin_id: i32,
pub head_id: i32,
pub quality_id: i32,
#[cfg(feature = "strict_json_fields")]
pub name: String,
#[cfg(feature = "strict_json_fields")]
pub title_name: String,
#[cfg(feature = "strict_json_fields")]
pub sub_dec_name: String,
#[cfg(feature = "strict_json_fields")]
pub type_description: String,
#[cfg(feature = "strict_json_fields")]
pub attributes_description: String,
#[cfg(feature = "strict_json_fields")]
pub bg_description: String,
#[cfg(feature = "strict_json_fields")]
pub icon_middle: String,
#[cfg(feature = "strict_json_fields")]
pub icon_small: String,
#[cfg(feature = "strict_json_fields")]
pub item_access: Vec<i32>,
#[cfg(feature = "strict_json_fields")]
pub sort_index: i32,
#[cfg(feature = "strict_json_fields")]
pub red_dot_disable_rule: i32,
#[cfg(feature = "strict_json_fields")]
pub show_in_bag: bool,
#[cfg(feature = "strict_json_fields")]
pub obtained_show_description: String,
#[cfg(feature = "strict_json_fields")]
pub icon: String,
#[cfg(feature = "strict_json_fields")]
pub function_desc: String,
#[cfg(feature = "strict_json_fields")]
pub first_obtain_desc: String,
#[cfg(feature = "strict_json_fields")]
pub quality: u8,
#[cfg(feature = "strict_json_fields")]
pub tag: String,
#[cfg(feature = "strict_json_fields")]
pub role_head_icon_circle: String,
#[cfg(feature = "strict_json_fields")]
pub role_head_icon_large: String,
#[cfg(feature = "strict_json_fields")]
pub role_head_icon_big: String,
#[cfg(feature = "strict_json_fields")]
pub card: String,
#[cfg(feature = "strict_json_fields")]
pub role_head_icon: String,
#[cfg(feature = "strict_json_fields")]
pub preview_role_card: String,
#[cfg(feature = "strict_json_fields")]
pub buy_shop_preview_role_card: String,
#[cfg(feature = "strict_json_fields")]
pub formation_role_card: String,
#[cfg(feature = "strict_json_fields")]
pub role_stand: String,
#[cfg(feature = "strict_json_fields")]
pub suit_weapon_skin_color: String,
#[cfg(feature = "strict_json_fields")]
pub role_obtain_color1: String,
#[cfg(feature = "strict_json_fields")]
pub role_obtain_color2: String,
#[cfg(feature = "strict_json_fields")]
pub role_portrait: String,
#[cfg(feature = "strict_json_fields")]
pub mesh_id: i32,
#[cfg(feature = "strict_json_fields")]
pub ui_mesh_id: i32,
#[cfg(feature = "strict_json_fields")]
pub role_body: String,
#[cfg(feature = "strict_json_fields")]
#[serde(rename = "UiScenePerformanceABP")]
pub ui_scene_performance_abp: String,
#[cfg(feature = "strict_json_fields")]
pub foot_step_state: String,
#[cfg(feature = "strict_json_fields")]
pub pay_shop_preview_role_texture_path: String,
#[cfg(feature = "strict_json_fields")]
pub pay_shop_preview_role_texture_bg_path: String,
#[cfg(feature = "strict_json_fields")]
pub pay_shop_preview_weapon_texture_path: String,
#[cfg(feature = "strict_json_fields")]
pub pay_shop_preview_buy_role_texture_path: String,
#[cfg(feature = "strict_json_fields")]
pub pay_shop_preview_buy_role_suit_weapon_texture_path: String,
#[cfg(feature = "strict_json_fields")]
pub share_texture_path: String,
#[cfg(feature = "strict_json_fields")]
pub spine_skeleton_data: String,
#[cfg(feature = "strict_json_fields")]
pub small_spine_atlas: String,
}

View file

@ -19,7 +19,7 @@ load_textmaps = true
quadrant_size = 1000000
[asset_config]
asset_url = "https://git.xeondev.com/wickedwaifus/wicked-waifus-data/releases/download/pioneer_2.4.1/bundle.zip"
asset_url = "https://git.xeondev.com/wickedwaifus/wicked-waifus-data/releases/download/pioneer_2.3.1/bundle.zip"
buffer_size = 268435456
[default_unlocks]

View file

@ -80,17 +80,17 @@ impl BufManager {
let mut buffs = wicked_waifus_data::buff_data::iter().filter(|(id, buf)| {
id.to_string().starts_with(&role_id.to_string()) // must be part of char kit :)
&&
!id.to_string().contains("666")// KURO IS EVIL
&&
buf.duration_policy == 1
&&
!buf.ge_desc.contains("【废弃】") // remove "deprecated" buffs
(
!id.to_string().contains("666")// KURO IS EVIL
&&
buf.duration_policy == 1
)
// &&
// !buf.ge_desc.contains("【废弃】") // remove "deprecated" buffs
})
.map(|x| *x.0)
.collect::<Vec<i64>>();
tracing::debug!("adding roleid {:#?}", buffs);
buffs.extend(OVERRIDE_BUFFS.iter().copied());
if let Some(role_buff_overrides) = get_role_buff_overrides(role_id) {
buffs.extend(role_buff_overrides.iter().copied());
@ -120,26 +120,6 @@ impl BufManager {
})
.collect::<Vec<_>>()
}
pub fn create_buff(&mut self, origin_id: i64, buff_id: i64) -> FightBuffInformation {
let mut buff = FightBuffInformation {
handle_id: 0,
buff_id,
level: 1,
stack_count: 1,
instigator_id: origin_id,
entity_id: origin_id,
apply_type: 0,
duration: -1f32,
left_duration: -1f32,
context: vec![],
is_active: true,
server_id: 0,
message_id: 0,
};
self.create(&mut buff);
buff
}
}
impl Default for BufManager {

View file

@ -108,15 +108,11 @@ impl WorldEntity {
self.components.remove(&entity_id).is_some() && self.entity_manager.remove(entity_id)
}
pub fn get_all_entity_ids(&mut self) -> Vec<i32> {
self.entity_manager.get_all_entity_id()
pub fn active_entity_empty(&self) -> bool {
self.entity_manager.active_entity_empty()
}
pub fn generate_role_permanent_buffs(&mut self, entity_id: i32, role_id: i32) -> Vec<FightBuffInformation> {
self.buff_manager.create_permanent_buffs(entity_id as i64, role_id)
}
pub fn create_buff(&mut self, entity_id: i32, buff_id: i64) -> FightBuffInformation {
self.buff_manager.create_buff(entity_id as i64, buff_id)
}
}

View file

@ -2,10 +2,12 @@ use rand::prelude::IndexedRandom;
use rand::Rng;
use wicked_waifus_protocol::{ErrorCode, GachaResult, GachaReward};
use wicked_waifus_data::GachaViewTypeInfoId::{
BeginnersChoiceConvene, FeaturedResonatorConvene, FeaturedWeaponConvene,
MultipleChoiceResonatorConvene, MultipleChoiceWeaponConvene, NoviceConvene,
StandardResonatorConvene, StandardWeaponConvene,
use wicked_waifus_data::GachaViewTypeInfoId::{BeginnersChoiceConvene,
FeaturedResonatorConvene,
FeaturedWeaponConvene,
NoviceConvene,
StandardResonatorConvene,
StandardWeaponConvene,
};
use crate::logic::gacha::pool_info::PoolInfo;
@ -51,23 +53,16 @@ impl GachaPool {
}
}
pub fn pull<T: Rng>(
&mut self,
rng: &mut T,
player: &mut Player,
) -> Result<GachaResult, ErrorCode> {
pub fn pull<T: Rng>(&mut self,
rng: &mut T,
player: &mut Player) -> Result<GachaResult, ErrorCode> {
self.check_limits()?;
let result = if (self.info.pool_type == BeginnersChoiceConvene)
&& (self.info.pool_id > 50)
&& (self.info.pool_id < 60)
{
&& (self.info.pool_id > 50) && (self.info.pool_id < 60) {
let item_id = self.info.guaranteed_character_id.unwrap();
GachaResult {
gacha_reward: Some(GachaReward {
item_id,
item_count: 1,
}),
gacha_reward: Some(GachaReward { item_id, item_count: 1 }),
extra_rewards: self.calculate_extra_rewards(2),
transform_rewards: Self::get_transform_rewards(player, item_id),
bottom: None,
@ -89,14 +84,13 @@ impl GachaPool {
};
item_id
}
_ => self.get_random_item(rarity, rng),
_ => {
self.get_random_item(rarity, rng)
}
};
self.update_pity(rarity);
GachaResult {
gacha_reward: Some(GachaReward {
item_id,
item_count: 1,
}),
gacha_reward: Some(GachaReward { item_id, item_count: 1 }),
extra_rewards: self.calculate_extra_rewards(rarity),
transform_rewards: Self::get_transform_rewards(player, item_id),
bottom: None,
@ -129,29 +123,15 @@ impl GachaPool {
fn get_random_item(&self, rarity: usize, rng: &mut impl Rng) -> i32 {
let items: &[i32] = match rarity {
0 => &[
21010013, 21020013, 21030013, 21040013, 21050013, 21010023, 21020023, 21030023,
21040023, 21050023, 21010043, 21020043, 21030043, 21040043, 21050043,
],
0 => &[21010013, 21020013, 21030013, 21040013, 21050013, 21010023, 21020023, 21030023, 21040023, 21050023, 21010043, 21020043, 21030043, 21040043, 21050043],
1 => match self.info.pool_type {
StandardWeaponConvene => &[
21010024, 21020024, 21030024, 21040024, 21050024, 21010044, 21020044, 21030044,
21040044, 21050044, 21010064, 21020064, 21030064, 21040064, 21050064,
],
FeaturedResonatorConvene | FeaturedWeaponConvene => {
&self.info.rate_up_four_star[..]
}
StandardWeaponConvene => &[21010024, 21020024, 21030024, 21040024, 21050024, 21010044, 21020044, 21030044, 21040044, 21050044, 21010064, 21020064, 21030064, 21040064, 21050064],
FeaturedResonatorConvene | FeaturedWeaponConvene => &self.info.rate_up_four_star[..],
_ => &[1303, 1602, 1102, 1204, 1403, 1103, 1402, 1202, 1601],
},
2 => match self.info.pool_type {
NoviceConvene | StandardResonatorConvene => &[1405, 1301, 1503, 1104, 1203],
// TODO: Review MultipleChoiceConvene
FeaturedResonatorConvene
| FeaturedWeaponConvene
| StandardWeaponConvene
| BeginnersChoiceConvene
| MultipleChoiceResonatorConvene
| MultipleChoiceWeaponConvene => &self.info.rate_up_five_star[..],
FeaturedResonatorConvene | FeaturedWeaponConvene | StandardWeaponConvene | BeginnersChoiceConvene => &self.info.rate_up_five_star[..],
},
_ => unreachable!(),
};
@ -174,23 +154,15 @@ impl GachaPool {
}
fn calculate_probabilities(&self) -> [f32; 3] {
let mut prob = [
self.rates.three_star,
self.rates.four_star,
self.rates.five_star,
];
let mut prob = [self.rates.three_star, self.rates.four_star, self.rates.five_star];
if self.pull_count >= self.info.pity_system.soft_pity_start {
let extra_prob =
0.8 + 8.0 * (self.pull_count - self.info.pity_system.soft_pity_start - 1) as f32;
let extra_prob = 0.8 + 8.0 * (self.pull_count - self.info.pity_system.soft_pity_start - 1) as f32;
prob[0] -= extra_prob;
prob[2] = extra_prob;
}
match (
self.pity_four + 1 >= self.info.pity_system.hard_pity_four,
self.pull_count + 1 >= self.info.pity_system.hard_pity_five,
) {
match (self.pity_four + 1 >= self.info.pity_system.hard_pity_four, self.pull_count + 1 >= self.info.pity_system.hard_pity_five) {
(true, _) => [0.0, 100.0, 0.0],
(_, true) => [0.0, 0.0, 100.0],
_ => prob,
@ -200,9 +172,9 @@ impl GachaPool {
fn determine_rarity(&self, prob: &[f32; 3], rng: &mut impl Rng) -> usize {
let roll: f32 = rng.random_range(0.0..100.0);
match (roll < prob[2], roll < prob[2] + prob[1]) {
(true, _) => 2, // 5-star
(_, true) => 1, // 4-star
_ => 0, // 3-star
(true, _) => 2, // 5-star
(_, true) => 1, // 4-star
_ => 0, // 3-star
}
}
@ -234,18 +206,18 @@ impl GachaPool {
}
/*
TODO: update rewards for duplicates
TODO: update rewards for duplicates
4-star duplicate:
1st to 6th duplicate: 3 afterglow corals and 1 waveband of that char
7th duplicate onwards: 8 afterglow corals
will not receive any afterglow corals when you pull a 4-star that you do not already own for the first time.
4-star duplicate:
1st to 6th duplicate: 3 afterglow corals and 1 waveband of that char
7th duplicate onwards: 8 afterglow corals
will not receive any afterglow corals when you pull a 4-star that you do not already own for the first time.
5-star duplicate:
1st to 6th duplicate: 15 afterglow corals and 1 waveband of that char
7th duplicate onwards: 40 afterglow corals
will not receive any afterglow corals when you pull a 5-star that you do not already own for the first time.
*/
5-star duplicate:
1st to 6th duplicate: 15 afterglow corals and 1 waveband of that char
7th duplicate onwards: 40 afterglow corals
will not receive any afterglow corals when you pull a 5-star that you do not already own for the first time.
*/
match rarity {
2 => rewards.push(GachaReward {
item_id: 50004, // afterglow corals

View file

@ -1,10 +1,12 @@
use std::time::SystemTime;
use wicked_waifus_data::GachaViewTypeInfoId;
use wicked_waifus_data::GachaViewTypeInfoId::{
BeginnersChoiceConvene, FeaturedResonatorConvene, FeaturedWeaponConvene,
MultipleChoiceResonatorConvene, MultipleChoiceWeaponConvene, NoviceConvene,
StandardResonatorConvene, StandardWeaponConvene,
use wicked_waifus_data::GachaViewTypeInfoId::{BeginnersChoiceConvene,
FeaturedResonatorConvene,
FeaturedWeaponConvene,
NoviceConvene,
StandardResonatorConvene,
StandardWeaponConvene,
};
use crate::logic::gacha::category::PoolCategory;
@ -56,37 +58,30 @@ impl PoolInfo {
const NOVICE_GACHA_POOL_RESOURCE: &'static str = "UiItem_NewPlayerGachaPool";
const BASE_GACHA_POOL_RESOURCE: &'static str = "UiItem_BaseGachaPool";
pub(crate) fn new(
pool_id: i32,
pool_type: GachaViewTypeInfoId,
category: PoolCategory,
rate_up_five_star: &[i32],
rate_up_four_star: &[i32],
guaranteed_character_id: Option<i32>,
) -> Self {
pub(crate) fn new(pool_id: i32,
pool_type: GachaViewTypeInfoId,
category: PoolCategory,
rate_up_five_star: &[i32],
rate_up_four_star: &[i32],
guaranteed_character_id: Option<i32>) -> Self {
let start_time = SystemTime::now();
let end_time = match category {
PoolCategory::Permanent => None,
PoolCategory::Event(duration) | PoolCategory::Special(duration) => {
Some(start_time + duration)
}
PoolCategory::Event(duration) | PoolCategory::Special(duration) => Some(start_time + duration),
};
// TODO: Make objects const 50001, 50002, 50005, 50006 or check if gacha consumes exist
let (item_id, daily_limit, total_limit, pity_system) = match pool_type {
NoviceConvene => (50001, 0, 50, PitySystem::novice()),
StandardResonatorConvene | StandardWeaponConvene => {
(50001, 0, 80, PitySystem::default())
}
// TODO: Review MultipleChoiceConvene
FeaturedResonatorConvene
| MultipleChoiceResonatorConvene
| MultipleChoiceWeaponConvene => (50002, 0, 0, PitySystem::default()),
StandardResonatorConvene | StandardWeaponConvene => (50001, 0, 80, PitySystem::default()),
FeaturedResonatorConvene => (50002, 0, 0, PitySystem::default()),
FeaturedWeaponConvene => (50005, 0, 0, PitySystem::default()),
BeginnersChoiceConvene => match pool_id {
51..56 => (50006, 0, 1, PitySystem::default()),
_ => (50001, 0, 80, PitySystem::default()),
},
BeginnersChoiceConvene => {
match pool_id {
51..56 => (50006, 0, 1, PitySystem::default()),
_ => (50001, 0, 80, PitySystem::default()),
}
}
};
Self {

View file

@ -5,10 +5,12 @@ use rand::prelude::StdRng;
use rand::SeedableRng;
use wicked_waifus_data::gacha_view_info_data;
use wicked_waifus_data::GachaViewTypeInfoId::{
BeginnersChoiceConvene, FeaturedResonatorConvene, FeaturedWeaponConvene,
MultipleChoiceResonatorConvene, MultipleChoiceWeaponConvene, NoviceConvene,
StandardResonatorConvene, StandardWeaponConvene,
use wicked_waifus_data::GachaViewTypeInfoId::{BeginnersChoiceConvene,
FeaturedResonatorConvene,
FeaturedWeaponConvene,
NoviceConvene,
StandardResonatorConvene,
StandardWeaponConvene,
};
use wicked_waifus_protocol::{ErrorCode, GachaResult};
@ -38,48 +40,29 @@ impl GachaService {
for element in gacha_view_info_data::iter() {
let duration = match element.r#type {
NoviceConvene | StandardResonatorConvene | StandardWeaponConvene => {
PoolCategory::Permanent
}
// TODO: Review MultipleChoiceConvene
FeaturedResonatorConvene
| FeaturedWeaponConvene
| MultipleChoiceResonatorConvene
| MultipleChoiceWeaponConvene => PoolCategory::Event(Self::THREE_WEEKS),
NoviceConvene | StandardResonatorConvene | StandardWeaponConvene => PoolCategory::Permanent,
FeaturedResonatorConvene | FeaturedWeaponConvene => PoolCategory::Event(Self::THREE_WEEKS),
BeginnersChoiceConvene => match element.id {
51..56 => PoolCategory::Special(Self::ONE_WEEK),
_ => PoolCategory::Permanent,
},
};
let guaranteed = if (element.show_id_list.len() > 0)
&& (element.r#type == FeaturedResonatorConvene)
{
let guaranteed = if (element.show_id_list.len() > 0) && (element.r#type == FeaturedResonatorConvene) {
Some(element.show_id_list[0])
} else {
None
};
let info = PoolInfo::new(
element.id,
element.r#type,
duration,
&element.up_list[..],
&element.show_id_list[..],
guaranteed,
);
let info = PoolInfo::new(element.id, element.r#type, duration, &element.up_list[..], &element.show_id_list[..], guaranteed);
pools.insert(element.id, GachaPool::new(info));
}
pools
}
pub fn pull(
&mut self,
player: &mut Player,
pool_id: i32,
times: i32,
) -> Result<Vec<GachaResult>, ErrorCode> {
let pool = self
.pools
.get_mut(&pool_id)
pub fn pull(&mut self,
player: &mut Player,
pool_id: i32,
times: i32) -> Result<Vec<GachaResult>, ErrorCode> {
let pool = self.pools.get_mut(&pool_id)
.ok_or(ErrorCode::ErrGachaPoolConfigNotFound)?;
if !pool.is_active() {
@ -100,8 +83,7 @@ impl GachaService {
}
pub fn get_active_pools(&self) -> Vec<(i32, &GachaPool)> {
self.pools
.iter()
self.pools.iter()
.filter(|(_, pool)| pool.is_active())
.map(|(id, pool)| (*id, pool))
.collect()
@ -109,8 +91,7 @@ impl GachaService {
#[allow(dead_code)]
pub fn get_all_pools(&self) -> Vec<(i32, &PoolInfo)> {
self.pools
.iter()
self.pools.iter()
.map(|(id, pool)| (*id, &pool.info))
.collect()
}

View file

@ -1,255 +0,0 @@
use std::collections::HashMap;
use wicked_waifus_protocol::{
CommonTagData, EntityCommonTagNotify, EntityStateReadyNotify, FightBuffInformation, ItemRewardNotify, NormalItemUpdateNotify, RewardItemInfo, WR
};
use wicked_waifus_data::pb_components::action::{
AddBuffToEntity, AddBuffToPlayer, ChangeSelfEntityState, CollectParams, RemoveBuffFromEntity, RemoveBuffFromPlayer, UnlockTeleportTrigger
};
use wicked_waifus_data::pb_components::entity_state::EntityStateComponent;
use crate::logic::ecs::component::ComponentContainer;
use crate::logic::ecs::world::WorldEntity;
use crate::logic::handler::handle_action;
use crate::logic::player::{ItemUsage, Player};
use crate::logic::utils::tag_utils;
use crate::query_components;
pub fn collect_action(
player: &mut Player,
_entity_id: i64,
level_entity_data: &wicked_waifus_data::LevelEntityConfigData,
template_config: &wicked_waifus_data::TemplateConfigData,
_: CollectParams
) {
if let Some(reward_component) = level_entity_data
.components_data
.reward_component
.as_ref()
.or(template_config.components_data.reward_component.as_ref())
{
if reward_component.disabled.unwrap_or(false) {
return;
}
// TODO: check the use of reward_type and drop_on_event
// Seems type 0 is reward from preview, while 1 and 2 is unknown
if let Some(reward_id) = reward_component.reward_id {
let drop = wicked_waifus_data::drop_package_data::get(&reward_id).unwrap();
let usages = drop
.drop_preview
.iter()
.map(|(&id, &quantity)| ItemUsage { id, quantity })
.collect::<Vec<_>>();
let updated_items = player.inventory.add_items(&usages);
let normal_item_list = player
.inventory
.to_normal_item_list_filtered(updated_items.keys().cloned().collect::<Vec<i32>>());
player.notify(NormalItemUpdateNotify {
normal_item_list,
no_tips: false,
});
// UpdateHandBookActiveStateMapNotify
let mut rewards: HashMap<i32, WR> = HashMap::new();
rewards.insert(
0,
WR {
item_list: drop
.drop_preview
.iter()
.map(|(&id, &quantity)| RewardItemInfo {
show_plan_id: 0, // TODO: Check how to get this
item_id: id,
count: quantity,
incr_id: 0,
})
.collect::<Vec<_>>(),
},
);
player.notify(ItemRewardNotify {
drop_id: reward_id,
reason: 15000,
magnification: 1,
reward_items: rewards,
});
}
// TODO: Should we remove entity?? get pcap
}
}
#[inline(always)]
pub fn unlock_teleport_trigger_action(
player: &mut Player,
_entity_id: i64,
_level_entity_data: &wicked_waifus_data::LevelEntityConfigData,
_template_config: &wicked_waifus_data::TemplateConfigData,
action: UnlockTeleportTrigger
) {
player.unlock_teleport(action.teleport_id)
}
pub fn change_self_entity_state_action(
player: &mut Player,
entity_id: i64,
level_entity_data: &wicked_waifus_data::LevelEntityConfigData,
template_config: &wicked_waifus_data::TemplateConfigData,
action: ChangeSelfEntityState,
) {
let state = tag_utils::get_tag_id_by_name(action.entity_state.as_str());
// TODO: update Tag::CommonEntityTags too??
let old_state = {
let world_ref = player.world.borrow();
let world = world_ref.get_world_entity();
let mut state_tag = query_components!(world, entity_id, StateTag).0.unwrap();
let old_state = state_tag.state_tag_id;
tracing::debug!("ChangeSelfEntityState: old state {old_state} -> new state: {state}");
state_tag.state_tag_id = state;
old_state
};
if let Some(entity_state_component) = level_entity_data
.components_data
.entity_state_component
.as_ref()
.or(template_config
.components_data
.entity_state_component
.as_ref())
.cloned()
{
let entity_state_component: EntityStateComponent = entity_state_component; // TODO: Remove this line, used for casting only
// TODO: implement rest of cases
if let Some(state_change_behaviors) = entity_state_component.state_change_behaviors {
for state_change_behavior in state_change_behaviors {
// TODO: implement rest of cases
let expected = tag_utils::get_tag_id_by_name(state_change_behavior.state.as_str());
if expected == state {
if let Some(actions) = state_change_behavior.action {
for sub in actions {
handle_action(
player,
entity_id,
level_entity_data,
template_config,
sub,
);
}
}
}
}
}
}
player.notify(EntityCommonTagNotify {
id: entity_id,
tags: vec![
CommonTagData {
tag_id: old_state,
remove_tag_ids: false,
}, // Remove
CommonTagData {
tag_id: state,
remove_tag_ids: true,
}, // Add
],
});
player.notify(EntityStateReadyNotify {
entity_id,
tag_id: state,
ready: true, // TODO: Always true? or shall we compare it to something??
});
}
fn add_buff_to_entity(
world: &mut WorldEntity,
entity_ids: Vec<i64>,
buff_ids: Vec<i64>,
) {
for entity_id in entity_ids {
let (Some(mut buff_component),) = query_components!(world, entity_id, FightBuff) else {
continue;
};
for buff_id in &buff_ids {
buff_component.fight_buff_infos.push(FightBuffInformation {
handle_id: 1,
buff_id: *buff_id,
level: 1,
stack_count: 1,
instigator_id: 0,
entity_id: 0,
apply_type: 0,
duration: -1.0,
left_duration: -1.0,
context: vec![],
is_active: true,
server_id: 1,
message_id: 1,
});
}
}
}
pub fn add_buff_to_entity_action(
player: &mut Player,
entity_id: i64,
level_entity_data: &wicked_waifus_data::LevelEntityConfigData,
template_config: &wicked_waifus_data::TemplateConfigData,
params: AddBuffToEntity
) {
tracing::info!("entity buff request received with the following details: {:#?}.", params);
let mut world_ref = player.world.borrow_mut();
let world = world_ref.get_mut_world_entity();
match params {
AddBuffToEntity::SingleEntityBuffs(single_entity_buffs) => {
add_buff_to_entity(world, vec![single_entity_buffs.entity_id], single_entity_buffs.buff_ids)
},
AddBuffToEntity::MultipleEntitiesBuff(multiple_entities_buff) => {
add_buff_to_entity(world, multiple_entities_buff.entity_ids, multiple_entities_buff.buff_ids)
},
AddBuffToEntity::SelfEntityBuff(self_entity_buff) => {
add_buff_to_entity(world, vec![entity_id], self_entity_buff.buff_ids)
},
}
}
pub fn remove_buff_from_entity_action(
player: &mut Player,
entity_id: i64,
level_entity_data: &wicked_waifus_data::LevelEntityConfigData,
template_config: &wicked_waifus_data::TemplateConfigData,
params: RemoveBuffFromEntity
) {
tracing::info!("entity buff request received with the following details: {:#?}.", params);
let mut world_ref = player.world.borrow_mut();
let world = world_ref.get_mut_world_entity();
}
pub fn add_buff_to_player_action(
player: &mut Player,
entity_id: i64,
level_entity_data: &wicked_waifus_data::LevelEntityConfigData,
template_config: &wicked_waifus_data::TemplateConfigData,
params: AddBuffToPlayer
) {
tracing::info!("entity buff request received with the following details: {:#?}.", params);
let mut world_ref = player.world.borrow_mut();
let world = world_ref.get_mut_world_entity();
}
pub fn remove_buff_from_player_action(
player: &mut Player,
entity_id: i64,
level_entity_data: &wicked_waifus_data::LevelEntityConfigData,
template_config: &wicked_waifus_data::TemplateConfigData,
params: RemoveBuffFromPlayer
) {
tracing::info!("entity buff request received with the following details: {:#?}.", params);
let mut world_ref = player.world.borrow_mut();
let world = world_ref.get_mut_world_entity();
}

View file

@ -1,58 +0,0 @@
use wicked_waifus_protocol::{AttributeChangedRequest, AttributeChangedResponse, EAttributeType, ErrorCode, FormationAttrRequest, FormationAttrResponse};
use crate::{logic::{ecs::component::ComponentContainer, player::Player}, query_components};
pub fn on_attribute_changed_request(
player: &mut Player,
request: AttributeChangedRequest,
response: &mut AttributeChangedResponse,
) {
let mut world_ref = player.world.borrow_mut();
let world = world_ref.get_mut_world_entity();
let id = request.id;
if let (Some(mut component),) = query_components!(world, id, Attribute) {
for needs_editing in request.attributes {
if let Ok(attr_type) = EAttributeType::try_from(needs_editing.attribute_type) {
component.attr_map.get_mut(&attr_type).unwrap().0 = needs_editing.current_value;
component.attr_map.get_mut(&attr_type).unwrap().1 = needs_editing.value_increment;
} else {
tracing::warn!("Attribute skipped!");
continue;
}
}
response.error_code = ErrorCode::Success.into()
} else {
response.error_code = ErrorCode::ErrEntityNotFound.into()
};
}
pub fn on_formation_attr_request(
player: &mut Player,
request: FormationAttrRequest,
response: &mut FormationAttrResponse,
) {
let mut world_ref = player.world.borrow_mut();
let world = world_ref.get_mut_world_entity();
let formation = &player.formation_list[&player.cur_formation_id];
for role_id in formation.role_ids.clone() {
if let (Some(mut component),) = query_components!(world, role_id as i64, Attribute) {
for needs_editing in &request.formation_attrs {
if let Ok(attr_type) = EAttributeType::try_from(needs_editing.attr_id) {
component.attr_map.get_mut(&attr_type).unwrap().0 = needs_editing.current_value;
component.attr_map.get_mut(&attr_type).unwrap().1 = needs_editing.max_value;
} else {
tracing::warn!("Attribute skipped!");
continue;
}
}
response.error_code = ErrorCode::Success.into()
} else {
response.error_code = ErrorCode::ErrEntityNotFound.into()
};
}
}

View file

@ -3,12 +3,7 @@ use wicked_waifus_protocol::combat_message::{
combat_send_data, CombatNotifyData, CombatReceiveData, CombatRequestData, CombatResponseData,
CombatSendPackRequest, CombatSendPackResponse,
};
use wicked_waifus_protocol::{
AttributeChangedNotify, CombatCommon, DErrorResult, DamageExecuteRequest,
DamageExecuteResponse, EAttributeType, ERemoveEntityType, ErrorCode,
FsmConditionPassRequest, FsmConditionPassResponse, GameplayAttributeData,
PlayerBattleStateChangeNotify, SwitchRoleRequest, SwitchRoleResponse,
};
use wicked_waifus_protocol::{AttributeChangedNotify, CombatCommon, DamageExecuteRequest, DamageExecuteResponse, EAttributeType, ERemoveEntityType, EntityRemoveNotify, ErrorCode, GameplayAttributeData, SwitchRoleRequest, SwitchRoleResponse};
use wicked_waifus_data::damage_data;
@ -60,9 +55,6 @@ pub fn on_combat_message_combat_send_pack_request(
combat_request_data::Message::SwitchRoleRequest(ref request) => {
handle_switch_role_request(player, request_data, request, response);
}
combat_request_data::Message::FsmConditionPassRequest(ref request) => {
handle_fsm_condition_request(player, request_data, request, response);
}
combat_request_data::Message::DamageExecuteRequest(ref request) => {
handle_damage_execute_request(player, request_data, request, response);
}
@ -125,20 +117,16 @@ fn handle_damage_execute_request(
.unwrap();
if let Ok(related_attribute) = EAttributeType::try_from(damage_data.related_property) {
if let Some((value, _)) = attribute.attr_map.get(&related_attribute) {
if let Some(&rate_lv) = damage_data
.rate_lv
.iter()
.find(|&lvl| *lvl == request.skill_level)
{
if let Some(&rate_lv) = damage_data.rate_lv.iter().find(|&lvl| *lvl == request.skill_level) {
let hardness_lv = damage_data.hardness_lv[0];
tracing::info!(
"atk: {}, damage_id: {}, role_id: {}, rate_lv: {}, hardness_lv: {}",
value,
request.damage_id,
config_id,
rate_lv,
hardness_lv
);
"atk: {}, damage_id: {}, role_id: {}, rate_lv: {}, hardness_lv: {}",
value,
request.damage_id,
config_id,
rate_lv,
hardness_lv
);
damage = if hardness_lv == 0 || rate_lv <= 0 {
1
} else {
@ -160,83 +148,34 @@ fn handle_damage_execute_request(
..Default::default()
}),
));
// if let Some((value, _)) = query_components!(world, request.target_entity_id, Attribute)
// .0
// .unwrap()
// .attr_map
// .get(&EAttributeType::Life)
// {
// let updated_value = match value - damage >= 0 {
// true => value - damage,
// false => 0,
// };
// receive_pack.data.push(create_combat_notify(
// CombatCommon {
// entity_id: request.target_entity_id,
// ..Default::default()
// },
// combat_notify_data::Message::AttributeChangedNotify(AttributeChangedNotify {
// id: request.target_entity_id,
// attributes: vec![GameplayAttributeData {
// current_value: updated_value,
// value_increment: updated_value,
// attribute_type: EAttributeType::Life.into(),
// }],
// }),
// ));
// if updated_value == 0 {
// world_util::remove_entity(
// player,
// request.target_entity_id,
// ERemoveEntityType::HpIsZero,
// );
// }
// }
if let Some((value, _)) = query_components!(world, request.target_entity_id, Attribute)
.0
.unwrap()
.attr_map
.get(&EAttributeType::Life)
{
let updated_value = match value - damage >= 0 {
true => value - damage,
false => 0,
};
receive_pack.data.push(create_combat_notify(
CombatCommon {
entity_id: request.target_entity_id,
..Default::default()
},
combat_notify_data::Message::AttributeChangedNotify(AttributeChangedNotify {
id: request.target_entity_id,
attributes: vec![GameplayAttributeData {
current_value: updated_value,
value_increment: updated_value,
attribute_type: EAttributeType::Life.into(),
}],
}),
));
if updated_value == 0 {
world_util::remove_entity(player, request.target_entity_id, ERemoveEntityType::HpIsZero);
}
}
response.error_code = ErrorCode::Success.into();
}
fn handle_battle(
player: &mut Player,
combat_request: &CombatRequestData,
response: &mut CombatSendPackResponse,
condition: bool,
) {
let receive_pack = response
.receive_pack_notify
.get_or_insert_with(Default::default);
receive_pack.data.push(create_combat_notify(
combat_request.combat_common.unwrap(),
combat_notify_data::Message::PlayerBattleStateChangeNotify(PlayerBattleStateChangeNotify {
player_id: player.basic_info.id,
in_battle: condition,
}),
));
}
fn handle_fsm_condition_request(
player: &mut Player,
combat_request: &CombatRequestData,
request: &FsmConditionPassRequest,
response: &mut CombatSendPackResponse,
) {
let receive_pack = response
.receive_pack_notify
.get_or_insert_with(Default::default);
receive_pack.data.push(create_combat_response(
combat_request,
combat_response_data::Message::FsmConditionPassResponse(FsmConditionPassResponse {
fsm_id: request.fsm_id,
error: Some(DErrorResult {
error_code: ErrorCode::Success.into(),
error_params: Vec::new(),
}),
}),
));
handle_battle(player, combat_request, response, true);
}

View file

@ -44,7 +44,6 @@ dummy_handler! {
TowerSeasonUpdate;
ValidTimeItem;
PayShopInfo;
PayInfo;
InitRange;
Activity;
BattlePass;

View file

@ -1,9 +1,9 @@
use wicked_waifus_protocol::{ApplyGameplayEffectPush, ApplyGameplayEffectRequest, ApplyGameplayEffectResponse, EntityAccessInfo, EntityAccessRangeRequest, EntityAccessRangeResponse, EntityActiveRequest, EntityActiveResponse, EntityFollowTrackRequest, EntityFollowTrackResponse, EntityInteractRequest, EntityInteractResponse, EntityOnLandedRequest, EntityOnLandedResponse, EntityPb, EntityPositionRequest, EntityPositionResponse, ErrorCode, GetRewardTreasureBoxRequest, GetRewardTreasureBoxResponse, MovePackagePush, OrderApplyBuffRequest, OrderApplyBuffResponse, OrderRemoveBuffRequest, OrderRemoveBuffResponse, RemoveGameplayEffectPush, RemoveGameplayEffectRequest, RemoveGameplayEffectResponse};
use wicked_waifus_protocol::{EntityAccessInfo, EntityAccessRangeRequest, EntityAccessRangeResponse, EntityActiveRequest, EntityActiveResponse, EntityFollowTrackRequest, EntityFollowTrackResponse, EntityInteractRequest, EntityInteractResponse, EntityOnLandedRequest, EntityOnLandedResponse, EntityPb, EntityPositionRequest, EntityPositionResponse, ErrorCode, GetRewardTreasureBoxRequest, GetRewardTreasureBoxResponse, MovePackagePush};
use wicked_waifus_data::pb_components::option::OptionType;
use crate::logic::handler::handle_action;
use crate::{logic, logic::ecs::component::ComponentContainer, logic::player::Player, query_components};
use crate::logic::utils::action_utils::perform_action;
use crate::logic::utils::condition_utils::check_condition;
pub fn on_entity_active_request(
@ -190,7 +190,7 @@ pub fn on_entity_interact_request(
match option_type {
OptionType::Actions(actions) => {
for action in actions.actions {
handle_action(player, request.entity_id, &entity, template_config, action);
perform_action(player, request.entity_id, &entity, template_config, action);
}
}
OptionType::Flow(_) => {
@ -234,52 +234,6 @@ pub fn on_get_reward_treasure_box_request(
tracing::debug!("GetRewardTreasureBoxRequest with ID: {} and ConfigID {config_id}", request.entity_id);
}
pub fn on_order_apply_buff_request(
player: &Player,
request: OrderApplyBuffRequest,
_response: &mut OrderApplyBuffResponse,
) {
tracing::info!("OrderApplyBuffRequest receuived");
}
pub fn on_order_remove_buff_request(
player: &Player,
request: OrderRemoveBuffRequest,
_response: &mut OrderRemoveBuffResponse,
) {
tracing::info!("OrderRemoveBuffRequest receuived");
}
pub fn on_apply_gameplay_effect_request(
player: &Player,
request: ApplyGameplayEffectRequest,
response: &mut ApplyGameplayEffectResponse
) {
tracing::info!("applygameplayeffect receuived");
}
pub fn on_apply_gameplay_effect_push(
player: &Player,
push: ApplyGameplayEffectPush
) {
tracing::info!("applygameplayeffect receuived");
}
pub fn on_remove_gameplay_effect_request(
player: &Player,
request: RemoveGameplayEffectRequest,
response: &mut RemoveGameplayEffectResponse
) {
tracing::info!("applygameplayeffect receuived");
}
pub fn on_remove_gameplay_effect_push(
player: &Player,
push: RemoveGameplayEffectPush
) {
tracing::info!("applygameplayeffect receuived");
}
fn get_config_id_from_entity_id(player: &Player, entity_id: i64) -> i64 {
let world_ref = player.world.borrow();
let world = world_ref.get_world_entity();

View file

@ -1,5 +1,3 @@
pub use action::*;
pub use attribute::*;
pub use advice::*;
pub use animal::*;
pub use chat::*;
@ -22,8 +20,6 @@ pub use skill::*;
pub use teleport::*;
pub use tutorial::*;
mod action;
mod attribute;
mod advice;
mod animal;
mod chat;
@ -59,7 +55,7 @@ macro_rules! handle_request {
return;
};
// tracing::debug!("logic: processing request {}", stringify!($($inner_package::)?[<$name Request>]));
tracing::debug!("logic: processing request {}", stringify!($($inner_package::)?[<$name Request>]));
let mut response = ::wicked_waifus_protocol::$($inner_package::)?[<$name Response>]::default();
[<on_ $($inner_package:snake _)? $name:snake _request>](player, request, &mut response);
@ -114,40 +110,6 @@ macro_rules! handle_push {
};
}
macro_rules! handle_action {
($($variant:ident),* $(,)?) => {
use wicked_waifus_data::pb_components::action::Action;
use crate::logic::player::Player;
fn perform_action(
player: &mut Player,
entity_id: i64,
level_entity_data: &wicked_waifus_data::LevelEntityConfigData,
template_config: &wicked_waifus_data::TemplateConfigData,
action: Action
) {
::paste::paste! {
match action {
$(
Action::$variant(inner) => {
[<$variant:snake _action>](
player,
entity_id,
level_entity_data,
template_config,
inner.params
)
},
)*
_ => {
::tracing::warn!("Action not implemented for: {:?}", action);
}
}
}
}
};
}
handle_request! {
// Advice
Advice;
@ -158,10 +120,6 @@ handle_request! {
AnimalDrop;
AnimalDestroy;
// Attribute
AttributeChanged;
FormationAttr;
// Chat (TODO: Review TODOs)
PrivateChat;
PrivateChatData;
@ -183,10 +141,6 @@ handle_request! {
EntityInteract;
EntityFollowTrack;
GetRewardTreasureBox;
OrderApplyBuff;
OrderRemoveBuff;
ApplyGameplayEffect;
RemoveGameplayEffect;
// Friend (TODO: Implement them)
FriendAll;
@ -244,6 +198,7 @@ handle_request! {
RoleShowListUpdate;
ClientCurrentRoleReport;
RoleFavorList;
FormationAttr;
UpdateFormation;
// Scene (TODO: Review this on_..., port some from go)
@ -261,7 +216,6 @@ handle_request! {
PayShopInfo;
// PayShopUpdate;
// MonthCard;
PayInfo;
// Skill (TODO: Review this on_..., port some from go)
VisionExploreSkillSet;
@ -325,200 +279,10 @@ handle_push! {
// Entity
MovePackage;
ApplyGameplayEffect;
RemoveGameplayEffect;
// Misc
VersionInfo;
}
handle_action! {
// ExecBattleAction,
// WaitBattleCondition,
// SetBattleState,
// PlayFlow,
Collect,
// LeisureInteract,
UnlockTeleportTrigger,
// EnableTemporaryTeleport,
// OpenSystemBoard,
// OpenSystemFunction,
ChangeSelfEntityState,
// SetPlayerOperationRestriction,
// Wait,
// ChangeEntityState,
// Log,
// EnableNearbyTracking,
// TeleportDungeon,
// DestroySelf,
// CameraLookAt,
// StopCameraLookAt,
// EnterOrbitalCamera,
// ExitOrbitalCamera,
// SendAiEvent,
// SetInteractionLockState,
// AwakeEntity,
// ChangeLiftTarget,
// CalculateVar,
AddBuffToPlayer,
RemoveBuffFromPlayer,
AddBuffToEntity,
RemoveBuffFromEntity,
// Prompt,
// SetEntityVisible,
// DestroyEntity,
// GuideTrigger,
// TriggerCameraShake,
// SetVar,
// VehicleEnter,
// VehicleExitPlayer,
// LockEntity,
// UnlockEntity,
// CommonTip,
// CommonTip2,
// PostAkEvent,
// VehicleEnterNpc,
// VehicleExitNpc,
// PlayerLookAt,
// PlayBubble,
// AddPlayBubble,
// ClearPlayBubble,
// ExecRiskHarvestEffect,
// EnableLevelPlay,
// ClaimLevelPlayReward,
// SettlementDungeon,
// ExitDungeon,
// FinishDungeon,
// RecordDungeonEvent,
// RecoverDurability,
// FadeInScreen,
// FadeOutScreen,
// ChangeNpcPerformState,
// EntityTurnTo,
// EntityLookAt,
// ToggleMapMarkState,
// RandomVar,
// ModifySceneItemAttributeTag,
// VehicleWaterfallClimbing,
// VehicleTeleport,
// RogueGotoNextFloor,
// RogueReceiveReward,
// RogueSelectRoom,
// RogueActivatePortal,
// MowingTowerGotoNextFloor,
// SlashAndTowerGotoNextFloor,
// PlayMontage,
// OpenSystemBoardWithReturn,
// UnlockSystemItem,
// SetSportsState,
// OpenSimpleGameplay,
// PlayEffect,
// PlayEffect2,
// RestorePlayerCameraAdjustment,
// AdjustPlayerCamera,
// SetPlayerPos,
// MoveWithSpline,
// EnableSplineMoveModel,
// ToggleScanSplineEffect,
// MoveSceneItem,
// StopSceneItemMove,
// FireBullet,
// ClearFishingCabinInSaleItems,
// AcceptFishingEntrust,
// DestroyFishingBoat,
// SetJigsawItem,
// SetJigsawFoundation,
// SetTeleControl,
// SetEntityClientVisible,
// ToggleHighlightExploreUi,
// ExecAlertSystemAction,
// AddFlowInteractOption,
// RemoveFlowInteractOption,
// EnableHostility,
// ChangePhantomFormation,
// RestorePhantomFormation,
// ChangeTimer,
// ToggleTimerPauseState,
// ChangeFightTeam,
// AddTrialFollowShooter,
// RemoveTrialFollowShooter,
// AddTrialCharacter,
// RemoveTrialCharacter,
// SetAreaState,
// SwitchSubLevels,
// ChangeTeamPosition,
// GetItem,
// CreatePrefab,
// DestroyPrefab,
// CompleteGuide,
// PlayDynamicSettlement,
// UsePhantomSkill,
// HideTargetRange,
// ChangeOtherState,
// SetRegionConfig,
// SetReviveRegion,
// ExecResurrection,
// ShowTargetRange,
// SetTime,
// SetTimeLockState,
// EnableSystem,
// EnableAoiNotify,
// SetForceLock,
// PlayRegisteredMontage,
// SetAudioState,
// HideGroup,
// ShowHidedGroup,
// HideSpecificEntities,
// ShowSpecificEntities,
// RemovePreloadResource,
// Preload,
// EnableAI,
// SwitchDataLayers,
// DestroyQuest,
// DestroyQuestItem,
// PromptQuestChapterUI,
// TakePlotPhoto,
// SetWuYinQuState,
// RunActions,
// ManualOccupations,
// SetWeather,
// SendNpcMail,
// EnableFunction,
// FocusOnMapMark,
// CharacterLookAt,
// AddGuestCharacter,
// RemoveGuestCharacter,
// TeleportToAndEnterVehicle,
// SetAreaTimeState,
// ResetPlayerCameraFocus,
// ResetLevelPlay,
// VehicleSprint,
// VehicleMoveWithPathLine,
// ClientPreEnableSubLevels,
// GuestOperateUiAnimation,
// ChangeEntityCamp,
// NewMoveWithSpline,
// DangoAbyssActivatePortal,
// DangoAbyssCreateRewardTreasureBox,
// DangoAbyssGotoNextFloor,
// DangoAbyssReceiveReward,
// SummonEntity,
// GetRewardByInteract,
// OpenQte,
// ActiveAntiGravitySafePoint,
// BvbPlayDialog,
// BvbSendSystemEvent,
// BvbSendAiEvent,
// BvbPlayerOperationConstraint,
// ExecClientBattleAction,
// TriggerSpecificScanEffect,
// SetActorVar,
// RunActorCustomEvent,
// StopUiScreenEffect,
// StopNewMoveWithSpline,
// RequestSystemFunction
}
pub fn handle_logic_message(player: &mut super::player::Player, msg: Message) {
match msg {
Message::Request { .. } => handle_request(player, msg),
@ -531,13 +295,3 @@ pub fn handle_logic_message(player: &mut super::player::Player, msg: Message) {
),
}
}
pub fn handle_action(
player: &mut Player,
entity_id: i64,
level_entity_data: &wicked_waifus_data::LevelEntityConfigData,
template_config: &wicked_waifus_data::TemplateConfigData,
element: Action
) {
perform_action(player, entity_id, level_entity_data, template_config, element)
}

View file

@ -7,12 +7,8 @@ use wicked_waifus_protocol::{
RoleShowListUpdateResponse, UpdateFormationRequest, UpdateFormationResponse,
};
use crate::logic::ecs::world;
use crate::logic::player::Player;
use crate::logic::role::{Role, RoleFormation};
use crate::logic::utils::world_util::{add_player_entities, summon_concomitant};
use crate::query_components;
use crate::logic::ecs::component::ComponentContainer;
pub fn on_role_show_list_update_request(
player: &mut Player,
@ -48,6 +44,14 @@ pub fn on_role_favor_list_request(
response.error_code = ErrorCode::Success.into();
}
pub fn on_formation_attr_request(
_player: &Player,
_request: FormationAttrRequest,
response: &mut FormationAttrResponse,
) {
response.error_code = ErrorCode::Success.into();
}
pub fn on_update_formation_request(
player: &mut Player,
request: UpdateFormationRequest,
@ -61,22 +65,6 @@ pub fn on_update_formation_request(
let cur_role = formation.cur_role;
let is_current = formation.is_current;
// update all formation and check formation_list
player
.formation_list
.entry(formation_id)
.and_modify(|r| {
r.cur_role = formation.cur_role;
r.role_ids = formation.role_ids.clone();
r.is_current = is_current;
})
.or_insert(RoleFormation {
id: formation_id,
cur_role: formation.cur_role,
role_ids: formation.role_ids.clone(),
is_current,
});
if is_current {
// update player current formation id
player.cur_formation_id = formation_id;
@ -93,40 +81,60 @@ pub fn on_update_formation_request(
}
if let Some(old_formation) = player.formation_list.get(&real_formation_id) {
let mut removed_entities: Vec<i64> = old_formation
let removed_entities: Vec<i64> = old_formation
.role_ids
.iter()
.map(|&role_id| world.get_entity_id(role_id))
.collect();
removed_entities.iter().for_each(|&entity_id| {
world.remove_entity(entity_id as i32);
});
player.notify(player.build_player_entity_remove_notify(
removed_entities,
ERemoveEntityType::RemoveTypeNormal,
));
}
let added_roles: Vec<Role> = formation
.role_ids
.iter()
.map(|&role_id| world.get_entity_id(role_id))
.map(|&role_id| Role::new(role_id))
.collect();
for id in removed_entities.clone() {
if let (Some(concomitant),) = query_components!(world, id, Concomitant) {
removed_entities.extend(concomitant.custom_entity_ids.clone());
};
if !added_roles.is_empty() {
// add new roles
player.notify(player.build_player_entity_add_notify(added_roles, world));
}
removed_entities.iter().for_each(|&entity_id| {
world.remove_entity(entity_id as i32);
});
player.notify(player.build_player_entity_remove_notify(
removed_entities,
ERemoveEntityType::RemoveTypeForce,
// send update group formation notify
player.notify(player.build_update_group_formation_notify(
RoleFormation {
id: formation_id,
cur_role,
role_ids: formation.role_ids.clone(),
is_current,
},
world,
));
}
player.build_player_entity_add_notify(world);
// send update group formation notify
player.notify(player.build_update_group_formation_notify(
RoleFormation {
id: formation_id,
cur_role,
role_ids: formation.role_ids.clone(),
is_current,
},
world,
));
response.formation = Some(formation.clone());
}
// update all formation and check formation_list
player
.formation_list
.entry(formation_id)
.and_modify(|r| {
r.cur_role = formation.cur_role;
r.role_ids = formation.role_ids.clone();
r.is_current = is_current;
})
.or_insert(RoleFormation {
id: formation_id,
cur_role: formation.cur_role,
role_ids: formation.role_ids,
is_current,
});
}
player.notify(player.build_update_formation_notify());

View file

@ -73,7 +73,5 @@ pub fn on_unlock_role_skin_list_request(
response: &mut UnlockRoleSkinListResponse,
) {
// TODO: port this from golang
response.role_skin_list = wicked_waifus_data::role_skin_data::iter()
.map(|data| data.id)
.collect::<Vec<_>>();
response.phantom_skin_list = vec![];
}

View file

@ -12,10 +12,6 @@ pub struct ExploreTools {
pub roulette: Roulette,
}
const ADDITIONAL_ROULETTE: &[i32] = &[
1015 // flight
];
impl ExploreTools {
pub fn build_save_data(&self) -> PlayerExploreToolsData {
PlayerExploreToolsData {
@ -67,16 +63,6 @@ impl ExploreTools {
.enumerate()
.for_each(|(i, e)| roulette[i] = e.phantom_skill_id);
let mut count = 2;
explore_tools_data::iter()
.for_each(|e| {
if ADDITIONAL_ROULETTE.contains(&e.phantom_skill_id) {
count += 1;
roulette[count] = e.phantom_skill_id
}
});
roulette
}
}

View file

@ -9,11 +9,11 @@ use wicked_waifus_protocol::message::Message;
use wicked_waifus_protocol::player_attr::Value;
use wicked_waifus_protocol::{
AdventreTask, AdventureManualData, AdventureUpdateNotify, AdviceSettingNotify, BuffItemNotify,
ControlInfoNotify, ERemoveEntityType, EnergyInfo, EnergyUpdateNotify,
EntityRemoveInfo, EntityRemoveNotify,
ControlInfoNotify, EEntityType, ERemoveEntityType, EnergyInfo, EnergyUpdateNotify,
EntityAddNotify, EntityConfigType, EntityPb, EntityRemoveInfo, EntityRemoveNotify, EntityState,
FavorItem, FightFormationNotifyInfo, FightRoleInfo, FightRoleInfos, FormationRoleInfo,
GroupFormation, HostTeleportUnlockNotify, InstDataNotify, ItemPkgOpenNotify,
LevelPlayInfoNotify, LivingStatus, MailInfosNotify,
LevelPlayInfoNotify, LivingStatus, MailInfosNotify, MapUnlockFieldNotify,
MonthCardDailyRewardNotify, MoonChasingTargetGetCountNotify,
MoonChasingTrackMoonHandbookRewardNotify, NormalItemUpdateNotify, PassiveSkillNotify,
PbGetRoleListNotify, PlayerAttr, PlayerAttrKey, PlayerAttrNotify, PlayerAttrType,
@ -24,12 +24,11 @@ use wicked_waifus_protocol::{
};
use wicked_waifus_protocol_internal::{PlayerBasicData, PlayerRoleData, PlayerSaveData};
use super::ecs::component::ComponentContainer;
use super::utils::world_util::add_player_entities;
use super::{
ecs::world::World,
role::{Role, RoleFormation},
};
use crate::logic::components::RoleSkin;
use crate::logic::ecs::world::WorldEntity;
use crate::logic::player::basic_info::PlayerBasicInfo;
use crate::logic::player::explore_tools::ExploreTools;
@ -47,8 +46,15 @@ use crate::logic::player::player_mc_element::PlayerMcElement;
use crate::logic::player::player_month_card::PlayerMonthCard;
use crate::logic::player::player_teleports::{PlayerTeleport, PlayerTeleports};
use crate::logic::player::player_tutorials::{PlayerTutorial, PlayerTutorials};
use crate::logic::{
components::{
Attribute, EntityConfig, Equip, FightBuff, Movement, OwnerPlayer, PlayerOwnedEntityMarker,
Position, Visibility, VisionSkill, SoarWingSkin
},
ecs::component::ComponentContainer,
};
use crate::session::Session;
use crate::{config, query_components};
use crate::{config, create_player_entity_pb, query_components};
use crate::logic::player::Element::Spectro;
mod basic_info;
@ -352,8 +358,16 @@ impl Player {
}
}
pub fn build_player_entity_add_notify(&self, world: &mut WorldEntity) {
add_player_entities(self, self.formation_list.get(&self.cur_formation_id).unwrap(), Some(world))
pub fn build_player_entity_add_notify(&self, role_list: Vec<Role>, world: &mut WorldEntity) -> EntityAddNotify {
create_player_entity_pb!(
role_list,
self.basic_info.cur_map_id,
self,
self.basic_info.id,
self.location.position.clone(),
self.explore_tools,
world
)
}
pub fn build_player_entity_remove_notify(
@ -389,7 +403,8 @@ impl Player {
.iter()
.map(|&role_id| {
let entity_id = world.get_entity_id(role_id);
let _role_skin = query_components!(world, entity_id, RoleSkin).0.unwrap();
let role_skin =
query_components!(world, entity_id, RoleSkin).0.unwrap();
FightRoleInfo {
role_id,
entity_id: world.get_entity_id(role_id),

View file

@ -8,8 +8,7 @@ pub struct RoleFormation {
}
// Will be updated every version
// const DEFAULT_FORMATION: &[i32] = &[5101, 1407, 1507];
const DEFAULT_FORMATION: &[i32] = &[1506, 1207, 1409];
const DEFAULT_FORMATION: &[i32] = &[1506, 1407, 1507];//5101, 1407, 1507]; // 5022 MChibi 5023 FChibi //5023, 5025, 5026 //1607
impl RoleFormation {
pub fn default_roles() -> &'static [i32] {

View file

@ -158,13 +158,13 @@ impl Role {
// Overwrite dynamic attributes with stores values
let mut base_stats = get_role_props_by_level(self.role_id, self.level, self.breakthrough);
// TODO: Integrity check, value has to be between 0 and max
base_stats.life = base_stats.life_max;
base_stats.energy = base_stats.energy_max;
base_stats.life = self.hp;
base_stats.energy = self.energy;
base_stats.special_energy_1 = self.special_energy_1;
base_stats.special_energy_2 = self.special_energy_2;
base_stats.special_energy_3 = self.special_energy_3;
base_stats.special_energy_4 = self.special_energy_4;
base_stats.element_energy = base_stats.element_energy_max;
base_stats.element_energy = self.element_energy;
base_stats
}

View file

@ -1,10 +1,6 @@
use super::{ecs::world::World, player::Player, utils::world_util};
use crate::logic::ecs::world::WorldEntity;
use crate::{
logic,
player_save_task::{self, PlayerSaveReason},
session::Session,
};
use wicked_waifus_commons::time_util;
use wicked_waifus_protocol_internal::PlayerSaveData;
use wicked_waifus_protocol::{message::Message, AfterJoinSceneNotify, EnterGameResponse, JoinSceneNotify, SilenceNpcNotify, TransitionOptionPb};
use std::collections::hash_map::Entry::Vacant;
use std::{
cell::RefCell,
@ -17,20 +13,16 @@ use std::{
thread,
time::Duration,
};
use wicked_waifus_commons::time_util;
use wicked_waifus_protocol::{
message::Message, AfterJoinSceneNotify, EnterGameResponse, JoinSceneNotify, SilenceNpcNotify,
TransitionOptionPb,
};
use wicked_waifus_protocol::{FormationAttr, FormationAttrNotify};
use wicked_waifus_protocol_internal::PlayerSaveData;
use super::{ecs::world::World, player::Player, utils::world_util};
use crate::logic::ecs::world::WorldEntity;
use crate::{logic, player_save_task::{self, PlayerSaveReason}, session::Session};
pub enum LogicInput {
AddPlayer {
player_id: i32,
enter_rpc_id: u16,
session: Arc<Session>,
player_save_data: Box<PlayerSaveData>,
player_save_data: PlayerSaveData,
},
RemovePlayer {
player_id: i32,
@ -140,14 +132,16 @@ fn handle_logic_input(state: &mut LogicState, input: LogicInput) {
} => {
let (player, is_player) = if let Vacant(e) = state.players.entry(player_id) {
(
e.insert(RefCell::new(Player::load_from_save(*player_save_data))),
e.insert(RefCell::new(Player::load_from_save(player_save_data))),
true,
)
} else if let Some(player) = state.players.get_mut(&player_id) {
(player, false)
} else {
tracing::warn!("logic_thread: get player requested, but player {player_id} with data doesn't exist");
return;
if let Some(player) = state.players.get_mut(&player_id) {
(player, false)
} else {
tracing::warn!("logic_thread: get player requested, but player {player_id} with data doesn't exist");
return;
}
};
let mut player = player.borrow_mut();
@ -169,7 +163,8 @@ fn handle_logic_input(state: &mut LogicState, input: LogicInput) {
.world
.borrow_mut()
.set_in_world_player_data(player.build_in_world_player());
world_util::add_player_entities(&player, player.formation_list.get(&player.cur_formation_id).unwrap(), None);
world_util::add_player_entities(&player);
let scene_info = world_util::build_scene_information(&player);
player.notify(SilenceNpcNotify::default());
@ -180,26 +175,6 @@ fn handle_logic_input(state: &mut LogicState, input: LogicInput) {
transition_option: Some(TransitionOptionPb::default()),
});
player.notify(FormationAttrNotify {
duration: 1534854458,
formation_attrs: vec![
FormationAttr {
attr_id: 1,
ratio: 2400,
base_max_value: 24000,
max_value: 24000,
current_value: 24000,
},
FormationAttr {
attr_id: 10,
ratio: 2400,
base_max_value: 15000,
max_value: 15000,
current_value: 15000,
},
],
});
player.notify(AfterJoinSceneNotify::default());
player.notify(player.build_update_formation_notify());
@ -236,14 +211,10 @@ fn handle_logic_input(state: &mut LogicState, input: LogicInput) {
return;
};
let removed_world = state.worlds.remove(&player_id).unwrap();
let mut removed_world_ref = removed_world.borrow_mut();
let world = removed_world_ref.get_mut_world_entity();
for entity_id in world.get_all_entity_ids() {
world.remove_entity(entity_id);
}
let _ = state.worlds.remove(&player_id);
// TODO: kick co-op players from removed world
// TODO: Remove all entities
player_save_task::push(
player_id,
player.borrow().build_save_data(),

View file

@ -0,0 +1,303 @@
use std::collections::HashMap;
use wicked_waifus_protocol::{CommonTagData, EntityCommonTagNotify, EntityStateReadyNotify, ItemRewardNotify, NormalItemUpdateNotify, RewardItemInfo, WR};
use wicked_waifus_data::pb_components::action::{Action, ChangeSelfEntityState, UnlockTeleportTrigger};
use wicked_waifus_data::pb_components::entity_state::EntityStateComponent;
use crate::logic::ecs::component::ComponentContainer;
use crate::logic::player::{ItemUsage, Player};
use crate::logic::utils::tag_utils;
use crate::query_components;
macro_rules! unimplemented_action {
($action:ident) => {
{
tracing::warn!("Action not implemented for: {:?}", $action);
}
}
}
pub fn perform_action(player: &mut Player,
entity_id: i64,
level_entity_data: &wicked_waifus_data::LevelEntityConfigData,
template_config: &wicked_waifus_data::TemplateConfigData,
element: Action) {
match element {
Action::SetBattleState(action) => unimplemented_action! { action },
Action::ExecBattleAction(action) => unimplemented_action! { action },
Action::WaitBattleCondition(action) => unimplemented_action! { action },
Action::PlayFlow(action) => unimplemented_action! { action },
Action::Collect(_) => collect_action(player, level_entity_data, template_config),
Action::LeisureInteract(action) => unimplemented_action! { action },
Action::UnlockTeleportTrigger(action) => unlock_teleport_trigger(player, action.params),
Action::EnableTemporaryTeleport(action) => unimplemented_action! { action },
Action::OpenSystemBoard(action) => unimplemented_action! { action },
Action::OpenSystemFunction(action) => unimplemented_action! { action },
Action::ChangeSelfEntityState(action) => change_self_entity_state(player, entity_id, level_entity_data, template_config, action.params),
Action::SetPlayerOperationRestriction(action) => unimplemented_action! { action },
Action::Wait(action) => unimplemented_action! { action },
Action::ChangeEntityState(action) => unimplemented_action! { action },
Action::Log(action) => unimplemented_action! { action },
Action::EnableNearbyTracking(action) => unimplemented_action! { action },
Action::TeleportDungeon(action) => unimplemented_action! { action },
Action::DestroySelf(action) => unimplemented_action! { action },
Action::CameraLookAt(action) => unimplemented_action! { action },
Action::EnterOrbitalCamera(action) => unimplemented_action! { action },
Action::ExitOrbitalCamera(action) => unimplemented_action! { action },
Action::SendAiEvent(action) => unimplemented_action! { action },
Action::SetInteractionLockState(action) => unimplemented_action! { action },
Action::AwakeEntity(action) => unimplemented_action! { action },
Action::ChangeLiftTarget(action) => unimplemented_action! { action },
Action::CalculateVar(action) => unimplemented_action! { action },
Action::AddBuffToPlayer(action) => unimplemented_action! { action },
Action::RemoveBuffFromPlayer(action) => unimplemented_action! { action },
Action::AddBuffToEntity(action) => unimplemented_action! { action },
Action::RemoveBuffFromEntity(action) => unimplemented_action! { action },
Action::Prompt(action) => unimplemented_action! { action },
Action::SetEntityVisible(action) => unimplemented_action! { action },
Action::DestroyEntity(action) => unimplemented_action! { action },
Action::GuideTrigger(action) => unimplemented_action! { action },
Action::TriggerCameraShake(action) => unimplemented_action! { action },
Action::SetVar(action) => unimplemented_action! { action },
Action::VehicleEnter(action) => unimplemented_action! { action },
Action::VehicleExitPlayer(action) => unimplemented_action! { action },
Action::LockEntity(action) => unimplemented_action! { action },
Action::UnlockEntity(action) => unimplemented_action! { action },
Action::CommonTip(action) => unimplemented_action! { action },
Action::CommonTip2(action) => unimplemented_action! { action },
Action::PostAkEvent(action) => unimplemented_action! { action },
Action::VehicleEnterNpc(action) => unimplemented_action! { action },
Action::VehicleExitNpc(action) => unimplemented_action! { action },
Action::PlayerLookAt(action) => unimplemented_action! { action },
Action::PlayBubble(action) => unimplemented_action! { action },
Action::AddPlayBubble(action) => unimplemented_action! { action },
Action::ClearPlayBubble(action) => unimplemented_action! { action },
Action::ExecRiskHarvestEffect(action) => unimplemented_action! { action },
Action::EnableLevelPlay(action) => unimplemented_action! { action },
Action::ClaimLevelPlayReward(action) => unimplemented_action! { action },
Action::SettlementDungeon(action) => unimplemented_action! { action },
Action::ExitDungeon(action) => unimplemented_action! { action },
Action::FinishDungeon(action) => unimplemented_action! { action },
Action::RecordDungeonEvent(action) => unimplemented_action! { action },
Action::RecoverDurability(action) => unimplemented_action! { action },
Action::FadeInScreen(action) => unimplemented_action! { action },
Action::FadeOutScreen(action) => unimplemented_action! { action },
Action::ChangeNpcPerformState(action) => unimplemented_action! { action },
Action::EntityTurnTo(action) => unimplemented_action! { action },
Action::EntityLookAt(action) => unimplemented_action! { action },
Action::ToggleMapMarkState(action) => unimplemented_action! { action },
Action::RandomVar(action) => unimplemented_action! { action },
Action::ModifySceneItemAttributeTag(action) => unimplemented_action! { action },
Action::VehicleWaterfallClimbing(action) => unimplemented_action! { action },
Action::VehicleTeleport(action) => unimplemented_action! { action },
Action::RogueGotoNextFloor(action) => unimplemented_action! { action },
Action::RogueReceiveReward(action) => unimplemented_action! { action },
Action::RogueSelectRoom(action) => unimplemented_action! { action },
Action::RogueActivatePortal(action) => unimplemented_action! { action },
Action::MowingTowerGotoNextFloor(action) => unimplemented_action! { action },
Action::SlashAndTowerGotoNextFloor(action) => unimplemented_action! { action },
Action::PlayMontage(action) => unimplemented_action! { action },
Action::OpenSystemBoardWithReturn(action) => unimplemented_action! { action },
Action::UnlockSystemItem(action) => unimplemented_action! { action },
Action::SetSportsState(action) => unimplemented_action! { action },
Action::OpenSimpleGameplay(action) => unimplemented_action! { action },
Action::PlayEffect(action) => unimplemented_action! { action },
Action::PlayEffect2(action) => unimplemented_action! { action },
Action::RestorePlayerCameraAdjustment(action) => unimplemented_action! { action },
Action::AdjustPlayerCamera(action) => unimplemented_action! { action },
Action::SetPlayerPos(action) => unimplemented_action! { action },
Action::MoveWithSpline(action) => unimplemented_action! { action },
Action::EnableSplineMoveModel(action) => unimplemented_action! { action },
Action::ToggleScanSplineEffect(action) => unimplemented_action! { action },
Action::MoveSceneItem(action) => unimplemented_action! { action },
Action::StopSceneItemMove(action) => unimplemented_action! { action },
Action::FireBullet(action) => unimplemented_action! { action },
Action::ClearFishingCabinInSaleItems(action) => unimplemented_action! { action },
Action::AcceptFishingEntrust(action) => unimplemented_action! { action },
Action::DestroyFishingBoat(action) => unimplemented_action! { action },
Action::SetJigsawItem(action) => unimplemented_action! { action },
Action::SetJigsawFoundation(action) => unimplemented_action! { action },
Action::SetTeleControl(action) => unimplemented_action! { action },
Action::SetEntityClientVisible(action) => unimplemented_action! { action },
Action::ToggleHighlightExploreUi(action) => unimplemented_action! { action },
Action::ExecAlertSystemAction(action) => unimplemented_action! { action },
Action::AddFlowInteractOption(action) => unimplemented_action! { action },
Action::RemoveFlowInteractOption(action) => unimplemented_action! { action },
Action::EnableHostility(action) => unimplemented_action! { action },
Action::ChangePhantomFormation(action) => unimplemented_action! { action },
Action::RestorePhantomFormation(action) => unimplemented_action! { action },
Action::ChangeTimer(action) => unimplemented_action! { action },
Action::ToggleTimerPauseState(action) => unimplemented_action! { action },
Action::ChangeFightTeam(action) => unimplemented_action! { action },
Action::AddTrialFollowShooter(action) => unimplemented_action! { action },
Action::RemoveTrialFollowShooter(action) => unimplemented_action! { action },
Action::AddTrialCharacter(action) => unimplemented_action! { action },
Action::RemoveTrialCharacter(action) => unimplemented_action! { action },
Action::SetAreaState(action) => unimplemented_action! { action },
Action::SwitchSubLevels(action) => unimplemented_action! { action },
Action::ChangeTeamPosition(action) => unimplemented_action! { action },
Action::GetItem(action) => unimplemented_action! { action },
Action::CreatePrefab(action) => unimplemented_action! { action },
Action::DestroyPrefab(action) => unimplemented_action! { action },
Action::CompleteGuide(action) => unimplemented_action! { action },
Action::PlayDynamicSettlement(action) => unimplemented_action! { action },
Action::UsePhantomSkill(action) => unimplemented_action! { action },
Action::HideTargetRange(action) => unimplemented_action! { action },
Action::ChangeOtherState(action) => unimplemented_action! { action },
Action::SetRegionConfig(action) => unimplemented_action! { action },
Action::SetReviveRegion(action) => unimplemented_action! { action },
Action::ExecResurrection(action) => unimplemented_action! { action },
Action::ShowTargetRange(action) => unimplemented_action! { action },
Action::SetTime(action) => unimplemented_action! { action },
Action::SetTimeLockState(action) => unimplemented_action! { action },
Action::EnableSystem(action) => unimplemented_action! { action },
Action::EnableAoiNotify(action) => unimplemented_action! { action },
Action::SetForceLock(action) => unimplemented_action! { action },
Action::PlayRegisteredMontage(action) => unimplemented_action! { action },
Action::SetAudioState(action) => unimplemented_action! { action },
Action::HideGroup(action) => unimplemented_action! { action },
Action::ShowHidedGroup(action) => unimplemented_action! { action },
Action::HideSpecificEntities(action) => unimplemented_action! { action },
Action::ShowSpecificEntities(action) => unimplemented_action! { action },
Action::RemovePreloadResource(action) => unimplemented_action! { action },
Action::Preload(action) => unimplemented_action! { action },
Action::EnableAI(action) => unimplemented_action! { action },
Action::SwitchDataLayers(action) => unimplemented_action! { action },
Action::DestroyQuest(action) => unimplemented_action! { action },
Action::DestroyQuestItem(action) => unimplemented_action! { action },
Action::PromptQuestChapterUI(action) => unimplemented_action! { action },
Action::TakePlotPhoto(action) => unimplemented_action! { action },
Action::SetWuYinQuState(action) => unimplemented_action! { action },
Action::RunActions(action) => unimplemented_action! { action },
Action::ManualOccupations(action) => unimplemented_action! { action },
Action::SetWeather(action) => unimplemented_action! { action },
Action::SendNpcMail(action) => unimplemented_action! { action },
Action::EnableFunction(action) => unimplemented_action! { action },
Action::FocusOnMapMark(action) => unimplemented_action! { action },
Action::CharacterLookAt(action) => unimplemented_action! { action },
Action::AddGuestCharacter(action) => unimplemented_action! { action },
Action::RemoveGuestCharacter(action) => unimplemented_action! { action },
Action::TeleportToAndEnterVehicle(action) => unimplemented_action! { action },
Action::SetAreaTimeState(action) => unimplemented_action! { action },
Action::ResetPlayerCameraFocus(action) => unimplemented_action! { action },
Action::ResetLevelPlay(action) => unimplemented_action! { action },
Action::VehicleSprint(action) => unimplemented_action! { action },
Action::VehicleMoveWithPathLine(action) => unimplemented_action! { action },
Action::ClientPreEnableSubLevels(action) => unimplemented_action! { action },
Action::GuestOperateUiAnimation(action) => unimplemented_action! { action },
Action::ChangeEntityCamp(action) => unimplemented_action! { action },
Action::NewMoveWithSpline(action) => unimplemented_action! { action },
Action::DangoAbyssActivatePortal(action) => unimplemented_action! { action },
Action::DangoAbyssCreateRewardTreasureBox(action) => unimplemented_action! { action },
Action::DangoAbyssGotoNextFloor(action) => unimplemented_action! { action },
Action::DangoAbyssReceiveReward(action) => unimplemented_action! { action },
Action::SummonEntity(action) => unimplemented_action! { action },
Action::GetRewardByInteract(action) => unimplemented_action! { action },
Action::OpenQte(action) => unimplemented_action! { action },
Action::ActiveAntiGravitySafePoint(action) => unimplemented_action! { action },
}
}
fn collect_action(player: &mut Player,
level_entity_data: &wicked_waifus_data::LevelEntityConfigData,
template_config: &wicked_waifus_data::TemplateConfigData) {
if let Some(reward_component) = level_entity_data.components_data.reward_component
.as_ref()
.or(template_config.components_data.reward_component.as_ref()) {
if reward_component.disabled.unwrap_or(false) {
return;
}
// TODO: check the use of reward_type and drop_on_event
// Seems type 0 is reward from preview, while 1 and 2 is unknown
if let Some(reward_id) = reward_component.reward_id {
let drop = wicked_waifus_data::drop_package_data::get(&reward_id).unwrap();
let usages = drop.drop_preview.iter()
.map(|(&id, &quantity)| ItemUsage { id, quantity })
.collect::<Vec<_>>();
let updated_items = player.inventory.add_items(&usages);
let normal_item_list = player.inventory.to_normal_item_list_filtered(
updated_items.keys().cloned().collect::<Vec<i32>>()
);
player.notify(NormalItemUpdateNotify { normal_item_list, no_tips: false });
// UpdateHandBookActiveStateMapNotify
let mut rewards: HashMap<i32, WR> = HashMap::new();
rewards.insert(0, WR {
item_list: drop.drop_preview.iter()
.map(|(&id, &quantity)| RewardItemInfo {
show_plan_id: 0, // TODO: Check how to get this
item_id: id,
count: quantity,
incr_id: 0,
})
.collect::<Vec<_>>(),
});
player.notify(ItemRewardNotify {
drop_id: reward_id,
reason: 15000,
magnification: 1,
reward_items: rewards,
});
}
// TODO: Should we remove entity?? get pcap
}
}
#[inline(always)]
fn unlock_teleport_trigger(player: &mut Player, action: UnlockTeleportTrigger) {
player.unlock_teleport(action.teleport_id)
}
fn change_self_entity_state(player: &mut Player,
entity_id: i64,
level_entity_data: &wicked_waifus_data::LevelEntityConfigData,
template_config: &wicked_waifus_data::TemplateConfigData,
action: ChangeSelfEntityState) {
let state = tag_utils::get_tag_id_by_name(action.entity_state.as_str());
// TODO: update Tag::CommonEntityTags too??
let old_state = {
let world_ref = player.world.borrow();
let world = world_ref.get_world_entity();
let mut state_tag = query_components!(world, entity_id, StateTag).0.unwrap();
let old_state = state_tag.state_tag_id;
tracing::debug!("ChangeSelfEntityState: old state {old_state} -> new state: {state}");
state_tag.state_tag_id = state;
old_state
};
if let Some(entity_state_component) = level_entity_data.components_data.entity_state_component.as_ref()
.or(template_config.components_data.entity_state_component.as_ref()).cloned() {
let entity_state_component: EntityStateComponent = entity_state_component; // TODO: Remove this line, used for casting only
// TODO: implement rest of cases
if let Some(state_change_behaviors) = entity_state_component.state_change_behaviors {
for state_change_behavior in state_change_behaviors {
// TODO: implement rest of cases
let expected = tag_utils::get_tag_id_by_name(state_change_behavior.state.as_str());
if expected == state {
if let Some(actions) = state_change_behavior.action {
for sub in actions {
perform_action(player, entity_id, level_entity_data, template_config, sub);
}
}
}
}
}
}
player.notify(EntityCommonTagNotify {
id: entity_id,
tags: vec![
CommonTagData { tag_id: old_state, remove_tag_ids: false }, // Remove
CommonTagData { tag_id: state, remove_tag_ids: true }, // Add
],
});
player.notify(EntityStateReadyNotify {
entity_id,
tag_id: state,
ready: true, // TODO: Always true? or shall we compare it to something??
});
}

View file

@ -119,11 +119,6 @@ pub fn check_condition(player: &Player,
Condition::CheckEntityGravityDirection(condition) => unimplemented_condition! { condition },
Condition::CheckTeleControlState(condition) => unimplemented_condition! { condition },
Condition::CheckEntityReward(condition) => unimplemented_condition! { condition },
Condition::CheckIsGramophonePlayingMusic(condition) => unimplemented_condition! { condition },
Condition::CheckBVBEvent(condition) => unimplemented_condition! { condition },
Condition::FinishBvbChallenge(condition) => unimplemented_condition! { condition },
Condition::CompareActorVar(condition) => unimplemented_condition! { condition },
Condition::CheckDangoCultivationProgress(condition) => unimplemented_condition! { condition },
}
}

View file

@ -62,6 +62,21 @@ impl_base_prop!(
damage_reduce_element4,
damage_reduce_element5,
damage_reduce_element6,
reaction_change1,
reaction_change2,
reaction_change3,
reaction_change4,
reaction_change5,
reaction_change6,
reaction_change7,
reaction_change8,
reaction_change9,
reaction_change10,
reaction_change11,
reaction_change12,
reaction_change13,
reaction_change14,
reaction_change15,
energy_max,
energy,
special_energy_1_max,

View file

@ -1,3 +1,4 @@
pub mod action_utils;
pub mod condition_utils;
pub mod entity_serializer;
pub mod load_role_info;

View file

@ -5,7 +5,7 @@ use wicked_waifus_protocol::{
use wicked_waifus_data::pb_components::ComponentsData;
use wicked_waifus_data::{
base_property_data, blueprint_config_data, summon_cfg_data, template_config_data, EntityLogic, EntityType, LevelEntityConfigData
base_property_data, blueprint_config_data, template_config_data, EntityLogic, EntityType, LevelEntityConfigData
};
use crate::logic::components::{Autonomous, Fsm, Interact, MonsterAi, SoarWingSkin, StateTag, Tag};
@ -13,7 +13,6 @@ use crate::logic::ecs::entity::{Entity, EntityBuilder};
use crate::logic::ecs::world::{World, WorldEntity};
use crate::logic::math::Transform;
use crate::logic::player::Player;
use crate::logic::role::RoleFormation;
use crate::logic::utils::growth_utils::get_monster_props_by_level;
use crate::logic::utils::{entity_serializer, tag_utils};
use crate::logic::{
@ -27,35 +26,133 @@ use crate::logic::{
use crate::query_with;
pub fn summon_concomitant(player: &Player, world: &mut WorldEntity, template_cfg: &wicked_waifus_data::TemplateConfigData, cur_summon_id: i32) -> (Entity, Vec<i64>) {
#[macro_export]
macro_rules! create_player_entity_pb {
($role_list:expr, $cur_map_id:expr, $player:expr, $player_id:expr, $position:expr, $explore_tools:expr, $world:expr) => {{
let current_formation = $player
.formation_list
.get(&$player.cur_formation_id)
.unwrap();
let cur_role_id = current_formation.cur_role;
let mut pbs = Vec::new();
for role in $role_list {
let role_id: i32 = role.role_id;
let entity =
$world.create_entity(role.role_id, EEntityType::Player.into(), $cur_map_id);
let fight_buff_infos = $world.generate_role_permanent_buffs(entity.entity_id, role_id);
let buffs = FightBuff {
fight_buff_infos,
..Default::default()
};
let entity = $world
.create_builder(entity)
.with(ComponentContainer::PlayerOwnedEntityMarker(
PlayerOwnedEntityMarker {
entity_type: EEntityType::Player,
},
))
.with(ComponentContainer::EntityConfig(EntityConfig {
camp: 0,
config_id: role.role_id,
config_type: EntityConfigType::Character,
entity_type: EEntityType::Player.into(),
entity_state: EntityState::Default,
}))
.with(ComponentContainer::OwnerPlayer(OwnerPlayer($player_id)))
.with(ComponentContainer::Position(Position($position)))
.with(ComponentContainer::Visibility(Visibility {
is_visible: role.role_id == cur_role_id,
is_actor_visible: true,
}))
.with(ComponentContainer::Attribute(Attribute::from_data(
&role.get_base_properties(),
None,
None,
)))
.with(ComponentContainer::Movement(Movement::default()))
.with(ComponentContainer::Equip(Equip {
weapon_id: role.equip_weapon,
weapon_breach_level: 90,
}))
.with(ComponentContainer::VisionSkill(VisionSkill {
skill_id: $explore_tools.active_explore_skill,
}))
.with(ComponentContainer::RoleSkin(RoleSkin {
skin_id: role.skin_id,
}))
.with(ComponentContainer::SoarWingSkin(SoarWingSkin {
skin_id: 84000001,
}))
.with(ComponentContainer::FightBuff(buffs))
.build();
let mut pb = EntityPb {
id: entity.entity_id as i64,
..Default::default()
};
$world
.get_entity_components(entity.entity_id)
.into_iter()
.for_each(|comp| comp.set_pb_data(&mut pb));
pbs.push(pb);
}
EntityAddNotify {
entity_pbs: pbs,
remove_tag_ids: true,
}
}};
}
fn summon_concomitant(player: &Player, world: &mut WorldEntity, summon_cfg: &wicked_waifus_data::SummonCfgData) -> Entity {
let mut concomitant_buffs: Vec<FightBuffInformation> = Vec::new();
let summon_cfg = summon_cfg_data::get(&template_cfg.blueprint_type).unwrap();
let concomitant_config_id = template_cfg.id;
for buff_id in &summon_cfg.born_buff_id {
concomitant_buffs
.push(FightBuffInformation {
handle_id: 1,
buff_id: *buff_id,
level: 1,
stack_count: 1,
instigator_id: 0,
entity_id: 0,
apply_type: 0,
duration: -1.0,
left_duration: -1.0,
context: vec![],
is_active: true,
server_id: 1,
message_id: 1,
}
);
}
let concomitant_id = template_config_data::get(&summon_cfg.blueprint_type).unwrap().id;
tracing::info!("Adding Concomitant with id: {}", concomitant_id);
let con_buffs = concomitant_buffs.clone();
let con_entity = world.create_entity(
cur_summon_id,
concomitant_id,
EEntityType::Monster.into(),
player.basic_info.cur_map_id,
);
for buff_id in &summon_cfg.born_buff_id {
concomitant_buffs.push(world.create_buff(cur_summon_id, *buff_id));
}
tracing::info!("Adding Concomitant with id: {} and buffs {:#?}", concomitant_config_id, concomitant_buffs);
(world
world
.create_builder(con_entity)
.with(ComponentContainer::PlayerOwnedEntityMarker(PlayerOwnedEntityMarker {
entity_type: EEntityType::Monster,
}))
.with(ComponentContainer::EntityConfig(EntityConfig {
camp: 0,
config_id: concomitant_config_id,
config_id: concomitant_id,
config_type: EntityConfigType::Template,
entity_type: EEntityType::Monster,
entity_state: EntityState::Born,
entity_state: EntityState::Sleep,
}))
.with(ComponentContainer::OwnerPlayer(OwnerPlayer(
player.basic_info.id,
@ -65,194 +162,129 @@ pub fn summon_concomitant(player: &Player, world: &mut WorldEntity, template_cfg
)))
.with(ComponentContainer::Visibility(Visibility {
is_visible: false,
is_actor_visible: true,
is_actor_visible: false,
}))
.with(ComponentContainer::Attribute(Attribute::from_data(
base_property_data::iter()
.find(|d| d.id == template_cfg.components_data.attribute_component.clone().unwrap().property_id.unwrap())
.unwrap(),
.find(|d| d.id == concomitant_id as i32)
.unwrap_or_else(|| {
base_property_data::iter()
.find(|d| d.id == 390070051)
.unwrap_or_else(|| {
tracing::error!("Default base property concomitant not found!");
panic!("Critical config missing: base property concomitant")
})
}),
None,
None,
)))
.with(ComponentContainer::FightBuff(FightBuff { fight_buff_infos: concomitant_buffs, ..Default::default() }))
.with(ComponentContainer::Movement(Movement::default()))
.with(ComponentContainer::FightBuff(FightBuff { fight_buff_infos: con_buffs, ..Default::default() }))
.with(ComponentContainer::Summoner(Summoner {
summon_cfg_id: summon_cfg.id,
summon_skill_id: 0,
summon_type: ESummonType::ESummonTypeConcomitantCustom.into()
}))
.with(ComponentContainer::Autonomous(Autonomous { autonomous_id: 3 }))
.build(), summon_cfg.born_buff_id.clone())
.build()
}
fn add_player_entity(player: &Player, formation: &RoleFormation, world: &mut WorldEntity) {
let role_vec = formation
pub fn add_player_entities(player: &Player) {
let mut world_ref = player.world.borrow_mut();
let world = world_ref.get_mut_world_entity();
let current_formation = player.formation_list.get(&player.cur_formation_id).unwrap();
let role_vec = current_formation
.role_ids
.iter()
.map(|role_id| player.role_list.get(role_id).unwrap())
.collect::<Vec<_>>();
let cur_role_id = current_formation.cur_role;
tracing::info!("adding player entity for formation {:#?}", formation.role_ids);
let cur_role_id = formation.cur_role;
if world.active_entity_empty() {
for role in role_vec {
let mut concomitants: Vec<i64> = vec![];
let mut pbs = Vec::new();
for role in role_vec {
let entity = world.create_entity(
role.role_id,
EEntityType::Player.into(),
player.basic_info.cur_map_id,
);
let mut fight_buff_infos = world.generate_role_permanent_buffs(entity.entity_id, role.role_id);
// TODO: add actual weapon switching and remove this! - rabby
let equip_weapon = match role.role_id {
1409 => 21020056, // cartethyia
1207 => 21010036, // lupa
1301 => 21010036,
_ => role.equip_weapon,
};
let mut concomitants: Vec<i64> = vec![];
let mut concom_pbs = Vec::new();
let role_data = wicked_waifus_data::role_info_data::iter().find(|r| r.id == role.role_id).unwrap();
if let Some(skin_damage_first) = role_data.skin_damage.first() {
let role_name = skin_damage_first.as_str()
.split('/').next_back()
.and_then(|s| s.strip_prefix("DA_"))
.and_then(|s| s.split('_').next()).unwrap();
let mut summon_id = 1000;
for model_config in wicked_waifus_data::model_config_preload_data::iter().filter(|cfg| {
cfg.actor_class_path.starts_with("/Game/Aki/Character/Monster/Summon/") && cfg.actor_class_path.contains(role_name)
for (_, summon_cfg) in wicked_waifus_data::summon_cfg_data::iter().filter(|(_, cfg)| {
cfg.blueprint_type.starts_with("Player0") && cfg.born_buff_id.iter().any(|x| {
x.to_string().starts_with(&role.role_id.to_string())
})
}) {
let template_cfg = wicked_waifus_data::template_config_data::iter().find(|cfg| {
let template_model_component = cfg.1.components_data.model_component.clone();
template_model_component.is_some()
&&
template_model_component.clone().unwrap().model_type.unwrap().model_id.is_some()
&&
template_model_component.unwrap().model_type.unwrap().model_id.unwrap() == model_config.id
}).unwrap().1;
let (concomitant, buffs) = summon_concomitant(player, world, template_cfg, summon_id);
let mut pb = EntityPb {
id: summon_id as i64,
..Default::default()
};
for buff_id in buffs {
fight_buff_infos.push(world.create_buff(entity.entity_id, buff_id));
}
world
.get_entity_components(summon_id)
.into_iter()
.for_each(|comp| comp.set_pb_data(&mut pb));
concom_pbs.push(pb);
summon_id += 1;
let concomitant = summon_concomitant(player, world, summon_cfg);
concomitants.push(concomitant.entity_id.into());
}
player.notify(EntityAddNotify {
entity_pbs: concom_pbs,
remove_tag_ids: true,
});
}
fight_buff_infos.dedup_by(|x, z| x.buff_id == z.buff_id);
let buf_manager = FightBuff {
fight_buff_infos,
list_buff_effect_cd: vec![]
};
let entity = world
.create_builder(entity)
.with(ComponentContainer::PlayerOwnedEntityMarker(
PlayerOwnedEntityMarker {
let entity = world.create_entity(
role.role_id,
EEntityType::Player.into(),
player.basic_info.cur_map_id,
);
let fight_buff_infos = world.generate_role_permanent_buffs(entity.entity_id, role.role_id);
let buf_manager = FightBuff {
fight_buff_infos,
list_buff_effect_cd: vec![]
};
let entity = world
.create_builder(entity)
.with(ComponentContainer::PlayerOwnedEntityMarker(
PlayerOwnedEntityMarker {
entity_type: EEntityType::Player,
},
))
.with(ComponentContainer::EntityConfig(EntityConfig {
camp: 0,
config_id: role.role_id,
config_type: EntityConfigType::Character,
entity_type: EEntityType::Player,
},
))
.with(ComponentContainer::EntityConfig(EntityConfig {
camp: 0,
config_id: role.role_id,
config_type: EntityConfigType::Character,
entity_type: EEntityType::Player,
entity_state: EntityState::Default,
}))
.with(ComponentContainer::OwnerPlayer(OwnerPlayer(
player.basic_info.id,
)))
.with(ComponentContainer::Position(Position(
player.location.position.clone(),
)))
.with(ComponentContainer::Visibility(Visibility {
is_visible: role.role_id == cur_role_id,
is_actor_visible: true,
}))
// TODO: from role
// TODO: Check if role has hardness or rage_mode
// TODO: Support AddProp from Equipment(Echo, weapon, buffs??), weapon base state goes to base_prop too.
.with(ComponentContainer::Attribute(Attribute::from_data(
&role.get_base_properties(),
None,
None,
)))
.with(ComponentContainer::Movement(Movement::default()))
.with(ComponentContainer::Equip(Equip {
weapon_id: equip_weapon,
weapon_breach_level: 0, // TODO: store this too
}))
.with(ComponentContainer::VisionSkill(VisionSkill {
skill_id: player.explore_tools.active_explore_skill,
}))
.with(ComponentContainer::RoleSkin(RoleSkin {
skin_id: role.skin_id,
}))
.with(ComponentContainer::SoarWingSkin(SoarWingSkin {
skin_id: 84000001,
}))
.with(ComponentContainer::FightBuff(buf_manager))
.with(ComponentContainer::Concomitant(Concomitant {
vision_entity_id: 0,
custom_entity_ids: concomitants,
phantom_role_id: 0
}))
.build();
entity_state: EntityState::Default,
}))
.with(ComponentContainer::OwnerPlayer(OwnerPlayer(
player.basic_info.id,
)))
.with(ComponentContainer::Position(Position(
player.location.position.clone(),
)))
.with(ComponentContainer::Visibility(Visibility {
is_visible: role.role_id == cur_role_id,
is_actor_visible: true,
}))
// TODO: from role
// TODO: Check if role has hardness or rage_mode
// TODO: Support AddProp from Equipment(Echo, weapon, buffs??), weapon base state goes to base_prop too.
.with(ComponentContainer::Attribute(Attribute::from_data(
&role.get_base_properties(),
None,
None,
)))
.with(ComponentContainer::Movement(Movement::default()))
.with(ComponentContainer::Equip(Equip {
weapon_id: role.equip_weapon,
weapon_breach_level: 0, // TODO: store this too
}))
.with(ComponentContainer::VisionSkill(VisionSkill {
skill_id: player.explore_tools.active_explore_skill,
}))
.with(ComponentContainer::RoleSkin(RoleSkin {
skin_id: role.skin_id,
}))
.with(ComponentContainer::SoarWingSkin(SoarWingSkin {
skin_id: 84000001,
}))
.with(ComponentContainer::FightBuff(buf_manager))
.with(ComponentContainer::Concomitant(Concomitant {
vision_entity_id: 0,
custom_entity_ids: concomitants,
phantom_role_id: 0,
}))
.build();
let mut pb = EntityPb {
id: entity.entity_id as i64,
..Default::default()
};
world
.get_entity_components(entity.entity_id)
.into_iter()
.for_each(|comp| comp.set_pb_data(&mut pb));
pbs.push(pb);
tracing::debug!(
"created player entity, id: {}, role_id: {}",
entity.entity_id,
role.role_id
);
}
player.notify(EntityAddNotify {
entity_pbs: pbs,
remove_tag_ids: true,
});
}
pub fn add_player_entities(player: &Player, formation: &RoleFormation, possible_world: Option<&mut WorldEntity>) {
match possible_world {
Some(world) => add_player_entity(player, formation, world),
None => {
let mut world_ref = player.world.borrow_mut();
add_player_entity(player, formation, world_ref.get_mut_world_entity())
tracing::debug!(
"created player entity, id: {}, role_id: {}",
entity.entity_id,
role.role_id
);
}
};
}
}
pub fn build_scene_information(player: &Player) -> SceneInformation {

View file

@ -51,12 +51,12 @@ async fn handler_loop(
return;
};
// tracing::debug!(
// "received message from service: {}, rpc_id: {} message_id: {}",
// message.src_service_id,
// message.rpc_id,
// message.message_id
// );
tracing::debug!(
"received message from service: {}, rpc_id: {} message_id: {}",
message.src_service_id,
message.rpc_id,
message.message_id
);
match message.message_id {
CreatePlayerDataRequest::MESSAGE_ID => {
@ -141,7 +141,7 @@ async fn on_start_player_session_request(
player_id: player_data.player_id,
enter_rpc_id: message.rpc_id,
session: session.clone(),
player_save_data: Box::new(player_save_data),
player_save_data,
});
session_mgr.add(session.clone());

View file

@ -4,19 +4,14 @@ edition = "2021"
version.workspace = true
[features]
# If supporting clients < 2.0 please use "--no-default-features"
# (additonally you could add "-F ack-cmd-conv" but it's currently a NO-OP)
default = ["ack-cmd-conv"]
debug-msg = []
ack-cmd-conv = []
ack-cmd-conv-crc-mtu = []
[dependencies]
# Framework
tokio.workspace = true
# Networking
kcp = { git = "https://git.xeondev.com/ReversedRoomsMisc/kcp-rs.git", features = ["wuthering-waves-old", "tokio"] }
kcp = { workspace = true, features = ["tokio"] }
# Serialization
serde.workspace = true

View file

@ -2,7 +2,6 @@ service_id = 1
[network]
kcp_port = 7777
kcp_crc = false
[protokey]
builtin_encryption_msg_id = [111, 112]

View file

@ -0,0 +1,19 @@
[package]
name = "kcp"
edition = "2021"
version.workspace = true
[features]
fastack-conserve = []
tokio = ["dep:tokio"]
[dependencies]
bytes = "1.6.0"
log = "0.4.21"
thiserror = "1.0.58"
tokio = { version = "1.37.0", optional = true, features = ["io-util"] }
[dev-dependencies]
time = "0.3.34"
rand = "0.8.5"

View file

@ -0,0 +1,54 @@
use std::{
error::Error as StdError,
io::{self, ErrorKind},
};
/// KCP protocol errors
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("conv inconsistent, expected {0}, found {1}")]
ConvInconsistent(u32, u32),
#[error("invalid mtu {0}")]
InvalidMtu(usize),
#[error("invalid segment size {0}")]
InvalidSegmentSize(usize),
#[error("invalid segment data size, expected {0}, found {1}")]
InvalidSegmentDataSize(usize, usize),
#[error("{0}")]
IoError(
#[from]
#[source]
io::Error,
),
#[error("need to call update() once")]
NeedUpdate,
#[error("recv queue is empty")]
RecvQueueEmpty,
#[error("expecting fragment")]
ExpectingFragment,
#[error("command {0} is not supported")]
UnsupportedCmd(u8),
#[error("user's send buffer is too big")]
UserBufTooBig,
#[error("user's recv buffer is too small")]
UserBufTooSmall,
}
fn make_io_error<T>(kind: ErrorKind, msg: T) -> io::Error
where
T: Into<Box<dyn StdError + Send + Sync>>,
{
io::Error::new(kind, msg)
}
impl From<Error> for io::Error {
fn from(err: Error) -> Self {
let kind = match err {
Error::IoError(err) => return err,
Error::RecvQueueEmpty | Error::ExpectingFragment => ErrorKind::WouldBlock,
_ => ErrorKind::Other,
};
make_io_error(kind, err)
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,17 @@
extern crate bytes;
#[macro_use]
extern crate log;
mod error;
mod kcp;
/// The `KCP` prelude
pub mod prelude {
pub use super::{get_conv, Kcp, KCP_OVERHEAD};
}
pub use error::Error;
pub use kcp::{get_conv, get_sn, set_conv, Kcp, KCP_OVERHEAD};
/// KCP result
pub type KcpResult<T> = Result<T, Error>;

View file

@ -17,7 +17,6 @@ pub struct ServerConfig {
#[derive(Deserialize)]
pub struct NetworkSettings {
pub kcp_port: u16,
pub kcp_crc: Option<bool>
}
impl TomlConfig for ServerConfig {

View file

@ -38,7 +38,6 @@ async fn main() -> Result<()> {
let server = UdpServer::new(
&CONFIG.network,
PROTOKEY_HELPER.get_or_init(|| protokey_helper),
CONFIG.network.kcp_crc.unwrap_or(false),
&SESSION_MGR,
Arc::new(database),
)

View file

@ -41,7 +41,6 @@ impl Session {
addr: SocketAddr,
socket: Arc<UdpSocket>,
helper: &'static ServerProtoKeyHelper,
use_crc: bool,
database: Arc<PgPool>,
) -> Self {
let output = SessionOutput {
@ -52,7 +51,7 @@ impl Session {
let cur_time_ms = time_util::unix_timestamp_ms();
Self {
protokey_helper: helper,
kcp: Kcp::new(conv_id, 0, use_crc, 0, true, output),
kcp: Kcp::new(conv_id, true, output),
decoder: LengthFieldBasedDecoder::new(),
start_time_ms: cur_time_ms,
last_heartbeat_time_ms: cur_time_ms,

View file

@ -9,7 +9,6 @@ use crate::{config::NetworkSettings, session::Session, session::SessionManager};
pub struct UdpServer {
socket: Arc<UdpSocket>,
protokey_helper: &'static ServerProtoKeyHelper,
kcp_use_crc: bool,
session_mgr: &'static SessionManager,
db: Arc<PgPool>,
}
@ -22,7 +21,6 @@ impl UdpServer {
pub async fn new(
network_settings: &'static NetworkSettings,
protokey_helper: &'static ServerProtoKeyHelper,
kcp_use_crc: bool,
session_mgr: &'static SessionManager,
db: Arc<PgPool>,
) -> Result<Self, tokio::io::Error> {
@ -31,7 +29,6 @@ impl UdpServer {
Ok(Self {
socket: Arc::new(socket),
protokey_helper,
kcp_use_crc,
session_mgr,
db,
})
@ -68,7 +65,6 @@ impl UdpServer {
addr,
self.socket.clone(),
self.protokey_helper,
self.kcp_use_crc,
self.db.clone(),
);
self.session_mgr.add(conv_id, session);
@ -76,11 +72,6 @@ impl UdpServer {
let mut ack = Vec::with_capacity(5);
ack.push(Self::CMD_ACK);
ack.extend(conv_id.to_le_bytes());
#[cfg(feature = "ack-cmd-conv-crc-mtu")]
{
ack.extend((self.kcp_use_crc as u32).to_le_bytes());
ack.extend(Self::MTU.to_le_bytes());
}
let _ = self.socket.send_to(&ack, addr).await;
tracing::debug!("new connection from {addr}, conv_id: {conv_id}");