6 个版本 (破坏性更新)
0.6.0 | 2024年7月4日 |
---|---|
0.5.0 | 2024年5月28日 |
0.4.0 | 2024年5月24日 |
0.3.0 | 2024年2月23日 |
0.1.0 | 2024年1月22日 |
#343 in 游戏开发
82KB
1K SLoC
Bevy Replicon Attributes
为服务器实体和事件扩展 bevy_replicon 的基于属性的可见性控制。
基本示例
use bevy::prelude::*;
use bevy_replicon::prelude::{ClientId, Replicated};
use bevy_replicon_attributes::prelude::*;
#[derive(Component)]
struct Bat;
#[derive(Event)]
struct SpawnBat;
#[derive(Event, Copy, Clone)]
struct BatAlert;
#[derive(Event)]
struct GainedNightVision(ClientId);
#[derive(VisibilityAttribute, Default, PartialEq)]
struct HasNightVision;
#[derive(VisibilityAttribute, Default, PartialEq)]
struct IsAwake;
#[derive(VisibilityAttribute, Default, PartialEq)]
struct HatesBats;
fn spawn_bats(
mut commands : Commands,
mut events : EventReader<SpawnBat>,
mut sender : ServerEventSender<BatAlert>,
attributes : ClientAttributes,
){
for _ in events.read()
{
// Entity
commands.spawn((Bat, Replicated, vis!(HasNightVision)));
// Server event
sender.send(&attributes, BatAlert, vis!(all!(HasNightVision, IsAwake, HatesBats)));
}
}
fn gain_night_vision(
mut events : EventReader<GainedNightVision>,
mut attributes : ClientAttributes,
){
for client_id in events.read()
{
// Client attribute
attributes.add(client_id, HasNightVision);
}
}
用法
设置
将 replicon 添加到您的服务器应用程序中。此软件包仅与 VisibilityPolicy::All
和 VisibilityPolicy::Whitelist
一起工作。
有关设置 renet 服务器的信息,请参阅 renet。
use bevy::prelude::*;
use bevy_replicon::prelude::*;
app.add_plugins(bevy::time::TimePlugin) //required by bevy_renet
.add_plugins(RepliconPlugins
.build()
.disable::<ClientPlugin>()
.set(ServerPlugin{
visibility_policy: VisibilityPolicy::Whitelist,
..Default::default(),
})
);
在 replicon 插件之后将 VisibilityAttributesPlugin
添加到您的服务器应用程序中。如果使用了 VisibilityPolicy::Blacklist
,则插件将引发恐慌。您必须指定一个 ReconnectPolicy
use bevy_replicon_attributes::prelude::*;
app.add_plugins(VisibilityAttributesPlugin{ reconnect_policy: ReconnectPolicy::Reset });
如果您选择 ReconnectPolicy::Repair
,我们建议同时使用 bevy_replicon_repair 以在客户端保留复制状态。
定义属性
可以使用 VisibilityAttribute
派生属性,它需要 Default
和 PartialEq
。仅应使用零大小类型的 derive。
#[derive(VisibilityAttribute, Default, PartialEq)]
struct InStartingArea;
更复杂的属性应手动实现 VisibilityAttribute
。
struct InLocation(x: u32, y: u32);
impl VisibilityAttribute for InLocation
{
fn inner_attribute_id(&self) -> u64
{
((self.x as u64) << 32) + (self.y as u64)
}
}
此处定义的 inner_attribute_id
用于区分相同类型的属性实例。
向客户端添加属性
使用 ClientAttributes
系统参数向客户端添加属性。
客户端属性用于评估实体 VisibilityConditions
,以确定实体是否应复制到客户端。
use bevy::prelude::*;
use bevy_replicon::prelude::ServerEvent;
use bevy_replicon_attributes::prelude::*;
#[derive(VisibilityAttribute, Default, PartialEq)]
struct IsDisconnected;
fn update_visibility_on_connect_events(
mut server_events : EventReader<ServerEvent>,
mut attributes : ClientAttributes,
){
for event in server_events.read()
{
match event
{
ServerEvent::ClientConnected{ id } =>
{
attributes.remove(id, IsDisconnected);
attributes.add(id, InStartingArea);
}
ServerEvent::ClientDisconnected{ id, _ } =>
{
attributes.add(id, IsDisconnected);
}
}
}
}
默认客户端属性
所有客户端在每次连接时都会获得 Global
和 Client
内置属性。
实体可见性
实体可见性由 VisibilityConditions
控制,这些是任意组合的 VisibilityAttributes
和 not()
/and()
/or()
逻辑。
实体可见性条件将与客户端属性列表进行比较,以确定实体是否可以被客户端看到。
为了方便,我们有一个 vis!()
宏,该宏生成新的 VisibilityCondition
组件。在 vis!()
宏内可以使用 any!()
/all!()
/none!()
宏,这些宏可以在 not()
/and()
/or()
之外使用。
空可见性条件始终评估为 false
。如果您想为实体设置全局可见性,请使用在客户端连接时提供的内置 Global
属性。
以下是一个低级示例,说明其工作原理。在实践中,您只需要将 VisibilityAttributes
添加到客户端,并将 VisibilityCondition
组件添加到实体。此crate将负责将此信息转换为 bevy_replicon
中的实体可见性。
use bevy::prelude::*;
use bevy_replicon_attributes::prelude::*;
fn entity_demo(
mut commands : Commands,
mut attributes : ClientAttributes,
){
let client_id = ClientId::from_raw(0u64);
// Add location to client.
attributes.add(client_id, InLocation(0, 20));
// Make location condition.
let location = vis!(InLocation(0, 20));
// Evaluate condition.
let client_attributes = attributes.get(client_id).unwrap();
assert!(location.evaluate(|a| client_attributes.contains(&a)));
// Spawn entity.
commands.spawn((Replicated, location));
}
以下是一些更复杂的可见性条件示例
// Basic
vis!();
vis!(A);
vis!(not(B));
vis!(and(A, B));
vis!(or(A, B));
vis!(and(A, not(B)));
// Composition
vis!(and(A, vis!(B)));
// Helpers
vis!(any!(A, B, C)); // vis!(or(A, or(B, C)))
vis!(all!(A, B, C)); // vis!(and(A, and(B, C)))
vis!(none!(A, B, C)); // vis!(not(or(A, or(B, C)))))
// Modification
vis!()
.and(A) // vis!(A)
.or(B) // vis!(or(A, B))
.replace(or(A, B), and(C(1), D)) // vis!(and(C(1), D))
.replace_type::<C>(E(2)) // vis!(and(E(2), D))
.remove(E(2)) // vis!(D)
;
服务器事件
服务器事件的可视性可以通过使用ServerEventSender
系统参数来控制。
服务器事件必须通过bevy_replicon
进行注册。客户端将通过EventReader<T>
接收服务器事件。
use bevy::prelude::*;
use bevy_replicon::prelude::*;
use bevy_replicon_attributes::prelude::*;
#[derive(Event, Copy, Clone)]
struct E;
fn setup(app: &mut App)
{
// Replicon server event registration
app.add_server_event::<E>(EventType::Ordered);
}
fn send_event(mut sender: ServerEventSender<E>, attributes: ClientAttributes)
{
sender.send(&attributes, E, vis!(any!(Client::from(1), Client::from(2), Client::from(3))));
}
bevy_replicon
兼容性
bevy_replicon |
bevy_replicon_attributes |
---|---|
0.27 | 0.6 - master |
0.26 | 0.5 |
0.25 | 0.4 |
0.21 | 0.1 - 0.3 |
依赖
~39–75MB
~1.5M SLoC