Getting started

Feather is distributed as a single binary and can run on almost any system, see Starting a server.

Starting a server

The latest version of feather can be found and downloaded from our github release page. Feather is platform dependent, therefor you must download the version corresponding to your operating system and your processors architecture.

The zip file contains a single executable that is compiled to the given target that when executed will generate a few files notable world/ and feather.toml, so it is recommended to execute the server in a separate folder.

Windows

After downloading and unzipping the executable feather.exe you can start it by simply double clicking it.

Mac OS-X

After downloading and unzipping you can execute feather from the terminal

./feather

Linux

After downloading and unzipping you can execute feather from the terminal

./feather

Configuring

Feather config files are written in the TOML format.

feather.toml

# Configuration for the Feather server.

# Many of the options here are unimplemented and have no effect.
# Those that are unimplemented have been labeled so.

[io]
# Packets with a size more than or equal to this value will be sent compressed.
# Compressing packets reduces bandwidth usage but increases CPU activity.
compression_threshold = 256

[server]
online_mode = true
motd = "A Feather server"
max_players = 16
default_gamemode = "survival"
difficulty = "none" # Unimplemented
view_distance = 6
address = "0.0.0.0"
port = 25565

[gameplay]
monster_spawning = true # Unimplemented
animal_spawning = true # Unimplemented
pvp = true # Unimplemented
nerf_spawner_mobs = false # Unimplemented
# Either "classic" for 1.8 PvP or "new" for 1.9
pvp_style = "classic" # Unimplemented

[log]
# If you prefer less verbose logs, switch this to "info."
# If you want to hurt your eyes while looking at the
# server console, set it to "trace."
level = "debug"

[resource_pack]
# Server resource pack which is sent to players
# upon joining. Set this to an empty string to disable.
url = ""
# Optional SHA1 hash of the resource pack file.
hash = ""

[world]
# The name of the directory containing the world.
name = "world"
# The generator to use if the world does not exist.
# Implemented values are: default, flat
generator = "default"
# The seed to use if the world does not exist.
# Leaving this value empty will generate a random seed.
# If this value is not a valid integer (i64), the string
# will be converted using a hash function.
seed = ""
# Interval at which to save modified chunks.
save_interval = "1min"

[proxy]
# Select the IP forwarding mode that is used by proxies like BungeeCord or Velocity.
# Valid values are
# - "None" - for usage without a proxy
# - "BungeeCord" - for BungeeCord/Waterfall/Travertine
# - "Velocity" - for Velocity style proxies (unimplemented)
proxy_mode = "None"

Developing a plugin

Plugins written for Feather can achieve incredible flexibility through Feather's data-oriented API. Our plugin system has been written from the start to support any functionality imaginable, to the extent all gameplay features could be implemented as plugins if needed. However writing a plugin for feather is very different from writing a plugin for any other Minecraft Server software.

Concepts

Feather is quite a bit different from regular Minecraft server software written in Java. Feather is written using the Entity Component System architecture, which greatly improves the utilization of the CPU, most notable being improved cache hit ratio, compared to Object Oriented Programming.

The following definitions is used throughout the book to avoid confusion

  1. Entity is a unique identifier used to associate data in ECS.
  2. Component is a container of data associated with a single entity in ECS.
  3. World is a container of queryable data associated with entity's in ECS.
  4. Spawn is the action of inserting an entity and its components into a world in ECS.
  5. Despawn is the action of removing an entity and its components from a world in ECS.
  6. Dimension is a world in Minecraft.

Chapters

  1. Entity Component
  2. World
  3. Resource
  4. System
  5. Scheduler
  6. Events

Additional resources

  1. Theres a great talk on ECS from RustConf 2018.
  2. Theres a great comparison between Specs and Legion here by Cora Sherratt who worked on specs.

What are Entity and Component

An Entity is a unique identifier that usually has a number of Components associated, these components are nothing more than simple data containers. For example a Player entity could have the attributes Health and Position associated. It is also common for entities to have a marker component associated, the marker is used to identify and describe the type of an entity. In the case of a Player it would be a struct Player; that is used to mark the entity as a Player.

Modeling a Player in ECS starts by defining some components that holds attributes for the player.

// Component used to mark an entity as a player
struct Player;

// Component storing health
struct Health(f64);

// Component storing position
struct Position {
    x: f64,
    y: f64,
    z: f64,
}

Here Health and Postion attributes could be shared across multiple types of entities, but the player marker would only exist for a Player entity. We could define a separate Zombie marker for a Zombie and have it share Health and Postion components with the Player.

// Component used to mark an entity as a zombie
struct Zombie;

In ECS each entity and its associated components are stored in a world, we can imagine the world being a large matrix where each column is a component, each row a unique entity, and each cell component data associated with the entity.

PlayerZombieHealthPosition
Player20.00.0, 0.0, 0.0
Zombie15.00.0, 0.0, 0.0

Now that we have defined two marker components Player and Zombie, and the associated attribute components Health and Postion, we can create Player and Zombie as entities and spawn them into the ECS world.

use fecs::EntityBuilder;

EntityBuilder::new()
    .with(Player)
    .with(Health(20.0))
    .with(Postion {
        x: 0.0,
        y: 0.0,
        z: 0.0,
    })
    .build()
    .spawn_in(&mut world);

EntityBuilder::new()
    .with(Zombie)
    .with(Health(15.0))
    .with(Position {
        x: 0.0,
        y: 0.0,
        z: 0.0,
    })
    .build()
    .spawn_in(&mut world);

Resource

World

When writing plugins for feather you will rarely have to create your own world, since feather provides two worlds that one of which are available asynchronous. But for the purpose of demonstrating ECS will be crating our own world, which is no different from a provided one.

We can create a world in Fecs by simply calling World::new.


#![allow(unused_variables)]
fn main() {
use fecs::World;

let world = World::new();
}

The set of components that makes up an entity is called archetype, Legion stores all its entities in chunks based on the archetype. This means that adding or removing components from an entity is an O(n) operation and should therefor be avoided.

By calling BuiltEntity::spawn we create two new chunks, in the world, where the entities of the archetypes, {Player, Health, Position} and {Zombie, Health, Position} are stored. We can add additional components to an entity by calling World::add, however this will change the archetype of the entity and we would have to move the entire entity to a new chunk. This is an expensive operation and involves copying all components to a new chunk in heap, it takes O(n) and therefor should be avoided if possible, this is the same cost as create an entire new entity. In most cases where you find your self adding and removing some component from an entity a mutable component can be used instead, it has greatly improved performance due to the entity not changing its archetype, it is an O(1) operation and is very cheap compared to World::add.

System

Feather is structured with a number of systems running in series, these system may perform their calculations in parallel by utilizing Rayon. These systems emit events that effects their outcome, for instance the block_place_system system emits both BlockChangeEvent and InteractItemEvent. The listeners attached to these events may poll in arbitrary data from the world and this is the major reason Systems are run in series and not parallel.

Scheduler

Events

Advanced

These chapters are meant for those who want to get into the gritty details.

Feather ECS

This chapter is mostly about the technical details of Fecs and by extension Legion.

Command handling

Contributing