Giter Club home page Giter Club logo

bevy_replicon_attributes's Introduction

Bevy Replicon Attributes

Extends bevy_replicon with attributes-based visibility control for server entities and events.

Basic example

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

Usage

Setup

Add replicon to your server app. This crate only works with VisibilityPolicy::All and VisibilityPolicy::Whitelist.

See renet for how to set up a renet server.

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

Add VisibilityAttributesPlugin to your server app after the replicon plugins. The plugin will panic if you used VisibilityPolicy::Blacklist. You must specify a ReconnectPolicy:

use bevy_replicon_attributes::prelude::*;

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

If you choose ReconnectPolicy::Repair, we recommend also using bevy_replicon_repair for preserving replicated state on clients.

Define attributes

Attributes can be derived with VisibilityAttribute, which requires Default and PartialEq. Only zero-sized types should use this derive.

#[derive(VisibilityAttribute, Default, PartialEq)]
struct InStartingArea;

More complex attributes should implement VisibilityAttribute manually.

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)
    }
}

The inner_attribute_id defined here is used to differentiate attribute instances of the same type.

Add attributes to a client

Add attributes to clients with the ClientAttributes system parameter.

Client attributes are used when evaluating entity VisibilityConditions to determine if entities should be replicated to a client.

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

Default client attributes

All clients are given the Global and Client builtin attributes each time they connect.

Entity visibility

Entity visibility is controlled by VisibilityConditions, which are arbitrary combinations of VisibilityAttributes and not()/and()/or() logic.

Entity visibility conditions are evaluated against client attribute lists to determine if entities can be seen by clients.

For convenience we have a vis!() macro which produces new VisibilityCondition components. The any!()/all!()/none!() macros can be used inside the vis!() macro in addition to not()/and()/or().

An empty visibility condition always evaluates to false. If you want global visibility for an entity, use the builtin Global attribute that is given to clients when they connect.

Here is a low-level example how it works. In practice you only need to add VisibilityAttributes to clients and VisibilityCondition components to entities. This crate will take care of translating that information into entity visibility within 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));
}

Here are examples of more complex visibility conditions:

// 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)
    ;

Server events

Visibility of server events can be controlled with the ServerEventSender system parameter.

Server events must be registered with bevy_replicon. Clients will receive server events with 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 compatability

bevy_replicon bevy_replicon_attributes
0.27 0.6 - master
0.26 0.5
0.25 0.4
0.21 0.1 - 0.3

bevy_replicon_attributes's People

Contributors

ukoehb avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.