bungee impl half completed

This commit is contained in:
lax1dude 2024-05-03 17:27:39 -07:00
commit ee06da5fb6
16 changed files with 1205 additions and 0 deletions

View File

@ -0,0 +1,197 @@
package net.lax1dude.eaglercraft.v1_8.plugin.eaglermotd;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.imageio.ImageIO;
/**
* Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class BitmapFile {
public final String name;
public final int[][] frame;
public final int w, h;
public BitmapFile(String name, int[][] frame, int w, int h) {
this.name = name;
this.frame = frame;
this.w = w;
this.h = h;
}
public static final Map<String, BitmapFile> bitmapCache = new HashMap();
public static BitmapFile getCachedIcon(String name) {
BitmapFile ret = bitmapCache.get(name);
if(ret == null) {
File f = new File(name);
if(f.exists()) {
try {
BufferedImage img = ImageIO.read(f);
int w = img.getWidth();
int h = img.getHeight();
if(w < 64 || h < 64) {
System.err.println("[EaglerMOTD] Icon '" + name + "' must be at least be 64x64 pixels large (it is " + w + "x" + h + ")");
}else {
int[][] load = new int[w][h];
for(int y = 0; y < h; ++y) {
for(int x = 0; x < w; ++x) {
load[x][y] = img.getRGB(x, y);
}
}
ret = new BitmapFile(name, load, w, h);
bitmapCache.put(name, ret);
}
} catch (IOException e) {
System.err.println("[EaglerMOTD] Could not load icon file: '" + name + "'");
System.err.println("[EaglerMOTD] Place the file in the same directory as 'messages.json'");
e.printStackTrace();
}
}
}
return ret;
}
public int[] getSprite(int x, int y) {
if(x < 0 || y < 0) {
return null;
}
int offsetX = x;
int offsetY = y;
if(offsetX + 64 > w || offsetY + 64 > h) {
return null;
}
int[] ret = new int[64 * 64];
for(int i = 0; i < ret.length; ++i) {
int xx = i % 64;
int yy = i / 64;
ret[i] = frame[offsetX + xx][offsetY + yy];
}
return ret;
}
public static int[] makeColor(int[] in, float r, float g, float b, float a) {
if(r < 0.0f) r = 0.0f;
if(r > 1.0f) r = 1.0f;
if(g < 0.0f) g = 0.0f;
if(g > 1.0f) g = 1.0f;
if(b < 0.0f) b = 0.0f;
if(b > 1.0f) b = 1.0f;
if(a < 0.0f) a = 0.0f;
if(a > 1.0f) a = 1.0f;
int c = ((int)(a*255.0f) << 24) | ((int)(r*255.0f) << 16) | ((int)(g*255.0f) << 8) | (int)(b*255.0f);
for(int i = 0; i < in.length; ++i) {
in[i] = c;
}
return in;
}
public static int[] applyColor(int[] in, float r, float g, float b, float a) {
for(int i = 0; i < in.length; ++i) {
float rr = ((in[i] >> 16) & 0xFF) / 255.0f;
float gg = ((in[i] >> 8) & 0xFF) / 255.0f;
float bb = (in[i] & 0xFF) / 255.0f;
float aa = ((in[i] >> 24) & 0xFF) / 255.0f;
rr = r * a + rr * (1.0f - a);
gg = g * a + gg * (1.0f - a);
bb = b * a + bb * (1.0f - a);
aa = a + aa * (1.0f - a);
if(rr < 0.0f) rr = 0.0f;
if(rr > 1.0f) rr = 1.0f;
if(gg < 0.0f) gg = 0.0f;
if(gg > 1.0f) gg = 1.0f;
if(bb < 0.0f) bb = 0.0f;
if(bb > 1.0f) bb = 1.0f;
if(aa < 0.0f) aa = 0.0f;
if(aa > 1.0f) aa = 1.0f;
in[i] = ((int)(aa*255.0f) << 24) | ((int)(rr*255.0f) << 16) | ((int)(gg*255.0f) << 8) | (int)(bb*255.0f);
}
return in;
}
public static int[] applyTint(int[] in, float r, float g, float b, float a) {
for(int i = 0; i < in.length; ++i) {
float rr = ((in[i] >> 16) & 0xFF) / 255.0f * r;
float gg = ((in[i] >> 8) & 0xFF) / 255.0f * g;
float bb = (in[i] & 0xFF) / 255.0f * b;
float aa = ((in[i] >> 24) & 0xFF) / 255.0f * a;
if(rr < 0.0f) rr = 0.0f;
if(rr > 1.0f) rr = 1.0f;
if(gg < 0.0f) gg = 0.0f;
if(gg > 1.0f) gg = 1.0f;
if(bb < 0.0f) bb = 0.0f;
if(bb > 1.0f) bb = 1.0f;
if(aa < 0.0f) aa = 0.0f;
if(aa > 1.0f) aa = 1.0f;
in[i] = ((int)(aa*255.0f) << 24) | ((int)(rr*255.0f) << 16) | ((int)(gg*255.0f) << 8) | (int)(bb*255.0f);
}
return in;
}
private static final ThreadLocal<int[]> flipTmpBuffer = ThreadLocal.withInitial(() -> new int[64]);
public static int[] flipX(int[] newIcon) {
int[] tmp = flipTmpBuffer.get();
for(int y = 0; y < 64; ++y) {
int o = y * 64;
System.arraycopy(newIcon, o, tmp, 0, 64);
for(int i = 0; i < 64; ++i) {
newIcon[o + i] = tmp[63 - i];
}
}
return newIcon;
}
public static int[] flipY(int[] newIcon) {
int[] tmp = flipTmpBuffer.get();
for(int x = 0; x < 64; ++x) {
for(int i = 0; i < 64; ++i) {
tmp[i] = newIcon[i * 64 + x];
}
for(int i = 0; i < 64; ++i) {
newIcon[i * 64 + x] = tmp[63 - i];
}
}
return newIcon;
}
private static int[] transpose(int[] in) {
int[] ret = new int[64*64];
for(int y = 0; y < 64; ++y) {
for(int x = 0; x < 64; ++x) {
ret[x * 64 + y] = in[y * 64 + x];
}
}
return ret;
}
public static int[] rotate(int[] newIcon, int rotate) {
rotate = rotate % 4;
if(rotate == 1) {
newIcon = flipX(transpose(newIcon));
}else if(rotate == 2) {
newIcon = flipY(flipX(newIcon));
}else if(rotate == 3) {
newIcon = flipY(transpose(newIcon));
}
return newIcon;
}
}

View File

@ -0,0 +1,52 @@
package net.lax1dude.eaglercraft.v1_8.plugin.eaglermotd;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.google.gson.JsonObject;
/**
* Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class EaglerMOTDConfiguration {
public final Map<String,List<MessagePoolEntry>> messages = new HashMap();
public final Map<String,MessagePool> messagePools = new HashMap();
public final Map<String,JsonObject> framesCache = new HashMap();
public int close_socket_after = 1200;
public int max_sockets_per_ip = 10;
public int max_total_sockets = 256;
public void reload(File pluginDir) {
}
public static final char COLOR_CHAR = '\u00A7';
public static final String ALL_CODES = "0123456789AaBbCcDdEeFfKkLlMmNnOoRrXx";
public static String translateAlternateColorCodes(char altColorChar, String textToTranslate) {
char[] b = textToTranslate.toCharArray();
for (int i = 0; i < b.length - 1; i++) {
if (b[i] == altColorChar && ALL_CODES.indexOf(b[i + 1]) > -1) {
b[i] = EaglerMOTDConfiguration.COLOR_CHAR;
b[i + 1] = Character.toLowerCase(b[i + 1]);
}
}
return new String(b);
}
}

View File

@ -0,0 +1,55 @@
package net.lax1dude.eaglercraft.v1_8.plugin.eaglermotd;
import java.net.InetAddress;
import java.util.List;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public interface EaglerMOTDConnectionAdapter {
boolean isClosed();
void close();
String getAccept();
InetAddress getAddress();
String getListener();
long getConnectionTimestamp();
long getConnectionAge();
void sendToUser();
String getLine1();
String getLine2();
List<String> getPlayerList();
int[] getBitmap();
int getOnlinePlayers();
int getMaxPlayers();
String getSubType();
void setLine1(String p);
void setLine2(String p);
void setPlayerList(List<String> p);
void setPlayerList(String... p);
void setBitmap(int[] p);
void setOnlinePlayers(int i);
void setMaxPlayers(int i);
void setKeepAlive(boolean b);
int getDefaultMaxPlayers();
int getDefaultOnlinePlayers();
List<String> getDefaultOnlinePlayersList(int maxLen);
}

View File

@ -0,0 +1,364 @@
package net.lax1dude.eaglercraft.v1_8.plugin.eaglermotd;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
/**
* Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class EaglerMOTDConnectionUpdater {
public final EaglerMOTDConfiguration conf;
public final String listenerName;
public final int defaultMaxPlayers;
public final EaglerMOTDConnectionAdapter motd;
public MessagePoolEntry currentMessage = null;
public int messageTimeTimer = 0;
public int messageIntervalTimer = 0;
public int currentFrame = 0;
public int ageTimer = 0;
public BitmapFile bitmap = null;
public int spriteX = 0;
public int spriteY = 0;
public boolean flipX = false;
public boolean flipY = false;
public int rotate = 0;
public float[] color = new float[] { 0.0f, 0.0f, 0.0f, 0.0f };
public float[] tint = new float[] { 0.0f, 0.0f, 0.0f, 0.0f };
private Random rand = null;
public EaglerMOTDConnectionUpdater(EaglerMOTDConfiguration conf, String listenerName, int defaultMaxPlayers, EaglerMOTDConnectionAdapter m) {
this.conf = conf;
this.motd = m;
this.listenerName = listenerName;
this.defaultMaxPlayers = defaultMaxPlayers;
}
public boolean execute() {
MessagePool p = conf.messagePools.get(listenerName);
if(p == null) {
return false;
}
messageTimeTimer = 0;
messageIntervalTimer = 0;
currentMessage = p.pickDefault();
if(currentMessage.random || currentMessage.shuffle) {
rand = new Random();
}
currentFrame = currentMessage.random ? rand.nextInt(currentMessage.frames.size()) : 0;
applyFrame(currentMessage.frames.get(currentFrame));
if(currentMessage.interval > 0 || currentMessage.next != null) {
this.motd.setKeepAlive(true);
return true;
}else {
this.motd.setKeepAlive(false);
return false;
}
}
public boolean tick() {
ageTimer++;
if(this.motd.isClosed()) {
return false;
}
if(ageTimer > conf.close_socket_after) {
this.motd.close();
return false;
}
messageTimeTimer++;
if(messageTimeTimer >= currentMessage.timeout) {
if(currentMessage.next != null) {
if(currentMessage.next.equalsIgnoreCase("any") || currentMessage.next.equalsIgnoreCase("random")) {
MessagePool p = conf.messagePools.get(listenerName);
if(p == null) {
this.motd.close();
return false;
}
if(p.messagePool.size() > 1) {
MessagePoolEntry m;
do {
m = p.pickNew();
}while(m == currentMessage);
currentMessage = m;
}
}else {
if(!changeMessageTo(listenerName, currentMessage.next)) {
boolean flag = false;
for(String s : conf.messages.keySet()) {
if(!s.equalsIgnoreCase(listenerName) && changeMessageTo(s, currentMessage.next)) {
flag = true;
break;
}
}
if(!flag) {
this.motd.close();
return false;
}
}
}
if(currentMessage == null) {
this.motd.close();
return false;
}
messageTimeTimer = 0;
messageIntervalTimer = 0;
if(rand == null && (currentMessage.random || currentMessage.shuffle)) {
rand = new Random();
}
currentFrame = currentMessage.random ? rand.nextInt(currentMessage.frames.size()) : 0;
applyFrame(currentMessage.frames.get(currentFrame));
motd.sendToUser();
if(currentMessage.next == null && currentMessage.interval <= 0) {
motd.close();
return false;
}else {
return true;
}
}else {
this.motd.close();
return false;
}
}else {
messageIntervalTimer++;
if(currentMessage.interval > 0 && messageIntervalTimer >= currentMessage.interval) {
messageIntervalTimer = 0;
if(currentMessage.frames.size() > 1) {
if(currentMessage.shuffle) {
int i;
do {
i = rand.nextInt(currentMessage.frames.size());
}while(i == currentFrame);
currentFrame = i;
}else {
++currentFrame;
if(currentFrame >= currentMessage.frames.size()) {
currentFrame = 0;
}
}
applyFrame(currentMessage.frames.get(currentFrame));
motd.sendToUser();
}
}
if(currentMessage.next == null && currentMessage.interval <= 0) {
motd.close();
return false;
}else {
return true;
}
}
}
private boolean changeMessageTo(String group, String s) {
if(group == null || s == null) {
return false;
}
List<MessagePoolEntry> lst = conf.messages.get(group);
if(lst == null) {
return false;
}
for(MessagePoolEntry m : lst) {
if(m.name.equalsIgnoreCase(s)) {
currentMessage = m;
return true;
}
}
return false;
}
public void applyFrame(JsonObject frame) {
boolean shouldPush = false;
JsonElement v = frame.get("online");
if(v != null) {
if(v.isJsonPrimitive() && ((JsonPrimitive)v).isNumber()) {
motd.setOnlinePlayers(v.getAsInt());
}else {
motd.setOnlinePlayers(motd.getDefaultOnlinePlayers());
}
shouldPush = true;
}
v = frame.get("max");
if(v != null) {
if(v.isJsonPrimitive() && ((JsonPrimitive)v).isNumber()) {
motd.setMaxPlayers(v.getAsInt());
}else {
motd.setMaxPlayers(motd.getDefaultMaxPlayers());
}
shouldPush = true;
}
v = frame.get("players");
if(v != null) {
if(v.isJsonArray()) {
List<String> players = new ArrayList();
JsonArray vv = (JsonArray) v;
for(int i = 0, l = vv.size(); i < l; ++i) {
players.add(EaglerMOTDConfiguration.translateAlternateColorCodes('&', vv.get(i).getAsString()));
}
motd.setPlayerList(players);
}else {
motd.setPlayerList(motd.getDefaultOnlinePlayersList(9));
}
shouldPush = true;
}
String line = optString(frame.get("text0"), optString(frame.get("text"), null));
if(line != null) {
int ix = line.indexOf('\n');
if(ix != -1) {
motd.setLine1(EaglerMOTDConfiguration.translateAlternateColorCodes('&', line.substring(0, ix)));
motd.setLine2(EaglerMOTDConfiguration.translateAlternateColorCodes('&', line.substring(ix + 1)));
}else {
motd.setLine1(EaglerMOTDConfiguration.translateAlternateColorCodes('&', line));
}
line = optString(frame.get("text1"), null);
if(line != null) {
motd.setLine2(EaglerMOTDConfiguration.translateAlternateColorCodes('&', line));
}
shouldPush = true;
}
if(!this.motd.getAccept().equalsIgnoreCase("motd.noicon")) {
boolean shouldRenderIcon = false;
JsonElement icon = frame.get("icon");
if(icon != null) {
String asString = (icon.isJsonPrimitive() && ((JsonPrimitive)icon).isString()) ? icon.getAsString() : null;
shouldRenderIcon = true;
if(icon.isJsonNull() || asString == null || asString.equalsIgnoreCase("none") || asString.equalsIgnoreCase("default")
|| asString.equalsIgnoreCase("null") || asString.equalsIgnoreCase("color")) {
bitmap = null;
}else {
bitmap = BitmapFile.getCachedIcon(asString);
}
spriteX = spriteY = rotate = 0;
flipX = flipY = false;
color = new float[] { 0.0f, 0.0f, 0.0f, 0.0f };
tint = new float[] { 1.0f, 1.0f, 1.0f, 1.0f };
}
int sprtX = optInt(frame.get("icon_spriteX"), -1) * 64;
if(sprtX >= 0 && sprtX != spriteX) {
shouldRenderIcon = true;
spriteX = sprtX;
}
int sprtY = optInt(frame.get("icon_spriteY"), -1) * 64;
if(sprtY >= 0 && sprtY != spriteY) {
shouldRenderIcon = true;
spriteY = sprtY;
}
sprtX = optInt(frame.get("icon_pixelX"), -1);
if(sprtX >= 0 && sprtX != spriteX) {
shouldRenderIcon = true;
spriteX = sprtX;
}
sprtY = optInt(frame.get("icon_pixelY"), -1);
if(sprtY >= 0 && sprtY != spriteY) {
shouldRenderIcon = true;
spriteY = sprtY;
}
JsonElement flip = frame.get("icon_flipX");
if(flip != null) {
shouldRenderIcon = true;
if(flip.isJsonPrimitive() && ((JsonPrimitive)flip).isBoolean()) {
flipX = flip.getAsBoolean();
}else {
flipX = false;
}
}
flip = frame.get("icon_flipY");
if(flip != null) {
shouldRenderIcon = true;
if(flip.isJsonPrimitive() && ((JsonPrimitive)flip).isBoolean()) {
flipY = flip.getAsBoolean();
}else {
flipY = false;
}
}
int rot = optInt(frame.get("icon_rotate"), -1);
if(rot >= 0) {
shouldRenderIcon = true;
rotate = rot % 4;
}
JsonArray colorF = optJSONArray(frame.get("icon_color"));
if(colorF != null && colorF.size() > 0) {
shouldRenderIcon = true;
color[0] = colorF.get(0).getAsFloat();
color[1] = colorF.size() > 1 ? colorF.get(1).getAsFloat() : color[1];
color[2] = colorF.size() > 2 ? colorF.get(2).getAsFloat() : color[2];
color[3] = colorF.size() > 3 ? colorF.get(3).getAsFloat() : 1.0f;
}
colorF = optJSONArray(frame.get("icon_tint"));
if(colorF != null && colorF.size() > 0) {
shouldRenderIcon = true;
tint[0] = colorF.get(0).getAsFloat();
tint[1] = colorF.size() > 1 ? colorF.get(1).getAsFloat() : tint[1];
tint[2] = colorF.size() > 2 ? colorF.get(2).getAsFloat() : tint[2];
tint[3] = colorF.size() > 3 ? colorF.get(3).getAsFloat() : 1.0f;
}
if(shouldRenderIcon) {
int[] newIcon = null;
if(bitmap != null) {
newIcon = bitmap.getSprite(spriteX, spriteY);
}
if(newIcon == null) {
newIcon = new int[64*64];
}
newIcon = BitmapFile.applyTint(newIcon, tint[0], tint[1], tint[2], tint[3]);
if(color[3] > 0.0f) {
newIcon = BitmapFile.applyColor(newIcon, color[0], color[1], color[2], color[3]);
}
if(bitmap != null) {
if(flipX) {
newIcon = BitmapFile.flipX(newIcon);
}
if(flipY) {
newIcon = BitmapFile.flipY(newIcon);
}
if(rotate != 0) {
newIcon = BitmapFile.rotate(newIcon, rotate);
}
}
motd.setBitmap(newIcon);
shouldPush = true;
}
}
if(shouldPush) {
motd.sendToUser();
}
}
public void close() {
motd.close();
}
private static String optString(JsonElement el, String def) {
return (el != null && el.isJsonPrimitive() && ((JsonPrimitive)el).isString()) ? el.getAsString() : def;
}
private static int optInt(JsonElement el, int def) {
return (el != null && el.isJsonPrimitive() && ((JsonPrimitive)el).isNumber()) ? el.getAsInt() : def;
}
private static JsonArray optJSONArray(JsonElement el) {
return (el != null && el instanceof JsonArray) ? (JsonArray)el : null;
}
}

View File

@ -0,0 +1,26 @@
package net.lax1dude.eaglercraft.v1_8.plugin.eaglermotd;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public interface EaglerMOTDLoggerAdapter {
void info(String msg);
void warn(String msg);
void error(String msg);
}

View File

@ -0,0 +1,33 @@
package net.lax1dude.eaglercraft.v1_8.plugin.eaglermotd;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
/**
* Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class EaglerMOTDUtils {
public static String makeListenerString(InetSocketAddress addr) {
InetAddress addrHost = addr.getAddress();
if(addrHost instanceof Inet6Address) {
return "[" + addrHost.getHostAddress() + "]:" + addr.getPort();
}else {
return addrHost.getHostAddress() + ":" + addr.getPort();
}
}
}

View File

@ -0,0 +1,65 @@
package net.lax1dude.eaglercraft.v1_8.plugin.eaglermotd;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
/**
* Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class MessagePool {
public final String poolName;
public final List<MessagePoolEntry> messagePool = new LinkedList();
public final Random random = new Random();
public MessagePool(String s) {
this.poolName = s;
}
public void sort() {
Collections.sort(messagePool);
}
public MessagePoolEntry pickNew() {
if(messagePool.size() <= 0) {
return null;
}
float f = 0.0f;
for(MessagePoolEntry m : messagePool) {
f += m.weight;
}
f *= random.nextFloat();
float f2 = 0.0f;
for(MessagePoolEntry m : messagePool) {
f2 += m.weight;
if(f2 >= f) {
return m;
}
}
return messagePool.get(0);
}
public MessagePoolEntry pickDefault() {
for(MessagePoolEntry m : messagePool) {
if("default".equalsIgnoreCase(m.name)) {
return m;
}
}
return pickNew();
}
}

View File

@ -0,0 +1,49 @@
package net.lax1dude.eaglercraft.v1_8.plugin.eaglermotd;
import java.util.List;
import com.google.gson.JsonObject;
/**
* Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class MessagePoolEntry implements Comparable<MessagePoolEntry> {
public final String name;
public final int interval;
public final int timeout;
public final boolean random;
public final boolean shuffle;
public final float weight;
public final String next;
public final List<JsonObject> frames;
public MessagePoolEntry(int interval, int timeout, boolean random, boolean shuffle, float weight, String next, List<JsonObject> frames, String name) {
this.interval = interval;
this.timeout = timeout;
this.random = random;
this.shuffle = shuffle;
this.weight = weight;
this.next = next;
this.frames = frames;
this.name = name;
}
@Override
public int compareTo(MessagePoolEntry o) {
return Float.compare(weight, o.weight);
}
}

View File

@ -0,0 +1,191 @@
package net.lax1dude.eaglercraft.v1_8.plugin.eaglermotd.bungee;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import net.lax1dude.eaglercraft.v1_8.plugin.eaglermotd.EaglerMOTDConnectionAdapter;
import net.lax1dude.eaglercraft.v1_8.plugin.eaglermotd.EaglerMOTDUtils;
import net.lax1dude.eaglercraft.v1_8.plugin.gateway_bungeecord.api.query.MOTDConnection;
import net.lax1dude.eaglercraft.v1_8.plugin.gateway_bungeecord.config.EaglerListenerConfig;
import net.lax1dude.eaglercraft.v1_8.plugin.gateway_bungeecord.server.query.MOTDQueryHandler;
import net.md_5.bungee.BungeeCord;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.connection.ProxiedPlayer;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class EaglerMOTDConnectionBungee implements EaglerMOTDConnectionAdapter {
private final MOTDConnection con;
private String listenerString = null;
public EaglerMOTDConnectionBungee(MOTDConnection con) {
this.con = con;
}
@Override
public boolean isClosed() {
return con.isClosed();
}
@Override
public void close() {
con.close();
}
@Override
public String getAccept() {
return con.getAccept();
}
@Override
public InetAddress getAddress() {
return con.getAddress();
}
@Override
public String getListener() {
if(listenerString == null) {
EaglerListenerConfig config = con.getListener();
if(config.getAddress() != null) {
this.listenerString = EaglerMOTDUtils.makeListenerString(config.getAddress());
}else if(config.getAddressV6() != null) {
this.listenerString = EaglerMOTDUtils.makeListenerString(config.getAddressV6());
}else {
throw new RuntimeException("Listener does not have an address!?");
}
}
return listenerString;
}
@Override
public long getConnectionTimestamp() {
return con.getConnectionTimestamp();
}
@Override
public long getConnectionAge() {
return con.getConnectionAge();
}
@Override
public void sendToUser() {
con.sendToUser();
}
@Override
public String getLine1() {
return con.getLine1();
}
@Override
public String getLine2() {
return con.getLine2();
}
@Override
public List<String> getPlayerList() {
return con.getPlayerList();
}
@Override
public int[] getBitmap() {
return con.getBitmap();
}
@Override
public int getOnlinePlayers() {
return con.getOnlinePlayers();
}
@Override
public int getMaxPlayers() {
return con.getMaxPlayers();
}
@Override
public String getSubType() {
return con.getSubType();
}
@Override
public void setLine1(String p) {
con.setLine1(p);
}
@Override
public void setLine2(String p) {
con.setLine2(p);
}
@Override
public void setPlayerList(List<String> p) {
con.setPlayerList(p);
}
@Override
public void setPlayerList(String... p) {
con.setPlayerList(p);
}
@Override
public void setBitmap(int[] p) {
con.setBitmap(p);
}
@Override
public void setOnlinePlayers(int i) {
con.setOnlinePlayers(i);
}
@Override
public void setMaxPlayers(int i) {
con.setMaxPlayers(i);
}
@Override
public void setKeepAlive(boolean b) {
// workaround for pre-1.2.0 EaglerXBungee
((MOTDQueryHandler)con).setKeepAlive(b);
}
@Override
public int getDefaultMaxPlayers() {
return con.getListener().getMaxPlayer();
}
@Override
public int getDefaultOnlinePlayers() {
return 0;
}
@Override
public List<String> getDefaultOnlinePlayersList(int maxLen) {
Collection<ProxiedPlayer> ppl = BungeeCord.getInstance().getPlayers();
List<String> players = new ArrayList(Math.min(ppl.size(), maxLen + 1));
for(ProxiedPlayer pp : ppl) {
players.add(pp.getDisplayName());
if(players.size() >= maxLen) {
players.add("" + ChatColor.GRAY + ChatColor.ITALIC + "(" + (ppl.size() - players.size()) + " more)");
break;
}
}
return players;
}
}

View File

@ -0,0 +1,29 @@
package net.lax1dude.eaglercraft.v1_8.plugin.eaglermotd.bungee;
import net.lax1dude.eaglercraft.v1_8.plugin.gateway_bungeecord.api.event.EaglercraftMOTDEvent;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.event.EventHandler;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class EaglerMOTDListenerBungee implements Listener {
@EventHandler
public void handleMOTDEvent(EaglercraftMOTDEvent evt) {
}
}

View File

@ -0,0 +1,34 @@
package net.lax1dude.eaglercraft.v1_8.plugin.eaglermotd.bungee;
import java.util.LinkedList;
import java.util.List;
import java.util.Timer;
import net.lax1dude.eaglercraft.v1_8.plugin.eaglermotd.EaglerMOTDConfiguration;
import net.lax1dude.eaglercraft.v1_8.plugin.eaglermotd.EaglerMOTDConnectionUpdater;
import net.md_5.bungee.api.plugin.Plugin;
/**
* Copyright (c) 2024 lax1dude. All Rights Reserved.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
public class EaglerMOTDPluginBungee extends Plugin {
private static EaglerMOTDPluginBungee instance = null;
public final EaglerMOTDConfiguration conf = new EaglerMOTDConfiguration();
public final Timer tickTimer = new Timer("MOTD Tick Timer");
public final List<EaglerMOTDConnectionUpdater> motdConnections = new LinkedList();
}

View File

@ -0,0 +1,44 @@
{
"frame1": {
"icon": "server-animation.png",
"icon_spriteX": 0,
"icon_spriteY": 0,
"online": "default",
"max": "default",
"players": "default",
"text0": "&7An Eaglercraft server",
"text1": "&0!!!!&8Running EaglerMOTD plugin"
},
"frame2": {
"icon": "server-animation.png",
"icon_spriteX": 1,
"icon_spriteY": 0,
"icon_color": [ 1.0, 0.0, 0.0, 0.15 ],
"online": 10,
"players": [ "fake player 1", "fake player 2" ],
"text0": "&6&nAn&r &7Eaglercraft server",
"text1": "&0!!&8!&0!&8Running EaglerMOTD plugin"
},
"frame3": {
"icon": "server-animation.png",
"icon_spriteX": 2,
"icon_spriteY": 0,
"icon_color": [ 1.0, 0.0, 0.0, 0.15 ],
"icon_tint": [ 0.8, 0.8, 1.0 ],
"online": 20,
"players": [],
"text0": "&7An &6&nEaglercraft&r &7server",
"text1": "&0!&8!!&0!&8Running EaglerMOTD plugin"
},
"frame4": {
"icon": "server-animation.png",
"icon_spriteX": 3,
"icon_spriteY": 0,
"icon_color": [ 1.0, 1.0, 0.0, 0.15 ],
"icon_tint": [ 0.8, 0.8, 1.0, 0.8 ],
"online": 30,
"players": "default",
"text0": "&7An Eaglercraft &6&nserver&r",
"text1": "&8!!!&0!&8Running EaglerMOTD plugin"
}
}

View File

@ -0,0 +1,24 @@
{
"close_socket_after": 1200,
"max_sockets_per_ip": 10,
"max_total_sockets": 256,
"messages": {
"all": [
{
"name": "default",
"frames": [
"frames.frame1",
"frames.frame2",
"frames.frame3",
"frames.frame4"
],
"interval": 8,
"random": false,
"shuffle": false,
"timeout": 500,
"weight": 1.0,
"next": "any"
}
]
}
}

View File

@ -0,0 +1,37 @@
{
"queries": {
"ExampleQuery1": {
"type": "ExampleQuery1_result",
"string": "This is a string"
},
"ExampleQuery2": {
"type": "ExampleQuery2_result",
"txt": "query2.txt"
},
"ExampleQuery3": {
"type": "ExampleQuery3_result",
"string": "This query returns binary",
"file": "binary.dat"
},
"ExampleQuery4": {
"type": "ExampleQuery4_result",
"json": "query4.json"
},
"ExampleQuery5": {
"type": "ExampleQuery5_result",
"json": {
"key1": "value1",
"key2": "value2"
}
},
"ExampleQuery6": {
"type": "ExampleQuery6_result",
"json": {
"desc": "This query returns JSON and a file",
"filename": "test_file.dat",
"size": 69
},
"file": "test_file.dat"
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

View File

@ -0,0 +1,5 @@
name: EaglerMOTD
main: net.lax1dude.eaglercraft.v1_8.plugin.eaglermotd.bungee.EaglerMOTDPluginBungee
version: 1.0.0
author: lax1dude
description: Plugin to add an animated MOTDs to your EaglercraftXBungee server