@@ -17,6 +17,20 @@ flowchart LR
1717 backend -->|"3 (Incoming)"| Velocity -->|"4 (Outgoing)"| player
1818```
1919
20+ :::warning
21+
22+ When listening to ` PluginMessageEvent ` , ensure the result is
23+ <Javadoc name = { " com/velocitypowered/api/event/connection/PluginMessageEvent$ForwardResult#handled()" } project = { " velocity" } >` ForwardResult.handled() ` </Javadoc >
24+ if you do not intend the client to participate.
25+
26+ If the result is forwarded, players can impersonate the proxy to your backend servers.
27+
28+ Additionally, ensure the result is set correctly after actually handling correct messages, to prevent them from being leaked to the other party.
29+
30+ This can be achieved with unconditionally setting the result between checking the identifier and checking the source, as shown in the examples.
31+
32+ :::
33+
2034Additionally, BungeeCord channel compatibility is included, which may remove the need for a companion Velocity plugin in certain cases.
2135
2236## Case 1: Receiving a plugin message from a player
@@ -26,6 +40,19 @@ It will require registering with the ChannelRegistrar for the event to be fired.
2640
2741An example use case could be logging messages from a mod that reports the enabled features.
2842
43+ ``` mermaid
44+ flowchart LR
45+ subgraph handle from player
46+ direction LR
47+ a[player] --> b[Velocity] ~~~ c[backend]
48+ end
49+ subgraph forward from player
50+ direction LR
51+ d[player] --> e[Velocity] --> f[backend]
52+ end
53+ ```
54+
55+
2956``` java
3057public static final MinecraftChannelIdentifier IDENTIFIER = MinecraftChannelIdentifier . from(" custom:main" );
3158
@@ -36,12 +63,23 @@ public void onProxyInitialization(ProxyInitializeEvent event) {
3663
3764@Subscribe
3865public void onPluginMessageFromPlayer(PluginMessageEvent event) {
39- if (! (event. getSource() instanceof Player )) {
66+ // Check if the identifier matches first, no matter the source.
67+ if (! IDENTIFIER . equals(event. getIdentifier())) {
4068 return ;
4169 }
42- Player player = (Player ) event. getSource();
43- // Ensure the identifier is what you expect before trying to handle the data
44- if (event. getIdentifier() != IDENTIFIER ) {
70+
71+ // mark PluginMessage as handled, indicating that the contents
72+ // should not be forwarding to their original destination.
73+ event. setResult(PluginMessageEvent . ForwardResult . handled());
74+
75+ // Alternatively:
76+
77+ // mark PluginMessage as forwarded, indicating that the contents
78+ // should be passed through, as if Velocity is not present.
79+ // event.setResult(PluginMessageEvent.ForwardResult.forward());
80+
81+ // only attempt parsing the data if the source is a player
82+ if (! (event. getSource() instanceof Player player)) {
4583 return ;
4684 }
4785
@@ -64,6 +102,15 @@ Otherwise, a player can pretend to be your proxy, and spoof them.
64102
65103:::
66104
105+ ``` mermaid
106+ flowchart LR
107+ subgraph Send to Backend
108+ direction LR
109+ player ~~~ Velocity --> backend
110+ end
111+ ```
112+
113+
67114### Using any connected player
68115
69116This is useful if you just want to communicate something relevant to the entire server,
@@ -104,6 +151,18 @@ for the event to be fired.
104151
105152An example use case could be handing a request to transfer the player to another server.
106153
154+ ``` mermaid
155+ flowchart LR
156+ subgraph handle from backend
157+ direction RL
158+ a[backend] --> b[Velocity] ~~~ c[ player]
159+ end
160+ subgraph forward from backend
161+ direction RL
162+ d[backend] --> e[Velocity] --> f[player]
163+ end
164+ ```
165+
107166``` java
108167public static final MinecraftChannelIdentifier IDENTIFIER = MinecraftChannelIdentifier . from(" custom:main" );
109168
@@ -114,12 +173,28 @@ public void onProxyInitialization(ProxyInitializeEvent event) {
114173
115174@Subscribe
116175public void onPluginMessageFromBackend(PluginMessageEvent event) {
117- if (! (event. getSource() instanceof ServerConnection )) {
176+ // Check if the identifier matches first, no matter the source.
177+ // this allows setting all messages to IDENTIFIER as handled,
178+ // preventing any client-originating messages from being forwarded.
179+ if (! IDENTIFIER . equals(event. getIdentifier())) {
118180 return ;
119181 }
120- ServerConnection backend = (ServerConnection ) event. getSource();
121- // Ensure the identifier is what you expect before trying to handle the data
122- if (event. getIdentifier() != IDENTIFIER ) {
182+
183+ // mark PluginMessage as handled, indicating that the contents
184+ // should not be forwarding to their original destination.
185+ event. setResult(PluginMessageEvent . ForwardResult . handled());
186+
187+ // Alternatively:
188+
189+ // mark PluginMessage as forwarded, indicating that the contents
190+ // should be passed through, as if Velocity is not present.
191+ //
192+ // this should be used with extreme caution,
193+ // as any client can freely send whatever it wants, pretending to be the proxy
194+ // event.setResult(PluginMessageEvent.ForwardResult.forward());
195+
196+ // only attempt parsing the data if the source is a backend server
197+ if (! (event. getSource() instanceof ServerConnection backend)) {
123198 return ;
124199 }
125200
@@ -138,6 +213,14 @@ This is only really useful for when you are making client-side mods. Otherwise,
138213
139214:::
140215
216+ ``` mermaid
217+ flowchart RL
218+ subgraph Send to Player
219+ direction RL
220+ backend ~~~ Velocity --> player
221+ end
222+ ```
223+
141224``` java
142225public boolean sendPluginMessageToPlayer(Player player, ChannelIdentifier identifier, byte [] data) {
143226 // On success, returns true
0 commit comments