-
-
Notifications
You must be signed in to change notification settings - Fork 151
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Dividing Clients and Entities into smaller components #199
Comments
This will be great to have. Can we get an ecs rewrite label on this?
For block entities: I would like to have a
Edit: This is no longer relevant, we've made the changes to make unit tests work. Could look like this? erDiagram
PacketStreamSource ||--|| Client : injects
PacketStreamSink ||--|| Client : extracts
classDiagram
class PacketStreamSource {
+recv()
}
class PacketStreamSink {
+send()
}
class MockPacketStreamSource {
queue
+recv()
}
class RealPacketStreamSource {
socket
+recv()
}
RealPacketStreamSource --|> PacketStreamSource
MockPacketStreamSource --|> PacketStreamSource
class MockPacketStreamSink {
record
+send()
}
class RealPacketStreamSink {
socket
+send()
}
RealPacketStreamSink --|> PacketStreamSink
MockPacketStreamSink --|> PacketStreamSink
Not a comprehensive diagram by any means, but just brainstorming Regarding some of your questions:
That sounds incredibly jank.
We might be able to do something with traits: https://bevy-cheatbook.github.io/patterns/generic-systems.html#using-traits
The
Yes, definitely. It should denote that the Entity it's attached to is directly correlated to a Minecraft entity.
The most effective way would be to put an API layer over all the ecs stuff that doesn't allow that stuff. This seems incredibly impractical, but certainly would be effective. Logging would probably be the preferred way to go about it. People get angry when their services shit themselves and die. Panics should be reserved for states that are absolutely and totally unrecoverable. It might not be worth the effort at all. Consider that it may be significantly easier to just make it so that doing these things are undesirable compared to whatever is "best practice". |
Think I'm going to start working on this in earnest after #184 is merged.
Agree. Also I believe Minecraft has a concept of "location" which is an XYZ coordinate paired with a dimension (hence
The position of a block entity would be known by its position in the
Originally clients were designed to work exactly like this. Clients had a pair of channels for sending and receiving packets. Encoding and decoding of those packets were handled elsewhere by a tokio task in another thread. Simple as that. Problem is, this is measurably less efficient than the current approach for a few reasons:
Here is what I propose: Add a public constructor to
I guess in theory we could make all of our internal systems that work on entities generic and register hundreds of monomorphized systems, but that's obviously not very practical. Even then I think there would have to be some major algorithm changes. Combining
How about the name
Panics in debug mode with warnings in release mode sound like the way to go. I don't think this would be very difficult to set up actually. All we need is a |
Ah, I see.
I think that's less clear. |
<!-- 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 <!-- Describe the changes you've made. You may include any justification you want here. --> Dropping items is heavily coupled to inventories. Clients also predict state changes when they try to drop items, so we need to be able to replicate that change in order to stay in sync. This will also remove `DropItem` events in favor of just `DropItemStack` events. Having 2 event streams that basically mean the same thing seems verbose and error prone. As of right now, these changes require the event loop to have a reference to the client's inventory. This seems like something we are going to need to do a lot more of to complete #199. ## 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. --> <details> <summary>Playground</summary> ```rust use tracing::info; use valence::client::despawn_disconnected_clients; use valence::client::event::{default_event_handler, DropItemStack}; use valence::prelude::*; #[allow(unused_imports)] use crate::extras::*; const SPAWN_Y: i32 = 64; pub fn build_app(app: &mut App) { app.add_plugin(ServerPlugin::new(()).with_connection_mode(ConnectionMode::Offline)) .add_system_to_stage(EventLoop, default_event_handler) .add_startup_system(setup) .add_system(init_clients) .add_system(despawn_disconnected_clients) .add_system(toggle_gamemode_on_sneak) .add_system(drop_items); } 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()); } } for z in -25..25 { for x in -25..25 { instance.set_block([x, SPAWN_Y, z], BlockState::GRASS_BLOCK); } } 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_position([0.5, SPAWN_Y as f64 + 1.0, 0.5]); client.set_instance(instance); client.set_game_mode(GameMode::Creative); } } fn drop_items(clients: Query<&Client>, mut drop_stack_events: EventReader<DropItemStack>) { if drop_stack_events.is_empty() { return; } for event in drop_stack_events.iter() { info!("drop stack: {:?}", event); } } ``` </details> <!-- You need to include steps regardless of whether or not you are using a playground. --> Steps: 1. `cargo test -p valence --tests` 2. Run playground `cargo run -p playground` 3. Open creative menu 4. Pick an item and click to drop it outside of the creative menu 5. Pick an entire stack of an item, place it in your hotbar 6. Hover over the item, press your drop key to drop an item from the stack 7. Press shift to switch to survival 8. Select the item stack in your hotbar, press your drop key to drop an item from the stack 9. Open your inventory, grab the stack, hover outside the window and click to drop the entire stack 10. Grab another stack from creative, place it in your hotbar 11. switch back to survival, select the stack, and press your control + drop key to drop the entire stack 12. For each item you dropped, you should see a log message with the event #### Related <!-- Link to any issues that have context for this or that this PR fixes. -->
## 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 <[email protected]> Co-authored-by: Carson McManus <[email protected]>
Brainstorming some ideas for how the monolithic
Client
andMcEntity
components could be split up into a set of smaller components. Here are some reasons you would want to do this:Some reasons you wouldn't want to do this:
Despawned
McEntity
and its other components.Client
Client
to existing entities somehow?McEntity
will allow you to take control.Disconnected
Location
old_instance == new_instance
. Can be used to respawn the client after death.Position
Direction
Position
modifications to form a single teleport.Velocity
OnGround
Vehicle
DeathLocation
(DimensionId, BlockPos)
pair. Used by respawning clients to set their recovery compass positionGameModeComponent
(GameMode
was taken)McEntity
Location
andPosition
to do so. Sets the protocol ID to the next unique value. Was initialized to zero when the component was created.EntityKindComponent
(EntityKind
was taken)*Metadata
, where*
is every entity type. Component and system definitions would be generated.TrackedData
) of a particular entity type.TrackedData
is currently an enum, so this would save a lot of space. Not to mention easier because it's queryable and you wouldn't have to match on any enums.EntityKindComponent
. WhenPlayerMetadata
is modified on a client, the changes are sent to the client's own player entity.ExpOrbCount
FallingBlockState
BlockState
of falling block entitiesStatuses
Animations
Hitbox
Questions
Location
/OldLocation
andPosition
/OldPosition
, or is that kind of thing too cumbersome?Client
likeis_hardcore
,is_flat
, etc?McEntity
.McEntity
need to exist? It's kind of an ugly name.The text was updated successfully, but these errors were encountered: