From 9a420b74d579c0bed97250f0b158b7384280a772 Mon Sep 17 00:00:00 2001 From: Minecrell Date: Sun, 21 Sep 2014 19:07:16 +0200 Subject: [PATCH] Add server status ping API. Merges #367, closes #331 --- src/main/java/org/spongepowered/api/Game.java | 7 + .../org/spongepowered/api/GameRegistry.java | 46 +++++++ .../org/spongepowered/api/GameVersion.java | 45 +++++++ .../java/org/spongepowered/api/Server.java | 14 +- .../spongepowered/api/entity/player/User.java | 11 +- .../api/event/server/StatusPingEvent.java | 120 ++++++++++++++++++ .../org/spongepowered/api/status/Favicon.java | 52 ++++++++ .../api/status/PlayerProfile.java | 41 ++++++ .../api/status/StatusClient.java | 72 +++++++++++ .../api/status/StatusResponse.java | 107 ++++++++++++++++ 10 files changed, 503 insertions(+), 12 deletions(-) create mode 100644 src/main/java/org/spongepowered/api/GameVersion.java create mode 100644 src/main/java/org/spongepowered/api/event/server/StatusPingEvent.java create mode 100644 src/main/java/org/spongepowered/api/status/Favicon.java create mode 100644 src/main/java/org/spongepowered/api/status/PlayerProfile.java create mode 100644 src/main/java/org/spongepowered/api/status/StatusClient.java create mode 100644 src/main/java/org/spongepowered/api/status/StatusResponse.java diff --git a/src/main/java/org/spongepowered/api/Game.java b/src/main/java/org/spongepowered/api/Game.java index 1f780b74711..ee91a381735 100644 --- a/src/main/java/org/spongepowered/api/Game.java +++ b/src/main/java/org/spongepowered/api/Game.java @@ -112,4 +112,11 @@ public interface Game { */ String getImplementationVersion(); + /** + * Gets the version of this game. + * + * @return The game version + */ + GameVersion getVersion(); + } diff --git a/src/main/java/org/spongepowered/api/GameRegistry.java b/src/main/java/org/spongepowered/api/GameRegistry.java index b52c4166502..08eeb740ead 100644 --- a/src/main/java/org/spongepowered/api/GameRegistry.java +++ b/src/main/java/org/spongepowered/api/GameRegistry.java @@ -48,9 +48,15 @@ import org.spongepowered.api.item.merchant.TradeOfferBuilder; import org.spongepowered.api.potion.PotionEffectBuilder; import org.spongepowered.api.potion.PotionEffectType; +import org.spongepowered.api.status.Favicon; import org.spongepowered.api.world.DimensionType; import org.spongepowered.api.world.biome.BiomeType; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; import java.util.Collection; import java.util.List; @@ -383,4 +389,44 @@ public interface GameRegistry { */ List getDimensionTypes(); + // TODO: Find a better place for these methods + + /** + * Loads a {@link Favicon} from the specified encoded string. The format of + * the input depends on the implementation. + * + * @param raw The encoded favicon + * @return The loaded favicon + * @throws IOException If the favicon couldn't be loaded + */ + Favicon loadFavicon(String raw) throws IOException; + + /** + * Loads a favicon from a specified {@link File}. + * + * @param file The favicon file + * @return The loaded favicon from the file + * @throws IOException If the favicon couldn't be loaded + * @throws FileNotFoundException If the file doesn't exist + */ + Favicon loadFavicon(File file) throws IOException; + + /** + * Loads a favicon from a specified {@link URL}. + * + * @param url The favicon URL + * @return The loaded favicon from the URL + * @throws IOException If the favicon couldn't be loaded + */ + Favicon loadFavicon(URL url) throws IOException; + + /** + * Loads a favicon from a specified {@link InputStream}. + * + * @param in The favicon input stream + * @return The loaded favicon from the input stream + * @throws IOException If the favicon couldn't be loaded + */ + Favicon loadFavicon(InputStream in) throws IOException; + } diff --git a/src/main/java/org/spongepowered/api/GameVersion.java b/src/main/java/org/spongepowered/api/GameVersion.java new file mode 100644 index 00000000000..4dfb8964cc8 --- /dev/null +++ b/src/main/java/org/spongepowered/api/GameVersion.java @@ -0,0 +1,45 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered.org + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.api; + +/** + * Represents a specific game version of a client or a server. + */ +public interface GameVersion extends Comparable { + + /** + * Gets the name of this game version. + * + *

+ * Note: The returned name does not necessarily represent + * the name of a Minecraft version. Depending on the client and + * implementation, this may also just return a numeric value. + *

+ * + * @return The version name + */ + String getName(); + +} diff --git a/src/main/java/org/spongepowered/api/Server.java b/src/main/java/org/spongepowered/api/Server.java index 5b70cb047f8..e53868ce71a 100644 --- a/src/main/java/org/spongepowered/api/Server.java +++ b/src/main/java/org/spongepowered/api/Server.java @@ -26,11 +26,17 @@ import com.google.common.base.Optional; import org.spongepowered.api.entity.player.Player; +import org.spongepowered.api.status.Favicon; import org.spongepowered.api.text.message.Message; import org.spongepowered.api.world.World; import org.spongepowered.api.world.gen.WorldGenerator; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; import java.net.InetSocketAddress; +import java.net.URL; import java.util.Collection; import java.util.UUID; @@ -197,9 +203,11 @@ public interface Server { boolean getOnlineMode(); /** - * Gets the message that is displayed in the server list of the client. - * @return The servers MOTD + * Gets the default message that is displayed in the server list of the + * client. + * + * @return The server's default description (MOTD) */ - Message getMOTD(); + Message getMotd(); } diff --git a/src/main/java/org/spongepowered/api/entity/player/User.java b/src/main/java/org/spongepowered/api/entity/player/User.java index 81a58fb5bd2..6c22ae2c55a 100644 --- a/src/main/java/org/spongepowered/api/entity/player/User.java +++ b/src/main/java/org/spongepowered/api/entity/player/User.java @@ -28,7 +28,7 @@ import com.google.common.base.Optional; import org.spongepowered.api.entity.ArmorEquipable; import org.spongepowered.api.service.persistence.DataSerializable; -import org.spongepowered.api.util.Identifiable; +import org.spongepowered.api.status.PlayerProfile; import java.util.Date; @@ -36,14 +36,7 @@ * A User is the data usually associated with a Player that is persisted across server restarts. * This is in contrast to Player which represents the ingame entity associated with an online User. */ -public interface User extends Identifiable, ArmorEquipable, DataSerializable { - - /** - * Gets the player's last known username. - * - * @return The player's last known username - */ - String getName(); +public interface User extends PlayerProfile, ArmorEquipable, DataSerializable { /** * Checks if this player has joined the server before. diff --git a/src/main/java/org/spongepowered/api/event/server/StatusPingEvent.java b/src/main/java/org/spongepowered/api/event/server/StatusPingEvent.java new file mode 100644 index 00000000000..a74f3bd693d --- /dev/null +++ b/src/main/java/org/spongepowered/api/event/server/StatusPingEvent.java @@ -0,0 +1,120 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered.org + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.api.event.server; + +import com.google.common.base.Optional; +import org.spongepowered.api.event.GameEvent; +import org.spongepowered.api.status.Favicon; +import org.spongepowered.api.status.PlayerProfile; +import org.spongepowered.api.status.StatusClient; +import org.spongepowered.api.status.StatusResponse; +import org.spongepowered.api.text.message.Message; +import org.spongepowered.api.util.event.Cancellable; + +import java.util.List; + +import javax.annotation.Nullable; + +/** + * Called when a client pings the server from the server list. + *

+ * If this event gets cancelled, it will close the client connection without + * sending any response. + *

+ */ +public interface StatusPingEvent extends GameEvent, Cancellable, StatusResponse { + + /** + * Gets the client pinging the server. + * + * @return The client of the status request + */ + StatusClient getClient(); + + /** + * Sets the description (MOTD) of the status response. + * + * @param description The description to display + */ + void setDescription(Message description); + + @Override + Optional getPlayers(); + + /** + * Sets whether the player count and the list of players on this server is + * hidden and doesn't get sent to the client. This will restore + * {@link #getPlayers()} if the players were previously hidden. + *

+ * Use {@link #getPlayers()}.{@link Optional#isPresent() isPresent()} to + * check if the players are already hidden. + *

+ *

+ * In Vanilla, this will display {@code ???} instead of the player count in + * the server list. + *

+ * + * @param hide {@code True} if the players should be hidden + */ + void setHidePlayers(boolean hide); + + /** + * Represents the information about the players on the server, sent after + * the {@link StatusPingEvent}. + */ + interface Players extends StatusResponse.Players { + + /** + * Sets the amount of online players to display on the client. + * + * @param online The amount of online players + */ + void setOnline(int online); + + /** + * Sets the maximum amount of allowed players to display on the client. + * + * @param max The maximum amount of players + */ + void setMax(int max); + + /** + * Gets an mutable list of online players on the server to display on + * the client. + * + * @return A mutable list of online players + */ + @Override + List getPlayers(); + } + + /** + * Sets the {@link Favicon} to display on the client. + * + * @param favicon The favicon, or {@code null} for none + */ + void setFavicon(@Nullable Favicon favicon); + +} diff --git a/src/main/java/org/spongepowered/api/status/Favicon.java b/src/main/java/org/spongepowered/api/status/Favicon.java new file mode 100644 index 00000000000..6c65bffaebd --- /dev/null +++ b/src/main/java/org/spongepowered/api/status/Favicon.java @@ -0,0 +1,52 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered.org + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.api.status; + +import org.spongepowered.api.Server; + +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.InputStream; +import java.net.URL; + +/** + * Represents an icon for the server sent in the {@link StatusResponse}. It can + * be loaded by calling one of the {@code loadFavicon} methods on {@link Server} + * . + * + * @see Server#loadFavicon(String) + * @see Server#loadFavicon(File) + * @see Server#loadFavicon(URL) + * @see Server#loadFavicon(InputStream) + */ +public interface Favicon { + + /** + * Gets the decoded image of this favicon. + * + * @return The decoded image + */ + BufferedImage getImage(); +} diff --git a/src/main/java/org/spongepowered/api/status/PlayerProfile.java b/src/main/java/org/spongepowered/api/status/PlayerProfile.java new file mode 100644 index 00000000000..6b48098d181 --- /dev/null +++ b/src/main/java/org/spongepowered/api/status/PlayerProfile.java @@ -0,0 +1,41 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered.org + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.api.status; + +import org.spongepowered.api.util.Identifiable; + +/** + * Holds basic player information about a player for the {@link StatusResponse}. + */ +public interface PlayerProfile extends Identifiable { + + /** + * Gets the player's last known username. + * + * @return The player's last known username + */ + String getName(); + +} diff --git a/src/main/java/org/spongepowered/api/status/StatusClient.java b/src/main/java/org/spongepowered/api/status/StatusClient.java new file mode 100644 index 00000000000..635258fd5ce --- /dev/null +++ b/src/main/java/org/spongepowered/api/status/StatusClient.java @@ -0,0 +1,72 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered.org + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.api.status; + +import com.google.common.base.Optional; +import org.spongepowered.api.GameVersion; + +import java.net.InetSocketAddress; + +/** + * Represents a client requesting a {@link StatusResponse}. Unlike normal player + * connections, it may not have the same version as the server. + */ +public interface StatusClient { + + /** + * Gets the address of the client. + * + * @return The address of the client + */ + InetSocketAddress getAddress(); + + /** + * Gets the game version of the client. + * + * @return The version of the client + */ + GameVersion getVersion(); + + /** + * Gets the address the player is connecting to. + * + * @return The address the player is connecting to, or + * {@link Optional#absent()} if not available (for example because + * of {@link #isLegacy()}). + */ + Optional getVirtualHost(); + + /** + * Returns whether the client is using an older version that doesn't support + * all of the features in {@link StatusResponse}. + *

+ * For Vanilla, this returns {@code true} for all clients older than 1.7. + *

+ * + * @return {@code True} if the client is using an older version + */ + boolean isLegacy(); + +} diff --git a/src/main/java/org/spongepowered/api/status/StatusResponse.java b/src/main/java/org/spongepowered/api/status/StatusResponse.java new file mode 100644 index 00000000000..ef3006ab723 --- /dev/null +++ b/src/main/java/org/spongepowered/api/status/StatusResponse.java @@ -0,0 +1,107 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered.org + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.spongepowered.api.status; + +import com.google.common.base.Optional; +import org.spongepowered.api.GameVersion; +import org.spongepowered.api.event.server.StatusPingEvent; +import org.spongepowered.api.text.message.Message; + +import java.util.List; + +/** + * Represents the response to a status request. Unlike {@link StatusPingEvent} + * this is immutable. + *

+ * This interface exists mostly for convenience and can be implemented in a + * library pinging other servers for example. + *

+ * + * @see StatusPingEvent + */ +public interface StatusResponse { + + /** + * Gets the description (MOTD) of the status response. + * + * @return The description to display + */ + Message getDescription(); + + /** + * Gets player count and the list of players currently playing on the + * server. + * + * @return The player information, or {@link Optional#absent()} if not + * available + */ + Optional getPlayers(); + + /** + * Gets the version of the server displayed when the client or the server + * are outdated. + * + * @return The server version + */ + GameVersion getVersion(); + + /** + * Represents the player count, slots and a list of players current playing + * on a server. + */ + interface Players { + + /** + * Gets the amount of online players on the server. + * + * @return The amount of online players + */ + int getOnline(); + + /** + * Gets the maximum amount of allowed players on the server. + * + * @return The maximum amount of allowed players + */ + int getMax(); + + /** + * Gets an immutable list of online players on the server to display on + * the client. + * + * @return An immutable list of online players + */ + List getPlayers(); + + } + + /** + * Gets the {@link Favicon} of the server. + * + * @return The favicon, or {@link Optional#absent()} if not available + */ + Optional getFavicon(); + +}