Commit graph

27 commits

Author SHA1 Message Date
Ryan Johnson 9c9f672a22
Update to 1.19.4 (#302)
## Description

Closes #291

- Update extractors to support Minecraft 1.19.4
- Update code generators.
- Changed generated entity component names to avoid name collisions.
- Update `glam` version.
- Added `Encode` and `Decode` for `glam` types in `valence_protocol`.
- Fixed inconsistent packet names and assign packet IDs automatically.
- Remove `ident` and rename `ident_str` to `ident`.
- Rework registry codec configuration. Biomes and dimensions exist as
entities.`BiomeRegistry` and `DimensionTypeRegistry` resources have been
added. The vanilla registry codec is loaded at startup.

### Issues
- Creating new instances has become more tedious than it should be. This
will be addressed later.

## Test Plan

Steps:
1. Boot up a vanilla server with online mode disabled.
2. Run the `packet_inspector`.
3. Connect to the vanilla server through the packet inspector to ensure
all packets are updated correctly.
4. Close the vanilla server and try some valence examples.
2023-03-31 14:58:47 -07:00
Ryan Johnson 53573642ec
Make Ident consistent with vanilla. (#309)
## Description

Makes `Ident` consistent with vanilla by prepending the default
namespace if none is provided in the constructor.

Previously, the constructor did not normalize `foo` to `minecraft:foo`.
This could lead to subtle bugs when the ident is eventually unwrapped
with `Ident::as_str`. (comparing `foo` with `minecraft:foo` while inside
the `Ident` was still handled correctly).

## Test Plan

Steps:
1. `cargo test`
2023-03-25 18:44:45 -07:00
Carson McManus a57800959f
Rough click slot packet validation (#293)
## Description

This adds some validation for incoming inventory packets that makes it
so that you can't just spawn items by sending malicious packets. It adds
type 1 and type 2 validations as outlined in #292.

This also adds some new helpers, `InventoryWindow` and
`InventoryWindowMut`.

fixes #292

<details>

<summary>Playground</summary>

```rust
use valence::client::{default_event_handler, despawn_disconnected_clients};
use valence::prelude::event::PlayerInteractBlock;
use valence::prelude::*;

#[allow(unused_imports)]
use crate::extras::*;

const SPAWN_Y: i32 = 64;
const CHEST_POS: [i32; 3] = [0, SPAWN_Y + 1, 3];

pub fn build_app(app: &mut App) {
    app.add_plugin(ServerPlugin::new(()).with_connection_mode(ConnectionMode::Offline))
        .add_startup_system(setup)
        .add_system(default_event_handler.in_schedule(EventLoopSchedule))
        .add_system(init_clients)
        .add_system(despawn_disconnected_clients)
        .add_systems((toggle_gamemode_on_sneak, open_chest).in_schedule(EventLoopSchedule));
}

fn setup(mut commands: Commands, server: Res<Server>) {
    let mut instance = server.new_instance(DimensionId::default());

    for z in -5..5 {
        for x in -5..5 {
            instance.insert_chunk([x, z], Chunk::default());
        }
    }

    for z in -25..25 {
        for x in -25..25 {
            instance.set_block([x, SPAWN_Y, z], BlockState::GRASS_BLOCK);
        }
    }
    instance.set_block(CHEST_POS, BlockState::CHEST);

    commands.spawn(instance);

    let mut inventory = Inventory::new(InventoryKind::Generic9x3);
    inventory.set_slot(0, ItemStack::new(ItemKind::Apple, 100, None));
    inventory.set_slot(1, ItemStack::new(ItemKind::Diamond, 40, None));
    inventory.set_slot(2, ItemStack::new(ItemKind::Diamond, 30, None));
    commands.spawn(inventory);
}

fn init_clients(
    mut clients: Query<(&mut Position, &mut Location, &mut Inventory), Added<Client>>,
    instances: Query<Entity, With<Instance>>,
) {
    for (mut pos, mut loc, mut inv) in &mut clients {
        pos.0 = [0.5, SPAWN_Y as f64 + 1.0, 0.5].into();
        loc.0 = instances.single();

        inv.set_slot(24, ItemStack::new(ItemKind::Apple, 100, None));
        inv.set_slot(25, ItemStack::new(ItemKind::Apple, 10, None));
    }
}

// Add new systems here!

fn open_chest(
    mut commands: Commands,
    inventories: Query<Entity, (With<Inventory>, Without<Client>)>,
    mut events: EventReader<PlayerInteractBlock>,
) {
    let Ok(inventory) = inventories.get_single() else {
        return;
    };

    for event in events.iter() {
        if event.position != CHEST_POS.into() {
            continue;
        }
        let open_inventory = OpenInventory::new(inventory);
        commands.entity(event.client).insert(open_inventory);
    }
}

```

</details>

## Test Plan

Steps:
1. `cargo test`

---------

Co-authored-by: Ryan Johnson <ryanj00a@gmail.com>
2023-03-24 05:53:32 -07:00
Ryan Johnson 4cf6e1a207
Entity Rework (#294)
## Description

Closes #269
Closes #199 

- Removes `McEntity` and replaces it with bundles of components, one for
each entity type.
- Tracked data types are now separate components rather than stuffing
everything into a `TrackedData` enum.
- Tracked data is now cached in binary form within each entity,
eliminating some work when entities enter the view of clients.
- Complete redesign of entity code generator.
- More docs for some components.
- Field bits are moved out of the entity extractor and into the valence
entity module.
- Moved hitbox code to separate module.
- Refactor instance update systems to improve parallelism.

### TODOs
- [x] Update examples.
- [x] Update `default_event_handler`.
- [x] Fix bugs.

## Test Plan

Steps:
1. Check out the entity module docs with `cargo d --open`.
2. Run examples.
2023-03-21 23:29:38 -07:00
Ryan Johnson 2c0fb2d8c4
Refactor Schedule (#289)
## Description

- Tweak the system schedule to be more parallel-friendly and explicit.
Dependencies between systems is clearer.
- System and resource configuration is better encapsulated in each
module by using plugins.

The schedule graph for `Main` now looks like this (using
`bevy_mod_debugdump`):


![graph](https://user-images.githubusercontent.com/31678482/225321113-0ec4f4dd-86f6-45fe-8158-12a451536770.svg)

### Unresolved

- What to do about ambiguous systems? Many systems here are ambiguous
because they take `&mut Client`, but the order they write packets isn't
really important. Marking them as ambiguous explicitly with
`.ambiguous_with*` across module boundaries seems difficult and
cumbersome.

## Test Plan

Steps:
1. Run examples. Check that I didn't screw up the system order.
2023-03-15 16:12:59 -07:00
AviiNL 68cf6e83a0
Abstract scoreboard display position (#286)
## Description

The scoreboard display packet has a position field that can contain one
of the following:
- 0: List
- 1: Sidebar
- 2: BelowName
- 3..=18: Team specific sidebar indexed as 3 + team color (according to
wiki.vg)

I'm not really sure how team specific sidebars are supposed to work, so
left that as a byte, maybe that can have some more abstraction?

## Test Plan

<details>

<summary>Playground</summary>

```rust
use valence::client::despawn_disconnected_clients;
use valence::client::event::default_event_handler;
use valence::prelude::*;
use valence::protocol::packet::s2c::play::scoreboard_display::ScoreboardPosition;
use valence::protocol::packet::s2c::play::scoreboard_objective_update::{Mode, RenderType};
use valence::protocol::packet::s2c::play::scoreboard_player_update::Action;
use valence::protocol::packet::s2c::play::{
    ScoreboardDisplayS2c, ScoreboardObjectiveUpdateS2c, ScoreboardPlayerUpdateS2c,
};
use valence::protocol::var_int::VarInt;

const SPAWN_Y: i32 = 64;

pub fn build_app(app: &mut App) {
    app.add_plugin(ServerPlugin::new(()))
        .add_system(default_event_handler.in_schedule(EventLoopSchedule))
        .add_startup_system(setup)
        .add_system(init_clients)
        .add_system(scoreboard)
        .add_system(despawn_disconnected_clients)
        .add_systems(PlayerList::default_systems());
}

fn setup(mut commands: Commands, server: Res<Server>) {
    let mut instance = server.new_instance(DimensionId::default());

    for z in -5..5 {
        for x in -5..5 {
            instance.insert_chunk([x, z], Chunk::default());
        }
    }

    for z in -25..25 {
        for x in -25..25 {
            instance.set_block([x, SPAWN_Y, z], BlockState::GRASS_BLOCK);
        }
    }

    commands.spawn(instance);
}

fn init_clients(
    mut clients: Query<&mut Client, Added<Client>>,
    instances: Query<Entity, With<Instance>>,
) {
    for mut client in &mut clients {
        client.set_position([0.0, SPAWN_Y as f64 + 1.0, 0.0]);
        client.set_instance(instances.single());
        client.set_game_mode(GameMode::Creative);
    }
}

// Add new systems here!
fn scoreboard(mut clients: Query<&mut Client, Added<Client>>) {
    for mut client in &mut clients {
        client.write_packet(&ScoreboardObjectiveUpdateS2c {
            objective_name: "sidebar",
            mode: Mode::Create {
                objective_display_name: "Sidebar".into_text(),
                render_type: RenderType::Integer,
            },
        });
        client.write_packet(&ScoreboardPlayerUpdateS2c {
            action: Action::Update {
                objective_score: VarInt(42),
                objective_name: "sidebar",
            },
            entity_name: "name",
        });
        client.write_packet(&ScoreboardDisplayS2c {
            position: ScoreboardPosition::Sidebar, // Position is now an Enum
            score_name: "sidebar",
        });
    }
}
```

</details>

---------

Co-authored-by: Ryan Johnson <ryanj00a@gmail.com>
2023-03-12 04:51:49 -07:00
Ryan Johnson b46cc502aa
Client Component Division (#266)
## Description

Divides the `Client` component into a set of smaller components as
described by #199 (with many deviations). `McEntity` will be dealt with
in a future PR.

- Divide `Client` into smaller components (There's a lot to look at).
- Move common components to `component` module.
- Remove `Username` type from `valence_protocol` because the added
complexity wasn't adding much benefit.
- Clean up the inventory module.

I've stopped worrying about the "Effect When Added" and "Effect When
Removed" behavior of components so much, and instead assume that all
components of a particular thing are required unless otherwise stated.

## Test Plan

Steps:
1. Run examples and tests.

A large number of tweaks have been made to the inventory module. I tried
to preserve semantics but I could have made a mistake there.

---------

Co-authored-by: Carson McManus <dyc3@users.noreply.github.com>
Co-authored-by: Carson McManus <carson.mcmanus1@gmail.com>
2023-03-11 06:04:14 -08:00
Guac 8bd20e964e
Fix ScoreboardPlayerUpdate packet (#285)
## Description

Fix the contents of the `ScoreboardPlayerUpdateS2c` packet resolving
#284.

## Test Plan

Run the included playground code.

<details>

<summary>Playground</summary>

```rust
use valence::client::despawn_disconnected_clients;
use valence::client::event::default_event_handler;
use valence::prelude::*;
use valence::protocol::packet::s2c::play::scoreboard_objective_update::{Mode, RenderType};
use valence::protocol::packet::s2c::play::scoreboard_player_update::Action;
use valence::protocol::packet::s2c::play::{
    ScoreboardObjectiveUpdateS2c, ScoreboardPlayerUpdateS2c,
};
use valence::protocol::var_int::VarInt;

pub fn build_app(app: &mut App) {
    app.add_plugin(ServerPlugin::new(()))
        .add_system(default_event_handler.in_schedule(EventLoopSchedule))
        .add_startup_system(setup)
        .add_system(init_clients)
        .add_system(scoreboard)
        .add_system(despawn_disconnected_clients);
}

fn setup(world: &mut World) {
    let mut instance = world
        .resource::<Server>()
        .new_instance(DimensionId::default());

    for z in -5..5 {
        for x in -5..5 {
            instance.insert_chunk([x, z], Chunk::default());
        }
    }

    world.spawn(instance);
}

fn init_clients(
    mut clients: Query<&mut Client, Added<Client>>,
    instances: Query<Entity, With<Instance>>,
) {
    let instance = instances.get_single().unwrap();

    for mut client in &mut clients {
        client.set_instance(instance);
    }
}

// Add new systems here!
fn scoreboard(mut clients: Query<&mut Client, Added<Client>>) {
    for mut client in &mut clients {
        client.write_packet(&ScoreboardObjectiveUpdateS2c {
            objective_name: "test",
            mode: Mode::Create {
                objective_display_name: "test display".into_text(),
                render_type: RenderType::Integer,
            },
        });
        client.write_packet(&ScoreboardPlayerUpdateS2c {
            action: Action::Update {
                objective_score: VarInt(0),
                objective_name: "test",
            },
            entity_name: "name",
        });
        client.write_packet(&ScoreboardPlayerUpdateS2c {
            action: Action::Remove {
                objective_name: "test",
            },
            entity_name: "name",
        });
    }
}

```

</details>
2023-03-11 02:41:48 -08:00
AviiNL cd7dd8cc4c
Fix Particle packet id (#281)
Fixes #267

## Description

Swap packet ids `ParticleS2c` with `LightUpdateS2c`

## Test Plan

Steps:
1. Run the `particles.rs` example
2023-03-09 04:02:03 -08:00
Ryan Johnson e933fd69f5
Add RawPacket (#276)
## Description

Adds a `RawPacket` type to `valence_protocol`. This type simply reads
and writes data to a slice, analogous to the `RawBytes` type in the same
module.

## Test Plan

Steps:
1. `cargo t -p valence_protocol`
2023-03-07 20:15:30 -08:00
Ryan e49ab70f16 Fix typo in packet_group macro 2023-03-07 04:23:11 -08:00
Ryan Johnson e64f1b7123
Add packet_name (#274)
## Description

Adds `packet_name` method to the `Packet` trait to help with #238.

## Test Plan

Steps:
1. `cargo t -p valence_protocol`
2023-03-07 04:12:08 -08:00
Ryan Johnson 7af119da72
Replace EncodePacket and DecodePacket with Packet (#261)
## Description

Combines the `EncodePacket` and `DecodePacket` trait into a single
`Packet` trait. This makes `valence_protocol` simpler and easier to use.
This can be done because all packets were made to be bidirectional in
#253.

Additionally, a `packet_id` method has been added. This should help with
#238.

## Test Plan

Steps:
1. Run examples, packet_inspector, etc. Behavior should be the same.
2023-02-25 11:21:25 -08:00
Ryan Johnson 0960ad7ead
Refactor valence_protocol (#253)
## Description

- Remove duplicate packet definitions by using `Cow`.
- Rename packets to match yarn mappings.
- Remove some top-level re-exports.
- Move every packet into its own module for consistency.
- Move packet-specific types from the `types` module into the
appropriate packet module.
- Remove internal use of `EncodePacket`/`DecodePacket` derives and move
packet identification to `packet_group`. This can be done because there
are no duplicate packets anymore.
- Simplify some events.

In a future PR I plan to clean things up further by properly bounding
packet data (to prevent DoS exploits) and fixing any remaining
inconsistencies with the game's packet definitions.

## Test Plan

Behavior of `valence_protocol` should be the same.

Steps:
1. Use the packet inspector against the vanilla server to ensure packet
behavior has not changed.
2. Run the examples.
3. Run `valence_stresser`.
2023-02-23 22:16:22 -08:00
Jade Ellis 9931c8a80b
Provide API for getting the wall variant of blocks (#255)
<!-- Please make sure that your PR is aligned with the guidelines in
CONTRIBUTING.md to the best of your ability. -->
<!-- Good PRs have tests! Make sure you have sufficient test coverage.
-->

## Description

This adds an API for getting the wall / attachable variant of a block. 
Unlike #117 it does not add convenience methods for orientation, and it
does not modify the example to use this code.

## Test Plan

<!-- Explain how you tested your changes, and include any code that you
used to test this. -->
<!-- If there is an example that is sufficient to use in place of a
playground, replace the playground section with a note that indicates
this. -->

The extractor is not tested. 
The API has some tests in the test module.

#### Related

<!-- Link to any issues that have context for this or that this PR
fixes. -->

#115 - it does not fix this, as it doesn't modify the example, but it
could lead to it.

---------

Co-authored-by: EmperialDev <saroke.dev@gmail.com>
2023-02-23 21:21:27 -08:00
Mrln 1ceafe0ce0
Add block entities (#32)
This PR aims to add block entities.
Fixes #5

---------

Co-authored-by: Ryan Johnson <ryanj00a@gmail.com>
2023-02-18 10:16:01 -08:00
Gingeh 50018a52bf
Add sounds (#244)
This is my first time contributing here so I was pretty unfamiliar with
the codebase and may have done some things incorrectly.

## Description
 - Added a sound extractor to extract sound event ids and identifiers
 - Added a `Sound` enum (with a build script) to represent sound effects
 - Added a `play_sound` method to `Instance` and `Client`
 - Re-implemented sound effects in the parkour example

## Test Plan
I tested this using the sounds I added to the parkour example.

#### Related
Hopefully fixes #206
2023-02-15 02:36:21 -08:00
Ryan Johnson 909f7d3909
Clean up dimension/biome code (#239) 2023-02-14 03:36:52 -08:00
Guac c494b83a56
VarInt/VarLong Encode and Decode Optimizations (#227)
Aims to improve upon VarInt/VarLong Encode and Decode procedures (#208).
# Baselines:
## VarInt:

![VarInt::decode](https://user-images.githubusercontent.com/60993440/218295740-c7507993-1c1f-4d71-a42b-4ba9f1437bd7.png)

![VarInt::encode](https://user-images.githubusercontent.com/60993440/218295804-3cda044a-e2e4-4109-83ce-6e0a135d467b.png)
## VarLong

![VarLong::encode](https://user-images.githubusercontent.com/60993440/218295958-e445c2ea-ec2e-422f-92a4-d53bf41c8ec4.png)

![VarLong::decode](https://user-images.githubusercontent.com/60993440/218296047-802cec4a-b69b-435b-a140-0d9bf5df49a8.png)
2023-02-14 03:04:32 -08:00
Ryan Johnson cb9230ec34
ECS Rewrite (#184)
This PR redesigns Valence's architecture around the Bevy Entity
Component System framework (`bevy_ecs` and `bevy_app`). Along the way, a
large number of changes and improvements have been made.
- Valence is now a Bevy plugin. This allows Valence to integrate with
the wider Bevy ecosystem.
- The `Config` trait has been replaced with the plugin struct which is
much easier to configure. Async callbacks are grouped into their own
trait.
- `World` has been renamed to `Instance` to avoid confusion with
`bevy_ecs::world::World`.
- Entities, clients, player list, and inventories are all just ECS
components/resources. There is no need for us to have our own
generational arena/slotmap/etc for each one.
- Client events use Bevy's event system. Users can read events with the
`EventReader` system parameter. This also means that events are
dispatched at an earlier stage of the program where access to the full
server is available. There is a special "event loop" stage which is used
primarily to avoid the loss of ordering information between events.
- Chunks have been completely overhauled to be simpler and faster. The
distinction between loaded and unloaded chunks has been mostly
eliminated. The per-section bitset that tracked changes has been
removed, which should further reduce memory usage. More operations on
chunks are available such as removal and cloning.
- The full client's game profile is accessible rather than just the
textures.
- Replaced `vek` with `glam` for parity with Bevy.
- Basic inventory support has been added.
- Various small changes to `valence_protocol`.
- New Examples
- The terrain and anvil examples are now fully asynchronous and will not
block the main tick loop while chunks are loading.

# TODOs
- [x] Implement and dispatch client events.
- ~~[ ] Finish implementing the new entity/chunk update algorithm.~~ New
approach ended up being slower. And also broken.
- [x] [Update rust-mc-bot to
1.19.3](https://github.com/Eoghanmc22/rust-mc-bot/pull/3).
- [x] Use rust-mc-bot to test for and fix any performance regressions.
Revert to old entity/chunk update algorithm if the new one turns out to
be slower for some reason.
- [x] Make inventories an ECS component.
- [x] Make player lists an ECS ~~component~~ resource.
- [x] Expose all properties of the client's game profile.
- [x] Update the examples.
- [x] Update `valence_anvil`.
- ~~[ ] Update `valence_spatial_index` to use `glam` instead of `vek`.~~
Maybe later
- [x] Make entity events use a bitset.
- [x] Update docs.

Closes #69
Closes #179
Closes #53

---------

Co-authored-by: Carson McManus <dyc3@users.noreply.github.com>
Co-authored-by: AviiNL <me@avii.nl>
Co-authored-by: Danik Vitek <x3665107@gmail.com>
Co-authored-by: Snowiiii <71594357+Snowiiii@users.noreply.github.com>
2023-02-11 09:51:53 -08:00
Guac 44ea6915db
Implement remaining clientbound packets (#197)
Aims to close #186
2023-02-03 22:30:12 -08:00
Ryan Johnson b5a355c756
Non-Object Text Deserialization (#194)
- Extends `Text`'s `Deserialize` impl to allow for deserializing JSON
data types other than objects.
- Add additional `From` impls for `Text`.
- Better `Debug` impl for `Text`.
- Tweaked text unit tests.
2023-01-21 00:17:19 -08:00
Guac ad89e4457c
Implement clientbound packets (#190)
Co-authored-by: Ryan Johnson <ryanj00a@gmail.com>
2023-01-19 22:00:35 -08:00
Ryan Johnson 34c01d0f24
Add debug logging to valence_protocol (#191)
Adds `tracing` to `valence_protocol` so we can log debug info about
partially decoded packets. `packet_inspector` has been set to print log
messages at the debug level.
2023-01-16 16:32:22 -08:00
Ryan Johnson 7574fa33c5
Commands and recipe book packets (#183)
Implement the commands and recipe book packets. Also reorganizes some
modules in valence_protocol.
2022-12-31 22:59:22 -08:00
Ryan Johnson 8d9c0a7553
Add recipe and tags packets (#182)
Also improve generated `Encode`, `Decode` error messages and fix
unnecessary build script reruns.
2022-12-30 06:18:24 -08:00
Ryan Johnson 2597e92b8f
Reorganize Packages (#180)
Moves all the packages to the `crates/` directory.
2022-12-29 16:51:05 -08:00