#attributes #derive #bevy #visibility #replicon #bevy-replicon-attributes #visibility-attribute

bevy_replicon_attributes_derive

为 bevy_replicon_attributes 提供派生功能

1 个不稳定版本

0.1.0 2024年1月22日

#18 in #visibility


bevy_replicon_attributes 中使用

MIT/Apache

3KB

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::AllVisibilityPolicy::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(),
        })
    );

VisibilityAttributesPlugin 添加到您的服务器应用程序中,并在 replicon 插件之后。如果使用了 VisibilityPolicy::Blacklist,则插件会引发恐慌。您必须指定一个 ReconnectPolicy

use bevy_replicon_attributes::prelude::*;

app.add_plugins(VisibilityAttributesPlugin{ reconnect_policy: ReconnectPolicy::Reset });

如果选择了 ReconnectPolicy::Repair,我们建议还使用 bevy_replicon_repair 以在客户端上保留复制的状态。

定义属性

可以使用 VisibilityAttribute 来派生属性,它需要 DefaultPartialEq。仅应使用零大小类型来使用此派生。

#[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);
            }
        }
    }
}

默认客户端属性

每次客户端连接时,都会分配GlobalClient内置属性。

实体可见性

实体可见性由VisibilityConditions控制,它们是VisibilityAttributes和逻辑操作符not()/and()/or()的任意组合。

将实体可见性条件与客户端属性列表进行比较,以确定实体是否可见。

为了方便,我们有一个vis!()宏,它生成新的VisibilityCondition组件。可以在vis!()宏内部使用any!()/all!()/none!()宏,除了not()/and()/or()

空可见性条件始终评估为false。如果您想为实体设置全局可见性,请使用客户端连接时分配的内置Global属性。

这里是一个低级示例,说明它是如何工作的。在实际应用中,您只需要将 VisibilityAttributes 添加到客户端,并将 VisibilityCondition 组件添加到实体中。这个包将负责将此信息转换为 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.26 0.5 - master
0.25 0.4
0.21 0.1 - 0.3

依赖项

~260–700KB
~17K SLoC