Store backend command tree per server connection to allow on-demand resending of command set#1808
Conversation
…esending of command set
| * | ||
| * @return a future that completes once the command list has been sent | ||
| */ | ||
| CompletableFuture<Void> sendAvailableCommands(); |
There was a problem hiding this comment.
I'm not too sure if we need to return a CompletableFuture here. This doesn't get returned anywhere else in the Player interface, but at the same time, when this is completed it does guarantee that all PlayerAvailableCommandsEvents have been fired and the packet is on its way to the player.
Could this be useful for plugins? Or should we just return void and rely on plugins listening for this even to figure out that the packet is (about to be) on it's way, as a plugin calling this method, is most likely also manipulating this event?
R00tB33rMan
left a comment
There was a problem hiding this comment.
Approving in its current state - changes may need to be made for other considerations by authors, of course
|
My initial thought was to put this behind add a feature flag system, which would need to be enabled by plugins on init but... |
I mean we could do this intuitively.
interface AvailableCommandsService {
void sendAvailableCommands(Player player);
}Plugins would need to obtain the The issue is however that plugins really need to do this on startup, or they'll end up missing the backend command trees from players that are already connected. Though I don't really like this. Seems complex and unnecessary to avoid a couple megabytes of ram, realistically. |
|
Wouldn't it need to be renamed from RootBeer? Edit: lol I'm an idiot I read |
We could also just expose the |
I don't think we have any feature that works like this right? If we are going to set a precedent for "resource intensive feature that must be opt-in in an elegant way" we need to think of a proper solution, one that would also work for future features like this. An alternative for this specific PR could be to store the raw packet instead of the decoded command tree. Decode the packet only when |
Sure, though we also should think about the users of this API and if it is hidden behind some 'obscure' mechanism they might not find it |
I mean, if we don't want to hide this API, we could keep This should never really produce an exception at runtime, because plugin developers will (should) catch this during development. Alternatively we could log an error or warning and have it behave like a NOP instead of throwing. |
This is really cursed. |
Well this is what I meant.
Well I think this could be annoying, and idk but I see no benefit with this option |
Inspired by:
With this PR, plugins may dynamically decide to add commands to the client's command tree by triggering
Player#sendAvailableCommandsand listening for thePlayerAvailableCommandsEventthat gets fired as a result of it.How much memory does this PR consume per player?
Let's assume 1.000 commands per player. A conservative lower bound, and a complete but educated-ish guess, would be about ~64 bytes per command, giving 64kb per player (for 500 players, this is 32MB)
Take this with a giant grain of salt, but I had Claude Opus 4.7 have a go at estimating the memory footprint this PR brings with it.
Prompt:
Investigate exactly how much memory 'RootCommandNode<CommandSource> backendCommandsNode' in 'BackendPlaySessionHandler' consumes per player for 1000 commands with typical string lengths.After 7 minutes of "brewing", it estimated 274-331 bytes per command, giving ~300kb per player. This would be a more substantial 150MB at 500 players.
If this does become a feature of Velocity, we may consider hiding the
velocity:callbackcommand from the command tree unless a plugin registers a click-callback through Adventure (vanilla Velocity never uses this feature; this command only really needs to be sent to the client if a plugin does actually make use of this feature). See: GemstoneGG#866