Reviewed-on: WutheringSlaves/wicked-waifus-rs#19
This commit is contained in:
xavo95 2025-06-26 06:28:24 +00:00
parent 05034b1774
commit 1758cfd13e
73 changed files with 2454 additions and 1471 deletions

84
Cargo.lock generated
View file

@ -105,13 +105,13 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]] [[package]]
name = "axum" name = "axum"
version = "0.7.9" version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" checksum = "021e862c184ae977658b36c4500f7feac3221ca5da43e3f25bd04ab6c79a29b5"
dependencies = [ dependencies = [
"async-trait",
"axum-core", "axum-core",
"bytes", "bytes",
"form_urlencoded",
"futures-util", "futures-util",
"http", "http",
"http-body", "http-body",
@ -139,13 +139,12 @@ dependencies = [
[[package]] [[package]]
name = "axum-core" name = "axum-core"
version = "0.4.5" version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" checksum = "68464cd0412f486726fb3373129ef5d2993f90c34bc2bc1c1e9943b2f4fc7ca6"
dependencies = [ dependencies = [
"async-trait",
"bytes", "bytes",
"futures-util", "futures-core",
"http", "http",
"http-body", "http-body",
"http-body-util", "http-body-util",
@ -1238,9 +1237,9 @@ dependencies = [
[[package]] [[package]]
name = "matchit" name = "matchit"
version = "0.7.3" version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3"
[[package]] [[package]]
name = "md-5" name = "md-5"
@ -1546,9 +1545,9 @@ dependencies = [
[[package]] [[package]]
name = "prettyplease" name = "prettyplease"
version = "0.2.32" version = "0.2.35"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "664ec5419c51e34154eec046ebcba56312d5a2fc3b09a06da188e1ad21afadf6" checksum = "061c1221631e079b26479d25bbf2275bfe5917ae8419cd7e34f13bfc2aa7539a"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"syn", "syn",
@ -1565,9 +1564,9 @@ dependencies = [
[[package]] [[package]]
name = "prost" name = "prost"
version = "0.13.5" version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" checksum = "7231bd9b3d3d33c86b58adbac74b5ec0ad9f496b19d22801d773636feaa95f3d"
dependencies = [ dependencies = [
"bytes", "bytes",
"prost-derive", "prost-derive",
@ -1575,9 +1574,9 @@ dependencies = [
[[package]] [[package]]
name = "prost-build" name = "prost-build"
version = "0.13.5" version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf" checksum = "ac6c3320f9abac597dcbc668774ef006702672474aad53c6d596b62e487b40b1"
dependencies = [ dependencies = [
"heck", "heck",
"itertools", "itertools",
@ -1595,9 +1594,9 @@ dependencies = [
[[package]] [[package]]
name = "prost-derive" name = "prost-derive"
version = "0.13.5" version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" checksum = "9120690fafc389a67ba3803df527d0ec9cbbc9cc45e4cc20b332996dfb672425"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"itertools", "itertools",
@ -1608,9 +1607,9 @@ dependencies = [
[[package]] [[package]]
name = "prost-types" name = "prost-types"
version = "0.13.5" version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16" checksum = "b9b4db3d6da204ed77bb26ba83b6122a73aeb2e87e25fbf7ad2e84c4ccbf8f72"
dependencies = [ dependencies = [
"prost", "prost",
] ]
@ -1942,9 +1941,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_spanned" name = "serde_spanned"
version = "0.6.8" version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3"
dependencies = [ dependencies = [
"serde", "serde",
] ]
@ -2285,9 +2284,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.101" version = "2.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -2474,9 +2473,9 @@ dependencies = [
[[package]] [[package]]
name = "toml" name = "toml"
version = "0.8.22" version = "0.8.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
dependencies = [ dependencies = [
"serde", "serde",
"serde_spanned", "serde_spanned",
@ -2486,18 +2485,18 @@ dependencies = [
[[package]] [[package]]
name = "toml_datetime" name = "toml_datetime"
version = "0.6.9" version = "0.6.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
dependencies = [ dependencies = [
"serde", "serde",
] ]
[[package]] [[package]]
name = "toml_edit" name = "toml_edit"
version = "0.22.26" version = "0.22.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
dependencies = [ dependencies = [
"indexmap", "indexmap",
"serde", "serde",
@ -2509,9 +2508,9 @@ dependencies = [
[[package]] [[package]]
name = "toml_write" name = "toml_write"
version = "0.1.1" version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
[[package]] [[package]]
name = "tower" name = "tower"
@ -2531,12 +2530,13 @@ dependencies = [
[[package]] [[package]]
name = "tower-http" name = "tower-http"
version = "0.6.4" version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fdb0c213ca27a9f57ab69ddb290fd80d970922355b83ae380b395d3986b8a2e" checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"bytes", "bytes",
"futures-core",
"futures-util", "futures-util",
"http", "http",
"http-body", "http-body",
@ -2876,7 +2876,7 @@ name = "wicked-waifus-asset-updater"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"git2", "git2",
"thiserror 1.0.69", "thiserror 2.0.12",
"tracing", "tracing",
"ureq", "ureq",
"zip-extract", "zip-extract",
@ -2914,7 +2914,7 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"serde_repr", "serde_repr",
"thiserror 1.0.69", "thiserror 2.0.12",
"tracing", "tracing",
] ]
@ -2937,7 +2937,7 @@ dependencies = [
"paste", "paste",
"rand 0.9.1", "rand 0.9.1",
"serde", "serde",
"thiserror 1.0.69", "thiserror 2.0.12",
"tokio", "tokio",
"tracing", "tracing",
"unreal-niggery-rs", "unreal-niggery-rs",
@ -2962,7 +2962,7 @@ dependencies = [
"kcp", "kcp",
"paste", "paste",
"serde", "serde",
"thiserror 1.0.69", "thiserror 2.0.12",
"tokio", "tokio",
"tracing", "tracing",
"wicked-waifus-commons", "wicked-waifus-commons",
@ -2996,7 +2996,7 @@ dependencies = [
"cbc", "cbc",
"rbase64", "rbase64",
"serde", "serde",
"thiserror 1.0.69", "thiserror 2.0.12",
"tower-http", "tower-http",
"tracing", "tracing",
] ]
@ -3027,7 +3027,7 @@ dependencies = [
[[package]] [[package]]
name = "wicked-waifus-protocol" name = "wicked-waifus-protocol"
version = "0.1.0" version = "0.1.0"
source = "git+https://git.xeondev.com/wickedwaifus/wicked-waifus-proto#316e3ee06f5ee0405e4cab567e67f4315c0f2cfb" source = "git+https://github.com/xavo95/wicked-waifus-proto-dev.git?branch=2.5.1#17cd6d994259ef38c8c74ef9acf6306c24c582b8"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"crc32fast", "crc32fast",
@ -3045,7 +3045,7 @@ dependencies = [
[[package]] [[package]]
name = "wicked-waifus-protocol-derive" name = "wicked-waifus-protocol-derive"
version = "0.1.0" version = "0.1.0"
source = "git+https://git.xeondev.com/wickedwaifus/wicked-waifus-proto#316e3ee06f5ee0405e4cab567e67f4315c0f2cfb" source = "git+https://github.com/xavo95/wicked-waifus-proto-dev.git?branch=2.5.1#17cd6d994259ef38c8c74ef9acf6306c24c582b8"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -3062,7 +3062,7 @@ dependencies = [
"prost-build", "prost-build",
"serde", "serde",
"serde_json", "serde_json",
"thiserror 1.0.69", "thiserror 2.0.12",
"wicked-waifus-protocol", "wicked-waifus-protocol",
"wicked-waifus-protocol-derive", "wicked-waifus-protocol-derive",
] ]
@ -3077,7 +3077,7 @@ dependencies = [
"rbase64", "rbase64",
"rsa", "rsa",
"serde", "serde",
"thiserror 1.0.69", "thiserror 2.0.12",
"tracing", "tracing",
] ]

View file

@ -7,14 +7,14 @@ version = "0.1.0"
[workspace.dependencies] [workspace.dependencies]
# Framework # Framework
tokio = { version = "1.39.3", features = ["full"] } tokio = { version = "1.45.1", features = ["full"] }
tower-http = { version = "0.6.1", features = ["fs", "trace"] } tower-http = { version = "0.6.6", features = ["fs", "trace"] }
axum = "0.7.5" axum = "0.8.4"
axum-server = "0.7.1" axum-server = "0.7.2"
zeromq = { version = "0.4.0", default-features = false, features = ["tokio-runtime", "tcp-transport"] } zeromq = { version = "0.4.0", default-features = false, features = ["tokio-runtime", "tcp-transport"] }
# Database # Database
sqlx = { version = "0.8.2", features = ["postgres", "runtime-tokio-rustls"] } sqlx = { version = "0.8.6", features = ["postgres", "runtime-tokio-rustls"] }
# Cryptography # Cryptography
aes = "0.8.4" aes = "0.8.4"
@ -25,16 +25,16 @@ rand = "0.8.5"
rsa = { version = "0.9.6", features = ["pem"] } rsa = { version = "0.9.6", features = ["pem"] }
# Serialization # Serialization
serde = { version = "1.0.209", features = ["derive"] } serde = { version = "1.0.219", features = ["derive"] }
serde_json = "1.0.128" serde_json = "1.0.140"
serde_repr = "0.1.19" serde_repr = "0.1.20"
toml = "0.8.19" toml = "0.8.23"
prost = "0.13.2" prost = "0.14.1"
prost-build = "0.13.2" prost-build = "0.14.1"
# Utility # Utility
anyhow = "1.0.86" anyhow = "1.0.98"
thiserror = "1.0.63" thiserror = "2.0.12"
paste = "1.0.15" paste = "1.0.15"
rbase64 = "2.0.3" rbase64 = "2.0.3"
dashmap = "6.1.0" dashmap = "6.1.0"
@ -42,8 +42,8 @@ hex = "0.4.3"
byteorder = "1.5.0" byteorder = "1.5.0"
# Tracing # Tracing
tracing = "0.1.40" tracing = "0.1.41"
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } tracing-subscriber = { version = "0.3.19", features = ["env-filter"] }
# Internal # Internal
wicked-waifus-asset-updater = { path = "wicked-waifus-asset-updater" } wicked-waifus-asset-updater = { path = "wicked-waifus-asset-updater" }

View file

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

View file

@ -1,5 +1,88 @@
use serde::Deserialize; use serde::Deserialize;
use crate::StateMachineJson;
#[derive(Clone, Debug, Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct StateMachineTransition {
pub from: i32,
pub to: i32,
pub transition_prediction_type: i32,
pub weight: i32,
#[cfg(feature = "strict_json_fields")]
pub conditions: Vec<serde_json::Value>, // TODO: Implement conditions
}
#[derive(Clone, Debug, Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct StateMachineNodeCommon {
pub uuid: i32,
#[cfg(feature = "strict_json_fields")]
pub is_anim_state_machine: Option<bool>,
#[cfg(feature = "strict_json_fields")]
pub is_conduit_node: Option<bool>,
#[cfg(feature = "strict_json_fields")]
pub is_any_state: Option<bool>,
#[cfg(feature = "strict_json_fields")]
pub name: String,
#[cfg(feature = "strict_json_fields")]
pub take_control_type: i32,
#[cfg(feature = "strict_json_fields")]
pub transition_rule: i32,
pub children: Option<Vec<i32>>,
pub transitions: Option<Vec<StateMachineTransition>>,
#[cfg(feature = "strict_json_fields")]
pub on_enter_actions: Option<Vec<serde_json::Value>>, // TODO: Implement actions
#[cfg(feature = "strict_json_fields")]
pub on_exit_actions: Option<Vec<serde_json::Value>>, // TODO: Implement actions
#[cfg(feature = "strict_json_fields")]
pub bind_states: Option<Vec<serde_json::Value>>, // TODO: Implement bindStates
#[cfg(feature = "strict_json_fields")]
pub task: Option<serde_json::Value>, // TODO: Implement bindStates
}
#[derive(Clone, Debug, Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct StateMachineNodeReferenced {
pub reference_uuid: i32,
#[serde(flatten)]
pub common: StateMachineNodeCommon,
}
#[derive(Clone, Debug, Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct StateMachineNodeOverrideCommon {
pub override_common_uuid: i32,
#[serde(flatten)]
pub common: StateMachineNodeCommon,
}
#[derive(Clone, Debug, Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct StateMachineNodeCustom {
#[serde(flatten)]
pub common: StateMachineNodeCommon,
}
#[derive(Clone, Debug, Deserialize)]
#[serde(untagged)]
pub enum StateMachineNode {
Reference(StateMachineNodeReferenced),
Override(StateMachineNodeOverrideCommon),
Custom(StateMachineNodeCustom),
}
#[derive(Clone, Debug, Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct StateMachineJson {
pub version: u32,
pub state_machines: Vec<i32>,
pub nodes: Vec<StateMachineNode>,
}
#[derive(Clone, Debug, Deserialize)] #[derive(Clone, Debug, Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] #[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]

View file

@ -1,6 +1,206 @@
use serde::Deserialize; use serde::Deserialize;
use crate::{EntityLogic, EntityType}; #[derive(Deserialize, PartialEq, Debug, Copy, Clone)]
pub enum EntityType {
AdsorptionFoundation,
AdviseItem,
AiAlertNotifier,
AiGearController,
AiMovementGear,
AirPassage,
AiSceneItem,
Animal,
Animal2,
AnnunciatorCenter,
AnnunciatorWire,
AreaOccupation,
Audio,
AudioBox,
BatchBulletCaster,
BeamCastBullet,
BeamCaster,
BeamCrystal,
BeamDeliver,
BeamReceiver,
BondageTrap,
BuffConsumer,
BuffProducer,
BurstCrystalFoundation,
Chair,
Chair2,
ChallengeInteract,
Chessboard,
Chessman,
ClientTrigger,
Collect,
Collect2,
Collect3,
CollectAnimal,
CollectAnimalPart,
CombatAnimal,
CombatAnimal2,
CombinedVisibleGroup,
ControlConnector,
ConveyorBelt,
CookTool,
CurveControlDestructible,
CustomAoiEditor,
Destructible,
DestructibleControl,
DestructibleExploreInteractor,
DestructibleSceneBullet,
DestructibleTrigger,
Disc,
Drop,
DungeonEntry,
DynamicPortalCreater,
EffectArea,
EnrichmentArea,
EntityBatchRefresh,
EntityBundle,
EntityList,
EntityPackage,
ExploreSkillInteractor,
FishingBoat,
FollowShooter,
FollowShooter2,
FollowTrack,
FollowTrackFoundation,
Gramophone,
GravityFlip,
GroupAi,
HackingTypeFollowShooter,
HitConditionListener,
HookLockPoint,
HookSoundBox,
HookWithRange,
HorseBettingTuanzi,
InhaledItem,
InteractFoundation,
InteractFoundationWithSceneItemAttribute,
InteractGear,
InteractGearGroup,
InteractiveConditionListener,
Item,
ItemFoundation,
JigsawFoundation,
JigsawItem,
KiteHook,
LevelPlay,
LevelPlayReward,
LevelQteTrigger,
LevelSeqTrigger,
LevitateMagnet,
LifePointCenter,
Lift,
Lift2,
LightDeliver,
LocationSafety,
Monitor,
Monster,
MonsterGachaBase,
MonsterGachaItem,
MoveableTrigger,
MusicStand,
NoRenderPortal,
Npc,
Npc2,
PasserbyNpc,
PerformanceOptimizer,
PhotoTarget,
PhysicsSwing,
Portal,
Position,
ProgressBarController,
ProgressBarControllerWithAttribute,
PullingObject,
Range,
RangeTriggerTargetGear,
ReboundPlateGear,
RefreshGroup,
RenderSpecifiedRange,
RenderSpecifiedRange2,
Resurrection,
RewardNpc,
RollingFireball,
Rotator,
SceneAura,
SceneBullet,
SceneBulletCanHit,
SceneBulletTrigger,
SceneBulletWithMovement,
SceneItemStateHint,
SimpleInteract,
SimpleNPc,
SkyboxTrigger,
SlideRail,
Slots,
SoundBox,
SpawnMonster,
SpawnPasserbyNpc,
Spline,
SplineRange,
SummonGongduolaPoint,
StateSceneItem,
StateTrigger,
StatueFoundation,
SuiGuangHook,
TargetGear,
TargetGear2,
TargetGearGroup,
TargetGearGroup2,
TargetGearPro,
TargetGearWithLevelPrefabPerform,
TeleControl,
TeleControl3,
TeleControl4,
TeleControlGroup,
Teleporter,
TemplateEntitySpawner,
TemporaryTeleporter,
TimedStrikeDevice,
TimelineTrackController,
TimeScaledHook,
TimeStop,
Trample,
Trample2,
Trample3,
TrampleWithSceneItemAttribute,
TreasureBox,
Trigger,
TriggerConditionListener,
TuanziNpc,
TuningStand,
TurntableController,
VacuumCleaner,
VarManager,
Vehicle,
Vehicle2,
VehicleNpc,
VehicleSceneItem,
VisibleTrigger,
Vision,
VisionItem,
VisionTreasureBox,
WalkingPatternController,
WaterCollection,
WaterSpout,
Weapon,
WindSource,
}
#[derive(Deserialize, PartialEq, Debug, Copy, Clone)]
pub enum EntityLogic {
Item,
Animal,
Monster,
Vehicle,
Npc,
Vision,
ClientOnly,
ServerOnly,
Custom,
}
#[derive(Deserialize)] #[derive(Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] #[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
@ -10,10 +210,7 @@ pub struct BlueprintConfigData {
pub blueprint_type: String, pub blueprint_type: String,
pub entity_type: EntityType, pub entity_type: EntityType,
pub entity_logic: EntityLogic, pub entity_logic: EntityLogic,
#[cfg(feature = "strict_json_fields")]
pub model_id: i32, pub model_id: i32,
#[cfg(feature = "strict_json_fields")]
pub half_height: i32, pub half_height: i32,
#[cfg(feature = "strict_json_fields")]
pub track_height: i32, pub track_height: i32,
} }

View file

@ -0,0 +1,109 @@
use serde::Deserialize;
#[derive(Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct BuffData {
pub id: i64,
pub ge_desc: String,
pub duration_policy: i32, // TODO: Enum ??
#[cfg(feature = "strict_json_fields")]
pub duration_calculation_policy: Vec<i32>,
#[cfg(feature = "strict_json_fields")]
pub duration_magnitude: Vec<i32>,
#[cfg(feature = "strict_json_fields")]
pub duration_magnitude2: Vec<i32>,
#[cfg(feature = "strict_json_fields")]
pub b_duration_affected_by_bullet_time: bool,
#[cfg(feature = "strict_json_fields")]
pub formation_policy: i32, // TODO: Enum ??
#[cfg(feature = "strict_json_fields")]
pub probability: i32,
#[cfg(feature = "strict_json_fields")]
pub period: i32,
#[cfg(feature = "strict_json_fields")]
pub b_execute_periodic_effect_on_application: bool,
#[cfg(feature = "strict_json_fields")]
pub periodic_inhibition_policy: i32, // TODO: Enum ??
#[serde(rename = "GameAttributeID")]
pub game_attribute_id: i32,
#[cfg(feature = "strict_json_fields")]
pub calculation_policy: Vec<i32>,
#[cfg(feature = "strict_json_fields")]
pub modifier_magnitude: Vec<i32>,
#[cfg(feature = "strict_json_fields")]
pub modifier_magnitude2: Vec<i32>,
#[cfg(feature = "strict_json_fields")]
pub stacking_type: i32, // TODO: Enum??
#[cfg(feature = "strict_json_fields")]
pub default_stack_count: i32,
#[cfg(feature = "strict_json_fields")]
pub stack_append_count: i32,
#[cfg(feature = "strict_json_fields")]
pub stack_limit_count: i32,
#[cfg(feature = "strict_json_fields")]
pub stack_duration_refresh_policy: i32,
#[cfg(feature = "strict_json_fields")]
pub stack_period_reset_policy: i32,
#[cfg(feature = "strict_json_fields")]
pub stack_expiration_remove_number: i32,
#[cfg(feature = "strict_json_fields")]
pub b_deny_overflow_application: bool,
#[cfg(feature = "strict_json_fields")]
pub b_clear_stack_on_overflow: bool,
#[cfg(feature = "strict_json_fields")]
pub b_require_modifier_success_to_trigger_cues: bool,
#[cfg(feature = "strict_json_fields")]
pub b_suppress_stacking_cues: bool,
pub gameplay_cue_ids: Vec<i64>,
#[cfg(feature = "strict_json_fields")]
pub granted_tags: Vec<String>,
#[cfg(feature = "strict_json_fields")]
pub application_source_tag_requirements: Vec<String>,
#[cfg(feature = "strict_json_fields")]
pub application_source_tag_ignores: Vec<String>,
#[cfg(feature = "strict_json_fields")]
pub application_tag_requirements: Vec<String>,
#[cfg(feature = "strict_json_fields")]
pub application_tag_ignores: Vec<String>,
pub ongoing_tag_requirements: Vec<String>,
pub ongoing_tag_ignores: Vec<String>,
pub removal_tag_requirements: Vec<String>,
pub removal_tag_ignores: Vec<String>,
#[cfg(feature = "strict_json_fields")]
pub remove_buff_with_tags: Vec<String>,
#[cfg(feature = "strict_json_fields")]
pub granted_application_immunity_tags: Vec<String>,
#[cfg(feature = "strict_json_fields")]
pub granted_application_immunity_tag_ignores: Vec<String>,
#[cfg(feature = "strict_json_fields")]
pub premature_expiration_effects: Vec<String>,
#[cfg(feature = "strict_json_fields")]
pub routine_expiration_effects: Vec<String>,
#[cfg(feature = "strict_json_fields")]
pub overflow_effects: Vec<String>,
#[cfg(feature = "strict_json_fields")]
pub related_extra_effect_buff_id: Vec<String>,
#[serde(rename = "ExtraEffectID")]
pub extra_effect_id: i32,
pub extra_effect_parameters: Vec<String>,
pub extra_effect_parameters_grow1: Vec<i32>,
pub extra_effect_parameters_grow2: Vec<i32>,
#[cfg(feature = "strict_json_fields")]
pub extra_effect_requirements: Vec<String>,
#[cfg(feature = "strict_json_fields")]
pub extra_effect_req_para: Vec<String>,
#[cfg(feature = "strict_json_fields")]
pub extra_effect_req_setting: i32, // TODO: Enum??
#[cfg(feature = "strict_json_fields")]
pub extra_effect_cd: Vec<i32>,
#[cfg(feature = "strict_json_fields")]
pub extra_effect_remove_stack_num: i32,
#[cfg(feature = "strict_json_fields")]
pub extra_effect_probability: Vec<i32>,
#[cfg(feature = "strict_json_fields")]
pub buff_action: Vec<String>,
#[cfg(feature = "strict_json_fields")]
pub tag_logic: Vec<String>,
pub dead_remove: bool,
}

View file

@ -1,5 +1,20 @@
use serde::Deserialize; use serde::Deserialize;
use crate::GachaViewTypeInfoId; use serde_repr::Deserialize_repr;
#[derive(Deserialize_repr, PartialEq, Debug, Copy, Clone)]
#[repr(i32)]
pub enum GachaViewTypeInfoId {
NoviceConvene = 1,
FeaturedResonatorConvene = 2,
FeaturedWeaponConvene = 3,
StandardResonatorConvene = 4,
StandardWeaponConvene = 5,
BeginnersChoiceConvene = 6,
AnniversaryResonatorConvene = 7,
AnniversaryWeaponConvene = 8,
NewVoyageResonatorConvene = 9,
NewVoyageWeaponConvene = 10,
}
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] #[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]

View file

@ -2,7 +2,14 @@ use std::collections::HashMap;
use serde::Deserialize; use serde::Deserialize;
use crate::{EntranceEntityData, VectorData}; use crate::VectorData;
#[derive(Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct EntranceEntityData {
pub dungeon_id: i32,
pub entrance_entity_id: i64,
}
#[derive(Deserialize)] #[derive(Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] #[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]

View file

@ -1,5 +1,154 @@
use serde::Deserialize; use serde::Deserialize;
use crate::LevelPlayDataDetail;
#[derive(Debug, Deserialize)]
pub enum LevelPlayType {
Challenge,
SilentArea,
Dungeon,
MonsterTreasure,
Quest,
Riddle,
}
#[derive(Debug, Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase", deny_unknown_fields)]
pub struct LevelPlayOpenCondition {
pub conditions: Option<Vec<Condition>>,
}
#[derive(Debug, Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase", deny_unknown_fields)]
pub struct LevelPlayActive {
pub active_type: i32,
}
#[derive(Debug, Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase", deny_unknown_fields)]
pub struct LevelPlayRewardConfigResetTypeMidNight {
pub count: i32,
}
#[derive(Debug, Deserialize)]
#[serde(tag = "Type")]
pub enum LevelPlayRewardConfigResetType {
MidNight(LevelPlayRewardConfigResetTypeMidNight),
}
#[derive(Debug, Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase", deny_unknown_fields)]
pub struct LevelPlayRewardConfigInteract {
pub reward_id: i32,
pub reward_entity_id: i64,
pub reward_complete_actions: Vec<Action>,
pub first_complete_actions: Option<Vec<Action>>,
pub reset: Option<LevelPlayRewardConfigResetType>,
}
#[derive(Debug, Deserialize)]
#[serde(tag = "Type")]
pub enum LevelPlayRewardConfig {
None,
Interact(LevelPlayRewardConfigInteract),
}
#[derive(Debug, Deserialize)]
pub enum FixedDateTime {
Daily,
Weekly
}
#[derive(Debug, Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase", deny_unknown_fields)]
pub struct LevelPlayRefreshConfigFixedDateTime {
pub update_type: FixedDateTime,
}
#[derive(Debug, Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase", deny_unknown_fields)]
pub struct LevelPlayRefreshConfigCompleted {
pub min_refresh_cd: i32,
pub max_refresh_cd: i32,
}
#[derive(Debug, Deserialize)]
#[serde(tag = "Type")]
pub enum LevelPlayRefreshConfig {
None,
FixedDateTime(LevelPlayRefreshConfigFixedDateTime),
Completed(LevelPlayRefreshConfigCompleted),
}
#[derive(Debug, Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase", deny_unknown_fields)]
pub struct LevelPlayTrack {
pub track_radius: i32,
pub track_priority: i32,
}
#[derive(Debug, Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase", deny_unknown_fields)]
pub struct LevelPlayMark {
pub mark_id: i32,
pub map_bg_path: String,
}
#[derive(Debug, Deserialize)]
pub enum OnlineType {
Multiplayer,
Local,
Hang,
}
#[derive(Debug, Deserialize)]
pub enum ObjType {
LevelPlay,
}
#[derive(Debug, Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase", deny_unknown_fields)]
pub struct LevelPlayDataDetail { // Json file contains Data in name, so it has to be DataData
pub id: i32,
pub key: String,
#[cfg(feature = "strict_json_fields")]
pub internal_dest: String,
pub level_id: i32,
#[cfg(feature = "strict_json_fields")]
pub tid_name: String,
pub r#type: LevelPlayType,
pub instance_id: i32,
pub level_play_entity_id: i64,
pub level_additive_id: i32,
pub enter_radius: i32,
pub leave_radius: i32,
pub delay_refresh: bool,
pub delay_destroy: bool,
pub level_play_open_condition: LevelPlayOpenCondition,
pub level_play_active: LevelPlayActive,
pub level_play_reward_config: LevelPlayRewardConfig,
pub level_play_refresh_config: LevelPlayRefreshConfig,
pub level_play_track: LevelPlayTrack,
pub level_play_mark: Option<LevelPlayMark>,
pub enter_in_range_actions: Option<Vec<Action>>,
pub pack_id: i32,
pub online_type: OnlineType,
pub obj_type: ObjType,
#[cfg(feature = "strict_json_fields")]
pub children: Option<Vec<String>>,
#[cfg(feature = "strict_json_fields")]
pub reference: Vec<String>,
#[cfg(feature = "strict_json_fields")]
pub weak_reference: Option<Vec<String>>,
pub exploratory_degree: Option<i32>,
}
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] #[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]

View file

@ -3,7 +3,6 @@ use std::io::BufReader;
use paste::paste; use paste::paste;
pub use level_entity_config::LevelEntityConfigData;
pub use misc_data::*; pub use misc_data::*;
pub mod node_data; pub mod node_data;
@ -11,6 +10,7 @@ pub mod pb_components;
pub mod text_map_data; pub mod text_map_data;
mod misc_data; mod misc_data;
mod level_entity_config;
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug)]
pub enum LoadDataError { pub enum LoadDataError {
@ -24,13 +24,14 @@ macro_rules! json_data {
($($table_type:ident;)*) => { ($($table_type:ident;)*) => {
$(paste! { $(paste! {
mod [<$table_type:snake>]; mod [<$table_type:snake>];
pub use [<$table_type:snake>]::[<$table_type Data>];
})* })*
$(paste! { $(paste! {
pub mod [<$table_type:snake _data>] { pub mod [<$table_type:snake _data>] {
pub use super::[<$table_type:snake>]::*;
use std::sync::OnceLock; use std::sync::OnceLock;
type Data = super::[<$table_type Data>]; type Data = super::[<$table_type:snake>]::[<$table_type Data>];
pub(crate) static TABLE: OnceLock<Vec<Data>> = OnceLock::new(); pub(crate) static TABLE: OnceLock<Vec<Data>> = OnceLock::new();
pub fn iter() -> std::slice::Iter<'static, Data> { pub fn iter() -> std::slice::Iter<'static, Data> {
@ -58,15 +59,16 @@ macro_rules! json_hash_table_data {
($($table_type:ident, $key_param:expr, $key_type:ty;)*) => { ($($table_type:ident, $key_param:expr, $key_type:ty;)*) => {
$(paste! { $(paste! {
mod [<$table_type:snake>]; mod [<$table_type:snake>];
pub use [<$table_type:snake>]::[<$table_type Data>];
})* })*
$(paste! { $(paste! {
pub mod [<$table_type:snake _data>] { pub mod [<$table_type:snake _data>] {
pub use super::[<$table_type:snake>]::*;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::OnceLock; use std::sync::OnceLock;
pub(crate) type Data = super::[<$table_type Data>]; pub(crate) type Data = super::[<$table_type:snake>]::[<$table_type Data>];
pub(crate) static TABLE: OnceLock<HashMap<$key_type, Data>> = OnceLock::new(); pub(crate) static TABLE: OnceLock<HashMap<$key_type, Data>> = OnceLock::new();
pub fn iter() -> std::collections::hash_map::Iter<'static, $key_type, Data> { pub fn iter() -> std::collections::hash_map::Iter<'static, $key_type, Data> {
@ -139,9 +141,12 @@ json_data! {
LevelPlayNodeData; LevelPlayNodeData;
LivenessTask; LivenessTask;
LordGym; LordGym;
ModelConfigPreload;
MonsterDetection; MonsterDetection;
MonsterPropertyGrowth; MonsterPropertyGrowth;
Motion; Motion;
PhantomCustomizeItem;
PhantomItem;
QuestNodeData; QuestNodeData;
ResonanceAmplification; ResonanceAmplification;
ResonantChain; ResonantChain;
@ -166,19 +171,21 @@ json_hash_table_data! {
AiBase, id, i32; AiBase, id, i32;
AiStateMachineConfig, id, String; AiStateMachineConfig, id, String;
BlueprintConfig, blueprint_type, String; BlueprintConfig, blueprint_type, String;
Buff, id, i64;
DragonPool, id, i32; DragonPool, id, i32;
DropPackage, id, i32; DropPackage, id, i32;
RoleExpItem, id, i32; RoleExpItem, id, i32;
SummonCfg, blueprint_type, String;
TemplateConfig, blueprint_type, String; TemplateConfig, blueprint_type, String;
} }
mod level_entity_config;
pub mod level_entity_config_data { pub mod level_entity_config_data {
pub use super::level_entity_config::*;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::OnceLock; use std::sync::OnceLock;
pub(crate) type Data = super::LevelEntityConfigData; pub(crate) type Data = LevelEntityConfigData;
pub(crate) static TABLE: OnceLock<HashMap<String, Data>> = OnceLock::new(); pub(crate) static TABLE: OnceLock<HashMap<String, Data>> = OnceLock::new();
pub fn iter() -> std::collections::hash_map::Iter<'static, String, Data> { pub fn iter() -> std::collections::hash_map::Iter<'static, String, Data> {

View file

@ -1,8 +1,4 @@
use serde::Deserialize; use serde::Deserialize;
use serde_repr::Deserialize_repr;
use crate::pb_components::action::Action;
use crate::pb_components::condition::Condition;
#[derive(Deserialize)] #[derive(Deserialize)]
#[serde(rename_all = "PascalCase")] #[serde(rename_all = "PascalCase")]
@ -52,455 +48,9 @@ impl RawVectorData {
} }
} }
#[derive(Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct EntranceEntityData {
pub dungeon_id: i32,
pub entrance_entity_id: i64,
}
#[derive(Deserialize_repr, PartialEq, Debug, Copy, Clone)]
#[repr(i32)]
pub enum GachaViewTypeInfoId {
NoviceConvene = 1,
FeaturedResonatorConvene = 2,
FeaturedWeaponConvene = 3,
StandardResonatorConvene = 4,
StandardWeaponConvene = 5,
BeginnersChoiceConvene = 6,
MultipleChoiceResonatorConvene = 7,
MultipleChoiceWeaponConvene = 8,
}
#[derive(Debug, Deserialize, Clone)] #[derive(Debug, Deserialize, Clone)]
#[serde(rename_all = "PascalCase")] #[serde(rename_all = "PascalCase")]
pub struct ConsumeItem { pub struct ConsumeItem {
pub item_id: i32, pub item_id: i32,
pub count: i32, pub count: i32,
}
#[derive(Deserialize, PartialEq, Debug, Copy, Clone)]
pub enum EntityType {
AdsorptionFoundation,
AdviseItem,
AiAlertNotifier,
AiGearController,
AiMovementGear,
AirPassage,
AiSceneItem,
Animal,
Animal2,
AnnunciatorCenter,
AnnunciatorWire,
AreaOccupation,
Audio,
AudioBox,
BatchBulletCaster,
BeamCastBullet,
BeamCaster,
BeamCrystal,
BeamDeliver,
BeamReceiver,
BondageTrap,
BuffConsumer,
BuffProducer,
BurstCrystalFoundation,
Chair,
Chair2,
ChallengeInteract,
Chessboard,
Chessman,
ClientTrigger,
Collect,
Collect2,
Collect3,
CollectAnimal,
CollectAnimalPart,
CombatAnimal,
CombatAnimal2,
CombinedVisibleGroup,
ControlConnector,
ConveyorBelt,
CookTool,
CurveControlDestructible,
CustomAoiEditor,
Destructible,
DestructibleControl,
DestructibleExploreInteractor,
DestructibleSceneBullet,
DestructibleTrigger,
Disc,
Drop,
DungeonEntry,
DynamicPortalCreater,
EffectArea,
EnrichmentArea,
EntityBatchRefresh,
EntityBundle,
EntityList,
EntityPackage,
ExploreSkillInteractor,
FishingBoat,
FollowShooter,
FollowShooter2,
FollowTrack,
FollowTrackFoundation,
Gramophone,
GravityFlip,
GroupAi,
HackingTypeFollowShooter,
HookLockPoint,
HookSoundBox,
HookWithRange,
HorseBettingTuanzi,
InhaledItem,
InteractFoundation,
InteractFoundationWithSceneItemAttribute,
InteractGear,
InteractGearGroup,
InteractiveConditionListener,
Item,
ItemFoundation,
JigsawFoundation,
JigsawItem,
KiteHook,
LevelPlay,
LevelPlayReward,
LevelQteTrigger,
LevelSeqTrigger,
LevitateMagnet,
LifePointCenter,
Lift,
LightDeliver,
LocationSafety,
Monitor,
Monster,
MonsterGachaBase,
MonsterGachaItem,
MoveableTrigger,
NoRenderPortal,
Npc,
Npc2,
PasserbyNpc,
PhotoTarget,
PhysicsSwing,
Portal,
Position,
ProgressBarController,
ProgressBarControllerWithAttribute,
PullingObject,
Range,
RangeTriggerTargetGear,
ReboundPlateGear,
RefreshGroup,
RenderSpecifiedRange,
RenderSpecifiedRange2,
Resurrection,
RewardNpc,
RollingFireball,
Rotator,
SceneAura,
SceneBullet,
SceneBulletCanHit,
SceneBulletWithMovement,
SceneItemStateHint,
SimpleInteract,
SimpleNPc,
SkyboxTrigger,
SlideRail,
SoundBox,
SpawnMonster,
SpawnPasserbyNpc,
Spline,
SplineRange,
SummonGongduolaPoint,
StateSceneItem,
StateTrigger,
StatueFoundation,
SuiGuangHook,
TargetGear,
TargetGear2,
TargetGearGroup,
TargetGearGroup2,
TargetGearPro,
TargetGearWithLevelPrefabPerform,
TeleControl,
TeleControl3,
TeleControlGroup,
Teleporter,
TemplateEntitySpawner,
TemporaryTeleporter,
TimedStrikeDevice,
TimelineTrackController,
TimeStop,
Trample,
Trample2,
Trample3,
TreasureBox,
Trigger,
TriggerConditionListener,
TuanziNpc,
TurntableController,
VacuumCleaner,
VarManager,
Vehicle,
Vehicle2,
VehicleNpc,
VehicleSceneItem,
VisibleTrigger,
Vision,
VisionItem,
VisionTreasureBox,
WalkingPatternController,
WaterCollection,
WaterSpout,
Weapon,
WindSource,
}
#[derive(Deserialize, PartialEq, Debug, Copy, Clone)]
pub enum EntityLogic {
Item,
Animal,
Monster,
Vehicle,
Npc,
Vision,
ClientOnly,
ServerOnly,
Custom,
}
#[derive(Debug, Deserialize)]
pub enum LevelPlayType {
Challenge,
SilentArea,
Dungeon,
MonsterTreasure,
Quest,
Riddle,
}
#[derive(Debug, Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase", deny_unknown_fields)]
pub struct LevelPlayOpenCondition {
pub conditions: Option<Vec<Condition>>,
}
#[derive(Debug, Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase", deny_unknown_fields)]
pub struct LevelPlayActive {
pub active_type: i32,
}
#[derive(Debug, Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase", deny_unknown_fields)]
pub struct LevelPlayRewardConfigResetTypeMidNight {
pub count: i32,
}
#[derive(Debug, Deserialize)]
#[serde(tag = "Type")]
pub enum LevelPlayRewardConfigResetType {
MidNight(LevelPlayRewardConfigResetTypeMidNight),
}
#[derive(Debug, Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase", deny_unknown_fields)]
pub struct LevelPlayRewardConfigInteract {
pub reward_id: i32,
pub reward_entity_id: i64,
pub reward_complete_actions: Vec<Action>,
pub first_complete_actions: Option<Vec<Action>>,
pub reset: Option<LevelPlayRewardConfigResetType>,
}
#[derive(Debug, Deserialize)]
#[serde(tag = "Type")]
pub enum LevelPlayRewardConfig {
None,
Interact(LevelPlayRewardConfigInteract),
}
#[derive(Debug, Deserialize)]
pub enum FixedDateTime {
Daily,
Weekly
}
#[derive(Debug, Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase", deny_unknown_fields)]
pub struct LevelPlayRefreshConfigFixedDateTime {
pub update_type: FixedDateTime,
}
#[derive(Debug, Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase", deny_unknown_fields)]
pub struct LevelPlayRefreshConfigCompleted {
pub min_refresh_cd: i32,
pub max_refresh_cd: i32,
}
#[derive(Debug, Deserialize)]
#[serde(tag = "Type")]
pub enum LevelPlayRefreshConfig {
None,
FixedDateTime(LevelPlayRefreshConfigFixedDateTime),
Completed(LevelPlayRefreshConfigCompleted),
}
#[derive(Debug, Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase", deny_unknown_fields)]
pub struct LevelPlayTrack {
pub track_radius: i32,
pub track_priority: i32,
}
#[derive(Debug, Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase", deny_unknown_fields)]
pub struct LevelPlayMark {
pub mark_id: i32,
pub map_bg_path: String,
}
#[derive(Debug, Deserialize)]
pub enum OnlineType {
Multiplayer,
Local,
Hang,
}
#[derive(Debug, Deserialize)]
pub enum ObjType {
LevelPlay,
}
#[derive(Debug, Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase", deny_unknown_fields)]
pub struct LevelPlayDataDetail { // Json file contains Data in name, so it has to be DataData
pub id: i32,
pub key: String,
#[cfg(feature = "strict_json_fields")]
pub internal_dest: String,
pub level_id: i32,
#[cfg(feature = "strict_json_fields")]
pub tid_name: String,
pub r#type: LevelPlayType,
pub instance_id: i32,
pub level_play_entity_id: i64,
pub level_additive_id: i32,
pub enter_radius: i32,
pub leave_radius: i32,
pub delay_refresh: bool,
pub delay_destroy: bool,
pub level_play_open_condition: LevelPlayOpenCondition,
pub level_play_active: LevelPlayActive,
pub level_play_reward_config: LevelPlayRewardConfig,
pub level_play_refresh_config: LevelPlayRefreshConfig,
pub level_play_track: LevelPlayTrack,
pub level_play_mark: Option<LevelPlayMark>,
pub enter_in_range_actions: Option<Vec<Action>>,
pub pack_id: i32,
pub online_type: OnlineType,
pub obj_type: ObjType,
#[cfg(feature = "strict_json_fields")]
pub children: Option<Vec<String>>,
#[cfg(feature = "strict_json_fields")]
pub reference: Vec<String>,
#[cfg(feature = "strict_json_fields")]
pub weak_reference: Option<Vec<String>>,
pub exploratory_degree: Option<i32>,
}
#[derive(Clone, Debug, Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct StateMachineTransition {
pub from: i32,
pub to: i32,
pub transition_prediction_type: i32,
pub weight: i32,
#[cfg(feature = "strict_json_fields")]
pub conditions: Vec<serde_json::Value>, // TODO: Implement conditions
}
#[derive(Clone, Debug, Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct StateMachineNodeCommon {
pub uuid: i32,
#[cfg(feature = "strict_json_fields")]
pub is_anim_state_machine: Option<bool>,
#[cfg(feature = "strict_json_fields")]
pub is_conduit_node: Option<bool>,
#[cfg(feature = "strict_json_fields")]
pub is_any_state: Option<bool>,
#[cfg(feature = "strict_json_fields")]
pub name: String,
#[cfg(feature = "strict_json_fields")]
pub take_control_type: i32,
#[cfg(feature = "strict_json_fields")]
pub transition_rule: i32,
pub children: Option<Vec<i32>>,
pub transitions: Option<Vec<StateMachineTransition>>,
#[cfg(feature = "strict_json_fields")]
pub on_enter_actions: Option<Vec<serde_json::Value>>, // TODO: Implement actions
#[cfg(feature = "strict_json_fields")]
pub on_exit_actions: Option<Vec<serde_json::Value>>, // TODO: Implement actions
#[cfg(feature = "strict_json_fields")]
pub bind_states: Option<Vec<serde_json::Value>>, // TODO: Implement bindStates
#[cfg(feature = "strict_json_fields")]
pub task: Option<serde_json::Value>, // TODO: Implement bindStates
}
#[derive(Clone, Debug, Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct StateMachineNodeReferenced {
pub reference_uuid: i32,
#[serde(flatten)]
pub common: StateMachineNodeCommon,
}
#[derive(Clone, Debug, Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct StateMachineNodeOverrideCommon {
pub override_common_uuid: i32,
#[serde(flatten)]
pub common: StateMachineNodeCommon,
}
#[derive(Clone, Debug, Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct StateMachineNodeCustom {
#[serde(flatten)]
pub common: StateMachineNodeCommon,
}
#[derive(Clone, Debug, Deserialize)]
#[serde(untagged)]
pub enum StateMachineNode {
Reference(StateMachineNodeReferenced),
Override(StateMachineNodeOverrideCommon),
Custom(StateMachineNodeCustom),
}
#[derive(Clone, Debug, Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct StateMachineJson {
pub version: u32,
pub state_machines: Vec<i32>,
pub nodes: Vec<StateMachineNode>,
} }

View file

@ -0,0 +1,25 @@
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

@ -1097,6 +1097,7 @@ pub enum VehicleType {
FishingBoat, FishingBoat,
Gongduola, Gongduola,
Appointed(AppointedVehicleType), Appointed(AppointedVehicleType),
Current,
} }
#[derive(Deserialize, Debug, Clone)] #[derive(Deserialize, Debug, Clone)]
@ -1215,6 +1216,7 @@ pub enum SystemType {
ConfirmBox(SystemTypeConfirmBox), ConfirmBox(SystemTypeConfirmBox),
FishingItemDelivery(SystemTypeFishingItemDelivery), FishingItemDelivery(SystemTypeFishingItemDelivery),
SoaringChallenge(SystemTypeSoaringChallenge), SoaringChallenge(SystemTypeSoaringChallenge),
ConfirmBox2, // TODO:
} }
#[derive(Deserialize, Debug, Clone)] #[derive(Deserialize, Debug, Clone)]
@ -1439,6 +1441,7 @@ pub enum GameplayConfig {
FishingRoulette, FishingRoulette,
DaolingAuthentication, DaolingAuthentication,
SundialPuzzle, SundialPuzzle,
TuningStand,
} }
#[derive(Deserialize, Debug, Clone)] #[derive(Deserialize, Debug, Clone)]
@ -1760,6 +1763,35 @@ pub struct RemoveTrialCharacter {
pub character_group: Vec<i64>, pub character_group: Vec<i64>,
} }
#[derive(Deserialize, Debug, Clone)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct CharacterGroup {
pub character_id: i64,
pub is_ai_character: bool,
}
#[derive(Deserialize, Debug, Clone)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct UpdateTrialCharacter {
pub character_group_new: Option<Vec<CharacterGroup>>,
pub auto_change: Option<bool>,
pub is_remove_tips: Option<bool>,
pub enable_map_and_teleport: Option<bool>,
pub dungeon_list: Option<Vec<i32>>,
pub enter_range_entities: Option<Vec<i64>>,
pub create_temp_team: Option<bool>,
// TODO: IsDisableRollBackRestoreCharacter ActiveRange
}
#[derive(Deserialize, Debug, Clone)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct RestoreTrialCharacter {
// TODO
}
#[derive(Deserialize, Debug, Clone)] #[derive(Deserialize, Debug, Clone)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] #[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")] #[serde(rename_all = "PascalCase")]
@ -2351,6 +2383,30 @@ pub struct RequestSystemFunction {
pub config: serde_json::Value, 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 SetTimeScale {
#[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 EndCommonTip {
#[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 SetupMoraleSystem {
#[cfg(feature = "strict_json_fields")]
pub config: serde_json::Value,
}
#[derive(Deserialize, Debug, Clone)] #[derive(Deserialize, Debug, Clone)]
#[serde(tag = "Name")] #[serde(tag = "Name")]
pub enum Action { pub enum Action {
@ -2465,6 +2521,8 @@ pub enum Action {
RemoveTrialFollowShooter(ActionFields<RemoveTrialFollowShooter>), RemoveTrialFollowShooter(ActionFields<RemoveTrialFollowShooter>),
AddTrialCharacter(ActionFields<AddTrialCharacter>), AddTrialCharacter(ActionFields<AddTrialCharacter>),
RemoveTrialCharacter(ActionFields<RemoveTrialCharacter>), RemoveTrialCharacter(ActionFields<RemoveTrialCharacter>),
UpdateTrialCharacter(ActionFields<UpdateTrialCharacter>),
RestoreTrialCharacter(ActionFields<RestoreTrialCharacter>),
SetAreaState(ActionFields<SetAreaState>), SetAreaState(ActionFields<SetAreaState>),
SwitchSubLevels(ActionFields<SwitchSubLevels>), SwitchSubLevels(ActionFields<SwitchSubLevels>),
ChangeTeamPosition(ActionFields<ChangeTeamPosition>), ChangeTeamPosition(ActionFields<ChangeTeamPosition>),
@ -2538,6 +2596,9 @@ pub enum Action {
StopUiScreenEffect(ActionFields<StopUiScreenEffect>), StopUiScreenEffect(ActionFields<StopUiScreenEffect>),
StopNewMoveWithSpline(ActionFields<StopNewMoveWithSpline>), StopNewMoveWithSpline(ActionFields<StopNewMoveWithSpline>),
RequestSystemFunction(ActionFields<RequestSystemFunction>), RequestSystemFunction(ActionFields<RequestSystemFunction>),
SetTimeScale(ActionFields<SetTimeScale>),
EndCommonTip(ActionFields<EndCommonTip>),
SetupMoraleSystem(ActionFields<SetupMoraleSystem>),
} }
#[derive(Deserialize, Debug, Clone)] #[derive(Deserialize, Debug, Clone)]

View file

@ -336,6 +336,7 @@ pub enum VehicleType {
FishingBoat, FishingBoat,
Gongduola, Gongduola,
SceneItemAutoMoveVehicle, SceneItemAutoMoveVehicle,
CoBathingEmptyVehicle,
} }
#[derive(Deserialize, Debug, Clone)] #[derive(Deserialize, Debug, Clone)]
@ -1198,6 +1199,24 @@ pub struct CheckDangoCultivationProgress {
pub UiType: serde_json::Value, 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 CheckPlayerMoraleLevelRange {
// 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 ProgramSpecialProcess {
// TODO:
#[cfg(feature = "strict_json_fields")]
pub UiType: serde_json::Value,
}
#[derive(Deserialize, Debug, Clone)] #[derive(Deserialize, Debug, Clone)]
#[serde(tag = "Type")] #[serde(tag = "Type")]
pub enum Condition { pub enum Condition {
@ -1305,6 +1324,8 @@ pub enum Condition {
FinishBvbChallenge(FinishBvbChallenge), FinishBvbChallenge(FinishBvbChallenge),
CompareActorVar(CompareActorVar), CompareActorVar(CompareActorVar),
CheckDangoCultivationProgress(CheckDangoCultivationProgress), CheckDangoCultivationProgress(CheckDangoCultivationProgress),
CheckPlayerMoraleLevelRange(CheckPlayerMoraleLevelRange),
ProgramSpecialProcess(ProgramSpecialProcess),
} }
#[derive(Deserialize, Debug, Clone)] #[derive(Deserialize, Debug, Clone)]

View file

@ -9,6 +9,7 @@ pub mod condition;
pub mod entity_state; pub mod entity_state;
pub mod flow; pub mod flow;
pub mod interact; pub mod interact;
pub mod model;
pub mod monster; pub mod monster;
pub mod option; pub mod option;
pub mod reward; pub mod reward;
@ -69,8 +70,7 @@ pub struct ComponentsData {
pub guide_line_creator_component: Option<serde_json::Value>, pub guide_line_creator_component: Option<serde_json::Value>,
#[cfg(feature = "strict_json_fields")] #[cfg(feature = "strict_json_fields")]
pub photo_target_component: Option<serde_json::Value>, pub photo_target_component: Option<serde_json::Value>,
#[cfg(feature = "strict_json_fields")] pub model_component: Option<model::ModelComponent>,
pub model_component: Option<serde_json::Value>,
#[cfg(feature = "strict_json_fields")] #[cfg(feature = "strict_json_fields")]
pub entity_group_component: Option<serde_json::Value>, pub entity_group_component: Option<serde_json::Value>,
#[cfg(feature = "strict_json_fields")] #[cfg(feature = "strict_json_fields")]
@ -222,14 +222,51 @@ pub struct ComponentsData {
impl ComponentsData { impl ComponentsData {
pub fn merge_with_template(&self, template: &Self) -> Self { pub fn merge_with_template(&self, template: &Self) -> Self {
Self { Self {
base_info_component: self.base_info_component.as_ref().or(template.base_info_component.as_ref()).cloned(), base_info_component: self
ai_component: self.ai_component.as_ref().or(template.ai_component.as_ref()).cloned(), .base_info_component
attribute_component: self.attribute_component.as_ref().or(template.attribute_component.as_ref()).cloned(), .as_ref()
teleport_component: self.teleport_component.as_ref().or(template.teleport_component.as_ref()).cloned(), .or(template.base_info_component.as_ref())
monster_component: self.monster_component.as_ref().or(template.monster_component.as_ref()).cloned(), .cloned(),
interact_component: self.interact_component.as_ref().or(template.interact_component.as_ref()).cloned(), ai_component: self
entity_state_component: self.entity_state_component.as_ref().or(template.entity_state_component.as_ref()).cloned(), .ai_component
reward_component: self.reward_component.as_ref().or(template.reward_component.as_ref()).cloned(), .as_ref()
.or(template.ai_component.as_ref())
.cloned(),
attribute_component: self
.attribute_component
.as_ref()
.or(template.attribute_component.as_ref())
.cloned(),
teleport_component: self
.teleport_component
.as_ref()
.or(template.teleport_component.as_ref())
.cloned(),
monster_component: self
.monster_component
.as_ref()
.or(template.monster_component.as_ref())
.cloned(),
interact_component: self
.interact_component
.as_ref()
.or(template.interact_component.as_ref())
.cloned(),
entity_state_component: self
.entity_state_component
.as_ref()
.or(template.entity_state_component.as_ref())
.cloned(),
reward_component: self
.reward_component
.as_ref()
.or(template.reward_component.as_ref())
.cloned(),
model_component: self
.model_component
.as_ref()
.or(template.model_component.as_ref())
.cloned(),
} }
} }
} }

View file

@ -0,0 +1,85 @@
use serde::Deserialize;
#[derive(Deserialize, Debug, Clone)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct ModelIdType {
pub model_id: i32
}
#[derive(Deserialize, Debug, Clone)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct PrefabStateList {
#[cfg(feature = "strict_json_fields")]
pub scene_interaction_state: i32,
#[cfg(feature = "strict_json_fields")]
pub level_tag: i64,
}
#[derive(Deserialize, Debug, Clone)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct LevelPrefabType {
#[cfg(feature = "strict_json_fields")]
pub blueprint_path: String,
#[cfg(feature = "strict_json_fields")]
pub prefab_path: String,
#[cfg(feature = "strict_json_fields")]
pub prefab_state_list: Vec<PrefabStateList>,
#[cfg(feature = "strict_json_fields")]
pub effect_state_list: Vec<String>,
}
#[derive(Deserialize, Debug, Clone)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct MeshType {
#[cfg(feature = "strict_json_fields")]
pub mesh: String,
}
#[derive(Deserialize, Debug, Clone)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct DaType {
#[cfg(feature = "strict_json_fields")]
pub da: String,
}
#[derive(Deserialize, Debug, Clone)]
#[serde(tag = "Type")]
pub enum NpcModel {
Mesh(MeshType),
Da(DaType),
}
#[derive(Deserialize, Debug, Clone)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct NpcType {
#[cfg(feature = "strict_json_fields")]
pub blueprint_path: String,
#[cfg(feature = "strict_json_fields")]
pub npc_model: NpcModel,
#[cfg(feature = "strict_json_fields")]
pub abp: String,
}
#[derive(Deserialize, Debug, Clone)]
#[serde(tag = "Type")]
pub enum ModelType {
ModelId(ModelIdType),
LevelPrefab(LevelPrefabType),
Npc(NpcType),
}
#[derive(Deserialize, Debug, Clone)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct ModelComponent {
pub half_height: Option<i32>,
pub track_height: Option<i32>,
pub disabled: Option<bool>,
pub model_type: Option<ModelType>,
}

View file

@ -0,0 +1,10 @@
use serde::Deserialize;
#[derive(Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct PhantomCustomizeItemData {
pub item_id: i32,
pub phantom_id: i32,
pub skin_item_id: i32,
}

View file

@ -0,0 +1,58 @@
use serde::Deserialize;
#[derive(Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct MainProp {
pub rand_group_id: i32,
pub rand_num: i32,
}
#[derive(Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct PhantomItemData {
pub item_id: i32,
pub monster_id: i32,
#[cfg(feature = "strict_json_fields")]
pub monster_name: String,
pub element_type: Vec<i32>,
pub main_prop: MainProp,
pub level_up_group_id: i32,
pub skill_id: i32,
pub calabash_buffs: Vec<i32>,
pub rarity: i32,
pub mesh_id: i32,
pub zoom: [f32; 3],
pub location: [f32; 3],
pub rotator: [f32; 3],
#[cfg(feature = "strict_json_fields")]
pub stand_anim: 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 icon: 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 mesh: String,
pub quality_id: i32,
pub max_capcity: i32,
pub item_access: Vec<i32>,
pub obtained_show: i32,
#[cfg(feature = "strict_json_fields")]
pub obtained_show_description: String,
pub num_limit: i32,
pub show_in_bag: bool,
pub sort_index: i32,
#[cfg(feature = "strict_json_fields")]
pub skill_icon: String,
pub destructible: bool,
pub red_dot_disable_rule: i32,
pub fetter_group: Vec<i32>,
pub phantom_type: i32,
pub parent_monster_id: i32,
}

View file

@ -77,7 +77,6 @@ pub struct RoleSkinData {
pub ui_mesh_id: i32, pub ui_mesh_id: i32,
#[cfg(feature = "strict_json_fields")] #[cfg(feature = "strict_json_fields")]
pub role_body: String, pub role_body: String,
#[cfg(feature = "strict_json_fields")]
#[serde(rename = "UiScenePerformanceABP")] #[serde(rename = "UiScenePerformanceABP")]
pub ui_scene_performance_abp: String, pub ui_scene_performance_abp: String,
#[cfg(feature = "strict_json_fields")] #[cfg(feature = "strict_json_fields")]

View file

@ -0,0 +1,12 @@
use serde::Deserialize;
#[derive(Debug, Deserialize)]
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
#[serde(rename_all = "PascalCase")]
pub struct SummonCfgData {
pub id: i32,
pub blueprint_type: String,
#[cfg(feature = "strict_json_fields")]
pub name: String,
pub born_buff_id: Vec<i64>,
}

View file

@ -19,7 +19,7 @@ load_textmaps = true
quadrant_size = 1000000 quadrant_size = 1000000
[asset_config] [asset_config]
asset_url = "https://git.xeondev.com/wickedwaifus/wicked-waifus-data/releases/download/pioneer_2.4.4/bundle.zip" asset_url = "https://git.xeondev.com/wickedwaifus/wicked-waifus-data/releases/download/pioneer_2.5.2/bundle.zip"
buffer_size = 268435456 buffer_size = 268435456
[default_unlocks] [default_unlocks]
@ -39,4 +39,7 @@ unlock_all_role_skins = false
# TODO: Set this to the same value as unlock_all_role_skins, without it, it fails(maybe jinshi weapon skin problem??) # TODO: Set this to the same value as unlock_all_role_skins, without it, it fails(maybe jinshi weapon skin problem??)
unlock_all_weapon_skins = false unlock_all_weapon_skins = false
unlock_all_fly_skins = false unlock_all_fly_skins = false
unlock_all_wing_skins = false unlock_all_wing_skins = false
unlock_all_echo_skins = false
unlock_all_echo = false
# TODO: Add max level here too??

View file

@ -0,0 +1,96 @@
const UE = require("ue");
const Info_1 = require("../../../Core/Common/Info");
const MathUtils_1 = require("../../../Core/Utils/MathUtils");
const UiLayerType_1 = require("../../Ui/Define/UiLayerType");
const UiLayer_1 = require("../../Ui/UiLayer");
var _a = require("../Module/WaterMask/WaterMaskController").WaterMaskView;
_a.LOo = 0.12;
_a.yOo = 700;
_a.IOo = 700;
let colorCycle = [
"#FF0000",
"#FF7F00",
"#FFFF00",
"#00FF00",
"#0000FF",
"#4B0082",
"#9400D3",
];
let colorIndex = 0;
let directionX = 3;
let directionY = 3;
const SPEED = 8;
const TEXT_OFFSET_X = 270;
const TEXT_OFFSET_Y = 20;
_a.vOo = function () {
void 0 !== _a.SOo && _a.EOo();
let e = UiLayer_1.UiLayer.GetLayerRootUiItem(
UiLayerType_1.ELayerType.WaterMask,
);
_a.SOo = UE.KuroActorManager.SpawnActor(
Info_1.Info.World,
UE.UIContainerActor.StaticClass(),
MathUtils_1.MathUtils.DefaultTransform,
void 0,
);
let t = _a.SOo.RootComponent;
t.SetDisplayName("WaterMaskContainer");
UE.KuroStaticLibrary.SetActorPermanent(_a.SOo, !0, !0);
_a.SOo.K2_AttachRootComponentTo(e);
let rootComponent = t.GetRootCanvas().GetOwner().RootComponent;
let screenWidth = rootComponent.widget.width;
let screenHeight = rootComponent.widget.height;
let textActor = UE.KuroActorManager.SpawnActor(
Info_1.Info.World,
UE.UITextActor.StaticClass(),
MathUtils_1.MathUtils.DefaultTransform,
void 0,
);
let textRoot = textActor.RootComponent;
textActor.K2_AttachRootComponentTo(t);
textRoot.SetDisplayName("NangPoRao:fuckhadros:");
let textComponent = textActor.GetComponentByClass(UE.UIText.StaticClass());
textComponent.SetFontSize(48);
textComponent.SetOverflowType(0);
textComponent.SetAlpha(_a.LOo);
textComponent.SetFont(UE.LGUIFontData.GetDefaultFont());
textComponent.SetText("{PLAYER_USERNAME}{CUSTOM_TEXT}");
textComponent.SetColor(UE.Color.FromHex(colorCycle[colorIndex]));
let posX = 0;
let posY = 0;
const halfWidth = screenWidth / 2 - TEXT_OFFSET_X;
const halfHeight = screenHeight / 2 - TEXT_OFFSET_Y;
function updatePosition() {
posX += directionX;
posY += directionY;
if (posX > halfWidth || posX < -halfWidth) {
directionX *= -1;
colorIndex = (colorIndex + 1) % colorCycle.length;
textComponent.SetColor(UE.Color.FromHex(colorCycle[colorIndex]));
textComponent.SetAlpha(_a.LOo);
}
if (posY > halfHeight || posY < -halfHeight) {
directionY *= -1;
colorIndex = (colorIndex + 1) % colorCycle.length;
textComponent.SetColor(UE.Color.FromHex(colorCycle[colorIndex]));
textComponent.SetAlpha(_a.LOo);
}
textRoot.SetUIRelativeLocation(new UE.Vector(posX, posY, 0));
}
setInterval(updatePosition, 16);
};
_a.vOo();

View file

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

View file

@ -49,6 +49,8 @@ pub struct DefaultUnlocks {
pub unlock_all_weapon_skins: bool, pub unlock_all_weapon_skins: bool,
pub unlock_all_fly_skins: bool, pub unlock_all_fly_skins: bool,
pub unlock_all_wing_skins: bool, pub unlock_all_wing_skins: bool,
pub unlock_all_echo_skins: bool,
pub unlock_all_echo: bool,
} }
impl TomlConfig for ServiceConfig { impl TomlConfig for ServiceConfig {

View file

@ -1,10 +1,9 @@
use wicked_waifus_data::BasePropertyData;
use wicked_waifus_protocol::{ use wicked_waifus_protocol::{
entity_component_pb::ComponentPb, AttrData, AttributeComponentPb, EAttributeType, entity_component_pb::ComponentPb, AttrData, AttributeComponentPb, EAttributeType,
EntityComponentPb, LivingStatus, EntityComponentPb, LivingStatus,
}; };
use std::collections::HashMap; use std::collections::HashMap;
use wicked_waifus_data::base_property_data::BasePropertyData;
use crate::logic::ecs::component::Component; use crate::logic::ecs::component::Component;
use crate::logic::utils::load_role_info::attribute_from_data; use crate::logic::utils::load_role_info::attribute_from_data;

View file

@ -0,0 +1,22 @@
use wicked_waifus_protocol::entity_component_pb::ComponentPb;
use wicked_waifus_protocol::{CharacterAttachComponentPb, CharacterAttachInfo, EntityComponentPb};
use crate::logic::ecs::component::Component;
pub struct CharacterAttach {
pub pb_combine_part_info_list: Vec<CharacterAttachInfo>,
pub pb_combine_target_server_id: i64,
}
impl Component for CharacterAttach {
fn set_pb_data(&self, pb: &mut wicked_waifus_protocol::EntityPb) {
pb.component_pbs.push(EntityComponentPb {
component_pb: Some(ComponentPb::CharacterAttachComponentPb(
CharacterAttachComponentPb {
pb_combine_part_info_list: self.pb_combine_part_info_list.clone(),
pb_combine_target_server_id: self.pb_combine_target_server_id,
},
)),
})
}
}

View file

@ -5,8 +5,8 @@ use indexmap::IndexMap;
use wicked_waifus_protocol::{DFsm, DFsmBlackBoard, EntityComponentPb, EntityFsmComponentPb, FsmCustomBlackboardDatas}; use wicked_waifus_protocol::{DFsm, DFsmBlackBoard, EntityComponentPb, EntityFsmComponentPb, FsmCustomBlackboardDatas};
use wicked_waifus_protocol::entity_component_pb::ComponentPb; use wicked_waifus_protocol::entity_component_pb::ComponentPb;
use wicked_waifus_data::{ai_base_data, ai_state_machine_config_data, AiStateMachineConfigData, StateMachineJson, StateMachineNode, StateMachineNodeCommon}; use wicked_waifus_data::{ai_base_data, ai_state_machine_config_data};
use wicked_waifus_data::ai_state_machine_config_data::{AiStateMachineConfigData, StateMachineJson, StateMachineNode, StateMachineNodeCommon};
use crate::logic::ecs::component::Component; use crate::logic::ecs::component::Component;
static COMMON_FSM: OnceLock<AiStateMachineConfigData> = OnceLock::new(); static COMMON_FSM: OnceLock<AiStateMachineConfigData> = OnceLock::new();

View file

@ -0,0 +1,24 @@
use wicked_waifus_protocol::entity_component_pb::ComponentPb;
use wicked_waifus_protocol::{EntityComponentPb, LogicStateComponentPb};
use crate::logic::ecs::component::Component;
pub struct LogicState {
pub position_state: i32,
pub move_state: i32,
pub direction_state: i32,
pub position_sub_state: i32,
}
impl Component for LogicState {
fn set_pb_data(&self, pb: &mut wicked_waifus_protocol::EntityPb) {
pb.component_pbs.push(EntityComponentPb {
component_pb: Some(ComponentPb::LogicStateComponentPb(LogicStateComponentPb {
position_state: self.position_state,
move_state: self.move_state,
direction_state: self.direction_state,
position_sub_state: self.position_sub_state,
})),
})
}
}

View file

@ -1,11 +1,13 @@
mod attribute; mod attribute;
mod autonomous; mod autonomous;
mod character_attach;
mod concomitant; mod concomitant;
mod entity_config; mod entity_config;
mod equip; mod equip;
mod fight_buff; mod fight_buff;
mod fsm; mod fsm;
mod interact; mod interact;
mod logic_state;
mod monster_ai; mod monster_ai;
mod movement; mod movement;
mod owner_player; mod owner_player;
@ -23,12 +25,14 @@ mod weapon_skin;
pub use attribute::Attribute; pub use attribute::Attribute;
pub use autonomous::Autonomous; pub use autonomous::Autonomous;
pub use character_attach::CharacterAttach;
pub use concomitant::Concomitant; pub use concomitant::Concomitant;
pub use entity_config::EntityConfig; pub use entity_config::EntityConfig;
pub use equip::Equip; pub use equip::Equip;
pub use fight_buff::FightBuff; pub use fight_buff::FightBuff;
pub use fsm::Fsm; pub use fsm::Fsm;
pub use interact::Interact; pub use interact::Interact;
pub use logic_state::LogicState;
pub use monster_ai::MonsterAi; pub use monster_ai::MonsterAi;
pub use movement::Movement; pub use movement::Movement;
pub use owner_player::OwnerPlayer; pub use owner_player::OwnerPlayer;

View file

@ -4,6 +4,7 @@ use wicked_waifus_protocol::entity_component_pb::ComponentPb;
use crate::logic::ecs::component::Component; use crate::logic::ecs::component::Component;
pub struct Summoner { pub struct Summoner {
pub summoner_id: i64,
pub summon_cfg_id: i32, pub summon_cfg_id: i32,
pub summon_skill_id: i32, pub summon_skill_id: i32,
pub summon_type: i32, pub summon_type: i32,
@ -13,7 +14,7 @@ impl Component for Summoner {
fn set_pb_data(&self, pb: &mut wicked_waifus_protocol::EntityPb) { fn set_pb_data(&self, pb: &mut wicked_waifus_protocol::EntityPb) {
pb.component_pbs.push(EntityComponentPb { pb.component_pbs.push(EntityComponentPb {
component_pb: Some(ComponentPb::SummonerComponent(SummonerComponentPb { component_pb: Some(ComponentPb::SummonerComponent(SummonerComponentPb {
summoner_id: pb.id + 1, summoner_id: self.summoner_id,
summon_cfg_id: self.summon_cfg_id, summon_cfg_id: self.summon_cfg_id,
summon_skill_id: self.summon_skill_id, summon_skill_id: self.summon_skill_id,
player_id: pb.player_id, player_id: pb.player_id,

View file

@ -23,27 +23,29 @@ macro_rules! impl_component_container {
} }
impl_component_container! { impl_component_container! {
Position;
EntityConfig;
OwnerPlayer;
Visibility;
Attribute; Attribute;
PlayerOwnedEntityMarker;
Movement;
Equip;
VisionSkill;
MonsterAi;
Fsm;
RoleSkin;
FightBuff;
StateTag;
Tag;
Autonomous; Autonomous;
Interact; CharacterAttach;
Concomitant; Concomitant;
Summoner; EntityConfig;
SoarWingSkin; Equip;
FightBuff;
Fsm;
Interact;
LogicState;
MonsterAi;
Movement;
OwnerPlayer;
ParaglidingSkin; ParaglidingSkin;
PlayerOwnedEntityMarker;
Position;
RoleSkin;
SoarWingSkin;
StateTag;
Summoner;
Tag;
Visibility;
VisionSkill;
WeaponSkin; WeaponSkin;
} }

View file

@ -25,8 +25,8 @@ macro_rules! find_component {
// Query specified components from all entities (and) // Query specified components from all entities (and)
#[macro_export] #[macro_export]
macro_rules! query_with { macro_rules! query_with {
($world_entitys:expr, $($comp:ident),*) => { ($world_entities:expr, $($comp:ident),*) => {
$world_entitys.components().iter().filter(|(_, comps)| { $world_entities.components().iter().filter(|(_, comps)| {
$(comps.iter().any(|comp| matches!(&*comp.borrow(), ComponentContainer::$comp(_))) && ) $(comps.iter().any(|comp| matches!(&*comp.borrow(), ComponentContainer::$comp(_))) && )
* true * true
}) })
@ -44,8 +44,8 @@ macro_rules! query_with {
// Query specified components from all entities (or) // Query specified components from all entities (or)
#[macro_export] #[macro_export]
macro_rules! query_hn_with { macro_rules! query_hn_with {
($world_entitys:expr, $($comp:ident),*) => { ($world_entities:expr, $($comp:ident),*) => {
$world_entitys.components().iter().filter(|(_, comps)| { $world_entities.components().iter().filter(|(_, comps)| {
$(comps.iter().any(|comp| matches!(&*comp.borrow(), ComponentContainer::$comp(_))) || ) $(comps.iter().any(|comp| matches!(&*comp.borrow(), ComponentContainer::$comp(_))) || )
* false * false
}) })
@ -70,8 +70,8 @@ macro_rules! ident_as_none {
// Query components of specified entity // Query components of specified entity
#[macro_export] #[macro_export]
macro_rules! query_components { macro_rules! query_components {
($world_entitys:expr, $entity_id:expr, $($comp:ident),*) => { ($world_entities:expr, $entity_id:expr, $($comp:ident),*) => {
$world_entitys.components().iter().find(|(id, _)| $entity_id == i64::from(**id)) $world_entities.components().iter().find(|(id, _)| $entity_id == i64::from(**id))
.map(|(_, comps)| { .map(|(_, comps)| {
($( ($(
$crate::find_component!(comps, $comp), $crate::find_component!(comps, $comp),

View file

@ -7,6 +7,7 @@ use std::collections::hash_map::{Keys, Values};
use std::collections::HashMap; use std::collections::HashMap;
use wicked_waifus_protocol::FightBuffInformation; use wicked_waifus_protocol::FightBuffInformation;
#[derive(Default)]
pub struct WorldEntity { pub struct WorldEntity {
components: HashMap<i32, Vec<RefCell<ComponentContainer>>>, components: HashMap<i32, Vec<RefCell<ComponentContainer>>>,
entity_manager: EntityManager, entity_manager: EntityManager,
@ -15,7 +16,7 @@ pub struct WorldEntity {
pub struct World { pub struct World {
pub player_cur_map_id: i32, pub player_cur_map_id: i32,
pub world_entitys: HashMap<i32, WorldEntity>, // i32 -> map_id pub world_entities: HashMap<i32, WorldEntity>, // i32 -> map_id
pub in_world_players: HashMap<i32, InWorldPlayer>, // joined players metadata pub in_world_players: HashMap<i32, InWorldPlayer>, // joined players metadata
} }
@ -23,7 +24,7 @@ impl World {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
player_cur_map_id: 8, player_cur_map_id: 8,
world_entitys: HashMap::new(), world_entities: HashMap::new(),
in_world_players: HashMap::new(), in_world_players: HashMap::new(),
} }
} }
@ -42,13 +43,13 @@ impl World {
} }
pub fn get_mut_world_entity(&mut self) -> &mut WorldEntity { pub fn get_mut_world_entity(&mut self) -> &mut WorldEntity {
self.world_entitys self.world_entities
.get_mut(&self.player_cur_map_id) .get_mut(&self.player_cur_map_id)
.unwrap_or_else(|| panic!("Failed to get cur map data: {}", self.player_cur_map_id)) .unwrap_or_else(|| panic!("Failed to get cur map data: {}", self.player_cur_map_id))
} }
pub fn get_world_entity(&self) -> &WorldEntity { pub fn get_world_entity(&self) -> &WorldEntity {
self.world_entitys self.world_entities
.get(&self.player_cur_map_id) .get(&self.player_cur_map_id)
.unwrap_or_else(|| panic!("Failed to get cur map data: {}", self.player_cur_map_id)) .unwrap_or_else(|| panic!("Failed to get cur map data: {}", self.player_cur_map_id))
} }
@ -64,7 +65,7 @@ impl WorldEntity {
entity, entity,
self.components self.components
.entry(entity.entity_id) .entry(entity.entity_id)
.or_insert(Vec::new()), .or_default(),
) )
} }
@ -114,14 +115,4 @@ impl WorldEntity {
pub fn generate_role_permanent_buffs(&mut self, entity_id: i64) -> Vec<FightBuffInformation> { pub fn generate_role_permanent_buffs(&mut self, entity_id: i64) -> Vec<FightBuffInformation> {
self.buff_manager.create_permanent_buffs(entity_id) self.buff_manager.create_permanent_buffs(entity_id)
} }
} }
impl Default for WorldEntity {
fn default() -> Self {
Self {
components: HashMap::new(),
entity_manager: EntityManager::default(),
buff_manager: BufManager::default(),
}
}
}

View file

@ -2,10 +2,10 @@ use rand::prelude::IndexedRandom;
use rand::Rng; use rand::Rng;
use wicked_waifus_protocol::{ErrorCode, GachaResult, GachaReward}; use wicked_waifus_protocol::{ErrorCode, GachaResult, GachaReward};
use wicked_waifus_data::GachaViewTypeInfoId::{ use wicked_waifus_data::gacha_view_info_data::GachaViewTypeInfoId::{
BeginnersChoiceConvene, FeaturedResonatorConvene, FeaturedWeaponConvene, AnniversaryResonatorConvene, AnniversaryWeaponConvene, BeginnersChoiceConvene,
MultipleChoiceResonatorConvene, MultipleChoiceWeaponConvene, NoviceConvene, FeaturedResonatorConvene, FeaturedWeaponConvene, NewVoyageResonatorConvene,
StandardResonatorConvene, StandardWeaponConvene, NewVoyageWeaponConvene, NoviceConvene, StandardResonatorConvene, StandardWeaponConvene,
}; };
use crate::logic::gacha::pool_info::PoolInfo; use crate::logic::gacha::pool_info::PoolInfo;
@ -118,7 +118,10 @@ impl GachaPool {
let weapon_id = role.equip_weapon; let weapon_id = role.equip_weapon;
player.role_list.insert(item_id, role); player.role_list.insert(item_id, role);
// TODO notifies player update // TODO notifies player update
player.inventory.add_weapon(role_id, 0, 1, 0, 0, 0, weapon_id).unwrap(); player
.inventory
.add_weapon(role_id, 0, 1, 0, 0, 0, weapon_id)
.unwrap();
// TODO notifies weapon update // TODO notifies weapon update
} }
} }
@ -151,13 +154,15 @@ impl GachaPool {
}, },
2 => match self.info.pool_type { 2 => match self.info.pool_type {
NoviceConvene | StandardResonatorConvene => &[1405, 1301, 1503, 1104, 1203], NoviceConvene | StandardResonatorConvene => &[1405, 1301, 1503, 1104, 1203],
// TODO: Review MultipleChoiceConvene // TODO: Review MultipleChoiceConvene(anniversary and new voyage)
FeaturedResonatorConvene FeaturedResonatorConvene
| FeaturedWeaponConvene | FeaturedWeaponConvene
| StandardWeaponConvene | StandardWeaponConvene
| BeginnersChoiceConvene | BeginnersChoiceConvene
| MultipleChoiceResonatorConvene | AnniversaryResonatorConvene
| MultipleChoiceWeaponConvene => &self.info.rate_up_five_star[..], | AnniversaryWeaponConvene
| NewVoyageResonatorConvene
| NewVoyageWeaponConvene => &self.info.rate_up_five_star[..],
}, },
_ => unreachable!(), _ => unreachable!(),
}; };

View file

@ -1,10 +1,10 @@
use std::time::SystemTime; use std::time::SystemTime;
use wicked_waifus_data::GachaViewTypeInfoId; use wicked_waifus_data::gacha_view_info_data::GachaViewTypeInfoId;
use wicked_waifus_data::GachaViewTypeInfoId::{ use wicked_waifus_data::gacha_view_info_data::GachaViewTypeInfoId::{
BeginnersChoiceConvene, FeaturedResonatorConvene, FeaturedWeaponConvene, AnniversaryResonatorConvene, AnniversaryWeaponConvene, BeginnersChoiceConvene,
MultipleChoiceResonatorConvene, MultipleChoiceWeaponConvene, NoviceConvene, FeaturedResonatorConvene, FeaturedWeaponConvene, NewVoyageResonatorConvene,
StandardResonatorConvene, StandardWeaponConvene, NewVoyageWeaponConvene, NoviceConvene, StandardResonatorConvene, StandardWeaponConvene,
}; };
use crate::logic::gacha::category::PoolCategory; use crate::logic::gacha::category::PoolCategory;
@ -78,11 +78,14 @@ impl PoolInfo {
StandardResonatorConvene | StandardWeaponConvene => { StandardResonatorConvene | StandardWeaponConvene => {
(50001, 0, 80, PitySystem::default()) (50001, 0, 80, PitySystem::default())
} }
// TODO: Review MultipleChoiceConvene // TODO: Review MultipleChoiceConvene(anniversary and new voyage)
FeaturedResonatorConvene FeaturedResonatorConvene | AnniversaryResonatorConvene | NewVoyageResonatorConvene => {
| MultipleChoiceResonatorConvene (50002, 0, 0, PitySystem::default())
| MultipleChoiceWeaponConvene => (50002, 0, 0, PitySystem::default()), }
FeaturedWeaponConvene => (50005, 0, 0, PitySystem::default()), // TODO: Review MultipleChoiceConvene(anniversary and new voyage)
FeaturedWeaponConvene | AnniversaryWeaponConvene | NewVoyageWeaponConvene => {
(50005, 0, 0, PitySystem::default())
}
BeginnersChoiceConvene => match pool_id { BeginnersChoiceConvene => match pool_id {
51..56 => (50006, 0, 1, PitySystem::default()), 51..56 => (50006, 0, 1, PitySystem::default()),
_ => (50001, 0, 80, PitySystem::default()), _ => (50001, 0, 80, PitySystem::default()),

View file

@ -5,10 +5,10 @@ use rand::prelude::StdRng;
use rand::SeedableRng; use rand::SeedableRng;
use wicked_waifus_data::gacha_view_info_data; use wicked_waifus_data::gacha_view_info_data;
use wicked_waifus_data::GachaViewTypeInfoId::{ use wicked_waifus_data::gacha_view_info_data::GachaViewTypeInfoId::{
BeginnersChoiceConvene, FeaturedResonatorConvene, FeaturedWeaponConvene, AnniversaryResonatorConvene, AnniversaryWeaponConvene, BeginnersChoiceConvene,
MultipleChoiceResonatorConvene, MultipleChoiceWeaponConvene, NoviceConvene, FeaturedResonatorConvene, FeaturedWeaponConvene, NewVoyageResonatorConvene,
StandardResonatorConvene, StandardWeaponConvene, NewVoyageWeaponConvene, NoviceConvene, StandardResonatorConvene, StandardWeaponConvene,
}; };
use wicked_waifus_protocol::{ErrorCode, GachaResult}; use wicked_waifus_protocol::{ErrorCode, GachaResult};
@ -41,11 +41,15 @@ impl GachaService {
NoviceConvene | StandardResonatorConvene | StandardWeaponConvene => { NoviceConvene | StandardResonatorConvene | StandardWeaponConvene => {
PoolCategory::Permanent PoolCategory::Permanent
} }
// TODO: Review MultipleChoiceConvene // TODO: Review MultipleChoiceConvene(anniversary and new voyage)
FeaturedResonatorConvene FeaturedResonatorConvene
| FeaturedWeaponConvene | FeaturedWeaponConvene
| MultipleChoiceResonatorConvene | StandardWeaponConvene
| MultipleChoiceWeaponConvene => PoolCategory::Event(Self::THREE_WEEKS), | BeginnersChoiceConvene
| AnniversaryResonatorConvene
| AnniversaryWeaponConvene
| NewVoyageResonatorConvene
| NewVoyageWeaponConvene => PoolCategory::Event(Self::THREE_WEEKS),
BeginnersChoiceConvene => match element.id { BeginnersChoiceConvene => match element.id {
51..56 => PoolCategory::Special(Self::ONE_WEEK), 51..56 => PoolCategory::Special(Self::ONE_WEEK),
_ => PoolCategory::Permanent, _ => PoolCategory::Permanent,

View file

@ -1,13 +1,13 @@
use crate::logic::thread_mgr::NetContext;
use wicked_waifus_protocol::{AdviceSetRequest, AdviceSetResponse, ErrorCode}; use wicked_waifus_protocol::{AdviceSetRequest, AdviceSetResponse, ErrorCode};
use crate::logic::player::Player;
pub fn on_advice_set_request( pub fn on_advice_set_request(
player: &mut Player, ctx: &mut NetContext,
request: AdviceSetRequest, request: AdviceSetRequest,
response: &mut AdviceSetResponse, response: &mut AdviceSetResponse,
) { ) {
player.advise.is_show = request.is_show; ctx.player.advise.is_show = request.is_show;
response.is_show = request.is_show; response.is_show = request.is_show;
response.error_code = ErrorCode::Success.into(); response.error_code = ErrorCode::Success.into();
} }

View file

@ -1,17 +1,21 @@
use wicked_waifus_protocol::{AnimalDestroyRequest, AnimalDestroyResponse, AnimalDieRequest, AnimalDieResponse, AnimalDropRequest, AnimalDropResponse, EEntityType, ERemoveEntityType, EntityLivingStatusNotify, ErrorCode, LivingStatus}; use wicked_waifus_protocol::{
AnimalDestroyRequest, AnimalDestroyResponse, AnimalDieRequest, AnimalDieResponse,
AnimalDropRequest, AnimalDropResponse, EEntityType, ERemoveEntityType,
EntityLivingStatusNotify, ErrorCode, LivingStatus,
};
use crate::logic::ecs::component::ComponentContainer; use crate::logic::ecs::component::ComponentContainer;
use crate::logic::player::Player; use crate::logic::thread_mgr::NetContext;
use crate::logic::utils::world_util; use crate::logic::utils::world_util;
use crate::query_components; use crate::query_components;
pub fn on_animal_die_request( pub fn on_animal_die_request(
player: &mut Player, ctx: &mut NetContext,
request: AnimalDieRequest, request: AnimalDieRequest,
response: &mut AnimalDieResponse, response: &mut AnimalDieResponse,
) { ) {
tracing::warn!("AnimalDieRequest not fully implemented"); tracing::warn!("AnimalDieRequest not fully implemented");
player.notify(EntityLivingStatusNotify { ctx.player.notify(EntityLivingStatusNotify {
id: request.entity_id, id: request.entity_id,
living_status: LivingStatus::Dead.into(), living_status: LivingStatus::Dead.into(),
drop_vision_item: vec![], drop_vision_item: vec![],
@ -21,7 +25,7 @@ pub fn on_animal_die_request(
} }
pub fn on_animal_drop_request( pub fn on_animal_drop_request(
_player: &mut Player, _ctx: &mut NetContext,
_request: AnimalDropRequest, _request: AnimalDropRequest,
response: &mut AnimalDropResponse, response: &mut AnimalDropResponse,
) { ) {
@ -32,15 +36,13 @@ pub fn on_animal_drop_request(
} }
pub fn on_animal_destroy_request( pub fn on_animal_destroy_request(
player: &mut Player, ctx: &mut NetContext,
request: AnimalDestroyRequest, request: AnimalDestroyRequest,
response: &mut AnimalDestroyResponse, response: &mut AnimalDestroyResponse,
) { ) {
let entity_id = request.entity_id;
{ {
let entity_id = request.entity_id; let (Some(config), ) = query_components!(ctx.world.get_world_entity(), entity_id, EntityConfig) else {
let world_ref = player.world.borrow();
let world = world_ref.get_world_entity();
let (Some(config), ) = query_components!(world,entity_id,EntityConfig) else {
response.error_code = ErrorCode::ErrAnimalEntityNotExist.into(); response.error_code = ErrorCode::ErrAnimalEntityNotExist.into();
return; return;
}; };
@ -48,7 +50,7 @@ pub fn on_animal_destroy_request(
response.error_code = ErrorCode::ErrNotAnimalEntity.into(); response.error_code = ErrorCode::ErrNotAnimalEntity.into();
} }
} }
world_util::remove_entity(player, request.entity_id, ERemoveEntityType::RemoveTypeNormal); world_util::remove_entity(ctx, request.entity_id, ERemoveEntityType::RemoveTypeNormal);
response.error_code = ErrorCode::Success.into(); response.error_code = ErrorCode::Success.into();
} }
@ -62,4 +64,4 @@ fn get_animal_reward() {
// NormalItemUpdateNotify // NormalItemUpdateNotify
// UpdateHandBookActiveStateMapNotify // UpdateHandBookActiveStateMapNotify
// ItemRewardNotify // ItemRewardNotify
} }

View file

@ -1,17 +1,21 @@
use tracing::debug; use tracing::debug;
use wicked_waifus_protocol::{ErrorCode, PrivateChatDataRequest, PrivateChatDataResponse, PrivateChatHistoryRequest, PrivateChatHistoryResponse, PrivateChatOperateRequest, PrivateChatOperateResponse, PrivateChatOperateType, PrivateChatRequest, PrivateChatResponse}; use wicked_waifus_protocol::{
ErrorCode, PrivateChatDataRequest, PrivateChatDataResponse, PrivateChatHistoryRequest,
PrivateChatHistoryResponse, PrivateChatOperateRequest, PrivateChatOperateResponse,
PrivateChatOperateType, PrivateChatRequest, PrivateChatResponse,
};
use crate::logic::player::Player; use crate::logic::thread_mgr::NetContext;
pub fn on_private_chat_request( pub fn on_private_chat_request(
player: &mut Player, ctx: &mut NetContext,
request: PrivateChatRequest, request: PrivateChatRequest,
response: &mut PrivateChatResponse, response: &mut PrivateChatResponse,
) { ) {
let own_id = player.basic_info.id; let own_id = ctx.player.basic_info.id;
// TODO: Implement block and ban checks?? Ignore them for the time being // TODO: Implement block and ban checks?? Ignore them for the time being
let result = player.player_chat.validate_message( let result = ctx.player.player_chat.validate_message(
own_id, own_id,
request.target_uid, request.target_uid,
request.chat_content_type, request.chat_content_type,
@ -19,7 +23,7 @@ pub fn on_private_chat_request(
); );
match result { match result {
Ok(message) => { Ok(message) => {
player.player_chat.add_message(own_id, message.clone()); ctx.player.player_chat.add_message(own_id, message.clone());
// TODO: Check how to search a player from a different world(db search or session search) // TODO: Check how to search a player from a different world(db search or session search)
// let other_player = ...; // let other_player = ...;
// let other_player_message = message.clone(); // let other_player_message = message.clone();
@ -37,38 +41,37 @@ pub fn on_private_chat_request(
// ) // )
// }) // })
} }
Err(error_code) => response.error_code = error_code Err(error_code) => response.error_code = error_code,
}; };
} }
pub fn on_private_chat_data_request( pub fn on_private_chat_data_request(
_: &Player, _: &NetContext,
_: PrivateChatDataRequest, _: PrivateChatDataRequest,
_: &mut PrivateChatDataResponse, _: &mut PrivateChatDataResponse,
) { ) {
} }
pub fn on_private_chat_history_request( pub fn on_private_chat_history_request(
player: &Player, ctx: &NetContext,
request: PrivateChatHistoryRequest, request: PrivateChatHistoryRequest,
response: &mut PrivateChatHistoryResponse, response: &mut PrivateChatHistoryResponse,
) { ) {
match player.player_chat.build_private_chat_history_content_proto( match ctx
request.target_uid, .player
request.start_index, .player_chat
) { .build_private_chat_history_content_proto(request.target_uid, request.start_index)
{
Ok(chat_history_content_proto) => { Ok(chat_history_content_proto) => {
response.error_code = ErrorCode::Success.into(); response.error_code = ErrorCode::Success.into();
response.data = Some(chat_history_content_proto) response.data = Some(chat_history_content_proto)
} }
Err(error_code) => response.error_code = error_code Err(error_code) => response.error_code = error_code,
} }
} }
pub fn on_private_chat_operate_request( pub fn on_private_chat_operate_request(
_player: &Player, _ctx: &NetContext,
request: PrivateChatOperateRequest, request: PrivateChatOperateRequest,
response: &mut PrivateChatOperateResponse, response: &mut PrivateChatOperateResponse,
) { ) {
@ -78,7 +81,10 @@ pub fn on_private_chat_operate_request(
response.error_code = ErrorCode::Success.into(); response.error_code = ErrorCode::Success.into();
} else { } else {
// TODO: Additional checks // TODO: Additional checks
debug!("on_private_chat_operate_request called for unimplemented case: {:?}", request); debug!(
"on_private_chat_operate_request called for unimplemented case: {:?}",
request
);
response.error_code = ErrorCode::Success.into(); response.error_code = ErrorCode::Success.into();
} }
} }

View file

@ -5,15 +5,15 @@ use wicked_waifus_protocol::combat_message::{
}; };
use wicked_waifus_protocol::{ use wicked_waifus_protocol::{
AttributeChangedNotify, CombatCommon, DErrorResult, DamageExecuteRequest, AttributeChangedNotify, CombatCommon, DErrorResult, DamageExecuteRequest,
DamageExecuteResponse, EAttributeType, ERemoveEntityType, ErrorCode, DamageExecuteResponse, EAttributeType, ERemoveEntityType, ErrorCode, FsmConditionPassRequest,
FsmConditionPassRequest, FsmConditionPassResponse, GameplayAttributeData, FsmConditionPassResponse, GameplayAttributeData, PlayerBattleStateChangeNotify,
PlayerBattleStateChangeNotify, SwitchRoleRequest, SwitchRoleResponse, SwitchRoleRequest, SwitchRoleResponse,
}; };
use wicked_waifus_data::damage_data; use wicked_waifus_data::damage_data;
use crate::logic::ecs::component::ComponentContainer; use crate::logic::ecs::component::ComponentContainer;
use crate::logic::player::Player; use crate::logic::thread_mgr::NetContext;
use crate::logic::utils::world_util; use crate::logic::utils::world_util;
use crate::query_components; use crate::query_components;
@ -49,7 +49,7 @@ fn create_combat_notify(
} }
pub fn on_combat_message_combat_send_pack_request( pub fn on_combat_message_combat_send_pack_request(
player: &mut Player, ctx: &mut NetContext,
request: CombatSendPackRequest, request: CombatSendPackRequest,
response: &mut CombatSendPackResponse, response: &mut CombatSendPackResponse,
) { ) {
@ -58,13 +58,13 @@ pub fn on_combat_message_combat_send_pack_request(
if let Some(ref request_message) = request_data.message { if let Some(ref request_message) = request_data.message {
match request_message { match request_message {
combat_request_data::Message::SwitchRoleRequest(ref request) => { combat_request_data::Message::SwitchRoleRequest(ref request) => {
handle_switch_role_request(player, request_data, request, response); handle_switch_role_request(ctx, request_data, request, response);
} }
combat_request_data::Message::FsmConditionPassRequest(ref request) => { combat_request_data::Message::FsmConditionPassRequest(ref request) => {
handle_fsm_condition_request(player, request_data, request, response); handle_fsm_condition_request(ctx, request_data, request, response);
} }
combat_request_data::Message::DamageExecuteRequest(ref request) => { combat_request_data::Message::DamageExecuteRequest(ref request) => {
handle_damage_execute_request(player, request_data, request, response); handle_damage_execute_request(ctx, request_data, request, response);
} }
_ => {} _ => {}
} }
@ -75,13 +75,18 @@ pub fn on_combat_message_combat_send_pack_request(
} }
fn handle_switch_role_request( fn handle_switch_role_request(
player: &mut Player, ctx: &mut NetContext,
combat_request: &CombatRequestData, combat_request: &CombatRequestData,
request: &SwitchRoleRequest, request: &SwitchRoleRequest,
response: &mut CombatSendPackResponse, response: &mut CombatSendPackResponse,
) { ) {
// Find current formation and update current role // Find current formation and update current role
if let Some(formation) = player.formation_list.values_mut().find(|f| f.is_current) { if let Some(formation) = ctx
.player
.formation_list
.values_mut()
.find(|f| f.is_current)
{
formation.cur_role = request.role_id; formation.cur_role = request.role_id;
let receive_pack = response let receive_pack = response
@ -105,7 +110,7 @@ fn handle_switch_role_request(
} }
fn handle_damage_execute_request( fn handle_damage_execute_request(
player: &mut Player, ctx: &mut NetContext,
combat_request: &CombatRequestData, combat_request: &CombatRequestData,
request: &DamageExecuteRequest, request: &DamageExecuteRequest,
response: &mut CombatSendPackResponse, response: &mut CombatSendPackResponse,
@ -114,8 +119,7 @@ fn handle_damage_execute_request(
.receive_pack_notify .receive_pack_notify
.get_or_insert_with(Default::default); .get_or_insert_with(Default::default);
let mut world_ref = player.world.borrow_mut(); let world = ctx.world.get_mut_world_entity();
let world = world_ref.get_mut_world_entity();
let config_id = world.get_config_id(request.attacker_entity_id.try_into().unwrap()); let config_id = world.get_config_id(request.attacker_entity_id.try_into().unwrap());
let mut damage = 1; // TODO: Fix the formula with real parameters(10 field equation) let mut damage = 1; // TODO: Fix the formula with real parameters(10 field equation)
if config_id.to_string().len() == 4 { if config_id.to_string().len() == 4 {
@ -160,6 +164,7 @@ fn handle_damage_execute_request(
..Default::default() ..Default::default()
}), }),
)); ));
let mut entities_to_remove = Vec::new();
if let Some((value, _)) = query_components!(world, request.target_entity_id, Attribute) if let Some((value, _)) = query_components!(world, request.target_entity_id, Attribute)
.0 .0
.unwrap() .unwrap()
@ -185,19 +190,18 @@ fn handle_damage_execute_request(
}), }),
)); ));
if updated_value == 0 { if updated_value == 0 {
world_util::remove_entity( entities_to_remove.push(request.target_entity_id);
player,
request.target_entity_id,
ERemoveEntityType::HpIsZero,
);
} }
} }
for entity in entities_to_remove {
world_util::remove_entity(ctx, entity, ERemoveEntityType::HpIsZero);
}
response.error_code = ErrorCode::Success.into(); response.error_code = ErrorCode::Success.into();
} }
fn handle_battle( fn handle_battle(
player: &mut Player, ctx: &mut NetContext,
combat_request: &CombatRequestData, combat_request: &CombatRequestData,
response: &mut CombatSendPackResponse, response: &mut CombatSendPackResponse,
condition: bool, condition: bool,
@ -209,15 +213,14 @@ fn handle_battle(
receive_pack.data.push(create_combat_notify( receive_pack.data.push(create_combat_notify(
combat_request.combat_common.unwrap(), combat_request.combat_common.unwrap(),
combat_notify_data::Message::PlayerBattleStateChangeNotify(PlayerBattleStateChangeNotify { combat_notify_data::Message::PlayerBattleStateChangeNotify(PlayerBattleStateChangeNotify {
player_id: player.basic_info.id, player_id: ctx.player.basic_info.id,
in_battle: condition, in_battle: condition,
}), }),
)); ));
} }
fn handle_fsm_condition_request( fn handle_fsm_condition_request(
player: &mut Player, ctx: &mut NetContext,
combat_request: &CombatRequestData, combat_request: &CombatRequestData,
request: &FsmConditionPassRequest, request: &FsmConditionPassRequest,
response: &mut CombatSendPackResponse, response: &mut CombatSendPackResponse,
@ -238,5 +241,5 @@ fn handle_fsm_condition_request(
}), }),
}), }),
)); ));
handle_battle(player, combat_request, response, true); handle_battle(ctx, combat_request, response, true);
} }

View file

@ -1,8 +1,8 @@
use crate::logic::thread_mgr::NetContext;
use wicked_waifus_protocol::{ErrorCode, LobbyListRequest, LobbyListResponse}; use wicked_waifus_protocol::{ErrorCode, LobbyListRequest, LobbyListResponse};
use crate::logic::player::Player;
pub fn on_lobby_list_request( pub fn on_lobby_list_request(
_player: &mut Player, _ctx: &mut NetContext,
request: LobbyListRequest, request: LobbyListRequest,
response: &mut LobbyListResponse, response: &mut LobbyListResponse,
) { ) {
@ -15,4 +15,4 @@ pub fn on_lobby_list_request(
} }
} }
response.error_code = ErrorCode::Success.into(); response.error_code = ErrorCode::Success.into();
} }

View file

@ -1,4 +1,4 @@
use crate::logic::player::Player; use crate::logic::thread_mgr::NetContext;
macro_rules! dummy_handler { macro_rules! dummy_handler {
($($type_name:ident;)*) => { ($($type_name:ident;)*) => {
@ -9,7 +9,7 @@ macro_rules! dummy_handler {
$(::paste::paste! { $(::paste::paste! {
pub fn [<on_ $type_name:snake _request>]( pub fn [<on_ $type_name:snake _request>](
_player: &Player, _ctx: &NetContext,
_request: [<$type_name Request>], _request: [<$type_name Request>],
_response: &mut [<$type_name Response>], _response: &mut [<$type_name Response>],
) { ) {

View file

@ -1,24 +1,30 @@
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_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 wicked_waifus_data::pb_components::option::OptionType;
use crate::{logic, logic::ecs::component::ComponentContainer, logic::player::Player, query_components}; use crate::logic::thread_mgr::NetContext;
use crate::logic::utils::action_utils::perform_action; use crate::logic::utils::action_utils::perform_action;
use crate::logic::utils::condition_utils::check_condition; use crate::logic::utils::condition_utils::check_condition;
use crate::{logic, logic::ecs::component::ComponentContainer, query_components};
pub fn on_entity_active_request( pub fn on_entity_active_request(
player: &Player, ctx: &NetContext,
request: EntityActiveRequest, request: EntityActiveRequest,
response: &mut EntityActiveResponse, response: &mut EntityActiveResponse,
) { ) {
let world_ref = player.world.borrow(); let world = ctx.world.get_world_entity();
let world = world_ref.get_world_entity();
if !world.is_in_all_world_map(request.entity_id as i32) { if !world.is_in_all_world_map(request.entity_id as i32) {
tracing::debug!( tracing::debug!(
"EntityActiveRequest: entity with id {} doesn't exist, player_id: {}", "EntityActiveRequest: entity with id {} doesn't exist, player_id: {}",
request.entity_id, request.entity_id,
player.basic_info.id ctx.player.basic_info.id
); );
return; return;
}; };
@ -29,17 +35,19 @@ pub fn on_entity_active_request(
..Default::default() ..Default::default()
}; };
world.get_entity_components(request.entity_id as i32) world
.get_entity_components(request.entity_id as i32)
.into_iter() .into_iter()
.for_each(|comp| comp.set_pb_data(&mut pb)); .for_each(|comp| comp.set_pb_data(&mut pb));
pb.component_pbs pb.component_pbs
}; };
// TODO: Remove attribute // TODO: Remove attribute
if let (Some(position), Some(_attribute)) = if let (Some(position), Some(_attribute), Some(visibility)) =
query_components!(world, request.entity_id, Position, Attribute) query_components!(world, request.entity_id, Position, Attribute, Visibility)
{ {
response.is_visible = true; response.is_visible = visibility.is_visible;
response.pos = Some(position.0.get_position_protobuf()); response.pos = Some(position.0.get_position_protobuf());
response.rot = Some(position.0.get_rotation_protobuf()); response.rot = Some(position.0.get_rotation_protobuf());
@ -51,13 +59,12 @@ pub fn on_entity_active_request(
"EntityActiveRequest: entity with id {} not found", "EntityActiveRequest: entity with id {} not found",
request.entity_id request.entity_id
); );
response.error_code = ErrorCode::ErrEntityNotFound.into(); // TODO: replace with appropriate error code response.error_code = ErrorCode::ErrEntityNotFound.into(); // TODO: replace with appropriate error code;
return;
}; };
} }
pub fn on_entity_on_landed_request( pub fn on_entity_on_landed_request(
_: &Player, _: &NetContext,
request: EntityOnLandedRequest, request: EntityOnLandedRequest,
_: &mut EntityOnLandedResponse, _: &mut EntityOnLandedResponse,
) { ) {
@ -69,7 +76,7 @@ pub fn on_entity_on_landed_request(
} }
pub fn on_entity_position_request( pub fn on_entity_position_request(
_: &Player, _: &NetContext,
request: EntityPositionRequest, request: EntityPositionRequest,
_: &mut EntityPositionResponse, _: &mut EntityPositionResponse,
) { ) {
@ -81,27 +88,25 @@ pub fn on_entity_position_request(
); );
} }
pub fn on_move_package_push(player: &mut Player, push: MovePackagePush) { pub fn on_move_package_push(ctx: &mut NetContext, push: MovePackagePush) {
for moving_entity in push.moving_entities { for moving_entity in push.moving_entities {
// Query components borrows world component so lets wrap it
{ {
let world_ref = player.world.borrow(); let world = ctx.world.get_world_entity();
let world = world_ref.get_world_entity();
if !world.is_in_all_world_map(moving_entity.entity_id as i32) { if !world.is_in_all_world_map(moving_entity.entity_id as i32) {
tracing::debug!( tracing::debug!(
"MovePackage: entity with id {} doesn't exist", "MovePackage: entity with id {} doesn't exist",
moving_entity.entity_id moving_entity.entity_id
); );
continue; continue;
} }
let Some(mut movement) = query_components!(world, moving_entity.entity_id, Movement).0 let Some(mut movement) = query_components!(world, moving_entity.entity_id, Movement).0
else { else {
tracing::warn!( tracing::warn!(
"MovePackage: entity {} doesn't have movement component", "MovePackage: entity {} doesn't have movement component",
moving_entity.entity_id moving_entity.entity_id
); );
continue; continue;
}; };
@ -110,24 +115,25 @@ pub fn on_move_package_push(player: &mut Player, push: MovePackagePush) {
.extend(moving_entity.move_infos); .extend(moving_entity.move_infos);
} }
let map = logic::utils::quadrant_util::get_map(player.basic_info.cur_map_id); let map = logic::utils::quadrant_util::get_map(ctx.player.basic_info.cur_map_id);
let quadrant_id = map.get_quadrant_id( let quadrant_id = map.get_quadrant_id(
player.location.position.position.x * 100.0, ctx.player.location.position.position.x * 100.0,
player.location.position.position.y * 100.0, ctx.player.location.position.position.y * 100.0,
); );
// TODO: This may require some changes for Co-Op // TODO: This may require some changes for Co-Op
if quadrant_id != player.quadrant_id { if quadrant_id != ctx.player.quadrant_id {
let (entities_to_remove, entities_to_add) = map.get_update_entities(player.quadrant_id, quadrant_id); let (entities_to_remove, entities_to_add) =
player.quadrant_id = quadrant_id; map.get_update_entities(ctx.player.quadrant_id, quadrant_id);
logic::utils::world_util::remove_entities(player, &entities_to_remove); ctx.player.quadrant_id = quadrant_id;
logic::utils::world_util::add_entities(player, &entities_to_add, false); logic::utils::world_util::remove_entities(ctx, &entities_to_remove);
logic::utils::world_util::add_entities(ctx, &entities_to_add, false);
} }
} }
} }
pub fn on_entity_access_range_request( pub fn on_entity_access_range_request(
_: &Player, _: &NetContext,
request: EntityAccessRangeRequest, request: EntityAccessRangeRequest,
response: &mut EntityAccessRangeResponse, response: &mut EntityAccessRangeResponse,
) { ) {
@ -147,26 +153,40 @@ pub fn on_entity_access_range_request(
} }
pub fn on_entity_interact_request( pub fn on_entity_interact_request(
player: &mut Player, ctx: &mut NetContext,
request: EntityInteractRequest, request: EntityInteractRequest,
response: &mut EntityInteractResponse, response: &mut EntityInteractResponse,
) { ) {
let config_id = get_config_id_from_entity_id(player, request.entity_id); let config_id = get_config_id_from_entity_id(ctx, request.entity_id);
tracing::debug!("EntityInteractRequest with ID: {} and ConfigID {}", request.entity_id, config_id); tracing::debug!(
"EntityInteractRequest with ID: {} and ConfigID {}",
request.entity_id,
config_id
);
// TODO: add cases outside LevelEntityConfig if exist // TODO: add cases outside LevelEntityConfig if exist
let Some(entity) = wicked_waifus_data::level_entity_config_data::get(player.basic_info.cur_map_id, config_id) else { let Some(entity) = wicked_waifus_data::level_entity_config_data::get(
ctx.player.basic_info.cur_map_id,
config_id,
) else {
response.error_code = ErrorCode::ErrEntityNotFound.into(); response.error_code = ErrorCode::ErrEntityNotFound.into();
return; return;
}; };
let Some(template_config) = wicked_waifus_data::template_config_data::get(&entity.blueprint_type) else { let Some(template_config) =
wicked_waifus_data::template_config_data::get(&entity.blueprint_type)
else {
response.error_code = ErrorCode::ErrEntityNotFound.into(); response.error_code = ErrorCode::ErrEntityNotFound.into();
return; return;
}; };
let Some(interact_component) = entity.components_data.interact_component.as_ref() let Some(interact_component) = entity
.or(template_config.components_data.interact_component.as_ref()).cloned() else { .components_data
.interact_component
.as_ref()
.or(template_config.components_data.interact_component.as_ref())
.cloned()
else {
response.error_code = ErrorCode::ErrInteractComponentNotExist.into(); response.error_code = ErrorCode::ErrInteractComponentNotExist.into();
return; return;
}; };
@ -179,7 +199,7 @@ pub fn on_entity_interact_request(
let mut check = true; let mut check = true;
if let Some(conditions) = option.condition { if let Some(conditions) = option.condition {
for element in conditions.conditions { for element in conditions.conditions {
check = check_condition(player, request.entity_id, &entity, template_config, element); check = check_condition(ctx, request.entity_id, entity, template_config, element);
if !check { if !check {
break; break;
} }
@ -190,7 +210,13 @@ pub fn on_entity_interact_request(
match option_type { match option_type {
OptionType::Actions(actions) => { OptionType::Actions(actions) => {
for action in actions.actions { for action in actions.actions {
perform_action(player, request.entity_id, &entity, template_config, action); perform_action(
ctx,
request.entity_id,
entity,
template_config,
action,
);
} }
} }
OptionType::Flow(_) => { OptionType::Flow(_) => {
@ -206,15 +232,16 @@ pub fn on_entity_interact_request(
} }
pub fn on_entity_follow_track_request( pub fn on_entity_follow_track_request(
player: &Player, ctx: &mut NetContext,
request: EntityFollowTrackRequest, request: EntityFollowTrackRequest,
response: &mut EntityFollowTrackResponse, response: &mut EntityFollowTrackResponse,
) { ) {
let config_id = get_config_id_from_entity_id(player, request.entity_id); let config_id = get_config_id_from_entity_id(ctx, request.entity_id);
let position = { let position = {
let world_ref = player.world.borrow(); let world = ctx.world.get_world_entity();
let world = world_ref.get_world_entity(); let position = query_components!(world, request.entity_id, Position)
let position = query_components!(world, request.entity_id, Position).0.unwrap(); .0
.unwrap();
position.0.clone() position.0.clone()
}; };
tracing::debug!( tracing::debug!(
@ -226,17 +253,19 @@ pub fn on_entity_follow_track_request(
} }
pub fn on_get_reward_treasure_box_request( pub fn on_get_reward_treasure_box_request(
player: &Player, ctx: &NetContext,
request: GetRewardTreasureBoxRequest, request: GetRewardTreasureBoxRequest,
_response: &mut GetRewardTreasureBoxResponse, _response: &mut GetRewardTreasureBoxResponse,
) { ) {
let config_id = get_config_id_from_entity_id(player, request.entity_id); let config_id = get_config_id_from_entity_id(ctx, request.entity_id);
tracing::debug!("GetRewardTreasureBoxRequest with ID: {} and ConfigID {config_id}", request.entity_id); tracing::debug!(
"GetRewardTreasureBoxRequest with ID: {} and ConfigID {config_id}",
request.entity_id
);
} }
fn get_config_id_from_entity_id(player: &Player, entity_id: i64) -> i64 { fn get_config_id_from_entity_id(ctx: &NetContext, entity_id: i64) -> i64 {
let world_ref = player.world.borrow(); let world = ctx.world.get_world_entity();
let world = world_ref.get_world_entity();
let entity_config = query_components!(world, entity_id, EntityConfig).0.unwrap(); let entity_config = query_components!(world, entity_id, EntityConfig).0.unwrap();
entity_config.config_id as i64 entity_config.config_id as i64
} }

View file

@ -1,11 +1,11 @@
use crate::logic::player::Player; use crate::logic::thread_mgr::NetContext;
use wicked_waifus_protocol::{ use wicked_waifus_protocol::{
ErrorCode, FriendAllRequest, FriendAllResponse, FriendInfo, PlayerBasicInfoGetRequest, ErrorCode, FriendAllRequest, FriendAllResponse, FriendInfo, PlayerBasicInfoGetRequest,
PlayerBasicInfoGetResponse, PlayerDetails, PlayerBasicInfoGetResponse, PlayerDetails,
}; };
pub fn on_friend_all_request( pub fn on_friend_all_request(
_player: &Player, _ctx: &NetContext,
_: FriendAllRequest, _: FriendAllRequest,
response: &mut FriendAllResponse, response: &mut FriendAllResponse,
) { ) {
@ -23,7 +23,7 @@ pub fn on_friend_all_request(
} }
// pub fn on_friend_apply_send_request( // pub fn on_friend_apply_send_request(
// _player: &Player, // _ctx: &NetContext,
// _request: FriendApplySendRequest, // _request: FriendApplySendRequest,
// _response: &mut FriendApplySendResponse, // _response: &mut FriendApplySendResponse,
// ) { // ) {
@ -31,7 +31,7 @@ pub fn on_friend_all_request(
// } // }
// //
// pub fn on_friend_recently_team_request( // pub fn on_friend_recently_team_request(
// _player: &Player, // _ctx: &NetContext,
// _request: FriendRecentlyTeamRequest, // _request: FriendRecentlyTeamRequest,
// _response: &mut FriendRecentlyTeamResponse, // _response: &mut FriendRecentlyTeamResponse,
// ) { // ) {
@ -39,7 +39,7 @@ pub fn on_friend_all_request(
// } // }
pub fn on_player_basic_info_get_request( pub fn on_player_basic_info_get_request(
_player: &Player, _ctx: &NetContext,
request: PlayerBasicInfoGetRequest, request: PlayerBasicInfoGetRequest,
response: &mut PlayerBasicInfoGetResponse, response: &mut PlayerBasicInfoGetResponse,
) { ) {

View file

@ -2,31 +2,35 @@ use std::collections::HashMap;
use std::sync::{Mutex, OnceLock}; use std::sync::{Mutex, OnceLock};
use std::time::UNIX_EPOCH; use std::time::UNIX_EPOCH;
use wicked_waifus_data::{gacha_pool_data, gacha_view_info_data, GachaPoolData, text_map_data};
use wicked_waifus_data::GachaViewTypeInfoId::{BeginnersChoiceConvene, NoviceConvene};
use wicked_waifus_protocol::{ErrorCode, GachaConsume, GachaInfo, GachaInfoRequest, GachaInfoResponse,
GachaPoolInfo, GachaRequest, GachaResponse, GachaResult, GachaReward,
GachaUsePoolRequest, GachaUsePoolResponse, WeaponItem};
use crate::logic::gacha::gacha_pool::GachaPool; use crate::logic::gacha::gacha_pool::GachaPool;
use crate::logic::gacha::pool_info::PoolInfo; use crate::logic::gacha::pool_info::PoolInfo;
use crate::logic::gacha::service::GachaService; use crate::logic::gacha::service::GachaService;
use crate::logic::player::Player; use crate::logic::player::Player;
use crate::logic::thread_mgr::NetContext;
use wicked_waifus_data::gacha_pool_data::GachaPoolData;
use wicked_waifus_data::gacha_view_info_data::GachaViewTypeInfoId::{
BeginnersChoiceConvene, NoviceConvene,
};
use wicked_waifus_data::{gacha_pool_data, gacha_view_info_data, text_map_data};
use wicked_waifus_protocol::{
ErrorCode, GachaConsume, GachaInfo, GachaInfoRequest, GachaInfoResponse, GachaPoolInfo,
GachaRequest, GachaResponse, GachaResult, GachaReward, GachaUsePoolRequest,
GachaUsePoolResponse, WeaponItem,
};
static GACHA_SERVICE: OnceLock<Mutex<GachaService>> = OnceLock::new(); static GACHA_SERVICE: OnceLock<Mutex<GachaService>> = OnceLock::new();
pub fn on_gacha_request( pub fn on_gacha_request(ctx: &mut NetContext, request: GachaRequest, response: &mut GachaResponse) {
player: &mut Player, let mut gacha_service = GACHA_SERVICE
request: GachaRequest, .get_or_init(|| Mutex::new(GachaService::new()))
response: &mut GachaResponse, .lock()
) { .unwrap();
let mut gacha_service = GACHA_SERVICE.get_or_init(|| Mutex::new(GachaService::new())).lock().unwrap();
// TODO: ensure we have enough elements before pulling // TODO: ensure we have enough elements before pulling
match gacha_service.pull(player, request.gacha_id, request.gacha_times) { match gacha_service.pull(ctx.player, request.gacha_id, request.gacha_times) {
Ok(results) => { Ok(results) => {
match consume_tides(player, request.gacha_id, request.gacha_times) { match consume_tides(ctx.player, request.gacha_id, request.gacha_times) {
Ok(_) => { Ok(_) => {
let _summary = process_gacha_results(&results); let _summary = process_gacha_results(&results);
//update_player_inventory(player, summary); //update_player_inventory(player, summary);
@ -48,20 +52,22 @@ pub fn on_gacha_request(
} }
pub fn on_gacha_info_request( pub fn on_gacha_info_request(
_player: &Player, _ctx: &NetContext,
request: GachaInfoRequest, request: GachaInfoRequest,
response: &mut GachaInfoResponse, response: &mut GachaInfoResponse,
) { ) {
tracing::debug!("received gacha request for language: {}", request.language); tracing::debug!("received gacha request for language: {}", request.language);
let text_map = text_map_data::get_textmap(request.language); let text_map = text_map_data::get_textmap(request.language);
let gacha_service = GACHA_SERVICE.get_or_init(|| Mutex::new(GachaService::new())).lock().unwrap(); let gacha_service = GACHA_SERVICE
.get_or_init(|| Mutex::new(GachaService::new()))
.lock()
.unwrap();
let active_pools = gacha_service.get_active_pools(); let active_pools = gacha_service.get_active_pools();
response.gacha_infos = active_pools.into_iter() response.gacha_infos = active_pools
.filter_map(|(pool_id, pool)| { .into_iter()
create_gacha_info(pool_id, pool, text_map) .filter_map(|(pool_id, pool)| create_gacha_info(pool_id, pool, text_map))
})
.collect(); .collect();
response.error_code = ErrorCode::Success.into(); response.error_code = ErrorCode::Success.into();
@ -73,7 +79,7 @@ pub fn on_gacha_info_request(
} }
pub fn on_gacha_use_pool_request( pub fn on_gacha_use_pool_request(
_player: &Player, _ctx: &NetContext,
_request: GachaUsePoolRequest, _request: GachaUsePoolRequest,
response: &mut GachaUsePoolResponse, response: &mut GachaUsePoolResponse,
) { ) {
@ -81,9 +87,11 @@ pub fn on_gacha_use_pool_request(
response.error_code = ErrorCode::Success.into(); response.error_code = ErrorCode::Success.into();
} }
fn create_gacha_info(pool_id: i32, fn create_gacha_info(
pool: &GachaPool, pool_id: i32,
textmap: &HashMap<String, String>) -> Option<GachaInfo> { pool: &GachaPool,
textmap: &HashMap<String, String>,
) -> Option<GachaInfo> {
let pools: Vec<GachaPoolInfo> = gacha_pool_data::iter() let pools: Vec<GachaPoolInfo> = gacha_pool_data::iter()
.filter(|p| p.gacha_id == pool_id) .filter(|p| p.gacha_id == pool_id)
.filter_map(|p| create_pool_info(p, &pool.info, textmap)) .filter_map(|p| create_pool_info(p, &pool.info, textmap))
@ -103,8 +111,15 @@ fn create_gacha_info(pool_id: i32,
gacha_consumes, gacha_consumes,
use_pool_id: pools[0].id, use_pool_id: pools[0].id,
pools, pools,
begin_time: pool.info.start_time.duration_since(UNIX_EPOCH).unwrap().as_secs() as i64, begin_time: pool
end_time: pool.info.end_time.map_or(0, |end_time| end_time.duration_since(UNIX_EPOCH).unwrap().as_secs() as i64), .info
.start_time
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs() as i64,
end_time: pool.info.end_time.map_or(0, |end_time| {
end_time.duration_since(UNIX_EPOCH).unwrap().as_secs() as i64
}),
daily_limit_times: pool.info.daily_limit, daily_limit_times: pool.info.daily_limit,
total_limit_times: pool.info.total_limit, total_limit_times: pool.info.total_limit,
resources_id: pool.info.resources_id().to_string(), resources_id: pool.info.resources_id().to_string(),
@ -121,29 +136,51 @@ fn create_pool_info(
// TODO: debug textmap logic // TODO: debug textmap logic
gacha_view_info_data::iter() gacha_view_info_data::iter()
.find(|view| view.id == pool.id) .find(|view| view.id == pool.id)
.map(|view| { .map(|view| GachaPoolInfo {
GachaPoolInfo { id: pool.id,
id: pool.id, begin_time: pool_info
begin_time: pool_info.start_time.duration_since(UNIX_EPOCH).unwrap().as_secs() as i64, .start_time
end_time: pool_info.end_time.map_or(0, |end_time| end_time.duration_since(UNIX_EPOCH).unwrap().as_secs() as i64), .duration_since(UNIX_EPOCH)
title: textmap.get(&view.summary_title).unwrap_or(&view.summary_title).to_string(), .unwrap()
description: textmap.get(&view.summary_describe).unwrap_or(&view.summary_describe).to_string(), .as_secs() as i64,
ui_type: view.r#type as i32, end_time: pool_info.end_time.map_or(0, |end_time| {
theme_color: view.theme_color.clone(), end_time.duration_since(UNIX_EPOCH).unwrap().as_secs() as i64
show_id_list: view.show_id_list.clone(), }),
up_list: view.up_list.clone(), title: textmap
preview_id_list: view.preview_id_list.clone(), .get(&view.summary_title)
} .unwrap_or(&view.summary_title)
.to_string(),
description: textmap
.get(&view.summary_describe)
.unwrap_or(&view.summary_describe)
.to_string(),
ui_type: view.r#type as i32,
theme_color: view.theme_color.clone(),
show_id_list: view.show_id_list.clone(),
up_list: view.up_list.clone(),
preview_id_list: view.preview_id_list.clone(),
}) })
} }
fn handle_gacha_consumes(pool_info: &PoolInfo) -> Vec<GachaConsume> { fn handle_gacha_consumes(pool_info: &PoolInfo) -> Vec<GachaConsume> {
match (pool_info.pool_type, pool_info.pool_id) { match (pool_info.pool_type, pool_info.pool_id) {
(NoviceConvene, _) => vec![GachaConsume { times: 10, consume: 0 }], // 8 (NoviceConvene, _) => vec![GachaConsume {
(BeginnersChoiceConvene, 51..56) => vec![GachaConsume { times: 1, consume: 0 }], // 1, times: 10,
consume: 0,
}], // 8
(BeginnersChoiceConvene, 51..56) => vec![GachaConsume {
times: 1,
consume: 0,
}], // 1,
(_, _) => vec![ (_, _) => vec![
GachaConsume { times: 1, consume: 0 }, // 1 GachaConsume {
GachaConsume { times: 10, consume: 0 }, // 10 times: 1,
consume: 0,
}, // 1
GachaConsume {
times: 10,
consume: 0,
}, // 10
], ],
} }
} }
@ -214,9 +251,9 @@ fn consume_tides(_player: &mut Player, pool_id: i32, pull_count: i32) -> Result<
(50001, discounted_cost) (50001, discounted_cost)
} }
2 | 31..=35 | 41..=45 => (50001, pull_count), // Standard, permanent weapon, and beginner character -> Lustrous Tide 2 | 31..=35 | 41..=45 => (50001, pull_count), // Standard, permanent weapon, and beginner character -> Lustrous Tide
100001..=100100 => (50002, pull_count), // Character -> Radiant Tide 100001..=100100 => (50002, pull_count), // Character -> Radiant Tide
200001..=200100 => (50005, pull_count), // Weapon -> Forging Tide 200001..=200100 => (50005, pull_count), // Weapon -> Forging Tide
51..56 => (50006, pull_count), // Special -> Voucher of Reciprocal Tides 51..56 => (50006, pull_count), // Special -> Voucher of Reciprocal Tides
_ => return Err(ErrorCode::ErrGachaPoolConfigNotFound), _ => return Err(ErrorCode::ErrGachaPoolConfigNotFound),
}; };
@ -228,4 +265,4 @@ fn consume_tides(_player: &mut Player, pool_id: i32, pull_count: i32) -> Result<
//player.remove_item(currency_id, actual_cost); //player.remove_item(currency_id, actual_cost);
Ok(()) Ok(())
} }

View file

@ -1,51 +1,54 @@
use wicked_waifus_protocol::{ErrorCode, GuideFinishRequest, GuideFinishResponse, GuideInfoRequest, GuideInfoResponse, GuideTriggerRequest, GuideTriggerResponse};
use crate::logic::player::Player; use crate::logic::player::Player;
use crate::logic::thread_mgr::NetContext;
use wicked_waifus_protocol::{
ErrorCode, GuideFinishRequest, GuideFinishResponse, GuideInfoRequest, GuideInfoResponse,
GuideTriggerRequest, GuideTriggerResponse,
};
pub fn on_guide_info_request( pub fn on_guide_info_request(
player: &Player, ctx: &NetContext,
_: GuideInfoRequest, _: GuideInfoRequest,
response: &mut GuideInfoResponse, response: &mut GuideInfoResponse,
) { ) {
response.guide_group_finish_list = player.guides.finished_guides.iter() response.guide_group_finish_list = ctx.player.guides.finished_guides.iter().cloned().collect();
.cloned()
.collect();
} }
pub fn on_guide_trigger_request( pub fn on_guide_trigger_request(
player: &mut Player, ctx: &mut NetContext,
request: GuideTriggerRequest, request: GuideTriggerRequest,
response: &mut GuideTriggerResponse, response: &mut GuideTriggerResponse,
) { ) {
response.error_code = check_if_guide_exists_and_is_repeatable(player, request.group_id); response.error_code = check_if_guide_exists_and_is_repeatable(ctx.player, request.group_id);
if response.error_code == <ErrorCode as Into<i32>>::into(ErrorCode::Success) { if response.error_code == <ErrorCode as Into<i32>>::into(ErrorCode::Success) {
// TODO: We need to check if guide can be repeated or not // TODO: We need to check if guide can be repeated or not
// if player.guides.started_guides.contains(&request.group_id) { // if player.guides.started_guides.contains(&request.group_id) {
// response.error_code = ErrorCode::GuideGroupDoing.into(); // response.error_code = ErrorCode::GuideGroupDoing.into();
// return; // return;
// } // }
player.guides.started_guides.insert(request.group_id); ctx.player.guides.started_guides.insert(request.group_id);
} }
} }
pub fn on_guide_finish_request( pub fn on_guide_finish_request(
player: &mut Player, ctx: &mut NetContext,
request: GuideFinishRequest, request: GuideFinishRequest,
response: &mut GuideFinishResponse, response: &mut GuideFinishResponse,
) { ) {
response.error_code = check_if_guide_exists_and_is_repeatable(player, request.group_id); response.error_code = check_if_guide_exists_and_is_repeatable(ctx.player, request.group_id);
if response.error_code == <ErrorCode as Into<i32>>::into(ErrorCode::Success) { if response.error_code == <ErrorCode as Into<i32>>::into(ErrorCode::Success) {
if !player.guides.started_guides.contains(&request.group_id) { if !ctx.player.guides.started_guides.contains(&request.group_id) {
response.error_code = ErrorCode::GuideGroupNoClient.into(); response.error_code = ErrorCode::GuideGroupNoClient.into();
return; return;
} }
player.guides.started_guides.remove(&request.group_id); ctx.player.guides.started_guides.remove(&request.group_id);
player.guides.finished_guides.insert(request.group_id); ctx.player.guides.finished_guides.insert(request.group_id);
} }
} }
fn check_if_guide_exists_and_is_repeatable(player: &Player, guide_id: i32) -> i32 { fn check_if_guide_exists_and_is_repeatable(player: &Player, guide_id: i32) -> i32 {
let Some(guide) = wicked_waifus_data::guide_group_data::iter().find(|guide| guide.id == guide_id) else { let Some(guide) =
wicked_waifus_data::guide_group_data::iter().find(|guide| guide.id == guide_id)
else {
return ErrorCode::GuideGroupIdNoMatch.into(); return ErrorCode::GuideGroupIdNoMatch.into();
}; };
// TODO: We need to check if guide can be repeated or not // TODO: We need to check if guide can be repeated or not
@ -53,4 +56,4 @@ fn check_if_guide_exists_and_is_repeatable(player: &Player, guide_id: i32) -> i3
return ErrorCode::GuideGroupIsNotRepeat.into(); return ErrorCode::GuideGroupIsNotRepeat.into();
} }
ErrorCode::Success.into() ErrorCode::Success.into()
} }

View file

@ -1,35 +1,48 @@
use wicked_waifus_protocol::{ItemExchangeInfo, ItemExchangeInfoRequest, ItemExchangeInfoResponse, NormalItemRequest, NormalItemResponse, PhantomItemRequest, PhantomItemResponse, WeaponItemRequest, WeaponItemResponse}; use crate::logic::thread_mgr::NetContext;
use wicked_waifus_protocol::{
use crate::logic::player::Player; ItemExchangeInfo, ItemExchangeInfoRequest, ItemExchangeInfoResponse, NormalItemRequest,
NormalItemResponse, PhantomItemRequest, PhantomItemResponse, WeaponItemRequest,
WeaponItemResponse,
};
pub fn on_normal_item_request( pub fn on_normal_item_request(
player: &mut Player, ctx: &NetContext,
_: NormalItemRequest, _: NormalItemRequest,
response: &mut NormalItemResponse, response: &mut NormalItemResponse,
) { ) {
tracing::debug!("Received NormalItemRequest, returning player inventory"); tracing::debug!("Received NormalItemRequest, returning player inventory");
response.normal_item_list = player.inventory.to_normal_item_list(); response.normal_item_list = ctx.player.inventory.to_normal_item_list();
} }
pub fn on_weapon_item_request( pub fn on_weapon_item_request(
player: &mut Player, ctx: &NetContext,
_: WeaponItemRequest, _: WeaponItemRequest,
response: &mut WeaponItemResponse, response: &mut WeaponItemResponse,
) { ) {
response.weapon_item_list = player.inventory.to_weapon_item_list(); response.weapon_item_list = ctx.player.inventory.to_weapon_item_list();
} }
pub fn on_phantom_item_request( pub fn on_phantom_item_request(
_player: &mut Player, ctx: &mut NetContext,
_: PhantomItemRequest, _: PhantomItemRequest,
_response: &mut PhantomItemResponse, response: &mut PhantomItemResponse,
) { ) {
// TODO: Implement this let (items, equip_info, prop_info) = ctx.player.inventory.get_echoes_list();
tracing::warn!("Unhandled PhantomItemRequest"); response.phantom_item_list = items;
response.equip_info_list = equip_info;
response.ows = prop_info;
response.max_cost = 8; // TODO: Max cost from calabash
response.phantom_skin_list = ctx
.player
.unlocked_skins
.echo_skins
.iter()
.copied()
.collect();
} }
pub fn on_item_exchange_info_request( pub fn on_item_exchange_info_request(
_player: &mut Player, _ctx: &mut NetContext,
_: ItemExchangeInfoRequest, _: ItemExchangeInfoRequest,
response: &mut ItemExchangeInfoResponse, response: &mut ItemExchangeInfoResponse,
) { ) {

View file

@ -1,9 +1,9 @@
use wicked_waifus_protocol::{LordGymInfoRequest, LordGymInfoResponse}; use wicked_waifus_protocol::{LordGymInfoRequest, LordGymInfoResponse};
use crate::logic::player::Player; use crate::logic::thread_mgr::NetContext;
pub fn on_lord_gym_info_request( pub fn on_lord_gym_info_request(
_player: &Player, _ctx: &NetContext,
request: LordGymInfoRequest, request: LordGymInfoRequest,
_response: &mut LordGymInfoResponse, _response: &mut LordGymInfoResponse,
) { ) {

View file

@ -1,9 +1,9 @@
use wicked_waifus_protocol::{MailBind, MailBindInfoRequest, MailBindInfoResponse}; use wicked_waifus_protocol::{MailBind, MailBindInfoRequest, MailBindInfoResponse};
use crate::logic::player::Player; use crate::logic::thread_mgr::NetContext;
pub fn on_mail_bind_info_request( pub fn on_mail_bind_info_request(
_: &Player, _: &NetContext,
_: MailBindInfoRequest, _: MailBindInfoRequest,
response: &mut MailBindInfoResponse, response: &mut MailBindInfoResponse,
) { ) {

View file

@ -6,10 +6,10 @@ use wicked_waifus_protocol::{
PlayerAccessEffectAreaResponse, PlayerAccessEffectAreaResponse,
}; };
use crate::logic::player::Player; use crate::logic::thread_mgr::NetContext;
pub fn on_dark_coast_delivery_request( pub fn on_dark_coast_delivery_request(
_player: &mut Player, _ctx: &mut NetContext,
request: DarkCoastDeliveryRequest, request: DarkCoastDeliveryRequest,
response: &mut DarkCoastDeliveryResponse, response: &mut DarkCoastDeliveryResponse,
) { ) {
@ -40,36 +40,36 @@ pub fn on_dark_coast_delivery_request(
} }
pub fn on_map_cancel_trace_request( pub fn on_map_cancel_trace_request(
player: &mut Player, ctx: &mut NetContext,
request: MapCancelTraceRequest, request: MapCancelTraceRequest,
response: &mut MapCancelTraceResponse, response: &mut MapCancelTraceResponse,
) { ) {
player.map_trace.traces.remove(&request.mark_id); ctx.player.map_trace.traces.remove(&request.mark_id);
response.mark_id = request.mark_id; response.mark_id = request.mark_id;
response.error_code = ErrorCode::Success.into(); response.error_code = ErrorCode::Success.into();
} }
pub fn on_map_trace_request( pub fn on_map_trace_request(
player: &mut Player, ctx: &mut NetContext,
request: MapTraceRequest, request: MapTraceRequest,
response: &mut MapTraceResponse, response: &mut MapTraceResponse,
) { ) {
player.map_trace.traces.insert(request.mark_id); ctx.player.map_trace.traces.insert(request.mark_id);
response.mark_id = request.mark_id; response.mark_id = request.mark_id;
response.error_code = ErrorCode::Success.into(); response.error_code = ErrorCode::Success.into();
} }
pub fn on_map_trace_info_request( pub fn on_map_trace_info_request(
player: &Player, ctx: &NetContext,
_: MapTraceInfoRequest, _: MapTraceInfoRequest,
response: &mut MapTraceInfoResponse, response: &mut MapTraceInfoResponse,
) { ) {
response.mark_id_list = player.map_trace.traces.iter().cloned().collect(); response.mark_id_list = ctx.player.map_trace.traces.iter().cloned().collect();
response.error_code = ErrorCode::Success.into(); response.error_code = ErrorCode::Success.into();
} }
pub fn on_map_unlock_field_info_request( pub fn on_map_unlock_field_info_request(
_player: &mut Player, _ctx: &NetContext,
_: MapUnlockFieldInfoRequest, _: MapUnlockFieldInfoRequest,
response: &mut MapUnlockFieldInfoResponse, response: &mut MapUnlockFieldInfoResponse,
) { ) {
@ -81,7 +81,7 @@ pub fn on_map_unlock_field_info_request(
} }
pub fn on_player_access_effect_area_request( pub fn on_player_access_effect_area_request(
_player: &Player, _ctx: &NetContext,
request: PlayerAccessEffectAreaRequest, request: PlayerAccessEffectAreaRequest,
response: &mut PlayerAccessEffectAreaResponse, response: &mut PlayerAccessEffectAreaResponse,
) { ) {

View file

@ -1,28 +1,32 @@
use wicked_waifus_protocol::{ErrorCode, InputSettingRequest, InputSettingResponse, InputSettingUpdateRequest, InputSettingUpdateResponse, LanguageSettingUpdateRequest, LanguageSettingUpdateResponse, MonthCardRequest, MonthCardResponse, ServerPlayStationPlayOnlyStateRequest, ServerPlayStationPlayOnlyStateResponse, UpdateVoxelEnvRequest, UpdateVoxelEnvResponse, VersionInfoPush, WebSignRequest, WebSignResponse, Zih}; use wicked_waifus_protocol::{
ErrorCode, InputSettingRequest, InputSettingResponse, InputSettingUpdateRequest,
InputSettingUpdateResponse, LanguageSettingUpdateRequest, LanguageSettingUpdateResponse,
MonthCardRequest, MonthCardResponse, ServerPlayStationPlayOnlyStateRequest,
ServerPlayStationPlayOnlyStateResponse, UpdateVoxelEnvRequest, UpdateVoxelEnvResponse,
VersionInfoPush, WebSignRequest, WebSignResponse, Zih,
};
use crate::logic::player::Player; use crate::logic::thread_mgr::NetContext;
pub fn on_month_card_request( pub fn on_month_card_request(
player: &mut Player, ctx: &mut NetContext,
_: MonthCardRequest, _: MonthCardRequest,
response: &mut MonthCardResponse, response: &mut MonthCardResponse,
) { ) {
// TODO: Check if we should send MonthCardUseNotify // TODO: Check if we should send MonthCardUseNotify
response.days = player.month_card.days; response.days = ctx.player.month_card.days;
response.is_daily_got = wicked_waifus_commons::time_util::unix_days() == player.month_card.last_received_day; response.is_daily_got =
wicked_waifus_commons::time_util::unix_days() == ctx.player.month_card.last_received_day;
response.error_code = ErrorCode::Success.into(); response.error_code = ErrorCode::Success.into();
} }
pub fn on_web_sign_request( pub fn on_web_sign_request(_: &mut NetContext, _: WebSignRequest, response: &mut WebSignResponse) {
_: &mut Player, response.notice_sign =
_: WebSignRequest, "Welcome to Wicked Waifus PS provided by Reversed Rooms Dev Team".to_string();
response: &mut WebSignResponse,
) {
response.notice_sign = "Welcome to Wicked Waifus PS provided by Reversed Rooms Dev Team".to_string();
} }
pub fn on_input_setting_request( pub fn on_input_setting_request(
_: &Player, _: &NetContext,
_: InputSettingRequest, _: InputSettingRequest,
response: &mut InputSettingResponse, response: &mut InputSettingResponse,
) { ) {
@ -30,7 +34,7 @@ pub fn on_input_setting_request(
} }
pub fn on_input_setting_update_request( pub fn on_input_setting_update_request(
_: &Player, _: &NetContext,
_: InputSettingUpdateRequest, _: InputSettingUpdateRequest,
response: &mut InputSettingUpdateResponse, response: &mut InputSettingUpdateResponse,
) { ) {
@ -38,7 +42,7 @@ pub fn on_input_setting_update_request(
} }
pub fn on_language_setting_update_request( pub fn on_language_setting_update_request(
_: &Player, _: &NetContext,
_: LanguageSettingUpdateRequest, _: LanguageSettingUpdateRequest,
response: &mut LanguageSettingUpdateResponse, response: &mut LanguageSettingUpdateResponse,
) { ) {
@ -46,14 +50,14 @@ pub fn on_language_setting_update_request(
} }
pub fn on_server_play_station_play_only_state_request( pub fn on_server_play_station_play_only_state_request(
_: &Player, _: &NetContext,
_: ServerPlayStationPlayOnlyStateRequest, _: ServerPlayStationPlayOnlyStateRequest,
response: &mut ServerPlayStationPlayOnlyStateResponse, response: &mut ServerPlayStationPlayOnlyStateResponse,
) { ) {
response.cross_play_enabled = false; response.cross_play_enabled = false;
} }
pub fn on_version_info_push(_player: &Player, push: VersionInfoPush) { pub fn on_version_info_push(_player: &NetContext, push: VersionInfoPush) {
// TODO: Shall we do safety check and ensure we have compatible versions? // TODO: Shall we do safety check and ensure we have compatible versions?
tracing::debug!( tracing::debug!(
"Client versions: launcher: {}, app: {}, resources: {}", "Client versions: launcher: {}, app: {}, resources: {}",
@ -64,7 +68,7 @@ pub fn on_version_info_push(_player: &Player, push: VersionInfoPush) {
} }
pub fn on_update_voxel_env_request( pub fn on_update_voxel_env_request(
_: &Player, _: &NetContext,
request: UpdateVoxelEnvRequest, request: UpdateVoxelEnvRequest,
response: &mut UpdateVoxelEnvResponse, response: &mut UpdateVoxelEnvResponse,
) { ) {

View file

@ -45,7 +45,7 @@ mod weapon;
macro_rules! handle_request { macro_rules! handle_request {
($($name:ident $(, $inner_package:ident)?;)*) => { ($($name:ident $(, $inner_package:ident)?;)*) => {
fn handle_request(player: &mut super::player::Player, mut msg: Message) { fn handle_request(ctx: &mut super::thread_mgr::NetContext, mut msg: Message) {
use ::wicked_waifus_protocol::{MessageID, Protobuf}; use ::wicked_waifus_protocol::{MessageID, Protobuf};
::paste::paste! { ::paste::paste! {
@ -53,16 +53,16 @@ macro_rules! handle_request {
$( $(
::wicked_waifus_protocol::$($inner_package::)?[<$name Request>]::MESSAGE_ID => { ::wicked_waifus_protocol::$($inner_package::)?[<$name Request>]::MESSAGE_ID => {
let Ok(request) = ::wicked_waifus_protocol::$($inner_package::)?[<$name Request>]::decode(&*msg.remove_payload()) else { let Ok(request) = ::wicked_waifus_protocol::$($inner_package::)?[<$name Request>]::decode(&*msg.remove_payload()) else {
tracing::debug!("failed to decode {}, player_id: {}", stringify!($($inner_package::)?[<$name Request>]), player.basic_info.id); tracing::debug!("failed to decode {}, player_id: {}", stringify!($($inner_package::)?[<$name Request>]), ctx.player.basic_info.id);
return; 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(); let mut response = ::wicked_waifus_protocol::$($inner_package::)?[<$name Response>]::default();
[<on_ $($inner_package:snake _)? $name:snake _request>](player, request, &mut response); [<on_ $($inner_package:snake _)? $name:snake _request>](ctx, request, &mut response);
player.respond(response, msg.get_rpc_id()); ctx.player.respond(response, msg.get_rpc_id());
}, },
)* )*
unhandled => { unhandled => {
@ -81,7 +81,7 @@ macro_rules! handle_request {
macro_rules! handle_push { macro_rules! handle_push {
($($name:ident $(, $inner_package:ident)?;)*) => { ($($name:ident $(, $inner_package:ident)?;)*) => {
fn handle_push(player: &mut super::player::Player, mut msg: Message) { fn handle_push(ctx: &mut super::thread_mgr::NetContext, mut msg: Message) {
use ::wicked_waifus_protocol::{MessageID, Protobuf}; use ::wicked_waifus_protocol::{MessageID, Protobuf};
::paste::paste! { ::paste::paste! {
@ -89,13 +89,13 @@ macro_rules! handle_push {
$( $(
::wicked_waifus_protocol::$($inner_package::)?[<$name Push>]::MESSAGE_ID => { ::wicked_waifus_protocol::$($inner_package::)?[<$name Push>]::MESSAGE_ID => {
let Ok(push) = ::wicked_waifus_protocol::$($inner_package::)?[<$name Push>]::decode(&*msg.remove_payload()) else { let Ok(push) = ::wicked_waifus_protocol::$($inner_package::)?[<$name Push>]::decode(&*msg.remove_payload()) else {
tracing::debug!("failed to decode {}, player_id: {}", stringify!($($inner_package::)?[<$name Push>]), player.basic_info.id); tracing::debug!("failed to decode {}, player_id: {}", stringify!($($inner_package::)?[<$name Push>]), ctx.player.basic_info.id);
return; return;
}; };
tracing::debug!("logic: processing push {}", stringify!($($inner_package::)?[<$name Push>])); tracing::debug!("logic: processing push {}", stringify!($($inner_package::)?[<$name Push>]));
[<on_ $($inner_package:snake _)? $name:snake _push>](player, push); [<on_ $($inner_package:snake _)? $name:snake _push>](ctx, push);
}, },
)* )*
unhandled => { unhandled => {
@ -297,15 +297,15 @@ handle_push! {
VersionInfo; VersionInfo;
} }
pub fn handle_logic_message(player: &mut super::player::Player, msg: Message) { pub fn handle_logic_message(ctx: &mut super::thread_mgr::NetContext, msg: Message) {
match msg { match msg {
Message::Request { .. } => handle_request(player, msg), Message::Request { .. } => handle_request(ctx, msg),
Message::Push { .. } => handle_push(player, msg), Message::Push { .. } => handle_push(ctx, msg),
_ => tracing::warn!( _ => tracing::warn!(
"handle_logic_message: wrong message type: {}, message_id: {}, player_id: {}", "handle_logic_message: wrong message type: {}, message_id: {}, player_id: {}",
msg.get_message_type(), msg.get_message_type(),
msg.get_message_id(), msg.get_message_id(),
player.basic_info.id, ctx.player.basic_info.id,
), ),
} }
} }

View file

@ -2,21 +2,35 @@ use std::collections::HashSet;
use crate::logic::components::{ParaglidingSkin, RoleSkin, SoarWingSkin, WeaponSkin}; use crate::logic::components::{ParaglidingSkin, RoleSkin, SoarWingSkin, WeaponSkin};
use crate::logic::ecs::component::ComponentContainer; use crate::logic::ecs::component::ComponentContainer;
use crate::logic::player::{ItemUsage, Player}; use crate::logic::player::ItemUsage;
use crate::logic::role::{Role, RoleFormation}; use crate::logic::role::{Role, RoleFormation};
use crate::logic::thread_mgr::NetContext;
use crate::modify_component; use crate::modify_component;
use wicked_waifus_protocol::{ArrayIntInt, ClientCurrentRoleReportRequest, ClientCurrentRoleReportResponse, ERemoveEntityType, EntityAddNotify, EntityEquipSkinChangeNotify, EntityFlySkinChangeData, EntityPb, EntityRemoveInfo, EntityRemoveNotify, EquipFlySkinData, ErrorCode, FlySkinConfigData, FlySkinWearAllRoleRequest, FlySkinWearAllRoleResponse, FlySkinWearRequest, FlySkinWearResponse, FormationAttrRequest, FormationAttrResponse, PbUpLevelRoleRequest, PbUpLevelRoleResponse, PlayerMotionRequest, PlayerMotionResponse, RoleBreakThroughViewRequest, RoleBreakThroughViewResponse, RoleFavorListRequest, RoleFavorListResponse, RoleFlyEquipChangeNotify, RoleLevelUpViewRequest, RoleLevelUpViewResponse, RoleShowListUpdateRequest, RoleShowListUpdateResponse, RoleSkinChangeRequest, RoleSkinChangeResponse, SoarWingOrParaglidingSkinChangeNotify, UnlockRoleSkinListRequest, UnlockRoleSkinListResponse, UpdateFormationRequest, UpdateFormationResponse, WeaponSkinComponentPb}; use wicked_waifus_protocol::{
ArrayIntInt, ClientCurrentRoleReportRequest, ClientCurrentRoleReportResponse,
ERemoveEntityType, EntityAddNotify, EntityEquipSkinChangeNotify, EntityFlySkinChangeData,
EntityPb, EntityRemoveInfo, EntityRemoveNotify, EquipFlySkinData, ErrorCode, FlySkinConfigData,
FlySkinWearAllRoleRequest, FlySkinWearAllRoleResponse, FlySkinWearRequest, FlySkinWearResponse,
FormationAttrRequest, FormationAttrResponse, PbUpLevelRoleRequest, PbUpLevelRoleResponse,
PlayerMotionRequest, PlayerMotionResponse, RoleBreakThroughViewRequest,
RoleBreakThroughViewResponse, RoleFavorListRequest, RoleFavorListResponse,
RoleFlyEquipChangeNotify, RoleLevelUpViewRequest, RoleLevelUpViewResponse,
RoleShowListUpdateRequest, RoleShowListUpdateResponse, RoleSkinChangeRequest,
RoleSkinChangeResponse, SoarWingOrParaglidingSkinChangeNotify, UnlockRoleSkinListRequest,
UnlockRoleSkinListResponse, UpdateFormationRequest, UpdateFormationResponse,
WeaponSkinComponentPb,
};
pub fn on_role_show_list_update_request( pub fn on_role_show_list_update_request(
player: &mut Player, ctx: &mut NetContext,
request: RoleShowListUpdateRequest, request: RoleShowListUpdateRequest,
response: &mut RoleShowListUpdateResponse, response: &mut RoleShowListUpdateResponse,
) { ) {
let role_ids: HashSet<i32> = player.role_list.keys().cloned().collect(); let role_ids: HashSet<i32> = ctx.player.role_list.keys().cloned().collect();
let all_exist = request.role_list.iter().all(|id| role_ids.contains(id)); let all_exist = request.role_list.iter().all(|id| role_ids.contains(id));
if all_exist { if all_exist {
player.basic_info.role_show_list = request.role_list; ctx.player.basic_info.role_show_list = request.role_list;
response.error_code = ErrorCode::Success.into(); response.error_code = ErrorCode::Success.into();
} else { } else {
response.error_code = ErrorCode::InvalidRequest.into(); // TODO: replace with appropriate error code response.error_code = ErrorCode::InvalidRequest.into(); // TODO: replace with appropriate error code
@ -24,7 +38,7 @@ pub fn on_role_show_list_update_request(
} }
pub fn on_client_current_role_report_request( pub fn on_client_current_role_report_request(
_player: &Player, _ctx: &NetContext,
request: ClientCurrentRoleReportRequest, request: ClientCurrentRoleReportRequest,
response: &mut ClientCurrentRoleReportResponse, response: &mut ClientCurrentRoleReportResponse,
) { ) {
@ -33,7 +47,7 @@ pub fn on_client_current_role_report_request(
} }
pub fn on_role_favor_list_request( pub fn on_role_favor_list_request(
_player: &Player, _ctx: &NetContext,
_request: RoleFavorListRequest, _request: RoleFavorListRequest,
response: &mut RoleFavorListResponse, response: &mut RoleFavorListResponse,
) { ) {
@ -42,7 +56,7 @@ pub fn on_role_favor_list_request(
} }
pub fn on_formation_attr_request( pub fn on_formation_attr_request(
_player: &Player, _ctx: &NetContext,
_request: FormationAttrRequest, _request: FormationAttrRequest,
response: &mut FormationAttrResponse, response: &mut FormationAttrResponse,
) { ) {
@ -50,12 +64,11 @@ pub fn on_formation_attr_request(
} }
pub fn on_update_formation_request( pub fn on_update_formation_request(
player: &mut Player, ctx: &mut NetContext,
request: UpdateFormationRequest, request: UpdateFormationRequest,
response: &mut UpdateFormationResponse, response: &mut UpdateFormationResponse,
) { ) {
let mut world_ref = player.world.borrow_mut(); let world = ctx.world.get_mut_world_entity();
let world = world_ref.get_mut_world_entity();
for formation in request.formations { for formation in request.formations {
let formation_id = formation.formation_id; let formation_id = formation.formation_id;
@ -64,11 +77,12 @@ pub fn on_update_formation_request(
if is_current { if is_current {
// update player current formation id // update player current formation id
player.cur_formation_id = formation_id; ctx.player.cur_formation_id = formation_id;
// search old formation id and set real_formation_id, set is_current to false // search old formation id and set real_formation_id, set is_current to false
let mut real_formation_id = formation_id; let mut real_formation_id = formation_id;
if let Some(rf) = player if let Some(rf) = ctx
.player
.formation_list .formation_list
.values_mut() .values_mut()
.find(|rf| rf.is_current && rf.id != formation_id) .find(|rf| rf.is_current && rf.id != formation_id)
@ -77,7 +91,7 @@ pub fn on_update_formation_request(
rf.is_current = false; rf.is_current = false;
} }
if let Some(old_formation) = player.formation_list.get(&real_formation_id) { if let Some(old_formation) = ctx.player.formation_list.get(&real_formation_id) {
let removed_entities: Vec<i64> = old_formation let removed_entities: Vec<i64> = old_formation
.role_ids .role_ids
.iter() .iter()
@ -86,39 +100,44 @@ pub fn on_update_formation_request(
removed_entities.iter().for_each(|&entity_id| { removed_entities.iter().for_each(|&entity_id| {
world.remove_entity(entity_id as i32); world.remove_entity(entity_id as i32);
}); });
player.notify(player.build_player_entity_remove_notify( ctx.player
removed_entities, .notify(ctx.player.build_player_entity_remove_notify(
ERemoveEntityType::RemoveTypeNormal, removed_entities,
)); ERemoveEntityType::RemoveTypeNormal,
));
} }
let added_roles: Vec<Role> = formation let added_roles: Vec<&Role> = formation
.role_ids .role_ids
.iter() .iter()
.map(|&role_id| Role::new(role_id)) .map(|role_id| ctx.player.role_list.get(role_id).unwrap())
.collect(); .collect();
if !added_roles.is_empty() { if !added_roles.is_empty() {
// add new roles // add new roles
player.notify(player.build_player_entity_add_notify(added_roles, world)); ctx.player.notify(
ctx.player
.build_player_entity_add_notify(added_roles, world),
);
} }
// send update group formation notify // send update group formation notify
player.notify(player.build_update_group_formation_notify( ctx.player
RoleFormation { .notify(ctx.player.build_update_group_formation_notify(
id: formation_id, RoleFormation {
cur_role, id: formation_id,
role_ids: formation.role_ids.clone(), cur_role,
is_current, role_ids: formation.role_ids.clone(),
}, is_current,
world, },
)); world,
));
response.formation = Some(formation.clone()); response.formation = Some(formation.clone());
} }
// update all formation and check formation_list // update all formation and check formation_list
player ctx.player
.formation_list .formation_list
.entry(formation_id) .entry(formation_id)
.and_modify(|r| { .and_modify(|r| {
@ -134,13 +153,14 @@ pub fn on_update_formation_request(
}); });
} }
player.notify(player.build_update_formation_notify()); ctx.player
.notify(ctx.player.build_update_formation_notify());
response.error_code = ErrorCode::Success.into(); response.error_code = ErrorCode::Success.into();
} }
pub fn on_player_motion_request( pub fn on_player_motion_request(
_: &Player, _: &NetContext,
request: PlayerMotionRequest, request: PlayerMotionRequest,
response: &mut PlayerMotionResponse, response: &mut PlayerMotionResponse,
) { ) {
@ -151,20 +171,20 @@ pub fn on_player_motion_request(
} }
pub fn on_unlock_role_skin_list_request( pub fn on_unlock_role_skin_list_request(
player: &Player, ctx: &NetContext,
_request: UnlockRoleSkinListRequest, _request: UnlockRoleSkinListRequest,
response: &mut UnlockRoleSkinListResponse, response: &mut UnlockRoleSkinListResponse,
) { ) {
response.role_skin_list = player.unlocked_skins.role_skins.iter().cloned().collect(); response.role_skin_list = ctx.player.unlocked_skins.role_skins.iter().cloned().collect();
} }
pub fn on_role_skin_change_request( pub fn on_role_skin_change_request(
player: &mut Player, ctx: &mut NetContext,
request: RoleSkinChangeRequest, request: RoleSkinChangeRequest,
response: &mut RoleSkinChangeResponse, response: &mut RoleSkinChangeResponse,
) { ) {
// TODO: Should we verify role id first against bindata? // TODO: Should we verify role id first against bindata?
let role = player.role_list.get_mut(&request.role_id); let role = ctx.player.role_list.get_mut(&request.role_id);
let Some(role) = role else { let Some(role) = role else {
response.error_code = ErrorCode::NotValidRole.into(); response.error_code = ErrorCode::NotValidRole.into();
return; return;
@ -179,7 +199,7 @@ pub fn on_role_skin_change_request(
}; };
// Verify Skin is unlocked // Verify Skin is unlocked
if !player.unlocked_skins.role_skins.contains(&skin_data.id) { if !ctx.player.unlocked_skins.role_skins.contains(&skin_data.id) {
response.error_code = ErrorCode::ErrRoleSkinLocked.into(); response.error_code = ErrorCode::ErrRoleSkinLocked.into();
return; return;
} }
@ -198,67 +218,67 @@ pub fn on_role_skin_change_request(
} }
role.weapon_skin_id = skin_data.suit_weapon_skin_id; role.weapon_skin_id = skin_data.suit_weapon_skin_id;
} }
{
let world_ref = player.world.borrow(); let world = ctx.world.get_world_entity();
let world = world_ref.get_world_entity(); let entity_id = world.get_entity_id(request.role_id);
let entity_id = world.get_entity_id(request.role_id); modify_component!(
world.get_entity_components(entity_id as i32),
RoleSkin,
|skin_component: &mut RoleSkin| {
skin_component.skin_id = role.skin_id;
}
);
if request.is_wear_weapon_skin {
// Check for suit_weapon_skin_id == 0 has already been done
modify_component!( modify_component!(
world.get_entity_components(entity_id as i32), world.get_entity_components(entity_id as i32),
RoleSkin, WeaponSkin,
|skin_component: &mut RoleSkin| { |skin_component: &mut WeaponSkin| {
skin_component.skin_id = role.skin_id; skin_component.skin_id = skin_data.suit_weapon_skin_id;
} }
); );
if request.is_wear_weapon_skin { // Since the whole entity is recreated this shouldn't be needed but meh, whatever
// Check for suit_weapon_skin_id == 0 has already been done ctx.player.notify(EntityEquipSkinChangeNotify {
modify_component!( entity_id,
world.get_entity_components(entity_id as i32), weapon_skin_component_pb: Some(WeaponSkinComponentPb {
WeaponSkin, weapon_skin_id: skin_data.suit_weapon_skin_id,
|skin_component: &mut WeaponSkin| { }),
skin_component.skin_id = skin_data.suit_weapon_skin_id;
}
);
// Since the whole entity is recreated this shouldn't be needed but meh, whatever
player.notify(EntityEquipSkinChangeNotify {
entity_id,
weapon_skin_component_pb: Some(WeaponSkinComponentPb {
weapon_skin_id:skin_data.suit_weapon_skin_id,
}),
});
}
player.notify(EntityRemoveNotify {
remove_infos: vec![EntityRemoveInfo {
entity_id,
r#type: 0,
}],
is_remove: false,
});
let mut pb = EntityPb {
id: entity_id,
..Default::default()
};
world
.get_entity_components(entity_id as i32)
.into_iter()
.for_each(|comp| comp.set_pb_data(&mut pb));
player.notify(EntityAddNotify {
entity_pbs: vec![pb],
remove_tag_ids: false,
}); });
} }
player.notify(player.build_update_formation_notify()); ctx.player.notify(EntityRemoveNotify {
remove_infos: vec![EntityRemoveInfo {
entity_id,
r#type: 0,
}],
is_remove: false,
});
let mut pb = EntityPb {
id: entity_id,
..Default::default()
};
world
.get_entity_components(entity_id as i32)
.into_iter()
.for_each(|comp| comp.set_pb_data(&mut pb));
ctx.player.notify(EntityAddNotify {
entity_pbs: vec![pb],
remove_tag_ids: false,
});
// player.notify(player.build_update_group_formation_notify(aaa, world));
ctx.player
.notify(ctx.player.build_update_formation_notify());
response.error_code = ErrorCode::Success.into(); response.error_code = ErrorCode::Success.into();
} }
pub fn on_fly_skin_wear_request( pub fn on_fly_skin_wear_request(
player: &mut Player, ctx: &mut NetContext,
request: FlySkinWearRequest, request: FlySkinWearRequest,
response: &mut FlySkinWearResponse, response: &mut FlySkinWearResponse,
) { ) {
let role = player.role_list.get_mut(&request.role_id); let role = ctx.player.role_list.get_mut(&request.role_id);
let Some(role) = role else { let Some(role) = role else {
response.error_code = ErrorCode::NotValidRole.into(); response.error_code = ErrorCode::NotValidRole.into();
return; return;
@ -275,14 +295,14 @@ pub fn on_fly_skin_wear_request(
match skin.skin_type { match skin.skin_type {
0 => { 0 => {
// Verify Skin is unlocked // Verify Skin is unlocked
if !player.unlocked_skins.fly_skins.contains(&skin.id) { if !ctx.player.unlocked_skins.fly_skins.contains(&skin.id) {
response.error_code = ErrorCode::ErrRoleSkinLocked.into(); response.error_code = ErrorCode::ErrRoleSkinLocked.into();
return; return;
} }
role.fly_skin_id = request.skin_id role.fly_skin_id = request.skin_id
} }
1 => { 1 => {
if !player.unlocked_skins.wing_skins.contains(&skin.id) { if !ctx.player.unlocked_skins.wing_skins.contains(&skin.id) {
response.error_code = ErrorCode::ErrRoleSkinLocked.into(); response.error_code = ErrorCode::ErrRoleSkinLocked.into();
return; return;
} }
@ -293,43 +313,40 @@ pub fn on_fly_skin_wear_request(
return; return;
} }
} }
{ let world = ctx.world.get_world_entity();
let world_ref = player.world.borrow(); let entity_id = world.get_entity_id(request.role_id);
let world = world_ref.get_world_entity(); match skin.skin_type {
let entity_id = world.get_entity_id(request.role_id); 0 => {
match skin.skin_type { modify_component!(
0 => { world.get_entity_components(entity_id as i32),
modify_component!( SoarWingSkin,
world.get_entity_components(entity_id as i32), |skin_component: &mut SoarWingSkin| {
SoarWingSkin, skin_component.skin_id = role.skin_id;
|skin_component: &mut SoarWingSkin| { }
skin_component.skin_id = role.skin_id; );
}
);
}
1 => {
modify_component!(
world.get_entity_components(entity_id as i32),
ParaglidingSkin,
|skin_component: &mut ParaglidingSkin| {
skin_component.skin_id = role.skin_id;
}
);
}
_ => unreachable!("Already tested above"),
} }
player.notify(SoarWingOrParaglidingSkinChangeNotify { 1 => {
fly_skin_data: vec![EntityFlySkinChangeData { modify_component!(
entity_id, world.get_entity_components(entity_id as i32),
fly_skin_config_data: vec![FlySkinConfigData { ParaglidingSkin,
skin_id: request.skin_id, |skin_component: &mut ParaglidingSkin| {
fly_skin_id: skin.skin_type, skin_component.skin_id = role.skin_id;
}], }
}], );
}); }
_ => unreachable!("Already tested above"),
} }
ctx.player.notify(SoarWingOrParaglidingSkinChangeNotify {
fly_skin_data: vec![EntityFlySkinChangeData {
entity_id,
fly_skin_config_data: vec![FlySkinConfigData {
skin_id: request.skin_id,
fly_skin_id: skin.skin_type,
}],
}],
});
player.notify(RoleFlyEquipChangeNotify { ctx.player.notify(RoleFlyEquipChangeNotify {
fly_skin_data: vec![EquipFlySkinData { fly_skin_data: vec![EquipFlySkinData {
role_id: request.role_id, role_id: request.role_id,
skin_id: request.skin_id, skin_id: request.skin_id,
@ -339,7 +356,7 @@ pub fn on_fly_skin_wear_request(
} }
pub fn on_fly_skin_wear_all_role_request( pub fn on_fly_skin_wear_all_role_request(
player: &mut Player, ctx: &mut NetContext,
request: FlySkinWearAllRoleRequest, request: FlySkinWearAllRoleRequest,
response: &mut FlySkinWearAllRoleResponse, response: &mut FlySkinWearAllRoleResponse,
) { ) {
@ -353,20 +370,20 @@ pub fn on_fly_skin_wear_all_role_request(
match skin.skin_type { match skin.skin_type {
0 => { 0 => {
// Verify Skin is unlocked // Verify Skin is unlocked
if !player.unlocked_skins.fly_skins.contains(&skin.id) { if !ctx.player.unlocked_skins.fly_skins.contains(&skin.id) {
response.error_code = ErrorCode::ErrRoleSkinLocked.into(); response.error_code = ErrorCode::ErrRoleSkinLocked.into();
return; return;
} }
for role in player.role_list.values_mut() { for role in ctx.player.role_list.values_mut() {
role.fly_skin_id = request.skin_id; role.fly_skin_id = request.skin_id;
} }
} }
1 => { 1 => {
if !player.unlocked_skins.wing_skins.contains(&skin.id) { if !ctx.player.unlocked_skins.wing_skins.contains(&skin.id) {
response.error_code = ErrorCode::ErrRoleSkinLocked.into(); response.error_code = ErrorCode::ErrRoleSkinLocked.into();
return; return;
} }
for role in player.role_list.values_mut() { for role in ctx.player.role_list.values_mut() {
role.wing_skin_id = request.skin_id; role.wing_skin_id = request.skin_id;
} }
} }
@ -375,8 +392,9 @@ pub fn on_fly_skin_wear_all_role_request(
return; return;
} }
} }
player.notify(RoleFlyEquipChangeNotify { ctx.player.notify(RoleFlyEquipChangeNotify {
fly_skin_data: player fly_skin_data: ctx
.player
.role_list .role_list
.values() .values()
.map(|r| EquipFlySkinData { .map(|r| EquipFlySkinData {
@ -385,61 +403,59 @@ pub fn on_fly_skin_wear_all_role_request(
}) })
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
}); });
{ let world = ctx.world.get_world_entity();
let world_ref = player.world.borrow(); let data = ctx
let world = world_ref.get_world_entity(); .player
let data = player .role_list
.role_list .values()
.values() .filter_map(|role| {
.filter_map(|role| { let entity_id = world.get_entity_id(role.role_id);
let entity_id = world.get_entity_id(role.role_id); if entity_id == -1 {
if entity_id == -1 { None
None } else {
} else { match skin.skin_type {
match skin.skin_type { 0 => {
0 => { modify_component!(
modify_component!( world.get_entity_components(entity_id as i32),
world.get_entity_components(entity_id as i32), SoarWingSkin,
SoarWingSkin, |skin_component: &mut SoarWingSkin| {
|skin_component: &mut SoarWingSkin| { skin_component.skin_id = role.skin_id;
skin_component.skin_id = role.skin_id; }
} );
);
}
1 => {
modify_component!(
world.get_entity_components(entity_id as i32),
ParaglidingSkin,
|skin_component: &mut ParaglidingSkin| {
skin_component.skin_id = role.skin_id;
}
);
}
_ => unreachable!("Already tested above"),
} }
Some(EntityFlySkinChangeData { 1 => {
entity_id, modify_component!(
fly_skin_config_data: vec![FlySkinConfigData { world.get_entity_components(entity_id as i32),
skin_id: request.skin_id, ParaglidingSkin,
fly_skin_id: skin.skin_type, |skin_component: &mut ParaglidingSkin| {
}], skin_component.skin_id = role.skin_id;
}) }
);
}
_ => unreachable!("Already tested above"),
} }
}) Some(EntityFlySkinChangeData {
.collect::<Vec<_>>(); entity_id,
player.notify(SoarWingOrParaglidingSkinChangeNotify { fly_skin_config_data: vec![FlySkinConfigData {
fly_skin_data: data, skin_id: request.skin_id,
}); fly_skin_id: skin.skin_type,
} }],
})
}
})
.collect::<Vec<_>>();
ctx.player.notify(SoarWingOrParaglidingSkinChangeNotify {
fly_skin_data: data,
});
response.error_code = ErrorCode::Success.into(); response.error_code = ErrorCode::Success.into();
} }
pub fn on_role_level_up_view_request( pub fn on_role_level_up_view_request(
player: &mut Player, ctx: &mut NetContext,
request: RoleLevelUpViewRequest, request: RoleLevelUpViewRequest,
response: &mut RoleLevelUpViewResponse, response: &mut RoleLevelUpViewResponse,
) { ) {
let role = player.role_list.get(&request.role_id); let role = ctx.player.role_list.get(&request.role_id);
let Some(role) = role else { let Some(role) = role else {
response.error_code = ErrorCode::NotValidRole.into(); response.error_code = ErrorCode::NotValidRole.into();
return; return;
@ -454,24 +470,24 @@ pub fn on_role_level_up_view_request(
let items = wicked_waifus_data::role_exp_item_data::iter() let items = wicked_waifus_data::role_exp_item_data::iter()
.map(|(&id, _)| id) .map(|(&id, _)| id)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
response.item_list = player.inventory.to_array_int_int_filtered(&items); response.item_list = ctx.player.inventory.to_array_int_int_filtered(&items);
response.error_code = ErrorCode::Success.into(); response.error_code = ErrorCode::Success.into();
} }
pub fn on_pb_up_level_role_request( pub fn on_pb_up_level_role_request(
player: &mut Player, ctx: &mut NetContext,
request: PbUpLevelRoleRequest, request: PbUpLevelRoleRequest,
response: &mut PbUpLevelRoleResponse, response: &mut PbUpLevelRoleResponse,
) { ) {
response.role_id = request.role_id; response.role_id = request.role_id;
let role = player.role_list.get(&request.role_id); let role = ctx.player.role_list.get(&request.role_id);
let Some(role) = role else { let Some(role) = role else {
response.error_code = ErrorCode::NotValidRole.into(); response.error_code = ErrorCode::NotValidRole.into();
return; return;
}; };
// TODO: no shell_credit??? :turtle_skull: // TODO: no shell_credit??? :turtle_skull:
let items = player.inventory.consume_items( let items = ctx.player.inventory.consume_items(
&request &request
.item_list .item_list
.iter() .iter()
@ -525,11 +541,11 @@ pub fn on_pb_up_level_role_request(
// on_role_break_through_view_request // on_role_break_through_view_request
pub fn on_role_break_through_view_request( pub fn on_role_break_through_view_request(
player: &mut Player, ctx: &mut NetContext,
request: RoleBreakThroughViewRequest, request: RoleBreakThroughViewRequest,
response: &mut RoleBreakThroughViewResponse, response: &mut RoleBreakThroughViewResponse,
) { ) {
let role = player.role_list.get(&request.role_id); let role = ctx.player.role_list.get(&request.role_id);
let Some(role) = role else { let Some(role) = role else {
response.error_code = ErrorCode::NotValidRole.into(); response.error_code = ErrorCode::NotValidRole.into();
return; return;

View file

@ -10,10 +10,10 @@ const UID_FIX: &str = include_str!("../../../scripts/uidfix.js");
const CENSORSHIP_FIX: &str = include_str!("../../../scripts/censorshipfix.js"); const CENSORSHIP_FIX: &str = include_str!("../../../scripts/censorshipfix.js");
const DEBUG_DISABLE: &str = include_str!("../../../scripts/debug_disable.js"); const DEBUG_DISABLE: &str = include_str!("../../../scripts/debug_disable.js");
use crate::logic::player::Player; use crate::logic::thread_mgr::NetContext;
pub fn on_scene_trace_request( pub fn on_scene_trace_request(
_player: &Player, _ctx: &NetContext,
request: SceneTraceRequest, request: SceneTraceRequest,
_: &mut SceneTraceResponse, _: &mut SceneTraceResponse,
) { ) {
@ -21,22 +21,22 @@ pub fn on_scene_trace_request(
} }
pub fn on_scene_loading_finish_request( pub fn on_scene_loading_finish_request(
player: &Player, ctx: &NetContext,
_request: SceneLoadingFinishRequest, _request: SceneLoadingFinishRequest,
response: &mut SceneLoadingFinishResponse, response: &mut SceneLoadingFinishResponse,
) { ) {
player.notify(JsPatchNotify { ctx.player.notify(JsPatchNotify {
content: WATER_MASK.to_string(), content: WATER_MASK.to_string(),
}); });
player.notify(JsPatchNotify { ctx.player.notify(JsPatchNotify {
content: UID_FIX content: UID_FIX
.replace("{PLAYER_USERNAME}", &player.basic_info.name) .replace("{PLAYER_USERNAME}", &ctx.player.basic_info.name)
.replace("{SELECTED_COLOR}", "50FC71"), .replace("{SELECTED_COLOR}", "50FC71"),
}); });
player.notify(JsPatchNotify { ctx.player.notify(JsPatchNotify {
content: CENSORSHIP_FIX.to_string(), content: CENSORSHIP_FIX.to_string(),
}); });
player.notify(JsPatchNotify { ctx.player.notify(JsPatchNotify {
content: DEBUG_DISABLE.to_string(), content: DEBUG_DISABLE.to_string(),
}); });
@ -45,7 +45,7 @@ pub fn on_scene_loading_finish_request(
} }
pub fn on_update_scene_date_request( pub fn on_update_scene_date_request(
_player: &Player, _ctx: &NetContext,
_request: UpdateSceneDateRequest, _request: UpdateSceneDateRequest,
response: &mut UpdateSceneDateResponse, response: &mut UpdateSceneDateResponse,
) { ) {
@ -54,7 +54,7 @@ pub fn on_update_scene_date_request(
} }
pub fn on_access_path_time_server_config_request( pub fn on_access_path_time_server_config_request(
_player: &Player, _ctx: &NetContext,
_request: AccessPathTimeServerConfigRequest, _request: AccessPathTimeServerConfigRequest,
response: &mut AccessPathTimeServerConfigResponse, response: &mut AccessPathTimeServerConfigResponse,
) { ) {
@ -63,7 +63,7 @@ pub fn on_access_path_time_server_config_request(
} }
pub fn on_player_head_data_request( pub fn on_player_head_data_request(
_player: &Player, _ctx: &NetContext,
_request: PlayerHeadDataRequest, _request: PlayerHeadDataRequest,
response: &mut PlayerHeadDataResponse, response: &mut PlayerHeadDataResponse,
) { ) {

View file

@ -1,23 +1,26 @@
use crate::logic::ecs::component::ComponentContainer; use crate::logic::ecs::component::ComponentContainer;
use wicked_waifus_protocol::{ErrorCode, ExploreSkillRouletteSetRequest, ExploreSkillRouletteSetResponse, VisionExploreSkillSetRequest, VisionExploreSkillSetResponse, VisionSkillChangeNotify, VisionSkillInformation}; use wicked_waifus_protocol::{
ErrorCode, ExploreSkillRouletteSetRequest, ExploreSkillRouletteSetResponse,
VisionExploreSkillSetRequest, VisionExploreSkillSetResponse, VisionSkillChangeNotify,
VisionSkillInformation,
};
use crate::{logic::player::Player, query_with}; use crate::logic::thread_mgr::NetContext;
use crate::query_with;
pub fn on_vision_explore_skill_set_request( pub fn on_vision_explore_skill_set_request(
player: &mut Player, ctx: &mut NetContext,
request: VisionExploreSkillSetRequest, request: VisionExploreSkillSetRequest,
response: &mut VisionExploreSkillSetResponse, response: &mut VisionExploreSkillSetResponse,
) { ) {
player.explore_tools.active_explore_skill = request.skill_id; ctx.player.explore_tools.active_explore_skill = request.skill_id;
for (entity, owner, mut vision_skill) in query_with!( for (entity, owner, mut vision_skill) in
player.world.borrow().get_world_entity(), query_with!(ctx.world.get_world_entity(), OwnerPlayer, VisionSkill)
OwnerPlayer, {
VisionSkill if owner.0 == ctx.player.basic_info.id {
) {
if owner.0 == player.basic_info.id {
vision_skill.skill_id = request.skill_id; vision_skill.skill_id = request.skill_id;
player.notify(VisionSkillChangeNotify { ctx.player.notify(VisionSkillChangeNotify {
entity_id: entity.into(), entity_id: entity.into(),
vision_skill_infos: vec![VisionSkillInformation { vision_skill_infos: vec![VisionSkillInformation {
skill_id: request.skill_id, skill_id: request.skill_id,
@ -32,25 +35,34 @@ pub fn on_vision_explore_skill_set_request(
} }
pub fn on_explore_skill_roulette_set_request( pub fn on_explore_skill_roulette_set_request(
player: &mut Player, ctx: &mut NetContext,
request: ExploreSkillRouletteSetRequest, request: ExploreSkillRouletteSetRequest,
response: &mut ExploreSkillRouletteSetResponse, response: &mut ExploreSkillRouletteSetResponse,
) { ) {
let mut illegal_skill = false; let mut illegal_skill = false;
for skill_roulette in &request.skill_roulettes { for skill_roulette in &request.skill_roulettes {
for skill_id in &skill_roulette.skill_ids { for skill_id in &skill_roulette.skill_ids {
if *skill_id != 0 && !player.explore_tools.unlocked_explore_skills.contains(skill_id) { if *skill_id != 0
&& !ctx
.player
.explore_tools
.unlocked_explore_skills
.contains(skill_id)
{
illegal_skill = true; illegal_skill = true;
break break;
} }
} }
} }
match illegal_skill { match illegal_skill {
true => response.error_code = ErrorCode::ErrRouletteFuncIdInvaild.into(), true => response.error_code = ErrorCode::ErrRouletteFuncIdInvaild.into(),
false => { false => {
player.explore_tools.roulette = request.skill_roulettes.get(0).unwrap().skill_ids.iter() ctx.player.explore_tools.roulette = request
.map(|&skill_id| skill_id) .skill_roulettes
.collect::<Vec<i32>>() .first()
.unwrap()
.skill_ids
.to_vec()
.as_slice() .as_slice()
.try_into() .try_into()
.unwrap(); .unwrap();
@ -58,4 +70,4 @@ pub fn on_explore_skill_roulette_set_request(
response.skill_roulettes = request.skill_roulettes; response.skill_roulettes = request.skill_roulettes;
} }
} }
} }

View file

@ -1,37 +1,51 @@
use wicked_waifus_protocol::{ErrorCode, JoinSceneNotify, LeaveSceneNotify, TeleportDataRequest, TeleportDataResponse, TeleportFinishRequest, TeleportFinishResponse, TeleportNotify, TeleportReason, TeleportTransferRequest, TeleportTransferResponse, TransitionOptionPb}; use wicked_waifus_protocol::{
ErrorCode, JoinSceneNotify, LeaveSceneNotify, TeleportDataRequest, TeleportDataResponse,
TeleportFinishRequest, TeleportFinishResponse, TeleportNotify, TeleportReason,
TeleportTransferRequest, TeleportTransferResponse, TransitionOptionPb,
};
use wicked_waifus_data::{level_entity_config_data, RawVectorData};
use wicked_waifus_data::pb_components::teleport::TeleportComponent; use wicked_waifus_data::pb_components::teleport::TeleportComponent;
use wicked_waifus_data::{level_entity_config_data, RawVectorData};
use crate::logic::math::Vector3f; use crate::logic::math::Vector3f;
use crate::logic::player::Player; use crate::logic::thread_mgr::NetContext;
use crate::logic::utils::world_util; use crate::logic::utils::world_util;
pub fn on_teleport_data_request( pub fn on_teleport_data_request(
player: &mut Player, ctx: &NetContext,
_: TeleportDataRequest, _: TeleportDataRequest,
response: &mut TeleportDataResponse, response: &mut TeleportDataResponse,
) { ) {
response.error_code = ErrorCode::Success.into(); response.error_code = ErrorCode::Success.into();
response.ids = player.teleports.teleports_data.iter() response.ids = ctx
.player
.teleports
.teleports_data
.iter()
.map(|teleport| teleport.id) .map(|teleport| teleport.id)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
} }
pub fn on_teleport_transfer_request( pub fn on_teleport_transfer_request(
player: &mut Player, ctx: &mut NetContext,
request: TeleportTransferRequest, request: TeleportTransferRequest,
response: &mut TeleportTransferResponse, response: &mut TeleportTransferResponse,
) { ) {
tracing::debug!("received transfer request for teleport id: {}", request.id); tracing::debug!("received transfer request for teleport id: {}", request.id);
let Some(teleport) = wicked_waifus_data::teleporter_data::iter() let Some(teleport) =
.find(|teleporter| request.id == teleporter.id) else { wicked_waifus_data::teleporter_data::iter().find(|teleporter| request.id == teleporter.id)
else {
response.error_code = ErrorCode::ErrTeleportIdNotExist.into(); response.error_code = ErrorCode::ErrTeleportIdNotExist.into();
return; return;
}; };
println!("received transfer request for teleport entity id: {}", &teleport.teleport_entity_config_id); println!(
let Some(tp) = level_entity_config_data::get(teleport.map_id, teleport.teleport_entity_config_id) else { "received transfer request for teleport entity id: {}",
&teleport.teleport_entity_config_id
);
let Some(tp) =
level_entity_config_data::get(teleport.map_id, teleport.teleport_entity_config_id)
else {
response.error_code = ErrorCode::ErrTeleportEntityNotExist.into(); response.error_code = ErrorCode::ErrTeleportEntityNotExist.into();
return; return;
}; };
@ -41,8 +55,7 @@ pub fn on_teleport_transfer_request(
return; return;
}; };
if teleport_component.disabled.unwrap_or(false) || if teleport_component.disabled.unwrap_or(false) || teleport_component.teleporter_id.is_none() {
teleport_component.teleporter_id.is_none() {
response.error_code = ErrorCode::ErrTeleportGmGetCreatureGenCfgFailed.into(); response.error_code = ErrorCode::ErrTeleportGmGetCreatureGenCfgFailed.into();
} }
if teleport_component.teleporter_id.unwrap() != request.id { if teleport_component.teleporter_id.unwrap() != request.id {
@ -58,8 +71,8 @@ pub fn on_teleport_transfer_request(
response.yaw = 0f32; response.yaw = 0f32;
response.roll = 0f32; response.roll = 0f32;
if player.basic_info.cur_map_id == teleport.map_id { if ctx.player.basic_info.cur_map_id == teleport.map_id {
player.notify(TeleportNotify { ctx.player.notify(TeleportNotify {
map_id: teleport.map_id, map_id: teleport.map_id,
pos: Some(teleport_position.to_protobuf()), pos: Some(teleport_position.to_protobuf()),
rot: None, rot: None,
@ -71,14 +84,14 @@ pub fn on_teleport_transfer_request(
}); });
} else { } else {
// remove entity // remove entity
player.notify(LeaveSceneNotify { ctx.player.notify(LeaveSceneNotify {
player_id: player.basic_info.id, player_id: ctx.player.basic_info.id,
scene_id: "".to_string(), scene_id: "".to_string(),
transition_option: Some(TransitionOptionPb::default()), transition_option: Some(TransitionOptionPb::default()),
}); });
let scene_info = world_util::build_scene_information(&player); let scene_info = world_util::build_scene_information(ctx);
// TODO: Trigger initial join world flow?? // TODO: Trigger initial join world flow??
player.notify(JoinSceneNotify { ctx.player.notify(JoinSceneNotify {
scene_info: Some(scene_info), scene_info: Some(scene_info),
max_entity_id: i64::MAX, max_entity_id: i64::MAX,
transition_option: Some(TransitionOptionPb::default()), transition_option: Some(TransitionOptionPb::default()),
@ -88,7 +101,7 @@ pub fn on_teleport_transfer_request(
} }
pub fn on_teleport_finish_request( pub fn on_teleport_finish_request(
_player: &mut Player, _ctx: &mut NetContext,
_: TeleportFinishRequest, _: TeleportFinishRequest,
response: &mut TeleportFinishResponse, response: &mut TeleportFinishResponse,
) { ) {
@ -103,4 +116,4 @@ fn get_teleport_position(transform: &[RawVectorData], component: &TeleportCompon
entity_position.add_teleport_position(teleport_position); entity_position.add_teleport_position(teleport_position);
} }
entity_position entity_position
} }

View file

@ -4,14 +4,15 @@ use wicked_waifus_protocol::{
TutorialReceiveResponse, TutorialUnlockRequest, TutorialUnlockResponse, TutorialReceiveResponse, TutorialUnlockRequest, TutorialUnlockResponse,
}; };
use crate::logic::player::Player; use crate::logic::thread_mgr::NetContext;
pub fn on_tutorial_info_request( pub fn on_tutorial_info_request(
player: &mut Player, ctx: &NetContext,
_: TutorialInfoRequest, _: TutorialInfoRequest,
response: &mut TutorialInfoResponse, response: &mut TutorialInfoResponse,
) { ) {
response.unlock_list = player response.unlock_list = ctx
.player
.tutorials .tutorials
.tutorials .tutorials
.iter() .iter()
@ -24,7 +25,7 @@ pub fn on_tutorial_info_request(
} }
pub fn on_tutorial_receive_request( pub fn on_tutorial_receive_request(
player: &mut Player, ctx: &mut NetContext,
request: TutorialReceiveRequest, request: TutorialReceiveRequest,
response: &mut TutorialReceiveResponse, response: &mut TutorialReceiveResponse,
) { ) {
@ -35,12 +36,13 @@ pub fn on_tutorial_receive_request(
return; return;
}; };
let Some(tutorial) = player let Some(tutorial) = ctx
.player
.tutorials .tutorials
.tutorials .tutorials
.iter() .iter()
.find(|tutorial| tutorial.id == request.id) else { .find(|tutorial| tutorial.id == request.id)
else {
response.error_code = ErrorCode::GuideTutorialNotUnlock.into(); response.error_code = ErrorCode::GuideTutorialNotUnlock.into();
return; return;
}; };
@ -51,7 +53,10 @@ pub fn on_tutorial_receive_request(
} }
// TODO: Search the rewards in drop_package // TODO: Search the rewards in drop_package
tracing::debug!("Tutorial receive request with drop: {}", tutorial_data.drop_id); tracing::debug!(
"Tutorial receive request with drop: {}",
tutorial_data.drop_id
);
// TODO: Fill in the item map // TODO: Fill in the item map
response.error_code = ErrorCode::Success.into(); response.error_code = ErrorCode::Success.into();
@ -59,7 +64,7 @@ pub fn on_tutorial_receive_request(
} }
pub fn on_tutorial_unlock_request( pub fn on_tutorial_unlock_request(
player: &mut Player, ctx: &mut NetContext,
request: TutorialUnlockRequest, request: TutorialUnlockRequest,
response: &mut TutorialUnlockResponse, response: &mut TutorialUnlockResponse,
) { ) {
@ -70,7 +75,8 @@ pub fn on_tutorial_unlock_request(
return; return;
}; };
if let Some(tutorial) = player if let Some(tutorial) = ctx
.player
.tutorials .tutorials
.tutorials .tutorials
.iter() .iter()
@ -84,7 +90,7 @@ pub fn on_tutorial_unlock_request(
return; return;
} }
let tutorial = player.unlock_tutorial(request.id); let tutorial = ctx.player.unlock_tutorial(request.id);
response.un_lock_info = Some(TutorialInfo { response.un_lock_info = Some(TutorialInfo {
id: tutorial.id, id: tutorial.id,
create_time: tutorial.create_time, create_time: tutorial.create_time,

View file

@ -1,29 +1,26 @@
use crate::logic::components::{Equip, WeaponSkin}; use crate::logic::components::{Equip, WeaponSkin};
use crate::logic::ecs::component::ComponentContainer; use crate::logic::ecs::component::ComponentContainer;
use crate::logic::player::Player; use crate::logic::player::Player;
use crate::logic::thread_mgr::NetContext;
use crate::modify_component; use crate::modify_component;
use wicked_waifus_protocol::{EntityEquipChangeNotify, EntityEquipSkinChangeNotify, EquipComponentPb, EquipTakeOnNotify, EquipTakeOnRequest, EquipTakeOnResponse, EquipWeaponSkinRequest, EquipWeaponSkinResponse, ErrorCode, LoadEquipData, SendEquipSkinRequest, SendEquipSkinResponse, WeaponSkinComponentPb, WeaponSkinDeleteNotify, WeaponSkinRequest, WeaponSkinResponse}; use wicked_waifus_protocol::{
EntityEquipChangeNotify, EntityEquipSkinChangeNotify, EquipComponentPb, EquipTakeOnNotify,
EquipTakeOnRequest, EquipTakeOnResponse, EquipWeaponSkinRequest, EquipWeaponSkinResponse,
ErrorCode, LoadEquipData, SendEquipSkinRequest, SendEquipSkinResponse, WeaponSkinComponentPb,
WeaponSkinDeleteNotify, WeaponSkinRequest, WeaponSkinResponse,
};
pub fn on_weapon_skin_request( pub fn on_weapon_skin_request(
player: &Player, ctx: &NetContext,
_request: WeaponSkinRequest, _request: WeaponSkinRequest,
response: &mut WeaponSkinResponse, response: &mut WeaponSkinResponse,
) { ) {
response.equip_list = player response.equip_list = get_player_weapons(ctx.player);
.role_list
.values()
.filter(|role| role.weapon_skin_id != 0)
.map(|role| LoadEquipData {
role_id: role.role_id,
skin_id: role.weapon_skin_id,
})
.collect();
response.error_code = ErrorCode::Success.into(); response.error_code = ErrorCode::Success.into();
} }
pub fn on_equip_weapon_skin_request( pub fn on_equip_weapon_skin_request(
player: &mut Player, ctx: &mut NetContext,
request: EquipWeaponSkinRequest, request: EquipWeaponSkinRequest,
response: &mut EquipWeaponSkinResponse, response: &mut EquipWeaponSkinResponse,
) { ) {
@ -31,7 +28,7 @@ pub fn on_equip_weapon_skin_request(
return; return;
}; };
let role = player.role_list.get_mut(&equip_data.role_id); let role = ctx.player.role_list.get_mut(&equip_data.role_id);
let Some(role) = role else { let Some(role) = role else {
response.error_code = ErrorCode::NotValidRole.into(); response.error_code = ErrorCode::NotValidRole.into();
return; return;
@ -46,50 +43,44 @@ pub fn on_equip_weapon_skin_request(
}; };
// Verify Skin is unlocked // Verify Skin is unlocked
if !player.unlocked_skins.weapon_skins.contains(&skin_data.id) { if !ctx
.player
.unlocked_skins
.weapon_skins
.contains(&skin_data.id)
{
response.error_code = ErrorCode::WeaponSkinUnLockErr.into(); response.error_code = ErrorCode::WeaponSkinUnLockErr.into();
return; return;
} }
role.weapon_skin_id = equip_data.skin_id; role.weapon_skin_id = equip_data.skin_id;
{ let world = ctx.world.get_world_entity();
let world_ref = player.world.borrow(); let entity_id = world.get_entity_id(equip_data.role_id);
let world = world_ref.get_world_entity(); modify_component!(
let entity_id = world.get_entity_id(equip_data.role_id); world.get_entity_components(entity_id as i32),
modify_component!( WeaponSkin,
world.get_entity_components(entity_id as i32), |skin_component: &mut WeaponSkin| {
WeaponSkin, skin_component.skin_id = equip_data.skin_id;
|skin_component: &mut WeaponSkin| { }
skin_component.skin_id = equip_data.skin_id; );
} ctx.player.notify(EntityEquipSkinChangeNotify {
); entity_id,
player.notify(EntityEquipSkinChangeNotify { weapon_skin_component_pb: Some(WeaponSkinComponentPb {
entity_id, weapon_skin_id: equip_data.skin_id,
weapon_skin_component_pb: Some(WeaponSkinComponentPb { }),
weapon_skin_id: equip_data.skin_id, });
}),
});
}
// Is the all list needed or only the new one?? // Is the all list needed or only the new one??
response.data_list = player response.data_list = get_player_weapons(ctx.player);
.role_list
.values()
.filter(|role| role.weapon_skin_id != 0)
.map(|role| LoadEquipData {
role_id: role.role_id,
skin_id: role.weapon_skin_id,
})
.collect();
response.error_code = ErrorCode::Success.into(); response.error_code = ErrorCode::Success.into();
} }
pub fn on_send_equip_skin_request( pub fn on_send_equip_skin_request(
player: &mut Player, ctx: &mut NetContext,
request: SendEquipSkinRequest, request: SendEquipSkinRequest,
response: &mut SendEquipSkinResponse, response: &mut SendEquipSkinResponse,
) { ) {
let role = player.role_list.get_mut(&request.role_id); let role = ctx.player.role_list.get_mut(&request.role_id);
let Some(role) = role else { let Some(role) = role else {
response.error_code = ErrorCode::NotValidRole.into(); response.error_code = ErrorCode::NotValidRole.into();
return; return;
@ -97,79 +88,90 @@ pub fn on_send_equip_skin_request(
let old_skin_id = role.weapon_skin_id; let old_skin_id = role.weapon_skin_id;
role.weapon_skin_id = 0; role.weapon_skin_id = 0;
{ let world = ctx.world.get_world_entity();
let world_ref = player.world.borrow(); let entity_id = world.get_entity_id(request.role_id);
let world = world_ref.get_world_entity(); modify_component!(
let entity_id = world.get_entity_id(request.role_id); world.get_entity_components(entity_id as i32),
modify_component!( WeaponSkin,
world.get_entity_components(entity_id as i32), |skin_component: &mut WeaponSkin| {
WeaponSkin, skin_component.skin_id = 0;
|skin_component: &mut WeaponSkin| { }
skin_component.skin_id = 0; );
} ctx.player.notify(EntityEquipSkinChangeNotify {
); entity_id,
player.notify(EntityEquipSkinChangeNotify { weapon_skin_component_pb: Some(WeaponSkinComponentPb { weapon_skin_id: 0 }),
entity_id, });
weapon_skin_component_pb: Some(WeaponSkinComponentPb { ctx.player.notify(WeaponSkinDeleteNotify {
weapon_skin_id: 0, role_id: request.role_id,
}), skin_id: old_skin_id,
}); });
player.notify(WeaponSkinDeleteNotify {
role_id: request.role_id,
skin_id: old_skin_id,
})
}
response.error_code = ErrorCode::Success.into(); response.error_code = ErrorCode::Success.into();
} }
pub fn on_equip_take_on_request( pub fn on_equip_take_on_request(
player: &mut Player, ctx: &mut NetContext,
request: EquipTakeOnRequest, request: EquipTakeOnRequest,
response: &mut EquipTakeOnResponse, response: &mut EquipTakeOnResponse,
) { ) {
let Some(equip_data) = request.data else { let Some(equip_data) = request.data else {
return; return;
}; };
// TODO: Add sanity checks(add from another role, a.k.a.: switch from roles)
player.notify(EquipTakeOnNotify { data_list: vec![equip_data] });
let role = player.role_list.get_mut(&equip_data.role_id); // TODO: Add sanity checks(add from another role, a.k.a.: switch from roles)
ctx.player.notify(EquipTakeOnNotify {
data_list: vec![equip_data],
});
let role = ctx.player.role_list.get_mut(&equip_data.role_id);
let Some(role) = role else { let Some(role) = role else {
response.error_code = ErrorCode::NotValidRole.into(); response.error_code = ErrorCode::NotValidRole.into();
return; return;
}; };
let Some((id, breach)) = player.inventory.get_weapon_equip_info(equip_data.equip_inc_id) else { let Some((id, breach)) = ctx
.player
.inventory
.get_weapon_equip_info(equip_data.equip_inc_id)
else {
response.error_code = ErrorCode::ErrItemNotFound.into(); response.error_code = ErrorCode::ErrItemNotFound.into();
return; return;
}; };
role.equip_weapon = id; role.equip_weapon = id;
// TODO: Change attributes based on weapon (PbRolePropsNotify + buffs + CombatNotifyAttributeChangedNotify) // TODO: Change attributes based on weapon (PbRolePropsNotify + buffs + CombatNotifyAttributeChangedNotify)
{ // TODO: remove from old one if in scene in case of weapon switch
// TODO: remove from old one if in scene in case of weapon switch let world = ctx.world.get_world_entity();
let world_ref = player.world.borrow(); let entity_id = world.get_entity_id(equip_data.role_id);
let world = world_ref.get_world_entity(); modify_component!(
let entity_id = world.get_entity_id(equip_data.role_id); world.get_entity_components(entity_id as i32),
modify_component!( Equip,
world.get_entity_components(entity_id as i32), |equip_component: &mut Equip| {
Equip, equip_component.weapon_id = id;
|equip_component: &mut Equip| { equip_component.weapon_breach_level = breach;
equip_component.weapon_id = id; }
equip_component.weapon_breach_level = breach; );
} ctx.player.notify(EntityEquipChangeNotify {
); entity_id,
player.notify(EntityEquipChangeNotify { equip_component: Some(EquipComponentPb {
entity_id, weapon_id: id,
equip_component: Some(EquipComponentPb { weapon_breach_level: breach,
weapon_id: id, }),
weapon_breach_level: breach, });
}),
})
}
// TODO: Should we return all of them?? // TODO: Should we return all of them??
response.data_list = vec![equip_data]; response.data_list = vec![equip_data];
response.error_code = ErrorCode::Success.into(); response.error_code = ErrorCode::Success.into();
} }
#[inline(always)]
fn get_player_weapons(player: &Player) -> Vec<LoadEquipData> {
player
.role_list
.values()
.filter(|role| role.weapon_skin_id != 0)
.map(|role| LoadEquipData {
role_id: role.role_id,
skin_id: role.weapon_skin_id,
})
.collect()
}

View file

@ -30,9 +30,9 @@ impl Transform {
} }
pub fn set_rotation_from_protobuf(&mut self, rotator: &Rotator) { pub fn set_rotation_from_protobuf(&mut self, rotator: &Rotator) {
self.rotation.x = rotator.pitch; self.rotation.x = rotator.roll;
self.rotation.y = rotator.yaw; self.rotation.y = rotator.pitch;
self.rotation.z = rotator.roll; self.rotation.z = rotator.yaw;
} }
pub fn load_from_save(data: TransformData) -> Self { pub fn load_from_save(data: TransformData) -> Self {

View file

@ -1,7 +1,5 @@
pub use in_world_player::InWorldPlayer; pub use in_world_player::InWorldPlayer;
use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
use wicked_waifus_commons::time_util; use wicked_waifus_commons::time_util;
use wicked_waifus_data::motion_data; use wicked_waifus_data::motion_data;
@ -24,10 +22,7 @@ use wicked_waifus_protocol::{
}; };
use wicked_waifus_protocol_internal::{PlayerBasicData, PlayerRoleData, PlayerSaveData}; use wicked_waifus_protocol_internal::{PlayerBasicData, PlayerRoleData, PlayerSaveData};
use super::{ use super::role::{Role, RoleFormation};
ecs::world::World,
role::{Role, RoleFormation},
};
use crate::logic::components::RoleSkin; use crate::logic::components::RoleSkin;
use crate::logic::ecs::world::WorldEntity; use crate::logic::ecs::world::WorldEntity;
use crate::logic::player::basic_info::PlayerBasicInfo; use crate::logic::player::basic_info::PlayerBasicInfo;
@ -97,7 +92,7 @@ pub struct Player {
pub mc_element: PlayerMcElement, pub mc_element: PlayerMcElement,
pub unlocked_skins: PlayerUnlockedSkins, pub unlocked_skins: PlayerUnlockedSkins,
// Runtime // Runtime
pub world: Rc<RefCell<World>>, pub world_owner_id: i32,
pub last_save_time: u64, pub last_save_time: u64,
pub quadrant_id: u64, pub quadrant_id: u64,
} }
@ -308,6 +303,8 @@ impl Player {
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
now_chapter: global_status.now_chapter, now_chapter: global_status.now_chapter,
received_chapter: global_status.received_chapter, received_chapter: global_status.received_chapter,
i_k1: vec![],
r_k1: vec![],
}) })
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
} }
@ -435,7 +432,7 @@ impl Player {
} }
} }
pub fn build_player_entity_add_notify(&self, role_list: Vec<Role>, world: &mut WorldEntity) -> EntityAddNotify { pub fn build_player_entity_add_notify(&self, role_list: Vec<&Role>, world: &mut WorldEntity) -> EntityAddNotify {
create_player_entity_pb!( create_player_entity_pb!(
role_list, role_list,
self.basic_info.cur_map_id, self.basic_info.cur_map_id,
@ -662,7 +659,7 @@ impl Player {
.unlocked_skins .unlocked_skins
.map(PlayerUnlockedSkins::load_from_save) .map(PlayerUnlockedSkins::load_from_save)
.unwrap_or_default(), .unwrap_or_default(),
world: Rc::new(RefCell::new(World::new())), world_owner_id: 0,
last_save_time: time_util::unix_timestamp(), last_save_time: time_util::unix_timestamp(),
quadrant_id: 0, quadrant_id: 0,
} }

View file

@ -1,15 +1,22 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::atomic::AtomicI32; use std::sync::atomic::AtomicI32;
use wicked_waifus_protocol::{ArrayIntInt, NormalItem, WeaponItem}; use wicked_waifus_protocol::{
ArrayIntInt, NormalItem, PhantomItem, PhantomPropInfo, RolePhantomEquipInfo,
RolePhantomPropInfo, WeaponItem,
};
use crate::config; use crate::config;
use crate::logic::utils::seq_utils::{SequenceGenerator, Sequencer}; use crate::logic::utils::seq_utils::{SequenceGenerator, Sequencer};
use wicked_waifus_protocol_internal::{PlayerInventoryData, PlayerInventoryWeaponData}; use wicked_waifus_protocol_internal::{
PlayerInventoryData, PlayerInventoryPhantomData, PlayerInventoryWeaponData,
};
pub struct PlayerInventory { pub struct PlayerInventory {
items: HashMap<i32, i32>, items: HashMap<i32, i32>,
weapons_seq: SequenceGenerator<i32, AtomicI32>, weapons_seq: SequenceGenerator<i32, AtomicI32>,
weapons: HashMap<i32, PlayerInventoryWeaponData>, weapons: HashMap<i32, PlayerInventoryWeaponData>,
echoes_seq: SequenceGenerator<i32, AtomicI32>,
echoes: HashMap<i32, PlayerInventoryPhantomData>,
} }
pub struct ItemUsage { pub struct ItemUsage {
@ -38,8 +45,10 @@ impl PlayerInventory {
pub fn load_from_save(data: PlayerInventoryData) -> Self { pub fn load_from_save(data: PlayerInventoryData) -> Self {
Self { Self {
weapons_seq: SequenceGenerator::from_data(&data.weapons), weapons_seq: SequenceGenerator::from_data(&data.weapons),
echoes_seq: SequenceGenerator::from_data(&data.echoes),
items: data.items.clone(), items: data.items.clone(),
weapons: data.weapons.clone(), weapons: data.weapons.clone(),
echoes: data.echoes.clone(),
} }
} }
@ -47,6 +56,8 @@ impl PlayerInventory {
PlayerInventoryData { PlayerInventoryData {
items: self.items.clone(), items: self.items.clone(),
weapons: self.weapons.clone(), weapons: self.weapons.clone(),
echoes: self.echoes.clone(),
echo_presets: Default::default(),
} }
} }
@ -212,6 +223,75 @@ impl PlayerInventory {
.map(|weapon_data| (weapon_data.id, weapon_data.breach)) .map(|weapon_data| (weapon_data.id, weapon_data.breach))
} }
pub fn get_echoes_list(
&self,
) -> (
Vec<PhantomItem>,
Vec<RolePhantomEquipInfo>,
Vec<RolePhantomPropInfo>,
) {
let mut equip_info: HashMap<i32, Vec<i32>> = HashMap::new();
// TODO: probably change vec to hashmaps so comulative attributes are O(1) search range
let mut prop_info: HashMap<i32, (Vec<ArrayIntInt>, Vec<ArrayIntInt>)> = HashMap::new();
let echoes = self
.echoes
.iter()
.map(|(&inc_id, data)| {
if data.role_id != 0 {
equip_info.entry(data.role_id).or_default().push(inc_id);
// TODO add propInfo here
prop_info.entry(data.role_id).or_default();
}
PhantomItem {
id: data.id,
incr_id: inc_id,
func_value: data.func_value,
phantom_level: data.level,
phantom_exp: data.exp,
phantom_main_prop: data
.main_prop
.iter()
.map(|data| PhantomPropInfo {
phantom_prop_id: data.prop_id,
value: data.value,
})
.collect(),
phantom_sub_prop: data
.sub_prop
.iter()
.map(|data| PhantomPropInfo {
phantom_prop_id: data.prop_id,
value: data.value,
})
.collect(),
fetter_group_id: data.fetter_group_id,
skin_id: data.skin_id,
}
})
.collect();
let equip_info = equip_info
.iter()
.map(|(&role_id, info)| RolePhantomEquipInfo {
role_id,
phantom_item_incr_id: info.clone(),
})
.collect();
let prop_info = prop_info
.iter()
.map(|(&role_id, info)| RolePhantomPropInfo {
role_id,
base_prop: info.0.clone(),
add_prop: info.1.clone(),
})
.collect();
(echoes, equip_info, prop_info)
}
#[inline(always)] #[inline(always)]
fn add_internal(&mut self, id: i32, quantity: i32) -> i32 { fn add_internal(&mut self, id: i32, quantity: i32) -> i32 {
*self *self
@ -307,10 +387,37 @@ impl Default for PlayerInventory {
.collect::<HashMap<_, _>>(), .collect::<HashMap<_, _>>(),
false => Default::default(), false => Default::default(),
}; };
let mut echoes_seq = SequenceGenerator::new();
let echoes: HashMap<i32, PlayerInventoryPhantomData> =
if default_unlocks.unlock_all_echo {
wicked_waifus_data::phantom_item_data::iter()
.filter(|data| data.item_id % 10 == 5) // TODO: Naruse??
.flat_map(|data| {
let phantom_incr_id = echoes_seq.take_id();
data.fetter_group.iter()
.map(move |&fetter_group_id| {
(
phantom_incr_id,
PlayerInventoryPhantomData {
id: data.item_id,
func_value: 0,
level: 25, // TODO: Max level config
fetter_group_id,
..Default::default()
},
)
})
})
.collect()
} else {
HashMap::new()
};
Self { Self {
items: HashMap::new(), items: HashMap::new(),
weapons_seq, weapons_seq,
weapons, weapons,
echoes_seq,
echoes,
} }
} }
} }

View file

@ -7,6 +7,7 @@ pub struct PlayerUnlockedSkins {
pub weapon_skins: HashSet<i32>, pub weapon_skins: HashSet<i32>,
pub fly_skins: HashSet<i32>, pub fly_skins: HashSet<i32>,
pub wing_skins: HashSet<i32>, pub wing_skins: HashSet<i32>,
pub echo_skins: HashSet<i32>,
} }
impl PlayerUnlockedSkins { impl PlayerUnlockedSkins {
@ -16,6 +17,7 @@ impl PlayerUnlockedSkins {
weapon_skins: data.weapon_skins.iter().cloned().collect(), weapon_skins: data.weapon_skins.iter().cloned().collect(),
fly_skins: data.fly_skins.iter().cloned().collect(), fly_skins: data.fly_skins.iter().cloned().collect(),
wing_skins: data.wing_skins.iter().cloned().collect(), wing_skins: data.wing_skins.iter().cloned().collect(),
echo_skins: data.echo_skins.iter().cloned().collect(),
} }
} }
@ -25,6 +27,7 @@ impl PlayerUnlockedSkins {
weapon_skins: self.weapon_skins.iter().cloned().collect(), weapon_skins: self.weapon_skins.iter().cloned().collect(),
fly_skins: self.fly_skins.iter().cloned().collect(), fly_skins: self.fly_skins.iter().cloned().collect(),
wing_skins: self.wing_skins.iter().cloned().collect(), wing_skins: self.wing_skins.iter().cloned().collect(),
echo_skins: self.echo_skins.iter().cloned().collect(),
} }
} }
} }
@ -67,6 +70,15 @@ impl Default for PlayerUnlockedSkins {
} else { } else {
HashSet::new() HashSet::new()
}, },
echo_skins: if unlocks.unlock_all_echo_skins {
wicked_waifus_data::phantom_customize_item_data::iter()
.filter(|data| data.skin_item_id != 0)
.map(|data| data.skin_item_id)
.collect()
} else {
HashSet::new()
},
} }
} }
} }

View file

@ -7,7 +7,8 @@ use crate::logic::utils::growth_utils::get_role_props_by_level;
use crate::logic::utils::load_role_info::load_key_value; use crate::logic::utils::load_role_info::load_key_value;
pub use formation::RoleFormation; pub use formation::RoleFormation;
use wicked_waifus_commons::time_util; use wicked_waifus_commons::time_util;
use wicked_waifus_data::{role_info_data, BasePropertyData}; use wicked_waifus_data::base_property_data::BasePropertyData;
use wicked_waifus_data::role_info_data;
use wicked_waifus_protocol_internal::{RoleData, RoleStats}; use wicked_waifus_protocol_internal::{RoleData, RoleStats};
use crate::logic::player::Element; use crate::logic::player::Element;
@ -147,11 +148,7 @@ impl Role {
.max() .max()
.unwrap_or(0) .unwrap_or(0)
} else { } else {
wicked_waifus_data::resonant_chain_data::iter() 0
.filter(|level_data| level_data.group_id == data.resonant_chain_group_id)
.map(|level_data| level_data.group_index)
.min()
.unwrap_or(0)
}; };
// TODO: add weapon and echo stats // TODO: add weapon and echo stats
let base_stats = &get_role_props_by_level(role_id, level, breakthrough); let base_stats = &get_role_props_by_level(role_id, level, breakthrough);

View file

@ -1,7 +1,6 @@
use wicked_waifus_commons::time_util; use wicked_waifus_commons::time_util;
use wicked_waifus_protocol_internal::PlayerSaveData; use wicked_waifus_protocol_internal::PlayerSaveData;
use wicked_waifus_protocol::{message::Message, AfterJoinSceneNotify, EnterGameResponse, JoinSceneNotify, SilenceNpcNotify, TransitionOptionPb}; use wicked_waifus_protocol::{message::Message, AfterJoinSceneNotify, EnterGameResponse, JoinSceneNotify, SilenceNpcNotify, TransitionOptionPb};
use std::collections::hash_map::Entry::Vacant;
use std::{ use std::{
cell::RefCell, cell::RefCell,
collections::{HashMap, VecDeque}, collections::{HashMap, VecDeque},
@ -122,6 +121,11 @@ fn logic_thread_func(receiver: mpsc::Receiver<LogicInput>, load: Arc<AtomicUsize
} }
} }
pub struct NetContext<'logic> {
pub player: &'logic mut Player,
pub world: &'logic mut World,
}
fn handle_logic_input(state: &mut LogicState, input: LogicInput) { fn handle_logic_input(state: &mut LogicState, input: LogicInput) {
match input { match input {
LogicInput::AddPlayer { LogicInput::AddPlayer {
@ -130,64 +134,56 @@ fn handle_logic_input(state: &mut LogicState, input: LogicInput) {
session, session,
player_save_data, player_save_data,
} => { } => {
let (player, is_player) = if let Vacant(e) = state.players.entry(player_id) { let mut player = state.players.entry(player_id).or_insert_with(|| {
( RefCell::new(Player::load_from_save(player_save_data))
e.insert(RefCell::new(Player::load_from_save(player_save_data))), }).borrow_mut();
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;
}
};
let mut player = player.borrow_mut(); // TODO: shall we search in coop?
if is_player { player.world_owner_id = player_id;
player let mut world = state.worlds.entry(player_id).or_insert_with(|| {
.world let mut world = World::new();
.borrow_mut() world.world_entities.insert(
.world_entitys player.basic_info.cur_map_id,
.insert(player.basic_info.cur_map_id, WorldEntity::default()); WorldEntity::default(),
state.worlds.insert(player_id, player.world.clone()); );
} Rc::new(RefCell::new(world))
}).borrow_mut();
player.init(); player.init();
player.set_session(session); player.set_session(session);
player.respond(EnterGameResponse::default(), enter_rpc_id); player.respond(EnterGameResponse::default(), enter_rpc_id);
player.notify_general_data(); player.notify_general_data();
player world.set_in_world_player_data(player.build_in_world_player());
.world
.borrow_mut()
.set_in_world_player_data(player.build_in_world_player());
world_util::add_player_entities(&player); let mut ctx = NetContext {
let scene_info = world_util::build_scene_information(&player); player: &mut player,
world: &mut world,
};
world_util::add_player_entities(&mut ctx);
let scene_info = world_util::build_scene_information(&mut ctx);
player.notify(SilenceNpcNotify::default()); ctx.player.notify(SilenceNpcNotify::default());
player.notify(JoinSceneNotify { ctx.player.notify(JoinSceneNotify {
scene_info: Some(scene_info), scene_info: Some(scene_info),
max_entity_id: i64::MAX, max_entity_id: i64::MAX,
transition_option: Some(TransitionOptionPb::default()), transition_option: Some(TransitionOptionPb::default()),
}); });
player.notify(AfterJoinSceneNotify::default()); ctx.player.notify(AfterJoinSceneNotify::default());
player.notify(player.build_update_formation_notify()); ctx.player.notify(ctx.player.build_update_formation_notify());
let map = logic::utils::quadrant_util::get_map(player.basic_info.cur_map_id); let map = logic::utils::quadrant_util::get_map(ctx.player.basic_info.cur_map_id);
let quadrant_id = map.get_quadrant_id( let quadrant_id = map.get_quadrant_id(
player.location.position.position.x * 100.0, ctx.player.location.position.position.x * 100.0,
player.location.position.position.y * 100.0, ctx.player.location.position.position.y * 100.0,
); );
player.quadrant_id = quadrant_id; ctx.player.quadrant_id = quadrant_id;
player.notify_month_card(); ctx.player.notify_month_card();
let entities = map.get_initial_entities(quadrant_id); let entities = map.get_initial_entities(quadrant_id);
world_util::add_entities(&player, &entities, false); world_util::add_entities(&mut ctx, &entities, false);
drop(player); drop(player);
@ -200,8 +196,17 @@ fn handle_logic_input(state: &mut LogicState, input: LogicInput) {
tracing::warn!("logic_thread: process message requested, but player with id {player_id} doesn't exist"); tracing::warn!("logic_thread: process message requested, but player with id {player_id} doesn't exist");
return; return;
}; };
let mut player = player.borrow_mut();
super::handler::handle_logic_message(&mut player.borrow_mut(), message); let Some(world) = state.worlds.get_mut(&player.world_owner_id) else {
tracing::warn!("logic_thread: process message requested, but world for player id {} doesn't exist", player.world_owner_id);
return;
};
let mut world = world.borrow_mut();
let mut net_context = NetContext {
player: &mut player,
world: &mut world,
};
super::handler::handle_logic_message(&mut net_context, message);
} }
LogicInput::RemovePlayer { player_id } => { LogicInput::RemovePlayer { player_id } => {
let Some(player) = state.players.remove(&player_id) else { let Some(player) = state.players.remove(&player_id) else {

View file

@ -6,7 +6,8 @@ use wicked_waifus_data::pb_components::action::{Action, ChangeSelfEntityState, U
use wicked_waifus_data::pb_components::entity_state::EntityStateComponent; use wicked_waifus_data::pb_components::entity_state::EntityStateComponent;
use crate::logic::ecs::component::ComponentContainer; use crate::logic::ecs::component::ComponentContainer;
use crate::logic::player::{ItemUsage, Player}; use crate::logic::player::ItemUsage;
use crate::logic::thread_mgr::NetContext;
use crate::logic::utils::tag_utils; use crate::logic::utils::tag_utils;
use crate::query_components; use crate::query_components;
@ -18,23 +19,23 @@ macro_rules! unimplemented_action {
} }
} }
pub fn perform_action(player: &mut Player, pub fn perform_action(ctx: &mut NetContext,
entity_id: i64, entity_id: i64,
level_entity_data: &wicked_waifus_data::LevelEntityConfigData, level_entity_data: &wicked_waifus_data::level_entity_config_data::LevelEntityConfigData,
template_config: &wicked_waifus_data::TemplateConfigData, template_config: &wicked_waifus_data::template_config_data::TemplateConfigData,
element: Action) { element: Action) {
match element { match element {
Action::SetBattleState(action) => unimplemented_action! { action }, Action::SetBattleState(action) => unimplemented_action! { action },
Action::ExecBattleAction(action) => unimplemented_action! { action }, Action::ExecBattleAction(action) => unimplemented_action! { action },
Action::WaitBattleCondition(action) => unimplemented_action! { action }, Action::WaitBattleCondition(action) => unimplemented_action! { action },
Action::PlayFlow(action) => unimplemented_action! { action }, Action::PlayFlow(action) => unimplemented_action! { action },
Action::Collect(_) => collect_action(player, level_entity_data, template_config), Action::Collect(_) => collect_action(ctx, level_entity_data, template_config),
Action::LeisureInteract(action) => unimplemented_action! { action }, Action::LeisureInteract(action) => unimplemented_action! { action },
Action::UnlockTeleportTrigger(action) => unlock_teleport_trigger(player, action.params), Action::UnlockTeleportTrigger(action) => unlock_teleport_trigger(ctx, action.params),
Action::EnableTemporaryTeleport(action) => unimplemented_action! { action }, Action::EnableTemporaryTeleport(action) => unimplemented_action! { action },
Action::OpenSystemBoard(action) => unimplemented_action! { action }, Action::OpenSystemBoard(action) => unimplemented_action! { action },
Action::OpenSystemFunction(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::ChangeSelfEntityState(action) => change_self_entity_state(ctx, entity_id, level_entity_data, template_config, action.params),
Action::SetPlayerOperationRestriction(action) => unimplemented_action! { action }, Action::SetPlayerOperationRestriction(action) => unimplemented_action! { action },
Action::Wait(action) => unimplemented_action! { action }, Action::Wait(action) => unimplemented_action! { action },
Action::ChangeEntityState(action) => unimplemented_action! { action }, Action::ChangeEntityState(action) => unimplemented_action! { action },
@ -135,6 +136,8 @@ pub fn perform_action(player: &mut Player,
Action::RemoveTrialFollowShooter(action) => unimplemented_action! { action }, Action::RemoveTrialFollowShooter(action) => unimplemented_action! { action },
Action::AddTrialCharacter(action) => unimplemented_action! { action }, Action::AddTrialCharacter(action) => unimplemented_action! { action },
Action::RemoveTrialCharacter(action) => unimplemented_action! { action }, Action::RemoveTrialCharacter(action) => unimplemented_action! { action },
Action::UpdateTrialCharacter(action) => unimplemented_action! { action },
Action::RestoreTrialCharacter(action) => unimplemented_action! { action },
Action::SetAreaState(action) => unimplemented_action! { action }, Action::SetAreaState(action) => unimplemented_action! { action },
Action::SwitchSubLevels(action) => unimplemented_action! { action }, Action::SwitchSubLevels(action) => unimplemented_action! { action },
Action::ChangeTeamPosition(action) => unimplemented_action! { action }, Action::ChangeTeamPosition(action) => unimplemented_action! { action },
@ -208,12 +211,15 @@ pub fn perform_action(player: &mut Player,
Action::StopUiScreenEffect(action) => unimplemented_action! { action }, Action::StopUiScreenEffect(action) => unimplemented_action! { action },
Action::StopNewMoveWithSpline(action) => unimplemented_action! { action }, Action::StopNewMoveWithSpline(action) => unimplemented_action! { action },
Action::RequestSystemFunction(action) => unimplemented_action! { action }, Action::RequestSystemFunction(action) => unimplemented_action! { action },
Action::SetTimeScale(action) => unimplemented_action! { action },
Action::EndCommonTip(action) => unimplemented_action! { action },
Action::SetupMoraleSystem(action) => unimplemented_action! { action },
} }
} }
fn collect_action(player: &mut Player, fn collect_action(ctx: &mut NetContext,
level_entity_data: &wicked_waifus_data::LevelEntityConfigData, level_entity_data: &wicked_waifus_data::level_entity_config_data::LevelEntityConfigData,
template_config: &wicked_waifus_data::TemplateConfigData) { template_config: &wicked_waifus_data::template_config_data::TemplateConfigData) {
if let Some(reward_component) = level_entity_data.components_data.reward_component if let Some(reward_component) = level_entity_data.components_data.reward_component
.as_ref() .as_ref()
.or(template_config.components_data.reward_component.as_ref()) { .or(template_config.components_data.reward_component.as_ref()) {
@ -227,11 +233,11 @@ fn collect_action(player: &mut Player,
let usages = drop.drop_preview.iter() let usages = drop.drop_preview.iter()
.map(|(&id, &quantity)| ItemUsage { id, quantity }) .map(|(&id, &quantity)| ItemUsage { id, quantity })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let updated_items = player.inventory.add_items(&usages); let updated_items = ctx.player.inventory.add_items(&usages);
let normal_item_list = player.inventory.to_normal_item_list_filtered( let normal_item_list = ctx.player.inventory.to_normal_item_list_filtered(
&updated_items.keys().cloned().collect::<Vec<i32>>() &updated_items.keys().cloned().collect::<Vec<i32>>()
); );
player.notify(NormalItemUpdateNotify { normal_item_list, no_tips: false }); ctx.player.notify(NormalItemUpdateNotify { normal_item_list, no_tips: false });
// UpdateHandBookActiveStateMapNotify // UpdateHandBookActiveStateMapNotify
let mut rewards: HashMap<i32, WR> = HashMap::new(); let mut rewards: HashMap<i32, WR> = HashMap::new();
rewards.insert(0, WR { rewards.insert(0, WR {
@ -244,7 +250,7 @@ fn collect_action(player: &mut Player,
}) })
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
}); });
player.notify(ItemRewardNotify { ctx.player.notify(ItemRewardNotify {
drop_id: reward_id, drop_id: reward_id,
reason: 15000, reason: 15000,
magnification: 1, magnification: 1,
@ -256,21 +262,20 @@ fn collect_action(player: &mut Player,
} }
#[inline(always)] #[inline(always)]
fn unlock_teleport_trigger(player: &mut Player, action: UnlockTeleportTrigger) { fn unlock_teleport_trigger(ctx: &mut NetContext, action: UnlockTeleportTrigger) {
player.unlock_teleport(action.teleport_id) ctx.player.unlock_teleport(action.teleport_id)
} }
fn change_self_entity_state(player: &mut Player, fn change_self_entity_state(ctx: &mut NetContext,
entity_id: i64, entity_id: i64,
level_entity_data: &wicked_waifus_data::LevelEntityConfigData, level_entity_data: &wicked_waifus_data::level_entity_config_data::LevelEntityConfigData,
template_config: &wicked_waifus_data::TemplateConfigData, template_config: &wicked_waifus_data::template_config_data::TemplateConfigData,
action: ChangeSelfEntityState) { action: ChangeSelfEntityState) {
let state = tag_utils::get_tag_id_by_name(action.entity_state.as_str()); let state = tag_utils::get_tag_id_by_name(action.entity_state.as_str());
// TODO: update Tag::CommonEntityTags too?? // TODO: update Tag::CommonEntityTags too??
let old_state = { let old_state = {
let world_ref = player.world.borrow(); let world = ctx.world.get_world_entity();
let world = world_ref.get_world_entity();
let mut state_tag = query_components!(world, entity_id, StateTag).0.unwrap(); let mut state_tag = query_components!(world, entity_id, StateTag).0.unwrap();
let old_state = state_tag.state_tag_id; let old_state = state_tag.state_tag_id;
tracing::debug!("ChangeSelfEntityState: old state {old_state} -> new state: {state}"); tracing::debug!("ChangeSelfEntityState: old state {old_state} -> new state: {state}");
@ -291,7 +296,7 @@ fn change_self_entity_state(player: &mut Player,
if expected == state { if expected == state {
if let Some(actions) = state_change_behavior.action { if let Some(actions) = state_change_behavior.action {
for sub in actions { for sub in actions {
perform_action(player, entity_id, level_entity_data, template_config, sub); perform_action(ctx, entity_id, level_entity_data, template_config, sub);
} }
} }
} }
@ -299,7 +304,7 @@ fn change_self_entity_state(player: &mut Player,
} }
} }
player.notify(EntityCommonTagNotify { ctx.player.notify(EntityCommonTagNotify {
id: entity_id, id: entity_id,
tags: vec![ tags: vec![
CommonTagData { tag_id: old_state, remove_tag_ids: false }, // Remove CommonTagData { tag_id: old_state, remove_tag_ids: false }, // Remove
@ -307,7 +312,7 @@ fn change_self_entity_state(player: &mut Player,
], ],
}); });
player.notify(EntityStateReadyNotify { ctx.player.notify(EntityStateReadyNotify {
entity_id, entity_id,
tag_id: state, tag_id: state,
ready: true, // TODO: Always true? or shall we compare it to something?? ready: true, // TODO: Always true? or shall we compare it to something??

View file

@ -1,28 +1,30 @@
use wicked_waifus_data::pb_components::condition::{CheckConditionGroup, CompareEntityState, Condition}; use wicked_waifus_data::pb_components::condition::{
CheckConditionGroup, CompareEntityState, Condition, HasBuff,
};
use crate::logic::ecs::component::ComponentContainer; use crate::logic::ecs::component::ComponentContainer;
use crate::logic::player::Player; use crate::logic::thread_mgr::NetContext;
use crate::logic::utils::tag_utils; use crate::logic::utils::tag_utils;
use crate::query_components; use crate::query_components;
macro_rules! unimplemented_condition { macro_rules! unimplemented_condition {
($condition:ident) => { ($condition:ident) => {{
{ tracing::warn!("Condition check not implemented for: {:?}", $condition);
tracing::warn!("Condition check not implemented for: {:?}", $condition); true
true }};
}
}
} }
pub fn check_condition(player: &Player, pub fn check_condition(
entity_id: i64, ctx: &mut NetContext,
level_entity_data: &wicked_waifus_data::LevelEntityConfigData, entity_id: i64,
template_config: &wicked_waifus_data::TemplateConfigData, level_entity_data: &wicked_waifus_data::level_entity_config_data::LevelEntityConfigData,
element: Condition) -> bool { template_config: &wicked_waifus_data::template_config_data::TemplateConfigData,
element: Condition,
) -> bool {
match element { match element {
Condition::CompareTimePeriod(condition) => unimplemented_condition! { condition }, Condition::CompareTimePeriod(condition) => unimplemented_condition! { condition },
Condition::CheckChildQuestFinished(condition) => unimplemented_condition! { condition }, Condition::CheckChildQuestFinished(condition) => unimplemented_condition! { condition },
Condition::CompareEntityState(condition) => compare_entity_state(player, entity_id, condition), Condition::CompareEntityState(condition) => compare_entity_state(ctx, entity_id, condition),
Condition::CheckEntityState(condition) => unimplemented_condition! { condition }, Condition::CheckEntityState(condition) => unimplemented_condition! { condition },
Condition::CompareVar(condition) => unimplemented_condition! { condition }, Condition::CompareVar(condition) => unimplemented_condition! { condition },
Condition::CompareWeather(condition) => unimplemented_condition! { condition }, Condition::CompareWeather(condition) => unimplemented_condition! { condition },
@ -36,13 +38,15 @@ pub fn check_condition(player: &Player,
Condition::PreLevelPlay(condition) => unimplemented_condition! { condition }, Condition::PreLevelPlay(condition) => unimplemented_condition! { condition },
Condition::CheckLevelPlay(condition) => unimplemented_condition! { condition }, Condition::CheckLevelPlay(condition) => unimplemented_condition! { condition },
Condition::CheckLevelPlayState(condition) => unimplemented_condition! { condition }, Condition::CheckLevelPlayState(condition) => unimplemented_condition! { condition },
Condition::CheckLevelPlayCompleteNumber(condition) => unimplemented_condition! { condition }, Condition::CheckLevelPlayCompleteNumber(condition) => {
unimplemented_condition! { condition }
}
Condition::CompareLevelPlayRewardState(condition) => unimplemented_condition! { condition }, Condition::CompareLevelPlayRewardState(condition) => unimplemented_condition! { condition },
Condition::CheckItems(condition) => unimplemented_condition! { condition }, Condition::CheckItems(condition) => unimplemented_condition! { condition },
Condition::HandInItems(condition) => unimplemented_condition! { condition }, Condition::HandInItems(condition) => unimplemented_condition! { condition },
Condition::GetItem(condition) => unimplemented_condition! { condition }, Condition::GetItem(condition) => unimplemented_condition! { condition },
Condition::UseItem(condition) => unimplemented_condition! { condition }, Condition::UseItem(condition) => unimplemented_condition! { condition },
Condition::HasBuff(condition) => unimplemented_condition! { condition }, Condition::HasBuff(condition) => has_buff(ctx, entity_id, condition),
Condition::CompareLift(condition) => unimplemented_condition! { condition }, Condition::CompareLift(condition) => unimplemented_condition! { condition },
Condition::CheckJigsawInfo(condition) => unimplemented_condition! { condition }, Condition::CheckJigsawInfo(condition) => unimplemented_condition! { condition },
Condition::CheckInCombat(condition) => unimplemented_condition! { condition }, Condition::CheckInCombat(condition) => unimplemented_condition! { condition },
@ -68,14 +72,20 @@ pub fn check_condition(player: &Player,
Condition::CheckEntityLocked(condition) => unimplemented_condition! { condition }, Condition::CheckEntityLocked(condition) => unimplemented_condition! { condition },
Condition::CheckRogueAbilitySelect(condition) => unimplemented_condition! { condition }, Condition::CheckRogueAbilitySelect(condition) => unimplemented_condition! { condition },
Condition::CompareFishingBoatState(condition) => unimplemented_condition! { condition }, Condition::CompareFishingBoatState(condition) => unimplemented_condition! { condition },
Condition::CompleteCertainFishingEntrust(condition) => unimplemented_condition! { condition }, Condition::CompleteCertainFishingEntrust(condition) => {
unimplemented_condition! { condition }
}
Condition::CompareFishingPrestigeLevel(condition) => unimplemented_condition! { condition }, Condition::CompareFishingPrestigeLevel(condition) => unimplemented_condition! { condition },
Condition::CheckCertainFishingItemCount(condition) => unimplemented_condition! { condition }, Condition::CheckCertainFishingItemCount(condition) => {
unimplemented_condition! { condition }
}
Condition::CompareFishingTechLevel(condition) => unimplemented_condition! { condition }, Condition::CompareFishingTechLevel(condition) => unimplemented_condition! { condition },
Condition::ListenEntitySelfEvent(condition) => unimplemented_condition! { condition }, Condition::ListenEntitySelfEvent(condition) => unimplemented_condition! { condition },
Condition::CheckHookLockPoint(condition) => unimplemented_condition! { condition }, Condition::CheckHookLockPoint(condition) => unimplemented_condition! { condition },
Condition::CheckEntitesExist(condition) => unimplemented_condition! { condition }, Condition::CheckEntitesExist(condition) => unimplemented_condition! { condition },
Condition::CheckEntityHasSceneItemAttributeTag(condition) => unimplemented_condition! { condition }, Condition::CheckEntityHasSceneItemAttributeTag(condition) => {
unimplemented_condition! { condition }
}
Condition::CheckTargetBattleAttribute(condition) => unimplemented_condition! { condition }, Condition::CheckTargetBattleAttribute(condition) => unimplemented_condition! { condition },
Condition::CheckAlertAreaEnabled(condition) => unimplemented_condition! { condition }, Condition::CheckAlertAreaEnabled(condition) => unimplemented_condition! { condition },
Condition::CompareAlertValue(condition) => unimplemented_condition! { condition }, Condition::CompareAlertValue(condition) => unimplemented_condition! { condition },
@ -99,7 +109,13 @@ pub fn check_condition(player: &Player,
Condition::ParallaxAlign(condition) => unimplemented_condition! { condition }, Condition::ParallaxAlign(condition) => unimplemented_condition! { condition },
Condition::WaitBattleCondition(condition) => unimplemented_condition! { condition }, Condition::WaitBattleCondition(condition) => unimplemented_condition! { condition },
Condition::CheckDirection(condition) => unimplemented_condition! { condition }, Condition::CheckDirection(condition) => unimplemented_condition! { condition },
Condition::CheckConditionGroup(condition) => check_condition_group(player, entity_id, level_entity_data, template_config, condition), Condition::CheckConditionGroup(condition) => check_condition_group(
ctx,
entity_id,
level_entity_data,
template_config,
condition,
),
Condition::CheckTreasureBeenClaimed(condition) => unimplemented_condition! { condition }, Condition::CheckTreasureBeenClaimed(condition) => unimplemented_condition! { condition },
Condition::RangeSphere(condition) => unimplemented_condition! { condition }, Condition::RangeSphere(condition) => unimplemented_condition! { condition },
Condition::CheckInRange(condition) => unimplemented_condition! { condition }, Condition::CheckInRange(condition) => unimplemented_condition! { condition },
@ -119,40 +135,68 @@ pub fn check_condition(player: &Player,
Condition::CheckEntityGravityDirection(condition) => unimplemented_condition! { condition }, Condition::CheckEntityGravityDirection(condition) => unimplemented_condition! { condition },
Condition::CheckTeleControlState(condition) => unimplemented_condition! { condition }, Condition::CheckTeleControlState(condition) => unimplemented_condition! { condition },
Condition::CheckEntityReward(condition) => unimplemented_condition! { condition }, Condition::CheckEntityReward(condition) => unimplemented_condition! { condition },
Condition::CheckIsGramophonePlayingMusic(condition) => unimplemented_condition! { condition }, Condition::CheckIsGramophonePlayingMusic(condition) => {
unimplemented_condition! { condition }
}
Condition::CheckBVBEvent(condition) => unimplemented_condition! { condition }, Condition::CheckBVBEvent(condition) => unimplemented_condition! { condition },
Condition::FinishBvbChallenge(condition) => unimplemented_condition! { condition }, Condition::FinishBvbChallenge(condition) => unimplemented_condition! { condition },
Condition::CompareActorVar(condition) => unimplemented_condition! { condition }, Condition::CompareActorVar(condition) => unimplemented_condition! { condition },
Condition::CheckDangoCultivationProgress(condition) => unimplemented_condition! { condition }, Condition::CheckDangoCultivationProgress(condition) => {
unimplemented_condition! { condition }
},
Condition::CheckPlayerMoraleLevelRange(condition) => {
unimplemented_condition! { condition }
},
Condition::ProgramSpecialProcess(condition) => {
unimplemented_condition! { condition }
}
} }
} }
fn compare_entity_state(player: &Player, entity_id: i64, condition: CompareEntityState) -> bool { fn compare_entity_state(ctx: &NetContext, entity_id: i64, condition: CompareEntityState) -> bool {
let actual = { let actual = {
let world_ref = player.world.borrow(); let world = ctx.world.get_world_entity();
let world = world_ref.get_world_entity();
let state_tag = query_components!(world, entity_id, StateTag).0.unwrap(); let state_tag = query_components!(world, entity_id, StateTag).0.unwrap();
state_tag.state_tag_id state_tag.state_tag_id
}; };
let expected = tag_utils::get_tag_id_by_name(condition.state.as_str()); let expected = tag_utils::get_tag_id_by_name(condition.state.as_str());
// In theory, we can only check for equal or not equal // In theory, we can only check for equal or not equal
tracing::debug!("CompareEntityState: type {:?}, actual: {actual}, expected: {expected}", condition.compare); tracing::debug!(
"CompareEntityState: type {:?}, actual: {actual}, expected: {expected}",
condition.compare
);
condition.compare.cmp(&expected, &actual) condition.compare.cmp(&expected, &actual)
} }
fn check_condition_group(player: &Player, fn has_buff(ctx: &NetContext, entity_id: i64, condition: HasBuff) -> bool {
entity_id: i64, let has_buff = {
level_entity_data: &wicked_waifus_data::LevelEntityConfigData, let world = ctx.world.get_world_entity();
template_config: &wicked_waifus_data::TemplateConfigData, let buff = query_components!(world, entity_id, FightBuff).0.unwrap();
condition: CheckConditionGroup) -> bool { // TODO: use online condition
// TODO: Check if there are other type of Eq
buff.fight_buff_infos
.iter()
.find(|buf| buf.buff_id == condition.buff_id)
.is_some()
};
tracing::debug!("Entity {entity_id} has buff: {has_buff:?}");
has_buff
}
fn check_condition_group(
ctx: &mut NetContext,
entity_id: i64,
level_entity_data: &wicked_waifus_data::level_entity_config_data::LevelEntityConfigData,
template_config: &wicked_waifus_data::template_config_data::TemplateConfigData,
condition: CheckConditionGroup,
) -> bool {
let mut check = true; let mut check = true;
// TODO: Investigate if type has a meaning // TODO: Investigate if type has a meaning
for element in condition.condition.conditions { for element in condition.condition.conditions {
check = check_condition(player, entity_id, level_entity_data, template_config, element); check = check_condition(ctx, entity_id, level_entity_data, template_config, element);
if !check { if !check {
break; break;
} }
} }
check check
} }

View file

@ -3,31 +3,27 @@ use wicked_waifus_protocol::{EEntityType, EntityPb, PlayerSceneAoiData};
use std::collections::HashSet; use std::collections::HashSet;
use crate::logic::components::Visibility; use crate::logic::components::Visibility;
use crate::logic::player::Player;
use crate::{modify_component, query_hn_with}; use crate::{modify_component, query_hn_with};
use crate::logic::thread_mgr::NetContext;
pub fn build_scene_add_on_init_data(player: &Player) -> PlayerSceneAoiData { pub fn build_scene_add_on_init_data(ctx: &mut NetContext) -> PlayerSceneAoiData {
let mut world_ref = player.world.borrow_mut(); let world = ctx.world.get_mut_world_entity();
let world = world_ref.get_mut_world_entity();
let entities = query_hn_with!(world, PlayerOwnedEntityMarker) let entities = query_hn_with!(world, PlayerOwnedEntityMarker)
.into_iter() .into_iter()
.map(|(entity_id, _)| { .map(|(entity_id, _)| {
let res_map: (EEntityType, i32);
match EEntityType::try_from( match EEntityType::try_from(
world.get_entity(world.get_config_id(entity_id)).entity_type, world.get_entity(world.get_config_id(entity_id)).entity_type,
) { ) {
Ok(EEntityType::Player) => { Ok(EEntityType::Player) => {
res_map = (EEntityType::Player, entity_id); (EEntityType::Player, entity_id)
} }
Ok(EEntityType::Monster) => { Ok(EEntityType::Monster) => {
res_map = (EEntityType::Monster, entity_id); (EEntityType::Monster, entity_id)
} }
_ => { _ => {
res_map = (EEntityType::default(), -1); (EEntityType::default(), -1)
} }
} }
res_map
}) })
.collect::<HashSet<(EEntityType, i32)>>(); .collect::<HashSet<(EEntityType, i32)>>();
@ -44,9 +40,9 @@ pub fn build_scene_add_on_init_data(player: &Player) -> PlayerSceneAoiData {
world.get_entity_components(entity_id), world.get_entity_components(entity_id),
Visibility, Visibility,
|vis: &mut Visibility| { |vis: &mut Visibility| {
let cur_role_id = player let cur_role_id = ctx.player
.formation_list .formation_list
.get(&player.cur_formation_id) .get(&ctx.player.cur_formation_id)
.unwrap() .unwrap()
.cur_role; .cur_role;
(vis.is_visible, vis.is_actor_visible) = if config_id == cur_role_id { (vis.is_visible, vis.is_actor_visible) = if config_id == cur_role_id {

View file

@ -1,4 +1,5 @@
use wicked_waifus_data::{BasePropertyData, base_property_data, monster_property_growth_data, role_property_growth_data}; use wicked_waifus_data::{base_property_data, monster_property_growth_data, role_property_growth_data};
use wicked_waifus_data::base_property_data::BasePropertyData;
pub fn get_role_props_by_level(id: i32, level: i32, breach: i32) -> BasePropertyData { pub fn get_role_props_by_level(id: i32, level: i32, breach: i32) -> BasePropertyData {
let mut base_props = get_role_props_or_default(id).clone(); let mut base_props = get_role_props_or_default(id).clone();

View file

@ -1,4 +1,4 @@
use wicked_waifus_data::BasePropertyData; use wicked_waifus_data::base_property_data::BasePropertyData;
use wicked_waifus_protocol::EAttributeType; use wicked_waifus_protocol::EAttributeType;
use std::collections::HashMap; use std::collections::HashMap;

View file

@ -1,7 +1,6 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::OnceLock; use std::sync::OnceLock;
use wicked_waifus_data::level_entity_config_data::LevelEntityConfigData;
use wicked_waifus_data::LevelEntityConfigData;
pub(crate) struct StaticConfig { pub(crate) struct StaticConfig {
edge_size: f32, edge_size: f32,

View file

@ -4,18 +4,16 @@ use wicked_waifus_protocol::{
SceneMode, ScenePlayerInformation, SceneTimeInfo, SceneMode, ScenePlayerInformation, SceneTimeInfo,
}; };
use wicked_waifus_data::pb_components::ComponentsData; use crate::logic::components::{
use wicked_waifus_data::{ Autonomous, Fsm, Interact, MonsterAi, ParaglidingSkin, SoarWingSkin, StateTag, Tag, WeaponSkin,
blueprint_config_data, template_config_data, EntityLogic, EntityType, LevelEntityConfigData,
}; };
use crate::logic::components::{Autonomous, Fsm, Interact, MonsterAi, ParaglidingSkin, SoarWingSkin, StateTag, Tag, WeaponSkin};
use crate::logic::ecs::entity::EntityBuilder; use crate::logic::ecs::entity::EntityBuilder;
use crate::logic::ecs::world::World; use crate::logic::ecs::world::World;
use crate::logic::math::Transform; use crate::logic::math::Transform;
use crate::logic::player::Player; use crate::logic::player::Player;
use crate::logic::utils::{entity_serializer, tag_utils}; use crate::logic::thread_mgr::NetContext;
use crate::logic::utils::growth_utils::get_monster_props_by_level; use crate::logic::utils::growth_utils::get_monster_props_by_level;
use crate::logic::utils::{entity_serializer, tag_utils};
use crate::logic::{ use crate::logic::{
components::{ components::{
Attribute, EntityConfig, Equip, FightBuff, Movement, OwnerPlayer, PlayerOwnedEntityMarker, Attribute, EntityConfig, Equip, FightBuff, Movement, OwnerPlayer, PlayerOwnedEntityMarker,
@ -24,6 +22,15 @@ use crate::logic::{
ecs::component::ComponentContainer, ecs::component::ComponentContainer,
}; };
use crate::query_with; use crate::query_with;
use wicked_waifus_data::blueprint_config_data::{EntityLogic, EntityType};
use wicked_waifus_data::level_entity_config_data::LevelEntityConfigData;
use wicked_waifus_data::pb_components::ComponentsData;
use wicked_waifus_data::{blueprint_config_data, template_config_data};
const COUNT_OVERRIDE: &[(i32, i32)] = &[
(1105, 3),
(1301, 4)
];
#[macro_export] #[macro_export]
macro_rules! create_player_entity_pb { macro_rules! create_player_entity_pb {
@ -114,16 +121,18 @@ macro_rules! create_player_entity_pb {
}}; }};
} }
pub fn add_player_entities(player: &Player) { pub fn add_player_entities(ctx: &mut NetContext) {
let mut world_ref = player.world.borrow_mut(); let world = ctx.world.get_mut_world_entity();
let world = world_ref.get_mut_world_entity(); let current_formation = ctx
.player
let current_formation = player.formation_list.get(&player.cur_formation_id).unwrap(); .formation_list
.get(&ctx.player.cur_formation_id)
.unwrap();
let role_vec = current_formation let role_vec = current_formation
.role_ids .role_ids
.iter() .iter()
.map(|role_id| player.role_list.get(&role_id).unwrap()) .map(|role_id| ctx.player.role_list.get(role_id).unwrap())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let cur_role_id = current_formation.cur_role; let cur_role_id = current_formation.cur_role;
@ -132,7 +141,7 @@ pub fn add_player_entities(player: &Player) {
let entity = world.create_entity( let entity = world.create_entity(
role.role_id, role.role_id,
EEntityType::Player.into(), EEntityType::Player.into(),
player.basic_info.cur_map_id, ctx.player.basic_info.cur_map_id,
); );
// Once per character buffs are implemented, add a mut on role_buffs // Once per character buffs are implemented, add a mut on role_buffs
let fight_buff_infos = world.generate_role_permanent_buffs(entity.entity_id as i64); let fight_buff_infos = world.generate_role_permanent_buffs(entity.entity_id as i64);
@ -155,10 +164,10 @@ pub fn add_player_entities(player: &Player) {
entity_state: EntityState::Default, entity_state: EntityState::Default,
})) }))
.with(ComponentContainer::OwnerPlayer(OwnerPlayer( .with(ComponentContainer::OwnerPlayer(OwnerPlayer(
player.basic_info.id, ctx.player.basic_info.id,
))) )))
.with(ComponentContainer::Position(Position( .with(ComponentContainer::Position(Position(
player.location.position.clone(), ctx.player.location.position.clone(),
))) )))
.with(ComponentContainer::Visibility(Visibility { .with(ComponentContainer::Visibility(Visibility {
is_visible: role.role_id == cur_role_id, is_visible: role.role_id == cur_role_id,
@ -178,7 +187,7 @@ pub fn add_player_entities(player: &Player) {
weapon_breach_level: 0, // TODO: store this too weapon_breach_level: 0, // TODO: store this too
})) }))
.with(ComponentContainer::VisionSkill(VisionSkill { .with(ComponentContainer::VisionSkill(VisionSkill {
skill_id: player.explore_tools.active_explore_skill, skill_id: ctx.player.explore_tools.active_explore_skill,
})) }))
.with(ComponentContainer::RoleSkin(RoleSkin { .with(ComponentContainer::RoleSkin(RoleSkin {
skin_id: role.skin_id, skin_id: role.skin_id,
@ -204,23 +213,23 @@ pub fn add_player_entities(player: &Player) {
} }
} }
pub fn build_scene_information(player: &Player) -> SceneInformation { pub fn build_scene_information(ctx: &mut NetContext) -> SceneInformation {
SceneInformation { SceneInformation {
scene_id: String::new(), scene_id: String::new(),
instance_id: player.location.instance_id, instance_id: ctx.player.location.instance_id,
owner_id: player.basic_info.id, owner_id: ctx.player.basic_info.id,
dynamic_entity_list: Vec::new(), dynamic_entity_list: Vec::new(),
blackboard_params: Vec::new(), blackboard_params: Vec::new(),
end_time: 0, end_time: 0,
aoi_data: Some(entity_serializer::build_scene_add_on_init_data(player)), aoi_data: Some(entity_serializer::build_scene_add_on_init_data(ctx)),
player_infos: build_player_info_list(&player.world.borrow_mut()), player_infos: build_player_info_list(ctx.world),
mode: SceneMode::Single.into(), mode: SceneMode::Single.into(),
time_info: Some(SceneTimeInfo { time_info: Some(SceneTimeInfo {
owner_time_clock_time_span: 0, owner_time_clock_time_span: 0,
hour: 8, hour: 8,
minute: 0, minute: 0,
}), }),
cur_context_id: player.basic_info.id as i64, cur_context_id: ctx.player.basic_info.id as i64,
..Default::default() ..Default::default()
} }
} }
@ -255,7 +264,9 @@ fn build_player_info_list(world: &World) -> Vec<ScenePlayerInformation> {
EntityConfig EntityConfig
) )
.into_iter() .into_iter()
.filter(|(_, _, owner, _)| owner.0 == sp.player_id); .filter(|(_, e, owner, _)| {
owner.0 == sp.player_id && e.entity_type == EEntityType::Player
});
ScenePlayerInformation { ScenePlayerInformation {
cur_role: cur_role_id, cur_role: cur_role_id,
@ -287,12 +298,14 @@ fn build_player_info_list(world: &World) -> Vec<ScenePlayerInformation> {
.collect() .collect()
} }
pub fn remove_entity(player: &Player, entity_id: i64, remove_type: ERemoveEntityType) { pub fn remove_entity(ctx: &mut NetContext, entity_id: i64, remove_type: ERemoveEntityType) {
let mut world_ref = player.world.borrow_mut(); if ctx
let world = world_ref.get_mut_world_entity(); .world
.get_mut_world_entity()
if world.remove_entity(entity_id as i32) { .remove_entity(entity_id as i32)
player.notify(EntityRemoveNotify { {
// TODO: For COOP find a way to get players from world
ctx.player.notify(EntityRemoveNotify {
remove_infos: vec![EntityRemoveInfo { remove_infos: vec![EntityRemoveInfo {
entity_id, entity_id,
r#type: remove_type.into(), r#type: remove_type.into(),
@ -302,22 +315,19 @@ pub fn remove_entity(player: &Player, entity_id: i64, remove_type: ERemoveEntity
} }
} }
pub fn remove_entities(player: &Player, entities: &[&LevelEntityConfigData]) { pub fn remove_entities(ctx: &mut NetContext, entities: &[&LevelEntityConfigData]) {
let mut removed_entities = Vec::with_capacity(entities.len()); let mut removed_entities = Vec::with_capacity(entities.len());
// Enclose to drop borrow mut ASAP
{
let mut world_ref = player.world.borrow_mut();
let world = world_ref.get_mut_world_entity();
for entity in entities { let world = ctx.world.get_mut_world_entity();
let entity_id = entity.entity_id as i32; // TODO: Should be i64 for entity in entities {
if world.remove_entity(entity_id) { let entity_id = entity.entity_id as i32; // TODO: Should be i64
removed_entities.push(world.get_entity_id(entity_id)); if world.remove_entity(entity_id) {
} removed_entities.push(world.get_entity_id(entity_id));
} }
} }
for entity_id in removed_entities { for entity_id in removed_entities {
player.notify(EntityRemoveNotify { // TODO: For COOP find a way to get players from world
ctx.player.notify(EntityRemoveNotify {
remove_infos: vec![EntityRemoveInfo { remove_infos: vec![EntityRemoveInfo {
entity_id, entity_id,
r#type: 0, r#type: 0,
@ -327,128 +337,139 @@ pub fn remove_entities(player: &Player, entities: &[&LevelEntityConfigData]) {
} }
} }
pub fn add_entities(player: &Player, entities: &[&LevelEntityConfigData], external_awake: bool) { pub fn add_entities(
ctx: &mut NetContext,
entities: &[&LevelEntityConfigData],
external_awake: bool,
) {
let mut added_entities = Vec::with_capacity(entities.len()); let mut added_entities = Vec::with_capacity(entities.len());
// Enclose to drop borrow mut ASAP
{
let mut world_ref = player.world.borrow_mut();
let world = world_ref.get_mut_world_entity();
for entity in entities { let world = ctx.world.get_mut_world_entity();
// Skip hidden entities for entity in entities {
if entity.is_hidden { // Skip hidden entities
tracing::debug!("Hidden entity with config id: {}", entity.entity_id); if entity.is_hidden {
continue; tracing::debug!("Hidden entity with config id: {}", entity.entity_id);
} continue;
if entity.in_sleep && !external_awake { }
if entity.in_sleep && !external_awake {
tracing::debug!(
"Sleep entity with config id not spawned: {}",
entity.entity_id
);
continue;
}
let blueprint_config = blueprint_config_data::get(&entity.blueprint_type);
let template_config = template_config_data::get(&entity.blueprint_type);
if blueprint_config.is_none() || template_config.is_none() {
continue;
}
let entity_logic: EntityLogic = blueprint_config.unwrap().entity_logic;
let (config_type, entity_type, mut entity_state) = match entity_logic {
EntityLogic::Item => (
EntityConfigType::Level,
EEntityType::SceneItem,
EntityState::Default,
),
EntityLogic::Animal => (
EntityConfigType::Level,
EEntityType::Animal,
EntityState::Default,
),
EntityLogic::Monster => (
EntityConfigType::Level,
EEntityType::Monster,
EntityState::Born,
),
EntityLogic::Vehicle => (
EntityConfigType::Level,
EEntityType::Vehicle,
EntityState::Default,
),
EntityLogic::Npc => (
EntityConfigType::Level,
EEntityType::Npc,
EntityState::Default,
),
EntityLogic::Vision => (
EntityConfigType::Level,
EEntityType::Vision,
EntityState::Default,
),
EntityLogic::ClientOnly => (
EntityConfigType::Level,
EEntityType::ClientOnly,
EntityState::Default,
),
EntityLogic::ServerOnly => {
tracing::debug!( tracing::debug!(
"Sleep entity with config id not spawned: {}", "Unhandled entity to be added of logic: {:?} with blueprint_type {} and id: {}",
entity_logic,
entity.blueprint_type,
entity.entity_id entity.entity_id
); );
continue; continue;
} }
EntityLogic::Custom => (
EntityConfigType::Level,
EEntityType::Custom,
EntityState::Default,
),
};
let blueprint_config = blueprint_config_data::get(&entity.blueprint_type); if entity.in_sleep {
let template_config = template_config_data::get(&entity.blueprint_type); entity_state = EntityState::Sleep;
if blueprint_config.is_none() || template_config.is_none() {
continue;
}
let entity_logic: EntityLogic = blueprint_config.unwrap().entity_logic;
let (config_type, entity_type, mut entity_state) = match entity_logic {
EntityLogic::Item => (
EntityConfigType::Level,
EEntityType::SceneItem,
EntityState::Default,
),
EntityLogic::Animal => (
EntityConfigType::Level,
EEntityType::Animal,
EntityState::Default,
),
EntityLogic::Monster => (
EntityConfigType::Level,
EEntityType::Monster,
EntityState::Born,
),
EntityLogic::Vehicle => (
EntityConfigType::Level,
EEntityType::Vehicle,
EntityState::Default,
),
EntityLogic::Npc => (
EntityConfigType::Level,
EEntityType::Npc,
EntityState::Default,
),
EntityLogic::Vision => (
EntityConfigType::Level,
EEntityType::Vision,
EntityState::Default,
),
EntityLogic::ClientOnly => (
EntityConfigType::Level,
EEntityType::ClientOnly,
EntityState::Default,
),
EntityLogic::ServerOnly => {
tracing::debug!("Unhandled entity to be added of logic: {:?} with blueprint_type {} and id: {}", entity_logic, entity.blueprint_type, entity.entity_id);
continue;
}
EntityLogic::Custom => (
EntityConfigType::Level,
EEntityType::Custom,
EntityState::Default,
),
};
if entity.in_sleep {
entity_state = EntityState::Sleep;
}
let config_id = entity.entity_id as i32; // TODO: i64????
let map_id = entity.map_id;
let components: ComponentsData = entity
.components_data
.merge_with_template(&template_config.unwrap().components_data);
let tmp_entity = world.create_entity(config_id, config_type.into(), map_id);
let mut builder = world.create_builder(tmp_entity);
builder
.with(ComponentContainer::EntityConfig(EntityConfig {
camp: components
.base_info_component
.as_ref()
.and_then(|b| b.camp)
.unwrap_or(0),
config_id,
config_type,
entity_type,
entity_state,
}))
.with(ComponentContainer::Position(Position(Transform::from(
&entity.transform[..],
))))
.with(ComponentContainer::Visibility(Visibility {
is_visible: true,
is_actor_visible: true,
}))
// Some entities may not actually have movement, but it's okay since we won't
// receive move package push for them
.with(ComponentContainer::Movement(Movement::default()));
build_autonomous_component(&mut builder, player.basic_info.id, entity_logic);
build_interact_component(&mut builder, &components);
build_tags_components(&mut builder, &components, player, blueprint_config.unwrap().entity_type, config_id as i64);
build_attribute_component(&mut builder, &components, player.location.instance_id);
build_ai_components(&mut builder, &components);
added_entities.push(builder.build());
} }
let config_id = entity.entity_id as i32; // TODO: i64????
let map_id = entity.map_id;
let components: ComponentsData = entity
.components_data
.merge_with_template(&template_config.unwrap().components_data);
let tmp_entity = world.create_entity(config_id, config_type.into(), map_id);
let mut builder = world.create_builder(tmp_entity);
builder
.with(ComponentContainer::EntityConfig(EntityConfig {
camp: components
.base_info_component
.as_ref()
.and_then(|b| b.camp)
.unwrap_or(0),
config_id,
config_type,
entity_type,
entity_state,
}))
.with(ComponentContainer::Position(Position(Transform::from(
&entity.transform[..],
))))
.with(ComponentContainer::Visibility(Visibility {
is_visible: true,
is_actor_visible: true,
}))
// Some entities may not actually have movement, but it's okay since we won't
// receive move package push for them
.with(ComponentContainer::Movement(Movement::default()));
build_autonomous_component(&mut builder, ctx.player.basic_info.id, entity_logic);
build_interact_component(&mut builder, &components);
build_tags_components(
&mut builder,
&components,
ctx.player,
blueprint_config.unwrap().entity_type,
config_id as i64,
);
build_attribute_component(&mut builder, &components, ctx.player.location.instance_id);
build_ai_components(&mut builder, &components);
added_entities.push(builder.build());
} }
let world_ref = player.world.borrow(); let world = ctx.world.get_world_entity();
let world = world_ref.get_world_entity();
// Since kuro has issues, we can only send one // Since kuro has issues, we can only send one
for entity in added_entities { for entity in added_entities {
// TODO: For COOP find a way to get players from world
let mut pb = EntityPb { let mut pb = EntityPb {
id: entity.entity_id as i64, // TODO: Should be i64 id: entity.entity_id as i64, // TODO: Should be i64
..Default::default() ..Default::default()
@ -459,7 +480,7 @@ pub fn add_entities(player: &Player, entities: &[&LevelEntityConfigData], extern
.into_iter() .into_iter()
.for_each(|comp| comp.set_pb_data(&mut pb)); .for_each(|comp| comp.set_pb_data(&mut pb));
player.notify(EntityAddNotify { ctx.player.notify(EntityAddNotify {
entity_pbs: vec![pb], entity_pbs: vec![pb],
remove_tag_ids: true, remove_tag_ids: true,
}); });
@ -504,7 +525,10 @@ fn build_tags_components(
if let Some(entity_state_component) = &components.entity_state_component { if let Some(entity_state_component) = &components.entity_state_component {
let state = match entity_type { let state = match entity_type {
EntityType::Teleporter | EntityType::TemporaryTeleporter => { EntityType::Teleporter | EntityType::TemporaryTeleporter => {
let result = player.teleports.teleports_data.iter() let result = player
.teleports
.teleports_data
.iter()
.find(|teleporter| teleporter.entity_config_id == config_id); .find(|teleporter| teleporter.entity_config_id == config_id);
match result.is_some() { match result.is_some() {
true => tag_utils::get_tag_id_by_name("关卡.Common.状态.激活"), true => tag_utils::get_tag_id_by_name("关卡.Common.状态.激活"),

View file

@ -59,7 +59,10 @@ impl<S: Clone + Send + Sync + 'static> Application<S> {
} }
pub fn serve_dir(mut self, path: &str, dir: &str) -> Self { pub fn serve_dir(mut self, path: &str, dir: &str) -> Self {
self.router = self.router.nest_service(path, ServeDir::new(dir)); self.router = match path {
"" | "/" => self.router.fallback_service(ServeDir::new(dir)),
_ => self.router.nest_service(path, ServeDir::new(dir))
};
self self
} }

View file

@ -148,9 +148,33 @@ message PlayerInventoryWeaponData {
int32 role_id = 7; int32 role_id = 7;
} }
message PhantomPropInfo {
int32 prop_id = 1;
int32 value = 2;
}
message PlayerInventoryPhantomData {
int32 id = 1;
int32 func_value = 2;
int32 level = 3;
int32 exp = 4;
repeated PhantomPropInfo main_prop = 5; // TODO: repeated vs map
repeated PhantomPropInfo sub_prop = 6; // TODO: repeated vs map
int32 fetter_group_id = 7;
int32 skin_id = 8;
int32 role_id = 9;
}
message PlayerInventoryPhantomLoadoutData {
int32 name = 1;
map<int32, int32> incr_id = 2; // Key is position (0,1,2,3,4), value is incr_id
}
message PlayerInventoryData { message PlayerInventoryData {
map<int32, int32> items = 1; map<int32, int32> items = 1;
map<int32, PlayerInventoryWeaponData> weapons = 2; map<int32, PlayerInventoryWeaponData> weapons = 2; // Key is incr_id
map<int32, PlayerInventoryPhantomData> echoes = 3; // Key is incr_id
map<int32, PlayerInventoryPhantomLoadoutData> echo_presets = 4; // Key is loadout number
} }
message PlayerTeleportData { message PlayerTeleportData {
@ -201,6 +225,7 @@ message PlayerUnlockedSkinsData {
repeated int32 weapon_skins = 2; repeated int32 weapon_skins = 2;
repeated int32 fly_skins = 3; repeated int32 fly_skins = 3;
repeated int32 wing_skins = 4; repeated int32 wing_skins = 4;
repeated int32 echo_skins = 5;
} }
message PlayerSaveData { message PlayerSaveData {