Compare commits
167 Commits
Minecraft-
...
Minecraft-
Author | SHA1 | Date | |
---|---|---|---|
![]() |
a9603a6372 | ||
![]() |
b15ed87ad5 | ||
![]() |
3e816f628b | ||
![]() |
7bfc4bf819 | ||
![]() |
f8d15f4c88 | ||
![]() |
a73b06eee3 | ||
![]() |
2069679140 | ||
![]() |
9a173968f1 | ||
![]() |
13f1fa7443 | ||
![]() |
0f7da279ef | ||
![]() |
a6ba661a32 | ||
![]() |
22133bc8d2 | ||
![]() |
f9c9517958 | ||
![]() |
7a79bd0816 | ||
![]() |
6a60376033 | ||
![]() |
4ce0eee232 | ||
![]() |
72f3a79759 | ||
![]() |
dbb6aebf58 | ||
![]() |
54040ec48d | ||
![]() |
8c4ddf458c | ||
![]() |
07fb6490f8 | ||
![]() |
d9eb8c66b8 | ||
![]() |
7fab3ba372 | ||
![]() |
92c3ef1989 | ||
![]() |
fbf2d8969e | ||
![]() |
1881507712 | ||
![]() |
fd2a72477f | ||
![]() |
d4cbac1bdf | ||
![]() |
fa0671ab2a | ||
![]() |
184154a8b3 | ||
![]() |
cbec4e836a | ||
![]() |
3ce7982778 | ||
![]() |
b55944e2fb | ||
![]() |
12cba14657 | ||
![]() |
78e67283cc | ||
![]() |
f0f1e71c93 | ||
![]() |
3c1a5aabfd | ||
![]() |
f0d4e8c24a | ||
![]() |
ba8bd7faf0 | ||
![]() |
787692070e | ||
![]() |
523e991018 | ||
![]() |
7733fbfb28 | ||
![]() |
44ac36941f | ||
![]() |
0235c4a01e | ||
![]() |
b4220e9229 | ||
![]() |
9b9addfccd | ||
![]() |
b75a2b5060 | ||
![]() |
b5aecd5dcc | ||
![]() |
4d51d16512 | ||
![]() |
05a9342854 | ||
![]() |
483fede234 | ||
![]() |
ce8f1b44b6 | ||
![]() |
b1e3f6a75b | ||
![]() |
33d315b719 | ||
![]() |
d11e130d61 | ||
![]() |
45a93c8cfc | ||
![]() |
fd411edddb | ||
![]() |
ac5e8dbaff | ||
![]() |
340d82812a | ||
![]() |
eaf99cf4a6 | ||
![]() |
4baae5a230 | ||
![]() |
aa1a871967 | ||
![]() |
18f5ed3102 | ||
![]() |
d1dd7379b1 | ||
![]() |
0b0d09427d | ||
![]() |
dce0f6b408 | ||
![]() |
c5307c4451 | ||
![]() |
4f2b98188e | ||
![]() |
d5eb37c7a6 | ||
![]() |
2a421cdd8d | ||
![]() |
757f8f0cb9 | ||
![]() |
388d2620db | ||
![]() |
3ba52cb98b | ||
![]() |
e652214071 | ||
![]() |
0821404f92 | ||
![]() |
11b90b91b7 | ||
![]() |
aa3989db19 | ||
![]() |
76c914db14 | ||
![]() |
639e5f3c1d | ||
![]() |
9fd69068ae | ||
![]() |
9c35cad824 | ||
![]() |
d82b29e15a | ||
![]() |
9b0c827c37 | ||
![]() |
125d3f07f7 | ||
![]() |
2f45f0d578 | ||
![]() |
ad4c143ce4 | ||
![]() |
835e4e332c | ||
![]() |
0578f94522 | ||
![]() |
0cd4c9030c | ||
![]() |
0d666168f0 | ||
![]() |
cfb823f077 | ||
![]() |
36a5e89ff9 | ||
![]() |
bb4e8e29a5 | ||
![]() |
8e34e038d6 | ||
![]() |
d1950389cc | ||
![]() |
9d841bb91a | ||
![]() |
828cebcc4b | ||
![]() |
12fec2fcdd | ||
![]() |
8b6b134662 | ||
![]() |
538beb33a6 | ||
![]() |
97338cbfad | ||
![]() |
3e28decef2 | ||
![]() |
f93b647df3 | ||
![]() |
775ffdc998 | ||
![]() |
80c22027de | ||
![]() |
122987dd83 | ||
![]() |
ac4bab2425 | ||
![]() |
a51ffb1f4c | ||
![]() |
77e0dcc7f8 | ||
![]() |
ddb93fd988 | ||
![]() |
7eac22d362 | ||
![]() |
185dc97ca6 | ||
![]() |
e0d19cf305 | ||
![]() |
0e9002091b | ||
![]() |
9fdcded97f | ||
![]() |
32fdc83841 | ||
![]() |
1bf126d4f8 | ||
![]() |
56533c6259 | ||
![]() |
4cb46c6e5c | ||
![]() |
6decf860c9 | ||
![]() |
29f22f9be9 | ||
![]() |
98860ffd02 | ||
![]() |
2c225a05e7 | ||
![]() |
c1dfd0fb7b | ||
![]() |
9be44d51a6 | ||
![]() |
2a2c2717d5 | ||
![]() |
3f994a1c4c | ||
![]() |
9a0da50e6c | ||
![]() |
67fdc830c2 | ||
![]() |
64e8a79551 | ||
![]() |
afc387ce0d | ||
![]() |
8a70af5293 | ||
![]() |
57793e93f0 | ||
![]() |
a48ef137bd | ||
![]() |
ff32d29e09 | ||
![]() |
9f3359f8fa | ||
![]() |
539fccb873 | ||
![]() |
b25c81daf3 | ||
![]() |
21a354fa75 | ||
![]() |
aefe3333a9 | ||
![]() |
0afefa8f61 | ||
![]() |
834ac24b38 | ||
![]() |
c465eca03b | ||
![]() |
beb0bf9836 | ||
![]() |
688c42219c | ||
![]() |
1ea53f01aa | ||
![]() |
202dab5c98 | ||
![]() |
49ea7f908f | ||
![]() |
9d3bddedb6 | ||
![]() |
332bdaaec0 | ||
![]() |
904a1bfaa3 | ||
![]() |
5eb7a6eba7 | ||
![]() |
8e262cf428 | ||
![]() |
125df5c22d | ||
![]() |
7b631092f5 | ||
![]() |
d3c1339cc9 | ||
![]() |
679bf2fca9 | ||
![]() |
7436621481 | ||
![]() |
6236cff658 | ||
![]() |
6b504d9160 | ||
![]() |
d1124ca70b | ||
![]() |
779582d441 | ||
![]() |
b91564f77a | ||
![]() |
30b2e5008b | ||
![]() |
140830efe0 | ||
![]() |
5f8e76c61c | ||
![]() |
b7511abfda |
7
.gitignore
vendored
7
.gitignore
vendored
@@ -1,12 +1,11 @@
|
||||
# Eclipse stuff
|
||||
.classpath/
|
||||
.project/
|
||||
.settings/
|
||||
.classpath
|
||||
.project
|
||||
.settings
|
||||
|
||||
# netbeans
|
||||
nbproject/
|
||||
nbactions.xml
|
||||
nb-configuration.xml
|
||||
|
||||
# we use maven!
|
||||
build.xml
|
||||
|
31
api/nb-configuration.xml
Normal file
31
api/nb-configuration.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project-shared-configuration>
|
||||
<!--
|
||||
This file contains additional configuration written by modules in the NetBeans IDE.
|
||||
The configuration is intended to be shared among all the users of project and
|
||||
therefore it is assumed to be part of version control checkout.
|
||||
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
|
||||
-->
|
||||
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
|
||||
<!--
|
||||
Properties that influence various parts of the IDE, especially code formatting and the like.
|
||||
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
|
||||
That way multiple projects can share the same settings (useful for formatting rules for example).
|
||||
Any value defined here will override the pom.xml file value but is only applicable to the current project.
|
||||
-->
|
||||
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>
|
||||
</properties>
|
||||
</project-shared-configuration>
|
14
api/pom.xml
14
api/pom.xml
@@ -28,7 +28,19 @@
|
||||
<dependency>
|
||||
<groupId>com.ning</groupId>
|
||||
<artifactId>async-http-client</artifactId>
|
||||
<version>1.7.14</version>
|
||||
<version>1.7.17</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-event</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-protocol</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
@@ -1,111 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 The Guava Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.common.eventbus;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.reflect.TypeToken;
|
||||
import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A {@link HandlerFindingStrategy} for collecting all event handler methods that are marked with
|
||||
* the {@link Subscribe} annotation.
|
||||
*
|
||||
* @author Cliff Biffle
|
||||
* @author Louis Wasserman
|
||||
*/
|
||||
class AnnotatedHandlerFinder implements HandlerFindingStrategy {
|
||||
/**
|
||||
* A thread-safe cache that contains the mapping from each class to all methods in that class and
|
||||
* all super-classes, that are annotated with {@code @Subscribe}. The cache is shared across all
|
||||
* instances of this class; this greatly improves performance if multiple EventBus instances are
|
||||
* created and objects of the same class are registered on all of them.
|
||||
*/
|
||||
private static final LoadingCache<Class<?>, ImmutableList<Method>> handlerMethodsCache =
|
||||
CacheBuilder.newBuilder()
|
||||
.weakKeys()
|
||||
.build(new CacheLoader<Class<?>, ImmutableList<Method>>() {
|
||||
@Override
|
||||
public ImmutableList<Method> load(Class<?> concreteClass) throws Exception {
|
||||
return getAnnotatedMethodsInternal(concreteClass);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* This implementation finds all methods marked with a {@link Subscribe} annotation.
|
||||
*/
|
||||
@Override
|
||||
public Multimap<Class<?>, EventHandler> findAllHandlers(Object listener) {
|
||||
Multimap<Class<?>, EventHandler> methodsInListener = HashMultimap.create();
|
||||
Class<?> clazz = listener.getClass();
|
||||
for (Method method : getAnnotatedMethods(clazz)) {
|
||||
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||
Class<?> eventType = parameterTypes[0];
|
||||
EventHandler handler = new EventHandler(listener, method);
|
||||
methodsInListener.put(eventType, handler);
|
||||
}
|
||||
return methodsInListener;
|
||||
}
|
||||
|
||||
private static ImmutableList<Method> getAnnotatedMethods(Class<?> clazz) {
|
||||
try {
|
||||
return handlerMethodsCache.getUnchecked(clazz);
|
||||
} catch (UncheckedExecutionException e) {
|
||||
throw Throwables.propagate(e.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
private static ImmutableList<Method> getAnnotatedMethodsInternal(Class<?> clazz) {
|
||||
Set<? extends Class<?>> supers = TypeToken.of(clazz).getTypes().rawTypes();
|
||||
ImmutableList.Builder<Method> result = ImmutableList.builder();
|
||||
for (Method method : clazz.getMethods()) {
|
||||
/*
|
||||
* Iterate over each distinct method of {@code clazz}, checking if it is annotated with
|
||||
* @Subscribe by any of the superclasses or superinterfaces that declare it.
|
||||
*/
|
||||
for (Class<?> c : supers) {
|
||||
try {
|
||||
Method m = c.getMethod(method.getName(), method.getParameterTypes());
|
||||
if (m.isAnnotationPresent(Subscribe.class)) {
|
||||
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||
if (parameterTypes.length != 1) {
|
||||
throw new IllegalArgumentException("Method " + method
|
||||
+ " has @Subscribe annotation, but requires " + parameterTypes.length
|
||||
+ " arguments. Event handler methods must require a single argument.");
|
||||
}
|
||||
Class<?> eventType = parameterTypes[0];
|
||||
result.add(method);
|
||||
break;
|
||||
}
|
||||
} catch (NoSuchMethodException ignored) {
|
||||
// Move on.
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.build();
|
||||
}
|
||||
}
|
@@ -12,9 +12,9 @@ import lombok.Getter;
|
||||
import net.md_5.bungee.api.config.ConfigurationAdapter;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.connection.Server;
|
||||
import net.md_5.bungee.api.plugin.Plugin;
|
||||
import net.md_5.bungee.api.scheduler.TaskScheduler;
|
||||
import net.md_5.bungee.api.tab.CustomTabList;
|
||||
|
||||
public abstract class ProxyServer
|
||||
{
|
||||
@@ -49,6 +49,13 @@ public abstract class ProxyServer
|
||||
*/
|
||||
public abstract String getVersion();
|
||||
|
||||
/**
|
||||
* Gets a localized string from the .properties file.
|
||||
*
|
||||
* @return the localized string
|
||||
*/
|
||||
public abstract String getTranslation(String name);
|
||||
|
||||
/**
|
||||
* Gets the main logger which can be used as a suitable replacement for
|
||||
* {@link System#out} and {@link System#err}.
|
||||
@@ -72,20 +79,6 @@ public abstract class ProxyServer
|
||||
*/
|
||||
public abstract ProxiedPlayer getPlayer(String name);
|
||||
|
||||
/**
|
||||
* Get a server by its name. The instance returned will be taken from a
|
||||
* player currently on that server to facilitate abstract proxy -> server
|
||||
* actions.
|
||||
*
|
||||
* @param name the name to lookup
|
||||
* @return the associated server
|
||||
* @deprecated in most cases the {@link #getServerInfo(java.lang.String)}
|
||||
* method should be used, as it will return a server even when no players
|
||||
* are online.
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract Server getServer(String name);
|
||||
|
||||
/**
|
||||
* Return all servers registered to this proxy, keyed by name. Unlike the
|
||||
* methods in {@link ConfigurationAdapter#getServers()}, this will not
|
||||
@@ -127,21 +120,6 @@ public abstract class ProxyServer
|
||||
*/
|
||||
public abstract void setConfigurationAdapter(ConfigurationAdapter adapter);
|
||||
|
||||
/**
|
||||
* Get the currently in use tab list handle.
|
||||
*
|
||||
* @return the tab list handler
|
||||
*/
|
||||
public abstract TabListHandler getTabListHandler();
|
||||
|
||||
/**
|
||||
* Set the used tab list handler, should not be changed once players have
|
||||
* connected
|
||||
*
|
||||
* @param handler the tab list handler to set
|
||||
*/
|
||||
public abstract void setTabListHandler(TabListHandler handler);
|
||||
|
||||
/**
|
||||
* Get the currently in use reconnect handler.
|
||||
*
|
||||
@@ -247,4 +225,28 @@ public abstract class ProxyServer
|
||||
* @return the server's {@link AsyncHttpClient} instance
|
||||
*/
|
||||
public abstract AsyncHttpClient getHttpClient();
|
||||
|
||||
/**
|
||||
* Get the current number of connected users. The default implementation is
|
||||
* more efficient than {@link #getPlayers()} as it does not take a lock or
|
||||
* make a copy.
|
||||
*
|
||||
* @return the current number of connected players
|
||||
*/
|
||||
public abstract int getOnlineCount();
|
||||
|
||||
/**
|
||||
* Send the specified message to the console and all connected players.
|
||||
*
|
||||
* @param message the message to broadcast
|
||||
*/
|
||||
public abstract void broadcast(String message);
|
||||
|
||||
/**
|
||||
* Gets a new instance of this proxies custom tab list.
|
||||
*
|
||||
* @param player the player to generate this list in the context of
|
||||
* @return a new {@link CustomTabList} instance
|
||||
*/
|
||||
public abstract CustomTabList customTabList(ProxiedPlayer player);
|
||||
}
|
||||
|
@@ -12,7 +12,7 @@ public interface ReconnectHandler
|
||||
* @param player the connecting player
|
||||
* @return the server to connect to
|
||||
*/
|
||||
public ServerInfo getServer(ProxiedPlayer player);
|
||||
ServerInfo getServer(ProxiedPlayer player);
|
||||
|
||||
/**
|
||||
* Save the server of this player before they disconnect so it can be
|
||||
@@ -20,12 +20,20 @@ public interface ReconnectHandler
|
||||
*
|
||||
* @param player the player to save
|
||||
*/
|
||||
public void setServer(ProxiedPlayer player);
|
||||
void setServer(ProxiedPlayer player); // TOOD: String + String arguments?
|
||||
|
||||
/**
|
||||
* Save all pending reconnect locations. Whilst not used for database
|
||||
* connections, this method will be called at a predefined interval to allow
|
||||
* the saving of reconnect files.
|
||||
*/
|
||||
public void save();
|
||||
void save();
|
||||
|
||||
/**
|
||||
* Close all connections indicating that the proxy is about to shutdown and
|
||||
* all data should be saved. No new requests will be made after this method
|
||||
* has been called.
|
||||
*
|
||||
*/
|
||||
void close();
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package net.md_5.bungee.api.config;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Map;
|
||||
import lombok.Data;
|
||||
import net.md_5.bungee.api.tab.TabListHandler;
|
||||
|
||||
/**
|
||||
* Class representing the configuration of a server listener. Used for allowing
|
||||
@@ -52,4 +53,8 @@ public class ListenerInfo
|
||||
* null.
|
||||
*/
|
||||
private final TexturePackInfo texturePack;
|
||||
/**
|
||||
* Class used to build tab lists for this player.
|
||||
*/
|
||||
private final Class<? extends TabListHandler> tabList;
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package net.md_5.bungee.api.connection;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import net.md_5.bungee.protocol.packet.DefinedPacket;
|
||||
|
||||
/**
|
||||
* A proxy connection is defined as a connection directly connected to a socket.
|
||||
@@ -15,7 +16,7 @@ public interface Connection
|
||||
*
|
||||
* @return the remote address
|
||||
*/
|
||||
public InetSocketAddress getAddress();
|
||||
InetSocketAddress getAddress();
|
||||
|
||||
/**
|
||||
* Disconnects this end of the connection for the specified reason. If this
|
||||
@@ -25,5 +26,23 @@ public interface Connection
|
||||
* @param reason the reason shown to the player / sent to the server on
|
||||
* disconnect
|
||||
*/
|
||||
public void disconnect(String reason);
|
||||
void disconnect(String reason);
|
||||
|
||||
/**
|
||||
* Get the unsafe methods of this class.
|
||||
*
|
||||
* @return the unsafe method interface
|
||||
*/
|
||||
Unsafe unsafe();
|
||||
|
||||
interface Unsafe
|
||||
{
|
||||
|
||||
/**
|
||||
* Send a packet to this connection.
|
||||
*
|
||||
* @param packet the packet to send
|
||||
*/
|
||||
void sendPacket(DefinedPacket packet);
|
||||
}
|
||||
}
|
||||
|
@@ -2,6 +2,8 @@ package net.md_5.bungee.api.connection;
|
||||
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.config.TexturePackInfo;
|
||||
import net.md_5.bungee.api.tab.TabListHandler;
|
||||
|
||||
/**
|
||||
* Represents a player who's connection is being connected to somewhere else,
|
||||
@@ -15,7 +17,7 @@ public interface ProxiedPlayer extends Connection, CommandSender
|
||||
*
|
||||
* @return the players current display name
|
||||
*/
|
||||
public String getDisplayName();
|
||||
String getDisplayName();
|
||||
|
||||
/**
|
||||
* Sets this players display name to be used as their nametag and tab list
|
||||
@@ -23,7 +25,7 @@ public interface ProxiedPlayer extends Connection, CommandSender
|
||||
*
|
||||
* @param name the name to set
|
||||
*/
|
||||
public void setDisplayName(String name);
|
||||
void setDisplayName(String name);
|
||||
|
||||
/**
|
||||
* Connects / transfers this user to the specified connection, gracefully
|
||||
@@ -32,21 +34,21 @@ public interface ProxiedPlayer extends Connection, CommandSender
|
||||
*
|
||||
* @param target the new server to connect to
|
||||
*/
|
||||
public void connect(ServerInfo target);
|
||||
void connect(ServerInfo target);
|
||||
|
||||
/**
|
||||
* Gets the server this player is connected to.
|
||||
*
|
||||
* @return the server this player is connected to
|
||||
*/
|
||||
public Server getServer();
|
||||
Server getServer();
|
||||
|
||||
/**
|
||||
* Gets the ping time between the proxy and this connection.
|
||||
*
|
||||
* @return the current ping time
|
||||
*/
|
||||
public int getPing();
|
||||
int getPing();
|
||||
|
||||
/**
|
||||
* Send a plugin message to this player.
|
||||
@@ -54,19 +56,41 @@ public interface ProxiedPlayer extends Connection, CommandSender
|
||||
* @param channel the channel to send this data via
|
||||
* @param data the data to send
|
||||
*/
|
||||
public void sendData(String channel, byte[] data);
|
||||
void sendData(String channel, byte[] data);
|
||||
|
||||
/**
|
||||
* Get the pending connection that belongs to this player.
|
||||
*
|
||||
* @return the pending connection that this player used
|
||||
*/
|
||||
public PendingConnection getPendingConnection();
|
||||
PendingConnection getPendingConnection();
|
||||
|
||||
/**
|
||||
* Make this player chat (say something), to the server he is currently on.
|
||||
*
|
||||
* @param message the message to say
|
||||
*/
|
||||
public void chat(String message);
|
||||
void chat(String message);
|
||||
|
||||
/**
|
||||
* Send a request to change the players texture pack.
|
||||
*
|
||||
* @param pack the pack to request
|
||||
*/
|
||||
void setTexturePack(TexturePackInfo pack);
|
||||
|
||||
/**
|
||||
* Sets the new tab list for the user. At this stage it is not advisable to
|
||||
* change after the user has logged in!
|
||||
*
|
||||
* @param list the new list
|
||||
*/
|
||||
void setTabList(TabListHandler list);
|
||||
|
||||
/**
|
||||
* Get the current tab list.
|
||||
*
|
||||
* @return the tab list in use by this user
|
||||
*/
|
||||
TabListHandler getTabList();
|
||||
}
|
||||
|
@@ -67,7 +67,7 @@ public class AsyncEvent<T> extends Event
|
||||
{
|
||||
Preconditions.checkState( intents.contains( plugin ), "Plugin %s has not registered intent for event %s", plugin, this );
|
||||
intents.remove( plugin );
|
||||
if ( latch.decrementAndGet() == 0 )
|
||||
if ( latch.decrementAndGet() == 0 && fired.get() )
|
||||
{
|
||||
done.done( (T) this, null );
|
||||
}
|
||||
|
@@ -1,18 +1,17 @@
|
||||
package net.md_5.bungee.api.event;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.plugin.Cancellable;
|
||||
import net.md_5.bungee.api.plugin.Event;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@ToString(callSuper = false)
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class ServerConnectEvent extends Event
|
||||
public class ServerConnectEvent extends Event implements Cancellable
|
||||
{
|
||||
|
||||
/**
|
||||
@@ -23,4 +22,14 @@ public class ServerConnectEvent extends Event
|
||||
* Server the player will be connected to.
|
||||
*/
|
||||
private ServerInfo target;
|
||||
/**
|
||||
* Cancelled state.
|
||||
*/
|
||||
private boolean cancelled;
|
||||
|
||||
public ServerConnectEvent(ProxiedPlayer player, ServerInfo target)
|
||||
{
|
||||
this.player = player;
|
||||
this.target = target;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,22 @@
|
||||
package net.md_5.bungee.api.event;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.plugin.Event;
|
||||
|
||||
/**
|
||||
* Called when a player has changed servers.
|
||||
*/
|
||||
@Data
|
||||
@ToString(callSuper = false)
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class ServerSwitchEvent extends Event
|
||||
{
|
||||
|
||||
/**
|
||||
* Player whom the server is for.
|
||||
*/
|
||||
private final ProxiedPlayer player;
|
||||
}
|
@@ -2,6 +2,7 @@ package net.md_5.bungee.api.plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.util.logging.Logger;
|
||||
import lombok.Getter;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.config.ConfigurationAdapter;
|
||||
@@ -19,6 +20,8 @@ public class Plugin
|
||||
private ProxyServer proxy;
|
||||
@Getter
|
||||
private File file;
|
||||
@Getter
|
||||
private Logger logger;
|
||||
|
||||
/**
|
||||
* Called when the plugin has just been loaded. Most of the proxy will not
|
||||
@@ -73,10 +76,11 @@ public class Plugin
|
||||
* @param description the description that describes this plugin
|
||||
* @param jarfile this plugins jar or container
|
||||
*/
|
||||
final void init(ProxyServer proxy, PluginDescription description, File file)
|
||||
final void init(ProxyServer proxy, PluginDescription description)
|
||||
{
|
||||
this.proxy = proxy;
|
||||
this.description = description;
|
||||
this.file = file;
|
||||
this.file = description.getFile();
|
||||
this.logger = new PluginLogger( this );
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package net.md_5.bungee.api.plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import lombok.AllArgsConstructor;
|
||||
@@ -35,4 +36,8 @@ public class PluginDescription
|
||||
* Plugin hard dependencies.
|
||||
*/
|
||||
private Set<String> depends = new HashSet<>();
|
||||
/**
|
||||
* File we were loaded from.
|
||||
*/
|
||||
private File file = null;
|
||||
}
|
||||
|
@@ -0,0 +1,25 @@
|
||||
package net.md_5.bungee.api.plugin;
|
||||
|
||||
import java.util.logging.LogRecord;
|
||||
import java.util.logging.Logger;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
|
||||
public class PluginLogger extends Logger
|
||||
{
|
||||
|
||||
private String pluginName;
|
||||
|
||||
protected PluginLogger(Plugin plugin)
|
||||
{
|
||||
super( plugin.getClass().getCanonicalName(), null );
|
||||
pluginName = "[" + plugin.getDescription().getName() + "] ";
|
||||
setParent( ProxyServer.getInstance().getLogger() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(LogRecord logRecord)
|
||||
{
|
||||
logRecord.setMessage( pluginName + logRecord.getMessage() );
|
||||
super.log( logRecord );
|
||||
}
|
||||
}
|
@@ -1,15 +1,16 @@
|
||||
package net.md_5.bungee.api.plugin;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.eventbus.EventBus;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
import java.util.jar.JarEntry;
|
||||
@@ -20,7 +21,8 @@ import lombok.RequiredArgsConstructor;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.event.LoginEvent;
|
||||
import net.md_5.bungee.event.EventBus;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
|
||||
/**
|
||||
@@ -36,9 +38,17 @@ public class PluginManager
|
||||
private final ProxyServer proxy;
|
||||
/*========================================================================*/
|
||||
private final Yaml yaml = new Yaml();
|
||||
private final EventBus eventBus = new EventBus();
|
||||
private final Map<String, Plugin> plugins = new HashMap<>();
|
||||
private final EventBus eventBus;
|
||||
private final Map<String, Plugin> plugins = new LinkedHashMap<>();
|
||||
private final Map<String, Command> commandMap = new HashMap<>();
|
||||
private Map<String, PluginDescription> toLoad = new HashMap<>();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public PluginManager(ProxyServer proxy)
|
||||
{
|
||||
this.proxy = proxy;
|
||||
eventBus = new EventBus( proxy.getLogger(), Subscribe.class, EventHandler.class );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a command so that it may be executed.
|
||||
@@ -85,7 +95,7 @@ public class PluginManager
|
||||
String permission = command.getPermission();
|
||||
if ( permission != null && !permission.isEmpty() && !sender.hasPermission( permission ) )
|
||||
{
|
||||
sender.sendMessage( ChatColor.RED + "You do not have permission to execute this command!" );
|
||||
sender.sendMessage( proxy.getTranslation( "no_permission" ) );
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -122,23 +132,37 @@ public class PluginManager
|
||||
return plugins.get( name );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable all plugins by calling the {@link Plugin#onEnable()} method.
|
||||
*/
|
||||
public void enablePlugins()
|
||||
public void loadAndEnablePlugins()
|
||||
{
|
||||
Map<Plugin, Boolean> pluginStatuses = new HashMap<>();
|
||||
for ( Map.Entry<String, Plugin> entry : plugins.entrySet() )
|
||||
Map<PluginDescription, Boolean> pluginStatuses = new HashMap<>();
|
||||
for ( Map.Entry<String, PluginDescription> entry : toLoad.entrySet() )
|
||||
{
|
||||
Plugin plugin = entry.getValue();
|
||||
if ( !this.enablePlugin( pluginStatuses, new Stack<Plugin>(), plugin ) )
|
||||
PluginDescription plugin = entry.getValue();
|
||||
if ( !enablePlugin( pluginStatuses, new Stack<PluginDescription>(), plugin ) )
|
||||
{
|
||||
ProxyServer.getInstance().getLogger().warning( "Failed to enable " + entry.getKey() );
|
||||
}
|
||||
}
|
||||
toLoad.clear();
|
||||
toLoad = null;
|
||||
|
||||
for ( Plugin plugin : plugins.values() )
|
||||
{
|
||||
try
|
||||
{
|
||||
plugin.onEnable();
|
||||
ProxyServer.getInstance().getLogger().log( Level.INFO, "Enabled plugin {0} version {1} by {2}", new Object[]
|
||||
{
|
||||
plugin.getDescription().getName(), plugin.getDescription().getVersion(), plugin.getDescription().getAuthor()
|
||||
} );
|
||||
} catch ( Throwable t )
|
||||
{
|
||||
ProxyServer.getInstance().getLogger().log( Level.WARNING, "Exception encountered when loading plugin: " + plugin.getDescription().getName(), t );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean enablePlugin(Map<Plugin, Boolean> pluginStatuses, Stack<Plugin> dependStack, Plugin plugin)
|
||||
private boolean enablePlugin(Map<PluginDescription, Boolean> pluginStatuses, Stack<PluginDescription> dependStack, PluginDescription plugin)
|
||||
{
|
||||
if ( pluginStatuses.containsKey( plugin ) )
|
||||
{
|
||||
@@ -149,9 +173,9 @@ public class PluginManager
|
||||
boolean status = true;
|
||||
|
||||
// try to load dependencies first
|
||||
for ( String dependName : plugin.getDescription().getDepends() )
|
||||
for ( String dependName : plugin.getDepends() )
|
||||
{
|
||||
Plugin depend = this.plugins.get( dependName );
|
||||
PluginDescription depend = toLoad.get( dependName );
|
||||
Boolean dependStatus = depend != null ? pluginStatuses.get( depend ) : Boolean.FALSE;
|
||||
|
||||
if ( dependStatus == null )
|
||||
@@ -159,11 +183,11 @@ public class PluginManager
|
||||
if ( dependStack.contains( depend ) )
|
||||
{
|
||||
StringBuilder dependencyGraph = new StringBuilder();
|
||||
for ( Plugin element : dependStack )
|
||||
for ( PluginDescription element : dependStack )
|
||||
{
|
||||
dependencyGraph.append( element.getDescription().getName() ).append( " -> " );
|
||||
dependencyGraph.append( element.getName() ).append( " -> " );
|
||||
}
|
||||
dependencyGraph.append( plugin.getDescription().getName() ).append( " -> " ).append( dependName );
|
||||
dependencyGraph.append( plugin.getName() ).append( " -> " ).append( dependName );
|
||||
ProxyServer.getInstance().getLogger().log( Level.WARNING, "Circular dependency detected: " + dependencyGraph );
|
||||
status = false;
|
||||
} else
|
||||
@@ -178,7 +202,7 @@ public class PluginManager
|
||||
{
|
||||
ProxyServer.getInstance().getLogger().log( Level.WARNING, "{0} (required by {1}) is unavailable", new Object[]
|
||||
{
|
||||
depend.getDescription().getName(), plugin.getDescription().getName()
|
||||
depend.getName(), plugin.getName()
|
||||
} );
|
||||
status = false;
|
||||
}
|
||||
@@ -194,15 +218,23 @@ public class PluginManager
|
||||
{
|
||||
try
|
||||
{
|
||||
plugin.onEnable();
|
||||
ProxyServer.getInstance().getLogger().log( Level.INFO, "Enabled plugin {0} version {1} by {2}", new Object[]
|
||||
URLClassLoader loader = new PluginClassloader( new URL[]
|
||||
{
|
||||
plugin.getDescription().getName(), plugin.getDescription().getVersion(), plugin.getDescription().getAuthor()
|
||||
plugin.getFile().toURI().toURL()
|
||||
} );
|
||||
Class<?> main = loader.loadClass( plugin.getMain() );
|
||||
Plugin clazz = (Plugin) main.getDeclaredConstructor().newInstance();
|
||||
|
||||
clazz.init( proxy, plugin );
|
||||
plugins.put( plugin.getName(), clazz );
|
||||
clazz.onLoad();
|
||||
ProxyServer.getInstance().getLogger().log( Level.INFO, "Loaded plugin {0} version {1} by {2}", new Object[]
|
||||
{
|
||||
plugin.getName(), plugin.getVersion(), plugin.getAuthor()
|
||||
} );
|
||||
} catch ( Throwable t )
|
||||
{
|
||||
ProxyServer.getInstance().getLogger().log( Level.WARNING, "Exception encountered when loading plugin: " + plugin.getDescription().getName(), t );
|
||||
status = false;
|
||||
proxy.getLogger().log( Level.WARNING, "Error enabling plugin " + plugin.getName(), t );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,51 +242,12 @@ public class PluginManager
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a plugin from the specified file. This file must be in jar format.
|
||||
* This will not enable plugins, {@link #enablePlugins()} must be called.
|
||||
*
|
||||
* @param file the file to load from
|
||||
* @throws Exception Any exceptions encountered when loading a plugin from
|
||||
* this file.
|
||||
*/
|
||||
public void loadPlugin(File file) throws Exception
|
||||
{
|
||||
Preconditions.checkNotNull( file, "file" );
|
||||
Preconditions.checkArgument( file.isFile(), "Must load from file" );
|
||||
|
||||
try ( JarFile jar = new JarFile( file ) )
|
||||
{
|
||||
JarEntry pdf = jar.getJarEntry( "plugin.yml" );
|
||||
Preconditions.checkNotNull( pdf, "Plugin must have a plugin.yml" );
|
||||
|
||||
try ( InputStream in = jar.getInputStream( pdf ) )
|
||||
{
|
||||
PluginDescription desc = yaml.loadAs( in, PluginDescription.class );
|
||||
URLClassLoader loader = new PluginClassloader( new URL[]
|
||||
{
|
||||
file.toURI().toURL()
|
||||
} );
|
||||
Class<?> main = loader.loadClass( desc.getMain() );
|
||||
Plugin plugin = (Plugin) main.getDeclaredConstructor().newInstance();
|
||||
|
||||
plugin.init( proxy, desc, file );
|
||||
plugins.put( desc.getName(), plugin );
|
||||
plugin.onLoad();
|
||||
ProxyServer.getInstance().getLogger().log( Level.INFO, "Loaded plugin {0} version {1} by {2}", new Object[]
|
||||
{
|
||||
desc.getName(), desc.getVersion(), desc.getAuthor()
|
||||
} );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all plugins from the specified folder.
|
||||
*
|
||||
* @param folder the folder to search for plugins in
|
||||
*/
|
||||
public void loadPlugins(File folder)
|
||||
public void detectPlugins(File folder)
|
||||
{
|
||||
Preconditions.checkNotNull( folder, "folder" );
|
||||
Preconditions.checkArgument( folder.isDirectory(), "Must load from a directory" );
|
||||
@@ -263,9 +256,17 @@ public class PluginManager
|
||||
{
|
||||
if ( file.isFile() && file.getName().endsWith( ".jar" ) )
|
||||
{
|
||||
try
|
||||
try ( JarFile jar = new JarFile( file ) )
|
||||
{
|
||||
loadPlugin( file );
|
||||
JarEntry pdf = jar.getJarEntry( "plugin.yml" );
|
||||
Preconditions.checkNotNull( pdf, "Plugin must have a plugin.yml" );
|
||||
|
||||
try ( InputStream in = jar.getInputStream( pdf ) )
|
||||
{
|
||||
PluginDescription desc = yaml.loadAs( in, PluginDescription.class );
|
||||
desc.setFile( file );
|
||||
toLoad.put( desc.getName(), desc );
|
||||
}
|
||||
} catch ( Exception ex )
|
||||
{
|
||||
ProxyServer.getInstance().getLogger().log( Level.WARNING, "Could not load plugin from file " + file, ex );
|
||||
@@ -311,6 +312,16 @@ public class PluginManager
|
||||
*/
|
||||
public void registerListener(Plugin plugin, Listener listener)
|
||||
{
|
||||
for ( Method method : listener.getClass().getDeclaredMethods() )
|
||||
{
|
||||
if ( method.isAnnotationPresent( Subscribe.class ) )
|
||||
{
|
||||
proxy.getLogger().log( Level.WARNING, "Listener " + listener + " has registered using depreceated subscribe annotation!"
|
||||
+ " Please advice author to update to @EventHandler."
|
||||
+ " As a server owner you may safely ignore this.", new Exception() );
|
||||
}
|
||||
}
|
||||
|
||||
eventBus.register( listener );
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
package net.md_5.bungee.api.scoreboard;
|
||||
package net.md_5.bungee.api.score;
|
||||
|
||||
import lombok.Data;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
package net.md_5.bungee.api.scoreboard;
|
||||
package net.md_5.bungee.api.score;
|
||||
|
||||
/**
|
||||
* Represents locations for a scoreboard to be displayed.
|
@@ -1,4 +1,4 @@
|
||||
package net.md_5.bungee.api.scoreboard;
|
||||
package net.md_5.bungee.api.score;
|
||||
|
||||
import lombok.Data;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
package net.md_5.bungee.api.scoreboard;
|
||||
package net.md_5.bungee.api.score;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import java.util.Collection;
|
||||
@@ -59,7 +59,6 @@ public class Scoreboard
|
||||
public void addScore(Score score)
|
||||
{
|
||||
Preconditions.checkNotNull( score, "score" );
|
||||
Preconditions.checkArgument( !scores.containsKey( score.getItemName() ), "Score %s already exists in this scoreboard", score.getItemName() );
|
||||
scores.put( score.getItemName(), score );
|
||||
}
|
||||
|
@@ -1,20 +1,22 @@
|
||||
package net.md_5.bungee.api.scoreboard;
|
||||
package net.md_5.bungee.api.score;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import lombok.Data;
|
||||
import lombok.NonNull;
|
||||
|
||||
@Data
|
||||
public class Team
|
||||
{
|
||||
|
||||
@NonNull
|
||||
private final String name;
|
||||
private String displayName;
|
||||
private String prefix;
|
||||
private String suffix;
|
||||
private byte friendlyMode;
|
||||
private boolean friendlyFire;
|
||||
private Set<String> players = new HashSet<>();
|
||||
|
||||
public Collection<String> getPlayers()
|
60
api/src/main/java/net/md_5/bungee/api/tab/CustomTabList.java
Normal file
60
api/src/main/java/net/md_5/bungee/api/tab/CustomTabList.java
Normal file
@@ -0,0 +1,60 @@
|
||||
package net.md_5.bungee.api.tab;
|
||||
|
||||
/**
|
||||
* Represents a custom tab list, which may have slots manipulated.
|
||||
*/
|
||||
public interface CustomTabList extends TabListHandler
|
||||
{
|
||||
|
||||
/**
|
||||
* Blank out this tab list and update immediately.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* Gets the columns in this list.
|
||||
*
|
||||
* @return the width of this list
|
||||
*/
|
||||
int getColumns();
|
||||
|
||||
/**
|
||||
* Gets the rows in this list.
|
||||
*
|
||||
* @return the height of this list
|
||||
*/
|
||||
int getRows();
|
||||
|
||||
/**
|
||||
* Get the total size of this list.
|
||||
*
|
||||
* @return {@link #getRows()} * {@link #getColumns()}
|
||||
*/
|
||||
int getSize();
|
||||
|
||||
/**
|
||||
* Set the text in the specified slot and update immediately.
|
||||
*
|
||||
* @param row the row to set
|
||||
* @param column the column to set
|
||||
* @param text the text to set
|
||||
* @return the padded text
|
||||
*/
|
||||
String setSlot(int row, int column, String text);
|
||||
|
||||
/**
|
||||
* Set the text in the specified slot.
|
||||
*
|
||||
* @param row the row to set
|
||||
* @param column the column to set
|
||||
* @param text the text to set
|
||||
* @param update whether or not to invoke {@link #update()} upon completion
|
||||
* @return the padded text
|
||||
*/
|
||||
String setSlot(int row, int column, String text, boolean update);
|
||||
|
||||
/**
|
||||
* Flush all queued changes to the user.
|
||||
*/
|
||||
void update();
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
package net.md_5.bungee.api.tab;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
|
||||
@NoArgsConstructor
|
||||
public abstract class TabListAdapter implements TabListHandler
|
||||
{
|
||||
|
||||
@Getter
|
||||
private ProxiedPlayer player;
|
||||
|
||||
@Override
|
||||
public void init(ProxiedPlayer player)
|
||||
{
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnect()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisconnect()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServerChange()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPingChange(int ping)
|
||||
{
|
||||
}
|
||||
}
|
@@ -1,23 +1,30 @@
|
||||
package net.md_5.bungee.api;
|
||||
package net.md_5.bungee.api.tab;
|
||||
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
|
||||
public interface TabListHandler
|
||||
{
|
||||
|
||||
/**
|
||||
* Called so that this class may set member fields to keep track of its
|
||||
* internal state. You should not do any packet sending or manipulation of
|
||||
* the passed player, other than storing it.
|
||||
*
|
||||
* @param player the player to be associated with this list
|
||||
*/
|
||||
void init(ProxiedPlayer player);
|
||||
|
||||
/**
|
||||
* Called when this player first connects to the proxy.
|
||||
*/
|
||||
void onConnect();
|
||||
|
||||
/**
|
||||
* Called when a player first connects to the proxy.
|
||||
*
|
||||
* @param player the connecting player
|
||||
*/
|
||||
public void onConnect(ProxiedPlayer player);
|
||||
|
||||
/**
|
||||
* Called when a player changes their connected server.
|
||||
*
|
||||
* @param player the player who changed servers
|
||||
*/
|
||||
public void onServerChange(ProxiedPlayer player);
|
||||
void onServerChange();
|
||||
|
||||
/**
|
||||
* Called when a players ping changes. The new ping will have not updated in
|
||||
@@ -26,14 +33,14 @@ public interface TabListHandler
|
||||
* @param player the player who's ping changed
|
||||
* @param ping the player's new ping.
|
||||
*/
|
||||
public void onPingChange(ProxiedPlayer player, int ping);
|
||||
void onPingChange(int ping);
|
||||
|
||||
/**
|
||||
* Called when a player disconnects.
|
||||
*
|
||||
* @param player the disconnected player
|
||||
*/
|
||||
public void onDisconnect(ProxiedPlayer player);
|
||||
void onDisconnect();
|
||||
|
||||
/**
|
||||
* Called when a list update packet is sent from server to client.
|
||||
@@ -44,5 +51,5 @@ public interface TabListHandler
|
||||
* @param ping ping of the subject player
|
||||
* @return whether to send the packet to the client
|
||||
*/
|
||||
public boolean onListUpdate(ProxiedPlayer player, String name, boolean online, int ping);
|
||||
boolean onListUpdate(String name, boolean online, int ping);
|
||||
}
|
31
config/nb-configuration.xml
Normal file
31
config/nb-configuration.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project-shared-configuration>
|
||||
<!--
|
||||
This file contains additional configuration written by modules in the NetBeans IDE.
|
||||
The configuration is intended to be shared among all the users of project and
|
||||
therefore it is assumed to be part of version control checkout.
|
||||
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
|
||||
-->
|
||||
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
|
||||
<!--
|
||||
Properties that influence various parts of the IDE, especially code formatting and the like.
|
||||
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
|
||||
That way multiple projects can share the same settings (useful for formatting rules for example).
|
||||
Any value defined here will override the pom.xml file value but is only applicable to the current project.
|
||||
-->
|
||||
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>
|
||||
</properties>
|
||||
</project-shared-configuration>
|
31
event/nb-configuration.xml
Normal file
31
event/nb-configuration.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project-shared-configuration>
|
||||
<!--
|
||||
This file contains additional configuration written by modules in the NetBeans IDE.
|
||||
The configuration is intended to be shared among all the users of project and
|
||||
therefore it is assumed to be part of version control checkout.
|
||||
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
|
||||
-->
|
||||
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
|
||||
<!--
|
||||
Properties that influence various parts of the IDE, especially code formatting and the like.
|
||||
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
|
||||
That way multiple projects can share the same settings (useful for formatting rules for example).
|
||||
Any value defined here will override the pom.xml file value but is only applicable to the current project.
|
||||
-->
|
||||
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>
|
||||
</properties>
|
||||
</project-shared-configuration>
|
29
event/pom.xml
Normal file
29
event/pom.xml
Normal file
@@ -0,0 +1,29 @@
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-parent</artifactId>
|
||||
<version>1.5-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-event</artifactId>
|
||||
<version>1.5-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>BungeeCord-Event</name>
|
||||
<description>Generic java event dispatching API intended for use with BungeeCord</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.11</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
163
event/src/main/java/net/md_5/bungee/event/EventBus.java
Normal file
163
event/src/main/java/net/md_5/bungee/event/EventBus.java
Normal file
@@ -0,0 +1,163 @@
|
||||
package net.md_5.bungee.event;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class EventBus
|
||||
{
|
||||
|
||||
private final Map<Class<?>, Map<Object, Method[]>> eventToHandler = new HashMap<>();
|
||||
private final ReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
private final Logger logger;
|
||||
private final Class<? extends Annotation>[] annotations;
|
||||
|
||||
public EventBus()
|
||||
{
|
||||
this( null, (Class<? extends Annotation>[]) null );
|
||||
}
|
||||
|
||||
public EventBus(Logger logger)
|
||||
{
|
||||
this( logger, (Class<? extends Annotation>[]) null );
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public EventBus(Class<? extends Annotation>... annotations)
|
||||
{
|
||||
this( null, annotations );
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public EventBus(Logger logger, Class<? extends Annotation>... annotations)
|
||||
{
|
||||
this.logger = ( logger == null ) ? Logger.getGlobal() : logger;
|
||||
this.annotations = ( annotations == null || annotations.length == 0 ) ? new Class[]
|
||||
{
|
||||
EventHandler.class
|
||||
} : annotations;
|
||||
}
|
||||
|
||||
public void post(Object event)
|
||||
{
|
||||
lock.readLock().lock();
|
||||
try
|
||||
{
|
||||
Map<Object, Method[]> handlers = eventToHandler.get( event.getClass() );
|
||||
if ( handlers != null )
|
||||
{
|
||||
for ( Map.Entry<Object, Method[]> handler : handlers.entrySet() )
|
||||
{
|
||||
for ( Method method : handler.getValue() )
|
||||
{
|
||||
try
|
||||
{
|
||||
method.invoke( handler.getKey(), event );
|
||||
} catch ( IllegalAccessException ex )
|
||||
{
|
||||
throw new Error( "Method became inaccessible: " + event, ex );
|
||||
} catch ( IllegalArgumentException ex )
|
||||
{
|
||||
throw new Error( "Method rejected target/argument: " + event, ex );
|
||||
} catch ( InvocationTargetException ex )
|
||||
{
|
||||
logger.log( Level.WARNING, MessageFormat.format( "Error dispatching event {0} to listener {1}", event, handler.getKey() ), ex.getCause() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally
|
||||
{
|
||||
lock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private Map<Class<?>, Set<Method>> findHandlers(Object listener)
|
||||
{
|
||||
Map<Class<?>, Set<Method>> handler = new HashMap<>();
|
||||
for ( Method m : listener.getClass().getDeclaredMethods() )
|
||||
{
|
||||
for ( Class<? extends Annotation> annotation : annotations )
|
||||
{
|
||||
if ( m.isAnnotationPresent( annotation ) )
|
||||
{
|
||||
Class<?>[] params = m.getParameterTypes();
|
||||
if ( params.length != 1 )
|
||||
{
|
||||
logger.log( Level.INFO, "Method {0} in class {1} annotated with {2} does not have single argument", new Object[]
|
||||
{
|
||||
m, listener.getClass(), annotation
|
||||
} );
|
||||
continue;
|
||||
}
|
||||
|
||||
Set<Method> existing = handler.get( params[0] );
|
||||
if ( existing == null )
|
||||
{
|
||||
existing = new HashSet<>();
|
||||
handler.put( params[0], existing );
|
||||
}
|
||||
existing.add( m );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return handler;
|
||||
}
|
||||
|
||||
public void register(Object listener)
|
||||
{
|
||||
Map<Class<?>, Set<Method>> handler = findHandlers( listener );
|
||||
lock.writeLock().lock();
|
||||
try
|
||||
{
|
||||
for ( Map.Entry<Class<?>, Set<Method>> e : handler.entrySet() )
|
||||
{
|
||||
Map<Object, Method[]> a = eventToHandler.get( e.getKey() );
|
||||
if ( a == null )
|
||||
{
|
||||
a = new HashMap<>();
|
||||
eventToHandler.put( e.getKey(), a );
|
||||
}
|
||||
Method[] baked = new Method[ e.getValue().size() ];
|
||||
a.put( listener, e.getValue().toArray( baked ) );
|
||||
}
|
||||
} finally
|
||||
{
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void unregister(Object listener)
|
||||
{
|
||||
Map<Class<?>, Set<Method>> handler = findHandlers( listener );
|
||||
lock.writeLock().lock();
|
||||
try
|
||||
{
|
||||
for ( Map.Entry<Class<?>, Set<Method>> e : handler.entrySet() )
|
||||
{
|
||||
Map<Object, Method[]> a = eventToHandler.get( e.getKey() );
|
||||
if ( a != null )
|
||||
{
|
||||
a.remove( listener );
|
||||
if ( a.isEmpty() )
|
||||
{
|
||||
eventToHandler.remove( e.getKey() );
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally
|
||||
{
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
}
|
12
event/src/main/java/net/md_5/bungee/event/EventHandler.java
Normal file
12
event/src/main/java/net/md_5/bungee/event/EventHandler.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package net.md_5.bungee.event;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface EventHandler
|
||||
{
|
||||
}
|
42
event/src/test/java/net/md_5/bungee/event/EventBusTest.java
Normal file
42
event/src/test/java/net/md_5/bungee/event/EventBusTest.java
Normal file
@@ -0,0 +1,42 @@
|
||||
package net.md_5.bungee.event;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class EventBusTest
|
||||
{
|
||||
|
||||
private final EventBus bus = new EventBus();
|
||||
private final CountDownLatch latch = new CountDownLatch( 2 );
|
||||
|
||||
@Test
|
||||
public void testNestedEvents()
|
||||
{
|
||||
bus.register( this );
|
||||
bus.post( new FirstEvent() );
|
||||
Assert.assertEquals( latch.getCount(), 0 );
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void firstListener(FirstEvent event)
|
||||
{
|
||||
bus.post( new SecondEvent() );
|
||||
Assert.assertEquals( latch.getCount(), 1 );
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void secondListener(SecondEvent event)
|
||||
{
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
public static class FirstEvent
|
||||
{
|
||||
}
|
||||
|
||||
public static class SecondEvent
|
||||
{
|
||||
}
|
||||
}
|
31
nb-configuration.xml
Normal file
31
nb-configuration.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project-shared-configuration>
|
||||
<!--
|
||||
This file contains additional configuration written by modules in the NetBeans IDE.
|
||||
The configuration is intended to be shared among all the users of project and
|
||||
therefore it is assumed to be part of version control checkout.
|
||||
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
|
||||
-->
|
||||
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
|
||||
<!--
|
||||
Properties that influence various parts of the IDE, especially code formatting and the like.
|
||||
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
|
||||
That way multiple projects can share the same settings (useful for formatting rules for example).
|
||||
Any value defined here will override the pom.xml file value but is only applicable to the current project.
|
||||
-->
|
||||
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>
|
||||
</properties>
|
||||
</project-shared-configuration>
|
9
pom.xml
9
pom.xml
@@ -38,6 +38,7 @@
|
||||
|
||||
<modules>
|
||||
<module>api</module>
|
||||
<module>event</module>
|
||||
<module>protocol</module>
|
||||
<module>proxy</module>
|
||||
</modules>
|
||||
@@ -58,11 +59,17 @@
|
||||
|
||||
<properties>
|
||||
<build.number>unknown</build.number>
|
||||
<netty.version>4.0.0.CR1</netty.version>
|
||||
<netty.version>4.0.0.CR7</netty.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.11</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
|
31
protocol/nb-configuration.xml
Normal file
31
protocol/nb-configuration.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project-shared-configuration>
|
||||
<!--
|
||||
This file contains additional configuration written by modules in the NetBeans IDE.
|
||||
The configuration is intended to be shared among all the users of project and
|
||||
therefore it is assumed to be part of version control checkout.
|
||||
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
|
||||
-->
|
||||
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
|
||||
<!--
|
||||
Properties that influence various parts of the IDE, especially code formatting and the like.
|
||||
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
|
||||
That way multiple projects can share the same settings (useful for formatting rules for example).
|
||||
Any value defined here will override the pom.xml file value but is only applicable to the current project.
|
||||
-->
|
||||
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>
|
||||
</properties>
|
||||
</project-shared-configuration>
|
33
protocol/src/main/java/net/md_5/bungee/protocol/Forge.java
Normal file
33
protocol/src/main/java/net/md_5/bungee/protocol/Forge.java
Normal file
@@ -0,0 +1,33 @@
|
||||
package net.md_5.bungee.protocol;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.Getter;
|
||||
import net.md_5.bungee.protocol.packet.DefinedPacket;
|
||||
import net.md_5.bungee.protocol.packet.forge.Forge1Login;
|
||||
import net.md_5.bungee.protocol.skip.PacketReader;
|
||||
|
||||
public class Forge extends Vanilla
|
||||
{
|
||||
|
||||
@Getter
|
||||
private static final Forge instance = new Forge();
|
||||
|
||||
public Forge()
|
||||
{
|
||||
classes[0x01] = Forge1Login.class;
|
||||
skipper = new PacketReader( this ); // TODO: :(
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefinedPacket read(short packetId, ByteBuf buf)
|
||||
{
|
||||
int start = buf.readerIndex();
|
||||
DefinedPacket packet = read( packetId, buf, this );
|
||||
if ( buf.readerIndex() == start )
|
||||
{
|
||||
packet = super.read( packetId, buf );
|
||||
}
|
||||
|
||||
return packet;
|
||||
}
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
package net.md_5.bungee.protocol;
|
||||
|
||||
public enum OpCode
|
||||
{
|
||||
|
||||
BOOLEAN, BULK_CHUNK, BYTE, BYTE_INT, DOUBLE, FLOAT, INT, INT_3, INT_BYTE, ITEM, LONG, METADATA, OPTIONAL_MOTION, SHORT, SHORT_BYTE, SHORT_ITEM, STRING, USHORT_BYTE
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
package net.md_5.bungee.protocol;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.lang.reflect.Constructor;
|
||||
import net.md_5.bungee.protocol.packet.DefinedPacket;
|
||||
import net.md_5.bungee.protocol.skip.PacketReader;
|
||||
|
||||
public interface Protocol
|
||||
{
|
||||
|
||||
PacketReader getSkipper();
|
||||
|
||||
DefinedPacket read(short packetId, ByteBuf buf);
|
||||
|
||||
OpCode[][] getOpCodes();
|
||||
|
||||
Class<? extends DefinedPacket>[] getClasses();
|
||||
|
||||
Constructor<? extends DefinedPacket>[] getConstructors();
|
||||
}
|
@@ -1,38 +1,128 @@
|
||||
package net.md_5.bungee.protocol;
|
||||
|
||||
import static net.md_5.bungee.protocol.PacketDefinitions.OpCode.*;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import lombok.Getter;
|
||||
import static net.md_5.bungee.protocol.OpCode.*;
|
||||
import net.md_5.bungee.protocol.packet.DefinedPacket;
|
||||
import net.md_5.bungee.protocol.packet.Packet0KeepAlive;
|
||||
import net.md_5.bungee.protocol.packet.Packet1Login;
|
||||
import net.md_5.bungee.protocol.packet.Packet2Handshake;
|
||||
import net.md_5.bungee.protocol.packet.Packet3Chat;
|
||||
import net.md_5.bungee.protocol.packet.Packet9Respawn;
|
||||
import net.md_5.bungee.protocol.packet.PacketC9PlayerListItem;
|
||||
import net.md_5.bungee.protocol.packet.PacketCCSettings;
|
||||
import net.md_5.bungee.protocol.packet.PacketCDClientStatus;
|
||||
import net.md_5.bungee.protocol.packet.PacketCEScoreboardObjective;
|
||||
import net.md_5.bungee.protocol.packet.PacketCFScoreboardScore;
|
||||
import net.md_5.bungee.protocol.packet.PacketD0DisplayScoreboard;
|
||||
import net.md_5.bungee.protocol.packet.PacketD1Team;
|
||||
import net.md_5.bungee.protocol.packet.PacketFAPluginMessage;
|
||||
import net.md_5.bungee.protocol.packet.PacketFCEncryptionResponse;
|
||||
import net.md_5.bungee.protocol.packet.PacketFDEncryptionRequest;
|
||||
import net.md_5.bungee.protocol.packet.PacketFEPing;
|
||||
import net.md_5.bungee.protocol.packet.PacketFFKick;
|
||||
import net.md_5.bungee.protocol.skip.PacketReader;
|
||||
|
||||
public class PacketDefinitions
|
||||
public class Vanilla implements Protocol
|
||||
{
|
||||
|
||||
public static final OpCode[][] opCodes = new OpCode[ 512 ][];
|
||||
public static final int VANILLA_PROTOCOL = 0;
|
||||
public static final int FORGE_PROTOCOL = 256;
|
||||
public static final byte PROTOCOL_VERSION = 61;
|
||||
public static final String GAME_VERSION = "1.5.2";
|
||||
@Getter
|
||||
private static final Vanilla instance = new Vanilla();
|
||||
/*========================================================================*/
|
||||
@Getter
|
||||
private final OpCode[][] opCodes = new OpCode[ 256 ][];
|
||||
@SuppressWarnings("unchecked")
|
||||
@Getter
|
||||
protected Class<? extends DefinedPacket>[] classes = new Class[ 256 ];
|
||||
@SuppressWarnings("unchecked")
|
||||
@Getter
|
||||
private Constructor<? extends DefinedPacket>[] constructors = new Constructor[ 256 ];
|
||||
@Getter
|
||||
protected PacketReader skipper;
|
||||
/*========================================================================*/
|
||||
|
||||
public enum OpCode
|
||||
public Vanilla()
|
||||
{
|
||||
|
||||
BOOLEAN, BULK_CHUNK, BYTE, BYTE_INT, DOUBLE, FLOAT, INT, INT_3, INT_BYTE, ITEM, LONG, METADATA, OPTIONAL_MOTION, SCORE, SHORT, SHORT_BYTE, SHORT_ITEM, STRING, TEAM, USHORT_BYTE
|
||||
classes[0x00] = Packet0KeepAlive.class;
|
||||
classes[0x01] = Packet1Login.class;
|
||||
classes[0x02] = Packet2Handshake.class;
|
||||
classes[0x03] = Packet3Chat.class;
|
||||
classes[0x09] = Packet9Respawn.class;
|
||||
classes[0xC9] = PacketC9PlayerListItem.class;
|
||||
classes[0xCC] = PacketCCSettings.class;
|
||||
classes[0xCD] = PacketCDClientStatus.class;
|
||||
classes[0xCE] = PacketCEScoreboardObjective.class;
|
||||
classes[0xCF] = PacketCFScoreboardScore.class;
|
||||
classes[0xD0] = PacketD0DisplayScoreboard.class;
|
||||
classes[0xD1] = PacketD1Team.class;
|
||||
classes[0xFA] = PacketFAPluginMessage.class;
|
||||
classes[0xFC] = PacketFCEncryptionResponse.class;
|
||||
classes[0xFD] = PacketFDEncryptionRequest.class;
|
||||
classes[0xFE] = PacketFEPing.class;
|
||||
classes[0xFF] = PacketFFKick.class;
|
||||
skipper = new PacketReader( this );
|
||||
}
|
||||
|
||||
static
|
||||
@Override
|
||||
public DefinedPacket read(short packetId, ByteBuf buf)
|
||||
{
|
||||
opCodes[0x00] = new OpCode[]
|
||||
int start = buf.readerIndex();
|
||||
DefinedPacket packet = read( packetId, buf, this );
|
||||
if ( buf.readerIndex() == start )
|
||||
{
|
||||
INT
|
||||
};
|
||||
opCodes[0x01] = new OpCode[]
|
||||
throw new RuntimeException( "Unknown packet id " + packetId );
|
||||
}
|
||||
return packet;
|
||||
}
|
||||
|
||||
public static DefinedPacket read(short id, ByteBuf buf, Protocol protocol)
|
||||
{
|
||||
INT, STRING, BYTE, BYTE, BYTE, BYTE, BYTE
|
||||
};
|
||||
opCodes[0x02] = new OpCode[]
|
||||
DefinedPacket packet = packet( id, protocol );
|
||||
if ( packet != null )
|
||||
{
|
||||
BYTE, STRING, STRING, INT
|
||||
};
|
||||
opCodes[0x03] = new OpCode[]
|
||||
packet.read( buf );
|
||||
return packet;
|
||||
}
|
||||
protocol.getSkipper().tryRead( id, buf );
|
||||
return null;
|
||||
}
|
||||
|
||||
public static DefinedPacket packet(short id, Protocol protocol)
|
||||
{
|
||||
DefinedPacket ret = null;
|
||||
Class<? extends DefinedPacket> clazz = protocol.getClasses()[id];
|
||||
|
||||
if ( clazz != null )
|
||||
{
|
||||
try
|
||||
{
|
||||
Constructor<? extends DefinedPacket> constructor = protocol.getConstructors()[id];
|
||||
if ( constructor == null )
|
||||
{
|
||||
constructor = clazz.getDeclaredConstructor();
|
||||
constructor.setAccessible( true );
|
||||
protocol.getConstructors()[id] = constructor;
|
||||
}
|
||||
|
||||
if ( constructor != null )
|
||||
{
|
||||
ret = constructor.newInstance();
|
||||
}
|
||||
} catch ( NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex )
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
STRING
|
||||
};
|
||||
opCodes[0x04] = new OpCode[]
|
||||
{
|
||||
LONG, LONG
|
||||
@@ -53,10 +143,6 @@ public class PacketDefinitions
|
||||
{
|
||||
SHORT, SHORT, FLOAT
|
||||
};
|
||||
opCodes[0x09] = new OpCode[]
|
||||
{
|
||||
INT, BYTE, BYTE, SHORT, STRING
|
||||
};
|
||||
opCodes[0x0A] = new OpCode[]
|
||||
{
|
||||
BOOLEAN
|
||||
@@ -281,10 +367,6 @@ public class PacketDefinitions
|
||||
{
|
||||
INT, BYTE
|
||||
};
|
||||
opCodes[0xC9] = new OpCode[]
|
||||
{
|
||||
STRING, BOOLEAN, SHORT
|
||||
};
|
||||
opCodes[0xCA] = new OpCode[]
|
||||
{
|
||||
BYTE, BYTE, BYTE
|
||||
@@ -293,54 +375,5 @@ public class PacketDefinitions
|
||||
{
|
||||
STRING
|
||||
};
|
||||
opCodes[0xCC] = new OpCode[]
|
||||
{
|
||||
STRING, BYTE, BYTE, BYTE, BOOLEAN
|
||||
};
|
||||
opCodes[0xCD] = new OpCode[]
|
||||
{
|
||||
BYTE
|
||||
};
|
||||
opCodes[0xCE] = new OpCode[]
|
||||
{
|
||||
STRING, STRING, BYTE
|
||||
};
|
||||
opCodes[0xCF] = new OpCode[]
|
||||
{
|
||||
SCORE
|
||||
};
|
||||
opCodes[0xD0] = new OpCode[]
|
||||
{
|
||||
BYTE, STRING
|
||||
};
|
||||
opCodes[0xD1] = new OpCode[]
|
||||
{
|
||||
TEAM
|
||||
};
|
||||
opCodes[0xFA] = new OpCode[]
|
||||
{
|
||||
STRING, SHORT_BYTE
|
||||
};
|
||||
opCodes[0xFC] = new OpCode[]
|
||||
{
|
||||
SHORT_BYTE, SHORT_BYTE
|
||||
};
|
||||
opCodes[0xFD] = new OpCode[]
|
||||
{
|
||||
STRING, SHORT_BYTE, SHORT_BYTE
|
||||
};
|
||||
opCodes[0xFE] = new OpCode[]
|
||||
{
|
||||
BYTE
|
||||
};
|
||||
opCodes[0xFF] = new OpCode[]
|
||||
{
|
||||
STRING
|
||||
};
|
||||
/*========================== Minecraft Forge ===========================*/
|
||||
opCodes[0x01 + FORGE_PROTOCOL] = new OpCode[]
|
||||
{
|
||||
INT, STRING, BYTE, INT, BYTE, BYTE, BYTE
|
||||
};
|
||||
}
|
||||
}
|
@@ -1,19 +0,0 @@
|
||||
package net.md_5.bungee.protocol.netty;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.io.IOException;
|
||||
|
||||
public class Score extends Instruction
|
||||
{
|
||||
|
||||
@Override
|
||||
void read(ByteBuf in) throws IOException
|
||||
{
|
||||
STRING.read( in );
|
||||
if ( in.readByte() == 0 )
|
||||
{
|
||||
STRING.read( in );
|
||||
INT.read( in );
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,26 +0,0 @@
|
||||
package net.md_5.bungee.protocol.netty;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.io.IOException;
|
||||
|
||||
class Team extends Instruction
|
||||
{
|
||||
|
||||
@Override
|
||||
void read(ByteBuf in) throws IOException
|
||||
{
|
||||
STRING.read( in );
|
||||
byte mode = in.readByte();
|
||||
if ( mode == 0 || mode == 2 )
|
||||
{
|
||||
STRING.read( in );
|
||||
STRING.read( in );
|
||||
STRING.read( in );
|
||||
BYTE.read( in );
|
||||
}
|
||||
if ( mode == 0 || mode == 3 || mode == 4 )
|
||||
{
|
||||
STRING_ARRAY.read( in );
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,29 +1,8 @@
|
||||
package net.md_5.bungee.packet;
|
||||
package net.md_5.bungee.protocol.packet;
|
||||
|
||||
import net.md_5.bungee.netty.ChannelWrapper;
|
||||
|
||||
public abstract class PacketHandler
|
||||
public abstract class AbstractPacketHandler
|
||||
{
|
||||
|
||||
@Override
|
||||
public abstract String toString();
|
||||
|
||||
public void connected(ChannelWrapper channel) throws Exception
|
||||
{
|
||||
}
|
||||
|
||||
public void disconnected(ChannelWrapper channel) throws Exception
|
||||
{
|
||||
}
|
||||
|
||||
public void exception(Throwable t) throws Exception
|
||||
{
|
||||
}
|
||||
|
||||
public void handle(byte[] buf) throws Exception
|
||||
{
|
||||
}
|
||||
|
||||
public void handle(Packet0KeepAlive alive) throws Exception
|
||||
{
|
||||
}
|
@@ -0,0 +1,69 @@
|
||||
package net.md_5.bungee.protocol.packet;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public abstract class DefinedPacket
|
||||
{
|
||||
|
||||
private final int id;
|
||||
|
||||
public final int getId()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
public void writeString(String s, ByteBuf buf)
|
||||
{
|
||||
// TODO: Check len - use Guava?
|
||||
buf.writeShort( s.length() );
|
||||
for ( char c : s.toCharArray() )
|
||||
{
|
||||
buf.writeChar( c );
|
||||
}
|
||||
}
|
||||
|
||||
public String readString(ByteBuf buf)
|
||||
{
|
||||
// TODO: Check len - use Guava?
|
||||
short len = buf.readShort();
|
||||
char[] chars = new char[ len ];
|
||||
for ( int i = 0; i < len; i++ )
|
||||
{
|
||||
chars[i] = buf.readChar();
|
||||
}
|
||||
return new String( chars );
|
||||
}
|
||||
|
||||
public void writeArray(byte[] b, ByteBuf buf)
|
||||
{
|
||||
// TODO: Check len - use Guava?
|
||||
buf.writeShort( b.length );
|
||||
buf.writeBytes( b );
|
||||
}
|
||||
|
||||
public byte[] readArray(ByteBuf buf)
|
||||
{
|
||||
// TODO: Check len - use Guava?
|
||||
short len = buf.readShort();
|
||||
byte[] ret = new byte[ len ];
|
||||
buf.readBytes( ret );
|
||||
return ret;
|
||||
}
|
||||
|
||||
public abstract void read(ByteBuf buf);
|
||||
|
||||
public abstract void write(ByteBuf buf);
|
||||
|
||||
public abstract void handle(AbstractPacketHandler handler) throws Exception;
|
||||
|
||||
@Override
|
||||
public abstract boolean equals(Object obj);
|
||||
|
||||
@Override
|
||||
public abstract int hashCode();
|
||||
|
||||
@Override
|
||||
public abstract String toString();
|
||||
}
|
@@ -0,0 +1,38 @@
|
||||
package net.md_5.bungee.protocol.packet;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class Packet0KeepAlive extends DefinedPacket
|
||||
{
|
||||
|
||||
private int randomId;
|
||||
|
||||
private Packet0KeepAlive()
|
||||
{
|
||||
super( 0x00 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(ByteBuf buf)
|
||||
{
|
||||
randomId = buf.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf buf)
|
||||
{
|
||||
buf.writeInt( randomId );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(AbstractPacketHandler handler) throws Exception
|
||||
{
|
||||
handler.handle( this );
|
||||
}
|
||||
}
|
@@ -0,0 +1,73 @@
|
||||
package net.md_5.bungee.protocol.packet;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class Packet1Login extends DefinedPacket
|
||||
{
|
||||
|
||||
protected int entityId;
|
||||
protected String levelType;
|
||||
protected byte gameMode;
|
||||
protected int dimension;
|
||||
protected byte difficulty;
|
||||
protected byte unused;
|
||||
protected byte maxPlayers;
|
||||
|
||||
protected Packet1Login()
|
||||
{
|
||||
super( 0x01 );
|
||||
}
|
||||
|
||||
public Packet1Login(int entityId, String levelType, byte gameMode, byte dimension, byte difficulty, byte unused, byte maxPlayers)
|
||||
{
|
||||
this( entityId, levelType, gameMode, (int) dimension, difficulty, unused, maxPlayers );
|
||||
}
|
||||
|
||||
public Packet1Login(int entityId, String levelType, byte gameMode, int dimension, byte difficulty, byte unused, byte maxPlayers)
|
||||
{
|
||||
this();
|
||||
this.entityId = entityId;
|
||||
this.levelType = levelType;
|
||||
this.gameMode = gameMode;
|
||||
this.dimension = dimension;
|
||||
this.difficulty = difficulty;
|
||||
this.unused = unused;
|
||||
this.maxPlayers = maxPlayers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(ByteBuf buf)
|
||||
{
|
||||
entityId = buf.readInt();
|
||||
levelType = readString( buf );
|
||||
gameMode = buf.readByte();
|
||||
dimension = buf.readByte();
|
||||
difficulty = buf.readByte();
|
||||
unused = buf.readByte();
|
||||
maxPlayers = buf.readByte();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf buf)
|
||||
{
|
||||
buf.writeInt( entityId );
|
||||
writeString( levelType, buf );
|
||||
buf.writeByte( gameMode );
|
||||
buf.writeByte( dimension );
|
||||
buf.writeByte( difficulty );
|
||||
buf.writeByte( unused );
|
||||
buf.writeByte( maxPlayers );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(AbstractPacketHandler handler) throws Exception
|
||||
{
|
||||
handler.handle( this );
|
||||
}
|
||||
}
|
@@ -0,0 +1,47 @@
|
||||
package net.md_5.bungee.protocol.packet;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class Packet2Handshake extends DefinedPacket
|
||||
{
|
||||
|
||||
private byte procolVersion;
|
||||
private String username;
|
||||
private String host;
|
||||
private int port;
|
||||
|
||||
private Packet2Handshake()
|
||||
{
|
||||
super( 0x02 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(ByteBuf buf)
|
||||
{
|
||||
procolVersion = buf.readByte();
|
||||
username = readString( buf );
|
||||
host = readString( buf );
|
||||
port = buf.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf buf)
|
||||
{
|
||||
buf.writeByte( procolVersion );
|
||||
writeString( username, buf );
|
||||
writeString( host, buf );
|
||||
buf.writeInt( port );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(AbstractPacketHandler handler) throws Exception
|
||||
{
|
||||
handler.handle( this );
|
||||
}
|
||||
}
|
@@ -0,0 +1,44 @@
|
||||
package net.md_5.bungee.protocol.packet;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class Packet3Chat extends DefinedPacket
|
||||
{
|
||||
|
||||
private String message;
|
||||
|
||||
private Packet3Chat()
|
||||
{
|
||||
super( 0x03 );
|
||||
}
|
||||
|
||||
public Packet3Chat(String message)
|
||||
{
|
||||
this();
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(ByteBuf buf)
|
||||
{
|
||||
message = readString( buf );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf buf)
|
||||
{
|
||||
writeString( message, buf );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(AbstractPacketHandler handler) throws Exception
|
||||
{
|
||||
handler.handle( this );
|
||||
}
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
package net.md_5.bungee.protocol.packet;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
@ToString
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class Packet9Respawn extends DefinedPacket
|
||||
{
|
||||
|
||||
private int dimension;
|
||||
private byte difficulty;
|
||||
private byte gameMode;
|
||||
private short worldHeight;
|
||||
private String levelType;
|
||||
|
||||
private Packet9Respawn()
|
||||
{
|
||||
super( 0x09 );
|
||||
}
|
||||
|
||||
public Packet9Respawn(int dimension, byte difficulty, byte gameMode, short worldHeight, String levelType)
|
||||
{
|
||||
this();
|
||||
this.dimension = dimension;
|
||||
this.difficulty = difficulty;
|
||||
this.gameMode = gameMode;
|
||||
this.worldHeight = worldHeight;
|
||||
this.levelType = levelType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(ByteBuf buf)
|
||||
{
|
||||
dimension = buf.readInt();
|
||||
difficulty = buf.readByte();
|
||||
gameMode = buf.readByte();
|
||||
worldHeight = buf.readShort();
|
||||
levelType = readString( buf );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf buf)
|
||||
{
|
||||
buf.writeInt( dimension );
|
||||
buf.writeByte( difficulty );
|
||||
buf.writeByte( gameMode );
|
||||
buf.writeShort( worldHeight );
|
||||
writeString( levelType, buf );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(AbstractPacketHandler handler) throws Exception
|
||||
{
|
||||
handler.handle( this );
|
||||
}
|
||||
}
|
@@ -0,0 +1,52 @@
|
||||
package net.md_5.bungee.protocol.packet;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class PacketC9PlayerListItem extends DefinedPacket
|
||||
{
|
||||
|
||||
private String username;
|
||||
private boolean online;
|
||||
private short ping;
|
||||
|
||||
private PacketC9PlayerListItem()
|
||||
{
|
||||
super( 0xC9 );
|
||||
}
|
||||
|
||||
public PacketC9PlayerListItem(String username, boolean online, short ping)
|
||||
{
|
||||
super( 0xC9 );
|
||||
this.username = username;
|
||||
this.online = online;
|
||||
this.ping = ping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(ByteBuf buf)
|
||||
{
|
||||
username = readString( buf );
|
||||
online = buf.readBoolean();
|
||||
ping = buf.readShort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf buf)
|
||||
{
|
||||
writeString( username, buf );
|
||||
buf.writeBoolean( online );
|
||||
buf.writeShort(ping );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(AbstractPacketHandler handler) throws Exception
|
||||
{
|
||||
handler.handle( this );
|
||||
}
|
||||
}
|
@@ -0,0 +1,48 @@
|
||||
package net.md_5.bungee.protocol.packet;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
@ToString
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class PacketCCSettings extends DefinedPacket
|
||||
{
|
||||
|
||||
private String locale;
|
||||
private byte viewDistance;
|
||||
private byte chatFlags;
|
||||
private byte difficulty;
|
||||
private boolean showCape;
|
||||
|
||||
private PacketCCSettings()
|
||||
{
|
||||
super( 0xCC );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(ByteBuf buf)
|
||||
{
|
||||
locale = readString( buf );
|
||||
viewDistance = buf.readByte();
|
||||
chatFlags = buf.readByte();
|
||||
difficulty = buf.readByte();
|
||||
showCape = buf.readBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf buf)
|
||||
{
|
||||
writeString( locale, buf );
|
||||
buf.writeByte( viewDistance );
|
||||
buf.writeByte( chatFlags );
|
||||
buf.writeByte( difficulty );
|
||||
buf.writeBoolean( showCape );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(AbstractPacketHandler handler) throws Exception
|
||||
{
|
||||
handler.handle( this );
|
||||
}
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
package net.md_5.bungee.protocol.packet;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
@ToString
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class PacketCDClientStatus extends DefinedPacket
|
||||
{
|
||||
|
||||
private byte payload;
|
||||
|
||||
private PacketCDClientStatus()
|
||||
{
|
||||
super( 0xCD );
|
||||
}
|
||||
|
||||
public PacketCDClientStatus(byte payload)
|
||||
{
|
||||
this();
|
||||
this.payload = payload;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(ByteBuf buf)
|
||||
{
|
||||
payload = buf.readByte();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf buf)
|
||||
{
|
||||
buf.writeByte( payload );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(AbstractPacketHandler handler) throws Exception
|
||||
{
|
||||
handler.handle( this );
|
||||
}
|
||||
}
|
@@ -0,0 +1,55 @@
|
||||
package net.md_5.bungee.protocol.packet;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class PacketCEScoreboardObjective extends DefinedPacket
|
||||
{
|
||||
|
||||
private String name;
|
||||
private String text;
|
||||
/**
|
||||
* 0 to create, 1 to remove.
|
||||
*/
|
||||
private byte action;
|
||||
|
||||
private PacketCEScoreboardObjective()
|
||||
{
|
||||
super( 0xCE );
|
||||
}
|
||||
|
||||
public PacketCEScoreboardObjective(String name, String text, byte action)
|
||||
{
|
||||
this();
|
||||
this.name = name;
|
||||
this.text = text;
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(ByteBuf buf)
|
||||
{
|
||||
name = readString( buf );
|
||||
text = readString( buf );
|
||||
action = buf.readByte();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf buf)
|
||||
{
|
||||
writeString( name, buf );
|
||||
writeString( text, buf );
|
||||
buf.writeByte( action );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(AbstractPacketHandler handler) throws Exception
|
||||
{
|
||||
handler.handle( this );
|
||||
}
|
||||
}
|
@@ -0,0 +1,56 @@
|
||||
package net.md_5.bungee.protocol.packet;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class PacketCFScoreboardScore extends DefinedPacket
|
||||
{
|
||||
|
||||
private String itemName;
|
||||
/**
|
||||
* 0 = create / update, 1 = remove.
|
||||
*/
|
||||
private byte action;
|
||||
private String scoreName;
|
||||
private int value;
|
||||
|
||||
private PacketCFScoreboardScore()
|
||||
{
|
||||
super( 0xCF );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(ByteBuf buf)
|
||||
{
|
||||
itemName = readString( buf );
|
||||
action = buf.readByte();
|
||||
if ( action != 1 )
|
||||
{
|
||||
scoreName = readString( buf );
|
||||
value = buf.readInt();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf buf)
|
||||
{
|
||||
writeString( itemName, buf );
|
||||
buf.writeByte( action );
|
||||
if ( action != 1 )
|
||||
{
|
||||
writeString( scoreName, buf );
|
||||
buf.writeInt( value );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(AbstractPacketHandler handler) throws Exception
|
||||
{
|
||||
handler.handle( this );
|
||||
}
|
||||
}
|
@@ -0,0 +1,44 @@
|
||||
package net.md_5.bungee.protocol.packet;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class PacketD0DisplayScoreboard extends DefinedPacket
|
||||
{
|
||||
|
||||
/**
|
||||
* 0 = list, 1 = side, 2 = below.
|
||||
*/
|
||||
private byte position;
|
||||
private String name;
|
||||
|
||||
private PacketD0DisplayScoreboard()
|
||||
{
|
||||
super( 0xD0 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(ByteBuf buf)
|
||||
{
|
||||
position = buf.readByte();
|
||||
name = readString( buf );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf buf)
|
||||
{
|
||||
buf.writeByte( position );
|
||||
writeString( name, buf );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(AbstractPacketHandler handler) throws Exception
|
||||
{
|
||||
handler.handle( this );
|
||||
}
|
||||
}
|
@@ -0,0 +1,92 @@
|
||||
package net.md_5.bungee.protocol.packet;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class PacketD1Team extends DefinedPacket
|
||||
{
|
||||
|
||||
private String name;
|
||||
/**
|
||||
* 0 - create, 1 remove, 2 info update, 3 player add, 4 player remove.
|
||||
*/
|
||||
private byte mode;
|
||||
private String displayName;
|
||||
private String prefix;
|
||||
private String suffix;
|
||||
private boolean friendlyFire;
|
||||
private short playerCount;
|
||||
private String[] players;
|
||||
|
||||
private PacketD1Team()
|
||||
{
|
||||
super( 0xD1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Packet to destroy a team.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public PacketD1Team(String name)
|
||||
{
|
||||
this();
|
||||
this.name = name;
|
||||
this.mode = 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(ByteBuf buf)
|
||||
{
|
||||
name = readString( buf );
|
||||
mode = buf.readByte();
|
||||
if ( mode == 0 || mode == 2 )
|
||||
{
|
||||
displayName = readString( buf );
|
||||
prefix = readString( buf );
|
||||
suffix = readString( buf );
|
||||
friendlyFire = buf.readBoolean();
|
||||
}
|
||||
if ( mode == 0 || mode == 3 || mode == 4 )
|
||||
{
|
||||
players = new String[ buf.readShort() ];
|
||||
for ( int i = 0; i < getPlayers().length; i++ )
|
||||
{
|
||||
players[i] = readString( buf );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf buf)
|
||||
{
|
||||
writeString( name, buf );
|
||||
buf.writeByte( mode );
|
||||
if ( mode == 0 || mode == 2 )
|
||||
{
|
||||
writeString( displayName, buf );
|
||||
writeString( prefix, buf );
|
||||
writeString( suffix, buf );
|
||||
buf.writeBoolean( friendlyFire );
|
||||
}
|
||||
if ( mode == 0 || mode == 3 || mode == 4 )
|
||||
{
|
||||
buf.writeShort( players.length );
|
||||
for ( int i = 0; i < players.length; i++ )
|
||||
{
|
||||
writeString( players[i], buf );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(AbstractPacketHandler handler) throws Exception
|
||||
{
|
||||
handler.handle( this );
|
||||
}
|
||||
}
|
@@ -0,0 +1,48 @@
|
||||
package net.md_5.bungee.protocol.packet;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class PacketFAPluginMessage extends DefinedPacket
|
||||
{
|
||||
|
||||
private String tag;
|
||||
private byte[] data;
|
||||
|
||||
private PacketFAPluginMessage()
|
||||
{
|
||||
super( 0xFA );
|
||||
}
|
||||
|
||||
public PacketFAPluginMessage(String tag, byte[] data)
|
||||
{
|
||||
this();
|
||||
this.tag = tag;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(ByteBuf buf)
|
||||
{
|
||||
tag = readString( buf );
|
||||
data = readArray( buf );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf buf)
|
||||
{
|
||||
writeString( tag, buf );
|
||||
writeArray( data, buf );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(AbstractPacketHandler handler) throws Exception
|
||||
{
|
||||
handler.handle( this );
|
||||
}
|
||||
}
|
@@ -0,0 +1,48 @@
|
||||
package net.md_5.bungee.protocol.packet;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class PacketFCEncryptionResponse extends DefinedPacket
|
||||
{
|
||||
|
||||
private byte[] sharedSecret;
|
||||
private byte[] verifyToken;
|
||||
|
||||
private PacketFCEncryptionResponse()
|
||||
{
|
||||
super( 0xFC );
|
||||
}
|
||||
|
||||
public PacketFCEncryptionResponse(byte[] sharedSecret, byte[] verifyToken)
|
||||
{
|
||||
this();
|
||||
this.sharedSecret = sharedSecret;
|
||||
this.verifyToken = verifyToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(ByteBuf buf)
|
||||
{
|
||||
sharedSecret = readArray( buf );
|
||||
verifyToken = readArray( buf );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf buf)
|
||||
{
|
||||
writeArray( sharedSecret, buf );
|
||||
writeArray( verifyToken, buf );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(AbstractPacketHandler handler) throws Exception
|
||||
{
|
||||
handler.handle( this );
|
||||
}
|
||||
}
|
@@ -0,0 +1,52 @@
|
||||
package net.md_5.bungee.protocol.packet;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class PacketFDEncryptionRequest extends DefinedPacket
|
||||
{
|
||||
|
||||
private String serverId;
|
||||
private byte[] publicKey;
|
||||
private byte[] verifyToken;
|
||||
|
||||
private PacketFDEncryptionRequest()
|
||||
{
|
||||
super( 0xFD );
|
||||
}
|
||||
|
||||
public PacketFDEncryptionRequest(String serverId, byte[] publicKey, byte[] verifyToken)
|
||||
{
|
||||
this();
|
||||
this.serverId = serverId;
|
||||
this.publicKey = publicKey;
|
||||
this.verifyToken = verifyToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(ByteBuf buf)
|
||||
{
|
||||
serverId = readString( buf );
|
||||
publicKey = readArray( buf );
|
||||
verifyToken = readArray( buf );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf buf)
|
||||
{
|
||||
writeString( serverId, buf );
|
||||
writeArray( publicKey, buf );
|
||||
writeArray( verifyToken, buf );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(AbstractPacketHandler handler) throws Exception
|
||||
{
|
||||
handler.handle( this );
|
||||
}
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
package net.md_5.bungee.protocol.packet;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
@ToString
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class PacketFEPing extends DefinedPacket
|
||||
{
|
||||
|
||||
private byte version;
|
||||
|
||||
private PacketFEPing()
|
||||
{
|
||||
super( 0xFE );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(ByteBuf buf)
|
||||
{
|
||||
version = buf.readByte();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf buf)
|
||||
{
|
||||
buf.writeByte( version );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(AbstractPacketHandler handler) throws Exception
|
||||
{
|
||||
handler.handle( this );
|
||||
}
|
||||
}
|
@@ -0,0 +1,44 @@
|
||||
package net.md_5.bungee.protocol.packet;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class PacketFFKick extends DefinedPacket
|
||||
{
|
||||
|
||||
private String message;
|
||||
|
||||
private PacketFFKick()
|
||||
{
|
||||
super( 0xFF );
|
||||
}
|
||||
|
||||
public PacketFFKick(String message)
|
||||
{
|
||||
this();
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(ByteBuf buf)
|
||||
{
|
||||
message = readString( buf );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf buf)
|
||||
{
|
||||
writeString( message, buf );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(AbstractPacketHandler handler) throws Exception
|
||||
{
|
||||
handler.handle( this );
|
||||
}
|
||||
}
|
@@ -0,0 +1,52 @@
|
||||
package net.md_5.bungee.protocol.packet.forge;
|
||||
|
||||
import net.md_5.bungee.protocol.packet.*;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
@ToString
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class Forge1Login extends Packet1Login
|
||||
{
|
||||
|
||||
private Forge1Login()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public Forge1Login(int entityId, String levelType, byte gameMode, int dimension, byte difficulty, byte unused, byte maxPlayers)
|
||||
{
|
||||
super( entityId, levelType, gameMode, dimension, difficulty, unused, maxPlayers );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(ByteBuf buf)
|
||||
{
|
||||
entityId = buf.readInt();
|
||||
levelType = readString( buf );
|
||||
gameMode = buf.readByte();
|
||||
dimension = buf.readInt();
|
||||
difficulty = buf.readByte();
|
||||
unused = buf.readByte();
|
||||
maxPlayers = buf.readByte();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuf buf)
|
||||
{
|
||||
buf.writeInt( entityId );
|
||||
writeString( levelType, buf );
|
||||
buf.writeByte( gameMode );
|
||||
buf.writeInt( dimension );
|
||||
buf.writeByte( difficulty );
|
||||
buf.writeByte( unused );
|
||||
buf.writeByte( maxPlayers );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(AbstractPacketHandler handler) throws Exception
|
||||
{
|
||||
handler.handle( this );
|
||||
}
|
||||
}
|
@@ -1,13 +1,12 @@
|
||||
package net.md_5.bungee.protocol.netty;
|
||||
package net.md_5.bungee.protocol.skip;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.io.IOException;
|
||||
|
||||
public class BulkChunk extends Instruction
|
||||
{
|
||||
|
||||
@Override
|
||||
void read(ByteBuf in) throws IOException
|
||||
void read(ByteBuf in)
|
||||
{
|
||||
short count = in.readShort();
|
||||
int size = in.readInt();
|
@@ -1,7 +1,6 @@
|
||||
package net.md_5.bungee.protocol.netty;
|
||||
package net.md_5.bungee.protocol.skip;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.io.IOException;
|
||||
|
||||
class ByteHeader extends Instruction
|
||||
{
|
||||
@@ -14,7 +13,7 @@ class ByteHeader extends Instruction
|
||||
}
|
||||
|
||||
@Override
|
||||
void read(ByteBuf in) throws IOException
|
||||
void read(ByteBuf in)
|
||||
{
|
||||
byte size = in.readByte();
|
||||
for ( byte b = 0; b < size; b++ )
|
@@ -1,7 +1,6 @@
|
||||
package net.md_5.bungee.protocol.netty;
|
||||
package net.md_5.bungee.protocol.skip;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.io.IOException;
|
||||
|
||||
abstract class Instruction
|
||||
{
|
||||
@@ -19,17 +18,15 @@ abstract class Instruction
|
||||
static final Instruction LONG = new Jump( 8 );
|
||||
static final Instruction METADATA = new MetaData();
|
||||
static final Instruction OPTIONAL_MOTION = new OptionalMotion();
|
||||
static final Instruction SCORE = new Score();
|
||||
static final Instruction SHORT = new Jump( 2 );
|
||||
static final Instruction SHORT_BYTE = new ShortHeader( BYTE );
|
||||
static final Instruction SHORT_ITEM = new ShortHeader( ITEM );
|
||||
static final Instruction STRING = new ShortHeader( new Jump( 2 ) );
|
||||
static final Instruction TEAM = new Team();
|
||||
static final Instruction USHORT_BYTE = new UnsignedShortByte();
|
||||
// Illegal forward references below this line
|
||||
static final Instruction BYTE_INT = new ByteHeader( INT );
|
||||
// Custom instructions
|
||||
static final Instruction STRING_ARRAY = new ShortHeader( STRING );
|
||||
|
||||
abstract void read(ByteBuf in) throws IOException;
|
||||
abstract void read(ByteBuf in);
|
||||
}
|
@@ -1,7 +1,6 @@
|
||||
package net.md_5.bungee.protocol.netty;
|
||||
package net.md_5.bungee.protocol.skip;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.io.IOException;
|
||||
|
||||
class IntHeader extends Instruction
|
||||
{
|
||||
@@ -14,7 +13,7 @@ class IntHeader extends Instruction
|
||||
}
|
||||
|
||||
@Override
|
||||
void read(ByteBuf in) throws IOException
|
||||
void read(ByteBuf in)
|
||||
{
|
||||
int size = in.readInt();
|
||||
for ( int i = 0; i < size; i++ )
|
@@ -1,13 +1,12 @@
|
||||
package net.md_5.bungee.protocol.netty;
|
||||
package net.md_5.bungee.protocol.skip;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.io.IOException;
|
||||
|
||||
class Item extends Instruction
|
||||
{
|
||||
|
||||
@Override
|
||||
void read(ByteBuf in) throws IOException
|
||||
void read(ByteBuf in)
|
||||
{
|
||||
short type = in.readShort();
|
||||
if ( type >= 0 )
|
@@ -1,7 +1,6 @@
|
||||
package net.md_5.bungee.protocol.netty;
|
||||
package net.md_5.bungee.protocol.skip;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.io.IOException;
|
||||
|
||||
class Jump extends Instruction
|
||||
{
|
||||
@@ -18,7 +17,7 @@ class Jump extends Instruction
|
||||
}
|
||||
|
||||
@Override
|
||||
void read(ByteBuf in) throws IOException
|
||||
void read(ByteBuf in)
|
||||
{
|
||||
in.skipBytes( len );
|
||||
}
|
@@ -1,13 +1,12 @@
|
||||
package net.md_5.bungee.protocol.netty;
|
||||
package net.md_5.bungee.protocol.skip;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.io.IOException;
|
||||
|
||||
class MetaData extends Instruction
|
||||
{
|
||||
|
||||
@Override
|
||||
void read(ByteBuf in) throws IOException
|
||||
void read(ByteBuf in)
|
||||
{
|
||||
int x = in.readUnsignedByte();
|
||||
while ( x != 127 )
|
@@ -1,13 +1,12 @@
|
||||
package net.md_5.bungee.protocol.netty;
|
||||
package net.md_5.bungee.protocol.skip;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.io.IOException;
|
||||
|
||||
class OptionalMotion extends Instruction
|
||||
{
|
||||
|
||||
@Override
|
||||
void read(ByteBuf in) throws IOException
|
||||
void read(ByteBuf in)
|
||||
{
|
||||
int data = in.readInt();
|
||||
if ( data > 0 )
|
@@ -1,24 +1,24 @@
|
||||
package net.md_5.bungee.protocol.netty;
|
||||
package net.md_5.bungee.protocol.skip;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import net.md_5.bungee.protocol.PacketDefinitions;
|
||||
import net.md_5.bungee.protocol.PacketDefinitions.OpCode;
|
||||
import net.md_5.bungee.protocol.OpCode;
|
||||
import net.md_5.bungee.protocol.Protocol;
|
||||
|
||||
public class PacketReader
|
||||
{
|
||||
|
||||
private static final Instruction[][] instructions = new Instruction[ PacketDefinitions.opCodes.length ][];
|
||||
private final Instruction[][] instructions;
|
||||
|
||||
static
|
||||
public PacketReader(Protocol protocol)
|
||||
{
|
||||
instructions = new Instruction[ protocol.getOpCodes().length ][];
|
||||
for ( int i = 0; i < instructions.length; i++ )
|
||||
{
|
||||
List<Instruction> output = new ArrayList<>();
|
||||
|
||||
OpCode[] enums = PacketDefinitions.opCodes[i];
|
||||
OpCode[] enums = protocol.getOpCodes()[i];
|
||||
if ( enums != null )
|
||||
{
|
||||
for ( OpCode struct : enums )
|
||||
@@ -59,35 +59,16 @@ public class PacketReader
|
||||
}
|
||||
}
|
||||
|
||||
private static void readPacket(int packetId, ByteBuf in, int protocol) throws IOException
|
||||
public void tryRead(short packetId, ByteBuf in)
|
||||
{
|
||||
Instruction[] packetDef = null;
|
||||
if ( packetId + protocol < instructions.length )
|
||||
{
|
||||
packetDef = instructions[packetId + protocol];
|
||||
}
|
||||
Instruction[] packetDef = instructions[packetId];
|
||||
|
||||
if ( packetDef == null )
|
||||
if ( packetDef != null )
|
||||
{
|
||||
if ( protocol == PacketDefinitions.VANILLA_PROTOCOL )
|
||||
{
|
||||
throw new IOException( "Unknown packet id " + packetId );
|
||||
} else
|
||||
{
|
||||
readPacket( packetId, in, PacketDefinitions.VANILLA_PROTOCOL );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for ( Instruction instruction : packetDef )
|
||||
{
|
||||
instruction.read( in );
|
||||
}
|
||||
}
|
||||
|
||||
public static void readPacket(ByteBuf in, int protocol) throws IOException
|
||||
{
|
||||
int packetId = in.readUnsignedByte();
|
||||
readPacket( packetId, in, protocol );
|
||||
}
|
||||
}
|
@@ -1,7 +1,6 @@
|
||||
package net.md_5.bungee.protocol.netty;
|
||||
package net.md_5.bungee.protocol.skip;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.io.IOException;
|
||||
|
||||
class ShortHeader extends Instruction
|
||||
{
|
||||
@@ -14,7 +13,7 @@ class ShortHeader extends Instruction
|
||||
}
|
||||
|
||||
@Override
|
||||
void read(ByteBuf in) throws IOException
|
||||
void read(ByteBuf in)
|
||||
{
|
||||
short size = in.readShort();
|
||||
for ( short s = 0; s < size; s++ )
|
@@ -1,13 +1,12 @@
|
||||
package net.md_5.bungee.protocol.netty;
|
||||
package net.md_5.bungee.protocol.skip;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.io.IOException;
|
||||
|
||||
class UnsignedShortByte extends Instruction
|
||||
{
|
||||
|
||||
@Override
|
||||
void read(ByteBuf in) throws IOException
|
||||
void read(ByteBuf in)
|
||||
{
|
||||
int size = in.readUnsignedShort();
|
||||
in.skipBytes( size );
|
@@ -0,0 +1,45 @@
|
||||
package net.md_5.bungee.protocol;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import net.md_5.bungee.protocol.packet.AbstractPacketHandler;
|
||||
import net.md_5.bungee.protocol.packet.DefinedPacket;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class PacketTest
|
||||
{
|
||||
|
||||
@Test
|
||||
public void testPackets() throws Exception
|
||||
{
|
||||
AbstractPacketHandler handler = new AbstractPacketHandler()
|
||||
{
|
||||
};
|
||||
|
||||
for ( short i = 0; i < 256; i++ )
|
||||
{
|
||||
Class<? extends DefinedPacket> clazz = Vanilla.getInstance().getClasses()[ i];
|
||||
if ( clazz != null )
|
||||
{
|
||||
Assert.assertTrue( "Packet " + clazz + " is not public", Modifier.isPublic( clazz.getModifiers() ) );
|
||||
DefinedPacket packet = Vanilla.packet( i, Vanilla.getInstance() );
|
||||
Assert.assertTrue( "Could not create packet with id " + i + " and class " + clazz, packet != null );
|
||||
Assert.assertTrue( "Packet with id " + i + " does not have correct class (expected " + clazz + " but got " + packet.getClass(), packet.getClass() == clazz );
|
||||
Assert.assertTrue( "Packet " + clazz + " does not report correct id", packet.getId() == i );
|
||||
Assert.assertTrue( "Packet " + clazz + " does not have custom hash code", packet.hashCode() != System.identityHashCode( packet ) );
|
||||
Assert.assertTrue( "Packet " + clazz + " does not have custom toString", packet.toString().indexOf( '@' ) == -1 );
|
||||
// TODO: Enable this test again in v2
|
||||
// Assert.assertTrue( "Packet " + clazz + " does not have private no args constructor", Modifier.isPrivate( clazz.getDeclaredConstructor().getModifiers() ) );
|
||||
|
||||
for ( Field field : clazz.getDeclaredFields() )
|
||||
{
|
||||
// TODO: Enable this test again in v2
|
||||
// Assert.assertTrue( "Packet " + clazz + " has non private field " + field, Modifier.isPrivate( field.getModifiers() ) );
|
||||
}
|
||||
|
||||
packet.handle( handler ); // Make sure there are no exceptions
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
package net.md_5.bungee.protocol;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ProtocolTest
|
||||
{
|
||||
|
||||
@Test
|
||||
public void testProtocol()
|
||||
{
|
||||
Assert.assertFalse( "Protocols should have different login packet", Vanilla.getInstance().getClasses()[0x01] == Forge.getInstance().classes[0x01] );
|
||||
}
|
||||
}
|
31
proxy/nb-configuration.xml
Normal file
31
proxy/nb-configuration.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project-shared-configuration>
|
||||
<!--
|
||||
This file contains additional configuration written by modules in the NetBeans IDE.
|
||||
The configuration is intended to be shared among all the users of project and
|
||||
therefore it is assumed to be part of version control checkout.
|
||||
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
|
||||
-->
|
||||
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
|
||||
<!--
|
||||
Properties that influence various parts of the IDE, especially code formatting and the like.
|
||||
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
|
||||
That way multiple projects can share the same settings (useful for formatting rules for example).
|
||||
Any value defined here will override the pom.xml file value but is only applicable to the current project.
|
||||
-->
|
||||
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>
|
||||
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>
|
||||
</properties>
|
||||
</project-shared-configuration>
|
@@ -31,6 +31,12 @@
|
||||
<version>${netty.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jline</groupId>
|
||||
<artifactId>jline</artifactId>
|
||||
<version>2.11</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-protocol</artifactId>
|
||||
@@ -53,7 +59,19 @@
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>5.1.24</version>
|
||||
<scope>compile</scope>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.javassist</groupId>
|
||||
<artifactId>javassist</artifactId>
|
||||
<version>3.18.0-GA</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.xerial</groupId>
|
||||
<artifactId>sqlite-jdbc</artifactId>
|
||||
<version>3.7.2</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
@@ -1,5 +1,8 @@
|
||||
package net.md_5.bungee;
|
||||
|
||||
import com.google.common.io.ByteStreams;
|
||||
import net.md_5.bungee.log.BungeeLogger;
|
||||
import net.md_5.bungee.reconnect.SQLReconnectHandler;
|
||||
import net.md_5.bungee.scheduler.BungeeScheduler;
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import com.ning.http.client.AsyncHttpClient;
|
||||
@@ -15,43 +18,55 @@ import io.netty.channel.MultithreadEventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import net.md_5.bungee.config.Configuration;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import jline.UnsupportedTerminal;
|
||||
import jline.console.ConsoleReader;
|
||||
import jline.internal.Log;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.Synchronized;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.ReconnectHandler;
|
||||
import net.md_5.bungee.api.TabListHandler;
|
||||
import net.md_5.bungee.api.config.ConfigurationAdapter;
|
||||
import net.md_5.bungee.api.config.ListenerInfo;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.connection.Server;
|
||||
import net.md_5.bungee.api.plugin.Plugin;
|
||||
import net.md_5.bungee.api.plugin.PluginManager;
|
||||
import net.md_5.bungee.api.scheduler.TaskScheduler;
|
||||
import net.md_5.bungee.api.tab.CustomTabList;
|
||||
import net.md_5.bungee.command.*;
|
||||
import net.md_5.bungee.config.YamlConfig;
|
||||
import net.md_5.bungee.log.LoggingOutputStream;
|
||||
import net.md_5.bungee.netty.PipelineUtils;
|
||||
import net.md_5.bungee.packet.DefinedPacket;
|
||||
import net.md_5.bungee.packet.PacketFAPluginMessage;
|
||||
import net.md_5.bungee.protocol.packet.DefinedPacket;
|
||||
import net.md_5.bungee.protocol.packet.Packet3Chat;
|
||||
import net.md_5.bungee.protocol.packet.PacketFAPluginMessage;
|
||||
import net.md_5.bungee.protocol.Vanilla;
|
||||
import net.md_5.bungee.scheduler.BungeeThreadPool;
|
||||
import net.md_5.bungee.tab.Custom;
|
||||
import net.md_5.bungee.util.CaseInsensitiveMap;
|
||||
import org.fusesource.jansi.AnsiConsole;
|
||||
|
||||
/**
|
||||
* Main BungeeCord proxy class.
|
||||
@@ -59,14 +74,6 @@ import net.md_5.bungee.scheduler.BungeeThreadPool;
|
||||
public class BungeeCord extends ProxyServer
|
||||
{
|
||||
|
||||
/**
|
||||
* Server protocol version.
|
||||
*/
|
||||
public static final byte PROTOCOL_VERSION = 60;
|
||||
/**
|
||||
* Server game version.
|
||||
*/
|
||||
public static final String GAME_VERSION = "1.5";
|
||||
/**
|
||||
* Current operation state.
|
||||
*/
|
||||
@@ -75,15 +82,20 @@ public class BungeeCord extends ProxyServer
|
||||
* Configuration.
|
||||
*/
|
||||
public final Configuration config = new Configuration();
|
||||
/**
|
||||
* Localization bundle.
|
||||
*/
|
||||
public final ResourceBundle bundle = ResourceBundle.getBundle( "messages_en" );
|
||||
/**
|
||||
* Thread pools.
|
||||
*/
|
||||
public final ScheduledThreadPoolExecutor executors = new BungeeThreadPool( new ThreadFactoryBuilder().setNameFormat( "Bungee Pool Thread #%1$d" ).build() );
|
||||
public final MultithreadEventLoopGroup eventLoops = new NioEventLoopGroup( 0, new ThreadFactoryBuilder().setNameFormat( "Netty IO Thread #%1$d" ).build() );
|
||||
public final MultithreadEventLoopGroup eventLoops = new NioEventLoopGroup( Runtime.getRuntime().availableProcessors(), new ThreadFactoryBuilder().setNameFormat( "Netty IO Thread #%1$d" ).build() );
|
||||
/**
|
||||
* locations.yml save thread.
|
||||
*/
|
||||
private final Timer saveThread = new Timer( "Reconnect Saver" );
|
||||
private final Timer metricsThread = new Timer( "Metrics Thread" );
|
||||
/**
|
||||
* Server socket listener.
|
||||
*/
|
||||
@@ -91,13 +103,8 @@ public class BungeeCord extends ProxyServer
|
||||
/**
|
||||
* Fully qualified connections.
|
||||
*/
|
||||
public Map<String, UserConnection> connections = new ConcurrentHashMap<>();
|
||||
/**
|
||||
* Tab list handler
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public TabListHandler tabListHandler;
|
||||
private final Map<String, UserConnection> connections = new CaseInsensitiveMap<>();
|
||||
private final ReadWriteLock connectionLock = new ReentrantReadWriteLock();
|
||||
/**
|
||||
* Plugin manager.
|
||||
*/
|
||||
@@ -119,6 +126,10 @@ public class BungeeCord extends ProxyServer
|
||||
new NettyAsyncHttpProvider(
|
||||
new AsyncHttpClientConfig.Builder().setAsyncHttpClientProviderConfig(
|
||||
new NettyAsyncHttpProviderConfig().addProperty( NettyAsyncHttpProviderConfig.BOSS_EXECUTOR_SERVICE, executors ) ).setExecutorService( executors ).build() ) );
|
||||
@Getter
|
||||
private ConsoleReader consoleReader;
|
||||
@Getter
|
||||
private final Logger logger;
|
||||
|
||||
|
||||
{
|
||||
@@ -132,6 +143,7 @@ public class BungeeCord extends ProxyServer
|
||||
getPluginManager().registerCommand( null, new CommandBungee() );
|
||||
getPluginManager().registerCommand( null, new CommandPerms() );
|
||||
getPluginManager().registerCommand( null, new CommandSend() );
|
||||
getPluginManager().registerCommand( null, new CommandFind() );
|
||||
|
||||
registerChannel( "BungeeCord" );
|
||||
}
|
||||
@@ -141,6 +153,23 @@ public class BungeeCord extends ProxyServer
|
||||
return (BungeeCord) ProxyServer.getInstance();
|
||||
}
|
||||
|
||||
public BungeeCord() throws IOException
|
||||
{
|
||||
Log.setOutput( new PrintStream( ByteStreams.nullOutputStream() ) ); // TODO: Bug JLine
|
||||
AnsiConsole.systemInstall();
|
||||
consoleReader = new ConsoleReader();
|
||||
|
||||
logger = new BungeeLogger( this );
|
||||
System.setErr( new PrintStream( new LoggingOutputStream( logger, Level.SEVERE ), true ) );
|
||||
System.setOut( new PrintStream( new LoggingOutputStream( logger, Level.INFO ), true ) );
|
||||
|
||||
if ( consoleReader.getTerminal() instanceof UnsupportedTerminal )
|
||||
{
|
||||
logger.info( "Unable to initialize fancy terminal. To fix this on Windows, install the correct Microsoft Visual C++ 2008 Runtime" );
|
||||
logger.info( "NOTE: This error is non crucial, and BungeeCord will still function correctly! Do not bug the author about it unless you are still unable to get it working" );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a new instance of BungeeCord.
|
||||
*
|
||||
@@ -150,7 +179,7 @@ public class BungeeCord extends ProxyServer
|
||||
public static void main(String[] args) throws Exception
|
||||
{
|
||||
Calendar deadline = Calendar.getInstance();
|
||||
deadline.set( 2013, 5, 26 ); // year, month, date
|
||||
deadline.set( 2013, 7, 1 ); // year, month, date
|
||||
if ( Calendar.getInstance().after( deadline ) )
|
||||
{
|
||||
System.err.println( "*** Warning, this build is outdated ***" );
|
||||
@@ -165,16 +194,14 @@ public class BungeeCord extends ProxyServer
|
||||
bungee.getLogger().info( "Enabled BungeeCord version " + bungee.getVersion() );
|
||||
bungee.start();
|
||||
|
||||
BufferedReader br = new BufferedReader( new InputStreamReader( System.in ) );
|
||||
while ( bungee.isRunning )
|
||||
{
|
||||
String line = br.readLine();
|
||||
String line = bungee.getConsoleReader().readLine( ">" );
|
||||
if ( line != null )
|
||||
{
|
||||
boolean handled = getInstance().getPluginManager().dispatchCommand( ConsoleCommandSender.getInstance(), line );
|
||||
if ( !handled )
|
||||
if ( !bungee.getPluginManager().dispatchCommand( ConsoleCommandSender.getInstance(), line ) )
|
||||
{
|
||||
System.err.println( "Command not found" );
|
||||
bungee.getConsole().sendMessage( ChatColor.RED + "Command not found" );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -190,15 +217,15 @@ public class BungeeCord extends ProxyServer
|
||||
public void start() throws Exception
|
||||
{
|
||||
pluginsFolder.mkdir();
|
||||
pluginManager.loadPlugins( pluginsFolder );
|
||||
pluginManager.detectPlugins( pluginsFolder );
|
||||
config.load();
|
||||
if ( reconnectHandler == null )
|
||||
{
|
||||
reconnectHandler = new YamlReconnectHandler();
|
||||
reconnectHandler = new SQLReconnectHandler();
|
||||
}
|
||||
isRunning = true;
|
||||
|
||||
pluginManager.enablePlugins();
|
||||
pluginManager.loadAndEnablePlugins();
|
||||
|
||||
startListeners();
|
||||
|
||||
@@ -210,21 +237,14 @@ public class BungeeCord extends ProxyServer
|
||||
getReconnectHandler().save();
|
||||
}
|
||||
}, 0, TimeUnit.MINUTES.toMillis( 5 ) );
|
||||
|
||||
new Metrics().start();
|
||||
metricsThread.scheduleAtFixedRate( new Metrics(), 0, TimeUnit.MINUTES.toMillis( Metrics.PING_INTERVAL ) );
|
||||
}
|
||||
|
||||
public void startListeners()
|
||||
{
|
||||
for ( final ListenerInfo info : config.getListeners() )
|
||||
{
|
||||
new ServerBootstrap()
|
||||
.channel( NioServerSocketChannel.class )
|
||||
.childAttr( PipelineUtils.LISTENER, info )
|
||||
.childHandler( PipelineUtils.SERVER_CHILD )
|
||||
.group( eventLoops )
|
||||
.localAddress( info.getHost() )
|
||||
.bind().addListener( new ChannelFutureListener()
|
||||
ChannelFutureListener listener = new ChannelFutureListener()
|
||||
{
|
||||
@Override
|
||||
public void operationComplete(ChannelFuture future) throws Exception
|
||||
@@ -238,7 +258,14 @@ public class BungeeCord extends ProxyServer
|
||||
getLogger().log( Level.WARNING, "Could not bind to host " + info.getHost(), future.cause() );
|
||||
}
|
||||
}
|
||||
} );
|
||||
};
|
||||
new ServerBootstrap()
|
||||
.channel( NioServerSocketChannel.class )
|
||||
.childAttr( PipelineUtils.LISTENER, info )
|
||||
.childHandler( PipelineUtils.SERVER_CHILD )
|
||||
.group( eventLoops )
|
||||
.localAddress( info.getHost() )
|
||||
.bind().addListener( listener );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,7 +288,12 @@ public class BungeeCord extends ProxyServer
|
||||
@Override
|
||||
public void stop()
|
||||
{
|
||||
this.isRunning = false;
|
||||
new Thread( "Shutdown Thread" )
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
BungeeCord.this.isRunning = false;
|
||||
|
||||
httpClient.close();
|
||||
executors.shutdown();
|
||||
@@ -269,18 +301,33 @@ public class BungeeCord extends ProxyServer
|
||||
stopListeners();
|
||||
getLogger().info( "Closing pending connections" );
|
||||
|
||||
connectionLock.readLock().lock();
|
||||
try
|
||||
{
|
||||
getLogger().info( "Disconnecting " + connections.size() + " connections" );
|
||||
for ( UserConnection user : connections.values() )
|
||||
{
|
||||
user.disconnect( "Proxy restarting, brb." );
|
||||
user.disconnect( getTranslation( "restart" ) );
|
||||
}
|
||||
} finally
|
||||
{
|
||||
connectionLock.readLock().unlock();
|
||||
}
|
||||
|
||||
getLogger().info( "Closing IO threads" );
|
||||
eventLoops.shutdown();
|
||||
eventLoops.shutdownGracefully();
|
||||
try
|
||||
{
|
||||
eventLoops.awaitTermination( Long.MAX_VALUE, TimeUnit.NANOSECONDS );
|
||||
} catch ( InterruptedException ex )
|
||||
{
|
||||
}
|
||||
|
||||
getLogger().info( "Saving reconnect locations" );
|
||||
reconnectHandler.save();
|
||||
reconnectHandler.close();
|
||||
saveThread.cancel();
|
||||
metricsThread.cancel();
|
||||
|
||||
// TODO: Fix this shit
|
||||
getLogger().info( "Disabling plugins" );
|
||||
@@ -293,6 +340,8 @@ public class BungeeCord extends ProxyServer
|
||||
getLogger().info( "Thankyou and goodbye" );
|
||||
System.exit( 0 );
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts a packet to all clients that is connected to this instance.
|
||||
@@ -300,10 +349,17 @@ public class BungeeCord extends ProxyServer
|
||||
* @param packet the packet to send
|
||||
*/
|
||||
public void broadcast(DefinedPacket packet)
|
||||
{
|
||||
connectionLock.readLock().lock();
|
||||
try
|
||||
{
|
||||
for ( UserConnection con : connections.values() )
|
||||
{
|
||||
con.sendPacket( packet );
|
||||
con.unsafe().sendPacket( packet );
|
||||
}
|
||||
} finally
|
||||
{
|
||||
connectionLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,29 +376,49 @@ public class BungeeCord extends ProxyServer
|
||||
}
|
||||
|
||||
@Override
|
||||
public Logger getLogger()
|
||||
public String getTranslation(String name)
|
||||
{
|
||||
return BungeeLogger.instance;
|
||||
String translation = "<translation '" + name + "' missing>";
|
||||
try
|
||||
{
|
||||
translation = bundle.getString( name );
|
||||
} catch ( MissingResourceException ex )
|
||||
{
|
||||
}
|
||||
return translation;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked") // TODO: Abstract more
|
||||
@SuppressWarnings("unchecked")
|
||||
public Collection<ProxiedPlayer> getPlayers()
|
||||
{
|
||||
return (Collection) connections.values();
|
||||
connectionLock.readLock().lock();
|
||||
try
|
||||
{
|
||||
return (Collection) new HashSet<>( connections.values() );
|
||||
} finally
|
||||
{
|
||||
connectionLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOnlineCount()
|
||||
{
|
||||
return connections.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProxiedPlayer getPlayer(String name)
|
||||
{
|
||||
return connections.get( name );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Server getServer(String name)
|
||||
connectionLock.readLock().lock();
|
||||
try
|
||||
{
|
||||
Collection<ProxiedPlayer> users = getServers().get( name ).getPlayers();
|
||||
return ( users != null && !users.isEmpty() ) ? users.iterator().next().getServer() : null;
|
||||
return connections.get( name );
|
||||
} finally
|
||||
{
|
||||
connectionLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -380,26 +456,19 @@ public class BungeeCord extends ProxyServer
|
||||
|
||||
public PacketFAPluginMessage registerChannels()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for ( String s : getChannels() )
|
||||
{
|
||||
sb.append( s );
|
||||
sb.append( '\00' );
|
||||
}
|
||||
byte[] payload = sb.substring( 0, sb.length() - 1 ).getBytes();
|
||||
return new PacketFAPluginMessage( "REGISTER", payload );
|
||||
return new PacketFAPluginMessage( "REGISTER", Util.format( pluginChannels, "\00" ).getBytes() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getProtocolVersion()
|
||||
{
|
||||
return PROTOCOL_VERSION;
|
||||
return Vanilla.PROTOCOL_VERSION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGameVersion()
|
||||
{
|
||||
return GAME_VERSION;
|
||||
return Vanilla.GAME_VERSION;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -413,4 +482,41 @@ public class BungeeCord extends ProxyServer
|
||||
{
|
||||
return ConsoleCommandSender.getInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void broadcast(String message)
|
||||
{
|
||||
getConsole().sendMessage( message );
|
||||
broadcast( new Packet3Chat( message ) );
|
||||
}
|
||||
|
||||
public void addConnection(UserConnection con)
|
||||
{
|
||||
connectionLock.writeLock().lock();
|
||||
try
|
||||
{
|
||||
connections.put( con.getName(), con );
|
||||
} finally
|
||||
{
|
||||
connectionLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void removeConnection(UserConnection con)
|
||||
{
|
||||
connectionLock.writeLock().lock();
|
||||
try
|
||||
{
|
||||
connections.remove( con.getName() );
|
||||
} finally
|
||||
{
|
||||
connectionLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CustomTabList customTabList(ProxiedPlayer player)
|
||||
{
|
||||
return new Custom( player );
|
||||
}
|
||||
}
|
||||
|
@@ -1,99 +0,0 @@
|
||||
package net.md_5.bungee;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.logging.FileHandler;
|
||||
import java.util.logging.Formatter;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.LogRecord;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Logger to handle formatting and storage of the proxy's logger.
|
||||
*/
|
||||
public class BungeeLogger extends Logger
|
||||
{
|
||||
|
||||
private static final Formatter formatter = new ConsoleLogFormatter();
|
||||
static final BungeeLogger instance = new BungeeLogger();
|
||||
|
||||
public BungeeLogger()
|
||||
{
|
||||
super( "BungeeCord", null );
|
||||
try
|
||||
{
|
||||
FileHandler handler = new FileHandler( "proxy.log", 1 << 24, 8, true );
|
||||
handler.setFormatter( formatter );
|
||||
addHandler( handler );
|
||||
} catch ( IOException ex )
|
||||
{
|
||||
System.err.println( "Could not register logger!" );
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(LogRecord record)
|
||||
{
|
||||
super.log( record );
|
||||
String message = formatter.format( record );
|
||||
if ( record.getLevel() == Level.SEVERE || record.getLevel() == Level.WARNING )
|
||||
{
|
||||
System.err.print( message );
|
||||
} else
|
||||
{
|
||||
System.out.print( message );
|
||||
}
|
||||
}
|
||||
|
||||
public static class ConsoleLogFormatter extends Formatter
|
||||
{
|
||||
|
||||
private SimpleDateFormat formatter = new SimpleDateFormat( "HH:mm:ss" );
|
||||
|
||||
@Override
|
||||
public String format(LogRecord logrecord)
|
||||
{
|
||||
StringBuilder formatted = new StringBuilder();
|
||||
|
||||
formatted.append( formatter.format( logrecord.getMillis() ) );
|
||||
Level level = logrecord.getLevel();
|
||||
|
||||
if ( level == Level.FINEST )
|
||||
{
|
||||
formatted.append( " [FINEST] " );
|
||||
} else if ( level == Level.FINER )
|
||||
{
|
||||
formatted.append( " [FINER] " );
|
||||
} else if ( level == Level.FINE )
|
||||
{
|
||||
formatted.append( " [FINE] " );
|
||||
} else if ( level == Level.INFO )
|
||||
{
|
||||
formatted.append( " [INFO] " );
|
||||
} else if ( level == Level.WARNING )
|
||||
{
|
||||
formatted.append( " [WARNING] " );
|
||||
} else if ( level == Level.SEVERE )
|
||||
{
|
||||
formatted.append( " [SEVERE] " );
|
||||
}
|
||||
|
||||
formatted.append( formatMessage( logrecord ) );
|
||||
formatted.append( '\n' );
|
||||
Throwable throwable = logrecord.getThrown();
|
||||
|
||||
if ( throwable != null )
|
||||
{
|
||||
StringWriter writer = new StringWriter();
|
||||
|
||||
throwable.printStackTrace( new PrintWriter( writer ) );
|
||||
formatted.append( writer );
|
||||
}
|
||||
|
||||
return formatted.toString();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,5 +1,6 @@
|
||||
package net.md_5.bungee;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
@@ -9,15 +10,14 @@ import java.net.InetSocketAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Objects;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Synchronized;
|
||||
import net.md_5.bungee.api.Callback;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.ServerPing;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
@@ -25,8 +25,8 @@ import net.md_5.bungee.api.connection.Server;
|
||||
import net.md_5.bungee.connection.PingHandler;
|
||||
import net.md_5.bungee.netty.HandlerBoss;
|
||||
import net.md_5.bungee.netty.PipelineUtils;
|
||||
import net.md_5.bungee.packet.DefinedPacket;
|
||||
import net.md_5.bungee.packet.PacketFAPluginMessage;
|
||||
import net.md_5.bungee.protocol.packet.DefinedPacket;
|
||||
import net.md_5.bungee.protocol.packet.PacketFAPluginMessage;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class BungeeServerInfo implements ServerInfo
|
||||
@@ -40,7 +40,7 @@ public class BungeeServerInfo implements ServerInfo
|
||||
@Getter
|
||||
private final boolean restricted;
|
||||
@Getter
|
||||
private final Queue<DefinedPacket> packetQueue = new ConcurrentLinkedQueue<>();
|
||||
private final Queue<DefinedPacket> packetQueue = new LinkedList<>();
|
||||
|
||||
@Synchronized("players")
|
||||
public void addPlayer(ProxiedPlayer player)
|
||||
@@ -64,6 +64,7 @@ public class BungeeServerInfo implements ServerInfo
|
||||
@Override
|
||||
public boolean canAccess(CommandSender player)
|
||||
{
|
||||
Preconditions.checkNotNull( player, "player" );
|
||||
return !restricted || player.hasPermission( "bungeecord.server." + name );
|
||||
}
|
||||
|
||||
@@ -79,30 +80,32 @@ public class BungeeServerInfo implements ServerInfo
|
||||
return address.hashCode();
|
||||
}
|
||||
|
||||
// TODO: Don't like this method
|
||||
@Override
|
||||
public void sendData(String channel, byte[] data)
|
||||
{
|
||||
Server server = ProxyServer.getInstance().getServer( getName() );
|
||||
Preconditions.checkNotNull( channel, "channel" );
|
||||
Preconditions.checkNotNull( data, "data" );
|
||||
|
||||
Server server = ( players.isEmpty() ) ? null : players.iterator().next().getServer();
|
||||
if ( server != null )
|
||||
{
|
||||
server.sendData( channel, data );
|
||||
} else
|
||||
{
|
||||
synchronized ( packetQueue )
|
||||
{
|
||||
packetQueue.add( new PacketFAPluginMessage( channel, data ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ping(final Callback<ServerPing> callback)
|
||||
{
|
||||
new Bootstrap()
|
||||
.channel( NioSocketChannel.class )
|
||||
.group( BungeeCord.getInstance().eventLoops )
|
||||
.handler( PipelineUtils.BASE )
|
||||
.option( ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000 ) // TODO: Configurable
|
||||
.remoteAddress( getAddress() )
|
||||
.connect()
|
||||
.addListener( new ChannelFutureListener()
|
||||
Preconditions.checkNotNull( callback, "callback" );
|
||||
|
||||
ChannelFutureListener listener = new ChannelFutureListener()
|
||||
{
|
||||
@Override
|
||||
public void operationComplete(ChannelFuture future) throws Exception
|
||||
@@ -115,6 +118,14 @@ public class BungeeServerInfo implements ServerInfo
|
||||
callback.done( null, future.cause() );
|
||||
}
|
||||
}
|
||||
} );
|
||||
};
|
||||
new Bootstrap()
|
||||
.channel( NioSocketChannel.class )
|
||||
.group( BungeeCord.getInstance().eventLoops )
|
||||
.handler( PipelineUtils.BASE )
|
||||
.option( ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000 ) // TODO: Configurable
|
||||
.remoteAddress( getAddress() )
|
||||
.connect()
|
||||
.addListener( listener );
|
||||
}
|
||||
}
|
||||
|
@@ -1,23 +1,22 @@
|
||||
package net.md_5.bungee;
|
||||
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.Key;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PublicKey;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import net.md_5.bungee.packet.PacketFCEncryptionResponse;
|
||||
import net.md_5.bungee.packet.PacketFDEncryptionRequest;
|
||||
import lombok.Getter;
|
||||
import net.md_5.bungee.protocol.packet.PacketFCEncryptionResponse;
|
||||
import net.md_5.bungee.protocol.packet.PacketFDEncryptionRequest;
|
||||
|
||||
/**
|
||||
* Class containing all encryption related methods for the proxy.
|
||||
@@ -27,14 +26,22 @@ public class EncryptionUtil
|
||||
|
||||
private static final Random random = new Random();
|
||||
public static KeyPair keys;
|
||||
@Getter
|
||||
private static SecretKey secret = new SecretKeySpec( new byte[ 16 ], "AES" );
|
||||
|
||||
public static PacketFDEncryptionRequest encryptRequest() throws NoSuchAlgorithmException
|
||||
static
|
||||
{
|
||||
if ( keys == null )
|
||||
try
|
||||
{
|
||||
keys = KeyPairGenerator.getInstance( "RSA" ).generateKeyPair();
|
||||
} catch ( NoSuchAlgorithmException ex )
|
||||
{
|
||||
throw new ExceptionInInitializerError( ex );
|
||||
}
|
||||
}
|
||||
|
||||
public static PacketFDEncryptionRequest encryptRequest()
|
||||
{
|
||||
String hash = ( BungeeCord.getInstance().config.isOnlineMode() ) ? Long.toString( random.nextLong(), 16 ) : "-";
|
||||
byte[] pubKey = keys.getPublic().getEncoded();
|
||||
byte[] verify = new byte[ 4 ];
|
||||
@@ -42,22 +49,19 @@ public class EncryptionUtil
|
||||
return new PacketFDEncryptionRequest( hash, pubKey, verify );
|
||||
}
|
||||
|
||||
public static SecretKey getSecret(PacketFCEncryptionResponse resp, PacketFDEncryptionRequest request) throws BadPaddingException, IllegalBlockSizeException, IllegalStateException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException
|
||||
public static SecretKey getSecret(PacketFCEncryptionResponse resp, PacketFDEncryptionRequest request) throws GeneralSecurityException
|
||||
{
|
||||
Cipher cipher = Cipher.getInstance( "RSA" );
|
||||
cipher.init( Cipher.DECRYPT_MODE, keys.getPrivate() );
|
||||
byte[] decrypted = cipher.doFinal( resp.verifyToken );
|
||||
byte[] decrypted = cipher.doFinal( resp.getVerifyToken() );
|
||||
|
||||
if ( !Arrays.equals( request.verifyToken, decrypted ) )
|
||||
if ( !Arrays.equals( request.getVerifyToken(), decrypted ) )
|
||||
{
|
||||
throw new IllegalStateException( "Key pairs do not match!" );
|
||||
}
|
||||
|
||||
cipher.init( Cipher.DECRYPT_MODE, keys.getPrivate() );
|
||||
byte[] shared = resp.sharedSecret;
|
||||
byte[] secret = cipher.doFinal( shared );
|
||||
|
||||
return new SecretKeySpec( secret, "AES" );
|
||||
return new SecretKeySpec( cipher.doFinal( resp.getSharedSecret() ), "AES" );
|
||||
}
|
||||
|
||||
public static Cipher getCipher(int opMode, Key shared) throws GeneralSecurityException
|
||||
@@ -66,4 +70,16 @@ public class EncryptionUtil
|
||||
cip.init( opMode, shared, new IvParameterSpec( shared.getEncoded() ) );
|
||||
return cip;
|
||||
}
|
||||
|
||||
public static PublicKey getPubkey(PacketFDEncryptionRequest request) throws GeneralSecurityException
|
||||
{
|
||||
return KeyFactory.getInstance( "RSA" ).generatePublic( new X509EncodedKeySpec( request.getPublicKey() ) );
|
||||
}
|
||||
|
||||
public static byte[] encrypt(Key key, byte[] b) throws GeneralSecurityException
|
||||
{
|
||||
Cipher hasher = Cipher.getInstance( "RSA" );
|
||||
hasher.init( Cipher.ENCRYPT_MODE, key );
|
||||
return hasher.doFinal( b );
|
||||
}
|
||||
}
|
||||
|
@@ -152,7 +152,8 @@ public class EntityMap
|
||||
int type = packet[5] & 0xFF;
|
||||
if ( type == 60 || type == 90 )
|
||||
{
|
||||
if ( readInt( packet, 20 ) == oldId )
|
||||
int index20 = readInt( packet, 20 );
|
||||
if ( packet.length > 24 && index20 == oldId )
|
||||
{
|
||||
setInt( packet, 20, newId );
|
||||
}
|
||||
|
@@ -8,9 +8,10 @@ import java.io.UnsupportedEncodingException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.TimerTask;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
|
||||
public class Metrics extends Thread
|
||||
public class Metrics extends TimerTask
|
||||
{
|
||||
|
||||
/**
|
||||
@@ -28,19 +29,11 @@ public class Metrics extends Thread
|
||||
/**
|
||||
* Interval of time to ping (in minutes)
|
||||
*/
|
||||
private final static int PING_INTERVAL = 10;
|
||||
|
||||
public Metrics()
|
||||
{
|
||||
super( "Metrics Gathering Thread" );
|
||||
setDaemon( true );
|
||||
}
|
||||
final static int PING_INTERVAL = 10;
|
||||
boolean firstPost = true;
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
boolean firstPost = true;
|
||||
while ( true )
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -56,14 +49,6 @@ public class Metrics extends Thread
|
||||
{
|
||||
ProxyServer.getInstance().getLogger().info( "[Metrics] " + ex.getMessage() );
|
||||
}
|
||||
try
|
||||
{
|
||||
sleep( PING_INTERVAL * 1000 * 60 );
|
||||
} catch ( InterruptedException ex )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -76,7 +61,7 @@ public class Metrics extends Thread
|
||||
data.append( encode( "guid" ) ).append( '=' ).append( encode( BungeeCord.getInstance().config.getUuid() ) );
|
||||
encodeDataPair( data, "version", ProxyServer.getInstance().getVersion() );
|
||||
encodeDataPair( data, "server", "0" );
|
||||
encodeDataPair( data, "players", Integer.toString( ProxyServer.getInstance().getPlayers().size() ) );
|
||||
encodeDataPair( data, "players", Integer.toString( ProxyServer.getInstance().getOnlineCount() ) );
|
||||
encodeDataPair( data, "revision", String.valueOf( REVISION ) );
|
||||
|
||||
// If we're pinging, append it
|
||||
|
18
proxy/src/main/java/net/md_5/bungee/PacketConstants.java
Normal file
18
proxy/src/main/java/net/md_5/bungee/PacketConstants.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package net.md_5.bungee;
|
||||
|
||||
import net.md_5.bungee.protocol.packet.Packet9Respawn;
|
||||
import net.md_5.bungee.protocol.packet.PacketCDClientStatus;
|
||||
import net.md_5.bungee.protocol.packet.PacketFAPluginMessage;
|
||||
|
||||
public class PacketConstants
|
||||
{
|
||||
|
||||
public static final Packet9Respawn DIM1_SWITCH = new Packet9Respawn( (byte) 1, (byte) 0, (byte) 0, (short) 256, "DEFAULT" );
|
||||
public static final Packet9Respawn DIM2_SWITCH = new Packet9Respawn( (byte) -1, (byte) 0, (byte) 0, (short) 256, "DEFAULT" );
|
||||
public static final PacketCDClientStatus CLIENT_LOGIN = new PacketCDClientStatus( (byte) 0 );
|
||||
public static final PacketFAPluginMessage FORGE_MOD_REQUEST = new PacketFAPluginMessage( "FML", new byte[]
|
||||
{
|
||||
0, 0, 0, 0, 0, 2
|
||||
} );
|
||||
public static final PacketFAPluginMessage I_AM_BUNGEE = new PacketFAPluginMessage( "BungeeCord", new byte[ 0 ] );
|
||||
}
|
@@ -1,6 +1,5 @@
|
||||
package net.md_5.bungee;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import lombok.Getter;
|
||||
@@ -8,9 +7,9 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import net.md_5.bungee.api.connection.Server;
|
||||
import net.md_5.bungee.netty.ChannelWrapper;
|
||||
import net.md_5.bungee.packet.Packet1Login;
|
||||
import net.md_5.bungee.packet.PacketFAPluginMessage;
|
||||
import net.md_5.bungee.packet.PacketFFKick;
|
||||
import net.md_5.bungee.protocol.packet.DefinedPacket;
|
||||
import net.md_5.bungee.protocol.packet.PacketFAPluginMessage;
|
||||
import net.md_5.bungee.protocol.packet.PacketFFKick;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class ServerConnection implements Server
|
||||
@@ -21,23 +20,29 @@ public class ServerConnection implements Server
|
||||
@Getter
|
||||
private final BungeeServerInfo info;
|
||||
@Getter
|
||||
private final Packet1Login loginPacket;
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean isObsolete;
|
||||
private final Unsafe unsafe = new Unsafe()
|
||||
{
|
||||
@Override
|
||||
public void sendPacket(DefinedPacket packet)
|
||||
{
|
||||
ch.write( packet );
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void sendData(String channel, byte[] data)
|
||||
{
|
||||
ch.write( new PacketFAPluginMessage( channel, data ) );
|
||||
unsafe().sendPacket( new PacketFAPluginMessage( channel, data ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void disconnect(String reason)
|
||||
{
|
||||
if ( ch.getHandle().isActive() )
|
||||
if ( !ch.isClosed() )
|
||||
{
|
||||
ch.write( new PacketFFKick( reason ) );
|
||||
unsafe().sendPacket( new PacketFFKick( reason ) );
|
||||
ch.getHandle().eventLoop().schedule( new Runnable()
|
||||
{
|
||||
@Override
|
||||
@@ -54,4 +59,10 @@ public class ServerConnection implements Server
|
||||
{
|
||||
return getInfo().getAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Unsafe unsafe()
|
||||
{
|
||||
return unsafe;
|
||||
}
|
||||
}
|
||||
|
@@ -1,33 +1,44 @@
|
||||
package net.md_5.bungee;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.io.ByteArrayDataInput;
|
||||
import com.google.common.io.ByteArrayDataOutput;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import java.security.PublicKey;
|
||||
import java.util.Objects;
|
||||
import java.util.Queue;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.SecretKey;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.event.ServerConnectedEvent;
|
||||
import net.md_5.bungee.api.event.ServerKickEvent;
|
||||
import net.md_5.bungee.api.scoreboard.Objective;
|
||||
import net.md_5.bungee.api.scoreboard.Scoreboard;
|
||||
import net.md_5.bungee.api.scoreboard.Team;
|
||||
import net.md_5.bungee.api.event.ServerSwitchEvent;
|
||||
import net.md_5.bungee.api.score.Objective;
|
||||
import net.md_5.bungee.api.score.Scoreboard;
|
||||
import net.md_5.bungee.api.score.Team;
|
||||
import net.md_5.bungee.connection.CancelSendSignal;
|
||||
import net.md_5.bungee.connection.DownstreamBridge;
|
||||
import net.md_5.bungee.netty.HandlerBoss;
|
||||
import net.md_5.bungee.netty.ChannelWrapper;
|
||||
import net.md_5.bungee.packet.DefinedPacket;
|
||||
import net.md_5.bungee.packet.Packet1Login;
|
||||
import net.md_5.bungee.packet.Packet9Respawn;
|
||||
import net.md_5.bungee.packet.PacketCDClientStatus;
|
||||
import net.md_5.bungee.packet.PacketCEScoreboardObjective;
|
||||
import net.md_5.bungee.packet.PacketD1Team;
|
||||
import net.md_5.bungee.packet.PacketFAPluginMessage;
|
||||
import net.md_5.bungee.packet.PacketFDEncryptionRequest;
|
||||
import net.md_5.bungee.packet.PacketFFKick;
|
||||
import net.md_5.bungee.packet.PacketHandler;
|
||||
import net.md_5.bungee.netty.CipherDecoder;
|
||||
import net.md_5.bungee.netty.CipherEncoder;
|
||||
import net.md_5.bungee.netty.PacketDecoder;
|
||||
import net.md_5.bungee.netty.PacketHandler;
|
||||
import net.md_5.bungee.netty.PipelineUtils;
|
||||
import net.md_5.bungee.protocol.Forge;
|
||||
import net.md_5.bungee.protocol.packet.DefinedPacket;
|
||||
import net.md_5.bungee.protocol.packet.Packet1Login;
|
||||
import net.md_5.bungee.protocol.packet.Packet9Respawn;
|
||||
import net.md_5.bungee.protocol.packet.PacketCEScoreboardObjective;
|
||||
import net.md_5.bungee.protocol.packet.PacketD1Team;
|
||||
import net.md_5.bungee.protocol.packet.PacketFAPluginMessage;
|
||||
import net.md_5.bungee.protocol.packet.PacketFCEncryptionResponse;
|
||||
import net.md_5.bungee.protocol.packet.PacketFDEncryptionRequest;
|
||||
import net.md_5.bungee.protocol.packet.PacketFFKick;
|
||||
import net.md_5.bungee.protocol.packet.forge.Forge1Login;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class ServerConnector extends PacketHandler
|
||||
@@ -38,11 +49,26 @@ public class ServerConnector extends PacketHandler
|
||||
private final UserConnection user;
|
||||
private final BungeeServerInfo target;
|
||||
private State thisState = State.ENCRYPT_REQUEST;
|
||||
private SecretKey secretkey;
|
||||
private boolean sentMessages;
|
||||
|
||||
private enum State
|
||||
{
|
||||
|
||||
ENCRYPT_REQUEST, LOGIN, FINISHED;
|
||||
ENCRYPT_REQUEST, ENCRYPT_RESPONSE, LOGIN, FINISHED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exception(Throwable t) throws Exception
|
||||
{
|
||||
String message = "Exception Connecting:" + Util.exception( t );
|
||||
if ( user.getServer() == null )
|
||||
{
|
||||
user.disconnect( message );
|
||||
} else
|
||||
{
|
||||
user.sendMessage( ChatColor.RED + message );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -52,12 +78,17 @@ public class ServerConnector extends PacketHandler
|
||||
|
||||
ByteArrayDataOutput out = ByteStreams.newDataOutput();
|
||||
out.writeUTF( "Login" );
|
||||
out.writeUTF( user.getAddress().getAddress().getHostAddress() );
|
||||
out.writeUTF( user.getAddress().getHostString() );
|
||||
out.writeInt( user.getAddress().getPort() );
|
||||
channel.write( new PacketFAPluginMessage( "BungeeCord", out.toByteArray() ) );
|
||||
|
||||
channel.write( user.getPendingConnection().getHandshake() );
|
||||
channel.write( PacketCDClientStatus.CLIENT_LOGIN );
|
||||
|
||||
// Skip encryption if we are not using Forge
|
||||
if ( user.getPendingConnection().getForgeLogin() == null )
|
||||
{
|
||||
channel.write( PacketConstants.CLIENT_LOGIN );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -71,18 +102,32 @@ public class ServerConnector extends PacketHandler
|
||||
{
|
||||
Preconditions.checkState( thisState == State.LOGIN, "Not exepcting LOGIN" );
|
||||
|
||||
ServerConnection server = new ServerConnection( ch, target, login );
|
||||
ServerConnection server = new ServerConnection( ch, target );
|
||||
ServerConnectedEvent event = new ServerConnectedEvent( user, server );
|
||||
bungee.getPluginManager().callEvent( event );
|
||||
|
||||
ch.write( BungeeCord.getInstance().registerChannels() );
|
||||
|
||||
// TODO: Race conditions with many connects
|
||||
Queue<DefinedPacket> packetQueue = ( (BungeeServerInfo) target ).getPacketQueue();
|
||||
Queue<DefinedPacket> packetQueue = target.getPacketQueue();
|
||||
synchronized ( packetQueue )
|
||||
{
|
||||
while ( !packetQueue.isEmpty() )
|
||||
{
|
||||
ch.write( packetQueue.poll() );
|
||||
}
|
||||
}
|
||||
|
||||
for ( PacketFAPluginMessage message : user.getPendingConnection().getRegisterMessages() )
|
||||
{
|
||||
ch.write( message );
|
||||
}
|
||||
if ( !sentMessages )
|
||||
{
|
||||
for ( PacketFAPluginMessage message : user.getPendingConnection().getLoginMessages() )
|
||||
{
|
||||
ch.write( message );
|
||||
}
|
||||
}
|
||||
|
||||
if ( user.getSettings() != null )
|
||||
{
|
||||
ch.write( user.getSettings() );
|
||||
@@ -93,38 +138,40 @@ public class ServerConnector extends PacketHandler
|
||||
if ( user.getServer() == null )
|
||||
{
|
||||
// Once again, first connection
|
||||
user.setClientEntityId( login.entityId );
|
||||
user.setServerEntityId( login.entityId );
|
||||
// Set tab list size
|
||||
Packet1Login modLogin = new Packet1Login(
|
||||
login.entityId,
|
||||
login.levelType,
|
||||
login.gameMode,
|
||||
(byte) login.dimension,
|
||||
login.difficulty,
|
||||
login.unused,
|
||||
user.setClientEntityId( login.getEntityId() );
|
||||
user.setServerEntityId( login.getEntityId() );
|
||||
|
||||
// Set tab list size, this sucks balls, TODO: what shall we do about packet mutability
|
||||
Packet1Login modLogin;
|
||||
if ( ch.getHandle().pipeline().get( PacketDecoder.class ).getProtocol() == Forge.getInstance() )
|
||||
{
|
||||
modLogin = new Forge1Login( login.getEntityId(), login.getLevelType(), login.getGameMode(), login.getDimension(), login.getDifficulty(), login.getUnused(),
|
||||
(byte) user.getPendingConnection().getListener().getTabListSize() );
|
||||
user.sendPacket( modLogin );
|
||||
} else
|
||||
{
|
||||
bungee.getTabListHandler().onServerChange( user );
|
||||
modLogin = new Packet1Login( login.getEntityId(), login.getLevelType(), login.getGameMode(), (byte) login.getDimension(), login.getDifficulty(), login.getUnused(),
|
||||
(byte) user.getPendingConnection().getListener().getTabListSize() );
|
||||
}
|
||||
user.unsafe().sendPacket( modLogin );
|
||||
} else
|
||||
{
|
||||
user.getTabList().onServerChange();
|
||||
|
||||
Scoreboard serverScoreboard = user.getServerSentScoreboard();
|
||||
for ( Objective objective : serverScoreboard.getObjectives() )
|
||||
{
|
||||
user.sendPacket( new PacketCEScoreboardObjective( objective.getName(), objective.getValue(), (byte) 1 ) );
|
||||
user.unsafe().sendPacket( new PacketCEScoreboardObjective( objective.getName(), objective.getValue(), (byte) 1 ) );
|
||||
}
|
||||
for ( Team team : serverScoreboard.getTeams() )
|
||||
{
|
||||
user.sendPacket( PacketD1Team.destroy( team.getName() ) );
|
||||
user.unsafe().sendPacket( new PacketD1Team( team.getName() ) );
|
||||
}
|
||||
serverScoreboard.clear();
|
||||
|
||||
user.sendPacket( Packet9Respawn.DIM1_SWITCH );
|
||||
user.sendPacket( Packet9Respawn.DIM2_SWITCH );
|
||||
user.sendDimensionSwitch();
|
||||
|
||||
user.setServerEntityId( login.entityId );
|
||||
user.sendPacket( new Packet9Respawn( login.dimension, login.difficulty, login.gameMode, (short) 256, login.levelType ) );
|
||||
user.setServerEntityId( login.getEntityId() );
|
||||
user.unsafe().sendPacket( new Packet9Respawn( login.getDimension(), login.getDifficulty(), login.getGameMode(), (short) 256, login.getLevelType() ) );
|
||||
|
||||
// Remove from old servers
|
||||
user.getServer().setObsolete( true );
|
||||
@@ -149,6 +196,8 @@ public class ServerConnector extends PacketHandler
|
||||
ch.getHandle().pipeline().get( HandlerBoss.class ).setHandler( new DownstreamBridge( bungee, user, server ) );
|
||||
}
|
||||
|
||||
bungee.getPluginManager().callEvent( new ServerSwitchEvent( user ) );
|
||||
|
||||
thisState = State.FINISHED;
|
||||
|
||||
throw new CancelSendSignal();
|
||||
@@ -158,6 +207,39 @@ public class ServerConnector extends PacketHandler
|
||||
public void handle(PacketFDEncryptionRequest encryptRequest) throws Exception
|
||||
{
|
||||
Preconditions.checkState( thisState == State.ENCRYPT_REQUEST, "Not expecting ENCRYPT_REQUEST" );
|
||||
|
||||
// Only need to handle this if we want to use encryption
|
||||
if ( user.getPendingConnection().getForgeLogin() != null )
|
||||
{
|
||||
PublicKey publickey = EncryptionUtil.getPubkey( encryptRequest );
|
||||
this.secretkey = EncryptionUtil.getSecret();
|
||||
|
||||
byte[] shared = EncryptionUtil.encrypt( publickey, secretkey.getEncoded() );
|
||||
byte[] token = EncryptionUtil.encrypt( publickey, encryptRequest.getVerifyToken() );
|
||||
|
||||
ch.write( new PacketFCEncryptionResponse( shared, token ) );
|
||||
|
||||
Cipher encrypt = EncryptionUtil.getCipher( Cipher.ENCRYPT_MODE, secretkey );
|
||||
ch.getHandle().pipeline().addBefore( PipelineUtils.PACKET_DECODE_HANDLER, PipelineUtils.ENCRYPT_HANDLER, new CipherEncoder( encrypt ) );
|
||||
|
||||
thisState = State.ENCRYPT_RESPONSE;
|
||||
} else
|
||||
{
|
||||
thisState = State.LOGIN;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(PacketFCEncryptionResponse encryptResponse) throws Exception
|
||||
{
|
||||
Preconditions.checkState( thisState == State.ENCRYPT_RESPONSE, "Not expecting ENCRYPT_RESPONSE" );
|
||||
|
||||
Cipher decrypt = EncryptionUtil.getCipher( Cipher.DECRYPT_MODE, secretkey );
|
||||
ch.getHandle().pipeline().addBefore( PipelineUtils.PACKET_DECODE_HANDLER, PipelineUtils.DECRYPT_HANDLER, new CipherDecoder( decrypt ) );
|
||||
|
||||
ch.write( user.getPendingConnection().getForgeLogin() );
|
||||
|
||||
ch.write( PacketConstants.CLIENT_LOGIN );
|
||||
thisState = State.LOGIN;
|
||||
}
|
||||
|
||||
@@ -169,14 +251,14 @@ public class ServerConnector extends PacketHandler
|
||||
{
|
||||
def = null;
|
||||
}
|
||||
ServerKickEvent event = bungee.getPluginManager().callEvent( new ServerKickEvent( user, kick.message, def ) );
|
||||
ServerKickEvent event = bungee.getPluginManager().callEvent( new ServerKickEvent( user, kick.getMessage(), def ) );
|
||||
if ( event.isCancelled() && event.getCancelServer() != null )
|
||||
{
|
||||
user.connect( event.getCancelServer() );
|
||||
return;
|
||||
}
|
||||
|
||||
String message = ChatColor.RED + "Kicked whilst connecting to " + target.getName() + ": " + kick.message;
|
||||
String message = bungee.getTranslation( "connect_kick" ) + target.getName() + ": " + kick.getMessage();
|
||||
if ( user.getServer() == null )
|
||||
{
|
||||
user.disconnect( message );
|
||||
@@ -186,6 +268,41 @@ public class ServerConnector extends PacketHandler
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(PacketFAPluginMessage pluginMessage) throws Exception
|
||||
{
|
||||
if ( pluginMessage.equals( PacketConstants.I_AM_BUNGEE ) )
|
||||
{
|
||||
throw new IllegalStateException( "May not connect to another BungeCord!" );
|
||||
}
|
||||
|
||||
if ( pluginMessage.getTag().equals( "FML" ) && ( pluginMessage.getData()[0] & 0xFF ) == 0 )
|
||||
{
|
||||
ByteArrayDataInput in = ByteStreams.newDataInput( pluginMessage.getData() );
|
||||
in.readUnsignedByte();
|
||||
int count = in.readInt();
|
||||
for ( int i = 0; i < count; i++ )
|
||||
{
|
||||
in.readUTF();
|
||||
}
|
||||
if ( in.readByte() != 0 )
|
||||
{
|
||||
// TODO: Using forge flag
|
||||
ch.getHandle().pipeline().get( PacketDecoder.class ).setProtocol( Forge.getInstance() );
|
||||
}
|
||||
}
|
||||
|
||||
user.unsafe().sendPacket( pluginMessage ); // We have to forward these to the user, especially with Forge as stuff might break
|
||||
if ( !sentMessages && user.getPendingConnection().getForgeLogin() != null )
|
||||
{
|
||||
for ( PacketFAPluginMessage message : user.getPendingConnection().getLoginMessages() )
|
||||
{
|
||||
ch.write( message );
|
||||
}
|
||||
sentMessages = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
|
@@ -8,6 +8,7 @@ import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -21,20 +22,22 @@ import lombok.Setter;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.config.TexturePackInfo;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.PermissionCheckEvent;
|
||||
import net.md_5.bungee.api.event.ServerConnectEvent;
|
||||
import net.md_5.bungee.api.scoreboard.Scoreboard;
|
||||
import net.md_5.bungee.api.score.Scoreboard;
|
||||
import net.md_5.bungee.api.tab.TabListHandler;
|
||||
import net.md_5.bungee.connection.InitialHandler;
|
||||
import net.md_5.bungee.netty.ChannelWrapper;
|
||||
import net.md_5.bungee.netty.HandlerBoss;
|
||||
import net.md_5.bungee.netty.PipelineUtils;
|
||||
import net.md_5.bungee.packet.DefinedPacket;
|
||||
import net.md_5.bungee.packet.Packet3Chat;
|
||||
import net.md_5.bungee.packet.Packet9Respawn;
|
||||
import net.md_5.bungee.packet.PacketCCSettings;
|
||||
import net.md_5.bungee.packet.PacketFAPluginMessage;
|
||||
import net.md_5.bungee.packet.PacketFFKick;
|
||||
import net.md_5.bungee.protocol.packet.DefinedPacket;
|
||||
import net.md_5.bungee.protocol.packet.Packet3Chat;
|
||||
import net.md_5.bungee.protocol.packet.PacketCCSettings;
|
||||
import net.md_5.bungee.protocol.packet.PacketFAPluginMessage;
|
||||
import net.md_5.bungee.protocol.packet.PacketFFKick;
|
||||
import net.md_5.bungee.util.CaseInsensitiveSet;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public final class UserConnection implements ProxiedPlayer
|
||||
@@ -49,7 +52,6 @@ public final class UserConnection implements ProxiedPlayer
|
||||
@NonNull
|
||||
private final String name;
|
||||
@Getter
|
||||
@NonNull
|
||||
private final InitialHandler pendingConnection;
|
||||
/*========================================================================*/
|
||||
@Getter
|
||||
@@ -61,6 +63,8 @@ public final class UserConnection implements ProxiedPlayer
|
||||
private final Collection<ServerInfo> pendingConnects = new HashSet<>();
|
||||
/*========================================================================*/
|
||||
@Getter
|
||||
private TabListHandler tabList;
|
||||
@Getter
|
||||
@Setter
|
||||
private int sentPingId;
|
||||
@Getter
|
||||
@@ -70,10 +74,11 @@ public final class UserConnection implements ProxiedPlayer
|
||||
@Setter
|
||||
private int ping = 100;
|
||||
/*========================================================================*/
|
||||
private final Collection<String> groups = new HashSet<>();
|
||||
private final Collection<String> permissions = new HashSet<>();
|
||||
private final Collection<String> groups = new CaseInsensitiveSet();
|
||||
private final Collection<String> permissions = new CaseInsensitiveSet();
|
||||
/*========================================================================*/
|
||||
@Getter
|
||||
@Setter
|
||||
private int clientEntityId;
|
||||
@Getter
|
||||
@Setter
|
||||
@@ -87,10 +92,26 @@ public final class UserConnection implements ProxiedPlayer
|
||||
@Getter
|
||||
private String displayName;
|
||||
/*========================================================================*/
|
||||
private final Unsafe unsafe = new Unsafe()
|
||||
{
|
||||
@Override
|
||||
public void sendPacket(DefinedPacket packet)
|
||||
{
|
||||
ch.write( packet );
|
||||
}
|
||||
};
|
||||
|
||||
public void init()
|
||||
{
|
||||
this.displayName = name;
|
||||
try
|
||||
{
|
||||
this.tabList = getPendingConnection().getListener().getTabList().getDeclaredConstructor().newInstance();
|
||||
} catch ( ReflectiveOperationException ex )
|
||||
{
|
||||
throw new RuntimeException( ex );
|
||||
}
|
||||
this.tabList.init( this );
|
||||
|
||||
Collection<String> g = bungee.getConfigurationAdapter().getGroups( name );
|
||||
for ( String s : g )
|
||||
@@ -99,9 +120,11 @@ public final class UserConnection implements ProxiedPlayer
|
||||
}
|
||||
}
|
||||
|
||||
public void sendPacket(DefinedPacket p)
|
||||
@Override
|
||||
public void setTabList(TabListHandler tabList)
|
||||
{
|
||||
ch.write( p );
|
||||
tabList.init( this );
|
||||
this.tabList = tabList;
|
||||
}
|
||||
|
||||
public void sendPacket(byte[] b)
|
||||
@@ -112,7 +135,7 @@ public final class UserConnection implements ProxiedPlayer
|
||||
@Deprecated
|
||||
public boolean isActive()
|
||||
{
|
||||
return ch.getHandle().isActive();
|
||||
return !ch.isClosed();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -120,9 +143,9 @@ public final class UserConnection implements ProxiedPlayer
|
||||
{
|
||||
Preconditions.checkNotNull( name, "displayName" );
|
||||
Preconditions.checkArgument( name.length() <= 16, "Display name cannot be longer than 16 characters" );
|
||||
bungee.getTabListHandler().onDisconnect( this );
|
||||
getTabList().onDisconnect();
|
||||
displayName = name;
|
||||
bungee.getTabListHandler().onConnect( this );
|
||||
getTabList().onConnect();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -131,19 +154,26 @@ public final class UserConnection implements ProxiedPlayer
|
||||
connect( target, false );
|
||||
}
|
||||
|
||||
void sendDimensionSwitch()
|
||||
{
|
||||
unsafe().sendPacket( PacketConstants.DIM1_SWITCH );
|
||||
unsafe().sendPacket( PacketConstants.DIM2_SWITCH );
|
||||
}
|
||||
|
||||
public void connectNow(ServerInfo target)
|
||||
{
|
||||
sendPacket( Packet9Respawn.DIM1_SWITCH );
|
||||
sendPacket( Packet9Respawn.DIM2_SWITCH );
|
||||
sendDimensionSwitch();
|
||||
connect( target );
|
||||
}
|
||||
|
||||
public void connect(ServerInfo info, final boolean retry)
|
||||
{
|
||||
ServerConnectEvent event = new ServerConnectEvent( this, info );
|
||||
ProxyServer.getInstance().getPluginManager().callEvent( event );
|
||||
if ( bungee.getPluginManager().callEvent( event ).isCancelled() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Preconditions.checkArgument( event.getTarget() instanceof BungeeServerInfo, "BungeeCord can only connect to BungeeServerInfo instances" );
|
||||
final BungeeServerInfo target = (BungeeServerInfo) event.getTarget(); // Update in case the event changed target
|
||||
|
||||
if ( getServer() != null && Objects.equals( getServer().getInfo(), target ) )
|
||||
@@ -159,10 +189,7 @@ public final class UserConnection implements ProxiedPlayer
|
||||
|
||||
pendingConnects.add( target );
|
||||
|
||||
new Bootstrap()
|
||||
.channel( NioSocketChannel.class )
|
||||
.group( BungeeCord.getInstance().eventLoops )
|
||||
.handler( new ChannelInitializer()
|
||||
ChannelInitializer initializer = new ChannelInitializer()
|
||||
{
|
||||
@Override
|
||||
protected void initChannel(Channel ch) throws Exception
|
||||
@@ -170,10 +197,8 @@ public final class UserConnection implements ProxiedPlayer
|
||||
PipelineUtils.BASE.initChannel( ch );
|
||||
ch.pipeline().get( HandlerBoss.class ).setHandler( new ServerConnector( bungee, UserConnection.this, target ) );
|
||||
}
|
||||
} )
|
||||
.option( ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000 ) // TODO: Configurable
|
||||
.remoteAddress( target.getAddress() )
|
||||
.connect().addListener( new ChannelFutureListener()
|
||||
};
|
||||
ChannelFutureListener listener = new ChannelFutureListener()
|
||||
{
|
||||
@Override
|
||||
public void operationComplete(ChannelFuture future) throws Exception
|
||||
@@ -186,21 +211,33 @@ public final class UserConnection implements ProxiedPlayer
|
||||
ServerInfo def = ProxyServer.getInstance().getServers().get( getPendingConnection().getListener().getFallbackServer() );
|
||||
if ( retry & target != def && ( getServer() == null || def != getServer().getInfo() ) )
|
||||
{
|
||||
sendMessage( ChatColor.RED + "Could not connect to target server, you have been moved to the lobby server" );
|
||||
sendMessage( bungee.getTranslation( "fallback_lobby" ) );
|
||||
connect( def, false );
|
||||
} else
|
||||
{
|
||||
if ( server == null )
|
||||
{
|
||||
disconnect( "Could not connect to default server, please try again later: " + future.cause().getClass().getName() );
|
||||
disconnect( bungee.getTranslation( "fallback_kick" ) + future.cause().getClass().getName() );
|
||||
} else
|
||||
{
|
||||
sendMessage( ChatColor.RED + "Could not connect to selected server, please try again later: " + future.cause().getClass().getName() );
|
||||
sendMessage( bungee.getTranslation( "fallback_kick" ) + future.cause().getClass().getName() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} );
|
||||
};
|
||||
Bootstrap b = new Bootstrap()
|
||||
.channel( NioSocketChannel.class )
|
||||
.group( BungeeCord.getInstance().eventLoops )
|
||||
.handler( initializer )
|
||||
.option( ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000 ) // TODO: Configurable
|
||||
.remoteAddress( target.getAddress() );
|
||||
// Windows is bugged, multi homed users will just have to live with random connecting IPs
|
||||
if ( !PlatformDependent.isWindows() )
|
||||
{
|
||||
b.localAddress( getPendingConnection().getListener().getHost().getHostString(), 0 );
|
||||
}
|
||||
b.connect().addListener( listener );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -209,8 +246,8 @@ public final class UserConnection implements ProxiedPlayer
|
||||
if ( ch.getHandle().isActive() )
|
||||
{
|
||||
bungee.getLogger().log( Level.INFO, "[" + getName() + "] disconnected with: " + reason );
|
||||
sendPacket( new PacketFFKick( reason ) );
|
||||
ch.getHandle().close();
|
||||
unsafe().sendPacket( new PacketFFKick( reason ) );
|
||||
ch.close();
|
||||
if ( server != null )
|
||||
{
|
||||
server.disconnect( "Quitting" );
|
||||
@@ -228,7 +265,7 @@ public final class UserConnection implements ProxiedPlayer
|
||||
@Override
|
||||
public void sendMessage(String message)
|
||||
{
|
||||
sendPacket( new Packet3Chat( message ) );
|
||||
unsafe().sendPacket( new Packet3Chat( message ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -243,7 +280,7 @@ public final class UserConnection implements ProxiedPlayer
|
||||
@Override
|
||||
public void sendData(String channel, byte[] data)
|
||||
{
|
||||
sendPacket( new PacketFAPluginMessage( channel, data ) );
|
||||
unsafe().sendPacket( new PacketFAPluginMessage( channel, data ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -308,9 +345,15 @@ public final class UserConnection implements ProxiedPlayer
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setClientEntityId(int clientEntityId)
|
||||
@Override
|
||||
public void setTexturePack(TexturePackInfo pack)
|
||||
{
|
||||
Preconditions.checkState( this.clientEntityId == 0, "Client entityId already set!" );
|
||||
this.clientEntityId = clientEntityId;
|
||||
unsafe().sendPacket( new PacketFAPluginMessage( "MC|TPack", ( pack.getUrl() + "\00" + pack.getSize() ).getBytes() ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Unsafe unsafe()
|
||||
{
|
||||
return unsafe;
|
||||
}
|
||||
}
|
||||
|
@@ -2,7 +2,6 @@ package net.md_5.bungee;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Series of utility classes to perform various operations.
|
||||
|
@@ -1,93 +0,0 @@
|
||||
package net.md_5.bungee;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.ReconnectHandler;
|
||||
import net.md_5.bungee.api.config.ListenerInfo;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
|
||||
public class YamlReconnectHandler implements ReconnectHandler
|
||||
{
|
||||
|
||||
private final Yaml yaml = new Yaml();
|
||||
private final File file = new File( "locations.yml" );
|
||||
/*========================================================================*/
|
||||
private Map<String, String> data;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public YamlReconnectHandler()
|
||||
{
|
||||
try
|
||||
{
|
||||
file.createNewFile();
|
||||
try ( FileReader rd = new FileReader( file ) )
|
||||
{
|
||||
data = yaml.loadAs( rd, Map.class );
|
||||
}
|
||||
} catch ( IOException ex )
|
||||
{
|
||||
ProxyServer.getInstance().getLogger().log( Level.WARNING, "Could not load reconnect locations", ex );
|
||||
}
|
||||
|
||||
if ( data == null )
|
||||
{
|
||||
data = new HashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerInfo getServer(ProxiedPlayer player)
|
||||
{
|
||||
ListenerInfo listener = player.getPendingConnection().getListener();
|
||||
String name;
|
||||
String forced = listener.getForcedHosts().get( player.getPendingConnection().getVirtualHost().getHostName().toLowerCase() );
|
||||
if ( forced == null && listener.isForceDefault() )
|
||||
{
|
||||
forced = listener.getDefaultServer();
|
||||
}
|
||||
|
||||
String server = ( forced == null ) ? data.get( key( player ) ) : forced;
|
||||
name = ( server != null ) ? server : listener.getDefaultServer();
|
||||
ServerInfo info = ProxyServer.getInstance().getServerInfo( name );
|
||||
if ( info == null )
|
||||
{
|
||||
info = ProxyServer.getInstance().getServerInfo( listener.getDefaultServer() );
|
||||
}
|
||||
Preconditions.checkState( info != null, "Default server not defined" );
|
||||
return info;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setServer(ProxiedPlayer player)
|
||||
{
|
||||
data.put( key( player ), player.getServer().getInfo().getName() );
|
||||
}
|
||||
|
||||
private String key(ProxiedPlayer player)
|
||||
{
|
||||
InetSocketAddress host = player.getPendingConnection().getVirtualHost();
|
||||
return player.getName() + ";" + host.getHostString() + ":" + host.getPort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void save()
|
||||
{
|
||||
try ( FileWriter wr = new FileWriter( file ) )
|
||||
{
|
||||
yaml.dump( data, wr );
|
||||
} catch ( IOException ex )
|
||||
{
|
||||
ProxyServer.getInstance().getLogger().log( Level.WARNING, "Could not save reconnect locations", ex );
|
||||
}
|
||||
}
|
||||
}
|
@@ -29,8 +29,7 @@ public class CommandAlert extends Command
|
||||
args[0] = args[0].substring( 2, args[0].length() );
|
||||
} else
|
||||
{
|
||||
builder.append( ChatColor.DARK_PURPLE );
|
||||
builder.append( "[Alert] " );
|
||||
builder.append( ProxyServer.getInstance().getTranslation( "alert" ) );
|
||||
}
|
||||
|
||||
for ( String s : args )
|
||||
@@ -40,10 +39,8 @@ public class CommandAlert extends Command
|
||||
}
|
||||
|
||||
String message = builder.substring( 0, builder.length() - 1 );
|
||||
for ( ProxiedPlayer player : ProxyServer.getInstance().getPlayers() )
|
||||
{
|
||||
player.sendMessage( message );
|
||||
}
|
||||
|
||||
ProxyServer.getInstance().broadcast( message );
|
||||
ProxyServer.getInstance().getConsole().sendMessage( message );
|
||||
}
|
||||
}
|
||||
|
35
proxy/src/main/java/net/md_5/bungee/command/CommandFind.java
Normal file
35
proxy/src/main/java/net/md_5/bungee/command/CommandFind.java
Normal file
@@ -0,0 +1,35 @@
|
||||
package net.md_5.bungee.command;
|
||||
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.plugin.Command;
|
||||
|
||||
public class CommandFind extends Command
|
||||
{
|
||||
|
||||
public CommandFind()
|
||||
{
|
||||
super( "find", "bungeecord.command.find" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender, String[] args)
|
||||
{
|
||||
if ( args.length != 1 )
|
||||
{
|
||||
sender.sendMessage( ChatColor.RED + "Please follow this command by a user name" );
|
||||
} else
|
||||
{
|
||||
ProxiedPlayer player = ProxyServer.getInstance().getPlayer( args[0] );
|
||||
if ( player == null || player.getServer() == null )
|
||||
{
|
||||
sender.sendMessage( ChatColor.RED + "That user is not online" );
|
||||
} else
|
||||
{
|
||||
sender.sendMessage( ChatColor.BLUE + args[0] + " is online at " + player.getServer().getInfo().getName() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -58,6 +58,6 @@ public class CommandList extends Command
|
||||
sender.sendMessage( message.toString() );
|
||||
}
|
||||
|
||||
sender.sendMessage( "Total players online: " + ProxyServer.getInstance().getPlayers().size() );
|
||||
sender.sendMessage( ProxyServer.getInstance().getTranslation( "total_players" ) + ProxyServer.getInstance().getOnlineCount() );
|
||||
}
|
||||
}
|
||||
|
@@ -19,6 +19,7 @@ public class CommandReload extends Command
|
||||
BungeeCord.getInstance().config.load();
|
||||
BungeeCord.getInstance().stopListeners();
|
||||
BungeeCord.getInstance().startListeners();
|
||||
sender.sendMessage( ChatColor.GREEN + "Reloaded config, please restart if you have any issues" );
|
||||
sender.sendMessage( ChatColor.BOLD.toString() + ChatColor.RED.toString() + "BungeeCord has been reloaded."
|
||||
+ " This is NOT advisable and you will not be supported with any issues that arise! Please restart BungeeCord ASAP." );
|
||||
}
|
||||
}
|
||||
|
@@ -26,7 +26,8 @@ public class CommandSend extends Command
|
||||
ServerInfo target = ProxyServer.getInstance().getServerInfo( args[1] );
|
||||
if ( target == null )
|
||||
{
|
||||
sender.sendMessage( ChatColor.RED + "Target server does not exist" );
|
||||
sender.sendMessage( ProxyServer.getInstance().getTranslation( "no_server" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( args[0].equalsIgnoreCase( "all" ) )
|
||||
@@ -40,6 +41,7 @@ public class CommandSend extends Command
|
||||
if ( !( sender instanceof ProxiedPlayer ) )
|
||||
{
|
||||
sender.sendMessage( ChatColor.RED + "Only in game players can use this command" );
|
||||
return;
|
||||
}
|
||||
ProxiedPlayer player = (ProxiedPlayer) sender;
|
||||
for ( ProxiedPlayer p : player.getServer().getInfo().getPlayers() )
|
||||
@@ -52,6 +54,7 @@ public class CommandSend extends Command
|
||||
if ( player == null )
|
||||
{
|
||||
sender.sendMessage( ChatColor.RED + "That player is not online" );
|
||||
return;
|
||||
}
|
||||
summon( player, target, sender );
|
||||
}
|
||||
|
@@ -1,7 +1,6 @@
|
||||
package net.md_5.bungee.command;
|
||||
|
||||
import java.util.Map;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
@@ -30,6 +29,8 @@ public class CommandServer extends Command
|
||||
Map<String, ServerInfo> servers = ProxyServer.getInstance().getServers();
|
||||
if ( args.length == 0 )
|
||||
{
|
||||
player.sendMessage( ProxyServer.getInstance().getTranslation( "current_server" ) + player.getServer().getInfo().getName() );
|
||||
|
||||
StringBuilder serverList = new StringBuilder();
|
||||
for ( ServerInfo server : servers.values() )
|
||||
{
|
||||
@@ -43,16 +44,16 @@ public class CommandServer extends Command
|
||||
{
|
||||
serverList.setLength( serverList.length() - 2 );
|
||||
}
|
||||
player.sendMessage( ChatColor.GOLD + "You may connect to the following servers at this time: " + serverList.toString() );
|
||||
player.sendMessage( ProxyServer.getInstance().getTranslation( "server_list" ) + serverList.toString() );
|
||||
} else
|
||||
{
|
||||
ServerInfo server = servers.get( args[0] );
|
||||
if ( server == null )
|
||||
{
|
||||
player.sendMessage( ChatColor.RED + "The specified server does not exist" );
|
||||
player.sendMessage( ProxyServer.getInstance().getTranslation( "no_server" ) );
|
||||
} else if ( !server.canAccess( player ) )
|
||||
{
|
||||
player.sendMessage( ChatColor.RED + "You don't have permission to access this server" );
|
||||
player.sendMessage( ProxyServer.getInstance().getTranslation( "no_server_permission" ) );
|
||||
} else
|
||||
{
|
||||
player.connect( server );
|
||||
|
@@ -3,8 +3,8 @@ package net.md_5.bungee.command;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import lombok.Getter;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
|
||||
/**
|
||||
* Command sender representing the proxy console.
|
||||
@@ -22,7 +22,7 @@ public class ConsoleCommandSender implements CommandSender
|
||||
@Override
|
||||
public void sendMessage(String message)
|
||||
{
|
||||
System.out.println( ChatColor.stripColor( message ) );
|
||||
ProxyServer.getInstance().getLogger().info( message );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package net.md_5.bungee.config;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import gnu.trove.map.TMap;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
@@ -9,9 +10,10 @@ import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.config.ConfigurationAdapter;
|
||||
import net.md_5.bungee.api.config.ListenerInfo;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.tablist.GlobalPing;
|
||||
import net.md_5.bungee.tablist.Global;
|
||||
import net.md_5.bungee.tablist.ServerUnique;
|
||||
import net.md_5.bungee.tab.GlobalPing;
|
||||
import net.md_5.bungee.tab.Global;
|
||||
import net.md_5.bungee.tab.ServerUnique;
|
||||
import net.md_5.bungee.util.CaseInsensitiveMap;
|
||||
|
||||
/**
|
||||
* Core configuration for the proxy.
|
||||
@@ -20,14 +22,6 @@ import net.md_5.bungee.tablist.ServerUnique;
|
||||
public class Configuration
|
||||
{
|
||||
|
||||
/**
|
||||
* The default tab list options available for picking.
|
||||
*/
|
||||
private enum DefaultTabList
|
||||
{
|
||||
|
||||
GLOBAL, GLOBAL_PING, SERVER;
|
||||
}
|
||||
/**
|
||||
* Time before users are disconnected due to no network activity.
|
||||
*/
|
||||
@@ -43,7 +37,7 @@ public class Configuration
|
||||
/**
|
||||
* Set of all servers.
|
||||
*/
|
||||
private Map<String, ServerInfo> servers;
|
||||
private TMap<String, ServerInfo> servers;
|
||||
/**
|
||||
* Should we check minecraft.net auth.
|
||||
*/
|
||||
@@ -55,30 +49,12 @@ public class Configuration
|
||||
ConfigurationAdapter adapter = ProxyServer.getInstance().getConfigurationAdapter();
|
||||
adapter.load();
|
||||
|
||||
listeners = adapter.getListeners();
|
||||
timeout = adapter.getInt( "timeout", timeout );
|
||||
uuid = adapter.getString( "stats", uuid );
|
||||
onlineMode = adapter.getBoolean( "online_mode", onlineMode );
|
||||
playerLimit = adapter.getInt( "player_limit", playerLimit );
|
||||
|
||||
DefaultTabList tab = DefaultTabList.valueOf( adapter.getString( "tab_list", "GLOBAL_PING" ) );
|
||||
if ( tab == null )
|
||||
{
|
||||
tab = DefaultTabList.GLOBAL_PING;
|
||||
}
|
||||
switch ( tab )
|
||||
{
|
||||
case GLOBAL:
|
||||
ProxyServer.getInstance().setTabListHandler( new Global() );
|
||||
break;
|
||||
case GLOBAL_PING:
|
||||
ProxyServer.getInstance().setTabListHandler( new GlobalPing() );
|
||||
break;
|
||||
case SERVER:
|
||||
ProxyServer.getInstance().setTabListHandler( new ServerUnique() );
|
||||
break;
|
||||
}
|
||||
|
||||
listeners = adapter.getListeners();
|
||||
Preconditions.checkArgument( listeners != null && !listeners.isEmpty(), "No listeners defined." );
|
||||
|
||||
Map<String, ServerInfo> newServers = adapter.getServers();
|
||||
@@ -86,7 +62,7 @@ public class Configuration
|
||||
|
||||
if ( servers == null )
|
||||
{
|
||||
servers = newServers;
|
||||
servers = new CaseInsensitiveMap<>( newServers );
|
||||
} else
|
||||
{
|
||||
for ( ServerInfo oldServer : servers.values() )
|
||||
|
@@ -14,6 +14,7 @@ import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.md_5.bungee.Util;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
@@ -21,12 +22,27 @@ import net.md_5.bungee.api.config.ConfigurationAdapter;
|
||||
import net.md_5.bungee.api.config.ListenerInfo;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.config.TexturePackInfo;
|
||||
import net.md_5.bungee.api.tab.TabListHandler;
|
||||
import net.md_5.bungee.tab.Global;
|
||||
import net.md_5.bungee.tab.GlobalPing;
|
||||
import net.md_5.bungee.tab.ServerUnique;
|
||||
import net.md_5.bungee.util.CaseInsensitiveMap;
|
||||
import org.yaml.snakeyaml.DumperOptions;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
|
||||
public class YamlConfig implements ConfigurationAdapter
|
||||
{
|
||||
|
||||
/**
|
||||
* The default tab list options available for picking.
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
private enum DefaultTabList
|
||||
{
|
||||
|
||||
GLOBAL( Global.class ), GLOBAL_PING( GlobalPing.class ), SERVER( ServerUnique.class );
|
||||
private final Class<? extends TabListHandler> clazz;
|
||||
}
|
||||
private Yaml yaml;
|
||||
private Map config;
|
||||
private final File file = new File( "config.yml" );
|
||||
@@ -48,7 +64,10 @@ public class YamlConfig implements ConfigurationAdapter
|
||||
|
||||
if ( config == null )
|
||||
{
|
||||
config = new HashMap();
|
||||
config = new CaseInsensitiveMap();
|
||||
} else
|
||||
{
|
||||
config = new CaseInsensitiveMap( config );
|
||||
}
|
||||
} catch ( IOException ex )
|
||||
{
|
||||
@@ -186,11 +205,18 @@ public class YamlConfig implements ConfigurationAdapter
|
||||
String host = get( "host", "0.0.0.0:25577", val );
|
||||
int tabListSize = get( "tab_size", 60, val );
|
||||
InetSocketAddress address = Util.getAddr( host );
|
||||
Map<String, String> forced = get( "forced_hosts", forcedDef, val );
|
||||
Map<String, String> forced = new CaseInsensitiveMap<>( get( "forced_hosts", forcedDef, val ) );
|
||||
String textureURL = get( "texture_url", null, val );
|
||||
int textureSize = get( "texture_size", 16, val );
|
||||
TexturePackInfo texture = ( textureURL == null ) ? null : new TexturePackInfo( textureURL, textureSize );
|
||||
ListenerInfo info = new ListenerInfo( address, motd, maxPlayers, tabListSize, defaultServer, fallbackServer, forceDefault, forced, texture );
|
||||
String tabListName = get( "tab_list", "GLOBAL_PING", val );
|
||||
DefaultTabList value = DefaultTabList.valueOf( tabListName.toUpperCase() );
|
||||
if ( value == null )
|
||||
{
|
||||
value = DefaultTabList.GLOBAL_PING;
|
||||
}
|
||||
|
||||
ListenerInfo info = new ListenerInfo( address, motd, maxPlayers, tabListSize, defaultServer, fallbackServer, forceDefault, forced, texture, value.clazz );
|
||||
ret.add( info );
|
||||
}
|
||||
|
||||
|
@@ -3,7 +3,6 @@ package net.md_5.bungee.connection;
|
||||
import com.google.common.io.ByteArrayDataInput;
|
||||
import com.google.common.io.ByteArrayDataOutput;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import io.netty.channel.Channel;
|
||||
import java.util.Objects;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.md_5.bungee.EntityMap;
|
||||
@@ -14,25 +13,25 @@ import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.ChatEvent;
|
||||
import net.md_5.bungee.api.event.PluginMessageEvent;
|
||||
import net.md_5.bungee.api.event.ServerKickEvent;
|
||||
import net.md_5.bungee.api.scoreboard.Objective;
|
||||
import net.md_5.bungee.api.scoreboard.Position;
|
||||
import net.md_5.bungee.api.scoreboard.Score;
|
||||
import net.md_5.bungee.api.scoreboard.Scoreboard;
|
||||
import net.md_5.bungee.api.scoreboard.Team;
|
||||
import net.md_5.bungee.api.score.Objective;
|
||||
import net.md_5.bungee.api.score.Position;
|
||||
import net.md_5.bungee.api.score.Score;
|
||||
import net.md_5.bungee.api.score.Scoreboard;
|
||||
import net.md_5.bungee.api.score.Team;
|
||||
import net.md_5.bungee.netty.ChannelWrapper;
|
||||
import net.md_5.bungee.packet.Packet0KeepAlive;
|
||||
import net.md_5.bungee.packet.Packet3Chat;
|
||||
import net.md_5.bungee.packet.PacketC9PlayerListItem;
|
||||
import net.md_5.bungee.packet.PacketCEScoreboardObjective;
|
||||
import net.md_5.bungee.packet.PacketCFScoreboardScore;
|
||||
import net.md_5.bungee.packet.PacketD0DisplayScoreboard;
|
||||
import net.md_5.bungee.packet.PacketD1Team;
|
||||
import net.md_5.bungee.packet.PacketFAPluginMessage;
|
||||
import net.md_5.bungee.packet.PacketFFKick;
|
||||
import net.md_5.bungee.packet.PacketHandler;
|
||||
import net.md_5.bungee.netty.PacketHandler;
|
||||
import net.md_5.bungee.protocol.packet.Packet0KeepAlive;
|
||||
import net.md_5.bungee.protocol.packet.PacketC9PlayerListItem;
|
||||
import net.md_5.bungee.protocol.packet.PacketCEScoreboardObjective;
|
||||
import net.md_5.bungee.protocol.packet.PacketCFScoreboardScore;
|
||||
import net.md_5.bungee.protocol.packet.PacketD0DisplayScoreboard;
|
||||
import net.md_5.bungee.protocol.packet.PacketD1Team;
|
||||
import net.md_5.bungee.protocol.packet.PacketFAPluginMessage;
|
||||
import net.md_5.bungee.protocol.packet.PacketFFKick;
|
||||
|
||||
;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class DownstreamBridge extends PacketHandler
|
||||
@@ -65,41 +64,32 @@ public class DownstreamBridge extends PacketHandler
|
||||
|
||||
if ( !server.isObsolete() )
|
||||
{
|
||||
con.disconnect( "[Proxy] Lost connection to server D:" );
|
||||
con.disconnect( bungee.getTranslation( "lost_connection" ) );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(byte[] buf) throws Exception
|
||||
{
|
||||
if ( !server.isObsolete() )
|
||||
{
|
||||
EntityMap.rewrite( buf, con.getServerEntityId(), con.getClientEntityId() );
|
||||
con.sendPacket( buf );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Packet0KeepAlive alive) throws Exception
|
||||
{
|
||||
con.setSentPingId( alive.id );
|
||||
con.setSentPingId( alive.getRandomId() );
|
||||
con.setSentPingTime( System.currentTimeMillis() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Packet3Chat chat) throws Exception
|
||||
{
|
||||
ChatEvent chatEvent = new ChatEvent( con.getServer(), con, chat.message );
|
||||
bungee.getPluginManager().callEvent( chatEvent );
|
||||
|
||||
if ( chatEvent.isCancelled() )
|
||||
{
|
||||
throw new CancelSendSignal();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(PacketC9PlayerListItem playerList) throws Exception
|
||||
{
|
||||
|
||||
if ( !bungee.getTabListHandler().onListUpdate( con, playerList.username, playerList.online, playerList.ping ) )
|
||||
if ( !con.getTabList().onListUpdate( playerList.getUsername(), playerList.isOnline(), playerList.getPing() ) )
|
||||
{
|
||||
throw new CancelSendSignal();
|
||||
}
|
||||
@@ -109,13 +99,13 @@ public class DownstreamBridge extends PacketHandler
|
||||
public void handle(PacketCEScoreboardObjective objective) throws Exception
|
||||
{
|
||||
Scoreboard serverScoreboard = con.getServerSentScoreboard();
|
||||
switch ( objective.action )
|
||||
switch ( objective.getAction() )
|
||||
{
|
||||
case 0:
|
||||
serverScoreboard.addObjective( new Objective( objective.name, objective.text ) );
|
||||
serverScoreboard.addObjective( new Objective( objective.getName(), objective.getText() ) );
|
||||
break;
|
||||
case 1:
|
||||
serverScoreboard.removeObjective( objective.name );
|
||||
serverScoreboard.removeObjective( objective.getName() );
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -124,15 +114,15 @@ public class DownstreamBridge extends PacketHandler
|
||||
public void handle(PacketCFScoreboardScore score) throws Exception
|
||||
{
|
||||
Scoreboard serverScoreboard = con.getServerSentScoreboard();
|
||||
switch ( score.action )
|
||||
switch ( score.getAction() )
|
||||
{
|
||||
case 0:
|
||||
Score s = new Score( score.itemName, score.scoreName, score.value );
|
||||
serverScoreboard.removeScore( score.itemName );
|
||||
Score s = new Score( score.getItemName(), score.getScoreName(), score.getValue() );
|
||||
serverScoreboard.removeScore( score.getItemName() );
|
||||
serverScoreboard.addScore( s );
|
||||
break;
|
||||
case 1:
|
||||
serverScoreboard.removeScore( score.itemName );
|
||||
serverScoreboard.removeScore( score.getItemName() );
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -141,8 +131,8 @@ public class DownstreamBridge extends PacketHandler
|
||||
public void handle(PacketD0DisplayScoreboard displayScoreboard) throws Exception
|
||||
{
|
||||
Scoreboard serverScoreboard = con.getServerSentScoreboard();
|
||||
serverScoreboard.setName( displayScoreboard.name );
|
||||
serverScoreboard.setPosition( Position.values()[displayScoreboard.position] );
|
||||
serverScoreboard.setName( displayScoreboard.getName() );
|
||||
serverScoreboard.setPosition( Position.values()[displayScoreboard.getPosition()] );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -150,37 +140,37 @@ public class DownstreamBridge extends PacketHandler
|
||||
{
|
||||
Scoreboard serverScoreboard = con.getServerSentScoreboard();
|
||||
// Remove team and move on
|
||||
if ( team.mode == 1 )
|
||||
if ( team.getMode() == 1 )
|
||||
{
|
||||
serverScoreboard.removeTeam( team.name );
|
||||
serverScoreboard.removeTeam( team.getName() );
|
||||
return;
|
||||
}
|
||||
|
||||
// Create or get old team
|
||||
Team t;
|
||||
if ( team.mode == 0 )
|
||||
if ( team.getMode() == 0 )
|
||||
{
|
||||
t = new Team( team.name );
|
||||
t = new Team( team.getName() );
|
||||
serverScoreboard.addTeam( t );
|
||||
} else
|
||||
{
|
||||
t = serverScoreboard.getTeam( team.name );
|
||||
t = serverScoreboard.getTeam( team.getName() );
|
||||
}
|
||||
|
||||
if ( t != null )
|
||||
{
|
||||
if ( team.mode == 0 || team.mode == 2 )
|
||||
if ( team.getMode() == 0 || team.getMode() == 2 )
|
||||
{
|
||||
t.setDisplayName( team.displayName );
|
||||
t.setPrefix( team.prefix );
|
||||
t.setSuffix( team.suffix );
|
||||
t.setFriendlyMode( team.friendlyFire );
|
||||
t.setDisplayName( team.getDisplayName() );
|
||||
t.setPrefix( team.getPrefix() );
|
||||
t.setSuffix( team.getSuffix() );
|
||||
t.setFriendlyFire( team.isFriendlyFire() );
|
||||
}
|
||||
if ( team.players != null )
|
||||
if ( team.getPlayers() != null )
|
||||
{
|
||||
for ( String s : team.players )
|
||||
for ( String s : team.getPlayers() )
|
||||
{
|
||||
if ( team.mode == 0 || team.mode == 3 )
|
||||
if ( team.getMode() == 0 || team.getMode() == 3 )
|
||||
{
|
||||
t.addPlayer( s );
|
||||
} else
|
||||
@@ -195,20 +185,20 @@ public class DownstreamBridge extends PacketHandler
|
||||
@Override
|
||||
public void handle(PacketFAPluginMessage pluginMessage) throws Exception
|
||||
{
|
||||
ByteArrayDataInput in = ByteStreams.newDataInput( pluginMessage.data );
|
||||
PluginMessageEvent event = new PluginMessageEvent( con.getServer(), con, pluginMessage.tag, pluginMessage.data.clone() );
|
||||
ByteArrayDataInput in = ByteStreams.newDataInput( pluginMessage.getData() );
|
||||
PluginMessageEvent event = new PluginMessageEvent( con.getServer(), con, pluginMessage.getTag(), pluginMessage.getData().clone() );
|
||||
|
||||
if ( bungee.getPluginManager().callEvent( event ).isCancelled() )
|
||||
{
|
||||
throw new CancelSendSignal();
|
||||
}
|
||||
|
||||
if ( pluginMessage.tag.equals( "MC|TPack" ) && con.getPendingConnection().getListener().getTexturePack() != null )
|
||||
if ( pluginMessage.getTag().equals( "MC|TPack" ) && con.getPendingConnection().getListener().getTexturePack() != null )
|
||||
{
|
||||
throw new CancelSendSignal();
|
||||
}
|
||||
|
||||
if ( pluginMessage.tag.equals( "BungeeCord" ) )
|
||||
if ( pluginMessage.getTag().equals( "BungeeCord" ) )
|
||||
{
|
||||
ByteArrayDataOutput out = ByteStreams.newDataOutput();
|
||||
String subChannel = in.readUTF();
|
||||
@@ -265,20 +255,29 @@ public class DownstreamBridge extends PacketHandler
|
||||
}
|
||||
if ( subChannel.equals( "PlayerCount" ) )
|
||||
{
|
||||
ServerInfo server = bungee.getServerInfo( in.readUTF() );
|
||||
String target = in.readUTF();
|
||||
out.writeUTF( "PlayerCount" );
|
||||
if ( target.equals( "ALL" ) )
|
||||
{
|
||||
out.writeUTF( "ALL" );
|
||||
out.writeInt( bungee.getOnlineCount() );
|
||||
} else
|
||||
{
|
||||
ServerInfo server = bungee.getServerInfo( target );
|
||||
if ( server != null )
|
||||
{
|
||||
out.writeUTF( "PlayerCount" );
|
||||
out.writeUTF( server.getName() );
|
||||
out.writeInt( server.getPlayers().size() );
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( subChannel.equals( "PlayerList" ) )
|
||||
{
|
||||
String target = in.readUTF();
|
||||
out.writeUTF( "PlayerList" );
|
||||
if ( target.equals( "ALL" ) )
|
||||
{
|
||||
out.writeUTF( "ALL" );
|
||||
out.writeUTF( Util.csv( bungee.getPlayers() ) );
|
||||
} else
|
||||
{
|
||||
@@ -329,13 +328,13 @@ public class DownstreamBridge extends PacketHandler
|
||||
{
|
||||
def = null;
|
||||
}
|
||||
ServerKickEvent event = bungee.getPluginManager().callEvent( new ServerKickEvent( con, kick.message, def ) );
|
||||
ServerKickEvent event = bungee.getPluginManager().callEvent( new ServerKickEvent( con, kick.getMessage(), def ) );
|
||||
if ( event.isCancelled() && event.getCancelServer() != null )
|
||||
{
|
||||
con.connectNow( event.getCancelServer() );
|
||||
} else
|
||||
{
|
||||
con.disconnect( "[Kicked] " + event.getKickReason() );
|
||||
con.disconnect( bungee.getTranslation( "server_kick" ) + event.getKickReason() );
|
||||
}
|
||||
server.setObsolete( true );
|
||||
throw new CancelSendSignal();
|
||||
|
@@ -10,12 +10,14 @@ import java.security.GeneralSecurityException;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.SecretKey;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.md_5.bungee.BungeeCord;
|
||||
import net.md_5.bungee.EncryptionUtil;
|
||||
import net.md_5.bungee.PacketConstants;
|
||||
import net.md_5.bungee.UserConnection;
|
||||
import net.md_5.bungee.Util;
|
||||
import net.md_5.bungee.api.Callback;
|
||||
@@ -29,17 +31,24 @@ import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.LoginEvent;
|
||||
import net.md_5.bungee.api.event.PostLoginEvent;
|
||||
import net.md_5.bungee.api.event.ProxyPingEvent;
|
||||
import net.md_5.bungee.netty.CipherCodec;
|
||||
import net.md_5.bungee.netty.HandlerBoss;
|
||||
import net.md_5.bungee.netty.ChannelWrapper;
|
||||
import net.md_5.bungee.packet.Packet2Handshake;
|
||||
import net.md_5.bungee.packet.PacketCDClientStatus;
|
||||
import net.md_5.bungee.packet.PacketFAPluginMessage;
|
||||
import net.md_5.bungee.packet.PacketFCEncryptionResponse;
|
||||
import net.md_5.bungee.packet.PacketFDEncryptionRequest;
|
||||
import net.md_5.bungee.packet.PacketFEPing;
|
||||
import net.md_5.bungee.packet.PacketFFKick;
|
||||
import net.md_5.bungee.packet.PacketHandler;
|
||||
import net.md_5.bungee.netty.CipherDecoder;
|
||||
import net.md_5.bungee.netty.CipherEncoder;
|
||||
import net.md_5.bungee.netty.PacketDecoder;
|
||||
import net.md_5.bungee.netty.PacketHandler;
|
||||
import net.md_5.bungee.netty.PipelineUtils;
|
||||
import net.md_5.bungee.protocol.Forge;
|
||||
import net.md_5.bungee.protocol.Vanilla;
|
||||
import net.md_5.bungee.protocol.packet.DefinedPacket;
|
||||
import net.md_5.bungee.protocol.packet.Packet1Login;
|
||||
import net.md_5.bungee.protocol.packet.Packet2Handshake;
|
||||
import net.md_5.bungee.protocol.packet.PacketCDClientStatus;
|
||||
import net.md_5.bungee.protocol.packet.PacketFAPluginMessage;
|
||||
import net.md_5.bungee.protocol.packet.PacketFCEncryptionResponse;
|
||||
import net.md_5.bungee.protocol.packet.PacketFDEncryptionRequest;
|
||||
import net.md_5.bungee.protocol.packet.PacketFEPing;
|
||||
import net.md_5.bungee.protocol.packet.PacketFFKick;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
@@ -50,12 +59,24 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
@Getter
|
||||
private final ListenerInfo listener;
|
||||
@Getter
|
||||
private Packet1Login forgeLogin;
|
||||
@Getter
|
||||
private Packet2Handshake handshake;
|
||||
private PacketFDEncryptionRequest request;
|
||||
@Getter
|
||||
private List<PacketFAPluginMessage> loginMessages = new ArrayList<>();
|
||||
@Getter
|
||||
private List<PacketFAPluginMessage> registerMessages = new ArrayList<>();
|
||||
private State thisState = State.HANDSHAKE;
|
||||
private SecretKey sharedKey;
|
||||
private boolean disconnected;
|
||||
private final Unsafe unsafe = new Unsafe()
|
||||
{
|
||||
@Override
|
||||
public void sendPacket(DefinedPacket packet)
|
||||
{
|
||||
ch.write( packet );
|
||||
}
|
||||
};
|
||||
|
||||
private enum State
|
||||
{
|
||||
@@ -77,15 +98,22 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
|
||||
@Override
|
||||
public void handle(PacketFAPluginMessage pluginMessage) throws Exception
|
||||
{
|
||||
// TODO: Unregister?
|
||||
if ( pluginMessage.getTag().equals( "REGISTER" ) )
|
||||
{
|
||||
registerMessages.add( pluginMessage );
|
||||
} else
|
||||
{
|
||||
loginMessages.add( pluginMessage );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(PacketFEPing ping) throws Exception
|
||||
{
|
||||
ServerPing response = new ServerPing( bungee.getProtocolVersion(), bungee.getGameVersion(),
|
||||
listener.getMotd(), bungee.getPlayers().size(), listener.getMaxPlayers() );
|
||||
listener.getMotd(), bungee.getOnlineCount(), listener.getMaxPlayers() );
|
||||
|
||||
response = bungee.getPluginManager().callEvent( new ProxyPingEvent( this, response ) ).getResponse();
|
||||
|
||||
@@ -98,21 +126,54 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
disconnect( kickMessage );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Packet1Login login) throws Exception
|
||||
{
|
||||
Preconditions.checkState( thisState == State.LOGIN, "Not expecting FORGE LOGIN" );
|
||||
Preconditions.checkState( forgeLogin == null, "Already received FORGE LOGIN" );
|
||||
forgeLogin = login;
|
||||
|
||||
ch.getHandle().pipeline().get( PacketDecoder.class ).setProtocol( Forge.getInstance() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Packet2Handshake handshake) throws Exception
|
||||
{
|
||||
Preconditions.checkState( thisState == State.HANDSHAKE, "Not expecting HANDSHAKE" );
|
||||
if ( handshake.username.length() > 16 )
|
||||
this.handshake = handshake;
|
||||
bungee.getLogger().log( Level.INFO, "{0} has connected", this );
|
||||
|
||||
if ( handshake.getProcolVersion() > Vanilla.PROTOCOL_VERSION )
|
||||
{
|
||||
disconnect( "Outdated server!" );
|
||||
} else if ( handshake.getProcolVersion() < Vanilla.PROTOCOL_VERSION )
|
||||
{
|
||||
disconnect( "Outdated client!" );
|
||||
}
|
||||
|
||||
if ( handshake.getUsername().length() > 16 )
|
||||
{
|
||||
disconnect( "Cannot have username longer than 16 characters" );
|
||||
return;
|
||||
}
|
||||
|
||||
int limit = BungeeCord.getInstance().config.getPlayerLimit();
|
||||
Preconditions.checkState( limit <= 0 || bungee.getPlayers().size() < limit, "Server is full!" );
|
||||
if ( limit > 0 && bungee.getOnlineCount() > limit )
|
||||
{
|
||||
disconnect( bungee.getTranslation( "proxy_full" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
this.handshake = handshake;
|
||||
ch.write( request = EncryptionUtil.encryptRequest() );
|
||||
// If offline mode and they are already on, don't allow connect
|
||||
if ( !BungeeCord.getInstance().config.isOnlineMode() && bungee.getPlayer( handshake.getUsername() ) != null )
|
||||
{
|
||||
disconnect( bungee.getTranslation( "already_connected" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
unsafe().sendPacket( PacketConstants.I_AM_BUNGEE );
|
||||
unsafe().sendPacket( PacketConstants.FORGE_MOD_REQUEST );
|
||||
unsafe().sendPacket( request = EncryptionUtil.encryptRequest() );
|
||||
thisState = State.ENCRYPT;
|
||||
}
|
||||
|
||||
@@ -122,6 +183,9 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
Preconditions.checkState( thisState == State.ENCRYPT, "Not expecting ENCRYPT" );
|
||||
|
||||
sharedKey = EncryptionUtil.getSecret( encryptResponse, request );
|
||||
Cipher decrypt = EncryptionUtil.getCipher( Cipher.DECRYPT_MODE, sharedKey );
|
||||
ch.getHandle().pipeline().addBefore( PipelineUtils.PACKET_DECODE_HANDLER, PipelineUtils.DECRYPT_HANDLER, new CipherDecoder( decrypt ) );
|
||||
|
||||
if ( BungeeCord.getInstance().config.isOnlineMode() )
|
||||
{
|
||||
String encName = URLEncoder.encode( InitialHandler.this.getName(), "UTF-8" );
|
||||
@@ -129,7 +193,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
MessageDigest sha = MessageDigest.getInstance( "SHA-1" );
|
||||
for ( byte[] bit : new byte[][]
|
||||
{
|
||||
request.serverId.getBytes( "ISO_8859_1" ), sharedKey.getEncoded(), EncryptionUtil.keys.getPublic().getEncoded()
|
||||
request.getServerId().getBytes( "ISO_8859_1" ), sharedKey.getEncoded(), EncryptionUtil.keys.getPublic().getEncoded()
|
||||
} )
|
||||
{
|
||||
sha.update( bit );
|
||||
@@ -155,7 +219,8 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
@Override
|
||||
public void onThrowable(Throwable t)
|
||||
{
|
||||
disconnect( "Error occured while contacting login servers, are they down?" + Util.exception( t ) );
|
||||
disconnect( bungee.getTranslation( "mojang_fail" ) );
|
||||
bungee.getLogger().log( Level.SEVERE, "Error authenticating " + getName() + " with minecraft.net", t );
|
||||
}
|
||||
} );
|
||||
} else
|
||||
@@ -167,10 +232,10 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
private void finish() throws GeneralSecurityException
|
||||
{
|
||||
// Check for multiple connections
|
||||
ProxiedPlayer old = bungee.getPlayer( handshake.username );
|
||||
ProxiedPlayer old = bungee.getPlayer( handshake.getUsername() );
|
||||
if ( old != null )
|
||||
{
|
||||
old.disconnect( "You are already connected to the server" );
|
||||
old.disconnect( bungee.getTranslation( "already_connected" ) );
|
||||
}
|
||||
|
||||
Callback<LoginEvent> complete = new Callback<LoginEvent>()
|
||||
@@ -182,23 +247,29 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
{
|
||||
disconnect( result.getCancelReason() );
|
||||
}
|
||||
if ( disconnected )
|
||||
if ( ch.isClosed() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
thisState = InitialHandler.State.LOGIN;
|
||||
|
||||
ch.getHandle().eventLoop().execute( new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
unsafe().sendPacket( new PacketFCEncryptionResponse( new byte[ 0 ], new byte[ 0 ] ) );
|
||||
try
|
||||
{
|
||||
Cipher encrypt = EncryptionUtil.getCipher( Cipher.ENCRYPT_MODE, sharedKey );
|
||||
Cipher decrypt = EncryptionUtil.getCipher( Cipher.DECRYPT_MODE, sharedKey );
|
||||
ch.write( new PacketFCEncryptionResponse() );
|
||||
ch.getHandle().pipeline().addBefore( "decoder", "cipher", new CipherCodec( encrypt, decrypt ) );
|
||||
thisState = InitialHandler.State.LOGIN;
|
||||
ch.getHandle().pipeline().addBefore( PipelineUtils.DECRYPT_HANDLER, PipelineUtils.ENCRYPT_HANDLER, new CipherEncoder( encrypt ) );
|
||||
} catch ( GeneralSecurityException ex )
|
||||
{
|
||||
disconnect( "Cipher error: " + Util.exception( ex ) );
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
};
|
||||
|
||||
// fire login event
|
||||
@@ -227,30 +298,29 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
@Override
|
||||
public synchronized void disconnect(String reason)
|
||||
{
|
||||
if ( ch.getHandle().isActive() )
|
||||
if ( !ch.isClosed() )
|
||||
{
|
||||
ch.write( new PacketFFKick( reason ) );
|
||||
ch.getHandle().close();
|
||||
disconnected = true;
|
||||
unsafe().sendPacket( new PacketFFKick( reason ) );
|
||||
ch.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName()
|
||||
{
|
||||
return ( handshake == null ) ? null : handshake.username;
|
||||
return ( handshake == null ) ? null : handshake.getUsername();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getVersion()
|
||||
{
|
||||
return ( handshake == null ) ? -1 : handshake.procolVersion;
|
||||
return ( handshake == null ) ? -1 : handshake.getProcolVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetSocketAddress getVirtualHost()
|
||||
{
|
||||
return ( handshake == null ) ? null : new InetSocketAddress( handshake.host, handshake.port );
|
||||
return ( handshake == null ) ? null : new InetSocketAddress( handshake.getHost(), handshake.getPort() );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -259,6 +329,12 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
return (InetSocketAddress) ch.getHandle().remoteAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Unsafe unsafe()
|
||||
{
|
||||
return unsafe;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
|
@@ -5,8 +5,8 @@ import net.md_5.bungee.api.Callback;
|
||||
import net.md_5.bungee.api.ServerPing;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.netty.ChannelWrapper;
|
||||
import net.md_5.bungee.packet.PacketFFKick;
|
||||
import net.md_5.bungee.packet.PacketHandler;
|
||||
import net.md_5.bungee.netty.PacketHandler;
|
||||
import net.md_5.bungee.protocol.packet.PacketFFKick;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class PingHandler extends PacketHandler
|
||||
@@ -34,7 +34,7 @@ public class PingHandler extends PacketHandler
|
||||
@Override
|
||||
public void handle(PacketFFKick kick) throws Exception
|
||||
{
|
||||
String[] split = kick.message.split( "\00" );
|
||||
String[] split = kick.getMessage().split( "\00" );
|
||||
ServerPing ping = new ServerPing( Byte.parseByte( split[1] ), split[2], split[3], Integer.parseInt( split[4] ), Integer.parseInt( split[5] ) );
|
||||
callback.done( ping, null );
|
||||
}
|
||||
|
@@ -1,7 +1,5 @@
|
||||
package net.md_5.bungee.connection;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.md_5.bungee.BungeeCord;
|
||||
import net.md_5.bungee.EntityMap;
|
||||
import net.md_5.bungee.UserConnection;
|
||||
@@ -12,11 +10,11 @@ import net.md_5.bungee.api.event.ChatEvent;
|
||||
import net.md_5.bungee.api.event.PlayerDisconnectEvent;
|
||||
import net.md_5.bungee.api.event.PluginMessageEvent;
|
||||
import net.md_5.bungee.netty.ChannelWrapper;
|
||||
import net.md_5.bungee.packet.Packet0KeepAlive;
|
||||
import net.md_5.bungee.packet.Packet3Chat;
|
||||
import net.md_5.bungee.packet.PacketCCSettings;
|
||||
import net.md_5.bungee.packet.PacketFAPluginMessage;
|
||||
import net.md_5.bungee.packet.PacketHandler;
|
||||
import net.md_5.bungee.netty.PacketHandler;
|
||||
import net.md_5.bungee.protocol.packet.Packet0KeepAlive;
|
||||
import net.md_5.bungee.protocol.packet.Packet3Chat;
|
||||
import net.md_5.bungee.protocol.packet.PacketCCSettings;
|
||||
import net.md_5.bungee.protocol.packet.PacketFAPluginMessage;
|
||||
|
||||
public class UpstreamBridge extends PacketHandler
|
||||
{
|
||||
@@ -29,14 +27,14 @@ public class UpstreamBridge extends PacketHandler
|
||||
this.bungee = bungee;
|
||||
this.con = con;
|
||||
|
||||
BungeeCord.getInstance().connections.put( con.getName(), con );
|
||||
bungee.getTabListHandler().onConnect( con );
|
||||
con.sendPacket( BungeeCord.getInstance().registerChannels() );
|
||||
BungeeCord.getInstance().addConnection( con );
|
||||
con.getTabList().onConnect();
|
||||
con.unsafe().sendPacket( BungeeCord.getInstance().registerChannels() );
|
||||
|
||||
TexturePackInfo texture = con.getPendingConnection().getListener().getTexturePack();
|
||||
if ( texture != null )
|
||||
{
|
||||
con.sendPacket( new PacketFAPluginMessage( "MC|TPack", ( texture.getUrl() + "\00" + texture.getSize() ).getBytes() ) );
|
||||
con.setTexturePack( texture );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,8 +50,8 @@ public class UpstreamBridge extends PacketHandler
|
||||
// We lost connection to the client
|
||||
PlayerDisconnectEvent event = new PlayerDisconnectEvent( con );
|
||||
bungee.getPluginManager().callEvent( event );
|
||||
bungee.getTabListHandler().onDisconnect( con );
|
||||
BungeeCord.getInstance().connections.remove( con.getName() ); //TODO: Better way, why do we need to raw access?
|
||||
con.getTabList().onDisconnect();
|
||||
BungeeCord.getInstance().removeConnection( con );
|
||||
|
||||
if ( con.getServer() != null )
|
||||
{
|
||||
@@ -74,10 +72,10 @@ public class UpstreamBridge extends PacketHandler
|
||||
@Override
|
||||
public void handle(Packet0KeepAlive alive) throws Exception
|
||||
{
|
||||
if ( alive.id == con.getSentPingId() )
|
||||
if ( alive.getRandomId() == con.getSentPingId() )
|
||||
{
|
||||
int newPing = (int) ( System.currentTimeMillis() - con.getSentPingTime() );
|
||||
bungee.getTabListHandler().onPingChange( con, newPing );
|
||||
con.getTabList().onPingChange( newPing );
|
||||
con.setPing( newPing );
|
||||
}
|
||||
}
|
||||
@@ -85,14 +83,14 @@ public class UpstreamBridge extends PacketHandler
|
||||
@Override
|
||||
public void handle(Packet3Chat chat) throws Exception
|
||||
{
|
||||
ChatEvent chatEvent = new ChatEvent( con, con.getServer(), chat.message );
|
||||
ChatEvent chatEvent = new ChatEvent( con, con.getServer(), chat.getMessage() );
|
||||
if ( bungee.getPluginManager().callEvent( chatEvent ).isCancelled() )
|
||||
{
|
||||
throw new CancelSendSignal();
|
||||
}
|
||||
if ( chatEvent.isCommand() )
|
||||
{
|
||||
if ( bungee.getPluginManager().dispatchCommand( con, chat.message.substring( 1 ) ) )
|
||||
if ( bungee.getPluginManager().dispatchCommand( con, chat.getMessage().substring( 1 ) ) )
|
||||
{
|
||||
throw new CancelSendSignal();
|
||||
}
|
||||
@@ -108,16 +106,27 @@ public class UpstreamBridge extends PacketHandler
|
||||
@Override
|
||||
public void handle(PacketFAPluginMessage pluginMessage) throws Exception
|
||||
{
|
||||
if ( pluginMessage.tag.equals( "BungeeCord" ) )
|
||||
if ( pluginMessage.getTag().equals( "BungeeCord" ) )
|
||||
{
|
||||
throw new CancelSendSignal();
|
||||
}
|
||||
// Hack around Forge race conditions
|
||||
if ( pluginMessage.getTag().equals( "FML" ) && ( pluginMessage.getData()[0] & 0xFF ) == 1 )
|
||||
{
|
||||
throw new CancelSendSignal();
|
||||
}
|
||||
|
||||
PluginMessageEvent event = new PluginMessageEvent( con, con.getServer(), pluginMessage.tag, pluginMessage.data.clone() );
|
||||
PluginMessageEvent event = new PluginMessageEvent( con, con.getServer(), pluginMessage.getTag(), pluginMessage.getData().clone() );
|
||||
if ( bungee.getPluginManager().callEvent( event ).isCancelled() )
|
||||
{
|
||||
throw new CancelSendSignal();
|
||||
}
|
||||
|
||||
// TODO: Unregister as well?
|
||||
if ( pluginMessage.getTag().equals( "REGISTER" ) )
|
||||
{
|
||||
con.getPendingConnection().getRegisterMessages().add( pluginMessage );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
48
proxy/src/main/java/net/md_5/bungee/log/BungeeLogger.java
Normal file
48
proxy/src/main/java/net/md_5/bungee/log/BungeeLogger.java
Normal file
@@ -0,0 +1,48 @@
|
||||
package net.md_5.bungee.log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.logging.FileHandler;
|
||||
import java.util.logging.Formatter;
|
||||
import java.util.logging.LogRecord;
|
||||
import java.util.logging.Logger;
|
||||
import net.md_5.bungee.BungeeCord;
|
||||
|
||||
public class BungeeLogger extends Logger
|
||||
{
|
||||
|
||||
private final BungeeCord bungee;
|
||||
private final ColouredWriter writer;
|
||||
private final Formatter formatter = new ConciseFormatter();
|
||||
private final LogDispatcher dispatcher = new LogDispatcher( this );
|
||||
|
||||
public BungeeLogger(BungeeCord bungee)
|
||||
{
|
||||
super( "BungeeCord", null );
|
||||
this.bungee = bungee;
|
||||
this.writer = new ColouredWriter( bungee.getConsoleReader() );
|
||||
|
||||
try
|
||||
{
|
||||
FileHandler handler = new FileHandler( "proxy.log", 1 << 24, 8, true );
|
||||
handler.setFormatter( formatter );
|
||||
addHandler( handler );
|
||||
} catch ( IOException ex )
|
||||
{
|
||||
System.err.println( "Could not register logger!" );
|
||||
ex.printStackTrace();
|
||||
}
|
||||
dispatcher.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(LogRecord record)
|
||||
{
|
||||
dispatcher.queue( record );
|
||||
}
|
||||
|
||||
void doLog(LogRecord record)
|
||||
{
|
||||
super.log( record );
|
||||
writer.print( formatter.format( record ) );
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user