Compare commits
4 commits
44e7ec1527
...
90179f1001
Author | SHA1 | Date | |
---|---|---|---|
90179f1001 | |||
46e57fe2dc | |||
432c68ff74 | |||
be69d00e2c |
32 changed files with 2681861 additions and 126 deletions
20
Cargo.lock
generated
20
Cargo.lock
generated
|
@ -402,7 +402,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
|
checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"hashbrown",
|
"hashbrown 0.14.5",
|
||||||
"lock_api",
|
"lock_api",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"parking_lot_core",
|
"parking_lot_core",
|
||||||
|
@ -416,7 +416,7 @@ checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
"hashbrown",
|
"hashbrown 0.14.5",
|
||||||
"lock_api",
|
"lock_api",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"parking_lot_core",
|
"parking_lot_core",
|
||||||
|
@ -724,13 +724,19 @@ dependencies = [
|
||||||
"allocator-api2",
|
"allocator-api2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashlink"
|
name = "hashlink"
|
||||||
version = "0.9.1"
|
version = "0.9.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af"
|
checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hashbrown",
|
"hashbrown 0.14.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -890,12 +896,12 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.4.0"
|
version = "2.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c"
|
checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown",
|
"hashbrown 0.15.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1927,7 +1933,7 @@ dependencies = [
|
||||||
"futures-intrusive",
|
"futures-intrusive",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"hashbrown",
|
"hashbrown 0.14.5",
|
||||||
"hashlink",
|
"hashlink",
|
||||||
"hex",
|
"hex",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
FROM rust:1.81-alpine3.20
|
FROM rust:1.82-alpine3.20
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
|
@ -2,5 +2,5 @@ FROM alpine:3.20
|
||||||
ARG MICROSERVICE
|
ARG MICROSERVICE
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY --from=camellya-builder:1.3.0-SNAPSHOT /app/target/release/$MICROSERVICE ./service
|
COPY --from=wicked-waifus-builder:1.4.0-SNAPSHOT /app/target/release/$MICROSERVICE ./service
|
||||||
CMD ["./service"]
|
CMD ["./service"]
|
2681165
assets/logic/BinData/LevelEntityConfig.json
Normal file
2681165
assets/logic/BinData/LevelEntityConfig.json
Normal file
File diff suppressed because it is too large
Load diff
16
builder.bat
16
builder.bat
|
@ -1,12 +1,12 @@
|
||||||
docker build -t camellya-builder:1.3.0-SNAPSHOT -f Dockerfile-builder .
|
docker build -t wicked-waifus-builder:1.4.0-SNAPSHOT -f Dockerfile-builder .
|
||||||
|
|
||||||
docker build -t camellya-config-server:1.3.0-SNAPSHOT --build-arg MICROSERVICE=config-server -f Dockerfile-service .
|
docker build -t wicked-waifus-config-server:1.4.0-SNAPSHOT --build-arg MICROSERVICE=config-server -f Dockerfile-service .
|
||||||
docker build -t camellya-hotpatch-server:1.3.0-SNAPSHOT --build-arg MICROSERVICE=hotpatch-server -f Dockerfile-service .
|
docker build -t wicked-waifus-hotpatch-server:1.4.0-SNAPSHOT --build-arg MICROSERVICE=hotpatch-server -f Dockerfile-service .
|
||||||
docker build -t camellya-login-server:1.3.0-SNAPSHOT --build-arg MICROSERVICE=login-server -f Dockerfile-service .
|
docker build -t wicked-waifus-login-server:1.4.0-SNAPSHOT --build-arg MICROSERVICE=login-server -f Dockerfile-service .
|
||||||
docker build -t camellya-gateway-server:1.3.0-SNAPSHOT --build-arg MICROSERVICE=gateway-server -f Dockerfile-service .
|
docker build -t wicked-waifus-gateway-server:1.4.0-SNAPSHOT --build-arg MICROSERVICE=gateway-server -f Dockerfile-service .
|
||||||
docker build -t camellya-game-server:1.3.0-SNAPSHOT --build-arg MICROSERVICE=game-server -f Dockerfile-service .
|
docker build -t wicked-waifus-game-server:1.4.0-SNAPSHOT --build-arg MICROSERVICE=game-server -f Dockerfile-service .
|
||||||
|
|
||||||
docker rmi camellya-builder:1.3.0-SNAPSHOT
|
docker rmi wicked-waifus-builder:1.4.0-SNAPSHOT
|
||||||
|
|
||||||
: Persistence for the application
|
: Persistence for the application
|
||||||
docker volume create camellya-postgres-vol
|
: docker volume create wicked-waifus-postgres-vol
|
16
builder.sh
16
builder.sh
|
@ -1,12 +1,12 @@
|
||||||
docker build -t camellya-builder:1.3.0-SNAPSHOT -f Dockerfile-builder .
|
docker build -t wicked-waifus-builder:1.4.0-SNAPSHOT -f Dockerfile-builder .
|
||||||
|
|
||||||
docker build -t camellya-config-server:1.3.0-SNAPSHOT --build-arg MICROSERVICE=config-server -f Dockerfile-service .
|
docker build -t wicked-waifus-config-server:1.4.0-SNAPSHOT --build-arg MICROSERVICE=config-server -f Dockerfile-service .
|
||||||
docker build -t camellya-hotpatch-server:1.3.0-SNAPSHOT --build-arg MICROSERVICE=hotpatch-server -f Dockerfile-service .
|
docker build -t wicked-waifus-hotpatch-server:1.4.0-SNAPSHOT --build-arg MICROSERVICE=hotpatch-server -f Dockerfile-service .
|
||||||
docker build -t camellya-login-server:1.3.0-SNAPSHOT --build-arg MICROSERVICE=login-server -f Dockerfile-service .
|
docker build -t wicked-waifus-login-server:1.4.0-SNAPSHOT --build-arg MICROSERVICE=login-server -f Dockerfile-service .
|
||||||
docker build -t camellya-gateway-server:1.3.0-SNAPSHOT --build-arg MICROSERVICE=gateway-server -f Dockerfile-service .
|
docker build -t wicked-waifus-gateway-server:1.4.0-SNAPSHOT --build-arg MICROSERVICE=gateway-server -f Dockerfile-service .
|
||||||
docker build -t camellya-game-server:1.3.0-SNAPSHOT --build-arg MICROSERVICE=game-server -f Dockerfile-service .
|
docker build -t wicked-waifus-game-server:1.4.0-SNAPSHOT --build-arg MICROSERVICE=game-server -f Dockerfile-service .
|
||||||
|
|
||||||
docker rmi camellya-builder:1.3.0-SNAPSHOT
|
docker rmi wicked-waifus-builder:1.4.0-SNAPSHOT
|
||||||
|
|
||||||
# Persistence for the application
|
# Persistence for the application
|
||||||
docker volume create camellya-postgres-vol
|
# docker volume create wicked-waifus-postgres-vol
|
|
@ -1,10 +1,10 @@
|
||||||
name: camellya-ps
|
name: wicked-waifus-ps
|
||||||
|
|
||||||
services:
|
services:
|
||||||
camellya-hotpatch-server:
|
wicked-waifus-hotpatch-server:
|
||||||
image: camellya-hotpatch-server:1.3.0-SNAPSHOT
|
image: wicked-waifus-hotpatch-server:1.4.0-SNAPSHOT
|
||||||
depends_on:
|
depends_on:
|
||||||
camellya-postgres:
|
wicked-waifus-postgres:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
ports:
|
ports:
|
||||||
- '10002:10002'
|
- '10002:10002'
|
||||||
|
|
|
@ -1,29 +1,29 @@
|
||||||
name: camellya-ps
|
name: wicked-waifus-ps
|
||||||
|
|
||||||
services:
|
services:
|
||||||
camellya-config-server:
|
wicked-waifus-config-server:
|
||||||
image: camellya-config-server:1.3.0-SNAPSHOT
|
image: wicked-waifus-config-server:1.4.0-SNAPSHOT
|
||||||
depends_on:
|
depends_on:
|
||||||
camellya-postgres:
|
wicked-waifus-postgres:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
ports:
|
ports:
|
||||||
- '10001:10001'
|
- '10001:10001'
|
||||||
volumes:
|
volumes:
|
||||||
- "./docker/configserver.toml:/app/configserver.toml"
|
- "./docker/configserver.toml:/app/configserver.toml"
|
||||||
- "./assets/config:/app/assets/config"
|
- "./assets/config:/app/assets/config"
|
||||||
camellya-login-server:
|
wicked-waifus-login-server:
|
||||||
image: camellya-login-server:1.3.0-SNAPSHOT
|
image: wicked-waifus-login-server:1.4.0-SNAPSHOT
|
||||||
depends_on:
|
depends_on:
|
||||||
camellya-postgres:
|
wicked-waifus-postgres:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
ports:
|
ports:
|
||||||
- '5500:5500'
|
- '5500:5500'
|
||||||
volumes:
|
volumes:
|
||||||
- "./docker/loginserver.toml:/app/loginserver.toml"
|
- "./docker/loginserver.toml:/app/loginserver.toml"
|
||||||
camellya-gateway-server:
|
wicked-waifus-gateway-server:
|
||||||
image: camellya-gateway-server:1.3.0-SNAPSHOT
|
image: wicked-waifus-gateway-server:1.4.0-SNAPSHOT
|
||||||
depends_on:
|
depends_on:
|
||||||
camellya-postgres:
|
wicked-waifus-postgres:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
ports:
|
ports:
|
||||||
# Uncomment this if you want to have manual access
|
# Uncomment this if you want to have manual access
|
||||||
|
@ -31,10 +31,10 @@ services:
|
||||||
- '7777:7777/udp'
|
- '7777:7777/udp'
|
||||||
volumes:
|
volumes:
|
||||||
- "./docker/gateway.toml:/app/gateway.toml"
|
- "./docker/gateway.toml:/app/gateway.toml"
|
||||||
camellya-game-server:
|
wicked-waifus-game-server:
|
||||||
image: camellya-game-server:1.3.0-SNAPSHOT
|
image: wicked-waifus-game-server:1.4.0-SNAPSHOT
|
||||||
depends_on:
|
depends_on:
|
||||||
camellya-postgres:
|
wicked-waifus-postgres:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
# Uncomment this if you want to have manual access
|
# Uncomment this if you want to have manual access
|
||||||
# ports:
|
# ports:
|
||||||
|
@ -42,7 +42,7 @@ services:
|
||||||
volumes:
|
volumes:
|
||||||
- "./docker/gameserver.toml:/app/gameserver.toml"
|
- "./docker/gameserver.toml:/app/gameserver.toml"
|
||||||
- "./assets/logic:/app/assets/logic"
|
- "./assets/logic:/app/assets/logic"
|
||||||
camellya-postgres:
|
wicked-waifus-postgres:
|
||||||
image: postgres:16.4-alpine3.20
|
image: postgres:16.4-alpine3.20
|
||||||
user: postgres
|
user: postgres
|
||||||
# Uncomment this if you want to have manual access
|
# Uncomment this if you want to have manual access
|
||||||
|
@ -57,7 +57,7 @@ services:
|
||||||
- "POSTGRES_PASSWORD=toor"
|
- "POSTGRES_PASSWORD=toor"
|
||||||
volumes:
|
volumes:
|
||||||
- "./docker/postgres/scripts:/docker-entrypoint-initdb.d"
|
- "./docker/postgres/scripts:/docker-entrypoint-initdb.d"
|
||||||
- camellya-postgres-vol:/var/lib/postgresql/data
|
- wicked-waifus-postgres-vol:/var/lib/postgresql/data
|
||||||
volumes:
|
volumes:
|
||||||
camellya-postgres-vol:
|
wicked-waifus-postgres-vol:
|
||||||
external: true
|
external: true
|
|
@ -1,13 +1,13 @@
|
||||||
service_id = 2
|
service_id = 2
|
||||||
|
|
||||||
[database]
|
[database]
|
||||||
host = "shorekeeper-postgres:5432"
|
host = "wicked-waifus-postgres:5432"
|
||||||
user_name = "shorekeeper_user"
|
user_name = "wicked_waifus_user"
|
||||||
password = "shorekeeper_pass"
|
password = "wicked_waifus_pass"
|
||||||
db_name = "shorekeeper_db"
|
db_name = "wicked_waifus_db"
|
||||||
|
|
||||||
[service_end_point]
|
[service_end_point]
|
||||||
addr = "tcp://0.0.0.0:10004"
|
addr = "tcp://0.0.0.0:10004"
|
||||||
|
|
||||||
[gateway_end_point]
|
[gateway_end_point]
|
||||||
addr = "tcp://shorekeeper-gateway-server:10003"
|
addr = "tcp://wicked-waifus-gateway-server:10003"
|
||||||
|
|
|
@ -11,10 +11,10 @@ use_client_key = true
|
||||||
addr = "tcp://0.0.0.0:10003"
|
addr = "tcp://0.0.0.0:10003"
|
||||||
|
|
||||||
[game_server_end_point]
|
[game_server_end_point]
|
||||||
addr = "tcp://shorekeeper-game-server:10004"
|
addr = "tcp://wicked-waifus-game-server:10004"
|
||||||
|
|
||||||
[database]
|
[database]
|
||||||
host = "shorekeeper-postgres:5432"
|
host = "wicked-waifus-postgres:5432"
|
||||||
user_name = "shorekeeper_user"
|
user_name = "wicked_waifus_user"
|
||||||
password = "shorekeeper_pass"
|
password = "wicked_waifus_pass"
|
||||||
db_name = "shorekeeper_db"
|
db_name = "wicked_waifus_db"
|
||||||
|
|
|
@ -6,7 +6,7 @@ host = "host.docker.internal"
|
||||||
port = 7777
|
port = 7777
|
||||||
|
|
||||||
[database]
|
[database]
|
||||||
host = "shorekeeper-postgres:5432"
|
host = "wicked-waifus-postgres:5432"
|
||||||
user_name = "shorekeeper_user"
|
user_name = "wicked_waifus_user"
|
||||||
password = "shorekeeper_pass"
|
password = "wicked_waifus_pass"
|
||||||
db_name = "shorekeeper_db"
|
db_name = "wicked_waifus_db"
|
|
@ -1,3 +1,3 @@
|
||||||
CREATE DATABASE camellya_db;
|
CREATE DATABASE wicked_waifus_db;
|
||||||
CREATE USER camellya_user WITH encrypted password 'camellya_pass';
|
CREATE USER wicked_waifus_user WITH encrypted password 'wicked_waifus_pass';
|
||||||
GRANT ALL PRIVILEGES ON DATABASE camellya_db to camellya_user;
|
GRANT ALL PRIVILEGES ON DATABASE wicked_waifus_db to wicked_waifus_user;
|
|
@ -1,2 +1,2 @@
|
||||||
\c camellya_db;
|
\c wicked_waifus_db;
|
||||||
GRANT ALL ON SCHEMA public TO camellya_user;
|
GRANT ALL ON SCHEMA public TO wicked_waifus_user;
|
|
@ -1,15 +1,19 @@
|
||||||
use shorekeeper_protocol::EntityConfigType;
|
use shorekeeper_protocol::{EEntityType, EntityConfigType, EntityState};
|
||||||
|
|
||||||
use crate::logic::ecs::component::Component;
|
use crate::logic::ecs::component::Component;
|
||||||
|
|
||||||
pub struct EntityConfig {
|
pub struct EntityConfig {
|
||||||
pub config_id: i32,
|
pub config_id: i32,
|
||||||
pub config_type: EntityConfigType,
|
pub config_type: EntityConfigType,
|
||||||
|
pub entity_type: EEntityType,
|
||||||
|
pub entity_state: EntityState
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for EntityConfig {
|
impl Component for EntityConfig {
|
||||||
fn set_pb_data(&self, pb: &mut shorekeeper_protocol::EntityPb) {
|
fn set_pb_data(&self, pb: &mut shorekeeper_protocol::EntityPb) {
|
||||||
pb.config_id = self.config_id;
|
pb.config_id = self.config_id;
|
||||||
pb.config_type = self.config_type.into();
|
pb.config_type = self.config_type.into();
|
||||||
|
pb.entity_type = self.entity_type.into();
|
||||||
|
pb.entity_state = self.entity_state.into();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
25
game-server/src/logic/components/fsm.rs
Normal file
25
game-server/src/logic/components/fsm.rs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
use crate::logic::ecs::component::Component;
|
||||||
|
use shorekeeper_protocol::entity_component_pb::ComponentPb;
|
||||||
|
use shorekeeper_protocol::{DFsm, DFsmBlackBoard, EntityComponentPb, EntityFsmComponentPb, FsmCustomBlackboardDatas};
|
||||||
|
|
||||||
|
pub struct Fsm {
|
||||||
|
pub fsms: Vec<DFsm>,
|
||||||
|
pub hash_code: i32,
|
||||||
|
pub common_hash_code: i32,
|
||||||
|
pub black_board: Vec<DFsmBlackBoard>,
|
||||||
|
pub fsm_custom_blackboard_datas: Option<FsmCustomBlackboardDatas>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Component for Fsm {
|
||||||
|
fn set_pb_data(&self, pb: &mut shorekeeper_protocol::EntityPb) {
|
||||||
|
pb.component_pbs.push(EntityComponentPb {
|
||||||
|
component_pb: Some(ComponentPb::EntityFsmComponentPb(EntityFsmComponentPb {
|
||||||
|
fsms: self.fsms.clone(),
|
||||||
|
hash_code: self.hash_code,
|
||||||
|
common_hash_code: self.common_hash_code,
|
||||||
|
black_board: self.black_board.clone(),
|
||||||
|
fsm_custom_blackboard_datas: self.fsm_custom_blackboard_datas.clone(),
|
||||||
|
})),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,6 +7,8 @@ mod player_entity_marker;
|
||||||
mod position;
|
mod position;
|
||||||
mod visibility;
|
mod visibility;
|
||||||
mod vision_skill;
|
mod vision_skill;
|
||||||
|
mod monster_ai;
|
||||||
|
mod fsm;
|
||||||
|
|
||||||
pub use attribute::Attribute;
|
pub use attribute::Attribute;
|
||||||
pub use entity_config::EntityConfig;
|
pub use entity_config::EntityConfig;
|
||||||
|
@ -17,3 +19,5 @@ pub use player_entity_marker::PlayerEntityMarker;
|
||||||
pub use position::Position;
|
pub use position::Position;
|
||||||
pub use visibility::Visibility;
|
pub use visibility::Visibility;
|
||||||
pub use vision_skill::VisionSkill;
|
pub use vision_skill::VisionSkill;
|
||||||
|
pub use monster_ai::MonsterAi;
|
||||||
|
pub use fsm::Fsm;
|
||||||
|
|
23
game-server/src/logic/components/monster_ai.rs
Normal file
23
game-server/src/logic/components/monster_ai.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
use crate::logic::ecs::component::Component;
|
||||||
|
use shorekeeper_protocol::entity_component_pb::ComponentPb;
|
||||||
|
use shorekeeper_protocol::{EntityComponentPb, MonsterAiComponentPb};
|
||||||
|
|
||||||
|
pub struct MonsterAi {
|
||||||
|
pub weapon_id: i32,
|
||||||
|
pub hatred_group_id: i64,
|
||||||
|
pub ai_team_init_id: i32,
|
||||||
|
pub combat_message_id: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Component for MonsterAi {
|
||||||
|
fn set_pb_data(&self, pb: &mut shorekeeper_protocol::EntityPb) {
|
||||||
|
pb.component_pbs.push(EntityComponentPb {
|
||||||
|
component_pb: Some(ComponentPb::MonsterAiComponentPb(MonsterAiComponentPb {
|
||||||
|
weapon_id: self.weapon_id,
|
||||||
|
hatred_group_id: self.hatred_group_id,
|
||||||
|
ai_team_init_id: self.ai_team_init_id,
|
||||||
|
combat_message_id: self.combat_message_id,
|
||||||
|
})),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -32,6 +32,8 @@ impl_component_container! {
|
||||||
Movement;
|
Movement;
|
||||||
Equip;
|
Equip;
|
||||||
VisionSkill;
|
VisionSkill;
|
||||||
|
MonsterAi;
|
||||||
|
Fsm;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Component {
|
pub trait Component {
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
use crate::{logic::ecs::component::ComponentContainer, logic::player::Player, query_components};
|
use shorekeeper_protocol::{EntityActiveRequest, EntityActiveResponse, EntityLoadCompleteRequest,
|
||||||
use shorekeeper_protocol::entity_component_pb::ComponentPb;
|
EntityLoadCompleteResponse, EntityOnLandedRequest,
|
||||||
use shorekeeper_protocol::{
|
EntityOnLandedResponse, EntityPb, EntityPositionRequest,
|
||||||
EntityActiveRequest, EntityActiveResponse, EntityComponentPb, EntityLoadCompleteRequest,
|
EntityPositionResponse, ErrorCode, MovePackagePush};
|
||||||
EntityLoadCompleteResponse, EntityOnLandedRequest, EntityOnLandedResponse,
|
|
||||||
EntityPositionRequest, EntityPositionResponse, ErrorCode, MovePackagePush,
|
use crate::{logic, logic::ecs::component::ComponentContainer, logic::player::Player, query_components};
|
||||||
};
|
|
||||||
|
|
||||||
pub fn on_entity_active_request(
|
pub fn on_entity_active_request(
|
||||||
player: &Player,
|
player: &Player,
|
||||||
|
@ -23,18 +22,27 @@ pub fn on_entity_active_request(
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
if let (Some(position), Some(attribute)) =
|
let component_pbs = {
|
||||||
|
let mut pb = EntityPb {
|
||||||
|
id: request.entity_id,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
world.get_entity_components(request.entity_id as i32)
|
||||||
|
.into_iter()
|
||||||
|
.for_each(|comp| comp.set_pb_data(&mut pb));
|
||||||
|
pb.component_pbs
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: Remove attribute
|
||||||
|
if let (Some(position), Some(_attribute)) =
|
||||||
query_components!(world, request.entity_id, Position, Attribute)
|
query_components!(world, request.entity_id, Position, Attribute)
|
||||||
{
|
{
|
||||||
response.is_visible = true;
|
response.is_visible = true;
|
||||||
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());
|
||||||
|
|
||||||
response.component_pbs.push(EntityComponentPb {
|
response.component_pbs.extend_from_slice(&component_pbs);
|
||||||
component_pb: Some(ComponentPb::AttributeComponent(
|
|
||||||
attribute.build_entity_attribute(),
|
|
||||||
)),
|
|
||||||
});
|
|
||||||
|
|
||||||
response.error_code = ErrorCode::Success.into();
|
response.error_code = ErrorCode::Success.into();
|
||||||
} else {
|
} else {
|
||||||
|
@ -85,10 +93,12 @@ pub fn on_entity_load_complete_request(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_move_package_push(player: &mut Player, push: MovePackagePush) {
|
pub fn on_move_package_push(player: &mut Player, push: MovePackagePush) {
|
||||||
|
for moving_entity in push.moving_entities {
|
||||||
|
// Query components borrows world component so lets wrap it
|
||||||
|
{
|
||||||
let world_ref = player.world.borrow();
|
let world_ref = player.world.borrow();
|
||||||
let world = world_ref.get_world_entity();
|
let world = world_ref.get_world_entity();
|
||||||
|
|
||||||
for moving_entity in push.moving_entities {
|
|
||||||
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",
|
||||||
|
@ -110,4 +120,20 @@ pub fn on_move_package_push(player: &mut Player, push: MovePackagePush) {
|
||||||
.pending_movement_vec
|
.pending_movement_vec
|
||||||
.extend(moving_entity.move_infos);
|
.extend(moving_entity.move_infos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: review instance id vs map id in world
|
||||||
|
let map = logic::utils::quadrant_util::get_map(player.location.instance_id);
|
||||||
|
let quadrant_id = map.get_quadrant_id(
|
||||||
|
player.location.position.position.x * 100.0,
|
||||||
|
player.location.position.position.y * 100.0,
|
||||||
|
);
|
||||||
|
|
||||||
|
// TODO: This may require some changes for Co-Op
|
||||||
|
if quadrant_id != player.quadrant_id {
|
||||||
|
let (entities_to_remove, entities_to_add) = map.get_update_entities(player.quadrant_id, quadrant_id);
|
||||||
|
player.quadrant_id = quadrant_id;
|
||||||
|
logic::utils::world_util::remove_entities(player, &entities_to_remove);
|
||||||
|
logic::utils::world_util::add_entities(player, &entities_to_add);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use shorekeeper_data::RawVectorData;
|
||||||
use shorekeeper_protocol::{Rotator, TransformData};
|
use shorekeeper_protocol::{Rotator, TransformData};
|
||||||
|
|
||||||
use super::Vector3f;
|
use super::Vector3f;
|
||||||
|
@ -47,3 +48,12 @@ impl Transform {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<&[RawVectorData]> for Transform {
|
||||||
|
fn from(transform: &[RawVectorData]) -> Self {
|
||||||
|
Self {
|
||||||
|
position: Vector3f::from(&transform[0]),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
use shorekeeper_data::RawVectorData;
|
||||||
use shorekeeper_protocol::{Vector, VectorData};
|
use shorekeeper_protocol::{Vector, VectorData};
|
||||||
|
|
||||||
#[derive(Default, Clone, PartialEq, Debug)]
|
#[derive(Default, Clone, PartialEq, Debug)]
|
||||||
|
@ -40,3 +41,13 @@ impl Vector3f {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<&RawVectorData> for Vector3f {
|
||||||
|
fn from(transform: &RawVectorData) -> Self {
|
||||||
|
Self {
|
||||||
|
x: transform.x / 100.0,
|
||||||
|
y: transform.y / 100.0,
|
||||||
|
z: transform.z / 100.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
use common::time_util;
|
use common::time_util;
|
||||||
use shorekeeper_protocol::{
|
use shorekeeper_protocol::{
|
||||||
EEntityType, ERemoveEntityType, EntityAddNotify, EntityConfigType, EntityPb, EntityRemoveInfo,
|
EEntityType, EntityState, ERemoveEntityType, EntityAddNotify, EntityConfigType, EntityPb, EntityRemoveInfo,
|
||||||
EntityRemoveNotify, FightFormationNotifyInfo, FightRoleInfo, FightRoleInfos, FormationRoleInfo,
|
EntityRemoveNotify, FightFormationNotifyInfo, FightRoleInfo, FightRoleInfos, FormationRoleInfo,
|
||||||
GroupFormation, ItemPkgOpenNotify, LivingStatus, PbGetRoleListNotify, PlayerBasicData,
|
GroupFormation, ItemPkgOpenNotify, LivingStatus, PbGetRoleListNotify, PlayerBasicData,
|
||||||
PlayerFightFormations, PlayerRoleData, PlayerSaveData, ProtocolUnit, UpdateFormationNotify,
|
PlayerFightFormations, PlayerRoleData, PlayerSaveData, ProtocolUnit, UpdateFormationNotify,
|
||||||
|
@ -55,6 +55,7 @@ pub struct Player {
|
||||||
// Runtime
|
// Runtime
|
||||||
pub world: Rc<RefCell<World>>,
|
pub world: Rc<RefCell<World>>,
|
||||||
pub last_save_time: u64,
|
pub last_save_time: u64,
|
||||||
|
pub quadrant_id: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Player {
|
impl Player {
|
||||||
|
@ -312,6 +313,7 @@ impl Player {
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
world: Rc::new(RefCell::new(World::new())),
|
world: Rc::new(RefCell::new(World::new())),
|
||||||
last_save_time: time_util::unix_timestamp(),
|
last_save_time: time_util::unix_timestamp(),
|
||||||
|
quadrant_id: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,10 +19,7 @@ use std::{
|
||||||
|
|
||||||
use super::{ecs::world::World, player::Player, utils::world_util};
|
use super::{ecs::world::World, player::Player, utils::world_util};
|
||||||
use crate::logic::ecs::world::WorldEntity;
|
use crate::logic::ecs::world::WorldEntity;
|
||||||
use crate::{
|
use crate::{logic, player_save_task::{self, PlayerSaveReason}, session::Session};
|
||||||
player_save_task::{self, PlayerSaveReason},
|
|
||||||
session::Session,
|
|
||||||
};
|
|
||||||
|
|
||||||
const WATER_MASK: &str = include_str!("../../watermask-rr.js");
|
const WATER_MASK: &str = include_str!("../../watermask-rr.js");
|
||||||
const UID_FIX: &str = include_str!("../../uidfix.js");
|
const UID_FIX: &str = include_str!("../../uidfix.js");
|
||||||
|
@ -200,6 +197,16 @@ fn handle_logic_input(state: &mut LogicState, input: LogicInput) {
|
||||||
content: CENSORSHIP_FIX.to_string(),
|
content: CENSORSHIP_FIX.to_string(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let map = logic::utils::quadrant_util::get_map(player.location.instance_id);
|
||||||
|
let quadrant_id = map.get_quadrant_id(
|
||||||
|
player.location.position.position.x * 100.0,
|
||||||
|
player.location.position.position.y * 100.0,
|
||||||
|
);
|
||||||
|
player.quadrant_id = quadrant_id;
|
||||||
|
|
||||||
|
let entities = map.get_initial_entities(quadrant_id);
|
||||||
|
world_util::add_entities(&player, &entities);
|
||||||
|
|
||||||
drop(player);
|
drop(player);
|
||||||
|
|
||||||
state
|
state
|
||||||
|
@ -224,6 +231,7 @@ fn handle_logic_input(state: &mut LogicState, input: LogicInput) {
|
||||||
|
|
||||||
let _ = state.worlds.remove(&player_id);
|
let _ = state.worlds.remove(&player_id);
|
||||||
// TODO: kick co-op players from removed world
|
// TODO: kick co-op players from removed world
|
||||||
|
// TODO: Remove all entitie
|
||||||
|
|
||||||
player_save_task::push(
|
player_save_task::push(
|
||||||
player_id,
|
player_id,
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
pub mod entity_serializer;
|
pub mod entity_serializer;
|
||||||
pub mod load_role_info;
|
pub mod load_role_info;
|
||||||
pub mod world_util;
|
pub mod world_util;
|
||||||
|
pub mod quadrant_util;
|
||||||
|
|
230
game-server/src/logic/utils/quadrant_util.rs
Normal file
230
game-server/src/logic/utils/quadrant_util.rs
Normal file
|
@ -0,0 +1,230 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
|
use shorekeeper_data::LevelEntityConfigData;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct MapBounds {
|
||||||
|
x_max: f32,
|
||||||
|
x_min: f32,
|
||||||
|
x_translate: f32,
|
||||||
|
y_max: f32,
|
||||||
|
y_min: f32,
|
||||||
|
y_translate: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct Quadrant {
|
||||||
|
entities: HashMap<i64, &'static LevelEntityConfigData>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Map {
|
||||||
|
bounds: MapBounds,
|
||||||
|
width: u64,
|
||||||
|
height: u64,
|
||||||
|
quadrants: HashMap<u64, Quadrant>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Make it configurable?
|
||||||
|
const EDGE_SIZE: f32 = 1000000f32;
|
||||||
|
const EDGE_CHECK: f32 = EDGE_SIZE * 3.0f32;
|
||||||
|
|
||||||
|
pub(crate) static MAP_TABLE: OnceLock<HashMap<i32, Map>> = OnceLock::new();
|
||||||
|
|
||||||
|
impl MapBounds {
|
||||||
|
fn find_max_min(slice: &[&LevelEntityConfigData]) -> (Self, bool) {
|
||||||
|
let mut x_max = 0f32;
|
||||||
|
let mut x_min = 0f32;
|
||||||
|
|
||||||
|
let mut y_max = 0f32;
|
||||||
|
let mut y_min = 0f32;
|
||||||
|
|
||||||
|
// Find max and min coordinates
|
||||||
|
for entity in slice.iter() {
|
||||||
|
if entity.transform[0].x < x_min { x_min = entity.transform[0].x }
|
||||||
|
if entity.transform[0].x > x_max { x_max = entity.transform[0].x }
|
||||||
|
|
||||||
|
if entity.transform[0].y < y_min { y_min = entity.transform[0].y }
|
||||||
|
if entity.transform[0].y > y_max { y_max = entity.transform[0].y }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f32::abs(x_max - x_min) < EDGE_CHECK) || (f32::abs(y_max - y_min) < EDGE_CHECK) {
|
||||||
|
// TODO: Handle this special case, since all entities fit, no need for quadrant
|
||||||
|
|
||||||
|
// Move everything to positive coordinates to prevent corner cases
|
||||||
|
let (x_max, x_min, x_translate) = recenter_map(x_max, x_min);
|
||||||
|
let (y_max, y_min, y_translate) = recenter_map(y_max, y_min);
|
||||||
|
|
||||||
|
(MapBounds { x_max, x_min, x_translate, y_max, y_min, y_translate }, false)
|
||||||
|
} else {
|
||||||
|
// Round to edge
|
||||||
|
x_max = round_max_coordinate(x_max, EDGE_SIZE);
|
||||||
|
x_min = round_min_coordinate(x_min, EDGE_SIZE);
|
||||||
|
y_max = round_max_coordinate(y_max, EDGE_SIZE);
|
||||||
|
y_min = round_min_coordinate(y_min, EDGE_SIZE);
|
||||||
|
|
||||||
|
// Adding bounds to prevent OOB when moving
|
||||||
|
x_max += EDGE_SIZE;
|
||||||
|
x_min -= EDGE_SIZE;
|
||||||
|
y_max += EDGE_SIZE;
|
||||||
|
y_min -= EDGE_SIZE;
|
||||||
|
|
||||||
|
// Move everything to positive coordinates to prevent corner cases
|
||||||
|
let (x_max, x_min, x_translate) = recenter_map(x_max, x_min);
|
||||||
|
let (y_max, y_min, y_translate) = recenter_map(y_max, y_min);
|
||||||
|
|
||||||
|
(MapBounds { x_max, x_min, x_translate, y_max, y_min, y_translate }, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Quadrant {
|
||||||
|
fn insert_entity(&mut self, entity_id: i64, entity: &'static LevelEntityConfigData) {
|
||||||
|
self.entities.insert(entity_id, entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_entities(&self) -> Vec<&LevelEntityConfigData> {
|
||||||
|
self.entities
|
||||||
|
.iter()
|
||||||
|
.map(|(_, v)| *v)
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Map {
|
||||||
|
fn insert_entity(&mut self, entity: &'static LevelEntityConfigData) {
|
||||||
|
let index = self.get_quadrant_id(entity.transform[0].x, entity.transform[0].y);
|
||||||
|
self.quadrants.entry(index).or_default().insert_entity(entity.entity_id, entity)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_neighbour_cells(&self, quadrant_id: u64) -> [u64; 9] {
|
||||||
|
let x = quadrant_id % self.width;
|
||||||
|
let y = (quadrant_id - x) / self.width;
|
||||||
|
return [
|
||||||
|
(self.width * (y - 1)) + (x - 1),
|
||||||
|
(self.width * (y - 1)) + (x),
|
||||||
|
(self.width * (y - 1)) + (x + 1),
|
||||||
|
(self.width * (y)) + (x - 1),
|
||||||
|
(self.width * (y)) + (x),
|
||||||
|
(self.width * (y)) + (x + 1),
|
||||||
|
(self.width * (y + 1)) + (x - 1),
|
||||||
|
(self.width * (y + 1)) + (x),
|
||||||
|
(self.width * (y + 1)) + (x + 1),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collect_quadrant_differences(&self, discriminant: [u64; 9], discriminator: [u64; 9]) -> Vec<&LevelEntityConfigData> {
|
||||||
|
let mut output = Vec::new();
|
||||||
|
for quadrant in discriminant {
|
||||||
|
if !discriminator.contains(&quadrant) {
|
||||||
|
if let Some(quadrant) = &self.quadrants.get(&quadrant) {
|
||||||
|
output.extend_from_slice(&quadrant.get_entities())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_quadrant_id(&self, x: f32, y: f32) -> u64 {
|
||||||
|
let width: u64 = unsafe {
|
||||||
|
f32::to_int_unchecked(
|
||||||
|
f32::trunc(
|
||||||
|
(self.bounds.x_max + self.bounds.x_translate - x) / EDGE_SIZE
|
||||||
|
)
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let height: u64 = unsafe {
|
||||||
|
f32::to_int_unchecked(
|
||||||
|
f32::trunc(
|
||||||
|
(self.bounds.y_max + self.bounds.y_translate - y) / EDGE_SIZE
|
||||||
|
)
|
||||||
|
)
|
||||||
|
};
|
||||||
|
(self.width * height) + width
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_initial_entities(&self, quadrant_id: u64) -> Vec<&LevelEntityConfigData> {
|
||||||
|
let quadrants = self.get_neighbour_cells(quadrant_id);
|
||||||
|
let mut output = Vec::new();
|
||||||
|
for quadrant in quadrants {
|
||||||
|
if let Some(quadrant) = &self.quadrants.get(&quadrant) {
|
||||||
|
output.extend_from_slice(&quadrant.get_entities())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_update_entities(&self, old_quadrant_id: u64, new_quadrant_id: u64) -> (Vec<&LevelEntityConfigData>, Vec<&LevelEntityConfigData>) {
|
||||||
|
let old_quadrants = self.get_neighbour_cells(old_quadrant_id);
|
||||||
|
let new_quadrants = self.get_neighbour_cells(new_quadrant_id);
|
||||||
|
|
||||||
|
let entities_to_remove = self.collect_quadrant_differences(old_quadrants, new_quadrants);
|
||||||
|
let entities_to_add = self.collect_quadrant_differences(new_quadrants, old_quadrants);
|
||||||
|
|
||||||
|
(entities_to_remove, entities_to_add)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn maps_iter() -> std::collections::hash_map::Iter<'static, i32, Map> {
|
||||||
|
MAP_TABLE.get().unwrap().iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn initialize_quadrant_system() {
|
||||||
|
let mut map_grouped_entities: HashMap<i32, Vec<&LevelEntityConfigData>> = HashMap::new();
|
||||||
|
for (_, entity) in shorekeeper_data::level_entity_config_data::iter() {
|
||||||
|
map_grouped_entities.entry(entity.map_id).or_default().push(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut maps: HashMap<i32, Map> = HashMap::new();
|
||||||
|
for (map_id, entities) in map_grouped_entities {
|
||||||
|
let (bounds, _quadrant_enabled) = MapBounds::find_max_min(&entities[..]);
|
||||||
|
let width = unsafe { f32::to_int_unchecked((bounds.x_max - bounds.x_min) / EDGE_SIZE) };
|
||||||
|
let height = unsafe { f32::to_int_unchecked((bounds.y_max - bounds.y_min) / EDGE_SIZE) };
|
||||||
|
let map = maps.entry(map_id).or_insert(
|
||||||
|
Map {
|
||||||
|
bounds: bounds.clone(),
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
quadrants: HashMap::new(),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
for entity in entities {
|
||||||
|
map.insert_entity(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = MAP_TABLE.set(maps);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_map(map_id: i32) -> &'static Map {
|
||||||
|
// TODO: Error check for map id
|
||||||
|
MAP_TABLE.get().unwrap().get(&map_id).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn recenter_map(max: f32, min: f32) -> (f32, f32, f32) {
|
||||||
|
match min < 0.0 {
|
||||||
|
true => (max + f32::abs(min), 0.0, min),
|
||||||
|
false => (max, min, 0.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn round_max_coordinate(coordinate: f32, round: f32) -> f32 {
|
||||||
|
let rounded = f32::round(coordinate);
|
||||||
|
let remainder = rounded % round;
|
||||||
|
if remainder != 0f32 {
|
||||||
|
rounded + (if rounded > 0.0 { round } else { 0.0 } - remainder)
|
||||||
|
} else {
|
||||||
|
rounded
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn round_min_coordinate(coordinate: f32, round: f32) -> f32 {
|
||||||
|
let rounded = f32::round(coordinate);
|
||||||
|
let remainder = rounded % round;
|
||||||
|
if remainder != 0f32 {
|
||||||
|
rounded + (remainder.signum() * (if rounded > 0.0 { 0.0 } else { round } - f32::abs(remainder)))
|
||||||
|
} else {
|
||||||
|
rounded
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,11 @@
|
||||||
use crate::logic::ecs::world::World;
|
use std::cell::{BorrowMutError, RefMut};
|
||||||
use crate::logic::player::Player;
|
|
||||||
use crate::logic::utils::entity_serializer;
|
use shorekeeper_data::{base_property_data, LevelEntityConfigData};
|
||||||
|
use shorekeeper_protocol::{DFsm, EEntityType, EntityAddNotify, EntityConfigType, EntityPb,
|
||||||
|
EntityRemoveInfo, EntityRemoveNotify, EntityState, FightRoleInfo,
|
||||||
|
FightRoleInfos, LivingStatus, SceneInformation, SceneMode,
|
||||||
|
ScenePlayerInformation, SceneTimeInfo};
|
||||||
|
|
||||||
use crate::logic::{
|
use crate::logic::{
|
||||||
components::{
|
components::{
|
||||||
Attribute, EntityConfig, Equip, Movement, OwnerPlayer, PlayerEntityMarker, Position,
|
Attribute, EntityConfig, Equip, Movement, OwnerPlayer, PlayerEntityMarker, Position,
|
||||||
|
@ -8,12 +13,13 @@ use crate::logic::{
|
||||||
},
|
},
|
||||||
ecs::component::ComponentContainer,
|
ecs::component::ComponentContainer,
|
||||||
};
|
};
|
||||||
|
use crate::logic::components::{Fsm, MonsterAi};
|
||||||
|
use crate::logic::ecs::entity::Entity;
|
||||||
|
use crate::logic::ecs::world::{World, WorldEntity};
|
||||||
|
use crate::logic::math::Transform;
|
||||||
|
use crate::logic::player::Player;
|
||||||
|
use crate::logic::utils::entity_serializer;
|
||||||
use crate::query_with;
|
use crate::query_with;
|
||||||
use shorekeeper_data::base_property_data;
|
|
||||||
use shorekeeper_protocol::{
|
|
||||||
EEntityType, EntityConfigType, FightRoleInfo, FightRoleInfos, LivingStatus, SceneInformation,
|
|
||||||
SceneMode, ScenePlayerInformation, SceneTimeInfo,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! create_player_entity_pb {
|
macro_rules! create_player_entity_pb {
|
||||||
|
@ -32,6 +38,8 @@ macro_rules! create_player_entity_pb {
|
||||||
.with(ComponentContainer::EntityConfig(EntityConfig {
|
.with(ComponentContainer::EntityConfig(EntityConfig {
|
||||||
config_id: role_id,
|
config_id: role_id,
|
||||||
config_type: EntityConfigType::Character,
|
config_type: EntityConfigType::Character,
|
||||||
|
entity_type: EEntityType::Player.into(),
|
||||||
|
entity_state: EntityState::Default
|
||||||
}))
|
}))
|
||||||
.with(ComponentContainer::OwnerPlayer(OwnerPlayer($player_id)))
|
.with(ComponentContainer::OwnerPlayer(OwnerPlayer($player_id)))
|
||||||
.with(ComponentContainer::Position(Position($position)))
|
.with(ComponentContainer::Position(Position($position)))
|
||||||
|
@ -95,6 +103,8 @@ pub fn add_player_entities(player: &Player) {
|
||||||
.with(ComponentContainer::EntityConfig(EntityConfig {
|
.with(ComponentContainer::EntityConfig(EntityConfig {
|
||||||
config_id: role.role_id,
|
config_id: role.role_id,
|
||||||
config_type: EntityConfigType::Character,
|
config_type: EntityConfigType::Character,
|
||||||
|
entity_type: EEntityType::Player.into(),
|
||||||
|
entity_state: EntityState::Default,
|
||||||
}))
|
}))
|
||||||
.with(ComponentContainer::OwnerPlayer(OwnerPlayer(
|
.with(ComponentContainer::OwnerPlayer(OwnerPlayer(
|
||||||
player.basic_info.id,
|
player.basic_info.id,
|
||||||
|
@ -209,3 +219,118 @@ fn build_player_info_list(world: &World) -> Vec<ScenePlayerInformation> {
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn build_monster_entity(world: &mut WorldEntity, config_id: i32, map_id: i32, transform: Transform) -> Entity {
|
||||||
|
// TODO: Check for more components, AI and so
|
||||||
|
world.create_entity(config_id, EEntityType::Monster.into(), map_id)
|
||||||
|
.with(ComponentContainer::EntityConfig(EntityConfig {
|
||||||
|
config_id,
|
||||||
|
config_type: EntityConfigType::Level,
|
||||||
|
entity_type: EEntityType::Monster.into(),
|
||||||
|
entity_state: EntityState::Born,
|
||||||
|
}))
|
||||||
|
.with(ComponentContainer::Position(Position(transform)))
|
||||||
|
.with(ComponentContainer::Visibility(Visibility(true)))
|
||||||
|
.with(ComponentContainer::Attribute(Attribute::from_data(
|
||||||
|
base_property_data::iter()
|
||||||
|
.find(|d| d.id == 600000100) // TODO: Implement monster stats
|
||||||
|
.unwrap(),
|
||||||
|
)))
|
||||||
|
.with(ComponentContainer::MonsterAi(MonsterAi {
|
||||||
|
weapon_id: 0,
|
||||||
|
hatred_group_id: 0,
|
||||||
|
ai_team_init_id: 100,
|
||||||
|
combat_message_id: 0,
|
||||||
|
}))
|
||||||
|
.with(ComponentContainer::Fsm(Fsm {
|
||||||
|
fsms: vec![
|
||||||
|
DFsm {
|
||||||
|
fsm_id: 10007,
|
||||||
|
current_state: 10013,
|
||||||
|
flag: 0,
|
||||||
|
k_ts: 0,
|
||||||
|
},
|
||||||
|
DFsm {
|
||||||
|
fsm_id: 10007,
|
||||||
|
current_state: 10015,
|
||||||
|
flag: 0,
|
||||||
|
k_ts: 0,
|
||||||
|
},
|
||||||
|
DFsm {
|
||||||
|
fsm_id: 10007,
|
||||||
|
current_state: 10012,
|
||||||
|
flag: 0,
|
||||||
|
k_ts: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
hash_code: 0,
|
||||||
|
common_hash_code: 0,
|
||||||
|
black_board: vec![],
|
||||||
|
fsm_custom_blackboard_datas: None,
|
||||||
|
}))
|
||||||
|
.with(ComponentContainer::Movement(Movement::default()))
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_entities(player: &Player, entities: &[&LevelEntityConfigData]) {
|
||||||
|
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 entity_id = entity.entity_id as i32; // TODO: Should be i64
|
||||||
|
if world.remove_entity(entity_id) {
|
||||||
|
removed_entities.push(world.get_entity_id(entity_id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for entity_id in removed_entities {
|
||||||
|
player.notify(EntityRemoveNotify {
|
||||||
|
remove_infos: vec![EntityRemoveInfo { entity_id, r#type: 0 }],
|
||||||
|
is_remove: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_entities(player: &Player, entities: &[&LevelEntityConfigData]) {
|
||||||
|
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 {
|
||||||
|
// TODO: review other types
|
||||||
|
tracing::debug!("Entity to be added of type: {}", entity.blueprint_type);
|
||||||
|
if entity.blueprint_type.contains("Monster") {
|
||||||
|
added_entities.push(build_monster_entity(
|
||||||
|
world,
|
||||||
|
entity.entity_id as i32, // TODO: Should be i64
|
||||||
|
entity.map_id,
|
||||||
|
Transform::from(&entity.transform[..]),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut world_ref = player.world.borrow();
|
||||||
|
let world = world_ref.get_world_entity();
|
||||||
|
// Since kuro has issues, we can only send one
|
||||||
|
for entity in added_entities {
|
||||||
|
let mut pb = EntityPb {
|
||||||
|
id: entity.entity_id as i64, // TODO: Should be i64
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
world.get_entity_components(entity.entity_id)
|
||||||
|
.into_iter()
|
||||||
|
.for_each(|comp| comp.set_pb_data(&mut pb));
|
||||||
|
|
||||||
|
player.notify(EntityAddNotify {
|
||||||
|
entity_pbs: vec![pb],
|
||||||
|
is_add: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,7 +20,8 @@ async fn main() -> Result<()> {
|
||||||
|
|
||||||
::common::splash::print_splash();
|
::common::splash::print_splash();
|
||||||
::common::logging::init(::tracing::Level::DEBUG);
|
::common::logging::init(::tracing::Level::DEBUG);
|
||||||
shorekeeper_data::load_json_data("assets/logic/BinData")?;
|
shorekeeper_data::load_all_json_data("assets/logic/BinData")?;
|
||||||
|
logic::utils::quadrant_util::initialize_quadrant_system();
|
||||||
|
|
||||||
let database = Arc::new(shorekeeper_database::connect_to(&CONFIG.database).await?);
|
let database = Arc::new(shorekeeper_database::connect_to(&CONFIG.database).await?);
|
||||||
shorekeeper_database::run_migrations(database.as_ref()).await?;
|
shorekeeper_database::run_migrations(database.as_ref()).await?;
|
||||||
|
|
|
@ -26,11 +26,12 @@ async fn main() -> Result<()> {
|
||||||
LazyLock::new(|| config_util::load_or_create("hotpatch.toml"));
|
LazyLock::new(|| config_util::load_or_create("hotpatch.toml"));
|
||||||
|
|
||||||
::common::splash::print_splash();
|
::common::splash::print_splash();
|
||||||
::common::logging::init(::tracing::Level::DEBUG);
|
::common::logging::init_axum(::tracing::Level::DEBUG);
|
||||||
|
|
||||||
Application::new()
|
Application::new()
|
||||||
.get("/:env/client/:hash/:platform/config.json", get_config)
|
.get("/:env/client/:hash/:platform/config.json", get_config)
|
||||||
.with_encryption(&CONFIG.encryption)
|
.with_encryption(&CONFIG.encryption)
|
||||||
|
.with_logger()
|
||||||
.serve(&CONFIG.network)
|
.serve(&CONFIG.network)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use std::{process, sync::LazyLock};
|
use std::{process, sync::LazyLock};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
use config::{GatewayConfig, ServerConfig};
|
use config::{GatewayConfig, ServerConfig};
|
||||||
use shorekeeper_database::PgPool;
|
use shorekeeper_database::PgPool;
|
||||||
use shorekeeper_http::{Application, StatusCode};
|
use shorekeeper_http::{Application, StatusCode};
|
||||||
|
@ -21,7 +22,7 @@ async fn main() -> Result<()> {
|
||||||
LazyLock::new(|| ::common::config_util::load_or_create("loginserver.toml"));
|
LazyLock::new(|| ::common::config_util::load_or_create("loginserver.toml"));
|
||||||
|
|
||||||
::common::splash::print_splash();
|
::common::splash::print_splash();
|
||||||
::common::logging::init(::tracing::Level::DEBUG);
|
::common::logging::init_axum(::tracing::Level::DEBUG);
|
||||||
|
|
||||||
let Ok(pool) = shorekeeper_database::connect_to(&CONFIG.database).await else {
|
let Ok(pool) = shorekeeper_database::connect_to(&CONFIG.database).await else {
|
||||||
tracing::error!(
|
tracing::error!(
|
||||||
|
@ -39,6 +40,7 @@ async fn main() -> Result<()> {
|
||||||
})
|
})
|
||||||
.get("/health", || async { StatusCode::OK })
|
.get("/health", || async { StatusCode::OK })
|
||||||
.get("/api/login", handler::handle_login_api_call)
|
.get("/api/login", handler::handle_login_api_call)
|
||||||
|
.with_logger()
|
||||||
.serve(&CONFIG.network)
|
.serve(&CONFIG.network)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|
18
shorekeeper-data/src/level_entity_config.rs
Normal file
18
shorekeeper-data/src/level_entity_config.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
use serde::Deserialize;
|
||||||
|
use crate::RawVectorData;
|
||||||
|
|
||||||
|
#[derive(Deserialize, Clone)]
|
||||||
|
#[serde(rename_all = "PascalCase")]
|
||||||
|
pub struct LevelEntityConfigData {
|
||||||
|
pub id: i32,
|
||||||
|
pub map_id: i32,
|
||||||
|
pub entity_id: i64,
|
||||||
|
pub blueprint_type: String,
|
||||||
|
pub name: String,
|
||||||
|
pub in_sleep: bool,
|
||||||
|
pub is_hidden: bool,
|
||||||
|
pub area_id: i32,
|
||||||
|
pub transform: Vec<RawVectorData>,
|
||||||
|
// Schemaless property, any suggestions @xeondev??
|
||||||
|
pub components_data: serde_json::Value,
|
||||||
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
use paste::paste;
|
use paste::paste;
|
||||||
|
|
||||||
mod misc_data;
|
|
||||||
pub use misc_data::*;
|
pub use misc_data::*;
|
||||||
|
|
||||||
|
mod misc_data;
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
pub enum LoadDataError {
|
pub enum LoadDataError {
|
||||||
#[error("I/O error: {0}")]
|
#[error("I/O error: {0}")]
|
||||||
|
@ -30,7 +30,7 @@ macro_rules! json_data {
|
||||||
}
|
}
|
||||||
})*
|
})*
|
||||||
|
|
||||||
pub fn load_json_data(base_path: &str) -> Result<(), LoadDataError> {
|
fn load_json_data(base_path: &str) -> Result<(), LoadDataError> {
|
||||||
$(paste! {
|
$(paste! {
|
||||||
let json_content = std::fs::read_to_string(&format!("{}/{}.json", base_path, stringify!($table_type)))?;
|
let json_content = std::fs::read_to_string(&format!("{}/{}.json", base_path, stringify!($table_type)))?;
|
||||||
let _ = [<$table_type:snake _data>]::TABLE.set(serde_json::from_str(&json_content)?);
|
let _ = [<$table_type:snake _data>]::TABLE.set(serde_json::from_str(&json_content)?);
|
||||||
|
@ -41,6 +41,50 @@ macro_rules! json_data {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! json_hash_table_data {
|
||||||
|
($($table_type:ident, $key_param:expr;)*) => {
|
||||||
|
$(paste! {
|
||||||
|
mod [<$table_type:snake>];
|
||||||
|
pub use [<$table_type:snake>]::[<$table_type Data>];
|
||||||
|
})*
|
||||||
|
|
||||||
|
$(paste! {
|
||||||
|
pub mod [<$table_type:snake _data>] {
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
|
pub(crate) type Data = super::[<$table_type Data>];
|
||||||
|
pub(crate) static TABLE: OnceLock<HashMap<i64, Data>> = OnceLock::new();
|
||||||
|
|
||||||
|
pub fn iter() -> std::collections::hash_map::Iter<'static, i64, Data> {
|
||||||
|
TABLE.get().unwrap().iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})*
|
||||||
|
|
||||||
|
fn load_json_hash_table_data(base_path: &str) -> Result<(), LoadDataError> {
|
||||||
|
$(paste! {
|
||||||
|
let json_content = std::fs::read_to_string(&format!("{}/{}.json", base_path, stringify!($table_type)))?;
|
||||||
|
let _ = [<$table_type:snake _data>]::TABLE.set(
|
||||||
|
serde_json::from_str::<Vec<[<$table_type:snake _data>]::Data>>(&json_content)?
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.map(|element| (element.$key_param, element))
|
||||||
|
.collect::<std::collections::HashMap<_, _>>()
|
||||||
|
);
|
||||||
|
})*
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_all_json_data(base_path: &str) -> Result<(), LoadDataError> {
|
||||||
|
load_json_data(base_path)?;
|
||||||
|
load_json_hash_table_data(base_path)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
json_data! {
|
json_data! {
|
||||||
RoleInfo;
|
RoleInfo;
|
||||||
WeaponConf;
|
WeaponConf;
|
||||||
|
@ -48,4 +92,9 @@ json_data! {
|
||||||
InstanceDungeon;
|
InstanceDungeon;
|
||||||
FunctionCondition;
|
FunctionCondition;
|
||||||
ExploreTools;
|
ExploreTools;
|
||||||
|
LordGym;
|
||||||
|
}
|
||||||
|
|
||||||
|
json_hash_table_data! {
|
||||||
|
LevelEntityConfig, entity_id;
|
||||||
}
|
}
|
|
@ -26,6 +26,28 @@ impl VectorData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Clone)]
|
||||||
|
#[serde(rename_all = "PascalCase")]
|
||||||
|
pub struct RawVectorData {
|
||||||
|
pub x: f32,
|
||||||
|
pub y: f32,
|
||||||
|
pub z: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RawVectorData {
|
||||||
|
pub fn get_x(&self) -> f32 {
|
||||||
|
self.x
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_y(&self) -> f32 {
|
||||||
|
self.y
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_z(&self) -> f32 {
|
||||||
|
self.z
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
#[serde(rename_all = "PascalCase")]
|
#[serde(rename_all = "PascalCase")]
|
||||||
pub struct EntranceEntityData {
|
pub struct EntranceEntityData {
|
||||||
|
|
Loading…
Reference in a new issue