-
-
Notifications
You must be signed in to change notification settings - Fork 145
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
Visibility layers for Minecraft Entities #362
Conversation
## Description Basic implementation of world border World border is not enabled by default. It can be enabled by inserting `WorldBorderBundle` bundle. Currently, this PR only implements world borders per instance, I'm considering expanding this per client. However, the same functionality can be achieved by Visibility Layers #362 <details> <summary>Playground:</summary> ```rust fn border_controls( mut events: EventReader<ChatMessageEvent>, mut instances: Query<(Entity, &WorldBorderDiameter, &mut WorldBorderCenter), With<Instance>>, mut event_writer: EventWriter<SetWorldBorderSizeEvent>, ) { for x in events.iter() { let parts: Vec<&str> = x.message.split(' ').collect(); match parts[0] { "add" => { let Ok(value) = parts[1].parse::<f64>() else { return; }; let Ok(speed) = parts[2].parse::<i64>() else { return; }; let Ok((entity, diameter, _)) = instances.get_single_mut() else { return; }; event_writer.send(SetWorldBorderSizeEvent { instance: entity, new_diameter: diameter.diameter() + value, speed, }) } "center" => { let Ok(x) = parts[1].parse::<f64>() else { return; }; let Ok(z) = parts[2].parse::<f64>() else { return; }; instances.single_mut().2 .0 = DVec2 { x, y: z }; } _ => (), } } } ``` </details> example: `cargo run --package valence --example world_border` tests: `cargo test --package valence --lib -- tests::world_border` **Related** part of #210
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to see some unit tests for this.
Currently working on a redesign of Instances and Chunks to fix a number of issues. I'd like to finish my redesign before taking a closer look at this, since it may have a large impact on the approach taken here. |
Visibility Layers will impact a lot of features IMO. I think we should take our time and make it right the first time or it gonna be expensive to fix later. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work on implementing Visibility Layers. I have a few suggestions and design choices to consider.
/// Example: you have `Layer(0)` on a cow, it will only be visible to clients | ||
/// with the access to layer 0 in their `ClientLayerSet`. | ||
#[derive(Component, Copy, Clone, PartialEq, Eq, Debug)] | ||
pub struct Layer(pub LayerType); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should an Entity be on multiple layers? It could be useful for interactions between different entities such as collisions, ai behaviors, hit-scanning
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't really know for this one, cause the use of the layer is primarily for visibility, and having entity on multiple layer pose question like if the entity and client have two layers in common, what append ?
I think that maybe we can rename this one visibility layer and there could be other layer types for collisions and ai.
But even that I don't really see the use case ngl.
Finished the chunk/instance redesign in #402. Let me know if you have any issues. |
Here's my take on visibility layers: #424. |
# Objective The objective of this PR is to solve the following problems with a holistic redesign of instances. Closes #342, #362, but deviates greatly from the solution described in the issue. - If an entity is within the view distance of a client, packets for that entity are sent to the client unconditionally. However, there is often a need to limit the visibility of entities to certain clients depending on the situation. Some examples: - You have a minigame with spectators and players. Spectators can see both players and spectators, but players can only see players and _not_ spectators. - An entity or set of entities is used as a makeshift GUI, only visible to the client using the GUI. - The server has many separate "arenas" that have identical chunk data, and you wish to share the chunk data across arenas to save memory. - You want to make a player truly invisible and potentially have some other entity take its place. It is possible to work around the problem by using invisibility effects or sending packets manually. But these are hacky solutions that are incomplete, inefficient, and inconvenient. - Updating clients involves looking up every chunk in the client's view distance every tick for every client. This wastes CPU time and doesn't scale well with larger view distances[^1]. - Sometimes we want to broadcast packets to all clients matching some condition. Conditions could include... - If a chunk position is within the client's view. - If the client is within a certain radius of some position. - If the client is not some specific client (self exclusion). It isn't really possible to add all of these conditions in an efficient way using the current design. # Solution Split the existing `Instance` component into two new components: `ChunkLayer` and `EntityLayer`. Chunk layers contain all of the chunks in a world along with some global configuration, like the world's dimension. Entity layers contain Minecraft entities. A `LayerBundle` containing both is provided for convenience. Both `ChunkLayer` and `EntityLayer` implement the common `Layer` trait. The key idea is this: Clients can only view one chunk layer[^2], but can view any number of entity layers. These are the `VisibleChunkLayer` and `VisibleEntityLayers` components respectively. The client will receive entity packets from only the layers it can see. Clients can add and remove entity layers at any time to spawn and despawn the entities in the layer. Every layer contains a "message buffer" for broadcasting information to all viewers. Every message contains a "key" and a payload of bytes (its meaning depends on the message). Clients walk through the list of messages and use this to update themselves. There are a few things done to make this faster: - Message processing is parallelized over all clients. - The messages are sorted by their "key" and then deduplicated by merging payloads together. For instance, messages sending packet data on the condition that a certain chunk position is in view will be merged together if the chunk position is the same. Now there's only one memcpy instead of two. - Messages are split into two categories: "global" and "local". Local messages are those that have some spatial condition to them. Local messages are put in a bounding volume hierarchy so that large swaths of messages do not need to be examined by clients. [^1]: At least the work is completely parallelized ¯\\\_(ツ)\_/¯. [^2]: Viewing multiple chunk layers has some technical problems and I don't see it as a design worth pursuing. --------- Co-authored-by: Carson McManus <[email protected]>
Ref
#342
Description
Implementation of a layer system for mob, the client can have a
ClientLayerMask
component which determine for what layer he can see mobs. The mobs them can have aLayer
component which determine on what layer they are.Implementation
Potential Upgrade
layer
component be able to have the ref of an client to not use a layer per client when we just need to sned to one playerPlayground
code