Implement Favicon API
This commit is contained in:
parent
3ced0b675d
commit
18316eb5f8
105
api/src/main/java/net/md_5/bungee/api/Favicon.java
Normal file
105
api/src/main/java/net/md_5/bungee/api/Favicon.java
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
package net.md_5.bungee.api;
|
||||||
|
|
||||||
|
import com.google.common.io.BaseEncoding;
|
||||||
|
import com.google.gson.TypeAdapter;
|
||||||
|
import com.google.gson.internal.bind.TypeAdapters;
|
||||||
|
import com.google.gson.stream.JsonReader;
|
||||||
|
import com.google.gson.stream.JsonWriter;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Favicon shown in the server list.
|
||||||
|
*/
|
||||||
|
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
public class Favicon
|
||||||
|
{
|
||||||
|
|
||||||
|
private static final TypeAdapter<Favicon> FAVICON_TYPE_ADAPTER = new TypeAdapter<Favicon>()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void write(JsonWriter out, Favicon value) throws IOException
|
||||||
|
{
|
||||||
|
TypeAdapters.STRING.write( out, value.getEncoded() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Favicon read(JsonReader in) throws IOException
|
||||||
|
{
|
||||||
|
return create( TypeAdapters.STRING.read( in ) );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static TypeAdapter<Favicon> getFaviconTypeAdapter()
|
||||||
|
{
|
||||||
|
return FAVICON_TYPE_ADAPTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base64 encoded favicon, including MIME header.
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
private final String encoded;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a favicon from an image.
|
||||||
|
*
|
||||||
|
* @param image the image to create on
|
||||||
|
* @return the created favicon instance
|
||||||
|
* @throws IllegalArgumentException if the favicon is larger than
|
||||||
|
* {@link Short#MAX_VALUE} or not of dimensions 64x64 pixels.
|
||||||
|
*/
|
||||||
|
public static Favicon create(BufferedImage image)
|
||||||
|
{
|
||||||
|
// check size
|
||||||
|
if ( image.getWidth() != 64 || image.getHeight() != 64 )
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException( "Server icon must be exactly 64x64 pixels" );
|
||||||
|
}
|
||||||
|
|
||||||
|
// dump image PNG
|
||||||
|
byte[] imageBytes;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||||
|
ImageIO.write( image, "PNG", stream );
|
||||||
|
imageBytes = stream.toByteArray();
|
||||||
|
} catch ( IOException e )
|
||||||
|
{
|
||||||
|
// ByteArrayOutputStream should never throw this
|
||||||
|
throw new AssertionError( e );
|
||||||
|
}
|
||||||
|
|
||||||
|
// encode with header
|
||||||
|
String encoded = "data:image/png;base64," + BaseEncoding.base64().encode( imageBytes );
|
||||||
|
|
||||||
|
// check encoded image size
|
||||||
|
if ( encoded.length() > Short.MAX_VALUE )
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException( "Favicon file too large for server to process" );
|
||||||
|
}
|
||||||
|
|
||||||
|
// create
|
||||||
|
return new Favicon( encoded );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Favicon from an encoded PNG.
|
||||||
|
*
|
||||||
|
* @deprecated Use #create(java.awt.image.BufferedImage) or one of the read
|
||||||
|
* methods instead.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public static Favicon create(String encodedString)
|
||||||
|
{
|
||||||
|
return new Favicon( encodedString );
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,11 @@
|
|||||||
package net.md_5.bungee.api;
|
package net.md_5.bungee.api;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import net.md_5.bungee.Util;
|
import net.md_5.bungee.Util;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the standard list data returned by opening a server in the
|
* Represents the standard list data returned by opening a server in the
|
||||||
* Minecraft client server list, or hitting it with a packet 0xFE.
|
* Minecraft client server list, or hitting it with a packet 0xFE.
|
||||||
@ -73,5 +72,33 @@ public class ServerPing
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
private String description;
|
private String description;
|
||||||
private String favicon;
|
private Favicon favicon;
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public ServerPing(Protocol version, Players players, String description, String favicon)
|
||||||
|
{
|
||||||
|
this( version, players, description, Favicon.create( favicon ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public String getFavicon()
|
||||||
|
{
|
||||||
|
return getFaviconObject() == null ? null : getFaviconObject().getEncoded();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Favicon getFaviconObject()
|
||||||
|
{
|
||||||
|
return this.favicon;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public void setFavicon(String favicon)
|
||||||
|
{
|
||||||
|
setFavicon( favicon == null ? null : Favicon.create( favicon ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFavicon(Favicon favicon)
|
||||||
|
{
|
||||||
|
this.favicon = favicon;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package net.md_5.bungee;
|
package net.md_5.bungee;
|
||||||
|
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
|
import net.md_5.bungee.api.Favicon;
|
||||||
import net.md_5.bungee.api.ServerPing;
|
import net.md_5.bungee.api.ServerPing;
|
||||||
import net.md_5.bungee.module.ModuleManager;
|
import net.md_5.bungee.module.ModuleManager;
|
||||||
import com.google.common.io.ByteStreams;
|
import com.google.common.io.ByteStreams;
|
||||||
@ -126,9 +127,11 @@ public class BungeeCord extends ProxyServer
|
|||||||
@Getter
|
@Getter
|
||||||
private final Logger logger;
|
private final Logger logger;
|
||||||
public final Gson gson = new GsonBuilder()
|
public final Gson gson = new GsonBuilder()
|
||||||
.registerTypeAdapter( ServerPing.PlayerInfo.class, new PlayerInfoSerializer( 5 ) ).create();
|
.registerTypeAdapter( ServerPing.PlayerInfo.class, new PlayerInfoSerializer( 5 ) )
|
||||||
|
.registerTypeAdapter( Favicon.class, Favicon.getFaviconTypeAdapter() ).create();
|
||||||
public final Gson gsonLegacy = new GsonBuilder()
|
public final Gson gsonLegacy = new GsonBuilder()
|
||||||
.registerTypeAdapter( ServerPing.PlayerInfo.class, new PlayerInfoSerializer( 4 ) ).create();
|
.registerTypeAdapter( ServerPing.PlayerInfo.class, new PlayerInfoSerializer( 4 ) )
|
||||||
|
.registerTypeAdapter( Favicon.class, Favicon.getFaviconTypeAdapter() ).create();
|
||||||
@Getter
|
@Getter
|
||||||
private ConnectionThrottle connectionThrottle;
|
private ConnectionThrottle connectionThrottle;
|
||||||
private final ModuleManager moduleManager = new ModuleManager();
|
private final ModuleManager moduleManager = new ModuleManager();
|
||||||
|
@ -1,12 +1,7 @@
|
|||||||
package net.md_5.bungee.conf;
|
package net.md_5.bungee.conf;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import com.google.common.io.BaseEncoding;
|
|
||||||
import com.google.common.io.Files;
|
|
||||||
import gnu.trove.map.TMap;
|
import gnu.trove.map.TMap;
|
||||||
import java.awt.Image;
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -16,6 +11,7 @@ import java.util.UUID;
|
|||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import net.md_5.bungee.api.Favicon;
|
||||||
import net.md_5.bungee.api.ProxyConfig;
|
import net.md_5.bungee.api.ProxyConfig;
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
import net.md_5.bungee.api.config.ConfigurationAdapter;
|
import net.md_5.bungee.api.config.ConfigurationAdapter;
|
||||||
@ -55,7 +51,7 @@ public class Configuration implements ProxyConfig
|
|||||||
private Collection<String> disabledCommands;
|
private Collection<String> disabledCommands;
|
||||||
private int throttle = 4000;
|
private int throttle = 4000;
|
||||||
private boolean ipFoward;
|
private boolean ipFoward;
|
||||||
public String favicon;
|
private Favicon favicon;
|
||||||
|
|
||||||
public void load()
|
public void load()
|
||||||
{
|
{
|
||||||
@ -67,28 +63,8 @@ public class Configuration implements ProxyConfig
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
BufferedImage image = ImageIO.read( fav );
|
favicon = Favicon.create( ImageIO.read( fav ) );
|
||||||
if ( image != null )
|
} catch ( IOException | IllegalArgumentException ex )
|
||||||
{
|
|
||||||
if ( image.getHeight() == 64 && image.getWidth() == 64 )
|
|
||||||
{
|
|
||||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
|
||||||
ImageIO.write( image, "png", bytes );
|
|
||||||
favicon = "data:image/png;base64," + BaseEncoding.base64().encode( bytes.toByteArray() );
|
|
||||||
if ( favicon.length() > Short.MAX_VALUE )
|
|
||||||
{
|
|
||||||
ProxyServer.getInstance().getLogger().log( Level.WARNING, "Favicon file too large for server to process" );
|
|
||||||
favicon = null;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
ProxyServer.getInstance().getLogger().log( Level.WARNING, "Server icon must be exactly 64x64 pixels" );
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
ProxyServer.getInstance().getLogger().log( Level.WARNING, "Could not load server icon for unknown reason. Please double check its format." );
|
|
||||||
}
|
|
||||||
} catch ( IOException ex )
|
|
||||||
{
|
{
|
||||||
ProxyServer.getInstance().getLogger().log( Level.WARNING, "Could not load server icon", ex );
|
ProxyServer.getInstance().getLogger().log( Level.WARNING, "Could not load server icon", ex );
|
||||||
}
|
}
|
||||||
@ -143,4 +119,15 @@ public class Configuration implements ProxyConfig
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public String getFavicon()
|
||||||
|
{
|
||||||
|
return getFaviconObject().getEncoded();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Favicon getFaviconObject()
|
||||||
|
{
|
||||||
|
return favicon;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import net.md_5.bungee.*;
|
import net.md_5.bungee.*;
|
||||||
import net.md_5.bungee.api.Callback;
|
import net.md_5.bungee.api.Callback;
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
|
import net.md_5.bungee.api.Favicon;
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
import net.md_5.bungee.api.ServerPing;
|
import net.md_5.bungee.api.ServerPing;
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
@ -130,7 +131,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
|||||||
public void handle(LegacyPing ping) throws Exception
|
public void handle(LegacyPing ping) throws Exception
|
||||||
{
|
{
|
||||||
ServerPing legacy = new ServerPing( new ServerPing.Protocol( bungee.getGameVersion(), bungee.getProtocolVersion() ),
|
ServerPing legacy = new ServerPing( new ServerPing.Protocol( bungee.getGameVersion(), bungee.getProtocolVersion() ),
|
||||||
new ServerPing.Players( listener.getMaxPlayers(), bungee.getOnlineCount(), null ), listener.getMotd(), null );
|
new ServerPing.Players( listener.getMaxPlayers(), bungee.getOnlineCount(), null ), listener.getMotd(), (Favicon) null );
|
||||||
legacy = bungee.getPluginManager().callEvent( new ProxyPingEvent( this, legacy ) ).getResponse();
|
legacy = bungee.getPluginManager().callEvent( new ProxyPingEvent( this, legacy ) ).getResponse();
|
||||||
|
|
||||||
String kickMessage = ChatColor.DARK_BLUE
|
String kickMessage = ChatColor.DARK_BLUE
|
||||||
@ -179,7 +180,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
|||||||
pingBack.done( new ServerPing(
|
pingBack.done( new ServerPing(
|
||||||
new ServerPing.Protocol( bungee.getGameVersion(), protocol ),
|
new ServerPing.Protocol( bungee.getGameVersion(), protocol ),
|
||||||
new ServerPing.Players( listener.getMaxPlayers(), bungee.getOnlineCount(), null ),
|
new ServerPing.Players( listener.getMaxPlayers(), bungee.getOnlineCount(), null ),
|
||||||
motd, BungeeCord.getInstance().config.favicon ),
|
motd, BungeeCord.getInstance().config.getFaviconObject() ),
|
||||||
null );
|
null );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user